@ash-qw/dsh-theme-prts 2.5.2 → 2.5.3
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 -0
- package/lib/client.js +94 -33
- package/package.json +1 -1
- package/src/client/conversation-control-adapter.js +71 -17
- package/src/client/custom-avatar.js +1 -1
- package/src/client/index.js +1 -0
- package/src/client/sidebar-control-adapter.js +26 -12
- package/src/client/theme-transfer.js +4 -1
- package/src/styles/custom-background.css +10 -0
package/package.json
CHANGED
|
@@ -11,6 +11,15 @@ function closestWithClassSuffix(node, suffix) {
|
|
|
11
11
|
return null
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
function isPendingInteractionAction(button) {
|
|
15
|
+
if (!button || button.tagName !== 'BUTTON') return false
|
|
16
|
+
if (button.closest('[data-approval-key]')) return true
|
|
17
|
+
if (button.closest('[data-question-key]')) {
|
|
18
|
+
return hasClassSuffix(button, '_waitButton') || Boolean(closestWithClassSuffix(button, '_footerActions'))
|
|
19
|
+
}
|
|
20
|
+
return Boolean(button.closest('[data-plan-review-key]') && closestWithClassSuffix(button, '_actions'))
|
|
21
|
+
}
|
|
22
|
+
|
|
14
23
|
function classify(button, operation) {
|
|
15
24
|
// The host's process disclosure owns its transparent, full-width hit area.
|
|
16
25
|
if (button.hasAttribute('data-turn-process')) return null
|
|
@@ -138,14 +147,16 @@ function mountBodyTargetFrame(document, window, operation) {
|
|
|
138
147
|
// Nonvisual hosts can still mount the theme without an animation clock.
|
|
139
148
|
if (!window?.requestAnimationFrame || !window?.cancelAnimationFrame) return () => {}
|
|
140
149
|
const composerButton=':is([data-composer-card],[data-prts-composer-fallback]) button:not([data-slot="conversation.input.attachments"] *,[data-prts-glass-menu] *,[data-prts-floating-glass] *,[role="menu"] *,[role="listbox"] *)'
|
|
141
|
-
const selector='[data-prts-conversation-control],[data-presented-file],[data-changed-files],[data-produced-files-row] > button,[data-prts-glass-control],[data-prts-footer-action],[data-prts-transfer] button,'+composerButton
|
|
150
|
+
const selector='[data-prts-to-bottom],[data-prts-conversation-control],[data-presented-file],[data-changed-files],[data-produced-files-row] > button,[data-prts-glass-control],[data-prts-footer-action],[data-prts-transfer] button,'+composerButton
|
|
142
151
|
const frame=document.createElement('div')
|
|
143
152
|
frame.setAttribute('data-prts-body-target-frame','');frame.setAttribute('aria-hidden','true')
|
|
144
153
|
const corners=Array.from({length:4},()=>frame.appendChild(document.createElement('i')))
|
|
145
154
|
document.body.append(frame)
|
|
146
155
|
if(frame.showPopover)frame.setAttribute('popover','manual')
|
|
147
|
-
let layer=null
|
|
148
|
-
const hideFrame=()=>{
|
|
156
|
+
let layer=null, imageRetiring=false
|
|
157
|
+
const hideFrame=()=>{
|
|
158
|
+
if(frame.hidePopover && frame.matches(':popover-open'))frame.hidePopover()
|
|
159
|
+
}
|
|
149
160
|
const showFrame=()=>{
|
|
150
161
|
if(!frame.showPopover)return
|
|
151
162
|
const modal=target?.closest('dialog[open]')
|
|
@@ -153,27 +164,36 @@ function mountBodyTargetFrame(document, window, operation) {
|
|
|
153
164
|
if(!frame.matches(':popover-open'))frame.showPopover()
|
|
154
165
|
layer=modal
|
|
155
166
|
}
|
|
156
|
-
let target=null, hovered=null, focused=null, raf=0, pressed=false, disposed=false
|
|
157
|
-
let pointer={x:0,y:0}, state=null, settled=false, tween=null, bounds=null, boundsDirty=false, hitDirty=false, exitGoal=null, motionDuration=240, targetArm=7
|
|
167
|
+
let target=null, hovered=null, focused=null, raf=0, pressed=false, releasePending=false, disposed=false
|
|
168
|
+
let pointer={x:0,y:0}, state=null, settled=false, tween=null, bounds=null, boundsDirty=false, hitDirty=false, exitGoal=null, motionDuration=240, targetArm=7, retiringBounds=null, targetRetires=false
|
|
158
169
|
const resizeObserver=window.ResizeObserver?new window.ResizeObserver(()=>{boundsDirty=true;wake()}):null
|
|
159
170
|
const reduced=window.matchMedia?.('(prefers-reduced-motion: reduce)')
|
|
160
171
|
const fine=window.matchMedia?.('(hover:hover) and (pointer:fine)')
|
|
172
|
+
let activeModal=null
|
|
161
173
|
const find=node=>{
|
|
174
|
+
if(activeModal && !activeModal.contains(node))return null
|
|
162
175
|
if (!node?.closest || node.closest('[data-prts-workspace-actions],[data-prts-session-actions]')) return null
|
|
163
176
|
const card=node.closest('[data-presented-file],[data-changed-files]')
|
|
164
|
-
const
|
|
177
|
+
const button=node.closest('button')
|
|
178
|
+
const pendingAction=operation.contains(button) && isPendingInteractionAction(button) ? button : null
|
|
179
|
+
const candidate=card || pendingAction || node.closest(selector)
|
|
165
180
|
return candidate && !candidate.matches(':disabled,[aria-disabled="true"]') && !candidate.closest('[inert]') ? candidate : null
|
|
166
181
|
}
|
|
167
182
|
const measure=()=>{bounds=target.getBoundingClientRect();targetArm=7+Math.max(0,Math.min(1,(Math.min(bounds.width,bounds.height)-36)/36))*5;boundsDirty=false}
|
|
168
183
|
const wake=()=>{if(!raf && !disposed)raf=window.requestAnimationFrame(draw)}
|
|
169
184
|
const choose=()=>{
|
|
170
|
-
const next=hovered || focused
|
|
185
|
+
const next=(hovered?.isConnected?hovered:null) || (focused?.isConnected?focused:null)
|
|
171
186
|
if(next!==target){
|
|
187
|
+
const retire=!next && target && !target.isConnected && targetRetires && releasePending && bounds && !reduced?.matches
|
|
188
|
+
imageRetiring=false
|
|
189
|
+
retiringBounds=retire?{left:bounds.left,top:bounds.top,width:bounds.width,height:bounds.height}:null
|
|
172
190
|
target?.removeAttribute('data-prts-corner-target')
|
|
173
|
-
|
|
191
|
+
if(retire){hovered=focused=target=null;boundsDirty=false;resizeObserver?.disconnect();wake();return}
|
|
192
|
+
pressed=false;releasePending=false;settled=false;tween=null;exitGoal=null;motionDuration=240;target=next;boundsDirty=true
|
|
174
193
|
resizeObserver?.disconnect()
|
|
175
194
|
if(target)resizeObserver?.observe(target)
|
|
176
195
|
if(target){
|
|
196
|
+
targetRetires=hasClassSuffix(target,'_toBottom') || isPendingInteractionAction(target)
|
|
177
197
|
target.setAttribute('data-prts-corner-target','');showFrame()
|
|
178
198
|
measure();const box=bounds
|
|
179
199
|
if(!state || state.alpha<.01)state={x:(hovered?pointer.x:box.left+box.width/2)-10,y:(hovered?pointer.y:box.top+box.height/2)-10,w:20,h:20,alpha:0,arm:7}
|
|
@@ -185,14 +205,15 @@ function mountBodyTargetFrame(document, window, operation) {
|
|
|
185
205
|
}
|
|
186
206
|
function draw(time) {
|
|
187
207
|
raf=0
|
|
208
|
+
if(target && !target.isConnected)choose()
|
|
188
209
|
if(hitDirty){hitDirty=false;hovered=find(document.elementFromPoint(pointer.x,pointer.y));choose()}
|
|
189
|
-
if(target && !target.isConnected){target.removeAttribute('data-prts-corner-target');target=hovered=focused=null;pressed=false;settled=false;exitGoal=null}
|
|
210
|
+
if(target && !target.isConnected){target.removeAttribute('data-prts-corner-target');target=hovered=focused=null;pressed=false;releasePending=false;settled=false;exitGoal=null}
|
|
190
211
|
if(!state)return
|
|
191
212
|
if(target && boundsDirty){
|
|
192
213
|
measure()
|
|
193
|
-
if(!bounds.width && !bounds.height){target.removeAttribute('data-prts-corner-target');target=hovered=focused=null;pressed=false;settled=false;exitGoal=null;resizeObserver?.disconnect()}
|
|
214
|
+
if(!bounds.width && !bounds.height){target.removeAttribute('data-prts-corner-target');target=hovered=focused=null;pressed=false;releasePending=false;settled=false;exitGoal=null;resizeObserver?.disconnect()}
|
|
194
215
|
}
|
|
195
|
-
const box=target?bounds:
|
|
216
|
+
const box=target?bounds:retiringBounds,gap=pressed?(imageRetiring?0:3):5
|
|
196
217
|
// Freeze the exit destination: subsequent pointer motion must not restart the fade.
|
|
197
218
|
const goal=box?{x:box.left-gap,y:box.top-gap,w:box.width+gap*2,h:box.height+gap*2,alpha:1,arm:targetArm}:
|
|
198
219
|
(exitGoal ||= {x:pointer.x-10,y:pointer.y-10,w:20,h:20,alpha:0,arm:7})
|
|
@@ -223,7 +244,11 @@ function mountBodyTargetFrame(document, window, operation) {
|
|
|
223
244
|
if(frame.style.opacity!==opacity)frame.style.opacity=opacity
|
|
224
245
|
settled=!moving
|
|
225
246
|
frame.toggleAttribute('data-pressed',pressed)
|
|
226
|
-
if(moving)
|
|
247
|
+
if(releasePending && pressed && !moving){
|
|
248
|
+
if(retiringBounds){exitGoal={...state,alpha:0};retiringBounds=null}
|
|
249
|
+
releasePending=false;pressed=false;motionDuration=imageRetiring?120:140;settled=false;wake()
|
|
250
|
+
}
|
|
251
|
+
else if(moving)wake()
|
|
227
252
|
else {tween=null;if(!state.alpha)hideFrame()}
|
|
228
253
|
}
|
|
229
254
|
const move=event=>{
|
|
@@ -240,21 +265,49 @@ function mountBodyTargetFrame(document, window, operation) {
|
|
|
240
265
|
pointer={x:event.clientX,y:event.clientY}
|
|
241
266
|
if(event.pointerType==='touch')hovered=find(event.target)
|
|
242
267
|
choose()
|
|
243
|
-
if(target && find(event.target)===target){pressed=true;motionDuration=100;settled=false;wake()}
|
|
268
|
+
if(target && find(event.target)===target){pressed=true;releasePending=false;motionDuration=100;settled=false;wake()}
|
|
269
|
+
}
|
|
270
|
+
const release=()=>{
|
|
271
|
+
// A tap can release before the first paint. Finish one contraction, then
|
|
272
|
+
// expand; one flag keeps repeated taps interruptible without a timer queue.
|
|
273
|
+
if(pressed && !settled && !reduced?.matches){releasePending=true;settled=false;wake()}
|
|
274
|
+
else {pressed=false;releasePending=false;motionDuration=140;settled=false;wake()}
|
|
244
275
|
}
|
|
245
|
-
const up=event=>{
|
|
276
|
+
const up=event=>{release();if(event.pointerType==='touch')hovered=null;choose()}
|
|
246
277
|
const reset=()=>{
|
|
247
278
|
target?.removeAttribute('data-prts-corner-target');hideFrame()
|
|
248
|
-
hovered=focused=target=null;state=tween=bounds=exitGoal=null
|
|
249
|
-
|
|
279
|
+
hovered=focused=target=null;state=tween=bounds=exitGoal=retiringBounds=null
|
|
280
|
+
imageRetiring=false
|
|
281
|
+
pressed=false;releasePending=false;settled=true;boundsDirty=hitDirty=false
|
|
250
282
|
resizeObserver?.disconnect();window.cancelAnimationFrame(raf);raf=0
|
|
251
283
|
frame.style.opacity='0';frame.removeAttribute('data-pressed')
|
|
252
284
|
}
|
|
285
|
+
const syncModal=()=>{
|
|
286
|
+
const modals=[...document.querySelectorAll('dialog[open],[role="dialog"][aria-modal="true"]')]
|
|
287
|
+
const previousModal=activeModal
|
|
288
|
+
activeModal=modals.filter(node=>!node.hidden && node.getAttribute('aria-hidden')!=='true').at(-1) ?? null
|
|
289
|
+
if(activeModal===previousModal)return
|
|
290
|
+
if(activeModal && target && !activeModal.contains(target) && target.querySelector('img') && activeModal.querySelector('img') && releasePending && bounds && !reduced?.matches){
|
|
291
|
+
// The preview is opaque: show a bounded click acknowledgment above it,
|
|
292
|
+
// then fade at the thumbnail position instead of retaining a hover target.
|
|
293
|
+
imageRetiring=true;motionDuration=120;tween=null
|
|
294
|
+
retiringBounds={left:bounds.left,top:bounds.top,width:bounds.width,height:bounds.height}
|
|
295
|
+
target.removeAttribute('data-prts-corner-target');hovered=focused=target=null
|
|
296
|
+
boundsDirty=hitDirty=false;resizeObserver?.disconnect();settled=false;wake()
|
|
297
|
+
}else if(imageRetiring || activeModal && (!target || !activeModal.contains(target)))reset()
|
|
298
|
+
}
|
|
299
|
+
// Native image previews mount a body portal without moving the pointer.
|
|
300
|
+
// Watch portal changes only, not the streaming conversation subtree.
|
|
301
|
+
const modalObserver=window.MutationObserver?new window.MutationObserver(syncModal):null
|
|
302
|
+
modalObserver?.observe(document.body,{childList:true})
|
|
303
|
+
const modalToggle=event=>{if(event.target?.matches?.('dialog'))syncModal()}
|
|
304
|
+
document.addEventListener('toggle',modalToggle,true)
|
|
305
|
+
syncModal()
|
|
253
306
|
const visibility=()=>{if(document.hidden)reset()}
|
|
254
307
|
const scroll=()=>{if(!target && !state?.alpha)return;boundsDirty=true;hitDirty=!!hovered;wake()}
|
|
255
308
|
document.addEventListener('scroll',scroll,true)
|
|
256
309
|
window.addEventListener('resize',reset)
|
|
257
|
-
const key=event=>{if(target && (event.key===' ' || event.key==='Enter')){
|
|
310
|
+
const key=event=>{if(target && (event.key===' ' || event.key==='Enter')){if(event.type==='keyup')release();else {pressed=true;releasePending=false;motionDuration=100;settled=false;wake()}}}
|
|
258
311
|
const listeners=[
|
|
259
312
|
[document,'pointermove',move],[document,'pointerleave',leave],
|
|
260
313
|
[document,'focusin',focus],[document,'focusout',blur],
|
|
@@ -264,6 +317,7 @@ function mountBodyTargetFrame(document, window, operation) {
|
|
|
264
317
|
]
|
|
265
318
|
for(const [node,event,handler] of listeners)node.addEventListener(event,handler)
|
|
266
319
|
return ()=>{
|
|
320
|
+
modalObserver?.disconnect();document.removeEventListener('toggle',modalToggle,true)
|
|
267
321
|
disposed=true;target?.removeAttribute('data-prts-corner-target');hideFrame();window.cancelAnimationFrame(raf);resizeObserver?.disconnect()
|
|
268
322
|
document.removeEventListener('scroll',scroll,true);window.removeEventListener('resize',reset)
|
|
269
323
|
for(const [node,event,handler] of listeners)node.removeEventListener(event,handler)
|
|
@@ -43,7 +43,7 @@ export function createAvatarStore({window,document}){
|
|
|
43
43
|
const focus=()=>{if(window.fetch)void refresh().catch(()=>{})}
|
|
44
44
|
window.addEventListener('focus',focus)
|
|
45
45
|
return{
|
|
46
|
-
snapshot:()=>state,refresh,
|
|
46
|
+
snapshot:()=>state,refresh,applySnapshot:apply,
|
|
47
47
|
subscribe(fn){listeners.add(fn);fn(state);return()=>listeners.delete(fn)},
|
|
48
48
|
async edit(role){
|
|
49
49
|
const response=await window.fetch(API+'/edit/'+role,{credentials:'same-origin',signal:controller?.signal})
|
package/src/client/index.js
CHANGED
|
@@ -208,6 +208,7 @@ export function applyPrtsPlugin(ctx, environment) {
|
|
|
208
208
|
document, window, assets, adapter, hostGeometry, customEmblemStore, avatarStore, backgroundStore,
|
|
209
209
|
themeTransfer: themeTransfer ||= createThemeTransfer({ window, getPreferences: () => nativePreferences.value,
|
|
210
210
|
savePreferences: (value, revision) => nativePreferences.replace(value, revision),
|
|
211
|
+
onAvatarConfiguration: value => avatarStore.applySnapshot(value),
|
|
211
212
|
checkWritable: () => nativePreferences.checkWritable(), checkExport: () => nativePreferences.checkReadable(), themeVersion: version }),
|
|
212
213
|
onSchemeToggle(next, interaction) {
|
|
213
214
|
return theme.setTheme(next, { ...interaction, animate: true })
|
|
@@ -95,9 +95,13 @@ function visibleSessionSummaries(sessions, workspaces, sessionStatus) {
|
|
|
95
95
|
})
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
function setSidebarAttribute(node, attribute, value) {
|
|
99
|
+
if (node.getAttribute(attribute) !== value) node.setAttribute(attribute, value)
|
|
100
|
+
}
|
|
101
|
+
|
|
98
102
|
function markSidebarNode(node, attribute, next) {
|
|
99
103
|
if (!node) return
|
|
100
|
-
node
|
|
104
|
+
setSidebarAttribute(node, attribute, '')
|
|
101
105
|
next.add(node)
|
|
102
106
|
}
|
|
103
107
|
|
|
@@ -174,9 +178,9 @@ function ensureFacilityFace(document, row, kind, next) {
|
|
|
174
178
|
face.setAttribute('data-prts-owned-facility', '')
|
|
175
179
|
row.insertBefore(face, row.firstChild)
|
|
176
180
|
}
|
|
177
|
-
face
|
|
178
|
-
face
|
|
179
|
-
face
|
|
181
|
+
setSidebarAttribute(face, 'data-prts-facility-face', kind)
|
|
182
|
+
setSidebarAttribute(face, 'data-prts-facility-texture', kind === 'workspace' ? 'silhouette' : 'pickup')
|
|
183
|
+
setSidebarAttribute(face, 'aria-hidden', 'true')
|
|
180
184
|
next.add(face)
|
|
181
185
|
return face
|
|
182
186
|
}
|
|
@@ -188,8 +192,8 @@ function ensureFacilitySpine(document, row, kind, next) {
|
|
|
188
192
|
spine.setAttribute('data-prts-owned-facility-spine', '')
|
|
189
193
|
row.insertBefore(spine, row.firstChild)
|
|
190
194
|
}
|
|
191
|
-
spine
|
|
192
|
-
spine
|
|
195
|
+
setSidebarAttribute(spine, 'data-prts-facility-spine', kind)
|
|
196
|
+
setSidebarAttribute(spine, 'aria-hidden', 'true')
|
|
193
197
|
next.add(spine)
|
|
194
198
|
return spine
|
|
195
199
|
}
|
|
@@ -223,6 +227,7 @@ export function createSidebarControlAdapter({ document, window, sessions, worksp
|
|
|
223
227
|
let statusSourcesStarted = false
|
|
224
228
|
let summaryRoot
|
|
225
229
|
let summarySignature = ''
|
|
230
|
+
let sourceSummarySignature = ''
|
|
226
231
|
let heldPreviewState
|
|
227
232
|
let hoveredSummary, summaryLeaveTimer
|
|
228
233
|
let summaryDismissed = false, pointerLeftSummary = false
|
|
@@ -327,18 +332,26 @@ export function createSidebarControlAdapter({ document, window, sessions, worksp
|
|
|
327
332
|
sourceRetryTimer = undefined
|
|
328
333
|
}
|
|
329
334
|
}
|
|
335
|
+
function onSummarySourceChange() {
|
|
336
|
+
// Streaming activity often republishes unchanged title/status summaries.
|
|
337
|
+
// Native DOM mutations still handle row mounts, selection and hierarchy.
|
|
338
|
+
const signature = JSON.stringify(visibleSessionSummaries(sessions, workspaces, sessionStatus))
|
|
339
|
+
if (signature === sourceSummarySignature && !pendingReveal) return
|
|
340
|
+
sourceSummarySignature = signature
|
|
341
|
+
queueScan()
|
|
342
|
+
}
|
|
330
343
|
function connectSummarySources() {
|
|
331
344
|
if (getSessions) sessions = getSessions()
|
|
332
345
|
if (getWorkspaces) workspaces = getWorkspaces()
|
|
333
346
|
if (subscribedSessions !== sessions?.list) {
|
|
334
347
|
stopSessionList()
|
|
335
348
|
subscribedSessions = sessions?.list
|
|
336
|
-
stopSessionList = subscribedSessions?.subscribe?.(
|
|
349
|
+
stopSessionList = subscribedSessions?.subscribe?.(onSummarySourceChange) ?? (() => {})
|
|
337
350
|
}
|
|
338
351
|
if (subscribedWorkspaces !== workspaces?.list) {
|
|
339
352
|
stopWorkspaceList()
|
|
340
353
|
subscribedWorkspaces = workspaces?.list
|
|
341
|
-
stopWorkspaceList = subscribedWorkspaces?.subscribe?.(
|
|
354
|
+
stopWorkspaceList = subscribedWorkspaces?.subscribe?.(onSummarySourceChange) ?? (() => {})
|
|
342
355
|
}
|
|
343
356
|
}
|
|
344
357
|
function connectSessionStatus() {
|
|
@@ -346,7 +359,7 @@ export function createSidebarControlAdapter({ document, window, sessions, worksp
|
|
|
346
359
|
if (source === sessionStatus) return
|
|
347
360
|
stopSessionStatus()
|
|
348
361
|
sessionStatus = source
|
|
349
|
-
stopSessionStatus = source?.subscribe?.(
|
|
362
|
+
stopSessionStatus = source?.subscribe?.(onSummarySourceChange) ?? (() => {})
|
|
350
363
|
}
|
|
351
364
|
|
|
352
365
|
let selectionTarget, selectionTargetTimer
|
|
@@ -861,6 +874,7 @@ export function createSidebarControlAdapter({ document, window, sessions, worksp
|
|
|
861
874
|
function scan() {
|
|
862
875
|
if (!adapterActive) return
|
|
863
876
|
syncSummarySources()
|
|
877
|
+
sourceSummarySignature = JSON.stringify(visibleSessionSummaries(sessions, workspaces, sessionStatus))
|
|
864
878
|
const root = document?.querySelector?.('[data-prts-region="sessions"] [data-slot="sidebar.workspaces"]')
|
|
865
879
|
const next = new Set()
|
|
866
880
|
const nextVectorOwners = new Set()
|
|
@@ -919,16 +933,16 @@ export function createSidebarControlAdapter({ document, window, sessions, worksp
|
|
|
919
933
|
}
|
|
920
934
|
markSidebarNode(row, 'data-prts-session-row', next)
|
|
921
935
|
if (state) {
|
|
922
|
-
row
|
|
936
|
+
setSidebarAttribute(row, 'data-prts-session-state', state)
|
|
923
937
|
next.add(row)
|
|
924
938
|
} else {
|
|
925
939
|
row.removeAttribute('data-prts-session-state')
|
|
926
940
|
}
|
|
927
|
-
row
|
|
941
|
+
setSidebarAttribute(row, 'data-prts-session-index', sessionIndex)
|
|
928
942
|
const title = resolveRowTitle(row, 'session', controls.actions)
|
|
929
943
|
markSidebarNode(title, 'data-prts-row-title', next)
|
|
930
944
|
markSidebarNode(resolveSessionTime(row, title, controls.actions), 'data-prts-session-time', next)
|
|
931
|
-
if (title) title
|
|
945
|
+
if (title) setSidebarAttribute(title, 'data-prts-session-index', sessionIndex)
|
|
932
946
|
row.toggleAttribute('data-prts-row-menu-open', controls.menu?.getAttribute('aria-expanded') === 'true'
|
|
933
947
|
|| row.classList.contains('menuOpen'))
|
|
934
948
|
markSidebarNode(controls.actions, 'data-prts-session-actions', next)
|
|
@@ -101,7 +101,7 @@ export function describeThemePackage(value) {
|
|
|
101
101
|
return `${count} 项主题设置、${transferSlots.filter(k => a.backgrounds[k]).length} 张背景、${transferRoles.filter(k => a.avatars[k]).length} 个头像、${a.emblems.items.length} 个自定义徽记。将替换当前素材及徽记排列,空项恢复为默认。`
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
export function createThemeTransfer({ window, getPreferences, savePreferences, checkWritable, checkExport = checkWritable, themeVersion }) {
|
|
104
|
+
export function createThemeTransfer({ window, getPreferences, savePreferences, checkWritable, checkExport = checkWritable, themeVersion, onAvatarConfiguration = () => {} }) {
|
|
105
105
|
let busy = false, backup
|
|
106
106
|
const request = async (path, data, signal) => {
|
|
107
107
|
checkTransferCancelled(signal)
|
|
@@ -198,7 +198,10 @@ export function createThemeTransfer({ window, getPreferences, savePreferences, c
|
|
|
198
198
|
undo.push(async () => {
|
|
199
199
|
const restored = await request(kind + '/configuration', { ...previous, revision: revisions[kind] })
|
|
200
200
|
revisions[kind] = restored.revision
|
|
201
|
+
if (kind === 'avatars') onAvatarConfiguration(restored)
|
|
201
202
|
})
|
|
203
|
+
// Apply the acknowledged images locally; SSE remains for other pages.
|
|
204
|
+
if (kind === 'avatars') onAvatarConfiguration(result)
|
|
202
205
|
}
|
|
203
206
|
try {
|
|
204
207
|
if (value.assets) {
|
|
@@ -485,3 +485,13 @@ background:color-mix(in srgb,var(--prts-panel) 28%,transparent);
|
|
|
485
485
|
-webkit-backdrop-filter:blur(12px);
|
|
486
486
|
backdrop-filter:blur(12px);
|
|
487
487
|
}
|
|
488
|
+
|
|
489
|
+
/* The task manager mounts directly in main, outside the conversation root. */
|
|
490
|
+
html[data-dsh-prts] [data-prts-region="operation"] [data-testid="task-manager-page"],
|
|
491
|
+
html[data-dsh-prts] [data-testid="task-manager-page"] :is([class$="_detail"],[class$="_detailNotice"]) {
|
|
492
|
+
background: var(--prts-canvas);
|
|
493
|
+
}
|
|
494
|
+
html[data-dsh-prts]:is([data-prts-background-mode="full"][data-prts-background-full],[data-prts-background-mode="split"][data-prts-background-conversation]) [data-prts-region="operation"] [data-testid="task-manager-page"],
|
|
495
|
+
html[data-dsh-prts]:is([data-prts-background-mode="full"][data-prts-background-full],[data-prts-background-mode="split"][data-prts-background-conversation]) [data-testid="task-manager-page"] :is([class$="_detail"],[class$="_detailNotice"]) {
|
|
496
|
+
background: transparent;
|
|
497
|
+
}
|