mirror of
https://github.com/ChenQihan666/MyBlog-Next.git
synced 2026-08-14 07:33:07 +08:00
feat: add ViewTransitions from Astro
Integrate ViewTransitions API from Astro v3. resolve #96
This commit is contained in:
+14
-7
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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>
|
||||||
|
|||||||
@@ -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]);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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 />
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
@@ -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,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 }) => (
|
||||||
|
|||||||
Reference in New Issue
Block a user