@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,7 @@
|
|
|
1
|
+
import type { Tab } from '../../types';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
tab: Tab;
|
|
4
|
+
};
|
|
5
|
+
declare const FlatGeobufViewer: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
6
|
+
type FlatGeobufViewer = ReturnType<typeof FlatGeobufViewer>;
|
|
7
|
+
export default FlatGeobufViewer;
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import LocateIcon from '@lucide/svelte/icons/locate';
|
|
3
|
+
import type maplibregl from 'maplibre-gl';
|
|
4
|
+
import { onDestroy } from 'svelte';
|
|
5
|
+
import { t } from '../../i18n/index.svelte.js';
|
|
6
|
+
import type { MapQueryResult, SchemaField } from '../../query/engine';
|
|
7
|
+
import { settings } from '../../stores/settings.svelte.js';
|
|
8
|
+
import { tabResources } from '../../stores/tab-resources.svelte.js';
|
|
9
|
+
import type { Tab } from '../../types';
|
|
10
|
+
import {
|
|
11
|
+
buildSelectionLayer,
|
|
12
|
+
createGeoArrowLayers,
|
|
13
|
+
createGeoArrowOverlay,
|
|
14
|
+
hoverCursor,
|
|
15
|
+
loadGeoArrowModules
|
|
16
|
+
} from '../../utils/deck.js';
|
|
17
|
+
import {
|
|
18
|
+
buildGeoArrowTables,
|
|
19
|
+
type GeoArrowGeomType,
|
|
20
|
+
type GeoArrowResult
|
|
21
|
+
} from '../../utils/geoarrow.js';
|
|
22
|
+
import { parseWKB } from '../../utils/wkb.js';
|
|
23
|
+
import LoadProgress, { type ProgressEntry } from './LoadProgress.svelte';
|
|
24
|
+
import AttributeTable from './map/AttributeTable.svelte';
|
|
25
|
+
import MapContainer from './map/MapContainer.svelte';
|
|
26
|
+
|
|
27
|
+
let {
|
|
28
|
+
tab,
|
|
29
|
+
schema,
|
|
30
|
+
mapData = null,
|
|
31
|
+
sourceCrs = null,
|
|
32
|
+
knownGeomType = undefined,
|
|
33
|
+
metadataBounds = null,
|
|
34
|
+
isCustomQuery = false,
|
|
35
|
+
progressEntries = []
|
|
36
|
+
}: {
|
|
37
|
+
tab: Tab;
|
|
38
|
+
schema: SchemaField[];
|
|
39
|
+
mapData?: MapQueryResult | null;
|
|
40
|
+
sourceCrs?: string | null;
|
|
41
|
+
knownGeomType?: GeoArrowGeomType;
|
|
42
|
+
metadataBounds?: [number, number, number, number] | null;
|
|
43
|
+
isCustomQuery?: boolean;
|
|
44
|
+
progressEntries?: ProgressEntry[];
|
|
45
|
+
} = $props();
|
|
46
|
+
|
|
47
|
+
let loading = $state(true);
|
|
48
|
+
let error = $state<string | null>(null);
|
|
49
|
+
let featureCount = $state(0);
|
|
50
|
+
let selectedFeature = $state<Record<string, any> | null>(null);
|
|
51
|
+
let showAttributes = $state(false);
|
|
52
|
+
let bounds = $state<[number, number, number, number] | undefined>();
|
|
53
|
+
|
|
54
|
+
let firstFeatureCoord = $state<[number, number] | null>(null);
|
|
55
|
+
|
|
56
|
+
let loadGen = 0;
|
|
57
|
+
|
|
58
|
+
let geoArrowState: {
|
|
59
|
+
modules: Record<string, any>;
|
|
60
|
+
geoArrowResults: GeoArrowResult[];
|
|
61
|
+
} | null = null;
|
|
62
|
+
let overlayRef: any = null;
|
|
63
|
+
let dataLayersRef: any[] = [];
|
|
64
|
+
let mapRef: maplibregl.Map | null = null;
|
|
65
|
+
let wkbArraysRef: Uint8Array[] = [];
|
|
66
|
+
|
|
67
|
+
/** Drill into nested coordinate arrays to find the first [lng, lat] pair. */
|
|
68
|
+
function extractFirstCoord(coords: any): [number, number] | null {
|
|
69
|
+
if (!Array.isArray(coords) || coords.length === 0) return null;
|
|
70
|
+
if (typeof coords[0] === 'number') return [coords[0] as number, coords[1] as number];
|
|
71
|
+
return extractFirstCoord(coords[0]);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function flyToFirstFeature() {
|
|
75
|
+
if (!mapRef || !firstFeatureCoord) return;
|
|
76
|
+
mapRef.flyTo({ center: firstFeatureCoord, zoom: 14 });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// mapData is read synchronously in loadGeoData (before any await),
|
|
80
|
+
// so Svelte 5 tracks it as a dependency. The effect re-fires when
|
|
81
|
+
// mapData changes — on initial load, pagination, sort, page size change.
|
|
82
|
+
$effect(() => {
|
|
83
|
+
if (!tab || schema.length === 0) return;
|
|
84
|
+
loadGeoData();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
function cleanup() {
|
|
88
|
+
if (overlayRef && mapRef) {
|
|
89
|
+
try {
|
|
90
|
+
mapRef.removeControl(overlayRef);
|
|
91
|
+
} catch {
|
|
92
|
+
/* already removed */
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
overlayRef = null;
|
|
96
|
+
mapRef = null;
|
|
97
|
+
geoArrowState = null;
|
|
98
|
+
wkbArraysRef = [];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
$effect(() => {
|
|
102
|
+
const id = tab.id;
|
|
103
|
+
const unregister = tabResources.register(id, cleanup);
|
|
104
|
+
return unregister;
|
|
105
|
+
});
|
|
106
|
+
onDestroy(cleanup);
|
|
107
|
+
|
|
108
|
+
async function loadGeoData() {
|
|
109
|
+
const gen = ++loadGen;
|
|
110
|
+
error = null;
|
|
111
|
+
|
|
112
|
+
// Always use preloaded map data from TableViewer's unified query.
|
|
113
|
+
// No independent fetch — avoids duplicate DuckDB queries.
|
|
114
|
+
// The $effect re-fires when mapData changes (tracked read below).
|
|
115
|
+
if (!mapData || mapData.rowCount === 0) {
|
|
116
|
+
loading = true;
|
|
117
|
+
return; // Wait — effect will re-fire when mapData arrives
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const result = mapData;
|
|
122
|
+
|
|
123
|
+
const modules = await loadGeoArrowModules();
|
|
124
|
+
if (gen !== loadGen) return;
|
|
125
|
+
|
|
126
|
+
// Keep WKB ref for selection highlight (no copy — same typed arrays)
|
|
127
|
+
wkbArraysRef = result.wkbArrays;
|
|
128
|
+
|
|
129
|
+
// Convert WKB → GeoArrow Arrow Tables (zero-copy direct binary read)
|
|
130
|
+
// Skip knownGeomType for custom queries — the user's SQL may return
|
|
131
|
+
// different geometry types or join different tables.
|
|
132
|
+
const effectiveGeomType = isCustomQuery ? undefined : knownGeomType;
|
|
133
|
+
const geoArrowResults = buildGeoArrowTables(
|
|
134
|
+
result.wkbArrays,
|
|
135
|
+
result.attributes,
|
|
136
|
+
effectiveGeomType
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
if (geoArrowResults.length === 0) {
|
|
140
|
+
console.warn('[GeoMap] Empty geoArrow results:', {
|
|
141
|
+
wkbCount: result.wkbArrays.length,
|
|
142
|
+
effectiveGeomType,
|
|
143
|
+
gen
|
|
144
|
+
});
|
|
145
|
+
error = t('map.noData');
|
|
146
|
+
loading = false;
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
geoArrowState = { modules, geoArrowResults };
|
|
151
|
+
featureCount = geoArrowResults.reduce((sum, r) => sum + r.table.numRows, 0);
|
|
152
|
+
// Use metadata bounds if available (no client-side computation needed)
|
|
153
|
+
bounds = metadataBounds ?? geoArrowResults[0].bounds;
|
|
154
|
+
|
|
155
|
+
// Extract first feature coordinate for fly-to
|
|
156
|
+
if (result.wkbArrays.length > 0) {
|
|
157
|
+
const parsed = parseWKB(result.wkbArrays[0]);
|
|
158
|
+
if (parsed) firstFeatureCoord = extractFirstCoord(parsed.coordinates);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// If map is already alive, update overlay in-place (no remount)
|
|
162
|
+
if (overlayRef && mapRef) {
|
|
163
|
+
const newLayers = createGeoArrowLayers(modules, {
|
|
164
|
+
layerId: 'geoarrow-data',
|
|
165
|
+
geoArrowResults,
|
|
166
|
+
onHover: hoverCursor(mapRef),
|
|
167
|
+
onClick: handleFeatureClick
|
|
168
|
+
});
|
|
169
|
+
dataLayersRef = newLayers;
|
|
170
|
+
overlayRef.setProps({ layers: newLayers });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
loading = false;
|
|
174
|
+
} catch (err) {
|
|
175
|
+
if (gen !== loadGen) return;
|
|
176
|
+
error = err instanceof Error ? err.message : String(err);
|
|
177
|
+
loading = false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function handleFeatureClick(props: Record<string, any>, sourceIndex: number) {
|
|
182
|
+
selectedFeature = props;
|
|
183
|
+
showAttributes = true;
|
|
184
|
+
// Reconstruct GeoJSON Feature from WKB for selection highlight
|
|
185
|
+
if (!geoArrowState || !overlayRef) return;
|
|
186
|
+
const GeoJsonLayer = geoArrowState.modules.GeoJsonLayer;
|
|
187
|
+
const wkb = wkbArraysRef[sourceIndex];
|
|
188
|
+
if (wkb) {
|
|
189
|
+
const geom = parseWKB(wkb);
|
|
190
|
+
if (geom) {
|
|
191
|
+
const selLayer = buildSelectionLayer(GeoJsonLayer, {
|
|
192
|
+
type: 'Feature',
|
|
193
|
+
geometry: geom as GeoJSON.Geometry,
|
|
194
|
+
properties: {}
|
|
195
|
+
});
|
|
196
|
+
if (selLayer) {
|
|
197
|
+
overlayRef.setProps({ layers: [...dataLayersRef, selLayer] });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function onMapReady(map: maplibregl.Map) {
|
|
204
|
+
if (!geoArrowState) return;
|
|
205
|
+
mapRef = map;
|
|
206
|
+
|
|
207
|
+
const { modules, geoArrowResults } = geoArrowState;
|
|
208
|
+
|
|
209
|
+
const { overlay, layers: dataLayers } = createGeoArrowOverlay(modules, {
|
|
210
|
+
layerId: 'geoarrow-data',
|
|
211
|
+
geoArrowResults,
|
|
212
|
+
onHover: hoverCursor(map),
|
|
213
|
+
onClick: handleFeatureClick
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
dataLayersRef = dataLayers;
|
|
217
|
+
overlayRef = overlay;
|
|
218
|
+
|
|
219
|
+
map.addControl(overlay as any);
|
|
220
|
+
}
|
|
221
|
+
</script>
|
|
222
|
+
|
|
223
|
+
<div class="relative flex h-full overflow-hidden">
|
|
224
|
+
{#if loading}
|
|
225
|
+
<LoadProgress stage={t('map.loadingGeometry')} entries={progressEntries} />
|
|
226
|
+
{:else if error}
|
|
227
|
+
<div class="flex flex-1 items-center justify-center">
|
|
228
|
+
<p class="text-sm text-red-400">{error}</p>
|
|
229
|
+
</div>
|
|
230
|
+
{:else}
|
|
231
|
+
<div class="flex-1">
|
|
232
|
+
<MapContainer {onMapReady} {bounds} />
|
|
233
|
+
</div>
|
|
234
|
+
|
|
235
|
+
<!-- Floating feature count badge + fly-to -->
|
|
236
|
+
{#if featureCount > 0}
|
|
237
|
+
<div
|
|
238
|
+
class="absolute left-2 top-2 z-10 flex items-center gap-1"
|
|
239
|
+
>
|
|
240
|
+
<div
|
|
241
|
+
class="pointer-events-none rounded bg-card/80 px-2 py-1 text-xs text-card-foreground backdrop-blur-sm"
|
|
242
|
+
>
|
|
243
|
+
{featureCount.toLocaleString()} features{#if !isCustomQuery && featureCount >= settings.featureLimit}
|
|
244
|
+
<span class="text-amber-300">(limit)</span>{/if}
|
|
245
|
+
</div>
|
|
246
|
+
{#if firstFeatureCoord}
|
|
247
|
+
<button
|
|
248
|
+
class="rounded bg-card/80 p-1.5 text-card-foreground backdrop-blur-sm hover:bg-card"
|
|
249
|
+
onclick={flyToFirstFeature}
|
|
250
|
+
title={t('map.flyToFirst')}
|
|
251
|
+
>
|
|
252
|
+
<LocateIcon class="size-3.5" />
|
|
253
|
+
</button>
|
|
254
|
+
{/if}
|
|
255
|
+
</div>
|
|
256
|
+
{/if}
|
|
257
|
+
|
|
258
|
+
<!-- Floating button group -->
|
|
259
|
+
{#if selectedFeature}
|
|
260
|
+
<div class="absolute right-2 top-2 z-10 flex gap-1">
|
|
261
|
+
<button
|
|
262
|
+
class="rounded bg-card/80 px-2 py-1 text-xs text-card-foreground backdrop-blur-sm hover:bg-card"
|
|
263
|
+
class:ring-1={showAttributes}
|
|
264
|
+
class:ring-primary={showAttributes}
|
|
265
|
+
onclick={() => (showAttributes = !showAttributes)}
|
|
266
|
+
>
|
|
267
|
+
{t('map.attributes')}
|
|
268
|
+
</button>
|
|
269
|
+
</div>
|
|
270
|
+
{/if}
|
|
271
|
+
|
|
272
|
+
<AttributeTable
|
|
273
|
+
feature={selectedFeature}
|
|
274
|
+
visible={showAttributes}
|
|
275
|
+
onClose={() => (showAttributes = false)}
|
|
276
|
+
/>
|
|
277
|
+
{/if}
|
|
278
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { MapQueryResult, SchemaField } from '../../query/engine';
|
|
2
|
+
import type { Tab } from '../../types';
|
|
3
|
+
import { type GeoArrowGeomType } from '../../utils/geoarrow.js';
|
|
4
|
+
import { type ProgressEntry } from './LoadProgress.svelte';
|
|
5
|
+
type $$ComponentProps = {
|
|
6
|
+
tab: Tab;
|
|
7
|
+
schema: SchemaField[];
|
|
8
|
+
mapData?: MapQueryResult | null;
|
|
9
|
+
sourceCrs?: string | null;
|
|
10
|
+
knownGeomType?: GeoArrowGeomType;
|
|
11
|
+
metadataBounds?: [number, number, number, number] | null;
|
|
12
|
+
isCustomQuery?: boolean;
|
|
13
|
+
progressEntries?: ProgressEntry[];
|
|
14
|
+
};
|
|
15
|
+
declare const GeoParquetMapViewer: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
16
|
+
type GeoParquetMapViewer = ReturnType<typeof GeoParquetMapViewer>;
|
|
17
|
+
export default GeoParquetMapViewer;
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import EllipsisVerticalIcon from '@lucide/svelte/icons/ellipsis-vertical';
|
|
3
|
+
import MaximizeIcon from '@lucide/svelte/icons/maximize';
|
|
4
|
+
import MinusIcon from '@lucide/svelte/icons/minus';
|
|
5
|
+
import PlusIcon from '@lucide/svelte/icons/plus';
|
|
6
|
+
import RotateCwIcon from '@lucide/svelte/icons/rotate-cw';
|
|
7
|
+
import ScanIcon from '@lucide/svelte/icons/scan';
|
|
8
|
+
import { onDestroy } from 'svelte';
|
|
9
|
+
import { Badge } from '../ui/badge/index.js';
|
|
10
|
+
import { Button } from '../ui/button/index.js';
|
|
11
|
+
import * as DropdownMenu from '../ui/dropdown-menu/index.js';
|
|
12
|
+
import { t } from '../../i18n/index.svelte.js';
|
|
13
|
+
import { getAdapter } from '../../storage/index.js';
|
|
14
|
+
import { tabResources } from '../../stores/tab-resources.svelte.js';
|
|
15
|
+
import type { Tab } from '../../types';
|
|
16
|
+
import { buildHttpsUrl, canStreamDirectly } from '../../utils/url.js';
|
|
17
|
+
|
|
18
|
+
const mimeMap: Record<string, string> = {
|
|
19
|
+
png: 'image/png',
|
|
20
|
+
jpg: 'image/jpeg',
|
|
21
|
+
jpeg: 'image/jpeg',
|
|
22
|
+
gif: 'image/gif',
|
|
23
|
+
webp: 'image/webp',
|
|
24
|
+
avif: 'image/avif',
|
|
25
|
+
svg: 'image/svg+xml',
|
|
26
|
+
bmp: 'image/bmp',
|
|
27
|
+
ico: 'image/x-icon'
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
let { tab }: { tab: Tab } = $props();
|
|
31
|
+
|
|
32
|
+
let abortController: AbortController | null = null;
|
|
33
|
+
let imgSrc = $state<string | null>(null);
|
|
34
|
+
let blobUrl = $state<string | null>(null);
|
|
35
|
+
let loading = $state(true);
|
|
36
|
+
let error = $state<string | null>(null);
|
|
37
|
+
let scale = $state(1);
|
|
38
|
+
let rotation = $state(0);
|
|
39
|
+
let panX = $state(0);
|
|
40
|
+
let panY = $state(0);
|
|
41
|
+
let dragging = $state(false);
|
|
42
|
+
let lastX = 0;
|
|
43
|
+
let lastY = 0;
|
|
44
|
+
let wrapperEl: HTMLDivElement | undefined = $state();
|
|
45
|
+
|
|
46
|
+
$effect(() => {
|
|
47
|
+
if (!tab) return;
|
|
48
|
+
loadImage();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
async function loadImage() {
|
|
52
|
+
loading = true;
|
|
53
|
+
error = null;
|
|
54
|
+
cleanup();
|
|
55
|
+
abortController = new AbortController();
|
|
56
|
+
const { signal } = abortController;
|
|
57
|
+
resetView();
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
if (canStreamDirectly(tab)) {
|
|
61
|
+
// Direct URL — browser streams natively (no CORS needed for <img>)
|
|
62
|
+
imgSrc = buildHttpsUrl(tab);
|
|
63
|
+
} else {
|
|
64
|
+
// Authenticated S3 — download via storage adapter
|
|
65
|
+
const adapter = getAdapter(tab.source, tab.connectionId);
|
|
66
|
+
const data = await adapter.read(tab.path, undefined, undefined, signal);
|
|
67
|
+
const ext = tab.extension.toLowerCase();
|
|
68
|
+
const blob = new Blob([data as unknown as BlobPart], {
|
|
69
|
+
type: mimeMap[ext] || 'application/octet-stream'
|
|
70
|
+
});
|
|
71
|
+
blobUrl = URL.createObjectURL(blob);
|
|
72
|
+
imgSrc = blobUrl;
|
|
73
|
+
}
|
|
74
|
+
} catch (err) {
|
|
75
|
+
if (err instanceof DOMException && err.name === 'AbortError') return;
|
|
76
|
+
error = err instanceof Error ? err.message : String(err);
|
|
77
|
+
} finally {
|
|
78
|
+
loading = false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function resetView() {
|
|
83
|
+
scale = 1;
|
|
84
|
+
rotation = 0;
|
|
85
|
+
panX = 0;
|
|
86
|
+
panY = 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function zoomIn() {
|
|
90
|
+
scale = Math.min(scale * 1.4, 20);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function zoomOut() {
|
|
94
|
+
scale = Math.max(scale / 1.4, 0.1);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function fitView() {
|
|
98
|
+
resetView();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function rotate() {
|
|
102
|
+
rotation = (rotation + 90) % 360;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function fullscreen() {
|
|
106
|
+
wrapperEl?.requestFullscreen?.();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function handleWheel(e: WheelEvent) {
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
const factor = e.deltaY > 0 ? 0.9 : 1.1;
|
|
112
|
+
scale = Math.max(0.1, Math.min(20, scale * factor));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function handlePointerDown(e: PointerEvent) {
|
|
116
|
+
if (e.button !== 0) return;
|
|
117
|
+
dragging = true;
|
|
118
|
+
lastX = e.clientX;
|
|
119
|
+
lastY = e.clientY;
|
|
120
|
+
(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function handlePointerMove(e: PointerEvent) {
|
|
124
|
+
if (!dragging) return;
|
|
125
|
+
panX += e.clientX - lastX;
|
|
126
|
+
panY += e.clientY - lastY;
|
|
127
|
+
lastX = e.clientX;
|
|
128
|
+
lastY = e.clientY;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function handlePointerUp() {
|
|
132
|
+
dragging = false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function handleDblClick() {
|
|
136
|
+
if (scale !== 1 || panX !== 0 || panY !== 0) {
|
|
137
|
+
resetView();
|
|
138
|
+
} else {
|
|
139
|
+
scale = 2;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function cleanup() {
|
|
144
|
+
abortController?.abort();
|
|
145
|
+
abortController = null;
|
|
146
|
+
if (blobUrl) {
|
|
147
|
+
URL.revokeObjectURL(blobUrl);
|
|
148
|
+
blobUrl = null;
|
|
149
|
+
}
|
|
150
|
+
imgSrc = null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
$effect(() => {
|
|
154
|
+
const id = tab.id;
|
|
155
|
+
const unregister = tabResources.register(id, cleanup);
|
|
156
|
+
return unregister;
|
|
157
|
+
});
|
|
158
|
+
onDestroy(cleanup);
|
|
159
|
+
</script>
|
|
160
|
+
|
|
161
|
+
<div class="flex h-full flex-col">
|
|
162
|
+
<div
|
|
163
|
+
class="flex items-center gap-1 border-b border-zinc-200 px-2 py-1.5 sm:gap-2 sm:px-4 dark:border-zinc-800"
|
|
164
|
+
>
|
|
165
|
+
<span class="truncate max-w-[120px] text-sm font-medium text-zinc-700 sm:max-w-none dark:text-zinc-300">{tab.name}</span>
|
|
166
|
+
<Badge variant="secondary">{tab.extension.toUpperCase()}</Badge>
|
|
167
|
+
|
|
168
|
+
<div class="ms-auto flex items-center gap-1">
|
|
169
|
+
<!-- Desktop controls -->
|
|
170
|
+
<div class="hidden items-center gap-1 sm:flex">
|
|
171
|
+
<Button variant="ghost" size="sm" class="h-7 px-1.5" onclick={zoomIn} title={t('image.zoomIn')}>
|
|
172
|
+
<PlusIcon class="size-3.5" />
|
|
173
|
+
</Button>
|
|
174
|
+
<Button variant="ghost" size="sm" class="h-7 px-1.5" onclick={zoomOut} title={t('image.zoomOut')}>
|
|
175
|
+
<MinusIcon class="size-3.5" />
|
|
176
|
+
</Button>
|
|
177
|
+
<Button variant="ghost" size="sm" class="h-7 px-1.5" onclick={fitView} title={t('image.fit')}>
|
|
178
|
+
<ScanIcon class="size-3.5" />
|
|
179
|
+
</Button>
|
|
180
|
+
<Button variant="ghost" size="sm" class="h-7 px-1.5" onclick={rotate} title={t('image.rotate')}>
|
|
181
|
+
<RotateCwIcon class="size-3.5" />
|
|
182
|
+
</Button>
|
|
183
|
+
<Button variant="ghost" size="sm" class="h-7 px-1.5" onclick={fullscreen} title={t('image.fullscreen')}>
|
|
184
|
+
<MaximizeIcon class="size-3.5" />
|
|
185
|
+
</Button>
|
|
186
|
+
</div>
|
|
187
|
+
|
|
188
|
+
<!-- Mobile overflow menu -->
|
|
189
|
+
<div class="flex sm:hidden">
|
|
190
|
+
<DropdownMenu.Root>
|
|
191
|
+
<DropdownMenu.Trigger class="rounded p-1 text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800">
|
|
192
|
+
<EllipsisVerticalIcon class="size-4" />
|
|
193
|
+
</DropdownMenu.Trigger>
|
|
194
|
+
<DropdownMenu.Content align="end" class="w-40">
|
|
195
|
+
<DropdownMenu.Item onclick={zoomIn}>{t('image.zoomIn')}</DropdownMenu.Item>
|
|
196
|
+
<DropdownMenu.Item onclick={zoomOut}>{t('image.zoomOut')}</DropdownMenu.Item>
|
|
197
|
+
<DropdownMenu.Item onclick={fitView}>{t('image.fit')}</DropdownMenu.Item>
|
|
198
|
+
<DropdownMenu.Item onclick={rotate}>{t('image.rotate')}</DropdownMenu.Item>
|
|
199
|
+
<DropdownMenu.Item onclick={fullscreen}>{t('image.fullscreen')}</DropdownMenu.Item>
|
|
200
|
+
</DropdownMenu.Content>
|
|
201
|
+
</DropdownMenu.Root>
|
|
202
|
+
</div>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
207
|
+
<div
|
|
208
|
+
bind:this={wrapperEl}
|
|
209
|
+
class="relative flex flex-1 items-center justify-center overflow-hidden bg-zinc-100 dark:bg-zinc-900"
|
|
210
|
+
class:cursor-grab={scale > 1 && !dragging}
|
|
211
|
+
class:cursor-grabbing={dragging}
|
|
212
|
+
onwheel={handleWheel}
|
|
213
|
+
ondblclick={handleDblClick}
|
|
214
|
+
>
|
|
215
|
+
{#if loading}
|
|
216
|
+
<p class="text-sm text-zinc-400">{t('image.loading')}</p>
|
|
217
|
+
{:else if error}
|
|
218
|
+
<p class="text-sm text-red-400">{error}</p>
|
|
219
|
+
{:else if imgSrc}
|
|
220
|
+
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
221
|
+
<img
|
|
222
|
+
src={imgSrc}
|
|
223
|
+
alt={tab.name}
|
|
224
|
+
class="max-h-full max-w-full select-none"
|
|
225
|
+
style="transform: translate({panX}px, {panY}px) scale({scale}) rotate({rotation}deg); transition: {dragging ? 'none' : 'transform 0.15s ease-out'};"
|
|
226
|
+
draggable="false"
|
|
227
|
+
onpointerdown={handlePointerDown}
|
|
228
|
+
onpointermove={handlePointerMove}
|
|
229
|
+
onpointerup={handlePointerUp}
|
|
230
|
+
/>
|
|
231
|
+
{/if}
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import CheckCircleIcon from '@lucide/svelte/icons/circle-check';
|
|
3
|
+
import Loader2Icon from '@lucide/svelte/icons/loader-2';
|
|
4
|
+
import XCircleIcon from '@lucide/svelte/icons/x-circle';
|
|
5
|
+
import { t } from '../../i18n/index.svelte.js';
|
|
6
|
+
|
|
7
|
+
export type ProgressEntry = {
|
|
8
|
+
label: string;
|
|
9
|
+
value: string;
|
|
10
|
+
detail?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
stage = '',
|
|
15
|
+
entries = [],
|
|
16
|
+
onCancel,
|
|
17
|
+
onForceCancel,
|
|
18
|
+
forceCancelVisible = false
|
|
19
|
+
}: {
|
|
20
|
+
stage?: string;
|
|
21
|
+
entries?: ProgressEntry[];
|
|
22
|
+
onCancel?: () => void;
|
|
23
|
+
onForceCancel?: () => void;
|
|
24
|
+
forceCancelVisible?: boolean;
|
|
25
|
+
} = $props();
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<div class="flex flex-1 flex-col items-center justify-center gap-4 px-4">
|
|
29
|
+
<!-- Active step -->
|
|
30
|
+
<div class="flex items-center gap-2 text-center">
|
|
31
|
+
<Loader2Icon class="size-4 shrink-0 animate-spin text-primary" />
|
|
32
|
+
<p class="text-sm text-zinc-500 dark:text-zinc-400">{stage || t('table.loading')}</p>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<!-- Discovered metadata -->
|
|
36
|
+
{#if entries.length > 0}
|
|
37
|
+
<div
|
|
38
|
+
class="w-full max-w-md rounded-lg border border-zinc-200/60 bg-zinc-50/80 px-3 py-2.5 sm:px-4 sm:py-3 dark:border-zinc-800/60 dark:bg-zinc-900/50"
|
|
39
|
+
>
|
|
40
|
+
<div class="flex flex-col gap-1.5">
|
|
41
|
+
{#each entries as entry}
|
|
42
|
+
<div class="flex items-start gap-1.5 sm:gap-2">
|
|
43
|
+
<CheckCircleIcon class="mt-0.5 size-3 shrink-0 text-green-500/80" />
|
|
44
|
+
<span
|
|
45
|
+
class="w-14 shrink-0 text-[11px] leading-4 text-zinc-400 sm:w-[4.5rem] sm:text-xs dark:text-zinc-500"
|
|
46
|
+
>
|
|
47
|
+
{entry.label}
|
|
48
|
+
</span>
|
|
49
|
+
<div class="min-w-0 flex-1">
|
|
50
|
+
<span class="break-all text-[11px] font-medium leading-4 text-zinc-600 sm:text-xs dark:text-zinc-300">
|
|
51
|
+
{entry.value}
|
|
52
|
+
</span>
|
|
53
|
+
{#if entry.detail}
|
|
54
|
+
<p
|
|
55
|
+
class="mt-0.5 truncate font-mono text-[10px] leading-tight text-zinc-400 dark:text-zinc-500"
|
|
56
|
+
>
|
|
57
|
+
{entry.detail}
|
|
58
|
+
</p>
|
|
59
|
+
{/if}
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
{/each}
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
{/if}
|
|
66
|
+
|
|
67
|
+
<!-- Cancel -->
|
|
68
|
+
{#if onCancel}
|
|
69
|
+
<div class="flex flex-col items-center gap-2">
|
|
70
|
+
<button
|
|
71
|
+
class="flex items-center gap-1 rounded border border-zinc-300 px-3 py-1 text-xs text-zinc-500 hover:bg-zinc-100 dark:border-zinc-700 dark:text-zinc-400 dark:hover:bg-zinc-800"
|
|
72
|
+
onclick={onCancel}
|
|
73
|
+
>
|
|
74
|
+
<XCircleIcon class="size-3" />
|
|
75
|
+
{t('table.cancel')}
|
|
76
|
+
</button>
|
|
77
|
+
{#if forceCancelVisible && onForceCancel}
|
|
78
|
+
<div class="flex flex-col items-center gap-1">
|
|
79
|
+
<button
|
|
80
|
+
class="flex items-center gap-1 rounded border border-red-400 bg-red-50 px-3 py-1 text-xs text-red-600 hover:bg-red-100 dark:border-red-700 dark:bg-red-950 dark:text-red-400 dark:hover:bg-red-900"
|
|
81
|
+
onclick={onForceCancel}
|
|
82
|
+
>
|
|
83
|
+
<XCircleIcon class="size-3" />
|
|
84
|
+
{t('table.forceStop')}
|
|
85
|
+
</button>
|
|
86
|
+
<p class="max-w-xs text-center text-[10px] text-zinc-400 dark:text-zinc-500">
|
|
87
|
+
{t('table.forceStopWarning')}
|
|
88
|
+
</p>
|
|
89
|
+
</div>
|
|
90
|
+
{/if}
|
|
91
|
+
</div>
|
|
92
|
+
{/if}
|
|
93
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type ProgressEntry = {
|
|
2
|
+
label: string;
|
|
3
|
+
value: string;
|
|
4
|
+
detail?: string;
|
|
5
|
+
};
|
|
6
|
+
type $$ComponentProps = {
|
|
7
|
+
stage?: string;
|
|
8
|
+
entries?: ProgressEntry[];
|
|
9
|
+
onCancel?: () => void;
|
|
10
|
+
onForceCancel?: () => void;
|
|
11
|
+
forceCancelVisible?: boolean;
|
|
12
|
+
};
|
|
13
|
+
declare const LoadProgress: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
14
|
+
type LoadProgress = ReturnType<typeof LoadProgress>;
|
|
15
|
+
export default LoadProgress;
|