@ash-qw/dsh-theme-prts 0.1.92 → 0.1.93
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/CHANGELOG.md +31 -0
- package/README.en.md +23 -34
- package/README.md +23 -36
- package/lib/client.js +1018 -50
- package/package.json +12 -2
- package/src/client/conversation-scale-adapter.js +77 -0
- package/src/client/index.js +18 -3
- package/src/client/operations-shell-v2.js +214 -16
- package/src/client/particle-field-adapter.js +89 -9
- package/src/client/preferences.js +24 -5
- package/src/client/theme-controller-v2.js +609 -16
- package/src/client/theme-settings-workbench.js +69 -2
- package/src/styles/prts.css +362 -5
- package/src/styles/theme-settings-workbench.css +17 -0
package/package.json
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ash-qw/dsh-theme-prts",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.93",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
|
-
"description": "Unofficial
|
|
6
|
+
"description": "Unofficial Arknights P.R.T.S.-inspired UI theme for DeepSeek Harness Web",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"deepseek-harness",
|
|
9
|
+
"dsh",
|
|
10
|
+
"dsh-plugin",
|
|
11
|
+
"theme",
|
|
12
|
+
"ui",
|
|
13
|
+
"arknights",
|
|
14
|
+
"prts"
|
|
15
|
+
],
|
|
7
16
|
"license": "SEE LICENSE IN LICENSE",
|
|
8
17
|
"repository": {
|
|
9
18
|
"type": "git",
|
|
@@ -44,6 +53,7 @@
|
|
|
44
53
|
"cordis.patch.yml",
|
|
45
54
|
"README.md",
|
|
46
55
|
"README.en.md",
|
|
56
|
+
"CHANGELOG.md",
|
|
47
57
|
"LICENSE",
|
|
48
58
|
"THIRD_PARTY_NOTICES.md"
|
|
49
59
|
],
|
|
@@ -107,6 +107,7 @@ const PREVIEW_TOUCH_DURATION = 1200
|
|
|
107
107
|
const SNAP_DELAY = 110
|
|
108
108
|
const TOUCH_WAVE_DURATION = 620
|
|
109
109
|
const HISTORY_PAGE_SETTLE_LIMIT = 4000
|
|
110
|
+
const GEOMETRY_SETTLE_FRAME_LIMIT = 24
|
|
110
111
|
let scaleInstanceSeed = 0
|
|
111
112
|
|
|
112
113
|
function clamp(value, minimum, maximum) {
|
|
@@ -764,6 +765,9 @@ export function createConversationScaleAdapter({ document, window, sessions }) {
|
|
|
764
765
|
let scaleLengths = resolveConversationScaleLengths(focusContrast)
|
|
765
766
|
let contentLeft
|
|
766
767
|
let geometryDirty = true
|
|
768
|
+
let geometrySettleFrame
|
|
769
|
+
let geometrySettleFramesRemaining = 0
|
|
770
|
+
let geometrySettleSignature
|
|
767
771
|
let observedOperationWidth
|
|
768
772
|
let observedOperationHeight
|
|
769
773
|
let started = false
|
|
@@ -786,6 +790,63 @@ export function createConversationScaleAdapter({ document, window, sessions }) {
|
|
|
786
790
|
? timestamp
|
|
787
791
|
: window?.performance?.now?.() ?? Date.now()
|
|
788
792
|
|
|
793
|
+
function currentGeometrySignature() {
|
|
794
|
+
if (!operation || !scroller) return undefined
|
|
795
|
+
const operationBox = operation.getBoundingClientRect?.()
|
|
796
|
+
const scrollerBox = scroller.getBoundingClientRect?.()
|
|
797
|
+
const composerBox = composer?.getBoundingClientRect?.()
|
|
798
|
+
if (!operationBox || !scrollerBox) return undefined
|
|
799
|
+
const values = [
|
|
800
|
+
operationBox.width,
|
|
801
|
+
operationBox.height,
|
|
802
|
+
scrollerBox.top - operationBox.top,
|
|
803
|
+
scrollerBox.bottom - operationBox.top,
|
|
804
|
+
scrollerBox.left - operationBox.left,
|
|
805
|
+
scrollerBox.right - operationBox.left,
|
|
806
|
+
composerBox ? composerBox.top - operationBox.top : -1,
|
|
807
|
+
composerBox ? composerBox.bottom - operationBox.top : -1,
|
|
808
|
+
composerBox ? composerBox.left - operationBox.left : -1,
|
|
809
|
+
composerBox ? composerBox.right - operationBox.left : -1,
|
|
810
|
+
]
|
|
811
|
+
if (!values.every(Number.isFinite)) return undefined
|
|
812
|
+
return values.map(value => Number(value.toFixed(2))).join(':')
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
function sampleGeometryStabilization() {
|
|
816
|
+
geometrySettleFrame = undefined
|
|
817
|
+
if (!started || failed || geometrySettleFramesRemaining <= 0) return
|
|
818
|
+
geometrySettleFramesRemaining -= 1
|
|
819
|
+
const signature = currentGeometrySignature()
|
|
820
|
+
if (signature !== undefined && signature !== geometrySettleSignature) {
|
|
821
|
+
geometrySettleSignature = signature
|
|
822
|
+
geometryDirty = true
|
|
823
|
+
obstructionDirty = true
|
|
824
|
+
schedule()
|
|
825
|
+
}
|
|
826
|
+
if (geometrySettleFramesRemaining > 0) {
|
|
827
|
+
geometrySettleFrame = requestFrame(sampleGeometryStabilization)
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
function requestGeometryStabilization() {
|
|
832
|
+
if (!started || failed) return
|
|
833
|
+
geometrySettleFramesRemaining = GEOMETRY_SETTLE_FRAME_LIMIT
|
|
834
|
+
if (geometrySettleFrame === undefined) {
|
|
835
|
+
geometrySettleFrame = requestFrame(sampleGeometryStabilization)
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
function stopGeometryStabilization() {
|
|
840
|
+
cancelFrame(geometrySettleFrame)
|
|
841
|
+
geometrySettleFrame = undefined
|
|
842
|
+
geometrySettleFramesRemaining = 0
|
|
843
|
+
geometrySettleSignature = undefined
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
function onHostGeometryChange() {
|
|
847
|
+
requestGeometryStabilization()
|
|
848
|
+
}
|
|
849
|
+
|
|
789
850
|
function reducedMotion() {
|
|
790
851
|
return window?.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches
|
|
791
852
|
|| document.documentElement.dataset.prtsMotion === 'reduced'
|
|
@@ -1117,10 +1178,12 @@ export function createConversationScaleAdapter({ document, window, sessions }) {
|
|
|
1117
1178
|
setScaleResizeState(resizeActive)
|
|
1118
1179
|
cancelJump()
|
|
1119
1180
|
resetWave()
|
|
1181
|
+
requestGeometryStabilization()
|
|
1120
1182
|
return true
|
|
1121
1183
|
}
|
|
1122
1184
|
|
|
1123
1185
|
function disconnectRoots() {
|
|
1186
|
+
stopGeometryStabilization()
|
|
1124
1187
|
clearTimers()
|
|
1125
1188
|
hidePreview()
|
|
1126
1189
|
disconnectPreviewObserver()
|
|
@@ -2129,10 +2192,15 @@ export function createConversationScaleAdapter({ document, window, sessions }) {
|
|
|
2129
2192
|
if (started || !document) return
|
|
2130
2193
|
started = true
|
|
2131
2194
|
failed = false
|
|
2195
|
+
window?.addEventListener?.('resize', onHostGeometryChange)
|
|
2196
|
+
window?.addEventListener?.('orientationchange', onHostGeometryChange)
|
|
2197
|
+
window?.addEventListener?.('pageshow', onHostGeometryChange)
|
|
2198
|
+
window?.visualViewport?.addEventListener?.('resize', onHostGeometryChange)
|
|
2132
2199
|
const ResizeObserver = window?.ResizeObserver
|
|
2133
2200
|
if (typeof ResizeObserver === 'function') {
|
|
2134
2201
|
resizeObserver = new ResizeObserver((entries = []) => {
|
|
2135
2202
|
geometryDirty = true
|
|
2203
|
+
requestGeometryStabilization()
|
|
2136
2204
|
const operationEntry = entries.find(entry => entry.target === operation)
|
|
2137
2205
|
const width = Number(operationEntry?.contentRect?.width)
|
|
2138
2206
|
const height = Number(operationEntry?.contentRect?.height)
|
|
@@ -2173,6 +2241,7 @@ export function createConversationScaleAdapter({ document, window, sessions }) {
|
|
|
2173
2241
|
const external = mutations.filter(mutation =>
|
|
2174
2242
|
!mutation.target?.closest?.('[data-prts-conversation-scale], [data-prts-conversation-preview], [data-prts-conversation-history-hint], [data-prts-conversation-history-status]')
|
|
2175
2243
|
)
|
|
2244
|
+
if (external.length) requestGeometryStabilization()
|
|
2176
2245
|
const historyRelevant = external.some(mutation =>
|
|
2177
2246
|
mutation.type === 'childList'
|
|
2178
2247
|
&& operation?.contains?.(mutation.target)
|
|
@@ -2210,9 +2279,17 @@ export function createConversationScaleAdapter({ document, window, sessions }) {
|
|
|
2210
2279
|
],
|
|
2211
2280
|
})
|
|
2212
2281
|
}
|
|
2282
|
+
document.fonts?.ready?.then?.(() => {
|
|
2283
|
+
if (started) requestGeometryStabilization()
|
|
2284
|
+
}).catch?.(() => {})
|
|
2213
2285
|
schedule(true)
|
|
2214
2286
|
},
|
|
2215
2287
|
dispose() {
|
|
2288
|
+
window?.removeEventListener?.('resize', onHostGeometryChange)
|
|
2289
|
+
window?.removeEventListener?.('orientationchange', onHostGeometryChange)
|
|
2290
|
+
window?.removeEventListener?.('pageshow', onHostGeometryChange)
|
|
2291
|
+
window?.visualViewport?.removeEventListener?.('resize', onHostGeometryChange)
|
|
2292
|
+
stopGeometryStabilization()
|
|
2216
2293
|
started = false
|
|
2217
2294
|
failed = false
|
|
2218
2295
|
mutationObserver?.disconnect()
|
package/src/client/index.js
CHANGED
|
@@ -45,7 +45,6 @@ export function applyPrtsPlugin(ctx, environment) {
|
|
|
45
45
|
const safeMode = isSafeMode(window?.location?.search ?? '')
|
|
46
46
|
const storage = window?.localStorage
|
|
47
47
|
const themeService = contextService(ctx, 'theme')
|
|
48
|
-
const theme = createThemeController({ document, window, cssText, service: themeService })
|
|
49
48
|
const startup = createPrtsStartupSequence({ document, window, prtsEmblem: assets.prtsEmblem, rhodesEmblem: assets.emblem, timings: startupTimings })
|
|
50
49
|
const composerGlass = createComposerGlassAdapter({ document, window })
|
|
51
50
|
const assistantGlass = createAssistantGlassAdapter({ document, window })
|
|
@@ -60,6 +59,15 @@ export function applyPrtsPlugin(ctx, environment) {
|
|
|
60
59
|
sync()
|
|
61
60
|
},
|
|
62
61
|
})
|
|
62
|
+
const theme = createThemeController({
|
|
63
|
+
document,
|
|
64
|
+
window,
|
|
65
|
+
cssText,
|
|
66
|
+
service: themeService,
|
|
67
|
+
onTransitionStateChange(active) {
|
|
68
|
+
particleField.setSchemeTransitionActive(active)
|
|
69
|
+
},
|
|
70
|
+
})
|
|
63
71
|
const sessions = contextService(ctx, 'sessions')
|
|
64
72
|
const toBottom = createToBottomAdapter({ document, window })
|
|
65
73
|
const conversationControls = createConversationControlAdapter({ document, window })
|
|
@@ -160,8 +168,11 @@ export function applyPrtsPlugin(ctx, environment) {
|
|
|
160
168
|
if (!themeAlreadyApplied) theme.apply(preferences)
|
|
161
169
|
operations ||= createOperationsShell({
|
|
162
170
|
document, window, assets, adapter, hostGeometry,
|
|
163
|
-
onSchemeToggle(next) {
|
|
164
|
-
theme.setTheme(next)
|
|
171
|
+
onSchemeToggle(next, interaction) {
|
|
172
|
+
return theme.setTheme(next, { ...interaction, animate: true })
|
|
173
|
+
},
|
|
174
|
+
onSchemeDragStart(next, interaction) {
|
|
175
|
+
return theme.beginThemeTransition(next, interaction)
|
|
165
176
|
},
|
|
166
177
|
onThemeDisable() {
|
|
167
178
|
persistAndApply(updatePreferenceValue(preferences, 'enabled', false))
|
|
@@ -169,6 +180,10 @@ export function applyPrtsPlugin(ctx, environment) {
|
|
|
169
180
|
onPreferenceChange(key, value) {
|
|
170
181
|
persistAndApply(updatePreferenceValue(preferences, key, value))
|
|
171
182
|
},
|
|
183
|
+
onPreferencePreview(key, value) {
|
|
184
|
+
if (key !== 'particleTraversalSpeed') return
|
|
185
|
+
particleField.update(updatePreferenceValue(preferences, key, value))
|
|
186
|
+
},
|
|
172
187
|
onVisualReset() {
|
|
173
188
|
persistAndApply({
|
|
174
189
|
...DEFAULT_PREFERENCES,
|
|
@@ -35,8 +35,10 @@ export function createOperationsShell({
|
|
|
35
35
|
adapter,
|
|
36
36
|
hostGeometry,
|
|
37
37
|
onSchemeToggle = () => {},
|
|
38
|
+
onSchemeDragStart = () => undefined,
|
|
38
39
|
onThemeDisable = () => {},
|
|
39
40
|
onPreferenceChange = () => {},
|
|
41
|
+
onPreferencePreview = () => {},
|
|
40
42
|
onVisualReset = () => {},
|
|
41
43
|
getConversationScalePreview = () => ({ visible: false, reason: 'unmeasured', mode: 'hidden' }),
|
|
42
44
|
onRetrySave = () => {},
|
|
@@ -47,14 +49,79 @@ export function createOperationsShell({
|
|
|
47
49
|
let navRail
|
|
48
50
|
let railLauncher
|
|
49
51
|
let railMode
|
|
52
|
+
let railViewport
|
|
53
|
+
let railDefaultHidden = false
|
|
50
54
|
let railViewportQuery
|
|
51
55
|
let settingsOverlay
|
|
52
56
|
let schemeToggle
|
|
57
|
+
let schemeIntent
|
|
58
|
+
let schemePressRevision = 0
|
|
59
|
+
let schemePressAnimation
|
|
60
|
+
let schemePointer
|
|
61
|
+
let suppressSchemeClick = false
|
|
62
|
+
let suppressSchemeClickTimer
|
|
53
63
|
let themeDisable
|
|
54
64
|
let connectionIndicator
|
|
55
65
|
let conversationObserver
|
|
56
66
|
let schemeObserver
|
|
57
67
|
let operationRegion
|
|
68
|
+
const schemePressDelays = new Set()
|
|
69
|
+
|
|
70
|
+
function reducedMotion() {
|
|
71
|
+
if (root.dataset.prtsMotion === 'reduced') return true
|
|
72
|
+
try { return window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches === true } catch { return false }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function playSchemePress() {
|
|
76
|
+
if (!schemeToggle || reducedMotion()) return
|
|
77
|
+
const revision = ++schemePressRevision
|
|
78
|
+
schemePressAnimation?.cancel?.()
|
|
79
|
+
schemePressAnimation = undefined
|
|
80
|
+
schemeToggle.removeAttribute('data-prts-scheme-press')
|
|
81
|
+
|
|
82
|
+
if (typeof schemeToggle.animate === 'function') {
|
|
83
|
+
const animation = schemeToggle.animate([
|
|
84
|
+
{ transform: 'translateY(0) scale(1)' },
|
|
85
|
+
{ transform: 'translateY(0) scale(.96)', offset: 0.5 },
|
|
86
|
+
{ transform: 'translateY(0) scale(1)' },
|
|
87
|
+
], { duration: 100, easing: 'cubic-bezier(.22, 1, .36, 1)' })
|
|
88
|
+
schemePressAnimation = animation
|
|
89
|
+
Promise.resolve(animation.finished).catch(() => {}).finally(() => {
|
|
90
|
+
if (revision === schemePressRevision && schemePressAnimation === animation) schemePressAnimation = undefined
|
|
91
|
+
})
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
schemeToggle.setAttribute('data-prts-scheme-press', '')
|
|
96
|
+
const entry = { timer: undefined }
|
|
97
|
+
entry.timer = window.setTimeout(() => {
|
|
98
|
+
schemePressDelays.delete(entry)
|
|
99
|
+
if (revision === schemePressRevision) schemeToggle?.removeAttribute('data-prts-scheme-press')
|
|
100
|
+
}, 100)
|
|
101
|
+
schemePressDelays.add(entry)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function clearSchemePressDelays() {
|
|
105
|
+
schemePressRevision += 1
|
|
106
|
+
schemePressAnimation?.cancel?.()
|
|
107
|
+
schemePressAnimation = undefined
|
|
108
|
+
schemeToggle?.removeAttribute('data-prts-scheme-press')
|
|
109
|
+
for (const entry of schemePressDelays) {
|
|
110
|
+
window.clearTimeout(entry.timer)
|
|
111
|
+
}
|
|
112
|
+
schemePressDelays.clear()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function schemeTarget() {
|
|
116
|
+
const current = schemeIntent ?? (root.dataset.prtsScheme === 'dark' ? 'dark' : 'light')
|
|
117
|
+
return current === 'dark' ? 'light' : 'dark'
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function schemeOrigin() {
|
|
121
|
+
const rect = schemeToggle?.getBoundingClientRect?.()
|
|
122
|
+
return rect ? { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 } : undefined
|
|
123
|
+
}
|
|
124
|
+
|
|
58
125
|
function syncConversationState() {
|
|
59
126
|
if (!operationRegion) return
|
|
60
127
|
const candidate = operationRegion.querySelector(
|
|
@@ -65,13 +132,122 @@ export function createOperationsShell({
|
|
|
65
132
|
settingsOverlay?.refreshScalePreview()
|
|
66
133
|
}
|
|
67
134
|
|
|
68
|
-
function toggleScheme() {
|
|
69
|
-
|
|
135
|
+
function toggleScheme(event) {
|
|
136
|
+
if (suppressSchemeClick) {
|
|
137
|
+
event?.preventDefault?.()
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
const next = schemeTarget()
|
|
141
|
+
schemeIntent = next
|
|
142
|
+
playSchemePress()
|
|
143
|
+
let request
|
|
144
|
+
try { request = onSchemeToggle(next, { origin: schemeOrigin() }) } catch { request = undefined }
|
|
145
|
+
Promise.resolve(request).catch(() => {}).finally(() => {
|
|
146
|
+
if (schemeIntent === next) schemeIntent = undefined
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function schemePointerProgress(event) {
|
|
151
|
+
const width = Math.max(1, Number(window.innerWidth) || Number(root.clientWidth) || 1)
|
|
152
|
+
return Math.min(1, Math.max(0, Number(event?.clientX) / width || 0))
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function clearSchemeClickSuppression() {
|
|
156
|
+
if (suppressSchemeClickTimer !== undefined) window.clearTimeout(suppressSchemeClickTimer)
|
|
157
|
+
suppressSchemeClickTimer = undefined
|
|
158
|
+
suppressSchemeClick = false
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function suppressNextSchemeClick() {
|
|
162
|
+
clearSchemeClickSuppression()
|
|
163
|
+
suppressSchemeClick = true
|
|
164
|
+
suppressSchemeClickTimer = window.setTimeout(() => {
|
|
165
|
+
suppressSchemeClickTimer = undefined
|
|
166
|
+
suppressSchemeClick = false
|
|
167
|
+
}, 0)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function settleSchemePointer({ commit = false } = {}) {
|
|
171
|
+
const pointer = schemePointer
|
|
172
|
+
if (!pointer) return
|
|
173
|
+
schemePointer = undefined
|
|
174
|
+
try { schemeToggle?.releasePointerCapture?.(pointer.pointerId) } catch {}
|
|
175
|
+
if (!pointer.dragging) return
|
|
176
|
+
suppressNextSchemeClick()
|
|
177
|
+
let result
|
|
178
|
+
try { result = pointer.gesture?.finish?.(commit) } catch { result = undefined }
|
|
179
|
+
Promise.resolve(result).catch(() => {}).finally(() => {
|
|
180
|
+
if (schemeIntent === pointer.target) schemeIntent = undefined
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function onSchemePointerDown(event) {
|
|
185
|
+
if ((event.button ?? 0) !== 0 || schemePointer) return
|
|
186
|
+
const pointerId = event.pointerId ?? 1
|
|
187
|
+
schemePointer = {
|
|
188
|
+
pointerId,
|
|
189
|
+
startX: Number(event.clientX) || 0,
|
|
190
|
+
startY: Number(event.clientY) || 0,
|
|
191
|
+
target: schemeTarget(),
|
|
192
|
+
origin: schemeOrigin(),
|
|
193
|
+
dragging: false,
|
|
194
|
+
gesture: undefined,
|
|
195
|
+
}
|
|
196
|
+
try { schemeToggle?.setPointerCapture?.(pointerId) } catch {}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function onSchemePointerMove(event) {
|
|
200
|
+
const pointer = schemePointer
|
|
201
|
+
if (!pointer || (event.pointerId ?? 1) !== pointer.pointerId) return
|
|
202
|
+
const deltaX = (Number(event.clientX) || 0) - pointer.startX
|
|
203
|
+
if (!pointer.dragging) {
|
|
204
|
+
if (deltaX < 8) return
|
|
205
|
+
pointer.dragging = true
|
|
206
|
+
schemeIntent = pointer.target
|
|
207
|
+
playSchemePress()
|
|
208
|
+
const progress = schemePointerProgress(event)
|
|
209
|
+
try {
|
|
210
|
+
pointer.gesture = onSchemeDragStart(pointer.target, {
|
|
211
|
+
origin: pointer.origin,
|
|
212
|
+
progress,
|
|
213
|
+
clientX: Number(event.clientX) || 0,
|
|
214
|
+
})
|
|
215
|
+
} catch {
|
|
216
|
+
pointer.gesture = undefined
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
event.preventDefault?.()
|
|
220
|
+
pointer.gesture?.update?.(schemePointerProgress(event))
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function onSchemePointerUp(event) {
|
|
224
|
+
const pointer = schemePointer
|
|
225
|
+
if (!pointer || (event.pointerId ?? 1) !== pointer.pointerId) return
|
|
226
|
+
const commit = pointer.dragging && schemePointerProgress(event) >= .5
|
|
227
|
+
settleSchemePointer({ commit })
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function cancelSchemePointer() {
|
|
231
|
+
const pointer = schemePointer
|
|
232
|
+
if (!pointer) return
|
|
233
|
+
if (pointer.dragging) {
|
|
234
|
+
try { pointer.gesture?.cancel?.() } catch {}
|
|
235
|
+
}
|
|
236
|
+
schemePointer = undefined
|
|
237
|
+
try { schemeToggle?.releasePointerCapture?.(pointer.pointerId) } catch {}
|
|
238
|
+
if (pointer.dragging) suppressNextSchemeClick()
|
|
239
|
+
if (schemeIntent === pointer.target) schemeIntent = undefined
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function onSchemeLostPointerCapture(event) {
|
|
243
|
+
if (!schemePointer || (event.pointerId ?? 1) !== schemePointer.pointerId) return
|
|
244
|
+
cancelSchemePointer()
|
|
70
245
|
}
|
|
71
246
|
|
|
72
247
|
function syncSchemeToggle() {
|
|
73
248
|
if (!schemeToggle) return
|
|
74
249
|
const current = root.dataset.prtsScheme === 'dark' ? 'dark' : 'light'
|
|
250
|
+
if (schemeIntent === current) schemeIntent = undefined
|
|
75
251
|
schemeToggle.dataset.prtsSchemeCurrent = current
|
|
76
252
|
schemeToggle.setAttribute('aria-label', current === 'dark' ? '切换到日间模式' : '切换到夜间模式')
|
|
77
253
|
}
|
|
@@ -110,13 +286,16 @@ export function createOperationsShell({
|
|
|
110
286
|
else window?.setTimeout?.(focusFirst, 0)
|
|
111
287
|
}
|
|
112
288
|
|
|
113
|
-
function setRailViewport(width = window.innerWidth) {
|
|
114
|
-
const
|
|
115
|
-
|
|
289
|
+
function setRailViewport(width = window.innerWidth, { forceClose = false } = {}) {
|
|
290
|
+
const nextViewport = Number(width) >= 1180 ? 'wide' : 'narrow'
|
|
291
|
+
const viewportChanged = nextViewport !== railViewport
|
|
292
|
+
const nextMode = railDefaultHidden || nextViewport === 'narrow' ? 'overlay' : 'docked'
|
|
293
|
+
const modeChanged = nextMode !== railMode
|
|
294
|
+
if (!viewportChanged && !modeChanged && !forceClose) return railMode
|
|
295
|
+
railViewport = nextViewport
|
|
116
296
|
railMode = nextMode
|
|
117
297
|
root.dataset.prtsRailMode = nextMode
|
|
118
|
-
|
|
119
|
-
else root.removeAttribute('data-prts-rail-open')
|
|
298
|
+
root.removeAttribute('data-prts-rail-open')
|
|
120
299
|
syncRailState()
|
|
121
300
|
return nextMode
|
|
122
301
|
}
|
|
@@ -134,15 +313,12 @@ export function createOperationsShell({
|
|
|
134
313
|
|
|
135
314
|
function onDocumentClick(event) {
|
|
136
315
|
if (railMode !== 'overlay' || !root.hasAttribute('data-prts-rail-open')) return
|
|
137
|
-
|
|
316
|
+
const settingsPanel = shell?.querySelector?.('[data-prts-theme-settings]')
|
|
317
|
+
const insideSettingsContent = settingsPanel?.contains?.(event.target) && event.target !== settingsPanel
|
|
318
|
+
if (navRail?.contains?.(event.target) || railLauncher?.contains?.(event.target) || insideSettingsContent) return
|
|
138
319
|
closeRail()
|
|
139
320
|
}
|
|
140
321
|
|
|
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
322
|
function onResponsiveChange() {
|
|
147
323
|
setRailViewport(window.innerWidth)
|
|
148
324
|
settingsOverlay?.scheduleScalePreviewRefresh?.()
|
|
@@ -177,6 +353,7 @@ export function createOperationsShell({
|
|
|
177
353
|
panel: shell.querySelector('[data-prts-theme-settings]'),
|
|
178
354
|
backdrop: shell.querySelector('[data-prts-settings-backdrop]'),
|
|
179
355
|
onPreferenceChange,
|
|
356
|
+
onPreferencePreview,
|
|
180
357
|
onResetVisual: onVisualReset,
|
|
181
358
|
onRetrySave,
|
|
182
359
|
getConversationScalePreview,
|
|
@@ -191,10 +368,15 @@ export function createOperationsShell({
|
|
|
191
368
|
schemeObserver = new window.MutationObserver(syncSchemeToggle)
|
|
192
369
|
schemeObserver.observe(root, { attributes: true, attributeFilter: ['data-prts-scheme'] })
|
|
193
370
|
railLauncher.addEventListener('click', toggleRail)
|
|
194
|
-
navRail.addEventListener('click', onRailAction)
|
|
195
371
|
document.addEventListener('keydown', onRailKeydown)
|
|
196
372
|
document.addEventListener('click', onDocumentClick)
|
|
197
373
|
schemeToggle.addEventListener('click', toggleScheme)
|
|
374
|
+
schemeToggle.addEventListener('pointerdown', onSchemePointerDown)
|
|
375
|
+
schemeToggle.addEventListener('pointermove', onSchemePointerMove)
|
|
376
|
+
schemeToggle.addEventListener('pointerup', onSchemePointerUp)
|
|
377
|
+
schemeToggle.addEventListener('pointercancel', cancelSchemePointer)
|
|
378
|
+
schemeToggle.addEventListener('lostpointercapture', onSchemeLostPointerCapture)
|
|
379
|
+
window.addEventListener?.('blur', cancelSchemePointer)
|
|
198
380
|
themeDisable.addEventListener('click', disableTheme)
|
|
199
381
|
syncConversationState()
|
|
200
382
|
syncSchemeToggle()
|
|
@@ -202,11 +384,19 @@ export function createOperationsShell({
|
|
|
202
384
|
}
|
|
203
385
|
|
|
204
386
|
function dispose() {
|
|
387
|
+
cancelSchemePointer()
|
|
388
|
+
clearSchemeClickSuppression()
|
|
389
|
+
clearSchemePressDelays()
|
|
205
390
|
railLauncher?.removeEventListener('click', toggleRail)
|
|
206
|
-
navRail?.removeEventListener('click', onRailAction)
|
|
207
391
|
document.removeEventListener('keydown', onRailKeydown)
|
|
208
392
|
document.removeEventListener('click', onDocumentClick)
|
|
209
393
|
schemeToggle?.removeEventListener('click', toggleScheme)
|
|
394
|
+
schemeToggle?.removeEventListener('pointerdown', onSchemePointerDown)
|
|
395
|
+
schemeToggle?.removeEventListener('pointermove', onSchemePointerMove)
|
|
396
|
+
schemeToggle?.removeEventListener('pointerup', onSchemePointerUp)
|
|
397
|
+
schemeToggle?.removeEventListener('pointercancel', cancelSchemePointer)
|
|
398
|
+
schemeToggle?.removeEventListener('lostpointercapture', onSchemeLostPointerCapture)
|
|
399
|
+
window.removeEventListener?.('blur', cancelSchemePointer)
|
|
210
400
|
themeDisable?.removeEventListener('click', disableTheme)
|
|
211
401
|
railViewportQuery?.removeEventListener?.('change', onResponsiveChange)
|
|
212
402
|
railViewportQuery = undefined
|
|
@@ -218,7 +408,10 @@ export function createOperationsShell({
|
|
|
218
408
|
root.removeAttribute('data-prts-conversation-state')
|
|
219
409
|
root.removeAttribute('data-prts-rail-mode')
|
|
220
410
|
root.removeAttribute('data-prts-rail-open')
|
|
221
|
-
|
|
411
|
+
root.removeAttribute('data-prts-rail-default-hidden')
|
|
412
|
+
navRail = railLauncher = railMode = railViewport = undefined
|
|
413
|
+
railDefaultHidden = false
|
|
414
|
+
schemeIntent = undefined
|
|
222
415
|
shell = settingsOverlay = schemeToggle = themeDisable = connectionIndicator = undefined
|
|
223
416
|
conversationObserver = schemeObserver = undefined
|
|
224
417
|
operationRegion = undefined
|
|
@@ -232,7 +425,12 @@ export function createOperationsShell({
|
|
|
232
425
|
dispose()
|
|
233
426
|
return false
|
|
234
427
|
}
|
|
428
|
+
const nextRailDefaultHidden = Boolean(preferences.railDefaultHidden)
|
|
429
|
+
const railPreferenceChanged = nextRailDefaultHidden !== railDefaultHidden
|
|
430
|
+
railDefaultHidden = nextRailDefaultHidden
|
|
235
431
|
if (!mount()) return false
|
|
432
|
+
root.toggleAttribute('data-prts-rail-default-hidden', railDefaultHidden)
|
|
433
|
+
setRailViewport(window.innerWidth, { forceClose: railPreferenceChanged })
|
|
236
434
|
const connection = status?.connection || 'unknown'
|
|
237
435
|
const connectionLabel = status?.connectionLabel || '未知'
|
|
238
436
|
connectionIndicator.dataset.state = connection
|