@ash-qw/dsh-theme-prts 2.1.0 → 2.1.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ash-qw/dsh-theme-prts",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Unofficial Arknights P.R.T.S.-inspired UI theme for DeepSeek Harness Web and the official desktop client",
@@ -18,6 +18,8 @@ export function createBackgroundStore({ window, document }) {
18
18
  if (url) root.style.setProperty(`--prts-background-${slot}`, `url("${url}")`)
19
19
  else root.style.removeProperty(`--prts-background-${slot}`)
20
20
  }
21
+ const ratio = Number(state.sidebar?.width) / Number(state.sidebar?.height)
22
+ document.documentElement.style.setProperty('--prts-sidebar-image-ratio', String(Number.isFinite(ratio) && ratio > 0 ? ratio : 1))
21
23
  for (const listener of listeners) listener(state)
22
24
  }
23
25
  const request = async data => {
@@ -52,6 +54,7 @@ export function createBackgroundStore({ window, document }) {
52
54
  catch (error) { await refresh().catch(() => {}); throw error }
53
55
  },
54
56
  dispose() {
57
+ document.documentElement.style.removeProperty('--prts-sidebar-image-ratio')
55
58
  disposed = true; abort?.abort(); events?.close(); listeners.clear(); window.removeEventListener('focus', focus)
56
59
  for (const slot of Object.keys(backgroundLabels)) {
57
60
  document.documentElement.removeAttribute(`data-prts-background-${slot}`)
@@ -16,6 +16,8 @@ function cssPixels(value) {
16
16
  export function createHostGeometryAdapter({ document, window }) {
17
17
  const root = document?.documentElement
18
18
  let frame
19
+ let sidebar
20
+ let previousSidebarWidth
19
21
  let resizeObserver
20
22
  let frameRequest
21
23
  let resizeSettleTimer
@@ -31,6 +33,10 @@ export function createHostGeometryAdapter({ document, window }) {
31
33
  if (root.style.getPropertyValue(TOP_INSET_PROPERTY) !== value) {
32
34
  root.style.setProperty(TOP_INSET_PROPERTY, value)
33
35
  }
36
+ if (sidebar?.isConnected) {
37
+ const width = cssPixels(sidebar.getBoundingClientRect().width)
38
+ if (root.style.getPropertyValue('--prts-sidebar-width') !== width) root.style.setProperty('--prts-sidebar-width', width)
39
+ }
34
40
  return top
35
41
  }
36
42
 
@@ -62,6 +68,7 @@ export function createHostGeometryAdapter({ document, window }) {
62
68
  function onGeometryResize(entries = []) {
63
69
  let shouldMeasure = false
64
70
  for (const entry of entries) {
71
+ if (entry.target === sidebar) { shouldMeasure = true; continue }
65
72
  if (entry.target !== frame) continue
66
73
  const height = Number(entry.contentRect?.height)
67
74
  if (!Number.isFinite(height) || height <= 0) {
@@ -91,6 +98,9 @@ export function createHostGeometryAdapter({ document, window }) {
91
98
  else root.style.removeProperty(TOP_INSET_PROPERTY)
92
99
  previousValue = undefined
93
100
  previousPriority = undefined
101
+ if (previousSidebarWidth) root.style.setProperty('--prts-sidebar-width', previousSidebarWidth)
102
+ else root.style.removeProperty('--prts-sidebar-width')
103
+ sidebar = undefined
94
104
  frame = undefined
95
105
  observedFrameHeight = undefined
96
106
  started = false
@@ -105,6 +115,8 @@ export function createHostGeometryAdapter({ document, window }) {
105
115
  }
106
116
  if (started) dispose()
107
117
  frame = nextFrame
118
+ sidebar = frame.querySelector?.('[data-prts-region="sessions"]')
119
+ previousSidebarWidth = root.style.getPropertyValue('--prts-sidebar-width')
108
120
  previousValue = root.style.getPropertyValue(TOP_INSET_PROPERTY)
109
121
  previousPriority = root.style.getPropertyPriority(TOP_INSET_PROPERTY)
110
122
  started = true
@@ -112,6 +124,7 @@ export function createHostGeometryAdapter({ document, window }) {
112
124
  if (typeof window?.ResizeObserver === 'function') {
113
125
  resizeObserver = new window.ResizeObserver(onGeometryResize)
114
126
  resizeObserver.observe(frame)
127
+ if (sidebar) resizeObserver.observe(sidebar)
115
128
  }
116
129
  window?.addEventListener?.('resize', onWindowResize, { passive: true })
117
130
  scheduleSettledMeasure()
@@ -2,7 +2,7 @@
2
2
  // See src/vendor/react-bits/LICENSE.md and THIRD_PARTY_NOTICES.md.
3
3
  export const BACKGROUND_OPACITY_CONTROLS = Object.freeze([
4
4
  { key: 'sidebarOpacity', label: '会话列表侧栏', property: '--prts-sidebar-opacity', value: 94, blurKey: 'sidebarBlur', blurProperty: '--prts-sidebar-blur', blurDefault: 8 },
5
- { key: 'railOpacity', label: '设置侧栏', property: '--prts-rail-opacity', value: 70, blurKey: 'railBlur', blurProperty: '--prts-rail-blur', blurDefault: 12, fullBackgroundOnly: true },
5
+ { key: 'railOpacity', label: '设置侧栏', property: '--prts-rail-opacity', value: 70, blurKey: 'railBlur', blurProperty: '--prts-rail-blur', blurDefault: 12 },
6
6
  { key: 'bakerOpacity', label: 'Baker 气泡', property: '--prts-baker-opacity', value: 50, blurKey: 'bakerBlur', blurProperty: '--prts-baker-blur', blurDefault: 8, theme: 'deck-chat' },
7
7
  { key: 'classicUserOpacity', label: '经典用户消息', property: '--prts-classic-user-opacity', value: 50, blurKey: 'classicUserBlur', blurProperty: '--prts-classic-user-blur', blurDefault: 8, theme: 'native' },
8
8
  ])
@@ -109,8 +109,7 @@ export function mountOpacityDials({ section, window, onChange }) {
109
109
  paint(value)
110
110
  return {
111
111
  update(preferences, active) {
112
- container.hidden = Boolean((definition.theme && preferences.conversationStyle !== definition.theme)
113
- || (definition.fullBackgroundOnly && preferences.backgroundMode !== 'full'))
112
+ container.hidden = Boolean(definition.theme && preferences.conversationStyle !== definition.theme)
114
113
  saved = 100 - Math.round((preferences[definition.key] ?? (100 - definition.value) / 100) * 100)
115
114
  if (!grip && section.ownerDocument.activeElement !== input) paint(saved)
116
115
  savedBlur = preferences[definition.blurKey] ?? definition.blurDefault
@@ -127,7 +126,8 @@ export function mountOpacityDials({ section, window, onChange }) {
127
126
  const split = preferences.backgroundMode === 'split'
128
127
  section.querySelector('[data-prts-opacity-settings]').hidden = preferences.backgroundMode === 'off'
129
128
  const conversationImage = full || (split && Boolean(state.conversation))
130
- const active = [full || (split && Boolean(state.sidebar)), full,
129
+ const sidebarImage = full || (split && Boolean(state.sidebar))
130
+ const active = [sidebarImage, sidebarImage,
131
131
  conversationImage && preferences.conversationStyle === 'deck-chat',
132
132
  conversationImage && preferences.conversationStyle === 'native']
133
133
  controls.forEach((control,i)=>control.update(preferences,active[i]))
@@ -1,3 +1,4 @@
1
+ import { SCHEME_COMMIT_PROGRESS } from './theme-controller-v2.js'
1
2
  import { createThemeSettingsOverlay, themeSettingsMarkup } from './theme-settings-workbench.js'
2
3
 
3
4
  const PHONE_RAIL_BREAKPOINT = 640
@@ -83,9 +84,9 @@ export function createOperationsShell({
83
84
  try { return window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches === true } catch { return false }
84
85
  }
85
86
 
86
- function phoneRailGesture() {
87
+ function phoneRailGesture(pointerType) {
87
88
  if (railMode !== 'overlay' || Number(window.innerWidth) > PHONE_RAIL_BREAKPOINT) return false
88
- return railPointerQuery?.matches === true
89
+ return pointerType === 'touch' || railPointerQuery?.matches === true
89
90
  || railHoverQuery?.matches === true
90
91
  || Number(window.navigator?.maxTouchPoints) > 0
91
92
  }
@@ -105,13 +106,16 @@ export function createOperationsShell({
105
106
 
106
107
  function armRailGesture() {
107
108
  railHoldTimer = undefined
108
- if (!railPointer || !phoneRailGesture()) return
109
+ if (!railPointer || !phoneRailGesture('touch')) return
109
110
  railPointer.armed = true
110
111
  railLauncher?.setAttribute('data-prts-rail-gesture-active', '')
111
112
  }
112
113
 
114
+ let railInputType
113
115
  function onRailPointerDown(event) {
114
- if (!phoneRailGesture() || railPointer || (event.button ?? 0) !== 0) return
116
+ railInputType = event.pointerType || 'mouse'
117
+ if (railInputType !== 'touch') return
118
+ if (!phoneRailGesture(event.pointerType) || railPointer || (event.button ?? 0) !== 0) return
115
119
  const pointerId = event.pointerId ?? 1
116
120
  railPointer = {
117
121
  pointerId,
@@ -159,7 +163,9 @@ export function createOperationsShell({
159
163
  }
160
164
 
161
165
  function onRailClick(event) {
162
- if (phoneRailGesture() && Number(event?.detail) > 0) {
166
+ const inputType = event?.pointerType || railInputType
167
+ railInputType = undefined
168
+ if (phoneRailGesture(inputType) && inputType === 'touch' && Number(event?.detail) > 0) {
163
169
  event.preventDefault?.()
164
170
  return
165
171
  }
@@ -262,9 +268,19 @@ export function createOperationsShell({
262
268
  }, 1000)
263
269
  }
264
270
 
271
+ function flushSchemeProgress(pointer) {
272
+ if (pointer.frame !== undefined) window.cancelAnimationFrame(pointer.frame)
273
+ pointer.frame = undefined
274
+ if (pointer.progress !== undefined) {
275
+ pointer.gesture?.update?.(pointer.progress)
276
+ pointer.progress = undefined
277
+ }
278
+ }
279
+
265
280
  function settleSchemePointer({ commit = false } = {}) {
266
281
  const pointer = schemePointer
267
282
  if (!pointer) return
283
+ flushSchemeProgress(pointer)
268
284
  schemePointer = undefined
269
285
  try { schemeToggle?.releasePointerCapture?.(pointer.pointerId) } catch {}
270
286
  if (!pointer.dragging) return
@@ -313,19 +329,25 @@ export function createOperationsShell({
313
329
  }
314
330
  }
315
331
  event.preventDefault?.()
316
- pointer.gesture?.update?.(schemePointerProgress(event))
332
+ pointer.progress = schemePointerProgress(event)
333
+ if (pointer.frame === undefined) pointer.frame = window.requestAnimationFrame(() => {
334
+ pointer.frame = undefined
335
+ if (schemePointer === pointer) flushSchemeProgress(pointer)
336
+ })
317
337
  }
318
338
 
319
339
  function onSchemePointerUp(event) {
320
340
  const pointer = schemePointer
321
341
  if (!pointer || (event.pointerId ?? 1) !== pointer.pointerId) return
322
- const commit = pointer.dragging && schemePointerProgress(event) >= .5
342
+ if (pointer.dragging) pointer.progress = schemePointerProgress(event)
343
+ const commit = pointer.dragging && schemePointerProgress(event) >= SCHEME_COMMIT_PROGRESS
323
344
  settleSchemePointer({ commit })
324
345
  }
325
346
 
326
347
  function cancelSchemePointer() {
327
348
  const pointer = schemePointer
328
349
  if (!pointer) return
350
+ if (pointer.frame !== undefined) window.cancelAnimationFrame(pointer.frame)
329
351
  if (pointer.dragging) {
330
352
  try { pointer.gesture?.cancel?.() } catch {}
331
353
  }
@@ -353,7 +375,7 @@ export function createOperationsShell({
353
375
  const overlay = railMode === 'overlay'
354
376
  const open = overlay && root.hasAttribute('data-prts-rail-open')
355
377
  railLauncher.setAttribute('aria-expanded', String(open))
356
- const closedLabel = phoneRailGesture() ? '长按并向下滑动打开 P.R.T.S. 导航' : '打开 P.R.T.S. 导航'
378
+ const closedLabel = phoneRailGesture() ? '打开 P.R.T.S. 导航(触摸时长按并下滑)' : '打开 P.R.T.S. 导航'
357
379
  railLauncher.setAttribute('aria-label', open ? '关闭 P.R.T.S. 导航' : closedLabel)
358
380
  if (overlay && !open) {
359
381
  navRail.setAttribute('aria-hidden', 'true')
@@ -418,12 +440,16 @@ export function createOperationsShell({
418
440
  }
419
441
 
420
442
  function onResponsiveChange() {
443
+ railInputType = undefined
421
444
  clearRailGesture()
422
445
  setRailViewport(window.innerWidth)
423
446
  syncRailState()
424
447
  }
425
448
 
449
+ let railPhoneQuery
426
450
  function bindResponsiveQueries() {
451
+ railPhoneQuery = window.matchMedia?.('(max-width: 640px)')
452
+ railPhoneQuery?.addEventListener?.('change', onResponsiveChange)
427
453
  railViewportQuery = window.matchMedia?.('(min-width: 1180px)')
428
454
  railPointerQuery = window.matchMedia?.('(pointer: coarse)')
429
455
  railHoverQuery = window.matchMedia?.('(hover: none)')
@@ -507,6 +533,9 @@ export function createOperationsShell({
507
533
  schemeToggle?.removeEventListener('lostpointercapture', onSchemeLostPointerCapture)
508
534
  window.removeEventListener?.('blur', cancelSchemePointer)
509
535
  themeDisable?.removeEventListener('click', disableTheme)
536
+ railPhoneQuery?.removeEventListener?.('change', onResponsiveChange)
537
+ railPhoneQuery = undefined
538
+ railInputType = undefined
510
539
  railViewportQuery?.removeEventListener?.('change', onResponsiveChange)
511
540
  railPointerQuery?.removeEventListener?.('change', onResponsiveChange)
512
541
  railHoverQuery?.removeEventListener?.('change', onResponsiveChange)
@@ -1,6 +1,8 @@
1
1
  import { createCursorAdapter } from './cursor-adapter.js'
2
2
  import { normalizePreferences } from './preferences.js'
3
3
 
4
+ export const SCHEME_COMMIT_PROGRESS = .15
5
+
4
6
  const ROOT_ATTRIBUTES = [
5
7
  'data-dsh-prts',
6
8
  'data-prts-scheme',
@@ -244,11 +246,23 @@ export function createThemeController({ document, window, cssText, service, curs
244
246
  function updateRevealHud(session) {
245
247
  if (!session || session.settled) return
246
248
  const percentage = Math.round(revealProgress(session.progress) * 100)
247
- if (session.hudEdge) session.hudEdge.dataset.prtsSchemeRevealSide = 'left'
248
- root.style.setProperty('--prts-scheme-control-progress', String(session.progress))
249
- root.style.setProperty('--prts-scheme-control-meter-height', `${revealProgress(session.progress) * 48}px`)
250
- root.style.setProperty('--prts-scheme-control-value-image', revealValueImageUrl(percentage))
251
- root.toggleAttribute(TRANSITION_ARMED_ATTRIBUTE, session.interactive && session.progress >= .5)
249
+ if (session.hudEdge && session.hudEdge.dataset.prtsSchemeRevealSide !== 'left') session.hudEdge.dataset.prtsSchemeRevealSide = 'left'
250
+ if (session.hudPercentage !== percentage) {
251
+ session.hudPercentage = percentage
252
+ const image = revealValueImageUrl(percentage)
253
+ if (session.hudAnimation?.effect?.setKeyframes) {
254
+ const frame = {
255
+ backgroundImage: image + ',linear-gradient(#ffd400,#ffd400)',
256
+ backgroundSize: '24px 11px,2px ' + (percentage * .48) + 'px',
257
+ }
258
+ session.hudAnimation.effect.setKeyframes([frame, frame])
259
+ } else {
260
+ root.style.setProperty('--prts-scheme-control-meter-height', `${percentage * .48}px`)
261
+ root.style.setProperty('--prts-scheme-control-value-image', image)
262
+ }
263
+ }
264
+ const armed = session.interactive && session.progress >= SCHEME_COMMIT_PROGRESS
265
+ if (root.hasAttribute(TRANSITION_ARMED_ATTRIBUTE) !== armed) root.toggleAttribute(TRANSITION_ARMED_ATTRIBUTE, armed)
252
266
  }
253
267
 
254
268
  function releaseRevealHud(session) {
@@ -361,11 +375,16 @@ export function createThemeController({ document, window, cssText, service, curs
361
375
  ], options, '::view-transition-new(prts-scheme-grid)')
362
376
  const mark = revealNamedAnimation([
363
377
  { offset: 0, translate: revealGroupTranslate(0), rotate: '45deg' },
364
- { offset: .49, translate: revealGroupTranslate(session.geometry.width * .49), rotate: '45deg' },
365
- { offset: .51, translate: revealGroupTranslate(session.geometry.width * .51), rotate: '225deg' },
378
+ { offset: SCHEME_COMMIT_PROGRESS - .01, translate: revealGroupTranslate(session.geometry.width * (SCHEME_COMMIT_PROGRESS - .01)), rotate: '45deg' },
379
+ { offset: SCHEME_COMMIT_PROGRESS + .01, translate: revealGroupTranslate(session.geometry.width * (SCHEME_COMMIT_PROGRESS + .01)), rotate: '225deg' },
366
380
  { offset: 1, translate: revealGroupTranslate(session.geometry.width), rotate: '225deg' },
367
381
  ], options, '::view-transition-group(prts-scheme-mark)')
368
382
  session.scrubAnimations = [clip, edge, node, grid, gridPhase, mark]
383
+ session.hudAnimation = revealNamedAnimation([{}], options, '::view-transition-new(prts-scheme-node)')
384
+ session.hudAnimation.pause?.()
385
+ session.hudAnimation.currentTime = 0
386
+ session.hudPercentage = undefined
387
+ updateRevealHud(session)
369
388
  for (const animation of session.scrubAnimations) {
370
389
  animation.pause?.()
371
390
  animation.currentTime = session.progress * session.duration
@@ -377,11 +396,10 @@ export function createThemeController({ document, window, cssText, service, curs
377
396
  if (!session || session.settled) return
378
397
  session.progress = revealProgress(value)
379
398
  session.revealX = session.progress * session.geometry.width
380
- root.style.setProperty('--prts-scheme-reveal-x', `${session.revealX}px`)
399
+ if (!session.scrubAnimations) root.style.setProperty('--prts-scheme-reveal-x', `${session.revealX}px`)
381
400
  if (session.scrubAnimations) {
382
401
  try {
383
402
  for (const animation of session.scrubAnimations) {
384
- animation.pause?.()
385
403
  animation.currentTime = session.progress * session.duration
386
404
  }
387
405
  } catch {}
@@ -402,12 +420,19 @@ export function createThemeController({ document, window, cssText, service, curs
402
420
  for (const animation of session?.scrubAnimations || []) {
403
421
  try { animation?.cancel?.() } catch {}
404
422
  }
405
- if (session) session.scrubAnimations = undefined
423
+ session?.hudAnimation?.cancel?.()
424
+ if (session) {
425
+ session.scrubAnimations = undefined
426
+ session.hudAnimation = undefined
427
+ session.hudPercentage = undefined
428
+ }
406
429
  }
407
430
 
408
431
  function animateRevealTo(session, value, duration, easing) {
409
432
  if (!session || session.settled) return Promise.resolve(false)
410
433
  cancelRevealAnimation(session)
434
+ // Transfer the last HUD value once before the release animation takes over.
435
+ updateRevealHud(session)
411
436
  const targetProgress = revealProgress(value)
412
437
  const targetX = revealTargetX(session, targetProgress)
413
438
  if (!(duration > 0)) {
@@ -449,8 +474,8 @@ export function createThemeController({ document, window, cssText, service, curs
449
474
  { backgroundSize: `2px ${targetProgress * 48}px` },
450
475
  ], options, '::view-transition-new(prts-scheme-node)')
451
476
  const mark = revealNamedAnimation([
452
- { translate: revealGroupTranslate(session.revealX), rotate: session.progress >= .5 ? '225deg' : '45deg' },
453
- { translate: revealGroupTranslate(targetX), rotate: targetProgress >= .5 ? '225deg' : '45deg' },
477
+ { translate: revealGroupTranslate(session.revealX), rotate: session.progress >= SCHEME_COMMIT_PROGRESS ? '225deg' : '45deg' },
478
+ { translate: revealGroupTranslate(targetX), rotate: targetProgress >= SCHEME_COMMIT_PROGRESS ? '225deg' : '45deg' },
454
479
  ], options, '::view-transition-group(prts-scheme-mark)')
455
480
  animations = [clip, edge, node, grid, gridPhase, nodeProgress, mark]
456
481
  } catch {
@@ -608,7 +633,7 @@ export function createThemeController({ document, window, cssText, service, curs
608
633
  let settled = false
609
634
  return {
610
635
  update(value) { if (!settled) progress = revealProgress(value) },
611
- finish(commit = progress >= .5) {
636
+ finish(commit = progress >= SCHEME_COMMIT_PROGRESS) {
612
637
  if (settled) return root.dataset.prtsScheme
613
638
  settled = true
614
639
  return commit ? setTheme(target, { animate: false }) : source