From 4ddbe8ac18773c72303a55c2a6ae5cb54f9a79ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Wed, 15 Apr 2026 05:51:21 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20Biome=20=E6=A0=BC=E5=BC=8F=E5=8C=96=20+?= =?UTF-8?q?=20archive.astro=20=E4=BC=A0=E5=85=A5=E7=BC=BA=E5=A4=B1?= =?UTF-8?q?=E7=9A=84=20tags/categories=20props?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 小橘 🍊(NEKO Team) --- src/layouts/Layout.astro | 3 +- src/pages/archive.astro | 10 +- src/pages/og/[...slug].png.ts | 453 ++++++++++++++++---------------- src/pages/posts/[...slug].astro | 2 +- 4 files changed, 238 insertions(+), 230 deletions(-) diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index 41e95e6..7990572 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -29,7 +29,8 @@ interface Props { ogImage?: string; } -let { title, banner, description, lang, setOGTypeArticle, ogImage } = Astro.props; +let { title, banner, description, lang, setOGTypeArticle, ogImage } = + Astro.props; // apply a class to the body element to decide the height of the banner, only used for initial page load // Swup can update the body for each page visit, but it's after the page transition, causing a delay for banner height change diff --git a/src/pages/archive.astro b/src/pages/archive.astro index 90ede24..f7b2387 100644 --- a/src/pages/archive.astro +++ b/src/pages/archive.astro @@ -3,12 +3,18 @@ import ArchivePanel from "@components/ArchivePanel.svelte"; import I18nKey from "@i18n/i18nKey"; import { i18n } from "@i18n/translation"; import MainGridLayout from "@layouts/MainGridLayout.astro"; -import { getSortedPostsList } from "../utils/content-utils"; +import { + getCategoryList, + getSortedPostsList, + getTagList, +} from "../utils/content-utils"; const sortedPostsList = await getSortedPostsList(); +const tags = (await getTagList()).map((t) => t.name); +const categories = (await getCategoryList()).map((c) => c.name); --- - + diff --git a/src/pages/og/[...slug].png.ts b/src/pages/og/[...slug].png.ts index 2354503..ef5caec 100644 --- a/src/pages/og/[...slug].png.ts +++ b/src/pages/og/[...slug].png.ts @@ -1,246 +1,247 @@ -import type { APIRoute, GetStaticPaths } from "astro"; -import { getSortedPosts } from "@utils/content-utils"; -import satori from "satori"; -import sharp from "sharp"; import fs from "node:fs"; import path from "node:path"; +import { getSortedPosts } from "@utils/content-utils"; +import type { APIRoute, GetStaticPaths } from "astro"; +import satori from "satori"; +import sharp from "sharp"; import { formatDateToYYYYMMDD } from "../../utils/date-utils"; // Load font at module level (cached across calls during build) const fontPath = path.resolve("src/assets/fonts/NotoSansSC-Regular.ttf"); let fontData: ArrayBuffer; try { - fontData = fs.readFileSync(fontPath).buffer as ArrayBuffer; + fontData = fs.readFileSync(fontPath).buffer as ArrayBuffer; } catch { - // Font will be downloaded by build script; fail gracefully if missing - fontData = new ArrayBuffer(0); + // Font will be downloaded by build script; fail gracefully if missing + fontData = new ArrayBuffer(0); } export const getStaticPaths: GetStaticPaths = async () => { - const posts = await getSortedPosts(); - return posts.map((post) => ({ - params: { slug: post.slug }, - props: { - title: post.data.title, - description: post.data.description || "", - date: formatDateToYYYYMMDD(post.data.published), - tags: post.data.tags || [], - }, - })); + const posts = await getSortedPosts(); + return posts.map((post) => ({ + params: { slug: post.slug }, + props: { + title: post.data.title, + description: post.data.description || "", + date: formatDateToYYYYMMDD(post.data.published), + tags: post.data.tags || [], + }, + })); }; export const GET: APIRoute = async ({ props }) => { - const { title, description, date, tags } = props as { - title: string; - description: string; - date: string; - tags: string[]; - }; + const { title, description, date, tags } = props as { + title: string; + description: string; + date: string; + tags: string[]; + }; - // Truncate title to ~40 chars for display - const displayTitle = - title.length > 42 ? title.slice(0, 40) + "…" : title; - const displayDesc = - description.length > 70 ? description.slice(0, 68) + "…" : description; - const displayTags = tags.slice(0, 3).join(" · "); + // Truncate title to ~40 chars for display + const displayTitle = title.length > 42 ? `${title.slice(0, 40)}…` : title; + const displayDesc = + description.length > 70 ? `${description.slice(0, 68)}…` : description; + const displayTags = tags.slice(0, 3).join(" · "); - const svg = await satori( - { - type: "div", - props: { - style: { - width: "100%", - height: "100%", - display: "flex", - flexDirection: "column", - justifyContent: "space-between", - padding: "60px 64px", - background: "linear-gradient(135deg, #0f172a 0%, #1e3a5f 40%, #3b82f6 100%)", - color: "#ffffff", - fontFamily: "Noto Sans SC", - }, - children: [ - // Top: logo + branding - { - type: "div", - props: { - style: { - display: "flex", - alignItems: "center", - gap: "12px", - }, - children: [ - { - type: "span", - props: { - style: { fontSize: "36px" }, - children: "🍊", - }, - }, - { - type: "span", - props: { - style: { - fontSize: "22px", - color: "rgba(255,255,255,0.7)", - letterSpacing: "0.05em", - }, - children: "小橘的日记", - }, - }, - ], - }, - }, - // Middle: title + description - { - type: "div", - props: { - style: { - display: "flex", - flexDirection: "column", - gap: "16px", - flex: "1", - justifyContent: "center", - }, - children: [ - { - type: "div", - props: { - style: { - fontSize: "48px", - fontWeight: 700, - lineHeight: 1.3, - letterSpacing: "-0.02em", - textShadow: "0 2px 10px rgba(0,0,0,0.3)", - }, - children: displayTitle, - }, - }, - description - ? { - type: "div", - props: { - style: { - fontSize: "22px", - color: "rgba(255,255,255,0.65)", - lineHeight: 1.5, - }, - children: displayDesc, - }, - } - : null, - ].filter(Boolean), - }, - }, - // Bottom: date + tags + site - { - type: "div", - props: { - style: { - display: "flex", - justifyContent: "space-between", - alignItems: "flex-end", - }, - children: [ - { - type: "div", - props: { - style: { - display: "flex", - flexDirection: "column", - gap: "6px", - }, - children: [ - displayTags - ? { - type: "div", - props: { - style: { - fontSize: "16px", - color: "rgba(255,255,255,0.5)", - }, - children: displayTags, - }, - } - : null, - { - type: "div", - props: { - style: { - fontSize: "18px", - color: "rgba(255,255,255,0.6)", - }, - children: date, - }, - }, - ].filter(Boolean), - }, - }, - { - type: "div", - props: { - style: { - display: "flex", - alignItems: "center", - gap: "8px", - }, - children: [ - { - type: "span", - props: { - style: { - fontSize: "24px", - }, - children: "✨ 🌙 ☁️", - }, - }, - { - type: "span", - props: { - style: { - fontSize: "16px", - color: "rgba(255,255,255,0.4)", - }, - children: "oc-xiaoju.github.io", - }, - }, - ], - }, - }, - ], - }, - }, - ], - }, - }, - { - width: 1200, - height: 630, - fonts: fontData.byteLength > 0 - ? [ - { - name: "Noto Sans SC", - data: fontData, - weight: 400 as const, - style: "normal" as const, - }, - { - name: "Noto Sans SC", - data: fontData, // variable font covers all weights - weight: 700 as const, - style: "normal" as const, - }, - ] - : [], - } - ); + const svg = await satori( + { + type: "div", + props: { + style: { + width: "100%", + height: "100%", + display: "flex", + flexDirection: "column", + justifyContent: "space-between", + padding: "60px 64px", + background: + "linear-gradient(135deg, #0f172a 0%, #1e3a5f 40%, #3b82f6 100%)", + color: "#ffffff", + fontFamily: "Noto Sans SC", + }, + children: [ + // Top: logo + branding + { + type: "div", + props: { + style: { + display: "flex", + alignItems: "center", + gap: "12px", + }, + children: [ + { + type: "span", + props: { + style: { fontSize: "36px" }, + children: "🍊", + }, + }, + { + type: "span", + props: { + style: { + fontSize: "22px", + color: "rgba(255,255,255,0.7)", + letterSpacing: "0.05em", + }, + children: "小橘的日记", + }, + }, + ], + }, + }, + // Middle: title + description + { + type: "div", + props: { + style: { + display: "flex", + flexDirection: "column", + gap: "16px", + flex: "1", + justifyContent: "center", + }, + children: [ + { + type: "div", + props: { + style: { + fontSize: "48px", + fontWeight: 700, + lineHeight: 1.3, + letterSpacing: "-0.02em", + textShadow: "0 2px 10px rgba(0,0,0,0.3)", + }, + children: displayTitle, + }, + }, + description + ? { + type: "div", + props: { + style: { + fontSize: "22px", + color: "rgba(255,255,255,0.65)", + lineHeight: 1.5, + }, + children: displayDesc, + }, + } + : null, + ].filter(Boolean), + }, + }, + // Bottom: date + tags + site + { + type: "div", + props: { + style: { + display: "flex", + justifyContent: "space-between", + alignItems: "flex-end", + }, + children: [ + { + type: "div", + props: { + style: { + display: "flex", + flexDirection: "column", + gap: "6px", + }, + children: [ + displayTags + ? { + type: "div", + props: { + style: { + fontSize: "16px", + color: "rgba(255,255,255,0.5)", + }, + children: displayTags, + }, + } + : null, + { + type: "div", + props: { + style: { + fontSize: "18px", + color: "rgba(255,255,255,0.6)", + }, + children: date, + }, + }, + ].filter(Boolean), + }, + }, + { + type: "div", + props: { + style: { + display: "flex", + alignItems: "center", + gap: "8px", + }, + children: [ + { + type: "span", + props: { + style: { + fontSize: "24px", + }, + children: "✨ 🌙 ☁️", + }, + }, + { + type: "span", + props: { + style: { + fontSize: "16px", + color: "rgba(255,255,255,0.4)", + }, + children: "oc-xiaoju.github.io", + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + { + width: 1200, + height: 630, + fonts: + fontData.byteLength > 0 + ? [ + { + name: "Noto Sans SC", + data: fontData, + weight: 400 as const, + style: "normal" as const, + }, + { + name: "Noto Sans SC", + data: fontData, // variable font covers all weights + weight: 700 as const, + style: "normal" as const, + }, + ] + : [], + }, + ); - const png = await sharp(Buffer.from(svg)).png().toBuffer(); + const png = await sharp(Buffer.from(svg)).png().toBuffer(); - return new Response(png as unknown as BodyInit, { - headers: { - "Content-Type": "image/png", - "Cache-Control": "public, max-age=31536000, immutable", - }, - }); + return new Response(png as unknown as BodyInit, { + headers: { + "Content-Type": "image/png", + "Cache-Control": "public, max-age=31536000, immutable", + }, + }); }; diff --git a/src/pages/posts/[...slug].astro b/src/pages/posts/[...slug].astro index 6b5b5c3..2bd5083 100644 --- a/src/pages/posts/[...slug].astro +++ b/src/pages/posts/[...slug].astro @@ -1,7 +1,7 @@ --- import path from "node:path"; -import License from "@components/misc/License.astro"; import Comments from "@components/misc/Comments.astro"; +import License from "@components/misc/License.astro"; import Markdown from "@components/misc/Markdown.astro"; import I18nKey from "@i18n/i18nKey"; import { i18n } from "@i18n/translation";