feat: add ViewTransitions from Astro

Integrate ViewTransitions API from Astro v3.

resolve #96
This commit is contained in:
satnaing
2023-09-14 14:00:08 +06:30
committed by Sat Naing
parent e486687610
commit cbdaa59bae
11 changed files with 103 additions and 35 deletions
+14 -7
View File
@@ -50,14 +50,21 @@ function reflectPreference() {
reflectPreference(); reflectPreference();
window.onload = () => { window.onload = () => {
// set on load so screen readers can get the latest value on the button function setThemeFeature() {
reflectPreference(); // set on load so screen readers can get the latest value on the button
reflectPreference();
// now this script can find and listen for clicks on the control // now this script can find and listen for clicks on the control
document.querySelector("#theme-btn")?.addEventListener("click", () => { document.querySelector("#theme-btn")?.addEventListener("click", () => {
themeValue = themeValue === "light" ? "dark" : "light"; themeValue = themeValue === "light" ? "dark" : "light";
setPreference(); setPreference();
}); });
}
setThemeFeature();
// Runs on view transitions navigation
document.addEventListener("astro:after-swap", setThemeFeature);
}; };
// sync with system changes // sync with system changes
+22
View File
@@ -0,0 +1,22 @@
---
import Datetime from "@components/Datetime";
import type { BlogFrontmatter } from "@content/_schemas";
export interface Props {
href?: string;
frontmatter: BlogFrontmatter;
secHeading?: boolean;
}
const { href, frontmatter, secHeading = true } = Astro.props;
const { title, pubDatetime, description } = frontmatter;
---
<li class="list-card">
<a href={href} transition:name={title}>
{secHeading ? <h2>{title}</h2> : <h3>{title}</h3>}
</a>
<Datetime datetime={pubDatetime} />
<p>{description}</p>
</li>
+21 -14
View File
@@ -189,19 +189,26 @@ const { activeNav } = Astro.props;
</style> </style>
<script> <script>
// Toggle menu function toggleNav() {
const menuBtn = document.querySelector(".hamburger-menu"); // Toggle menu
const menuIcon = document.querySelector(".menu-icon"); const menuBtn = document.querySelector(".hamburger-menu");
const menuItems = document.querySelector("#menu-items"); const menuIcon = document.querySelector(".menu-icon");
const menuItems = document.querySelector("#menu-items");
menuBtn?.addEventListener("click", () => { menuBtn?.addEventListener("click", () => {
const menuExpanded = menuBtn.getAttribute("aria-expanded") === "true"; const menuExpanded = menuBtn.getAttribute("aria-expanded") === "true";
menuIcon?.classList.toggle("is-active"); menuIcon?.classList.toggle("is-active");
menuBtn.setAttribute("aria-expanded", menuExpanded ? "false" : "true"); menuBtn.setAttribute("aria-expanded", menuExpanded ? "false" : "true");
menuBtn.setAttribute( menuBtn.setAttribute(
"aria-label", "aria-label",
menuExpanded ? "Open Menu" : "Close Menu" menuExpanded ? "Open Menu" : "Close Menu"
); );
menuItems?.classList.toggle("display-none"); menuItems?.classList.toggle("display-none");
}); });
}
toggleNav();
// Runs on view transitions navigation
document.addEventListener("astro:after-swap", toggleNav);
</script> </script>
+2 -2
View File
@@ -67,9 +67,9 @@ export default function SearchBar({ searchList }: Props) {
searchParams.set("q", inputVal); searchParams.set("q", inputVal);
const newRelativePathQuery = const newRelativePathQuery =
window.location.pathname + "?" + searchParams.toString(); window.location.pathname + "?" + searchParams.toString();
history.replaceState(null, "", newRelativePathQuery); history.replaceState(history.state, "", newRelativePathQuery);
} else { } else {
history.replaceState(null, "", window.location.pathname); history.replaceState(history.state, "", window.location.pathname);
} }
}, [inputVal]); }, [inputVal]);
+1
View File
@@ -14,6 +14,7 @@ const { name, size = "sm" } = Astro.props;
> >
<a <a
href={`/tags/${name.toLowerCase()}`} href={`/tags/${name.toLowerCase()}`}
transition:name={name.toLowerCase()}
class={`${size === "sm" ? "text-sm" : "text-lg"} pr-2 group`} class={`${size === "sm" ? "text-sm" : "text-lg"} pr-2 group`}
> >
<svg <svg
+4 -1
View File
@@ -1,6 +1,7 @@
--- ---
import { SITE } from "@config"; import { SITE } from "@config";
import "@styles/base.css"; import "@styles/base.css";
import { ViewTransitions } from "astro:transitions";
const googleSiteVerification = import.meta.env.PUBLIC_GOOGLE_SITE_VERIFICATION; const googleSiteVerification = import.meta.env.PUBLIC_GOOGLE_SITE_VERIFICATION;
@@ -26,7 +27,7 @@ const socialImageURL = new URL(
).href; ).href;
--- ---
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
@@ -77,6 +78,8 @@ const socialImageURL = new URL(
) )
} }
<ViewTransitions />
<script is:inline src="/toggle-theme.js"></script> <script is:inline src="/toggle-theme.js"></script>
</head> </head>
<body> <body>
+23 -4
View File
@@ -1,18 +1,37 @@
--- ---
import Breadcrumbs from "@components/Breadcrumbs.astro"; import Breadcrumbs from "@components/Breadcrumbs.astro";
export interface Props { interface StringTitleProp {
pageTitle: string; pageTitle: string;
pageDesc?: string; pageDesc?: string;
} }
const { pageTitle, pageDesc } = Astro.props; interface ArrayTitleProp {
pageTitle: [string, string];
titleTransition: string;
pageDesc?: string;
}
export type Props = StringTitleProp | ArrayTitleProp;
const { props } = Astro;
--- ---
<Breadcrumbs /> <Breadcrumbs />
<main id="main-content"> <main id="main-content">
<h1>{pageTitle}</h1> {
<p>{pageDesc}</p> "titleTransition" in props ? (
<h1>
{props.pageTitle[0]}
<span transition:name={props.titleTransition}>
{props.pageTitle[1]}
</span>
</h1>
) : (
<h1>{props.pageTitle}</h1>
)
}
<p>{props.pageDesc}</p>
<slot /> <slot />
</main> </main>
+10 -3
View File
@@ -13,7 +13,8 @@ export interface Props {
const { post } = Astro.props; const { post } = Astro.props;
const { title, author, description, ogImage, canonicalURL, pubDatetime, tags } = post.data; const { title, author, description, ogImage, canonicalURL, pubDatetime, tags } =
post.data;
const { Content } = await post.render(); const { Content } = await post.render();
@@ -21,7 +22,13 @@ const ogUrl = new URL(ogImage ? ogImage : `${title}.png`, Astro.url.origin)
.href; .href;
--- ---
<Layout title={title} author={author} description={description} ogImage={ogUrl} canonicalURL={canonicalURL}> <Layout
title={title}
author={author}
description={description}
ogImage={ogUrl}
canonicalURL={canonicalURL}
>
<Header /> <Header />
<div class="mx-auto flex w-full max-w-3xl justify-start px-2"> <div class="mx-auto flex w-full max-w-3xl justify-start px-2">
<button <button
@@ -36,7 +43,7 @@ const ogUrl = new URL(ogImage ? ogImage : `${title}.png`, Astro.url.origin)
</button> </button>
</div> </div>
<main id="main-content"> <main id="main-content">
<h1 class="post-title">{title}</h1> <h1 transition:name={title} class="post-title">{title}</h1>
<Datetime datetime={pubDatetime} size="lg" className="my-2" /> <Datetime datetime={pubDatetime} size="lg" className="my-2" />
<article id="article" role="article" class="prose mx-auto mt-8 max-w-3xl"> <article id="article" role="article" class="prose mx-auto mt-8 max-w-3xl">
<Content /> <Content />
+1 -1
View File
@@ -4,7 +4,7 @@ import Layout from "@layouts/Layout.astro";
import Main from "@layouts/Main.astro"; import Main from "@layouts/Main.astro";
import Header from "@components/Header.astro"; import Header from "@components/Header.astro";
import Footer from "@components/Footer.astro"; import Footer from "@components/Footer.astro";
import Card from "@components/Card"; import Card from "@components/Card.astro";
import LinkButton from "@components/LinkButton.astro"; import LinkButton from "@components/LinkButton.astro";
import slugify from "@utils/slugify"; import slugify from "@utils/slugify";
import type { CollectionEntry } from "astro:content"; import type { CollectionEntry } from "astro:content";
+1 -1
View File
@@ -5,7 +5,7 @@ import Header from "@components/Header.astro";
import Footer from "@components/Footer.astro"; import Footer from "@components/Footer.astro";
import LinkButton from "@components/LinkButton.astro"; import LinkButton from "@components/LinkButton.astro";
import Hr from "@components/Hr.astro"; import Hr from "@components/Hr.astro";
import Card from "@components/Card"; import Card from "@components/Card.astro";
import Socials from "@components/Socials.astro"; import Socials from "@components/Socials.astro";
import getSortedPosts from "@utils/getSortedPosts"; import getSortedPosts from "@utils/getSortedPosts";
import slugify from "@utils/slugify"; import slugify from "@utils/slugify";
+4 -2
View File
@@ -4,7 +4,7 @@ import Layout from "@layouts/Layout.astro";
import Main from "@layouts/Main.astro"; import Main from "@layouts/Main.astro";
import Header from "@components/Header.astro"; import Header from "@components/Header.astro";
import Footer from "@components/Footer.astro"; import Footer from "@components/Footer.astro";
import Card from "@components/Card"; import Card from "@components/Card.astro";
import getUniqueTags from "@utils/getUniqueTags"; import getUniqueTags from "@utils/getUniqueTags";
import getPostsByTag from "@utils/getPostsByTag"; import getPostsByTag from "@utils/getPostsByTag";
import slugify from "@utils/slugify"; import slugify from "@utils/slugify";
@@ -41,9 +41,11 @@ const sortTagsPost = getSortedPosts(tagPosts);
<Layout title={`Tag:${tag} | ${SITE.title}`}> <Layout title={`Tag:${tag} | ${SITE.title}`}>
<Header activeNav="tags" /> <Header activeNav="tags" />
<Main <Main
pageTitle={`Tag:${tag}`} pageTitle={[`Tag:`, `${tag}`]}
titleTransition={tag}
pageDesc={`All the articles with the tag "${tag}".`} pageDesc={`All the articles with the tag "${tag}".`}
> >
<h1 slot="title" transition:name={tag}>{`Tag:${tag}`}</h1>
<ul> <ul>
{ {
sortTagsPost.map(({ data }) => ( sortTagsPost.map(({ data }) => (