dsh-mega-chat-nav 0.1.1
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/LICENSE +201 -0
- package/README.en.md +149 -0
- package/README.md +149 -0
- package/cordis.patch.yml +4 -0
- package/lib/client/NavOverlay.js +35 -0
- package/lib/client/NavRail.js +12 -0
- package/lib/client/QuestionNavSettingsTab.js +26 -0
- package/lib/client/QuestionNavStrip.js +555 -0
- package/lib/client/components/ConfigPanel.js +14 -0
- package/lib/client/components/DotRail.js +62 -0
- package/lib/client/components/NavOverlay.js +121 -0
- package/lib/client/components/NavRail.js +97 -0
- package/lib/client/components/RailDispatch.js +22 -0
- package/lib/client/components/RailHost.js +79 -0
- package/lib/client/components/SearchBox.js +66 -0
- package/lib/client/components/SettingsPage.js +46 -0
- package/lib/client/components/StandaloneSettings.js +16 -0
- package/lib/client/components/codex/CodexRail.js +139 -0
- package/lib/client/components/deepseek/DeepseekRail.js +264 -0
- package/lib/client/components/minimal/MinimalRail.js +135 -0
- package/lib/client/components/minimal/cards.js +32 -0
- package/lib/client/components/minimal/dot.js +11 -0
- package/lib/client/components/minimal/hint.js +30 -0
- package/lib/client/components/minimal/paging.js +5 -0
- package/lib/client/components/minimal/quick-settings.js +28 -0
- package/lib/client/components/minimal/search.js +67 -0
- package/lib/client/components/minimal/useRail.js +716 -0
- package/lib/client/components/rail/cards.js +32 -0
- package/lib/client/components/rail/hint.js +30 -0
- package/lib/client/components/rail/paging.js +5 -0
- package/lib/client/components/rail/quick-settings.js +28 -0
- package/lib/client/components/rail/search.js +76 -0
- package/lib/client/components/rail/useRail.js +845 -0
- package/lib/client/components/settings/SettingsPage.js +46 -0
- package/lib/client/components/settings/SettingsTab.js +17 -0
- package/lib/client/components/settings/StandaloneSettings.js +16 -0
- package/lib/client/components/shared/Cascade.js +26 -0
- package/lib/client/components/shared/ConfigPanel.js +27 -0
- package/lib/client/components/shared/Dot.js +8 -0
- package/lib/client/components/shared/Hint.js +5 -0
- package/lib/client/components/shared/PagingButton.js +5 -0
- package/lib/client/components/shared/RailShell.js +78 -0
- package/lib/client/components/shared/SearchBox.js +63 -0
- package/lib/client/components/shared/hooks.js +427 -0
- package/lib/client/components/shared/types.js +1 -0
- package/lib/client/config.js +1 -0
- package/lib/client/engines/jump.js +34 -0
- package/lib/client/engines/useAtBottom.js +25 -0
- package/lib/client/engines/useJump.js +40 -0
- package/lib/client/engines/useScrollSpy.js +88 -0
- package/lib/client/hooks.js +11 -0
- package/lib/client/index.js +312 -0
- package/lib/client/jump.js +255 -0
- package/lib/client/locales.js +142 -0
- package/lib/client/pure.js +61 -0
- package/lib/client/settings.js +369 -0
- package/lib/client/virtual/VirtualList.js +21 -0
- package/lib/client.js +3213 -0
- package/lib/compat.js +145 -0
- package/lib/config.js +37 -0
- package/lib/core/active-dot.js +17 -0
- package/lib/core/align.js +9 -0
- package/lib/core/config.js +37 -0
- package/lib/core/focus.js +38 -0
- package/lib/core/jump.js +98 -0
- package/lib/core/logic/active-dot.js +16 -0
- package/lib/core/logic/focus.js +34 -0
- package/lib/core/logic/jump.js +188 -0
- package/lib/core/logic/nodes.js +59 -0
- package/lib/core/model/nav-item.js +1 -0
- package/lib/core/model/turns.js +73 -0
- package/lib/core/nav-item.js +1 -0
- package/lib/core/nodes.js +57 -0
- package/lib/core/page-size.js +7 -0
- package/lib/core/question-entry.js +1 -0
- package/lib/core/time.js +23 -0
- package/lib/core/turn-dots.js +85 -0
- package/lib/core/utils/measure.js +24 -0
- package/lib/core/utils/time.js +26 -0
- package/lib/index.js +64 -0
- package/lib/nav-item.js +1 -0
- package/lib/nodes.js +59 -0
- package/lib/projection.js +126 -0
- package/lib/schema.js +26 -0
- package/lib/search.js +285 -0
- package/lib/settings.js +89 -0
- package/lib/types/client/NavOverlay.d.ts +18 -0
- package/lib/types/client/NavRail.d.ts +7 -0
- package/lib/types/client/QuestionNavSettingsTab.d.ts +16 -0
- package/lib/types/client/QuestionNavStrip.d.ts +48 -0
- package/lib/types/client/components/ConfigPanel.d.ts +14 -0
- package/lib/types/client/components/DotRail.d.ts +15 -0
- package/lib/types/client/components/NavOverlay.d.ts +30 -0
- package/lib/types/client/components/NavRail.d.ts +16 -0
- package/lib/types/client/components/RailDispatch.d.ts +8 -0
- package/lib/types/client/components/RailHost.d.ts +27 -0
- package/lib/types/client/components/SearchBox.d.ts +9 -0
- package/lib/types/client/components/SettingsPage.d.ts +9 -0
- package/lib/types/client/components/StandaloneSettings.d.ts +13 -0
- package/lib/types/client/components/codex/CodexRail.d.ts +3 -0
- package/lib/types/client/components/deepseek/DeepseekRail.d.ts +3 -0
- package/lib/types/client/components/minimal/MinimalRail.d.ts +8 -0
- package/lib/types/client/components/minimal/cards.d.ts +19 -0
- package/lib/types/client/components/minimal/dot.d.ts +14 -0
- package/lib/types/client/components/minimal/hint.d.ts +11 -0
- package/lib/types/client/components/minimal/paging.d.ts +10 -0
- package/lib/types/client/components/minimal/quick-settings.d.ts +8 -0
- package/lib/types/client/components/minimal/search.d.ts +27 -0
- package/lib/types/client/components/minimal/useRail.d.ts +90 -0
- package/lib/types/client/components/rail/cards.d.ts +19 -0
- package/lib/types/client/components/rail/hint.d.ts +11 -0
- package/lib/types/client/components/rail/paging.d.ts +10 -0
- package/lib/types/client/components/rail/quick-settings.d.ts +8 -0
- package/lib/types/client/components/rail/search.d.ts +34 -0
- package/lib/types/client/components/rail/useRail.d.ts +132 -0
- package/lib/types/client/components/settings/SettingsPage.d.ts +9 -0
- package/lib/types/client/components/settings/SettingsTab.d.ts +6 -0
- package/lib/types/client/components/settings/StandaloneSettings.d.ts +13 -0
- package/lib/types/client/components/shared/Cascade.d.ts +14 -0
- package/lib/types/client/components/shared/ConfigPanel.d.ts +8 -0
- package/lib/types/client/components/shared/Dot.d.ts +17 -0
- package/lib/types/client/components/shared/Hint.d.ts +6 -0
- package/lib/types/client/components/shared/PagingButton.d.ts +10 -0
- package/lib/types/client/components/shared/RailShell.d.ts +43 -0
- package/lib/types/client/components/shared/SearchBox.d.ts +18 -0
- package/lib/types/client/components/shared/hooks.d.ts +64 -0
- package/lib/types/client/components/shared/types.d.ts +101 -0
- package/lib/types/client/config.d.ts +9 -0
- package/lib/types/client/engines/jump.d.ts +17 -0
- package/lib/types/client/engines/useAtBottom.d.ts +1 -0
- package/lib/types/client/engines/useJump.d.ts +16 -0
- package/lib/types/client/engines/useScrollSpy.d.ts +12 -0
- package/lib/types/client/hooks.d.ts +7 -0
- package/lib/types/client/index.d.ts +31 -0
- package/lib/types/client/jump.d.ts +47 -0
- package/lib/types/client/locales.d.ts +142 -0
- package/lib/types/client/pure.d.ts +21 -0
- package/lib/types/client/settings.d.ts +173 -0
- package/lib/types/client/virtual/VirtualList.d.ts +15 -0
- package/lib/types/compat.d.ts +44 -0
- package/lib/types/config.d.ts +44 -0
- package/lib/types/core/active-dot.d.ts +15 -0
- package/lib/types/core/align.d.ts +10 -0
- package/lib/types/core/config.d.ts +44 -0
- package/lib/types/core/focus.d.ts +24 -0
- package/lib/types/core/jump.d.ts +39 -0
- package/lib/types/core/logic/active-dot.d.ts +15 -0
- package/lib/types/core/logic/focus.d.ts +22 -0
- package/lib/types/core/logic/jump.d.ts +39 -0
- package/lib/types/core/logic/nodes.d.ts +48 -0
- package/lib/types/core/model/nav-item.d.ts +12 -0
- package/lib/types/core/model/turns.d.ts +30 -0
- package/lib/types/core/nav-item.d.ts +12 -0
- package/lib/types/core/nodes.d.ts +43 -0
- package/lib/types/core/page-size.d.ts +8 -0
- package/lib/types/core/question-entry.d.ts +12 -0
- package/lib/types/core/time.d.ts +4 -0
- package/lib/types/core/turn-dots.d.ts +29 -0
- package/lib/types/core/utils/measure.d.ts +12 -0
- package/lib/types/core/utils/time.d.ts +4 -0
- package/lib/types/index.d.ts +4 -0
- package/lib/types/nav-item.d.ts +12 -0
- package/lib/types/nodes.d.ts +48 -0
- package/lib/types/projection.d.ts +71 -0
- package/lib/types/schema.d.ts +37 -0
- package/lib/types/search.d.ts +42 -0
- package/lib/types/settings.d.ts +99 -0
- package/package.json +71 -0
- package/src/client/components/RailDispatch.tsx +27 -0
- package/src/client/components/codex/CodexRail.tsx +348 -0
- package/src/client/components/deepseek/DeepseekRail.tsx +522 -0
- package/src/client/components/minimal/MinimalRail.tsx +324 -0
- package/src/client/components/minimal/dot.tsx +32 -0
- package/src/client/components/rail/cards.tsx +102 -0
- package/src/client/components/rail/hint.tsx +50 -0
- package/src/client/components/rail/paging.tsx +26 -0
- package/src/client/components/rail/quick-settings.tsx +130 -0
- package/src/client/components/rail/search.tsx +147 -0
- package/src/client/components/rail/useRail.ts +906 -0
- package/src/client/components/settings/SettingsPage.tsx +198 -0
- package/src/client/components/settings/StandaloneSettings.tsx +28 -0
- package/src/client/components/shared/types.ts +99 -0
- package/src/client/index.ts +388 -0
- package/src/client/jump.ts +293 -0
- package/src/client/locales.ts +143 -0
- package/src/client/settings.ts +482 -0
- package/src/client/styles.css +1580 -0
- package/src/compat.ts +161 -0
- package/src/index.ts +66 -0
- package/src/projection.ts +174 -0
- package/src/search.ts +291 -0
- package/src/settings.ts +169 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mega-chat-nav 词条字典(zh/en)。注册于 `mega-chat-nav` 命名空间;
|
|
3
|
+
* key 经绑定翻译函数消费。
|
|
4
|
+
*/
|
|
5
|
+
export const zh = {
|
|
6
|
+
'strip.empty': '本会话还没有提问',
|
|
7
|
+
'strip.up': '向上翻出更多提问圆点',
|
|
8
|
+
'strip.down': '向下翻出更多提问圆点',
|
|
9
|
+
'jump.inactive': '聊天视图未激活',
|
|
10
|
+
'jump.hidden': '目标无独立气泡,已定位到邻近内容',
|
|
11
|
+
'jump.notfound': '目标未加载或不存在(可能已压缩)',
|
|
12
|
+
'jump.timeout': '加载历史超时,可重试',
|
|
13
|
+
'jump.loading': '正在加载较早记录以定位(第 {n} 页)',
|
|
14
|
+
'search.historic': '另有 {n} 条来自更早历史',
|
|
15
|
+
'search.turnTitle': '第 {turn} 轮',
|
|
16
|
+
'search.tag.user': '用户',
|
|
17
|
+
'search.tag.assistant': '助手',
|
|
18
|
+
'search.tag.tool': '工具',
|
|
19
|
+
'settings.tab': '提问导航',
|
|
20
|
+
'label': 'mega 导航',
|
|
21
|
+
'config.align': '对齐方式',
|
|
22
|
+
'config.railOffset': '导航栏偏移',
|
|
23
|
+
'config.railOffset.desc': '导航条与对话列边缘的距离(0-32px,随左右对齐自适应)。',
|
|
24
|
+
'settings.align.desc': '选择圆点导航条锚定在对话栏的哪一侧。',
|
|
25
|
+
'settings.align.left': '左侧',
|
|
26
|
+
'settings.align.right': '右侧',
|
|
27
|
+
'settings.hosted': '配置已收纳至 mega 设置中心',
|
|
28
|
+
'config.bandHeight': '节点栏高度',
|
|
29
|
+
'config.bandHeight.desc': '节点栏的最大高度。',
|
|
30
|
+
'config.bandHeight.compact': '紧凑',
|
|
31
|
+
'config.bandHeight.standard': '标准',
|
|
32
|
+
'config.bandHeight.tall': '高',
|
|
33
|
+
'config.title': '导航条设置',
|
|
34
|
+
'config.settings': '设置',
|
|
35
|
+
'config.close': '关闭',
|
|
36
|
+
'config.scrollBehavior': '跳转动画',
|
|
37
|
+
'config.scrollBehavior.desc': '点击跳转时消息滚入的动画方式。',
|
|
38
|
+
'config.scrollBehavior.smooth': '平滑',
|
|
39
|
+
'config.scrollBehavior.instant': '瞬时',
|
|
40
|
+
'config.showCount': '轮次总数',
|
|
41
|
+
'config.showPaging': '翻页标记',
|
|
42
|
+
'config.showQuickSettings': '设置按钮',
|
|
43
|
+
'config.showFavorites': '收藏按钮',
|
|
44
|
+
'config.searchScopes': '搜索内容',
|
|
45
|
+
'config.searchScopes.desc': '搜索哪些消息类型(多选;用户必选)。',
|
|
46
|
+
'config.searchScopes.user': '用户',
|
|
47
|
+
'config.searchScopes.assistant': '助手',
|
|
48
|
+
'config.searchScopes.tool': '工具',
|
|
49
|
+
'config.style': '风格',
|
|
50
|
+
'config.style.minimal': '简约',
|
|
51
|
+
'config.style.codex': 'Codex',
|
|
52
|
+
'config.style.deepseek': 'Deepseek Chat',
|
|
53
|
+
'config.cardCount': '悬停卡片数',
|
|
54
|
+
'config.cardCount.desc': '悬停节点时弹出的卡片数量(1/3/5 张)。',
|
|
55
|
+
'config.cardItems': '悬浮卡功能',
|
|
56
|
+
'config.cardItems.desc': '勾选悬浮卡显示的内容块(多选)。',
|
|
57
|
+
'config.cardItems.turn': '轮次',
|
|
58
|
+
'config.cardItems.duration': '用时',
|
|
59
|
+
'config.cardItems.favorite': '收藏',
|
|
60
|
+
'config.markTone': '刻度色调',
|
|
61
|
+
'config.markTone.desc': 'codex 刻度条的明暗档:柔和低对比 / 深邃高对比(默认)。',
|
|
62
|
+
'config.markTone.soft': '柔和',
|
|
63
|
+
'config.markTone.deep': '深邃',
|
|
64
|
+
'fav.filter': '只看收藏',
|
|
65
|
+
'strip.noFavorites': '暂无收藏',
|
|
66
|
+
'config.showSearch': '搜索按钮',
|
|
67
|
+
'config.showMode.show': '显示',
|
|
68
|
+
'config.showMode.peek': '浮现',
|
|
69
|
+
'config.showMode.hide': '隐藏',
|
|
70
|
+
'search.placeholder': '搜索消息…',
|
|
71
|
+
'search.empty': '无匹配结果',
|
|
72
|
+
'search.loading': '正在搜索…',
|
|
73
|
+
} as const
|
|
74
|
+
|
|
75
|
+
export const en = {
|
|
76
|
+
'strip.empty': 'No questions in this session yet',
|
|
77
|
+
'strip.up': 'Reveal more question dots above',
|
|
78
|
+
'strip.down': 'Reveal more question dots below',
|
|
79
|
+
'jump.inactive': 'Chat view is not active',
|
|
80
|
+
'jump.hidden': 'No dedicated bubble; landed on nearby content',
|
|
81
|
+
'jump.notfound': 'Target not loaded or missing (maybe compacted)',
|
|
82
|
+
'jump.timeout': 'Timed out loading history; retry',
|
|
83
|
+
'jump.loading': 'Loading earlier records to locate (page {n})',
|
|
84
|
+
'search.historic': '{n} more from earlier history',
|
|
85
|
+
'search.turnTitle': 'Turn {turn}',
|
|
86
|
+
'search.tag.user': 'User',
|
|
87
|
+
'search.tag.assistant': 'Assistant',
|
|
88
|
+
'search.tag.tool': 'Tool',
|
|
89
|
+
'settings.tab': 'Question Nav',
|
|
90
|
+
'label': 'Mega Nav',
|
|
91
|
+
'config.align': 'Alignment',
|
|
92
|
+
'config.railOffset': 'Rail offset',
|
|
93
|
+
'config.railOffset.desc': 'Distance between the rail and the conversation edge (0-32px, adapts to alignment).',
|
|
94
|
+
'settings.align.desc': 'Choose which edge of the conversation column the dot rail anchors to.',
|
|
95
|
+
'settings.align.left': 'Left',
|
|
96
|
+
'settings.align.right': 'Right',
|
|
97
|
+
'settings.hosted': 'Config is hosted in the mega settings center',
|
|
98
|
+
'config.bandHeight': 'Band height',
|
|
99
|
+
'config.bandHeight.desc': 'Max height of the dot band.',
|
|
100
|
+
'config.bandHeight.compact': 'Compact',
|
|
101
|
+
'config.bandHeight.standard': 'Standard',
|
|
102
|
+
'config.bandHeight.tall': 'Tall',
|
|
103
|
+
'config.title': 'Nav settings',
|
|
104
|
+
'config.settings': 'Settings',
|
|
105
|
+
'config.close': 'Close',
|
|
106
|
+
'config.scrollBehavior': 'Jump animation',
|
|
107
|
+
'config.scrollBehavior.desc': 'How the chat scrolls when jumping to a message.',
|
|
108
|
+
'config.scrollBehavior.smooth': 'Smooth',
|
|
109
|
+
'config.scrollBehavior.instant': 'Instant',
|
|
110
|
+
'config.showCount': 'Turn count',
|
|
111
|
+
'config.showPaging': 'Paging markers',
|
|
112
|
+
'config.showQuickSettings': 'Settings button',
|
|
113
|
+
'config.showFavorites': 'Favorite button',
|
|
114
|
+
'config.searchScopes': 'Search content',
|
|
115
|
+
'config.searchScopes.desc': 'Message types included in search (multi-select; user is required).',
|
|
116
|
+
'config.searchScopes.user': 'User',
|
|
117
|
+
'config.searchScopes.assistant': 'Assistant',
|
|
118
|
+
'config.searchScopes.tool': 'Tool',
|
|
119
|
+
'config.style': 'Style',
|
|
120
|
+
'config.style.minimal': 'Minimal',
|
|
121
|
+
'config.style.codex': 'Codex',
|
|
122
|
+
'config.style.deepseek': 'Deepseek Chat',
|
|
123
|
+
'config.cardCount': 'Card count',
|
|
124
|
+
'config.cardCount.desc': 'Cascade cards shown on hover (1/3/5).',
|
|
125
|
+
'config.cardItems': 'Card contents',
|
|
126
|
+
'config.cardItems.desc': 'Content blocks shown on hover cards (multi-select).',
|
|
127
|
+
'config.cardItems.turn': 'Turn',
|
|
128
|
+
'config.cardItems.duration': 'Duration',
|
|
129
|
+
'config.cardItems.favorite': 'Favorite',
|
|
130
|
+
'config.markTone': 'Mark tone',
|
|
131
|
+
'config.markTone.desc': 'Codex tick contrast: soft / deep (default).',
|
|
132
|
+
'config.markTone.soft': 'Soft',
|
|
133
|
+
'config.markTone.deep': 'Deep',
|
|
134
|
+
'fav.filter': 'Favorites only',
|
|
135
|
+
'strip.noFavorites': 'No favorites yet',
|
|
136
|
+
'config.showSearch': 'Search button',
|
|
137
|
+
'config.showMode.show': 'Show',
|
|
138
|
+
'config.showMode.peek': 'Peek',
|
|
139
|
+
'config.showMode.hide': 'Hide',
|
|
140
|
+
'search.placeholder': 'Search messages…',
|
|
141
|
+
'search.empty': 'No matches',
|
|
142
|
+
'search.loading': 'Searching…',
|
|
143
|
+
} as const
|
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser mirror of the `mega-chat-nav` settings namespace: reads the rail
|
|
3
|
+
* settings from the settings scope (`ctx.settingsScope.bind`) and routes the
|
|
4
|
+
* user's choices back through the host bridge (POST /mega-chat-nav/settings).
|
|
5
|
+
*
|
|
6
|
+
* 配置选项为本插件自有定义:此处为 client 半持有的同值副本(与 host 半
|
|
7
|
+
* src/settings.ts 一致;client bundle 不得依赖宿主包)。
|
|
8
|
+
*
|
|
9
|
+
* The settings surface is optional and may apply after this plugin, so the
|
|
10
|
+
* controller starts unbound and degrades to the defaults until {@link attach}
|
|
11
|
+
* binds the scope.
|
|
12
|
+
*
|
|
13
|
+
* @module dsh-mega-chat-nav/client/settings
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { SettingsScope, SettingsScopeSnapshot, SettingsScopeSpec } from '@deepseek-ai/dsh-client-runtime/client'
|
|
17
|
+
|
|
18
|
+
/** 风格选项:简约 / codex(时间线刻度)/ deepseek(用户消息面板,常态短横折叠) */
|
|
19
|
+
export const STYLE_OPTIONS = ['minimal', 'codex', 'deepseek'] as const
|
|
20
|
+
export type NavStyle = typeof STYLE_OPTIONS[number]
|
|
21
|
+
|
|
22
|
+
/** 停靠侧选项 */
|
|
23
|
+
export const ALIGN_OPTIONS = ['left', 'right'] as const
|
|
24
|
+
export type RailAlign = typeof ALIGN_OPTIONS[number]
|
|
25
|
+
|
|
26
|
+
/** 节点栏条带高度档位 */
|
|
27
|
+
export const BAND_OPTIONS = ['compact', 'standard', 'tall'] as const
|
|
28
|
+
export type BandHeight = typeof BAND_OPTIONS[number]
|
|
29
|
+
|
|
30
|
+
/** 跳转动画方式 */
|
|
31
|
+
export const SCROLL_OPTIONS = ['smooth', 'instant'] as const
|
|
32
|
+
export type ScrollMode = typeof SCROLL_OPTIONS[number]
|
|
33
|
+
|
|
34
|
+
/** 显示策略:常显 / 悬停浮现 / 隐藏 */
|
|
35
|
+
export const SHOW_OPTIONS = ['show', 'peek', 'hide'] as const
|
|
36
|
+
export type ShowMode = typeof SHOW_OPTIONS[number]
|
|
37
|
+
|
|
38
|
+
/** 翻页标记显示策略(按风格独立默认):minimal 常显 / codex 隐藏 / deepseek 浮现 */
|
|
39
|
+
export const DEFAULT_PAGING: Record<NavStyle, ShowMode> = {
|
|
40
|
+
minimal: 'show',
|
|
41
|
+
codex: 'hide',
|
|
42
|
+
deepseek: 'peek',
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** 搜索内容范围(多选;用户必选) */
|
|
46
|
+
export const SEARCH_SCOPE_OPTIONS = ['user', 'assistant', 'tool'] as const
|
|
47
|
+
export type SearchScope = typeof SEARCH_SCOPE_OPTIONS[number]
|
|
48
|
+
export const DEFAULT_SEARCH_SCOPES: SearchScope[] = ['user', 'assistant', 'tool']
|
|
49
|
+
|
|
50
|
+
/** 悬停卡片数量 */
|
|
51
|
+
export const CARD_OPTIONS = [1, 3, 5] as const
|
|
52
|
+
export type CardCount = typeof CARD_OPTIONS[number]
|
|
53
|
+
|
|
54
|
+
/** 悬浮卡默认数量(按风格独立):minimal 3 张 / codex 1 张 / deepseek 1 张(无悬浮卡能力,占位) */
|
|
55
|
+
export const DEFAULT_CARD_COUNT: Record<NavStyle, CardCount> = {
|
|
56
|
+
minimal: 3,
|
|
57
|
+
codex: 1,
|
|
58
|
+
deepseek: 1,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** 悬浮卡内容块(多选) */
|
|
62
|
+
export const CARD_ITEM_OPTIONS = ['turn', 'duration', 'favorite'] as const
|
|
63
|
+
export type CardItem = typeof CARD_ITEM_OPTIONS[number]
|
|
64
|
+
export const DEFAULT_CARD_ITEMS: CardItem[] = ['turn', 'duration', 'favorite']
|
|
65
|
+
|
|
66
|
+
/** 刻度色调:柔和(低对比)/ 深邃(高对比、清晰) */
|
|
67
|
+
export const MARK_TONE_OPTIONS = ['soft', 'deep'] as const
|
|
68
|
+
export type MarkTone = typeof MARK_TONE_OPTIONS[number]
|
|
69
|
+
export const DEFAULT_MARK_TONE: MarkTone = 'deep'
|
|
70
|
+
|
|
71
|
+
export const DEFAULT_STYLE: NavStyle = 'minimal'
|
|
72
|
+
export const DEFAULT_ALIGN: RailAlign = 'left'
|
|
73
|
+
export const DEFAULT_BAND: BandHeight = 'standard'
|
|
74
|
+
export const DEFAULT_SCROLL: ScrollMode = 'smooth'
|
|
75
|
+
export const DEFAULT_SHOW: ShowMode = 'show'
|
|
76
|
+
|
|
77
|
+
/** 条带高度档位 → 像素(minimal/codex 共用基础几何;deepseek 行高 30px 自成一档)
|
|
78
|
+
* - minimal / codex:compact 140 / standard 210 / tall 280
|
|
79
|
+
* - deepseek:compact 160 / standard 220 / tall 280 */
|
|
80
|
+
export const BAND_HEIGHT_PX: Record<NavStyle, Record<BandHeight, number>> = {
|
|
81
|
+
minimal: { compact: 144, standard: 204, tall: 274 },
|
|
82
|
+
codex: { compact: 140, standard: 210, tall: 280 },
|
|
83
|
+
deepseek: { compact: 160, standard: 220, tall: 280 },
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** 风格能力:各风格声明自己的可选能力(组件与设置面据此取舍) */
|
|
87
|
+
export interface StyleCapabilities {
|
|
88
|
+
/** 悬停悬浮卡片(级联预览)——deepseek 面板自带消息预览,不需要 */
|
|
89
|
+
hoverCards: boolean
|
|
90
|
+
/** ▲/▼ 翻页标志(deepseek 面板内滚动,不需要显式翻页按钮) */
|
|
91
|
+
paging: boolean
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** 风格 → 能力表 */
|
|
95
|
+
export const STYLE_CAPABILITIES: Record<NavStyle, StyleCapabilities> = {
|
|
96
|
+
minimal: { hoverCards: true, paging: true },
|
|
97
|
+
codex: { hoverCards: true, paging: true },
|
|
98
|
+
deepseek: { hoverCards: false, paging: false },
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** 本插件设置命名空间 */
|
|
102
|
+
export const MGCN_NS = 'mega-chat-nav'
|
|
103
|
+
|
|
104
|
+
/** 导航栏偏移(px)范围与默认值 */
|
|
105
|
+
export const RAIL_OFFSET_MIN = 0
|
|
106
|
+
export const RAIL_OFFSET_MAX = 32
|
|
107
|
+
export const DEFAULT_RAIL_OFFSET = 8
|
|
108
|
+
|
|
109
|
+
/** Narrow a raw section value to the anchor field. */
|
|
110
|
+
function isRailAlign(value: unknown): value is RailAlign {
|
|
111
|
+
return (ALIGN_OPTIONS as readonly unknown[]).includes(value)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Narrow a raw section value to the style field. */
|
|
115
|
+
function isNavStyle(value: unknown): value is NavStyle {
|
|
116
|
+
return (STYLE_OPTIONS as readonly unknown[]).includes(value)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** 兼容旧 boolean 配置:true → show,false → hide;新值走枚举校验 */
|
|
120
|
+
function coerceShowMode(value: unknown): ShowMode {
|
|
121
|
+
if (typeof value === 'boolean') return value ? 'show' : 'hide'
|
|
122
|
+
return isShowMode(value) ? value : DEFAULT_SHOW
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** 翻页标记显示模式转换(默认按风格:minimal show / codex hide) */
|
|
126
|
+
function coercePagingMode(value: unknown, fallback: ShowMode): ShowMode {
|
|
127
|
+
if (typeof value === 'boolean') return value ? 'show' : 'hide'
|
|
128
|
+
return isShowMode(value) ? value : fallback
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function isShowMode(value: unknown): value is ShowMode {
|
|
132
|
+
return (SHOW_OPTIONS as readonly unknown[]).includes(value)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function isCardCount(value: unknown): value is CardCount {
|
|
136
|
+
return (CARD_OPTIONS as readonly unknown[]).includes(value)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function isBandHeight(value: unknown): value is BandHeight {
|
|
140
|
+
return (BAND_OPTIONS as readonly unknown[]).includes(value)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function isSearchScopes(value: unknown): value is SearchScope[] {
|
|
144
|
+
return Array.isArray(value)
|
|
145
|
+
&& value.every((s) => (SEARCH_SCOPE_OPTIONS as readonly unknown[]).includes(s))
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function isCardItems(value: unknown): value is CardItem[] {
|
|
149
|
+
return Array.isArray(value)
|
|
150
|
+
&& value.every((item) => (CARD_ITEM_OPTIONS as readonly unknown[]).includes(item))
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function isMarkTone(value: unknown): value is MarkTone {
|
|
154
|
+
return (MARK_TONE_OPTIONS as readonly unknown[]).includes(value)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function isScrollMode(value: unknown): value is ScrollMode {
|
|
158
|
+
return (SCROLL_OPTIONS as readonly unknown[]).includes(value)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** The minimal face of the settings scope service this controller needs. */
|
|
162
|
+
export interface SettingsScopeBinderLike {
|
|
163
|
+
bind<T>(spec: SettingsScopeSpec<T>): SettingsScope<T>
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** 单风格 wire 段(每风格独立;字段同 host schema) */
|
|
167
|
+
interface StyleWireSection {
|
|
168
|
+
bandHeight?: unknown
|
|
169
|
+
cardCount?: unknown
|
|
170
|
+
cardItems?: unknown
|
|
171
|
+
markTone?: unknown
|
|
172
|
+
showPaging?: unknown
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Wire section this plugin owns (the Host schema's fields). */
|
|
176
|
+
interface NavSettingsSection {
|
|
177
|
+
general?: {
|
|
178
|
+
style?: unknown
|
|
179
|
+
align?: unknown
|
|
180
|
+
scrollBehavior?: unknown
|
|
181
|
+
showCount?: unknown
|
|
182
|
+
showSearch?: unknown
|
|
183
|
+
showQuickSettings?: unknown
|
|
184
|
+
showFavorites?: unknown
|
|
185
|
+
searchScopes?: unknown
|
|
186
|
+
railOffset?: unknown
|
|
187
|
+
}
|
|
188
|
+
styles?: Partial<Record<NavStyle, StyleWireSection>>
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Snapshot consumed by the strip and the settings rows. */
|
|
192
|
+
export interface NavSettingsState {
|
|
193
|
+
/** Last accepted style. */
|
|
194
|
+
style: NavStyle
|
|
195
|
+
/** Last accepted anchor edge (default while the scope is absent/loading). */
|
|
196
|
+
align: RailAlign
|
|
197
|
+
/** Last accepted band height tier. */
|
|
198
|
+
bandHeight: BandHeight
|
|
199
|
+
/** Last accepted jump scroll mode. */
|
|
200
|
+
scrollBehavior: ScrollMode
|
|
201
|
+
/** Turn-count badge display mode. */
|
|
202
|
+
showCount: ShowMode
|
|
203
|
+
/** Search button display mode. */
|
|
204
|
+
showSearch: ShowMode
|
|
205
|
+
/** Quick settings gear display mode. */
|
|
206
|
+
showQuickSettings: ShowMode
|
|
207
|
+
/** Favorite filter button display mode. */
|
|
208
|
+
showFavorites: ShowMode
|
|
209
|
+
/** 翻页标记显示模式(show=常显 / peek=浮现 / hide=隐藏) */
|
|
210
|
+
showPaging: ShowMode
|
|
211
|
+
/** 搜索内容范围(多选;用户必选) */
|
|
212
|
+
searchScopes: SearchScope[]
|
|
213
|
+
/** 导航栏偏移距离(px,随左右对齐自适应) */
|
|
214
|
+
railOffset: number
|
|
215
|
+
/** Hover cascade card count. */
|
|
216
|
+
cardCount: CardCount
|
|
217
|
+
/** 悬浮卡内容块(多选:轮次 / 用时 / 收藏) */
|
|
218
|
+
cardItems: CardItem[]
|
|
219
|
+
/** 刻度色调(codex 刻度轨;minimal 忽略) */
|
|
220
|
+
markTone: MarkTone
|
|
221
|
+
/** Whether the user layer overrides the composition default. */
|
|
222
|
+
overridden: boolean
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** Reactive handle over the plugin's durable settings section. */
|
|
226
|
+
export class NavSettingsController {
|
|
227
|
+
private scope: SettingsScope<NavSettingsSection> | undefined
|
|
228
|
+
private readonly listeners = new Set<() => void>()
|
|
229
|
+
private unsubscribe: () => void = () => {}
|
|
230
|
+
private state: NavSettingsState = {
|
|
231
|
+
style: DEFAULT_STYLE,
|
|
232
|
+
align: DEFAULT_ALIGN,
|
|
233
|
+
bandHeight: DEFAULT_BAND,
|
|
234
|
+
scrollBehavior: DEFAULT_SCROLL,
|
|
235
|
+
showCount: DEFAULT_SHOW,
|
|
236
|
+
showSearch: DEFAULT_SHOW,
|
|
237
|
+
showQuickSettings: DEFAULT_SHOW,
|
|
238
|
+
showFavorites: DEFAULT_SHOW,
|
|
239
|
+
showPaging: DEFAULT_PAGING.minimal,
|
|
240
|
+
searchScopes: [...DEFAULT_SEARCH_SCOPES],
|
|
241
|
+
railOffset: DEFAULT_RAIL_OFFSET,
|
|
242
|
+
cardCount: DEFAULT_CARD_COUNT[DEFAULT_STYLE],
|
|
243
|
+
cardItems: [...DEFAULT_CARD_ITEMS],
|
|
244
|
+
markTone: DEFAULT_MARK_TONE,
|
|
245
|
+
overridden: false,
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Bind the namespace scope once the settings surface is present.
|
|
250
|
+
* A no-op after the first bind.
|
|
251
|
+
*/
|
|
252
|
+
attach(binder: SettingsScopeBinderLike): void {
|
|
253
|
+
if (this.scope !== undefined) return
|
|
254
|
+
this.scope = binder.bind<NavSettingsSection>({ namespace: MGCN_NS })
|
|
255
|
+
this.state = this.derive(this.scope.getSnapshot())
|
|
256
|
+
this.unsubscribe = this.scope.subscribe(() => {
|
|
257
|
+
if (this.scope === undefined) return
|
|
258
|
+
const next = this.derive(this.scope.getSnapshot())
|
|
259
|
+
if (next.style === this.state.style
|
|
260
|
+
&& next.align === this.state.align && next.bandHeight === this.state.bandHeight
|
|
261
|
+
&& next.cardCount === this.state.cardCount
|
|
262
|
+
&& next.scrollBehavior === this.state.scrollBehavior
|
|
263
|
+
&& next.showCount === this.state.showCount
|
|
264
|
+
&& next.showSearch === this.state.showSearch
|
|
265
|
+
&& next.showQuickSettings === this.state.showQuickSettings
|
|
266
|
+
&& next.overridden === this.state.overridden) return
|
|
267
|
+
this.state = next
|
|
268
|
+
for (const listener of this.listeners) listener()
|
|
269
|
+
})
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** 当前生效风格的 styles.<style> 段(快照内读取,供逐风格独立取值) */
|
|
273
|
+
private styleSection(snapshot: SettingsScopeSnapshot<NavSettingsSection>, style: NavStyle): StyleWireSection | undefined {
|
|
274
|
+
return snapshot.value?.styles?.[style]
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private derive(snapshot: SettingsScopeSnapshot<NavSettingsSection>): NavSettingsState {
|
|
278
|
+
const user = snapshot.user as NavSettingsSection | undefined
|
|
279
|
+
const general = snapshot.value?.general
|
|
280
|
+
const ready = snapshot.status === 'ready'
|
|
281
|
+
const style = ready && isNavStyle(general?.style) ? general.style : DEFAULT_STYLE
|
|
282
|
+
const active = this.styleSection(snapshot, style)
|
|
283
|
+
return {
|
|
284
|
+
style,
|
|
285
|
+
align: ready && isRailAlign(general?.align) ? general.align : DEFAULT_ALIGN,
|
|
286
|
+
bandHeight: ready && isBandHeight(active?.bandHeight) ? active.bandHeight : DEFAULT_BAND,
|
|
287
|
+
cardCount: ready && isCardCount(active?.cardCount) ? active.cardCount : DEFAULT_CARD_COUNT[style],
|
|
288
|
+
cardItems: ready && isCardItems(active?.cardItems) ? active.cardItems : [...DEFAULT_CARD_ITEMS],
|
|
289
|
+
markTone: ready && isMarkTone(active?.markTone) ? active.markTone : DEFAULT_MARK_TONE,
|
|
290
|
+
scrollBehavior: ready && isScrollMode(general?.scrollBehavior) ? general.scrollBehavior : DEFAULT_SCROLL,
|
|
291
|
+
showCount: ready ? coerceShowMode(general?.showCount) : DEFAULT_SHOW,
|
|
292
|
+
showSearch: ready ? coerceShowMode(general?.showSearch) : DEFAULT_SHOW,
|
|
293
|
+
showQuickSettings: ready ? coerceShowMode(general?.showQuickSettings) : DEFAULT_SHOW,
|
|
294
|
+
showFavorites: ready ? coerceShowMode(general?.showFavorites) : DEFAULT_SHOW,
|
|
295
|
+
showPaging: ready ? coercePagingMode(active?.showPaging, DEFAULT_PAGING[style]) : DEFAULT_PAGING[style],
|
|
296
|
+
searchScopes: ready && isSearchScopes(general?.searchScopes) ? general.searchScopes : [...DEFAULT_SEARCH_SCOPES],
|
|
297
|
+
railOffset: ready && typeof general?.railOffset === 'number' && general.railOffset >= 0 && general.railOffset <= 32
|
|
298
|
+
? Math.round(general.railOffset)
|
|
299
|
+
: DEFAULT_RAIL_OFFSET,
|
|
300
|
+
overridden: user !== undefined && (user.general !== undefined || user.styles !== undefined),
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** Release the scope subscription. */
|
|
305
|
+
dispose(): void {
|
|
306
|
+
this.unsubscribe()
|
|
307
|
+
this.listeners.clear()
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/** 乐观提交:更新状态并立即通知(UI 即时反映) */
|
|
311
|
+
private commit(next: NavSettingsState): void {
|
|
312
|
+
this.state = next
|
|
313
|
+
for (const listener of this.listeners) listener()
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** 当前 general 段(setter 整段写回用) */
|
|
317
|
+
private get general(): NavSettingsSection['general'] {
|
|
318
|
+
return {
|
|
319
|
+
style: this.state.style,
|
|
320
|
+
align: this.state.align,
|
|
321
|
+
scrollBehavior: this.state.scrollBehavior,
|
|
322
|
+
showCount: this.state.showCount,
|
|
323
|
+
showSearch: this.state.showSearch,
|
|
324
|
+
showQuickSettings: this.state.showQuickSettings,
|
|
325
|
+
showFavorites: this.state.showFavorites,
|
|
326
|
+
searchScopes: this.state.searchScopes,
|
|
327
|
+
railOffset: this.state.railOffset,
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** 当前风格段的完整值(setter 局部 patch 的基础) */
|
|
332
|
+
private get styleValues(): { bandHeight: BandHeight; cardCount: CardCount; cardItems: CardItem[]; markTone: MarkTone; showPaging: ShowMode } {
|
|
333
|
+
return {
|
|
334
|
+
bandHeight: this.state.bandHeight,
|
|
335
|
+
cardCount: this.state.cardCount,
|
|
336
|
+
cardItems: this.state.cardItems,
|
|
337
|
+
markTone: this.state.markTone,
|
|
338
|
+
showPaging: this.state.showPaging,
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** 按当前风格构造 write 的 styles 段(只含当前风格键,绝不染指其他风格段) */
|
|
343
|
+
private stylePatch(extra: Partial<StyleWireSection>): NavSettingsSection['styles'] {
|
|
344
|
+
const section = { ...this.styleValues, ...extra }
|
|
345
|
+
const patch: Partial<Record<NavStyle, StyleWireSection>> = {}
|
|
346
|
+
patch[this.state.style] = section
|
|
347
|
+
return patch
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/** @returns the current state (stable reference until the next change). */
|
|
351
|
+
getSnapshot(): NavSettingsState {
|
|
352
|
+
return this.state
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/** Observe state replacements; returns the disposer. */
|
|
356
|
+
subscribe(listener: () => void): () => void {
|
|
357
|
+
this.listeners.add(listener)
|
|
358
|
+
return () => { this.listeners.delete(listener) }
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* 写回宿主:scope.set 契约只接受 section 内**标量**字段,嵌套 section
|
|
363
|
+
* (general/styles 对象)无法经它持久化,所以走 host 桥
|
|
364
|
+
* (POST /mega-chat-nav/settings → settings.update 深层 merge + revision 围栏)。
|
|
365
|
+
*/
|
|
366
|
+
private write(patch: NavSettingsSection): void {
|
|
367
|
+
if (this.scope === undefined) return
|
|
368
|
+
const revision = this.scope.getSnapshot().revision
|
|
369
|
+
void fetch('/mega-chat-nav/settings', {
|
|
370
|
+
method: 'POST',
|
|
371
|
+
headers: { 'Content-Type': 'application/json' },
|
|
372
|
+
body: JSON.stringify({ patch, revision: revision ?? undefined }),
|
|
373
|
+
})
|
|
374
|
+
.then((resp) => resp.json().catch(() => ({})) as Promise<{ ok?: boolean }>)
|
|
375
|
+
.then((data) => {
|
|
376
|
+
if (!data.ok) console.error('[mega-chat-nav] settings write rejected')
|
|
377
|
+
})
|
|
378
|
+
.catch((e: unknown) => console.error('[mega-chat-nav] settings write failed:', e))
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/** Route the user's anchor-edge choice to the Host document. */
|
|
382
|
+
setAlign(align: RailAlign): void {
|
|
383
|
+
if (this.scope === undefined) return
|
|
384
|
+
this.commit({ ...this.state, align })
|
|
385
|
+
this.write({ general: { ...this.general, align } })
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/** Route the user's style choice to the Host document(切换后随即载入该风格自己的独立配置) */
|
|
389
|
+
setStyle(style: NavStyle): void {
|
|
390
|
+
if (this.scope === undefined) return
|
|
391
|
+
const snapshot = this.scope.getSnapshot()
|
|
392
|
+
const next = this.derive({ ...snapshot, value: { ...snapshot.value, general: { ...snapshot.value?.general, style } } })
|
|
393
|
+
this.commit({ ...next, overridden: this.state.overridden })
|
|
394
|
+
this.write({ general: { ...this.general, style } })
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/** Route the user's band-height choice to the Host document(写入当前风格的独立段) */
|
|
398
|
+
setBandHeight(band: BandHeight): void {
|
|
399
|
+
if (this.scope === undefined) return
|
|
400
|
+
this.commit({ ...this.state, bandHeight: band })
|
|
401
|
+
this.write({ styles: this.stylePatch({ bandHeight: band }) })
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/** Route the user's scroll-mode choice to the Host document. */
|
|
405
|
+
setScrollMode(mode: ScrollMode): void {
|
|
406
|
+
if (this.scope === undefined) return
|
|
407
|
+
this.commit({ ...this.state, scrollBehavior: mode })
|
|
408
|
+
this.write({ general: { ...this.general, scrollBehavior: mode } })
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/** Route the user's count-badge display mode to the Host document. */
|
|
412
|
+
setShowCount(mode: ShowMode): void {
|
|
413
|
+
if (this.scope === undefined) return
|
|
414
|
+
this.commit({ ...this.state, showCount: mode })
|
|
415
|
+
this.write({ general: { ...this.general, showCount: mode } })
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/** Route the user's search-button display mode to the Host document. */
|
|
419
|
+
setShowSearch(mode: ShowMode): void {
|
|
420
|
+
if (this.scope === undefined) return
|
|
421
|
+
this.commit({ ...this.state, showSearch: mode })
|
|
422
|
+
this.write({ general: { ...this.general, showSearch: mode } })
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Route the user's quick-settings display mode to the Host document. */
|
|
426
|
+
setShowQuickSettings(mode: ShowMode): void {
|
|
427
|
+
if (this.scope === undefined) return
|
|
428
|
+
this.commit({ ...this.state, showQuickSettings: mode })
|
|
429
|
+
this.write({ general: { ...this.general, showQuickSettings: mode } })
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/** Route the user's favorite-button display mode to the Host document. */
|
|
433
|
+
setShowFavorites(mode: ShowMode): void {
|
|
434
|
+
if (this.scope === undefined) return
|
|
435
|
+
this.commit({ ...this.state, showFavorites: mode })
|
|
436
|
+
this.write({ general: { ...this.general, showFavorites: mode } })
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/** Route the user's paging-marker display mode to the Host document(写入当前风格独立段) */
|
|
440
|
+
setShowPaging(mode: ShowMode): void {
|
|
441
|
+
if (this.scope === undefined) return
|
|
442
|
+
this.commit({ ...this.state, showPaging: mode })
|
|
443
|
+
this.write({ styles: this.stylePatch({ showPaging: mode }) })
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/** Route the user's search-scope selection to the Host document(用户必选,强制保留且置于首位) */
|
|
447
|
+
setSearchScopes(scopes: SearchScope[]): void {
|
|
448
|
+
if (this.scope === undefined) return
|
|
449
|
+
const normalized = ['user' as SearchScope, ...scopes.filter((s) => s !== 'user')]
|
|
450
|
+
this.commit({ ...this.state, searchScopes: normalized })
|
|
451
|
+
this.write({ general: { ...this.general, searchScopes: normalized } })
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/** Route the user's rail-offset choice to the Host document(0-32px 取整钳制) */
|
|
455
|
+
setRailOffset(offset: number): void {
|
|
456
|
+
if (this.scope === undefined) return
|
|
457
|
+
const clamped = Math.max(RAIL_OFFSET_MIN, Math.min(RAIL_OFFSET_MAX, Math.round(offset)))
|
|
458
|
+
this.commit({ ...this.state, railOffset: clamped })
|
|
459
|
+
this.write({ general: { ...this.general, railOffset: clamped } })
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/** Route the user's cascade-card count to the Host document(写入当前风格的独立段) */
|
|
463
|
+
setCardCount(count: CardCount): void {
|
|
464
|
+
if (this.scope === undefined) return
|
|
465
|
+
this.commit({ ...this.state, cardCount: count })
|
|
466
|
+
this.write({ styles: this.stylePatch({ cardCount: count }) })
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/** Route the user's card-content selection to the Host document(写入当前风格的独立段) */
|
|
470
|
+
setCardItems(items: CardItem[]): void {
|
|
471
|
+
if (this.scope === undefined) return
|
|
472
|
+
this.commit({ ...this.state, cardItems: items })
|
|
473
|
+
this.write({ styles: this.stylePatch({ cardItems: items }) })
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/** Route the user's mark-tone choice to the Host document(codex 刻度色调;写入当前风格段) */
|
|
477
|
+
setMarkTone(tone: MarkTone): void {
|
|
478
|
+
if (this.scope === undefined) return
|
|
479
|
+
this.commit({ ...this.state, markTone: tone })
|
|
480
|
+
this.write({ styles: this.stylePatch({ markTone: tone }) })
|
|
481
|
+
}
|
|
482
|
+
}
|