@walkthru-earth/objex 1.3.1 → 1.5.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 +5 -0
- package/README.md +28 -20
- package/dist/components/browser/FileTreeSidebar.svelte +32 -17
- package/dist/components/layout/AboutSheet.svelte +5 -2
- package/dist/components/layout/ConnectionDialog.svelte +7 -2
- package/dist/components/layout/SettingsSheet.svelte +238 -0
- package/dist/components/layout/SettingsSheet.svelte.d.ts +6 -0
- package/dist/components/layout/Sidebar.svelte +73 -6
- package/dist/components/layout/Sidebar.svelte.d.ts +4 -1
- package/dist/components/layout/StatusBar.svelte +17 -14
- package/dist/components/layout/TabBar.svelte +4 -4
- package/dist/components/ui/context-menu/context-menu-radio-group.svelte.d.ts +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte.d.ts +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +1 -1
- package/dist/components/ui/input/input.svelte.d.ts +1 -1
- package/dist/components/ui/resizable/index.d.ts +1 -1
- package/dist/components/ui/resizable/index.js +2 -2
- package/dist/components/ui/slider/index.d.ts +3 -0
- package/dist/components/ui/slider/index.js +5 -0
- package/dist/components/ui/slider/range-slider.svelte +94 -0
- package/dist/components/ui/slider/range-slider.svelte.d.ts +21 -0
- package/dist/components/ui/slider/slider.svelte +83 -0
- package/dist/components/ui/slider/slider.svelte.d.ts +7 -0
- package/dist/components/viewers/ArchiveViewer.svelte +140 -113
- package/dist/components/viewers/CodeViewer.svelte +45 -48
- package/dist/components/viewers/CodeViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/CogControls.svelte +338 -184
- package/dist/components/viewers/CogControls.svelte.d.ts +33 -10
- package/dist/components/viewers/CogViewer.svelte +269 -116
- package/dist/components/viewers/CopcViewer.svelte +8 -15
- package/dist/components/viewers/DatabaseViewer.svelte +22 -21
- package/dist/components/viewers/FileInfo.svelte +16 -16
- package/dist/components/viewers/FlatGeobufViewer.svelte +16 -46
- package/dist/components/viewers/GeoParquetMapViewer.svelte +11 -9
- package/dist/components/viewers/GeoParquetMapViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/ImageViewer.svelte +12 -14
- package/dist/components/viewers/LoadProgress.svelte +6 -6
- package/dist/components/viewers/MarkdownViewer.svelte +29 -30
- package/dist/components/viewers/MediaViewer.svelte +13 -14
- package/dist/components/viewers/ModelViewer.svelte +18 -21
- package/dist/components/viewers/MultiCogViewer.svelte +474 -106
- package/dist/components/viewers/MultiCogViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/NotebookViewer.svelte +28 -29
- package/dist/components/viewers/PdfViewer.svelte +24 -33
- package/dist/components/viewers/PmtilesViewer.svelte +13 -15
- package/dist/components/viewers/QueryHistoryPanel.svelte +18 -18
- package/dist/components/viewers/RawViewer.svelte +27 -21
- package/dist/components/viewers/StacMapViewer.svelte +6 -13
- package/dist/components/viewers/StacMosaicViewer.svelte +1764 -410
- package/dist/components/viewers/StacMosaicViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/StacTabViewer.svelte +26 -15
- package/dist/components/viewers/StacTabViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/TableGrid.svelte +38 -34
- package/dist/components/viewers/TableStatusBar.svelte +7 -7
- package/dist/components/viewers/TableToolbar.svelte +10 -9
- package/dist/components/viewers/TableViewer.svelte +47 -30
- package/dist/components/viewers/TableViewer.svelte.d.ts +1 -0
- package/dist/components/viewers/ViewerHeader.svelte +18 -0
- package/dist/components/viewers/ViewerHeader.svelte.d.ts +10 -0
- package/dist/components/viewers/ViewerRouter.svelte +16 -8
- package/dist/components/viewers/ViewerStatus.svelte +19 -0
- package/dist/components/viewers/ViewerStatus.svelte.d.ts +7 -0
- package/dist/components/viewers/ZarrMapViewer.svelte +24 -21
- package/dist/components/viewers/ZarrViewer.svelte +98 -65
- package/dist/components/viewers/cog/ChannelPicker.svelte +83 -0
- package/dist/components/viewers/cog/ChannelPicker.svelte.d.ts +13 -0
- package/dist/components/viewers/cog/PixelInspectorPanel.svelte +87 -0
- package/dist/components/viewers/cog/PixelInspectorPanel.svelte.d.ts +17 -0
- package/dist/components/viewers/cog/buildRgbLayer.d.ts +78 -0
- package/dist/components/viewers/cog/buildRgbLayer.js +176 -0
- package/dist/components/viewers/map/AttributeTable.svelte +7 -7
- package/dist/components/viewers/map/MapContainer.svelte +38 -12
- package/dist/components/viewers/pmtiles/PmtilesArchiveView.svelte +109 -83
- package/dist/components/viewers/pmtiles/PmtilesTileInspector.svelte +16 -16
- package/dist/components/viewers/stac/StacDatetimeBar.svelte +175 -0
- package/dist/components/viewers/stac/StacDatetimeBar.svelte.d.ts +10 -0
- package/dist/components/viewers/stac/StacFilterPanel.svelte +243 -0
- package/dist/components/viewers/stac/StacFilterPanel.svelte.d.ts +14 -0
- package/dist/components/viewers/stac/StacItemInspector.svelte +223 -0
- package/dist/components/viewers/stac/StacItemInspector.svelte.d.ts +10 -0
- package/dist/components/viewers/stac/StacItemStrip.svelte +228 -0
- package/dist/components/viewers/stac/StacItemStrip.svelte.d.ts +12 -0
- package/dist/constants.d.ts +6 -0
- package/dist/constants.js +8 -0
- package/dist/file-icons/index.d.ts +1 -1
- package/dist/file-icons/index.js +1 -1
- package/dist/i18n/ar.js +113 -2
- package/dist/i18n/en.js +113 -2
- package/dist/index.d.ts +2 -28
- package/dist/index.js +7 -23
- package/dist/query/engine.d.ts +10 -0
- package/dist/query/source.js +1 -1
- package/dist/query/stac-source-factory.d.ts +65 -0
- package/dist/query/stac-source-factory.js +77 -0
- package/dist/query/stac-source-parquet.d.ts +135 -0
- package/dist/query/stac-source-parquet.js +468 -0
- package/dist/query/wasm.d.ts +8 -0
- package/dist/query/wasm.js +310 -65
- package/dist/storage/presign.js +3 -2
- package/dist/storage/providers.js +7 -6
- package/dist/stores/config.svelte.d.ts +15 -0
- package/dist/stores/config.svelte.js +46 -0
- package/dist/stores/connections.svelte.d.ts +2 -2
- package/dist/stores/connections.svelte.js +1 -2
- package/dist/stores/files.svelte.d.ts +1 -1
- package/dist/stores/files.svelte.js +1 -1
- package/dist/stores/query-history.svelte.js +1 -1
- package/dist/stores/settings.svelte.d.ts +16 -1
- package/dist/stores/settings.svelte.js +104 -48
- package/dist/stores/tabs.svelte.d.ts +3 -0
- package/dist/stores/tabs.svelte.js +17 -0
- package/dist/utils/cog-histogram.d.ts +121 -0
- package/dist/utils/cog-histogram.js +424 -0
- package/dist/utils/cog.d.ts +177 -20
- package/dist/utils/cog.js +361 -76
- package/dist/utils/colormap-sprite.d.ts +0 -9
- package/dist/utils/colormap-sprite.js +0 -21
- package/dist/utils/deck.d.ts +18 -12
- package/dist/utils/deck.js +15 -7
- package/dist/utils/media-query.svelte.d.ts +14 -0
- package/dist/utils/media-query.svelte.js +29 -0
- package/dist/utils/pmtiles-tile.js +2 -2
- package/dist/utils/signed-url-effect.d.ts +7 -0
- package/dist/utils/signed-url-effect.js +19 -0
- package/dist/utils/{url.d.ts → signed-url.d.ts} +15 -1
- package/dist/utils/{url.js → signed-url.js} +32 -10
- package/dist/utils/url-state.d.ts +36 -0
- package/dist/utils/url-state.js +72 -2
- package/dist/utils/zarr-tab.d.ts +1 -2
- package/dist/utils/zarr-tab.js +1 -2
- package/dist/utils/zarr.d.ts +0 -17
- package/dist/utils/zarr.js +1 -45
- package/package.json +55 -84
- package/dist/components/browser/Breadcrumb.svelte +0 -50
- package/dist/components/browser/Breadcrumb.svelte.d.ts +0 -7
- package/dist/components/browser/CreateFolderDialog.svelte +0 -98
- package/dist/components/browser/CreateFolderDialog.svelte.d.ts +0 -6
- package/dist/components/browser/DeleteConfirmDialog.svelte +0 -90
- package/dist/components/browser/DeleteConfirmDialog.svelte.d.ts +0 -8
- package/dist/components/browser/DropZone.svelte +0 -83
- package/dist/components/browser/DropZone.svelte.d.ts +0 -7
- package/dist/components/browser/FileBrowser.svelte +0 -252
- package/dist/components/browser/FileBrowser.svelte.d.ts +0 -3
- package/dist/components/browser/FileRow.svelte +0 -117
- package/dist/components/browser/FileRow.svelte.d.ts +0 -9
- package/dist/components/browser/RenameDialog.svelte +0 -101
- package/dist/components/browser/RenameDialog.svelte.d.ts +0 -8
- package/dist/components/browser/SearchBar.svelte +0 -40
- package/dist/components/browser/SearchBar.svelte.d.ts +0 -6
- package/dist/components/browser/UploadButton.svelte +0 -65
- package/dist/components/browser/UploadButton.svelte.d.ts +0 -3
- package/dist/query/stac-geoparquet.d.ts +0 -31
- package/dist/query/stac-geoparquet.js +0 -136
- package/dist/utils/clipboard.d.ts +0 -13
- package/dist/utils/clipboard.js +0 -38
- package/dist/utils/cloud-url.d.ts +0 -27
- package/dist/utils/cloud-url.js +0 -61
- package/dist/utils/cog-pure.d.ts +0 -25
- package/dist/utils/cog-pure.js +0 -35
- package/dist/utils/column-types.d.ts +0 -5
- package/dist/utils/column-types.js +0 -137
- package/dist/utils/connection-identity.d.ts +0 -51
- package/dist/utils/connection-identity.js +0 -97
- package/dist/utils/error.d.ts +0 -8
- package/dist/utils/error.js +0 -12
- package/dist/utils/evidence-context.d.ts +0 -22
- package/dist/utils/evidence-context.js +0 -56
- package/dist/utils/export.d.ts +0 -22
- package/dist/utils/export.js +0 -76
- package/dist/utils/file-sort.d.ts +0 -20
- package/dist/utils/file-sort.js +0 -41
- package/dist/utils/format.d.ts +0 -24
- package/dist/utils/format.js +0 -78
- package/dist/utils/geoarrow.d.ts +0 -32
- package/dist/utils/geoarrow.js +0 -672
- package/dist/utils/geometry-type.d.ts +0 -52
- package/dist/utils/geometry-type.js +0 -76
- package/dist/utils/hex.d.ts +0 -10
- package/dist/utils/hex.js +0 -27
- package/dist/utils/host-detection.d.ts +0 -23
- package/dist/utils/host-detection.js +0 -95
- package/dist/utils/local-storage.d.ts +0 -16
- package/dist/utils/local-storage.js +0 -37
- package/dist/utils/markdown-sql.d.ts +0 -30
- package/dist/utils/markdown-sql.js +0 -72
- package/dist/utils/notebook.d.ts +0 -59
- package/dist/utils/notebook.js +0 -211
- package/dist/utils/parquet-metadata.d.ts +0 -64
- package/dist/utils/parquet-metadata.js +0 -262
- package/dist/utils/stac-geoparquet.d.ts +0 -90
- package/dist/utils/stac-geoparquet.js +0 -223
- package/dist/utils/stac-hydrate.d.ts +0 -38
- package/dist/utils/stac-hydrate.js +0 -243
- package/dist/utils/stac.d.ts +0 -136
- package/dist/utils/stac.js +0 -176
- package/dist/utils/storage-url.d.ts +0 -90
- package/dist/utils/storage-url.js +0 -568
- package/dist/utils/wkb.d.ts +0 -43
- package/dist/utils/wkb.js +0 -359
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import EllipsisVerticalIcon from '@lucide/svelte/icons/ellipsis-vertical';
|
|
3
|
+
import {
|
|
4
|
+
copyToClipboard,
|
|
5
|
+
handleLoadError,
|
|
6
|
+
renderNotebook,
|
|
7
|
+
wireCodeCopyButtons
|
|
8
|
+
} from '@walkthru-earth/objex-utils';
|
|
3
9
|
import type { BundledLanguage } from 'shiki';
|
|
4
10
|
import { onDestroy, tick } from 'svelte';
|
|
5
11
|
import { Badge } from '../ui/badge/index.js';
|
|
@@ -9,10 +15,9 @@ import { t } from '../../i18n/index.svelte.js';
|
|
|
9
15
|
import { getAdapter } from '../../storage/index.js';
|
|
10
16
|
import { tabResources } from '../../stores/tab-resources.svelte.js';
|
|
11
17
|
import type { Tab } from '../../types';
|
|
12
|
-
import { copyToClipboard, wireCodeCopyButtons } from '../../utils/clipboard.js';
|
|
13
|
-
import { handleLoadError } from '../../utils/error.js';
|
|
14
|
-
import { renderNotebook } from '../../utils/notebook';
|
|
15
18
|
import { highlightCodeReversed } from '../../utils/shiki';
|
|
19
|
+
import ViewerHeader from './ViewerHeader.svelte';
|
|
20
|
+
import ViewerStatus from './ViewerStatus.svelte';
|
|
16
21
|
|
|
17
22
|
let { tab }: { tab: Tab } = $props();
|
|
18
23
|
|
|
@@ -132,23 +137,21 @@ async function copyRaw() {
|
|
|
132
137
|
</script>
|
|
133
138
|
|
|
134
139
|
<div class="flex h-full flex-col">
|
|
135
|
-
<
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
{
|
|
150
|
-
|
|
151
|
-
<div class="ms-auto flex items-center gap-1 sm:gap-2">
|
|
140
|
+
<ViewerHeader {tab}>
|
|
141
|
+
{#snippet badge()}
|
|
142
|
+
<Badge variant="secondary">{t('notebook.badge')}</Badge>
|
|
143
|
+
{#if kernelName}
|
|
144
|
+
<Badge variant="outline" class="hidden border-orange-200 text-orange-600 sm:inline-flex dark:border-orange-800 dark:text-orange-300">
|
|
145
|
+
{kernelName}
|
|
146
|
+
</Badge>
|
|
147
|
+
{/if}
|
|
148
|
+
{#if cellCount > 0}
|
|
149
|
+
<span class="hidden text-xs text-muted-foreground sm:inline">
|
|
150
|
+
{cellCount} {t('notebook.cells')}
|
|
151
|
+
</span>
|
|
152
|
+
{/if}
|
|
153
|
+
{/snippet}
|
|
154
|
+
{#snippet actions()}
|
|
152
155
|
<!-- Desktop controls -->
|
|
153
156
|
<div class="hidden items-center gap-1 sm:flex">
|
|
154
157
|
<Button variant="ghost" size="sm" class="h-7 px-2 text-xs" onclick={toggleCode}>
|
|
@@ -162,7 +165,7 @@ async function copyRaw() {
|
|
|
162
165
|
<!-- Mobile overflow menu -->
|
|
163
166
|
<div class="flex sm:hidden">
|
|
164
167
|
<DropdownMenu.Root>
|
|
165
|
-
<DropdownMenu.Trigger class="rounded p-1 text-
|
|
168
|
+
<DropdownMenu.Trigger class="rounded p-1 text-muted-foreground hover:bg-muted">
|
|
166
169
|
<EllipsisVerticalIcon class="size-4" />
|
|
167
170
|
</DropdownMenu.Trigger>
|
|
168
171
|
<DropdownMenu.Content align="end" class="w-44">
|
|
@@ -175,18 +178,14 @@ async function copyRaw() {
|
|
|
175
178
|
</DropdownMenu.Content>
|
|
176
179
|
</DropdownMenu.Root>
|
|
177
180
|
</div>
|
|
178
|
-
|
|
179
|
-
</
|
|
181
|
+
{/snippet}
|
|
182
|
+
</ViewerHeader>
|
|
180
183
|
|
|
181
184
|
<div class="notebook-viewer flex-1 overflow-auto" dir="ltr">
|
|
182
185
|
{#if loading}
|
|
183
|
-
<
|
|
184
|
-
<p class="text-sm text-zinc-400">{t('notebook.loading')}</p>
|
|
185
|
-
</div>
|
|
186
|
+
<ViewerStatus kind="loading" message={t('notebook.loading')} />
|
|
186
187
|
{:else if error}
|
|
187
|
-
<
|
|
188
|
-
<p class="text-sm text-red-400">{error}</p>
|
|
189
|
-
</div>
|
|
188
|
+
<ViewerStatus kind="error" message={error} />
|
|
190
189
|
{/if}
|
|
191
190
|
<div bind:this={container} class="notebook-content" class:hidden={loading || !!error}></div>
|
|
192
191
|
</div>
|
|
@@ -4,6 +4,7 @@ import ChevronRightIcon from '@lucide/svelte/icons/chevron-right';
|
|
|
4
4
|
import EllipsisVerticalIcon from '@lucide/svelte/icons/ellipsis-vertical';
|
|
5
5
|
import MinusIcon from '@lucide/svelte/icons/minus';
|
|
6
6
|
import PlusIcon from '@lucide/svelte/icons/plus';
|
|
7
|
+
import { handleLoadError } from '@walkthru-earth/objex-utils';
|
|
7
8
|
import type { PDFDocumentLoadingTask, PDFDocumentProxy } from 'pdfjs-dist';
|
|
8
9
|
import { onDestroy, untrack } from 'svelte';
|
|
9
10
|
import { Badge } from '../ui/badge/index.js';
|
|
@@ -14,9 +15,10 @@ import { t } from '../../i18n/index.svelte.js';
|
|
|
14
15
|
import { getAdapter } from '../../storage/index.js';
|
|
15
16
|
import { tabResources } from '../../stores/tab-resources.svelte.js';
|
|
16
17
|
import type { Tab } from '../../types';
|
|
17
|
-
import { handleLoadError } from '../../utils/error.js';
|
|
18
18
|
import { loadPdfDocument, loadPdfFromUrl } from '../../utils/pdf';
|
|
19
|
-
import { buildHttpsUrl, canStreamDirectly } from '../../utils/url.js';
|
|
19
|
+
import { buildHttpsUrl, canStreamDirectly } from '../../utils/signed-url.js';
|
|
20
|
+
import ViewerHeader from './ViewerHeader.svelte';
|
|
21
|
+
import ViewerStatus from './ViewerStatus.svelte';
|
|
20
22
|
|
|
21
23
|
const LOAD_TIMEOUT_MS = 20_000;
|
|
22
24
|
|
|
@@ -136,7 +138,7 @@ async function renderPage(
|
|
|
136
138
|
await page.render({ canvasContext: ctx, viewport, canvas } as any).promise;
|
|
137
139
|
} catch (err) {
|
|
138
140
|
if (gen === renderGeneration) {
|
|
139
|
-
error =
|
|
141
|
+
error = handleLoadError(err);
|
|
140
142
|
}
|
|
141
143
|
}
|
|
142
144
|
}
|
|
@@ -174,17 +176,10 @@ onDestroy(cleanup);
|
|
|
174
176
|
</script>
|
|
175
177
|
|
|
176
178
|
<div class="flex h-full flex-col">
|
|
177
|
-
<
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
class="truncate max-w-[120px] text-sm font-medium text-zinc-700 sm:max-w-none dark:text-zinc-300"
|
|
182
|
-
>{tab.name}</span
|
|
183
|
-
>
|
|
184
|
-
<Badge variant="secondary">{t("pdf.badge")}</Badge>
|
|
185
|
-
|
|
186
|
-
{#if totalPages > 0}
|
|
187
|
-
<div class="ms-auto flex items-center gap-1 sm:gap-2">
|
|
179
|
+
<ViewerHeader {tab}>
|
|
180
|
+
{#snippet badge()}<Badge variant="secondary">{t('pdf.badge')}</Badge>{/snippet}
|
|
181
|
+
{#snippet actions()}
|
|
182
|
+
{#if totalPages > 0}
|
|
188
183
|
<!-- Pagination (always visible) -->
|
|
189
184
|
<Button
|
|
190
185
|
variant="ghost"
|
|
@@ -194,9 +189,9 @@ onDestroy(cleanup);
|
|
|
194
189
|
disabled={currentPage <= 1}
|
|
195
190
|
>
|
|
196
191
|
<ChevronLeftIcon class="size-3.5" />
|
|
197
|
-
<span class="hidden sm:inline">{t(
|
|
192
|
+
<span class="hidden sm:inline">{t('pdf.prev')}</span>
|
|
198
193
|
</Button>
|
|
199
|
-
<span class="text-xs text-
|
|
194
|
+
<span class="text-xs text-muted-foreground">
|
|
200
195
|
{currentPage} / {totalPages}
|
|
201
196
|
</span>
|
|
202
197
|
<Button
|
|
@@ -206,7 +201,7 @@ onDestroy(cleanup);
|
|
|
206
201
|
onclick={nextPage}
|
|
207
202
|
disabled={currentPage >= totalPages}
|
|
208
203
|
>
|
|
209
|
-
<span class="hidden sm:inline">{t(
|
|
204
|
+
<span class="hidden sm:inline">{t('pdf.next')}</span>
|
|
210
205
|
<ChevronRightIcon class="size-3.5" />
|
|
211
206
|
</Button>
|
|
212
207
|
|
|
@@ -218,11 +213,11 @@ onDestroy(cleanup);
|
|
|
218
213
|
size="sm"
|
|
219
214
|
class="h-7 px-1.5"
|
|
220
215
|
onclick={zoomOut}
|
|
221
|
-
title={t(
|
|
216
|
+
title={t('pdf.zoomOut')}
|
|
222
217
|
>
|
|
223
218
|
<MinusIcon class="size-3.5" />
|
|
224
219
|
</Button>
|
|
225
|
-
<span class="text-xs text-
|
|
220
|
+
<span class="text-xs text-muted-foreground">
|
|
226
221
|
{Math.round(scale * 100)}%
|
|
227
222
|
</span>
|
|
228
223
|
<Button
|
|
@@ -230,7 +225,7 @@ onDestroy(cleanup);
|
|
|
230
225
|
size="sm"
|
|
231
226
|
class="h-7 px-1.5"
|
|
232
227
|
onclick={zoomIn}
|
|
233
|
-
title={t(
|
|
228
|
+
title={t('pdf.zoomIn')}
|
|
234
229
|
>
|
|
235
230
|
<PlusIcon class="size-3.5" />
|
|
236
231
|
</Button>
|
|
@@ -240,39 +235,35 @@ onDestroy(cleanup);
|
|
|
240
235
|
<div class="flex sm:hidden">
|
|
241
236
|
<DropdownMenu.Root>
|
|
242
237
|
<DropdownMenu.Trigger
|
|
243
|
-
class="rounded p-1 text-
|
|
238
|
+
class="rounded p-1 text-muted-foreground hover:bg-muted"
|
|
244
239
|
>
|
|
245
240
|
<EllipsisVerticalIcon class="size-4" />
|
|
246
241
|
</DropdownMenu.Trigger>
|
|
247
242
|
<DropdownMenu.Content align="end" class="w-44">
|
|
248
243
|
<DropdownMenu.Item onclick={zoomIn}>
|
|
249
|
-
{t(
|
|
244
|
+
{t('pdf.zoomIn')}
|
|
250
245
|
</DropdownMenu.Item>
|
|
251
246
|
<DropdownMenu.Item onclick={zoomOut}>
|
|
252
|
-
{t(
|
|
247
|
+
{t('pdf.zoomOut')}
|
|
253
248
|
</DropdownMenu.Item>
|
|
254
249
|
<DropdownMenu.Separator />
|
|
255
250
|
<DropdownMenu.Item disabled>
|
|
256
|
-
{t(
|
|
251
|
+
{t('pdf.zoom')}: {Math.round(scale * 100)}%
|
|
257
252
|
</DropdownMenu.Item>
|
|
258
253
|
</DropdownMenu.Content>
|
|
259
254
|
</DropdownMenu.Root>
|
|
260
255
|
</div>
|
|
261
|
-
|
|
262
|
-
{/
|
|
263
|
-
</
|
|
256
|
+
{/if}
|
|
257
|
+
{/snippet}
|
|
258
|
+
</ViewerHeader>
|
|
264
259
|
|
|
265
260
|
<div
|
|
266
261
|
class="flex flex-1 items-start justify-center overflow-auto bg-zinc-200 p-4 dark:bg-zinc-800"
|
|
267
262
|
>
|
|
268
263
|
{#if loading}
|
|
269
|
-
<
|
|
270
|
-
<p class="text-sm text-zinc-400">{t("pdf.loading")}</p>
|
|
271
|
-
</div>
|
|
264
|
+
<ViewerStatus kind="loading" message={t('pdf.loading')} />
|
|
272
265
|
{:else if error}
|
|
273
|
-
<
|
|
274
|
-
<p class="text-sm text-red-400">{error}</p>
|
|
275
|
-
</div>
|
|
266
|
+
<ViewerStatus kind="error" message={error} />
|
|
276
267
|
{:else}
|
|
277
268
|
<canvas bind:this={canvasEl} class="shadow-lg"></canvas>
|
|
278
269
|
{/if}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import ArchiveIcon from '@lucide/svelte/icons/archive';
|
|
3
3
|
import GridIcon from '@lucide/svelte/icons/grid-3x3';
|
|
4
4
|
import MapIcon from '@lucide/svelte/icons/map';
|
|
5
|
+
import { handleLoadError } from '@walkthru-earth/objex-utils';
|
|
5
6
|
import type { PMTiles } from 'pmtiles';
|
|
6
7
|
import { onDestroy, untrack } from 'svelte';
|
|
7
8
|
import { Badge } from '../ui/badge/index.js';
|
|
@@ -11,8 +12,8 @@ import { t } from '../../i18n/index.svelte.js';
|
|
|
11
12
|
import { tabResources } from '../../stores/tab-resources.svelte.js';
|
|
12
13
|
import type { Tab } from '../../types';
|
|
13
14
|
import { loadPmtiles, type PmtilesMetadata } from '../../utils/pmtiles';
|
|
14
|
-
import { buildHttpsUrlAsync } from '../../utils/url.js';
|
|
15
|
-
import {
|
|
15
|
+
import { buildHttpsUrlAsync } from '../../utils/signed-url.js';
|
|
16
|
+
import { pickViewMode, updateUrlView } from '../../utils/url-state.js';
|
|
16
17
|
|
|
17
18
|
let { tab }: { tab: Tab } = $props();
|
|
18
19
|
|
|
@@ -25,10 +26,7 @@ let pmtilesInstance = $state<PMTiles | null>(null);
|
|
|
25
26
|
let pmtilesUrl = $state('');
|
|
26
27
|
|
|
27
28
|
// Read initial view from URL hash
|
|
28
|
-
|
|
29
|
-
let viewMode = $state<ViewMode>(
|
|
30
|
-
urlView === 'archive' ? 'archive' : urlView === 'inspector' ? 'inspector' : 'map'
|
|
31
|
-
);
|
|
29
|
+
let viewMode = $state<ViewMode>(pickViewMode<ViewMode>(['map', 'archive', 'inspector'], 'map'));
|
|
32
30
|
|
|
33
31
|
// Tile inspector initial coordinates (set when navigating from archive)
|
|
34
32
|
let inspectorZ = $state<number | undefined>();
|
|
@@ -78,7 +76,7 @@ async function load() {
|
|
|
78
76
|
pmtilesInstance = result.pmtiles;
|
|
79
77
|
metadata = result.metadata;
|
|
80
78
|
} catch (err) {
|
|
81
|
-
error =
|
|
79
|
+
error = handleLoadError(err);
|
|
82
80
|
} finally {
|
|
83
81
|
loading = false;
|
|
84
82
|
}
|
|
@@ -91,18 +89,18 @@ const fileName = $derived(tab.path.split('/').pop() ?? 'pmtiles');
|
|
|
91
89
|
<!-- Toolbar -->
|
|
92
90
|
{#if !loading && !error && metadata}
|
|
93
91
|
<div
|
|
94
|
-
class="flex items-center gap-1 border-b border-
|
|
92
|
+
class="flex items-center gap-1 border-b border-border px-2 py-1.5 sm:gap-2 sm:px-4"
|
|
95
93
|
>
|
|
96
94
|
<!-- File info -->
|
|
97
95
|
<span
|
|
98
|
-
class="max-w-[100px] truncate text-sm font-medium text-
|
|
96
|
+
class="max-w-[100px] truncate text-sm font-medium text-foreground sm:max-w-none"
|
|
99
97
|
>
|
|
100
98
|
{fileName}
|
|
101
99
|
</span>
|
|
102
100
|
<Badge variant="outline" class="hidden text-[10px] sm:inline-flex">
|
|
103
101
|
{metadata.formatLabel}
|
|
104
102
|
</Badge>
|
|
105
|
-
<span class="hidden text-xs text-
|
|
103
|
+
<span class="hidden text-xs text-muted-foreground sm:inline">
|
|
106
104
|
z{metadata.minZoom}-{metadata.maxZoom} · {metadata.numAddressedTiles.toLocaleString()} tiles
|
|
107
105
|
</span>
|
|
108
106
|
|
|
@@ -112,7 +110,7 @@ const fileName = $derived(tab.path.split('/').pop() ?? 'pmtiles');
|
|
|
112
110
|
variant={viewMode === 'map' ? 'default' : 'outline'}
|
|
113
111
|
size="sm"
|
|
114
112
|
class="h-7 gap-1 px-2 text-xs {viewMode !== 'map'
|
|
115
|
-
? 'border-
|
|
113
|
+
? 'border-border text-muted-foreground hover:bg-muted'
|
|
116
114
|
: ''}"
|
|
117
115
|
onclick={() => setViewMode('map')}
|
|
118
116
|
>
|
|
@@ -124,7 +122,7 @@ const fileName = $derived(tab.path.split('/').pop() ?? 'pmtiles');
|
|
|
124
122
|
variant={viewMode === 'archive' ? 'default' : 'outline'}
|
|
125
123
|
size="sm"
|
|
126
124
|
class="h-7 gap-1 px-2 text-xs {viewMode !== 'archive'
|
|
127
|
-
? 'border-
|
|
125
|
+
? 'border-border text-muted-foreground hover:bg-muted'
|
|
128
126
|
: ''}"
|
|
129
127
|
onclick={() => setViewMode('archive')}
|
|
130
128
|
>
|
|
@@ -136,7 +134,7 @@ const fileName = $derived(tab.path.split('/').pop() ?? 'pmtiles');
|
|
|
136
134
|
variant={viewMode === 'inspector' ? 'default' : 'outline'}
|
|
137
135
|
size="sm"
|
|
138
136
|
class="h-7 gap-1 px-2 text-xs {viewMode !== 'inspector'
|
|
139
|
-
? 'border-
|
|
137
|
+
? 'border-border text-muted-foreground hover:bg-muted'
|
|
140
138
|
: ''}"
|
|
141
139
|
onclick={() => setViewMode('inspector')}
|
|
142
140
|
>
|
|
@@ -151,11 +149,11 @@ const fileName = $derived(tab.path.split('/').pop() ?? 'pmtiles');
|
|
|
151
149
|
<div class="min-h-0 flex-1 overflow-hidden">
|
|
152
150
|
{#if loading}
|
|
153
151
|
<div class="flex h-full items-center justify-center">
|
|
154
|
-
<p class="text-sm text-
|
|
152
|
+
<p class="text-sm text-muted-foreground">{t('map.loadingPmtiles')}</p>
|
|
155
153
|
</div>
|
|
156
154
|
{:else if error}
|
|
157
155
|
<div class="flex h-full items-center justify-center">
|
|
158
|
-
<p class="text-sm text-
|
|
156
|
+
<p class="text-sm text-destructive">{error}</p>
|
|
159
157
|
</div>
|
|
160
158
|
{:else if metadata && pmtilesInstance}
|
|
161
159
|
{#if viewMode === 'map'}
|
|
@@ -50,22 +50,22 @@ function truncateSql(sql: string, maxLen = 120): string {
|
|
|
50
50
|
{#if visible}
|
|
51
51
|
<!-- Mobile: absolute overlay; Desktop: flex sidebar -->
|
|
52
52
|
<div
|
|
53
|
-
class="absolute inset-y-0 end-0 z-10 flex w-72 flex-col overflow-hidden border-s border-
|
|
53
|
+
class="absolute inset-y-0 end-0 z-10 flex w-72 flex-col overflow-hidden border-s border-border bg-muted sm:relative sm:z-auto sm:shrink-0"
|
|
54
54
|
>
|
|
55
55
|
<!-- Header -->
|
|
56
56
|
<div
|
|
57
|
-
class="flex items-center justify-between border-b border-
|
|
57
|
+
class="flex items-center justify-between border-b border-border px-3 py-2"
|
|
58
58
|
>
|
|
59
59
|
<div class="flex items-center gap-1.5">
|
|
60
|
-
<ClockIcon class="size-3.5 text-
|
|
61
|
-
<h3 class="text-xs font-medium text-
|
|
60
|
+
<ClockIcon class="size-3.5 text-muted-foreground" />
|
|
61
|
+
<h3 class="text-xs font-medium text-muted-foreground">
|
|
62
62
|
{t('queryHistory.title')}
|
|
63
63
|
</h3>
|
|
64
64
|
</div>
|
|
65
65
|
<div class="flex items-center gap-2">
|
|
66
66
|
{#if queryHistory.entries.length > 0}
|
|
67
67
|
<button
|
|
68
|
-
class="text-[10px] text-
|
|
68
|
+
class="text-[10px] text-muted-foreground hover:text-destructive"
|
|
69
69
|
onclick={() => queryHistory.clear()}
|
|
70
70
|
>
|
|
71
71
|
{t('queryHistory.clearAll')}
|
|
@@ -73,7 +73,7 @@ function truncateSql(sql: string, maxLen = 120): string {
|
|
|
73
73
|
{/if}
|
|
74
74
|
{#if onClose}
|
|
75
75
|
<button
|
|
76
|
-
class="rounded p-0.5 text-
|
|
76
|
+
class="rounded p-0.5 text-muted-foreground hover:bg-accent hover:text-accent-foreground sm:hidden"
|
|
77
77
|
onclick={onClose}
|
|
78
78
|
>
|
|
79
79
|
<XIcon class="size-3.5" />
|
|
@@ -83,20 +83,20 @@ function truncateSql(sql: string, maxLen = 120): string {
|
|
|
83
83
|
</div>
|
|
84
84
|
|
|
85
85
|
<!-- Search -->
|
|
86
|
-
<div class="border-b border-
|
|
86
|
+
<div class="border-b border-border px-3 py-1.5">
|
|
87
87
|
<div
|
|
88
|
-
class="flex items-center gap-1.5 rounded border border-
|
|
88
|
+
class="flex items-center gap-1.5 rounded border border-border bg-background px-2 py-1"
|
|
89
89
|
>
|
|
90
|
-
<SearchIcon class="size-3 shrink-0 text-
|
|
90
|
+
<SearchIcon class="size-3 shrink-0 text-muted-foreground" />
|
|
91
91
|
<input
|
|
92
92
|
type="text"
|
|
93
|
-
class="w-full bg-transparent text-xs outline-none placeholder:text-
|
|
93
|
+
class="w-full bg-transparent text-xs outline-none placeholder:text-muted-foreground"
|
|
94
94
|
placeholder={t('queryHistory.searchPlaceholder')}
|
|
95
95
|
bind:value={searchQuery}
|
|
96
96
|
/>
|
|
97
97
|
{#if searchQuery}
|
|
98
98
|
<button
|
|
99
|
-
class="shrink-0 text-
|
|
99
|
+
class="shrink-0 text-muted-foreground hover:text-foreground"
|
|
100
100
|
onclick={() => {
|
|
101
101
|
searchQuery = '';
|
|
102
102
|
}}
|
|
@@ -110,14 +110,14 @@ function truncateSql(sql: string, maxLen = 120): string {
|
|
|
110
110
|
<!-- Entries -->
|
|
111
111
|
<ScrollArea class="flex-1">
|
|
112
112
|
{#if filteredEntries.length === 0}
|
|
113
|
-
<div class="px-3 py-6 text-center text-xs text-
|
|
113
|
+
<div class="px-3 py-6 text-center text-xs text-muted-foreground">
|
|
114
114
|
{searchQuery ? 'No matching queries' : 'No query history yet'}
|
|
115
115
|
</div>
|
|
116
116
|
{:else}
|
|
117
|
-
<div class="divide-y divide-
|
|
117
|
+
<div class="divide-y divide-border">
|
|
118
118
|
{#each filteredEntries as entry (entry.id)}
|
|
119
119
|
<div
|
|
120
|
-
class="group flex w-full cursor-pointer flex-col gap-0.5 px-3 py-2 text-start hover:bg-
|
|
120
|
+
class="group flex w-full cursor-pointer flex-col gap-0.5 px-3 py-2 text-start hover:bg-accent"
|
|
121
121
|
role="button"
|
|
122
122
|
tabindex="0"
|
|
123
123
|
onclick={() => onSelect?.(entry.sql)}
|
|
@@ -126,18 +126,18 @@ function truncateSql(sql: string, maxLen = 120): string {
|
|
|
126
126
|
}}
|
|
127
127
|
>
|
|
128
128
|
<div
|
|
129
|
-
class="font-mono text-[11px] leading-snug text-
|
|
129
|
+
class="font-mono text-[11px] leading-snug text-foreground"
|
|
130
130
|
>
|
|
131
131
|
{truncateSql(entry.sql)}
|
|
132
132
|
</div>
|
|
133
|
-
<div class="flex items-center gap-2 text-[10px] text-
|
|
133
|
+
<div class="flex items-center gap-2 text-[10px] text-muted-foreground">
|
|
134
134
|
<span>{formatTime(entry.timestamp)}</span>
|
|
135
135
|
<span>{entry.durationMs}ms</span>
|
|
136
136
|
{#if entry.rowCount > 0}
|
|
137
137
|
<span>{entry.rowCount.toLocaleString()} rows</span>
|
|
138
138
|
{/if}
|
|
139
139
|
{#if entry.error}
|
|
140
|
-
<span class="text-
|
|
140
|
+
<span class="text-destructive">error</span>
|
|
141
141
|
{/if}
|
|
142
142
|
<button
|
|
143
143
|
class="ms-auto opacity-0 group-hover:opacity-100"
|
|
@@ -147,7 +147,7 @@ function truncateSql(sql: string, maxLen = 120): string {
|
|
|
147
147
|
}}
|
|
148
148
|
title="Remove"
|
|
149
149
|
>
|
|
150
|
-
<TrashIcon class="size-3 text-
|
|
150
|
+
<TrashIcon class="size-3 text-muted-foreground hover:text-destructive" />
|
|
151
151
|
</button>
|
|
152
152
|
</div>
|
|
153
153
|
</div>
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
formatFileSize,
|
|
4
|
+
generateHexDump,
|
|
5
|
+
type HexRow,
|
|
6
|
+
handleLoadError
|
|
7
|
+
} from '@walkthru-earth/objex-utils';
|
|
2
8
|
import { onDestroy } from 'svelte';
|
|
3
9
|
import { Badge } from '../ui/badge/index.js';
|
|
4
10
|
import { t } from '../../i18n/index.svelte.js';
|
|
5
11
|
import { getAdapter } from '../../storage/index.js';
|
|
6
12
|
import { tabResources } from '../../stores/tab-resources.svelte.js';
|
|
7
13
|
import type { Tab } from '../../types';
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import { generateHexDump, type HexRow } from '../../utils/hex';
|
|
14
|
+
import ViewerHeader from './ViewerHeader.svelte';
|
|
15
|
+
import ViewerStatus from './ViewerStatus.svelte';
|
|
11
16
|
|
|
12
17
|
let { tab }: { tab: Tab } = $props();
|
|
13
18
|
|
|
@@ -66,30 +71,31 @@ async function loadHexDump() {
|
|
|
66
71
|
</script>
|
|
67
72
|
|
|
68
73
|
<div class="flex h-full flex-col">
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
{
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
</span>
|
|
80
|
-
{#if truncated}
|
|
81
|
-
<span class="hidden text-xs text-amber-500 sm:inline">
|
|
82
|
-
({t('raw.showingFirst').replace('{size}', formatFileSize(MAX_BYTES))})
|
|
74
|
+
<ViewerHeader {tab}>
|
|
75
|
+
{#snippet badge()}
|
|
76
|
+
{#if tab.extension}
|
|
77
|
+
<Badge variant="secondary">{tab.extension}</Badge>
|
|
78
|
+
{/if}
|
|
79
|
+
{/snippet}
|
|
80
|
+
{#snippet actions()}
|
|
81
|
+
{#if !loading && fileSize > 0}
|
|
82
|
+
<span class="hidden text-xs text-muted-foreground sm:inline">
|
|
83
|
+
{formatFileSize(fileSize)}
|
|
83
84
|
</span>
|
|
85
|
+
{#if truncated}
|
|
86
|
+
<span class="hidden text-xs text-amber-500 sm:inline">
|
|
87
|
+
({t('raw.showingFirst').replace('{size}', formatFileSize(MAX_BYTES))})
|
|
88
|
+
</span>
|
|
89
|
+
{/if}
|
|
84
90
|
{/if}
|
|
85
|
-
{/
|
|
86
|
-
</
|
|
91
|
+
{/snippet}
|
|
92
|
+
</ViewerHeader>
|
|
87
93
|
|
|
88
94
|
<div class="flex-1 overflow-auto bg-zinc-950 p-4 font-mono text-xs">
|
|
89
95
|
{#if loading}
|
|
90
|
-
<
|
|
96
|
+
<ViewerStatus kind="loading" message={t('raw.loading')} />
|
|
91
97
|
{:else if error}
|
|
92
|
-
<
|
|
98
|
+
<ViewerStatus kind="error" message={error} />
|
|
93
99
|
{:else}
|
|
94
100
|
<table class="w-full border-collapse">
|
|
95
101
|
<thead>
|
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Tab } from '../../types';
|
|
3
|
-
import {
|
|
3
|
+
import { resolveSignedTabUrl } from '../../utils/signed-url-effect.js';
|
|
4
4
|
|
|
5
5
|
let { tab, variant = 'stac-map' }: { tab: Tab; variant?: 'stac-map' | 'stac-browser' } = $props();
|
|
6
6
|
|
|
7
7
|
let fileUrl = $state('');
|
|
8
8
|
|
|
9
|
-
$effect(() =>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (cancelled || id !== tab.id) return;
|
|
15
|
-
fileUrl = url;
|
|
16
|
-
})();
|
|
17
|
-
return () => {
|
|
18
|
-
cancelled = true;
|
|
19
|
-
};
|
|
20
|
-
});
|
|
9
|
+
$effect(() =>
|
|
10
|
+
resolveSignedTabUrl(tab, (u) => {
|
|
11
|
+
fileUrl = u;
|
|
12
|
+
})
|
|
13
|
+
);
|
|
21
14
|
|
|
22
15
|
const iframeSrc = $derived.by(() => {
|
|
23
16
|
if (!fileUrl) return '';
|