@chatcode/cco-better-sidebar 0.18.0-alpha.0
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/LICENSE +21 -0
- package/README.md +554 -0
- package/README_EN.md +563 -0
- package/assets/logo.svg +1 -0
- package/cordis.patch.yml +79 -0
- package/lib/client-editor.js +55744 -0
- package/lib/client-mermaid.js +208256 -0
- package/lib/client-registry.js +30378 -0
- package/lib/client-terminal.js +16894 -0
- package/lib/client.js +30378 -0
- package/lib/index.js +6897 -0
- package/lib/invariant.js +22 -0
- package/lib/types/agent-opens.d.ts +65 -0
- package/lib/types/agent-pty.d.ts +226 -0
- package/lib/types/browser-probe.d.ts +15 -0
- package/lib/types/bundle-route.d.ts +12 -0
- package/lib/types/chatcode-update.d.ts +47 -0
- package/lib/types/client/AccountMenu.d.ts +1 -0
- package/lib/types/client/AiRatioSection.d.ts +3 -0
- package/lib/types/client/BrowserView.d.ts +39 -0
- package/lib/types/client/ChatcodeGate.d.ts +6 -0
- package/lib/types/client/CodingPlanModelsSettings.d.ts +9 -0
- package/lib/types/client/DiffTab.d.ts +6 -0
- package/lib/types/client/DiffView.d.ts +51 -0
- package/lib/types/client/EditorHost.d.ts +13 -0
- package/lib/types/client/FenceErrorNotice.d.ts +5 -0
- package/lib/types/client/FileTree.d.ts +41 -0
- package/lib/types/client/FreeWindow.d.ts +29 -0
- package/lib/types/client/GitView.d.ts +12 -0
- package/lib/types/client/MarkdownHtml.d.ts +32 -0
- package/lib/types/client/OrphanedTab.d.ts +11 -0
- package/lib/types/client/PdfView.d.ts +6 -0
- package/lib/types/client/ReleaseNotesDialog.d.ts +11 -0
- package/lib/types/client/RenderBoundary.d.ts +32 -0
- package/lib/types/client/SandboxStatusBar.d.ts +10 -0
- package/lib/types/client/SideCardSection.d.ts +74 -0
- package/lib/types/client/Sidebar.d.ts +8 -0
- package/lib/types/client/TabBar.d.ts +54 -0
- package/lib/types/client/TerminalView.d.ts +24 -0
- package/lib/types/client/TextEditor.d.ts +10 -0
- package/lib/types/client/TreePanel.d.ts +27 -0
- package/lib/types/client/UpdateDialog.d.ts +10 -0
- package/lib/types/client/UpdateSettingsPanel.d.ts +1 -0
- package/lib/types/client/UpdateSettingsSection.d.ts +10 -0
- package/lib/types/client/UploadOverlay.d.ts +20 -0
- package/lib/types/client/UsageHeatmapSection.d.ts +4 -0
- package/lib/types/client/add-plugin-modal.d.ts +15 -0
- package/lib/types/client/api.d.ts +345 -0
- package/lib/types/client/binary-download.d.ts +12 -0
- package/lib/types/client/breakpoints.d.ts +17 -0
- package/lib/types/client/browser.d.ts +60 -0
- package/lib/types/client/builtins/index.d.ts +18 -0
- package/lib/types/client/builtins/tabs.d.ts +11 -0
- package/lib/types/client/builtins/viewers.d.ts +3 -0
- package/lib/types/client/chat-presentation.d.ts +13 -0
- package/lib/types/client/chunk-loader.d.ts +124 -0
- package/lib/types/client/chunks/editor.d.ts +9 -0
- package/lib/types/client/chunks/mermaid.d.ts +10 -0
- package/lib/types/client/chunks/terminal.d.ts +9 -0
- package/lib/types/client/cm-themes.d.ts +24 -0
- package/lib/types/client/conversation-draft.d.ts +14 -0
- package/lib/types/client/desktop-env.d.ts +35 -0
- package/lib/types/client/editor-load.d.ts +66 -0
- package/lib/types/client/frame-batcher.d.ts +24 -0
- package/lib/types/client/icons.d.ts +66 -0
- package/lib/types/client/image-types.d.ts +3 -0
- package/lib/types/client/ime-guard.d.ts +36 -0
- package/lib/types/client/index.d.ts +19 -0
- package/lib/types/client/intercept.d.ts +44 -0
- package/lib/types/client/lang.d.ts +14 -0
- package/lib/types/client/layout-push.d.ts +15 -0
- package/lib/types/client/lazy-chunk.d.ts +25 -0
- package/lib/types/client/link-intercept.d.ts +42 -0
- package/lib/types/client/locales-ar.d.ts +18 -0
- package/lib/types/client/locales-de.d.ts +4 -0
- package/lib/types/client/locales-fr.d.ts +10 -0
- package/lib/types/client/locales-hi.d.ts +17 -0
- package/lib/types/client/locales-id.d.ts +15 -0
- package/lib/types/client/locales-it.d.ts +8 -0
- package/lib/types/client/locales-ja.d.ts +17 -0
- package/lib/types/client/locales-ko.d.ts +9 -0
- package/lib/types/client/locales-nl.d.ts +16 -0
- package/lib/types/client/locales-pl.d.ts +19 -0
- package/lib/types/client/locales-pt.d.ts +1 -0
- package/lib/types/client/locales-ru.d.ts +13 -0
- package/lib/types/client/locales-sv.d.ts +1 -0
- package/lib/types/client/locales-th.d.ts +17 -0
- package/lib/types/client/locales-tr.d.ts +17 -0
- package/lib/types/client/locales-vi.d.ts +17 -0
- package/lib/types/client/locales-zh-HK.d.ts +32 -0
- package/lib/types/client/locales-zh-MO.d.ts +32 -0
- package/lib/types/client/locales-zh-TW.d.ts +32 -0
- package/lib/types/client/locales.d.ts +571 -0
- package/lib/types/client/markdown-html.d.ts +96 -0
- package/lib/types/client/markdown-images.d.ts +45 -0
- package/lib/types/client/markdown-labels.d.ts +21 -0
- package/lib/types/client/md-toc.d.ts +4 -0
- package/lib/types/client/mermaid-blocks.d.ts +47 -0
- package/lib/types/client/mermaid-sanitize.d.ts +2 -0
- package/lib/types/client/mermaid.d.ts +12 -0
- package/lib/types/client/open-when-sized.d.ts +20 -0
- package/lib/types/client/open-with-settings.d.ts +4 -0
- package/lib/types/client/open-with.d.ts +87 -0
- package/lib/types/client/openpath-intercept.d.ts +52 -0
- package/lib/types/client/paths.d.ts +43 -0
- package/lib/types/client/pdf-types.d.ts +2 -0
- package/lib/types/client/pinned.d.ts +86 -0
- package/lib/types/client/plugin-settings.d.ts +8 -0
- package/lib/types/client/plugins-shared.d.ts +27 -0
- package/lib/types/client/plugins-tabs.d.ts +3 -0
- package/lib/types/client/plugins-viewers.d.ts +3 -0
- package/lib/types/client/prefs.d.ts +41 -0
- package/lib/types/client/produced-files.d.ts +29 -0
- package/lib/types/client/selection-payload.d.ts +27 -0
- package/lib/types/client/service.d.ts +445 -0
- package/lib/types/client/session-pins.d.ts +14 -0
- package/lib/types/client/settings-nav-icon.d.ts +27 -0
- package/lib/types/client/shell-presets.d.ts +48 -0
- package/lib/types/client/split-pane.d.ts +38 -0
- package/lib/types/client/state.d.ts +480 -0
- package/lib/types/client/tab-content-memo.d.ts +40 -0
- package/lib/types/client/terminal-font.d.ts +78 -0
- package/lib/types/client/terminal-links.d.ts +119 -0
- package/lib/types/client/theme.d.ts +45 -0
- package/lib/types/client/titlebar-strip.d.ts +23 -0
- package/lib/types/client/ui-tweaks/appicons.d.ts +16 -0
- package/lib/types/client/ui-tweaks/archive.d.ts +42 -0
- package/lib/types/client/ui-tweaks/branding.d.ts +45 -0
- package/lib/types/client/ui-tweaks/cachehit.d.ts +41 -0
- package/lib/types/client/ui-tweaks/gitbar.d.ts +103 -0
- package/lib/types/client/ui-tweaks/index.d.ts +279 -0
- package/lib/types/client/ui-tweaks/mcp.d.ts +28 -0
- package/lib/types/client/ui-tweaks/notifier.d.ts +125 -0
- package/lib/types/client/ui-tweaks/whale.d.ts +55 -0
- package/lib/types/client/upload.d.ts +69 -0
- package/lib/types/client/useChatcodeAccount.d.ts +10 -0
- package/lib/types/client/wco.d.ts +47 -0
- package/lib/types/codingplan.d.ts +37 -0
- package/lib/types/config.d.ts +95 -0
- package/lib/types/context-types.d.ts +540 -0
- package/lib/types/fs-operations.d.ts +30 -0
- package/lib/types/fs-search.d.ts +24 -0
- package/lib/types/fs-tree.d.ts +51 -0
- package/lib/types/git.d.ts +124 -0
- package/lib/types/html-route.d.ts +59 -0
- package/lib/types/index.d.ts +47 -0
- package/lib/types/invariant.d.ts +15 -0
- package/lib/types/login-route.d.ts +2 -0
- package/lib/types/open-external.d.ts +24 -0
- package/lib/types/path-security.d.ts +26 -0
- package/lib/types/prefs-shared.d.ts +257 -0
- package/lib/types/pty-deps.d.ts +79 -0
- package/lib/types/pty-manager.d.ts +168 -0
- package/lib/types/tools.d.ts +34 -0
- package/lib/types/trust-fence.d.ts +24 -0
- package/lib/types/ui-tweaks/archive.d.ts +71 -0
- package/lib/types/ui-tweaks/config.d.ts +186 -0
- package/lib/types/ui-tweaks/git-web.d.ts +43 -0
- package/lib/types/ui-tweaks/git.d.ts +311 -0
- package/lib/types/ui-tweaks/index.d.ts +17 -0
- package/lib/types/ui-tweaks/mcp.d.ts +103 -0
- package/lib/types/ui-tweaks/turn-outcome.d.ts +57 -0
- package/lib/types/ui-tweaks/web.d.ts +55 -0
- package/lib/types/wire.d.ts +38 -0
- package/package.json +213 -0
- package/scripts/install.ps1 +310 -0
- package/scripts/install.sh +287 -0
- package/src/agent-opens.ts +265 -0
- package/src/agent-pty.ts +527 -0
- package/src/browser-probe.ts +26 -0
- package/src/bundle-route.ts +129 -0
- package/src/chatcode-update.ts +193 -0
- package/src/client/AccountMenu.tsx +177 -0
- package/src/client/AiRatioSection.module.css +329 -0
- package/src/client/AiRatioSection.tsx +292 -0
- package/src/client/BrowserView.tsx +289 -0
- package/src/client/ChatcodeGate.tsx +35 -0
- package/src/client/CodingPlanModelsSettings.module.css +118 -0
- package/src/client/CodingPlanModelsSettings.tsx +101 -0
- package/src/client/DiffTab.tsx +114 -0
- package/src/client/DiffView.tsx +305 -0
- package/src/client/EditorHost.tsx +563 -0
- package/src/client/FenceErrorNotice.tsx +40 -0
- package/src/client/FileTree.tsx +701 -0
- package/src/client/FreeWindow.tsx +337 -0
- package/src/client/GitView.tsx +722 -0
- package/src/client/MarkdownHtml.tsx +296 -0
- package/src/client/OrphanedTab.tsx +27 -0
- package/src/client/PdfView.tsx +110 -0
- package/src/client/ReleaseNotesDialog.tsx +91 -0
- package/src/client/RenderBoundary.tsx +49 -0
- package/src/client/SandboxStatusBar.tsx +60 -0
- package/src/client/SideCardSection.module.css +932 -0
- package/src/client/SideCardSection.tsx +1169 -0
- package/src/client/Sidebar.tsx +1857 -0
- package/src/client/TabBar.tsx +365 -0
- package/src/client/TerminalView.tsx +424 -0
- package/src/client/TextEditor.tsx +468 -0
- package/src/client/TreePanel.tsx +279 -0
- package/src/client/UpdateDialog.tsx +186 -0
- package/src/client/UpdateSettingsPanel.tsx +29 -0
- package/src/client/UpdateSettingsSection.tsx +22 -0
- package/src/client/UploadOverlay.tsx +62 -0
- package/src/client/UsageHeatmapSection.module.css +440 -0
- package/src/client/UsageHeatmapSection.tsx +301 -0
- package/src/client/add-plugin-modal.tsx +199 -0
- package/src/client/api.ts +433 -0
- package/src/client/binary-download.tsx +23 -0
- package/src/client/breakpoints.ts +61 -0
- package/src/client/browser.ts +167 -0
- package/src/client/builtins/index.ts +37 -0
- package/src/client/builtins/tabs.tsx +275 -0
- package/src/client/builtins/viewers.tsx +125 -0
- package/src/client/chat-presentation.ts +95 -0
- package/src/client/chunk-loader.ts +350 -0
- package/src/client/chunks/editor.tsx +9 -0
- package/src/client/chunks/mermaid.tsx +10 -0
- package/src/client/chunks/terminal.tsx +9 -0
- package/src/client/cm-themes.ts +129 -0
- package/src/client/conversation-draft.ts +29 -0
- package/src/client/css-modules.d.ts +5 -0
- package/src/client/desktop-env.ts +72 -0
- package/src/client/editor-load.ts +92 -0
- package/src/client/frame-batcher.ts +56 -0
- package/src/client/icons.tsx +170 -0
- package/src/client/image-types.ts +8 -0
- package/src/client/ime-guard.ts +47 -0
- package/src/client/index.tsx +501 -0
- package/src/client/intercept.tsx +172 -0
- package/src/client/lang.ts +225 -0
- package/src/client/layout-push.ts +37 -0
- package/src/client/layout.css +156 -0
- package/src/client/lazy-chunk.tsx +89 -0
- package/src/client/link-intercept.ts +73 -0
- package/src/client/locales-ar.ts +387 -0
- package/src/client/locales-de.ts +372 -0
- package/src/client/locales-fr.ts +379 -0
- package/src/client/locales-hi.ts +386 -0
- package/src/client/locales-id.ts +384 -0
- package/src/client/locales-it.ts +377 -0
- package/src/client/locales-ja.ts +486 -0
- package/src/client/locales-ko.ts +378 -0
- package/src/client/locales-nl.ts +384 -0
- package/src/client/locales-pl.ts +388 -0
- package/src/client/locales-pt.ts +369 -0
- package/src/client/locales-ru.ts +384 -0
- package/src/client/locales-sv.ts +369 -0
- package/src/client/locales-th.ts +386 -0
- package/src/client/locales-tr.ts +386 -0
- package/src/client/locales-vi.ts +386 -0
- package/src/client/locales-zh-HK.ts +401 -0
- package/src/client/locales-zh-MO.ts +401 -0
- package/src/client/locales-zh-TW.ts +401 -0
- package/src/client/locales.ts +1229 -0
- package/src/client/markdown-html.ts +331 -0
- package/src/client/markdown-images.ts +137 -0
- package/src/client/markdown-labels.tsx +31 -0
- package/src/client/md-toc.tsx +127 -0
- package/src/client/mermaid-blocks.ts +110 -0
- package/src/client/mermaid-sanitize.ts +93 -0
- package/src/client/mermaid.tsx +406 -0
- package/src/client/open-when-sized.ts +43 -0
- package/src/client/open-with-settings.tsx +135 -0
- package/src/client/open-with.ts +221 -0
- package/src/client/openpath-intercept.ts +79 -0
- package/src/client/paths.ts +63 -0
- package/src/client/pdf-types.ts +4 -0
- package/src/client/pinned.ts +184 -0
- package/src/client/plugin-settings.ts +43 -0
- package/src/client/plugins-shared.ts +29 -0
- package/src/client/plugins-tabs.ts +153 -0
- package/src/client/plugins-viewers.ts +44 -0
- package/src/client/prefs.ts +216 -0
- package/src/client/produced-files.ts +120 -0
- package/src/client/selection-payload.ts +86 -0
- package/src/client/service.ts +873 -0
- package/src/client/session-pins.tsx +334 -0
- package/src/client/settings-nav-icon.ts +55 -0
- package/src/client/shell-presets.ts +83 -0
- package/src/client/sidebar.module.css +3607 -0
- package/src/client/split-pane.tsx +333 -0
- package/src/client/state.ts +1646 -0
- package/src/client/tab-content-memo.ts +55 -0
- package/src/client/terminal-font.ts +224 -0
- package/src/client/terminal-links.ts +194 -0
- package/src/client/theme.ts +110 -0
- package/src/client/titlebar-strip.ts +37 -0
- package/src/client/ui-tweaks/appicons.ts +24 -0
- package/src/client/ui-tweaks/archive.tsx +281 -0
- package/src/client/ui-tweaks/branding.tsx +232 -0
- package/src/client/ui-tweaks/cachehit.tsx +122 -0
- package/src/client/ui-tweaks/gitbar.tsx +2559 -0
- package/src/client/ui-tweaks/index.tsx +1696 -0
- package/src/client/ui-tweaks/mcp.tsx +582 -0
- package/src/client/ui-tweaks/notifier.ts +514 -0
- package/src/client/ui-tweaks/whale.tsx +171 -0
- package/src/client/upload.ts +187 -0
- package/src/client/useChatcodeAccount.ts +103 -0
- package/src/client/wco.ts +120 -0
- package/src/codingplan.ts +146 -0
- package/src/config.ts +207 -0
- package/src/context-types.ts +559 -0
- package/src/fs-operations.ts +97 -0
- package/src/fs-search.ts +113 -0
- package/src/fs-tree.ts +158 -0
- package/src/git.ts +446 -0
- package/src/html-route.ts +106 -0
- package/src/index.ts +1524 -0
- package/src/invariant.ts +32 -0
- package/src/login-route.ts +26 -0
- package/src/open-external.ts +90 -0
- package/src/path-security.ts +81 -0
- package/src/prefs-shared.ts +303 -0
- package/src/pty-deps.ts +241 -0
- package/src/pty-manager.ts +376 -0
- package/src/tools.ts +482 -0
- package/src/trust-fence.ts +84 -0
- package/src/ui-tweaks/archive.ts +293 -0
- package/src/ui-tweaks/config.ts +257 -0
- package/src/ui-tweaks/git-web.ts +421 -0
- package/src/ui-tweaks/git.ts +1524 -0
- package/src/ui-tweaks/index.ts +61 -0
- package/src/ui-tweaks/mcp.ts +535 -0
- package/src/ui-tweaks/turn-outcome.ts +105 -0
- package/src/ui-tweaks/web.ts +225 -0
- package/src/wire.ts +110 -0
- package/vendor/addon-fit.js +2 -0
- package/vendor/xterm.css +218 -0
- package/vendor/xterm.js +5 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Syntax highlighting for the file editor: extension → CodeMirror language
|
|
3
|
+
* mapping. The key derivation is pure and unit-tested; the factories pull in
|
|
4
|
+
* the CodeMirror language packages (bundled into the client).
|
|
5
|
+
*/
|
|
6
|
+
import { Language, LanguageSupport, StreamLanguage } from '@codemirror/language'
|
|
7
|
+
import { javascript, jsxLanguage, typescriptLanguage, tsxLanguage } from '@codemirror/lang-javascript'
|
|
8
|
+
import { json } from '@codemirror/lang-json'
|
|
9
|
+
import { markdown } from '@codemirror/lang-markdown'
|
|
10
|
+
import { python } from '@codemirror/lang-python'
|
|
11
|
+
import { html } from '@codemirror/lang-html'
|
|
12
|
+
import { css, cssLanguage } from '@codemirror/lang-css'
|
|
13
|
+
import { xml } from '@codemirror/lang-xml'
|
|
14
|
+
import { yaml } from '@codemirror/lang-yaml'
|
|
15
|
+
import { sql } from '@codemirror/lang-sql'
|
|
16
|
+
import { java } from '@codemirror/lang-java'
|
|
17
|
+
import { cpp } from '@codemirror/lang-cpp'
|
|
18
|
+
import { rust } from '@codemirror/lang-rust'
|
|
19
|
+
import { go } from '@codemirror/lang-go'
|
|
20
|
+
import { php } from '@codemirror/lang-php'
|
|
21
|
+
import { vue } from '@codemirror/lang-vue'
|
|
22
|
+
import { shell } from '@codemirror/legacy-modes/mode/shell'
|
|
23
|
+
import { toml } from '@codemirror/legacy-modes/mode/toml'
|
|
24
|
+
import { nginx } from '@codemirror/legacy-modes/mode/nginx'
|
|
25
|
+
import { dockerFile } from '@codemirror/legacy-modes/mode/dockerfile'
|
|
26
|
+
import { properties } from '@codemirror/legacy-modes/mode/properties'
|
|
27
|
+
import { csharp, kotlin, dart, scala, objectiveCpp } from '@codemirror/legacy-modes/mode/clike'
|
|
28
|
+
import { swift } from '@codemirror/legacy-modes/mode/swift'
|
|
29
|
+
import { sCSS, less } from '@codemirror/legacy-modes/mode/css'
|
|
30
|
+
import { sass } from '@codemirror/legacy-modes/mode/sass'
|
|
31
|
+
import { stylus } from '@codemirror/legacy-modes/mode/stylus'
|
|
32
|
+
import { ruby } from '@codemirror/legacy-modes/mode/ruby'
|
|
33
|
+
import { lua } from '@codemirror/legacy-modes/mode/lua'
|
|
34
|
+
import { perl } from '@codemirror/legacy-modes/mode/perl'
|
|
35
|
+
import { r } from '@codemirror/legacy-modes/mode/r'
|
|
36
|
+
import { groovy } from '@codemirror/legacy-modes/mode/groovy'
|
|
37
|
+
import { powerShell } from '@codemirror/legacy-modes/mode/powershell'
|
|
38
|
+
import { diff } from '@codemirror/legacy-modes/mode/diff'
|
|
39
|
+
import { protobuf } from '@codemirror/legacy-modes/mode/protobuf'
|
|
40
|
+
import { cmake } from '@codemirror/legacy-modes/mode/cmake'
|
|
41
|
+
import { pug } from '@codemirror/legacy-modes/mode/pug'
|
|
42
|
+
import { tcl } from '@codemirror/legacy-modes/mode/tcl'
|
|
43
|
+
import { haskell } from '@codemirror/legacy-modes/mode/haskell'
|
|
44
|
+
import { clojure } from '@codemirror/legacy-modes/mode/clojure'
|
|
45
|
+
import { erlang } from '@codemirror/legacy-modes/mode/erlang'
|
|
46
|
+
import { julia } from '@codemirror/legacy-modes/mode/julia'
|
|
47
|
+
import { pascal } from '@codemirror/legacy-modes/mode/pascal'
|
|
48
|
+
import { vb } from '@codemirror/legacy-modes/mode/vb'
|
|
49
|
+
import { vhdl } from '@codemirror/legacy-modes/mode/vhdl'
|
|
50
|
+
import { stex } from '@codemirror/legacy-modes/mode/stex'
|
|
51
|
+
|
|
52
|
+
/** The lowercased file extension of a path ('' when none). */
|
|
53
|
+
export function extOf(path: string): string {
|
|
54
|
+
const at = path.lastIndexOf('.')
|
|
55
|
+
if (at === -1) return ''
|
|
56
|
+
const base = path.slice(at + 1).toLowerCase()
|
|
57
|
+
return base.includes('/') || base.includes('\\') ? '' : base
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Language key for an extension, or null for plain text. Pure (tested). */
|
|
61
|
+
export function languageKeyForExt(ext: string): string | null {
|
|
62
|
+
switch (ext) {
|
|
63
|
+
case 'js': case 'mjs': case 'cjs': return 'js'
|
|
64
|
+
case 'jsx': return 'jsx'
|
|
65
|
+
case 'ts': case 'mts': case 'cts': return 'ts'
|
|
66
|
+
case 'tsx': return 'tsx'
|
|
67
|
+
case 'json': case 'jsonc': return 'json'
|
|
68
|
+
case 'md': case 'markdown': return 'md'
|
|
69
|
+
case 'py': case 'pyw': return 'python'
|
|
70
|
+
case 'html': case 'htm': return 'html'
|
|
71
|
+
case 'css': return 'css'
|
|
72
|
+
case 'xml': case 'xsl': return 'xml'
|
|
73
|
+
case 'yaml': case 'yml': return 'yaml'
|
|
74
|
+
case 'sql': return 'sql'
|
|
75
|
+
case 'java': return 'java'
|
|
76
|
+
case 'cs': return 'csharp'
|
|
77
|
+
case 'kt': case 'kts': return 'kotlin'
|
|
78
|
+
case 'swift': return 'swift'
|
|
79
|
+
case 'c': case 'h': return 'c'
|
|
80
|
+
case 'cc': case 'cpp': case 'cxx': case 'hpp': case 'hh': case 'hxx': return 'cpp'
|
|
81
|
+
case 'rs': return 'rust'
|
|
82
|
+
case 'go': return 'go'
|
|
83
|
+
case 'php': return 'php'
|
|
84
|
+
case 'sh': case 'bash': case 'zsh': return 'shell'
|
|
85
|
+
case 'toml': return 'toml'
|
|
86
|
+
case 'nginx': case 'conf': return 'nginx'
|
|
87
|
+
case 'dockerfile': case 'docker': return 'dockerfile'
|
|
88
|
+
case 'properties': case 'env': return 'properties'
|
|
89
|
+
case 'vue': return 'vue'
|
|
90
|
+
case 'scss': return 'scss'
|
|
91
|
+
case 'sass': return 'sass'
|
|
92
|
+
case 'less': return 'less'
|
|
93
|
+
case 'styl': return 'stylus'
|
|
94
|
+
case 'rb': return 'ruby'
|
|
95
|
+
case 'lua': return 'lua'
|
|
96
|
+
case 'pl': case 'pm': return 'perl'
|
|
97
|
+
case 'r': return 'r'
|
|
98
|
+
case 'dart': return 'dart'
|
|
99
|
+
case 'scala': case 'sc': return 'scala'
|
|
100
|
+
case 'groovy': return 'groovy'
|
|
101
|
+
case 'ps1': case 'psm1': return 'powershell'
|
|
102
|
+
case 'diff': case 'patch': return 'diff'
|
|
103
|
+
case 'proto': return 'protobuf'
|
|
104
|
+
case 'cmake': return 'cmake'
|
|
105
|
+
case 'pug': return 'pug'
|
|
106
|
+
case 'tcl': return 'tcl'
|
|
107
|
+
case 'hs': return 'haskell'
|
|
108
|
+
case 'clj': case 'cljs': return 'clojure'
|
|
109
|
+
case 'erl': return 'erlang'
|
|
110
|
+
case 'jl': return 'julia'
|
|
111
|
+
case 'pas': return 'pascal'
|
|
112
|
+
case 'vb': return 'vb'
|
|
113
|
+
case 'vhd': return 'vhdl'
|
|
114
|
+
case 'tex': return 'stex'
|
|
115
|
+
case 'mm': return 'objectivecpp'
|
|
116
|
+
// '.v' (Verilog/Coq/V) 与 '.m' (Objective-C/MATLAB) 存在跨语言歧义,
|
|
117
|
+
// 故意不映射——错配高亮比纯文本更误导。
|
|
118
|
+
default: return null
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Per-lang `<style>` parsers for the Vue SFC factory (built once, shared). */
|
|
123
|
+
const VUE_STYLE_PARSERS = {
|
|
124
|
+
scss: StreamLanguage.define(sCSS).parser,
|
|
125
|
+
sass: StreamLanguage.define(sass).parser,
|
|
126
|
+
less: StreamLanguage.define(less).parser,
|
|
127
|
+
stylus: StreamLanguage.define(stylus).parser,
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const FACTORIES: Record<string, () => Language | LanguageSupport> = {
|
|
131
|
+
js: () => javascript({ jsx: true }),
|
|
132
|
+
jsx: () => javascript({ jsx: true }),
|
|
133
|
+
ts: () => javascript({ typescript: true }),
|
|
134
|
+
tsx: () => javascript({ typescript: true, jsx: true }),
|
|
135
|
+
json: () => json(),
|
|
136
|
+
md: () => markdown(),
|
|
137
|
+
python: () => python(),
|
|
138
|
+
html: () => html(),
|
|
139
|
+
css: () => css(),
|
|
140
|
+
xml: () => xml(),
|
|
141
|
+
yaml: () => yaml(),
|
|
142
|
+
sql: () => sql(),
|
|
143
|
+
java: () => java(),
|
|
144
|
+
csharp: () => StreamLanguage.define(csharp),
|
|
145
|
+
kotlin: () => StreamLanguage.define(kotlin),
|
|
146
|
+
swift: () => StreamLanguage.define(swift),
|
|
147
|
+
c: () => cpp(),
|
|
148
|
+
cpp: () => cpp(),
|
|
149
|
+
rust: () => rust(),
|
|
150
|
+
go: () => go(),
|
|
151
|
+
php: () => php(),
|
|
152
|
+
shell: () => StreamLanguage.define(shell),
|
|
153
|
+
toml: () => StreamLanguage.define(toml),
|
|
154
|
+
nginx: () => StreamLanguage.define(nginx),
|
|
155
|
+
dockerfile: () => StreamLanguage.define(dockerFile),
|
|
156
|
+
properties: () => StreamLanguage.define(properties),
|
|
157
|
+
// Vue SFC: lang-html's default html() base ALREADY parses <script>
|
|
158
|
+
// (no type → JS, type="module" → JS, lang="ts" → TS, JSON/importmap MIME
|
|
159
|
+
// types) and <style> → CSS through its built-in defaultNesting. The
|
|
160
|
+
// explicit entries only ADD what the defaults miss — case-insensitive
|
|
161
|
+
// lang="ts", lang="tsx"/"jsx" (the defaults only recognize the text/jsx &
|
|
162
|
+
// text/typescript-jsx MIME types), and per-lang <style> preprocessor
|
|
163
|
+
// dispatch. Same-tag entries are first-match wins and ours precede the
|
|
164
|
+
// defaults, so the predicates stay narrow: a constant-true entry would
|
|
165
|
+
// shadow the default JSON/importmap script handling and force the CSS
|
|
166
|
+
// parser onto <style lang="stylus">.
|
|
167
|
+
vue: () => vue({
|
|
168
|
+
base: html({
|
|
169
|
+
nestedLanguages: [
|
|
170
|
+
{ tag: 'script', attrs: a => (a.lang ?? '').toLowerCase() === 'ts', parser: typescriptLanguage.parser },
|
|
171
|
+
{ tag: 'script', attrs: a => (a.lang ?? '').toLowerCase() === 'tsx', parser: tsxLanguage.parser },
|
|
172
|
+
{ tag: 'script', attrs: a => (a.lang ?? '').toLowerCase() === 'jsx', parser: jsxLanguage.parser },
|
|
173
|
+
{ tag: 'style', attrs: a => (a.lang ?? '').toLowerCase() === 'css', parser: cssLanguage.parser },
|
|
174
|
+
{ tag: 'style', attrs: a => (a.lang ?? '').toLowerCase() === 'scss', parser: VUE_STYLE_PARSERS.scss },
|
|
175
|
+
{ tag: 'style', attrs: a => (a.lang ?? '').toLowerCase() === 'sass', parser: VUE_STYLE_PARSERS.sass },
|
|
176
|
+
{ tag: 'style', attrs: a => (a.lang ?? '').toLowerCase() === 'less', parser: VUE_STYLE_PARSERS.less },
|
|
177
|
+
{ tag: 'style', attrs: a => (a.lang ?? '').toLowerCase() === 'stylus', parser: VUE_STYLE_PARSERS.stylus },
|
|
178
|
+
],
|
|
179
|
+
}),
|
|
180
|
+
}),
|
|
181
|
+
scss: () => StreamLanguage.define(sCSS),
|
|
182
|
+
sass: () => StreamLanguage.define(sass),
|
|
183
|
+
less: () => StreamLanguage.define(less),
|
|
184
|
+
stylus: () => StreamLanguage.define(stylus),
|
|
185
|
+
ruby: () => StreamLanguage.define(ruby),
|
|
186
|
+
lua: () => StreamLanguage.define(lua),
|
|
187
|
+
perl: () => StreamLanguage.define(perl),
|
|
188
|
+
r: () => StreamLanguage.define(r),
|
|
189
|
+
dart: () => StreamLanguage.define(dart),
|
|
190
|
+
scala: () => StreamLanguage.define(scala),
|
|
191
|
+
groovy: () => StreamLanguage.define(groovy),
|
|
192
|
+
powershell: () => StreamLanguage.define(powerShell),
|
|
193
|
+
diff: () => StreamLanguage.define(diff),
|
|
194
|
+
protobuf: () => StreamLanguage.define(protobuf),
|
|
195
|
+
cmake: () => StreamLanguage.define(cmake),
|
|
196
|
+
pug: () => StreamLanguage.define(pug),
|
|
197
|
+
tcl: () => StreamLanguage.define(tcl),
|
|
198
|
+
haskell: () => StreamLanguage.define(haskell),
|
|
199
|
+
clojure: () => StreamLanguage.define(clojure),
|
|
200
|
+
erlang: () => StreamLanguage.define(erlang),
|
|
201
|
+
julia: () => StreamLanguage.define(julia),
|
|
202
|
+
pascal: () => StreamLanguage.define(pascal),
|
|
203
|
+
vb: () => StreamLanguage.define(vb),
|
|
204
|
+
vhdl: () => StreamLanguage.define(vhdl),
|
|
205
|
+
stex: () => StreamLanguage.define(stex),
|
|
206
|
+
objectivecpp: () => StreamLanguage.define(objectiveCpp),
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** Every language key the extension table can produce (test seam). */
|
|
210
|
+
export function supportedLanguageKeys(): readonly string[] {
|
|
211
|
+
return Object.keys(FACTORIES)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** The CodeMirror language support for a path, or null for plain text. */
|
|
215
|
+
export function languageForPath(path: string): Language | LanguageSupport | null {
|
|
216
|
+
const key = languageKeyForExt(extOf(path))
|
|
217
|
+
if (key === null) return null
|
|
218
|
+
try {
|
|
219
|
+
return FACTORIES[key]!()
|
|
220
|
+
} catch (error) {
|
|
221
|
+
// A broken factory degrades to plain text, never crashes the editor.
|
|
222
|
+
console.warn(`[dsh-better-sidebar] language factory "${key}" failed:`, error)
|
|
223
|
+
return null
|
|
224
|
+
}
|
|
225
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Size written to `--dsh-sidebar-width` / `--dsh-sidebar-height`.
|
|
3
|
+
* The conversation column (output + composer) must keep at least
|
|
4
|
+
* {@link PANEL_MIN} of the viewport after the bottom panel claims height.
|
|
5
|
+
*/
|
|
6
|
+
import { PANEL_MIN } from './state.ts'
|
|
7
|
+
|
|
8
|
+
export interface LayoutPushInput {
|
|
9
|
+
narrow: boolean
|
|
10
|
+
panelOpen: boolean
|
|
11
|
+
bottomOpen: boolean
|
|
12
|
+
width: number
|
|
13
|
+
bottomHeight: number
|
|
14
|
+
viewportWidth: number
|
|
15
|
+
viewportHeight: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface LayoutPushSize {
|
|
19
|
+
width: number
|
|
20
|
+
height: number
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function finiteNonNegative(value: number): number {
|
|
24
|
+
return Number.isFinite(value) ? Math.max(0, value) : 0
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Compute the live layout-push size. Narrow drawers float and push 0. */
|
|
28
|
+
export function layoutPushSize(input: LayoutPushInput): LayoutPushSize {
|
|
29
|
+
if (input.narrow) return { width: 0, height: 0 }
|
|
30
|
+
const viewportWidth = finiteNonNegative(input.viewportWidth)
|
|
31
|
+
const viewportHeight = finiteNonNegative(input.viewportHeight)
|
|
32
|
+
const maxHeight = Math.max(0, viewportHeight - Math.min(PANEL_MIN, viewportHeight))
|
|
33
|
+
return {
|
|
34
|
+
width: input.panelOpen ? Math.min(finiteNonNegative(input.width), viewportWidth) : 0,
|
|
35
|
+
height: input.bottomOpen ? Math.min(finiteNonNegative(input.bottomHeight), maxHeight) : 0,
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout push: when a panel is open it OCCUPIES the layout instead of
|
|
3
|
+
* floating over it — the app shell (#root, the AppFrame three-column grid)
|
|
4
|
+
* gives up space. Only the center column is flexible (1fr), so the right
|
|
5
|
+
* panel's width squeeze (margin-right on #root) lands exactly on the
|
|
6
|
+
* conversation output and the input bar, like a VSCode sidebar.
|
|
7
|
+
*
|
|
8
|
+
* The width rides `calc(100% - var(...))` instead of a bare margin on a
|
|
9
|
+
* full-width box: some desktop shells (DSH Desktop, #208) set #root to
|
|
10
|
+
* width:100%, where a margin would overflow the viewport additively —
|
|
11
|
+
* the calc keeps the box at exactly 100% minus the push in every shell.
|
|
12
|
+
* Width and margin transition in lockstep (same variable, same duration
|
|
13
|
+
* and easing), so expand/collapse animates the content width exactly as
|
|
14
|
+
* the bare-margin version did.
|
|
15
|
+
*
|
|
16
|
+
* The bottom panel squeezes ONLY the center column — it must not cover the
|
|
17
|
+
* app's own left sidebar or the right panel. The anchor is the frame's
|
|
18
|
+
* center grid item through stable slot/data attributes, not a positional
|
|
19
|
+
* path: current hosts put [data-slot="main"] directly inside the center
|
|
20
|
+
* column, while earlier hosts exposed [data-pane="conversation"] or a
|
|
21
|
+
* [data-slot="conversation"] child. A stretched grid item shrinks by its
|
|
22
|
+
* margins, so the conversation content (output + input bar) lifts without
|
|
23
|
+
* touching the sidebars.
|
|
24
|
+
*
|
|
25
|
+
* The sizes ride CSS variables updated by the Sidebar shell (0 while
|
|
26
|
+
* collapsed); expand/collapse animates both the margins and the panel
|
|
27
|
+
* slides on the same theme duration. Drags disable the transition so the
|
|
28
|
+
* layout tracks the pointer.
|
|
29
|
+
*/
|
|
30
|
+
#root {
|
|
31
|
+
margin-right: var(--dsh-sidebar-width, 0px);
|
|
32
|
+
width: calc(100% - var(--dsh-sidebar-width, 0px));
|
|
33
|
+
transition:
|
|
34
|
+
margin-right var(--ds-transition-duration-slow) var(--ds-ease-in-out),
|
|
35
|
+
width var(--ds-transition-duration-slow) var(--ds-ease-in-out);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* The AppFrame's center column, anchored by data attributes (see above).
|
|
39
|
+
Composite selector: current DSH puts `[data-slot="main"]` directly inside
|
|
40
|
+
the center grid item; earlier shells name the item
|
|
41
|
+
`[data-pane="conversation"]` or put `[data-slot="conversation"]` inside it.
|
|
42
|
+
Every selector resolves to that same center element. */
|
|
43
|
+
#root :has(> [data-slot="main"]),
|
|
44
|
+
#root [data-dsh-frame] > [data-pane="conversation"],
|
|
45
|
+
#root :has(> [data-slot="conversation"]) {
|
|
46
|
+
margin-bottom: var(--dsh-sidebar-height, 0px);
|
|
47
|
+
/* Grid/flex items default to min-height:auto. A long unbreakable token
|
|
48
|
+
(OAuth URL) then grows this column past the viewport and clips the
|
|
49
|
+
composer + left-rail Settings row. min-height:0 lets the cell shrink;
|
|
50
|
+
overflow-wrap lets the token wrap instead of forcing its intrinsic
|
|
51
|
+
size. The host's own descendants remain responsible for scrolling. */
|
|
52
|
+
min-height: 0;
|
|
53
|
+
overflow-wrap: anywhere;
|
|
54
|
+
transition: margin-bottom var(--ds-transition-duration-slow) var(--ds-ease-in-out);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* On older hosts, a collapsed sidebar puts the fallback cluster in the
|
|
58
|
+
top-right corner. Push the DSH session header's right padding out so its
|
|
59
|
+
utilities yield instead of hiding under the cluster. Current DSH hosts put
|
|
60
|
+
the controls directly beside the Session log action and set
|
|
61
|
+
data-dsh-native-sidebar-toggle, so this rule stays inactive. The Sidebar
|
|
62
|
+
shell publishes the required reserve; 188px is the older-host fallback. Anchor on
|
|
63
|
+
the header's slot host wrapper ([data-slot="conversation.session.header"])
|
|
64
|
+
rather than a positional path: DSH 0.1.x nests the header several levels
|
|
65
|
+
under the center column. The Sidebar shell toggles the body attributes with
|
|
66
|
+
the host capability and panel open state. */
|
|
67
|
+
body[data-dsh-sidebar-collapsed]:not([data-dsh-native-sidebar-toggle]) [data-slot="conversation.session.header"] > header {
|
|
68
|
+
padding-right: var(--dsh-sidebar-toggle-reserve, 188px);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
body[data-dsh-sidebar-dragging] #root,
|
|
72
|
+
body[data-dsh-sidebar-dragging] #root :has(> [data-slot="main"]),
|
|
73
|
+
body[data-dsh-sidebar-dragging] #root [data-dsh-frame] > [data-pane="conversation"],
|
|
74
|
+
body[data-dsh-sidebar-dragging] #root :has(> [data-slot="conversation"]) {
|
|
75
|
+
transition: none;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* DSH 0.1.x gives external settings sections a generic gear and exposes no
|
|
79
|
+
icon field in the settings.section contract. settings-nav-icon.ts marks
|
|
80
|
+
only this plugin's localized row; render the requested Lucide
|
|
81
|
+
gallery-horizontal-end SVG as a currentColor mask so it follows the native
|
|
82
|
+
nav hover/active colors without changing the shell's 16px icon rhythm. */
|
|
83
|
+
[data-dsh-better-sidebar-settings-nav] > svg:first-child {
|
|
84
|
+
display: none;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
[data-dsh-better-sidebar-settings-nav]::before {
|
|
88
|
+
content: '';
|
|
89
|
+
flex: none;
|
|
90
|
+
width: 16px;
|
|
91
|
+
height: 16px;
|
|
92
|
+
background: currentColor;
|
|
93
|
+
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 7v10'/%3E%3Cpath d='M6 5v14'/%3E%3Crect width='12' height='18' x='10' y='3' rx='2'/%3E%3C/svg%3E") center / contain no-repeat;
|
|
94
|
+
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 7v10'/%3E%3Cpath d='M6 5v14'/%3E%3Crect width='12' height='18' x='10' y='3' rx='2'/%3E%3C/svg%3E") center / contain no-repeat;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* The "Token 用量" heatmap section's nav row: same marker scheme as above,
|
|
98
|
+
painting a calendar glyph (Lucide calendar-days) — a month of days is the
|
|
99
|
+
section's whole subject. */
|
|
100
|
+
[data-dsh-better-sidebar-usage-nav] > svg:first-child {
|
|
101
|
+
display: none;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
[data-dsh-better-sidebar-usage-nav]::before {
|
|
105
|
+
content: '';
|
|
106
|
+
flex: none;
|
|
107
|
+
width: 16px;
|
|
108
|
+
height: 16px;
|
|
109
|
+
background: currentColor;
|
|
110
|
+
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M16 2v4'/%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M3 10h18'/%3E%3Cpath d='M8 14h.01'/%3E%3Cpath d='M12 14h.01'/%3E%3Cpath d='M16 14h.01'/%3E%3Cpath d='M8 18h.01'/%3E%3Cpath d='M12 18h.01'/%3E%3Cpath d='M16 18h.01'/%3E%3C/svg%3E") center / contain no-repeat;
|
|
111
|
+
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M16 2v4'/%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M3 10h18'/%3E%3Cpath d='M8 14h.01'/%3E%3Cpath d='M12 14h.01'/%3E%3Cpath d='M16 14h.01'/%3E%3Cpath d='M8 18h.01'/%3E%3Cpath d='M12 18h.01'/%3E%3Cpath d='M16 18h.01'/%3E%3C/svg%3E") center / contain no-repeat;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
[data-dsh-better-sidebar-ai-ratio-nav] > svg:first-child {
|
|
115
|
+
display: none;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
[data-dsh-better-sidebar-ai-ratio-nav]::before {
|
|
119
|
+
content: '';
|
|
120
|
+
flex: none;
|
|
121
|
+
width: 16px;
|
|
122
|
+
height: 16px;
|
|
123
|
+
background: currentColor;
|
|
124
|
+
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M2.25 13.75h11.5M4.5 13.75v-3.5M7.5 13.75v-6.5M10.5 13.75v-4.5' stroke='black' stroke-width='1.5' stroke-linecap='round'/%3E%3Cpath d='M13 .9l.5 1.6 1.6.5-1.6.5-.5 1.6-.5-1.6-1.6-.5 1.6-.5z' fill='black'/%3E%3C/svg%3E") center / contain no-repeat;
|
|
125
|
+
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M2.25 13.75h11.5M4.5 13.75v-3.5M7.5 13.75v-6.5M10.5 13.75v-4.5' stroke='black' stroke-width='1.5' stroke-linecap='round'/%3E%3Cpath d='M13 .9l.5 1.6 1.6.5-1.6.5-.5 1.6-.5-1.6-1.6-.5 1.6-.5z' fill='black'/%3E%3C/svg%3E") center / contain no-repeat;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* The "更新" section's nav row: same marker scheme, painting an upward
|
|
129
|
+
arrow (Lucide arrow-up) — an upgrade/one-click-update is the section's
|
|
130
|
+
whole purpose. */
|
|
131
|
+
[data-dsh-better-sidebar-update-nav] > svg:first-child {
|
|
132
|
+
display: none;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
[data-dsh-better-sidebar-update-nav]::before {
|
|
136
|
+
content: '';
|
|
137
|
+
flex: none;
|
|
138
|
+
width: 16px;
|
|
139
|
+
height: 16px;
|
|
140
|
+
background: currentColor;
|
|
141
|
+
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 7-7 7 7'/%3E%3Cpath d='M12 19V5'/%3E%3C/svg%3E") center / contain no-repeat;
|
|
142
|
+
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 7-7 7 7'/%3E%3Cpath d='M12 19V5'/%3E%3C/svg%3E") center / contain no-repeat;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
@media (prefers-reduced-motion: reduce) {
|
|
146
|
+
#root,
|
|
147
|
+
#root :has(> [data-slot="main"]),
|
|
148
|
+
#root [data-dsh-frame] > [data-pane="conversation"],
|
|
149
|
+
#root :has(> [data-slot="conversation"]) {
|
|
150
|
+
transition: none;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
[data-dsh-hidden-runtime-context] {
|
|
155
|
+
display: none !important;
|
|
156
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy chunk view wrapper: mounts a component that lives in a lazy chunk,
|
|
3
|
+
* showing a loading placeholder while the chunk script loads and an error +
|
|
4
|
+
* retry affordance on failure. Used by the built-in tab/viewer descriptors.
|
|
5
|
+
*
|
|
6
|
+
* Contract note: {@link lazyChunkComponent} returns a plain render-prop
|
|
7
|
+
* function — the descriptor contract is `component: (props) => ReactNode`,
|
|
8
|
+
* and the repo renders descriptors BOTH ways: Sidebar calls
|
|
9
|
+
* `descriptor.component(props)` directly, EditorHost renders it via
|
|
10
|
+
* `createElement`. The wrapper function body therefore contains no hooks;
|
|
11
|
+
* all state lives in the inner {@link LazyChunkView} component.
|
|
12
|
+
*/
|
|
13
|
+
import { createElement, useEffect, useState, type ComponentType, type ReactNode } from 'react'
|
|
14
|
+
import { loadChunk, type ChunkExports, type ChunkName } from './chunk-loader.ts'
|
|
15
|
+
import { t } from './locales.ts'
|
|
16
|
+
import css from './sidebar.module.css'
|
|
17
|
+
|
|
18
|
+
interface LazyChunkViewProps<P> {
|
|
19
|
+
chunk: ChunkName
|
|
20
|
+
/** Module-level-stable selector (an inline lambda would re-trigger the effect). */
|
|
21
|
+
pick: (mod: ChunkExports) => ComponentType<P> | undefined
|
|
22
|
+
props: P
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function LazyChunkView<P>({ chunk, pick, props }: LazyChunkViewProps<P>): ReactNode {
|
|
26
|
+
const [attempt, setAttempt] = useState(0)
|
|
27
|
+
const [state, setState] = useState<
|
|
28
|
+
| { status: 'loading' }
|
|
29
|
+
| { status: 'error'; message: string }
|
|
30
|
+
| { status: 'ready'; Comp: ComponentType<any> }
|
|
31
|
+
>({ status: 'loading' })
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
let cancelled = false
|
|
35
|
+
setState({ status: 'loading' })
|
|
36
|
+
loadChunk(chunk).then((mod) => {
|
|
37
|
+
if (cancelled) return
|
|
38
|
+
const Comp = pick(mod)
|
|
39
|
+
if (Comp === undefined) {
|
|
40
|
+
setState({ status: 'error', message: `[dsh-better-sidebar] chunk "${chunk}" is missing its component` })
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
setState({ status: 'ready', Comp })
|
|
44
|
+
}).catch((error: unknown) => {
|
|
45
|
+
if (cancelled) return
|
|
46
|
+
setState({ status: 'error', message: error instanceof Error ? error.message : String(error) })
|
|
47
|
+
})
|
|
48
|
+
return () => { cancelled = true }
|
|
49
|
+
}, [chunk, pick, attempt])
|
|
50
|
+
|
|
51
|
+
if (state.status === 'loading') {
|
|
52
|
+
return <div className={css.editorPlaceholder}>{t('loading')}</div>
|
|
53
|
+
}
|
|
54
|
+
if (state.status === 'error') {
|
|
55
|
+
return (
|
|
56
|
+
<div className={css.editorError}>
|
|
57
|
+
<span>{state.message}</span>
|
|
58
|
+
<button
|
|
59
|
+
type="button"
|
|
60
|
+
className={css.terminalRetry}
|
|
61
|
+
onClick={() => { setAttempt(current => current + 1) }}
|
|
62
|
+
>
|
|
63
|
+
{t('terminalRetry')}
|
|
64
|
+
</button>
|
|
65
|
+
</div>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
return createElement(state.Comp, props)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Build a descriptor-compatible lazy wrapper for a chunk-resident component.
|
|
73
|
+
* The returned function is the descriptor `component` itself: it returns an
|
|
74
|
+
* element and never calls hooks, so both invocation styles (plain function
|
|
75
|
+
* call and createElement/JSX render) work. `pick` must be a module-level
|
|
76
|
+
* function (stable identity) — an inline lambda would re-trigger the load
|
|
77
|
+
* effect on every render.
|
|
78
|
+
* @param chunk - the chunk name (see chunk-loader.ts).
|
|
79
|
+
* @param pick - select the component from the chunk's exports.
|
|
80
|
+
*/
|
|
81
|
+
export function lazyChunkComponent<P extends object>(
|
|
82
|
+
chunk: ChunkName,
|
|
83
|
+
pick: (mod: ChunkExports) => ComponentType<P> | undefined,
|
|
84
|
+
): (props: P) => ReactNode {
|
|
85
|
+
return (props: P) => createElement(
|
|
86
|
+
LazyChunkView as ComponentType<LazyChunkViewProps<P>>,
|
|
87
|
+
{ chunk, pick, props },
|
|
88
|
+
)
|
|
89
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat/GUI external-link interception: clicking an http(s) link that points
|
|
3
|
+
* OUTSIDE the GUI (chat messages, tool rows, prose mentions) opens the
|
|
4
|
+
* sidebar instead of a new browser tab. Gated by the caller through
|
|
5
|
+
* `takeoverEnabled(url)` — the `browserInterceptLinks` master, the URL's
|
|
6
|
+
* protocol flag (`browserInterceptHttp` / `browserInterceptHttps`) and the
|
|
7
|
+
* target tab's enable switch — and a Ctrl/Cmd/Shift/Alt-modified click
|
|
8
|
+
* always bypasses the takeover so the user can still force a real browser
|
|
9
|
+
* tab.
|
|
10
|
+
*
|
|
11
|
+
* Only the GUI's OWN document is watched — links inside the browser tab's
|
|
12
|
+
* sandboxed iframe live in another document and never bubble here (and
|
|
13
|
+
* their clicks must keep working inside the sidebar).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** The pure decision: the URL to open in the sidebar, or null to let the
|
|
17
|
+
* click fall through. Extracted so the policy is unit-testable without a
|
|
18
|
+
* DOM. `anchorHref` must be the ABSOLUTE href (`<a>.href` already is).
|
|
19
|
+
* The protocol/same-origin policy lives HERE; the prefs gates (master +
|
|
20
|
+
* protocol flags + target enablement) live in the caller's
|
|
21
|
+
* `takeoverEnabled(url)` callback. */
|
|
22
|
+
export function shouldInterceptLink(anchorHref: string, selfOrigin: string): string | null {
|
|
23
|
+
let url: URL
|
|
24
|
+
try {
|
|
25
|
+
url = new URL(anchorHref)
|
|
26
|
+
} catch {
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') return null
|
|
30
|
+
// Same-origin links are GUI-internal navigation (settings pages, tool
|
|
31
|
+
// docs) — never routed into the sidebar.
|
|
32
|
+
try {
|
|
33
|
+
if (url.origin === new URL(selfOrigin).origin) return null
|
|
34
|
+
} catch {
|
|
35
|
+
// Unparsable selfOrigin (never in practice): intercept defensively.
|
|
36
|
+
}
|
|
37
|
+
return url.href
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Whether a left-click may be taken over (unmodified left click only). */
|
|
41
|
+
export function isPlainLeftClick(event: { button: number; metaKey: boolean; ctrlKey: boolean; shiftKey: boolean; altKey: boolean }): boolean {
|
|
42
|
+
return event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Register the document-level click capture that funnels external links
|
|
47
|
+
* into the sidebar. Returns the disposer (HMR-safe).
|
|
48
|
+
*/
|
|
49
|
+
export function registerLinkInterception(opts: {
|
|
50
|
+
/** Whether the takeover may happen for THIS url (the caller's prefs
|
|
51
|
+
* gates: master switch, protocol flag, target enablement). */
|
|
52
|
+
takeoverEnabled: (url: URL) => boolean
|
|
53
|
+
/** Open the sidebar tab at `url` (the caller resolves the target type). */
|
|
54
|
+
openInSidebar: (url: string) => void
|
|
55
|
+
/** The GUI's own origin (window.location.origin at registration). */
|
|
56
|
+
selfOrigin: string
|
|
57
|
+
}): () => void {
|
|
58
|
+
const onClick = (event: MouseEvent): void => {
|
|
59
|
+
if (!isPlainLeftClick(event)) return
|
|
60
|
+
if (event.defaultPrevented) return
|
|
61
|
+
const target = event.target
|
|
62
|
+
if (target === null || typeof (target as Element).closest !== 'function') return
|
|
63
|
+
const anchor = (target as Element).closest('a[href]') as HTMLAnchorElement | null
|
|
64
|
+
if (anchor === null || anchor.dataset.dshExternal === 'true') return
|
|
65
|
+
const url = shouldInterceptLink(anchor.href, opts.selfOrigin)
|
|
66
|
+
if (url === null) return
|
|
67
|
+
if (!opts.takeoverEnabled(new URL(url))) return
|
|
68
|
+
event.preventDefault()
|
|
69
|
+
opts.openInSidebar(url)
|
|
70
|
+
}
|
|
71
|
+
document.addEventListener('click', onClick, true)
|
|
72
|
+
return () => { document.removeEventListener('click', onClick, true) }
|
|
73
|
+
}
|