@zlooks.cn/cli 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/command/index.js +57 -0
  2. package/dist/command/index.js.map +1 -1
  3. package/dist/theme-authoring.d.ts +36 -0
  4. package/dist/theme-authoring.d.ts.map +1 -0
  5. package/dist/theme-authoring.js +491 -0
  6. package/dist/theme-authoring.js.map +1 -0
  7. package/package.json +9 -3
  8. package/templates/blog-theme/README.md +26 -0
  9. package/templates/blog-theme/_gitignore +5 -0
  10. package/templates/blog-theme/hile-rsc.json +22 -0
  11. package/templates/blog-theme/package.json +64 -0
  12. package/templates/blog-theme/pnpm-workspace.yaml +5 -0
  13. package/templates/blog-theme/src/command/index.ts +11 -0
  14. package/templates/blog-theme/src/identity.ts +7 -0
  15. package/templates/blog-theme/src/plugin/archive-filter.tsx +62 -0
  16. package/templates/blog-theme/src/plugin/blog-frame.tsx +91 -0
  17. package/templates/blog-theme/src/plugin/blog-interactions.tsx +236 -0
  18. package/templates/blog-theme/src/plugin/page.tsx +174 -0
  19. package/templates/blog-theme/src/plugin/styles.d.ts +1 -0
  20. package/templates/blog-theme/src/plugin/theme.css +59 -0
  21. package/templates/blog-theme/src/services/blog-theme.boot.ts +17 -0
  22. package/templates/blog-theme/test/interactions.test.tsx.template +177 -0
  23. package/templates/blog-theme/test/pages.test.tsx.template +125 -0
  24. package/templates/blog-theme/test/shell.test.tsx.template +102 -0
  25. package/templates/blog-theme/test/theme-contract.test.ts.template +43 -0
  26. package/templates/blog-theme/tsconfig.json +16 -0
  27. package/templates/blog-theme/tsconfig.runtime.json +17 -0
  28. package/templates/blog-theme/vitest.config.ts +8 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-authoring.js","sourceRoot":"","sources":["../src/theme-authoring.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zlooks.cn/cli",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,8 @@
13
13
  }
14
14
  },
15
15
  "files": [
16
- "dist"
16
+ "dist",
17
+ "templates"
17
18
  ],
18
19
  "engines": {
19
20
  "node": ">=24.0.0"
@@ -29,10 +30,15 @@
29
30
  "@hile/ioredis": "4.0.1",
30
31
  "@hile/typeorm": "4.0.1",
31
32
  "@inquirer/prompts": "8.7.0",
33
+ "@zlooks.cn/blog-schema": "1.0.0",
34
+ "@zlooks.cn/blog-theme": "1.0.2",
35
+ "@zlooks.cn/global-config-shared": "1.0.0",
32
36
  "@zlooks.cn/infrastructure": "1.0.0",
33
37
  "@zlooks.cn/legacy-import": "1.0.2",
34
38
  "@zlooks.cn/public-host-contract": "1.0.0",
35
39
  "@zlooks.cn/registry-config": "1.0.0",
40
+ "@zlooks.cn/service-command": "1.0.0",
41
+ "@zlooks.cn/ui": "1.0.1",
36
42
  "commander": "15.0.0",
37
43
  "ioredis": "5.11.1",
38
44
  "pg": "8.23.0",
@@ -48,5 +54,5 @@
48
54
  "typescript": "7.0.2",
49
55
  "vitest": "4.1.11"
50
56
  },
51
- "gitHead": "19d023777e5b12872d5315e048da1a851db5e93d"
57
+ "gitHead": "d0c3ea8bfcf3040e8f3556f328fb96baac3b4935"
52
58
  }
@@ -0,0 +1,26 @@
1
+ # __DISPLAY_NAME_JSON__
2
+
3
+ 这是由 `zlooks theme create` 生成的 Blog RSC 主题起点。模板不是最终成品:请按用户要求设计视觉与布局,同时保留七条 Blog 路由、Hile 运行时、SEO、搜索、点赞、评论读取与提交,以及安全的 Markdown 渲染。
4
+
5
+ ## 开发
6
+
7
+ 1. 运行 `zlooks setup`,确认机器级 `~/.zlooks.cn/.env` 已包含 Registry 地址。
8
+ 2. 运行 `pnpm install`。
9
+ 3. 运行 `zlooks theme verify . --json`,依次完成结构、安装、测试、类型、构建、RSC 产物和真实 tarball 检查。结果必须为 `ok=true`、`stage=LOCAL_VERIFIED`。
10
+ 4. 运行 `pnpm run start`,使用已验证的生产构建,通过统一 Gateway 访问主题;本服务不会开放独立公共 HTTP 端口。
11
+
12
+ 只有用户明确使用配套开发模式 Gateway 时才使用 `pnpm run dev`。开发模式 React Flight 不能发送给生产模式 Gateway;`localhost` 地址不表示 Gateway 是开发模式。修改后重新执行完整验证,再重启生产主题进程。
13
+
14
+ 主题包名 `__PACKAGE_NAME__` 属于第三方命名空间,不要改成官方保留的 `@zlooks.cn/*`。
15
+ `antd` 使用与 UI SDK 匹配的精确版本,其余依赖声明使用 `^版本号`。保留由 pnpm 生成的锁文件;更新依赖后必须重新执行完整验证,尤其是 React/Hile/Ant Design 的实际安装版本兼容性。
16
+ 按钮与主题化反馈分别使用 `@zlooks.cn/ui/button` 和 `@zlooks.cn/ui/app`,不要绕回 Ant Design 的不兼容 directive barrel。
17
+
18
+ 公共壳层包含 `ZlooksUserAccess` 的登录方式、账户菜单、确认退出与不可用态;`useZlooksTheme` 驱动浅色、深色、自动三态;主导航消费 Host 初始投影并与 Blog 页面去重;备案和版权消费站点配置。不要用静态按钮替换共享组件、复制认证逻辑,或另建主题偏好存储。`test/shell.test.tsx` 使用真实 UI 组件验证这些接线;真实登录和内容交互属于另行约定的可选验收。
19
+
20
+ ## 验证边界
21
+
22
+ `test/theme-contract.test.ts` 检查路由、唯一 boot 和源码边界;`test/pages.test.tsx` 使用真实 SDK ViewModel 检查七类页面、SEO 和空状态;`test/interactions.test.tsx` 用交互测试检查搜索、点赞、评论和筛选。视觉调整可以更新展示断言,但必须保留功能断言。所有测试都参与类型检查。
23
+
24
+ 用户仅询问制作方法时,说明步骤和 SDK 边界即可,无须实际创建项目或执行验收。实际制作依次完成 `PRECHECK`、`SCAFFOLDED`、`DESIGNED`、`LOCAL_VERIFIED`,再启动生产构建,通过 Blog MCP 的主题目录和状态确认健康实例,记录 `RUNTIME_VERIFIED` 后即可报告主题制作完成。`LOCAL_VERIFIED` 本身不是运行证明。
25
+
26
+ `FUNCTION_VERIFIED` 是按用户要求追加的真实内容验收,单独记录覆盖范围。默认不验证登录后的行为,也不为制作主题创建账号或文章;缺少登录态、测试内容、写操作授权或浏览器条件不阻塞主题制作。切换主题、发布、点赞或评论等操作仍须明确授权。未执行的检查必须如实标注,制作完成不等于所有真实内容行为已经验收。
@@ -0,0 +1,5 @@
1
+ node_modules/
2
+ dist/
3
+ .hile-rsc/
4
+ .env
5
+ pnpm-debug.log*
@@ -0,0 +1,22 @@
1
+ {
2
+ "pluginId": "blog",
3
+ "cwd": ".",
4
+ "entry": "src/plugin/page.tsx",
5
+ "styles": ["@zlooks.cn/ui/antd.css"],
6
+ "routes": [
7
+ { "path": "/", "entry": "BlogHomePage" },
8
+ { "path": "/posts/[slug]", "entry": "BlogPostPage" },
9
+ { "path": "/archives", "entry": "BlogArchivePage" },
10
+ { "path": "/pages/[slug]", "entry": "BlogSinglePagePage" },
11
+ { "path": "/categories/[slug]", "entry": "BlogCategoryPage" },
12
+ { "path": "/tags/[slug]", "entry": "BlogTagPage" },
13
+ { "path": "/friends", "entry": "BlogFriendLinksPage" }
14
+ ],
15
+ "metadata": {
16
+ "displayName": __DISPLAY_NAME_JSON__,
17
+ "description": __DESCRIPTION_JSON__,
18
+ "navigation": [
19
+ { "id": "blog", "label": "博客", "path": "/", "order": 100 }
20
+ ]
21
+ }
22
+ }
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "__PACKAGE_NAME__",
3
+ "version": "1.0.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=24.0.0"
8
+ },
9
+ "bin": {
10
+ "__PACKAGE_NAME__": "dist/command/index.js"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ ".hile-rsc"
15
+ ],
16
+ "zlooks": {
17
+ "kind": "theme",
18
+ "themeId": "__THEME_ID__",
19
+ "description": __DESCRIPTION_JSON__,
20
+ "dependsOn": [],
21
+ "nodeConditions": [
22
+ "react-server"
23
+ ]
24
+ },
25
+ "scripts": {
26
+ "build:rsc": "pnpm run clean:rsc && hile-rsc build",
27
+ "verify:rsc": "hile-rsc verify",
28
+ "build:runtime": "pnpm run clean:runtime && tsc -p tsconfig.runtime.json && fix-esm-import-path --preserve-import-type ./dist",
29
+ "build": "pnpm run build:rsc && pnpm run build:runtime",
30
+ "clean:runtime": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
31
+ "clean:rsc": "node -e \"require('node:fs').rmSync('.hile-rsc', { recursive: true, force: true })\"",
32
+ "dev": "NODE_OPTIONS=--conditions=react-server hile start --dev --env-file ~/.zlooks.cn/.env",
33
+ "start": "NODE_OPTIONS=--conditions=react-server hile start --env-file ~/.zlooks.cn/.env",
34
+ "test": "vitest run",
35
+ "typecheck": "tsc -p tsconfig.runtime.json --noEmit && tsc -p tsconfig.json --noEmit"
36
+ },
37
+ "dependencies": {
38
+ "@hile/rsc": "^1.0.18",
39
+ "@zlooks.cn/blog-schema": "^__BLOG_SCHEMA_VERSION__",
40
+ "@zlooks.cn/blog-theme": "^__BLOG_THEME_VERSION__",
41
+ "@zlooks.cn/global-config-shared": "^__GLOBAL_CONFIG_VERSION__",
42
+ "@zlooks.cn/service-command": "^__SERVICE_COMMAND_VERSION__",
43
+ "@zlooks.cn/ui": "^__UI_VERSION__",
44
+ "antd": "6.6.1",
45
+ "react": "^19.2.8",
46
+ "react-dom": "^19.2.8",
47
+ "react-markdown": "^10.1.0",
48
+ "react-server-dom-webpack": "^19.2.8",
49
+ "remark-gfm": "^4.0.1"
50
+ },
51
+ "devDependencies": {
52
+ "@hile/cli": "^4.0.5",
53
+ "@hile/context": "^4.0.2",
54
+ "@hile/core": "^4.0.1",
55
+ "@hile/rsc-build": "^1.0.15",
56
+ "@types/node": "^26.2.0",
57
+ "@types/react": "^19.2.18",
58
+ "@types/react-dom": "^19.2.4",
59
+ "fix-esm-import-path": "^1.10.3",
60
+ "happy-dom": "^20.14.0",
61
+ "typescript": "^7.0.2",
62
+ "vitest": "^4.1.11"
63
+ }
64
+ }
@@ -0,0 +1,5 @@
1
+ packages:
2
+ - .
3
+
4
+ allowBuilds:
5
+ esbuild: true
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import { fileURLToPath } from 'node:url';
3
+ import { runServiceCommand } from '@zlooks.cn/service-command';
4
+
5
+ await runServiceCommand({
6
+ packageRoot: fileURLToPath(new URL('../../', import.meta.url)),
7
+ requiresReactServer: true,
8
+ }).catch((error: unknown) => {
9
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
10
+ process.exitCode = 1;
11
+ });
@@ -0,0 +1,7 @@
1
+ import { defineBlogTheme } from '@zlooks.cn/blog-theme';
2
+
3
+ export const BLOG_THEME = defineBlogTheme({
4
+ id: '__THEME_ID__',
5
+ displayName: __DISPLAY_NAME_JSON__,
6
+ description: __DESCRIPTION_JSON__,
7
+ });
@@ -0,0 +1,62 @@
1
+ 'use client';
2
+
3
+ import { RscLink, useRscNavigation } from '@hile/rsc/client/navigation';
4
+ import { blogPostArchiveInputSchema } from '@zlooks.cn/blog-schema';
5
+ import type { BlogArchiveFilter } from '@zlooks.cn/blog-theme';
6
+ import { ZlooksButton } from '@zlooks.cn/ui/button';
7
+ import Input from 'antd/es/input/Input.js';
8
+ import Select from 'antd/es/select/index.js';
9
+ import { useState, type FormEvent } from 'react';
10
+
11
+ type Mode = 'all' | 'year' | 'month' | 'range';
12
+
13
+ export default function ArchiveFilter({ filter }: { readonly filter: BlogArchiveFilter }) {
14
+ return <FilterForm key={JSON.stringify(filter)} filter={filter} />;
15
+ }
16
+
17
+ function FilterForm({ filter }: { readonly filter: BlogArchiveFilter }) {
18
+ const navigation = useRscNavigation();
19
+ const [mode, setMode] = useState<Mode>(filter.startYear ? 'range' : filter.month ? 'month' : filter.year ? 'year' : 'all');
20
+ const [year, setYear] = useState(String(filter.year ?? ''));
21
+ const [month, setMonth] = useState(monthValue(filter.year, filter.month));
22
+ const [start, setStart] = useState(monthValue(filter.startYear, filter.startMonth));
23
+ const [end, setEnd] = useState(monthValue(filter.endYear, filter.endMonth));
24
+ const [error, setError] = useState('');
25
+
26
+ function submit(event: FormEvent) {
27
+ event.preventDefault();
28
+ const selected = mode === 'all' ? {} : mode === 'year' ? { year: Number(year) }
29
+ : mode === 'month' ? parseMonth(month)
30
+ : { startYear: parseMonth(start).year, startMonth: parseMonth(start).month, endYear: parseMonth(end).year, endMonth: parseMonth(end).month };
31
+ const parsed = blogPostArchiveInputSchema.safeParse({ ...selected, limit: 1, monthLimit: 1 });
32
+ if (!parsed.success) { setError('请选择有效时间,起始月份不能晚于结束月份。'); return; }
33
+ setError('');
34
+ const query = new URLSearchParams(Object.entries(selected).map(([key, value]) => [key, String(value)]));
35
+ navigation.push(query.size ? `/blog/archives?${query}` : '/blog/archives');
36
+ }
37
+
38
+ return (
39
+ <form aria-label="归档时间筛选" className="theme-archive-filter" onSubmit={submit}>
40
+ <Select<Mode> aria-label="筛选方式" value={mode} onChange={(value) => { setMode(value); setError(''); }} options={[
41
+ { value: 'all', label: '全部' }, { value: 'year', label: '年份' }, { value: 'month', label: '月份' }, { value: 'range', label: '月份范围' },
42
+ ]} />
43
+ {mode === 'year' ? <Input aria-label="年份" type="number" min={1970} max={9999} required value={year} onChange={(event) => setYear(event.target.value)} /> : null}
44
+ {mode === 'month' ? <Input aria-label="月份" type="month" min="1970-01" max="9999-12" required value={month} onChange={(event) => setMonth(event.target.value)} /> : null}
45
+ {mode === 'range' ? <>
46
+ <Input aria-label="起始月份" type="month" min="1970-01" max="9999-12" required value={start} onChange={(event) => setStart(event.target.value)} />
47
+ <Input aria-label="结束月份" type="month" min={start || '1970-01'} max="9999-12" required value={end} onChange={(event) => setEnd(event.target.value)} />
48
+ </> : null}
49
+ <ZlooksButton htmlType="submit">应用筛选</ZlooksButton>
50
+ <RscLink href="/blog/archives">清除筛选</RscLink>
51
+ {error ? <p role="alert">{error}</p> : null}
52
+ </form>
53
+ );
54
+ }
55
+
56
+ function parseMonth(value: string) {
57
+ const [year, month] = value.split('-').map(Number);
58
+ return { year: year ?? NaN, month: month ?? NaN };
59
+ }
60
+ function monthValue(year?: number, month?: number): string {
61
+ return year && month ? `${year}-${String(month).padStart(2, '0')}` : '';
62
+ }
@@ -0,0 +1,91 @@
1
+ 'use client';
2
+
3
+ import { RscLink, useRscNavigation } from '@hile/rsc/client/navigation';
4
+ import type { BlogPageSummary } from '@zlooks.cn/blog-schema';
5
+ import type { SitePresentationSnapshot } from '@zlooks.cn/global-config-shared';
6
+ import { ZlooksUiProvider, useZlooksTheme, type ZlooksThemeMode } from '@zlooks.cn/ui';
7
+ import { ZlooksShellProvider, useZlooksNavigation, useZlooksPathname } from '@zlooks.cn/ui/shell-provider';
8
+ import { ZlooksUserAccess } from '@zlooks.cn/ui/shell';
9
+ import { useRequest } from '@zlooks.cn/ui/request';
10
+ import type { ZlooksRscShellContext } from '@zlooks.cn/ui/shell-context';
11
+ import { useSitePresentation, ZlooksSiteConfigProvider } from '@zlooks.cn/ui/site-config';
12
+ import type { ReactNode } from 'react';
13
+ import AntFlex from 'antd/es/flex/index.js';
14
+ import AntSegmented from 'antd/es/segmented/index.js';
15
+ import { BlogSearch } from './blog-interactions.js';
16
+ import './theme.css';
17
+
18
+ const Flex = (AntFlex as unknown as { default?: typeof AntFlex }).default ?? AntFlex;
19
+ const Segmented = (AntSegmented as unknown as { default?: typeof AntSegmented }).default ?? AntSegmented;
20
+
21
+ export default function BlogFrame({
22
+ children,
23
+ navigationPages,
24
+ shell,
25
+ site,
26
+ }: {
27
+ readonly children: ReactNode;
28
+ readonly navigationPages: readonly BlogPageSummary[];
29
+ readonly shell: ZlooksRscShellContext;
30
+ readonly site: SitePresentationSnapshot;
31
+ }) {
32
+ return (
33
+ <ZlooksUiProvider>
34
+ <ZlooksShellProvider initialContext={shell}>
35
+ <ZlooksSiteConfigProvider initialConfig={site}>
36
+ <ThemeLayout navigationPages={navigationPages}>{children}</ThemeLayout>
37
+ </ZlooksSiteConfigProvider>
38
+ </ZlooksShellProvider>
39
+ </ZlooksUiProvider>
40
+ );
41
+ }
42
+
43
+ function ThemeLayout({ children, navigationPages }: {
44
+ readonly children: ReactNode;
45
+ readonly navigationPages: readonly BlogPageSummary[];
46
+ }) {
47
+ const site = useSitePresentation();
48
+ const navigation = useZlooksNavigation();
49
+ const pathname = useZlooksPathname();
50
+ const rscNavigation = useRscNavigation();
51
+ const request = useRequest();
52
+ const { mode, setMode } = useZlooksTheme();
53
+ const links = [...navigation, { key: 'blog', label: '博客', href: '/blog' }, { key: 'archives', label: '归档', href: '/blog/archives' },
54
+ ...navigationPages.map((page) => ({ key: page.id, label: page.title, href: `/blog/pages/${page.slug}` })),
55
+ { key: 'friends', label: '友链', href: '/blog/friends' },
56
+ ].filter((item, index, items) => items.findIndex((other) => other.href === item.href) === index);
57
+ const activeHref = links.filter(({ href }) => pathname === href || (href !== '/' && pathname.startsWith(`${href}/`)))
58
+ .sort((a, b) => b.href.length - a.href.length)[0]?.href;
59
+
60
+ async function logout(href: string) {
61
+ await request(href, { method: 'POST', credentials: 'same-origin' }, { errorMessage: '退出登录失败' });
62
+ rscNavigation.refresh();
63
+ }
64
+ return (
65
+ <div className="theme-shell">
66
+ <Flex component="header" className="theme-header" align="center" gap="middle" wrap>
67
+ <RscLink className="theme-brand" href={site.identity.homeHref}>
68
+ {site.identity.logoUrl ? <img alt="" src={site.identity.logoUrl} /> : null}
69
+ <strong>{site.identity.name}</strong>
70
+ </RscLink>
71
+ <Flex component="nav" aria-label="主导航" gap="middle" wrap>
72
+ {links.map((item) => <RscLink aria-current={item.href === activeHref ? 'page' : undefined} href={item.href} key={item.href}>{item.label}</RscLink>)}
73
+ </Flex>
74
+ <BlogSearch />
75
+ <div role="group" aria-label="主题">
76
+ <Segmented<ZlooksThemeMode> value={mode} onChange={setMode} options={[
77
+ { label: '浅色', value: 'light' }, { label: '深色', value: 'dark' }, { label: '自动', value: 'default' },
78
+ ]} />
79
+ </div>
80
+ <ZlooksUserAccess onLogout={logout} onNavigate={rscNavigation.push} variant="avatar" />
81
+ </Flex>
82
+ <main className="theme-main">{children}</main>
83
+ <Flex component="footer" className="theme-footer" vertical align="center" gap="small">
84
+ {site.legal.registrations.map((registration) => registration.verificationUrl
85
+ ? <a key={registration.id} href={registration.verificationUrl} target="_blank" rel="noopener noreferrer">{registration.number}</a>
86
+ : <span key={registration.id}>{registration.number}</span>)}
87
+ <span>{site.legal.copyright ?? '由 Zlooks 驱动'}</span>
88
+ </Flex>
89
+ </div>
90
+ );
91
+ }
@@ -0,0 +1,236 @@
1
+ 'use client';
2
+
3
+ import { RscLink } from '@hile/rsc/client/navigation';
4
+ import type { BlogComment, BlogPostEngagement, BlogPostSummary } from '@zlooks.cn/blog-schema';
5
+ import { createBlogThemeClient } from '@zlooks.cn/blog-theme/client';
6
+ import { ZlooksButton as Button } from '@zlooks.cn/ui/button';
7
+ import { useRequest } from '@zlooks.cn/ui/request';
8
+ import Input from 'antd/es/input/Input.js';
9
+ import TextArea from 'antd/es/input/TextArea.js';
10
+ import { useEffect, useRef, useState, type FormEvent } from 'react';
11
+ import ReactMarkdown from 'react-markdown';
12
+ import remarkGfm from 'remark-gfm';
13
+
14
+ export function MarkdownContent({ children }: { readonly children: string }) {
15
+ return <ReactMarkdown skipHtml remarkPlugins={[remarkGfm]} components={{ h1: ({ children }) => <h2>{children}</h2> }}>{children}</ReactMarkdown>;
16
+ }
17
+
18
+ export function BlogSearch() {
19
+ const request = useRequest();
20
+ const client = createBlogThemeClient(request);
21
+ const controller = useRef<AbortController | undefined>(undefined);
22
+ const [query, setQuery] = useState('');
23
+ const [results, setResults] = useState<readonly BlogPostSummary[]>([]);
24
+ const [loading, setLoading] = useState(false);
25
+ const [searched, setSearched] = useState(false);
26
+ useEffect(() => () => controller.current?.abort(), []);
27
+
28
+ async function search(event: FormEvent) {
29
+ event.preventDefault();
30
+ const normalized = query.trim();
31
+ if (normalized.length < 2 || normalized.length > 100) return;
32
+ controller.current?.abort();
33
+ const current = new AbortController();
34
+ controller.current = current;
35
+ setLoading(true);
36
+ setSearched(false);
37
+ try {
38
+ const response = await client.searchPosts(
39
+ { query: normalized, limit: 10 },
40
+ { signal: current.signal, errorMessage: '文章搜索失败' },
41
+ );
42
+ if (!current.signal.aborted) {
43
+ setResults(response.items);
44
+ setSearched(true);
45
+ }
46
+ } catch {
47
+ // useRequest owns bounded user-facing error presentation.
48
+ } finally {
49
+ if (controller.current === current) controller.current = undefined;
50
+ if (!current.signal.aborted) setLoading(false);
51
+ }
52
+ }
53
+
54
+ return (
55
+ <form className="theme-search" onSubmit={search} role="search">
56
+ <Input
57
+ aria-label="搜索文章"
58
+ maxLength={100}
59
+ onChange={(event) => {
60
+ controller.current?.abort();
61
+ controller.current = undefined;
62
+ setLoading(false);
63
+ setSearched(false);
64
+ setResults([]);
65
+ setQuery(event.target.value);
66
+ }}
67
+ placeholder="搜索文章"
68
+ value={query}
69
+ />
70
+ <Button className="theme-action" htmlType="submit" loading={loading} disabled={query.trim().length < 2}>搜索</Button>
71
+ {results.length > 0 ? (
72
+ <div className="theme-search-results">
73
+ {results.map((post) => <RscLink href={`/blog/posts/${post.slug}`} key={post.id}>{post.title}</RscLink>)}
74
+ </div>
75
+ ) : null}
76
+ {searched && results.length === 0 ? <p role="status">未找到相关文章</p> : null}
77
+ </form>
78
+ );
79
+ }
80
+
81
+ export function ArticleEngagement({ engagement, postSlug }: {
82
+ readonly engagement: BlogPostEngagement;
83
+ readonly postSlug: string;
84
+ }) {
85
+ const request = useRequest();
86
+ const client = createBlogThemeClient(request);
87
+ const controller = useRef<AbortController | undefined>(undefined);
88
+ const [liked, setLiked] = useState(engagement.viewerState === 'liked');
89
+ const [likeCount, setLikeCount] = useState(engagement.likeCount);
90
+ const [loading, setLoading] = useState(false);
91
+ const canLike = engagement.viewerState === 'liked' || engagement.viewerState === 'not-liked';
92
+ useEffect(() => () => controller.current?.abort(), []);
93
+
94
+ async function toggleLike() {
95
+ if (!canLike || controller.current) return;
96
+ const current = new AbortController();
97
+ controller.current = current;
98
+ setLoading(true);
99
+ try {
100
+ const response = liked
101
+ ? await client.unlikePost({ slug: postSlug }, { signal: current.signal, errorMessage: '取消点赞失败' })
102
+ : await client.likePost({ slug: postSlug }, { signal: current.signal, errorMessage: '点赞失败' });
103
+ if (!current.signal.aborted) {
104
+ setLiked(response.liked);
105
+ setLikeCount(response.likeCount);
106
+ }
107
+ } catch {
108
+ // useRequest owns bounded user-facing error presentation.
109
+ } finally {
110
+ if (controller.current === current) controller.current = undefined;
111
+ if (!current.signal.aborted) setLoading(false);
112
+ }
113
+ }
114
+
115
+ return (
116
+ <div className="theme-engagement">
117
+ <span>{engagement.viewCount} 次浏览</span>
118
+ <Button type={liked ? 'primary' : 'default'} aria-pressed={liked} disabled={!canLike} loading={loading} onClick={() => void toggleLike()}>
119
+ {liked ? '已赞' : '点赞'} {likeCount}
120
+ </Button>
121
+ </div>
122
+ );
123
+ }
124
+
125
+ export function CommentSection({ comments, nextCursor: initialCursor, postSlug, viewerStatus }: {
126
+ readonly comments: readonly BlogComment[];
127
+ readonly nextCursor: string | null;
128
+ readonly postSlug: string;
129
+ readonly viewerStatus: 'authenticated' | 'anonymous' | 'unavailable';
130
+ }) {
131
+ const request = useRequest();
132
+ const client = createBlogThemeClient(request);
133
+ const controller = useRef<AbortController | undefined>(undefined);
134
+ const [items, setItems] = useState<readonly BlogComment[]>(comments);
135
+ const [cursor, setCursor] = useState(initialCursor);
136
+ const [order, setOrder] = useState<'desc' | 'asc'>('desc');
137
+ const [content, setContent] = useState('');
138
+ const [submitted, setSubmitted] = useState(false);
139
+ const [loading, setLoading] = useState(false);
140
+ useEffect(() => () => controller.current?.abort(), []);
141
+
142
+ async function load(nextOrder: 'desc' | 'asc', nextCursor?: string) {
143
+ // A read must never cancel an accepted write, and cursors belong to the committed order.
144
+ if (controller.current) return;
145
+ const current = new AbortController();
146
+ controller.current = current;
147
+ setLoading(true);
148
+ try {
149
+ const response = await client.listComments(
150
+ { postSlug, limit: 20, order: nextOrder, ...(nextCursor ? { cursor: nextCursor } : {}) },
151
+ { signal: current.signal, errorMessage: '评论加载失败' },
152
+ );
153
+ if (!current.signal.aborted) {
154
+ setItems((existing) => mergeComments(nextCursor ? existing : [], response.items, nextOrder));
155
+ setCursor(response.nextCursor);
156
+ setOrder(nextOrder);
157
+ }
158
+ } catch {
159
+ // useRequest owns bounded user-facing error presentation.
160
+ } finally {
161
+ if (controller.current === current) controller.current = undefined;
162
+ if (!current.signal.aborted) setLoading(false);
163
+ }
164
+ }
165
+
166
+ async function submit(event: FormEvent) {
167
+ event.preventDefault();
168
+ const normalized = content.trim();
169
+ if (viewerStatus !== 'authenticated' || !normalized || normalized.length > 2000 || controller.current) return;
170
+ const submittedSnapshot = content;
171
+ const current = new AbortController();
172
+ controller.current = current;
173
+ setLoading(true);
174
+ try {
175
+ const comment = await client.createComment(
176
+ { postSlug, content: normalized },
177
+ { signal: current.signal, errorMessage: '评论提交失败' },
178
+ );
179
+ if (!current.signal.aborted) {
180
+ setItems((existing) => mergeComments(existing, [comment], order));
181
+ setContent((latest) => latest === submittedSnapshot ? '' : latest);
182
+ setSubmitted(true);
183
+ }
184
+ } catch {
185
+ // useRequest owns bounded user-facing error presentation.
186
+ } finally {
187
+ if (controller.current === current) controller.current = undefined;
188
+ if (!current.signal.aborted) setLoading(false);
189
+ }
190
+ }
191
+
192
+ return (
193
+ <section className="theme-comments" id="comments">
194
+ <header><h2>评论</h2></header>
195
+ {viewerStatus === 'authenticated' ? (
196
+ <form onSubmit={submit}>
197
+ <TextArea aria-label="评论内容" maxLength={2000} onChange={(event) => { setContent(event.target.value); setSubmitted(false); }} rows={5} value={content} />
198
+ <Button type="primary" disabled={!content.trim()} htmlType="submit" loading={loading}>提交评论</Button>
199
+ {submitted ? <p role="status">评论已提交,审核通过后将公开展示。</p> : null}
200
+ </form>
201
+ ) : <p>{viewerStatus === 'anonymous' ? '登录后才能发表评论。' : '账户服务暂不可用。'}</p>}
202
+ {items.length > 0 ? (
203
+ <>
204
+ <div aria-label="评论排序" className="theme-comment-order" role="group">
205
+ <Button aria-pressed={order === 'desc'} type={order === 'desc' ? 'primary' : 'default'} disabled={loading} onClick={() => void load('desc')}>最新优先</Button>
206
+ <Button aria-pressed={order === 'asc'} type={order === 'asc' ? 'primary' : 'default'} disabled={loading} onClick={() => void load('asc')}>最早优先</Button>
207
+ </div>
208
+ <div className="theme-comment-list">
209
+ {items.map((comment) => (
210
+ <article key={comment.id}>
211
+ <header><strong>{comment.user.displayName ?? '读者'}</strong><time dateTime={comment.createdAt}>{formatDate(comment.createdAt)}</time></header>
212
+ {comment.pendingReview ? <span>待审核</span> : null}
213
+ <MarkdownContent>{comment.content}</MarkdownContent>
214
+ {comment.replyContent ? <aside><strong>站长回复</strong><MarkdownContent>{comment.replyContent}</MarkdownContent></aside> : null}
215
+ </article>
216
+ ))}
217
+ </div>
218
+ {cursor ? <Button block className="theme-action theme-action-block" loading={loading} onClick={() => void load(order, cursor)}>加载更多评论</Button> : null}
219
+ </>
220
+ ) : <p>暂无评论。</p>}
221
+ </section>
222
+ );
223
+ }
224
+
225
+ function mergeComments(current: readonly BlogComment[], incoming: readonly BlogComment[], order: 'asc' | 'desc'): readonly BlogComment[] {
226
+ const byId = new Map([...current, ...incoming].map((comment) => [comment.id, comment]));
227
+ return [...byId.values()].sort((left, right) => {
228
+ const comparison = Date.parse(left.createdAt) - Date.parse(right.createdAt)
229
+ || (left.id < right.id ? -1 : left.id > right.id ? 1 : 0);
230
+ return order === 'asc' ? comparison : -comparison;
231
+ });
232
+ }
233
+
234
+ function formatDate(value: string): string {
235
+ return new Intl.DateTimeFormat('zh-CN', { dateStyle: 'medium', timeZone: 'Asia/Shanghai' }).format(new Date(value));
236
+ }