@chatcode/cco-better-sidebar 0.18.0-rc.3 → 0.18.0-rc.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.
- package/README.md +19 -1
- package/README_EN.md +19 -1
- package/lib/client-editor.js +326 -258
- package/lib/client-mermaid.js +312 -259
- package/lib/client-registry.js +1392 -605
- package/lib/client-terminal.js +328 -260
- package/lib/client.js +1352 -565
- package/lib/index.js +162 -5
- package/lib/types/client/LogoutConfirmDialog.d.ts +5 -0
- package/lib/types/client/PluginMarketSettingsSection.d.ts +7 -0
- package/lib/types/client/PluginMarketView.d.ts +7 -0
- package/lib/types/client/api.d.ts +15 -0
- package/lib/types/client/builtins/tabs.d.ts +6 -3
- package/lib/types/client/locales.d.ts +23 -0
- package/lib/types/client/plugin-market-catalog.d.ts +25 -0
- package/lib/types/client/ui-tweaks/branding.d.ts +1 -1
- package/lib/types/client/ui-tweaks/index.d.ts +1 -1
- package/lib/types/client/ui-tweaks/sidebar-header.d.ts +6 -0
- package/lib/types/client/ui-tweaks/typography.d.ts +9 -0
- package/lib/types/login-page-script.d.ts +2 -0
- package/lib/types/login-route.d.ts +2 -0
- package/lib/types/plugin-market-api.d.ts +5 -0
- package/lib/types/plugin-market-shared.d.ts +37 -0
- package/lib/types/ui-tweaks/config.d.ts +5 -6
- package/package.json +1 -1
- package/src/client/AccountMenu.tsx +12 -2
- package/src/client/LogoutConfirmDialog.tsx +39 -0
- package/src/client/PluginMarketSettingsSection.tsx +55 -0
- package/src/client/PluginMarketView.module.css +35 -0
- package/src/client/PluginMarketView.tsx +154 -0
- package/src/client/api.ts +7 -0
- package/src/client/builtins/tabs.tsx +16 -3
- package/src/client/index.tsx +10 -1
- package/src/client/locales-ja.ts +23 -0
- package/src/client/locales.ts +48 -0
- package/src/client/plugin-market-catalog.ts +90 -0
- package/src/client/sidebar.module.css +81 -19
- package/src/client/ui-tweaks/branding.tsx +25 -16
- package/src/client/ui-tweaks/index.tsx +36 -99
- package/src/client/ui-tweaks/sidebar-header.ts +73 -0
- package/src/client/ui-tweaks/typography.ts +38 -0
- package/src/index.ts +2 -0
- package/src/login-page-script.ts +107 -0
- package/src/login-route.ts +7 -4
- package/src/plugin-market-api.ts +42 -0
- package/src/plugin-market-shared.ts +21 -0
- package/src/ui-tweaks/config.ts +10 -10
|
@@ -442,13 +442,11 @@
|
|
|
442
442
|
box-sizing: border-box;
|
|
443
443
|
gap: 8px;
|
|
444
444
|
width: 100%;
|
|
445
|
-
min-height:
|
|
446
|
-
padding:
|
|
445
|
+
min-height: 44px;
|
|
446
|
+
padding: 8px 12px max(8px, env(safe-area-inset-bottom));
|
|
447
447
|
border-radius: 0;
|
|
448
448
|
background: var(--dsw-alias-bg-layer-1);
|
|
449
|
-
font
|
|
450
|
-
font-size: var(--dsw-font-size-body-sm);
|
|
451
|
-
line-height: var(--dsw-font-line-height-body-sm);
|
|
449
|
+
font: var(--dsw-font-xs-13);
|
|
452
450
|
transition: background var(--ds-transition-duration-slow) var(--ds-ease-in-out);
|
|
453
451
|
}
|
|
454
452
|
|
|
@@ -466,18 +464,21 @@
|
|
|
466
464
|
.accountAvatar {
|
|
467
465
|
position: relative;
|
|
468
466
|
display: grid;
|
|
469
|
-
|
|
470
|
-
|
|
467
|
+
box-sizing: border-box;
|
|
468
|
+
width: 24px;
|
|
469
|
+
height: 24px;
|
|
471
470
|
flex: none;
|
|
472
471
|
place-items: center;
|
|
473
472
|
border-radius: 50%;
|
|
474
473
|
background: var(--dsw-alias-bg-layer-3);
|
|
475
474
|
border: 1px solid var(--dsw-alias-border-l2);
|
|
476
475
|
color: var(--dsw-alias-fg-accent);
|
|
476
|
+
font: var(--dsw-font-xxs-12);
|
|
477
477
|
font-weight: 600;
|
|
478
478
|
}
|
|
479
479
|
|
|
480
480
|
.accountName {
|
|
481
|
+
min-width: 0;
|
|
481
482
|
overflow: hidden;
|
|
482
483
|
text-overflow: ellipsis;
|
|
483
484
|
white-space: nowrap;
|
|
@@ -490,10 +491,10 @@
|
|
|
490
491
|
left: 8px;
|
|
491
492
|
display: grid;
|
|
492
493
|
box-sizing: border-box;
|
|
493
|
-
width: min(
|
|
494
|
-
padding:
|
|
494
|
+
width: min(224px, calc(100% - 16px));
|
|
495
|
+
padding: 8px 6px 6px;
|
|
495
496
|
border: 1px solid var(--dsw-alias-border-l2);
|
|
496
|
-
border-radius:
|
|
497
|
+
border-radius: 10px;
|
|
497
498
|
background: var(--dsw-alias-bg-layer-2);
|
|
498
499
|
z-index: 1;
|
|
499
500
|
}
|
|
@@ -502,16 +503,15 @@
|
|
|
502
503
|
display: flex;
|
|
503
504
|
align-items: center;
|
|
504
505
|
gap: 8px;
|
|
505
|
-
min-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
font
|
|
509
|
-
line-height: var(--dsw-font-line-height-body-sm);
|
|
506
|
+
min-width: 0;
|
|
507
|
+
min-height: 28px;
|
|
508
|
+
padding: 0 6px 6px;
|
|
509
|
+
font: var(--dsw-font-xs-13);
|
|
510
510
|
}
|
|
511
511
|
|
|
512
512
|
.accountMenuDivider {
|
|
513
513
|
height: 1px;
|
|
514
|
-
margin: 0 4px
|
|
514
|
+
margin: 0 4px 4px;
|
|
515
515
|
background: var(--dsw-alias-border-l2);
|
|
516
516
|
}
|
|
517
517
|
|
|
@@ -519,12 +519,12 @@
|
|
|
519
519
|
display: flex;
|
|
520
520
|
align-items: center;
|
|
521
521
|
gap: 8px;
|
|
522
|
-
min-height:
|
|
523
|
-
padding: 0
|
|
522
|
+
min-height: 30px;
|
|
523
|
+
padding: 0 8px;
|
|
524
524
|
border-radius: 7px;
|
|
525
525
|
background: transparent;
|
|
526
526
|
text-align: left;
|
|
527
|
-
font: var(--dsw-font-
|
|
527
|
+
font: var(--dsw-font-xs-13);
|
|
528
528
|
}
|
|
529
529
|
|
|
530
530
|
.accountItem:hover {
|
|
@@ -546,6 +546,68 @@
|
|
|
546
546
|
border-color: var(--dsw-alias-bg-layer-1);
|
|
547
547
|
}
|
|
548
548
|
|
|
549
|
+
/* The native top layer is viewport-centered even though the account rail is positioned. */
|
|
550
|
+
.accountLogoutDialog {
|
|
551
|
+
box-sizing: border-box;
|
|
552
|
+
width: min(400px, calc(100vw - 32px));
|
|
553
|
+
max-width: calc(100vw - 32px);
|
|
554
|
+
max-height: calc(100dvh - 32px);
|
|
555
|
+
margin: auto;
|
|
556
|
+
padding: 24px;
|
|
557
|
+
overflow: auto;
|
|
558
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
559
|
+
border-radius: 16px;
|
|
560
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
561
|
+
color: var(--dsw-alias-fg-base);
|
|
562
|
+
font: var(--dsw-font-s-14);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
.accountLogoutDialog::backdrop {
|
|
566
|
+
background: var(--dsw-alias-bg-mask-1);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
.accountLogoutTitle {
|
|
570
|
+
margin: 0;
|
|
571
|
+
font: var(--dsw-font-base-strong-16);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
.accountLogoutDescription {
|
|
575
|
+
margin: 12px 0 24px;
|
|
576
|
+
color: var(--dsw-alias-label-secondary);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.accountLogoutActions {
|
|
580
|
+
display: flex;
|
|
581
|
+
flex-wrap: wrap;
|
|
582
|
+
justify-content: flex-end;
|
|
583
|
+
gap: 8px;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.accountLogoutActions button {
|
|
587
|
+
min-height: 34px;
|
|
588
|
+
padding: 6px 14px;
|
|
589
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
590
|
+
border-radius: 8px;
|
|
591
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
592
|
+
color: var(--dsw-alias-fg-base);
|
|
593
|
+
font: var(--dsw-font-xs-13);
|
|
594
|
+
cursor: pointer;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.accountLogoutActions button:hover {
|
|
598
|
+
background: var(--dsw-alias-bg-hover);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
.accountLogoutActions button:focus-visible {
|
|
602
|
+
outline: 2px solid var(--dsw-alias-border-accent);
|
|
603
|
+
outline-offset: 2px;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.accountLogoutActions .accountLogoutConfirm {
|
|
607
|
+
border-color: var(--dsw-alias-state-error-primary);
|
|
608
|
+
color: var(--dsw-alias-state-error-primary);
|
|
609
|
+
}
|
|
610
|
+
|
|
549
611
|
/* The compatibility action cluster used when the host exposes no native
|
|
550
612
|
right-sidebar affordance. It stays pinned to the viewport corner, sitting
|
|
551
613
|
flush in the 34px tab strip (28px buttons at top: 3) whose right end it
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { ReactNode } from 'react'
|
|
11
|
+
import { clearSidebarHeader, SIDEBAR_HEADER_CSS, syncSidebarHeader } from './sidebar-header.ts'
|
|
11
12
|
|
|
12
13
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
13
14
|
interface SlotMap {
|
|
@@ -30,6 +31,8 @@ const PROJECT_NAME = 'ChatCode CLI'
|
|
|
30
31
|
const HERO_TITLE = '与世界,深一度对话'
|
|
31
32
|
const LEGACY_HOST_BRAND_TEXT = /DSH\s*(?:Local\s*Build|本地构建)|DeepSeek\s*Harness|ChatCode\s*CLI/giu
|
|
32
33
|
const LEGACY_HOST_BRAND_LABEL_TEXT = /^(?:DSH\s*(?:Local\s*Build|本地构建)|ChatCode\s*CLI)$/iu
|
|
34
|
+
const BRAND_SURFACE = '[class*="brandIdentity"],[class*="brandName"],[class*="headline"],.dut-sidebar-brand-name'
|
|
35
|
+
const USER_CONTENT = 'input,textarea,[contenteditable],[role="textbox"],pre,code,script,style'
|
|
33
36
|
const HOST_BUILD_VERSION_TEXT = /^v?\d+\.\d+\.\d+(?:[-+][0-9a-z.-]+)*$/iu
|
|
34
37
|
const HERO_HEADLINE = /探索未至之境/u
|
|
35
38
|
const HERO_PREVIEW_TEXT = /^(?:预览版|Preview)$/iu
|
|
@@ -87,14 +90,11 @@ body:not([data-ds-dark-theme]) .dut-unicom-primary-action:active{transform:trans
|
|
|
87
90
|
hovered, the host owns the complete interaction treatment again. */
|
|
88
91
|
body[data-ds-dark-theme] .dut-unicom-primary-action:not(:hover){background:#9B0B09 !important}
|
|
89
92
|
.dut-project-logo{display:block;object-fit:contain}
|
|
90
|
-
.dut-left-logo{width:
|
|
91
|
-
.dut-brand-title{font-
|
|
92
|
-
.dut-sidebar-logo{width:
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
44px knot is not cropped by that host-owned overflow boundary. */
|
|
96
|
-
[class*="brandIdentity"]:has(.dut-sidebar-logo){height:44px !important}
|
|
97
|
-
.dut-sidebar-brand-name{font-size:18px !important;line-height:22px !important;font-weight:600 !important;letter-spacing:0 !important;white-space:nowrap}
|
|
93
|
+
.dut-left-logo{width:24px !important;height:24px !important}
|
|
94
|
+
.dut-brand-title{font:var(--dsw-font-s-strong-14) !important}
|
|
95
|
+
.dut-sidebar-logo{width:24px !important;height:24px !important}
|
|
96
|
+
.dut-sidebar-brand-name{font:var(--dsw-font-s-strong-14) !important;letter-spacing:-.01em !important;white-space:nowrap}
|
|
97
|
+
${SIDEBAR_HEADER_CSS}
|
|
98
98
|
.dut-brand-version{display:none !important}
|
|
99
99
|
.dut-hero-preview{display:none !important}
|
|
100
100
|
.dut-hero-logo{width:60px !important;height:60px !important}
|
|
@@ -104,8 +104,12 @@ body[data-ds-dark-theme] .dut-unicom-primary-action:not(:hover){background:#9B0B
|
|
|
104
104
|
`
|
|
105
105
|
|
|
106
106
|
function hasPrimaryLabel(button: HTMLButtonElement): boolean {
|
|
107
|
+
// Plugin cards own their appearance. Inventory disclosure buttons include
|
|
108
|
+
// descriptions, where words like "install" do not identify a primary action.
|
|
109
|
+
if (button.closest('[data-chatcode-plugin-market], [data-plugin-module]')) return false
|
|
107
110
|
const label = `${button.textContent ?? ''} ${button.getAttribute('aria-label') ?? ''} ${button.title}`.trim().toLowerCase()
|
|
108
|
-
|
|
111
|
+
if (button.classList.contains('dut-sidebar-brand') || button.classList.contains('dut-sidebar-new-session')) return false
|
|
112
|
+
return /(?:^|\s)(send|install)(?:\s|$)|发送|(?:^|\s)安装(?:\s|$)/u.test(label)
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
/** Replace one host SVG while retaining its generated layout class names. */
|
|
@@ -193,19 +197,22 @@ function syncBranding(): void {
|
|
|
193
197
|
|
|
194
198
|
// The sidebar label identifies the precise icon to its left. Process it
|
|
195
199
|
// before the generic text pass so the sibling relationship is still intact.
|
|
196
|
-
document.querySelectorAll<HTMLElement>(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
200
|
+
document.querySelectorAll<HTMLElement>(BRAND_SURFACE).forEach((surface) => {
|
|
201
|
+
surface.querySelectorAll<HTMLElement>('*').forEach((element) => {
|
|
202
|
+
if (element.closest(USER_CONTENT) !== null) return
|
|
203
|
+
if (element.childElementCount !== 0 || !LEGACY_HOST_BRAND_LABEL_TEXT.test(element.textContent?.trim() ?? '')) return
|
|
204
|
+
if (element.textContent !== PROJECT_NAME) element.textContent = PROJECT_NAME
|
|
205
|
+
element.classList.add('dut-brand-title')
|
|
206
|
+
replaceLogoBesideBrandLabel(element)
|
|
207
|
+
hideVersionBesideBrandLabel(element)
|
|
208
|
+
})
|
|
202
209
|
})
|
|
203
210
|
|
|
204
211
|
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT)
|
|
205
212
|
let node: Text | null
|
|
206
213
|
while ((node = walker.nextNode() as Text | null) !== null) {
|
|
207
214
|
const parent = node.parentElement
|
|
208
|
-
if (parent
|
|
215
|
+
if (parent === null || parent.closest(USER_CONTENT) !== null || parent.closest(BRAND_SURFACE) === null) continue
|
|
209
216
|
if (LEGACY_HOST_BRAND_TEXT.test(node.data)) {
|
|
210
217
|
LEGACY_HOST_BRAND_TEXT.lastIndex = 0
|
|
211
218
|
node.data = node.data.replace(LEGACY_HOST_BRAND_TEXT, PROJECT_NAME)
|
|
@@ -233,6 +240,7 @@ function syncBranding(): void {
|
|
|
233
240
|
if (svg instanceof SVGElement) replaceHostLogo(svg)
|
|
234
241
|
})
|
|
235
242
|
|
|
243
|
+
syncSidebarHeader()
|
|
236
244
|
document.querySelectorAll<HTMLButtonElement>('button').forEach((button) => {
|
|
237
245
|
button.classList.toggle('dut-unicom-primary-action', hasPrimaryLabel(button))
|
|
238
246
|
})
|
|
@@ -277,6 +285,7 @@ export function installBranding(): () => void {
|
|
|
277
285
|
return () => {
|
|
278
286
|
observer.disconnect()
|
|
279
287
|
if (frame !== undefined) window.cancelAnimationFrame(frame)
|
|
288
|
+
clearSidebarHeader()
|
|
280
289
|
favicon.remove()
|
|
281
290
|
style.remove()
|
|
282
291
|
}
|
|
@@ -36,6 +36,7 @@ import { WhaleIndicator, installWhaleStyles } from './whale.tsx'
|
|
|
36
36
|
import { PreciseCacheHitEntry } from './cachehit.tsx'
|
|
37
37
|
import { installTaskNotifier, previewAlerts, requestNotifyPermission } from './notifier.ts'
|
|
38
38
|
import { HeroProjectLogo, installBranding, ProjectLogoIcon, SidebarProjectLogo, SidebarProjectName } from './branding.tsx'
|
|
39
|
+
import { buildFontCss } from './typography.ts'
|
|
39
40
|
|
|
40
41
|
const NS = 'ui-tweaks'
|
|
41
42
|
const SETTINGS_ROUTE = '/_dsh/ui-tweaks/settings'
|
|
@@ -43,12 +44,12 @@ const SETTINGS_ROUTE = '/_dsh/ui-tweaks/settings'
|
|
|
43
44
|
/** Client context narrowed to the browser sessions face in this combined build. */
|
|
44
45
|
type UITweaksClientContext = ClientContext & { sessions: ISessions }
|
|
45
46
|
|
|
46
|
-
const DEFAULT_FONT_SIZE =
|
|
47
|
+
const DEFAULT_FONT_SIZE = 14
|
|
47
48
|
const MIN_FONT_SIZE = 10
|
|
48
49
|
const MAX_FONT_SIZE = 32
|
|
49
50
|
/** Legacy: code font as a percentage of the message font size (81% = stock 13/16). */
|
|
50
51
|
const DEFAULT_CODE_FONT_SCALE = 81
|
|
51
|
-
/**
|
|
52
|
+
/** Default absolute code-block size, paired with 14px prose. */
|
|
52
53
|
const DEFAULT_CODE_FONT_SIZE = 13
|
|
53
54
|
const MIN_CODE_FONT_SIZE = 8
|
|
54
55
|
const MAX_CODE_FONT_SIZE = 32
|
|
@@ -134,7 +135,7 @@ const en = {
|
|
|
134
135
|
fontSize: 'Message font size',
|
|
135
136
|
fontSizeHint: `Number between ${MIN_FONT_SIZE} and ${MAX_FONT_SIZE}; applies to message text, headings, tables and code.`,
|
|
136
137
|
codeFontSize: 'Code font size',
|
|
137
|
-
codeFontSizeHint: `Absolute code size in px (${MIN_CODE_FONT_SIZE}–${MAX_CODE_FONT_SIZE}); ${DEFAULT_CODE_FONT_SIZE}px is ChatCode CLI's default at a
|
|
138
|
+
codeFontSizeHint: `Absolute code size in px (${MIN_CODE_FONT_SIZE}–${MAX_CODE_FONT_SIZE}); ${DEFAULT_CODE_FONT_SIZE}px is ChatCode CLI's default at a 14px body. Applies to code blocks; inline code follows proportionally.`,
|
|
138
139
|
lineHeight: 'Line spacing',
|
|
139
140
|
lineHeightHint: `Base vertical spacing in px: gaps between message rows (Think ↔ tool cards) and blocks inside one reply, plus text line-height, paragraph and list margins, all scale from it; ${DEFAULT_LINE_HEIGHT} is ChatCode CLI's default.`,
|
|
140
141
|
tableStyle: 'Table style',
|
|
@@ -334,7 +335,7 @@ const zh: Record<LocaleKey, string> = {
|
|
|
334
335
|
fontSize: '消息字体大小',
|
|
335
336
|
fontSizeHint: `取值 ${MIN_FONT_SIZE}–${MAX_FONT_SIZE},作用于消息正文、标题、表格与代码。`,
|
|
336
337
|
codeFontSize: '代码字号',
|
|
337
|
-
codeFontSizeHint: `代码绝对字号,取值 ${MIN_CODE_FONT_SIZE}–${MAX_CODE_FONT_SIZE}px;${DEFAULT_CODE_FONT_SIZE}px 为 ChatCode CLI 默认(正文
|
|
338
|
+
codeFontSizeHint: `代码绝对字号,取值 ${MIN_CODE_FONT_SIZE}–${MAX_CODE_FONT_SIZE}px;${DEFAULT_CODE_FONT_SIZE}px 为 ChatCode CLI 默认(正文 14 时)。作用于代码块,行内代码按比例跟随。`,
|
|
338
339
|
lineHeight: '行高',
|
|
339
340
|
lineHeightHint: `回复区垂直间距的基准值:消息之间(如 Think ↔ 工具卡片)、回复内块之间、正文行高、段落与列表边距都按它缩放;取值 ${MIN_LINE_HEIGHT}–${MAX_LINE_HEIGHT}px,${DEFAULT_LINE_HEIGHT} 为 ChatCode CLI 默认。`,
|
|
340
341
|
tableStyle: '表格样式',
|
|
@@ -533,11 +534,13 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
|
533
534
|
|
|
534
535
|
function resolveValue(value: TweaksValue | undefined): ResolvedTweaks {
|
|
535
536
|
const fontSize = typeof value?.fontSize === 'number' ? value.fontSize : DEFAULT_FONT_SIZE
|
|
536
|
-
|
|
537
|
-
//
|
|
537
|
+
const codeFontScale = value?.codeFontScale ?? DEFAULT_CODE_FONT_SCALE
|
|
538
|
+
// Explicit code sizing wins; the stock preference keeps readable 13px code.
|
|
538
539
|
const codeFontSize = typeof value?.codeFontSize === 'number'
|
|
539
540
|
? Math.min(MAX_CODE_FONT_SIZE, Math.max(MIN_CODE_FONT_SIZE, value.codeFontSize))
|
|
540
|
-
:
|
|
541
|
+
: codeFontScale === DEFAULT_CODE_FONT_SCALE
|
|
542
|
+
? DEFAULT_CODE_FONT_SIZE
|
|
543
|
+
: Math.max(8, Math.round(fontSize * (13 / 16) * (codeFontScale / DEFAULT_CODE_FONT_SCALE)))
|
|
541
544
|
return {
|
|
542
545
|
fontSize,
|
|
543
546
|
codeFontSize,
|
|
@@ -559,50 +562,6 @@ function resolveValue(value: TweaksValue | undefined): ResolvedTweaks {
|
|
|
559
562
|
}
|
|
560
563
|
}
|
|
561
564
|
|
|
562
|
-
/** Scale one theme px value proportionally to the chosen base size. */
|
|
563
|
-
function rel(base: number, fontSize: number): number {
|
|
564
|
-
return Math.max(8, Math.round((base / DEFAULT_FONT_SIZE) * fontSize))
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
/** Rebuild the markdown font tokens for the chosen base size, keeping the theme faces. */
|
|
568
|
-
function buildFontCss(fontSize: number, lineHeight: number, codeFontSize: number): string {
|
|
569
|
-
const cs = getComputedStyle(document.body)
|
|
570
|
-
const fam = (name: string, fallback: string): string => {
|
|
571
|
-
const value = cs.getPropertyValue(name).trim()
|
|
572
|
-
return value.length > 0 ? value : fallback
|
|
573
|
-
}
|
|
574
|
-
const base = fam('--dsw-font-markdown-base-font-family', '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif')
|
|
575
|
-
const code = fam('--dsw-font-markdown-code-font-family', '"SF Mono", Consolas, monospace')
|
|
576
|
-
const codeBlock = fam('--dsw-font-markdown-code-block-font-family', '"SF Mono", Consolas, monospace')
|
|
577
|
-
|
|
578
|
-
const parts: string[] = []
|
|
579
|
-
// `baseLine` is the token's line-height at the 16px baseline; it scales with
|
|
580
|
-
// both the chosen font size and the 行高 unit, so at the default (16) it
|
|
581
|
-
// reproduces the stock rhythm exactly.
|
|
582
|
-
const token = (shorthand: string, size: number, baseLine: number, family: string): void => {
|
|
583
|
-
const line = Math.max(12, Math.round((baseLine / DEFAULT_FONT_SIZE) * fontSize * (lineHeight / DEFAULT_LINE_HEIGHT)))
|
|
584
|
-
parts.push(`--${shorthand}:${size}px/${line}px ${family}`)
|
|
585
|
-
parts.push(`--${shorthand}-font-size:${size}px`)
|
|
586
|
-
parts.push(`--${shorthand}-line-height:${line}px`)
|
|
587
|
-
}
|
|
588
|
-
// Code fonts hang off the absolute code-block size (stock: 13px at a 16px
|
|
589
|
-
// body), with inline code slightly larger and the small variant slightly
|
|
590
|
-
// smaller, preserving DSH's hierarchy (14/13 and 12/13 of the block).
|
|
591
|
-
const codePx = (blockRatio: number): number => Math.max(8, Math.round(codeFontSize * blockRatio))
|
|
592
|
-
token('dsw-font-markdown-base', fontSize, 28, base)
|
|
593
|
-
token('dsw-font-markdown-base-strong', fontSize, 28, base)
|
|
594
|
-
token('dsw-font-markdown-base-italic', fontSize, 28, base)
|
|
595
|
-
token('dsw-font-markdown-base-strong-italic', fontSize, 28, base)
|
|
596
|
-
token('dsw-font-markdown-h1', rel(24, fontSize), 34, base)
|
|
597
|
-
token('dsw-font-markdown-h2', rel(22, fontSize), 32, base)
|
|
598
|
-
token('dsw-font-markdown-h3', rel(20, fontSize), 30, base)
|
|
599
|
-
token('dsw-font-markdown-h4', fontSize, 28, base)
|
|
600
|
-
token('dsw-font-markdown-code', codePx(14 / 13), 22, code)
|
|
601
|
-
token('dsw-font-markdown-code-block', codePx(1), 22, codeBlock)
|
|
602
|
-
token('dsw-font-markdown-code-block-small', codePx(12 / 13), 18, codeBlock)
|
|
603
|
-
return `body{${parts.join(';')}}`
|
|
604
|
-
}
|
|
605
|
-
|
|
606
565
|
/**
|
|
607
566
|
* Claude Desktop-ish markdown table look: light-gray rounded cell cards with
|
|
608
567
|
* small gaps, no borders. Cells share the theme's inline-code background and
|
|
@@ -610,7 +569,7 @@ function buildFontCss(fontSize: number, lineHeight: number, codeFontSize: number
|
|
|
610
569
|
* renderer, so headers and cells always match.
|
|
611
570
|
*/
|
|
612
571
|
const CLAUDE_TABLE_CSS = `
|
|
613
|
-
div[data-slot="conversation.chat.node"] table{
|
|
572
|
+
div[data-slot="conversation.chat.node"] [class*="_markdown"]:not([data-markdown-variant="compact"]) table{
|
|
614
573
|
border-collapse:separate !important;
|
|
615
574
|
border-spacing:3px !important;
|
|
616
575
|
width:100% !important;
|
|
@@ -621,7 +580,7 @@ div[data-slot="conversation.chat.node"] table{
|
|
|
621
580
|
border:none !important;
|
|
622
581
|
font-size:var(--dsw-font-markdown-base-font-size) !important;
|
|
623
582
|
}
|
|
624
|
-
div[data-slot="conversation.chat.node"] table thead th{
|
|
583
|
+
div[data-slot="conversation.chat.node"] [class*="_markdown"]:not([data-markdown-variant="compact"]) table thead th{
|
|
625
584
|
background:var(--dsw-alias-markdown-inline-code) !important;
|
|
626
585
|
color:inherit !important;
|
|
627
586
|
font-weight:400 !important;
|
|
@@ -630,7 +589,7 @@ div[data-slot="conversation.chat.node"] table thead th{
|
|
|
630
589
|
border:none !important;
|
|
631
590
|
border-radius:6px !important;
|
|
632
591
|
}
|
|
633
|
-
div[data-slot="conversation.chat.node"] table tbody td{
|
|
592
|
+
div[data-slot="conversation.chat.node"] [class*="_markdown"]:not([data-markdown-variant="compact"]) table tbody td{
|
|
634
593
|
background:var(--dsw-alias-markdown-inline-code) !important;
|
|
635
594
|
color:inherit !important;
|
|
636
595
|
font-size:inherit !important;
|
|
@@ -639,8 +598,8 @@ div[data-slot="conversation.chat.node"] table tbody td{
|
|
|
639
598
|
border:none !important;
|
|
640
599
|
border-radius:6px !important;
|
|
641
600
|
}
|
|
642
|
-
div[data-slot="conversation.chat.node"] table code,
|
|
643
|
-
div[data-slot="conversation.chat.node"] table pre{
|
|
601
|
+
div[data-slot="conversation.chat.node"] [class*="_markdown"]:not([data-markdown-variant="compact"]) table code,
|
|
602
|
+
div[data-slot="conversation.chat.node"] [class*="_markdown"]:not([data-markdown-variant="compact"]) table pre{
|
|
644
603
|
background:transparent !important;
|
|
645
604
|
border:none !important;
|
|
646
605
|
box-shadow:none !important;
|
|
@@ -650,52 +609,32 @@ div[data-slot="conversation.chat.node"] table pre{
|
|
|
650
609
|
function buildRuntimeCss(value: ResolvedTweaks): string {
|
|
651
610
|
const rules: string[] = []
|
|
652
611
|
rules.push(buildFontCss(value.fontSize, value.lineHeight, value.codeFontSize))
|
|
653
|
-
//
|
|
654
|
-
// route them through the same base so they follow the fontSize setting too.
|
|
612
|
+
// Sent messages share the reply metrics, including explicit UI Tweaks sizes.
|
|
655
613
|
// `steering` messages are sent while the agent is busy (busyEnter: steer);
|
|
656
614
|
// `[data-pending-steering]` is their in-flight bubble before it becomes durable.
|
|
657
|
-
rules.push(`[data-chat-flow-kind="user"] [class
|
|
658
|
-
//
|
|
659
|
-
//
|
|
660
|
-
|
|
661
|
-
//
|
|
662
|
-
|
|
663
|
-
//
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
// Markdown table cells are pinned by DSH (15px); let every table style follow
|
|
667
|
-
// the fontSize setting as well.
|
|
668
|
-
rules.push(`div[data-slot="conversation.chat.node"] table th,div[data-slot="conversation.chat.node"] table td{font-size:var(--dsw-font-markdown-base-font-size) !important}`)
|
|
669
|
-
// Inline code is pinned by DSH to 0.875em of the surrounding text (it ignores
|
|
670
|
-
// the code token); scale that em by how far the chosen code size sits from
|
|
671
|
-
// the stock ratio (a 13px block at this body size).
|
|
672
|
-
const stockCodeBlock = value.fontSize * (13 / 16)
|
|
615
|
+
rules.push(`[data-chat-flow-kind="user"] [class*="_bubble"],[data-chat-flow-kind="steering"] [class*="_bubble"],[data-pending-steering] [class*="_bubble"]{font-size:var(--dsw-font-markdown-base-font-size) !important;line-height:var(--dsw-font-markdown-base-line-height) !important}`)
|
|
616
|
+
// Current contenteditable composers and older textarea composers inherit
|
|
617
|
+
// one size/leading pair, including placeholders and measurement layers.
|
|
618
|
+
rules.push(`[data-composer-card]{font:var(--dsw-font-markdown-base) !important}`)
|
|
619
|
+
// Tables use the same body size and leading in both table styles.
|
|
620
|
+
rules.push(`div[data-slot="conversation.chat.node"] [class*="_markdown"]:not([data-markdown-variant="compact"]) table th,div[data-slot="conversation.chat.node"] [class*="_markdown"]:not([data-markdown-variant="compact"]) table td{font-size:var(--dsw-font-markdown-base-font-size) !important;line-height:var(--dsw-font-markdown-base-line-height) !important}`)
|
|
621
|
+
// Inline code normally uses 0.92em. Explicit code sizing follows the
|
|
622
|
+
// same ratio relative to the 14px body / 13px code baseline.
|
|
623
|
+
const stockCodeBlock = value.fontSize * (13 / 14)
|
|
673
624
|
if (Math.abs(value.codeFontSize - stockCodeBlock) > 0.5) {
|
|
674
|
-
const em = (0.
|
|
675
|
-
rules.push(`div[data-slot="conversation.chat.node"] div[class*="
|
|
625
|
+
const em = (0.92 * (value.codeFontSize / stockCodeBlock)).toFixed(3)
|
|
626
|
+
rules.push(`div[data-slot="conversation.chat.node"] div[class*="_markdown"]:not([data-markdown-variant="compact"]) :not(pre)>code{font-size:${em}em !important}`)
|
|
676
627
|
}
|
|
677
|
-
//
|
|
678
|
-
// the stock 16px, every vertical spacing scales from it proportionally:
|
|
679
|
-
// ① gaps between message rows (Think ↔ tool cards like pwsh, user ↔
|
|
680
|
-
// assistant) — the chat flow column;
|
|
681
|
-
// ② gaps between content blocks inside one assistant reply (Think ↔ text) —
|
|
682
|
-
// the Assistant Markdown block container (`Sxvs8a_body`, CSS-module
|
|
683
|
-
// hashed, stable within the pinned rc.8 conversation package);
|
|
684
|
-
// ③ the markdown typography rhythm: paragraphs (`p` has a stock `margin:
|
|
685
|
-
// 16px 0` that must be overridden on both axes, not just bottom, or it
|
|
686
|
-
// can never tighten below 16), list margins, list-item gaps (stock 6px),
|
|
687
|
-
// paragraphs inside list items (stock 8px), code blocks, headings and
|
|
688
|
-
// rules — all scaled from the 行高 unit.
|
|
689
|
-
// Text line-height itself scales in buildFontCss above.
|
|
628
|
+
// Custom spacing scales prose without expanding compact thinking.
|
|
690
629
|
if (value.lineHeight !== DEFAULT_LINE_HEIGHT) {
|
|
691
630
|
const n = value.lineHeight
|
|
692
|
-
const md = `div[data-slot="conversation.chat.node"] div[class*="
|
|
693
|
-
const liGap = Math.max(2, Math.round((
|
|
631
|
+
const md = `div[data-slot="conversation.chat.node"] div[class*="_markdown"]:not([data-markdown-variant="compact"])`
|
|
632
|
+
const liGap = Math.max(2, Math.round((4 * n) / DEFAULT_LINE_HEIGHT))
|
|
694
633
|
const liPGap = Math.max(2, Math.round((8 * n) / DEFAULT_LINE_HEIGHT))
|
|
695
|
-
rules.push(`div[data-slot="conversation.view"]
|
|
696
|
-
rules.push(`div[data-slot="conversation.chat.node"]
|
|
697
|
-
rules.push(`${md} p{margin:${n}px 0 !important}`)
|
|
698
|
-
rules.push(`${md} ul,${md} ol{margin:${n}px 0 !important}`)
|
|
634
|
+
rules.push(`div[data-slot="conversation.view"] [data-chat-flow]{gap:${n}px !important}`)
|
|
635
|
+
rules.push(`div[data-slot="conversation.chat.node"] [data-assistant-body]{--dsh-assistant-block-gap:${n}px}`)
|
|
636
|
+
rules.push(`${md} p{margin:${Math.round(0.75 * n)}px 0 !important}`)
|
|
637
|
+
rules.push(`${md} ul,${md} ol{margin:${Math.round(0.75 * n)}px 0 !important}`)
|
|
699
638
|
rules.push(`${md} pre{margin:${n}px 0 !important}`)
|
|
700
639
|
// Code blocks: the pre's inner vertical padding is stock 16px (shiki
|
|
701
640
|
// default); scale it so the block's own height follows 行高 too. Only
|
|
@@ -711,13 +650,11 @@ function buildRuntimeCss(value: ResolvedTweaks): string {
|
|
|
711
650
|
}
|
|
712
651
|
rules.push(`${md} li:not(:first-child){margin-top:${liGap}px !important}`)
|
|
713
652
|
rules.push(`${md} li>p{margin:${liPGap}px 0 !important}`)
|
|
714
|
-
rules.push(`${md} h1,${md} h2,${md} h3{margin:${
|
|
653
|
+
rules.push(`${md} h1,${md} h2,${md} h3{margin:${Math.round(1.5 * n)}px 0 ${Math.round(0.75 * n)}px !important}`)
|
|
715
654
|
rules.push(`${md} h4,${md} h5,${md} h6{margin:${n}px 0 !important}`)
|
|
716
655
|
rules.push(`${md} hr{margin:${2 * n}px 0 !important}`)
|
|
717
656
|
rules.push(`${md} blockquote{margin:${n}px 0 0 !important}`)
|
|
718
|
-
//
|
|
719
|
-
// margin (stock `>*:first-child` / `>*:last-child`), so a message starts
|
|
720
|
-
// and ends tight and the spacing to the next node stays the column gap.
|
|
657
|
+
// Preserve the first and last block's flush edges.
|
|
721
658
|
rules.push(`${md} > :first-child{margin-top:0 !important}`)
|
|
722
659
|
rules.push(`${md} > :last-child{margin-bottom:0 !important}`)
|
|
723
660
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/** Compact sidebar chrome; the host retains every button, shortcut and drag surface. */
|
|
2
|
+
export const SIDEBAR_HEADER_CSS = `
|
|
3
|
+
.dut-sidebar-header{height:44px !important;padding:0 4px !important;margin-bottom:8px !important;gap:8px !important}
|
|
4
|
+
.dut-sidebar-brand{min-width:0 !important;background:transparent !important;box-shadow:none !important}
|
|
5
|
+
.dut-sidebar-identity{height:24px !important;gap:8px !important}
|
|
6
|
+
.dut-sidebar-wordmark{font:var(--dsw-font-s-strong-14) !important;letter-spacing:-.01em !important;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
7
|
+
.dut-sidebar-toggle{width:28px !important;height:28px !important;border-radius:8px !important;color:var(--dsw-alias-label-secondary) !important}
|
|
8
|
+
.dut-sidebar-toggle:hover{background:var(--dsw-alias-interactive-bg-hover) !important}
|
|
9
|
+
/* Reuse the original ChatCode primary-action red, scoped to this marked CTA. */
|
|
10
|
+
.dut-sidebar-new-session{height:40px !important;justify-content:flex-start !important;gap:8px !important;margin:0 0 10px !important;padding:8px 10px !important;border:1px solid #9B0B09 !important;border-radius:10px !important;background:linear-gradient(135deg,#9B0B09,#b71916) !important;color:#fff !important;font:var(--dsw-font-s-strong-14) !important;font-weight:600 !important;box-shadow:none !important;transform:none !important}
|
|
11
|
+
.dut-sidebar-new-session:hover{background:linear-gradient(135deg,#b71916,#cf302c) !important}
|
|
12
|
+
.dut-sidebar-new-session:active{background:#9B0B09 !important}
|
|
13
|
+
.dut-sidebar-new-session:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}
|
|
14
|
+
.dut-sidebar-new-session > span:first-child{flex:1;min-width:0;overflow:hidden;mask-image:none !important}
|
|
15
|
+
.dut-sidebar-new-session > span:first-child > span{width:auto !important;justify-content:flex-start !important;gap:8px !important;min-width:0}
|
|
16
|
+
.dut-sidebar-new-session > span:first-child > span > svg{width:16px;height:16px;flex:none;color:inherit}
|
|
17
|
+
.dut-sidebar-new-session > span:first-child > span > span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
18
|
+
.dut-sidebar-new-session > span + span{opacity:1 !important;flex:none;color:color-mix(in srgb,currentColor 75%,transparent);font:var(--dsw-font-xxs-12)}
|
|
19
|
+
/* Temporary navigation-only hide. Remove this block to restore Plugins;
|
|
20
|
+
registrations, settings, installed plugins and other panel entries stay intact. */
|
|
21
|
+
nav:is([aria-label="全局面板"],[aria-label="Global panels"]) > button:is([aria-label="插件"],[aria-label="Plugins"]),
|
|
22
|
+
nav:is([aria-label="全局面板"],[aria-label="Global panels"]):has(> button:is([aria-label="插件"],[aria-label="Plugins"]):only-child){display:none !important}
|
|
23
|
+
`
|
|
24
|
+
|
|
25
|
+
const HEADER_CLASSES = [
|
|
26
|
+
'dut-sidebar-header', 'dut-sidebar-brand', 'dut-sidebar-identity',
|
|
27
|
+
'dut-sidebar-wordmark', 'dut-sidebar-toggle', 'dut-sidebar-new-session',
|
|
28
|
+
] as const
|
|
29
|
+
type HeaderClass = typeof HEADER_CLASSES[number]
|
|
30
|
+
|
|
31
|
+
/** Mark only the expanded brand row and its adjacent native New Session button. */
|
|
32
|
+
export function syncSidebarHeader(): void {
|
|
33
|
+
const desired = new Map<HTMLElement, Set<HeaderClass>>()
|
|
34
|
+
const mark = (element: Element | null | undefined, className: HeaderClass): void => {
|
|
35
|
+
if (!(element instanceof HTMLElement)) return
|
|
36
|
+
const classes = desired.get(element) ?? new Set<HeaderClass>()
|
|
37
|
+
classes.add(className)
|
|
38
|
+
desired.set(element, classes)
|
|
39
|
+
}
|
|
40
|
+
for (const name of document.querySelectorAll<HTMLElement>('.dut-sidebar-brand-name,.dut-brand-title')) {
|
|
41
|
+
const row = name.closest<HTMLElement>('[data-window-drag]')
|
|
42
|
+
const logo = row?.querySelector('.dut-sidebar-logo,.dut-left-logo')
|
|
43
|
+
if (!row || !logo) continue
|
|
44
|
+
const brand = [...row.children].find(child => child.contains(name) && child.contains(logo))
|
|
45
|
+
if (!brand) continue
|
|
46
|
+
mark(row, 'dut-sidebar-header')
|
|
47
|
+
mark(brand, 'dut-sidebar-brand')
|
|
48
|
+
mark(logo.closest('[class*="brandIdentity"]'), 'dut-sidebar-identity')
|
|
49
|
+
mark(name, 'dut-sidebar-wordmark')
|
|
50
|
+
for (const button of row.querySelectorAll('button')) {
|
|
51
|
+
if (!brand.contains(button) && button !== brand) mark(button, 'dut-sidebar-toggle')
|
|
52
|
+
}
|
|
53
|
+
// The host renders this native action directly after the drag row. Do
|
|
54
|
+
// not infer a new action from arbitrary text in another panel or dialog.
|
|
55
|
+
const next = row.nextElementSibling
|
|
56
|
+
if (next instanceof HTMLButtonElement) mark(next, 'dut-sidebar-new-session')
|
|
57
|
+
}
|
|
58
|
+
// A collapsed rail no longer has a wordmark. Remove expanded-only styling
|
|
59
|
+
// without changing the host's rail geometry or its logo/expand interaction.
|
|
60
|
+
for (const className of HEADER_CLASSES) {
|
|
61
|
+
for (const element of document.querySelectorAll<HTMLElement>(`.${className}`)) {
|
|
62
|
+
if (!desired.get(element)?.has(className)) element.classList.remove(className)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const [element, classes] of desired) element.classList.add(...classes)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Restore native header styling when the branding effect is disposed. */
|
|
69
|
+
export function clearSidebarHeader(): void {
|
|
70
|
+
for (const className of HEADER_CLASSES) {
|
|
71
|
+
for (const element of document.querySelectorAll(`.${className}`)) element.classList.remove(className)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Font overrides for the conversation, preserving the live theme families. */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Apply the UI Tweaks size and spacing preferences to the host's prose tokens.
|
|
5
|
+
* @param fontSize - Selected body size in pixels.
|
|
6
|
+
* @param lineHeight - Vertical-spacing unit; 16 retains the normal rhythm.
|
|
7
|
+
* @param codeFontSize - Selected code-block size in pixels.
|
|
8
|
+
* @returns Theme-token overrides for a runtime stylesheet.
|
|
9
|
+
*/
|
|
10
|
+
export function buildFontCss(fontSize: number, lineHeight: number, codeFontSize: number): string {
|
|
11
|
+
const parts: string[] = []
|
|
12
|
+
const base = 'var(--dsw-font-markdown-base-font-family, var(--dsw-font-family))'
|
|
13
|
+
const code = 'var(--dsw-font-markdown-code-block-font-family, var(--ds-font-family-code))'
|
|
14
|
+
const token = (name: string, size: number, leading: number, family: string, weight = 400, style = 'normal'): void => {
|
|
15
|
+
const line = Math.max(12, Math.round(leading * (lineHeight / 16)))
|
|
16
|
+
parts.push(`--${name}:${style} ${weight} ${size}px/${line}px ${family}`)
|
|
17
|
+
parts.push(`--${name}-font-size:${size}px`)
|
|
18
|
+
parts.push(`--${name}-line-height:${line}px`)
|
|
19
|
+
parts.push(`--${name}-font-weight:${weight}`)
|
|
20
|
+
parts.push(`--${name}-font-style:${style}`)
|
|
21
|
+
}
|
|
22
|
+
const bodyLine = fontSize + 10
|
|
23
|
+
token('dsw-font-markdown-base', fontSize, bodyLine, base)
|
|
24
|
+
token('dsw-font-markdown-base-strong', fontSize, bodyLine, base, 600)
|
|
25
|
+
token('dsw-font-markdown-base-italic', fontSize, bodyLine, base, 400, 'italic')
|
|
26
|
+
token('dsw-font-markdown-base-strong-italic', fontSize, bodyLine, base, 600, 'italic')
|
|
27
|
+
token('dsw-font-markdown-h1', fontSize + 4, bodyLine + 4, base, 600)
|
|
28
|
+
token('dsw-font-markdown-h2', fontSize + 2, bodyLine + 2, base, 600)
|
|
29
|
+
token('dsw-font-markdown-h3', fontSize + 1, bodyLine + 1, base, 600)
|
|
30
|
+
token('dsw-font-markdown-h4', fontSize, bodyLine, base, 600)
|
|
31
|
+
token('dsw-font-markdown-table', fontSize, bodyLine, base)
|
|
32
|
+
token('dsw-font-markdown-table-head', fontSize, bodyLine, base, 500)
|
|
33
|
+
token('dsw-font-markdown-code', codeFontSize, codeFontSize + 7,
|
|
34
|
+
'var(--dsw-font-markdown-code-font-family, var(--ds-font-family-code))')
|
|
35
|
+
token('dsw-font-markdown-code-block', codeFontSize, codeFontSize + 7, code)
|
|
36
|
+
token('dsw-font-markdown-code-block-small', Math.max(8, codeFontSize - 2), codeFontSize + 3, code)
|
|
37
|
+
return `body{${parts.join(';')}}`
|
|
38
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -54,6 +54,7 @@ import { CodingPlanCatalogue } from './codingplan.ts'
|
|
|
54
54
|
import { checkOneUpdate, CHATCODE_UPDATE_PACKAGES, performAllUpdates } from './chatcode-update.ts'
|
|
55
55
|
import { readJsonBody, requireString, SidebarError, writeError, writeJson, writeOk } from './wire.ts'
|
|
56
56
|
import { apply as applyUiTweaksHost } from './ui-tweaks/index.ts'
|
|
57
|
+
import { buildPluginMarketApi } from './plugin-market-api.ts'
|
|
57
58
|
|
|
58
59
|
export { Config }
|
|
59
60
|
export type { SidebarConfig, ResolvedSidebarConfig }
|
|
@@ -491,6 +492,7 @@ function buildApi(
|
|
|
491
492
|
const { sessionId, cwd } = await cwdOf(payload)
|
|
492
493
|
return { sessionId, cwd, root: rootLabel(cwd), parent: parentOf(cwd) ?? null }
|
|
493
494
|
},
|
|
495
|
+
...buildPluginMarketApi(ctx, cwdOf),
|
|
494
496
|
'fs.tree': async (payload) => {
|
|
495
497
|
const { cwd } = await cwdOf(payload)
|
|
496
498
|
const record = payload as { path?: unknown }
|