dsh-data-domain-knowledge 0.1.0-alpha.2 → 0.1.0-alpha.3
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.
- package/README.md +31 -7
- package/cordis.patch.yml +11 -5
- package/lib/client.js +5557 -3056
- package/lib/doc-page.js +7740 -0
- package/lib/types/convert/host.d.ts.map +1 -1
- package/lib/types/convert/host.js +36 -9
- package/lib/types/convert/host.js.map +1 -1
- package/lib/types/diagnosis/cards.d.ts +8 -7
- package/lib/types/diagnosis/cards.d.ts.map +1 -1
- package/lib/types/diagnosis/cards.js +119 -49
- package/lib/types/diagnosis/cards.js.map +1 -1
- package/lib/types/diagnosis/run.d.ts +51 -0
- package/lib/types/diagnosis/run.d.ts.map +1 -0
- package/lib/types/diagnosis/run.js +239 -0
- package/lib/types/diagnosis/run.js.map +1 -0
- package/lib/types/diagnosis/schema.d.ts +25 -2
- package/lib/types/diagnosis/schema.d.ts.map +1 -1
- package/lib/types/diagnosis/schema.js +64 -25
- package/lib/types/diagnosis/schema.js.map +1 -1
- package/lib/types/diagnosis/seed-source.d.ts +17 -2
- package/lib/types/diagnosis/seed-source.d.ts.map +1 -1
- package/lib/types/diagnosis/seed-source.js +18 -1
- package/lib/types/diagnosis/seed-source.js.map +1 -1
- package/lib/types/diagnosis/seed.d.ts +32 -42
- package/lib/types/diagnosis/seed.d.ts.map +1 -1
- package/lib/types/diagnosis/seed.js +187 -51
- package/lib/types/diagnosis/seed.js.map +1 -1
- package/lib/types/diagnosis/store.d.ts +114 -26
- package/lib/types/diagnosis/store.d.ts.map +1 -1
- package/lib/types/diagnosis/store.js +336 -167
- package/lib/types/diagnosis/store.js.map +1 -1
- package/lib/types/diagnosis/types.d.ts +168 -16
- package/lib/types/diagnosis/types.d.ts.map +1 -1
- package/lib/types/diagnosis/types.js +1 -1
- package/lib/types/diagnosis/types.js.map +1 -1
- package/lib/types/document-page.d.ts +39 -0
- package/lib/types/document-page.d.ts.map +1 -0
- package/lib/types/document-page.js +43 -0
- package/lib/types/document-page.js.map +1 -0
- package/lib/types/fs-atomic.d.ts +12 -0
- package/lib/types/fs-atomic.d.ts.map +1 -0
- package/lib/types/fs-atomic.js +42 -0
- package/lib/types/fs-atomic.js.map +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +214 -24
- package/lib/types/index.js.map +1 -1
- package/lib/types/knowledge-bases.d.ts +10 -2
- package/lib/types/knowledge-bases.d.ts.map +1 -1
- package/lib/types/knowledge-bases.js +20 -18
- package/lib/types/knowledge-bases.js.map +1 -1
- package/lib/types/proposals.d.ts +166 -0
- package/lib/types/proposals.d.ts.map +1 -0
- package/lib/types/proposals.js +238 -0
- package/lib/types/proposals.js.map +1 -0
- package/lib/types/runtime.d.ts +199 -7
- package/lib/types/runtime.d.ts.map +1 -1
- package/lib/types/runtime.js +728 -145
- package/lib/types/runtime.js.map +1 -1
- package/lib/types/settings-schema.d.ts +2 -2
- package/lib/types/types.d.ts +61 -10
- package/lib/types/types.d.ts.map +1 -1
- package/lib/types/types.js +56 -8
- package/lib/types/types.js.map +1 -1
- package/lib/types/wiki-types.d.ts +8 -1
- package/lib/types/wiki-types.d.ts.map +1 -1
- package/lib/types/wiki-types.js +16 -25
- package/lib/types/wiki-types.js.map +1 -1
- package/package.json +4 -3
- package/preset/tita-data-agent/agent.cordis.yml +11 -5
- package/src/client/DirectoryPicker.tsx +12 -12
- package/src/client/InfoHint.tsx +21 -8
- package/src/client/IntentTab.tsx +20 -26
- package/src/client/KnowledgeBaseTab.tsx +190 -80
- package/src/client/KnowledgePanel.tsx +42 -9
- package/src/client/KnowledgeStepRail.tsx +3 -0
- package/src/client/NodeSettings.tsx +20 -22
- package/src/client/PreviewSections.tsx +87 -33
- package/src/client/ProposalReview.tsx +313 -0
- package/src/client/TypeDefinitionDrawer.tsx +72 -38
- package/src/client/WikiTypeEditor.tsx +193 -77
- package/src/client/arch/AgentArchitectureGraph.tsx +143 -14
- package/src/client/arch/NodeLogicPanel.tsx +6 -3
- package/src/client/arch/model.ts +164 -26
- package/src/client/architecture.css +29 -9
- package/src/client/architecture.tsx +54 -29
- package/src/client/attribution/AttributionGraph.tsx +481 -34
- package/src/client/attribution/AttributionTab.tsx +507 -106
- package/src/client/attribution/CaseView.tsx +9 -14
- package/src/client/attribution/GraphStage.tsx +25 -18
- package/src/client/attribution/RunView.tsx +27 -9
- package/src/client/attribution/StageChrome.tsx +296 -140
- package/src/client/attribution/graph-options.ts +611 -47
- package/src/client/attribution/model.ts +559 -30
- package/src/client/convert/ConvertPanel.tsx +6 -1
- package/src/client/doc-page.css +134 -0
- package/src/client/doc-page.tsx +263 -0
- package/src/client/panel-state.ts +105 -0
- package/src/client/request.ts +36 -0
- package/src/client/styles.css +317 -43
- package/src/client/useFitScale.ts +15 -2
- package/src/client/wiki-type-groups.ts +86 -0
- package/src/convert/host.ts +41 -7
- package/src/diagnosis/cards.ts +120 -50
- package/src/diagnosis/run.ts +245 -0
- package/src/diagnosis/schema.ts +67 -26
- package/src/diagnosis/seed-source.ts +28 -3
- package/src/diagnosis/seed.ts +187 -85
- package/src/diagnosis/store.ts +358 -174
- package/src/diagnosis/types.ts +181 -16
- package/src/document-page.ts +51 -0
- package/src/fs-atomic.ts +42 -0
- package/src/index.ts +209 -22
- package/src/knowledge-bases.ts +20 -18
- package/src/proposals.ts +337 -0
- package/src/runtime.ts +736 -135
- package/src/types.ts +113 -19
- package/src/wiki-types.ts +17 -27
package/src/client/styles.css
CHANGED
|
@@ -125,11 +125,24 @@ body {
|
|
|
125
125
|
box-shadow: 0 1px 2px rgb(15 23 42 / .12), inset 0 0 0 1px var(--tita-primary-shadow);
|
|
126
126
|
}
|
|
127
127
|
.tita-tabsList .tita-uiTabsTrigger[data-state='active'] svg { opacity: 1; }
|
|
128
|
-
/*
|
|
129
|
-
|
|
130
|
-
选择器权重相同,靠顺序取胜。 */
|
|
128
|
+
/* 抽屉里那一枚是**行内次级控件**:它站在正文块自己的「读法工具栏」上(0042 之前挤在
|
|
129
|
+
「内容」小节标题那一行里),所以比顶栏那枚小一号(顶栏是面板级导航,这里是同一个
|
|
130
|
+
分块里的两种读法)。放在基础规则之后覆盖 —— 选择器权重相同,靠顺序取胜。 */
|
|
131
131
|
.tita-kbViewTabs { min-height: 24px; }
|
|
132
|
-
.tita-kbViewTabs .tita-uiTabsTrigger { min-height:
|
|
132
|
+
.tita-kbViewTabs .tita-uiTabsTrigger { min-height: 22px; padding: 0 9px; font-size: 11px; }
|
|
133
|
+
/*
|
|
134
|
+
* wiki 栏内部的二级 tab(0042):**要比面板一级 tab 明显低一层**。
|
|
135
|
+
* 两排 tab 同时出现在一屏里时,层级差不是好不好看的问题,是会不会点错的问题 ——
|
|
136
|
+
* 所以这里用更小的字、更矮的按钮、更轻的底色,且左对齐(一级 tab 也是左对齐)。
|
|
137
|
+
*/
|
|
138
|
+
.tita-kbSubTabs { display: grid; gap: 10px; }
|
|
139
|
+
.tita-kbSubTabsList { justify-self: start; min-height: 28px; }
|
|
140
|
+
.tita-kbSubTabsList .tita-uiTabsTrigger { min-height: 24px; padding: 0 12px; font-size: 11.5px; }
|
|
141
|
+
/* 「新页面打开」是抽屉头上的**出口**,不是主操作:它和标题同一行、比面板级按钮小一号,
|
|
142
|
+
不去抢标题。0042 之前它长在「内容」小节里,且**只在正文被截断时**才渲染 ——
|
|
143
|
+
于是短文档上它根本不存在(用户报告的原话是「那个按钮我也没看到」)。
|
|
144
|
+
入口的显隐不能依赖内容长度:位置与可见性稳定,人才学得到「全文在那个整页里」。 */
|
|
145
|
+
.tita-drawerHeadAction { height: 26px; min-height: 26px; flex: 0 0 auto; gap: 4px; padding: 0 9px; font-size: 11px; }
|
|
133
146
|
|
|
134
147
|
/* ---------------------------------------------------------------- header */
|
|
135
148
|
/* 标题行只占一行:图标 + 标题 + 一句说明。状态徽标与 ⋯ 菜单已撤(0022)。 */
|
|
@@ -328,17 +341,72 @@ body {
|
|
|
328
341
|
*/
|
|
329
342
|
.tita-drawer { width: min(440px, 100vw); }
|
|
330
343
|
/*
|
|
331
|
-
*
|
|
344
|
+
* 抽屉头:左边是「这是什么」(标题 + 路径),右边是**出口**(新页面打开)。
|
|
345
|
+
* `min-width: 0` 是必需的:路径可以很长,没有它这一行会被撑破而不是省略。
|
|
346
|
+
*/
|
|
347
|
+
.tita-drawerHead { display: flex; min-width: 0; flex: 1 1 auto; align-items: flex-start; justify-content: space-between; gap: 10px; }
|
|
348
|
+
.tita-drawerHeadCopy { min-width: 0; flex: 1 1 auto; }
|
|
349
|
+
/*
|
|
350
|
+
* 编译那一枚按钮的下拉(0042)。
|
|
351
|
+
*
|
|
352
|
+
* **宽度不能跟触发器走。** 共享组件的 `DropdownMenuContent` 默认是
|
|
353
|
+
* `w-(--radix-dropdown-menu-trigger-width)` —— 触发器是「编译 ⌄」这么宽的一枚按钮,
|
|
354
|
+
* 于是菜单里每一句话都被挤进 ~110px 的竖条里,一句话断成六行(实测截图就是这样)。
|
|
355
|
+
* 这里把宽度还给菜单自己,并把每一项排成「名字 + 一行说明」。
|
|
356
|
+
*/
|
|
357
|
+
.tita-kbCompileMenu { width: 268px; max-width: calc(100vw - 24px); }
|
|
358
|
+
.tita-kbCompileMenu [data-slot='dropdown-menu-item'] { display: block; padding: 6px 8px; }
|
|
359
|
+
.tita-kbCompileItem { display: grid; gap: 1px; }
|
|
360
|
+
.tita-kbCompileItem b { color: var(--tita-ink); font-size: 11.5px; font-weight: 650; }
|
|
361
|
+
.tita-kbCompileItem small { color: var(--tita-ink-muted); font-size: 10.5px; line-height: 1.5; }
|
|
362
|
+
/*
|
|
363
|
+
* 正文分块:块与块之间 14px,块与块之间**画一条分隔线**(0042)。
|
|
332
364
|
*
|
|
333
365
|
* 它必须挂在抽屉正文上、而**分块容器**挂在每一块上 —— 因为一块(比如「元信息」)是
|
|
334
366
|
* 「小标题 + 它自己的表」两个同级节点,只在外层给统一 gap 会把标题和它自己的内容也
|
|
335
367
|
* 拉开 14px,读起来标题就不再管着下面那块了。
|
|
368
|
+
*
|
|
369
|
+
* 0042 补上分隔线:三块的分界原来只靠 14px 的间距,而小节头与正文又是同字号,
|
|
370
|
+
* 于是一条长抽屉读起来是一整段文字。分隔线是「这三块是三件事」最省字的表达。
|
|
336
371
|
*/
|
|
337
372
|
.tita-drawerStack { display: grid; gap: 14px; align-content: start; }
|
|
338
|
-
/*
|
|
339
|
-
.tita-drawerSection { display: grid; gap: 6px; align-content: start; }
|
|
373
|
+
/* 一块内部:标题与自己的内容贴紧。上分隔线画在块上,第一块不画(它顶着抽屉头)。 */
|
|
374
|
+
.tita-drawerSection { display: grid; gap: 6px; align-content: start; border-top: 1px solid var(--tita-line); padding-top: 12px; }
|
|
375
|
+
.tita-drawerSection:first-child { border-top: 0; padding-top: 0; }
|
|
340
376
|
/* 分块之后,标题的上边距交给块间距 —— 否则 14 + 16 会在两处叠出一个空洞。 */
|
|
341
377
|
.tita-drawerSection > .tita-kbSubHead { margin: 0; }
|
|
378
|
+
|
|
379
|
+
/*
|
|
380
|
+
* 小节头:**三种层级里的中间那层**。标题 15px(UI 包的 `uiDrawerTitle`)/
|
|
381
|
+
* 小节头 13px / 正文 12px。
|
|
382
|
+
*
|
|
383
|
+
* 0042 之前这里是 12px/700 —— 与正文**同字号**,只差一个字重,中间也没有分隔线,
|
|
384
|
+
* 所以「内容」两个字读起来是正文的第 0 行。字号差 1px 是刻意的:再大就和小节里的
|
|
385
|
+
* 正文抢,再小就回到原来那个问题。
|
|
386
|
+
*/
|
|
387
|
+
.tita-drawerSubHead { display: flex; min-width: 0; align-items: baseline; justify-content: space-between; gap: 8px; }
|
|
388
|
+
.tita-drawerSubHead h4 { display: inline-flex; min-width: 0; align-items: center; gap: 6px; margin: 0; color: var(--tita-ink); font-size: 13px; font-weight: 700; }
|
|
389
|
+
.tita-drawerSubHead h4 svg { flex: 0 0 auto; color: var(--tita-ink-faint); }
|
|
390
|
+
/* 小节右侧的事实(字符数 / 条目数):与标题同一行、比标题轻。 */
|
|
391
|
+
.tita-drawerHeadFact { flex: 0 0 auto; color: var(--tita-ink-faint); font-size: 10.5px; font-variant-numeric: tabular-nums; }
|
|
392
|
+
|
|
393
|
+
/* 读法工具栏:正文块自己的两种读法(Markdown / 文本)+ 本地展开。 */
|
|
394
|
+
.tita-drawerToolbar { display: flex; min-width: 0; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; }
|
|
395
|
+
.tita-drawerMore { height: 22px; min-height: 22px; flex: 0 0 auto; gap: 4px; padding: 0 7px; font-size: 10.5px; }
|
|
396
|
+
|
|
397
|
+
/*
|
|
398
|
+
* 正文块:**锁高内滚 + 阅读栏上限。**
|
|
399
|
+
*
|
|
400
|
+
* 0042 之前正文没有高度上限,整条抽屉体(`.tita-uiDrawerBody`)是一根长滚动条 ——
|
|
401
|
+
* 正文有多长,「版本」就被推到多远,而版本正是要动手的地方(回滚)。
|
|
402
|
+
* 现在正文自己滚,下面的分块位置不再随正文长度漂移。
|
|
403
|
+
* `min(45vh, 460px)`:矮窗口下按视口走,高窗口下不占满整屏。
|
|
404
|
+
*
|
|
405
|
+
* `max-width: 68ch` 是另一半:抽屉壳**可以拖宽**(宽表格需要宽度,那是壳的属性),
|
|
406
|
+
* 但正文的行宽不该跟着长 —— 12px 下一行 68 个字符,是能一眼读完的长度。
|
|
407
|
+
* 这个上限只在把抽屉拖宽之后才咬得住,默认 440px 下正文本来就更窄。
|
|
408
|
+
*/
|
|
409
|
+
.tita-drawerBody { max-height: min(45vh, 460px); max-width: 68ch; overflow: auto; overscroll-behavior: contain; }
|
|
342
410
|
.tita-toneBlue { background: var(--tita-primary-soft); color: var(--tita-primary); }
|
|
343
411
|
.tita-toneViolet { background: var(--tita-tone-violet-tint); color: var(--tita-tone-violet); }
|
|
344
412
|
.tita-toneGreen { background: var(--tita-tone-green-tint); color: var(--tita-tone-green); }
|
|
@@ -381,15 +449,19 @@ body {
|
|
|
381
449
|
* 把 `max-w-xs` 删掉,限宽于是彻底失效(实测宽度从 320px 变成 996px)。双写是这里唯一
|
|
382
450
|
* 与样式表顺序无关的写法。
|
|
383
451
|
*
|
|
384
|
-
* 限宽**不往窄了压**(这里 320px,和 UI
|
|
385
|
-
*
|
|
386
|
-
*
|
|
452
|
+
* 限宽**不往窄了压**(这里 320px,和 UI 包默认同值):说明是整句中文,窄一档就多一行,
|
|
453
|
+
* 而多出来的那行会把它推向视口边缘。位置本身现在由 radix 决定(上方放不下就翻到下方,
|
|
454
|
+
* 见 `InfoHint`),所以这里只需要管「一行多长」这一件事。
|
|
387
455
|
*/
|
|
388
456
|
.tita-infoHintPanel.tita-infoHintPanel { display: block; max-width: 320px; padding: 8px 12px; line-height: 1.65; text-align: left; white-space: normal; }
|
|
389
457
|
/* 小节标题旁的说明入口:图标常驻、说明悬停才出现(见 `InfoHint`)。 */
|
|
390
458
|
.tita-infoHint { display: inline-flex; width: 16px; height: 16px; align-items: center; justify-content: center; padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--tita-subtle); cursor: help; }
|
|
391
459
|
.tita-infoHint:hover { background: var(--tita-surface-muted); color: var(--tita-ink-muted); }
|
|
392
460
|
.tita-infoHint:focus-visible { outline: 2px solid var(--tita-blue); outline-offset: 1px; }
|
|
461
|
+
/* 标题里的那枚(`<h3>来源类型<InfoHint/></h3>`、设置小节同理):与标题文字留一格气,
|
|
462
|
+
并对齐文字的光学中线 —— 它与标题同在一行,不是独立一行。 */
|
|
463
|
+
.tita-settingsSectionHeader h3 > .tita-infoHint,
|
|
464
|
+
.tita-settingsSectionHeader h4 > .tita-infoHint { margin-left: 6px; vertical-align: -2px; }
|
|
393
465
|
.tita-settingsSectionHeader p { margin: 4px 0 0; color: var(--tita-ink-muted); font-size: 11px; }
|
|
394
466
|
.tita-settingMeta { display: inline-flex; flex: 0 0 auto; align-items: center; gap: 4px; color: var(--tita-ink-faint); font-size: 10px; text-align: right; }
|
|
395
467
|
/* 写失败时那一行不是「状态」,是**待处理的事**,所以给它警示色而不是灰。 */
|
|
@@ -405,17 +477,18 @@ body {
|
|
|
405
477
|
* 一列之后每项的宽度、标签基线、控件左边缘都一致,占两列那个变体也就没有意义了。
|
|
406
478
|
*/
|
|
407
479
|
.tita-settingsGrid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
480
|
+
/*
|
|
481
|
+
* 字段本身(标题 / 控件 / 说明)撤掉了,改用 `packages/ui` 的 `Field`。
|
|
482
|
+
*
|
|
483
|
+
* 这里曾经有过一整套 `.tita-settingField` + `.tita-settingHint`:标题 11px/600、
|
|
484
|
+
* 说明 10px、输入框圆角 8px / 底色 `--tita-surface`。而弹层里的 `.tita-kbField` 是
|
|
485
|
+
* 12px/400 的标题、11px 的说明,`Input` 自己是 7px 圆角 / 白底 —— **同一个 `Input`
|
|
486
|
+
* 组件,放进设置行和放进弹层就长两个样**,而那个分叉完全由「它套在哪个容器里」决定。
|
|
487
|
+
* `.tita-settingField input` 那条还以 (0,1,1) 压过 `Input` 自己的工具类,所以设置抽屉
|
|
488
|
+
* 里的输入框实际渲染的是 8px 圆角,不是共享控件声明的 7px。
|
|
489
|
+
*
|
|
490
|
+
* 现在只有一处定义(`Field`),边框、圆角、字号、只读态都从共享控件来。
|
|
491
|
+
*/
|
|
419
492
|
|
|
420
493
|
/* --------------------------------------------------- 根路径:选择 + 预览 */
|
|
421
494
|
.tita-pickerRow { display: flex; min-width: 0; align-items: center; gap: 8px; }
|
|
@@ -517,7 +590,6 @@ body {
|
|
|
517
590
|
.tita-skillGrid { grid-template-columns: minmax(0, 1fr); }
|
|
518
591
|
.tita-skillHero { align-items: flex-start; flex-wrap: wrap; }
|
|
519
592
|
.tita-skillHero > .tita-uiButton { width: 100%; }
|
|
520
|
-
.tita-settingFieldWide { grid-column: auto; }
|
|
521
593
|
.tita-inputRow { align-items: stretch; flex-direction: column; }
|
|
522
594
|
.tita-inputRow .tita-uiButton { width: 100%; }
|
|
523
595
|
}
|
|
@@ -557,6 +629,14 @@ body {
|
|
|
557
629
|
.tita-kbEyebrow { display: inline-flex; align-items: center; gap: 5px; color: var(--tita-ink-faint); font-size: 9.5px; font-weight: 700; letter-spacing: .09em; }
|
|
558
630
|
.tita-kbCardHead h3 { margin: 3px 0 0; color: var(--tita-ink); font-size: 14px; font-weight: 750; letter-spacing: -.01em; }
|
|
559
631
|
.tita-kbCount { flex: 0 0 auto; color: var(--tita-ink-faint); font-size: 11px; }
|
|
632
|
+
/*
|
|
633
|
+
* 行右侧的次要事实(类型 · 时间 / N 个来源 / N 张)。
|
|
634
|
+
*
|
|
635
|
+
* 0042 补的定义:这个类名被五处用着(卡片行、原文抽屉的编译产物、意图任务、
|
|
636
|
+
* 类型定义、Wiki 类型编辑器)却**一直没有样式** —— 于是它只传递了一个名字,
|
|
637
|
+
* 右对齐与「比主文字轻」全靠父级的 flex 碰运气。一次定义到位。
|
|
638
|
+
*/
|
|
639
|
+
.tita-kbTypeCount { flex: 0 0 auto; margin-left: auto; color: var(--tita-ink-faint); font-size: 10.5px; white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
560
640
|
.tita-kbHint { margin: 8px 0 0; color: var(--tita-ink-muted); font-size: 11px; line-height: 1.65; }
|
|
561
641
|
.tita-kbHint b { color: var(--tita-ink-muted); }
|
|
562
642
|
.tita-kbEmpty { margin: 12px 0 0; border: 1px dashed var(--tita-line); border-radius: 9px; color: var(--tita-ink-faint); padding: 12px; font-size: 11.5px; text-align: center; }
|
|
@@ -579,12 +659,11 @@ body {
|
|
|
579
659
|
.tita-kbPromptSteps { margin: 8px 0 0; padding-left: 18px; color: var(--tita-ink); font-size: 11px; line-height: 1.85; }
|
|
580
660
|
.tita-kbPromptSteps code { border-radius: 4px; background: var(--tita-surface-muted); padding: 0 4px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10px; }
|
|
581
661
|
.tita-kbPromptOff { color: var(--tita-danger); text-decoration: line-through; }
|
|
582
|
-
.tita-kbTextarea { width: 100%; min-height: 58px; resize: vertical; border: 1px solid var(--tita-line); border-radius: 8px; background: var(--tita-surface); color: var(--tita-ink); padding: 7px 9px; font-family: inherit; font-size: 11.5px; line-height: 1.6; }
|
|
583
|
-
.tita-kbTextarea:focus { border-color: var(--tita-primary-line); outline: 2px solid var(--tita-focus-ring); }
|
|
584
662
|
.tita-kbSourcePick { display: inline-flex; align-items: center; gap: 6px; color: var(--tita-ink-muted); font-size: 11px; }
|
|
585
663
|
.tita-kbSourcePick select { min-width: 150px; }
|
|
586
|
-
|
|
587
|
-
|
|
664
|
+
/* 「新增类型」现在独占这一行:它旁边那段常驻说明搬进了节标题的说明图标,
|
|
665
|
+
所以这里只负责把按钮放到右侧(原来是 `space-between` 把说明和按钮分到两头)。 */
|
|
666
|
+
.tita-kbSourceAdd { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 8px; margin-top: 10px; }
|
|
588
667
|
|
|
589
668
|
/* 筛选行:搜索 · 来源分类 · 文件类型 · 刷新 · 添加文件。
|
|
590
669
|
0027 之前这里是两行(上传行 + 筛选行),而「来源分类」在两个地方各有一个控件;
|
|
@@ -606,14 +685,16 @@ body {
|
|
|
606
685
|
.tita-kbDocMeta { overflow: hidden; color: var(--tita-ink-faint); font-size: 10.5px; text-overflow: ellipsis; white-space: nowrap; }
|
|
607
686
|
.tita-kbDocActions { display: flex; flex: 0 0 auto; align-items: center; gap: 2px; }
|
|
608
687
|
|
|
688
|
+
/* 弹层里的字段**一格一行**。字段本身(标题 / 控件 / 说明)由 `packages/ui` 的
|
|
689
|
+
`Field` 提供,这里只剩「一组字段之间的间距」—— `.tita-kbField` 撤掉了,
|
|
690
|
+
它和 `Field` 是同一件事的两份写法。 */
|
|
609
691
|
.tita-kbForm { display: grid; gap: 10px; }
|
|
610
|
-
.tita-kbField { display: grid; gap: 5px; }
|
|
611
692
|
.tita-kbKv { display: grid; margin: 0; gap: 4px; }
|
|
612
693
|
.tita-kbKv > div { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 8px; }
|
|
613
694
|
.tita-kbKv dt { color: var(--tita-ink-faint); font-size: 11px; }
|
|
614
695
|
.tita-kbKv dd { margin: 0; overflow-wrap: anywhere; color: var(--tita-ink); font-size: 11.5px; }
|
|
615
696
|
.tita-kbCode { border-radius: 4px; background: var(--tita-surface-muted); padding: 1px 4px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10px; overflow-wrap: anywhere; }
|
|
616
|
-
.tita-kbAssets { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 8px; margin-top: 12px; }
|
|
697
|
+
.tita-kbAssets { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 8px; margin-top: 12px; max-height: 260px; overflow: auto; }
|
|
617
698
|
.tita-kbAsset { margin: 0; border: 1px solid var(--tita-line); border-radius: 8px; padding: 4px; }
|
|
618
699
|
.tita-kbAsset img { display: block; width: 100%; height: 62px; object-fit: contain; }
|
|
619
700
|
.tita-kbAsset figcaption { margin-top: 3px; color: var(--tita-ink-faint); font-size: 10px; text-align: center; }
|
|
@@ -626,6 +707,9 @@ body {
|
|
|
626
707
|
.tita-kbMarkdown > :last-child { margin-bottom: 0; }
|
|
627
708
|
.tita-kbMarkdown img { max-width: 100%; border-radius: 6px; }
|
|
628
709
|
.tita-kbPre { max-height: 320px; margin: 0; border: 1px solid var(--tita-line); border-radius: 9px; background: var(--tita-surface); color: var(--tita-ink); padding: 10px; overflow: auto; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10.5px; line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
710
|
+
/* 文本视图的 `<pre>` 自带 max-height(它同时被意图 / 类型定义两处用),进了正文块之后
|
|
711
|
+
由外层那一层负责滚 —— 同一件事不画两条滚动条。 */
|
|
712
|
+
.tita-drawerBody .tita-kbPre { max-height: none; }
|
|
629
713
|
|
|
630
714
|
/* ------------------------------------------------------ intent (issue 0019) */
|
|
631
715
|
.tita-intentHead { display: flex; align-items: center; gap: 8px; }
|
|
@@ -722,29 +806,104 @@ body {
|
|
|
722
806
|
.tita-wikiTypeIssueCount { border: 1px solid var(--tita-tone-amber-line); border-radius: 999px; background: var(--tita-tone-amber-tint); color: var(--tita-tone-amber); padding: 2px 9px; font-size: 10.5px; }
|
|
723
807
|
.tita-wikiTypeList { display: grid; margin: 8px 0 0; padding: 0; list-style: none; gap: 6px; }
|
|
724
808
|
/*
|
|
725
|
-
*
|
|
809
|
+
* 一行一个类型。**一行就是一行**:名字 + id + 层级 / 自定义标签 + 说明图标,
|
|
810
|
+
* 右边是张数、开关、编辑、删除。
|
|
726
811
|
*
|
|
727
|
-
*
|
|
728
|
-
*
|
|
729
|
-
*
|
|
730
|
-
*
|
|
731
|
-
*
|
|
812
|
+
* 这个格子换过两次形,两次都是为了同一件事 —— 窄栏(380–420px)里放不下第四个东西:
|
|
813
|
+
* 1. 最早是 6 列 grid,最小宽度约 398px,中间那列说明被压成 0 宽、整块看起来像「间距异常」。
|
|
814
|
+
* 2. 改成 flex 两行:第一行身份 + 操作,说明用 `order: 1` 换到第二行占满整宽。
|
|
815
|
+
* 3. 现在(2026-09-26)说明也搬进行首那枚图标:十一个类型本来要读三十多行小字,
|
|
816
|
+
* 而这一页问的是「有哪些类型、哪个没启用」。要定义、必填小节与必填字段时,
|
|
817
|
+
* 悬停或聚焦那枚图标就有 —— 内容没删,只是不再常驻。
|
|
732
818
|
*
|
|
733
|
-
*
|
|
734
|
-
*
|
|
735
|
-
* 读屏照旧先听到描述。最长的文本拿到整宽才读得下去,第一行也不再有 200px 硬下限。
|
|
819
|
+
* `align-items: baseline` 保留:名字、id、层级标签三样要坐在同一条基线上才读得成一行。
|
|
820
|
+
* 说明图标自己 `align-self: center`,因为一个只有 svg 的按钮没有可用的文字基线。
|
|
736
821
|
*/
|
|
737
822
|
.tita-wikiTypeRow { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; border: 1px solid var(--tita-line); border-radius: 9px; background: var(--tita-surface); padding: 8px 10px; }
|
|
738
823
|
.tita-wikiTypeName { display: flex; flex: 1 1 auto; min-width: 0; flex-wrap: wrap; align-items: baseline; gap: 6px; }
|
|
739
824
|
.tita-wikiTypeLabel { color: var(--tita-ink); font-size: 12px; font-weight: 620; }
|
|
740
825
|
.tita-wikiTypeTag { flex: 0 0 auto; border-radius: 4px; background: var(--tita-primary-soft); color: var(--tita-primary); padding: 1px 5px; font-size: 9.5px; }
|
|
741
|
-
/*
|
|
742
|
-
|
|
826
|
+
/* 行首那枚说明图标:长名字不把它挤扁(它跟着的是「这一行是什么」),
|
|
827
|
+
也不与文字比基线 —— 一个只装 svg 的按钮没有可用的基线。 */
|
|
828
|
+
.tita-kbSourceName > .tita-infoHint,
|
|
829
|
+
.tita-wikiTypeName > .tita-infoHint { flex: 0 0 auto; align-self: center; }
|
|
743
830
|
.tita-wikiTypeIssues { display: grid; margin: 8px 0 0; padding: 0; list-style: none; gap: 5px; }
|
|
744
831
|
.tita-wikiTypeIssues li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; color: var(--tita-ink-muted); font-size: 11px; line-height: 1.6; }
|
|
745
832
|
.tita-wikiTypeIssues code { border-radius: 4px; background: var(--tita-surface-muted); padding: 1px 4px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10px; }
|
|
746
833
|
.tita-wikiTypeIssueLevel { border-radius: 4px; background: var(--tita-surface-muted); color: var(--tita-ink-muted); padding: 0 5px; font-size: 9.5px; }
|
|
747
834
|
|
|
835
|
+
/*
|
|
836
|
+
* 按 id 前缀折成的一组(0040 §4.3)。
|
|
837
|
+
*
|
|
838
|
+
* 分组只做一件事:让「这五个是同一套 schema」在列表里看得出来。所以组**不是一个
|
|
839
|
+
* 盒子**:它没有边框、没有底色,只有一条左缩进与一枚可点的组名行。真正承载内容的
|
|
840
|
+
* 还是里面那些 `.tita-wikiTypeRow` —— 给组再加一层描边,一组五个人就会看起来像
|
|
841
|
+
* 卡片套卡片,而这一屏本来就已经是列表套列表。
|
|
842
|
+
*
|
|
843
|
+
* 缩进是唯一的结构信号。组的 `<details>` 默认展开(`open`):折叠是给"太长"用的,
|
|
844
|
+
* 而这里折叠是**默认的阅读顺序**,不是隐藏内容。
|
|
845
|
+
*/
|
|
846
|
+
.tita-wikiTypeGroup { margin: 0; }
|
|
847
|
+
.tita-wikiTypeGroupBox { display: grid; gap: 5px; }
|
|
848
|
+
.tita-wikiTypeGroupHead { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; border-radius: 6px; padding: 2px 4px; cursor: pointer; list-style: none; }
|
|
849
|
+
.tita-wikiTypeGroupHead::-webkit-details-marker { display: none; }
|
|
850
|
+
/* 展开态把箭头转 90°(`▸` → `▾`):图形只有一个,方向由状态决定。
|
|
851
|
+
`transition` 与按钮那套时长一致,转起来不抢注意力。 */
|
|
852
|
+
.tita-wikiTypeGroupCaret { flex: 0 0 auto; color: var(--tita-ink-faint); transition: transform 150ms cubic-bezier(0.22, 0.61, 0.36, 1); }
|
|
853
|
+
.tita-wikiTypeGroupBox[open] > .tita-wikiTypeGroupHead .tita-wikiTypeGroupCaret { transform: rotate(90deg); }
|
|
854
|
+
@media (prefers-reduced-motion: reduce) { .tita-wikiTypeGroupCaret { transition: none; } }
|
|
855
|
+
.tita-wikiTypeGroupHead:hover { background: var(--tita-surface-muted); }
|
|
856
|
+
/* 组名比成员更重、比整个抽屉的节标题更轻:它在"有哪些类型"这一层里是一个中间层级。 */
|
|
857
|
+
.tita-wikiTypeGroupLabel { color: var(--tita-ink-muted); font-size: 11px; font-weight: 650; letter-spacing: .01em; }
|
|
858
|
+
.tita-wikiTypeGroupCount { margin-left: auto; color: var(--tita-ink-faint); font-size: 10px; }
|
|
859
|
+
/* 成员缩进 12px:正好是组名那枚 `▾` 加间距的宽度,缩进后成员与组名对齐成一条轴。 */
|
|
860
|
+
.tita-wikiTypeGroupList { display: grid; margin: 0; padding: 0 0 0 12px; list-style: none; gap: 6px; }
|
|
861
|
+
|
|
862
|
+
/*
|
|
863
|
+
* 模板卡预览(0040 §4.4 第 3、4 条)。它是**只读块**,不是控件:
|
|
864
|
+
* 沉底(`--tita-surface-muted`)+ 虚线描边 + 等宽内容,与旁边那几个白底实边框的
|
|
865
|
+
* `Input` / `Textarea` 一眼可分。虚线而不是实线,是因为实线在这个面板里已经
|
|
866
|
+
* 专门表示"可编辑的输入框"。
|
|
867
|
+
*
|
|
868
|
+
* 两块(front matter / 正文)共用同一套排版,只有标题与说明不同 —— 它们的分工
|
|
869
|
+
* 靠**标题**说清,不靠两套长相。
|
|
870
|
+
*/
|
|
871
|
+
.tita-wikiPreview { display: grid; gap: 8px; }
|
|
872
|
+
.tita-wikiPreviewHead { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; }
|
|
873
|
+
.tita-wikiPreviewHead h4 { margin: 0; color: var(--tita-ink); font-size: 12px; }
|
|
874
|
+
.tita-wikiPreviewOrigin { color: var(--tita-ink-faint); font-size: 10.5px; }
|
|
875
|
+
.tita-wikiPreviewBlock { display: grid; gap: 5px; border: 1px dashed var(--tita-line-strong); border-radius: 9px; background: var(--tita-surface-muted); padding: 9px 10px; }
|
|
876
|
+
.tita-wikiPreviewBlockTitle { margin: 0; color: var(--tita-ink-muted); font-size: 11px; font-weight: 700; }
|
|
877
|
+
.tita-wikiPreviewBlockNote { margin: 0; color: var(--tita-ink-faint); font-size: 10.5px; line-height: 1.6; }
|
|
878
|
+
.tita-wikiPreviewFields { display: grid; margin: 2px 0 0; gap: 3px; }
|
|
879
|
+
.tita-wikiPreviewField { display: flex; min-width: 0; flex-wrap: wrap; align-items: baseline; gap: 6px; }
|
|
880
|
+
.tita-wikiPreviewField dt { flex: 0 0 auto; margin: 0; color: var(--tita-ink); font-family: var(--font-tita-mono); font-size: 10.5px; }
|
|
881
|
+
.tita-wikiPreviewField dd { margin: 0; color: var(--tita-ink-muted); font-size: 10.5px; line-height: 1.6; overflow-wrap: anywhere; }
|
|
882
|
+
.tita-wikiPreviewSections { display: grid; margin: 2px 0 0; padding: 0; list-style: none; gap: 3px; }
|
|
883
|
+
.tita-wikiPreviewSections li { display: flex; min-width: 0; flex-wrap: wrap; align-items: baseline; gap: 6px; }
|
|
884
|
+
.tita-wikiPreviewSections code { color: var(--tita-ink); font-family: var(--font-tita-mono); font-size: 10.5px; }
|
|
885
|
+
.tita-wikiPreviewPlaceholder { color: var(--tita-ink-faint); font-size: 10.5px; }
|
|
886
|
+
.tita-wikiPreviewEmpty { margin: 2px 0 0; color: var(--tita-ink-faint); font-size: 10.5px; line-height: 1.6; }
|
|
887
|
+
|
|
888
|
+
/*
|
|
889
|
+
* 只读字段的形态(0040 §4.4 第 1 条)。
|
|
890
|
+
*
|
|
891
|
+
* `Input` 的 `readonly` 样式(`packages/ui`)已经给了沉底 + 浅描边 + 文本光标,
|
|
892
|
+
* 这里补的是"这不能改"那一点:文字收到 `--tita-ink-muted`。**不用 opacity** ——
|
|
893
|
+
* 靠透明度变灰会把对比度一起压下去,而 4.5:1 是硬线;`--tita-ink-muted` 在
|
|
894
|
+
* `--tita-surface-muted` 上是 6.98:1(按主题真值实算),灰得明确又读得清。
|
|
895
|
+
*
|
|
896
|
+
* 选择器写 `[data-tita-readonly='true']` 而不是 `input[readonly]`:这条规约只作用于
|
|
897
|
+
* **声明了它**的字段,不能顺手把别处(目录选择器那种"当前值"框)的只读输入框也改掉。
|
|
898
|
+
* 对话框走 Portal,不在 `.tita-panel` 里,所以两处都写上。
|
|
899
|
+
*/
|
|
900
|
+
.tita-panel input[data-tita-readonly='true'],
|
|
901
|
+
.tita-uiPortal input[data-tita-readonly='true'] { border-color: var(--tita-line); background: var(--tita-surface-muted); color: var(--tita-ink-muted); }
|
|
902
|
+
|
|
903
|
+
/* 组名行是 `<summary>`,也就是一个可聚焦的按钮:焦点环走全局面板规则,
|
|
904
|
+
但它的圆角只有 6px,偏移 2px 会顶到相邻行,所以这一处收一点。 */
|
|
905
|
+
.tita-wikiTypeGroupHead:focus-visible { outline-offset: 1px; }
|
|
906
|
+
|
|
748
907
|
/* 意图分类注册表(issue 0023):预置项是模型的匹配依据,所以定义与"例如"要露在行上。 */
|
|
749
908
|
.tita-intentCategoryList { display: grid; margin: 10px 0 0; padding: 0; list-style: none; gap: 6px; }
|
|
750
909
|
.tita-intentCategoryRow { display: grid; grid-template-columns: minmax(210px, auto) minmax(0, 1fr) auto auto auto; align-items: center; gap: 8px; border: 1px solid var(--tita-line); border-radius: 9px; background: var(--tita-surface); padding: 7px 9px; }
|
|
@@ -804,16 +963,27 @@ body {
|
|
|
804
963
|
/* 记忆:真实落盘计数(04_memory)与「示意」卡片分开摆,避免把占位数字读成真实数据。 */
|
|
805
964
|
.tita-memoryReal { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-bottom: 14px; }
|
|
806
965
|
|
|
807
|
-
/* 知识库文档详情:该文档编译出的 wiki 卡片(对应 WeKnora 的「分块」列表)。
|
|
808
|
-
|
|
809
|
-
.tita-
|
|
966
|
+
/* 知识库文档详情:该文档编译出的 wiki 卡片(对应 WeKnora 的「分块」列表)。
|
|
967
|
+
两处用同一套类名:wiki 栏的卡片列表,以及原文抽屉里的「编译产物」列表。 */
|
|
968
|
+
.tita-cardList { display: grid; margin: 8px 0 0; padding: 0; list-style: none; gap: 4px; }
|
|
969
|
+
/*
|
|
970
|
+
* **一条列表,不是一堆卡片**(0042)。
|
|
971
|
+
*
|
|
972
|
+
* 0042 之前每一行都有一圈常驻边框 + 圆角,外面还套着一层 `Card`(`.tita-kbCard` 也有
|
|
973
|
+
* 边框)—— 3 张卡片就是 3 个框、行与行之间又各画一圈,看到的是「框套框」。
|
|
974
|
+
* 现在照 `.tita-kbDocRow` 的做法:**常态边框透明**,hover 才显边框 + 浅底。
|
|
975
|
+
* 顺带修掉原来的空转规则:`:hover` 给的取值与常态完全相同,等于没有反馈。
|
|
976
|
+
*/
|
|
977
|
+
.tita-cardRow { display: grid; min-width: 0; gap: 4px; border: 1px solid transparent; border-radius: 8px; padding: 6px 8px; }
|
|
810
978
|
.tita-cardRowHead { display: flex; min-width: 0; flex-wrap: wrap; align-items: center; gap: 6px; }
|
|
811
979
|
.tita-cardRowTitle { min-width: 0; overflow: hidden; color: var(--tita-ink); font-size: 11.5px; font-weight: 620; text-overflow: ellipsis; white-space: nowrap; }
|
|
980
|
+
/* 摘要只出现在**抽屉里**那份列表(那一屏是逐条核对的,不是扫的)。 */
|
|
812
981
|
.tita-cardRowText { margin: 0; color: var(--tita-ink-muted); font-size: 10.5px; line-height: 1.6; overflow-wrap: anywhere; }
|
|
813
982
|
/* 0025:卡片行变成可点入口(点开看内容与版本)。按钮要抹掉浏览器默认外观,
|
|
814
983
|
同时保留 `.tita-cardRow` 的网格排版 —— 否则文字会掉到按钮默认的居中样式里。 */
|
|
815
984
|
.tita-cardRowMain { display: grid; width: 100%; gap: 4px; border: 0; background: none; padding: 0; color: inherit; font: inherit; text-align: left; cursor: pointer; }
|
|
816
|
-
.tita-cardRow:hover { border-color: var(--tita-line); background: var(--tita-surface); }
|
|
985
|
+
.tita-cardRow:hover { border-color: var(--tita-line); background: var(--tita-surface-muted); }
|
|
986
|
+
.tita-cardRow:focus-within { border-color: var(--tita-primary-line); background: var(--tita-surface-muted); }
|
|
817
987
|
|
|
818
988
|
/* 知识库的步骤轨:**一条流水线,不是一排并列的 tab**。
|
|
819
989
|
收录 → 编译 → 关联 → 检索 → 精排,步与步之间用箭头连起来 —— 方向本身就是信息
|
|
@@ -938,3 +1108,107 @@ body {
|
|
|
938
1108
|
.tita-panel ::-webkit-scrollbar-thumb { border: 3px solid transparent; border-radius: 999px; background-clip: content-box; background-color: var(--tita-line-strong); }
|
|
939
1109
|
.tita-panel ::-webkit-scrollbar-thumb:hover { background-color: var(--tita-ink-faint); }
|
|
940
1110
|
.tita-panel ::-webkit-scrollbar-corner { background: transparent; }
|
|
1111
|
+
|
|
1112
|
+
/* ════════════════════════════════════════════════════════════════════════════
|
|
1113
|
+
智能归因图谱 · 动线视角的泳道带(0021 §7.7)
|
|
1114
|
+
|
|
1115
|
+
它叠在 G6 画布上,只负责「这一段是什么、这一段有几个、哪一段断在这里」。
|
|
1116
|
+
两条约束决定它必须这么写:
|
|
1117
|
+
|
|
1118
|
+
1. **整层不吃事件**(`pointer-events: none`,§7.4 第 10 条):带子只负责读,
|
|
1119
|
+
命中一律落到画布上,否则点节点、拖画布都会被这层吞掉。
|
|
1120
|
+
2. **坐标由 TS 算**(`laneLayoutOf` 的 `top/left/width/height` 走行内 style):
|
|
1121
|
+
这里只描述「长什么样」,不描述「摆在哪」。同一份几何同时喂画布与这一层,
|
|
1122
|
+
两处不可能对不上。
|
|
1123
|
+
|
|
1124
|
+
颜色全部是 `color-mix()` 混出来的,基底取共享令牌 —— 主题一换,带子跟着走,
|
|
1125
|
+
不需要第二份颜色。`--tita-band-tint` 由 React 按段给(实例层偏琥珀,其余偏蓝)。
|
|
1126
|
+
════════════════════════════════════════════════════════════════════════════ */
|
|
1127
|
+
.tita-attrBand {
|
|
1128
|
+
position: absolute;
|
|
1129
|
+
/* 5% 是「看得出有分区、但绝不和节点抢注意力」的那一档;段头带稍重一点(9%),
|
|
1130
|
+
因为它是这一段唯一的文字锚点。 */
|
|
1131
|
+
background: color-mix(in srgb, var(--tita-band-tint, var(--tita-tone-blue)) 5%, var(--tita-surface));
|
|
1132
|
+
border-radius: 8px;
|
|
1133
|
+
}
|
|
1134
|
+
.tita-attrBandHeader {
|
|
1135
|
+
display: flex;
|
|
1136
|
+
width: 100%;
|
|
1137
|
+
min-width: 0;
|
|
1138
|
+
align-items: center;
|
|
1139
|
+
/* 不换行:段头高 20px,一换行就把段名顶出带子。放不下的部分由各段自己省略。 */
|
|
1140
|
+
flex-wrap: nowrap;
|
|
1141
|
+
gap: 6px;
|
|
1142
|
+
padding: 0 8px;
|
|
1143
|
+
background: color-mix(in srgb, var(--tita-band-tint, var(--tita-tone-blue)) 9%, var(--tita-surface));
|
|
1144
|
+
border-radius: 8px 8px 0 0;
|
|
1145
|
+
}
|
|
1146
|
+
/* 段头左侧那一块(段名 + 计数 + 读法)是一个按钮:点它收起 / 展开这一段。
|
|
1147
|
+
按钮的默认外观必须显式抹掉 —— 没有 preflight 时它的字体、字号、对齐、边框、
|
|
1148
|
+
背景都会退回浏览器默认值,表现出来就是「段头的字比别处大一号、还带一圈近黑描边」。 */
|
|
1149
|
+
.tita-attrBandHeadMain {
|
|
1150
|
+
display: flex;
|
|
1151
|
+
min-width: 0;
|
|
1152
|
+
flex: 1 1 auto;
|
|
1153
|
+
align-items: center;
|
|
1154
|
+
gap: 6px;
|
|
1155
|
+
padding: 0;
|
|
1156
|
+
border: 0;
|
|
1157
|
+
background: transparent;
|
|
1158
|
+
font: inherit;
|
|
1159
|
+
color: inherit;
|
|
1160
|
+
text-align: left;
|
|
1161
|
+
cursor: pointer;
|
|
1162
|
+
}
|
|
1163
|
+
/* 不能收起 / 展开的段头(空段、被切面关掉的段、只剩一个节点的段):纯读数,不该看起来能点。 */
|
|
1164
|
+
.tita-attrBandHeadMain:disabled { cursor: default; }
|
|
1165
|
+
.tita-attrBandHeadMain:not(:disabled):hover .tita-attrBandName { color: var(--tita-primary); }
|
|
1166
|
+
.tita-attrBandHeadMain:focus-visible { outline: 2px solid var(--tita-primary); outline-offset: 1px; border-radius: 4px; }
|
|
1167
|
+
/* ① 段的「换一个现象」入口。它是**换一条动线**,不是筛选 —— 所以做成段头上的小按钮,
|
|
1168
|
+
不进左栏的筛选组(那会让人以为图被裁掉了)。 */
|
|
1169
|
+
.tita-attrBandPicks { display: flex; flex: 0 0 auto; align-items: center; gap: 4px; white-space: nowrap; }
|
|
1170
|
+
.tita-attrBandPicksLabel { color: var(--tita-ink-faint); font-size: 10px; }
|
|
1171
|
+
.tita-attrBandPick {
|
|
1172
|
+
padding: 1px 5px;
|
|
1173
|
+
border: 1px solid var(--tita-line-strong);
|
|
1174
|
+
border-radius: 5px;
|
|
1175
|
+
background: var(--tita-surface);
|
|
1176
|
+
color: var(--tita-ink-muted);
|
|
1177
|
+
font-family: var(--tita-mono);
|
|
1178
|
+
font-size: 10px;
|
|
1179
|
+
line-height: 14px;
|
|
1180
|
+
cursor: pointer;
|
|
1181
|
+
}
|
|
1182
|
+
.tita-attrBandPick:hover { border-color: var(--tita-primary); color: var(--tita-primary); }
|
|
1183
|
+
.tita-attrBandPick:focus-visible { outline: 2px solid var(--tita-primary); outline-offset: 1px; }
|
|
1184
|
+
/* 被收起 / 被关掉的段:带子沉下去,与「这一段是空的」区分开 ——
|
|
1185
|
+
空段仍然是正常底色(它是一条待办),而收起是用户的选择,视觉上要退到后面。 */
|
|
1186
|
+
.tita-attrBand[data-tita-lane-state='collapsed'],
|
|
1187
|
+
.tita-attrBand[data-tita-lane-state='off'] { opacity: .72; }
|
|
1188
|
+
/* 段名:这一段唯一必须读到的字。11px / 650 让它压得住节点标题(10.5px / 600)。 */
|
|
1189
|
+
.tita-attrBandName { flex: 0 0 auto; white-space: nowrap; color: var(--tita-ink); font-size: 11px; font-weight: 650; letter-spacing: -.01em; }
|
|
1190
|
+
/* 计数:等宽 + 表格数字,段与段之间扫一眼就能比大小。 */
|
|
1191
|
+
.tita-attrBandCount { flex: 0 0 auto; color: var(--tita-ink); font-family: var(--tita-mono); font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums; }
|
|
1192
|
+
.tita-attrBandCountDim { color: var(--tita-ink-faint); font-weight: 500; }
|
|
1193
|
+
/* 排序依据(或空段说明):段头右侧的弱化文字。它是「这一段怎么读」的读法,
|
|
1194
|
+
不是标题,所以不抢墨色;但仍然是 10px 的正文级对比度,不用 ad-hoc 灰。 */
|
|
1195
|
+
.tita-attrBandHint {
|
|
1196
|
+
min-width: 0;
|
|
1197
|
+
flex: 1 1 auto;
|
|
1198
|
+
overflow: hidden;
|
|
1199
|
+
color: var(--tita-ink-faint);
|
|
1200
|
+
font-size: 10px;
|
|
1201
|
+
line-height: 1.3;
|
|
1202
|
+
text-align: right;
|
|
1203
|
+
white-space: nowrap;
|
|
1204
|
+
text-overflow: ellipsis;
|
|
1205
|
+
}
|
|
1206
|
+
/* 内容左沿的一条竖线:段头文字与节点左对齐到同一列,这一段才读起来像一段。
|
|
1207
|
+
1px 且只有段高的一半 —— 它是对齐提示,不是分隔线。 */
|
|
1208
|
+
.tita-attrBandRule {
|
|
1209
|
+
position: absolute;
|
|
1210
|
+
top: 100%;
|
|
1211
|
+
bottom: 0;
|
|
1212
|
+
width: 1px;
|
|
1213
|
+
background: color-mix(in srgb, var(--tita-band-tint, var(--tita-tone-blue)) 26%, transparent);
|
|
1214
|
+
}
|
|
@@ -16,6 +16,16 @@ import { useEffect, useState, type RefObject } from 'react'
|
|
|
16
16
|
/** 窄栏下的两档。`fit` = 整图缩到容器,`actual` = 1:1(滚动查看)。 */
|
|
17
17
|
export type ZoomMode = 'fit' | 'actual'
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* 适应哪一条轴。
|
|
21
|
+
*
|
|
22
|
+
* - `both`(默认):宽高都缩进容器,缩完就是容器的整块面积 —— 知识图谱那一栏用它。
|
|
23
|
+
* - `width`:只按宽度缩,高度允许溢出 —— 概览画布用它。概览是一块**自持视口**的画布
|
|
24
|
+
* (见 `architecture.css` 的 `.tita-archScrollStage`),纵向溢出由空格 + 拖拽平移看,
|
|
25
|
+
* 而不是把整块板缩到读不出字。
|
|
26
|
+
*/
|
|
27
|
+
export type FitAxis = 'both' | 'width'
|
|
28
|
+
|
|
19
29
|
export interface FitScale {
|
|
20
30
|
scale: number
|
|
21
31
|
/** 缩放后的板高;容器高度就用它(`fit` 档下正好没有可滚的余量)。 */
|
|
@@ -31,6 +41,7 @@ export interface FitScale {
|
|
|
31
41
|
* @param enabled 容器不可见时不要量(隐藏容器尺寸为 0,算出来的比例是 0)
|
|
32
42
|
* @param fullscreen 全屏时两个方向都按容器算;窄栏只有宽度可用
|
|
33
43
|
* @param mode 缩放档
|
|
44
|
+
* @param fit 适应哪条轴;`width` 时高度永不算进比例(溢出交由平移)
|
|
34
45
|
*/
|
|
35
46
|
export function useFitScale(
|
|
36
47
|
scroller: RefObject<HTMLDivElement | null>,
|
|
@@ -39,6 +50,7 @@ export function useFitScale(
|
|
|
39
50
|
enabled: boolean,
|
|
40
51
|
fullscreen: boolean,
|
|
41
52
|
mode: ZoomMode,
|
|
53
|
+
fit: FitAxis = 'both',
|
|
42
54
|
): FitScale {
|
|
43
55
|
/**
|
|
44
56
|
* 可视尺寸。用 `offsetWidth/Height` 而不是 `clientWidth/clientHeight`:后者会随
|
|
@@ -60,9 +72,10 @@ export function useFitScale(
|
|
|
60
72
|
}, [enabled, fullscreen])
|
|
61
73
|
|
|
62
74
|
// 窄栏只有宽度是可用的:高度由板高自己决定,拿它去算比例就成了一条回路,
|
|
63
|
-
//
|
|
75
|
+
// 所以那里高度按设计高度算(即「只按宽度适应」)。`fit: 'width'` 把这条规则
|
|
76
|
+
// 从「窄栏的例外」提升成「这一栏的常态」—— 全屏下也不再把高度算进比例。
|
|
64
77
|
const availW = viewport.w || contentW
|
|
65
|
-
const availH = fullscreen ? (viewport.h || contentH) : contentH
|
|
78
|
+
const availH = fit === 'width' ? contentH : fullscreen ? (viewport.h || contentH) : contentH
|
|
66
79
|
const scale = mode === 'actual' ? 1 : Math.min(1, availW / contentW, availH / contentH)
|
|
67
80
|
return { scale, boardH: contentH * scale }
|
|
68
81
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wiki 类型列表的**分组与排布计划**(0040 §4.3)。
|
|
3
|
+
*
|
|
4
|
+
* 抽成独立模块的理由是**它出过一次错,而且是静默的**:把「列表怎么摆」直接写在 JSX 的
|
|
5
|
+
* 三元里时,`prefix === ''` 那一支只渲染了 `members[0]` —— 于是六个没有斜杠的通用类型
|
|
6
|
+
* (concept / metric / table / event / playbook / case)在界面上只剩第一个,
|
|
7
|
+
* 另外五个**不见了**,而且没有任何报错。这里把「摆成几行、哪几个进折叠组」
|
|
8
|
+
* 变成一个可以单独断言的纯函数:它没有 React、没有样式、没有 DOM,输入是注册表、
|
|
9
|
+
* 输出是行清单。
|
|
10
|
+
*
|
|
11
|
+
* 三条规则(都是呈现层行为,不改注册表结构、不改 `entity_type`):
|
|
12
|
+
*
|
|
13
|
+
* 1. **没有斜杠的 id 各自平铺成一行。** 它们不构成一组 —— `concept` 与 `case` 之间
|
|
14
|
+
* 除了「都没有命名空间」之外没有任何共同点,把它们折成一组只是把六个类型藏进一个
|
|
15
|
+
* 名字叫空字符串的组里。
|
|
16
|
+
* 2. **同一个前缀的成员聚成一组,组内保持类型定义顺序**,组与组按前缀第一次出现的
|
|
17
|
+
* 位置排。注册表的顺序仍然是唯一真源,这里不重排、不排序。
|
|
18
|
+
* 3. **前缀下只有一个成员时不折叠**(折成只装一项的组,多一次点击、少一次直达),
|
|
19
|
+
* 那个成员直接平铺回一级列表。
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
export interface WikiTypeGroup<T> {
|
|
23
|
+
prefix: string
|
|
24
|
+
label: string
|
|
25
|
+
/** 组内保持注册表里的定义顺序。 */
|
|
26
|
+
members: T[]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** 一行要画什么:一个平铺的类型,还是一个可折叠的组。 */
|
|
30
|
+
export type WikiTypeRow<T> =
|
|
31
|
+
| { kind: 'row'; type: T }
|
|
32
|
+
| { kind: 'group'; prefix: string; label: string; members: T[] }
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 组名默认取前缀本身 —— 只有真正需要翻译的才写进这张表。
|
|
36
|
+
*
|
|
37
|
+
* 写死五个 `diagnosis/*` 的 id 是不行的:自定义类型也允许带斜杠,
|
|
38
|
+
* `diagnosis` 前缀下的类型是可增删的。
|
|
39
|
+
*/
|
|
40
|
+
export const GROUP_LABELS: Record<string, string> = { diagnosis: '归因图谱' }
|
|
41
|
+
|
|
42
|
+
export const idPrefix = (id: string): string => {
|
|
43
|
+
const at = id.indexOf('/')
|
|
44
|
+
return at > 0 ? id.slice(0, at) : ''
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const groupLabel = (prefix: string): string => GROUP_LABELS[prefix] ?? prefix
|
|
48
|
+
|
|
49
|
+
/** 按 id 前缀把类型折成组。顺序 = 前缀第一次出现的位置。 */
|
|
50
|
+
export function groupWikiTypes<T extends { id: string }>(types: T[]): Array<WikiTypeGroup<T>> {
|
|
51
|
+
const groups: Array<WikiTypeGroup<T>> = []
|
|
52
|
+
const byPrefix = new Map<string, WikiTypeGroup<T>>()
|
|
53
|
+
for (const type of types) {
|
|
54
|
+
const prefix = idPrefix(type.id)
|
|
55
|
+
const existing = byPrefix.get(prefix)
|
|
56
|
+
if (existing) { existing.members.push(type); continue }
|
|
57
|
+
const created: WikiTypeGroup<T> = { prefix, label: groupLabel(prefix), members: [type] }
|
|
58
|
+
byPrefix.set(prefix, created)
|
|
59
|
+
groups.push(created)
|
|
60
|
+
}
|
|
61
|
+
return groups
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 类型注册表 → 界面上的行清单。
|
|
66
|
+
*
|
|
67
|
+
* **不丢任何一个类型**是它的核心承诺:`rows` 里所有 `type` 加起来必须与输入一一对应。
|
|
68
|
+
* 测试钉住了这一条(见 `tests/wiki-type-groups.test.mjs`)—— 上一次出错时
|
|
69
|
+
* 界面少了五个类型,而所有既有测试都是绿的。
|
|
70
|
+
*/
|
|
71
|
+
export function wikiTypeRows<T extends { id: string }>(types: T[]): Array<WikiTypeRow<T>> {
|
|
72
|
+
const rows: Array<WikiTypeRow<T>> = []
|
|
73
|
+
for (const group of groupWikiTypes(types)) {
|
|
74
|
+
// 没有命名空间的照旧平铺 —— **每一个成员各占一行**,不是只画第一个。
|
|
75
|
+
if (group.prefix === '') {
|
|
76
|
+
for (const type of group.members) rows.push({ kind: 'row', type })
|
|
77
|
+
continue
|
|
78
|
+
}
|
|
79
|
+
if (group.members.length === 1) {
|
|
80
|
+
rows.push({ kind: 'row', type: group.members[0]! })
|
|
81
|
+
continue
|
|
82
|
+
}
|
|
83
|
+
rows.push({ kind: 'group', prefix: group.prefix, label: group.label, members: group.members })
|
|
84
|
+
}
|
|
85
|
+
return rows
|
|
86
|
+
}
|