@happyvertical/smrt-svelte 0.30.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/AGENTS.md +317 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/README.md +185 -0
- package/dist/Provider.svelte +204 -0
- package/dist/Provider.svelte.d.ts +73 -0
- package/dist/Provider.svelte.d.ts.map +1 -0
- package/dist/__tests__/app-state.test.js +156 -0
- package/dist/__tests__/warm-clients.test.js +186 -0
- package/dist/browser-ai/adapters/llm/factory.d.ts +38 -0
- package/dist/browser-ai/adapters/llm/factory.d.ts.map +1 -0
- package/dist/browser-ai/adapters/llm/factory.js +91 -0
- package/dist/browser-ai/adapters/llm/index.d.ts +7 -0
- package/dist/browser-ai/adapters/llm/index.d.ts.map +1 -0
- package/dist/browser-ai/adapters/llm/index.js +6 -0
- package/dist/browser-ai/adapters/llm/types.d.ts +182 -0
- package/dist/browser-ai/adapters/llm/types.d.ts.map +1 -0
- package/dist/browser-ai/adapters/llm/types.js +43 -0
- package/dist/browser-ai/adapters/llm/webllm.d.ts +33 -0
- package/dist/browser-ai/adapters/llm/webllm.d.ts.map +1 -0
- package/dist/browser-ai/adapters/llm/webllm.js +225 -0
- package/dist/browser-ai/adapters/stt/browser-speech.d.ts +31 -0
- package/dist/browser-ai/adapters/stt/browser-speech.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/browser-speech.js +217 -0
- package/dist/browser-ai/adapters/stt/factory.d.ts +49 -0
- package/dist/browser-ai/adapters/stt/factory.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/factory.js +110 -0
- package/dist/browser-ai/adapters/stt/index.d.ts +9 -0
- package/dist/browser-ai/adapters/stt/index.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/index.js +8 -0
- package/dist/browser-ai/adapters/stt/types.d.ts +154 -0
- package/dist/browser-ai/adapters/stt/types.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/types.js +4 -0
- package/dist/browser-ai/adapters/stt/whisper-cpp.d.ts +46 -0
- package/dist/browser-ai/adapters/stt/whisper-cpp.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/whisper-cpp.js +348 -0
- package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts +51 -0
- package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/whisper-wasm.js +380 -0
- package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts +42 -0
- package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts.map +1 -0
- package/dist/browser-ai/adapters/tts/browser-synthesis.js +235 -0
- package/dist/browser-ai/adapters/tts/factory.d.ts +53 -0
- package/dist/browser-ai/adapters/tts/factory.d.ts.map +1 -0
- package/dist/browser-ai/adapters/tts/factory.js +92 -0
- package/dist/browser-ai/adapters/tts/index.d.ts +7 -0
- package/dist/browser-ai/adapters/tts/index.d.ts.map +1 -0
- package/dist/browser-ai/adapters/tts/index.js +6 -0
- package/dist/browser-ai/adapters/tts/types.d.ts +140 -0
- package/dist/browser-ai/adapters/tts/types.d.ts.map +1 -0
- package/dist/browser-ai/adapters/tts/types.js +4 -0
- package/dist/browser-ai/capabilities/detector.d.ts +38 -0
- package/dist/browser-ai/capabilities/detector.d.ts.map +1 -0
- package/dist/browser-ai/capabilities/detector.js +211 -0
- package/dist/browser-ai/core/errors.d.ts +62 -0
- package/dist/browser-ai/core/errors.d.ts.map +1 -0
- package/dist/browser-ai/core/errors.js +92 -0
- package/dist/browser-ai/core/index.d.ts +6 -0
- package/dist/browser-ai/core/index.d.ts.map +1 -0
- package/dist/browser-ai/core/index.js +5 -0
- package/dist/browser-ai/core/types.d.ts +115 -0
- package/dist/browser-ai/core/types.d.ts.map +1 -0
- package/dist/browser-ai/core/types.js +34 -0
- package/dist/browser-ai/index.d.ts +12 -0
- package/dist/browser-ai/index.d.ts.map +1 -0
- package/dist/browser-ai/index.js +16 -0
- package/dist/browser-ai/svelte/components/AILoadingOverlay.svelte +77 -0
- package/dist/browser-ai/svelte/components/AILoadingOverlay.svelte.d.ts +16 -0
- package/dist/browser-ai/svelte/components/AILoadingOverlay.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/components/CapabilityGate.svelte +57 -0
- package/dist/browser-ai/svelte/components/CapabilityGate.svelte.d.ts +15 -0
- package/dist/browser-ai/svelte/components/CapabilityGate.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/components/DownloadProgress.svelte +141 -0
- package/dist/browser-ai/svelte/components/DownloadProgress.svelte.d.ts +15 -0
- package/dist/browser-ai/svelte/components/DownloadProgress.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/components/STTTest.svelte +379 -0
- package/dist/browser-ai/svelte/components/STTTest.svelte.d.ts +9 -0
- package/dist/browser-ai/svelte/components/STTTest.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/components/VoiceInput.svelte +200 -0
- package/dist/browser-ai/svelte/components/VoiceInput.svelte.d.ts +16 -0
- package/dist/browser-ai/svelte/components/VoiceInput.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/index.d.ts +15 -0
- package/dist/browser-ai/svelte/index.d.ts.map +1 -0
- package/dist/browser-ai/svelte/index.js +28 -0
- package/dist/browser-ai/ui.d.ts +16 -0
- package/dist/browser-ai/ui.d.ts.map +1 -0
- package/dist/browser-ai/ui.js +67 -0
- package/dist/components/admin/AgentAdminPanel.svelte +111 -0
- package/dist/components/admin/AgentAdminPanel.svelte.d.ts +25 -0
- package/dist/components/admin/AgentAdminPanel.svelte.d.ts.map +1 -0
- package/dist/components/admin/AgentAdminTabs.svelte +280 -0
- package/dist/components/admin/AgentAdminTabs.svelte.d.ts +23 -0
- package/dist/components/admin/AgentAdminTabs.svelte.d.ts.map +1 -0
- package/dist/components/admin/AgentSettingsShell.svelte +257 -0
- package/dist/components/admin/AgentSettingsShell.svelte.d.ts +33 -0
- package/dist/components/admin/AgentSettingsShell.svelte.d.ts.map +1 -0
- package/dist/components/admin/index.d.ts +5 -0
- package/dist/components/admin/index.d.ts.map +1 -0
- package/dist/components/admin/index.js +6 -0
- package/dist/components/forms/AddressInput.svelte +500 -0
- package/dist/components/forms/AddressInput.svelte.d.ts +36 -0
- package/dist/components/forms/AddressInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/CheckboxInput.svelte +208 -0
- package/dist/components/forms/CheckboxInput.svelte.d.ts +20 -0
- package/dist/components/forms/CheckboxInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/DateRangeInput.svelte +628 -0
- package/dist/components/forms/DateRangeInput.svelte.d.ts +33 -0
- package/dist/components/forms/DateRangeInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/DateTimeInput.svelte +521 -0
- package/dist/components/forms/DateTimeInput.svelte.d.ts +24 -0
- package/dist/components/forms/DateTimeInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/FileUpload.svelte +358 -0
- package/dist/components/forms/FileUpload.svelte.d.ts +22 -0
- package/dist/components/forms/FileUpload.svelte.d.ts.map +1 -0
- package/dist/components/forms/Form.svelte +771 -0
- package/dist/components/forms/Form.svelte.d.ts +26 -0
- package/dist/components/forms/Form.svelte.d.ts.map +1 -0
- package/dist/components/forms/FormGroup.svelte +86 -0
- package/dist/components/forms/FormGroup.svelte.d.ts +13 -0
- package/dist/components/forms/FormGroup.svelte.d.ts.map +1 -0
- package/dist/components/forms/FormMicButton.svelte +179 -0
- package/dist/components/forms/FormMicButton.svelte.d.ts +10 -0
- package/dist/components/forms/FormMicButton.svelte.d.ts.map +1 -0
- package/dist/components/forms/Input.svelte +83 -0
- package/dist/components/forms/Input.svelte.d.ts +9 -0
- package/dist/components/forms/Input.svelte.d.ts.map +1 -0
- package/dist/components/forms/MeasurementInput.svelte +505 -0
- package/dist/components/forms/MeasurementInput.svelte.d.ts +35 -0
- package/dist/components/forms/MeasurementInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/MoneyInput.svelte +412 -0
- package/dist/components/forms/MoneyInput.svelte.d.ts +30 -0
- package/dist/components/forms/MoneyInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/NumberInput.svelte +310 -0
- package/dist/components/forms/NumberInput.svelte.d.ts +28 -0
- package/dist/components/forms/NumberInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/PhoneInput.svelte +530 -0
- package/dist/components/forms/PhoneInput.svelte.d.ts +22 -0
- package/dist/components/forms/PhoneInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/SearchInput.svelte +358 -0
- package/dist/components/forms/SearchInput.svelte.d.ts +33 -0
- package/dist/components/forms/SearchInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/Select.svelte +83 -0
- package/dist/components/forms/Select.svelte.d.ts +11 -0
- package/dist/components/forms/Select.svelte.d.ts.map +1 -0
- package/dist/components/forms/SelectInput.svelte +254 -0
- package/dist/components/forms/SelectInput.svelte.d.ts +25 -0
- package/dist/components/forms/SelectInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/TextInput.svelte +415 -0
- package/dist/components/forms/TextInput.svelte.d.ts +26 -0
- package/dist/components/forms/TextInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/Textarea.svelte +85 -0
- package/dist/components/forms/Textarea.svelte.d.ts +10 -0
- package/dist/components/forms/Textarea.svelte.d.ts.map +1 -0
- package/dist/components/forms/TextareaInput.svelte +386 -0
- package/dist/components/forms/TextareaInput.svelte.d.ts +26 -0
- package/dist/components/forms/TextareaInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/Toggle.svelte +217 -0
- package/dist/components/forms/Toggle.svelte.d.ts +37 -0
- package/dist/components/forms/Toggle.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/AddressInput.behavior.test.js +122 -0
- package/dist/components/forms/__tests__/CheckboxInput.test.js +92 -0
- package/dist/components/forms/__tests__/DateRangeInput.behavior.test.js +135 -0
- package/dist/components/forms/__tests__/DateTimeInput.behavior.test.js +103 -0
- package/dist/components/forms/__tests__/FileUpload.test.js +90 -0
- package/dist/components/forms/__tests__/Form.behavior.test.js +137 -0
- package/dist/components/forms/__tests__/Form.test.js +58 -0
- package/dist/components/forms/__tests__/FormGroup.test.js +48 -0
- package/dist/components/forms/__tests__/FormMicButton.test.js +86 -0
- package/dist/components/forms/__tests__/Input.test.js +49 -0
- package/dist/components/forms/__tests__/MeasurementInput.behavior.test.js +129 -0
- package/dist/components/forms/__tests__/MoneyInput.behavior.test.js +124 -0
- package/dist/components/forms/__tests__/NumberInput.behavior.test.js +141 -0
- package/dist/components/forms/__tests__/PhoneInput.behavior.test.js +96 -0
- package/dist/components/forms/__tests__/SearchInput.test.js +79 -0
- package/dist/components/forms/__tests__/Select.test.js +37 -0
- package/dist/components/forms/__tests__/SelectInput.behavior.test.js +132 -0
- package/dist/components/forms/__tests__/TextInput.behavior.test.js +131 -0
- package/dist/components/forms/__tests__/Textarea.test.js +39 -0
- package/dist/components/forms/__tests__/TextareaInput.behavior.test.js +96 -0
- package/dist/components/forms/__tests__/Toggle.test.js +87 -0
- package/dist/components/forms/__tests__/composite-inputs-a11y.test.js +69 -0
- package/dist/components/forms/__tests__/form-group-input.fixture.svelte +16 -0
- package/dist/components/forms/__tests__/form-group-input.fixture.svelte.d.ts +9 -0
- package/dist/components/forms/__tests__/form-group-input.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte +33 -0
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts +12 -0
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/rich-inputs-a11y.test.js +87 -0
- package/dist/components/forms/index.d.ts +25 -0
- package/dist/components/forms/index.d.ts.map +1 -0
- package/dist/components/forms/index.js +25 -0
- package/dist/components/forms/types.d.ts +33 -0
- package/dist/components/forms/types.d.ts.map +1 -0
- package/dist/components/forms/types.js +4 -0
- package/dist/components/module/ModulePanel.svelte +134 -0
- package/dist/components/module/ModulePanel.svelte.d.ts +22 -0
- package/dist/components/module/ModulePanel.svelte.d.ts.map +1 -0
- package/dist/components/module/index.d.ts +5 -0
- package/dist/components/module/index.d.ts.map +1 -0
- package/dist/components/module/index.js +4 -0
- package/dist/components/workspace/Breadcrumbs.svelte +141 -0
- package/dist/components/workspace/Breadcrumbs.svelte.d.ts +21 -0
- package/dist/components/workspace/Breadcrumbs.svelte.d.ts.map +1 -0
- package/dist/components/workspace/NavTree.svelte +354 -0
- package/dist/components/workspace/NavTree.svelte.d.ts +45 -0
- package/dist/components/workspace/NavTree.svelte.d.ts.map +1 -0
- package/dist/components/workspace/README.md +34 -0
- package/dist/components/workspace/RoleShell.svelte +309 -0
- package/dist/components/workspace/RoleShell.svelte.d.ts +91 -0
- package/dist/components/workspace/RoleShell.svelte.d.ts.map +1 -0
- package/dist/components/workspace/WorkspaceShell.svelte +951 -0
- package/dist/components/workspace/WorkspaceShell.svelte.d.ts +112 -0
- package/dist/components/workspace/WorkspaceShell.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/RoleShell.test.js +772 -0
- package/dist/components/workspace/__tests__/WorkspaceShell.test.js +630 -0
- package/dist/components/workspace/__tests__/breadcrumbs-helpers.test.js +141 -0
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte +45 -0
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte.d.ts +21 -0
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/define-tools-dock.test.js +1010 -0
- package/dist/components/workspace/__tests__/harness.svelte +25 -0
- package/dist/components/workspace/__tests__/harness.svelte.d.ts +14 -0
- package/dist/components/workspace/__tests__/harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/index.test.js +37 -0
- package/dist/components/workspace/__tests__/manifest-nav-helpers.test.js +24 -0
- package/dist/components/workspace/__tests__/manifest-nav.test.js +599 -0
- package/dist/components/workspace/__tests__/nav-helpers.test.js +95 -0
- package/dist/components/workspace/__tests__/render-harness.svelte +66 -0
- package/dist/components/workspace/__tests__/render-harness.svelte.d.ts +32 -0
- package/dist/components/workspace/__tests__/render-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/render-tools-dock.test.js +243 -0
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte +58 -0
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte.d.ts +16 -0
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte +41 -0
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte.d.ts +13 -0
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/test-icon.svelte +17 -0
- package/dist/components/workspace/__tests__/test-icon.svelte.d.ts +19 -0
- package/dist/components/workspace/__tests__/test-icon.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte +38 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte.d.ts +22 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.d.ts +65 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.js +115 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.d.ts +15 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.js +7 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture.test.js +115 -0
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte +9 -0
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte.d.ts +19 -0
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/use-harness.svelte +23 -0
- package/dist/components/workspace/__tests__/use-harness.svelte.d.ts +8 -0
- package/dist/components/workspace/__tests__/use-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/use-tools-dock.test.js +33 -0
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte +43 -0
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte.d.ts +11 -0
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/breadcrumbs-helpers.d.ts +44 -0
- package/dist/components/workspace/breadcrumbs-helpers.d.ts.map +1 -0
- package/dist/components/workspace/breadcrumbs-helpers.js +88 -0
- package/dist/components/workspace/index.d.ts +16 -0
- package/dist/components/workspace/index.d.ts.map +1 -0
- package/dist/components/workspace/index.js +14 -0
- package/dist/components/workspace/manifest-nav.d.ts +200 -0
- package/dist/components/workspace/manifest-nav.d.ts.map +1 -0
- package/dist/components/workspace/manifest-nav.js +408 -0
- package/dist/components/workspace/nav-helpers.d.ts +36 -0
- package/dist/components/workspace/nav-helpers.d.ts.map +1 -0
- package/dist/components/workspace/nav-helpers.js +60 -0
- package/dist/components/workspace/server/__tests__/compose-availability.test.js +383 -0
- package/dist/components/workspace/server/__tests__/typed-context-fixture.d.ts +78 -0
- package/dist/components/workspace/server/__tests__/typed-context-fixture.d.ts.map +1 -0
- package/dist/components/workspace/server/__tests__/typed-context-fixture.js +104 -0
- package/dist/components/workspace/server/compose-availability.d.ts +73 -0
- package/dist/components/workspace/server/compose-availability.d.ts.map +1 -0
- package/dist/components/workspace/server/compose-availability.js +114 -0
- package/dist/components/workspace/server/index.d.ts +13 -0
- package/dist/components/workspace/server/index.d.ts.map +1 -0
- package/dist/components/workspace/server/index.js +11 -0
- package/dist/components/workspace/server/types.d.ts +108 -0
- package/dist/components/workspace/server/types.d.ts.map +1 -0
- package/dist/components/workspace/server/types.js +11 -0
- package/dist/components/workspace/tools-dock/ToolsDock.svelte +565 -0
- package/dist/components/workspace/tools-dock/ToolsDock.svelte.d.ts +14 -0
- package/dist/components/workspace/tools-dock/ToolsDock.svelte.d.ts.map +1 -0
- package/dist/components/workspace/tools-dock/define-tools-dock.svelte.d.ts +143 -0
- package/dist/components/workspace/tools-dock/define-tools-dock.svelte.d.ts.map +1 -0
- package/dist/components/workspace/tools-dock/define-tools-dock.svelte.js +487 -0
- package/dist/components/workspace/tools-dock/use-tools-dock.d.ts +41 -0
- package/dist/components/workspace/tools-dock/use-tools-dock.d.ts.map +1 -0
- package/dist/components/workspace/tools-dock/use-tools-dock.js +50 -0
- package/dist/components/workspace/types.d.ts +372 -0
- package/dist/components/workspace/types.d.ts.map +1 -0
- package/dist/components/workspace/types.js +6 -0
- package/dist/hooks/index.d.ts +11 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +10 -0
- package/dist/hooks/useAppState.svelte.d.ts +46 -0
- package/dist/hooks/useAppState.svelte.d.ts.map +1 -0
- package/dist/hooks/useAppState.svelte.js +59 -0
- package/dist/hooks/useAuth.svelte.d.ts +41 -0
- package/dist/hooks/useAuth.svelte.d.ts.map +1 -0
- package/dist/hooks/useAuth.svelte.js +43 -0
- package/dist/hooks/useLLM.svelte.d.ts +69 -0
- package/dist/hooks/useLLM.svelte.d.ts.map +1 -0
- package/dist/hooks/useLLM.svelte.js +85 -0
- package/dist/hooks/useSTT.svelte.d.ts +68 -0
- package/dist/hooks/useSTT.svelte.d.ts.map +1 -0
- package/dist/hooks/useSTT.svelte.js +97 -0
- package/dist/hooks/useSocket.svelte.d.ts +45 -0
- package/dist/hooks/useSocket.svelte.d.ts.map +1 -0
- package/dist/hooks/useSocket.svelte.js +54 -0
- package/dist/hooks/useTTS.svelte.d.ts +65 -0
- package/dist/hooks/useTTS.svelte.d.ts.map +1 -0
- package/dist/hooks/useTTS.svelte.js +93 -0
- package/dist/hooks/useTheme.d.ts +13 -0
- package/dist/hooks/useTheme.d.ts.map +1 -0
- package/dist/hooks/useTheme.js +16 -0
- package/dist/i18n/__tests__/server.spec.js +50 -0
- package/dist/i18n/server.d.ts +47 -0
- package/dist/i18n/server.d.ts.map +1 -0
- package/dist/i18n/server.js +58 -0
- package/dist/i18n/strings.forms.d.ts +33 -0
- package/dist/i18n/strings.forms.d.ts.map +1 -0
- package/dist/i18n/strings.forms.js +54 -0
- package/dist/i18n/strings.workspace.d.ts +34 -0
- package/dist/i18n/strings.workspace.d.ts.map +1 -0
- package/dist/i18n/strings.workspace.js +40 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/state/__tests__/warm-clients.test.js +40 -0
- package/dist/state/app-state.d.ts +308 -0
- package/dist/state/app-state.d.ts.map +1 -0
- package/dist/state/app-state.js +64 -0
- package/dist/state/app-state.svelte.d.ts +196 -0
- package/dist/state/app-state.svelte.d.ts.map +1 -0
- package/dist/state/app-state.svelte.js +774 -0
- package/dist/state/context.d.ts +23 -0
- package/dist/state/context.d.ts.map +1 -0
- package/dist/state/context.js +32 -0
- package/dist/state/form-context.d.ts +59 -0
- package/dist/state/form-context.d.ts.map +1 -0
- package/dist/state/form-context.js +31 -0
- package/dist/state/form-group-context.d.ts +13 -0
- package/dist/state/form-group-context.d.ts.map +1 -0
- package/dist/state/form-group-context.js +28 -0
- package/dist/state/index.d.ts +9 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +8 -0
- package/dist/state/warm-clients.d.ts +136 -0
- package/dist/state/warm-clients.d.ts.map +1 -0
- package/dist/state/warm-clients.js +231 -0
- package/package.json +137 -0
|
@@ -0,0 +1,951 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
import { M } from '../../i18n/strings.workspace.js';
|
|
5
|
+
|
|
6
|
+
const { t } = useI18n();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* WorkspaceShell — SvelteKit-agnostic, SSR-safe admin shell primitive.
|
|
10
|
+
*
|
|
11
|
+
* A composition of snippet slots that lays out a typical workspace UI: brand
|
|
12
|
+
* + nav sidebar, sticky topbar, main content, optional right-side inspector
|
|
13
|
+
* panel and a thin icon rail. The component owns no domain logic — every
|
|
14
|
+
* visible region (brand, nav, account menu, tools dock, etc.) is provided by
|
|
15
|
+
* the consumer via Svelte 5 snippets.
|
|
16
|
+
*
|
|
17
|
+
* Responsive behavior:
|
|
18
|
+
* - Desktop (>1240px): sidebar visible, inspector fixed-right when open.
|
|
19
|
+
* - Tablet (961–1240px): sidebar collapses to icon rail.
|
|
20
|
+
* - Mobile (≤960px): sidebar becomes a drawer with backdrop; inspector
|
|
21
|
+
* becomes a right-side drawer with backdrop.
|
|
22
|
+
*
|
|
23
|
+
* Sidebar collapse is controlled — consumer owns persistence. Mobile drawer
|
|
24
|
+
* state defaults to internal/transient but can be lifted via the bindable
|
|
25
|
+
* `mobileNavOpen` prop (see below) for consumers that need to close the
|
|
26
|
+
* drawer in response to events the shell doesn't own (e.g. a route change
|
|
27
|
+
* fired from a nav-tree click). Pair `bind:mobileNavOpen={...}` on the
|
|
28
|
+
* shell with `<NavTree onNavigate={() => (mobileNavOpen = false)} />`
|
|
29
|
+
* inside the `nav` snippet to close the drawer on every link click —
|
|
30
|
+
* no DOM querying required.
|
|
31
|
+
*
|
|
32
|
+
* See `@happyvertical/smrt#1227` for the issue tracking this primitive,
|
|
33
|
+
* and `happyvertical/smrt#1235` for the bindable-drawer follow-up.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
export interface Props {
|
|
37
|
+
/** Brand/product title shown in the brand snippet area fallback. */
|
|
38
|
+
title?: string;
|
|
39
|
+
/** Secondary line under the title. */
|
|
40
|
+
subtitle?: string;
|
|
41
|
+
/** Small uppercase eyebrow label rendered above the title. */
|
|
42
|
+
eyebrow?: string;
|
|
43
|
+
/** Topbar mode label (e.g. "Local-first mode"). */
|
|
44
|
+
modeLabel?: string;
|
|
45
|
+
/** Status keyword that maps to a dot color. */
|
|
46
|
+
modeStatus?:
|
|
47
|
+
| 'active'
|
|
48
|
+
| 'offline'
|
|
49
|
+
| 'local-only'
|
|
50
|
+
| 'attention'
|
|
51
|
+
| (string & {});
|
|
52
|
+
/** Secondary detail line shown next to the mode badge. */
|
|
53
|
+
modeDetail?: string;
|
|
54
|
+
/** Whether the inspector panel/drawer is currently shown. */
|
|
55
|
+
showInspector?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Label rendered in the inspector header. Defaults to `'Inspector'`.
|
|
58
|
+
* Consumers may rename to `'Properties'`, `'Details'`, etc.
|
|
59
|
+
*/
|
|
60
|
+
inspectorTitle?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Invoked when the inspector close button (or Escape) is activated.
|
|
63
|
+
*
|
|
64
|
+
* Focus restoration: because `showInspector` is a controlled prop, the
|
|
65
|
+
* consumer owns when the inspector opens and is therefore responsible
|
|
66
|
+
* for restoring focus to the activating element after close (WCAG
|
|
67
|
+
* 2.4.3). A common pattern is to capture `document.activeElement`
|
|
68
|
+
* immediately before flipping `showInspector` to `true`, then call
|
|
69
|
+
* `.focus()` on it inside this handler.
|
|
70
|
+
*
|
|
71
|
+
* The component-owned mobile drawer handles focus restoration
|
|
72
|
+
* internally — only the inspector is consumer-driven.
|
|
73
|
+
*/
|
|
74
|
+
onCloseInspector?: () => void;
|
|
75
|
+
/** Sidebar collapsed state (controlled by consumer). */
|
|
76
|
+
collapsed?: boolean;
|
|
77
|
+
/** Invoked when the internal collapse toggle is clicked. */
|
|
78
|
+
onToggleCollapsed?: () => void;
|
|
79
|
+
/** Whether to render the collapse toggle at all. Default: true. */
|
|
80
|
+
collapsible?: boolean;
|
|
81
|
+
/** Top-left brand area (logo + product name). */
|
|
82
|
+
brand?: Snippet;
|
|
83
|
+
/** Main sidebar navigation region. */
|
|
84
|
+
nav?: Snippet;
|
|
85
|
+
/** Bottom of sidebar (account menu, tenant switcher, etc.). */
|
|
86
|
+
sidebarFooter?: Snippet;
|
|
87
|
+
/** Right side of the top bar. */
|
|
88
|
+
topbarActions?: Snippet;
|
|
89
|
+
/** Optional vertical icon rail along the right edge. */
|
|
90
|
+
inspectorRail?: Snippet;
|
|
91
|
+
/**
|
|
92
|
+
* Inspector panel content (right side). Rendered into a `position: fixed`
|
|
93
|
+
* panel anchored to the right edge — z-index `22` on desktop, `22` on
|
|
94
|
+
* mobile (with a `21` scrim).
|
|
95
|
+
*
|
|
96
|
+
* **Positioning conflict**: do NOT use this snippet simultaneously with
|
|
97
|
+
* `<ToolsDock layout='topbar'>`. In topbar mode, the dock owns its own
|
|
98
|
+
* `position: fixed` panel anchored to the bottom-right (z-index `40`)
|
|
99
|
+
* with no z-index coordination against the shell's inspector — both
|
|
100
|
+
* panels will visibly overlap and compete for clicks. Pick one:
|
|
101
|
+
* - For consumer-driven inspector content → use this snippet only,
|
|
102
|
+
* and use `<ToolsDock layout='rail'>` (the rail layout renders its
|
|
103
|
+
* panel inside its own aside, no positioning conflict)
|
|
104
|
+
* - For tools-dock-driven content → leave this snippet unused and
|
|
105
|
+
* render `<ToolsDock layout='topbar'>` inside `topbarActions`
|
|
106
|
+
*/
|
|
107
|
+
inspector?: Snippet;
|
|
108
|
+
/** Main content. */
|
|
109
|
+
children: Snippet;
|
|
110
|
+
/**
|
|
111
|
+
* Mobile drawer open-state. Defaults to `false` and is managed
|
|
112
|
+
* internally — the hamburger button, backdrop, and Escape key all
|
|
113
|
+
* toggle it. Consumers who need to close the drawer in response to
|
|
114
|
+
* events outside the shell (e.g. a nav-link click in their nav
|
|
115
|
+
* snippet) can lift the state via `bind:mobileNavOpen={...}` and
|
|
116
|
+
* mutate it directly. SSR-safe — initial value is honored on the
|
|
117
|
+
* server (the drawer is only visible on the ≤960px breakpoint).
|
|
118
|
+
*/
|
|
119
|
+
mobileNavOpen?: boolean;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
let {
|
|
123
|
+
title = '',
|
|
124
|
+
subtitle = '',
|
|
125
|
+
eyebrow = '',
|
|
126
|
+
modeLabel = '',
|
|
127
|
+
modeStatus = '',
|
|
128
|
+
modeDetail = '',
|
|
129
|
+
showInspector = false,
|
|
130
|
+
inspectorTitle = 'Inspector',
|
|
131
|
+
onCloseInspector,
|
|
132
|
+
collapsed = false,
|
|
133
|
+
onToggleCollapsed,
|
|
134
|
+
collapsible = true,
|
|
135
|
+
brand,
|
|
136
|
+
nav,
|
|
137
|
+
sidebarFooter,
|
|
138
|
+
topbarActions,
|
|
139
|
+
inspectorRail,
|
|
140
|
+
inspector,
|
|
141
|
+
children,
|
|
142
|
+
mobileNavOpen = $bindable(false),
|
|
143
|
+
}: Props = $props();
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Tracks whether the viewport is in the mobile drawer breakpoint
|
|
147
|
+
* (≤960px). Used to mark the sidebar `inert` when it's slid off-screen
|
|
148
|
+
* so keyboard users can't tab into invisible nav links. SSR-safe — stays
|
|
149
|
+
* `false` until mounted, which matches the desktop-first default layout.
|
|
150
|
+
*/
|
|
151
|
+
let isMobileViewport = $state(false);
|
|
152
|
+
/**
|
|
153
|
+
* Element that held focus when the mobile drawer was opened. We restore
|
|
154
|
+
* focus to it when the drawer closes (Escape, backdrop click, etc.) to
|
|
155
|
+
* satisfy WCAG 2.4.3 Focus Order for the component-owned drawer state.
|
|
156
|
+
* The inspector's open state is consumer-controlled, so focus restoration
|
|
157
|
+
* for it is documented as a caller responsibility (see `onCloseInspector`).
|
|
158
|
+
*/
|
|
159
|
+
let lastFocusedBeforeMobileNav: HTMLElement | null = null;
|
|
160
|
+
|
|
161
|
+
function toggleMobileNav(): void {
|
|
162
|
+
if (!mobileNavOpen) {
|
|
163
|
+
// Capture the currently focused element before we open the drawer so
|
|
164
|
+
// we can return focus to it on close (WCAG 2.4.3).
|
|
165
|
+
if (typeof document !== 'undefined') {
|
|
166
|
+
const active = document.activeElement;
|
|
167
|
+
lastFocusedBeforeMobileNav =
|
|
168
|
+
active instanceof HTMLElement ? active : null;
|
|
169
|
+
}
|
|
170
|
+
mobileNavOpen = true;
|
|
171
|
+
} else {
|
|
172
|
+
closeMobileNav();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function closeMobileNav(): void {
|
|
177
|
+
mobileNavOpen = false;
|
|
178
|
+
// Restore focus to the element that opened the drawer (the hamburger
|
|
179
|
+
// button in the default flow). Guarded so SSR/non-DOM environments are
|
|
180
|
+
// a no-op, and so a detached/removed element doesn't throw.
|
|
181
|
+
const target = lastFocusedBeforeMobileNav;
|
|
182
|
+
lastFocusedBeforeMobileNav = null;
|
|
183
|
+
if (
|
|
184
|
+
target &&
|
|
185
|
+
typeof document !== 'undefined' &&
|
|
186
|
+
document.contains(target) &&
|
|
187
|
+
typeof target.focus === 'function'
|
|
188
|
+
) {
|
|
189
|
+
target.focus();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function handleCollapseToggle(): void {
|
|
194
|
+
onToggleCollapsed?.();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function handleInspectorClose(): void {
|
|
198
|
+
onCloseInspector?.();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Escape closes mobile drawer (with focus restoration) or inspector if
|
|
202
|
+
// open. Mounted-only (SSR-safe via $effect).
|
|
203
|
+
$effect(() => {
|
|
204
|
+
if (typeof window === 'undefined') return;
|
|
205
|
+
|
|
206
|
+
function onKeydown(event: KeyboardEvent) {
|
|
207
|
+
if (event.key !== 'Escape') return;
|
|
208
|
+
if (mobileNavOpen) {
|
|
209
|
+
closeMobileNav();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (showInspector && onCloseInspector) {
|
|
213
|
+
onCloseInspector();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
window.addEventListener('keydown', onKeydown);
|
|
218
|
+
return () => window.removeEventListener('keydown', onKeydown);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Track mobile breakpoint so the sidebar can be marked `inert` while it
|
|
222
|
+
// is slid off-screen. Mirrors the `@media (max-width: 960px)` block.
|
|
223
|
+
$effect(() => {
|
|
224
|
+
if (typeof window === 'undefined' || !window.matchMedia) return;
|
|
225
|
+
|
|
226
|
+
const mql = window.matchMedia('(max-width: 960px)');
|
|
227
|
+
isMobileViewport = mql.matches;
|
|
228
|
+
|
|
229
|
+
function handleChange(event: MediaQueryListEvent) {
|
|
230
|
+
isMobileViewport = event.matches;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// `addEventListener` is the modern API. Older Safari only has
|
|
234
|
+
// `addListener` — feature-detect to stay compatible. The deprecated
|
|
235
|
+
// `addListener`/`removeListener` methods are typed in current lib.dom.d.ts,
|
|
236
|
+
// so no `@ts-expect-error` is needed.
|
|
237
|
+
if (typeof mql.addEventListener === 'function') {
|
|
238
|
+
mql.addEventListener('change', handleChange);
|
|
239
|
+
return () => mql.removeEventListener('change', handleChange);
|
|
240
|
+
}
|
|
241
|
+
mql.addListener(handleChange);
|
|
242
|
+
return () => {
|
|
243
|
+
mql.removeListener(handleChange);
|
|
244
|
+
};
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
const hasInspector = $derived(Boolean(inspector) && showInspector);
|
|
248
|
+
const hasInspectorRail = $derived(Boolean(inspectorRail));
|
|
249
|
+
/**
|
|
250
|
+
* Mark the sidebar `inert` when it's slid off-screen on mobile so keyboard
|
|
251
|
+
* users can't tab into invisible nav links / footer controls.
|
|
252
|
+
*/
|
|
253
|
+
const sidebarInert = $derived(isMobileViewport && !mobileNavOpen);
|
|
254
|
+
</script>
|
|
255
|
+
|
|
256
|
+
<div
|
|
257
|
+
class="smrt-workspace-shell"
|
|
258
|
+
class:sidebar-collapsed={collapsed}
|
|
259
|
+
class:nav-open={mobileNavOpen}
|
|
260
|
+
class:has-inspector={hasInspector}
|
|
261
|
+
class:has-inspector-rail={hasInspectorRail}
|
|
262
|
+
>
|
|
263
|
+
<!-- Mobile sidebar backdrop -->
|
|
264
|
+
<button
|
|
265
|
+
class="mobile-backdrop"
|
|
266
|
+
type="button"
|
|
267
|
+
aria-label={t(M['ui.workspace_shell.close_navigation'])}
|
|
268
|
+
tabindex={mobileNavOpen ? 0 : -1}
|
|
269
|
+
onclick={closeMobileNav}
|
|
270
|
+
></button>
|
|
271
|
+
|
|
272
|
+
<!--
|
|
273
|
+
Mobile inspector backdrop. Only renders an interactive button when the
|
|
274
|
+
consumer provided `onCloseInspector` — otherwise the backdrop would be a
|
|
275
|
+
focusable no-op. When no close handler is provided we render a passive
|
|
276
|
+
`<div>` so the visual scrim still appears on mobile.
|
|
277
|
+
-->
|
|
278
|
+
{#if hasInspector}
|
|
279
|
+
{#if onCloseInspector}
|
|
280
|
+
<button
|
|
281
|
+
class="inspector-backdrop"
|
|
282
|
+
type="button"
|
|
283
|
+
aria-label={t(M['ui.workspace_shell.close_inspector'])}
|
|
284
|
+
onclick={handleInspectorClose}
|
|
285
|
+
></button>
|
|
286
|
+
{:else}
|
|
287
|
+
<div class="inspector-backdrop" aria-hidden="true"></div>
|
|
288
|
+
{/if}
|
|
289
|
+
{/if}
|
|
290
|
+
|
|
291
|
+
<aside
|
|
292
|
+
class="smrt-workspace-sidebar"
|
|
293
|
+
aria-label={t(M['ui.workspace_shell.primary_navigation'])}
|
|
294
|
+
inert={sidebarInert}
|
|
295
|
+
>
|
|
296
|
+
<div class="brand-row">
|
|
297
|
+
<div class="brand">
|
|
298
|
+
{#if brand}
|
|
299
|
+
{@render brand()}
|
|
300
|
+
{:else}
|
|
301
|
+
{#if eyebrow}
|
|
302
|
+
<span class="eyebrow">{eyebrow}</span>
|
|
303
|
+
{/if}
|
|
304
|
+
{#if title}
|
|
305
|
+
<h1>{title}</h1>
|
|
306
|
+
{/if}
|
|
307
|
+
{#if subtitle}
|
|
308
|
+
<p class="subtitle">{subtitle}</p>
|
|
309
|
+
{/if}
|
|
310
|
+
{/if}
|
|
311
|
+
</div>
|
|
312
|
+
|
|
313
|
+
{#if collapsible && onToggleCollapsed}
|
|
314
|
+
<button
|
|
315
|
+
class="shell-toggle"
|
|
316
|
+
type="button"
|
|
317
|
+
onclick={handleCollapseToggle}
|
|
318
|
+
aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}
|
|
319
|
+
aria-expanded={!collapsed}
|
|
320
|
+
>
|
|
321
|
+
<span class="shell-toggle-glyph" aria-hidden="true">
|
|
322
|
+
{collapsed ? '›' : '‹'}
|
|
323
|
+
</span>
|
|
324
|
+
</button>
|
|
325
|
+
{/if}
|
|
326
|
+
</div>
|
|
327
|
+
|
|
328
|
+
{#if nav}
|
|
329
|
+
<nav class="nav-region" aria-label={t(M['ui.workspace_shell.workspace_navigation'])}>
|
|
330
|
+
{@render nav()}
|
|
331
|
+
</nav>
|
|
332
|
+
{/if}
|
|
333
|
+
|
|
334
|
+
{#if sidebarFooter}
|
|
335
|
+
<div class="sidebar-footer">
|
|
336
|
+
{@render sidebarFooter()}
|
|
337
|
+
</div>
|
|
338
|
+
{/if}
|
|
339
|
+
</aside>
|
|
340
|
+
|
|
341
|
+
<div class="smrt-workspace-main">
|
|
342
|
+
<header class="smrt-workspace-topbar">
|
|
343
|
+
<div class="topbar-left">
|
|
344
|
+
<button
|
|
345
|
+
class="mobile-menu"
|
|
346
|
+
type="button"
|
|
347
|
+
onclick={toggleMobileNav}
|
|
348
|
+
aria-label={mobileNavOpen ? 'Close navigation' : 'Open navigation'}
|
|
349
|
+
aria-expanded={mobileNavOpen}
|
|
350
|
+
>
|
|
351
|
+
<span aria-hidden="true">≡</span>
|
|
352
|
+
</button>
|
|
353
|
+
<div class="topbar-brand">
|
|
354
|
+
{#if eyebrow}
|
|
355
|
+
<div class="eyebrow topbar-eyebrow">{eyebrow}</div>
|
|
356
|
+
{/if}
|
|
357
|
+
{#if modeLabel}
|
|
358
|
+
<p class="mode-title">{modeLabel}</p>
|
|
359
|
+
{/if}
|
|
360
|
+
</div>
|
|
361
|
+
</div>
|
|
362
|
+
|
|
363
|
+
<div class="topbar-right">
|
|
364
|
+
{#if topbarActions}
|
|
365
|
+
<div class="topbar-actions">
|
|
366
|
+
{@render topbarActions()}
|
|
367
|
+
</div>
|
|
368
|
+
{/if}
|
|
369
|
+
{#if modeLabel || modeStatus}
|
|
370
|
+
<span
|
|
371
|
+
class="mode-badge"
|
|
372
|
+
data-status={modeStatus || 'default'}
|
|
373
|
+
role="status"
|
|
374
|
+
aria-live="polite"
|
|
375
|
+
>
|
|
376
|
+
<span class="mode-dot" aria-hidden="true"></span>
|
|
377
|
+
<span class="mode-badge-label">{modeLabel || modeStatus}</span>
|
|
378
|
+
</span>
|
|
379
|
+
{/if}
|
|
380
|
+
{#if modeDetail}
|
|
381
|
+
<p class="mode-detail">{modeDetail}</p>
|
|
382
|
+
{/if}
|
|
383
|
+
</div>
|
|
384
|
+
</header>
|
|
385
|
+
|
|
386
|
+
<div class="smrt-workspace-stage">
|
|
387
|
+
<main class="smrt-workspace-content">
|
|
388
|
+
{@render children()}
|
|
389
|
+
</main>
|
|
390
|
+
|
|
391
|
+
{#if hasInspector}
|
|
392
|
+
<aside
|
|
393
|
+
class="smrt-workspace-inspector"
|
|
394
|
+
aria-label={inspectorTitle}
|
|
395
|
+
>
|
|
396
|
+
<div class="inspector-header">
|
|
397
|
+
<span class="inspector-title">{inspectorTitle}</span>
|
|
398
|
+
{#if onCloseInspector}
|
|
399
|
+
<button
|
|
400
|
+
class="inspector-close"
|
|
401
|
+
type="button"
|
|
402
|
+
onclick={handleInspectorClose}
|
|
403
|
+
aria-label={t(M['ui.workspace_shell.close_inspector'])}
|
|
404
|
+
>
|
|
405
|
+
<span aria-hidden="true">×</span>
|
|
406
|
+
</button>
|
|
407
|
+
{/if}
|
|
408
|
+
</div>
|
|
409
|
+
<div class="inspector-body">
|
|
410
|
+
{@render inspector!()}
|
|
411
|
+
</div>
|
|
412
|
+
</aside>
|
|
413
|
+
{/if}
|
|
414
|
+
|
|
415
|
+
{#if hasInspectorRail}
|
|
416
|
+
<div
|
|
417
|
+
class="smrt-workspace-inspector-rail"
|
|
418
|
+
role="toolbar"
|
|
419
|
+
aria-label={t(M['ui.workspace_shell.inspector_tools'])}
|
|
420
|
+
aria-orientation="vertical"
|
|
421
|
+
>
|
|
422
|
+
{@render inspectorRail!()}
|
|
423
|
+
</div>
|
|
424
|
+
{/if}
|
|
425
|
+
</div>
|
|
426
|
+
</div>
|
|
427
|
+
</div>
|
|
428
|
+
|
|
429
|
+
<style>
|
|
430
|
+
.smrt-workspace-shell {
|
|
431
|
+
--smrt-ws-sidebar-width: 280px;
|
|
432
|
+
--smrt-ws-sidebar-collapsed-width: 96px;
|
|
433
|
+
--smrt-ws-inspector-width: min(420px, calc(100vw - var(--smrt-ws-sidebar-width) - 1rem));
|
|
434
|
+
--smrt-ws-rail-width: 3.25rem;
|
|
435
|
+
--smrt-ws-topbar-height: 3.75rem;
|
|
436
|
+
--smrt-ws-page-pad: 1.5rem;
|
|
437
|
+
|
|
438
|
+
position: relative;
|
|
439
|
+
display: grid;
|
|
440
|
+
grid-template-columns: var(--smrt-ws-sidebar-width) 1fr;
|
|
441
|
+
min-height: 100vh;
|
|
442
|
+
min-height: 100dvh;
|
|
443
|
+
background: var(--smrt-color-surface-container-low, #f8fafc);
|
|
444
|
+
color: var(--smrt-color-on-surface, #1f2937);
|
|
445
|
+
isolation: isolate;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.smrt-workspace-shell.sidebar-collapsed {
|
|
449
|
+
grid-template-columns: var(--smrt-ws-sidebar-collapsed-width) 1fr;
|
|
450
|
+
/*
|
|
451
|
+
* When the sidebar is collapsed, recompute the inspector-width clamp
|
|
452
|
+
* against the collapsed sidebar so narrower desktops with both the
|
|
453
|
+
* inspector and a collapsed sidebar still fit content. Without this
|
|
454
|
+
* override, padding-right on `.smrt-workspace-content` would still be
|
|
455
|
+
* sized as if the sidebar were full-width.
|
|
456
|
+
*/
|
|
457
|
+
--smrt-ws-inspector-width: min(
|
|
458
|
+
420px,
|
|
459
|
+
calc(100vw - var(--smrt-ws-sidebar-collapsed-width) - 1rem)
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/* ─── Sidebar ─────────────────────────────────────────── */
|
|
464
|
+
|
|
465
|
+
.smrt-workspace-sidebar {
|
|
466
|
+
position: sticky;
|
|
467
|
+
top: 0;
|
|
468
|
+
align-self: start;
|
|
469
|
+
display: flex;
|
|
470
|
+
flex-direction: column;
|
|
471
|
+
gap: 1.25rem;
|
|
472
|
+
padding: 1.25rem 1rem;
|
|
473
|
+
height: 100vh;
|
|
474
|
+
height: 100dvh;
|
|
475
|
+
box-sizing: border-box;
|
|
476
|
+
background: var(--smrt-color-surface, #ffffff);
|
|
477
|
+
border-right: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
|
|
478
|
+
min-width: 0;
|
|
479
|
+
overflow: hidden;
|
|
480
|
+
overscroll-behavior: contain;
|
|
481
|
+
z-index: 20;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.brand-row {
|
|
485
|
+
display: flex;
|
|
486
|
+
justify-content: space-between;
|
|
487
|
+
align-items: flex-start;
|
|
488
|
+
gap: 0.75rem;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.brand {
|
|
492
|
+
display: grid;
|
|
493
|
+
gap: 0.35rem;
|
|
494
|
+
min-width: 0;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
.brand :global(h1),
|
|
498
|
+
.brand h1 {
|
|
499
|
+
margin: 0;
|
|
500
|
+
font-size: var(--smrt-typography-title-large-size, 1.25rem);
|
|
501
|
+
line-height: var(--smrt-typography-title-large-line-height, 1.1);
|
|
502
|
+
color: var(--smrt-color-on-surface, #111827);
|
|
503
|
+
font-weight: var(--smrt-typography-weight-semibold, 600);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.brand .subtitle {
|
|
507
|
+
margin: 0;
|
|
508
|
+
color: var(--smrt-color-on-surface-variant, #6b7280);
|
|
509
|
+
line-height: var(--smrt-typography-body-medium-line-height, 1.4);
|
|
510
|
+
font-size: var(--smrt-typography-body-medium-size, 0.9rem);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.eyebrow {
|
|
514
|
+
font-size: var(--smrt-typography-label-small-size, 0.7rem);
|
|
515
|
+
font-weight: var(--smrt-typography-weight-bold, 700);
|
|
516
|
+
letter-spacing: var(--smrt-typography-label-small-tracking, 0.12em);
|
|
517
|
+
text-transform: uppercase;
|
|
518
|
+
color: var(--smrt-color-on-surface-variant, #6b7280);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
.shell-toggle {
|
|
522
|
+
appearance: none;
|
|
523
|
+
border: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
|
|
524
|
+
background: var(--smrt-color-surface-container, #f3f4f6);
|
|
525
|
+
color: var(--smrt-color-on-surface, #111827);
|
|
526
|
+
border-radius: var(--smrt-radius-medium, 0.65rem);
|
|
527
|
+
width: 2rem;
|
|
528
|
+
height: 2rem;
|
|
529
|
+
display: inline-flex;
|
|
530
|
+
align-items: center;
|
|
531
|
+
justify-content: center;
|
|
532
|
+
cursor: pointer;
|
|
533
|
+
flex-shrink: 0;
|
|
534
|
+
transition:
|
|
535
|
+
background-color 150ms ease,
|
|
536
|
+
color 150ms ease;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
.shell-toggle:hover {
|
|
540
|
+
background: var(--smrt-color-surface-container-high, #e5e7eb);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.shell-toggle:focus-visible {
|
|
544
|
+
outline: 2px solid var(--smrt-color-primary, #2563eb);
|
|
545
|
+
outline-offset: 2px;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.shell-toggle-glyph {
|
|
549
|
+
font-size: var(--smrt-typography-body-large-size, 1rem);
|
|
550
|
+
line-height: 1;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
.nav-region {
|
|
554
|
+
display: flex;
|
|
555
|
+
flex-direction: column;
|
|
556
|
+
flex: 1 1 auto;
|
|
557
|
+
min-height: 0;
|
|
558
|
+
gap: 0.5rem;
|
|
559
|
+
overflow-y: auto;
|
|
560
|
+
overscroll-behavior: contain;
|
|
561
|
+
scrollbar-gutter: stable;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
.sidebar-footer {
|
|
565
|
+
margin-top: auto;
|
|
566
|
+
flex: 0 0 auto;
|
|
567
|
+
display: grid;
|
|
568
|
+
gap: 0.75rem;
|
|
569
|
+
padding-top: 0.75rem;
|
|
570
|
+
background: var(--smrt-color-surface, #ffffff);
|
|
571
|
+
border-top: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
|
|
572
|
+
z-index: 1;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/* ─── Main column ─────────────────────────────────────── */
|
|
576
|
+
|
|
577
|
+
.smrt-workspace-main {
|
|
578
|
+
display: flex;
|
|
579
|
+
flex-direction: column;
|
|
580
|
+
min-width: 0;
|
|
581
|
+
min-height: 0;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
.smrt-workspace-topbar {
|
|
585
|
+
position: sticky;
|
|
586
|
+
top: 0;
|
|
587
|
+
z-index: 10;
|
|
588
|
+
display: flex;
|
|
589
|
+
align-items: center;
|
|
590
|
+
justify-content: space-between;
|
|
591
|
+
gap: 0.85rem;
|
|
592
|
+
padding: 0.75rem var(--smrt-ws-page-pad);
|
|
593
|
+
min-height: var(--smrt-ws-topbar-height);
|
|
594
|
+
background: var(--smrt-color-surface, #ffffff);
|
|
595
|
+
border-bottom: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
|
|
596
|
+
box-shadow: var(--smrt-elevation-1, 0 1px 2px rgb(0 0 0 / 0.05));
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
.topbar-left,
|
|
600
|
+
.topbar-right {
|
|
601
|
+
display: flex;
|
|
602
|
+
align-items: center;
|
|
603
|
+
gap: 0.7rem;
|
|
604
|
+
min-width: 0;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
.topbar-right {
|
|
608
|
+
justify-content: flex-end;
|
|
609
|
+
flex-wrap: wrap;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
.topbar-actions {
|
|
613
|
+
display: flex;
|
|
614
|
+
align-items: center;
|
|
615
|
+
gap: 0.4rem;
|
|
616
|
+
flex-wrap: wrap;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
.topbar-brand {
|
|
620
|
+
display: grid;
|
|
621
|
+
gap: 0.1rem;
|
|
622
|
+
min-width: 0;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
.topbar-eyebrow {
|
|
626
|
+
color: var(--smrt-color-on-surface-variant, #6b7280);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
.mode-title,
|
|
630
|
+
.mode-detail {
|
|
631
|
+
margin: 0;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
.mode-title {
|
|
635
|
+
font-size: var(--smrt-typography-title-small-size, 0.9rem);
|
|
636
|
+
font-weight: var(--smrt-typography-weight-semibold, 600);
|
|
637
|
+
color: var(--smrt-color-on-surface, #111827);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
.mode-detail {
|
|
641
|
+
color: var(--smrt-color-on-surface-variant, #6b7280);
|
|
642
|
+
max-width: 18rem;
|
|
643
|
+
text-align: right;
|
|
644
|
+
font-size: var(--smrt-typography-body-medium-size, 0.85rem);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
.mode-badge {
|
|
648
|
+
display: inline-flex;
|
|
649
|
+
align-items: center;
|
|
650
|
+
gap: 0.4rem;
|
|
651
|
+
padding: 0.25rem 0.65rem;
|
|
652
|
+
border-radius: var(--smrt-radius-full, 999px);
|
|
653
|
+
border: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
|
|
654
|
+
background: var(--smrt-color-surface-container, #f3f4f6);
|
|
655
|
+
color: var(--smrt-color-on-surface, #111827);
|
|
656
|
+
font-size: var(--smrt-typography-label-medium-size, 0.78rem);
|
|
657
|
+
font-weight: var(--smrt-typography-weight-semibold, 600);
|
|
658
|
+
line-height: 1;
|
|
659
|
+
white-space: nowrap;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
.mode-dot {
|
|
663
|
+
width: 0.55rem;
|
|
664
|
+
height: 0.55rem;
|
|
665
|
+
border-radius: var(--smrt-radius-full, 9999px);
|
|
666
|
+
background: var(--smrt-color-on-surface-variant, #9ca3af);
|
|
667
|
+
flex-shrink: 0;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
.mode-badge[data-status='active'] .mode-dot {
|
|
671
|
+
background: var(--smrt-color-success, #16a34a);
|
|
672
|
+
}
|
|
673
|
+
.mode-badge[data-status='offline'] .mode-dot {
|
|
674
|
+
background: var(--smrt-color-on-surface-variant, #9ca3af);
|
|
675
|
+
}
|
|
676
|
+
.mode-badge[data-status='local-only'] .mode-dot {
|
|
677
|
+
background: var(--smrt-color-primary, #2563eb);
|
|
678
|
+
}
|
|
679
|
+
.mode-badge[data-status='attention'] .mode-dot {
|
|
680
|
+
background: var(--smrt-color-warning, #f59e0b);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
.mobile-menu {
|
|
684
|
+
display: none;
|
|
685
|
+
appearance: none;
|
|
686
|
+
border: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
|
|
687
|
+
background: var(--smrt-color-surface, #ffffff);
|
|
688
|
+
color: var(--smrt-color-on-surface, #111827);
|
|
689
|
+
border-radius: var(--smrt-radius-medium, 0.65rem);
|
|
690
|
+
width: 2.35rem;
|
|
691
|
+
height: 2.35rem;
|
|
692
|
+
align-items: center;
|
|
693
|
+
justify-content: center;
|
|
694
|
+
cursor: pointer;
|
|
695
|
+
font-size: var(--smrt-typography-body-large-size, 1.1rem);
|
|
696
|
+
line-height: 1;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
.mobile-menu:focus-visible,
|
|
700
|
+
.inspector-close:focus-visible {
|
|
701
|
+
outline: 2px solid var(--smrt-color-primary, #2563eb);
|
|
702
|
+
outline-offset: 2px;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/* ─── Stage / content / inspector ─────────────────────── */
|
|
706
|
+
|
|
707
|
+
.smrt-workspace-stage {
|
|
708
|
+
flex: 1;
|
|
709
|
+
min-height: 0;
|
|
710
|
+
position: relative;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.smrt-workspace-content {
|
|
714
|
+
padding: var(--smrt-ws-page-pad);
|
|
715
|
+
min-width: 0;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
.smrt-workspace-inspector {
|
|
719
|
+
position: fixed;
|
|
720
|
+
top: 0;
|
|
721
|
+
right: 0;
|
|
722
|
+
bottom: 0;
|
|
723
|
+
width: var(--smrt-ws-inspector-width);
|
|
724
|
+
display: flex;
|
|
725
|
+
flex-direction: column;
|
|
726
|
+
background: var(--smrt-color-surface, #ffffff);
|
|
727
|
+
border-left: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
|
|
728
|
+
box-shadow: var(--smrt-elevation-2, 0 4px 6px -1px rgb(0 0 0 / 0.1));
|
|
729
|
+
z-index: 22;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
.inspector-header {
|
|
733
|
+
display: flex;
|
|
734
|
+
align-items: center;
|
|
735
|
+
justify-content: space-between;
|
|
736
|
+
padding: 0.85rem 1rem;
|
|
737
|
+
border-bottom: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.inspector-title {
|
|
741
|
+
font-weight: var(--smrt-typography-weight-semibold, 600);
|
|
742
|
+
color: var(--smrt-color-on-surface, #111827);
|
|
743
|
+
font-size: var(--smrt-typography-title-medium-size, 0.95rem);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
.inspector-close {
|
|
747
|
+
appearance: none;
|
|
748
|
+
border: 1px solid transparent;
|
|
749
|
+
background: transparent;
|
|
750
|
+
color: var(--smrt-color-on-surface-variant, #6b7280);
|
|
751
|
+
border-radius: var(--smrt-radius-medium, 0.5rem);
|
|
752
|
+
width: 2rem;
|
|
753
|
+
height: 2rem;
|
|
754
|
+
display: inline-flex;
|
|
755
|
+
align-items: center;
|
|
756
|
+
justify-content: center;
|
|
757
|
+
font-size: var(--smrt-typography-title-large-size, 1.25rem);
|
|
758
|
+
line-height: 1;
|
|
759
|
+
cursor: pointer;
|
|
760
|
+
transition:
|
|
761
|
+
background-color 150ms ease,
|
|
762
|
+
color 150ms ease;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
.inspector-close:hover {
|
|
766
|
+
background: var(--smrt-color-surface-container-high, #e5e7eb);
|
|
767
|
+
color: var(--smrt-color-on-surface, #111827);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
.inspector-body {
|
|
771
|
+
flex: 1;
|
|
772
|
+
min-height: 0;
|
|
773
|
+
overflow-y: auto;
|
|
774
|
+
padding: 1rem;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
.smrt-workspace-inspector-rail {
|
|
778
|
+
position: fixed;
|
|
779
|
+
top: var(--smrt-ws-topbar-height);
|
|
780
|
+
right: 0;
|
|
781
|
+
bottom: 0;
|
|
782
|
+
width: var(--smrt-ws-rail-width);
|
|
783
|
+
display: flex;
|
|
784
|
+
flex-direction: column;
|
|
785
|
+
align-items: center;
|
|
786
|
+
gap: 0.4rem;
|
|
787
|
+
padding: 0.75rem 0.25rem;
|
|
788
|
+
background: var(--smrt-color-surface, #ffffff);
|
|
789
|
+
border-left: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
|
|
790
|
+
z-index: 18;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
/* When both inspector + rail are present, push rail off the panel. */
|
|
794
|
+
.smrt-workspace-shell.has-inspector.has-inspector-rail .smrt-workspace-inspector-rail {
|
|
795
|
+
right: var(--smrt-ws-inspector-width);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/* Reserve room on the right side so content doesn't slide under panel/rail. */
|
|
799
|
+
@media (min-width: 961px) {
|
|
800
|
+
.smrt-workspace-shell.has-inspector .smrt-workspace-content,
|
|
801
|
+
.smrt-workspace-shell.has-inspector .smrt-workspace-topbar {
|
|
802
|
+
padding-right: calc(var(--smrt-ws-inspector-width) + 1rem);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
.smrt-workspace-shell.has-inspector-rail:not(.has-inspector)
|
|
806
|
+
.smrt-workspace-content,
|
|
807
|
+
.smrt-workspace-shell.has-inspector-rail:not(.has-inspector)
|
|
808
|
+
.smrt-workspace-topbar {
|
|
809
|
+
padding-right: calc(var(--smrt-ws-rail-width) + 1rem);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/*
|
|
813
|
+
* When both the inspector panel AND the icon rail are present, the rail
|
|
814
|
+
* sits to the left of the panel (see `.has-inspector.has-inspector-rail
|
|
815
|
+
* .smrt-workspace-inspector-rail` above). Content padding must reserve
|
|
816
|
+
* room for both, otherwise the rail overlaps the right edge of content
|
|
817
|
+
* and topbar.
|
|
818
|
+
*/
|
|
819
|
+
.smrt-workspace-shell.has-inspector.has-inspector-rail
|
|
820
|
+
.smrt-workspace-content,
|
|
821
|
+
.smrt-workspace-shell.has-inspector.has-inspector-rail
|
|
822
|
+
.smrt-workspace-topbar {
|
|
823
|
+
padding-right: calc(
|
|
824
|
+
var(--smrt-ws-inspector-width) + var(--smrt-ws-rail-width) + 1rem
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/* ─── Backdrops (mobile only — hidden otherwise) ──────── */
|
|
830
|
+
|
|
831
|
+
/*
|
|
832
|
+
* Defence-in-depth: `display: none` already hides these on desktop, but a
|
|
833
|
+
* consumer global like `button { display: flex }` could undo that. Setting
|
|
834
|
+
* `pointer-events: none` ensures the backdrop can never intercept clicks
|
|
835
|
+
* on the desktop even if it slips back into the rendering tree.
|
|
836
|
+
*/
|
|
837
|
+
.mobile-backdrop,
|
|
838
|
+
.inspector-backdrop {
|
|
839
|
+
display: none;
|
|
840
|
+
pointer-events: none;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/* ─── Tablet — collapse sidebar to icon rail ──────────── */
|
|
844
|
+
|
|
845
|
+
@media (max-width: 1240px) and (min-width: 961px) {
|
|
846
|
+
.smrt-workspace-shell {
|
|
847
|
+
grid-template-columns: var(--smrt-ws-sidebar-collapsed-width) 1fr;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
.smrt-workspace-shell .brand-row {
|
|
851
|
+
justify-content: center;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
.smrt-workspace-shell .shell-toggle {
|
|
855
|
+
display: none;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
.smrt-workspace-shell .brand .subtitle,
|
|
859
|
+
.smrt-workspace-shell.sidebar-collapsed .brand .subtitle {
|
|
860
|
+
display: none;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/* ─── Mobile — drawer sidebar, drawer inspector ───────── */
|
|
865
|
+
|
|
866
|
+
@media (max-width: 960px) {
|
|
867
|
+
.smrt-workspace-shell,
|
|
868
|
+
.smrt-workspace-shell.sidebar-collapsed {
|
|
869
|
+
grid-template-columns: 1fr;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
.mobile-menu {
|
|
873
|
+
display: inline-flex;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
.shell-toggle {
|
|
877
|
+
display: none;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.smrt-workspace-sidebar {
|
|
881
|
+
position: fixed;
|
|
882
|
+
inset: 0 auto 0 0;
|
|
883
|
+
width: min(320px, calc(100vw - 3rem));
|
|
884
|
+
transform: translateX(-100%);
|
|
885
|
+
transition: transform 180ms ease;
|
|
886
|
+
z-index: 30;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
.smrt-workspace-shell.nav-open .smrt-workspace-sidebar {
|
|
890
|
+
transform: translateX(0);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
.mobile-backdrop {
|
|
894
|
+
display: block;
|
|
895
|
+
position: fixed;
|
|
896
|
+
inset: 0;
|
|
897
|
+
background: var(--smrt-color-scrim);
|
|
898
|
+
opacity: 0;
|
|
899
|
+
pointer-events: none;
|
|
900
|
+
transition: opacity 180ms ease;
|
|
901
|
+
border: 0;
|
|
902
|
+
z-index: 25;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
.smrt-workspace-shell.nav-open .mobile-backdrop {
|
|
906
|
+
opacity: 1;
|
|
907
|
+
pointer-events: auto;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
/* Override the inspector-width variable on mobile so the rail's right
|
|
911
|
+
* offset (.has-inspector.has-inspector-rail .smrt-workspace-inspector-rail
|
|
912
|
+
* uses var(--smrt-ws-inspector-width) for `right`) stays in sync with
|
|
913
|
+
* the actual rendered inspector width. */
|
|
914
|
+
.smrt-workspace-shell {
|
|
915
|
+
--smrt-ws-inspector-width: min(100vw, 420px);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
.smrt-workspace-shell.has-inspector .smrt-workspace-inspector-rail,
|
|
919
|
+
.smrt-workspace-shell.has-inspector-rail:not(.has-inspector)
|
|
920
|
+
.smrt-workspace-inspector-rail {
|
|
921
|
+
top: 0;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
.smrt-workspace-shell.has-inspector .smrt-workspace-content,
|
|
925
|
+
.smrt-workspace-shell.has-inspector .smrt-workspace-topbar {
|
|
926
|
+
padding-right: var(--smrt-ws-page-pad);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
.smrt-workspace-shell.has-inspector-rail:not(.has-inspector)
|
|
930
|
+
.smrt-workspace-content,
|
|
931
|
+
.smrt-workspace-shell.has-inspector-rail:not(.has-inspector)
|
|
932
|
+
.smrt-workspace-topbar {
|
|
933
|
+
padding-right: calc(var(--smrt-ws-rail-width) + var(--smrt-ws-page-pad));
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
.inspector-backdrop {
|
|
937
|
+
display: block;
|
|
938
|
+
pointer-events: auto;
|
|
939
|
+
position: fixed;
|
|
940
|
+
inset: 0;
|
|
941
|
+
background: var(--smrt-color-scrim);
|
|
942
|
+
border: 0;
|
|
943
|
+
z-index: 21;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
.mode-detail {
|
|
947
|
+
max-width: 100%;
|
|
948
|
+
text-align: left;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
</style>
|