diff --git a/wxbox-web/.env.example b/wxbox-web/.env.example new file mode 100644 index 0000000..e8a45c3 --- /dev/null +++ b/wxbox-web/.env.example @@ -0,0 +1,2 @@ +# Base url of your wxbox-tiler instance +PUBLIC_TILER_URL_BASE="" \ No newline at end of file diff --git a/wxbox-web/src/lib/Map.svelte b/wxbox-web/src/lib/Map.svelte deleted file mode 100644 index 65384b3..0000000 --- a/wxbox-web/src/lib/Map.svelte +++ /dev/null @@ -1,84 +0,0 @@ - - -
- - \ No newline at end of file diff --git a/wxbox-web/src/lib/index.ts b/wxbox-web/src/lib/index.ts deleted file mode 100644 index 856f2b6..0000000 --- a/wxbox-web/src/lib/index.ts +++ /dev/null @@ -1 +0,0 @@ -// place files you want to import through the `$lib` alias in this folder. diff --git a/wxbox-web/src/lib/map/Map.svelte b/wxbox-web/src/lib/map/Map.svelte new file mode 100644 index 0000000..dce82a7 --- /dev/null +++ b/wxbox-web/src/lib/map/Map.svelte @@ -0,0 +1,94 @@ + + +
+ + diff --git a/wxbox-web/src/lib/map/index.ts b/wxbox-web/src/lib/map/index.ts new file mode 100644 index 0000000..f619947 --- /dev/null +++ b/wxbox-web/src/lib/map/index.ts @@ -0,0 +1,2 @@ +// There is no good-looking three-pane view +export type View = 'one' | 'two' | 'four'; diff --git a/wxbox-web/src/lib/map/layer.ts b/wxbox-web/src/lib/map/layer.ts new file mode 100644 index 0000000..6c294d8 --- /dev/null +++ b/wxbox-web/src/lib/map/layer.ts @@ -0,0 +1,32 @@ +import { env } from '$env/dynamic/public'; + +export interface MutexLayerSet { + map1: ValidOpts | null; + map2: ValidOpts | null; + map3: ValidOpts | null; + map4: ValidOpts | null; +} +export interface OverlayLayerSet { + map1: ValidOpts[]; + map2: ValidOpts[]; + map3: ValidOpts[]; + map4: ValidOpts[]; +} + +export type BaseLayers = 'osm'; +export type DataLayers = 'noaa_mrms_merged_composite_reflectivity_qc'; + +export function tilerLayerUrl(id: DataLayers): string { + if (!env.PUBLIC_TILER_URL_BASE) { + throw new Error('PUBLIC_TILER_URL_BASE env var not set!'); + } + const base = new URL(env.PUBLIC_TILER_URL_BASE); + return (base + `${id}/{z}/{x}/{y}.png`).toString(); +} +export function tilerLayerAttribution(id: DataLayers): string { + let base; + if (id === 'noaa_mrms_merged_composite_reflectivity_qc') { + base = '© NOAA'; + } + return base + ', © wxbox'; +} diff --git a/wxbox-web/src/lib/map/sync.svelte.ts b/wxbox-web/src/lib/map/sync.svelte.ts new file mode 100644 index 0000000..0e5b086 --- /dev/null +++ b/wxbox-web/src/lib/map/sync.svelte.ts @@ -0,0 +1,60 @@ +import type { Map as LMap } from 'leaflet'; +import type { View } from '$lib/map'; + +export function syncMaps( + view: View, + map1: LMap | null, + map2: LMap | null, + map3: LMap | null, + map4: LMap | null +) { + // resize the shown maps + if (view === 'one' && map1) { + map1.invalidateSize(); + } else if (view === 'two') { + if (map1) map1.invalidateSize(); + if (map2) map2.invalidateSize(); + } else if (view === 'four') { + if (map1) map1.invalidateSize(); + if (map2) map2.invalidateSize(); + if (map3) map3.invalidateSize(); + if (map4) map4.invalidateSize(); + } + + if (map1 && map2) { + map2.setView(map1.getCenter(), map1.getZoom()); + // @ts-expect-error leaflet.sync does not provide typedefs + map1.sync(map2); + } + if (map1 && map3) { + map3.setView(map1.getCenter(), map1.getZoom()); + // @ts-expect-error leaflet.sync does not provide typedefs + map1.sync(map3); + } + if (map1 && map4) { + map4.setView(map1.getCenter(), map1.getZoom()); + // @ts-expect-error leaflet.sync does not provide typedefs + map1.sync(map4); + } + + // @ts-expect-error leaflet.sync does not provide typedefs + if (map2 && map1) map2.sync(map1); + // @ts-expect-error leaflet.sync does not provide typedefs + if (map2 && map3) map2.sync(map3); + // @ts-expect-error leaflet.sync does not provide typedefs + if (map2 && map4) map2.sync(map4); + + // @ts-expect-error leaflet.sync does not provide typedefs + if (map3 && map1) map3.sync(map1); + // @ts-expect-error leaflet.sync does not provide typedefs + if (map3 && map2) map3.sync(map2); + // @ts-expect-error leaflet.sync does not provide typedefs + if (map3 && map4) map3.sync(map4); + + // @ts-expect-error leaflet.sync does not provide typedefs + if (map4 && map1) map4.sync(map1); + // @ts-expect-error leaflet.sync does not provide typedefs + if (map4 && map2) map4.sync(map2); + // @ts-expect-error leaflet.sync does not provide typedefs + if (map4 && map3) map4.sync(map3); +} diff --git a/wxbox-web/src/lib/menubar/ButtonBar.svelte b/wxbox-web/src/lib/menubar/ButtonBar.svelte new file mode 100644 index 0000000..70b02cc --- /dev/null +++ b/wxbox-web/src/lib/menubar/ButtonBar.svelte @@ -0,0 +1,34 @@ + + + + +{#each menu as menuItem} + {#if menuItem.visible} + {@const index = menuItem.display.indexOf(menuItem.keyboard)} + + {/if} +{/each} diff --git a/wxbox-web/src/lib/menubar/buttonlib.ts b/wxbox-web/src/lib/menubar/buttonlib.ts new file mode 100644 index 0000000..80c1a33 --- /dev/null +++ b/wxbox-web/src/lib/menubar/buttonlib.ts @@ -0,0 +1,22 @@ +export type Mode = + | 'global' + | 'view' + | 'paneSelect' + | 'pane' + | 'baseLayerSelect' + | 'dataLayerSelect' + | 'overlayLayerSelect' + | 'dataNOAA' + | 'dataNOAAMRMS'; + +export interface MenuItem { + display: string; + keyboard: string; + disabled: boolean; + visible: boolean; + action: () => void; +} + +export type MenuRegistry = { + [id in Mode]: MenuItem[]; +}; diff --git a/wxbox-web/src/routes/+layout.svelte b/wxbox-web/src/routes/+layout.svelte index eb0fd15..cd94846 100644 --- a/wxbox-web/src/routes/+layout.svelte +++ b/wxbox-web/src/routes/+layout.svelte @@ -1,12 +1,12 @@ -{@render children()} \ No newline at end of file +{@render children()} diff --git a/wxbox-web/src/routes/+page.svelte b/wxbox-web/src/routes/+page.svelte index 2acedca..ad9782b 100644 --- a/wxbox-web/src/routes/+page.svelte +++ b/wxbox-web/src/routes/+page.svelte @@ -1,270 +1,383 @@ - -
-
-

wxbox

- {status} - {#each currentMenu as menuItem} - {#if menuItem.visible} - {@const index = menuItem.display.indexOf(menuItem.keyboard)} - - {/if} - {/each} -
-
- - {#if view === "two" || view === "four"} - - {/if} -
- {#if view === "four"} -
- - -
- {/if} - +
+

wxbox

+ {status} + +
+
+ + {#if view === 'two' || view === 'four'} + + {/if} +
+ {#if view === 'four'} +
+ + +
+ {/if} +
\ No newline at end of file + .toolbar { + margin: 0; + font-size: 12px; + display: flex; + flex-direction: row; + } + .toolbar h1 { + margin: 0; + } + :global(html body) { + margin: 0; + padding: 0; + } + .container { + display: flex; + flex-direction: row; + flex: 1; + } + .outercontainer { + display: flex; + flex-direction: column; + width: 100vw; + height: 100vh; + } + .footer { + display: flex; + justify-content: space-between; + } + .footer p { + margin: 0; + } +