@ash-qw/dsh-theme-prts 0.1.94 → 0.1.95
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 +7 -0
- package/README.en.md +3 -3
- package/README.md +3 -3
- package/lib/client.js +12 -2482
- package/package.json +2 -2
- package/src/client/composer-glass-adapter.js +6 -5
- package/src/client/index.js +1 -11
- package/src/client/operations-shell-v2.js +0 -4
- package/src/client/preferences.js +1 -35
- package/src/client/theme-settings-workbench.js +3 -234
- package/src/styles/prts.css +2 -61
- package/src/styles/theme-settings-workbench.css +1 -174
- package/src/client/conversation-scale-adapter.js +0 -2347
- package/src/styles/conversation-scale.css +0 -471
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ash-qw/dsh-theme-prts",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.95",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Unofficial Arknights P.R.T.S.-inspired UI theme for DeepSeek Harness Web",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"node": ">=18"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
|
-
"@playwright/test": "1.55.
|
|
73
|
+
"@playwright/test": "1.55.1",
|
|
74
74
|
"jsdom": "24.1.3"
|
|
75
75
|
}
|
|
76
76
|
}
|
|
@@ -9,6 +9,7 @@ const COMPOSER_RELEVANCE_SELECTOR = [
|
|
|
9
9
|
'button[aria-haspopup="listbox"]',
|
|
10
10
|
'[role="menu"]',
|
|
11
11
|
'[role="listbox"]',
|
|
12
|
+
'[data-trigger-menu]',
|
|
12
13
|
'[data-slot="conversation.input.overlay"]',
|
|
13
14
|
].join(', ')
|
|
14
15
|
const PRESET_TRIGGER_SELECTOR = [
|
|
@@ -27,7 +28,7 @@ function controlledPopup(document, trigger) {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
function localPopup(trigger) {
|
|
30
|
-
const selector = '[role="menu"], [role="listbox"], [class*="mufS8W_card"]'
|
|
31
|
+
const selector = '[role="menu"], [role="listbox"], [data-trigger-menu], [class*="mufS8W_card"]'
|
|
31
32
|
const sibling = trigger.nextElementSibling
|
|
32
33
|
if (sibling?.matches(selector)) return sibling
|
|
33
34
|
return trigger.parentElement?.querySelector(`:scope > ${selector}`) ?? null
|
|
@@ -36,7 +37,7 @@ function localPopup(trigger) {
|
|
|
36
37
|
function overlayPopup(document) {
|
|
37
38
|
const overlay = document.querySelector('[data-slot="conversation.input.overlay"]')
|
|
38
39
|
if (!overlay) return null
|
|
39
|
-
return overlay.querySelector('[role="listbox"], [role="menu"], [class*="mufS8W_card"]')
|
|
40
|
+
return overlay.querySelector('[data-trigger-menu], [role="listbox"], [role="menu"], [class*="mufS8W_card"]')
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
function linkedMenu(document, trigger) {
|
|
@@ -48,9 +49,9 @@ function linkedMenu(document, trigger) {
|
|
|
48
49
|
function markPopup(popup, kind) {
|
|
49
50
|
if (!popup) return
|
|
50
51
|
mark(popup, MENU_ATTRIBUTE, kind)
|
|
51
|
-
const card = popup.closest?.('[class*="mufS8W_card"]')
|
|
52
|
+
const card = popup.closest?.('[data-trigger-menu], [class*="mufS8W_card"]')
|
|
52
53
|
mark(card, MENU_ATTRIBUTE, kind)
|
|
53
|
-
for (const nested of popup.querySelectorAll?.('[role="menu"], [role="listbox"], [class*="mufS8W_card"]') ?? []) {
|
|
54
|
+
for (const nested of popup.querySelectorAll?.('[role="menu"], [role="listbox"], [data-trigger-menu], [class*="mufS8W_card"]') ?? []) {
|
|
54
55
|
mark(nested, MENU_ATTRIBUTE, kind)
|
|
55
56
|
}
|
|
56
57
|
}
|
|
@@ -162,7 +163,7 @@ export function createComposerGlassAdapter({ document, window }) {
|
|
|
162
163
|
|
|
163
164
|
const overlay = document?.querySelector?.('[data-slot="conversation.input.overlay"]')
|
|
164
165
|
if (overlay) {
|
|
165
|
-
for (const popup of overlay.querySelectorAll('[role="menu"], [role="listbox"], [class*="mufS8W_card"]')) {
|
|
166
|
+
for (const popup of overlay.querySelectorAll('[data-trigger-menu], [role="menu"], [role="listbox"], [class*="mufS8W_card"]')) {
|
|
166
167
|
markPopup(popup, popup.hasAttribute('aria-busy') ? 'model' : 'action')
|
|
167
168
|
}
|
|
168
169
|
}
|
package/src/client/index.js
CHANGED
|
@@ -12,7 +12,6 @@ import { createThemeController } from './theme-controller-v2.js'
|
|
|
12
12
|
import { createParticleFieldAdapter } from './particle-field-adapter.js'
|
|
13
13
|
import { createToBottomAdapter } from './to-bottom-adapter.js'
|
|
14
14
|
import { createConversationControlAdapter } from './conversation-control-adapter.js'
|
|
15
|
-
import { createConversationScaleAdapter } from './conversation-scale-adapter.js'
|
|
16
15
|
import { createLayoutStabilityDiagnostics } from './layout-stability-diagnostics.js'
|
|
17
16
|
import { createSidebarControlAdapter } from './sidebar-control-adapter.js'
|
|
18
17
|
import { createFloatingGlassAdapter } from './floating-glass-adapter.js'
|
|
@@ -68,10 +67,8 @@ export function applyPrtsPlugin(ctx, environment) {
|
|
|
68
67
|
particleField.setSchemeTransitionActive(active)
|
|
69
68
|
},
|
|
70
69
|
})
|
|
71
|
-
const sessions = contextService(ctx, 'sessions')
|
|
72
70
|
const toBottom = createToBottomAdapter({ document, window })
|
|
73
71
|
const conversationControls = createConversationControlAdapter({ document, window })
|
|
74
|
-
const conversationScale = createConversationScaleAdapter({ document, window, sessions })
|
|
75
72
|
const layoutDiagnostics = createLayoutStabilityDiagnostics({ document, window })
|
|
76
73
|
const sidebarControls = createSidebarControlAdapter({ document, window })
|
|
77
74
|
const floatingGlass = createFloatingGlassAdapter({ document, window })
|
|
@@ -153,7 +150,6 @@ export function applyPrtsPlugin(ctx, environment) {
|
|
|
153
150
|
particleField.update({ ...preferences, enabled: false })
|
|
154
151
|
toBottom.dispose()
|
|
155
152
|
conversationControls.dispose()
|
|
156
|
-
conversationScale.dispose()
|
|
157
153
|
layoutDiagnostics.dispose()
|
|
158
154
|
sidebarControls.dispose()
|
|
159
155
|
floatingGlass.dispose()
|
|
@@ -194,9 +190,6 @@ export function applyPrtsPlugin(ctx, environment) {
|
|
|
194
190
|
onRetrySave() {
|
|
195
191
|
retryPersistence()
|
|
196
192
|
},
|
|
197
|
-
getConversationScalePreview(value) {
|
|
198
|
-
return conversationScale.getCalibrationState(value)
|
|
199
|
-
},
|
|
200
193
|
})
|
|
201
194
|
if (!operations.update(preferences, status, settingsPersistence)) {
|
|
202
195
|
if (!mountWarningIssued) {
|
|
@@ -216,8 +209,6 @@ export function applyPrtsPlugin(ctx, environment) {
|
|
|
216
209
|
assistantGlass.start()
|
|
217
210
|
toBottom.start()
|
|
218
211
|
conversationControls.start()
|
|
219
|
-
conversationScale.update(preferences)
|
|
220
|
-
conversationScale.start()
|
|
221
212
|
layoutDiagnostics.start()
|
|
222
213
|
sidebarControls.start()
|
|
223
214
|
floatingGlass.start()
|
|
@@ -315,7 +306,6 @@ export function applyPrtsPlugin(ctx, environment) {
|
|
|
315
306
|
particleField.dispose()
|
|
316
307
|
toBottom.dispose()
|
|
317
308
|
conversationControls.dispose()
|
|
318
|
-
conversationScale.dispose()
|
|
319
309
|
layoutDiagnostics.dispose()
|
|
320
310
|
sidebarControls.dispose()
|
|
321
311
|
floatingGlass.dispose()
|
|
@@ -361,7 +351,7 @@ export function applyPrtsPlugin(ctx, environment) {
|
|
|
361
351
|
|
|
362
352
|
export function apply(ctx) {
|
|
363
353
|
const React = require('react')
|
|
364
|
-
const { defineStore } = require('@deepseek-ai/dsh-client-
|
|
354
|
+
const { defineStore } = require('@deepseek-ai/dsh-client-store')
|
|
365
355
|
applyPrtsPlugin(ctx, {
|
|
366
356
|
document,
|
|
367
357
|
window,
|
|
@@ -46,7 +46,6 @@ export function createOperationsShell({
|
|
|
46
46
|
onPreferenceChange = () => {},
|
|
47
47
|
onPreferencePreview = () => {},
|
|
48
48
|
onVisualReset = () => {},
|
|
49
|
-
getConversationScalePreview = () => ({ visible: false, reason: 'unmeasured', mode: 'hidden' }),
|
|
50
49
|
onRetrySave = () => {},
|
|
51
50
|
}) {
|
|
52
51
|
const root = document.documentElement
|
|
@@ -222,7 +221,6 @@ export function createOperationsShell({
|
|
|
222
221
|
)
|
|
223
222
|
const active = Boolean(candidate)
|
|
224
223
|
root.dataset.prtsConversationState = active ? 'active' : 'idle'
|
|
225
|
-
settingsOverlay?.refreshScalePreview()
|
|
226
224
|
}
|
|
227
225
|
|
|
228
226
|
function toggleScheme(event) {
|
|
@@ -418,7 +416,6 @@ export function createOperationsShell({
|
|
|
418
416
|
clearRailGesture()
|
|
419
417
|
setRailViewport(window.innerWidth)
|
|
420
418
|
syncRailState()
|
|
421
|
-
settingsOverlay?.scheduleScalePreviewRefresh?.()
|
|
422
419
|
}
|
|
423
420
|
|
|
424
421
|
function bindResponsiveQueries() {
|
|
@@ -457,7 +454,6 @@ export function createOperationsShell({
|
|
|
457
454
|
onPreferencePreview,
|
|
458
455
|
onResetVisual: onVisualReset,
|
|
459
456
|
onRetrySave,
|
|
460
|
-
getConversationScalePreview,
|
|
461
457
|
})
|
|
462
458
|
resizeShield.start([
|
|
463
459
|
operationRegion,
|
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
export const PRTS_STORAGE_KEY = 'dsh.ui.prts.v1'
|
|
2
2
|
|
|
3
|
-
export const CONVERSATION_SCALE_DISTANCE_MIN = 16
|
|
4
|
-
export const CONVERSATION_SCALE_DISTANCE_MAX = 240
|
|
5
|
-
export const CONVERSATION_SCALE_DISTANCE_STEP = 8
|
|
6
|
-
export const CONVERSATION_SCALE_DISTANCE_DEFAULT = 96
|
|
7
|
-
|
|
8
|
-
export const CONVERSATION_SCALE_FOCUS_CONTRAST_MIN = 0
|
|
9
|
-
export const CONVERSATION_SCALE_FOCUS_CONTRAST_MAX = 100
|
|
10
|
-
export const CONVERSATION_SCALE_FOCUS_CONTRAST_STEP = 10
|
|
11
|
-
export const CONVERSATION_SCALE_FOCUS_CONTRAST_DEFAULT = 70
|
|
12
|
-
|
|
13
3
|
export const PARTICLE_TRAVERSAL_SPEED_MIN = 0
|
|
14
4
|
export const PARTICLE_TRAVERSAL_SPEED_MAX = 2
|
|
15
5
|
export const PARTICLE_TRAVERSAL_SPEED_STEP = 0.25
|
|
@@ -28,8 +18,6 @@ export const DEFAULT_PREFERENCES = Object.freeze({
|
|
|
28
18
|
particleTraversalSpeed: PARTICLE_TRAVERSAL_SPEED_DEFAULT,
|
|
29
19
|
particlePattern: 'orthogonal',
|
|
30
20
|
railDefaultHidden: false,
|
|
31
|
-
conversationScaleMaxDistance: CONVERSATION_SCALE_DISTANCE_DEFAULT,
|
|
32
|
-
conversationScaleFocusContrast: CONVERSATION_SCALE_FOCUS_CONTRAST_DEFAULT,
|
|
33
21
|
})
|
|
34
22
|
|
|
35
23
|
export const VISUAL_PRESETS = Object.freeze({
|
|
@@ -70,7 +58,7 @@ export const PREFERENCE_GROUPS = Object.freeze({
|
|
|
70
58
|
particles: Object.freeze(['conversationParticleDensity', 'heroParticleDensity', 'particleTraversalSpeed']),
|
|
71
59
|
material: Object.freeze(['glass']),
|
|
72
60
|
accessibility: Object.freeze(['motion', 'bootAnimation']),
|
|
73
|
-
navigation: Object.freeze(['railDefaultHidden'
|
|
61
|
+
navigation: Object.freeze(['railDefaultHidden']),
|
|
74
62
|
})
|
|
75
63
|
|
|
76
64
|
const TEXTURES = new Set(['off', 'restrained', 'full'])
|
|
@@ -107,20 +95,6 @@ function enumOr(value, allowed, fallback) {
|
|
|
107
95
|
return allowed.has(value) ? value : fallback
|
|
108
96
|
}
|
|
109
97
|
|
|
110
|
-
function scaleDistanceOr(value, fallback) {
|
|
111
|
-
const numeric = Number(value)
|
|
112
|
-
if (!Number.isFinite(numeric)) return fallback
|
|
113
|
-
const clamped = Math.min(CONVERSATION_SCALE_DISTANCE_MAX, Math.max(CONVERSATION_SCALE_DISTANCE_MIN, numeric))
|
|
114
|
-
return Math.round(clamped / CONVERSATION_SCALE_DISTANCE_STEP) * CONVERSATION_SCALE_DISTANCE_STEP
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function scaleFocusContrastOr(value, fallback) {
|
|
118
|
-
const numeric = Number(value)
|
|
119
|
-
if (!Number.isFinite(numeric)) return fallback
|
|
120
|
-
const clamped = Math.min(CONVERSATION_SCALE_FOCUS_CONTRAST_MAX, Math.max(CONVERSATION_SCALE_FOCUS_CONTRAST_MIN, numeric))
|
|
121
|
-
return Math.round(clamped / CONVERSATION_SCALE_FOCUS_CONTRAST_STEP) * CONVERSATION_SCALE_FOCUS_CONTRAST_STEP
|
|
122
|
-
}
|
|
123
|
-
|
|
124
98
|
function particleTraversalSpeedOr(value, fallback) {
|
|
125
99
|
const numeric = Number(value)
|
|
126
100
|
if (!Number.isFinite(numeric)) return fallback
|
|
@@ -170,14 +144,6 @@ export function normalizePreferences(value) {
|
|
|
170
144
|
),
|
|
171
145
|
particlePattern: 'orthogonal',
|
|
172
146
|
railDefaultHidden: booleanOr(input.railDefaultHidden, DEFAULT_PREFERENCES.railDefaultHidden),
|
|
173
|
-
conversationScaleMaxDistance: scaleDistanceOr(
|
|
174
|
-
input.conversationScaleMaxDistance,
|
|
175
|
-
DEFAULT_PREFERENCES.conversationScaleMaxDistance,
|
|
176
|
-
),
|
|
177
|
-
conversationScaleFocusContrast: scaleFocusContrastOr(
|
|
178
|
-
input.conversationScaleFocusContrast,
|
|
179
|
-
DEFAULT_PREFERENCES.conversationScaleFocusContrast,
|
|
180
|
-
),
|
|
181
147
|
}
|
|
182
148
|
normalized.preset = matchedVisualPreset(normalized)
|
|
183
149
|
return normalized
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { resolveConversationScaleLengths } from './conversation-scale-adapter.js'
|
|
1
|
+
import { PARTICLE_TRAVERSAL_SPEED_DEFAULT, PARTICLE_TRAVERSAL_SPEED_MAX, PARTICLE_TRAVERSAL_SPEED_MIN, PARTICLE_TRAVERSAL_SPEED_STEP, resolveParticleDetail } from './preferences.js'
|
|
3
2
|
|
|
4
3
|
const SETTINGS_FOCUSABLE = [
|
|
5
4
|
'button:not([disabled])',
|
|
@@ -57,24 +56,6 @@ function particleMarkup() {
|
|
|
57
56
|
</button>`).join('')
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
function calibrationMarkup() {
|
|
61
|
-
return `<div data-prts-scale-calibration data-prts-calibration-mode="hidden" data-prts-calibration-reason="unmeasured">
|
|
62
|
-
<div data-prts-scale-calibration-viewport>
|
|
63
|
-
<div data-prts-scale-calibration-canvas aria-hidden="true">
|
|
64
|
-
<i data-prts-scale-calibration-sidebar></i>
|
|
65
|
-
<span data-prts-scale-calibration-measure><i></i><output data-prts-scale-calibration-value>96 px</output></span>
|
|
66
|
-
<span data-prts-scale-calibration-rail>${Array.from({ length: 9 }, (_, index) => `<i style="--prts-calibration-tick:${index}"></i>`).join('')}</span>
|
|
67
|
-
<i data-prts-scale-calibration-gap></i>
|
|
68
|
-
<span data-prts-scale-calibration-content><i></i><small>会话内容区</small></span>
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
<div data-prts-scale-calibration-meta>
|
|
72
|
-
<span data-prts-scale-calibration-scale hidden>缩放预览</span>
|
|
73
|
-
<output data-prts-scale-calibration-status aria-live="polite">当前视图:几何测量中</output>
|
|
74
|
-
</div>
|
|
75
|
-
</div>`
|
|
76
|
-
}
|
|
77
|
-
|
|
78
59
|
export function themeSettingsMarkup() {
|
|
79
60
|
return `<div data-prts-settings-backdrop hidden aria-hidden="true"></div>
|
|
80
61
|
<dialog id="prts-theme-settings" data-prts-theme-settings aria-label="P.R.T.S. 主题设置" aria-hidden="true">
|
|
@@ -100,7 +81,7 @@ export function themeSettingsMarkup() {
|
|
|
100
81
|
</section>
|
|
101
82
|
|
|
102
83
|
<details data-prts-settings-advanced>
|
|
103
|
-
<summary><span><small>精细调整</small><strong
|
|
84
|
+
<summary><span><small>精细调整</small><strong>粒子效果</strong></span><output data-prts-advanced-summary>标准 / 1×</output></summary>
|
|
104
85
|
<div data-prts-settings-advanced-content>
|
|
105
86
|
<section data-prts-particle-detail>
|
|
106
87
|
<header><strong>粒子精度</strong><span>同时调整会话与新会话徽记</span></header>
|
|
@@ -111,22 +92,6 @@ export function themeSettingsMarkup() {
|
|
|
111
92
|
</label>
|
|
112
93
|
<span data-prts-particle-error role="alert" hidden>粒子资源加载异常,主题已使用静态后备效果</span>
|
|
113
94
|
</section>
|
|
114
|
-
<section data-prts-scale-adjustment>
|
|
115
|
-
<header><strong>会话刻度</strong><span>调整位置距离与悬停焦点的视觉区分</span></header>
|
|
116
|
-
${calibrationMarkup()}
|
|
117
|
-
<label data-prts-setting-row="conversationScaleMaxDistance" data-prts-setting-range-row>
|
|
118
|
-
<span>最大距离</span>
|
|
119
|
-
<div><input type="range" min="16" max="240" step="8" value="96" data-prts-setting-range data-prts-setting-key="conversationScaleMaxDistance" aria-label="会话刻度最大距离"><output data-prts-scale-distance-output>96 px</output></div>
|
|
120
|
-
</label>
|
|
121
|
-
<label data-prts-setting-row="conversationScaleFocusContrast" data-prts-setting-range-row>
|
|
122
|
-
<span>聚焦区分度</span>
|
|
123
|
-
<div data-prts-scale-focus-control>
|
|
124
|
-
<span data-prts-scale-focus-preview aria-hidden="true">${Array.from({ length: 5 }, (_, index) => `<i data-prts-scale-focus-preview-tick="${index}"></i>`).join('')}</span>
|
|
125
|
-
<input type="range" min="0" max="100" step="10" value="70" data-prts-setting-range data-prts-setting-key="conversationScaleFocusContrast" aria-label="会话刻度聚焦区分度">
|
|
126
|
-
<output data-prts-scale-focus-output>70</output>
|
|
127
|
-
</div>
|
|
128
|
-
</label>
|
|
129
|
-
</section>
|
|
130
95
|
</div>
|
|
131
96
|
</details>
|
|
132
97
|
|
|
@@ -160,7 +125,6 @@ export function createThemeSettingsOverlay({
|
|
|
160
125
|
onPreferencePreview = () => {},
|
|
161
126
|
onResetVisual = () => {},
|
|
162
127
|
onRetrySave = () => {},
|
|
163
|
-
getConversationScalePreview = () => ({ visible: false, reason: 'unmeasured', mode: 'hidden' }),
|
|
164
128
|
}) {
|
|
165
129
|
const window = document?.defaultView
|
|
166
130
|
const transparencyMedia = window?.matchMedia?.('(prefers-reduced-transparency: reduce)')
|
|
@@ -171,17 +135,8 @@ export function createThemeSettingsOverlay({
|
|
|
171
135
|
let currentPreferences
|
|
172
136
|
let currentStatus
|
|
173
137
|
let currentPersistence = { phase: 'idle', revision: 0 }
|
|
174
|
-
let scaleDistanceDraft
|
|
175
|
-
let scaleDistanceDirty = false
|
|
176
|
-
let scaleFocusContrastDraft
|
|
177
|
-
let scaleFocusContrastDirty = false
|
|
178
138
|
let particleTraversalSpeedDraft
|
|
179
139
|
let particleTraversalSpeedDirty = false
|
|
180
|
-
let calibrationResizeObserver
|
|
181
|
-
let calibrationSettleTimer
|
|
182
|
-
let calibrationFrame
|
|
183
|
-
let calibrationViewportWidth
|
|
184
|
-
let calibrationFactor
|
|
185
140
|
let savedTimer
|
|
186
141
|
let feedbackTimer
|
|
187
142
|
let feedbackTarget
|
|
@@ -230,8 +185,6 @@ export function createThemeSettingsOverlay({
|
|
|
230
185
|
const value = Boolean(next)
|
|
231
186
|
if (value === isOpen) return isOpen
|
|
232
187
|
if (!value) {
|
|
233
|
-
commitScaleDistance()
|
|
234
|
-
commitScaleFocusContrast()
|
|
235
188
|
commitParticleTraversalSpeed()
|
|
236
189
|
}
|
|
237
190
|
isOpen = value
|
|
@@ -243,7 +196,6 @@ export function createThemeSettingsOverlay({
|
|
|
243
196
|
onOpen()
|
|
244
197
|
showPanel()
|
|
245
198
|
panel.setAttribute('data-prts-settings-visible', '')
|
|
246
|
-
renderScaleCalibration()
|
|
247
199
|
;(panel.querySelector('[data-prts-theme-settings-close]') ?? focusable()[0] ?? panel).focus?.()
|
|
248
200
|
} else {
|
|
249
201
|
panel.removeAttribute('data-prts-settings-visible')
|
|
@@ -254,27 +206,6 @@ export function createThemeSettingsOverlay({
|
|
|
254
206
|
return isOpen
|
|
255
207
|
}
|
|
256
208
|
|
|
257
|
-
function normalizeScaleDistance(value) {
|
|
258
|
-
const numeric = Number(value)
|
|
259
|
-
if (!Number.isFinite(numeric)) return 96
|
|
260
|
-
return Math.min(240, Math.max(16, Math.round(numeric / 8) * 8))
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function currentScaleDistance() {
|
|
264
|
-
return normalizeScaleDistance(scaleDistanceDirty ? scaleDistanceDraft : currentPreferences?.conversationScaleMaxDistance)
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function normalizeScaleFocusContrast(value) {
|
|
268
|
-
const numeric = Number(value)
|
|
269
|
-
if (!Number.isFinite(numeric)) return CONVERSATION_SCALE_FOCUS_CONTRAST_DEFAULT
|
|
270
|
-
const clamped = Math.min(CONVERSATION_SCALE_FOCUS_CONTRAST_MAX, Math.max(CONVERSATION_SCALE_FOCUS_CONTRAST_MIN, numeric))
|
|
271
|
-
return Math.round(clamped / CONVERSATION_SCALE_FOCUS_CONTRAST_STEP) * CONVERSATION_SCALE_FOCUS_CONTRAST_STEP
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
function currentScaleFocusContrast() {
|
|
275
|
-
return normalizeScaleFocusContrast(scaleFocusContrastDirty ? scaleFocusContrastDraft : currentPreferences?.conversationScaleFocusContrast)
|
|
276
|
-
}
|
|
277
|
-
|
|
278
209
|
function normalizeParticleTraversalSpeed(value) {
|
|
279
210
|
const numeric = Number(value)
|
|
280
211
|
if (!Number.isFinite(numeric)) return PARTICLE_TRAVERSAL_SPEED_DEFAULT
|
|
@@ -306,142 +237,10 @@ export function createThemeSettingsOverlay({
|
|
|
306
237
|
setText(panel.querySelector('[data-prts-particle-traversal-output]'), particleTraversalLabel(value))
|
|
307
238
|
}
|
|
308
239
|
|
|
309
|
-
function calibrationStatus(state, value) {
|
|
310
|
-
if (state?.mode === 'configured') return `当前视图:使用配置上限 / ${Math.round(Number(state.left) || value)} px`
|
|
311
|
-
if (state?.simulated) return `模拟布局:使用配置上限 / ${value} px`
|
|
312
|
-
if (state?.mode === 'centered') return `当前视图:自动居中 / 距侧栏 ${Math.round(Number(state.left) || 0)} px`
|
|
313
|
-
const reasons = {
|
|
314
|
-
drawer: '抽屉布局', phone: '手机布局', turns: '消息不足', corridor: '会话走廊不足',
|
|
315
|
-
preview: '会话预览空间不足', unmeasured: '模拟布局',
|
|
316
|
-
}
|
|
317
|
-
return `当前视图:隐藏 / ${reasons[state?.reason] || '空间不足'}`
|
|
318
|
-
}
|
|
319
|
-
|
|
320
240
|
function setText(node, value) {
|
|
321
241
|
if (node && node.textContent !== value) node.textContent = value
|
|
322
242
|
}
|
|
323
243
|
|
|
324
|
-
function setCalibrationResizeState(active) {
|
|
325
|
-
for (const node of [panel, backdrop]) {
|
|
326
|
-
if (!node || node.hasAttribute('data-prts-resizing') === active) continue
|
|
327
|
-
node.toggleAttribute('data-prts-resizing', active)
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
function cancelCalibrationFrame() {
|
|
332
|
-
if (calibrationFrame === undefined) return
|
|
333
|
-
window?.cancelAnimationFrame?.(calibrationFrame)
|
|
334
|
-
window?.clearTimeout?.(calibrationFrame)
|
|
335
|
-
calibrationFrame = undefined
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
function measureScaleCalibration() {
|
|
339
|
-
calibrationFrame = undefined
|
|
340
|
-
if (!isOpen) return
|
|
341
|
-
const viewport = panel?.querySelector?.('[data-prts-scale-calibration-viewport]')
|
|
342
|
-
const canvas = panel?.querySelector?.('[data-prts-scale-calibration-canvas]')
|
|
343
|
-
const calibration = panel?.querySelector?.('[data-prts-scale-calibration]')
|
|
344
|
-
const scaleNote = panel?.querySelector?.('[data-prts-scale-calibration-scale]')
|
|
345
|
-
if (!viewport || !canvas || !calibration) return
|
|
346
|
-
const available = calibrationViewportWidth || viewport.clientWidth
|
|
347
|
-
const factor = available > 0 ? Math.min(1, available / 360) : 1
|
|
348
|
-
const roundedFactor = Number(factor.toFixed(4))
|
|
349
|
-
const value = currentScaleDistance()
|
|
350
|
-
let state
|
|
351
|
-
try { state = getConversationScalePreview(value) } catch { state = { visible: false, reason: 'unmeasured', mode: 'hidden' } }
|
|
352
|
-
|
|
353
|
-
if (roundedFactor !== calibrationFactor) {
|
|
354
|
-
calibrationFactor = roundedFactor
|
|
355
|
-
canvas.style.transform = `scale(${roundedFactor})`
|
|
356
|
-
viewport.style.height = `${Math.ceil(94 * roundedFactor)}px`
|
|
357
|
-
}
|
|
358
|
-
const scaled = factor < .999
|
|
359
|
-
if (calibration.hasAttribute('data-prts-calibration-scaled') !== scaled) calibration.toggleAttribute('data-prts-calibration-scaled', scaled)
|
|
360
|
-
if (scaleNote && scaleNote.hidden !== !scaled) scaleNote.hidden = !scaled
|
|
361
|
-
const mode = state?.simulated ? 'simulated' : state?.mode || 'hidden'
|
|
362
|
-
const reason = state?.reason || 'unmeasured'
|
|
363
|
-
if (calibration.dataset.prtsCalibrationMode !== mode) calibration.dataset.prtsCalibrationMode = mode
|
|
364
|
-
if (calibration.dataset.prtsCalibrationReason !== reason) calibration.dataset.prtsCalibrationReason = reason
|
|
365
|
-
setText(panel.querySelector('[data-prts-scale-calibration-status]'), calibrationStatus(state, value))
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
function scheduleCalibrationMeasurement() {
|
|
369
|
-
if (!isOpen) return
|
|
370
|
-
cancelCalibrationFrame()
|
|
371
|
-
calibrationFrame = window?.requestAnimationFrame?.(measureScaleCalibration)
|
|
372
|
-
?? window?.setTimeout?.(measureScaleCalibration, 16)
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
function scheduleScalePreviewRefresh(entries = []) {
|
|
376
|
-
const viewportEntry = entries.find?.(entry => entry.target?.matches?.('[data-prts-scale-calibration-viewport]'))
|
|
377
|
-
const observedWidth = Number(viewportEntry?.contentRect?.width)
|
|
378
|
-
if (Number.isFinite(observedWidth) && observedWidth > 0) {
|
|
379
|
-
calibrationViewportWidth = observedWidth
|
|
380
|
-
}
|
|
381
|
-
if (!isOpen) return
|
|
382
|
-
setCalibrationResizeState(true)
|
|
383
|
-
if (calibrationSettleTimer !== undefined) window?.clearTimeout?.(calibrationSettleTimer)
|
|
384
|
-
calibrationSettleTimer = window?.setTimeout?.(() => {
|
|
385
|
-
calibrationSettleTimer = undefined
|
|
386
|
-
setCalibrationResizeState(false)
|
|
387
|
-
renderScaleCalibration()
|
|
388
|
-
}, 160)
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
function renderScaleCalibration() {
|
|
392
|
-
if (!isOpen) return
|
|
393
|
-
if (!panel || !currentPreferences) return
|
|
394
|
-
const value = currentScaleDistance()
|
|
395
|
-
const contrast = currentScaleFocusContrast()
|
|
396
|
-
const lengths = resolveConversationScaleLengths(contrast)
|
|
397
|
-
const calibration = panel.querySelector('[data-prts-scale-calibration]')
|
|
398
|
-
const distanceRange = panel.querySelector('input[data-prts-setting-range][data-prts-setting-key="conversationScaleMaxDistance"]')
|
|
399
|
-
const contrastRange = panel.querySelector('input[data-prts-setting-range][data-prts-setting-key="conversationScaleFocusContrast"]')
|
|
400
|
-
const distanceOutput = panel.querySelector('[data-prts-scale-distance-output]')
|
|
401
|
-
const contrastOutput = panel.querySelector('[data-prts-scale-focus-output]')
|
|
402
|
-
const calibrationValue = panel.querySelector('[data-prts-scale-calibration-value]')
|
|
403
|
-
if (distanceRange && distanceRange.value !== String(value)) distanceRange.value = String(value)
|
|
404
|
-
if (contrastRange && contrastRange.value !== String(contrast)) contrastRange.value = String(contrast)
|
|
405
|
-
setText(distanceOutput, `${value} px`)
|
|
406
|
-
setText(contrastOutput, String(contrast))
|
|
407
|
-
setText(calibrationValue, `${value} px`)
|
|
408
|
-
for (const tick of panel.querySelectorAll('[data-prts-scale-focus-preview-tick]')) {
|
|
409
|
-
const length = lengths[Number(tick.dataset.prtsScaleFocusPreviewTick)] ?? lengths.at(-1)
|
|
410
|
-
const width = `${length}px`
|
|
411
|
-
if (tick.style.width !== width) tick.style.width = width
|
|
412
|
-
}
|
|
413
|
-
const detail = resolveParticleDetail(currentPreferences)
|
|
414
|
-
const detailLabels = { compact: '精简', standard: '标准', precise: '精细' }
|
|
415
|
-
const advanced = panel.querySelector('[data-prts-advanced-summary]')
|
|
416
|
-
setText(advanced, `${detailLabels[detail]} / ${conciseNumber(currentParticleTraversalSpeed())}× / 区分度 ${contrast} / ${value} px`)
|
|
417
|
-
if (!calibration) return
|
|
418
|
-
const distance = `${value}px`
|
|
419
|
-
if (calibration.style.getPropertyValue('--prts-calibration-distance') !== distance) {
|
|
420
|
-
calibration.style.setProperty('--prts-calibration-distance', distance)
|
|
421
|
-
}
|
|
422
|
-
scheduleCalibrationMeasurement()
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
function commitScaleDistance() {
|
|
426
|
-
if (!scaleDistanceDirty || !currentPreferences) return false
|
|
427
|
-
const value = currentScaleDistance()
|
|
428
|
-
scaleDistanceDirty = false
|
|
429
|
-
scaleDistanceDraft = value
|
|
430
|
-
if (value !== normalizeScaleDistance(currentPreferences.conversationScaleMaxDistance)) onPreferenceChange('conversationScaleMaxDistance', value)
|
|
431
|
-
else renderScaleCalibration()
|
|
432
|
-
return true
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
function commitScaleFocusContrast() {
|
|
436
|
-
if (!scaleFocusContrastDirty || !currentPreferences) return false
|
|
437
|
-
const value = currentScaleFocusContrast()
|
|
438
|
-
scaleFocusContrastDirty = false
|
|
439
|
-
scaleFocusContrastDraft = value
|
|
440
|
-
if (value !== normalizeScaleFocusContrast(currentPreferences.conversationScaleFocusContrast)) onPreferenceChange('conversationScaleFocusContrast', value)
|
|
441
|
-
else renderScaleCalibration()
|
|
442
|
-
return true
|
|
443
|
-
}
|
|
444
|
-
|
|
445
244
|
function commitParticleTraversalSpeed() {
|
|
446
245
|
if (!particleTraversalSpeedDirty || !currentPreferences) return false
|
|
447
246
|
const value = currentParticleTraversalSpeed()
|
|
@@ -495,11 +294,8 @@ export function createThemeSettingsOverlay({
|
|
|
495
294
|
if (transparency) transparency.hidden = !(currentPreferences.glass !== 'off' && transparencyMedia?.matches)
|
|
496
295
|
const particleError = panel.querySelector('[data-prts-particle-error]')
|
|
497
296
|
if (particleError) particleError.hidden = currentStatus?.particle?.phase !== 'error'
|
|
498
|
-
if (!scaleDistanceDirty) scaleDistanceDraft = normalizeScaleDistance(currentPreferences.conversationScaleMaxDistance)
|
|
499
|
-
if (!scaleFocusContrastDirty) scaleFocusContrastDraft = normalizeScaleFocusContrast(currentPreferences.conversationScaleFocusContrast)
|
|
500
297
|
if (!particleTraversalSpeedDirty) particleTraversalSpeedDraft = normalizeParticleTraversalSpeed(currentPreferences.particleTraversalSpeed)
|
|
501
298
|
renderParticleTraversal()
|
|
502
|
-
renderScaleCalibration()
|
|
503
299
|
renderPersistence()
|
|
504
300
|
}
|
|
505
301
|
|
|
@@ -531,10 +327,6 @@ export function createThemeSettingsOverlay({
|
|
|
531
327
|
if (target.hasAttribute('data-prts-reset-visual')) { setResetConfirmation(true); return }
|
|
532
328
|
if (target.hasAttribute('data-prts-reset-cancel')) { setResetConfirmation(false); return }
|
|
533
329
|
if (target.hasAttribute('data-prts-reset-confirm-action')) {
|
|
534
|
-
scaleDistanceDirty = false
|
|
535
|
-
scaleDistanceDraft = undefined
|
|
536
|
-
scaleFocusContrastDirty = false
|
|
537
|
-
scaleFocusContrastDraft = undefined
|
|
538
330
|
particleTraversalSpeedDirty = false
|
|
539
331
|
particleTraversalSpeedDraft = undefined
|
|
540
332
|
setResetConfirmation(false)
|
|
@@ -547,13 +339,7 @@ export function createThemeSettingsOverlay({
|
|
|
547
339
|
if (!target?.matches?.('input[data-prts-setting-range]')) return
|
|
548
340
|
const value = Number(target.value)
|
|
549
341
|
if (!Number.isFinite(value)) return
|
|
550
|
-
if (target.dataset.prtsSettingKey === '
|
|
551
|
-
scaleDistanceDraft = value
|
|
552
|
-
scaleDistanceDirty = true
|
|
553
|
-
} else if (target.dataset.prtsSettingKey === 'conversationScaleFocusContrast') {
|
|
554
|
-
scaleFocusContrastDraft = value
|
|
555
|
-
scaleFocusContrastDirty = true
|
|
556
|
-
} else if (target.dataset.prtsSettingKey === 'particleTraversalSpeed') {
|
|
342
|
+
if (target.dataset.prtsSettingKey === 'particleTraversalSpeed') {
|
|
557
343
|
particleTraversalSpeedDraft = normalizeParticleTraversalSpeed(value)
|
|
558
344
|
particleTraversalSpeedDirty = true
|
|
559
345
|
renderParticleTraversal()
|
|
@@ -562,7 +348,6 @@ export function createThemeSettingsOverlay({
|
|
|
562
348
|
} else {
|
|
563
349
|
return
|
|
564
350
|
}
|
|
565
|
-
renderScaleCalibration()
|
|
566
351
|
}
|
|
567
352
|
|
|
568
353
|
function onKeydown(event) {
|
|
@@ -584,8 +369,6 @@ export function createThemeSettingsOverlay({
|
|
|
584
369
|
const commitFromControl = event => {
|
|
585
370
|
const target = event.target
|
|
586
371
|
if (!target?.matches?.('input[data-prts-setting-range]')) return
|
|
587
|
-
if (target.dataset.prtsSettingKey === 'conversationScaleMaxDistance') commitScaleDistance()
|
|
588
|
-
if (target.dataset.prtsSettingKey === 'conversationScaleFocusContrast') commitScaleFocusContrast()
|
|
589
372
|
if (target.dataset.prtsSettingKey === 'particleTraversalSpeed') commitParticleTraversalSpeed()
|
|
590
373
|
}
|
|
591
374
|
|
|
@@ -600,24 +383,15 @@ export function createThemeSettingsOverlay({
|
|
|
600
383
|
document.addEventListener('keydown', onKeydown)
|
|
601
384
|
transparencyMedia?.addEventListener?.('change', renderMediaState)
|
|
602
385
|
motionMedia?.addEventListener?.('change', renderMediaState)
|
|
603
|
-
if (typeof window?.ResizeObserver === 'function') {
|
|
604
|
-
calibrationResizeObserver = new window.ResizeObserver(scheduleScalePreviewRefresh)
|
|
605
|
-
const viewport = panel?.querySelector?.('[data-prts-scale-calibration-viewport]')
|
|
606
|
-
if (viewport) calibrationResizeObserver.observe(viewport)
|
|
607
|
-
}
|
|
608
386
|
|
|
609
387
|
return {
|
|
610
388
|
update(preferences, status, persistenceState = currentPersistence) {
|
|
611
389
|
currentPreferences = preferences
|
|
612
390
|
currentStatus = status
|
|
613
391
|
currentPersistence = persistenceState ?? { phase: 'idle', revision: 0 }
|
|
614
|
-
if (!scaleDistanceDirty) scaleDistanceDraft = normalizeScaleDistance(preferences?.conversationScaleMaxDistance)
|
|
615
|
-
if (!scaleFocusContrastDirty) scaleFocusContrastDraft = normalizeScaleFocusContrast(preferences?.conversationScaleFocusContrast)
|
|
616
392
|
if (!particleTraversalSpeedDirty) particleTraversalSpeedDraft = normalizeParticleTraversalSpeed(preferences?.particleTraversalSpeed)
|
|
617
393
|
renderState()
|
|
618
394
|
},
|
|
619
|
-
refreshScalePreview: renderScaleCalibration,
|
|
620
|
-
scheduleScalePreviewRefresh,
|
|
621
395
|
open: () => setOpen(true),
|
|
622
396
|
close: () => setOpen(false),
|
|
623
397
|
toggle,
|
|
@@ -626,10 +400,6 @@ export function createThemeSettingsOverlay({
|
|
|
626
400
|
hidePanel()
|
|
627
401
|
if (savedTimer !== undefined) window?.clearTimeout?.(savedTimer)
|
|
628
402
|
if (feedbackTimer !== undefined) window?.clearTimeout?.(feedbackTimer)
|
|
629
|
-
if (calibrationSettleTimer !== undefined) window?.clearTimeout?.(calibrationSettleTimer)
|
|
630
|
-
calibrationSettleTimer = undefined
|
|
631
|
-
cancelCalibrationFrame()
|
|
632
|
-
setCalibrationResizeState(false)
|
|
633
403
|
feedbackTarget?.removeAttribute?.('data-prts-setting-feedback')
|
|
634
404
|
trigger?.setAttribute('aria-expanded', 'false')
|
|
635
405
|
trigger?.removeEventListener('click', toggle)
|
|
@@ -643,7 +413,6 @@ export function createThemeSettingsOverlay({
|
|
|
643
413
|
document.removeEventListener('keydown', onKeydown)
|
|
644
414
|
transparencyMedia?.removeEventListener?.('change', renderMediaState)
|
|
645
415
|
motionMedia?.removeEventListener?.('change', renderMediaState)
|
|
646
|
-
calibrationResizeObserver?.disconnect()
|
|
647
416
|
document.documentElement.removeAttribute('data-prts-settings-open')
|
|
648
417
|
},
|
|
649
418
|
}
|