@ash-qw/dsh-theme-prts 0.1.91

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 (50) hide show
  1. package/LICENSE +24 -0
  2. package/README.en.md +103 -0
  3. package/README.md +107 -0
  4. package/THIRD_PARTY_NOTICES.md +48 -0
  5. package/cordis.patch.yml +4 -0
  6. package/lib/client.js +7466 -0
  7. package/lib/index.js +3 -0
  8. package/package.json +64 -0
  9. package/src/assets/faction-emblems/lungmen.png +0 -0
  10. package/src/assets/faction-emblems/penguin-logistics.png +0 -0
  11. package/src/assets/faction-emblems/reunion.png +0 -0
  12. package/src/assets/faction-emblems/rhine-lab.png +0 -0
  13. package/src/assets/faction-emblems/rhodes-island.png +0 -0
  14. package/src/assets/prts-original-avatar.png +0 -0
  15. package/src/assets/rhodes-dsh.svg +6 -0
  16. package/src/assets/topographic-map.svg +72 -0
  17. package/src/assets/topographic-tech.svg +19 -0
  18. package/src/client/assistant-glass-adapter.js +231 -0
  19. package/src/client/composer-glass-adapter.js +210 -0
  20. package/src/client/conversation-control-adapter.js +109 -0
  21. package/src/client/conversation-scale-adapter.js +2243 -0
  22. package/src/client/facility-geometry.js +60 -0
  23. package/src/client/facility-vector.js +230 -0
  24. package/src/client/floating-glass-adapter.js +177 -0
  25. package/src/client/host-geometry-adapter.js +123 -0
  26. package/src/client/index.js +359 -0
  27. package/src/client/layout-stability-diagnostics.js +162 -0
  28. package/src/client/operations-shell-v2.js +248 -0
  29. package/src/client/particle-field-adapter.js +1840 -0
  30. package/src/client/preferences.js +239 -0
  31. package/src/client/rc7-adapter.js +83 -0
  32. package/src/client/resize-shield-adapter.js +64 -0
  33. package/src/client/settings-page.js +62 -0
  34. package/src/client/sidebar-control-adapter.js +317 -0
  35. package/src/client/startup-sequence.js +366 -0
  36. package/src/client/status-projection.js +79 -0
  37. package/src/client/terrain-motion-adapter.js +188 -0
  38. package/src/client/theme-controller-v2.js +134 -0
  39. package/src/client/theme-controller.js +119 -0
  40. package/src/client/theme-settings-workbench.js +583 -0
  41. package/src/client/to-bottom-adapter.js +85 -0
  42. package/src/client/ui-store.js +23 -0
  43. package/src/index.js +4 -0
  44. package/src/styles/conversation-scale.css +471 -0
  45. package/src/styles/facility-vector.css +292 -0
  46. package/src/styles/prts.css +1223 -0
  47. package/src/styles/refinement.css +429 -0
  48. package/src/styles/stabilization.css +161 -0
  49. package/src/styles/startup-sequence.css +496 -0
  50. package/src/styles/theme-settings-workbench.css +803 -0
@@ -0,0 +1,248 @@
1
+ import { createThemeSettingsOverlay, themeSettingsMarkup } from './theme-settings-workbench.js'
2
+ import { createResizeShieldAdapter } from './resize-shield-adapter.js'
3
+
4
+ function setText(root, selector, value) {
5
+ const node = root?.querySelector(selector)
6
+ const next = String(value ?? '')
7
+ if (node && node.textContent !== next) node.textContent = next
8
+ }
9
+
10
+ function markup(emblem) {
11
+ return `<div data-prts-shell data-plugin="dsh-theme-prts">
12
+ <button type="button" data-prts-rail-launcher aria-label="打开 P.R.T.S. 导航" aria-controls="prts-nav-rail" aria-expanded="false"><span aria-hidden="true">P.R.T.S.</span></button>
13
+ <nav id="prts-nav-rail" data-prts-nav-rail aria-label="P.R.T.S. 导航">
14
+ <button type="button" data-prts-rail-brand aria-label="P.R.T.S. 终端设置" aria-controls="prts-theme-settings" aria-expanded="false">${emblem || ''}<span>P.R.T.S.</span></button>
15
+ <div data-prts-nav-bottom>
16
+ <div data-prts-connection-indicator data-state="unknown" tabindex="0" role="status" aria-label="Harness 主机连接状态:未知">
17
+ <i aria-hidden="true"></i><span data-prts-connection-label>未知</span>
18
+ </div>
19
+ <button type="button" data-prts-scheme-toggle aria-label="切换明暗模式">
20
+ <svg data-prts-scheme-icon="light" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2M12 20v2M4.93 4.93l1.42 1.42M17.65 17.65l1.42 1.42M2 12h2M20 12h2M4.93 19.07l1.42-1.42M17.65 6.35l1.42-1.42"></path></svg>
21
+ <svg data-prts-scheme-icon="dark" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.2 15.4A8.4 8.4 0 0 1 8.6 3.8 8.5 8.5 0 1 0 20.2 15.4Z"></path></svg>
22
+ <small>明暗</small>
23
+ </button>
24
+ <button type="button" data-prts-theme-disable aria-label="关闭 P.R.T.S. 主题"><b aria-hidden="true">×</b><small>关闭主题</small></button>
25
+ </div>
26
+ </nav>
27
+ ${themeSettingsMarkup()}
28
+ </div>`
29
+ }
30
+
31
+ export function createOperationsShell({
32
+ document,
33
+ window,
34
+ assets = {},
35
+ adapter,
36
+ hostGeometry,
37
+ onSchemeToggle = () => {},
38
+ onThemeDisable = () => {},
39
+ onPreferenceChange = () => {},
40
+ onVisualReset = () => {},
41
+ getConversationScalePreview = () => ({ visible: false, reason: 'unmeasured', mode: 'hidden' }),
42
+ onRetrySave = () => {},
43
+ }) {
44
+ const root = document.documentElement
45
+ const resizeShield = createResizeShieldAdapter({ window })
46
+ let shell
47
+ let navRail
48
+ let railLauncher
49
+ let railMode
50
+ let railViewportQuery
51
+ let settingsOverlay
52
+ let schemeToggle
53
+ let themeDisable
54
+ let connectionIndicator
55
+ let conversationObserver
56
+ let schemeObserver
57
+ let operationRegion
58
+ function syncConversationState() {
59
+ if (!operationRegion) return
60
+ const candidate = operationRegion.querySelector(
61
+ '[data-chat-flow-kind]:not([hidden]):not([aria-hidden="true"]), [data-message-role]:not([hidden]):not([aria-hidden="true"])',
62
+ )
63
+ const active = Boolean(candidate)
64
+ root.dataset.prtsConversationState = active ? 'active' : 'idle'
65
+ settingsOverlay?.refreshScalePreview()
66
+ }
67
+
68
+ function toggleScheme() {
69
+ onSchemeToggle(root.dataset.prtsScheme === 'dark' ? 'light' : 'dark')
70
+ }
71
+
72
+ function syncSchemeToggle() {
73
+ if (!schemeToggle) return
74
+ const current = root.dataset.prtsScheme === 'dark' ? 'dark' : 'light'
75
+ schemeToggle.dataset.prtsSchemeCurrent = current
76
+ schemeToggle.setAttribute('aria-label', current === 'dark' ? '切换到日间模式' : '切换到夜间模式')
77
+ }
78
+
79
+ function syncRailState() {
80
+ if (!navRail || !railLauncher) return
81
+ const overlay = railMode === 'overlay'
82
+ const open = overlay && root.hasAttribute('data-prts-rail-open')
83
+ railLauncher.setAttribute('aria-expanded', String(open))
84
+ railLauncher.setAttribute('aria-label', open ? '关闭 P.R.T.S. 导航' : '打开 P.R.T.S. 导航')
85
+ if (overlay && !open) {
86
+ navRail.setAttribute('aria-hidden', 'true')
87
+ navRail.setAttribute('inert', '')
88
+ } else {
89
+ navRail.removeAttribute('aria-hidden')
90
+ navRail.removeAttribute('inert')
91
+ }
92
+ }
93
+
94
+ function closeRail({ returnFocus = false } = {}) {
95
+ if (railMode !== 'overlay') return
96
+ const wasOpen = root.hasAttribute('data-prts-rail-open')
97
+ root.removeAttribute('data-prts-rail-open')
98
+ syncRailState()
99
+ if (returnFocus && wasOpen) railLauncher?.focus?.()
100
+ }
101
+
102
+ function openRail() {
103
+ if (railMode !== 'overlay') return
104
+ root.setAttribute('data-prts-rail-open', '')
105
+ syncRailState()
106
+ const focusFirst = () => {
107
+ if (root.hasAttribute('data-prts-rail-open')) navRail?.querySelector('button')?.focus?.()
108
+ }
109
+ if (window?.requestAnimationFrame) window.requestAnimationFrame(focusFirst)
110
+ else window?.setTimeout?.(focusFirst, 0)
111
+ }
112
+
113
+ function setRailViewport(width = window.innerWidth) {
114
+ const nextMode = Number(width) >= 1180 ? 'docked' : 'overlay'
115
+ if (nextMode === railMode) return railMode
116
+ railMode = nextMode
117
+ root.dataset.prtsRailMode = nextMode
118
+ if (nextMode === 'docked') root.removeAttribute('data-prts-rail-open')
119
+ else root.removeAttribute('data-prts-rail-open')
120
+ syncRailState()
121
+ return nextMode
122
+ }
123
+
124
+ function toggleRail() {
125
+ if (root.hasAttribute('data-prts-rail-open')) closeRail()
126
+ else openRail()
127
+ }
128
+
129
+ function onRailKeydown(event) {
130
+ if (event.key !== 'Escape' || railMode !== 'overlay' || !root.hasAttribute('data-prts-rail-open')) return
131
+ event.preventDefault()
132
+ closeRail({ returnFocus: true })
133
+ }
134
+
135
+ function onDocumentClick(event) {
136
+ if (railMode !== 'overlay' || !root.hasAttribute('data-prts-rail-open')) return
137
+ if (navRail?.contains?.(event.target) || railLauncher?.contains?.(event.target)) return
138
+ closeRail()
139
+ }
140
+
141
+ function onRailAction(event) {
142
+ const action = event.target?.closest?.('[data-prts-rail-brand], [data-prts-scheme-toggle]')
143
+ if (action && navRail?.contains?.(action)) closeRail()
144
+ }
145
+
146
+ function onResponsiveChange() {
147
+ setRailViewport(window.innerWidth)
148
+ settingsOverlay?.scheduleScalePreviewRefresh?.()
149
+ }
150
+
151
+ function bindResponsiveQueries() {
152
+ railViewportQuery = window.matchMedia?.('(min-width: 1180px)')
153
+ railViewportQuery?.addEventListener?.('change', onResponsiveChange)
154
+ }
155
+ function disableTheme() { onThemeDisable() }
156
+
157
+ function mount() {
158
+ if (shell?.isConnected) return true
159
+ const regions = adapter.mount()
160
+ if (!regions) return false
161
+ const template = document.createElement('template')
162
+ template.innerHTML = markup(assets.emblem).trim()
163
+ shell = template.content.firstElementChild
164
+ document.body.appendChild(shell)
165
+ bindResponsiveQueries()
166
+ navRail = shell.querySelector('[data-prts-nav-rail]')
167
+ railLauncher = shell.querySelector('[data-prts-rail-launcher]')
168
+ setRailViewport(window.innerWidth)
169
+ schemeToggle = shell.querySelector('[data-prts-scheme-toggle]')
170
+ themeDisable = shell.querySelector('[data-prts-theme-disable]')
171
+ connectionIndicator = shell.querySelector('[data-prts-connection-indicator]')
172
+ hostGeometry?.start?.(regions.frame)
173
+ operationRegion = regions.center
174
+ settingsOverlay = createThemeSettingsOverlay({
175
+ document,
176
+ trigger: shell.querySelector('[data-prts-rail-brand]'),
177
+ panel: shell.querySelector('[data-prts-theme-settings]'),
178
+ backdrop: shell.querySelector('[data-prts-settings-backdrop]'),
179
+ onPreferenceChange,
180
+ onResetVisual: onVisualReset,
181
+ onRetrySave,
182
+ getConversationScalePreview,
183
+ })
184
+ resizeShield.start([
185
+ operationRegion,
186
+ shell.querySelector('[data-prts-theme-settings]'),
187
+ shell.querySelector('[data-prts-settings-backdrop]'),
188
+ ])
189
+ conversationObserver = new window.MutationObserver(syncConversationState)
190
+ conversationObserver.observe(operationRegion, { childList: true, subtree: true, attributes: true, attributeFilter: ['hidden', 'data-chat-flow-kind', 'data-message-role'] })
191
+ schemeObserver = new window.MutationObserver(syncSchemeToggle)
192
+ schemeObserver.observe(root, { attributes: true, attributeFilter: ['data-prts-scheme'] })
193
+ railLauncher.addEventListener('click', toggleRail)
194
+ navRail.addEventListener('click', onRailAction)
195
+ document.addEventListener('keydown', onRailKeydown)
196
+ document.addEventListener('click', onDocumentClick)
197
+ schemeToggle.addEventListener('click', toggleScheme)
198
+ themeDisable.addEventListener('click', disableTheme)
199
+ syncConversationState()
200
+ syncSchemeToggle()
201
+ return true
202
+ }
203
+
204
+ function dispose() {
205
+ railLauncher?.removeEventListener('click', toggleRail)
206
+ navRail?.removeEventListener('click', onRailAction)
207
+ document.removeEventListener('keydown', onRailKeydown)
208
+ document.removeEventListener('click', onDocumentClick)
209
+ schemeToggle?.removeEventListener('click', toggleScheme)
210
+ themeDisable?.removeEventListener('click', disableTheme)
211
+ railViewportQuery?.removeEventListener?.('change', onResponsiveChange)
212
+ railViewportQuery = undefined
213
+ resizeShield.dispose()
214
+ settingsOverlay?.dispose()
215
+ conversationObserver?.disconnect()
216
+ schemeObserver?.disconnect()
217
+ shell?.remove()
218
+ root.removeAttribute('data-prts-conversation-state')
219
+ root.removeAttribute('data-prts-rail-mode')
220
+ root.removeAttribute('data-prts-rail-open')
221
+ navRail = railLauncher = railMode = undefined
222
+ shell = settingsOverlay = schemeToggle = themeDisable = connectionIndicator = undefined
223
+ conversationObserver = schemeObserver = undefined
224
+ operationRegion = undefined
225
+ hostGeometry?.dispose?.()
226
+ adapter.dispose()
227
+ }
228
+
229
+ return {
230
+ update(preferences, status, persistenceState) {
231
+ if (!preferences?.enabled) {
232
+ dispose()
233
+ return false
234
+ }
235
+ if (!mount()) return false
236
+ const connection = status?.connection || 'unknown'
237
+ const connectionLabel = status?.connectionLabel || '未知'
238
+ connectionIndicator.dataset.state = connection
239
+ connectionIndicator.setAttribute('aria-label', `Harness 主机连接状态:${connectionLabel}`)
240
+ setText(connectionIndicator, '[data-prts-connection-label]', connectionLabel)
241
+ settingsOverlay.update(preferences, status, persistenceState)
242
+ syncConversationState()
243
+ syncSchemeToggle()
244
+ return true
245
+ },
246
+ dispose,
247
+ }
248
+ }