fix: 修复后台文章计数为0 + 分类编辑补全描述字段 + CSP放行外部图片 + 更新关于页描述

- 文章管理:计数请求补 page=1 参数,命中分页接口返回正确的 total
- 分类管理:编辑模式新增描述输入框,保存时一并提交 description
- CSP:img-src 加入 https: 允许加载外部图片
- 关于页:数据存储描述从 JSON 文件更正为 SQLite 数据库
- Footer:添加 ICP 备案号
This commit is contained in:
胡旭
2026-06-24 13:51:48 +08:00
parent 3707eddfd4
commit 18e915bcbb
69 changed files with 6818 additions and 1422 deletions
+64 -3
View File
@@ -1,15 +1,68 @@
import type { Metadata } from "next";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import { Noto_Serif_SC, Noto_Sans_SC, Cormorant_Garamond, Geist } from "next/font/google";
import "./globals.css";
import { cn } from "@/lib/utils";
const geist = Geist({subsets:['latin'],variable:'--font-sans'});
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || "https://asui.xyz";
// ── 字体:用 next/font 自托管,避免 @import 阻塞渲染 ──
// Cormorant 仅含拉丁字符,display: swap 防止 FOIT
const cormorant = Cormorant_Garamond({
subsets: ["latin"],
weight: ["300", "400", "500", "600", "700"],
style: ["normal", "italic"],
display: "swap",
variable: "--font-cormorant",
});
// Noto Serif SC / Sans SC 体积大,预连接 + swap
const notoSerif = Noto_Serif_SC({
subsets: ["latin"],
weight: ["300", "400", "500", "600", "700"],
display: "swap",
variable: "--font-noto-serif",
preload: false,
});
const notoSans = Noto_Sans_SC({
subsets: ["latin"],
weight: ["300", "400", "500"],
display: "swap",
variable: "--font-noto-sans",
preload: false,
});
export const metadata: Metadata = {
metadataBase: new URL(SITE_URL),
title: {
default: "随 · asui.xyz",
template: "%s | 随",
},
description: "胡旭的个人博客 — 记录技术探索、生活感悟与创业路上的点滴",
keywords: ["博客", "技术", "生活", "创业", "Web开发", "AI"],
keywords: ["博客", "技术", "生活", "创业", "Web开发", "AI", "前端"],
authors: [{ name: "胡旭", url: SITE_URL }],
creator: "胡旭",
openGraph: {
type: "website",
locale: "zh_CN",
url: SITE_URL,
siteName: "随 · asui.xyz",
title: "随 · asui.xyz",
description: "胡旭的个人博客 — 记录技术探索、生活感悟与创业路上的点滴",
},
twitter: {
card: "summary_large_image",
title: "随 · asui.xyz",
description: "胡旭的个人博客 — 记录技术探索、生活感悟与创业路上的点滴",
},
robots: {
index: true,
follow: true,
},
};
export default function RootLayout({
@@ -18,10 +71,18 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang="zh-CN" className="h-full">
<html lang="zh-CN" className={cn("h-full", notoSerif.variable, notoSans.variable, cormorant.variable, "font-sans", geist.variable)}>
<body className="min-h-full flex flex-col">
<a
href="#main-content"
className="sr-only focus:not-sr-only focus:absolute focus:z-[100] focus:top-3 focus:left-3 focus:px-4 focus:py-2 focus:rounded-lg focus:bg-ink focus:text-cream focus:font-sans focus:text-sm"
>
</a>
<Header />
<main className="flex-1">{children}</main>
<main id="main-content" className="flex-1">
{children}
</main>
<Footer />
</body>
</html>