@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.
- package/LICENSE +24 -0
- package/README.en.md +103 -0
- package/README.md +107 -0
- package/THIRD_PARTY_NOTICES.md +48 -0
- package/cordis.patch.yml +4 -0
- package/lib/client.js +7466 -0
- package/lib/index.js +3 -0
- package/package.json +64 -0
- package/src/assets/faction-emblems/lungmen.png +0 -0
- package/src/assets/faction-emblems/penguin-logistics.png +0 -0
- package/src/assets/faction-emblems/reunion.png +0 -0
- package/src/assets/faction-emblems/rhine-lab.png +0 -0
- package/src/assets/faction-emblems/rhodes-island.png +0 -0
- package/src/assets/prts-original-avatar.png +0 -0
- package/src/assets/rhodes-dsh.svg +6 -0
- package/src/assets/topographic-map.svg +72 -0
- package/src/assets/topographic-tech.svg +19 -0
- package/src/client/assistant-glass-adapter.js +231 -0
- package/src/client/composer-glass-adapter.js +210 -0
- package/src/client/conversation-control-adapter.js +109 -0
- package/src/client/conversation-scale-adapter.js +2243 -0
- package/src/client/facility-geometry.js +60 -0
- package/src/client/facility-vector.js +230 -0
- package/src/client/floating-glass-adapter.js +177 -0
- package/src/client/host-geometry-adapter.js +123 -0
- package/src/client/index.js +359 -0
- package/src/client/layout-stability-diagnostics.js +162 -0
- package/src/client/operations-shell-v2.js +248 -0
- package/src/client/particle-field-adapter.js +1840 -0
- package/src/client/preferences.js +239 -0
- package/src/client/rc7-adapter.js +83 -0
- package/src/client/resize-shield-adapter.js +64 -0
- package/src/client/settings-page.js +62 -0
- package/src/client/sidebar-control-adapter.js +317 -0
- package/src/client/startup-sequence.js +366 -0
- package/src/client/status-projection.js +79 -0
- package/src/client/terrain-motion-adapter.js +188 -0
- package/src/client/theme-controller-v2.js +134 -0
- package/src/client/theme-controller.js +119 -0
- package/src/client/theme-settings-workbench.js +583 -0
- package/src/client/to-bottom-adapter.js +85 -0
- package/src/client/ui-store.js +23 -0
- package/src/index.js +4 -0
- package/src/styles/conversation-scale.css +471 -0
- package/src/styles/facility-vector.css +292 -0
- package/src/styles/prts.css +1223 -0
- package/src/styles/refinement.css +429 -0
- package/src/styles/stabilization.css +161 -0
- package/src/styles/startup-sequence.css +496 -0
- 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
|
+
}
|