@dongfangw/study-kit 0.0.0-stage → 0.1.0

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 (110) hide show
  1. package/LICENSE +671 -0
  2. package/README.md +28 -2
  3. package/cordis.patch.yml +3 -0
  4. package/ext/adoc-convert/index.mjs +62 -0
  5. package/lib/client.js +5917 -0
  6. package/lib/client.js.map +1 -0
  7. package/lib/docsplit.d.ts +73 -0
  8. package/lib/docsplit.d.ts.map +1 -0
  9. package/lib/docsplit.js +241 -0
  10. package/lib/docsplit.js.map +1 -0
  11. package/lib/git.d.ts +29 -0
  12. package/lib/git.d.ts.map +1 -0
  13. package/lib/git.js +305 -0
  14. package/lib/git.js.map +1 -0
  15. package/lib/index.d.ts +10 -0
  16. package/lib/index.d.ts.map +1 -0
  17. package/lib/index.js +324 -0
  18. package/lib/index.js.map +1 -0
  19. package/lib/isolation.d.ts +33 -0
  20. package/lib/isolation.d.ts.map +1 -0
  21. package/lib/isolation.js +30 -0
  22. package/lib/isolation.js.map +1 -0
  23. package/lib/libraries.d.ts +36 -0
  24. package/lib/libraries.d.ts.map +1 -0
  25. package/lib/libraries.js +118 -0
  26. package/lib/libraries.js.map +1 -0
  27. package/lib/render.d.ts +22 -0
  28. package/lib/render.d.ts.map +1 -0
  29. package/lib/render.js +568 -0
  30. package/lib/render.js.map +1 -0
  31. package/lib/session.d.ts +23 -0
  32. package/lib/session.d.ts.map +1 -0
  33. package/lib/session.js +35 -0
  34. package/lib/session.js.map +1 -0
  35. package/lib/skills.d.ts +24 -0
  36. package/lib/skills.d.ts.map +1 -0
  37. package/lib/skills.js +111 -0
  38. package/lib/skills.js.map +1 -0
  39. package/lib/slidev.d.ts +13 -0
  40. package/lib/slidev.d.ts.map +1 -0
  41. package/lib/slidev.js +755 -0
  42. package/lib/slidev.js.map +1 -0
  43. package/lib/slidevBin.d.ts +7 -0
  44. package/lib/slidevBin.d.ts.map +1 -0
  45. package/lib/slidevBin.js +130 -0
  46. package/lib/slidevBin.js.map +1 -0
  47. package/lib/slidevEnv.d.ts +56 -0
  48. package/lib/slidevEnv.d.ts.map +1 -0
  49. package/lib/slidevEnv.js +702 -0
  50. package/lib/slidevEnv.js.map +1 -0
  51. package/lib/static.d.ts +8 -0
  52. package/lib/static.d.ts.map +1 -0
  53. package/lib/static.js +79 -0
  54. package/lib/static.js.map +1 -0
  55. package/lib/tools.d.ts +4 -0
  56. package/lib/tools.d.ts.map +1 -0
  57. package/lib/tools.js +160 -0
  58. package/lib/tools.js.map +1 -0
  59. package/lib/types/client/DocMarks.d.ts +76 -0
  60. package/lib/types/client/DocMarks.d.ts.map +1 -0
  61. package/lib/types/client/DocViewer.d.ts +21 -0
  62. package/lib/types/client/DocViewer.d.ts.map +1 -0
  63. package/lib/types/client/GitPanel.d.ts +20 -0
  64. package/lib/types/client/GitPanel.d.ts.map +1 -0
  65. package/lib/types/client/LibraryWorkspace.d.ts +5 -0
  66. package/lib/types/client/LibraryWorkspace.d.ts.map +1 -0
  67. package/lib/types/client/MyLibraries.d.ts +5 -0
  68. package/lib/types/client/MyLibraries.d.ts.map +1 -0
  69. package/lib/types/client/SlidevDeckViewer.d.ts +25 -0
  70. package/lib/types/client/SlidevDeckViewer.d.ts.map +1 -0
  71. package/lib/types/client/SlidevEnvPanel.d.ts +11 -0
  72. package/lib/types/client/SlidevEnvPanel.d.ts.map +1 -0
  73. package/lib/types/client/annotations.d.ts +161 -0
  74. package/lib/types/client/annotations.d.ts.map +1 -0
  75. package/lib/types/client/docEnhance.d.ts +55 -0
  76. package/lib/types/client/docEnhance.d.ts.map +1 -0
  77. package/lib/types/client/docKey.d.ts +22 -0
  78. package/lib/types/client/docKey.d.ts.map +1 -0
  79. package/lib/types/client/git.module.css.gen.d.ts +3 -0
  80. package/lib/types/client/git.module.css.gen.d.ts.map +1 -0
  81. package/lib/types/client/icons.d.ts +50 -0
  82. package/lib/types/client/icons.d.ts.map +1 -0
  83. package/lib/types/client/index.d.ts +12 -0
  84. package/lib/types/client/index.d.ts.map +1 -0
  85. package/lib/types/client/prose.d.ts +19 -0
  86. package/lib/types/client/prose.d.ts.map +1 -0
  87. package/lib/types/client/readerControls.d.ts +55 -0
  88. package/lib/types/client/readerControls.d.ts.map +1 -0
  89. package/lib/types/client/readerPrefs.d.ts +73 -0
  90. package/lib/types/client/readerPrefs.d.ts.map +1 -0
  91. package/lib/types/client/readingPos.d.ts +82 -0
  92. package/lib/types/client/readingPos.d.ts.map +1 -0
  93. package/lib/types/client/styles.module.css.gen.d.ts +3 -0
  94. package/lib/types/client/styles.module.css.gen.d.ts.map +1 -0
  95. package/lib/types/client/submitDraft.d.ts +29 -0
  96. package/lib/types/client/submitDraft.d.ts.map +1 -0
  97. package/lib/types/client/viewActive.d.ts +55 -0
  98. package/lib/types/client/viewActive.d.ts.map +1 -0
  99. package/lib/types/types.d.ts +351 -0
  100. package/lib/types/types.d.ts.map +1 -0
  101. package/lib/types.d.ts +351 -0
  102. package/lib/types.d.ts.map +1 -0
  103. package/lib/types.js +6 -0
  104. package/lib/types.js.map +1 -0
  105. package/package.json +101 -6
  106. package/skills/aero-concept-qa/SKILL.md +65 -0
  107. package/skills/aero-learning-path/SKILL.md +61 -0
  108. package/skills/aero-study-guide/SKILL.md +47 -0
  109. package/skills/aero-think/SKILL.md +59 -0
  110. package/skills/kb-organize/SKILL.md +73 -0
@@ -0,0 +1,161 @@
1
+ /**
2
+ * 阅读标注(荧光笔 / 重点线 / 便签提问):数据模型、持久化与正文锚定。
3
+ *
4
+ * 学生诉求:读知识库与课件时想「像微信读书那样」把重点用几种荧光色标出来、画一条
5
+ * 重点线、对不懂的地方写一句自己的提问。老师端因此要能看见这些标记并一键拿去问 AI。
6
+ *
7
+ * 为什么锚点做成「字符偏移 + 原文 + 前后文」三元组:
8
+ * · 正文每次打开都由宿主重新渲染(asciidoctor / markdown-it),DOM 节点不稳定,
9
+ * 不能存节点引用或 CSS 路径;
10
+ * · 偏移在**同一份渲染结果**内是稳定的(渲染是确定性的:同一份源、同一个渲染器、
11
+ * 同一套客户端增强 → 同一个文本),直接命中即可;
12
+ * · 文档改版导致偏移错位时,用原文 + 前后文重新定位(模糊兜底);
13
+ * 定位不到的标注**不删除**,只在控制台告警——学生的笔记不能被静默吞掉。
14
+ *
15
+ * 坐标系的定义:正文根节点(`.aero-doc-body`)内**所有文本节点**按文档序拼接成的
16
+ * 字符串。刻意不排除公式(KaTeX)与代码块的文本:`Range.toString()` 的语义正是
17
+ * 「范围内所有文本节点的 data 顺序拼接」,只有让索引与它逐字对齐,落点才不会漂。
18
+ * 公式内部不参与**绘制**(见 canPaint),免得破坏 KaTeX 的字距;标注仍会记下来、
19
+ * 在面板里能看见,只是那几段字形本身不上色。
20
+ */
21
+ /** 荧光笔颜色(与 doc-theme.css 的 --aero-mark-* 一一对应)。 */
22
+ export declare const ANNO_COLORS: readonly ["yellow", "green", "blue", "pink"];
23
+ export type AnnoColor = (typeof ANNO_COLORS)[number];
24
+ /** 颜色中文名(按钮 title / 面板文案)。 */
25
+ export declare const ANNO_COLOR_LABEL: Readonly<Record<AnnoColor, string>>;
26
+ /** 标注形态:荧光笔底纹 / 重点线(下划线)。 */
27
+ export type AnnoStyle = 'highlight' | 'underline';
28
+ /** 一条标注。`page` 只对课件有意义(1 起),文档一律 0。 */
29
+ export interface Annotation {
30
+ readonly id: string;
31
+ /** 正文纯文本起点(含)。 */
32
+ readonly start: number;
33
+ /** 正文纯文本终点(不含)。 */
34
+ readonly end: number;
35
+ /** 选中的原文(重新定位的依据)。 */
36
+ readonly quote: string;
37
+ /** 原文前若干字(消歧)。 */
38
+ readonly prefix: string;
39
+ /** 原文后若干字(消歧)。 */
40
+ readonly suffix: string;
41
+ readonly color: AnnoColor;
42
+ readonly style: AnnoStyle;
43
+ /** 自己的想法 / 提问;空串表示只是标记。 */
44
+ readonly note: string;
45
+ readonly page: number;
46
+ readonly createdAt: number;
47
+ readonly updatedAt: number;
48
+ }
49
+ /** 新建标注时由调用方给出的字段。 */
50
+ export type AnnotationInit = Omit<Annotation, 'id' | 'createdAt' | 'updatedAt'>;
51
+ /** 一次选区落成的锚点(尚未落库)。 */
52
+ export interface AnnoAnchor {
53
+ readonly start: number;
54
+ readonly end: number;
55
+ readonly quote: string;
56
+ readonly prefix: string;
57
+ readonly suffix: string;
58
+ }
59
+ /** 可修改的字段(改色 / 切换形态 / 改便签)。 */
60
+ export interface AnnotationPatch {
61
+ readonly color?: AnnoColor;
62
+ readonly style?: AnnoStyle;
63
+ readonly note?: string;
64
+ }
65
+ /** 单条标注最长可标注字数(超过基本是误选整篇)。 */
66
+ export declare const MAX_QUOTE_CHARS = 2400;
67
+ import { deckKeyOf, docKeyOf, labelOfKey } from './docKey.js';
68
+ export { deckKeyOf, docKeyOf, labelOfKey };
69
+ /** 某文档的全部标注(按正文位置排序)。 */
70
+ export declare function annotationsOf(doc: string): readonly Annotation[];
71
+ /** 订阅某文档的标注(组件内使用)。 */
72
+ export declare function useAnnotations(doc: string): readonly Annotation[];
73
+ /** 全库标注总数(工具栏徽标)。 */
74
+ export declare function totalAnnotationCount(): number;
75
+ /** 新增一条标注;返回落库后的完整记录。 */
76
+ export declare function addAnnotation(doc: string, init: AnnotationInit): Annotation;
77
+ /** 合并到已有或新建:给定同一段文字已有标注时改它,没有才新建(取色点两次不会叠两条)。 */
78
+ export declare function paintAnnotation(doc: string, anchor: AnnoAnchor, color: AnnoColor, style: AnnoStyle, note: string): Annotation;
79
+ /**
80
+ * 课件标注:按「页 + 原文」去重后落库。
81
+ *
82
+ * 课件没有稳定的字符偏移坐标系(翻页时整页内容被替换),因此 start/end 只做占位,
83
+ * 定位完全靠 `page` 与 `quote`(见 SlidevDeckViewer 的 findQuoteRects)。
84
+ */
85
+ export declare function addPageAnnotation(doc: string, page: number, quote: string, color: AnnoColor, style: AnnoStyle, note: string): Annotation;
86
+ /** 修改一条标注(改色 / 切换形态 / 改便签)。 */
87
+ export declare function updateAnnotation(doc: string, id: string, patch: AnnotationPatch): void;
88
+ /** 删除一条标注。 */
89
+ export declare function removeAnnotation(doc: string, id: string): void;
90
+ /** 清空某文档的标注;返回清掉几条。 */
91
+ export declare function clearAnnotations(doc: string): number;
92
+ /**
93
+ * 导出为 Markdown。不传 `docs` 时导出全部文档;`docTitle` 用于把路径写成人类标题。
94
+ */
95
+ export declare function exportMarkdown(docs?: readonly string[], titleOf?: (key: string) => string): string;
96
+ /** 面板里每条标记的一行摘要(去掉多余空白,长引文截断)。 */
97
+ export declare function summarizeQuote(quote: string, max?: number): string;
98
+ interface TextEntry {
99
+ readonly node: Text;
100
+ readonly start: number;
101
+ }
102
+ /** 正文纯文本索引:`text` 与 `entries` 逐字对齐(= Range.toString() 的坐标系)。 */
103
+ export interface TextIndex {
104
+ readonly text: string;
105
+ readonly entries: readonly TextEntry[];
106
+ }
107
+ /** 建索引:按文档序收所有文本节点(含公式/代码里的),保证与 Range.toString() 一致。 */
108
+ export declare function buildTextIndex(root: Node): TextIndex;
109
+ /**
110
+ * 把一次 DOM 选区落成锚点。
111
+ *
112
+ * 偏移用两个 Range 的 `toString().length` 求(`selectNodeContents(root)` 起点 → 选区边界),
113
+ * 这样无论边界落在文本节点还是元素节点(三击选整段就是后者)都得到同一个坐标系,
114
+ * 不必自己走边界点。
115
+ */
116
+ export declare function anchorFromRange(root: HTMLElement, range: Range): AnnoAnchor | null;
117
+ /** 绘制结果(供 UI 徽标/边注圆点使用)。 */
118
+ export interface PaintResult {
119
+ /** 落笔成功的标注 id(按文档序)。 */
120
+ readonly painted: readonly string[];
121
+ /** 偏移失效且按原文也找不回来的标注 id。 */
122
+ readonly unresolved: readonly string[];
123
+ }
124
+ /** 摘掉上一轮绘制的 <mark>,把文本还回去(幂等绘制的前置步骤)。 */
125
+ export declare function clearPainted(root: HTMLElement): void;
126
+ /**
127
+ * 绘制全部标注。**幂等**:先摘掉旧 mark 再按当前文本重画。
128
+ *
129
+ * 同一段文字被多条标注覆盖时,**先建的那条占位**(后来的只画在剩余字符上):
130
+ * 叠加两种荧光色会变成脏色,且删除时无法判断该摘哪一层。
131
+ */
132
+ export declare function paintAnnotations(root: HTMLElement, annos: readonly Annotation[]): PaintResult;
133
+ /** 需要闪烁提示的标注(面板「定位」用):给它的 mark 打属性,1.6 s 后摘掉。 */
134
+ export declare function flashAnnotation(root: HTMLElement, id: string): void;
135
+ /** 滚到某条标注(面板「定位」)。 */
136
+ export declare function scrollToAnnotation(root: HTMLElement, id: string): boolean;
137
+ /** 正文里某条标注的第一个 mark 的视口矩形(弹层定位用)。 */
138
+ export declare function markRectOf(root: HTMLElement, id: string): DOMRect | null;
139
+ /**
140
+ * 文本偏移 → Range(课件页内高亮用:在 iframe 的文档里量选中文字的矩形)。
141
+ *
142
+ * `doc` 必须是这些文本节点所属的文档——跨文档 createRange 会抛 WrongDocumentError。
143
+ */
144
+ export declare function rangeFromOffsets(index: TextIndex, start: number, end: number, doc: Document): Range | null;
145
+ /** 一条边注圆点的定位信息(坐标相对滚动容器内容)。 */
146
+ export interface NotePin {
147
+ readonly id: string;
148
+ readonly color: AnnoColor;
149
+ readonly top: number;
150
+ readonly left: number;
151
+ readonly note: string;
152
+ readonly index: number;
153
+ }
154
+ /**
155
+ * 计算边注圆点位置。
156
+ *
157
+ * 圆点放在正文纸面的右缘外侧(版心右侧的留白里),纵向对齐它那条标注的首行;
158
+ * 同一行有多个圆点时向下让开(最小间距 PIN_GAP),不互相压住。
159
+ */
160
+ export declare function notePins(root: HTMLElement, scroller: HTMLElement, annos: readonly Annotation[]): NotePin[];
161
+ //# sourceMappingURL=annotations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotations.d.ts","sourceRoot":"","sources":["../../../src/client/annotations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * AsciiDoc 渲染结果的**阅读器端增强**(纯 DOM 后处理,不依赖宿主)。
3
+ *
4
+ * 为什么放在客户端而不是宿主 render.ts:
5
+ * 宿主把 asciidoctor 的输出直接交给浏览器,而宿主进程内改渲染参数需要重启
6
+ * `dsh`(会打断正在上课/备课的会话);本插件是客户端插件,lib/client.js 一写盘
7
+ * 就由 DSH 的 client-hmr 热重载,因此阅读体验的改进全部放在这里做。
8
+ *
9
+ * 五件事(都幂等,可重复执行):
10
+ * 1. 图注「落地」:知识库 `image::路径[图注]` 把图注写成了 alt 属性,
11
+ * 页面上原本**看不到图注**(STYLE.adoc 要求的「图注五要素」全被吞掉)。
12
+ * 这里把 alt 提升为可见题注,并拆成「图号 / 对象 / 条件→结论」三层。
13
+ * 2. 去重自动题注号:作者手写的「图 C05.9-1」与 asciidoctor 自动加的
14
+ * 「Figure 1. / 图 1.」会同时出现,中英混排很脏;仅当后面紧跟手写图号时去掉。
15
+ * 3. 宽表包一层横向滚动容器(直接给 <table> 加 overflow 会破坏列宽算法)。
16
+ * 4. 外链 target=_blank(否则点一个 http 链接会把整个工作台导航走)。
17
+ * 5. 节标题编号「1 / 1.1 / 1.1.1」:知识手册一节动辄数百行,长文里靠编号定位;
18
+ * **只给 knowledge-base 的 adoc**(教案自带「B — Bridge-in / 1.2.1 …」体系,
19
+ * 参考书 md 另成体系,一律不碰),编号与右侧「本页目录」共用同一份(见 sectionNumbers)。
20
+ */
21
+ /** 文档是否属于「节标题编号」范围(教案 adoc 与参考书 md 各自已有编号体系)。 */
22
+ export declare function isSectionNumberingTarget(relPath: string, kind: 'adoc' | 'md'): boolean;
23
+ /** 摘掉标题里手写的编号前缀(没有则原样返回)。 */
24
+ export declare function stripManualSectionNo(title: string): string;
25
+ /** 参与编号的标题(与宿主 `DocRenderResult.sections` 的最小公共形状)。 */
26
+ export interface SectionHeading {
27
+ readonly id: string;
28
+ readonly level: number;
29
+ readonly title: string;
30
+ }
31
+ /**
32
+ * 按标题层级算编号:同级递增、遇浅级重置更深级;`level <= 1`(文档标题 h1)不编号也不占号。
33
+ *
34
+ * 层级跳级(h2 直接到 h4)当前全库不存在;真出现时中间层记 0(`1.0.1`),
35
+ * 由 `scripts/tests/section-numbers.test.ts` 对全库断言「无跳级」兜底。
36
+ */
37
+ export declare function sectionNumbers(sections: readonly SectionHeading[]): Map<string, string>;
38
+ /**
39
+ * 对渲染后的正文做全部增强;幂等,可对同一节点重复调用。
40
+ *
41
+ * numbers 为 `sectionNumbers()` 的产物(键 = 标题 id,值 = `1.1`):传了才写节标题编号,
42
+ * 编号必须放在 `markSpecialSections` 之后,否则「本节小结」等固定小节匹配不上。
43
+ */
44
+ export declare function enhanceDoc(root: HTMLElement, numbers?: ReadonlyMap<string, string> | null): void;
45
+ /** 知识库文档头部元数据(键名统一小写,已去掉 `kb-` 前缀里的展示映射在 UI 层做)。 */
46
+ export interface DocMeta {
47
+ readonly title?: string;
48
+ readonly attrs: Readonly<Record<string, string>>;
49
+ }
50
+ /**
51
+ * 解析 AsciiDoc 文件头部:文档标题(`= …`)与紧随其后的 `:属性: 值` 行。
52
+ * 遇到首个空行或正文行即停止(AsciiDoc 头部只在文件最前面)。
53
+ */
54
+ export declare function parseAdocHeader(source: string): DocMeta;
55
+ //# sourceMappingURL=docEnhance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docEnhance.d.ts","sourceRoot":"","sources":["../../../src/client/docEnhance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAuKH,iDAAiD;AACjD,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAEtF;AASD,6BAA6B;AAC7B,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,uDAAuD;AACvD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAYvF;AA4ED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,CAQhG;AAOD,oDAAoD;AACpD,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CACjD;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAwBvD"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * 文档键 / 课件键:**标注**(`annotations.ts`)与**阅读位置**(`readingPos.ts`)共用。
3
+ *
4
+ * 单独成文件的两个理由:
5
+ * · 键是「同一个东西」——标注挂在 `<relPath>#<seg>` 上,阅读位置也挂在它上面;
6
+ * 两边各写一遍 key 的拼法,迟早会出现「标注在第 2 段、位置落在第 1 段」的漂移。
7
+ * · 本模块**零依赖**(不碰 DOM、不引 react),因此纯函数可以像 `docEnhance.ts` 一样
8
+ * 在 node 里直接单测(`scripts/tests/reading-pos.test.ts`);`annotations.ts` 在模块
9
+ * 初始化时会读 localStorage,把它当作键的唯一来源会绑死测试环境。
10
+ */
11
+ /**
12
+ * 文档键:`<relPath>#<seg>`。
13
+ *
14
+ * 为什么带段号:超长文档被宿主切段(src/docsplit.ts),每段是独立渲染结果,
15
+ * 段内偏移与别段没有可比性;带段号才能保证「第 3 段的第 120 字」永远指同一处。
16
+ */
17
+ export declare function docKeyOf(relPath: string, seg: number): string;
18
+ /** 课件键:与文档区分开,避免和同名 md 撞车。 */
19
+ export declare function deckKeyOf(relPath: string): string;
20
+ /** 键 → 人类可读标签(导出与面板标题用)。 */
21
+ export declare function labelOfKey(key: string): string;
22
+ //# sourceMappingURL=docKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docKey.d.ts","sourceRoot":"","sources":["../../../src/client/docKey.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,8BAA8B;AAC9B,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,4BAA4B;AAC5B,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK9C"}
@@ -0,0 +1,3 @@
1
+ declare const classes: Record<string, string>;
2
+ export default classes;
3
+ //# sourceMappingURL=git.module.css.gen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.module.css.gen.d.ts","sourceRoot":"","sources":["../../../src/client/git.module.css.gen.ts"],"names":[],"mappings":"AAaA,QAAA,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAmDnC,CAAA;AACD,eAAe,OAAO,CAAA"}
@@ -0,0 +1,50 @@
1
+ interface SvgProps {
2
+ size?: number;
3
+ className?: string;
4
+ }
5
+ export declare function BranchIcon(p: SvgProps): JSX.Element;
6
+ export declare function PullIcon(p: SvgProps): JSX.Element;
7
+ export declare function PushIcon(p: SvgProps): JSX.Element;
8
+ export declare function FetchIcon(p: SvgProps): JSX.Element;
9
+ export declare function CheckIcon(p: SvgProps): JSX.Element;
10
+ export declare function FolderIcon({ open, ...p }: SvgProps & {
11
+ open?: boolean;
12
+ }): JSX.Element;
13
+ export declare function ChevronIcon(p: SvgProps): JSX.Element;
14
+ export declare function FileIcon(p: SvgProps): JSX.Element;
15
+ export declare function CopyIcon(p: SvgProps): JSX.Element;
16
+ export declare function RefreshIcon(p: SvgProps): JSX.Element;
17
+ export declare function ExternalIcon(p: SvgProps): JSX.Element;
18
+ export declare function DownloadIcon(p: SvgProps): JSX.Element;
19
+ export declare function SigmaIcon(p: SvgProps): JSX.Element;
20
+ export declare function CursorIcon(p: SvgProps): JSX.Element;
21
+ export declare function MonitorIcon(p: SvgProps): JSX.Element;
22
+ export declare function LinkIcon(p: SvgProps): JSX.Element;
23
+ export declare function ListIcon(p: SvgProps): JSX.Element;
24
+ export declare function CloseIcon(p: SvgProps): JSX.Element;
25
+ /** 翻开的书(书籍版式)。 */
26
+ export declare function BookIcon(p: SvgProps): JSX.Element;
27
+ /** 文档页(网页版式)。 */
28
+ export declare function PageIcon(p: SvgProps): JSX.Element;
29
+ /** 字号(Aa)——阅读设置入口。 */
30
+ export declare function TypeIcon(p: SvgProps): JSX.Element;
31
+ /** 阅读设置(滑杆)。 */
32
+ export declare function SlidersIcon(p: SvgProps): JSX.Element;
33
+ /** 专注阅读(四角内收的取景框)。 */
34
+ export declare function ZenIcon(p: SvgProps): JSX.Element;
35
+ /** 进入全屏(箭头向四角张开)。 */
36
+ export declare function ExpandIcon(p: SvgProps): JSX.Element;
37
+ /** 退出全屏(箭头向中心收拢)。 */
38
+ export declare function ShrinkIcon(p: SvgProps): JSX.Element;
39
+ /** 荧光笔(阅读标注入口)。 */
40
+ export declare function PenIcon(p: SvgProps): JSX.Element;
41
+ /** 重点线(下划线)。 */
42
+ export declare function UnderlineIcon(p: SvgProps): JSX.Element;
43
+ /** 想法 / 提问(气泡)。 */
44
+ export declare function ChatIcon(p: SvgProps): JSX.Element;
45
+ /** 删除。 */
46
+ export declare function TrashIcon(p: SvgProps): JSX.Element;
47
+ /** 左侧文件树(带分栏的窗口)。 */
48
+ export declare function SidebarIcon(p: SvgProps): JSX.Element;
49
+ export {};
50
+ //# sourceMappingURL=icons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../../src/client/icons.tsx"],"names":[],"mappings":"AAGA,UAAU,QAAQ;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAqBD,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAUnD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAQjD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAQjD;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAOlD;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAMlD;AAED,wBAAgB,UAAU,CAAC,EAAE,IAAY,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,GAAG;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,GAAG,CAAC,OAAO,CAiB7F;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAMpD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAOjD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAOjD;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAOpD;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAQrD;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAQrD;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAMlD;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAMnD;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAOpD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAQjD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAOjD;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAMlD;AAED,kBAAkB;AAClB,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAOjD;AAED,iBAAiB;AACjB,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAOjD;AAED,sBAAsB;AACtB,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CASjD;AAED,gBAAgB;AAChB,wBAAgB,WAAW,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAQpD;AAED,sBAAsB;AACtB,wBAAgB,OAAO,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAShD;AAED,qBAAqB;AACrB,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CASnD;AAED,qBAAqB;AACrB,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CASnD;AAED,mBAAmB;AACnB,wBAAgB,OAAO,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAOhD;AAED,gBAAgB;AAChB,wBAAgB,aAAa,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAOtD;AAED,mBAAmB;AACnB,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAOjD;AAED,UAAU;AACV,wBAAgB,SAAS,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CASlD;AAED,qBAAqB;AACrB,wBAAgB,WAAW,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,OAAO,CAOpD"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * 客户端入口:两个标签页。
3
+ *
4
+ * - 「学习资料」(order 10):目录树 + 书籍版式阅读 + 标注 + 课件只读播放 + 阅读上下文提问
5
+ * - 「我的库」(order 20):库列表、加库向导、私人库说明、每库 Git 状态
6
+ *
7
+ * 边界:不含仿真(sim-kit)、不含备课写回(prep-kit)。
8
+ */
9
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
10
+ export declare const inject: string[];
11
+ export declare function apply(ctx: ClientContext): void;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AASnE,eAAO,MAAM,MAAM,UAAuC,CAAA;AAE1D,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAc9C"}
@@ -0,0 +1,19 @@
1
+ /** 阅读上下文(客户端跟踪,提问时自动附带)。 */
2
+ export interface ReadingContext {
3
+ /** 文件相对 KB 根的路径。 */
4
+ readonly relPath: string;
5
+ /** 文档/课件标题。 */
6
+ readonly title: string;
7
+ /** 当前小节标题(或幻灯片页码)。 */
8
+ readonly section: string;
9
+ /** 当前阅读内容的文字摘要。 */
10
+ readonly excerpt: string;
11
+ }
12
+ /** 注入 KaTeX CSS(链到 /aero-kb/katex/katex.min.css)与文档/幻灯片正文样式。 */
13
+ export declare function ensureGlobalCss(): void;
14
+ /** HTML → 纯文本(用于摘录/上下文)。 */
15
+ export declare function htmlToText(html: string): string;
16
+ export declare function truncate(s: string, n: number): string;
17
+ /** 组装「阅读上下文 + 问题」的提问文本。 */
18
+ export declare function buildContextPrompt(ctx: ReadingContext, question?: string): string;
19
+ //# sourceMappingURL=prose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prose.d.ts","sourceRoot":"","sources":["../../../src/client/prose.ts"],"names":[],"mappings":"AAEA,4BAA4B;AAC5B,MAAM,WAAW,cAAc;IAC7B,oBAAoB;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,eAAe;IACf,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,sBAAsB;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,mBAAmB;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AA0DD,gEAAgE;AAChE,wBAAgB,eAAe,IAAI,IAAI,CAYtC;AAED,4BAA4B;AAC5B,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,2BAA2B;AAC3B,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAcjF"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * 阅读器公共控件:把「学习资料」的正文阅读能力(目录 / 版式 / 阅读设置 / 专注 / 全屏)
3
+ * 收在一处实现,供「学习资料」与「备课」两个工作台共用。
4
+ *
5
+ * 为什么单独成文件:「备课」工作台的 adoc 教案渲染窗格已经改为直接内嵌 DocViewer
6
+ * (与「学习资料」同一份正文渲染与阅读偏好),若顶栏按钮各写一份,就会出现
7
+ * 两套措辞、两套快捷键、两套默认值。这里只留一份,两边调的是同一份
8
+ * readerPrefs 状态与同一个 Fullscreen API 封装。
9
+ *
10
+ * 职责边界:
11
+ * · useFullscreen —— 绑定某个工作台根节点的全屏开关,并跟踪 Esc 等外部退出;
12
+ * · useReaderShortcuts —— 正文区快捷键(+ / − / 0 / Z / O / F / Esc);
13
+ * · ReaderControls —— 顶栏按钮组本身(不含「文件树 / 列表」这类各台自有的按钮)。
14
+ */
15
+ import { type RefObject } from 'react';
16
+ /** 全屏开关(浏览器 Fullscreen API):当前是否全屏 + 切换函数。 */
17
+ export interface FullscreenControl {
18
+ active: boolean;
19
+ toggle: () => void;
20
+ }
21
+ /**
22
+ * 把某个工作台根节点做成全屏目标。
23
+ *
24
+ * 全屏作用于**工作台根节点**而不是正文容器:顶栏(退出全屏 / 目录 / 列表等入口)
25
+ * 必须留在全屏元素内部,否则用户在全屏里失去退出与切换的入口。
26
+ * 退出由浏览器接管(Esc / 系统手势),故这里同时监听 fullscreenchange 同步状态。
27
+ */
28
+ export declare function useFullscreen<T extends HTMLElement>(target: RefObject<T | null>): FullscreenControl;
29
+ /**
30
+ * 正文区快捷键:+ / − 字号、0 复位、Z 专注、O 目录、F 全屏、Esc 收尾。
31
+ *
32
+ * 两道让位:
33
+ * 1. 输入框与可编辑区域内一律让位给打字(备课台的源码编辑器就是 textarea);
34
+ * 2. 工作台根节点不可见(标签页被隐藏)时整体不响应——「学习资料」与「备课」
35
+ * 可能同时挂载,各挂一份 window 监听会互相抢键。
36
+ */
37
+ export declare function useReaderShortcuts<T extends HTMLElement>(rootRef: RefObject<T | null>, toggleFullscreen: () => void, onEscape: () => void): void;
38
+ interface Props {
39
+ /** 当前是否打开了可阅读的正文(adoc/md);为 false 时(未打开文档 / 选中课件)整组按钮不出现。 */
40
+ docOpen: boolean;
41
+ /** 全屏开关:由各工作台用 useFullscreen 绑定自己的根节点。 */
42
+ fullscreen: FullscreenControl;
43
+ /** 阅读设置面板的开合状态由工作台持有(全屏顶栏自动隐藏要读它)。 */
44
+ menuOpen: boolean;
45
+ onMenuOpenChange: (open: boolean) => void;
46
+ /** 「专注」会隐藏哪两块内容——两个工作台的措辞不同,由调用方给出。 */
47
+ zenHides: string;
48
+ }
49
+ /**
50
+ * 顶栏阅读控件组:目录 / 版式 / 阅读设置 / 专注 / 全屏。
51
+ * 各工作台自己的按钮(文件树、复制路径、Git、保存…)由调用方另行摆放。
52
+ */
53
+ export declare function ReaderControls({ docOpen, fullscreen, menuOpen, onMenuOpenChange, zenHides }: Props): JSX.Element;
54
+ export {};
55
+ //# sourceMappingURL=readerControls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readerControls.d.ts","sourceRoot":"","sources":["../../../src/client/readerControls.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAqD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAWzF,8CAA8C;AAC9C,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,EAAE,MAAM,IAAI,CAAA;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,iBAAiB,CAsBnG;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,WAAW,EACtD,OAAO,EAAE,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,EAC5B,gBAAgB,EAAE,MAAM,IAAI,EAC5B,QAAQ,EAAE,MAAM,IAAI,GACnB,IAAI,CA+BN;AA6DD,UAAU,KAAK;IACb,6DAA6D;IAC7D,OAAO,EAAE,OAAO,CAAA;IAChB,0CAA0C;IAC1C,UAAU,EAAE,iBAAiB,CAAA;IAC7B,sCAAsC;IACtC,QAAQ,EAAE,OAAO,CAAA;IACjB,gBAAgB,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACzC,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,EAAE,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAmHhH"}
@@ -0,0 +1,73 @@
1
+ export type DocLayout = 'book' | 'web';
2
+ export type DocFont = 'auto' | 'serif' | 'sans' | 'kai';
3
+ export type DocLeading = 'tight' | 'normal' | 'loose';
4
+ export type DocMeasure = 'auto' | 'narrow' | 'wide' | 'full';
5
+ export type DocPaper = 'theme' | 'white' | 'sepia' | 'green' | 'dark';
6
+ /**
7
+ * 字号档(倍率)。索引即持久化值,越界回落到默认档。
8
+ *
9
+ * 上限 160% → 300%(新增 180 / 200 / 250 / 300 四档):160% 对长时间阅读
10
+ * (投屏、视力不佳、高 DPI 小屏)仍然偏小,而倍率只作用于正文——版心按 em
11
+ * 缩放,行宽不会随字号失控。阶梯与浏览器缩放习惯对齐(…125 / 140 / 160 /
12
+ * 180 / 200 / 250 / 300),避免出现「再按一档跳过头」的档位。
13
+ *
14
+ * 这里是字号档的唯一真源:doc-theme.css 通过 --aero-scale 读取倍率,不再逐档
15
+ * 枚举 CSS 规则,因此改这一行就够,不会出现「表里有档、样式里没有」的漂移。
16
+ */
17
+ export declare const FONT_STEPS: readonly [0.9, 1, 1.1, 1.25, 1.4, 1.6, 1.8, 2, 2.5, 3];
18
+ export declare const FONT_STEP_DEFAULT = 1;
19
+ export declare const FONT_STEP_MAX: number;
20
+ /** 当前版式。 */
21
+ export declare function getDocLayout(): DocLayout;
22
+ /** 切换版式(写入 localStorage)。 */
23
+ export declare function setDocLayout(next: DocLayout): void;
24
+ /** 订阅版式(组件内使用)。 */
25
+ export declare function useDocLayout(): DocLayout;
26
+ /** 当前字号档索引。 */
27
+ export declare function getFontStep(): number;
28
+ /** 设置字号档;越界自动夹到 [0, FONT_STEP_MAX]。 */
29
+ export declare function setFontStep(next: number): void;
30
+ /** 字号加/减一档(快捷键与 A- / A+ 按钮共用)。 */
31
+ export declare function nudgeFontStep(delta: number): void;
32
+ /** 字号复位到默认档。 */
33
+ export declare function resetFontStep(): void;
34
+ export declare function useFontStep(): number;
35
+ export declare function getDocFont(): DocFont;
36
+ export declare function setDocFont(next: DocFont): void;
37
+ export declare function useDocFont(): DocFont;
38
+ export declare function getDocLeading(): DocLeading;
39
+ export declare function setDocLeading(next: DocLeading): void;
40
+ export declare function useDocLeading(): DocLeading;
41
+ export declare function getDocMeasure(): DocMeasure;
42
+ export declare function setDocMeasure(next: DocMeasure): void;
43
+ export declare function useDocMeasure(): DocMeasure;
44
+ export declare function getDocPaper(): DocPaper;
45
+ export declare function setDocPaper(next: DocPaper): void;
46
+ export declare function useDocPaper(): DocPaper;
47
+ /** 本页目录是否展开。 */
48
+ export declare function getOutlineOpen(): boolean;
49
+ export declare function setOutlineOpen(open: boolean): void;
50
+ /** 订阅「本页目录」显隐(组件内使用)。 */
51
+ export declare function useOutlineOpen(): boolean;
52
+ /** 专注阅读:隐藏左侧文件树与底部提问栏,正文独占。仅本会话有效(刷新即回到常规视图)。 */
53
+ export declare function getZen(): boolean;
54
+ export declare function setZen(on: boolean): void;
55
+ export declare function useZen(): boolean;
56
+ /** 左侧文件树是否展开。仅本会话有效:每次进入「学习资料」都从展开态开始(文档列表是入口,不能被记住的"隐藏"困住)。 */
57
+ export declare function getSidebarOpen(): boolean;
58
+ export declare function setSidebarOpen(on: boolean): void;
59
+ export declare function useSidebarOpen(): boolean;
60
+ /** 供视图层一次性取齐全部阅读偏好(固定顺序调用,不违反 Hooks 规则)。 */
61
+ export interface ReaderPrefs {
62
+ layout: DocLayout;
63
+ fontStep: number;
64
+ font: DocFont;
65
+ leading: DocLeading;
66
+ measure: DocMeasure;
67
+ paper: DocPaper;
68
+ outlineOpen: boolean;
69
+ zen: boolean;
70
+ sidebarOpen: boolean;
71
+ }
72
+ export declare function useReaderPrefs(): ReaderPrefs;
73
+ //# sourceMappingURL=readerPrefs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readerPrefs.d.ts","sourceRoot":"","sources":["../../../src/client/readerPrefs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * 每份文档「上次读到哪里」:数据模型、持久化与坐标换算。
3
+ *
4
+ * 教师诉求原话:「我在阅读知识库的多个文档时,经常在多个文档间切换,请保留每个文档
5
+ * 我上次阅读的位置,方便我对照查看。」
6
+ *
7
+ * 为什么位置不是「一个 scrollTop」:
8
+ * · 正文高度随**字号档**(0.9–3.0 十档)、**版心宽度**(四档)、**窗口宽度**、图注是否
9
+ * 加载完而变化——同一个 scrollTop 在另一个版式下指向完全不同的段落。这正是
10
+ * `annotations.ts` 不肯用节点引用/像素坐标的同一条理由。
11
+ * · 因此位置记成 **`anchor`(顶部可见标题的 id)+ `offset`(相对该标题顶端的像素)**:
12
+ * 标题 id 由宿主渲染时给出,是同一份源里稳定的锚;像素只负责标题内部的细粒度。
13
+ * 改字号、改版心、缩窗口之后仍然回到同一段文字。
14
+ * · 再记一个 `progress`(0..1 的滚动进度),只在锚点失效时兜底——文档改版、分段规则
15
+ * 变化会让某个标题 id 不再存在,那时按进度落到大致位置,总比回到开头强。
16
+ *
17
+ * 存储:`localStorage['aero.pos.v1']`,一个键存整库(与 `annotations.ts` 同一条路:
18
+ * **按浏览器/机器独立,不跨设备同步**)。键 = 文档键 `<relPath>#<seg>`(复用
19
+ * `docKeyOf`):超长文档被宿主切段(`src/docsplit.ts`),各段是独立渲染结果,
20
+ * 位置必须分开记,否则「第 2 段的第 1200 像素」会被用到第 1 段上。
21
+ *
22
+ * 刻意不做的事:
23
+ * · 不写「本页目录」里那种跟随高亮的章节目录之外的任何 UI(提示条由 DocViewer 画);
24
+ * · 不做跨标签页 storage 事件同步——同一会话不会在两个窗口里同时打开同一文档,
25
+ * 而每次写入都从本地最新库开始,最坏情况只是丢掉一次互相覆盖的位置。
26
+ */
27
+ /** 位置(不含时间戳):章节锚点 + 章内偏移 + 进度。 */
28
+ export interface DocSpot {
29
+ /** 顶部可见标题的 id;正文开头还没有标题(如章首摘要区)时为空串。 */
30
+ readonly anchor: string;
31
+ /** 相对标题顶端的像素(>=0);`anchor` 为空时退化为纯 scrollTop。 */
32
+ readonly offset: number;
33
+ /** 0..1 的阅读进度(scrollTop / 可滚高度),锚点失效时兜底。 */
34
+ readonly progress: number;
35
+ /** 保存时该标题的文字(提示条文案用),没有标题时为空串。 */
36
+ readonly label: string;
37
+ }
38
+ /** 落库的位置:位置 + 保存时间。 */
39
+ export interface DocPos extends DocSpot {
40
+ /** 保存时间(ms,`Date.now()`)。 */
41
+ readonly at: number;
42
+ }
43
+ /**
44
+ * 一个标题在**内容坐标**(= 滚动条坐标系)里的顶端位置。
45
+ *
46
+ * 为什么由调用方量好再传进来:本模块保持零 DOM 依赖,换算逻辑可以单测
47
+ * (`scripts/tests/reading-pos.test.ts`),而量矩形是视图层的事。
48
+ */
49
+ export interface HeadingMark {
50
+ readonly id: string;
51
+ /** 标题文字(已压掉多余空白的纯文本)。 */
52
+ readonly text: string;
53
+ /** 标题顶端相对内容顶端的像素。 */
54
+ readonly top: number;
55
+ }
56
+ /** 取某文档上次的位置;没读过返回 null。 */
57
+ export declare function loadPos(key: string): DocPos | null;
58
+ /** 记下某文档的位置(每次滚动节流后写一次)。 */
59
+ export declare function savePos(key: string, pos: DocPos): void;
60
+ /** 忘掉某文档的位置(「从头读」)。 */
61
+ export declare function clearPos(key: string): void;
62
+ /** 已记录位置的文档数(自检/调试用)。 */
63
+ export declare function positionCount(): number;
64
+ /** 低于这个像素量就认为「还在开头」:不弹提示、也不做恢复(打开新文档不该打扰人)。 */
65
+ export declare const RESUME_MIN_PX = 28;
66
+ /**
67
+ * 当前位置 → `DocSpot`。
68
+ *
69
+ * `headings` 必须按文档顺序给(`top` 递增):命中「顶端已越过视口上沿的最后一个标题」,
70
+ * 循环一越过就 break,所以深处的文档也不会每次都扫完几百个标题。
71
+ */
72
+ export declare function positionAt(headings: readonly HeadingMark[], scrollTop: number, scrollHeight: number, clientHeight: number): DocSpot;
73
+ /**
74
+ * `DocSpot` → scrollTop。
75
+ *
76
+ * 锚点存在就按「标题顶端 + 章内偏移」还原(改字号/版心后依然指向同一段文字);
77
+ * 锚点不存在(文档改版、切段规则变化)则按进度落到大致位置。
78
+ */
79
+ export declare function targetTop(spot: DocSpot, headings: readonly HeadingMark[], scrollHeight: number, clientHeight: number): number;
80
+ /** 保存时间 → 人话(「3 分钟前」「昨天」「12 天前」);提示条用,不参与逻辑。 */
81
+ export declare function describeAge(at: number, now?: number): string;
82
+ //# sourceMappingURL=readingPos.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readingPos.d.ts","sourceRoot":"","sources":["../../../src/client/readingPos.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAUH,kCAAkC;AAClC,MAAM,WAAW,OAAO;IACtB,wCAAwC;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,4CAA4C;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,kCAAkC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,uBAAuB;AACvB,MAAM,WAAW,MAAO,SAAQ,OAAO;IACrC,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,yBAAyB;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,qBAAqB;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AA2FD,4BAA4B;AAC5B,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAElD;AAED,4BAA4B;AAC5B,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAGtD;AAED,uBAAuB;AACvB,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAM1C;AAED,yBAAyB;AACzB,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAMD,+CAA+C;AAC/C,eAAO,MAAM,aAAa,KAAK,CAAA;AAU/B;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,SAAS,WAAW,EAAE,EAChC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,OAAO,CAgBT;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,SAAS,WAAW,EAAE,EAChC,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,MAAM,CAOR;AAMD,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM,CAYxE"}
@@ -0,0 +1,3 @@
1
+ declare const classes: Record<string, string>;
2
+ export default classes;
3
+ //# sourceMappingURL=styles.module.css.gen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.module.css.gen.d.ts","sourceRoot":"","sources":["../../../src/client/styles.module.css.gen.ts"],"names":[],"mappings":"AAaA,QAAA,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA0NnC,CAAA;AACD,eAAe,OAAO,CAAA"}