@flanksource/clicky-ui 0.2.19 → 0.2.21
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/dist/ai.cjs +26 -0
- package/dist/ai.cjs.map +1 -0
- package/dist/ai.d.ts +2 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +26 -0
- package/dist/ai.js.map +1 -0
- package/dist/chat.cjs +7 -0
- package/dist/chat.cjs.map +1 -1
- package/dist/chat.js +7 -0
- package/dist/chat.js.map +1 -1
- package/dist/components/FilterBar.cjs +49 -18
- package/dist/components/FilterBar.cjs.map +1 -1
- package/dist/components/FilterBar.d.ts +0 -2
- package/dist/components/FilterBar.d.ts.map +1 -1
- package/dist/components/FilterBar.js +50 -19
- package/dist/components/FilterBar.js.map +1 -1
- package/dist/components/SearchInput.cjs +63 -0
- package/dist/components/SearchInput.cjs.map +1 -0
- package/dist/components/SearchInput.d.ts +31 -0
- package/dist/components/SearchInput.d.ts.map +1 -0
- package/dist/components/SearchInput.js +63 -0
- package/dist/components/SearchInput.js.map +1 -0
- package/dist/components/SegmentedControl.cjs +88 -0
- package/dist/components/SegmentedControl.cjs.map +1 -0
- package/dist/components/SegmentedControl.d.ts +38 -0
- package/dist/components/SegmentedControl.d.ts.map +1 -0
- package/dist/components/SegmentedControl.js +88 -0
- package/dist/components/SegmentedControl.js.map +1 -0
- package/dist/components/Switch.cjs +51 -0
- package/dist/components/Switch.cjs.map +1 -0
- package/dist/components/Switch.d.ts +23 -0
- package/dist/components/Switch.d.ts.map +1 -0
- package/dist/components/Switch.js +51 -0
- package/dist/components/Switch.js.map +1 -0
- package/dist/components/TimeRange.cjs +53 -45
- package/dist/components/TimeRange.cjs.map +1 -1
- package/dist/components/TimeRange.d.ts.map +1 -1
- package/dist/components/TimeRange.js +53 -45
- package/dist/components/TimeRange.js.map +1 -1
- package/dist/components/TreePickerField.cjs +5 -1
- package/dist/components/TreePickerField.cjs.map +1 -1
- package/dist/components/TreePickerField.d.ts.map +1 -1
- package/dist/components/TreePickerField.js +5 -1
- package/dist/components/TreePickerField.js.map +1 -1
- package/dist/components/filter-bar-utils.cjs +5 -0
- package/dist/components/filter-bar-utils.cjs.map +1 -1
- package/dist/components/filter-bar-utils.d.ts +2 -0
- package/dist/components/filter-bar-utils.d.ts.map +1 -1
- package/dist/components/filter-bar-utils.js +5 -0
- package/dist/components/filter-bar-utils.js.map +1 -1
- package/dist/components/json-schema-form-fields.cjs +8 -2
- package/dist/components/json-schema-form-fields.cjs.map +1 -1
- package/dist/components/json-schema-form-fields.d.ts.map +1 -1
- package/dist/components/json-schema-form-fields.js +8 -2
- package/dist/components/json-schema-form-fields.js.map +1 -1
- package/dist/components/json-schema-form-resolve.cjs +1 -1
- package/dist/components/json-schema-form-resolve.cjs.map +1 -1
- package/dist/components/json-schema-form-resolve.js +1 -1
- package/dist/components/json-schema-form-resolve.js.map +1 -1
- package/dist/components.cjs +15 -1
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.ts +8 -1
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +15 -1
- package/dist/components.js.map +1 -1
- package/dist/data/Clicky.cjs +33 -44
- package/dist/data/Clicky.cjs.map +1 -1
- package/dist/data/Clicky.d.ts +0 -9
- package/dist/data/Clicky.d.ts.map +1 -1
- package/dist/data/Clicky.js +31 -42
- package/dist/data/Clicky.js.map +1 -1
- package/dist/data/DataTable.cjs +73 -50
- package/dist/data/DataTable.cjs.map +1 -1
- package/dist/data/DataTable.d.ts +4 -0
- package/dist/data/DataTable.d.ts.map +1 -1
- package/dist/data/DataTable.js +73 -50
- package/dist/data/DataTable.js.map +1 -1
- package/dist/data/Icon.cjs +2 -5
- package/dist/data/Icon.cjs.map +1 -1
- package/dist/data/Icon.d.ts +1 -21
- package/dist/data/Icon.d.ts.map +1 -1
- package/dist/data/Icon.js +3 -6
- package/dist/data/Icon.js.map +1 -1
- package/dist/data/MatrixTable.cjs +4 -4
- package/dist/data/MatrixTable.cjs.map +1 -1
- package/dist/data/MatrixTable.js +4 -4
- package/dist/data/MatrixTable.js.map +1 -1
- package/dist/data/RadialGauge.cjs +76 -0
- package/dist/data/RadialGauge.cjs.map +1 -0
- package/dist/data/RadialGauge.d.ts +24 -0
- package/dist/data/RadialGauge.d.ts.map +1 -0
- package/dist/data/RadialGauge.js +76 -0
- package/dist/data/RadialGauge.js.map +1 -0
- package/dist/data/StatusBreakdown.cjs +0 -4
- package/dist/data/StatusBreakdown.cjs.map +1 -1
- package/dist/data/StatusBreakdown.d.ts +0 -2
- package/dist/data/StatusBreakdown.d.ts.map +1 -1
- package/dist/data/StatusBreakdown.js +1 -5
- package/dist/data/StatusBreakdown.js.map +1 -1
- package/dist/data/Timeline.cjs +61 -0
- package/dist/data/Timeline.cjs.map +1 -0
- package/dist/data/Timeline.d.ts +36 -0
- package/dist/data/Timeline.d.ts.map +1 -0
- package/dist/data/Timeline.js +61 -0
- package/dist/data/Timeline.js.map +1 -0
- package/dist/data/TimeseriesCoreBars.cjs +2 -25
- package/dist/data/TimeseriesCoreBars.cjs.map +1 -1
- package/dist/data/TimeseriesCoreBars.d.ts +0 -19
- package/dist/data/TimeseriesCoreBars.d.ts.map +1 -1
- package/dist/data/TimeseriesCoreBars.js +2 -25
- package/dist/data/TimeseriesCoreBars.js.map +1 -1
- package/dist/data/TimeseriesCoreBars.model.cjs +27 -0
- package/dist/data/TimeseriesCoreBars.model.cjs.map +1 -0
- package/dist/data/TimeseriesCoreBars.model.d.ts +20 -0
- package/dist/data/TimeseriesCoreBars.model.d.ts.map +1 -0
- package/dist/data/TimeseriesCoreBars.model.js +27 -0
- package/dist/data/TimeseriesCoreBars.model.js.map +1 -0
- package/dist/data/TimeseriesPanel.axes.cjs.map +1 -1
- package/dist/data/TimeseriesPanel.axes.d.ts +1 -1
- package/dist/data/TimeseriesPanel.axes.d.ts.map +1 -1
- package/dist/data/TimeseriesPanel.axes.js.map +1 -1
- package/dist/data/TimeseriesPanel.cjs +4 -54
- package/dist/data/TimeseriesPanel.cjs.map +1 -1
- package/dist/data/TimeseriesPanel.d.ts +2 -138
- package/dist/data/TimeseriesPanel.d.ts.map +1 -1
- package/dist/data/TimeseriesPanel.js +2 -52
- package/dist/data/TimeseriesPanel.js.map +1 -1
- package/dist/data/TimeseriesPanel.model.cjs +53 -0
- package/dist/data/TimeseriesPanel.model.cjs.map +1 -0
- package/dist/data/TimeseriesPanel.model.d.ts +88 -0
- package/dist/data/TimeseriesPanel.model.d.ts.map +1 -0
- package/dist/data/TimeseriesPanel.model.js +53 -0
- package/dist/data/TimeseriesPanel.model.js.map +1 -0
- package/dist/data/Tree.cjs +1 -1
- package/dist/data/Tree.cjs.map +1 -1
- package/dist/data/Tree.js +1 -1
- package/dist/data/Tree.js.map +1 -1
- package/dist/data/ai/ChatFab.cjs +29 -0
- package/dist/data/ai/ChatFab.cjs.map +1 -0
- package/dist/data/ai/ChatFab.d.ts +12 -0
- package/dist/data/ai/ChatFab.d.ts.map +1 -0
- package/dist/data/ai/ChatFab.js +29 -0
- package/dist/data/ai/ChatFab.js.map +1 -0
- package/dist/data/ai/ChatWindow.cjs +178 -0
- package/dist/data/ai/ChatWindow.cjs.map +1 -0
- package/dist/data/ai/ChatWindow.d.ts +38 -0
- package/dist/data/ai/ChatWindow.d.ts.map +1 -0
- package/dist/data/ai/ChatWindow.js +156 -0
- package/dist/data/ai/ChatWindow.js.map +1 -0
- package/dist/data/ai/ChatWindowManager.cjs +139 -0
- package/dist/data/ai/ChatWindowManager.cjs.map +1 -0
- package/dist/data/ai/ChatWindowManager.d.ts +12 -0
- package/dist/data/ai/ChatWindowManager.d.ts.map +1 -0
- package/dist/data/ai/ChatWindowManager.js +139 -0
- package/dist/data/ai/ChatWindowManager.js.map +1 -0
- package/dist/data/ai/ContextBadges.cjs +74 -0
- package/dist/data/ai/ContextBadges.cjs.map +1 -0
- package/dist/data/ai/ContextBadges.d.ts +16 -0
- package/dist/data/ai/ContextBadges.d.ts.map +1 -0
- package/dist/data/ai/ContextBadges.js +74 -0
- package/dist/data/ai/ContextBadges.js.map +1 -0
- package/dist/data/ai/ThreadPicker.cjs +148 -0
- package/dist/data/ai/ThreadPicker.cjs.map +1 -0
- package/dist/data/ai/ThreadPicker.d.ts +37 -0
- package/dist/data/ai/ThreadPicker.d.ts.map +1 -0
- package/dist/data/ai/ThreadPicker.js +148 -0
- package/dist/data/ai/ThreadPicker.js.map +1 -0
- package/dist/data/ai/ToolPreferences.cjs +80 -0
- package/dist/data/ai/ToolPreferences.cjs.map +1 -0
- package/dist/data/ai/ToolPreferences.d.ts +19 -0
- package/dist/data/ai/ToolPreferences.d.ts.map +1 -0
- package/dist/data/ai/ToolPreferences.js +80 -0
- package/dist/data/ai/ToolPreferences.js.map +1 -0
- package/dist/data/ai/chat-window-context.cjs +78 -0
- package/dist/data/ai/chat-window-context.cjs.map +1 -0
- package/dist/data/ai/chat-window-context.d.ts +57 -0
- package/dist/data/ai/chat-window-context.d.ts.map +1 -0
- package/dist/data/ai/chat-window-context.js +78 -0
- package/dist/data/ai/chat-window-context.js.map +1 -0
- package/dist/data/ai/context.cjs +43 -0
- package/dist/data/ai/context.cjs.map +1 -0
- package/dist/data/ai/context.d.ts +35 -0
- package/dist/data/ai/context.d.ts.map +1 -0
- package/dist/data/ai/context.js +43 -0
- package/dist/data/ai/context.js.map +1 -0
- package/dist/data/ai/index.d.ts +10 -0
- package/dist/data/ai/index.d.ts.map +1 -0
- package/dist/data/cache-browser/CacheDetailPanel.cjs +15 -0
- package/dist/data/cache-browser/CacheDetailPanel.cjs.map +1 -1
- package/dist/data/cache-browser/CacheDetailPanel.d.ts.map +1 -1
- package/dist/data/cache-browser/CacheDetailPanel.js +15 -0
- package/dist/data/cache-browser/CacheDetailPanel.js.map +1 -1
- package/dist/data/cache-browser/cache-browser.fixtures.d.ts +10 -0
- package/dist/data/cache-browser/cache-browser.fixtures.d.ts.map +1 -0
- package/dist/data/cache-browser/download.cjs +13 -0
- package/dist/data/cache-browser/download.cjs.map +1 -0
- package/dist/data/cache-browser/download.d.ts +3 -0
- package/dist/data/cache-browser/download.d.ts.map +1 -0
- package/dist/data/cache-browser/download.js +13 -0
- package/dist/data/cache-browser/download.js.map +1 -0
- package/dist/data/chat/Chat.cjs +44 -3
- package/dist/data/chat/Chat.cjs.map +1 -1
- package/dist/data/chat/Chat.d.ts +5 -2
- package/dist/data/chat/Chat.d.ts.map +1 -1
- package/dist/data/chat/Chat.fixtures.cjs +86 -0
- package/dist/data/chat/Chat.fixtures.cjs.map +1 -0
- package/dist/data/chat/Chat.fixtures.d.ts +4 -0
- package/dist/data/chat/Chat.fixtures.d.ts.map +1 -1
- package/dist/data/chat/Chat.fixtures.js +86 -0
- package/dist/data/chat/Chat.fixtures.js.map +1 -0
- package/dist/data/chat/Chat.js +45 -4
- package/dist/data/chat/Chat.js.map +1 -1
- package/dist/data/chat/ContextUsage.cjs +99 -0
- package/dist/data/chat/ContextUsage.cjs.map +1 -0
- package/dist/data/chat/ContextUsage.d.ts +19 -0
- package/dist/data/chat/ContextUsage.d.ts.map +1 -0
- package/dist/data/chat/ContextUsage.js +99 -0
- package/dist/data/chat/ContextUsage.js.map +1 -0
- package/dist/data/chat/Conversation.cjs +47 -2
- package/dist/data/chat/Conversation.cjs.map +1 -1
- package/dist/data/chat/Conversation.d.ts +8 -2
- package/dist/data/chat/Conversation.d.ts.map +1 -1
- package/dist/data/chat/Conversation.js +47 -2
- package/dist/data/chat/Conversation.js.map +1 -1
- package/dist/data/chat/ModelSelector.cjs +28 -14
- package/dist/data/chat/ModelSelector.cjs.map +1 -1
- package/dist/data/chat/ModelSelector.d.ts +5 -4
- package/dist/data/chat/ModelSelector.d.ts.map +1 -1
- package/dist/data/chat/ModelSelector.js +28 -14
- package/dist/data/chat/ModelSelector.js.map +1 -1
- package/dist/data/chat/clickyOperationsToTools.cjs +21 -1
- package/dist/data/chat/clickyOperationsToTools.cjs.map +1 -1
- package/dist/data/chat/clickyOperationsToTools.d.ts +5 -4
- package/dist/data/chat/clickyOperationsToTools.d.ts.map +1 -1
- package/dist/data/chat/clickyOperationsToTools.js +21 -1
- package/dist/data/chat/clickyOperationsToTools.js.map +1 -1
- package/dist/data/chat/index.d.ts +4 -1
- package/dist/data/chat/index.d.ts.map +1 -1
- package/dist/data/chat/provider-icons.cjs +15 -0
- package/dist/data/chat/provider-icons.cjs.map +1 -0
- package/dist/data/chat/provider-icons.d.ts +7 -0
- package/dist/data/chat/provider-icons.d.ts.map +1 -0
- package/dist/data/chat/provider-icons.js +15 -0
- package/dist/data/chat/provider-icons.js.map +1 -0
- package/dist/data/chat/types.cjs.map +1 -1
- package/dist/data/chat/types.d.ts +41 -9
- package/dist/data/chat/types.d.ts.map +1 -1
- package/dist/data/chat/types.js.map +1 -1
- package/dist/data/clicky-parse.cjs +42 -0
- package/dist/data/clicky-parse.cjs.map +1 -0
- package/dist/data/clicky-parse.d.ts +11 -0
- package/dist/data/clicky-parse.d.ts.map +1 -0
- package/dist/data/clicky-parse.js +42 -0
- package/dist/data/clicky-parse.js.map +1 -0
- package/dist/data/diagnostics/FrameSourceWindow.cjs +0 -4
- package/dist/data/diagnostics/FrameSourceWindow.cjs.map +1 -1
- package/dist/data/diagnostics/FrameSourceWindow.d.ts +1 -11
- package/dist/data/diagnostics/FrameSourceWindow.d.ts.map +1 -1
- package/dist/data/diagnostics/FrameSourceWindow.js +1 -5
- package/dist/data/diagnostics/FrameSourceWindow.js.map +1 -1
- package/dist/data/diagnostics/FrameSourceWindow.utils.cjs +7 -0
- package/dist/data/diagnostics/FrameSourceWindow.utils.cjs.map +1 -0
- package/dist/data/diagnostics/FrameSourceWindow.utils.d.ts +12 -0
- package/dist/data/diagnostics/FrameSourceWindow.utils.d.ts.map +1 -0
- package/dist/data/diagnostics/FrameSourceWindow.utils.js +7 -0
- package/dist/data/diagnostics/FrameSourceWindow.utils.js.map +1 -0
- package/dist/data/diagnostics/JvmStackTrace.cjs +2 -1
- package/dist/data/diagnostics/JvmStackTrace.cjs.map +1 -1
- package/dist/data/diagnostics/JvmStackTrace.d.ts.map +1 -1
- package/dist/data/diagnostics/JvmStackTrace.js +2 -1
- package/dist/data/diagnostics/JvmStackTrace.js.map +1 -1
- package/dist/data/icon-fallback.cjs +12 -0
- package/dist/data/icon-fallback.cjs.map +1 -0
- package/dist/data/icon-fallback.d.ts +19 -0
- package/dist/data/icon-fallback.d.ts.map +1 -0
- package/dist/data/icon-fallback.js +12 -0
- package/dist/data/icon-fallback.js.map +1 -0
- package/dist/data/status-breakdown-utils.cjs +7 -0
- package/dist/data/status-breakdown-utils.cjs.map +1 -0
- package/dist/data/status-breakdown-utils.d.ts +4 -0
- package/dist/data/status-breakdown-utils.d.ts.map +1 -0
- package/dist/data/status-breakdown-utils.js +7 -0
- package/dist/data/status-breakdown-utils.js.map +1 -0
- package/dist/data/test-runner/TestRunSummary.cjs +36 -0
- package/dist/data/test-runner/TestRunSummary.cjs.map +1 -1
- package/dist/data/test-runner/TestRunSummary.d.ts +7 -1
- package/dist/data/test-runner/TestRunSummary.d.ts.map +1 -1
- package/dist/data/test-runner/TestRunSummary.js +36 -0
- package/dist/data/test-runner/TestRunSummary.js.map +1 -1
- package/dist/data/test-runner/TestRunner.cjs +5 -3
- package/dist/data/test-runner/TestRunner.cjs.map +1 -1
- package/dist/data/test-runner/TestRunner.d.ts +13 -1
- package/dist/data/test-runner/TestRunner.d.ts.map +1 -1
- package/dist/data/test-runner/TestRunner.js +5 -3
- package/dist/data/test-runner/TestRunner.js.map +1 -1
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.js +3 -3
- package/dist/data.cjs +19 -6
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +13 -5
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +18 -5
- package/dist/data.js.map +1 -1
- package/dist/index.cjs +51 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +50 -6
- package/dist/index.js.map +1 -1
- package/dist/layout/AppShell.cjs +179 -29
- package/dist/layout/AppShell.cjs.map +1 -1
- package/dist/layout/AppShell.d.ts +5 -5
- package/dist/layout/AppShell.d.ts.map +1 -1
- package/dist/layout/AppShell.js +179 -29
- package/dist/layout/AppShell.js.map +1 -1
- package/dist/layout/AppSidebar.cjs +239 -0
- package/dist/layout/AppSidebar.cjs.map +1 -0
- package/dist/layout/AppSidebar.d.ts +62 -0
- package/dist/layout/AppSidebar.d.ts.map +1 -0
- package/dist/layout/AppSidebar.js +239 -0
- package/dist/layout/AppSidebar.js.map +1 -0
- package/dist/overlay/DropdownMenu.cjs.map +1 -1
- package/dist/overlay/DropdownMenu.d.ts.map +1 -1
- package/dist/overlay/DropdownMenu.js.map +1 -1
- package/dist/overlay/Modal.cjs +4 -2
- package/dist/overlay/Modal.cjs.map +1 -1
- package/dist/overlay/Modal.d.ts +1 -1
- package/dist/overlay/Modal.d.ts.map +1 -1
- package/dist/overlay/Modal.js +4 -2
- package/dist/overlay/Modal.js.map +1 -1
- package/dist/overlay/Toast.cjs +89 -0
- package/dist/overlay/Toast.cjs.map +1 -0
- package/dist/overlay/Toast.d.ts +14 -0
- package/dist/overlay/Toast.d.ts.map +1 -0
- package/dist/overlay/Toast.js +89 -0
- package/dist/overlay/Toast.js.map +1 -0
- package/dist/overlay/toast-context.cjs +12 -0
- package/dist/overlay/toast-context.cjs.map +1 -0
- package/dist/overlay/toast-context.d.ts +24 -0
- package/dist/overlay/toast-context.d.ts.map +1 -0
- package/dist/overlay/toast-context.js +12 -0
- package/dist/overlay/toast-context.js.map +1 -0
- package/dist/rpc/AcceptPicker.cjs +81 -58
- package/dist/rpc/AcceptPicker.cjs.map +1 -1
- package/dist/rpc/AcceptPicker.d.ts.map +1 -1
- package/dist/rpc/AcceptPicker.js +81 -58
- package/dist/rpc/AcceptPicker.js.map +1 -1
- package/dist/rpc/CommandForm.cjs +5 -35
- package/dist/rpc/CommandForm.cjs.map +1 -1
- package/dist/rpc/CommandForm.d.ts +0 -3
- package/dist/rpc/CommandForm.d.ts.map +1 -1
- package/dist/rpc/CommandForm.js +2 -32
- package/dist/rpc/CommandForm.js.map +1 -1
- package/dist/rpc/CommandOutput.cjs +2 -1
- package/dist/rpc/CommandOutput.cjs.map +1 -1
- package/dist/rpc/CommandOutput.d.ts.map +1 -1
- package/dist/rpc/CommandOutput.js +2 -1
- package/dist/rpc/CommandOutput.js.map +1 -1
- package/dist/rpc/EntityExplorerApp.cjs +28 -83
- package/dist/rpc/EntityExplorerApp.cjs.map +1 -1
- package/dist/rpc/EntityExplorerApp.d.ts +1 -4
- package/dist/rpc/EntityExplorerApp.d.ts.map +1 -1
- package/dist/rpc/EntityExplorerApp.js +13 -68
- package/dist/rpc/EntityExplorerApp.js.map +1 -1
- package/dist/rpc/OperationCatalog.cjs +2 -2
- package/dist/rpc/OperationCatalog.cjs.map +1 -1
- package/dist/rpc/OperationCatalog.d.ts +1 -1
- package/dist/rpc/OperationCatalog.d.ts.map +1 -1
- package/dist/rpc/OperationCatalog.js +1 -1
- package/dist/rpc/OperationCatalog.js.map +1 -1
- package/dist/rpc/OperationCommandPage.cjs +6 -4
- package/dist/rpc/OperationCommandPage.cjs.map +1 -1
- package/dist/rpc/OperationCommandPage.d.ts.map +1 -1
- package/dist/rpc/OperationCommandPage.js +3 -1
- package/dist/rpc/OperationCommandPage.js.map +1 -1
- package/dist/rpc/RouterProvider.cjs +10 -0
- package/dist/rpc/RouterProvider.cjs.map +1 -0
- package/dist/rpc/RouterProvider.d.ts +10 -0
- package/dist/rpc/RouterProvider.d.ts.map +1 -0
- package/dist/rpc/RouterProvider.js +10 -0
- package/dist/rpc/RouterProvider.js.map +1 -0
- package/dist/rpc/apiClient.cjs +4 -4
- package/dist/rpc/apiClient.cjs.map +1 -1
- package/dist/rpc/apiClient.js +4 -4
- package/dist/rpc/apiClient.js.map +1 -1
- package/dist/rpc/command-form-utils.cjs +43 -0
- package/dist/rpc/command-form-utils.cjs.map +1 -0
- package/dist/rpc/command-form-utils.d.ts +5 -0
- package/dist/rpc/command-form-utils.d.ts.map +1 -0
- package/dist/rpc/command-form-utils.js +43 -0
- package/dist/rpc/command-form-utils.js.map +1 -0
- package/dist/rpc/commandHref.cjs +62 -0
- package/dist/rpc/commandHref.cjs.map +1 -0
- package/dist/rpc/commandHref.d.ts +7 -0
- package/dist/rpc/commandHref.d.ts.map +1 -0
- package/dist/rpc/commandHref.js +62 -0
- package/dist/rpc/commandHref.js.map +1 -0
- package/dist/rpc/formMetadata.cjs +1 -1
- package/dist/rpc/formMetadata.cjs.map +1 -1
- package/dist/rpc/formMetadata.js +1 -1
- package/dist/rpc/formMetadata.js.map +1 -1
- package/dist/rpc/router.cjs +83 -0
- package/dist/rpc/router.cjs.map +1 -0
- package/dist/rpc/router.d.ts +24 -0
- package/dist/rpc/router.d.ts.map +1 -0
- package/dist/rpc/router.js +83 -0
- package/dist/rpc/router.js.map +1 -0
- package/dist/rpc/rpc-story-fixtures/orders.fixture.d.ts +3 -0
- package/dist/rpc/rpc-story-fixtures/orders.fixture.d.ts.map +1 -0
- package/dist/rpc/rpc-story-fixtures/services.fixture.d.ts +3 -0
- package/dist/rpc/rpc-story-fixtures/services.fixture.d.ts.map +1 -0
- package/dist/rpc/rpc-story-fixtures/surface-fixture.d.ts +24 -0
- package/dist/rpc/rpc-story-fixtures/surface-fixture.d.ts.map +1 -0
- package/dist/rpc/rpc-story-fixtures/widgets.fixture.d.ts +3 -0
- package/dist/rpc/rpc-story-fixtures/widgets.fixture.d.ts.map +1 -0
- package/dist/rpc/rpc-story.fixtures.d.ts +16 -0
- package/dist/rpc/rpc-story.fixtures.d.ts.map +1 -0
- package/dist/rpc.cjs +17 -0
- package/dist/rpc.cjs.map +1 -1
- package/dist/rpc.d.ts +5 -0
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +18 -1
- package/dist/rpc.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +11 -1
package/dist/layout/AppShell.js
CHANGED
|
@@ -2,8 +2,11 @@ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState, useEffect } from "react";
|
|
3
3
|
import { cn } from "../lib/utils.js";
|
|
4
4
|
import { Icon } from "../data/Icon.js";
|
|
5
|
+
import { useRouter } from "../rpc/router.js";
|
|
5
6
|
import { SplitPane } from "./SplitPane.js";
|
|
6
7
|
import { UiSidebar } from "../icons/components/UiSidebar.js";
|
|
8
|
+
import { UiMenu } from "../icons/components/UiMenu.js";
|
|
9
|
+
import { UiClose } from "../icons/components/UiClose.js";
|
|
7
10
|
function readStored(key) {
|
|
8
11
|
if (!key || typeof window === "undefined") return null;
|
|
9
12
|
return window.localStorage.getItem(key);
|
|
@@ -25,6 +28,7 @@ function AppShell(props) {
|
|
|
25
28
|
collapsedStorageKey,
|
|
26
29
|
sidebarWidth = 240,
|
|
27
30
|
collapsedWidth = 56,
|
|
31
|
+
mobileSidebarLabel = "Navigation",
|
|
28
32
|
bodyHeader,
|
|
29
33
|
bodyActions,
|
|
30
34
|
bodySidebar,
|
|
@@ -38,6 +42,7 @@ function AppShell(props) {
|
|
|
38
42
|
contentClassName
|
|
39
43
|
} = props;
|
|
40
44
|
const hasSidebar = sidebar !== void 0 || ((navSections == null ? void 0 : navSections.length) ?? 0) > 0;
|
|
45
|
+
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
|
|
41
46
|
const [collapsed, setCollapsed] = useState(
|
|
42
47
|
() => readStored(collapsedStorageKey) === "true" || readStored(collapsedStorageKey) === null && defaultCollapsed
|
|
43
48
|
);
|
|
@@ -45,16 +50,33 @@ function AppShell(props) {
|
|
|
45
50
|
if (collapsedStorageKey && typeof window !== "undefined")
|
|
46
51
|
window.localStorage.setItem(collapsedStorageKey, String(collapsed));
|
|
47
52
|
}, [collapsed, collapsedStorageKey]);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!mobileSidebarOpen) return;
|
|
55
|
+
const onKeyDown = (event) => {
|
|
56
|
+
if (event.key === "Escape") setMobileSidebarOpen(false);
|
|
57
|
+
};
|
|
58
|
+
document.addEventListener("keydown", onKeyDown);
|
|
59
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
60
|
+
}, [mobileSidebarOpen]);
|
|
48
61
|
const railWidth = collapsed ? collapsedWidth : sidebarWidth;
|
|
49
62
|
const hasTopBar = !hasSidebar && brand !== void 0 || nav !== void 0 || search !== void 0 || actions !== void 0 || toolbar !== void 0;
|
|
63
|
+
const hasMobileHeader = hasSidebar;
|
|
50
64
|
const hasBodyHeader = bodyHeader !== void 0 || bodyActions !== void 0;
|
|
65
|
+
const renderSidebarContent = (collapsedValue, onNavigate) => typeof sidebar === "function" ? sidebar(collapsedValue) : sidebar !== void 0 ? sidebar : navSections && /* @__PURE__ */ jsx(
|
|
66
|
+
NavSections,
|
|
67
|
+
{
|
|
68
|
+
sections: navSections,
|
|
69
|
+
collapsed: collapsedValue,
|
|
70
|
+
...onNavigate ? { onNavigate } : {}
|
|
71
|
+
}
|
|
72
|
+
);
|
|
51
73
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full min-h-0 w-full bg-background", className), children: [
|
|
52
74
|
hasSidebar && /* @__PURE__ */ jsxs(
|
|
53
75
|
"aside",
|
|
54
76
|
{
|
|
55
77
|
style: { width: railWidth },
|
|
56
78
|
className: cn(
|
|
57
|
-
"
|
|
79
|
+
"hidden shrink-0 flex-col overflow-hidden border-r border-sidebar-border bg-sidebar text-sidebar-foreground transition-[width] duration-200 md:flex",
|
|
58
80
|
sidebarClassName
|
|
59
81
|
),
|
|
60
82
|
children: [
|
|
@@ -82,17 +104,38 @@ function AppShell(props) {
|
|
|
82
104
|
}
|
|
83
105
|
),
|
|
84
106
|
sidebarHeader && /* @__PURE__ */ jsx("div", { className: "shrink-0 border-b border-sidebar-border px-density-3 py-density-2", children: sidebarHeader }),
|
|
85
|
-
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto py-density-2", children:
|
|
107
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto py-density-2", children: renderSidebarContent(collapsed) }),
|
|
86
108
|
sidebarFooter && /* @__PURE__ */ jsx("div", { className: "mt-auto shrink-0 border-t border-sidebar-border px-density-3 py-density-2", children: sidebarFooter })
|
|
87
109
|
]
|
|
88
110
|
}
|
|
89
111
|
),
|
|
90
112
|
/* @__PURE__ */ jsxs("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: [
|
|
91
|
-
hasTopBar && /* @__PURE__ */ jsxs("header", { className: "shrink-0 border-b border-border bg-card", children: [
|
|
113
|
+
(hasTopBar || hasMobileHeader) && /* @__PURE__ */ jsxs("header", { className: "shrink-0 border-b border-border bg-card", children: [
|
|
114
|
+
hasMobileHeader && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-density-2 px-density-3 py-density-2 md:hidden", children: [
|
|
115
|
+
/* @__PURE__ */ jsx(
|
|
116
|
+
"button",
|
|
117
|
+
{
|
|
118
|
+
type: "button",
|
|
119
|
+
"aria-label": `Open ${mobileSidebarLabel}`,
|
|
120
|
+
title: mobileSidebarLabel,
|
|
121
|
+
className: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-border bg-background text-foreground transition-colors hover:bg-accent",
|
|
122
|
+
onClick: () => setMobileSidebarOpen(true),
|
|
123
|
+
children: /* @__PURE__ */ jsx(Icon, { icon: UiMenu, className: "h-4 w-4" })
|
|
124
|
+
}
|
|
125
|
+
),
|
|
126
|
+
brand && /* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 items-center gap-density-2", children: brand }),
|
|
127
|
+
actions && /* @__PURE__ */ jsx("div", { className: "ml-auto flex shrink-0 items-center gap-density-2", children: actions }),
|
|
128
|
+
search !== void 0 && /* @__PURE__ */ jsx("div", { className: "basis-full min-w-0", children: search }),
|
|
129
|
+
nav && /* @__PURE__ */ jsx("div", { className: "basis-full min-w-0 overflow-x-auto", children: nav })
|
|
130
|
+
] }),
|
|
92
131
|
/* @__PURE__ */ jsxs(
|
|
93
132
|
"div",
|
|
94
133
|
{
|
|
95
|
-
className: cn(
|
|
134
|
+
className: cn(
|
|
135
|
+
"hidden h-14 items-center gap-density-3 px-density-4 md:flex",
|
|
136
|
+
!hasSidebar && "flex",
|
|
137
|
+
headerClassName
|
|
138
|
+
),
|
|
96
139
|
children: [
|
|
97
140
|
!hasSidebar && brand && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-density-2", children: brand }),
|
|
98
141
|
nav && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center", children: nav }),
|
|
@@ -106,7 +149,7 @@ function AppShell(props) {
|
|
|
106
149
|
"div",
|
|
107
150
|
{
|
|
108
151
|
className: cn(
|
|
109
|
-
"flex items-center gap-density-2 border-t border-border bg-muted px-density-
|
|
152
|
+
"flex flex-wrap items-center gap-density-2 border-t border-border bg-muted px-density-3 py-density-2 md:px-density-4",
|
|
110
153
|
toolbarClassName
|
|
111
154
|
),
|
|
112
155
|
children: toolbar
|
|
@@ -117,64 +160,171 @@ function AppShell(props) {
|
|
|
117
160
|
"div",
|
|
118
161
|
{
|
|
119
162
|
className: cn(
|
|
120
|
-
"flex shrink-0
|
|
163
|
+
"flex shrink-0 flex-col items-stretch gap-density-2 border-b border-border bg-card px-density-3 py-density-2 md:flex-row md:items-start md:justify-between md:gap-density-3 md:px-density-4",
|
|
121
164
|
bodyHeaderClassName
|
|
122
165
|
),
|
|
123
166
|
children: [
|
|
124
167
|
/* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: bodyHeader }),
|
|
125
|
-
bodyActions && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-density-2", children: bodyActions })
|
|
168
|
+
bodyActions && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 flex-wrap items-center gap-density-2", children: bodyActions })
|
|
126
169
|
]
|
|
127
170
|
}
|
|
128
171
|
),
|
|
129
|
-
bodySidebar !== void 0 ? /* @__PURE__ */
|
|
130
|
-
|
|
172
|
+
bodySidebar !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
173
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden md:hidden", children: [
|
|
174
|
+
/* @__PURE__ */ jsx("div", { className: "max-h-[40vh] shrink-0 overflow-y-auto border-b border-border bg-background", children: bodySidebar }),
|
|
175
|
+
/* @__PURE__ */ jsx(
|
|
176
|
+
"main",
|
|
177
|
+
{
|
|
178
|
+
className: cn(
|
|
179
|
+
"min-h-0 min-w-0 flex-1 overflow-auto",
|
|
180
|
+
contentClassName
|
|
181
|
+
),
|
|
182
|
+
children
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
] }),
|
|
186
|
+
/* @__PURE__ */ jsx(
|
|
187
|
+
SplitPane,
|
|
188
|
+
{
|
|
189
|
+
className: "hidden min-h-0 flex-1 md:flex",
|
|
190
|
+
defaultSplit: bodySplit,
|
|
191
|
+
minLeft: 12,
|
|
192
|
+
minRight: 30,
|
|
193
|
+
left: bodySidebar,
|
|
194
|
+
right: /* @__PURE__ */ jsx("div", { className: cn("h-full min-w-0", contentClassName), children }),
|
|
195
|
+
rightClass: "overflow-y-auto"
|
|
196
|
+
}
|
|
197
|
+
)
|
|
198
|
+
] }) : /* @__PURE__ */ jsx(
|
|
199
|
+
"main",
|
|
131
200
|
{
|
|
132
|
-
className:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
right: /* @__PURE__ */ jsx("div", { className: cn("h-full min-w-0", contentClassName), children }),
|
|
138
|
-
rightClass: "overflow-y-auto"
|
|
201
|
+
className: cn(
|
|
202
|
+
"min-h-0 min-w-0 flex-1 overflow-auto",
|
|
203
|
+
contentClassName
|
|
204
|
+
),
|
|
205
|
+
children
|
|
139
206
|
}
|
|
140
|
-
)
|
|
141
|
-
] })
|
|
207
|
+
)
|
|
208
|
+
] }),
|
|
209
|
+
hasSidebar && mobileSidebarOpen && /* @__PURE__ */ jsxs(
|
|
210
|
+
"div",
|
|
211
|
+
{
|
|
212
|
+
className: "fixed inset-0 z-50 md:hidden",
|
|
213
|
+
role: "presentation",
|
|
214
|
+
onClick: () => setMobileSidebarOpen(false),
|
|
215
|
+
children: [
|
|
216
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/40" }),
|
|
217
|
+
/* @__PURE__ */ jsxs(
|
|
218
|
+
"aside",
|
|
219
|
+
{
|
|
220
|
+
role: "dialog",
|
|
221
|
+
"aria-modal": "true",
|
|
222
|
+
"aria-label": mobileSidebarLabel,
|
|
223
|
+
className: cn(
|
|
224
|
+
"relative z-10 flex h-full w-[min(20rem,85vw)] flex-col overflow-hidden border-r border-sidebar-border bg-sidebar text-sidebar-foreground shadow-xl",
|
|
225
|
+
sidebarClassName
|
|
226
|
+
),
|
|
227
|
+
onClick: (event) => event.stopPropagation(),
|
|
228
|
+
children: [
|
|
229
|
+
/* @__PURE__ */ jsxs("div", { className: "flex h-14 shrink-0 items-center justify-between border-b border-sidebar-border px-density-3", children: [
|
|
230
|
+
brand && /* @__PURE__ */ jsx("div", { className: "flex min-w-0 items-center gap-2", children: brand }),
|
|
231
|
+
/* @__PURE__ */ jsx(
|
|
232
|
+
"button",
|
|
233
|
+
{
|
|
234
|
+
type: "button",
|
|
235
|
+
"aria-label": `Close ${mobileSidebarLabel}`,
|
|
236
|
+
title: "Close",
|
|
237
|
+
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-sidebar-foreground/70 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
238
|
+
onClick: () => setMobileSidebarOpen(false),
|
|
239
|
+
children: /* @__PURE__ */ jsx(Icon, { icon: UiClose, className: "h-4 w-4" })
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
] }),
|
|
243
|
+
sidebarHeader && /* @__PURE__ */ jsx("div", { className: "shrink-0 border-b border-sidebar-border px-density-3 py-density-2", children: sidebarHeader }),
|
|
244
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto py-density-2", children: renderSidebarContent(false, () => setMobileSidebarOpen(false)) }),
|
|
245
|
+
sidebarFooter && /* @__PURE__ */ jsx("div", { className: "mt-auto shrink-0 border-t border-sidebar-border px-density-3 py-density-2", children: sidebarFooter })
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
)
|
|
249
|
+
]
|
|
250
|
+
}
|
|
251
|
+
)
|
|
142
252
|
] });
|
|
143
253
|
}
|
|
144
254
|
function NavSections({
|
|
145
255
|
sections,
|
|
146
|
-
collapsed
|
|
256
|
+
collapsed,
|
|
257
|
+
onNavigate
|
|
147
258
|
}) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
259
|
+
const { renderLink } = useRouter();
|
|
260
|
+
return /* @__PURE__ */ jsx(
|
|
261
|
+
"nav",
|
|
262
|
+
{
|
|
263
|
+
className: cn(
|
|
264
|
+
"flex flex-col gap-0.5",
|
|
265
|
+
collapsed ? "px-2" : "px-density-2"
|
|
266
|
+
),
|
|
267
|
+
children: sections.map((section, i) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
268
|
+
section.label && (collapsed ? /* @__PURE__ */ jsx("div", { className: "mx-2 mb-1 mt-3 border-t border-sidebar-border first:mt-1" }) : /* @__PURE__ */ jsx("div", { className: "mb-0.5 mt-3 px-density-2 text-[10px] font-semibold uppercase tracking-[0.18em] text-sidebar-foreground/55 first:mt-1", children: section.label })),
|
|
269
|
+
section.items.map((item) => /* @__PURE__ */ jsx(
|
|
270
|
+
NavItemRow,
|
|
271
|
+
{
|
|
272
|
+
item,
|
|
273
|
+
collapsed,
|
|
274
|
+
renderLink,
|
|
275
|
+
...onNavigate ? { onNavigate } : {}
|
|
276
|
+
},
|
|
277
|
+
item.key
|
|
278
|
+
))
|
|
279
|
+
] }, section.label ?? `section-${i}`))
|
|
280
|
+
}
|
|
281
|
+
);
|
|
152
282
|
}
|
|
153
|
-
function NavItemRow({
|
|
283
|
+
function NavItemRow({
|
|
284
|
+
item,
|
|
285
|
+
collapsed,
|
|
286
|
+
renderLink,
|
|
287
|
+
onNavigate
|
|
288
|
+
}) {
|
|
154
289
|
const className = cn(
|
|
155
290
|
"flex w-full items-center gap-2.5 rounded-md px-density-2 py-1.5 text-left text-[13px] text-sidebar-foreground transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
156
291
|
collapsed && "justify-center px-0",
|
|
157
292
|
item.active && "bg-sidebar-accent font-medium text-sidebar-primary"
|
|
158
293
|
);
|
|
159
294
|
const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
160
|
-
item.icon && /* @__PURE__ */ jsx("span", { className: "flex h-4 w-4 shrink-0 items-center justify-center", children: /* @__PURE__ */ jsx(
|
|
295
|
+
item.icon && /* @__PURE__ */ jsx("span", { className: "flex h-4 w-4 shrink-0 items-center justify-center", children: /* @__PURE__ */ jsx(
|
|
296
|
+
Icon,
|
|
297
|
+
{
|
|
298
|
+
...typeof item.icon === "string" ? { name: item.icon } : { icon: item.icon }
|
|
299
|
+
}
|
|
300
|
+
) }),
|
|
161
301
|
!collapsed && /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: item.label }),
|
|
162
302
|
!collapsed && item.badge
|
|
163
303
|
] });
|
|
164
304
|
const title = collapsed && typeof item.label === "string" ? item.label : void 0;
|
|
165
|
-
if (item.
|
|
305
|
+
if (item.external) {
|
|
166
306
|
return /* @__PURE__ */ jsx(
|
|
167
307
|
"a",
|
|
168
308
|
{
|
|
169
|
-
href: item.
|
|
309
|
+
href: item.to,
|
|
170
310
|
className,
|
|
171
311
|
title,
|
|
172
|
-
|
|
312
|
+
target: "_blank",
|
|
313
|
+
rel: "noopener noreferrer",
|
|
314
|
+
onClick: onNavigate,
|
|
173
315
|
children: inner
|
|
174
316
|
}
|
|
175
317
|
);
|
|
176
318
|
}
|
|
177
|
-
|
|
319
|
+
const link = renderLink({
|
|
320
|
+
key: item.key,
|
|
321
|
+
to: item.to,
|
|
322
|
+
className,
|
|
323
|
+
children: inner,
|
|
324
|
+
...title ? { title } : {}
|
|
325
|
+
});
|
|
326
|
+
if (!onNavigate) return link;
|
|
327
|
+
return /* @__PURE__ */ jsx("div", { onClick: onNavigate, children: link });
|
|
178
328
|
}
|
|
179
329
|
export {
|
|
180
330
|
AppShell
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppShell.js","sources":["../../src/layout/AppShell.tsx"],"sourcesContent":["import { useEffect, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"../data/Icon\";\nimport { UiSidebar } from \"../icons\";\nimport { SplitPane } from \"./SplitPane\";\n\n// AppShell is a sidebar-first application shell. The full-height DARK nav rail\n// owns the brand + collapse toggle and renders grouped nav sections; the top bar\n// (search, actions) sits to the RIGHT of the rail — there is no full-width top\n// bar when a rail is present. With no rail, the top bar spans full width. The\n// body carries a fixed bodyHeader + bodyActions row over an optional\n// bodySidebar | body-main split (body-main scrolls; bodySidebar — e.g. a tree —\n// scrolls independently via a resizable SplitPane).\n\nexport type AppShellNavItem = {\n /** Stable key; also the React key. */\n key: string;\n /** Visible label (hidden when the rail is collapsed). */\n label: ReactNode;\n /** Leading icon (icon name or component). */\n icon?: string | StaticIconComponent;\n /** Highlights the item as the current location. */\n active?: boolean;\n /** Click handler (rendered as a button when no `href`). */\n onClick?: () => void;\n /** Destination (rendered as an anchor). */\n href?: string;\n /** Opens `href` in a new tab. */\n external?: boolean;\n /** Trailing adornment (count, status dot). */\n badge?: ReactNode;\n};\n\nexport type AppShellNavSection = {\n /** Section heading; collapses to a divider when the rail is collapsed. */\n label?: string;\n items: AppShellNavItem[];\n};\n\nexport type AppShellProps = {\n // ── Top bar (right of the rail; full width when no rail) ─\n /** Brand mark / wordmark. Shown in the rail header when a rail is present, else in the top bar. */\n brand?: ReactNode;\n /** Inline primary nav (e.g. tabs) shown after the brand in the top bar. */\n nav?: ReactNode;\n /** Centered search slot; grows to fill and is width-capped. */\n search?: ReactNode;\n /** Right-aligned cluster (icon buttons, settings/org picker, …). */\n actions?: ReactNode;\n /** Optional second top-bar row for filters / bulk actions. */\n toolbar?: ReactNode;\n /** Max width of the centered search slot. Defaults to 28rem. */\n searchMaxWidth?: string | number;\n\n // ── Left nav rail (dark, collapsible, fixed width) ───────\n /** Declarative nav sections rendered into the rail (collapse-aware). */\n navSections?: AppShellNavSection[];\n /** Custom sidebar content; receives the collapsed flag. Overrides navSections. */\n sidebar?: ReactNode | ((collapsed: boolean) => ReactNode);\n /** Pinned below the rail header (e.g. a context switcher). */\n sidebarHeader?: ReactNode;\n /** Pinned to the bottom of the rail (version, account). */\n sidebarFooter?: ReactNode;\n /** Show the collapse toggle. Defaults to true when a rail is present. */\n collapsible?: boolean;\n /** Initial collapsed state (uncontrolled). */\n defaultCollapsed?: boolean;\n /** localStorage key persisting the collapsed state. */\n collapsedStorageKey?: string;\n /** Expanded rail width in px. Defaults to 240. */\n sidebarWidth?: number;\n /** Collapsed rail width in px. Defaults to 56. */\n collapsedWidth?: number;\n\n // ── Body ─────────────────────────────────────────────────\n /** Fixed header row, left side (breadcrumb, title, tabs). */\n bodyHeader?: ReactNode;\n /** Fixed header row, right side (entity actions) — same row as bodyHeader. */\n bodyActions?: ReactNode;\n /** Optional independent-scroll pane (e.g. a tree). Renders a SplitPane vs body-main. */\n bodySidebar?: ReactNode;\n /** bodySidebar width as a percent when present. Defaults to 24. */\n bodySplit?: number;\n /** Main content (body-main); fills the remaining space and scrolls. */\n children: ReactNode;\n\n className?: string;\n headerClassName?: string;\n toolbarClassName?: string;\n sidebarClassName?: string;\n bodyHeaderClassName?: string;\n contentClassName?: string;\n};\n\nfunction readStored(key: string | undefined): string | null {\n if (!key || typeof window === \"undefined\") return null;\n return window.localStorage.getItem(key);\n}\n\nexport function AppShell(props: AppShellProps) {\n const {\n brand,\n nav,\n search,\n actions,\n toolbar,\n searchMaxWidth = \"28rem\",\n navSections,\n sidebar,\n sidebarHeader,\n sidebarFooter,\n collapsible = true,\n defaultCollapsed = false,\n collapsedStorageKey,\n sidebarWidth = 240,\n collapsedWidth = 56,\n bodyHeader,\n bodyActions,\n bodySidebar,\n bodySplit = 24,\n children,\n className,\n headerClassName,\n toolbarClassName,\n sidebarClassName,\n bodyHeaderClassName,\n contentClassName,\n } = props;\n\n const hasSidebar = sidebar !== undefined || (navSections?.length ?? 0) > 0;\n\n const [collapsed, setCollapsed] = useState(\n () =>\n readStored(collapsedStorageKey) === \"true\" ||\n (readStored(collapsedStorageKey) === null && defaultCollapsed),\n );\n\n useEffect(() => {\n if (collapsedStorageKey && typeof window !== \"undefined\")\n window.localStorage.setItem(collapsedStorageKey, String(collapsed));\n }, [collapsed, collapsedStorageKey]);\n\n const railWidth = collapsed ? collapsedWidth : sidebarWidth;\n const hasTopBar =\n (!hasSidebar && brand !== undefined) ||\n nav !== undefined ||\n search !== undefined ||\n actions !== undefined ||\n toolbar !== undefined;\n const hasBodyHeader = bodyHeader !== undefined || bodyActions !== undefined;\n\n return (\n <div className={cn(\"flex h-full min-h-0 w-full bg-background\", className)}>\n {hasSidebar && (\n <aside\n style={{ width: railWidth }}\n className={cn(\n \"flex shrink-0 flex-col overflow-hidden border-r border-sidebar-border bg-sidebar text-sidebar-foreground transition-[width] duration-200\",\n sidebarClassName,\n )}\n >\n <div\n className={cn(\n \"flex h-14 shrink-0 items-center border-b border-sidebar-border\",\n collapsed ? \"justify-center px-2\" : \"justify-between px-density-3\",\n )}\n >\n {!collapsed && brand && <div className=\"flex min-w-0 items-center gap-2\">{brand}</div>}\n {collapsible && (\n <button\n type=\"button\"\n onClick={() => setCollapsed((c) => !c)}\n aria-label={collapsed ? \"Expand sidebar\" : \"Collapse sidebar\"}\n title={collapsed ? \"Expand sidebar\" : \"Collapse sidebar\"}\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-sidebar-foreground/70 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground\"\n >\n <Icon icon={UiSidebar} className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n {sidebarHeader && (\n <div className=\"shrink-0 border-b border-sidebar-border px-density-3 py-density-2\">\n {sidebarHeader}\n </div>\n )}\n <div className=\"min-h-0 flex-1 overflow-y-auto py-density-2\">\n {typeof sidebar === \"function\"\n ? sidebar(collapsed)\n : sidebar !== undefined\n ? sidebar\n : navSections && <NavSections sections={navSections} collapsed={collapsed} />}\n </div>\n {sidebarFooter && (\n <div className=\"mt-auto shrink-0 border-t border-sidebar-border px-density-3 py-density-2\">\n {sidebarFooter}\n </div>\n )}\n </aside>\n )}\n\n <div className=\"flex min-h-0 min-w-0 flex-1 flex-col\">\n {hasTopBar && (\n <header className=\"shrink-0 border-b border-border bg-card\">\n <div\n className={cn(\"flex h-14 items-center gap-density-3 px-density-4\", headerClassName)}\n >\n {!hasSidebar && brand && (\n <div className=\"flex shrink-0 items-center gap-density-2\">{brand}</div>\n )}\n {nav && <div className=\"flex shrink-0 items-center\">{nav}</div>}\n {search !== undefined && (\n <div className=\"flex min-w-0 flex-1 justify-center\">\n <div className=\"w-full\" style={{ maxWidth: searchMaxWidth }}>\n {search}\n </div>\n </div>\n )}\n {search === undefined && <div className=\"flex-1\" />}\n {actions && (\n <div className=\"flex shrink-0 items-center gap-density-2\">{actions}</div>\n )}\n </div>\n {toolbar && (\n <div\n className={cn(\n \"flex items-center gap-density-2 border-t border-border bg-muted px-density-4 py-density-2\",\n toolbarClassName,\n )}\n >\n {toolbar}\n </div>\n )}\n </header>\n )}\n\n {hasBodyHeader && (\n <div\n className={cn(\n \"flex shrink-0 items-start justify-between gap-density-3 border-b border-border bg-card px-density-4 py-density-2\",\n bodyHeaderClassName,\n )}\n >\n <div className=\"min-w-0 flex-1\">{bodyHeader}</div>\n {bodyActions && (\n <div className=\"flex shrink-0 items-center gap-density-2\">{bodyActions}</div>\n )}\n </div>\n )}\n\n {bodySidebar !== undefined ? (\n <SplitPane\n className=\"min-h-0 flex-1\"\n defaultSplit={bodySplit}\n minLeft={12}\n minRight={30}\n left={bodySidebar}\n right={<div className={cn(\"h-full min-w-0\", contentClassName)}>{children}</div>}\n rightClass=\"overflow-y-auto\"\n />\n ) : (\n <main className={cn(\"min-h-0 min-w-0 flex-1 overflow-auto\", contentClassName)}>\n {children}\n </main>\n )}\n </div>\n </div>\n );\n}\n\nfunction NavSections({\n sections,\n collapsed,\n}: {\n sections: AppShellNavSection[];\n collapsed: boolean;\n}) {\n return (\n <nav className={cn(\"flex flex-col gap-0.5\", collapsed ? \"px-2\" : \"px-density-2\")}>\n {sections.map((section, i) => (\n <div key={section.label ?? `section-${i}`} className=\"flex flex-col\">\n {section.label &&\n (collapsed ? (\n <div className=\"mx-2 mb-1 mt-3 border-t border-sidebar-border first:mt-1\" />\n ) : (\n <div className=\"mb-0.5 mt-3 px-density-2 text-[10px] font-semibold uppercase tracking-[0.18em] text-sidebar-foreground/55 first:mt-1\">\n {section.label}\n </div>\n ))}\n {section.items.map((item) => (\n <NavItemRow key={item.key} item={item} collapsed={collapsed} />\n ))}\n </div>\n ))}\n </nav>\n );\n}\n\nfunction NavItemRow({ item, collapsed }: { item: AppShellNavItem; collapsed: boolean }) {\n const className = cn(\n \"flex w-full items-center gap-2.5 rounded-md px-density-2 py-1.5 text-left text-[13px] text-sidebar-foreground transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground\",\n collapsed && \"justify-center px-0\",\n item.active && \"bg-sidebar-accent font-medium text-sidebar-primary\",\n );\n const inner = (\n <>\n {item.icon && (\n <span className=\"flex h-4 w-4 shrink-0 items-center justify-center\">\n <Icon {...(typeof item.icon === \"string\" ? { name: item.icon } : { icon: item.icon })} />\n </span>\n )}\n {!collapsed && <span className=\"flex-1 truncate\">{item.label}</span>}\n {!collapsed && item.badge}\n </>\n );\n const title = collapsed && typeof item.label === \"string\" ? item.label : undefined;\n\n if (item.href) {\n return (\n <a\n href={item.href}\n className={className}\n title={title}\n {...(item.external ? { target: \"_blank\", rel: \"noopener noreferrer\" } : {})}\n >\n {inner}\n </a>\n );\n }\n return (\n <button type=\"button\" onClick={item.onClick} className={className} title={title}>\n {inner}\n </button>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AppShell.js","sources":["../../src/layout/AppShell.tsx"],"sourcesContent":["import { useEffect, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"../data/Icon\";\nimport { UiClose, UiMenu, UiSidebar } from \"../icons\";\nimport { useRouter } from \"../rpc/router\";\nimport type { RenderLink } from \"../rpc/EndpointList\";\nimport { SplitPane } from \"./SplitPane\";\n\n// AppShell is a sidebar-first application shell. The full-height DARK nav rail\n// owns the brand + collapse toggle and renders grouped nav sections; the top bar\n// (search, actions) sits to the RIGHT of the rail — there is no full-width top\n// bar when a rail is present. With no rail, the top bar spans full width. The\n// body carries a fixed bodyHeader + bodyActions row over an optional\n// bodySidebar | body-main split (body-main scrolls; bodySidebar — e.g. a tree —\n// scrolls independently via a resizable SplitPane).\n\nexport type AppShellNavItem = {\n /** Stable key; also the React key. */\n key: string;\n /** Visible label (hidden when the rail is collapsed). */\n label: ReactNode;\n /** Leading icon (icon name or component). */\n icon?: string | StaticIconComponent;\n /** Highlights the item as the current location. */\n active?: boolean;\n /** Routing destination; rendered as an anchor via the RouterAdapter. */\n to: string;\n /** Opens `to` in a new tab. */\n external?: boolean;\n /** Trailing adornment (count, status dot). */\n badge?: ReactNode;\n};\n\nexport type AppShellNavSection = {\n /** Section heading; collapses to a divider when the rail is collapsed. */\n label?: string;\n items: AppShellNavItem[];\n};\n\nexport type AppShellProps = {\n // ── Top bar (right of the rail; full width when no rail) ─\n /** Brand mark / wordmark. Shown in the rail header when a rail is present, else in the top bar. */\n brand?: ReactNode;\n /** Inline primary nav (e.g. tabs) shown after the brand in the top bar. */\n nav?: ReactNode;\n /** Centered search slot; grows to fill and is width-capped. */\n search?: ReactNode;\n /** Right-aligned cluster (icon buttons, settings/org picker, …). */\n actions?: ReactNode;\n /** Optional second top-bar row for filters / bulk actions. */\n toolbar?: ReactNode;\n /** Max width of the centered search slot. Defaults to 28rem. */\n searchMaxWidth?: string | number;\n\n // ── Left nav rail (dark, collapsible, fixed width) ───────\n /** Declarative nav sections rendered into the rail (collapse-aware). */\n navSections?: AppShellNavSection[];\n /** Custom sidebar content; receives the collapsed flag. Overrides navSections. */\n sidebar?: ReactNode | ((collapsed: boolean) => ReactNode);\n /** Pinned below the rail header (e.g. a context switcher). */\n sidebarHeader?: ReactNode;\n /** Pinned to the bottom of the rail (version, account). */\n sidebarFooter?: ReactNode;\n /** Show the collapse toggle. Defaults to true when a rail is present. */\n collapsible?: boolean;\n /** Initial collapsed state (uncontrolled). */\n defaultCollapsed?: boolean;\n /** localStorage key persisting the collapsed state. */\n collapsedStorageKey?: string;\n /** Expanded rail width in px. Defaults to 240. */\n sidebarWidth?: number;\n /** Collapsed rail width in px. Defaults to 56. */\n collapsedWidth?: number;\n /** Accessible label for the mobile navigation drawer. Defaults to \"Navigation\". */\n mobileSidebarLabel?: string;\n\n // ── Body ─────────────────────────────────────────────────\n /** Fixed header row, left side (breadcrumb, title, tabs). */\n bodyHeader?: ReactNode;\n /** Fixed header row, right side (entity actions) — same row as bodyHeader. */\n bodyActions?: ReactNode;\n /** Optional independent-scroll pane (e.g. a tree). Renders a SplitPane vs body-main. */\n bodySidebar?: ReactNode;\n /** bodySidebar width as a percent when present. Defaults to 24. */\n bodySplit?: number;\n /** Main content (body-main); fills the remaining space and scrolls. */\n children: ReactNode;\n\n className?: string;\n headerClassName?: string;\n toolbarClassName?: string;\n sidebarClassName?: string;\n bodyHeaderClassName?: string;\n contentClassName?: string;\n};\n\nfunction readStored(key: string | undefined): string | null {\n if (!key || typeof window === \"undefined\") return null;\n return window.localStorage.getItem(key);\n}\n\nexport function AppShell(props: AppShellProps) {\n const {\n brand,\n nav,\n search,\n actions,\n toolbar,\n searchMaxWidth = \"28rem\",\n navSections,\n sidebar,\n sidebarHeader,\n sidebarFooter,\n collapsible = true,\n defaultCollapsed = false,\n collapsedStorageKey,\n sidebarWidth = 240,\n collapsedWidth = 56,\n mobileSidebarLabel = \"Navigation\",\n bodyHeader,\n bodyActions,\n bodySidebar,\n bodySplit = 24,\n children,\n className,\n headerClassName,\n toolbarClassName,\n sidebarClassName,\n bodyHeaderClassName,\n contentClassName,\n } = props;\n\n const hasSidebar = sidebar !== undefined || (navSections?.length ?? 0) > 0;\n const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);\n\n const [collapsed, setCollapsed] = useState(\n () =>\n readStored(collapsedStorageKey) === \"true\" ||\n (readStored(collapsedStorageKey) === null && defaultCollapsed),\n );\n\n useEffect(() => {\n if (collapsedStorageKey && typeof window !== \"undefined\")\n window.localStorage.setItem(collapsedStorageKey, String(collapsed));\n }, [collapsed, collapsedStorageKey]);\n\n useEffect(() => {\n if (!mobileSidebarOpen) return;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") setMobileSidebarOpen(false);\n };\n document.addEventListener(\"keydown\", onKeyDown);\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [mobileSidebarOpen]);\n\n const railWidth = collapsed ? collapsedWidth : sidebarWidth;\n const hasTopBar =\n (!hasSidebar && brand !== undefined) ||\n nav !== undefined ||\n search !== undefined ||\n actions !== undefined ||\n toolbar !== undefined;\n const hasMobileHeader = hasSidebar;\n const hasBodyHeader = bodyHeader !== undefined || bodyActions !== undefined;\n const renderSidebarContent = (collapsedValue: boolean, onNavigate?: () => void) =>\n typeof sidebar === \"function\"\n ? sidebar(collapsedValue)\n : sidebar !== undefined\n ? sidebar\n : navSections && (\n <NavSections\n sections={navSections}\n collapsed={collapsedValue}\n {...(onNavigate ? { onNavigate } : {})}\n />\n );\n\n return (\n <div className={cn(\"flex h-full min-h-0 w-full bg-background\", className)}>\n {hasSidebar && (\n <aside\n style={{ width: railWidth }}\n className={cn(\n \"hidden shrink-0 flex-col overflow-hidden border-r border-sidebar-border bg-sidebar text-sidebar-foreground transition-[width] duration-200 md:flex\",\n sidebarClassName,\n )}\n >\n <div\n className={cn(\n \"flex h-14 shrink-0 items-center border-b border-sidebar-border\",\n collapsed\n ? \"justify-center px-2\"\n : \"justify-between px-density-3\",\n )}\n >\n {!collapsed && brand && (\n <div className=\"flex min-w-0 items-center gap-2\">{brand}</div>\n )}\n {collapsible && (\n <button\n type=\"button\"\n onClick={() => setCollapsed((c) => !c)}\n aria-label={collapsed ? \"Expand sidebar\" : \"Collapse sidebar\"}\n title={collapsed ? \"Expand sidebar\" : \"Collapse sidebar\"}\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-sidebar-foreground/70 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground\"\n >\n <Icon icon={UiSidebar} className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n {sidebarHeader && (\n <div className=\"shrink-0 border-b border-sidebar-border px-density-3 py-density-2\">\n {sidebarHeader}\n </div>\n )}\n <div className=\"min-h-0 flex-1 overflow-y-auto py-density-2\">\n {renderSidebarContent(collapsed)}\n </div>\n {sidebarFooter && (\n <div className=\"mt-auto shrink-0 border-t border-sidebar-border px-density-3 py-density-2\">\n {sidebarFooter}\n </div>\n )}\n </aside>\n )}\n\n <div className=\"flex min-h-0 min-w-0 flex-1 flex-col\">\n {(hasTopBar || hasMobileHeader) && (\n <header className=\"shrink-0 border-b border-border bg-card\">\n {hasMobileHeader && (\n <div className=\"flex flex-wrap items-center gap-density-2 px-density-3 py-density-2 md:hidden\">\n <button\n type=\"button\"\n aria-label={`Open ${mobileSidebarLabel}`}\n title={mobileSidebarLabel}\n className=\"inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-border bg-background text-foreground transition-colors hover:bg-accent\"\n onClick={() => setMobileSidebarOpen(true)}\n >\n <Icon icon={UiMenu} className=\"h-4 w-4\" />\n </button>\n {brand && (\n <div className=\"flex min-w-0 flex-1 items-center gap-density-2\">\n {brand}\n </div>\n )}\n {actions && (\n <div className=\"ml-auto flex shrink-0 items-center gap-density-2\">\n {actions}\n </div>\n )}\n {search !== undefined && (\n <div className=\"basis-full min-w-0\">\n {search}\n </div>\n )}\n {nav && (\n <div className=\"basis-full min-w-0 overflow-x-auto\">\n {nav}\n </div>\n )}\n </div>\n )}\n <div\n className={cn(\n \"hidden h-14 items-center gap-density-3 px-density-4 md:flex\",\n !hasSidebar && \"flex\",\n headerClassName,\n )}\n >\n {!hasSidebar && brand && (\n <div className=\"flex shrink-0 items-center gap-density-2\">\n {brand}\n </div>\n )}\n {nav && <div className=\"flex shrink-0 items-center\">{nav}</div>}\n {search !== undefined && (\n <div className=\"flex min-w-0 flex-1 justify-center\">\n <div className=\"w-full\" style={{ maxWidth: searchMaxWidth }}>\n {search}\n </div>\n </div>\n )}\n {search === undefined && <div className=\"flex-1\" />}\n {actions && (\n <div className=\"flex shrink-0 items-center gap-density-2\">\n {actions}\n </div>\n )}\n </div>\n {toolbar && (\n <div\n className={cn(\n \"flex flex-wrap items-center gap-density-2 border-t border-border bg-muted px-density-3 py-density-2 md:px-density-4\",\n toolbarClassName,\n )}\n >\n {toolbar}\n </div>\n )}\n </header>\n )}\n\n {hasBodyHeader && (\n <div\n className={cn(\n \"flex shrink-0 flex-col items-stretch gap-density-2 border-b border-border bg-card px-density-3 py-density-2 md:flex-row md:items-start md:justify-between md:gap-density-3 md:px-density-4\",\n bodyHeaderClassName,\n )}\n >\n <div className=\"min-w-0 flex-1\">{bodyHeader}</div>\n {bodyActions && (\n <div className=\"flex shrink-0 flex-wrap items-center gap-density-2\">\n {bodyActions}\n </div>\n )}\n </div>\n )}\n\n {bodySidebar !== undefined ? (\n <>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-hidden md:hidden\">\n <div className=\"max-h-[40vh] shrink-0 overflow-y-auto border-b border-border bg-background\">\n {bodySidebar}\n </div>\n <main\n className={cn(\n \"min-h-0 min-w-0 flex-1 overflow-auto\",\n contentClassName,\n )}\n >\n {children}\n </main>\n </div>\n <SplitPane\n className=\"hidden min-h-0 flex-1 md:flex\"\n defaultSplit={bodySplit}\n minLeft={12}\n minRight={30}\n left={bodySidebar}\n right={\n <div className={cn(\"h-full min-w-0\", contentClassName)}>\n {children}\n </div>\n }\n rightClass=\"overflow-y-auto\"\n />\n </>\n ) : (\n <main\n className={cn(\n \"min-h-0 min-w-0 flex-1 overflow-auto\",\n contentClassName,\n )}\n >\n {children}\n </main>\n )}\n </div>\n {hasSidebar && mobileSidebarOpen && (\n <div\n className=\"fixed inset-0 z-50 md:hidden\"\n role=\"presentation\"\n onClick={() => setMobileSidebarOpen(false)}\n >\n <div className=\"absolute inset-0 bg-black/40\" />\n <aside\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={mobileSidebarLabel}\n className={cn(\n \"relative z-10 flex h-full w-[min(20rem,85vw)] flex-col overflow-hidden border-r border-sidebar-border bg-sidebar text-sidebar-foreground shadow-xl\",\n sidebarClassName,\n )}\n onClick={(event) => event.stopPropagation()}\n >\n <div className=\"flex h-14 shrink-0 items-center justify-between border-b border-sidebar-border px-density-3\">\n {brand && <div className=\"flex min-w-0 items-center gap-2\">{brand}</div>}\n <button\n type=\"button\"\n aria-label={`Close ${mobileSidebarLabel}`}\n title=\"Close\"\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-sidebar-foreground/70 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground\"\n onClick={() => setMobileSidebarOpen(false)}\n >\n <Icon icon={UiClose} className=\"h-4 w-4\" />\n </button>\n </div>\n {sidebarHeader && (\n <div className=\"shrink-0 border-b border-sidebar-border px-density-3 py-density-2\">\n {sidebarHeader}\n </div>\n )}\n <div className=\"min-h-0 flex-1 overflow-y-auto py-density-2\">\n {renderSidebarContent(false, () => setMobileSidebarOpen(false))}\n </div>\n {sidebarFooter && (\n <div className=\"mt-auto shrink-0 border-t border-sidebar-border px-density-3 py-density-2\">\n {sidebarFooter}\n </div>\n )}\n </aside>\n </div>\n )}\n </div>\n );\n}\n\nfunction NavSections({\n sections,\n collapsed,\n onNavigate,\n}: {\n sections: AppShellNavSection[];\n collapsed: boolean;\n onNavigate?: () => void;\n}) {\n const { renderLink } = useRouter();\n return (\n <nav\n className={cn(\n \"flex flex-col gap-0.5\",\n collapsed ? \"px-2\" : \"px-density-2\",\n )}\n >\n {sections.map((section, i) => (\n <div key={section.label ?? `section-${i}`} className=\"flex flex-col\">\n {section.label &&\n (collapsed ? (\n <div className=\"mx-2 mb-1 mt-3 border-t border-sidebar-border first:mt-1\" />\n ) : (\n <div className=\"mb-0.5 mt-3 px-density-2 text-[10px] font-semibold uppercase tracking-[0.18em] text-sidebar-foreground/55 first:mt-1\">\n {section.label}\n </div>\n ))}\n {section.items.map((item) => (\n <NavItemRow\n key={item.key}\n item={item}\n collapsed={collapsed}\n renderLink={renderLink}\n {...(onNavigate ? { onNavigate } : {})}\n />\n ))}\n </div>\n ))}\n </nav>\n );\n}\n\nfunction NavItemRow({\n item,\n collapsed,\n renderLink,\n onNavigate,\n}: {\n item: AppShellNavItem;\n collapsed: boolean;\n renderLink: RenderLink;\n onNavigate?: () => void;\n}) {\n const className = cn(\n \"flex w-full items-center gap-2.5 rounded-md px-density-2 py-1.5 text-left text-[13px] text-sidebar-foreground transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground\",\n collapsed && \"justify-center px-0\",\n item.active && \"bg-sidebar-accent font-medium text-sidebar-primary\",\n );\n const inner = (\n <>\n {item.icon && (\n <span className=\"flex h-4 w-4 shrink-0 items-center justify-center\">\n <Icon\n {...(typeof item.icon === \"string\"\n ? { name: item.icon }\n : { icon: item.icon })}\n />\n </span>\n )}\n {!collapsed && <span className=\"flex-1 truncate\">{item.label}</span>}\n {!collapsed && item.badge}\n </>\n );\n const title =\n collapsed && typeof item.label === \"string\" ? item.label : undefined;\n\n if (item.external) {\n return (\n <a\n href={item.to}\n className={className}\n title={title}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={onNavigate}\n >\n {inner}\n </a>\n );\n }\n const link = renderLink({\n key: item.key,\n to: item.to,\n className,\n children: inner,\n ...(title ? { title } : {}),\n });\n\n if (!onNavigate) return link;\n return (\n <div onClick={onNavigate}>\n {link}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const react = require("react");
|
|
5
|
+
const utils = require("../lib/utils.cjs");
|
|
6
|
+
const Icon = require("../data/Icon.cjs");
|
|
7
|
+
const router = require("../rpc/router.cjs");
|
|
8
|
+
const UiSidebar = require("../icons/components/UiSidebar.cjs");
|
|
9
|
+
const DEFAULT_COLLAPSE_KEY = "clicky-ui:app-sidebar:collapsed";
|
|
10
|
+
const DEFAULT_GROUP_COLLAPSE_KEY = "clicky-ui:app-sidebar:groups";
|
|
11
|
+
function defaultIsActive(pathname, to) {
|
|
12
|
+
if (to === "/") return pathname === "/";
|
|
13
|
+
return pathname === to || pathname.startsWith(`${to}/`);
|
|
14
|
+
}
|
|
15
|
+
function useCollapsed(storageKey) {
|
|
16
|
+
const [collapsed, setCollapsed] = react.useState(() => {
|
|
17
|
+
if (typeof window === "undefined") return false;
|
|
18
|
+
return window.localStorage.getItem(storageKey) === "true";
|
|
19
|
+
});
|
|
20
|
+
react.useEffect(() => {
|
|
21
|
+
if (typeof window === "undefined") return;
|
|
22
|
+
window.localStorage.setItem(storageKey, String(collapsed));
|
|
23
|
+
}, [collapsed, storageKey]);
|
|
24
|
+
return [collapsed, () => setCollapsed((c) => !c)];
|
|
25
|
+
}
|
|
26
|
+
function readGroupState(storageKey) {
|
|
27
|
+
if (typeof window === "undefined") return {};
|
|
28
|
+
try {
|
|
29
|
+
const raw = window.localStorage.getItem(storageKey);
|
|
30
|
+
if (!raw) return {};
|
|
31
|
+
const parsed = JSON.parse(raw);
|
|
32
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
33
|
+
} catch {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function useGroupCollapsed(storageKey) {
|
|
38
|
+
const [state, setState] = react.useState(() => readGroupState(storageKey));
|
|
39
|
+
react.useEffect(() => {
|
|
40
|
+
if (typeof window === "undefined") return;
|
|
41
|
+
try {
|
|
42
|
+
window.localStorage.setItem(storageKey, JSON.stringify(state));
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
}, [state, storageKey]);
|
|
46
|
+
return {
|
|
47
|
+
isCollapsed: (key, fallback) => state[key] ?? fallback,
|
|
48
|
+
toggle: (key, fallback) => setState((prev) => ({ ...prev, [key]: !(prev[key] ?? fallback) }))
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function flattenGroupItems(groups) {
|
|
52
|
+
const out = [];
|
|
53
|
+
for (const group of groups) {
|
|
54
|
+
if (group.items) out.push(...group.items);
|
|
55
|
+
if (group.groups) out.push(...flattenGroupItems(group.groups));
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
function AppSidebar({
|
|
60
|
+
sections,
|
|
61
|
+
pathname: pathnameProp,
|
|
62
|
+
renderLink: renderLinkProp,
|
|
63
|
+
header,
|
|
64
|
+
footer,
|
|
65
|
+
collapsedStorageKey = DEFAULT_COLLAPSE_KEY,
|
|
66
|
+
groupCollapsedStorageKey = DEFAULT_GROUP_COLLAPSE_KEY,
|
|
67
|
+
isActive = defaultIsActive,
|
|
68
|
+
className
|
|
69
|
+
}) {
|
|
70
|
+
const router$1 = router.useRouter();
|
|
71
|
+
const pathname = pathnameProp ?? router$1.pathname;
|
|
72
|
+
const renderLink = renderLinkProp ?? router$1.renderLink;
|
|
73
|
+
const [collapsed, toggleCollapsed] = useCollapsed(collapsedStorageKey);
|
|
74
|
+
const groupState = useGroupCollapsed(groupCollapsedStorageKey);
|
|
75
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
76
|
+
"nav",
|
|
77
|
+
{
|
|
78
|
+
className: utils.cn(
|
|
79
|
+
"flex shrink-0 flex-col overflow-hidden border-r border-border bg-muted/30 transition-[width] duration-200",
|
|
80
|
+
collapsed ? "w-16" : "w-64",
|
|
81
|
+
className
|
|
82
|
+
),
|
|
83
|
+
children: [
|
|
84
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
85
|
+
"div",
|
|
86
|
+
{
|
|
87
|
+
className: utils.cn(
|
|
88
|
+
"flex shrink-0 items-center border-b border-border py-3",
|
|
89
|
+
collapsed ? "justify-center px-2" : "justify-between px-4"
|
|
90
|
+
),
|
|
91
|
+
children: [
|
|
92
|
+
!collapsed && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: header }),
|
|
93
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
94
|
+
"button",
|
|
95
|
+
{
|
|
96
|
+
type: "button",
|
|
97
|
+
onClick: toggleCollapsed,
|
|
98
|
+
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
99
|
+
title: collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
100
|
+
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
|
|
101
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: UiSidebar.UiSidebar, className: "h-4 w-4" })
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
),
|
|
107
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: utils.cn("flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto py-2", collapsed ? "px-2" : "px-3"), children: sections.map((section, i) => {
|
|
108
|
+
var _a, _b;
|
|
109
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
110
|
+
section.label && /* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { collapsed, children: section.label }),
|
|
111
|
+
(_a = section.items) == null ? void 0 : _a.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
112
|
+
SidebarItem,
|
|
113
|
+
{
|
|
114
|
+
item,
|
|
115
|
+
active: isActive(pathname, item.to),
|
|
116
|
+
collapsed,
|
|
117
|
+
renderLink
|
|
118
|
+
},
|
|
119
|
+
item.key
|
|
120
|
+
)),
|
|
121
|
+
(_b = section.groups) == null ? void 0 : _b.map(
|
|
122
|
+
(group) => collapsed ? flattenGroupItems([group]).map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
123
|
+
SidebarItem,
|
|
124
|
+
{
|
|
125
|
+
item,
|
|
126
|
+
active: isActive(pathname, item.to),
|
|
127
|
+
collapsed: true,
|
|
128
|
+
renderLink
|
|
129
|
+
},
|
|
130
|
+
item.key
|
|
131
|
+
)) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
132
|
+
SidebarGroup,
|
|
133
|
+
{
|
|
134
|
+
group,
|
|
135
|
+
pathname,
|
|
136
|
+
isActive,
|
|
137
|
+
renderLink,
|
|
138
|
+
groupState
|
|
139
|
+
},
|
|
140
|
+
group.key
|
|
141
|
+
)
|
|
142
|
+
)
|
|
143
|
+
] }, section.label ?? `section-${i}`);
|
|
144
|
+
}) }),
|
|
145
|
+
footer && /* @__PURE__ */ jsxRuntime.jsx("div", { className: utils.cn("mt-auto border-t border-border py-3", collapsed ? "px-2" : "px-4"), children: footer })
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
function SidebarGroup({
|
|
151
|
+
group,
|
|
152
|
+
pathname,
|
|
153
|
+
isActive,
|
|
154
|
+
renderLink,
|
|
155
|
+
groupState
|
|
156
|
+
}) {
|
|
157
|
+
var _a, _b;
|
|
158
|
+
const fallback = group.defaultCollapsed ?? false;
|
|
159
|
+
const collapsed = groupState.isCollapsed(group.key, fallback);
|
|
160
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
161
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
162
|
+
"button",
|
|
163
|
+
{
|
|
164
|
+
type: "button",
|
|
165
|
+
onClick: () => groupState.toggle(group.key, fallback),
|
|
166
|
+
"aria-expanded": !collapsed,
|
|
167
|
+
className: "flex items-center gap-2 rounded-md px-3 py-1.5 text-[11px] font-semibold uppercase tracking-[0.14em] text-muted-foreground transition-colors hover:bg-accent/40",
|
|
168
|
+
children: [
|
|
169
|
+
group.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-4 w-4 shrink-0 items-center justify-center", children: group.icon }),
|
|
170
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate text-left", children: group.label }),
|
|
171
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "text-[0.65rem] opacity-60", children: collapsed ? "▸" : "▾" })
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
),
|
|
175
|
+
!collapsed && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-2 mt-0.5 flex flex-col gap-0.5 border-l border-border/60 pl-2", children: [
|
|
176
|
+
(_a = group.items) == null ? void 0 : _a.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
177
|
+
SidebarItem,
|
|
178
|
+
{
|
|
179
|
+
item,
|
|
180
|
+
active: isActive(pathname, item.to),
|
|
181
|
+
collapsed: false,
|
|
182
|
+
renderLink
|
|
183
|
+
},
|
|
184
|
+
item.key
|
|
185
|
+
)),
|
|
186
|
+
(_b = group.groups) == null ? void 0 : _b.map((sub) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
187
|
+
SidebarGroup,
|
|
188
|
+
{
|
|
189
|
+
group: sub,
|
|
190
|
+
pathname,
|
|
191
|
+
isActive,
|
|
192
|
+
renderLink,
|
|
193
|
+
groupState
|
|
194
|
+
},
|
|
195
|
+
sub.key
|
|
196
|
+
))
|
|
197
|
+
] })
|
|
198
|
+
] });
|
|
199
|
+
}
|
|
200
|
+
function SidebarItem({
|
|
201
|
+
item,
|
|
202
|
+
active,
|
|
203
|
+
collapsed,
|
|
204
|
+
renderLink
|
|
205
|
+
}) {
|
|
206
|
+
const className = utils.cn(
|
|
207
|
+
"flex items-center gap-2.5 rounded-md px-3 py-1.5 text-[13px] text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
|
|
208
|
+
collapsed && "justify-center px-0",
|
|
209
|
+
active && "bg-accent font-medium text-accent-foreground"
|
|
210
|
+
);
|
|
211
|
+
const title = collapsed ? item.title : void 0;
|
|
212
|
+
const children = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
213
|
+
item.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-4 w-4 shrink-0 items-center justify-center", children: item.icon }),
|
|
214
|
+
!collapsed && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: item.title }),
|
|
215
|
+
!collapsed && item.badge
|
|
216
|
+
] });
|
|
217
|
+
if (item.external) {
|
|
218
|
+
return /* @__PURE__ */ jsxRuntime.jsx("a", { href: item.to, className, title, target: "_blank", rel: "noopener noreferrer", children });
|
|
219
|
+
}
|
|
220
|
+
return renderLink({ key: item.key, to: item.to, className, children, ...title ? { title } : {} });
|
|
221
|
+
}
|
|
222
|
+
function SectionLabel({ children, collapsed }) {
|
|
223
|
+
if (collapsed) {
|
|
224
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-2 mb-1 mt-3 border-t border-border first:mt-2" });
|
|
225
|
+
}
|
|
226
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-0.5 mt-3 px-3 text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground first:mt-2", children });
|
|
227
|
+
}
|
|
228
|
+
function AppLayout({ sidebar, header, children, className }) {
|
|
229
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("flex h-full min-h-0 w-full overflow-hidden bg-background", className), children: [
|
|
230
|
+
sidebar,
|
|
231
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
232
|
+
header,
|
|
233
|
+
/* @__PURE__ */ jsxRuntime.jsx("main", { className: "min-h-0 min-w-0 flex-1 overflow-y-auto", children })
|
|
234
|
+
] })
|
|
235
|
+
] });
|
|
236
|
+
}
|
|
237
|
+
exports.AppLayout = AppLayout;
|
|
238
|
+
exports.AppSidebar = AppSidebar;
|
|
239
|
+
//# sourceMappingURL=AppSidebar.cjs.map
|