@ash-qw/dsh-theme-prts 2.5.1 → 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 +22 -0
- package/lib/client.js +98 -35
- 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 +31 -14
- package/src/client/theme-transfer.js +4 -1
- package/src/styles/custom-background.css +16 -0
- package/src/styles/refinement.css +6 -10
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,17 +95,24 @@ 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
|
|
|
104
108
|
function resolveRowControls(row, kind) {
|
|
105
109
|
const menu = row.querySelector(':scope > span > span > button[type="button"]')
|
|
106
110
|
const anchor = menu?.parentElement
|
|
107
|
-
|
|
108
|
-
|
|
111
|
+
// Ungrouped workspaces have a create button but no management menu.
|
|
112
|
+
const actions = anchor?.parentElement ?? (kind === 'workspace'
|
|
113
|
+
? Array.from(row.children).find(node => node.matches('span') && node.querySelector(':scope > button[type="button"]'))
|
|
114
|
+
: undefined)
|
|
115
|
+
if (actions?.parentElement !== row) return {}
|
|
109
116
|
const create = kind === 'workspace'
|
|
110
117
|
? actions.querySelector(':scope > button[type="button"]')
|
|
111
118
|
: undefined
|
|
@@ -171,9 +178,9 @@ function ensureFacilityFace(document, row, kind, next) {
|
|
|
171
178
|
face.setAttribute('data-prts-owned-facility', '')
|
|
172
179
|
row.insertBefore(face, row.firstChild)
|
|
173
180
|
}
|
|
174
|
-
face
|
|
175
|
-
face
|
|
176
|
-
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')
|
|
177
184
|
next.add(face)
|
|
178
185
|
return face
|
|
179
186
|
}
|
|
@@ -185,8 +192,8 @@ function ensureFacilitySpine(document, row, kind, next) {
|
|
|
185
192
|
spine.setAttribute('data-prts-owned-facility-spine', '')
|
|
186
193
|
row.insertBefore(spine, row.firstChild)
|
|
187
194
|
}
|
|
188
|
-
spine
|
|
189
|
-
spine
|
|
195
|
+
setSidebarAttribute(spine, 'data-prts-facility-spine', kind)
|
|
196
|
+
setSidebarAttribute(spine, 'aria-hidden', 'true')
|
|
190
197
|
next.add(spine)
|
|
191
198
|
return spine
|
|
192
199
|
}
|
|
@@ -220,6 +227,7 @@ export function createSidebarControlAdapter({ document, window, sessions, worksp
|
|
|
220
227
|
let statusSourcesStarted = false
|
|
221
228
|
let summaryRoot
|
|
222
229
|
let summarySignature = ''
|
|
230
|
+
let sourceSummarySignature = ''
|
|
223
231
|
let heldPreviewState
|
|
224
232
|
let hoveredSummary, summaryLeaveTimer
|
|
225
233
|
let summaryDismissed = false, pointerLeftSummary = false
|
|
@@ -324,18 +332,26 @@ export function createSidebarControlAdapter({ document, window, sessions, worksp
|
|
|
324
332
|
sourceRetryTimer = undefined
|
|
325
333
|
}
|
|
326
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
|
+
}
|
|
327
343
|
function connectSummarySources() {
|
|
328
344
|
if (getSessions) sessions = getSessions()
|
|
329
345
|
if (getWorkspaces) workspaces = getWorkspaces()
|
|
330
346
|
if (subscribedSessions !== sessions?.list) {
|
|
331
347
|
stopSessionList()
|
|
332
348
|
subscribedSessions = sessions?.list
|
|
333
|
-
stopSessionList = subscribedSessions?.subscribe?.(
|
|
349
|
+
stopSessionList = subscribedSessions?.subscribe?.(onSummarySourceChange) ?? (() => {})
|
|
334
350
|
}
|
|
335
351
|
if (subscribedWorkspaces !== workspaces?.list) {
|
|
336
352
|
stopWorkspaceList()
|
|
337
353
|
subscribedWorkspaces = workspaces?.list
|
|
338
|
-
stopWorkspaceList = subscribedWorkspaces?.subscribe?.(
|
|
354
|
+
stopWorkspaceList = subscribedWorkspaces?.subscribe?.(onSummarySourceChange) ?? (() => {})
|
|
339
355
|
}
|
|
340
356
|
}
|
|
341
357
|
function connectSessionStatus() {
|
|
@@ -343,7 +359,7 @@ export function createSidebarControlAdapter({ document, window, sessions, worksp
|
|
|
343
359
|
if (source === sessionStatus) return
|
|
344
360
|
stopSessionStatus()
|
|
345
361
|
sessionStatus = source
|
|
346
|
-
stopSessionStatus = source?.subscribe?.(
|
|
362
|
+
stopSessionStatus = source?.subscribe?.(onSummarySourceChange) ?? (() => {})
|
|
347
363
|
}
|
|
348
364
|
|
|
349
365
|
let selectionTarget, selectionTargetTimer
|
|
@@ -858,6 +874,7 @@ export function createSidebarControlAdapter({ document, window, sessions, worksp
|
|
|
858
874
|
function scan() {
|
|
859
875
|
if (!adapterActive) return
|
|
860
876
|
syncSummarySources()
|
|
877
|
+
sourceSummarySignature = JSON.stringify(visibleSessionSummaries(sessions, workspaces, sessionStatus))
|
|
861
878
|
const root = document?.querySelector?.('[data-prts-region="sessions"] [data-slot="sidebar.workspaces"]')
|
|
862
879
|
const next = new Set()
|
|
863
880
|
const nextVectorOwners = new Set()
|
|
@@ -916,16 +933,16 @@ export function createSidebarControlAdapter({ document, window, sessions, worksp
|
|
|
916
933
|
}
|
|
917
934
|
markSidebarNode(row, 'data-prts-session-row', next)
|
|
918
935
|
if (state) {
|
|
919
|
-
row
|
|
936
|
+
setSidebarAttribute(row, 'data-prts-session-state', state)
|
|
920
937
|
next.add(row)
|
|
921
938
|
} else {
|
|
922
939
|
row.removeAttribute('data-prts-session-state')
|
|
923
940
|
}
|
|
924
|
-
row
|
|
941
|
+
setSidebarAttribute(row, 'data-prts-session-index', sessionIndex)
|
|
925
942
|
const title = resolveRowTitle(row, 'session', controls.actions)
|
|
926
943
|
markSidebarNode(title, 'data-prts-row-title', next)
|
|
927
944
|
markSidebarNode(resolveSessionTime(row, title, controls.actions), 'data-prts-session-time', next)
|
|
928
|
-
if (title) title
|
|
945
|
+
if (title) setSidebarAttribute(title, 'data-prts-session-index', sessionIndex)
|
|
929
946
|
row.toggleAttribute('data-prts-row-menu-open', controls.menu?.getAttribute('aria-expanded') === 'true'
|
|
930
947
|
|| row.classList.contains('menuOpen'))
|
|
931
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) {
|
|
@@ -345,6 +345,12 @@ html[data-dsh-prts] [data-prts-settings-section="background"] [data-prts-backgro
|
|
|
345
345
|
[data-prts-composer-glass-setting], [data-prts-composer-glass-required] { display: block; margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--prts-line); }
|
|
346
346
|
[data-prts-composer-glass-required] { font-size: 12px; color: var(--prts-muted); }
|
|
347
347
|
|
|
348
|
+
/* Pending questions, approvals and plan reviews replace the glass composer.
|
|
349
|
+
* Keep its full-width seat clear even while no glass card is mounted. */
|
|
350
|
+
html[data-dsh-prts]:is([data-prts-background-mode="full"][data-prts-background-full],[data-prts-background-mode="split"][data-prts-background-conversation]) [data-composer-seat] {
|
|
351
|
+
background: transparent !important;
|
|
352
|
+
}
|
|
353
|
+
|
|
348
354
|
/* The native active composer fades into DSH's base color. Baker paints a
|
|
349
355
|
* different solid backdrop, so match that backdrop while keeping the fade. */
|
|
350
356
|
html[data-dsh-prts][data-prts-conversation-style="deck-chat"][data-prts-background-mode="off"] [data-phase="active"] [data-composer-seat]:not(:has([data-prts-composer-glass-active])) {
|
|
@@ -479,3 +485,13 @@ background:color-mix(in srgb,var(--prts-panel) 28%,transparent);
|
|
|
479
485
|
-webkit-backdrop-filter:blur(12px);
|
|
480
486
|
backdrop-filter:blur(12px);
|
|
481
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
|
+
}
|
|
@@ -32,20 +32,12 @@ html[data-dsh-prts] [data-prts-region="sessions"] [data-slot="sidebar.settings"]
|
|
|
32
32
|
color: var(--prts-ink) !important;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
/*
|
|
36
|
-
html[data-dsh-prts] [data-prts-workspace-icon]
|
|
37
|
-
display: none !important;
|
|
38
|
-
}
|
|
39
|
-
|
|
35
|
+
/* Keep native folder/chevron visibility and active color; align their shared seat. */
|
|
36
|
+
html[data-dsh-prts] [data-prts-workspace-icon],
|
|
40
37
|
html[data-dsh-prts] [data-prts-workspace-disclosure] {
|
|
41
38
|
position: relative;
|
|
42
39
|
z-index: 4;
|
|
43
|
-
width: 14px;
|
|
44
|
-
flex: 0 0 14px;
|
|
45
|
-
display: grid;
|
|
46
|
-
place-items: center;
|
|
47
40
|
margin-left: calc(var(--prts-spine-width) + 4px);
|
|
48
|
-
color: var(--prts-muted);
|
|
49
41
|
transform: translate3d(var(--prts-row-shift), 0, 0);
|
|
50
42
|
transition: transform 220ms var(--prts-ease-spring), color 160ms ease;
|
|
51
43
|
}
|
|
@@ -97,6 +89,10 @@ html[data-dsh-prts] [data-prts-workspace-actions] {
|
|
|
97
89
|
width: 57px !important;
|
|
98
90
|
}
|
|
99
91
|
|
|
92
|
+
html[data-dsh-prts] [data-prts-workspace-actions]:has(> [data-prts-workspace-create]:only-child) {
|
|
93
|
+
width: 28px !important;
|
|
94
|
+
}
|
|
95
|
+
|
|
100
96
|
html[data-dsh-prts] [data-prts-session-actions] {
|
|
101
97
|
width: auto !important;
|
|
102
98
|
}
|