@waterwx/dsh-novel-forge 2.1.4 → 2.1.5

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.
@@ -0,0 +1,42 @@
1
+ /**
2
+ * 卡片区块页头:「标题 + 计数 + 一句说明 + 右侧动作」的唯一样式源。
3
+ *
4
+ * 为什么需要它:审查发现同一个语义(卡片首行当页头)在面板里被手写了 19 遍,
5
+ * 内联样式出现 8 种变体(`justifyContent: space-between` / 少 `flexWrap` /
6
+ * 少 `alignItems` / `gap` 有 6、8、无 三档),导致同一层级的区块标题在垂直节奏上
7
+ * 肉眼可见地参差不齐。收敛到这一个组件后,标题层级、对齐、换行策略只有一处定义。
8
+ *
9
+ * 与 `PageHeader` 的分工:
10
+ * - `PageHeader` = 视图级页头(每视图仅一个,大号衬线标题 + eyebrow)
11
+ * - `CardHead` = 区块级页头(视图内多张卡的首行,小号、无 eyebrow)
12
+ * 两级只此两级,不再有第三种「行内 span 当标题」的写法。
13
+ */
14
+ import type { ReactNode } from 'react';
15
+ export interface CardHeadProps {
16
+ /** 区块标题(必填)。用短语而非句子。 */
17
+ title: ReactNode;
18
+ /** 计数后缀,例如 `(12)`。已含括号,避免调用方各写各的中英文标点。 */
19
+ count?: string | number;
20
+ /** 标题右侧的一句 meta(弱色、12px、可省略)。 */
21
+ note?: ReactNode;
22
+ /** 右侧动作区(按钮 / 下拉 / 切换)。 */
23
+ actions?: ReactNode;
24
+ /** 大号标题(该卡片是本视图唯一主体时用,避免小标题显得寒酸)。 */
25
+ large?: boolean;
26
+ /** 左侧 lucide 图标(16px 单色)。 */
27
+ icon?: ReactNode;
28
+ }
29
+ export declare function CardHead({ title, count, note, actions, large, icon }: CardHeadProps): JSX.Element;
30
+ /**
31
+ * 两端对齐行:把 8 种内联变体收成一个类。
32
+ * 用于「左右两端放东西但左边不是标题」的场景(纯布局,不构成页头层级)。
33
+ */
34
+ export declare function RowBetween({ wrap, align, gap, children }: {
35
+ /** 窄容器下是否换行(默认换行:宁可两行也不裁切)。 */
36
+ wrap?: boolean;
37
+ /** 垂直对齐方式。 */
38
+ align?: 'center' | 'baseline' | 'flex-start';
39
+ /** 间距档(默认 8)。 */
40
+ gap?: 6 | 8 | 12;
41
+ children: ReactNode;
42
+ }): JSX.Element;
@@ -0,0 +1,36 @@
1
+ export type ConfirmTone = 'danger' | 'warn' | 'info';
2
+ export interface ConfirmSpec {
3
+ /** 弹窗标题:一句话说清要做什么。 */
4
+ title: string;
5
+ /** 后果说明:到底会发生什么、什么会保留。 */
6
+ body: React.ReactNode;
7
+ /** 逐条列出的影响面。 */
8
+ effects?: string[];
9
+ /** 承诺:如「原稿会先自动备份为 .bak,可再换回来」。 */
10
+ assurance?: string;
11
+ confirmLabel?: string;
12
+ cancelLabel?: string;
13
+ tone?: ConfirmTone;
14
+ /** 需要逐字输入的确认词;给出时用户必须输入一致才能确认。 */
15
+ requirePhrase?: string;
16
+ /** 真正的动作。抛错时弹窗不关,就地显示错误并可重试。 */
17
+ onConfirm: () => void | Promise<void>;
18
+ }
19
+ export declare function ConfirmDialog({ spec, onCancel, onDone }: {
20
+ spec: ConfirmSpec;
21
+ onCancel: () => void;
22
+ onDone: () => void;
23
+ }): JSX.Element;
24
+ /**
25
+ * 用法(替代 window.confirm):
26
+ * const confirm = useConfirm()
27
+ * confirm({ title: '…', body: '…', tone: 'danger', onConfirm: async () => { await api.x() } })
28
+ * // …并在 JSX 里渲染 {confirm.dialog}
29
+ *
30
+ * 动作用回调传入(而不是 resolve(true) 后由调用方自己跑),这样执行失败时
31
+ * 弹窗能留在原地显示错误并提供重试 —— 不会退化成「关掉弹窗 + 一句红字」。
32
+ */
33
+ export declare function useConfirm(): {
34
+ confirm: (spec: ConfirmSpec) => void;
35
+ dialog: JSX.Element | null;
36
+ };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * 通知条(notice / error 统一出口)——取代此前 4 个视图各写一处的内联 notice/error。
3
+ *
4
+ * 为什么要这个组件(不是又一层抽象):
5
+ * 1. 此前 TensionView / StyleView / TimelineView / PromptSlotsView 各写一套,
6
+ * 且 success 与 error 共用同一个未定义的 var(--nf-text-12) → 字号静默失效,
7
+ * 两者视觉权重完全一样,「成功」和「失败」在屏幕上长得一样。
8
+ * 2. 错误态只有一行红字。作者最痛的时刻不是失败,是「失败了不知道还能怎么办」,
9
+ * 所以这里强制 error 形态带上「发生了什么 + 怎么办」,并把重试摆在同一行。
10
+ * 3. 颜色走 --nf-*-ink 文字版令牌(见 panel.module.css 注释):图形版语义色
11
+ * (--nf-success #34c759 等)在浅色四档纸面上只有 1.98~3.20:1,不能当文字用。
12
+ */
13
+ import type { ReactNode } from 'react';
14
+ export type NoticeKind = 'ok' | 'error' | 'warn' | 'info';
15
+ export declare function NoticeBar({ kind, children, onRetry, retryLabel, detail, actions }: {
16
+ kind: NoticeKind;
17
+ /** 主文案:一句话说清发生了什么。 */
18
+ children: ReactNode;
19
+ /** 次要说明:补充上下文(错误码、影响范围、下一步提示)。 */
20
+ detail?: ReactNode;
21
+ /** 重试回调。给了就在同一行显示重试按钮 —— 不给才是真的没救。 */
22
+ onRetry?: () => void;
23
+ retryLabel?: string;
24
+ /** 其他补救动作(如「换个模型再试」)。 */
25
+ actions?: ReactNode;
26
+ }): JSX.Element;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * 指标条内嵌迷你走势图(sparkline):把「一堆数字」变成「一条形状」。
3
+ *
4
+ * 为什么需要它:总编台四个常驻指标原本全是纯数字。作者看到「全书字数 87,431」
5
+ * 无法判断形状 —— 33 章是均匀分布的,还是前 5 章写了六成、中间塌了十章?
6
+ * sparkline 让「节奏」变成一眼可见的形态,而不需要点进任何视图。
7
+ *
8
+ * 设计约束(避免图表挤进 12px 高的指标格后反而变噪):
9
+ * - 不画坐标轴、不画网格、不画标签:只有形状;每根柱自带悬停提示给出该章字数,
10
+ * 峰值等形态解读由 describeShape() 以文字提供。
11
+ * - 柱高按 max 归一化,0 字章节画成基线上的 1px 短横("这一章还没写")。
12
+ * - 已过审 / 未过审用两套填充区分,替代图例文字。
13
+ * - 纯装饰性趋势:aria-hidden,真正的数据在相邻的 <b> 数字里,已由读屏播报。
14
+ */
15
+ export interface SparkPoint {
16
+ /** 章节号(仅用于 title 提示)。 */
17
+ no: number;
18
+ /** 该章字数。 */
19
+ chars: number;
20
+ /** 是否已过审 —— 决定用「过审色」还是「待定色」填充。 */
21
+ approved: boolean;
22
+ }
23
+ export interface SparklineProps {
24
+ points: SparkPoint[];
25
+ /** 无数据时的替代文本(例如「尚未开写」)。 */
26
+ emptyHint?: string;
27
+ }
28
+ /** 迷你柱状走势。宽固定 132、高 26,用 viewBox 缩放以适配窄容器。 */
29
+ export declare function Sparkline({ points, emptyHint }: SparklineProps): JSX.Element;
30
+ /**
31
+ * 形态解读:把序列讲成一句人话,给 sparkline 当无障碍替代与悬停提示。
32
+ * 不新增数据,只描述现有分布 —— 目的是让作者知道「该看哪里」而不是给结论。
33
+ */
34
+ export declare function describeShape(points: SparkPoint[]): string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@waterwx/dsh-novel-forge",
3
3
  "description": "AI 编译纯文本小说工作台 for the dsh web GUI: import a novel outline (docx/text), plan volumes & chapters with LLM, generate chapter by chapter (3000-4000 chars each), auto AI review & book audit, and export the full book as Markdown/TXT into your chosen output folder.",
4
- "version": "2.1.4",
4
+ "version": "2.1.5",
5
5
  "type": "module",
6
6
  "author": "waterwx",
7
7
  "repository": {
@@ -111,6 +111,9 @@
111
111
  "watch": "tsdown --watch",
112
112
  "typecheck": "tsc --noEmit",
113
113
  "check:styles": "node scripts/check-theme-sizes.mjs",
114
+ "check:vars": "node scripts/check-css-vars.mjs",
115
+ "check:dead-classes": "node scripts/check-dead-classes.mjs",
116
+ "check:fallback": "node scripts/check-fallback-tiers.mjs",
114
117
  "check:third-party": "node scripts/check-third-party.mjs",
115
118
  "check:contrast": "node scripts/audit-contrast.mjs",
116
119
  "check:third-party:list": "node scripts/check-third-party.mjs --list",