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.
Files changed (192) hide show
  1. package/LICENSE +201 -0
  2. package/README.en.md +149 -0
  3. package/README.md +149 -0
  4. package/cordis.patch.yml +4 -0
  5. package/lib/client/NavOverlay.js +35 -0
  6. package/lib/client/NavRail.js +12 -0
  7. package/lib/client/QuestionNavSettingsTab.js +26 -0
  8. package/lib/client/QuestionNavStrip.js +555 -0
  9. package/lib/client/components/ConfigPanel.js +14 -0
  10. package/lib/client/components/DotRail.js +62 -0
  11. package/lib/client/components/NavOverlay.js +121 -0
  12. package/lib/client/components/NavRail.js +97 -0
  13. package/lib/client/components/RailDispatch.js +22 -0
  14. package/lib/client/components/RailHost.js +79 -0
  15. package/lib/client/components/SearchBox.js +66 -0
  16. package/lib/client/components/SettingsPage.js +46 -0
  17. package/lib/client/components/StandaloneSettings.js +16 -0
  18. package/lib/client/components/codex/CodexRail.js +139 -0
  19. package/lib/client/components/deepseek/DeepseekRail.js +264 -0
  20. package/lib/client/components/minimal/MinimalRail.js +135 -0
  21. package/lib/client/components/minimal/cards.js +32 -0
  22. package/lib/client/components/minimal/dot.js +11 -0
  23. package/lib/client/components/minimal/hint.js +30 -0
  24. package/lib/client/components/minimal/paging.js +5 -0
  25. package/lib/client/components/minimal/quick-settings.js +28 -0
  26. package/lib/client/components/minimal/search.js +67 -0
  27. package/lib/client/components/minimal/useRail.js +716 -0
  28. package/lib/client/components/rail/cards.js +32 -0
  29. package/lib/client/components/rail/hint.js +30 -0
  30. package/lib/client/components/rail/paging.js +5 -0
  31. package/lib/client/components/rail/quick-settings.js +28 -0
  32. package/lib/client/components/rail/search.js +76 -0
  33. package/lib/client/components/rail/useRail.js +845 -0
  34. package/lib/client/components/settings/SettingsPage.js +46 -0
  35. package/lib/client/components/settings/SettingsTab.js +17 -0
  36. package/lib/client/components/settings/StandaloneSettings.js +16 -0
  37. package/lib/client/components/shared/Cascade.js +26 -0
  38. package/lib/client/components/shared/ConfigPanel.js +27 -0
  39. package/lib/client/components/shared/Dot.js +8 -0
  40. package/lib/client/components/shared/Hint.js +5 -0
  41. package/lib/client/components/shared/PagingButton.js +5 -0
  42. package/lib/client/components/shared/RailShell.js +78 -0
  43. package/lib/client/components/shared/SearchBox.js +63 -0
  44. package/lib/client/components/shared/hooks.js +427 -0
  45. package/lib/client/components/shared/types.js +1 -0
  46. package/lib/client/config.js +1 -0
  47. package/lib/client/engines/jump.js +34 -0
  48. package/lib/client/engines/useAtBottom.js +25 -0
  49. package/lib/client/engines/useJump.js +40 -0
  50. package/lib/client/engines/useScrollSpy.js +88 -0
  51. package/lib/client/hooks.js +11 -0
  52. package/lib/client/index.js +312 -0
  53. package/lib/client/jump.js +255 -0
  54. package/lib/client/locales.js +142 -0
  55. package/lib/client/pure.js +61 -0
  56. package/lib/client/settings.js +369 -0
  57. package/lib/client/virtual/VirtualList.js +21 -0
  58. package/lib/client.js +3213 -0
  59. package/lib/compat.js +145 -0
  60. package/lib/config.js +37 -0
  61. package/lib/core/active-dot.js +17 -0
  62. package/lib/core/align.js +9 -0
  63. package/lib/core/config.js +37 -0
  64. package/lib/core/focus.js +38 -0
  65. package/lib/core/jump.js +98 -0
  66. package/lib/core/logic/active-dot.js +16 -0
  67. package/lib/core/logic/focus.js +34 -0
  68. package/lib/core/logic/jump.js +188 -0
  69. package/lib/core/logic/nodes.js +59 -0
  70. package/lib/core/model/nav-item.js +1 -0
  71. package/lib/core/model/turns.js +73 -0
  72. package/lib/core/nav-item.js +1 -0
  73. package/lib/core/nodes.js +57 -0
  74. package/lib/core/page-size.js +7 -0
  75. package/lib/core/question-entry.js +1 -0
  76. package/lib/core/time.js +23 -0
  77. package/lib/core/turn-dots.js +85 -0
  78. package/lib/core/utils/measure.js +24 -0
  79. package/lib/core/utils/time.js +26 -0
  80. package/lib/index.js +64 -0
  81. package/lib/nav-item.js +1 -0
  82. package/lib/nodes.js +59 -0
  83. package/lib/projection.js +126 -0
  84. package/lib/schema.js +26 -0
  85. package/lib/search.js +285 -0
  86. package/lib/settings.js +89 -0
  87. package/lib/types/client/NavOverlay.d.ts +18 -0
  88. package/lib/types/client/NavRail.d.ts +7 -0
  89. package/lib/types/client/QuestionNavSettingsTab.d.ts +16 -0
  90. package/lib/types/client/QuestionNavStrip.d.ts +48 -0
  91. package/lib/types/client/components/ConfigPanel.d.ts +14 -0
  92. package/lib/types/client/components/DotRail.d.ts +15 -0
  93. package/lib/types/client/components/NavOverlay.d.ts +30 -0
  94. package/lib/types/client/components/NavRail.d.ts +16 -0
  95. package/lib/types/client/components/RailDispatch.d.ts +8 -0
  96. package/lib/types/client/components/RailHost.d.ts +27 -0
  97. package/lib/types/client/components/SearchBox.d.ts +9 -0
  98. package/lib/types/client/components/SettingsPage.d.ts +9 -0
  99. package/lib/types/client/components/StandaloneSettings.d.ts +13 -0
  100. package/lib/types/client/components/codex/CodexRail.d.ts +3 -0
  101. package/lib/types/client/components/deepseek/DeepseekRail.d.ts +3 -0
  102. package/lib/types/client/components/minimal/MinimalRail.d.ts +8 -0
  103. package/lib/types/client/components/minimal/cards.d.ts +19 -0
  104. package/lib/types/client/components/minimal/dot.d.ts +14 -0
  105. package/lib/types/client/components/minimal/hint.d.ts +11 -0
  106. package/lib/types/client/components/minimal/paging.d.ts +10 -0
  107. package/lib/types/client/components/minimal/quick-settings.d.ts +8 -0
  108. package/lib/types/client/components/minimal/search.d.ts +27 -0
  109. package/lib/types/client/components/minimal/useRail.d.ts +90 -0
  110. package/lib/types/client/components/rail/cards.d.ts +19 -0
  111. package/lib/types/client/components/rail/hint.d.ts +11 -0
  112. package/lib/types/client/components/rail/paging.d.ts +10 -0
  113. package/lib/types/client/components/rail/quick-settings.d.ts +8 -0
  114. package/lib/types/client/components/rail/search.d.ts +34 -0
  115. package/lib/types/client/components/rail/useRail.d.ts +132 -0
  116. package/lib/types/client/components/settings/SettingsPage.d.ts +9 -0
  117. package/lib/types/client/components/settings/SettingsTab.d.ts +6 -0
  118. package/lib/types/client/components/settings/StandaloneSettings.d.ts +13 -0
  119. package/lib/types/client/components/shared/Cascade.d.ts +14 -0
  120. package/lib/types/client/components/shared/ConfigPanel.d.ts +8 -0
  121. package/lib/types/client/components/shared/Dot.d.ts +17 -0
  122. package/lib/types/client/components/shared/Hint.d.ts +6 -0
  123. package/lib/types/client/components/shared/PagingButton.d.ts +10 -0
  124. package/lib/types/client/components/shared/RailShell.d.ts +43 -0
  125. package/lib/types/client/components/shared/SearchBox.d.ts +18 -0
  126. package/lib/types/client/components/shared/hooks.d.ts +64 -0
  127. package/lib/types/client/components/shared/types.d.ts +101 -0
  128. package/lib/types/client/config.d.ts +9 -0
  129. package/lib/types/client/engines/jump.d.ts +17 -0
  130. package/lib/types/client/engines/useAtBottom.d.ts +1 -0
  131. package/lib/types/client/engines/useJump.d.ts +16 -0
  132. package/lib/types/client/engines/useScrollSpy.d.ts +12 -0
  133. package/lib/types/client/hooks.d.ts +7 -0
  134. package/lib/types/client/index.d.ts +31 -0
  135. package/lib/types/client/jump.d.ts +47 -0
  136. package/lib/types/client/locales.d.ts +142 -0
  137. package/lib/types/client/pure.d.ts +21 -0
  138. package/lib/types/client/settings.d.ts +173 -0
  139. package/lib/types/client/virtual/VirtualList.d.ts +15 -0
  140. package/lib/types/compat.d.ts +44 -0
  141. package/lib/types/config.d.ts +44 -0
  142. package/lib/types/core/active-dot.d.ts +15 -0
  143. package/lib/types/core/align.d.ts +10 -0
  144. package/lib/types/core/config.d.ts +44 -0
  145. package/lib/types/core/focus.d.ts +24 -0
  146. package/lib/types/core/jump.d.ts +39 -0
  147. package/lib/types/core/logic/active-dot.d.ts +15 -0
  148. package/lib/types/core/logic/focus.d.ts +22 -0
  149. package/lib/types/core/logic/jump.d.ts +39 -0
  150. package/lib/types/core/logic/nodes.d.ts +48 -0
  151. package/lib/types/core/model/nav-item.d.ts +12 -0
  152. package/lib/types/core/model/turns.d.ts +30 -0
  153. package/lib/types/core/nav-item.d.ts +12 -0
  154. package/lib/types/core/nodes.d.ts +43 -0
  155. package/lib/types/core/page-size.d.ts +8 -0
  156. package/lib/types/core/question-entry.d.ts +12 -0
  157. package/lib/types/core/time.d.ts +4 -0
  158. package/lib/types/core/turn-dots.d.ts +29 -0
  159. package/lib/types/core/utils/measure.d.ts +12 -0
  160. package/lib/types/core/utils/time.d.ts +4 -0
  161. package/lib/types/index.d.ts +4 -0
  162. package/lib/types/nav-item.d.ts +12 -0
  163. package/lib/types/nodes.d.ts +48 -0
  164. package/lib/types/projection.d.ts +71 -0
  165. package/lib/types/schema.d.ts +37 -0
  166. package/lib/types/search.d.ts +42 -0
  167. package/lib/types/settings.d.ts +99 -0
  168. package/package.json +71 -0
  169. package/src/client/components/RailDispatch.tsx +27 -0
  170. package/src/client/components/codex/CodexRail.tsx +348 -0
  171. package/src/client/components/deepseek/DeepseekRail.tsx +522 -0
  172. package/src/client/components/minimal/MinimalRail.tsx +324 -0
  173. package/src/client/components/minimal/dot.tsx +32 -0
  174. package/src/client/components/rail/cards.tsx +102 -0
  175. package/src/client/components/rail/hint.tsx +50 -0
  176. package/src/client/components/rail/paging.tsx +26 -0
  177. package/src/client/components/rail/quick-settings.tsx +130 -0
  178. package/src/client/components/rail/search.tsx +147 -0
  179. package/src/client/components/rail/useRail.ts +906 -0
  180. package/src/client/components/settings/SettingsPage.tsx +198 -0
  181. package/src/client/components/settings/StandaloneSettings.tsx +28 -0
  182. package/src/client/components/shared/types.ts +99 -0
  183. package/src/client/index.ts +388 -0
  184. package/src/client/jump.ts +293 -0
  185. package/src/client/locales.ts +143 -0
  186. package/src/client/settings.ts +482 -0
  187. package/src/client/styles.css +1580 -0
  188. package/src/compat.ts +161 -0
  189. package/src/index.ts +66 -0
  190. package/src/projection.ts +174 -0
  191. package/src/search.ts +291 -0
  192. package/src/settings.ts +169 -0
@@ -0,0 +1,198 @@
1
+ // 完整配置页(mega-settings 成员页与自足入口共用)
2
+ import { useEffect, useState, type ReactNode } from 'react'
3
+ import { ALIGN_OPTIONS, CARD_ITEM_OPTIONS, CARD_OPTIONS, MARK_TONE_OPTIONS, SCROLL_OPTIONS, SEARCH_SCOPE_OPTIONS, SHOW_OPTIONS, STYLE_OPTIONS, STYLE_CAPABILITIES, type MarkTone } from '../../settings.ts'
4
+ import type { NavInjected, Translate } from '../shared/types.ts'
5
+
6
+ export interface SettingsPageProps {
7
+ injected: NavInjected
8
+ t: Translate
9
+ /** 已收纳至 mega-settings 时仅显示提示(自足入口让位) */
10
+ hosted?: boolean
11
+ }
12
+
13
+ function Seg<T extends string | number>(props: { options: readonly T[]; value: T; labels: Record<string, string>; onPick: (v: T) => void }): ReactNode {
14
+ return (
15
+ <div className="mgcn-segmented" role="radiogroup">
16
+ {props.options.map((o) => (
17
+ <button
18
+ key={String(o)}
19
+ type="button"
20
+ role="radio"
21
+ aria-checked={props.value === o}
22
+ className={props.value === o ? 'mgcn-segment mgcn-segmentActive' : 'mgcn-segment'}
23
+ onClick={() => props.onPick(o)}
24
+ >
25
+ {props.labels[String(o)] ?? String(o)}
26
+ </button>
27
+ ))}
28
+ </div>
29
+ )
30
+ }
31
+
32
+ function Field({ label, desc, children }: { label: string; desc?: string; children: ReactNode }): ReactNode {
33
+ return (
34
+ <div className="mgcn-settingsRow">
35
+ <div className="mgcn-settingsLabel">
36
+ <p className="mgcn-settingsTitle">{label}</p>
37
+ {desc !== undefined ? <p className="mgcn-settingsDesc">{desc}</p> : null}
38
+ </div>
39
+ <div className="mgcn-settingsControl">{children}</div>
40
+ </div>
41
+ )
42
+ }
43
+
44
+ function useSettingsTick(subscribe: NavInjected['subscribeSettings']): void {
45
+ const [, bump] = useState(0)
46
+ useEffect(() => subscribe(() => bump((n) => n + 1)), [subscribe])
47
+ }
48
+
49
+ export function SettingsPage(props: SettingsPageProps): ReactNode {
50
+ const { injected, t, hosted } = props
51
+ useSettingsTick(injected.subscribeSettings)
52
+ if (hosted === true) {
53
+ return <div className="mgcn-settings">{t('settings.hosted')}</div>
54
+ }
55
+ return (
56
+ <div className="mgcn-settings">
57
+ <Field label={t('config.style')}>
58
+ <Seg
59
+ options={STYLE_OPTIONS}
60
+ value={injected.style()}
61
+ labels={{ minimal: t('config.style.minimal'), codex: t('config.style.codex'), deepseek: t('config.style.deepseek') }}
62
+ onPick={(v) => injected.setStyle(v)}
63
+ />
64
+ </Field>
65
+ <Field label={t('config.railOffset')} desc={t('config.railOffset.desc')}>
66
+ <div className="mgcn-sliderRow">
67
+ <input
68
+ type="range"
69
+ min="0"
70
+ max="32"
71
+ step="1"
72
+ value={injected.railOffset()}
73
+ onChange={(e) => injected.setRailOffset(Number(e.target.value))}
74
+ />
75
+ <span className="mgcn-sliderValue">{injected.railOffset()}px</span>
76
+ </div>
77
+ </Field>
78
+ <Field label={t('config.align')} desc={t('settings.align.desc')}>
79
+ <Seg
80
+ options={ALIGN_OPTIONS}
81
+ value={injected.align()}
82
+ labels={{ left: t('settings.align.left'), right: t('settings.align.right') }}
83
+ onPick={(v) => injected.setAlign(v)}
84
+ />
85
+ </Field>
86
+ <Field label={t('config.scrollBehavior')} desc={t('config.scrollBehavior.desc')}>
87
+ <Seg
88
+ options={SCROLL_OPTIONS}
89
+ value={injected.scrollBehavior()}
90
+ labels={{ smooth: t('config.scrollBehavior.smooth'), instant: t('config.scrollBehavior.instant') }}
91
+ onPick={(v) => injected.setScrollMode(v)}
92
+ />
93
+ </Field>
94
+ {STYLE_CAPABILITIES[injected.style()].hoverCards ? (
95
+ <>
96
+ <Field label={t('config.cardCount')} desc={t('config.cardCount.desc')}>
97
+ <Seg
98
+ options={CARD_OPTIONS}
99
+ value={injected.cardCount()}
100
+ labels={{ 1: '1', 3: '3', 5: '5' }}
101
+ onPick={(v) => injected.setCardCount(v)}
102
+ />
103
+ </Field>
104
+ <Field label={t('config.cardItems')} desc={t('config.cardItems.desc')}>
105
+ <div className="mgcn-checkGroup">
106
+ {CARD_ITEM_OPTIONS.map((item) => {
107
+ const on = injected.cardItems().includes(item)
108
+ return (
109
+ <label key={item} className="mgcn-checkItem">
110
+ <input
111
+ type="checkbox"
112
+ checked={on}
113
+ onChange={(e) => {
114
+ const items = e.target.checked
115
+ ? [...injected.cardItems(), item]
116
+ : injected.cardItems().filter((x) => x !== item)
117
+ injected.setCardItems(items)
118
+ }}
119
+ />
120
+ <span>{t('config.cardItems.' + item)}</span>
121
+ </label>
122
+ )
123
+ })}
124
+ </div>
125
+ </Field>
126
+ </>
127
+ ) : null}
128
+
129
+ {injected.style() === 'codex' ? (
130
+ <Field label={t('config.markTone')} desc={t('config.markTone.desc')}>
131
+ <Seg
132
+ options={MARK_TONE_OPTIONS}
133
+ value={injected.markTone()}
134
+ labels={{ soft: t('config.markTone.soft'), deep: t('config.markTone.deep') }}
135
+ onPick={(v: MarkTone) => injected.setMarkTone(v)}
136
+ />
137
+ </Field>
138
+ ) : null}
139
+
140
+ <Field label={t('config.searchScopes')} desc={t('config.searchScopes.desc')}>
141
+ <div className="mgcn-checkGroup">
142
+ {SEARCH_SCOPE_OPTIONS.map((scope) => {
143
+ const on = injected.searchScopes().includes(scope)
144
+ const locked = scope === 'user' // 用户必选,不可取消
145
+ return (
146
+ <label key={scope} className="mgcn-checkItem">
147
+ <input
148
+ type="checkbox"
149
+ checked={on}
150
+ disabled={locked}
151
+ onChange={(e) => {
152
+ const items = e.target.checked
153
+ ? [...injected.searchScopes(), scope]
154
+ : injected.searchScopes().filter((x) => x !== scope)
155
+ injected.setSearchScopes(items)
156
+ }}
157
+ />
158
+ <span>{t('config.searchScopes.' + scope)}</span>
159
+ </label>
160
+ )
161
+ })}
162
+ </div>
163
+ </Field>
164
+ <Field label={t('config.showQuickSettings')}>
165
+ <ModeSeg value={injected.showQuickSettings()} onChange={(v) => injected.setShowQuickSettings(v)} t={t} />
166
+ </Field>
167
+ <Field label={t('config.showSearch')}>
168
+ <ModeSeg value={injected.showSearch()} onChange={(v) => injected.setShowSearch(v)} t={t} />
169
+ </Field>
170
+ <Field label={t('config.showFavorites')}>
171
+ <ModeSeg value={injected.showFavorites()} onChange={(v) => injected.setShowFavorites(v)} t={t} />
172
+ </Field>
173
+ <Field label={t('config.showCount')}>
174
+ <ModeSeg value={injected.showCount()} onChange={(v) => injected.setShowCount(v)} t={t} />
175
+ </Field>
176
+ {STYLE_CAPABILITIES[injected.style()].paging ? (
177
+ <Field label={t('config.showPaging')}>
178
+ <ModeSeg value={injected.showPaging()} onChange={(v) => injected.setShowPaging(v)} t={t} />
179
+ </Field>
180
+ ) : null}
181
+ </div>
182
+ )
183
+ }
184
+
185
+ function ModeSeg({ value, onChange, t }: { value: 'show' | 'peek' | 'hide'; onChange(v: 'show' | 'peek' | 'hide'): void; t: Translate }): ReactNode {
186
+ return (
187
+ <Seg
188
+ options={SHOW_OPTIONS}
189
+ value={value}
190
+ labels={{
191
+ show: t('config.showMode.show'),
192
+ peek: t('config.showMode.peek'),
193
+ hide: t('config.showMode.hide'),
194
+ }}
195
+ onPick={(v) => onChange(v)}
196
+ />
197
+ )
198
+ }
@@ -0,0 +1,28 @@
1
+ // 自足完整配置入口:宿主(mega-settings)已收纳时让位提示,否则渲染完整配置页
2
+ import { useEffect, useState, type ReactNode } from 'react'
3
+ import type { NavInjected, Translate } from '../shared/types.ts'
4
+ import { SettingsPage } from './SettingsPage.tsx'
5
+
6
+ interface SlotsLike {
7
+ entries?(key: string): readonly unknown[]
8
+ subscribe?(key: string, fn: () => void): () => void
9
+ }
10
+
11
+ export interface StandaloneSettingsProps {
12
+ injected: NavInjected
13
+ slots?: SlotsLike
14
+ t: Translate
15
+ }
16
+
17
+ export function StandaloneSettings(props: StandaloneSettingsProps): ReactNode {
18
+ const [hosted, setHosted] = useState(false)
19
+ useEffect(() => {
20
+ const check = () => {
21
+ const n = props.slots?.entries?.('mega.settings.member')?.length ?? 0
22
+ setHosted(n > 0)
23
+ }
24
+ check()
25
+ return props.slots?.subscribe?.('mega.settings.member', check)
26
+ }, [props.slots])
27
+ return <SettingsPage injected={props.injected} t={props.t} hosted={hosted} />
28
+ }
@@ -0,0 +1,99 @@
1
+ // 跨风格契约:注入面 / 数据形态 / 工具面(仅此——风格实现各自自治)
2
+ import type { BandHeight, CardCount, CardItem, MarkTone, NavStyle, RailAlign, ScrollMode, SearchScope, ShowMode } from '../../settings.ts'
3
+
4
+ /** 会话投影 face 最小面 */
5
+ export interface ObservableFace {
6
+ getSnapshot: () => unknown
7
+ subscribe: (listener: () => void) => () => void
8
+ }
9
+
10
+ /** 回合标记:某回合的提问组(或一条未入投影的活提问) */
11
+ export interface RailMarker {
12
+ /** 归属回合;活提问(投影未收)为 null */
13
+ readonly turn: number | null
14
+ /** 跳转锚点:组内首问的聊天 key */
15
+ readonly key: string
16
+ /** 首问锚点序号 */
17
+ readonly seq: number
18
+ /** 首问时间 */
19
+ readonly time: number
20
+ /** 组内全部提问文本(按序) */
21
+ readonly texts: readonly string[]
22
+ /** 组内全部聊天 key(活合并去重用) */
23
+ readonly members: readonly string[]
24
+ /** 该轮性能指标(投影附带;缺数据时省略) */
25
+ readonly metrics?: { durationMs: number; firstTokenMs: number; tokensPerSec: number }
26
+ }
27
+
28
+ /** 注册注入面(client/index.ts 装配;各风格经此拿数据与动作) */
29
+ export interface NavInjected {
30
+ readQuestions: (sessionId: string) => { key: string; anchorSeq: number; seq: number; time: number; text: string }[]
31
+ subscribeList: (cb: () => void) => () => void
32
+ subscribeContent: (sessionId: string, cb: () => void) => () => void
33
+ questionProjection: (sessionId: string) => ObservableFace | undefined
34
+ /** seq:目标轮序号(方向判定);currentSeq:当前阅读位置序号(可选,下方判定优先用) */
35
+ jump: (sessionId: string, key: string, seq?: number, currentSeq?: number) => void
36
+ style: () => NavStyle
37
+ setStyle: (style: NavStyle) => void
38
+ align: () => RailAlign
39
+ subscribeSettings: (cb: () => void) => () => void
40
+ setAlign: (align: RailAlign) => void
41
+ bandHeight: () => BandHeight
42
+ setBandHeight: (band: BandHeight) => void
43
+ scrollBehavior: () => ScrollMode
44
+ setScrollMode: (mode: ScrollMode) => void
45
+ showCount: () => ShowMode
46
+ setShowCount: (mode: ShowMode) => void
47
+ showSearch: () => ShowMode
48
+ setShowSearch: (mode: ShowMode) => void
49
+ showQuickSettings: () => ShowMode
50
+ setShowQuickSettings: (mode: ShowMode) => void
51
+ showFavorites: () => ShowMode
52
+ setShowFavorites: (mode: ShowMode) => void
53
+ showPaging: () => ShowMode
54
+ setShowPaging: (mode: ShowMode) => void
55
+ searchScopes: () => SearchScope[]
56
+ setSearchScopes: (scopes: SearchScope[]) => void
57
+ railOffset: () => number
58
+ setRailOffset: (offset: number) => void
59
+ cardCount: () => CardCount
60
+ setCardCount: (count: CardCount) => void
61
+ cardItems: () => CardItem[]
62
+ setCardItems: (items: CardItem[]) => void
63
+ markTone: () => MarkTone
64
+ setMarkTone: (tone: MarkTone) => void
65
+ }
66
+
67
+ /** 悬停聚焦窗口项 */
68
+ export interface FocusWindowItem {
69
+ dot: RailMarker
70
+ distance: number
71
+ }
72
+
73
+ /** 聚焦状态:卡片呈现所需几何 */
74
+ export interface FocusState {
75
+ key: string
76
+ items: FocusWindowItem[]
77
+ centerY: number
78
+ left?: number
79
+ right?: number
80
+ }
81
+
82
+ /** 会话列表最小面(useSessions selector) */
83
+ export interface SessionListLike {
84
+ current?: unknown
85
+ byId?: Record<string, { blank?: boolean }>
86
+ }
87
+
88
+ /** 翻译函数面 */
89
+ export type Translate = (key: string, vars?: Record<string, string | number>) => string
90
+
91
+ /** 会话选择器面(useSessions 最小面,宿主按风格组件注入) */
92
+ export type SessionSelector = <S>(selector: (s: SessionListLike) => S) => S
93
+
94
+ /** 风格组件统一 props 面(各风格自治实现,但入参一致) */
95
+ export interface RailProps {
96
+ injected: NavInjected | undefined
97
+ useSessions?: SessionSelector
98
+ t: Translate
99
+ }