@ash-qw/dsh-theme-prts 0.1.96 → 0.1.98
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 +12 -1
- package/README.en.md +3 -3
- package/README.md +3 -3
- package/lib/client.js +272 -52
- package/package.json +2 -2
- package/src/client/assistant-glass-adapter.js +54 -4
- package/src/client/composer-glass-adapter.js +27 -10
- package/src/client/index.js +25 -6
- package/src/client/operations-shell-v2.js +4 -1
- package/src/client/particle-field-adapter.js +24 -12
- package/src/client/preferences.js +7 -3
- package/src/client/rc7-adapter.js +48 -11
- package/src/client/startup-sequence.js +102 -9
- package/src/client/theme-controller-v2.js +2 -0
- package/src/client/theme-controller.js +2 -0
- package/src/client/theme-settings-workbench.js +3 -0
- package/src/styles/prts.css +362 -19
- package/src/styles/refinement.css +8 -4
- package/src/styles/stabilization.css +34 -2
- package/src/styles/startup-sequence.css +13 -6
- package/src/styles/theme-settings-workbench.css +7 -0
|
@@ -24,7 +24,7 @@ const STARTUP_STAGES = Object.freeze({
|
|
|
24
24
|
|
|
25
25
|
function startupMarkup(prtsEmblem = '', rhodesEmblem = '') {
|
|
26
26
|
const ticks = Array.from({ length: 21 }, (_, index) => `<i${index % 5 === 0 ? ' data-major' : ''}></i>`).join('')
|
|
27
|
-
return `<section data-prts-startup data-stage="boot" popover="manual" role="status" aria-live="assertive" aria-label="P.R.T.S. 启动序列"
|
|
27
|
+
return `<section data-prts-startup data-stage="boot" popover="manual" role="status" aria-live="assertive" aria-label="P.R.T.S. 启动序列">
|
|
28
28
|
<div data-prts-startup-grid aria-hidden="true"></div>
|
|
29
29
|
<div data-prts-startup-scan aria-hidden="true"></div>
|
|
30
30
|
<div data-prts-startup-cut="left" aria-hidden="true"></div>
|
|
@@ -73,16 +73,60 @@ function easeOutCubic(value) {
|
|
|
73
73
|
return 1 - Math.pow(1 - clamp01(value), 3)
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
function approachProgressAt(elapsed, duration) {
|
|
77
|
+
if (!(duration > 0)) return 90
|
|
78
|
+
return 90 * easeOutCubic(elapsed / duration)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function approachVelocityAt(elapsed, duration) {
|
|
82
|
+
if (!(duration > 0)) return 0
|
|
83
|
+
const remaining = 1 - clamp01(elapsed / duration)
|
|
84
|
+
return 270 * remaining * remaining / duration
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function finishProgressAt(startProgress, startVelocity, elapsed, duration) {
|
|
88
|
+
if (!(duration > 0)) return 100
|
|
89
|
+
const progressDelta = Math.max(0, 100 - startProgress)
|
|
90
|
+
if (progressDelta === 0) return 100
|
|
91
|
+
const time = clamp01(elapsed / duration)
|
|
92
|
+
const timeSquared = time * time
|
|
93
|
+
const timeCubed = timeSquared * time
|
|
94
|
+
const startWeight = 2 * timeCubed - 3 * timeSquared + 1
|
|
95
|
+
const velocityWeight = timeCubed - 2 * timeSquared + time
|
|
96
|
+
const endWeight = -2 * timeCubed + 3 * timeSquared
|
|
97
|
+
const startTangent = Math.min(progressDelta * 3, Math.max(0, startVelocity) * duration)
|
|
98
|
+
const progress = startWeight * startProgress
|
|
99
|
+
+ velocityWeight * startTangent
|
|
100
|
+
+ endWeight * 100
|
|
101
|
+
return Math.max(startProgress, Math.min(100, progress))
|
|
102
|
+
}
|
|
103
|
+
|
|
76
104
|
export function findNativeHarnessLoader(document) {
|
|
77
105
|
return document?.querySelector?.('[data-dsh-boot]') ?? null
|
|
78
106
|
}
|
|
79
107
|
|
|
108
|
+
function matchesOpenTopLayer(node) {
|
|
109
|
+
for (const selector of [':modal', ':popover-open']) {
|
|
110
|
+
try {
|
|
111
|
+
if (node?.matches?.(selector)) return true
|
|
112
|
+
} catch {}
|
|
113
|
+
}
|
|
114
|
+
return false
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function hostHasOpenTopLayer(document, overlay) {
|
|
118
|
+
const candidates = [...(document?.querySelectorAll?.('dialog[open], [popover]') ?? [])]
|
|
119
|
+
return candidates.some(node => node !== overlay && matchesOpenTopLayer(node))
|
|
120
|
+
}
|
|
121
|
+
|
|
80
122
|
export function createPrtsStartupSequence({
|
|
81
123
|
document,
|
|
82
124
|
window,
|
|
83
125
|
prtsEmblem = '',
|
|
84
126
|
rhodesEmblem = '',
|
|
85
127
|
timings = PRTS_STARTUP_TIMINGS,
|
|
128
|
+
onActiveChange = () => {},
|
|
129
|
+
onReady = () => {},
|
|
86
130
|
} = {}) {
|
|
87
131
|
const schedule = { ...PRTS_STARTUP_TIMINGS, ...timings }
|
|
88
132
|
let overlay
|
|
@@ -95,6 +139,7 @@ export function createPrtsStartupSequence({
|
|
|
95
139
|
let hostReady = false
|
|
96
140
|
let finishStartedAt
|
|
97
141
|
let finishStartedProgress = 0
|
|
142
|
+
let finishStartedVelocity = 0
|
|
98
143
|
let readyStartedAt
|
|
99
144
|
let exitStartedAt
|
|
100
145
|
let timeoutStartedAt
|
|
@@ -102,7 +147,12 @@ export function createPrtsStartupSequence({
|
|
|
102
147
|
let pendingStage
|
|
103
148
|
let copyTransitionStartedAt
|
|
104
149
|
let lastProgress = -1
|
|
150
|
+
let lastRoundedProgress = -1
|
|
105
151
|
let useReducedMotion = false
|
|
152
|
+
let progressFill
|
|
153
|
+
let progressPercent
|
|
154
|
+
let activeReported = false
|
|
155
|
+
let readyReported = false
|
|
106
156
|
|
|
107
157
|
const now = () => window?.performance?.now?.() ?? Date.now()
|
|
108
158
|
const requestFrame = callback => window?.requestAnimationFrame?.(callback)
|
|
@@ -113,6 +163,21 @@ export function createPrtsStartupSequence({
|
|
|
113
163
|
else window?.clearTimeout?.(id)
|
|
114
164
|
}
|
|
115
165
|
|
|
166
|
+
function notify(callback, value) {
|
|
167
|
+
try {
|
|
168
|
+
callback(value)
|
|
169
|
+
} catch {
|
|
170
|
+
// Startup remains fail-open when an integration callback fails.
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function reportActive(active) {
|
|
175
|
+
const next = Boolean(active)
|
|
176
|
+
if (activeReported === next) return
|
|
177
|
+
activeReported = next
|
|
178
|
+
notify(onActiveChange, next)
|
|
179
|
+
}
|
|
180
|
+
|
|
116
181
|
function restoreInteractivity() {
|
|
117
182
|
for (const record of inertRecords) {
|
|
118
183
|
if (!record.node?.isConnected) continue
|
|
@@ -135,9 +200,12 @@ export function createPrtsStartupSequence({
|
|
|
135
200
|
}
|
|
136
201
|
overlay?.remove?.()
|
|
137
202
|
overlay = undefined
|
|
203
|
+
progressFill = undefined
|
|
204
|
+
progressPercent = undefined
|
|
138
205
|
restoreInteractivity()
|
|
139
206
|
if (restoreFocus && previousFocus?.isConnected) previousFocus.focus?.()
|
|
140
207
|
previousFocus = undefined
|
|
208
|
+
reportActive(false)
|
|
141
209
|
}
|
|
142
210
|
|
|
143
211
|
function updateProgress(progress) {
|
|
@@ -145,9 +213,12 @@ export function createPrtsStartupSequence({
|
|
|
145
213
|
const safeProgress = Math.max(0, Math.min(100, progress))
|
|
146
214
|
if (Math.abs(safeProgress - lastProgress) < .01) return
|
|
147
215
|
lastProgress = safeProgress
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
if (
|
|
216
|
+
if (progressFill) progressFill.style.transform = `scaleX(${(safeProgress / 100).toFixed(4)})`
|
|
217
|
+
const roundedProgress = Math.round(safeProgress)
|
|
218
|
+
if (progressPercent && roundedProgress !== lastRoundedProgress) {
|
|
219
|
+
lastRoundedProgress = roundedProgress
|
|
220
|
+
progressPercent.textContent = `${String(roundedProgress).padStart(3, '0')}%`
|
|
221
|
+
}
|
|
151
222
|
}
|
|
152
223
|
|
|
153
224
|
function applyStage(name) {
|
|
@@ -161,6 +232,10 @@ export function createPrtsStartupSequence({
|
|
|
161
232
|
if (label) label.textContent = stage.label
|
|
162
233
|
if (detail) detail.textContent = stage.detail
|
|
163
234
|
overlay.setAttribute('aria-label', `P.R.T.S. 启动序列:${stage.detail}`)
|
|
235
|
+
if (name === 'ready' && !readyReported) {
|
|
236
|
+
readyReported = true
|
|
237
|
+
notify(onReady)
|
|
238
|
+
}
|
|
164
239
|
}
|
|
165
240
|
|
|
166
241
|
function requestStage(name, elapsed) {
|
|
@@ -218,7 +293,14 @@ export function createPrtsStartupSequence({
|
|
|
218
293
|
}
|
|
219
294
|
|
|
220
295
|
function promoteToTopLayer() {
|
|
221
|
-
if (
|
|
296
|
+
if (!hostHasOpenTopLayer(document, overlay)) {
|
|
297
|
+
overlay?.removeAttribute('popover')
|
|
298
|
+
return
|
|
299
|
+
}
|
|
300
|
+
if (typeof overlay?.showPopover !== 'function') {
|
|
301
|
+
overlay?.removeAttribute('popover')
|
|
302
|
+
return
|
|
303
|
+
}
|
|
222
304
|
try {
|
|
223
305
|
overlay.showPopover()
|
|
224
306
|
} catch {
|
|
@@ -266,7 +348,7 @@ export function createPrtsStartupSequence({
|
|
|
266
348
|
updateProgress(90)
|
|
267
349
|
if (elapsed - timeoutStartedAt >= schedule.timeoutHold) beginExit(elapsed, { failOpen: true })
|
|
268
350
|
} else {
|
|
269
|
-
const approachProgress =
|
|
351
|
+
const approachProgress = approachProgressAt(elapsed, schedule.approach)
|
|
270
352
|
let progress = Math.min(90, approachProgress)
|
|
271
353
|
|
|
272
354
|
if (!hostReady && elapsed >= schedule.timeout) {
|
|
@@ -275,9 +357,14 @@ export function createPrtsStartupSequence({
|
|
|
275
357
|
if (finishStartedAt === undefined) {
|
|
276
358
|
finishStartedAt = elapsed
|
|
277
359
|
finishStartedProgress = progress
|
|
360
|
+
finishStartedVelocity = approachVelocityAt(elapsed, schedule.approach)
|
|
278
361
|
}
|
|
279
|
-
progress =
|
|
280
|
-
|
|
362
|
+
progress = finishProgressAt(
|
|
363
|
+
finishStartedProgress,
|
|
364
|
+
finishStartedVelocity,
|
|
365
|
+
elapsed - finishStartedAt,
|
|
366
|
+
schedule.finish,
|
|
367
|
+
)
|
|
281
368
|
if (elapsed - finishStartedAt >= schedule.finish) {
|
|
282
369
|
progress = 100
|
|
283
370
|
requestStage('ready', elapsed)
|
|
@@ -332,18 +419,24 @@ export function createPrtsStartupSequence({
|
|
|
332
419
|
readyStartedAt = undefined
|
|
333
420
|
exitStartedAt = undefined
|
|
334
421
|
timeoutStartedAt = undefined
|
|
422
|
+
finishStartedVelocity = 0
|
|
335
423
|
currentStage = 'boot'
|
|
336
424
|
pendingStage = undefined
|
|
337
425
|
copyTransitionStartedAt = undefined
|
|
338
426
|
lastProgress = -1
|
|
427
|
+
activeReported = false
|
|
428
|
+
readyReported = false
|
|
339
429
|
useReducedMotion = reducedMotionRequested(reduced)
|
|
340
430
|
|
|
341
431
|
previousFocus = document.activeElement
|
|
432
|
+
lastRoundedProgress = -1
|
|
342
433
|
document.body.appendChild(overlay)
|
|
434
|
+
progressFill = overlay.querySelector('[data-prts-startup-fill]')
|
|
435
|
+
progressPercent = overlay.querySelector('[data-prts-startup-percent]')
|
|
343
436
|
promoteToTopLayer()
|
|
344
437
|
document.documentElement.setAttribute('data-prts-startup-active', '')
|
|
345
438
|
lockSiblings()
|
|
346
|
-
|
|
439
|
+
reportActive(true)
|
|
347
440
|
document.addEventListener('visibilitychange', onVisibilityChange)
|
|
348
441
|
|
|
349
442
|
if (useReducedMotion) {
|
|
@@ -7,6 +7,7 @@ const ROOT_ATTRIBUTES = [
|
|
|
7
7
|
'data-prts-glass',
|
|
8
8
|
'data-prts-motion',
|
|
9
9
|
'data-prts-particle-pattern',
|
|
10
|
+
'data-prts-conversation-style',
|
|
10
11
|
]
|
|
11
12
|
|
|
12
13
|
const TRANSITION_ATTRIBUTE = 'data-prts-scheme-transition'
|
|
@@ -715,6 +716,7 @@ export function createThemeController({ document, window, cssText, service, onTr
|
|
|
715
716
|
root.dataset.prtsGlass = preferences.glass
|
|
716
717
|
root.dataset.prtsMotion = preferences.motion
|
|
717
718
|
root.dataset.prtsParticlePattern = 'orthogonal'
|
|
719
|
+
root.dataset.prtsConversationStyle = preferences.conversationStyle
|
|
718
720
|
refresh()
|
|
719
721
|
},
|
|
720
722
|
sync,
|
|
@@ -7,6 +7,7 @@ const ROOT_ATTRIBUTES = [
|
|
|
7
7
|
'data-prts-glass',
|
|
8
8
|
'data-prts-motion',
|
|
9
9
|
'data-prts-particle-pattern',
|
|
10
|
+
'data-prts-conversation-style',
|
|
10
11
|
]
|
|
11
12
|
|
|
12
13
|
function themeIdentity(value) {
|
|
@@ -108,6 +109,7 @@ export function createThemeController({ document, window, cssText, service }) {
|
|
|
108
109
|
root.dataset.prtsGlass = preferences.glass
|
|
109
110
|
root.dataset.prtsMotion = preferences.motion
|
|
110
111
|
root.dataset.prtsParticlePattern = 'orthogonal'
|
|
112
|
+
root.dataset.prtsConversationStyle = preferences.conversationStyle
|
|
111
113
|
refresh()
|
|
112
114
|
},
|
|
113
115
|
sync,
|
|
@@ -19,6 +19,7 @@ const COMMON_CONTROLS = [
|
|
|
19
19
|
['texture', '环境底纹', [['off', '关闭'], ['restrained', '克制'], ['full', '完整']]],
|
|
20
20
|
['glass', '玻璃材质', [['off', '关闭'], ['soft', '柔和'], ['standard', '标准'], ['clear', '清晰']]],
|
|
21
21
|
['motion', '动态效果', [['system', '跟随系统'], ['reduced', '减少']]],
|
|
22
|
+
['conversationStyle', '会话主题', [['native', '原有'], ['deck-chat', '通讯链路']]],
|
|
22
23
|
]
|
|
23
24
|
|
|
24
25
|
const PARTICLE_OPTIONS = [
|
|
@@ -34,6 +35,8 @@ function settingButtons(key, label, options) {
|
|
|
34
35
|
? '<small data-prts-setting-note data-prts-effective-motion hidden>系统当前要求减少动态</small>'
|
|
35
36
|
: key === 'railDefaultHidden'
|
|
36
37
|
? '<small data-prts-setting-note>在任意窗口宽度下默认收起 P.R.T.S. 导航,可从左侧按钮临时展开</small>'
|
|
38
|
+
: key === 'conversationStyle'
|
|
39
|
+
? '<small data-prts-setting-note>立即切换会话背景、头像与消息气泡</small>'
|
|
37
40
|
: ''
|
|
38
41
|
const sample = value => key === 'texture' || key === 'glass'
|
|
39
42
|
? `<i data-prts-option-sample="${key}" data-prts-option-sample-value="${value}" aria-hidden="true"></i>`
|