mirror of
https://github.com/ChenQihan666/MyBlog-Next.git
synced 2026-08-14 07:33:07 +08:00
fix: sanitize post title for valid CSS view-transition-name (#650)
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
import type { CollectionEntry } from "astro:content";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import { getPostUrl } from "@/utils/getPostPaths";
|
import { getPostUrl } from "@/utils/getPostPaths";
|
||||||
import { slugifyStr } from "@/utils/slugify";
|
import { toTransitionName } from "@/utils/toTransitionName";
|
||||||
import Datetime from "./Datetime.astro";
|
import Datetime from "./Datetime.astro";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -22,7 +22,7 @@ const { title, description, ...props } = data;
|
|||||||
"focus-visible:no-underline focus-visible:underline-offset-0",
|
"focus-visible:no-underline focus-visible:underline-offset-0",
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Heading transition:name={slugifyStr(title.replaceAll(".", "-"))}>
|
<Heading transition:name={toTransitionName(title)}>
|
||||||
{title}
|
{title}
|
||||||
</Heading>
|
</Heading>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import Tag from "@/components/Tag.astro";
|
|||||||
import { getPostSlug, getPostUrl } from "@/utils/getPostPaths";
|
import { getPostSlug, getPostUrl } from "@/utils/getPostPaths";
|
||||||
import { getSortedPosts } from "@/utils/getSortedPosts";
|
import { getSortedPosts } from "@/utils/getSortedPosts";
|
||||||
import { slugifyStr } from "@/utils/slugify";
|
import { slugifyStr } from "@/utils/slugify";
|
||||||
|
import { toTransitionName } from "@/utils/toTransitionName";
|
||||||
import EditPost from "./_components/EditPost.astro";
|
import EditPost from "./_components/EditPost.astro";
|
||||||
import ShareLinks from "./_components/ShareLinks.astro";
|
import ShareLinks from "./_components/ShareLinks.astro";
|
||||||
import BackButton from "./_components/BackButton.astro";
|
import BackButton from "./_components/BackButton.astro";
|
||||||
@@ -111,7 +112,7 @@ const ogImage = ogImageUrl
|
|||||||
data-pagefind-body
|
data-pagefind-body
|
||||||
>
|
>
|
||||||
<h1
|
<h1
|
||||||
style={{ viewTransitionName: slugifyStr(title.replaceAll(".", "-")) }}
|
style={{ viewTransitionName: toTransitionName(title) }}
|
||||||
class="text-accent inline-block text-2xl font-bold sm:text-3xl"
|
class="text-accent inline-block text-2xl font-bold sm:text-3xl"
|
||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { slugifyStr } from "./slugify";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produce a valid CSS <custom-ident> for view-transition-name.
|
||||||
|
* CSS idents only allow [a-zA-Z0-9_-] plus Unicode U+00A0+.
|
||||||
|
* Non-ASCII chars are hex-encoded, ASCII special chars (:, /, etc.)
|
||||||
|
* are replaced with hyphens to keep the browser from ignoring the name.
|
||||||
|
*/
|
||||||
|
export const toTransitionName = (str: string): string => {
|
||||||
|
const base = slugifyStr(str.replaceAll(".", "-"));
|
||||||
|
let result = base
|
||||||
|
// encode non-ASCII chars (Chinese, Japanese, etc.)
|
||||||
|
.replace(
|
||||||
|
/[^\x00-\x7F]/gu,
|
||||||
|
c => "u" + c.codePointAt(0)!.toString(16).padStart(6, "0")
|
||||||
|
)
|
||||||
|
// replace any remaining invalid chars (colons, slashes, etc.)
|
||||||
|
.replace(/[^a-zA-Z0-9_-]/g, "-")
|
||||||
|
// collapse consecutive hyphens and trim
|
||||||
|
.replace(/-+/g, "-")
|
||||||
|
.replace(/^-+|-+$/g, "");
|
||||||
|
// CSS ident must not start with a digit
|
||||||
|
if (/^\d/.test(result)) result = "p-" + result;
|
||||||
|
if (!result) result = "post";
|
||||||
|
return result;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user