@walkthru-earth/objex 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +396 -0
- package/README.md +114 -0
- package/dist/assets/favicon.svg +17 -0
- package/dist/components/CLAUDE.md +44 -0
- package/dist/components/browser/Breadcrumb.svelte +50 -0
- package/dist/components/browser/Breadcrumb.svelte.d.ts +7 -0
- package/dist/components/browser/CreateFolderDialog.svelte +98 -0
- package/dist/components/browser/CreateFolderDialog.svelte.d.ts +6 -0
- package/dist/components/browser/DeleteConfirmDialog.svelte +90 -0
- package/dist/components/browser/DeleteConfirmDialog.svelte.d.ts +8 -0
- package/dist/components/browser/DropZone.svelte +83 -0
- package/dist/components/browser/DropZone.svelte.d.ts +7 -0
- package/dist/components/browser/FileBrowser.svelte +229 -0
- package/dist/components/browser/FileBrowser.svelte.d.ts +3 -0
- package/dist/components/browser/FileRow.svelte +112 -0
- package/dist/components/browser/FileRow.svelte.d.ts +9 -0
- package/dist/components/browser/FileTreeSidebar.svelte +559 -0
- package/dist/components/browser/FileTreeSidebar.svelte.d.ts +8 -0
- package/dist/components/browser/RenameDialog.svelte +101 -0
- package/dist/components/browser/RenameDialog.svelte.d.ts +8 -0
- package/dist/components/browser/SearchBar.svelte +40 -0
- package/dist/components/browser/SearchBar.svelte.d.ts +6 -0
- package/dist/components/browser/UploadButton.svelte +65 -0
- package/dist/components/browser/UploadButton.svelte.d.ts +3 -0
- package/dist/components/editor/CodeMirrorEditor.svelte +404 -0
- package/dist/components/editor/CodeMirrorEditor.svelte.d.ts +12 -0
- package/dist/components/editor/MilkdownEditor.svelte +98 -0
- package/dist/components/editor/MilkdownEditor.svelte.d.ts +9 -0
- package/dist/components/editor/SqlEditor.svelte +173 -0
- package/dist/components/editor/SqlEditor.svelte.d.ts +7 -0
- package/dist/components/editor/SqlResultBlock.svelte +199 -0
- package/dist/components/editor/SqlResultBlock.svelte.d.ts +9 -0
- package/dist/components/layout/ConnectionDialog.svelte +439 -0
- package/dist/components/layout/ConnectionDialog.svelte.d.ts +9 -0
- package/dist/components/layout/LocaleToggle.svelte +32 -0
- package/dist/components/layout/LocaleToggle.svelte.d.ts +3 -0
- package/dist/components/layout/SafeLockToggle.svelte +37 -0
- package/dist/components/layout/SafeLockToggle.svelte.d.ts +18 -0
- package/dist/components/layout/Sidebar.svelte +314 -0
- package/dist/components/layout/Sidebar.svelte.d.ts +3 -0
- package/dist/components/layout/StatusBar.svelte +73 -0
- package/dist/components/layout/StatusBar.svelte.d.ts +3 -0
- package/dist/components/layout/TabBar.svelte +102 -0
- package/dist/components/layout/TabBar.svelte.d.ts +7 -0
- package/dist/components/layout/ThemeToggle.svelte +52 -0
- package/dist/components/layout/ThemeToggle.svelte.d.ts +3 -0
- package/dist/components/ui/badge/badge.svelte +49 -0
- package/dist/components/ui/badge/badge.svelte.d.ts +32 -0
- package/dist/components/ui/badge/index.d.ts +1 -0
- package/dist/components/ui/badge/index.js +1 -0
- package/dist/components/ui/button/button.svelte +82 -0
- package/dist/components/ui/button/button.svelte.d.ts +64 -0
- package/dist/components/ui/button/index.d.ts +2 -0
- package/dist/components/ui/button/index.js +4 -0
- package/dist/components/ui/context-menu/context-menu-checkbox-item.svelte +40 -0
- package/dist/components/ui/context-menu/context-menu-checkbox-item.svelte.d.ts +9 -0
- package/dist/components/ui/context-menu/context-menu-content.svelte +28 -0
- package/dist/components/ui/context-menu/context-menu-content.svelte.d.ts +10 -0
- package/dist/components/ui/context-menu/context-menu-group-heading.svelte +21 -0
- package/dist/components/ui/context-menu/context-menu-group-heading.svelte.d.ts +7 -0
- package/dist/components/ui/context-menu/context-menu-group.svelte +7 -0
- package/dist/components/ui/context-menu/context-menu-group.svelte.d.ts +4 -0
- package/dist/components/ui/context-menu/context-menu-item.svelte +27 -0
- package/dist/components/ui/context-menu/context-menu-item.svelte.d.ts +8 -0
- package/dist/components/ui/context-menu/context-menu-label.svelte +24 -0
- package/dist/components/ui/context-menu/context-menu-label.svelte.d.ts +8 -0
- package/dist/components/ui/context-menu/context-menu-portal.svelte +7 -0
- package/dist/components/ui/context-menu/context-menu-portal.svelte.d.ts +3 -0
- package/dist/components/ui/context-menu/context-menu-radio-group.svelte +16 -0
- package/dist/components/ui/context-menu/context-menu-radio-group.svelte.d.ts +4 -0
- package/dist/components/ui/context-menu/context-menu-radio-item.svelte +33 -0
- package/dist/components/ui/context-menu/context-menu-radio-item.svelte.d.ts +4 -0
- package/dist/components/ui/context-menu/context-menu-separator.svelte +17 -0
- package/dist/components/ui/context-menu/context-menu-separator.svelte.d.ts +4 -0
- package/dist/components/ui/context-menu/context-menu-shortcut.svelte +20 -0
- package/dist/components/ui/context-menu/context-menu-shortcut.svelte.d.ts +5 -0
- package/dist/components/ui/context-menu/context-menu-sub-content.svelte +20 -0
- package/dist/components/ui/context-menu/context-menu-sub-content.svelte.d.ts +4 -0
- package/dist/components/ui/context-menu/context-menu-sub-trigger.svelte +29 -0
- package/dist/components/ui/context-menu/context-menu-sub-trigger.svelte.d.ts +8 -0
- package/dist/components/ui/context-menu/context-menu-sub.svelte +7 -0
- package/dist/components/ui/context-menu/context-menu-sub.svelte.d.ts +3 -0
- package/dist/components/ui/context-menu/context-menu-trigger.svelte +7 -0
- package/dist/components/ui/context-menu/context-menu-trigger.svelte.d.ts +4 -0
- package/dist/components/ui/context-menu/context-menu.svelte +7 -0
- package/dist/components/ui/context-menu/context-menu.svelte.d.ts +3 -0
- package/dist/components/ui/context-menu/index.d.ts +17 -0
- package/dist/components/ui/context-menu/index.js +19 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +43 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +9 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte +29 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte.d.ts +10 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte.d.ts +8 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-group.svelte +7 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-group.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte +27 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte.d.ts +8 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte +24 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte.d.ts +8 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-portal.svelte +7 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-portal.svelte.d.ts +3 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +33 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte +17 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +20 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte.d.ts +5 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +20 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte.d.ts +7 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub.svelte +7 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub.svelte.d.ts +3 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu.svelte +7 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu.svelte.d.ts +3 -0
- package/dist/components/ui/dropdown-menu/index.d.ts +18 -0
- package/dist/components/ui/dropdown-menu/index.js +18 -0
- package/dist/components/ui/input/index.d.ts +2 -0
- package/dist/components/ui/input/index.js +4 -0
- package/dist/components/ui/input/input.svelte +52 -0
- package/dist/components/ui/input/input.svelte.d.ts +13 -0
- package/dist/components/ui/resizable/index.d.ts +4 -0
- package/dist/components/ui/resizable/index.js +6 -0
- package/dist/components/ui/resizable/resizable-handle.svelte +30 -0
- package/dist/components/ui/resizable/resizable-handle.svelte.d.ts +8 -0
- package/dist/components/ui/resizable/resizable-pane-group.svelte +20 -0
- package/dist/components/ui/resizable/resizable-pane-group.svelte.d.ts +7 -0
- package/dist/components/ui/scroll-area/index.d.ts +3 -0
- package/dist/components/ui/scroll-area/index.js +5 -0
- package/dist/components/ui/scroll-area/scroll-area-scrollbar.svelte +31 -0
- package/dist/components/ui/scroll-area/scroll-area-scrollbar.svelte.d.ts +4 -0
- package/dist/components/ui/scroll-area/scroll-area.svelte +47 -0
- package/dist/components/ui/scroll-area/scroll-area.svelte.d.ts +11 -0
- package/dist/components/ui/separator/index.d.ts +2 -0
- package/dist/components/ui/separator/index.js +4 -0
- package/dist/components/ui/separator/separator.svelte +21 -0
- package/dist/components/ui/separator/separator.svelte.d.ts +4 -0
- package/dist/components/ui/sheet/index.d.ts +11 -0
- package/dist/components/ui/sheet/index.js +13 -0
- package/dist/components/ui/sheet/sheet-close.svelte +7 -0
- package/dist/components/ui/sheet/sheet-close.svelte.d.ts +4 -0
- package/dist/components/ui/sheet/sheet-content.svelte +62 -0
- package/dist/components/ui/sheet/sheet-content.svelte.d.ts +37 -0
- package/dist/components/ui/sheet/sheet-description.svelte +17 -0
- package/dist/components/ui/sheet/sheet-description.svelte.d.ts +4 -0
- package/dist/components/ui/sheet/sheet-footer.svelte +20 -0
- package/dist/components/ui/sheet/sheet-footer.svelte.d.ts +5 -0
- package/dist/components/ui/sheet/sheet-header.svelte +20 -0
- package/dist/components/ui/sheet/sheet-header.svelte.d.ts +5 -0
- package/dist/components/ui/sheet/sheet-overlay.svelte +20 -0
- package/dist/components/ui/sheet/sheet-overlay.svelte.d.ts +4 -0
- package/dist/components/ui/sheet/sheet-portal.svelte +7 -0
- package/dist/components/ui/sheet/sheet-portal.svelte.d.ts +3 -0
- package/dist/components/ui/sheet/sheet-title.svelte +13 -0
- package/dist/components/ui/sheet/sheet-title.svelte.d.ts +4 -0
- package/dist/components/ui/sheet/sheet-trigger.svelte +7 -0
- package/dist/components/ui/sheet/sheet-trigger.svelte.d.ts +4 -0
- package/dist/components/ui/sheet/sheet.svelte +7 -0
- package/dist/components/ui/sheet/sheet.svelte.d.ts +3 -0
- package/dist/components/ui/switch/index.d.ts +2 -0
- package/dist/components/ui/switch/index.js +4 -0
- package/dist/components/ui/switch/switch.svelte +28 -0
- package/dist/components/ui/switch/switch.svelte.d.ts +8 -0
- package/dist/components/ui/tabs/index.d.ts +5 -0
- package/dist/components/ui/tabs/index.js +7 -0
- package/dist/components/ui/tabs/tabs-content.svelte +17 -0
- package/dist/components/ui/tabs/tabs-content.svelte.d.ts +4 -0
- package/dist/components/ui/tabs/tabs-list.svelte +16 -0
- package/dist/components/ui/tabs/tabs-list.svelte.d.ts +4 -0
- package/dist/components/ui/tabs/tabs-trigger.svelte +20 -0
- package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +4 -0
- package/dist/components/ui/tabs/tabs.svelte +19 -0
- package/dist/components/ui/tabs/tabs.svelte.d.ts +4 -0
- package/dist/components/ui/tooltip/index.d.ts +6 -0
- package/dist/components/ui/tooltip/index.js +8 -0
- package/dist/components/ui/tooltip/tooltip-content.svelte +52 -0
- package/dist/components/ui/tooltip/tooltip-content.svelte.d.ts +11 -0
- package/dist/components/ui/tooltip/tooltip-portal.svelte +7 -0
- package/dist/components/ui/tooltip/tooltip-portal.svelte.d.ts +4 -0
- package/dist/components/ui/tooltip/tooltip-provider.svelte +7 -0
- package/dist/components/ui/tooltip/tooltip-provider.svelte.d.ts +4 -0
- package/dist/components/ui/tooltip/tooltip-trigger.svelte +7 -0
- package/dist/components/ui/tooltip/tooltip-trigger.svelte.d.ts +4 -0
- package/dist/components/ui/tooltip/tooltip.svelte +7 -0
- package/dist/components/ui/tooltip/tooltip.svelte.d.ts +4 -0
- package/dist/components/viewers/ArchiveViewer.svelte +586 -0
- package/dist/components/viewers/ArchiveViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/CLAUDE.md +60 -0
- package/dist/components/viewers/CodeViewer.svelte +553 -0
- package/dist/components/viewers/CodeViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/CogViewer.svelte +1345 -0
- package/dist/components/viewers/CogViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/CopcViewer.svelte +25 -0
- package/dist/components/viewers/CopcViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/DatabaseViewer.svelte +169 -0
- package/dist/components/viewers/DatabaseViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/FileInfo.svelte +174 -0
- package/dist/components/viewers/FileInfo.svelte.d.ts +10 -0
- package/dist/components/viewers/FlatGeobufViewer.svelte +755 -0
- package/dist/components/viewers/FlatGeobufViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/GeoParquetMapViewer.svelte +278 -0
- package/dist/components/viewers/GeoParquetMapViewer.svelte.d.ts +17 -0
- package/dist/components/viewers/ImageViewer.svelte +233 -0
- package/dist/components/viewers/ImageViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/LoadProgress.svelte +93 -0
- package/dist/components/viewers/LoadProgress.svelte.d.ts +15 -0
- package/dist/components/viewers/MapViewer.svelte +234 -0
- package/dist/components/viewers/MapViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/MarkdownViewer.svelte +478 -0
- package/dist/components/viewers/MarkdownViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/MediaViewer.svelte +121 -0
- package/dist/components/viewers/MediaViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/ModelViewer.svelte +164 -0
- package/dist/components/viewers/ModelViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/NotebookViewer.svelte +389 -0
- package/dist/components/viewers/NotebookViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/PdfViewer.svelte +278 -0
- package/dist/components/viewers/PdfViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/PmtilesViewer.svelte +191 -0
- package/dist/components/viewers/PmtilesViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/QueryHistoryPanel.svelte +159 -0
- package/dist/components/viewers/QueryHistoryPanel.svelte.d.ts +8 -0
- package/dist/components/viewers/RawViewer.svelte +117 -0
- package/dist/components/viewers/RawViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/StacMapViewer.svelte +20 -0
- package/dist/components/viewers/StacMapViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/StyleEditorOverlay.svelte +27 -0
- package/dist/components/viewers/StyleEditorOverlay.svelte.d.ts +7 -0
- package/dist/components/viewers/TableGrid.svelte +355 -0
- package/dist/components/viewers/TableGrid.svelte.d.ts +12 -0
- package/dist/components/viewers/TableStatusBar.svelte +92 -0
- package/dist/components/viewers/TableStatusBar.svelte.d.ts +11 -0
- package/dist/components/viewers/TableToolbar.svelte +382 -0
- package/dist/components/viewers/TableToolbar.svelte.d.ts +25 -0
- package/dist/components/viewers/TableViewer.svelte +923 -0
- package/dist/components/viewers/TableViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/ViewerRouter.svelte +70 -0
- package/dist/components/viewers/ViewerRouter.svelte.d.ts +7 -0
- package/dist/components/viewers/ZarrMapViewer.svelte +288 -0
- package/dist/components/viewers/ZarrMapViewer.svelte.d.ts +17 -0
- package/dist/components/viewers/ZarrViewer.svelte +256 -0
- package/dist/components/viewers/ZarrViewer.svelte.d.ts +7 -0
- package/dist/components/viewers/map/AttributeTable.svelte +52 -0
- package/dist/components/viewers/map/AttributeTable.svelte.d.ts +8 -0
- package/dist/components/viewers/map/MapContainer.svelte +158 -0
- package/dist/components/viewers/map/MapContainer.svelte.d.ts +12 -0
- package/dist/components/viewers/pmtiles/PmtilesArchiveView.svelte +389 -0
- package/dist/components/viewers/pmtiles/PmtilesArchiveView.svelte.d.ts +10 -0
- package/dist/components/viewers/pmtiles/PmtilesMapView.svelte +332 -0
- package/dist/components/viewers/pmtiles/PmtilesMapView.svelte.d.ts +11 -0
- package/dist/components/viewers/pmtiles/PmtilesTileInspector.svelte +373 -0
- package/dist/components/viewers/pmtiles/PmtilesTileInspector.svelte.d.ts +12 -0
- package/dist/components/viewers/pmtiles/SvgTileRenderer.svelte +112 -0
- package/dist/components/viewers/pmtiles/SvgTileRenderer.svelte.d.ts +10 -0
- package/dist/file-icons/CLAUDE.md +21 -0
- package/dist/file-icons/FileTypeIcon.svelte +74 -0
- package/dist/file-icons/FileTypeIcon.svelte.d.ts +9 -0
- package/dist/file-icons/index.d.ts +56 -0
- package/dist/file-icons/index.js +1070 -0
- package/dist/i18n/CLAUDE.md +19 -0
- package/dist/i18n/ar.d.ts +1 -0
- package/dist/i18n/ar.js +404 -0
- package/dist/i18n/en.d.ts +1 -0
- package/dist/i18n/en.js +404 -0
- package/dist/i18n/index.svelte.d.ts +9 -0
- package/dist/i18n/index.svelte.js +27 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +13 -0
- package/dist/query/CLAUDE.md +22 -0
- package/dist/query/engine.d.ts +56 -0
- package/dist/query/engine.js +6 -0
- package/dist/query/index.d.ts +4 -0
- package/dist/query/index.js +19 -0
- package/dist/query/wasm.d.ts +20 -0
- package/dist/query/wasm.js +890 -0
- package/dist/storage/CLAUDE.md +23 -0
- package/dist/storage/adapter.d.ts +21 -0
- package/dist/storage/adapter.js +1 -0
- package/dist/storage/browser-azure.d.ts +25 -0
- package/dist/storage/browser-azure.js +271 -0
- package/dist/storage/browser-cloud.d.ts +32 -0
- package/dist/storage/browser-cloud.js +293 -0
- package/dist/storage/index.d.ts +11 -0
- package/dist/storage/index.js +37 -0
- package/dist/storage/url-adapter.d.ts +19 -0
- package/dist/storage/url-adapter.js +51 -0
- package/dist/stores/CLAUDE.md +29 -0
- package/dist/stores/browser.svelte.d.ts +28 -0
- package/dist/stores/browser.svelte.js +160 -0
- package/dist/stores/connections.svelte.d.ts +56 -0
- package/dist/stores/connections.svelte.js +272 -0
- package/dist/stores/credentials.svelte.d.ts +56 -0
- package/dist/stores/credentials.svelte.js +79 -0
- package/dist/stores/files.svelte.d.ts +20 -0
- package/dist/stores/files.svelte.js +76 -0
- package/dist/stores/query-history.svelte.d.ts +16 -0
- package/dist/stores/query-history.svelte.js +57 -0
- package/dist/stores/safelock.svelte.d.ts +8 -0
- package/dist/stores/safelock.svelte.js +52 -0
- package/dist/stores/settings.svelte.d.ts +11 -0
- package/dist/stores/settings.svelte.js +101 -0
- package/dist/stores/tab-resources.svelte.d.ts +25 -0
- package/dist/stores/tab-resources.svelte.js +61 -0
- package/dist/stores/tabs.svelte.d.ts +17 -0
- package/dist/stores/tabs.svelte.js +110 -0
- package/dist/types/notebookjs.d.ts +14 -0
- package/dist/types.d.ts +47 -0
- package/dist/types.js +1 -0
- package/dist/utils/CLAUDE.md +54 -0
- package/dist/utils/analytics.d.ts +10 -0
- package/dist/utils/analytics.js +38 -0
- package/dist/utils/archive.d.ts +70 -0
- package/dist/utils/archive.js +333 -0
- package/dist/utils/column-types.d.ts +5 -0
- package/dist/utils/column-types.js +137 -0
- package/dist/utils/deck.d.ts +98 -0
- package/dist/utils/deck.js +208 -0
- package/dist/utils/evidence-context.d.ts +22 -0
- package/dist/utils/evidence-context.js +56 -0
- package/dist/utils/export.d.ts +2 -0
- package/dist/utils/export.js +51 -0
- package/dist/utils/format.d.ts +14 -0
- package/dist/utils/format.js +56 -0
- package/dist/utils/geoarrow.d.ts +32 -0
- package/dist/utils/geoarrow.js +672 -0
- package/dist/utils/hex.d.ts +10 -0
- package/dist/utils/hex.js +27 -0
- package/dist/utils/host-detection.d.ts +23 -0
- package/dist/utils/host-detection.js +289 -0
- package/dist/utils/map-selection.d.ts +12 -0
- package/dist/utils/map-selection.js +45 -0
- package/dist/utils/markdown-sql.d.ts +30 -0
- package/dist/utils/markdown-sql.js +73 -0
- package/dist/utils/markdown.d.ts +18 -0
- package/dist/utils/markdown.js +146 -0
- package/dist/utils/model3d.d.ts +13 -0
- package/dist/utils/model3d.js +62 -0
- package/dist/utils/parquet-metadata.d.ts +58 -0
- package/dist/utils/parquet-metadata.js +228 -0
- package/dist/utils/pdf.d.ts +8 -0
- package/dist/utils/pdf.js +28 -0
- package/dist/utils/pmtiles-tile.d.ts +38 -0
- package/dist/utils/pmtiles-tile.js +64 -0
- package/dist/utils/pmtiles.d.ts +46 -0
- package/dist/utils/pmtiles.js +135 -0
- package/dist/utils/shiki.d.ts +8 -0
- package/dist/utils/shiki.js +98 -0
- package/dist/utils/storage-url.d.ts +64 -0
- package/dist/utils/storage-url.js +374 -0
- package/dist/utils/url-state.d.ts +40 -0
- package/dist/utils/url-state.js +113 -0
- package/dist/utils/url.d.ts +27 -0
- package/dist/utils/url.js +115 -0
- package/dist/utils/wkb.d.ts +43 -0
- package/dist/utils/wkb.js +345 -0
- package/dist/utils/zarr.d.ts +39 -0
- package/dist/utils/zarr.js +204 -0
- package/dist/utils.d.ts +12 -0
- package/dist/utils.js +5 -0
- package/package.json +203 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import CloudIcon from '@lucide/svelte/icons/cloud';
|
|
3
|
+
import DatabaseIcon from '@lucide/svelte/icons/database';
|
|
4
|
+
import GlobeIcon from '@lucide/svelte/icons/globe';
|
|
5
|
+
import PencilIcon from '@lucide/svelte/icons/pencil';
|
|
6
|
+
import PlusIcon from '@lucide/svelte/icons/plus';
|
|
7
|
+
import TrashIcon from '@lucide/svelte/icons/trash-2';
|
|
8
|
+
import {
|
|
9
|
+
ContextMenu,
|
|
10
|
+
ContextMenuContent,
|
|
11
|
+
ContextMenuItem,
|
|
12
|
+
ContextMenuSeparator,
|
|
13
|
+
ContextMenuTrigger
|
|
14
|
+
} from '../ui/context-menu/index.js';
|
|
15
|
+
import { Separator } from '../ui/separator/index.js';
|
|
16
|
+
import {
|
|
17
|
+
Tooltip,
|
|
18
|
+
TooltipContent,
|
|
19
|
+
TooltipProvider,
|
|
20
|
+
TooltipTrigger
|
|
21
|
+
} from '../ui/tooltip/index.js';
|
|
22
|
+
import { t } from '../../i18n/index.svelte.js';
|
|
23
|
+
import { browser } from '../../stores/browser.svelte.js';
|
|
24
|
+
import { connections } from '../../stores/connections.svelte.js';
|
|
25
|
+
import { credentialStore, loadFromNative } from '../../stores/credentials.svelte.js';
|
|
26
|
+
import { tabs } from '../../stores/tabs.svelte.js';
|
|
27
|
+
import type { Connection } from '../../types.js';
|
|
28
|
+
import { type DetectedHost, detectHostBucket } from '../../utils/host-detection.js';
|
|
29
|
+
import { parseStorageUrl } from '../../utils/storage-url.js';
|
|
30
|
+
import { clearUrlState, syncUrlParam } from '../../utils/url-state.js';
|
|
31
|
+
import ConnectionDialog from './ConnectionDialog.svelte';
|
|
32
|
+
import LocaleToggle from './LocaleToggle.svelte';
|
|
33
|
+
import ThemeToggle from './ThemeToggle.svelte';
|
|
34
|
+
|
|
35
|
+
let dialogOpen = $state(false);
|
|
36
|
+
let editingConnection = $state<Connection | null>(null);
|
|
37
|
+
let detectedHost = $state<DetectedHost | null>(null);
|
|
38
|
+
let autoConnecting = $state(false);
|
|
39
|
+
|
|
40
|
+
$effect(() => {
|
|
41
|
+
connections.load().then(async () => {
|
|
42
|
+
await handleAutoDetection();
|
|
43
|
+
// On first visit (no connections, no URL params), load the demo bucket
|
|
44
|
+
if (connections.items.length === 0 && !new URL(window.location.href).searchParams.has('url')) {
|
|
45
|
+
await loadDemoConnection();
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Allow other components to request opening the new-connection dialog
|
|
51
|
+
$effect(() => {
|
|
52
|
+
if (connections.dialogRequested) {
|
|
53
|
+
connections.clearDialogRequest();
|
|
54
|
+
handleAddConnection();
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
async function handleAutoDetection() {
|
|
59
|
+
// Direct file URLs (e.g. ?url=https://...file.parquet) are opened eagerly
|
|
60
|
+
// in +page.svelte so they work on mobile. Skip if tab already exists.
|
|
61
|
+
const url = new URL(window.location.href);
|
|
62
|
+
const rawUrl = url.searchParams.get('url');
|
|
63
|
+
if (rawUrl && tabs.items.some((t) => t.id === `url:${rawUrl}`)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const detected = detectHostBucket();
|
|
68
|
+
if (!detected) return;
|
|
69
|
+
|
|
70
|
+
const hasUrlParam = url.searchParams.has('url');
|
|
71
|
+
|
|
72
|
+
if (hasUrlParam) {
|
|
73
|
+
// Auto-connect immediately for ?url= param (zero-friction)
|
|
74
|
+
autoConnecting = true;
|
|
75
|
+
try {
|
|
76
|
+
const connId = await connections.saveHostConnection(detected);
|
|
77
|
+
const conn = connections.getById(connId);
|
|
78
|
+
if (!conn) return;
|
|
79
|
+
|
|
80
|
+
if (!(await ensureCredentials(conn))) return;
|
|
81
|
+
|
|
82
|
+
const parsed = parseStorageUrl(url.searchParams.get('url')!);
|
|
83
|
+
const prefixParam = parsed.prefix;
|
|
84
|
+
|
|
85
|
+
if (prefixParam && !prefixParam.endsWith('/')) {
|
|
86
|
+
// It's a file — browse to its parent folder and open it
|
|
87
|
+
const parentPrefix = prefixParam.includes('/') ? prefixParam.replace(/\/[^/]*$/, '/') : '';
|
|
88
|
+
browser.browse(conn, parentPrefix || undefined);
|
|
89
|
+
const fileName = prefixParam.split('/').pop() || prefixParam;
|
|
90
|
+
const ext = fileName.includes('.') ? fileName.split('.').pop()!.toLowerCase() : '';
|
|
91
|
+
const tabId = `${conn.id}:${prefixParam}`;
|
|
92
|
+
tabs.open({
|
|
93
|
+
id: tabId,
|
|
94
|
+
name: fileName,
|
|
95
|
+
path: prefixParam,
|
|
96
|
+
source: 'remote',
|
|
97
|
+
connectionId: conn.id,
|
|
98
|
+
extension: ext
|
|
99
|
+
});
|
|
100
|
+
// Fire-and-forget: fetch file size via HEAD request
|
|
101
|
+
fetch(url.searchParams.get('url')!, { method: 'HEAD' })
|
|
102
|
+
.then((res) => {
|
|
103
|
+
const cl = res.headers.get('content-length');
|
|
104
|
+
if (cl) tabs.update(tabId, { size: Number(cl) });
|
|
105
|
+
})
|
|
106
|
+
.catch(() => {});
|
|
107
|
+
} else if (prefixParam) {
|
|
108
|
+
// It's a directory prefix
|
|
109
|
+
browser.browse(conn, prefixParam);
|
|
110
|
+
} else {
|
|
111
|
+
browser.browse(conn);
|
|
112
|
+
}
|
|
113
|
+
syncUrlParam(conn, prefixParam || undefined);
|
|
114
|
+
} finally {
|
|
115
|
+
autoConnecting = false;
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
// Show indicator for hostname-detected bucket
|
|
119
|
+
detectedHost = detected;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function loadDemoConnection() {
|
|
124
|
+
const id = await connections.save({
|
|
125
|
+
name: 'Source Cooperative',
|
|
126
|
+
provider: 's3',
|
|
127
|
+
endpoint: '',
|
|
128
|
+
bucket: 'us-west-2.opendata.source.coop',
|
|
129
|
+
region: 'us-west-2',
|
|
130
|
+
anonymous: true
|
|
131
|
+
});
|
|
132
|
+
if (!id) return;
|
|
133
|
+
const conn = connections.getById(id);
|
|
134
|
+
if (conn) {
|
|
135
|
+
browser.browse(conn);
|
|
136
|
+
syncUrlParam(conn);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function handleConnectDetected() {
|
|
141
|
+
if (!detectedHost || autoConnecting) return;
|
|
142
|
+
autoConnecting = true;
|
|
143
|
+
try {
|
|
144
|
+
const connId = await connections.saveHostConnection(detectedHost);
|
|
145
|
+
const conn = connections.getById(connId);
|
|
146
|
+
if (conn) {
|
|
147
|
+
if (!(await ensureCredentials(conn))) return;
|
|
148
|
+
browser.browse(conn);
|
|
149
|
+
syncUrlParam(conn);
|
|
150
|
+
}
|
|
151
|
+
detectedHost = null;
|
|
152
|
+
} finally {
|
|
153
|
+
autoConnecting = false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function handleAddConnection() {
|
|
158
|
+
editingConnection = null;
|
|
159
|
+
dialogOpen = true;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function handleEditConnection(connection: Connection) {
|
|
163
|
+
editingConnection = connection;
|
|
164
|
+
dialogOpen = true;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function handleDeleteConnection(connection: Connection) {
|
|
168
|
+
if (!confirm(t('sidebar.deleteConfirm', { name: connection.name }))) return;
|
|
169
|
+
await connections.remove(connection.id);
|
|
170
|
+
if (browser.activeConnection?.id === connection.id) {
|
|
171
|
+
browser.clear();
|
|
172
|
+
clearUrlState();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Ensure credentials are available for a non-anonymous connection.
|
|
178
|
+
* Tries the browser password manager first, then opens the dialog.
|
|
179
|
+
* Returns true if credentials are ready, false if the dialog was opened.
|
|
180
|
+
*/
|
|
181
|
+
async function ensureCredentials(connection: Connection): Promise<boolean> {
|
|
182
|
+
if (connection.anonymous) return true;
|
|
183
|
+
if (credentialStore.has(connection.id)) return true;
|
|
184
|
+
|
|
185
|
+
// Try restoring from browser password manager
|
|
186
|
+
const native = await loadFromNative(connection.id);
|
|
187
|
+
if (native) {
|
|
188
|
+
credentialStore.set(connection.id, native);
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// No credentials — open the dialog so the user can re-enter them
|
|
193
|
+
editingConnection = connection;
|
|
194
|
+
dialogOpen = true;
|
|
195
|
+
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async function handleBrowseConnection(connection: Connection) {
|
|
200
|
+
// Skip if this connection is already being browsed — avoids clearing entries
|
|
201
|
+
// and re-fetching, which causes DOM churn that can close the mobile Sheet.
|
|
202
|
+
if (browser.activeConnection?.id === connection.id) return;
|
|
203
|
+
if (!(await ensureCredentials(connection))) return;
|
|
204
|
+
browser.browse(connection);
|
|
205
|
+
syncUrlParam(connection);
|
|
206
|
+
}
|
|
207
|
+
</script>
|
|
208
|
+
|
|
209
|
+
<TooltipProvider>
|
|
210
|
+
<div class="flex h-full w-12 flex-col items-center bg-sidebar py-2">
|
|
211
|
+
<!-- App icon -->
|
|
212
|
+
<div class="mb-2 flex size-8 items-center justify-center">
|
|
213
|
+
<DatabaseIcon class="size-5 text-sidebar-primary" />
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
<Separator class="mx-2 mb-2" />
|
|
217
|
+
|
|
218
|
+
<!-- Connections -->
|
|
219
|
+
<div class="flex flex-1 flex-col items-center gap-1 overflow-auto">
|
|
220
|
+
<!-- Detected host indicator -->
|
|
221
|
+
{#if detectedHost}
|
|
222
|
+
<Tooltip>
|
|
223
|
+
<TooltipTrigger>
|
|
224
|
+
<button
|
|
225
|
+
class="group relative flex size-8 items-center justify-center rounded-lg border border-dashed border-primary/50 text-primary transition-colors hover:bg-primary/10"
|
|
226
|
+
class:animate-pulse={!autoConnecting}
|
|
227
|
+
onclick={handleConnectDetected}
|
|
228
|
+
disabled={autoConnecting}
|
|
229
|
+
>
|
|
230
|
+
<GlobeIcon class="size-4" />
|
|
231
|
+
</button>
|
|
232
|
+
</TooltipTrigger>
|
|
233
|
+
<TooltipContent side="right">
|
|
234
|
+
{t('sidebar.browseDetected', { name: detectedHost.bucket })}
|
|
235
|
+
</TooltipContent>
|
|
236
|
+
</Tooltip>
|
|
237
|
+
{/if}
|
|
238
|
+
|
|
239
|
+
{#each connections.items as connection (connection.id)}
|
|
240
|
+
{@const isActive = browser.activeConnection?.id === connection.id}
|
|
241
|
+
<ContextMenu>
|
|
242
|
+
<ContextMenuTrigger>
|
|
243
|
+
<Tooltip>
|
|
244
|
+
<TooltipTrigger>
|
|
245
|
+
<button
|
|
246
|
+
class="group relative flex size-8 items-center justify-center rounded-lg transition-colors {isActive ? 'bg-accent text-accent-foreground' : 'text-muted-foreground hover:bg-accent/50 hover:text-foreground'}"
|
|
247
|
+
onclick={() => handleBrowseConnection(connection)}
|
|
248
|
+
>
|
|
249
|
+
<CloudIcon class="size-4" />
|
|
250
|
+
{#if isActive}
|
|
251
|
+
<div class="absolute left-0 top-1/2 h-4 w-0.5 -translate-y-1/2 rounded-r bg-primary"></div>
|
|
252
|
+
{/if}
|
|
253
|
+
</button>
|
|
254
|
+
</TooltipTrigger>
|
|
255
|
+
<TooltipContent side="right">
|
|
256
|
+
{connection.name}
|
|
257
|
+
</TooltipContent>
|
|
258
|
+
</Tooltip>
|
|
259
|
+
</ContextMenuTrigger>
|
|
260
|
+
<ContextMenuContent class="w-40">
|
|
261
|
+
<ContextMenuItem onclick={() => handleEditConnection(connection)}>
|
|
262
|
+
<PencilIcon class="me-2 size-3.5" />
|
|
263
|
+
{t('sidebar.edit')}
|
|
264
|
+
</ContextMenuItem>
|
|
265
|
+
<ContextMenuSeparator />
|
|
266
|
+
<ContextMenuItem
|
|
267
|
+
class="text-destructive data-[highlighted]:text-destructive"
|
|
268
|
+
onclick={() => handleDeleteConnection(connection)}
|
|
269
|
+
>
|
|
270
|
+
<TrashIcon class="me-2 size-3.5" />
|
|
271
|
+
{t('sidebar.delete')}
|
|
272
|
+
</ContextMenuItem>
|
|
273
|
+
</ContextMenuContent>
|
|
274
|
+
</ContextMenu>
|
|
275
|
+
{/each}
|
|
276
|
+
|
|
277
|
+
<!-- Add connection button -->
|
|
278
|
+
<Tooltip>
|
|
279
|
+
<TooltipTrigger>
|
|
280
|
+
<button
|
|
281
|
+
class="flex size-8 items-center justify-center rounded-lg border border-dashed border-muted-foreground/30 text-muted-foreground transition-colors hover:border-foreground/50 hover:text-foreground"
|
|
282
|
+
onclick={handleAddConnection}
|
|
283
|
+
>
|
|
284
|
+
<PlusIcon class="size-4" />
|
|
285
|
+
</button>
|
|
286
|
+
</TooltipTrigger>
|
|
287
|
+
<TooltipContent side="right">{t('sidebar.addConnection')}</TooltipContent>
|
|
288
|
+
</Tooltip>
|
|
289
|
+
</div>
|
|
290
|
+
|
|
291
|
+
<!-- Bottom actions -->
|
|
292
|
+
<div class="mt-auto flex flex-col items-center gap-1 pt-2">
|
|
293
|
+
<LocaleToggle />
|
|
294
|
+
<ThemeToggle />
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
</TooltipProvider>
|
|
298
|
+
|
|
299
|
+
<ConnectionDialog
|
|
300
|
+
bind:open={dialogOpen}
|
|
301
|
+
editConnection={editingConnection}
|
|
302
|
+
onSaved={() => {
|
|
303
|
+
connections.reload();
|
|
304
|
+
// If we opened the dialog for a credential re-entry, auto-browse after save
|
|
305
|
+
if (editingConnection) {
|
|
306
|
+
const conn = connections.getById(editingConnection.id);
|
|
307
|
+
if (conn && credentialStore.has(conn.id)) {
|
|
308
|
+
browser.browse(conn);
|
|
309
|
+
syncUrlParam(conn);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
handleAutoDetection();
|
|
313
|
+
}}
|
|
314
|
+
/>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import CloudIcon from '@lucide/svelte/icons/cloud';
|
|
3
|
+
import FileTextIcon from '@lucide/svelte/icons/file-text';
|
|
4
|
+
import FolderIcon from '@lucide/svelte/icons/folder';
|
|
5
|
+
import GlobeIcon from '@lucide/svelte/icons/globe';
|
|
6
|
+
import InfoIcon from '@lucide/svelte/icons/info';
|
|
7
|
+
import { Separator } from '../ui/separator/index.js';
|
|
8
|
+
import { getFileTypeInfo } from '../../file-icons/index.js';
|
|
9
|
+
import { t } from '../../i18n/index.svelte.js';
|
|
10
|
+
import { browser } from '../../stores/browser.svelte.js';
|
|
11
|
+
import { files } from '../../stores/files.svelte.js';
|
|
12
|
+
import { tabs } from '../../stores/tabs.svelte.js';
|
|
13
|
+
import { formatFileSize } from '../../utils/format.js';
|
|
14
|
+
import SafeLockToggle from './SafeLockToggle.svelte';
|
|
15
|
+
|
|
16
|
+
let isBrowsingRemote = $derived(browser.activeConnection !== null);
|
|
17
|
+
|
|
18
|
+
let displayPath = $derived(isBrowsingRemote ? browser.currentPrefix : files.currentPath);
|
|
19
|
+
let displayCount = $derived(isBrowsingRemote ? browser.entries.length : files.entries.length);
|
|
20
|
+
|
|
21
|
+
let activeTab = $derived(tabs.active);
|
|
22
|
+
let activeFileInfo = $derived(activeTab ? getFileTypeInfo(activeTab.extension) : null);
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<div
|
|
26
|
+
class="flex h-7 shrink-0 items-center gap-1 border-t bg-muted/40 px-3 text-[11px] text-muted-foreground"
|
|
27
|
+
>
|
|
28
|
+
<!-- Connection / path context -->
|
|
29
|
+
{#if isBrowsingRemote && browser.activeConnection}
|
|
30
|
+
<CloudIcon class="size-3 shrink-0" />
|
|
31
|
+
<span class="max-w-[200px] truncate" title={browser.activeConnection.name}>
|
|
32
|
+
{browser.activeConnection.name}
|
|
33
|
+
</span>
|
|
34
|
+
{#if displayPath}
|
|
35
|
+
<span class="text-muted-foreground/50">/</span>
|
|
36
|
+
<span class="max-w-[200px] truncate" title={displayPath}>{displayPath}</span>
|
|
37
|
+
{/if}
|
|
38
|
+
<Separator orientation="vertical" class="mx-1.5 h-3.5" />
|
|
39
|
+
{:else if displayPath}
|
|
40
|
+
<FolderIcon class="size-3 shrink-0" />
|
|
41
|
+
<span class="max-w-[300px] truncate" title={displayPath}>{displayPath}</span>
|
|
42
|
+
<Separator orientation="vertical" class="mx-1.5 h-3.5" />
|
|
43
|
+
{/if}
|
|
44
|
+
|
|
45
|
+
<!-- Entry count -->
|
|
46
|
+
{#if displayCount > 0}
|
|
47
|
+
<FileTextIcon class="size-3 shrink-0" />
|
|
48
|
+
<span>{displayCount} {displayCount === 1 ? t('statusBar.item') : t('statusBar.items')}</span>
|
|
49
|
+
<Separator orientation="vertical" class="mx-1.5 h-3.5" />
|
|
50
|
+
{/if}
|
|
51
|
+
|
|
52
|
+
<!-- Active file info -->
|
|
53
|
+
{#if activeTab && activeFileInfo}
|
|
54
|
+
<InfoIcon class="size-3 shrink-0" />
|
|
55
|
+
<span>{activeFileInfo.label}</span>
|
|
56
|
+
{#if activeTab.size}
|
|
57
|
+
<span class="text-muted-foreground/50">·</span>
|
|
58
|
+
<span>{formatFileSize(activeTab.size)}</span>
|
|
59
|
+
{/if}
|
|
60
|
+
<Separator orientation="vertical" class="mx-1.5 h-3.5" />
|
|
61
|
+
{/if}
|
|
62
|
+
|
|
63
|
+
<!-- Spacer -->
|
|
64
|
+
<div class="flex-1"></div>
|
|
65
|
+
|
|
66
|
+
<!-- Safe lock toggle -->
|
|
67
|
+
<SafeLockToggle />
|
|
68
|
+
<Separator orientation="vertical" class="mx-1.5 h-3.5" />
|
|
69
|
+
|
|
70
|
+
<!-- Mode indicator -->
|
|
71
|
+
<GlobeIcon class="size-3 shrink-0" />
|
|
72
|
+
<span>{t('statusBar.web')}</span>
|
|
73
|
+
</div>
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import DatabaseIcon from '@lucide/svelte/icons/database';
|
|
3
|
+
import FileTextIcon from '@lucide/svelte/icons/file-text';
|
|
4
|
+
import XIcon from '@lucide/svelte/icons/x';
|
|
5
|
+
import type { Snippet } from 'svelte';
|
|
6
|
+
import { Button } from '../ui/button/index.js';
|
|
7
|
+
import * as ContextMenu from '../ui/context-menu/index.js';
|
|
8
|
+
import { ScrollArea } from '../ui/scroll-area/index.js';
|
|
9
|
+
import { t } from '../../i18n/index.svelte.js';
|
|
10
|
+
import { tabs } from '../../stores/tabs.svelte.js';
|
|
11
|
+
import { buildHttpsUrl, buildStorageUrl } from '../../utils/url.js';
|
|
12
|
+
|
|
13
|
+
let { leading }: { leading?: Snippet } = $props();
|
|
14
|
+
|
|
15
|
+
let copiedType = $state<string | null>(null);
|
|
16
|
+
|
|
17
|
+
function getTabIcon(tab: { connectionId?: string }) {
|
|
18
|
+
if (tab.connectionId) return DatabaseIcon;
|
|
19
|
+
return FileTextIcon;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function handleClose(event: MouseEvent, id: string) {
|
|
23
|
+
event.stopPropagation();
|
|
24
|
+
tabs.close(id);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function handleCopy(type: 'https' | 's3', tab: (typeof tabs.items)[0]) {
|
|
28
|
+
const url = type === 'https' ? buildHttpsUrl(tab) : buildStorageUrl(tab);
|
|
29
|
+
if (!url) return;
|
|
30
|
+
try {
|
|
31
|
+
await navigator.clipboard.writeText(url);
|
|
32
|
+
copiedType = `${type}-${tab.id}`;
|
|
33
|
+
setTimeout(() => (copiedType = null), 2000);
|
|
34
|
+
} catch {
|
|
35
|
+
// clipboard API may fail in some contexts
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
{#if tabs.items.length > 0 || leading}
|
|
41
|
+
<div class="flex h-9 shrink-0 items-center border-b bg-muted/30">
|
|
42
|
+
{#if leading}
|
|
43
|
+
<div class="flex items-center ps-1">
|
|
44
|
+
{@render leading()}
|
|
45
|
+
</div>
|
|
46
|
+
{/if}
|
|
47
|
+
<ScrollArea orientation="horizontal" class="w-full">
|
|
48
|
+
<div class="flex h-9 items-center">
|
|
49
|
+
{#each tabs.items as tab (tab.id)}
|
|
50
|
+
{@const TabIcon = getTabIcon(tab)}
|
|
51
|
+
{@const isActive = tabs.active?.id === tab.id}
|
|
52
|
+
<ContextMenu.Root>
|
|
53
|
+
<ContextMenu.Trigger>
|
|
54
|
+
<button
|
|
55
|
+
class="group relative flex h-9 shrink-0 items-center gap-1.5 border-e px-3 text-sm transition-colors
|
|
56
|
+
{isActive
|
|
57
|
+
? 'bg-background text-foreground'
|
|
58
|
+
: 'text-muted-foreground hover:bg-background/50 hover:text-foreground'}"
|
|
59
|
+
onclick={() => tabs.setActive(tab.id)}
|
|
60
|
+
>
|
|
61
|
+
<TabIcon class="size-3.5 shrink-0" />
|
|
62
|
+
<span class="max-w-[120px] truncate">{tab.name}</span>
|
|
63
|
+
<Button
|
|
64
|
+
variant="ghost"
|
|
65
|
+
size="icon-sm"
|
|
66
|
+
class="ms-1 size-5 opacity-0 transition-opacity group-hover:opacity-100
|
|
67
|
+
{isActive ? 'opacity-60' : ''}"
|
|
68
|
+
onclick={(e: MouseEvent) => handleClose(e, tab.id)}
|
|
69
|
+
aria-label={t('tabBar.closeTab', { name: tab.name })}
|
|
70
|
+
>
|
|
71
|
+
<XIcon class="size-3" />
|
|
72
|
+
</Button>
|
|
73
|
+
{#if isActive}
|
|
74
|
+
<div class="absolute bottom-0 left-0 right-0 h-0.5 bg-primary"></div>
|
|
75
|
+
{/if}
|
|
76
|
+
</button>
|
|
77
|
+
</ContextMenu.Trigger>
|
|
78
|
+
<ContextMenu.Content class="w-52">
|
|
79
|
+
<ContextMenu.Item onclick={() => handleCopy('https', tab)}>
|
|
80
|
+
{copiedType === `https-${tab.id}` ? t('tabBar.copied') : t('tabBar.copyHttps')}
|
|
81
|
+
</ContextMenu.Item>
|
|
82
|
+
{#if tab.source === 'remote'}
|
|
83
|
+
<ContextMenu.Item onclick={() => handleCopy('s3', tab)}>
|
|
84
|
+
{copiedType === `s3-${tab.id}` ? t('tabBar.copied') : t('tabBar.copyStorage')}
|
|
85
|
+
</ContextMenu.Item>
|
|
86
|
+
{/if}
|
|
87
|
+
<ContextMenu.Separator />
|
|
88
|
+
<ContextMenu.Item onclick={() => tabs.close(tab.id)}>
|
|
89
|
+
{t('tabBar.closeTab', { name: '' }).trim()}
|
|
90
|
+
</ContextMenu.Item>
|
|
91
|
+
{#if tabs.items.length > 1}
|
|
92
|
+
<ContextMenu.Item onclick={() => tabs.closeOthers(tab.id)}>
|
|
93
|
+
{t('tabBar.closeOtherTabs')}
|
|
94
|
+
</ContextMenu.Item>
|
|
95
|
+
{/if}
|
|
96
|
+
</ContextMenu.Content>
|
|
97
|
+
</ContextMenu.Root>
|
|
98
|
+
{/each}
|
|
99
|
+
</div>
|
|
100
|
+
</ScrollArea>
|
|
101
|
+
</div>
|
|
102
|
+
{/if}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import MonitorIcon from '@lucide/svelte/icons/monitor';
|
|
3
|
+
import MoonIcon from '@lucide/svelte/icons/moon';
|
|
4
|
+
import SunIcon from '@lucide/svelte/icons/sun';
|
|
5
|
+
import { Button } from '../ui/button/index.js';
|
|
6
|
+
import {
|
|
7
|
+
Tooltip,
|
|
8
|
+
TooltipContent,
|
|
9
|
+
TooltipProvider,
|
|
10
|
+
TooltipTrigger
|
|
11
|
+
} from '../ui/tooltip/index.js';
|
|
12
|
+
import { t } from '../../i18n/index.svelte.js';
|
|
13
|
+
import { settings } from '../../stores/settings.svelte.js';
|
|
14
|
+
|
|
15
|
+
const icons = {
|
|
16
|
+
light: SunIcon,
|
|
17
|
+
dark: MoonIcon,
|
|
18
|
+
system: MonitorIcon
|
|
19
|
+
} as const;
|
|
20
|
+
|
|
21
|
+
const cycle: Record<string, 'light' | 'dark' | 'system'> = {
|
|
22
|
+
light: 'dark',
|
|
23
|
+
dark: 'system',
|
|
24
|
+
system: 'light'
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function toggle() {
|
|
28
|
+
settings.setTheme(cycle[settings.theme]);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let CurrentIcon = $derived(icons[settings.theme]);
|
|
32
|
+
let label = $derived(t(`theme.${settings.theme}`));
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<Tooltip>
|
|
36
|
+
<TooltipTrigger onclick={toggle}>
|
|
37
|
+
{#snippet child({ props })}
|
|
38
|
+
<Button
|
|
39
|
+
{...props}
|
|
40
|
+
variant="ghost"
|
|
41
|
+
size="icon-sm"
|
|
42
|
+
class="rounded-lg text-muted-foreground hover:text-foreground"
|
|
43
|
+
aria-label={t('theme.tooltip', { mode: label })}
|
|
44
|
+
>
|
|
45
|
+
<CurrentIcon class="size-4" />
|
|
46
|
+
</Button>
|
|
47
|
+
{/snippet}
|
|
48
|
+
</TooltipTrigger>
|
|
49
|
+
<TooltipContent side="right">
|
|
50
|
+
{t('theme.tooltip', { mode: label })}
|
|
51
|
+
</TooltipContent>
|
|
52
|
+
</Tooltip>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import { tv, type VariantProps } from 'tailwind-variants';
|
|
3
|
+
|
|
4
|
+
export const badgeVariants = tv({
|
|
5
|
+
base: 'focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] [&>svg]:pointer-events-none [&>svg]:size-3',
|
|
6
|
+
variants: {
|
|
7
|
+
variant: {
|
|
8
|
+
default: 'bg-primary text-primary-foreground [a&]:hover:bg-primary/90 border-transparent',
|
|
9
|
+
secondary:
|
|
10
|
+
'bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90 border-transparent',
|
|
11
|
+
destructive:
|
|
12
|
+
'bg-destructive [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/70 border-transparent text-white',
|
|
13
|
+
outline: 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground'
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
defaultVariants: {
|
|
17
|
+
variant: 'default'
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export type BadgeVariant = VariantProps<typeof badgeVariants>['variant'];
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<script lang="ts">
|
|
25
|
+
import type { HTMLAnchorAttributes } from "svelte/elements";
|
|
26
|
+
import { cn, type WithElementRef } from "../../../utils.js";
|
|
27
|
+
|
|
28
|
+
let {
|
|
29
|
+
ref = $bindable(null),
|
|
30
|
+
href,
|
|
31
|
+
class: className,
|
|
32
|
+
variant = "default",
|
|
33
|
+
children,
|
|
34
|
+
...restProps
|
|
35
|
+
}: WithElementRef<HTMLAnchorAttributes> & {
|
|
36
|
+
variant?: BadgeVariant;
|
|
37
|
+
} = $props();
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<svelte:element
|
|
41
|
+
this={href ? "a" : "span"}
|
|
42
|
+
bind:this={ref}
|
|
43
|
+
data-slot="badge"
|
|
44
|
+
{href}
|
|
45
|
+
class={cn(badgeVariants({ variant }), className)}
|
|
46
|
+
{...restProps}
|
|
47
|
+
>
|
|
48
|
+
{@render children?.()}
|
|
49
|
+
</svelte:element>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type VariantProps } from 'tailwind-variants';
|
|
2
|
+
export declare const badgeVariants: import("tailwind-variants").TVReturnType<{
|
|
3
|
+
variant: {
|
|
4
|
+
default: string;
|
|
5
|
+
secondary: string;
|
|
6
|
+
destructive: string;
|
|
7
|
+
outline: string;
|
|
8
|
+
};
|
|
9
|
+
}, undefined, "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] [&>svg]:pointer-events-none [&>svg]:size-3", {
|
|
10
|
+
variant: {
|
|
11
|
+
default: string;
|
|
12
|
+
secondary: string;
|
|
13
|
+
destructive: string;
|
|
14
|
+
outline: string;
|
|
15
|
+
};
|
|
16
|
+
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
17
|
+
variant: {
|
|
18
|
+
default: string;
|
|
19
|
+
secondary: string;
|
|
20
|
+
destructive: string;
|
|
21
|
+
outline: string;
|
|
22
|
+
};
|
|
23
|
+
}, undefined, "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] [&>svg]:pointer-events-none [&>svg]:size-3", unknown, unknown, undefined>>;
|
|
24
|
+
export type BadgeVariant = VariantProps<typeof badgeVariants>['variant'];
|
|
25
|
+
import type { HTMLAnchorAttributes } from "svelte/elements";
|
|
26
|
+
import { type WithElementRef } from "../../../utils.js";
|
|
27
|
+
type $$ComponentProps = WithElementRef<HTMLAnchorAttributes> & {
|
|
28
|
+
variant?: BadgeVariant;
|
|
29
|
+
};
|
|
30
|
+
declare const Badge: import("svelte").Component<$$ComponentProps, {}, "ref">;
|
|
31
|
+
type Badge = ReturnType<typeof Badge>;
|
|
32
|
+
export default Badge;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { type BadgeVariant, badgeVariants, default as Badge } from './badge.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { badgeVariants, default as Badge } from './badge.svelte';
|