mirror of
https://github.com/ChenQihan666/MyBlog-Next.git
synced 2026-08-13 23:31: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 { getPostUrl } from "@/utils/getPostPaths";
|
||||
import { slugifyStr } from "@/utils/slugify";
|
||||
import { toTransitionName } from "@/utils/toTransitionName";
|
||||
import Datetime from "./Datetime.astro";
|
||||
|
||||
type Props = {
|
||||
@@ -22,7 +22,7 @@ const { title, description, ...props } = data;
|
||||
"focus-visible:no-underline focus-visible:underline-offset-0",
|
||||
]}
|
||||
>
|
||||
<Heading transition:name={slugifyStr(title.replaceAll(".", "-"))}>
|
||||
<Heading transition:name={toTransitionName(title)}>
|
||||
{title}
|
||||
</Heading>
|
||||
</a>
|
||||
|
||||
@@ -8,6 +8,7 @@ import Tag from "@/components/Tag.astro";
|
||||
import { getPostSlug, getPostUrl } from "@/utils/getPostPaths";
|
||||
import { getSortedPosts } from "@/utils/getSortedPosts";
|
||||
import { slugifyStr } from "@/utils/slugify";
|
||||
import { toTransitionName } from "@/utils/toTransitionName";
|
||||
import EditPost from "./_components/EditPost.astro";
|
||||
import ShareLinks from "./_components/ShareLinks.astro";
|
||||
import BackButton from "./_components/BackButton.astro";
|
||||
@@ -111,7 +112,7 @@ const ogImage = ogImageUrl
|
||||
data-pagefind-body
|
||||
>
|
||||
<h1
|
||||
style={{ viewTransitionName: slugifyStr(title.replaceAll(".", "-")) }}
|
||||
style={{ viewTransitionName: toTransitionName(title) }}
|
||||
class="text-accent inline-block text-2xl font-bold sm:text-3xl"
|
||||
>
|
||||
{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