@ash-qw/dsh-theme-prts 2.5.3 → 2.5.5

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.
@@ -171,6 +171,7 @@ export function themeSettingsMarkup() {
171
171
  <section data-prts-settings-common data-prts-settings-section="interaction" role="tabpanel" id="prts-page-interaction" aria-labelledby="prts-tab-interaction" tabindex="0" hidden>
172
172
  <div data-prts-settings-common-grid>
173
173
  ${COMMON_CONTROLS.filter(([key]) => ['cursor', 'railDefaultHidden', 'motion'].includes(key)).map(([key, label, options]) => settingButtons(key, label, options)).join('')}
174
+ <div data-prts-setting-row="cornerColor"><span><strong>交互提示框颜色</strong><small data-prts-setting-note>部分按钮和卡片的四角提示颜色,危险操作保持红色。</small></span><div data-prts-corner-presets role="group" aria-label="交互提示框预设颜色">${[['黄色','#f0c800'],['白色','#ffffff'],['青色','#65ddb0'],['蓝色','#6eb7f3'],['紫色','#b487ef']].map(([name,color]) => `<button type="button" data-prts-corner-preset="${color}" aria-label="${name}" title="${name}" aria-pressed="false" style="--swatch:${color}"><i aria-hidden="true"></i></button>`).join('')}<button type="button" data-prts-corner-custom title="选择自定义颜色"><i data-prts-corner-preview aria-hidden="true"></i><span>自定义</span></button><input type="color" data-prts-corner-color aria-label="交互提示框颜色" value="#f0c800" hidden></div></div>
174
175
  </div>
175
176
  </section>
176
177
  <section data-prts-settings-section="ai-tools" data-prts-ai-tools role="tabpanel" id="prts-page-ai-tools" aria-labelledby="prts-tab-ai-tools" tabindex="0" hidden>
@@ -531,6 +532,10 @@ export function createThemeSettingsOverlay({
531
532
 
532
533
  function renderState() {
533
534
  if (!panel || !currentPreferences) return
535
+ const cornerColor = panel.querySelector('[data-prts-corner-color]')
536
+ if (cornerColor) cornerColor.value = currentPreferences.cornerCustomColor
537
+ panel.querySelector('[data-prts-corner-preview]')?.style.setProperty('--swatch', currentPreferences.cornerCustomColor)
538
+ for (const preset of panel.querySelectorAll('[data-prts-corner-preset]')) preset.setAttribute('aria-pressed', String(preset.dataset.prtsCornerPreset === currentPreferences.cornerColor))
534
539
  for (const toggle of panel.querySelectorAll('[data-prts-setting-switch]')) {
535
540
  const key = toggle.dataset.prtsSettingSwitch
536
541
  const enabled = key === 'cursor' ? currentPreferences.cursor === 'prts'
@@ -625,6 +630,8 @@ export function createThemeSettingsOverlay({
625
630
  if (event.target === panel) { setOpen(false); return }
626
631
  const target = event.target?.closest?.('button')
627
632
  if (!target) return
633
+ if (target.hasAttribute('data-prts-corner-custom')) { panel.querySelector('[data-prts-corner-color]').click(); return }
634
+ if (target.hasAttribute('data-prts-corner-preset')) { onPreferenceChange('cornerColor', target.dataset.prtsCornerPreset); return }
628
635
  if (target.hasAttribute('data-prts-settings-jump')) {
629
636
  selectSection(target.dataset.prtsSettingsJump)
630
637
  return
@@ -663,6 +670,7 @@ export function createThemeSettingsOverlay({
663
670
 
664
671
  function onPanelInput(event) {
665
672
  const target = event.target
673
+ if (target?.matches?.('[data-prts-corner-color]')) { onPreferencePreview('cornerColor', target.value); return }
666
674
  if (target?.matches?.('[data-prts-preview-reply-limit]')) { onPreferenceChange('previewReplyLimit', Number(target.value)); return }
667
675
  if (target?.matches?.('input[data-prts-setting-color]')) {
668
676
  const key = target.dataset.prtsSettingKey
@@ -725,6 +733,7 @@ export function createThemeSettingsOverlay({
725
733
  const renderMediaState = () => renderState()
726
734
  const commitFromControl = event => {
727
735
  const target = event.target
736
+ if (target?.matches?.('[data-prts-corner-color]')) { if (event.type === 'change') onPreferenceChange('cornerCustomColor', target.value); return }
728
737
  if (target?.matches?.('input[data-prts-setting-color]')) {
729
738
  if (event.type === 'change' || event.type === 'focusout') commitSessionFlowColor(target.dataset.prtsSettingKey)
730
739
  return
@@ -13,9 +13,8 @@ export function themeTransferMarkup() {
13
13
  <button type="button" data-prts-transfer-export>导出主题文件 <span aria-hidden="true">↓</span></button>
14
14
  </section>
15
15
  <section data-prts-transfer-card="import" data-prts-transfer-drop>
16
- <h3>导入主题</h3><p>选择或拖入已导出的文件,确认内容后应用。</p>
17
- <div data-prts-transfer-file-hint><span aria-hidden="true">↑</span><small>.prts-theme.json · 最大 160 MB</small></div>
18
- <button type="button" data-prts-transfer-choose>选择主题文件 <span aria-hidden="true">↑</span></button>
16
+ <h3>导入主题</h3><p>导入已导出的主题文件,确认内容后应用。</p>
17
+ <button type="button" data-prts-transfer-file-hint data-prts-transfer-choose><span aria-hidden="true">↑</span><strong>点击选择或拖拽主题文件到此处</strong><small>.prts-theme.json · 最大 160 MB</small></button>
19
18
  <input type="file" accept=".prts-theme.json,application/json" aria-label="导入主题文件" data-prts-transfer-file hidden>
20
19
  </section>
21
20
  </div>
@@ -5,9 +5,10 @@ background: linear-gradient(var(--prts-background-wash), var(--prts-background-w
5
5
  }
6
6
  html[data-dsh-prts][data-prts-background-mode="full"][data-prts-background-full] :is([data-prts-region="sessions"], [data-prts-region="operation"]) { background: transparent; }
7
7
  html[data-dsh-prts][data-prts-background-mode="split"][data-prts-background-sidebar] {
8
+ & :is([data-prts-region="sessions"],[data-prts-nav-rail]) {
8
9
  --prts-wall-width:var(--prts-protected-sidebar-width,max(calc(var(--prts-sidebar-width,280px) + var(--prts-nav-width)),calc((100dvh - var(--prts-host-top-inset)) * var(--prts-sidebar-image-ratio,1))));
9
10
  --prts-wall-x:var(--prts-protected-sidebar-x,calc((var(--prts-sidebar-width,280px) + var(--prts-nav-width) - var(--prts-wall-width)) / 2));
10
- & :is([data-prts-region="sessions"],[data-prts-nav-rail]){background:linear-gradient(var(--prts-background-wash),var(--prts-background-wash)),var(--prts-background-sidebar) var(--prts-wall-x) var(--prts-protected-sidebar-y, 50%) / var(--prts-wall-width) auto no-repeat}
11
+ background:linear-gradient(var(--prts-background-wash),var(--prts-background-wash)),var(--prts-background-sidebar) var(--prts-wall-x) var(--prts-protected-sidebar-y, 50%) / var(--prts-wall-width) auto no-repeat}
11
12
  & [data-prts-region="sessions"]{background-position:center,calc(var(--prts-wall-x) - var(--prts-nav-width)) var(--prts-protected-sidebar-y, 50%)}
12
13
  }
13
14
  html[data-dsh-prts][data-prts-rail-mode="overlay"]:is([data-prts-background-mode="split"][data-prts-background-sidebar],[data-prts-background-mode="full"][data-prts-background-full]) [data-prts-nav-rail] { background: transparent; }
@@ -48,7 +48,7 @@ html[data-dsh-prts] [data-prts-session-idle-indicator] {
48
48
  fill: var(--prts-dim);
49
49
  }
50
50
 
51
- html[data-dsh-prts] [data-prts-session-state] [data-prts-session-idle-indicator] {
51
+ html[data-dsh-prts] :is([data-prts-session-state], [data-prts-session-row]:has([data-session-schedule-mark])) [data-prts-session-idle-indicator] {
52
52
  opacity: 0;
53
53
  }
54
54
 
@@ -572,11 +572,11 @@ html[data-dsh-prts] [data-prts-session-pickup-bar]:nth-of-type(10) { --prts-pick
572
572
  html[data-dsh-prts] [data-prts-session-pickup-bar]:nth-of-type(11) { --prts-pickup-duration: 560ms; --prts-pickup-delay: -.3s; }
573
573
 
574
574
  @media (prefers-reduced-motion: no-preference) {
575
- html[data-dsh-prts]:not([data-prts-motion="reduced"]) [data-prts-session-row]:hover [data-prts-session-pickup-indicator] {
575
+ html[data-dsh-prts]:not([data-prts-motion="reduced"]) [data-prts-session-row]:hover[data-prts-pickup-ready] [data-prts-session-pickup-indicator] {
576
576
  animation: prts-session-record-indicator 1.1s ease-in-out infinite;
577
577
  }
578
578
 
579
- html[data-dsh-prts]:not([data-prts-motion="reduced"]) [data-prts-session-row]:hover [data-prts-session-pickup-bar] {
579
+ html[data-dsh-prts]:not([data-prts-motion="reduced"]) [data-prts-session-row]:hover[data-prts-pickup-ready] [data-prts-session-pickup-bar] {
580
580
  animation: prts-session-pickup-sample var(--prts-pickup-duration) ease-in-out var(--prts-pickup-delay) infinite;
581
581
  }
582
582
  }
@@ -824,7 +824,7 @@ html[data-dsh-prts] [data-prts-session-summary-popover]:has(> [data-prts-preview
824
824
  }
825
825
 
826
826
  /* Keep different-sized state markers centered on the same axis. */
827
- html[data-dsh-prts] [data-prts-session-row] [data-state]:is([data-state="ongoing"], [data-state="done"], [data-state="warning"], [data-state="error"]) {
827
+ html[data-dsh-prts] [data-prts-session-row] :is([data-state="ongoing"], [data-state="done"], [data-state="warning"], [data-state="error"], [data-session-schedule-mark]) {
828
828
  flex-shrink: 0;
829
829
  margin-left: 20px;
830
830
  }
@@ -886,3 +886,15 @@ html[data-dsh-prts] [data-prts-tool-record] > div { display:flex;align-items:bas
886
886
  html[data-dsh-prts] [data-prts-tool-record] b { flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--prts-cyan);font:11px/1.6 var(--prts-mono); }
887
887
  html[data-dsh-prts] [data-prts-tool-record] small { flex:none;color:var(--prts-muted);font-size:10px; }
888
888
  html[data-dsh-prts] [data-prts-tool-record] p { display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;margin:4px 0 0; }
889
+
890
+ /* Show the baseline immediately; only start the pickup after a deliberate hover. */
891
+ html[data-dsh-prts] [data-prts-session-row]:not([data-prts-pickup-ready]) :is([data-prts-session-pickup-bar],[data-prts-session-pickup-indicator]) { visibility:hidden; }
892
+
893
+ html[data-dsh-prts] [data-prts-reply-entry][data-prts-reply-complete] { cursor:text; }
894
+
895
+ /* Reserve the cue's width so showing it never changes the truncation measurement. */
896
+ html[data-dsh-prts] [data-prts-reply-entry] > span { display:block;-webkit-line-clamp:unset;max-height:3.2em;color:#b8bec6; }
897
+ html[data-dsh-prts] [data-prts-reply-ellipsis] { flex:0 0 12px;align-self:flex-end;color:#f0e6d6;font:600 14px/1.4 var(--prts-body);visibility:hidden; }
898
+ html[data-dsh-prts] [data-prts-reply-overflow] > [data-prts-reply-ellipsis] { visibility:visible; }
899
+
900
+ html[data-dsh-prts] [data-prts-reply-overflow] > span { color:#f0e6d6; }
@@ -963,7 +963,7 @@ html[data-dsh-prts] [data-prts-row-title] {
963
963
  white-space: nowrap;
964
964
  }
965
965
 
966
- html[data-dsh-prts] [data-prts-session-row] > span:has(> [data-state]) {
966
+ html[data-dsh-prts] [data-prts-session-row] > span:has(> :is([data-state], [data-session-schedule-mark])) {
967
967
  padding-left: 0 !important;
968
968
  }
969
969
 
@@ -508,7 +508,7 @@ html[data-dsh-prts] [data-turn-trigger] {
508
508
  }
509
509
 
510
510
  /* Body interactions lock onto four corners; shell controls keep their own treatment. */
511
- html[data-dsh-prts] :is([data-chat-flow-kind],[data-message-role]) :is([data-prts-conversation-control],[data-presented-file],[data-changed-files],[data-produced-files-row] > button) {
511
+ html[data-dsh-prts] :is([data-chat-flow-kind],[data-message-role],[data-submission-echo],[data-pending-steering]) :is([data-prts-conversation-control],[data-presented-file],[data-changed-files],[data-produced-files-row] > button) {
512
512
  position:relative;
513
513
  --prts-control-outline:var(--prts-line);
514
514
  &:is(:hover,:focus-visible,:focus-within) {
@@ -967,7 +967,8 @@ html[data-dsh-prts] [data-prts-transfer] {
967
967
  & [data-prts-transfer-option] { align-items:flex-start; flex-wrap:nowrap; padding:12px 0 0; }
968
968
  & [data-prts-transfer-option] input { margin:5px 0 0; }
969
969
  & [data-prts-transfer-option] small { display:block; margin-top:4px; }
970
- & [data-prts-transfer-file-hint] { display:grid; place-items:center; flex:1; gap:6px; padding:12px; border:1px dashed var(--prts-line-strong); }
970
+ & [data-prts-transfer-card] > [data-prts-transfer-file-hint] { display:flex; flex-direction:column; justify-content:center; flex:1; gap:6px; min-height:130px; padding:16px 12px; border:1px dashed var(--prts-line-strong); text-align:center; white-space:normal; }
971
+ & [data-prts-transfer-file-hint] > strong { font-size:13px; font-weight:500; }
971
972
  & [data-prts-transfer-file-hint] > span { font-size:24px; color:var(--prts-muted); }
972
973
  & [data-prts-transfer-buttons] { display:flex; gap:8px; }
973
974
  & [data-prts-transfer-compatibility] { margin:0; padding:10px 12px; border:1px solid var(--prts-yellow); overflow-wrap:anywhere; }
@@ -1032,3 +1033,15 @@ html[data-dsh-prts] [data-prts-transfer]:not([aria-busy="true"]) [data-prts-tran
1032
1033
  }
1033
1034
  html[data-prts-motion="reduced"] [data-prts-transfer-card] { transition:none; }
1034
1035
  @media (prefers-reduced-motion:reduce) { [data-prts-transfer-card] { transition:none; } }
1036
+
1037
+ html[data-dsh-prts] [data-prts-setting-row="cornerColor"] { flex-wrap:wrap;gap:16px; }
1038
+ html[data-dsh-prts] [data-prts-corner-presets] { display:flex;flex-wrap:wrap;gap:6px;align-items:center;
1039
+ & > button { position:relative;display:grid;place-items:center;width:32px;height:32px;padding:5px;border:1px solid transparent;border-radius:4px;background:transparent; }
1040
+ & i { display:block;width:18px;height:18px;border-radius:3px;background:var(--swatch);box-shadow:inset 0 0 0 1px #8884; }
1041
+ & > button:hover { background:var(--prts-panel-raised); }
1042
+ & > button[aria-pressed="true"] { border-color:var(--prts-ink);background:var(--prts-panel-raised); }
1043
+ & > button[aria-pressed="true"]::after { content:"";position:absolute;width:8px;height:4px;border-left:2px solid #172025;border-bottom:2px solid #172025;transform:translateY(-1px) rotate(-45deg); }
1044
+ & > button:focus-visible { outline:2px solid var(--prts-ink);outline-offset:2px; }
1045
+ }
1046
+ html[data-dsh-prts] [data-prts-corner-presets] > [data-prts-corner-custom] { display:flex;align-items:center;gap:8px;width:auto;height:32px;margin-left:8px;padding:5px 10px;border:1px solid var(--prts-line-strong);border-radius:4px;background:var(--prts-panel-raised);color:var(--prts-ink);font:12px/1 var(--prts-body);white-space:nowrap; }
1047
+ html[data-dsh-prts] [data-prts-corner-presets] > [data-prts-corner-custom]:is(:hover,:focus-visible) { border-color:var(--prts-ink);background:color-mix(in srgb,var(--prts-ink) 8%,var(--prts-panel-raised)); }
@@ -407,14 +407,28 @@ const GlassSurface = ({
407
407
  useEffect(() => {
408
408
  if (!containerRef.current) return;
409
409
 
410
- const resizeObserver = new ResizeObserver(() => {
410
+ // PRTS: keep the existing map stretched with the live container while
411
+ // resizing. Rebuilding its distance field on every intermediate width
412
+ // defeats the outer composer's settled-shape update.
413
+ let timer;
414
+ let committed = '';
415
+ const commit = () => {
416
+ timer = undefined;
411
417
  const element = containerRef.current;
412
- if (element) setBoxSize(`${element.offsetWidth}x${element.offsetHeight}`);
418
+ if (!element || !element.offsetWidth || !element.offsetHeight) return;
419
+ const next = `${element.offsetWidth}x${element.offsetHeight}`;
420
+ if (next !== committed) { committed = next; setBoxSize(next); }
421
+ };
422
+ const resizeObserver = new ResizeObserver(() => {
423
+ clearTimeout(timer);
424
+ if (!committed) commit();
425
+ else timer = setTimeout(commit, 160);
413
426
  });
414
427
 
415
428
  resizeObserver.observe(containerRef.current);
416
429
 
417
430
  return () => {
431
+ clearTimeout(timer);
418
432
  resizeObserver.disconnect();
419
433
  };
420
434
  }, []);