@schlessera/brain-ui-react 0.35.0 → 0.37.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/README.md +82 -4
- package/dist/components/activity/activity-page.d.ts +17 -5
- package/dist/components/activity/activity-page.d.ts.map +1 -1
- package/dist/components/activity/activity-page.js +148 -50
- package/dist/components/activity/activity-page.js.map +1 -1
- package/dist/components/activity/activity-run-detail.d.ts +16 -1
- package/dist/components/activity/activity-run-detail.d.ts.map +1 -1
- package/dist/components/activity/activity-run-detail.js +47 -4
- package/dist/components/activity/activity-run-detail.js.map +1 -1
- package/dist/components/activity/activity-run-list.d.ts +7 -1
- package/dist/components/activity/activity-run-list.d.ts.map +1 -1
- package/dist/components/activity/activity-run-list.js +16 -8
- package/dist/components/activity/activity-run-list.js.map +1 -1
- package/dist/components/activity/activity-views.d.ts +63 -0
- package/dist/components/activity/activity-views.d.ts.map +1 -0
- package/dist/components/activity/activity-views.js +52 -0
- package/dist/components/activity/activity-views.js.map +1 -0
- package/dist/components/activity/approval-card.d.ts +29 -0
- package/dist/components/activity/approval-card.d.ts.map +1 -0
- package/dist/components/activity/approval-card.js +73 -0
- package/dist/components/activity/approval-card.js.map +1 -0
- package/dist/components/activity/digest-card.d.ts +3 -0
- package/dist/components/activity/digest-card.d.ts.map +1 -1
- package/dist/components/activity/digest-card.js +20 -16
- package/dist/components/activity/digest-card.js.map +1 -1
- package/dist/components/activity/digest-summary.d.ts +19 -0
- package/dist/components/activity/digest-summary.d.ts.map +1 -0
- package/dist/components/activity/digest-summary.js +20 -0
- package/dist/components/activity/digest-summary.js.map +1 -0
- package/dist/components/activity/push-switch.d.ts +25 -0
- package/dist/components/activity/push-switch.d.ts.map +1 -0
- package/dist/components/activity/push-switch.js +14 -0
- package/dist/components/activity/push-switch.js.map +1 -0
- package/dist/components/activity/push-toggle.d.ts +7 -0
- package/dist/components/activity/push-toggle.d.ts.map +1 -1
- package/dist/components/activity/push-toggle.js +72 -47
- package/dist/components/activity/push-toggle.js.map +1 -1
- package/dist/components/activity/span-bits.d.ts +11 -0
- package/dist/components/activity/span-bits.d.ts.map +1 -1
- package/dist/components/activity/span-bits.js +50 -7
- package/dist/components/activity/span-bits.js.map +1 -1
- package/dist/components/chat/ask-user-card.d.ts +76 -3
- package/dist/components/chat/ask-user-card.d.ts.map +1 -1
- package/dist/components/chat/ask-user-card.js +208 -149
- package/dist/components/chat/ask-user-card.js.map +1 -1
- package/dist/components/chat/ask-user-typed.d.ts +42 -0
- package/dist/components/chat/ask-user-typed.d.ts.map +1 -0
- package/dist/components/chat/ask-user-typed.js +60 -0
- package/dist/components/chat/ask-user-typed.js.map +1 -0
- package/dist/components/chat/brain-markdown-links.d.ts +2 -1
- package/dist/components/chat/brain-markdown-links.d.ts.map +1 -1
- package/dist/components/chat/brain-markdown-links.js +3 -4
- package/dist/components/chat/brain-markdown-links.js.map +1 -1
- package/dist/components/chat/brain-markdown.d.ts.map +1 -1
- package/dist/components/chat/brain-markdown.js +4 -2
- package/dist/components/chat/brain-markdown.js.map +1 -1
- package/dist/components/chat/chat-page.d.ts.map +1 -1
- package/dist/components/chat/chat-page.js +27 -11
- package/dist/components/chat/chat-page.js.map +1 -1
- package/dist/components/chat/composer-view.d.ts +75 -0
- package/dist/components/chat/composer-view.d.ts.map +1 -0
- package/dist/components/chat/composer-view.js +31 -0
- package/dist/components/chat/composer-view.js.map +1 -0
- package/dist/components/chat/composer.d.ts +4 -0
- package/dist/components/chat/composer.d.ts.map +1 -1
- package/dist/components/chat/composer.js +76 -59
- package/dist/components/chat/composer.js.map +1 -1
- package/dist/components/chat/markdown-content.d.ts +16 -1
- package/dist/components/chat/markdown-content.d.ts.map +1 -1
- package/dist/components/chat/markdown-content.js +47 -3
- package/dist/components/chat/markdown-content.js.map +1 -1
- package/dist/components/chat/mermaid-block.d.ts +4 -0
- package/dist/components/chat/mermaid-block.d.ts.map +1 -1
- package/dist/components/chat/mermaid-block.js +13 -5
- package/dist/components/chat/mermaid-block.js.map +1 -1
- package/dist/components/chat/mermaid-share.d.ts +2 -1
- package/dist/components/chat/mermaid-share.d.ts.map +1 -1
- package/dist/components/chat/mermaid-share.js +7 -8
- package/dist/components/chat/mermaid-share.js.map +1 -1
- package/dist/components/chat/mermaid-viewer.d.ts.map +1 -1
- package/dist/components/chat/mermaid-viewer.js +3 -1
- package/dist/components/chat/mermaid-viewer.js.map +1 -1
- package/dist/components/chat/message-bubble.d.ts +8 -1
- package/dist/components/chat/message-bubble.d.ts.map +1 -1
- package/dist/components/chat/message-bubble.js +53 -24
- package/dist/components/chat/message-bubble.js.map +1 -1
- package/dist/components/chat/message-share.d.ts +2 -1
- package/dist/components/chat/message-share.d.ts.map +1 -1
- package/dist/components/chat/message-share.js +6 -7
- package/dist/components/chat/message-share.js.map +1 -1
- package/dist/components/chat/renderers/bind.d.ts +39 -0
- package/dist/components/chat/renderers/bind.d.ts.map +1 -0
- package/dist/components/chat/renderers/bind.js +43 -0
- package/dist/components/chat/renderers/bind.js.map +1 -0
- package/dist/components/chat/renderers/brain-ui-tools.d.ts +3 -0
- package/dist/components/chat/renderers/brain-ui-tools.d.ts.map +1 -0
- package/dist/components/chat/renderers/brain-ui-tools.js +41 -0
- package/dist/components/chat/renderers/brain-ui-tools.js.map +1 -0
- package/dist/components/chat/renderers/claude-tools.d.ts.map +1 -1
- package/dist/components/chat/renderers/claude-tools.js +3 -2
- package/dist/components/chat/renderers/claude-tools.js.map +1 -1
- package/dist/components/chat/renderers/index.d.ts +10 -2
- package/dist/components/chat/renderers/index.d.ts.map +1 -1
- package/dist/components/chat/renderers/index.js +15 -10
- package/dist/components/chat/renderers/index.js.map +1 -1
- package/dist/components/chat/session-drawer.d.ts +4 -0
- package/dist/components/chat/session-drawer.d.ts.map +1 -1
- package/dist/components/chat/session-drawer.js +32 -32
- package/dist/components/chat/session-drawer.js.map +1 -1
- package/dist/components/chat/session-list.d.ts +41 -0
- package/dist/components/chat/session-list.d.ts.map +1 -0
- package/dist/components/chat/session-list.js +10 -0
- package/dist/components/chat/session-list.js.map +1 -0
- package/dist/components/chat/share-block.d.ts.map +1 -1
- package/dist/components/chat/share-block.js +12 -11
- package/dist/components/chat/share-block.js.map +1 -1
- package/dist/components/chat/share-card.js +2 -2
- package/dist/components/chat/share-card.js.map +1 -1
- package/dist/components/chat/subagent-view.js +1 -1
- package/dist/components/chat/subagent-view.js.map +1 -1
- package/dist/components/chat/tool-call-timeline.d.ts.map +1 -1
- package/dist/components/chat/tool-call-timeline.js +45 -14
- package/dist/components/chat/tool-call-timeline.js.map +1 -1
- package/dist/components/chat/tool-cards/block-card.d.ts +28 -0
- package/dist/components/chat/tool-cards/block-card.d.ts.map +1 -0
- package/dist/components/chat/tool-cards/block-card.js +103 -0
- package/dist/components/chat/tool-cards/block-card.js.map +1 -0
- package/dist/components/chat/tool-cards/image-mask-card.d.ts +70 -0
- package/dist/components/chat/tool-cards/image-mask-card.d.ts.map +1 -0
- package/dist/components/chat/tool-cards/image-mask-card.js +142 -0
- package/dist/components/chat/tool-cards/image-mask-card.js.map +1 -0
- package/dist/components/chat/tool-cards/location-card.d.ts +45 -0
- package/dist/components/chat/tool-cards/location-card.d.ts.map +1 -0
- package/dist/components/chat/tool-cards/location-card.js +128 -0
- package/dist/components/chat/tool-cards/location-card.js.map +1 -0
- package/dist/components/chat/tool-views.d.ts +19 -2
- package/dist/components/chat/tool-views.d.ts.map +1 -1
- package/dist/components/chat/tool-views.js +28 -22
- package/dist/components/chat/tool-views.js.map +1 -1
- package/dist/components/chat/transcript-turn.d.ts +45 -0
- package/dist/components/chat/transcript-turn.d.ts.map +1 -0
- package/dist/components/chat/transcript-turn.js +25 -0
- package/dist/components/chat/transcript-turn.js.map +1 -0
- package/dist/components/chat/use-chat-commands.d.ts.map +1 -1
- package/dist/components/chat/use-chat-commands.js +13 -16
- package/dist/components/chat/use-chat-commands.js.map +1 -1
- package/dist/components/chat/welcome-state.d.ts +7 -0
- package/dist/components/chat/welcome-state.d.ts.map +1 -1
- package/dist/components/chat/welcome-state.js +13 -5
- package/dist/components/chat/welcome-state.js.map +1 -1
- package/dist/components/connectivity/connection-gate.d.ts.map +1 -1
- package/dist/components/connectivity/connection-gate.js +27 -21
- package/dist/components/connectivity/connection-gate.js.map +1 -1
- package/dist/components/connectivity/login-form.d.ts +31 -0
- package/dist/components/connectivity/login-form.d.ts.map +1 -0
- package/dist/components/connectivity/login-form.js +19 -0
- package/dist/components/connectivity/login-form.js.map +1 -0
- package/dist/components/connectivity/login-screen.d.ts +5 -2
- package/dist/components/connectivity/login-screen.d.ts.map +1 -1
- package/dist/components/connectivity/login-screen.js +41 -31
- package/dist/components/connectivity/login-screen.js.map +1 -1
- package/dist/components/dev/share-harness.js +1 -1
- package/dist/components/dev/share-harness.js.map +1 -1
- package/dist/components/files/file-panel.d.ts +1 -1
- package/dist/components/files/file-panel.d.ts.map +1 -1
- package/dist/components/files/file-panel.js +74 -0
- package/dist/components/files/file-panel.js.map +1 -1
- package/dist/components/files/file-tree-view.d.ts +45 -0
- package/dist/components/files/file-tree-view.d.ts.map +1 -0
- package/dist/components/files/file-tree-view.js +51 -0
- package/dist/components/files/file-tree-view.js.map +1 -0
- package/dist/components/files/file-tree.d.ts +6 -0
- package/dist/components/files/file-tree.d.ts.map +1 -1
- package/dist/components/files/file-tree.js +39 -43
- package/dist/components/files/file-tree.js.map +1 -1
- package/dist/components/files/file-viewer-binary.d.ts.map +1 -1
- package/dist/components/files/file-viewer-binary.js +3 -2
- package/dist/components/files/file-viewer-binary.js.map +1 -1
- package/dist/components/files/file-viewer-frame.d.ts +36 -0
- package/dist/components/files/file-viewer-frame.d.ts.map +1 -0
- package/dist/components/files/file-viewer-frame.js +26 -0
- package/dist/components/files/file-viewer-frame.js.map +1 -0
- package/dist/components/files/file-viewer.d.ts +5 -0
- package/dist/components/files/file-viewer.d.ts.map +1 -1
- package/dist/components/files/file-viewer.js +26 -32
- package/dist/components/files/file-viewer.js.map +1 -1
- package/dist/components/files/frontmatter-chips.d.ts +18 -0
- package/dist/components/files/frontmatter-chips.d.ts.map +1 -0
- package/dist/components/files/frontmatter-chips.js +11 -0
- package/dist/components/files/frontmatter-chips.js.map +1 -0
- package/dist/components/files/frontmatter-panel.d.ts +5 -1
- package/dist/components/files/frontmatter-panel.d.ts.map +1 -1
- package/dist/components/files/frontmatter-panel.js +7 -6
- package/dist/components/files/frontmatter-panel.js.map +1 -1
- package/dist/components/files/staleness.d.ts +18 -0
- package/dist/components/files/staleness.d.ts.map +1 -0
- package/dist/components/files/staleness.js +27 -0
- package/dist/components/files/staleness.js.map +1 -0
- package/dist/components/graph/graph-canvas.d.ts.map +1 -1
- package/dist/components/graph/graph-canvas.js +24 -1
- package/dist/components/graph/graph-canvas.js.map +1 -1
- package/dist/components/graph/graph-controls-column.d.ts +14 -0
- package/dist/components/graph/graph-controls-column.d.ts.map +1 -0
- package/dist/components/graph/graph-controls-column.js +44 -0
- package/dist/components/graph/graph-controls-column.js.map +1 -0
- package/dist/components/graph/graph-controls.d.ts +20 -5
- package/dist/components/graph/graph-controls.d.ts.map +1 -1
- package/dist/components/graph/graph-controls.js +58 -37
- package/dist/components/graph/graph-controls.js.map +1 -1
- package/dist/components/graph/graph-form.d.ts +82 -0
- package/dist/components/graph/graph-form.d.ts.map +1 -0
- package/dist/components/graph/graph-form.js +69 -0
- package/dist/components/graph/graph-form.js.map +1 -0
- package/dist/components/graph/graph-maintenance.d.ts.map +1 -1
- package/dist/components/graph/graph-maintenance.js +6 -10
- package/dist/components/graph/graph-maintenance.js.map +1 -1
- package/dist/components/graph/graph-node-rail.d.ts +13 -0
- package/dist/components/graph/graph-node-rail.d.ts.map +1 -0
- package/dist/components/graph/graph-node-rail.js +92 -0
- package/dist/components/graph/graph-node-rail.js.map +1 -0
- package/dist/components/graph/graph-page.d.ts +7 -0
- package/dist/components/graph/graph-page.d.ts.map +1 -1
- package/dist/components/graph/graph-page.js +102 -12
- package/dist/components/graph/graph-page.js.map +1 -1
- package/dist/components/graph/graph-scene.d.ts.map +1 -1
- package/dist/components/graph/graph-scene.js +100 -24
- package/dist/components/graph/graph-scene.js.map +1 -1
- package/dist/components/graph/lib/graph-helpers.d.ts +42 -12
- package/dist/components/graph/lib/graph-helpers.d.ts.map +1 -1
- package/dist/components/graph/lib/graph-helpers.js +33 -41
- package/dist/components/graph/lib/graph-helpers.js.map +1 -1
- package/dist/components/graph/node-card.d.ts +28 -0
- package/dist/components/graph/node-card.d.ts.map +1 -0
- package/dist/components/graph/node-card.js +7 -0
- package/dist/components/graph/node-card.js.map +1 -0
- package/dist/components/graph/node-popover.d.ts +6 -2
- package/dist/components/graph/node-popover.d.ts.map +1 -1
- package/dist/components/graph/node-popover.js +13 -31
- package/dist/components/graph/node-popover.js.map +1 -1
- package/dist/components/graph/use-graph-theme.d.ts +32 -4
- package/dist/components/graph/use-graph-theme.d.ts.map +1 -1
- package/dist/components/graph/use-graph-theme.js +44 -32
- package/dist/components/graph/use-graph-theme.js.map +1 -1
- package/dist/components/graph/use-node-actions.d.ts +26 -0
- package/dist/components/graph/use-node-actions.d.ts.map +1 -0
- package/dist/components/graph/use-node-actions.js +54 -0
- package/dist/components/graph/use-node-actions.js.map +1 -0
- package/dist/components/images/image-share.d.ts +2 -1
- package/dist/components/images/image-share.d.ts.map +1 -1
- package/dist/components/images/image-share.js +3 -3
- package/dist/components/images/image-share.js.map +1 -1
- package/dist/components/images/image-viewer.d.ts.map +1 -1
- package/dist/components/images/image-viewer.js +3 -1
- package/dist/components/images/image-viewer.js.map +1 -1
- package/dist/components/images/mask-editor.d.ts.map +1 -1
- package/dist/components/images/mask-editor.js +7 -5
- package/dist/components/images/mask-editor.js.map +1 -1
- package/dist/components/layout/app-shell.d.ts.map +1 -1
- package/dist/components/layout/app-shell.js +4 -1
- package/dist/components/layout/app-shell.js.map +1 -1
- package/dist/components/layout/desktop-palette.d.ts +23 -0
- package/dist/components/layout/desktop-palette.d.ts.map +1 -0
- package/dist/components/layout/desktop-palette.js +132 -0
- package/dist/components/layout/desktop-palette.js.map +1 -0
- package/dist/components/layout/key-cap.d.ts +9 -0
- package/dist/components/layout/key-cap.d.ts.map +1 -0
- package/dist/components/layout/key-cap.js +10 -0
- package/dist/components/layout/key-cap.js.map +1 -0
- package/dist/components/layout/mobile-tab-bar.d.ts +13 -0
- package/dist/components/layout/mobile-tab-bar.d.ts.map +1 -1
- package/dist/components/layout/mobile-tab-bar.js +58 -47
- package/dist/components/layout/mobile-tab-bar.js.map +1 -1
- package/dist/components/layout/shortcut-switch.d.ts +13 -0
- package/dist/components/layout/shortcut-switch.d.ts.map +1 -0
- package/dist/components/layout/shortcut-switch.js +22 -0
- package/dist/components/layout/shortcut-switch.js.map +1 -0
- package/dist/components/layout/side-rail.d.ts +28 -0
- package/dist/components/layout/side-rail.d.ts.map +1 -1
- package/dist/components/layout/side-rail.js +72 -27
- package/dist/components/layout/side-rail.js.map +1 -1
- package/dist/components/layout/slide-panel.d.ts +25 -2
- package/dist/components/layout/slide-panel.d.ts.map +1 -1
- package/dist/components/layout/slide-panel.js +13 -4
- package/dist/components/layout/slide-panel.js.map +1 -1
- package/dist/components/layout/theme.d.ts +22 -0
- package/dist/components/layout/theme.d.ts.map +1 -0
- package/dist/components/layout/theme.js +44 -0
- package/dist/components/layout/theme.js.map +1 -0
- package/dist/components/quick-actions/add-form.d.ts +44 -0
- package/dist/components/quick-actions/add-form.d.ts.map +1 -0
- package/dist/components/quick-actions/add-form.js +32 -0
- package/dist/components/quick-actions/add-form.js.map +1 -0
- package/dist/components/quick-actions/add-modal.d.ts +7 -0
- package/dist/components/quick-actions/add-modal.d.ts.map +1 -1
- package/dist/components/quick-actions/add-modal.js +23 -20
- package/dist/components/quick-actions/add-modal.js.map +1 -1
- package/dist/components/quick-actions/search-modal.d.ts.map +1 -1
- package/dist/components/quick-actions/search-modal.js +8 -5
- package/dist/components/quick-actions/search-modal.js.map +1 -1
- package/dist/components/quick-actions/streaming-modal.d.ts +6 -0
- package/dist/components/quick-actions/streaming-modal.d.ts.map +1 -1
- package/dist/components/quick-actions/streaming-modal.js +53 -18
- package/dist/components/quick-actions/streaming-modal.js.map +1 -1
- package/dist/components/quick-actions/streaming-output.d.ts +38 -0
- package/dist/components/quick-actions/streaming-output.d.ts.map +1 -0
- package/dist/components/quick-actions/streaming-output.js +22 -0
- package/dist/components/quick-actions/streaming-output.js.map +1 -0
- package/dist/components/quick-actions/whatsup-modal.d.ts +5 -0
- package/dist/components/quick-actions/whatsup-modal.d.ts.map +1 -1
- package/dist/components/quick-actions/whatsup-modal.js +51 -10
- package/dist/components/quick-actions/whatsup-modal.js.map +1 -1
- package/dist/components/settings/devices-agents-tab.d.ts +6 -1
- package/dist/components/settings/devices-agents-tab.d.ts.map +1 -1
- package/dist/components/settings/devices-agents-tab.js +55 -20
- package/dist/components/settings/devices-agents-tab.js.map +1 -1
- package/dist/components/settings/models-list.d.ts +39 -0
- package/dist/components/settings/models-list.d.ts.map +1 -0
- package/dist/components/settings/models-list.js +72 -0
- package/dist/components/settings/models-list.js.map +1 -0
- package/dist/components/settings/models-tab.d.ts +4 -0
- package/dist/components/settings/models-tab.d.ts.map +1 -1
- package/dist/components/settings/models-tab.js +52 -102
- package/dist/components/settings/models-tab.js.map +1 -1
- package/dist/components/settings/one-time-agent-credential.js +1 -1
- package/dist/components/settings/one-time-agent-credential.js.map +1 -1
- package/dist/components/settings/passkey-list.d.ts +35 -0
- package/dist/components/settings/passkey-list.d.ts.map +1 -0
- package/dist/components/settings/passkey-list.js +34 -0
- package/dist/components/settings/passkey-list.js.map +1 -0
- package/dist/components/settings/passkey-tab.d.ts +3 -0
- package/dist/components/settings/passkey-tab.d.ts.map +1 -1
- package/dist/components/settings/passkey-tab.js +53 -45
- package/dist/components/settings/passkey-tab.js.map +1 -1
- package/dist/components/settings/pi-accounts-list.d.ts +27 -0
- package/dist/components/settings/pi-accounts-list.d.ts.map +1 -0
- package/dist/components/settings/pi-accounts-list.js +15 -0
- package/dist/components/settings/pi-accounts-list.js.map +1 -0
- package/dist/components/settings/pi-accounts.d.ts +3 -0
- package/dist/components/settings/pi-accounts.d.ts.map +1 -1
- package/dist/components/settings/pi-accounts.js +73 -55
- package/dist/components/settings/pi-accounts.js.map +1 -1
- package/dist/components/settings/principal-list.d.ts +37 -0
- package/dist/components/settings/principal-list.d.ts.map +1 -0
- package/dist/components/settings/principal-list.js +18 -0
- package/dist/components/settings/principal-list.js.map +1 -0
- package/dist/components/settings/settings-panel.d.ts +10 -3
- package/dist/components/settings/settings-panel.d.ts.map +1 -1
- package/dist/components/settings/settings-panel.js +71 -10
- package/dist/components/settings/settings-panel.js.map +1 -1
- package/dist/components/settings/skills-list.d.ts +53 -0
- package/dist/components/settings/skills-list.d.ts.map +1 -0
- package/dist/components/settings/skills-list.js +28 -0
- package/dist/components/settings/skills-list.js.map +1 -0
- package/dist/components/settings/skills-tab.d.ts.map +1 -1
- package/dist/components/settings/skills-tab.js +65 -38
- package/dist/components/settings/skills-tab.js.map +1 -1
- package/dist/components/settings/tool-permissions-list.d.ts +18 -0
- package/dist/components/settings/tool-permissions-list.d.ts.map +1 -0
- package/dist/components/settings/tool-permissions-list.js +6 -0
- package/dist/components/settings/tool-permissions-list.js.map +1 -0
- package/dist/components/settings/tool-permissions.d.ts +2 -1
- package/dist/components/settings/tool-permissions.d.ts.map +1 -1
- package/dist/components/settings/tool-permissions.js +33 -16
- package/dist/components/settings/tool-permissions.js.map +1 -1
- package/dist/components/settings/web-search-chain.d.ts +41 -0
- package/dist/components/settings/web-search-chain.d.ts.map +1 -0
- package/dist/components/settings/web-search-chain.js +47 -0
- package/dist/components/settings/web-search-chain.js.map +1 -0
- package/dist/components/settings/web-search-settings.d.ts +4 -7
- package/dist/components/settings/web-search-settings.d.ts.map +1 -1
- package/dist/components/settings/web-search-settings.js +54 -76
- package/dist/components/settings/web-search-settings.js.map +1 -1
- package/dist/components/share/share-menu.d.ts.map +1 -1
- package/dist/components/share/share-menu.js +24 -4
- package/dist/components/share/share-menu.js.map +1 -1
- package/dist/components/voice/dictation-sheet.js +3 -3
- package/dist/components/voice/dictation-sheet.js.map +1 -1
- package/dist/components/voice/mic-button.js +1 -1
- package/dist/components/voice/mic-button.js.map +1 -1
- package/dist/components/voice/review-card.js +1 -1
- package/dist/components/voice/review-card.js.map +1 -1
- package/dist/config.d.ts +5 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +15 -5
- package/dist/config.js.map +1 -1
- package/dist/connection.d.ts +12 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +421 -0
- package/dist/connection.js.map +1 -0
- package/dist/default-root.d.ts +3 -0
- package/dist/default-root.d.ts.map +1 -0
- package/dist/default-root.js +16 -0
- package/dist/default-root.js.map +1 -0
- package/dist/hooks/use-color-scheme.d.ts +14 -0
- package/dist/hooks/use-color-scheme.d.ts.map +1 -0
- package/dist/hooks/use-color-scheme.js +37 -0
- package/dist/hooks/use-color-scheme.js.map +1 -0
- package/dist/hooks/use-fine-pointer.d.ts +12 -0
- package/dist/hooks/use-fine-pointer.d.ts.map +1 -0
- package/dist/hooks/use-fine-pointer.js +15 -0
- package/dist/hooks/use-fine-pointer.js.map +1 -0
- package/dist/hooks/use-hash-routes.d.ts.map +1 -1
- package/dist/hooks/use-hash-routes.js +4 -2
- package/dist/hooks/use-hash-routes.js.map +1 -1
- package/dist/hooks/use-media-query.d.ts +9 -0
- package/dist/hooks/use-media-query.d.ts.map +1 -0
- package/dist/hooks/use-media-query.js +38 -0
- package/dist/hooks/use-media-query.js.map +1 -0
- package/dist/hooks/use-share-intake.d.ts.map +1 -1
- package/dist/hooks/use-share-intake.js +37 -12
- package/dist/hooks/use-share-intake.js.map +1 -1
- package/dist/hooks/use-vpn-status.d.ts.map +1 -1
- package/dist/hooks/use-vpn-status.js +17 -18
- package/dist/hooks/use-vpn-status.js.map +1 -1
- package/dist/hooks/use-websocket.d.ts +5 -24
- package/dist/hooks/use-websocket.d.ts.map +1 -1
- package/dist/hooks/use-websocket.js +11 -384
- package/dist/hooks/use-websocket.js.map +1 -1
- package/dist/hooks/websocket-handlers/activity.d.ts +2 -2
- package/dist/hooks/websocket-handlers/activity.d.ts.map +1 -1
- package/dist/hooks/websocket-handlers/activity.js +4 -5
- package/dist/hooks/websocket-handlers/activity.js.map +1 -1
- package/dist/hooks/websocket-handlers/chat.d.ts +1 -0
- package/dist/hooks/websocket-handlers/chat.d.ts.map +1 -1
- package/dist/hooks/websocket-handlers/chat.js +28 -6
- package/dist/hooks/websocket-handlers/chat.js.map +1 -1
- package/dist/hooks/websocket-handlers/connection.d.ts.map +1 -1
- package/dist/hooks/websocket-handlers/connection.js +4 -6
- package/dist/hooks/websocket-handlers/connection.js.map +1 -1
- package/dist/hooks/websocket-handlers/mask.d.ts +1 -1
- package/dist/hooks/websocket-handlers/mask.d.ts.map +1 -1
- package/dist/hooks/websocket-handlers/mask.js +2 -3
- package/dist/hooks/websocket-handlers/mask.js.map +1 -1
- package/dist/hooks/websocket-handlers/provider.d.ts.map +1 -1
- package/dist/hooks/websocket-handlers/provider.js +4 -6
- package/dist/hooks/websocket-handlers/provider.js.map +1 -1
- package/dist/hooks/websocket-handlers/types.d.ts +6 -2
- package/dist/hooks/websocket-handlers/types.d.ts.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/api-client.d.ts +289 -0
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +243 -224
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/backend.d.ts +19 -2
- package/dist/lib/backend.d.ts.map +1 -1
- package/dist/lib/backend.js +15 -9
- package/dist/lib/backend.js.map +1 -1
- package/dist/lib/diff.d.ts +8 -10
- package/dist/lib/diff.d.ts.map +1 -1
- package/dist/lib/diff.js +26 -53
- package/dist/lib/diff.js.map +1 -1
- package/dist/lib/light-dark.d.ts +37 -0
- package/dist/lib/light-dark.d.ts.map +1 -0
- package/dist/lib/light-dark.js +83 -0
- package/dist/lib/light-dark.js.map +1 -0
- package/dist/lib/mermaid-theme.d.ts +7 -2
- package/dist/lib/mermaid-theme.d.ts.map +1 -1
- package/dist/lib/mermaid-theme.js +125 -203
- package/dist/lib/mermaid-theme.js.map +1 -1
- package/dist/lib/passkeys.d.ts +6 -3
- package/dist/lib/passkeys.d.ts.map +1 -1
- package/dist/lib/passkeys.js +10 -4
- package/dist/lib/passkeys.js.map +1 -1
- package/dist/lib/push-registration.d.ts +4 -1
- package/dist/lib/push-registration.d.ts.map +1 -1
- package/dist/lib/push-registration.js +20 -2
- package/dist/lib/push-registration.js.map +1 -1
- package/dist/lib/share-intake.d.ts +2 -1
- package/dist/lib/share-intake.d.ts.map +1 -1
- package/dist/lib/share-intake.js +3 -3
- package/dist/lib/share-intake.js.map +1 -1
- package/dist/lib/share.d.ts +4 -3
- package/dist/lib/share.d.ts.map +1 -1
- package/dist/lib/share.js +6 -7
- package/dist/lib/share.js.map +1 -1
- package/dist/lib/single-key.d.ts +30 -0
- package/dist/lib/single-key.d.ts.map +1 -0
- package/dist/lib/single-key.js +45 -0
- package/dist/lib/single-key.js.map +1 -0
- package/dist/lib/tool-names.d.ts +8 -6
- package/dist/lib/tool-names.d.ts.map +1 -1
- package/dist/lib/tool-names.js +17 -7
- package/dist/lib/tool-names.js.map +1 -1
- package/dist/root-context.d.ts +229 -0
- package/dist/root-context.d.ts.map +1 -0
- package/dist/root-context.js +33 -0
- package/dist/root-context.js.map +1 -0
- package/dist/root.d.ts +38 -0
- package/dist/root.d.ts.map +1 -0
- package/dist/root.js +47 -0
- package/dist/root.js.map +1 -0
- package/dist/stores/activity-state.d.ts +29 -0
- package/dist/stores/activity-state.d.ts.map +1 -0
- package/dist/stores/activity-state.js +282 -0
- package/dist/stores/activity-state.js.map +1 -0
- package/dist/stores/activity-store.d.ts +10 -41
- package/dist/stores/activity-store.d.ts.map +1 -1
- package/dist/stores/activity-store.js +9 -271
- package/dist/stores/activity-store.js.map +1 -1
- package/dist/stores/chat-state.d.ts +233 -0
- package/dist/stores/chat-state.d.ts.map +1 -0
- package/dist/stores/chat-state.js +477 -0
- package/dist/stores/chat-state.js.map +1 -0
- package/dist/stores/chat-store.d.ts +4 -162
- package/dist/stores/chat-store.d.ts.map +1 -1
- package/dist/stores/chat-store.js +7 -418
- package/dist/stores/chat-store.js.map +1 -1
- package/dist/stores/connection-state.d.ts +40 -0
- package/dist/stores/connection-state.d.ts.map +1 -0
- package/dist/stores/connection-state.js +30 -0
- package/dist/stores/connection-state.js.map +1 -0
- package/dist/stores/connection-store.d.ts +4 -40
- package/dist/stores/connection-store.d.ts.map +1 -1
- package/dist/stores/connection-store.js +7 -27
- package/dist/stores/connection-store.js.map +1 -1
- package/dist/stores/create-stores.d.ts +23 -0
- package/dist/stores/create-stores.d.ts.map +1 -0
- package/dist/stores/create-stores.js +28 -0
- package/dist/stores/create-stores.js.map +1 -0
- package/dist/stores/file-state.d.ts +53 -0
- package/dist/stores/file-state.d.ts.map +1 -0
- package/dist/stores/file-state.js +341 -0
- package/dist/stores/file-state.js.map +1 -0
- package/dist/stores/file-store.d.ts +4 -52
- package/dist/stores/file-store.d.ts.map +1 -1
- package/dist/stores/file-store.js +7 -336
- package/dist/stores/file-store.js.map +1 -1
- package/dist/stores/graph-state.d.ts +95 -0
- package/dist/stores/graph-state.d.ts.map +1 -0
- package/dist/stores/graph-state.js +252 -0
- package/dist/stores/graph-state.js.map +1 -0
- package/dist/stores/graph-store.d.ts +7 -83
- package/dist/stores/graph-store.d.ts.map +1 -1
- package/dist/stores/graph-store.js +8 -249
- package/dist/stores/graph-store.js.map +1 -1
- package/dist/stores/mask-state.d.ts +21 -0
- package/dist/stores/mask-state.d.ts.map +1 -0
- package/dist/stores/mask-state.js +9 -0
- package/dist/stores/mask-state.js.map +1 -0
- package/dist/stores/mask-store.d.ts +4 -21
- package/dist/stores/mask-store.d.ts.map +1 -1
- package/dist/stores/mask-store.js +7 -6
- package/dist/stores/mask-store.js.map +1 -1
- package/dist/stores/principal-state.d.ts +16 -0
- package/dist/stores/principal-state.d.ts.map +1 -0
- package/dist/stores/principal-state.js +31 -0
- package/dist/stores/principal-state.js.map +1 -0
- package/dist/stores/principal-store.d.ts +4 -15
- package/dist/stores/principal-store.d.ts.map +1 -1
- package/dist/stores/principal-store.js +7 -28
- package/dist/stores/principal-store.js.map +1 -1
- package/dist/stores/provider-state.d.ts +24 -0
- package/dist/stores/provider-state.d.ts.map +1 -0
- package/dist/stores/provider-state.js +68 -0
- package/dist/stores/provider-state.js.map +1 -0
- package/dist/stores/provider-store.d.ts +4 -23
- package/dist/stores/provider-store.d.ts.map +1 -1
- package/dist/stores/provider-store.js +7 -64
- package/dist/stores/provider-store.js.map +1 -1
- package/dist/stores/share-state.d.ts +29 -0
- package/dist/stores/share-state.d.ts.map +1 -0
- package/dist/stores/share-state.js +21 -0
- package/dist/stores/share-state.js.map +1 -0
- package/dist/stores/share-store.d.ts +4 -28
- package/dist/stores/share-store.d.ts.map +1 -1
- package/dist/stores/share-store.js +7 -18
- package/dist/stores/share-store.js.map +1 -1
- package/dist/stores/store-environment.d.ts +10 -0
- package/dist/stores/store-environment.d.ts.map +1 -0
- package/dist/stores/store-environment.js +2 -0
- package/dist/stores/store-environment.js.map +1 -0
- package/dist/stores/ui-state.d.ts +71 -0
- package/dist/stores/ui-state.d.ts.map +1 -0
- package/dist/stores/ui-state.js +58 -0
- package/dist/stores/ui-state.js.map +1 -0
- package/dist/stores/ui-store.d.ts +4 -45
- package/dist/stores/ui-store.d.ts.map +1 -1
- package/dist/stores/ui-store.js +7 -36
- package/dist/stores/ui-store.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/theme.css +150 -97
- package/dist/voice/asr-clients.d.ts +2 -1
- package/dist/voice/asr-clients.d.ts.map +1 -1
- package/dist/voice/asr-clients.js +16 -17
- package/dist/voice/asr-clients.js.map +1 -1
- package/dist/voice/use-dictation.d.ts.map +1 -1
- package/dist/voice/use-dictation.js +12 -8
- package/dist/voice/use-dictation.js.map +1 -1
- package/dist/voice/voice-state.d.ts +25 -0
- package/dist/voice/voice-state.d.ts.map +1 -0
- package/dist/voice/voice-state.js +29 -0
- package/dist/voice/voice-state.js.map +1 -0
- package/dist/voice/voice-store.d.ts +4 -25
- package/dist/voice/voice-store.d.ts.map +1 -1
- package/dist/voice/voice-store.js +7 -26
- package/dist/voice/voice-store.js.map +1 -1
- package/package.json +3 -2
- package/src/components/activity/activity-page.tsx +341 -160
- package/src/components/activity/activity-run-detail.tsx +81 -47
- package/src/components/activity/activity-run-list.tsx +27 -59
- package/src/components/activity/activity-views.tsx +155 -0
- package/src/components/activity/approval-card.tsx +117 -0
- package/src/components/activity/digest-card.tsx +25 -61
- package/src/components/activity/digest-summary.tsx +52 -0
- package/src/components/activity/push-switch.tsx +62 -0
- package/src/components/activity/push-toggle.tsx +51 -81
- package/src/components/activity/span-bits.tsx +60 -7
- package/src/components/chat/ask-user-card.tsx +292 -356
- package/src/components/chat/ask-user-typed.ts +77 -0
- package/src/components/chat/brain-markdown-links.tsx +4 -4
- package/src/components/chat/brain-markdown.tsx +4 -2
- package/src/components/chat/chat-page.tsx +41 -11
- package/src/components/chat/composer-view.tsx +194 -0
- package/src/components/chat/composer.tsx +117 -296
- package/src/components/chat/markdown-content.tsx +53 -2
- package/src/components/chat/mermaid-block.tsx +13 -5
- package/src/components/chat/mermaid-share.ts +8 -7
- package/src/components/chat/mermaid-viewer.tsx +3 -1
- package/src/components/chat/message-bubble.tsx +78 -94
- package/src/components/chat/message-share.ts +7 -7
- package/src/components/chat/renderers/bind.tsx +94 -0
- package/src/components/chat/renderers/brain-ui-tools.tsx +56 -0
- package/src/components/chat/renderers/claude-tools.tsx +3 -2
- package/src/components/chat/renderers/index.ts +15 -10
- package/src/components/chat/session-drawer.tsx +41 -138
- package/src/components/chat/session-list.tsx +113 -0
- package/src/components/chat/share-block.tsx +16 -12
- package/src/components/chat/share-card.tsx +2 -2
- package/src/components/chat/subagent-view.tsx +4 -4
- package/src/components/chat/tool-call-timeline.tsx +75 -26
- package/src/components/chat/tool-cards/block-card.tsx +145 -0
- package/src/components/chat/tool-cards/image-mask-card.tsx +214 -0
- package/src/components/chat/tool-cards/location-card.tsx +159 -0
- package/src/components/chat/tool-views.tsx +30 -60
- package/src/components/chat/transcript-turn.tsx +108 -0
- package/src/components/chat/use-chat-commands.ts +14 -16
- package/src/components/chat/welcome-state.tsx +36 -91
- package/src/components/connectivity/connection-gate.tsx +32 -24
- package/src/components/connectivity/login-form.tsx +122 -0
- package/src/components/connectivity/login-screen.tsx +45 -100
- package/src/components/dev/share-harness.tsx +2 -2
- package/src/components/files/file-panel.tsx +168 -0
- package/src/components/files/file-tree-view.tsx +127 -0
- package/src/components/files/file-tree.tsx +55 -109
- package/src/components/files/file-viewer-binary.tsx +3 -2
- package/src/components/files/file-viewer-frame.tsx +113 -0
- package/src/components/files/file-viewer.tsx +40 -95
- package/src/components/files/frontmatter-chips.tsx +42 -0
- package/src/components/files/frontmatter-panel.tsx +6 -71
- package/src/components/files/staleness.ts +29 -0
- package/src/components/graph/graph-canvas.tsx +24 -1
- package/src/components/graph/graph-controls-column.tsx +92 -0
- package/src/components/graph/graph-controls.tsx +83 -127
- package/src/components/graph/graph-form.tsx +183 -0
- package/src/components/graph/graph-maintenance.tsx +9 -14
- package/src/components/graph/graph-node-rail.tsx +147 -0
- package/src/components/graph/graph-page.tsx +189 -49
- package/src/components/graph/graph-scene.tsx +200 -30
- package/src/components/graph/lib/graph-helpers.ts +65 -43
- package/src/components/graph/node-card.tsx +64 -0
- package/src/components/graph/node-popover.tsx +28 -117
- package/src/components/graph/use-graph-theme.ts +69 -32
- package/src/components/graph/use-node-actions.ts +56 -0
- package/src/components/images/image-share.ts +4 -2
- package/src/components/images/image-viewer.tsx +3 -1
- package/src/components/images/mask-editor.tsx +7 -4
- package/src/components/layout/app-shell.tsx +5 -1
- package/src/components/layout/desktop-palette.tsx +151 -0
- package/src/components/layout/key-cap.tsx +15 -0
- package/src/components/layout/mobile-tab-bar.tsx +80 -157
- package/src/components/layout/shortcut-switch.tsx +32 -0
- package/src/components/layout/side-rail.tsx +77 -150
- package/src/components/layout/slide-panel.tsx +49 -6
- package/src/components/layout/theme.tsx +67 -0
- package/src/components/quick-actions/add-form.tsx +196 -0
- package/src/components/quick-actions/add-modal.tsx +32 -153
- package/src/components/quick-actions/search-modal.tsx +15 -5
- package/src/components/quick-actions/streaming-modal.tsx +57 -72
- package/src/components/quick-actions/streaming-output.tsx +112 -0
- package/src/components/quick-actions/whatsup-modal.tsx +53 -59
- package/src/components/settings/devices-agents-tab.tsx +60 -152
- package/src/components/settings/models-list.tsx +299 -0
- package/src/components/settings/models-tab.tsx +63 -337
- package/src/components/settings/one-time-agent-credential.tsx +1 -1
- package/src/components/settings/passkey-list.tsx +201 -0
- package/src/components/settings/passkey-tab.tsx +53 -197
- package/src/components/settings/pi-accounts-list.tsx +128 -0
- package/src/components/settings/pi-accounts.tsx +71 -170
- package/src/components/settings/principal-list.tsx +172 -0
- package/src/components/settings/settings-panel.tsx +239 -25
- package/src/components/settings/skills-list.tsx +276 -0
- package/src/components/settings/skills-tab.tsx +82 -269
- package/src/components/settings/tool-permissions-list.tsx +54 -0
- package/src/components/settings/tool-permissions.tsx +27 -46
- package/src/components/settings/web-search-chain.tsx +300 -0
- package/src/components/settings/web-search-settings.tsx +58 -328
- package/src/components/share/share-menu.tsx +19 -4
- package/src/components/voice/dictation-sheet.tsx +5 -5
- package/src/components/voice/mic-button.tsx +1 -1
- package/src/components/voice/review-card.tsx +1 -1
- package/src/config.ts +21 -7
- package/src/connection.ts +443 -0
- package/src/default-root.ts +16 -0
- package/src/hooks/use-color-scheme.ts +36 -0
- package/src/hooks/use-fine-pointer.ts +15 -0
- package/src/hooks/use-hash-routes.ts +4 -2
- package/src/hooks/use-media-query.ts +35 -0
- package/src/hooks/use-share-intake.ts +32 -12
- package/src/hooks/use-vpn-status.ts +18 -17
- package/src/hooks/use-websocket.ts +12 -428
- package/src/hooks/websocket-handlers/activity.ts +4 -5
- package/src/hooks/websocket-handlers/chat.ts +28 -6
- package/src/hooks/websocket-handlers/connection.ts +4 -6
- package/src/hooks/websocket-handlers/mask.ts +2 -3
- package/src/hooks/websocket-handlers/provider.ts +4 -6
- package/src/hooks/websocket-handlers/types.ts +6 -2
- package/src/index.ts +7 -3
- package/src/lib/api-client.ts +426 -384
- package/src/lib/backend.ts +20 -10
- package/src/lib/diff.ts +28 -62
- package/src/lib/light-dark.ts +83 -0
- package/src/lib/mermaid-theme.ts +183 -214
- package/src/lib/passkeys.ts +12 -4
- package/src/lib/push-registration.ts +19 -2
- package/src/lib/share-intake.ts +6 -3
- package/src/lib/share.ts +7 -4
- package/src/lib/single-key.ts +47 -0
- package/src/lib/tool-names.ts +31 -8
- package/src/root-context.tsx +40 -0
- package/src/root.ts +83 -0
- package/src/stores/activity-state.ts +295 -0
- package/src/stores/activity-store.ts +11 -285
- package/src/stores/chat-state.ts +822 -0
- package/src/stores/chat-store.ts +11 -705
- package/src/stores/connection-state.ts +78 -0
- package/src/stores/connection-store.ts +11 -76
- package/src/stores/create-stores.ts +31 -0
- package/src/stores/file-state.ts +399 -0
- package/src/stores/file-store.ts +9 -390
- package/src/stores/graph-state.ts +368 -0
- package/src/stores/graph-store.ts +10 -355
- package/src/stores/mask-state.ts +30 -0
- package/src/stores/mask-store.ts +10 -27
- package/src/stores/principal-state.ts +42 -0
- package/src/stores/principal-store.ts +10 -37
- package/src/stores/provider-state.ts +103 -0
- package/src/stores/provider-store.ts +10 -95
- package/src/stores/share-state.ts +56 -0
- package/src/stores/share-store.ts +11 -54
- package/src/stores/store-environment.ts +10 -0
- package/src/stores/ui-state.ts +143 -0
- package/src/stores/ui-store.ts +11 -93
- package/src/styles.css +4 -1
- package/src/theme.css +150 -97
- package/src/voice/asr-clients.ts +17 -17
- package/src/voice/use-dictation.ts +11 -8
- package/src/voice/voice-state.ts +57 -0
- package/src/voice/voice-store.ts +11 -55
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
import { Suspense, lazy, useEffect } from "react";
|
|
2
|
+
import { Button, Label, Receipt, ScreenHeader } from "@schlessera/brain-ui-kit";
|
|
3
|
+
import type { ReceiptRow } from "@schlessera/brain-ui-kit";
|
|
2
4
|
import { ChevronDown, ChevronRight, X } from "lucide-react";
|
|
3
5
|
import { useFileStore } from "../../stores/file-store.js";
|
|
6
|
+
import { singleKey } from "../../lib/single-key.js";
|
|
7
|
+
import { useUIStore } from "../../stores/ui-store.js";
|
|
4
8
|
import { useDeferredUnmount } from "../../hooks/use-deferred-unmount.js";
|
|
9
|
+
import { useMediaQuery } from "../../hooks/use-media-query.js";
|
|
10
|
+
import { splitFrontmatter } from "../../lib/frontmatter.js";
|
|
5
11
|
import { cn } from "../../lib/utils.js";
|
|
12
|
+
import { formatSize } from "./file-viewer-frame.js";
|
|
13
|
+
import { DisabledToggleRow } from "../graph/graph-form.js";
|
|
14
|
+
import { STALE_AFTER_DAYS, ageInDays, formatAge } from "./staleness.js";
|
|
6
15
|
|
|
7
16
|
/** Matches the `duration-300` slide-out below. */
|
|
8
17
|
const SLIDE_OUT_MS = 300;
|
|
9
18
|
|
|
19
|
+
/**
|
|
20
|
+
* The `laptop:` breakpoint from `theme.css`. From here up the rail is
|
|
21
|
+
* expanded and the design's D3 draws Files as panes beside it; below, the
|
|
22
|
+
* drawer. Read as a media query rather than a class pair so only one of the
|
|
23
|
+
* two shapes is mounted — two would mean two file trees on the store.
|
|
24
|
+
*/
|
|
25
|
+
const PANES_QUERY = "(min-width: 900px)";
|
|
26
|
+
|
|
10
27
|
/**
|
|
11
28
|
* The tree and the viewers load the first time the panel is opened. Together
|
|
12
29
|
* they carry the markdown, HTML, image and PDF viewers, none of which the chat
|
|
@@ -20,6 +37,7 @@ export function FilePanel({ open, onClose }: { open: boolean; onClose: () => voi
|
|
|
20
37
|
const treeExpanded = useFileStore((s) => s.treeExpanded);
|
|
21
38
|
const setTreeExpanded = useFileStore((s) => s.setTreeExpanded);
|
|
22
39
|
const closeFile = useFileStore((s) => s.closeFile);
|
|
40
|
+
const panes = useMediaQuery(PANES_QUERY);
|
|
23
41
|
|
|
24
42
|
useEffect(() => {
|
|
25
43
|
if (!open) return;
|
|
@@ -55,6 +73,10 @@ export function FilePanel({ open, onClose }: { open: boolean; onClose: () => voi
|
|
|
55
73
|
const showContent = useDeferredUnmount(open, SLIDE_OUT_MS);
|
|
56
74
|
const showTree = showContent && (!currentPath || treeExpanded);
|
|
57
75
|
|
|
76
|
+
if (panes) {
|
|
77
|
+
return open ? <FilePanes onClose={onClose} /> : null;
|
|
78
|
+
}
|
|
79
|
+
|
|
58
80
|
return (
|
|
59
81
|
<>
|
|
60
82
|
{open && (
|
|
@@ -131,3 +153,149 @@ export function FilePanel({ open, onClose }: { open: boolean; onClose: () => voi
|
|
|
131
153
|
</>
|
|
132
154
|
);
|
|
133
155
|
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* D3 (the fifth design drop): from `laptop:` up Files is
|
|
159
|
+
* not a drawer but a layer of panes over the content area, beside the rail —
|
|
160
|
+
* a 300px tree, the reading pane at a 720px measure, and from `wide:` a
|
|
161
|
+
* 320px evidence rail. No backdrop: the rail stays reachable, and the layer
|
|
162
|
+
* is the app's own surface, not a sheet over it. The host still composes
|
|
163
|
+
* views, so this remains the same `FilePanel` the drawer is; only the shape
|
|
164
|
+
* changes with the width.
|
|
165
|
+
*
|
|
166
|
+
* The tree's title carries no document count: the file store has no total,
|
|
167
|
+
* and the design's `4,812 docs` is not something to make up.
|
|
168
|
+
*
|
|
169
|
+
* The footer prints the keys that fire. `j` / `k` are single-key letters
|
|
170
|
+
* and go with the Settings off switch (D37 — a key that does not fire is
|
|
171
|
+
* not advertised); `← →` and `⏎` are not letters, the switch does not
|
|
172
|
+
* cover them, and the kit `FileRow` binds them regardless — so they print
|
|
173
|
+
* regardless. `FileRow` already moves focus with ↑↓ and Home/End on its
|
|
174
|
+
* own, so nothing here binds movement a second time.
|
|
175
|
+
*
|
|
176
|
+
* The evidence rail (sixth pass §3a): each block is independent and simply
|
|
177
|
+
* absent when its data does not exist, but the COLUMN stays — "a pane count
|
|
178
|
+
* that changes as you click through files is a worse defect than a sparse
|
|
179
|
+
* rail." So the rail mounts with the panes, empty until a file is open, and
|
|
180
|
+
* a file with no frontmatter shows only the blocks it has.
|
|
181
|
+
*/
|
|
182
|
+
function FilePanes({ onClose }: { onClose: () => void }) {
|
|
183
|
+
const currentPath = useFileStore((s) => s.currentPath);
|
|
184
|
+
const content = useFileStore((s) => s.currentContent);
|
|
185
|
+
const singleKeyShortcuts = useUIStore((s) => s.singleKeyShortcuts);
|
|
186
|
+
const loaded = content !== null && content.path === currentPath ? content : null;
|
|
187
|
+
|
|
188
|
+
const frontmatter: ReceiptRow[] =
|
|
189
|
+
loaded?.kind === "markdown"
|
|
190
|
+
? splitFrontmatter(loaded.content ?? "").fields.map((f) => ({
|
|
191
|
+
k: f.key,
|
|
192
|
+
v: f.list ? f.list.join(", ") : f.value || "—",
|
|
193
|
+
}))
|
|
194
|
+
: [];
|
|
195
|
+
|
|
196
|
+
// Stale (sixth pass §3b): `mtime` is on every file the server serves, in
|
|
197
|
+
// milliseconds; the threshold is `STALE_AFTER_DAYS`. Past it the block
|
|
198
|
+
// turns gold — the same tone the tree's dot wears.
|
|
199
|
+
const modified = loaded ? ageInDays(loaded.mtime) : null;
|
|
200
|
+
const stale = modified !== null && modified >= STALE_AFTER_DAYS;
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<div
|
|
204
|
+
role="dialog"
|
|
205
|
+
aria-label="Files"
|
|
206
|
+
className="fixed bottom-0 right-0 top-0 z-40 flex bg-surface tablet:left-[60px] laptop:left-[208px]"
|
|
207
|
+
>
|
|
208
|
+
{/* Tree */}
|
|
209
|
+
<aside className="flex w-[300px] shrink-0 flex-col border-r border-border">
|
|
210
|
+
<div className="shrink-0 px-4 pb-2 pt-4">
|
|
211
|
+
<h2 className="font-[family-name:var(--font-display)] text-[22px] leading-tight text-foreground">Files</h2>
|
|
212
|
+
</div>
|
|
213
|
+
{/* Untrusted only (sixth pass §3b): needs the provenance record —
|
|
214
|
+
origin, who, when — which no file carries yet. Drawn, disabled,
|
|
215
|
+
with its reason, never dropped: it is one of the two facts that
|
|
216
|
+
decide whether an answer may cite a file. */}
|
|
217
|
+
<div className="shrink-0 border-b border-border">
|
|
218
|
+
<DisabledToggleRow label="Untrusted only" reason="needs provenance" tone="purple" last />
|
|
219
|
+
</div>
|
|
220
|
+
{/* `j` / `k` move between tree items while one holds focus (D36:
|
|
221
|
+
focus-scoped, printed where they apply); the kit `FileRow` owns
|
|
222
|
+
↑↓, Home, End and the ← → fold. */}
|
|
223
|
+
<div
|
|
224
|
+
className="min-h-0 flex-1 overflow-y-auto"
|
|
225
|
+
onKeyDown={(e) => {
|
|
226
|
+
if (!singleKeyShortcuts) return;
|
|
227
|
+
const key = singleKey(e);
|
|
228
|
+
if (key !== "j" && key !== "k") return;
|
|
229
|
+
const items = [...e.currentTarget.querySelectorAll<HTMLElement>('[role="treeitem"]')];
|
|
230
|
+
const here = items.indexOf(e.target as HTMLElement);
|
|
231
|
+
if (here === -1) return;
|
|
232
|
+
e.preventDefault();
|
|
233
|
+
items[(here + (key === "j" ? 1 : -1) + items.length) % items.length]?.focus();
|
|
234
|
+
}}
|
|
235
|
+
>
|
|
236
|
+
<Suspense fallback={null}>
|
|
237
|
+
<FileTree />
|
|
238
|
+
</Suspense>
|
|
239
|
+
</div>
|
|
240
|
+
<div className="shrink-0 border-t border-border px-4 py-2 font-[family-name:var(--font-mono)] text-[10px] text-muted-foreground">
|
|
241
|
+
{singleKeyShortcuts ? "j / k move · " : ""}← → fold · ⏎ open
|
|
242
|
+
</div>
|
|
243
|
+
</aside>
|
|
244
|
+
|
|
245
|
+
{/* Reading pane */}
|
|
246
|
+
<section className="flex min-w-0 flex-1 flex-col" aria-label={currentPath ?? "No file open"}>
|
|
247
|
+
<div className="flex shrink-0 items-start border-b border-border pr-3">
|
|
248
|
+
<div className="min-w-0 flex-1">
|
|
249
|
+
<ScreenHeader
|
|
250
|
+
variant="nav"
|
|
251
|
+
title={currentPath ?? "Files"}
|
|
252
|
+
subtitle={loaded ? formatSize(loaded.size) : undefined}
|
|
253
|
+
back={false}
|
|
254
|
+
divider={false}
|
|
255
|
+
/>
|
|
256
|
+
</div>
|
|
257
|
+
<div className="shrink-0 pt-2">
|
|
258
|
+
<Button label="Close" icon="dismiss" tone="ghost" size="sm" block={false} onClick={onClose} />
|
|
259
|
+
</div>
|
|
260
|
+
</div>
|
|
261
|
+
<div className="min-h-0 flex-1 overflow-hidden">
|
|
262
|
+
<div className="mx-auto h-full w-full max-w-[720px]">
|
|
263
|
+
<Suspense fallback={null}>
|
|
264
|
+
<FileViewer />
|
|
265
|
+
</Suspense>
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
</section>
|
|
269
|
+
|
|
270
|
+
{/* Evidence rail, from `wide:` only (the four-pane rule, D37 §2).
|
|
271
|
+
Always in the tree once the panes are: the column never collapses. */}
|
|
272
|
+
<aside
|
|
273
|
+
aria-label="Evidence"
|
|
274
|
+
className="hidden w-[320px] shrink-0 flex-col gap-4 overflow-y-auto border-l border-border bg-background px-4 py-4 wide:flex"
|
|
275
|
+
>
|
|
276
|
+
{frontmatter.length > 0 && (
|
|
277
|
+
<div className="flex flex-col gap-2" data-rail-block="frontmatter">
|
|
278
|
+
<Label text="Frontmatter" icon="scope" meta={`${frontmatter.length} ${frontmatter.length === 1 ? "key" : "keys"}`} />
|
|
279
|
+
<Receipt rows={frontmatter} keyWidth={72} />
|
|
280
|
+
</div>
|
|
281
|
+
)}
|
|
282
|
+
{modified !== null && (
|
|
283
|
+
<div className="flex flex-col gap-2" data-rail-block="modified" data-stale={stale ? "" : undefined}>
|
|
284
|
+
<Label text="Modified" icon="history" tone={stale ? "gold" : undefined} meta={stale ? "stale" : undefined} />
|
|
285
|
+
<div
|
|
286
|
+
className={cn(
|
|
287
|
+
"font-[family-name:var(--font-mono)] text-[10px]",
|
|
288
|
+
stale ? "text-[var(--bk-gold-ink)]" : "text-muted-foreground"
|
|
289
|
+
)}
|
|
290
|
+
>
|
|
291
|
+
modified {formatAge(modified)} · {stale ? "stale past" : "stale after"} {STALE_AFTER_DAYS}
|
|
292
|
+
</div>
|
|
293
|
+
</div>
|
|
294
|
+
)}
|
|
295
|
+
{/* The design also draws "Linked from" (backlinks) and "Provenance"
|
|
296
|
+
(git hash, host, date) here. The app has no API for either yet,
|
|
297
|
+
so neither is drawn: an evidence rail shows what is known. */}
|
|
298
|
+
</aside>
|
|
299
|
+
</div>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { FileRow, Placeholder } from "@schlessera/brain-ui-kit";
|
|
2
|
+
import type { FileKind } from "@schlessera/brain-ui-kit";
|
|
3
|
+
import { useEffect, useRef, type ReactNode } from "react";
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The file tree's rows, rendered from props (S7, the `files` directory). The
|
|
8
|
+
* design's `1e` screen draws the tree out of the kit's `FileRow` — folder,
|
|
9
|
+
* open folder, file, image — so that is what a row is here. `FileTree` is
|
|
10
|
+
* the container: it subscribes each node to the file store and decides
|
|
11
|
+
* expansion, loading, errors and the active path; these views decide how
|
|
12
|
+
* that looks.
|
|
13
|
+
*
|
|
14
|
+
* `TreeRow` is ONE row. The container renders it recursively so each node
|
|
15
|
+
* keeps its own store subscription (a change deep in one folder re-renders
|
|
16
|
+
* that row, not the tree); the children arrive as `children` already
|
|
17
|
+
* rendered. A highlighted row (the tree was asked to reveal this folder)
|
|
18
|
+
* scrolls itself into view and reports when the flash has run, so the
|
|
19
|
+
* container can clear the request.
|
|
20
|
+
*/
|
|
21
|
+
const IMAGE_EXT = new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".avif", ".bmp", ".ico"]);
|
|
22
|
+
|
|
23
|
+
export function fileKind(name: string, isDir: boolean, expanded: boolean): FileKind {
|
|
24
|
+
if (isDir) return expanded ? "open" : "folder";
|
|
25
|
+
const i = name.lastIndexOf(".");
|
|
26
|
+
const ext = i >= 0 ? name.slice(i).toLowerCase() : "";
|
|
27
|
+
return IMAGE_EXT.has(ext) ? "image" : "file";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface TreeRowProps {
|
|
31
|
+
name: string;
|
|
32
|
+
kind: FileKind;
|
|
33
|
+
depth: number;
|
|
34
|
+
/** The row the viewer is on. */
|
|
35
|
+
active: boolean;
|
|
36
|
+
/** A folder whose listing is in flight. */
|
|
37
|
+
loading: boolean;
|
|
38
|
+
/** The tree was asked to reveal this folder: flash it, scroll it into view. */
|
|
39
|
+
highlighted: boolean;
|
|
40
|
+
/** A folder's listing failed; shown under the row with a retry. */
|
|
41
|
+
error?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Days since the file was modified, given only when past the staleness
|
|
44
|
+
* threshold (`staleness.ts`). D3 draws it as the gold left-edge dot and
|
|
45
|
+
* the mono `stale 38d` meta, the same two marks the design's `1e` screen
|
|
46
|
+
* uses; the container decides from `mtime`, the row only prints.
|
|
47
|
+
*/
|
|
48
|
+
staleDays?: number;
|
|
49
|
+
children?: ReactNode;
|
|
50
|
+
onClick: () => void;
|
|
51
|
+
onRetry?: () => void;
|
|
52
|
+
onHighlightShown?: () => void;
|
|
53
|
+
/**
|
|
54
|
+
* The kit `FileRow` binds → on a closed folder to `onFold(true)` and ← on
|
|
55
|
+
* an open one to `onFold(false)` (sixth pass §8: the ARIA tree pattern
|
|
56
|
+
* requires them, and the footer prints them). Folders only.
|
|
57
|
+
*/
|
|
58
|
+
onFold?: (open: boolean) => void;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** How long the reveal flash runs before the request is cleared. */
|
|
62
|
+
export const HIGHLIGHT_MS = 1800;
|
|
63
|
+
|
|
64
|
+
export function TreeRow(p: TreeRowProps) {
|
|
65
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
66
|
+
const { highlighted, onHighlightShown } = p;
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (!highlighted || !ref.current) return;
|
|
69
|
+
ref.current.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
70
|
+
const t = setTimeout(() => onHighlightShown?.(), HIGHLIGHT_MS);
|
|
71
|
+
return () => clearTimeout(t);
|
|
72
|
+
}, [highlighted, onHighlightShown]);
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<li>
|
|
76
|
+
<div ref={ref} className={cn(highlighted && "brain-tree-highlight")}>
|
|
77
|
+
<FileRow
|
|
78
|
+
label={p.name}
|
|
79
|
+
kind={p.kind}
|
|
80
|
+
depth={p.depth}
|
|
81
|
+
active={p.active}
|
|
82
|
+
meta={p.loading ? "loading…" : p.staleDays !== undefined ? `stale ${p.staleDays}d` : undefined}
|
|
83
|
+
metaTone={!p.loading && p.staleDays !== undefined ? "gold" : undefined}
|
|
84
|
+
flag={p.staleDays !== undefined ? "gold" : undefined}
|
|
85
|
+
onClick={p.onClick}
|
|
86
|
+
onFold={p.onFold}
|
|
87
|
+
/>
|
|
88
|
+
</div>
|
|
89
|
+
{p.error ? (
|
|
90
|
+
<div style={{ paddingLeft: 8 + (p.depth + 1) * 22 }} className="py-1 pr-2">
|
|
91
|
+
<FileRow view="error" stateMessage="Folder unreadable" stateDetail={p.error} stateAction="Retry" onStateAction={p.onRetry} />
|
|
92
|
+
</div>
|
|
93
|
+
) : null}
|
|
94
|
+
{p.children ? <ul>{p.children}</ul> : null}
|
|
95
|
+
</li>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface FileTreeViewProps {
|
|
100
|
+
/** The root listing: `loading` before it arrives, `error` when it failed, `ready` with rows. */
|
|
101
|
+
state: "loading" | "error" | "ready";
|
|
102
|
+
error?: string;
|
|
103
|
+
children?: ReactNode;
|
|
104
|
+
onRetry?: () => void;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function FileTreeView(p: FileTreeViewProps) {
|
|
108
|
+
if (p.state === "error") {
|
|
109
|
+
return (
|
|
110
|
+
<div className="px-3 py-2">
|
|
111
|
+
<Placeholder variant="error" message="Files unreadable" detail={p.error} actionLabel="Retry" onAction={p.onRetry} />
|
|
112
|
+
</div>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (p.state === "loading") {
|
|
116
|
+
return (
|
|
117
|
+
<div className="px-3 py-2" aria-label="Loading files">
|
|
118
|
+
<Placeholder variant="loading" lines={4} bordered={false} pad={4} />
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
return (
|
|
123
|
+
<ul className="py-1 text-sm" role="tree">
|
|
124
|
+
{p.children}
|
|
125
|
+
</ul>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
@@ -1,21 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ChevronRight, Folder, FolderOpen, FileText, FileCode, FileImage, File as FileIcon, Loader2, AlertCircle } from "lucide-react";
|
|
1
|
+
import { useCallback, useEffect } from "react";
|
|
3
2
|
import { useFileStore } from "../../stores/file-store.js";
|
|
4
3
|
import type { FileEntry } from "@schlessera/brain-ui-sdk/protocol";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
const IMAGE_EXT = new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".avif", ".bmp", ".ico"]);
|
|
8
|
-
const CODE_EXT = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".rb", ".go", ".rs", ".java", ".sh", ".bash", ".css", ".html", ".json", ".yaml", ".yml", ".toml", ".sql"]);
|
|
9
|
-
|
|
10
|
-
function iconForFile(name: string) {
|
|
11
|
-
const i = name.lastIndexOf(".");
|
|
12
|
-
const ext = i >= 0 ? name.slice(i).toLowerCase() : "";
|
|
13
|
-
if (ext === ".md" || ext === ".markdown" || ext === ".txt") return FileText;
|
|
14
|
-
if (IMAGE_EXT.has(ext)) return FileImage;
|
|
15
|
-
if (CODE_EXT.has(ext)) return FileCode;
|
|
16
|
-
return FileIcon;
|
|
17
|
-
}
|
|
4
|
+
import { FileTreeView, TreeRow, fileKind } from "./file-tree-view.js";
|
|
5
|
+
import { ageInDays, isStale } from "./staleness.js";
|
|
18
6
|
|
|
7
|
+
/**
|
|
8
|
+
* The container (S7): every node subscribes to the file store for its own
|
|
9
|
+
* expansion, loading, error, active and highlight state, and renders a
|
|
10
|
+
* `TreeRow` with its children rendered the same way. The store owns the
|
|
11
|
+
* directory cache and the requests; the rows own nothing.
|
|
12
|
+
*/
|
|
19
13
|
export function FileTree() {
|
|
20
14
|
const loadDir = useFileStore((s) => s.loadDir);
|
|
21
15
|
const dirCache = useFileStore((s) => s.dirCache);
|
|
@@ -29,115 +23,67 @@ export function FileTree() {
|
|
|
29
23
|
|
|
30
24
|
const rootEntries = dirCache[""];
|
|
31
25
|
const rootError = dirErrors[""];
|
|
32
|
-
|
|
33
|
-
if (rootError) {
|
|
34
|
-
return (
|
|
35
|
-
<div className="flex items-start gap-2 px-4 py-3 text-xs text-destructive">
|
|
36
|
-
<AlertCircle className="h-4 w-4 shrink-0" />
|
|
37
|
-
<span>{rootError}</span>
|
|
38
|
-
</div>
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (!rootEntries) {
|
|
43
|
-
return (
|
|
44
|
-
<div className="flex items-center gap-2 px-4 py-3 text-xs text-muted-foreground">
|
|
45
|
-
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
|
46
|
-
Loading files...
|
|
47
|
-
</div>
|
|
48
|
-
);
|
|
49
|
-
}
|
|
26
|
+
const retryRoot = useCallback(() => void loadDir(""), [loadDir]);
|
|
50
27
|
|
|
51
28
|
return (
|
|
52
|
-
<
|
|
53
|
-
{rootEntries
|
|
29
|
+
<FileTreeView state={rootError ? "error" : rootEntries ? "ready" : "loading"} error={rootError} onRetry={retryRoot}>
|
|
30
|
+
{rootEntries?.map((entry) => (
|
|
54
31
|
<TreeNode key={entry.path} entry={entry} depth={0} />
|
|
55
32
|
))}
|
|
56
|
-
</
|
|
33
|
+
</FileTreeView>
|
|
57
34
|
);
|
|
58
35
|
}
|
|
59
36
|
|
|
60
37
|
function TreeNode({ entry, depth }: { entry: FileEntry; depth: number }) {
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
const
|
|
38
|
+
const isDir = entry.type === "dir";
|
|
39
|
+
const expanded = useFileStore((s) => isDir && s.expandedDirs.has(entry.path));
|
|
40
|
+
const loading = useFileStore((s) => isDir && s.loadingDirs.has(entry.path));
|
|
41
|
+
const childEntries = useFileStore((s) => (isDir ? s.dirCache[entry.path] : undefined));
|
|
42
|
+
const childError = useFileStore((s) => (isDir ? s.dirErrors[entry.path] : undefined));
|
|
65
43
|
const toggleDir = useFileStore((s) => s.toggleDir);
|
|
44
|
+
const loadDir = useFileStore((s) => s.loadDir);
|
|
66
45
|
const openFile = useFileStore((s) => s.openFile);
|
|
67
46
|
const isActive = useFileStore((s) => s.currentPath === entry.path);
|
|
68
|
-
const highlighted = useFileStore(
|
|
69
|
-
(s) => entry.type === "dir" && s.highlightedDir === entry.path
|
|
70
|
-
);
|
|
47
|
+
const highlighted = useFileStore((s) => isDir && s.highlightedDir === entry.path);
|
|
71
48
|
const setHighlightedDir = useFileStore((s) => s.setHighlightedDir);
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
if (!highlighted || !dirBtnRef.current) return;
|
|
76
|
-
dirBtnRef.current.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
77
|
-
const t = setTimeout(() => setHighlightedDir(null), 1800);
|
|
78
|
-
return () => clearTimeout(t);
|
|
79
|
-
}, [highlighted, setHighlightedDir]);
|
|
49
|
+
const clearHighlight = useCallback(() => setHighlightedDir(null), [setHighlightedDir]);
|
|
80
50
|
|
|
81
|
-
|
|
51
|
+
// Staleness is a fact about a FILE's content. A directory's mtime moves
|
|
52
|
+
// when an entry is added or removed, not when a note inside it changes,
|
|
53
|
+
// so a folder gets no dot: the design's gold folder (`context · stale
|
|
54
|
+
// 38d`) needs the newest child's mtime, which the tree only knows once
|
|
55
|
+
// that folder has been opened. The server sends `mtime` per entry; an
|
|
56
|
+
// older one without it draws nothing rather than guessing.
|
|
57
|
+
const staleDays =
|
|
58
|
+
!isDir && entry.mtime !== undefined && isStale(entry.mtime) ? ageInDays(entry.mtime) : undefined;
|
|
82
59
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
highlighted && "brain-tree-highlight"
|
|
92
|
-
)}
|
|
93
|
-
style={indent}
|
|
94
|
-
aria-expanded={expanded}
|
|
95
|
-
>
|
|
96
|
-
<ChevronRight
|
|
97
|
-
className={cn(
|
|
98
|
-
"h-3 w-3 shrink-0 text-muted-foreground transition-transform",
|
|
99
|
-
expanded && "rotate-90"
|
|
100
|
-
)}
|
|
101
|
-
/>
|
|
102
|
-
{expanded ? (
|
|
103
|
-
<FolderOpen className="h-4 w-4 shrink-0 text-primary/80" />
|
|
104
|
-
) : (
|
|
105
|
-
<Folder className="h-4 w-4 shrink-0 text-muted-foreground" />
|
|
106
|
-
)}
|
|
107
|
-
<span className="truncate">{entry.name}</span>
|
|
108
|
-
{loading && <Loader2 className="ml-auto h-3 w-3 animate-spin text-muted-foreground" />}
|
|
109
|
-
</button>
|
|
110
|
-
{expanded && (
|
|
111
|
-
<ul>
|
|
112
|
-
{childError && (
|
|
113
|
-
<li className="flex items-center gap-1.5 px-2 py-1 text-xs text-destructive" style={{ paddingLeft: (depth + 1) * 14 + 8 }}>
|
|
114
|
-
<AlertCircle className="h-3 w-3" /> {childError}
|
|
115
|
-
</li>
|
|
116
|
-
)}
|
|
117
|
-
{childEntries?.map((child) => (
|
|
118
|
-
<TreeNode key={child.path} entry={child} depth={depth + 1} />
|
|
119
|
-
))}
|
|
120
|
-
</ul>
|
|
121
|
-
)}
|
|
122
|
-
</li>
|
|
123
|
-
);
|
|
124
|
-
}
|
|
60
|
+
// ← / → fold (sixth pass §8). The kit only calls `onFold(true)` on a closed
|
|
61
|
+
// folder and `onFold(false)` on an open one, but the guard keeps the store
|
|
62
|
+
// honest if a stale `kind` and the key disagree for a frame.
|
|
63
|
+
const fold = isDir
|
|
64
|
+
? (open: boolean) => {
|
|
65
|
+
if (open !== expanded) void toggleDir(entry.path);
|
|
66
|
+
}
|
|
67
|
+
: undefined;
|
|
125
68
|
|
|
126
|
-
const Icon = iconForFile(entry.name);
|
|
127
69
|
return (
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
70
|
+
<TreeRow
|
|
71
|
+
name={entry.name}
|
|
72
|
+
kind={fileKind(entry.name, isDir, expanded)}
|
|
73
|
+
depth={depth}
|
|
74
|
+
active={isActive}
|
|
75
|
+
loading={loading}
|
|
76
|
+
highlighted={highlighted}
|
|
77
|
+
error={expanded ? childError : undefined}
|
|
78
|
+
staleDays={staleDays}
|
|
79
|
+
onClick={() => void (isDir ? toggleDir(entry.path) : openFile(entry.path))}
|
|
80
|
+
onRetry={() => void loadDir(entry.path)}
|
|
81
|
+
onHighlightShown={clearHighlight}
|
|
82
|
+
onFold={fold}
|
|
83
|
+
>
|
|
84
|
+
{expanded && childEntries?.length
|
|
85
|
+
? childEntries.map((child) => <TreeNode key={child.path} entry={child} depth={depth + 1} />)
|
|
86
|
+
: undefined}
|
|
87
|
+
</TreeRow>
|
|
142
88
|
);
|
|
143
89
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { FileWarning, Download } from "lucide-react";
|
|
2
2
|
import type { FileContentResponse } from "@schlessera/brain-ui-sdk/protocol";
|
|
3
|
-
import {
|
|
3
|
+
import { useBrainUiRoot } from "../../root-context.js";
|
|
4
4
|
import { ZoomableImage } from "../images/zoomable-image.js";
|
|
5
5
|
|
|
6
6
|
export function FileViewerBinary({ content }: { content: FileContentResponse }) {
|
|
7
|
+
const root = useBrainUiRoot();
|
|
7
8
|
const isImage = content.mime?.startsWith("image/");
|
|
8
|
-
const rawUrl = `${apiBase()}/files/content?path=${encodeURIComponent(content.path)}&raw=1`;
|
|
9
|
+
const rawUrl = `${root.apiBase()}/files/content?path=${encodeURIComponent(content.path)}&raw=1`;
|
|
9
10
|
|
|
10
11
|
if (isImage) {
|
|
11
12
|
const filename = content.path.split("/").pop() ?? content.path;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { Callout, EmptyState, FilterRow, Placeholder } from "@schlessera/brain-ui-kit";
|
|
2
|
+
import { Check, Copy, FolderOpen } from "lucide-react";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The viewer's chrome, rendered from props (S7): the toolbar over the file,
|
|
7
|
+
* and the three states the body can be in before there is a file to draw.
|
|
8
|
+
* `FileViewer` is the container — it reads the store, builds the share
|
|
9
|
+
* options (which need the root) and chooses the body renderer; this owns
|
|
10
|
+
* how the frame looks.
|
|
11
|
+
*
|
|
12
|
+
* The Preview / Raw switch is the kit's `FilterRow`: two pills, one
|
|
13
|
+
* selected, activation following focus, which is what a mode switch is.
|
|
14
|
+
* The reveal and copy controls stay native icon buttons (titled; the kit
|
|
15
|
+
* has no icon-only button) and the share menu arrives rendered.
|
|
16
|
+
*/
|
|
17
|
+
export type ViewMode = "preview" | "raw";
|
|
18
|
+
|
|
19
|
+
export interface ViewerToolbarProps {
|
|
20
|
+
fileName: string;
|
|
21
|
+
fullPath: string;
|
|
22
|
+
size?: number;
|
|
23
|
+
mode: ViewMode;
|
|
24
|
+
/** Only markdown, HTML and standalone diagrams have a preview to switch to. */
|
|
25
|
+
previewAvailable: boolean;
|
|
26
|
+
copied: boolean;
|
|
27
|
+
/** The share menu, already built by the container; null when nothing shares. */
|
|
28
|
+
share: ReactNode;
|
|
29
|
+
onMode: (mode: ViewMode) => void;
|
|
30
|
+
onCopyPath: () => void;
|
|
31
|
+
onReveal: () => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function ViewerToolbar(p: ViewerToolbarProps) {
|
|
35
|
+
return (
|
|
36
|
+
<div className="flex items-center gap-2 border-b border-border bg-surface px-4 py-2">
|
|
37
|
+
<button
|
|
38
|
+
type="button"
|
|
39
|
+
onClick={p.onReveal}
|
|
40
|
+
title="Reveal in tree"
|
|
41
|
+
className="rounded p-1 text-muted-foreground transition-colors hover:bg-surface-raised hover:text-foreground"
|
|
42
|
+
>
|
|
43
|
+
<FolderOpen className="h-3.5 w-3.5" />
|
|
44
|
+
</button>
|
|
45
|
+
<div className="min-w-0 flex-1">
|
|
46
|
+
<div className="truncate text-sm font-medium text-foreground" title={p.fullPath}>
|
|
47
|
+
{p.fileName}
|
|
48
|
+
</div>
|
|
49
|
+
<div className="truncate text-[10px] text-muted-foreground" title={p.fullPath}>
|
|
50
|
+
{p.fullPath}
|
|
51
|
+
{p.size !== undefined && <span className="ml-2">· {formatSize(p.size)}</span>}
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<button
|
|
55
|
+
type="button"
|
|
56
|
+
onClick={p.onCopyPath}
|
|
57
|
+
title="Copy path"
|
|
58
|
+
className="rounded p-1.5 text-muted-foreground transition-colors hover:bg-surface-raised hover:text-foreground"
|
|
59
|
+
>
|
|
60
|
+
{p.copied ? <Check className="h-3.5 w-3.5" /> : <Copy className="h-3.5 w-3.5" />}
|
|
61
|
+
</button>
|
|
62
|
+
{p.share}
|
|
63
|
+
{p.previewAvailable && (
|
|
64
|
+
<div className="w-auto shrink-0">
|
|
65
|
+
<FilterRow
|
|
66
|
+
items={[
|
|
67
|
+
{ label: "Preview", onClick: () => p.onMode("preview") },
|
|
68
|
+
{ label: "Raw", onClick: () => p.onMode("raw") },
|
|
69
|
+
]}
|
|
70
|
+
active={p.mode === "preview" ? 0 : 1}
|
|
71
|
+
mono={false}
|
|
72
|
+
/>
|
|
73
|
+
</div>
|
|
74
|
+
)}
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function ViewerLoading() {
|
|
80
|
+
return (
|
|
81
|
+
<div className="px-6 py-6" aria-label="Loading file">
|
|
82
|
+
<Placeholder variant="loading" lines={5} bordered={false} pad={0} />
|
|
83
|
+
</div>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function ViewerError({ message }: { message: string }) {
|
|
88
|
+
return (
|
|
89
|
+
<div className="m-4" role="alert">
|
|
90
|
+
<Callout tone="red" variant="banner" icon="failed" mono text={message} />
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function ViewerEmpty() {
|
|
96
|
+
return (
|
|
97
|
+
<EmptyState
|
|
98
|
+
variant="no-results"
|
|
99
|
+
icon="folder"
|
|
100
|
+
tone="neutral"
|
|
101
|
+
title="No file open"
|
|
102
|
+
body="Select a file from the tree to view it."
|
|
103
|
+
meta=""
|
|
104
|
+
minHeight={240}
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function formatSize(bytes: number): string {
|
|
110
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
111
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
112
|
+
return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
|
|
113
|
+
}
|