web


git clone https://radroots.dev/git/web.git
Log | Files | Refs | Submodules | README | LICENSE

commit c0447d401fbadab854e67523756a24e77b17fd27
parent f71e4069a1e43906d6657e4e57307faaded27e2c
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Mon,  7 Oct 2024 04:26:43 +0000

Refactor error/response handling logic, add map components, edit conf, edit stores, add styles

Diffstat:
Msrc/app.css | 7++++++-
Dsrc/lib/components/map-marker-dot.svelte | 29-----------------------------
Dsrc/lib/components/map-marker.svelte | 9---------
Asrc/lib/components/map_choose_location.svelte | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/components/map_marker_dot.svelte | 15+++++++++++++++
Asrc/lib/components/map_popup_location_info.svelte | 45+++++++++++++++++++++++++++++++++++++++++++++
Msrc/lib/conf.ts | 6++++++
Msrc/lib/stores.ts | 1-
Msrc/lib/utils/location_gcs.ts | 139+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/lib/utils/nostr.ts | 5++---
Msrc/lib/utils/trade_product.ts | 7++++---
Msrc/routes/(app)/+layout.svelte | 14++++++--------
Msrc/routes/(app)/+page.svelte | 4+++-
Msrc/routes/(app)/map/+page.svelte | 130++++++++++++++++++++++++++++++-------------------------------------------------
Msrc/routes/(app)/map/choose-location/+page.svelte | 109++++++++++++++++++++++++++++---------------------------------------------------
Msrc/routes/(app)/models/location-gcs/+page.svelte | 74+++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/routes/(app)/models/nostr-profile/+page.svelte | 41++++++++++++++++++++++-------------------
Msrc/routes/(app)/models/nostr-profile/edit/field/+page.svelte | 12+++++-------
Msrc/routes/(app)/models/nostr-profile/view/+page.svelte | 18++++++++++--------
Msrc/routes/(app)/models/nostr-relay/+page.svelte | 17+++++++++++------
Msrc/routes/(app)/models/nostr-relay/view/+page.svelte | 15+++++++++------
Msrc/routes/(app)/models/trade-product/+page.svelte | 58++++++++++++++++++++++++++++++++++------------------------
Msrc/routes/(app)/models/trade-product/add/+page.svelte | 114++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/routes/(conf)/init/+page.svelte | 28++++++++++++++--------------
Msrc/routes/+layout.svelte | 25++++++++++++++-----------
25 files changed, 611 insertions(+), 413 deletions(-)

diff --git a/src/app.css b/src/app.css @@ -20,5 +20,10 @@ .tap-scale { @apply active:scale-[97%] group-active:scale-[97%] delay-75 duration-700 ease-in-out transition-all; - } + } + + .map-trellis-1 { + height: 400px; + width: 100%; + } } \ No newline at end of file diff --git a/src/lib/components/map-marker-dot.svelte b/src/lib/components/map-marker-dot.svelte @@ -1,29 +0,0 @@ -<script lang="ts"> - import { Fill } from "@radroots/svelte-lib"; - - type MapMarkerDotStyleKey = `blue`; - export let basis: - | { - style?: MapMarkerDotStyleKey; - } - | undefined = undefined; - - $: classes_styles = basis?.style ? styles[basis.style] : styles[`blue`]; - - let styles: Record<MapMarkerDotStyleKey, string> = { - blue: `text-blue-400`, - }; -</script> - -<div class="flex flex-row p-1"> - <div - class={`flex flex-row h-map_circle w-map_circle justify-center items-center bg-white rounded-full shadow-lg`} - > - <div - class={`flex flex-row h-map_circle_inner w-map_circle_inner justify-center items-center rounded-full ${classes_styles}`} - > - <Fill /> - </div> - </div> -</div> -<div class="hidden text-blue-400" /> diff --git a/src/lib/components/map-marker.svelte b/src/lib/components/map-marker.svelte @@ -1,9 +0,0 @@ -<script lang="ts"> - import MapMarkerDot from "./map-marker-dot.svelte"; - - export let kind = "current"; -</script> - -{#if kind === `current`} - <MapMarkerDot /> -{/if} diff --git a/src/lib/components/map_choose_location.svelte b/src/lib/components/map_choose_location.svelte @@ -0,0 +1,102 @@ +<script lang="ts"> + import { geoc } from "$lib/client"; + import { _conf } from "$lib/conf"; + import { app_thc } from "$lib/stores"; + import type { GeocoderReverseResult } from "@radroots/geocoder"; + import { Loading, type CallbackPromise } from "@radroots/svelte-lib"; + import { MapLibre, Marker, Popup } from "@radroots/svelte-maplibre"; + import type { GeolocationCoordinatesPoint } from "@radroots/utils"; + import MapMarkerDot from "./map_marker_dot.svelte"; + import MapPopupLocationInfo from "./map_popup_location_info.svelte"; + + export let basis: { + classes_map: string; + loading?: boolean; + reset?: CallbackPromise; + }; + $: basis = basis; + + export let map_point_center: GeolocationCoordinatesPoint; + export let map_point_select: GeolocationCoordinatesPoint; + export let map_point_select_geoc: GeocoderReverseResult | undefined = + undefined; + + $: { + if ( + map_point_center && + map_point_center.lat !== 0 && + map_point_center.lng !== 0 + ) { + (async () => { + try { + const geoc_res = await geoc.reverse({ + point: map_point_center, + }); + if (`results` in geoc_res && geoc_res.results.length > 0) + map_point_select_geoc = geoc_res.results[0]; + else map_point_select_geoc = undefined; + } catch (e) {} + })(); + } + } +</script> + +<div + class={`relative flex flex-col justify-center items-center ${basis.classes_map} bg-layer-1-surface rounded-3xl overflow-hidden`} +> + <MapLibre + center={map_point_center} + zoom={10} + class={`${basis.classes_map} ${basis.loading ? `hidden` : ``}`} + style={_conf.map.styles.base[$app_thc]} + attributionControl={false} + > + <Marker + bind:lngLat={map_point_select} + draggable + on:dragend={async () => { + if (!map_point_select) return; + const geoc_res = await geoc.reverse({ + point: map_point_select, + limit: 1, + }); + if (`results` in geoc_res && geoc_res.results.length > 0) + map_point_select_geoc = geoc_res.results[0]; + }} + > + <MapMarkerDot /> + <Popup + offset={_conf.map.popup.dot.offset} + open={true} + closeOnClickOutside={false} + closeButton={false} + > + <MapPopupLocationInfo + basis={{ + point: map_point_select, + geoc: map_point_select_geoc, + }} + /> + </Popup> + </Marker> + </MapLibre> + {#if basis.loading} + <div + class={`absolute top-0 left-0 flex flex-col flex-grow h-full w-full justify-center items-center`} + > + <Loading /> + </div> + {/if} +</div> +<div class={`flex flex-col h-8 w-full justify-end items-center`}> + <button + class={`flex flex-row justify-center items-center`} + on:click={async () => { + if (basis.reset) await basis.reset(); + }} + > + <p class={`font-mono font-[400] text-layer-0-glyph text-sm`}> + {`reset`} + </p> + </button> +</div> diff --git a/src/lib/components/map_marker_dot.svelte b/src/lib/components/map_marker_dot.svelte @@ -0,0 +1,15 @@ +<script lang="ts"> + import { Fill } from "@radroots/svelte-lib"; +</script> + +<div class="flex flex-row p-1"> + <div + class={`z-20 flex flex-row h-map_circle w-map_circle justify-center items-center bg-white rounded-full shadow-lg`} + > + <div + class={`z-10 flex flex-row h-map_circle_inner w-map_circle_inner justify-center items-center bg-blue-400 rounded-full`} + > + <Fill /> + </div> + </div> +</div> diff --git a/src/lib/components/map_popup_location_info.svelte b/src/lib/components/map_popup_location_info.svelte @@ -0,0 +1,45 @@ +<script lang="ts"> + import type { GeocoderReverseResult } from "@radroots/geocoder"; + import type { GeolocationCoordinatesPoint } from "@radroots/utils"; + + export let basis: { + point: GeolocationCoordinatesPoint; + geoc?: GeocoderReverseResult; + }; +</script> + +<button + class={`flex flex-row justify-center items-center transition-all`} + on:click={async () => {}} +> + <div + class={`flex flex-col w-fit px-3 py-[0.5rem] gap-2 justify-start items-start`} + > + {#if basis.geoc} + <div class={`flex flex-col w-full gap-1 justify-start items-start`}> + <p class={`font-mono font-[400] text-layer-2-glyph`}> + {basis.geoc.name} + </p> + <p class={`font-mono font-[400] text-layer-2-glyph`}> + {`${basis.geoc.admin1_name}, ${basis.geoc.country_name}`} + </p> + </div> + {:else} + <div class={`flex flex-row w-full justify-start items-center`}> + <p class={`font-mono font-[400] text-layer-2-glyph`}> + {`Marker location:`} + </p> + </div> + <div + class={`flex flex-row w-full gap-2 justify-start items-center`} + > + <p class={`font-mono font-[400] text-layer-2-glyph`}> + {`${basis.point.lat.toFixed(4)}`} + </p> + <p class={`font-mono font-[400] text-layer-2-glyph`}> + {`${basis.point.lng.toFixed(4)}`} + </p> + </div> + {/if} + </div> +</button> diff --git a/src/lib/conf.ts b/src/lib/conf.ts @@ -51,6 +51,12 @@ export const _conf = { dot: { offset: [0, -10] as NumberTuple } + }, + coords: { + default: { + lat: 0, + lng: 0, + } } } }; \ No newline at end of file diff --git a/src/lib/stores.ts b/src/lib/stores.ts @@ -8,7 +8,6 @@ export const app_th = writable<ThemeKey>(`os`); export const app_nostr_key = writable<string>(``); export const app_pwa_polyfills = writable<boolean>(false); -export const app_sqlite = writable<boolean>(false); export const map_full_center = writable<NumberTuple>([0, 0]); export const map_full_zoom = writable<number>(4); diff --git a/src/lib/utils/location_gcs.ts b/src/lib/utils/location_gcs.ts @@ -1,69 +1,49 @@ import { geoc, lc } from "$lib/client"; +import type { GeocoderReverseResult } from "@radroots/geocoder"; import type { LocationGcsFormFields } from "@radroots/models"; import { location_geohash } from "@radroots/utils"; -export const location_gcs_add = async (): Promise<boolean> => { +export const location_gcs_add_geoc = async (opts: { + geoc: GeocoderReverseResult; + label?: string; +}): Promise<{ id: string } | undefined> => { try { - const loc_gcs = await lc.geo.current(); - if ( - loc_gcs && - typeof loc_gcs !== `string` - ) { - const loc_gcs_label = - await lc.dialog.prompt({ - title: `Geolocation Label`, - message: `What is the name of the location.`, - input_placeholder: `Enter location name`, - }); - if (loc_gcs_label === false) return false; - else if (!loc_gcs_label) { - await lc.dialog.alert(`A location name is required.`); - return false; - } - const opts: LocationGcsFormFields = { - lat: loc_gcs.lat.toString(), - lng: loc_gcs.lng.toString(), - geohash: location_geohash(loc_gcs), - label: loc_gcs_label, - } - const gc_reverse = await geoc.reverse({ - point: loc_gcs - }); - if (typeof gc_reverse !== `string` && gc_reverse.results.length > 0) { - const gc_result = gc_reverse.results[0]; - opts.gc_id = gc_result.id.toString(); - opts.gc_name = gc_result.name; - opts.gc_admin1_id = gc_result.admin1_id.toString(); - opts.gc_admin1_name = gc_result.admin1_name; - opts.gc_country_id = gc_result.country_id; - opts.gc_country_name = gc_result.country_name; - }; - console.log(JSON.stringify(opts, null, 4), `opts`) - const exe_res = - await lc.db.location_gcs_add(opts); - console.log(`exe_res `, exe_res) - if ( - typeof exe_res !== `string` && - `id` in exe_res - ) { - return true; - } else if ( - typeof exe_res === `string` && - exe_res === - `*-location-gcs-geohash-unique` - ) { - await lc.dialog.alert( - `This location has already been added.`, - ); - } - } else if ( - loc_gcs && - typeof loc_gcs === `string` + const { geoc } = opts; + const fields: LocationGcsFormFields = { + lat: geoc.latitude.toString(), + lng: geoc.longitude.toString(), + geohash: location_geohash({ lat: geoc.latitude, lng: geoc.longitude }), + gc_id: geoc.id.toString(), + gc_name: geoc.name, + gc_admin1_id: geoc.admin1_id.toString(), + gc_admin1_name: geoc.admin1_name, + gc_country_id: geoc.country_id, + gc_country_name: geoc.country_name, + }; + if (opts.label) fields.label = opts.label; + + const res = + await lc.db.location_gcs_add(fields); + if (`id` in res) return res; + else if (`err` in res && res.err === `*-location-gcs-geohash-unique` ) { - const dcf_res = await lc.dialog.confirm( + await lc.dialog.alert( + `This location has already been added.`, + ); + } + } catch (e) { + console.log(`(error) location_gcs_add_geoc `, e); + } +}; + +export const location_gcs_add_current = async (): Promise<{ id: string } | false> => { + try { + const geoloc = await lc.geo.current(); + if (`err` in geoloc) { + const confirm = await lc.dialog.confirm( `Location permissions are required to read geolocation.`, ); - if (dcf_res) { + if (confirm) { await lc.settings.open( lc.platform === `ios` ? { @@ -78,10 +58,51 @@ export const location_gcs_add = async (): Promise<boolean> => { }, ); } + return false; + } + + const dialog_label = + await lc.dialog.prompt({ + title: `Geolocation Label`, + message: `What is the name of the location.`, + input_placeholder: `Enter location name`, + }); + if (dialog_label === false) return false; + else if (!dialog_label) { + await lc.dialog.alert(`A location name is required.`); + return false; } + const fields: LocationGcsFormFields = { + lat: geoloc.lat.toString(), + lng: geoloc.lng.toString(), + geohash: location_geohash(geoloc), + label: dialog_label, + } + const geoc_res = await geoc.reverse({ + point: geoloc + }); + if (`results` in geoc_res && geoc_res.results.length > 0) { + const gc_result = geoc_res.results[0]; + fields.gc_id = gc_result.id.toString(); + fields.gc_name = gc_result.name; + fields.gc_admin1_id = gc_result.admin1_id.toString(); + fields.gc_admin1_name = gc_result.admin1_name; + fields.gc_country_id = gc_result.country_id; + fields.gc_country_name = gc_result.country_name; + }; + const res = + await lc.db.location_gcs_add(fields); + if (`id` in res) return res; + else if (`err` in res && res.err === `*-location-gcs-geohash-unique` + ) { + await lc.dialog.alert( + `This location has already been added.`, + ); + } + return false; } catch (e) { - console.log(`(error) location_gcs_add `, e); + console.log(`(error) location_gcs_add_current `, e); return false; } }; \ No newline at end of file diff --git a/src/lib/utils/nostr.ts b/src/lib/utils/nostr.ts @@ -12,9 +12,8 @@ export const nostr_sync_models_trade_product = async (opts: { const trade_products_all = await lc.db.trade_product_get({ list: [`all`], }); - if (typeof trade_products_all === `string`) return; - - for (const trade_product of trade_products_all) { + if (`err` in trade_products_all) return; + for (const trade_product of trade_products_all.results) { const tags_basis = await fmt_tags_basis_nip99({ d_tag: trade_product.id, title: trade_product.key, diff --git a/src/lib/utils/trade_product.ts b/src/lib/utils/trade_product.ts @@ -1,10 +1,11 @@ import { parse_trade_product_form_keys, trade_product_form_fields, trade_product_form_vals, type TradeProductFormFields } from "@radroots/models"; import { kv } from "@radroots/svelte-lib"; +import { err_msg, type ErrorMessage } from "@radroots/utils"; export const validate_trade_product_vals = async (opts: { kv_pref: string; no_validation?: string[] | true; -}): Promise<TradeProductFormFields | string> => { +}): Promise<TradeProductFormFields | ErrorMessage<string>> => { try { let no_validation = opts.no_validation || []; const vals = { @@ -27,13 +28,13 @@ export const validate_trade_product_vals = async (opts: { !field.validation.test(field_val)) ) { if (no_validation.includes(field_k)) continue; - else return field_k; + else return err_msg(field_k); } } return vals; } catch (e) { console.log(`(error) trade_product_submit_preview `, e); - return `` + return err_msg(String(e)) } }; diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte @@ -35,11 +35,9 @@ const nostr_relays = await lc.db.nostr_relay_get({ list: ["all"], }); - if (typeof nostr_relays === `string`) { - alert(`${nostr_relays} - go to recovery (todo)`); //@todo - return; - } - for (const { url } of nostr_relays) $ndk.addExplicitRelay(url); + if (`err` in nostr_relays) throw new Error(nostr_relays.err); + for (const { url } of nostr_relays.results) + $ndk.addExplicitRelay(url); await $ndk.connect(); const ndk_user = await ndk_init({ $ndk, @@ -121,9 +119,9 @@ const nostr_relays = await lc.db.nostr_relay_get({ list: [`on_profile`, { public_key: $app_nostr_key }], }); - if (typeof nostr_relays === `string`) throw new Error(); + if (`err` in nostr_relays) throw new Error(nostr_relays.err); - const unconnected_relays = nostr_relays.filter( + const unconnected_relays = nostr_relays.results.filter( (i) => !$nostr_relays_connected.includes(i.id), ); if (unconnected_relays.length === 0) { @@ -138,7 +136,7 @@ Accept: "application/nostr+json", }, }); - if (typeof res === `string`) continue; + if (`err` in res) continue; else if (res.status === 200 && res.data) { const doc = parse_nostr_relay_information_document_fields( res.data, diff --git a/src/routes/(app)/+page.svelte b/src/routes/(app)/+page.svelte @@ -167,7 +167,9 @@ }, { icon: `compass`, - callback: async (tab_i) => {}, + callback: async (tab_i) => { + await route(`/map/choose-location`); + }, }, { icon: `network`, diff --git a/src/routes/(app)/map/+page.svelte b/src/routes/(app)/map/+page.svelte @@ -1,94 +1,62 @@ <script lang="ts"> - import { lc } from "$lib/client"; - import MapControlFull from "$lib/components/map_control_full.svelte"; - import { _conf } from "$lib/conf"; - import { app_thc } from "$lib/stores"; - import { Fill, LoadingView, route, sleep } from "@radroots/svelte-lib"; - import { MapLibre, Marker, Popup } from "@radroots/svelte-maplibre"; - import { type NumberTuple } from "@radroots/utils"; - import { onMount } from "svelte"; + import { lc } from "$lib/client"; + import MapControlFull from "$lib/components/map_control_full.svelte"; + import MapMarkerDot from "$lib/components/map_marker_dot.svelte"; + import MapPopupLocationInfo from "$lib/components/map_popup_location_info.svelte"; + import { _conf } from "$lib/conf"; + import { app_thc } from "$lib/stores"; + import { LoadingView, route, sleep } from "@radroots/svelte-lib"; + import { MapLibre, Marker, Popup } from "@radroots/svelte-maplibre"; + import { type GeolocationCoordinatesPoint } from "@radroots/utils"; + import { onMount } from "svelte"; - let loading_layout = true; - let map_coords: NumberTuple | undefined = undefined; + let loading_layout = true; + let map_coords: GeolocationCoordinatesPoint | undefined = undefined; - onMount(async () => { - try { - const loc = await lc.geo.current(); - if (loc && typeof loc !== `string`) { - map_coords = [loc.lng, loc.lat]; - } - await sleep(_conf.delay.load); - } catch (e) { - console.log(`e `, e); - } finally { - loading_layout = false; - } - }); + onMount(async () => { + try { + const geoloc = await lc.geo.current(); + if (`err` in geoloc) return; + map_coords = geoloc; + await sleep(_conf.delay.load); + } catch (e) { + console.log(`e `, e); + } finally { + loading_layout = false; + } + }); </script> {#if map_coords} - <MapLibre - center={map_coords} - zoom={10} - class={`map-full ${loading_layout ? `hidden` : ``}`} - style={_conf.map.styles.base[$app_thc]} - > - <Marker lngLat={map_coords}> - <div class="flex flex-row p-1"> - <div - class={`flex flex-row h-map_circle w-map_circle justify-center items-center bg-white rounded-full shadow-lg`} - > - <div - class={`flex flex-row h-map_circle_inner w-map_circle_inner justify-center items-center bg-blue-400 rounded-full`} - > - <Fill /> - </div> - </div> - </div> - <Popup offset={_conf.map.popup.dot.offset}> - <button - class={`flex flex-row justify-center items-center transition-all`} - on:click={async () => {}} - > - <div - class={`flex flex-col w-fit px-2 py-1 gap-2 justify-start items-start`} - > - <div class={`flex flex-row w-full justify-start items-center`}> - <p class={`font-mono font-[400] text-layer-2-glyph`}> - {`Marker location:`} - </p> - </div> - <div - class={`flex flex-row w-full gap-2 justify-start items-center`} - > - <p class={`font-mono font-[400] text-layer-2-glyph`}> - {map_coords[0]} - </p> - <p class={`font-mono font-[400] text-layer-2-glyph`}> - {map_coords[1]} - </p> - </div> - </div> - </button> - </Popup> - </Marker> - </MapLibre> + <MapLibre + center={map_coords} + zoom={10} + class={`map-full ${loading_layout ? `hidden` : ``}`} + style={_conf.map.styles.base[$app_thc]} + > + <Marker lngLat={map_coords}> + <MapMarkerDot /> + <Popup offset={_conf.map.popup.dot.offset}> + <MapPopupLocationInfo basis={{ point: map_coords }} /> + </Popup> + </Marker> + </MapLibre> {/if} {#if loading_layout} - <LoadingView /> + <LoadingView /> {:else} - <MapControlFull - basis={{ - callback: async () => { - await route(`/`); - }, - }} - /> + <MapControlFull + basis={{ + callback: async () => { + await route(`/`); + }, + }} + /> {/if} <style> - :global(.map-full) { - height: 100vh; - width: 100vh; - } + :global(.map-full) { + height: 100vh; + width: 100vh; + } </style> diff --git a/src/routes/(app)/map/choose-location/+page.svelte b/src/routes/(app)/map/choose-location/+page.svelte @@ -1,35 +1,31 @@ <script lang="ts"> - import { lc } from "$lib/client"; + import { geoc, lc } from "$lib/client"; import MapControlFull from "$lib/components/map_control_full.svelte"; + import MapMarkerDot from "$lib/components/map_marker_dot.svelte"; + import MapPopupLocationInfo from "$lib/components/map_popup_location_info.svelte"; import { _conf } from "$lib/conf"; import { app_thc } from "$lib/stores"; - import { - Fill, - Glyph, - LoadingView, - route, - sleep, - } from "@radroots/svelte-lib"; - import { MapLibre, Marker } from "@radroots/svelte-maplibre"; - import { - location_geohash, - type GeolocationCoordinatesPoint, - } from "@radroots/utils"; + import { location_gcs_add_current } from "$lib/utils/location_gcs"; + import { LoadingView, route, sleep } from "@radroots/svelte-lib"; + import { MapLibre, Marker, Popup } from "@radroots/svelte-maplibre"; + import { type GeolocationCoordinatesPoint } from "@radroots/utils"; import { onMount } from "svelte"; let loading_layout = true; + let map_coords_inital: GeolocationCoordinatesPoint | undefined = undefined; let map_coords: GeolocationCoordinatesPoint | undefined = undefined; onMount(async () => { try { - const loc = await lc.geo.current(); - if (loc && typeof loc !== `string`) { - map_coords = loc; - } else { - map_coords = { + const geoloc = await lc.geo.current(); + if (`err` in geoloc) + map_coords_inital = { lat: 0, lng: 0, }; + else { + map_coords_inital = geoloc; + map_coords = geoloc; } await sleep(_conf.delay.load); } catch (e) { @@ -38,35 +34,36 @@ loading_layout = false; } }); - - $: { - console.log(`map_coords `, map_coords); - } </script> {#if map_coords} <MapLibre - center={map_coords} + center={map_coords_inital} zoom={10} class={`map-full ${loading_layout ? `hidden` : ``}`} style={_conf.map.styles.base[$app_thc]} > - <Marker bind:lngLat={map_coords} draggable> - <div class="relative flex flex-col w-4 items-center justify-center"> - <div - class={`absolute top-[3px] left-[3px] flex flex-row h-[10px] w-[10px] bg-red-100/30 rounded-full justify-start items-center`} - > - <Fill /> - </div> - <Glyph - basis={{ - classes: `text-red-700`, - key: `map-pin-simple`, - weight: `fill`, - dim: `xl`, - }} - /> - </div> + <Marker + bind:lngLat={map_coords} + draggable + on:dragend={async () => { + if (!map_coords) return; + const geoc_res = await geoc.reverse({ + point: map_coords, + limit: 1, + }); + if (`results` in geoc_res) { + console.log( + JSON.stringify(geoc_res.results, null, 4), + `geoc_res.results`, + ); + } + }} + > + <MapMarkerDot /> + <Popup offset={_conf.map.popup.dot.offset}> + <MapPopupLocationInfo basis={{ point: map_coords }} /> + </Popup> </Marker> </MapLibre> {/if} @@ -77,37 +74,9 @@ basis={{ callback: async () => { if (!map_coords) return; //@todo - - const location_gcs_label = await lc.dialog.prompt({ - title: `Geolocation Label`, - message: `What is the name of the location.`, - input_placeholder: `Enter location name`, - }); - if (location_gcs_label === false) return; - else if (!location_gcs_label) { - await lc.dialog.alert(`A location name is required.`); - return; - } - - const { lat, lng } = map_coords; - const new_location_gcs = await lc.db.location_gcs_add({ - label: location_gcs_label, - geohash: location_geohash(lat, lng), - lat: lat.toString(), - lng: lng.toString(), - }); - - if (typeof new_location_gcs === `string`) { - //@todo - return; - } else if (Array.isArray(new_location_gcs)) { - //@todo - return; - } - - await route(`/models/trade-product/add`, [ - [`id`, new_location_gcs.id], - ]); + const res = await location_gcs_add_current(); + if (res) + await route(`/models/trade-product/add`, [[`id`, res.id]]); }, }} /> diff --git a/src/routes/(app)/models/location-gcs/+page.svelte b/src/routes/(app)/models/location-gcs/+page.svelte @@ -1,8 +1,9 @@ <script lang="ts"> import { lc } from "$lib/client"; - import { location_gcs_add } from "$lib/utils/location_gcs"; + import { location_gcs_add_current } from "$lib/utils/location_gcs"; import { type LocationGcs } from "@radroots/models"; import { + app_notify, LayoutTrellis, LayoutView, Nav, @@ -11,36 +12,50 @@ } from "@radroots/svelte-lib"; import { onMount } from "svelte"; - let models_list: LocationGcs[] = []; - let loading_models = false; + type LoadData = { + location_gcss: LocationGcs[]; + }; + let ld: LoadData | undefined = undefined; onMount(async () => { try { - await fetch_models(); + ld = await load_data(); } catch (e) { } finally { } }); - const fetch_models = async (): Promise<void> => { + $: { + console.log(JSON.stringify(ld, null, 4), `ld`); + } + + const load_data = async (): Promise<LoadData | undefined> => { try { - loading_models = true; - const res = await lc.db.location_gcs_get({ + const location_gcss = await lc.db.location_gcs_get({ list: [`all`], }); - if (typeof res !== `string`) models_list = res; + if (`err` in location_gcss) { + app_notify.set(`Error loading page`); + return; + } else if (location_gcss.results.length < 1) { + app_notify.set(`Error loading page`); + return; + } + + const data: LoadData = { + location_gcss: location_gcss.results, + }; + return data; } catch (e) { - console.log(`(error) fetch_models `, e); - } finally { - loading_models = false; + console.log(`(error) load_data `, e); } }; </script> <LayoutView> <LayoutTrellis> - {#if models_list.length} - {#each models_list as li} + {#if ld && ld.location_gcss?.length > 0} + {#each ld.location_gcss as li} <Trellis basis={{ args: { @@ -61,7 +76,7 @@ ], right: [ { - value: li.label, + value: li.label || `test`, }, ], }, @@ -92,7 +107,7 @@ }} /> {/each} - {:else if !loading_models} + {:else if ld && ld?.location_gcss?.length === 0} <div class={`flex flex-col w-full justify-center items-center px-4 gap-3`} > @@ -103,8 +118,8 @@ <button class={`flex flex-row justify-center items-center`} on:click={async () => { - const res = await location_gcs_add(); - if (res === true) await fetch_models(); + const res = await location_gcs_add_current(); + if (res) ld = await load_data(); }} > <p @@ -128,18 +143,19 @@ value: `${$t(`common.locations`)}`, }, }, - option: models_list.length - ? { - label: { - value: `${$t(`common.add`)}`, - classes: `tap-color`, - }, - callback: async () => { - const res = await location_gcs_add(); - if (res === true) await fetch_models(); - }, - } - : undefined, + option: + ld && ld?.location_gcss?.length > 0 + ? { + label: { + value: `${$t(`common.add`)}`, + classes: `tap-color`, + }, + callback: async () => { + const res = await location_gcs_add_current(); + if (res) await load_data(); + }, + } + : undefined, }} /> diff --git a/src/routes/(app)/models/nostr-profile/+page.svelte b/src/routes/(app)/models/nostr-profile/+page.svelte @@ -1,12 +1,13 @@ <script lang="ts"> import { lc } from "$lib/client"; - import { location_gcs_add } from "$lib/utils/location_gcs"; + import { location_gcs_add_current } from "$lib/utils/location_gcs"; import { nostr_profile_form_vals, parse_nostr_profile_form_keys, type NostrProfile, } from "@radroots/models"; import { + app_notify, as_glyph_key, LayoutTrellis, LayoutView, @@ -16,37 +17,41 @@ } from "@radroots/svelte-lib"; import { onMount } from "svelte"; - let models_list: NostrProfile[] = []; - //let loading_models = false; + type LoadData = { + nostr_profiles: NostrProfile[]; + }; + let ld: LoadData | undefined = undefined; onMount(async () => { try { - await load_models(); + ld = await load_data(); } catch (e) { } finally { } }); - const load_models = async (): Promise<void> => { + const load_data = async (): Promise<LoadData | undefined> => { try { - //loading_models = true; - const res = await lc.db.nostr_profile_get({ + const nostr_profiles = await lc.db.nostr_profile_get({ list: [`all`], }); - console.log(JSON.stringify(res, null, 4), `res`); - if (typeof res !== `string`) models_list = res; + if (`err` in nostr_profiles) { + app_notify.set(`Error loading page`); + return; + } else if (nostr_profiles.results.length < 1) { + app_notify.set(`Error loading page`); + return; + } } catch (e) { - console.log(`(error) load_models `, e); - } finally { - //loading_models = false; + console.log(`(error) load_data `, e); } }; </script> <LayoutView> <LayoutTrellis> - {#if models_list.length} - {#each models_list as li} + {#if ld} + {#each ld.nostr_profiles as li} <Trellis basis={{ args: { @@ -105,8 +110,8 @@ <button class={`flex flex-row justify-center items-center`} on:click={async () => { - const res = await location_gcs_add(); - if (res === true) await load_models(); + const res = await location_gcs_add_current(); + if (res) ld = await load_data(); }} > <p @@ -130,15 +135,13 @@ value: `${$t(`common.profiles`)}`, }, }, - option: models_list.length + option: ld?.nostr_profiles?.length ? { label: { value: `${$t(`common.add`)}`, classes: `tap-color`, }, callback: async () => { - //const res = await location_gcs_add(); - //if (res === true) await load_models(); const ks_keys = await lc.keystore.keys(); console.log(JSON.stringify(ks_keys, null, 4), `ks_keys`); for (const ks_key of ks_keys || []) { diff --git a/src/routes/(app)/models/nostr-profile/edit/field/+page.svelte b/src/routes/(app)/models/nostr-profile/edit/field/+page.svelte @@ -64,7 +64,10 @@ const nostr_profiles = await lc.db.nostr_profile_get({ public_key: $qp_nostr_pk, }); - if (typeof nostr_profiles === `string`) { + if (`err` in nostr_profiles) { + app_notify.set(`Error loading profile`); + return; + } else if (nostr_profiles.results.length < 1) { app_notify.set(`Error loading profile`); return; } @@ -74,14 +77,9 @@ app_notify.set(`Error loading page`); return; } - const nostr_profile = nostr_profiles[0]; - - //const existing_field = nostr_profile[field_key]; - //console.log(`existing_field `, existing_field); - //if (existing_field) await kv.set(fmt_id($qp_rkey), existing_field); const data: LoadData = { - nostr_profile, + nostr_profile: nostr_profiles.results[0], field_key, }; return data; diff --git a/src/routes/(app)/models/nostr-profile/view/+page.svelte b/src/routes/(app)/models/nostr-profile/view/+page.svelte @@ -48,14 +48,16 @@ const nostr_profiles = await lc.db.nostr_profile_get({ public_key: $qp_nostr_pk, }); - if (typeof nostr_profiles === `string`) { - app_notify.set(`Error loading profile`); + if (`err` in nostr_profiles) { + app_notify.set(`Error loading page`); + return; + } else if (nostr_profiles.results.length < 1) { + app_notify.set(`Error loading page`); return; } - const nostr_profile = nostr_profiles[0]; const secret_key = await lc.keystore.get( - _conf.kv.nostr_key(nostr_profile.public_key), + _conf.kv.nostr_key($qp_nostr_pk), ); if (!secret_key) { @@ -74,13 +76,13 @@ }); const data: LoadData = { - nostr_profile, + nostr_profile: nostr_profiles.results[0], secret_key, nostr_relays: - typeof nostr_relays !== `string` ? nostr_relays : [], + `results` in nostr_relays ? nostr_relays.results : [], nostr_relays_unconnected: - typeof nostr_relays_unconnected !== `string` - ? nostr_relays_unconnected + `results` in nostr_relays_unconnected + ? nostr_relays_unconnected.results : [], }; return data; diff --git a/src/routes/(app)/models/nostr-relay/+page.svelte b/src/routes/(app)/models/nostr-relay/+page.svelte @@ -3,6 +3,7 @@ import { app_nostr_key } from "$lib/stores"; import type { NostrRelay } from "@radroots/models"; import { + app_notify, GlyphCircle, LayoutTrellis, LayoutView, @@ -39,19 +40,23 @@ list: [`on_profile`, { public_key: $app_nostr_key }], sort: `oldest`, }); + if (`err` in nostr_relays) { + app_notify.set(`Error loading page`); + return; + } const nostr_relays_other = await lc.db.nostr_relay_get({ list: [`off_profile`, { public_key: $app_nostr_key }], sort: `oldest`, }); + if (`err` in nostr_relays_other) { + app_notify.set(`Error loading page`); + return; + } const data: LoadData = { - nostr_relays: - typeof nostr_relays !== `string` ? nostr_relays : [], - nostr_relays_other: - typeof nostr_relays_other !== `string` - ? nostr_relays_other - : [], + nostr_relays: nostr_relays.results, + nostr_relays_other: nostr_relays_other.results, }; return data; } catch (e) { diff --git a/src/routes/(app)/models/nostr-relay/view/+page.svelte b/src/routes/(app)/models/nostr-relay/view/+page.svelte @@ -37,12 +37,15 @@ const nostr_relays = await lc.db.nostr_relay_get({ id: $qp_id, }); - if (typeof nostr_relays === `string`) { - app_notify.set(`Error loading relay`); + if (`err` in nostr_relays) { + app_notify.set(`Error loading page`); + return; + } else if (nostr_relays.results.length < 1) { + app_notify.set(`Error loading page`); return; } - const nostr_relay = nostr_relays[0]; + const nostr_relay = nostr_relays.results[0]; const nostr_profiles = await lc.db.nostr_profile_get({ list: [`on_relay`, { id: nostr_relay.id }], @@ -55,10 +58,10 @@ const data: LoadData = { nostr_relay, nostr_profiles: - typeof nostr_profiles !== `string` ? nostr_profiles : [], + `results` in nostr_profiles ? nostr_profiles.results : [], nostr_profiles_unconnected: - typeof nostr_profiles_unconnected !== `string` - ? nostr_profiles_unconnected + `results` in nostr_profiles_unconnected + ? nostr_profiles_unconnected.results : [], }; return data; diff --git a/src/routes/(app)/models/trade-product/+page.svelte b/src/routes/(app)/models/trade-product/+page.svelte @@ -2,6 +2,7 @@ import { lc } from "$lib/client"; import { type TradeProduct } from "@radroots/models"; import { + app_notify, LayoutTrellis, LayoutView, locale, @@ -13,36 +14,44 @@ } from "@radroots/svelte-lib"; import { onMount } from "svelte"; - let models_list: TradeProduct[] = []; - let loading_models = false; + type LoadData = { + trade_products: TradeProduct[]; + }; + let ld: LoadData | undefined = undefined; onMount(async () => { try { - await fetch_models(); + ld = await load_data(); } catch (e) { } finally { } }); - const fetch_models = async (): Promise<void> => { + const load_data = async (): Promise<LoadData | undefined> => { try { - loading_models = true; - const res = await lc.db.trade_product_get({ + const trade_products = await lc.db.trade_product_get({ list: [`all`], }); - if (typeof res !== `string`) models_list = res; + console.log(`trade_products `, trade_products); + if (`err` in trade_products) { + app_notify.set(`Error loading page`); + return; + } + + const data: LoadData = { + trade_products: trade_products.results, + }; + return data; } catch (e) { - console.log(`(error) fetch_models `, e); - } finally { - loading_models = false; + console.log(`(error) load_data `, e); } }; </script> <LayoutView> <LayoutTrellis> - {#if models_list.length} - {#each models_list as li, li_i} + {#if ld && ld.trade_products.length > 0} + {#each ld.trade_products as li, li_i} <Trellis basis={{ args: { @@ -140,7 +149,7 @@ }} /> {/each} - {:else if !loading_models} + {:else} <div class={`flex flex-col w-full justify-center items-center px-4 gap-2`} > @@ -169,16 +178,17 @@ value: `${$t(`common.products`)}`, }, }, - option: models_list.length - ? { - label: { - value: `${$t(`common.add`)}`, - classes: `tap-color`, - }, - callback: async () => { - await route(`/models/trade-product/add`); - }, - } - : undefined, + option: + ld && ld?.trade_products?.length > 0 + ? { + label: { + value: `${$t(`common.add`)}`, + classes: `tap-color`, + }, + callback: async () => { + await route(`/models/trade-product/add`); + }, + } + : undefined, }} /> diff --git a/src/routes/(app)/models/trade-product/add/+page.svelte b/src/routes/(app)/models/trade-product/add/+page.svelte @@ -1,11 +1,14 @@ <!-- svelte-ignore a11y-no-noninteractive-tabindex --> <script lang="ts"> import { lc } from "$lib/client"; - import { location_gcs_add } from "$lib/utils/location_gcs"; + import MapChooseLocation from "$lib/components/map_choose_location.svelte"; + import { _conf } from "$lib/conf"; + import { location_gcs_add_current } from "$lib/utils/location_gcs"; import { trade_product_kv_init, validate_trade_product_vals, } from "$lib/utils/trade_product"; + import type { GeocoderReverseResult } from "@radroots/geocoder"; import { mass_units, trade_product_form_fields, @@ -31,7 +34,7 @@ locale, Nav, NotifyGlyph, - route, + sleep, t, TextareaElement, view_effect, @@ -45,6 +48,7 @@ trade_keys, trade_quantities, type CurrencyPrice, + type GeolocationCoordinatesPoint, type TradeKey, } from "@radroots/utils"; import { onMount } from "svelte"; @@ -90,13 +94,25 @@ let el_trellis_wrap_price: HTMLElement | null; - type View = `form_1` | `load`; + type View = `load` | `form_1` | `map`; let view: View = `load`; $: { view_effect<View>(view); } + $: { + if (view === `map`) { + (async () => { + try { + loading_map = true; + await sleep(500); + loading_map = false; + } catch (e) {} + })(); + } + } + let show_sel_trade_product_key_other = false; let sel_trade_product_key: string = trade_key_default; $: sel_trade_product_key_parsed = parse_trade_key(sel_trade_product_key); @@ -106,6 +122,12 @@ let sel_location_gcs_id = ``; let ls_models_location_gcs: LocationGcs[] = []; + let map_point_location_gcs: GeolocationCoordinatesPoint = + _conf.map.coords.default; + let map_point_location_gcs_select: GeolocationCoordinatesPoint = + _conf.map.coords.default; + let map_point_location_gcs_select_geoc: GeocoderReverseResult | undefined = + undefined; let show_sel_trade_product_qty_tup_other = false; let sel_trade_product_qty_tup = ``; @@ -123,6 +145,7 @@ let review_location_gcs: LocationGcs | undefined = undefined; let loading_submit = false; + let loading_map = false; let loading_location_gcs = false; $: num_trade_product_qty_amt = preview_trade_product @@ -273,9 +296,9 @@ `title`, ], }); - if (typeof vals_init === `string`) { + if (`err` in vals_init) { await lc.dialog.alert( - `${$t(`trade.product.fields.${vals_init}.err_invalid`, { default: `${$t(`icu.invalid_*`, { value: vals_init })}` })}`, + `${$t(`trade.product.fields.${vals_init}.err_invalid`, { default: `${$t(`icu.invalid_*`, { value: vals_init.err })}` })}`, ); return; } @@ -294,7 +317,7 @@ kv_pref: fmt_id(), no_validation: [`summary`, `title`], }); - if (typeof vals === `string`) { + if (`err` in vals) { await lc.dialog.alert(`The entry is incomplete`); return; } @@ -312,12 +335,10 @@ const vals = await validate_trade_product_vals({ kv_pref: fmt_id(), }); - console.log(JSON.stringify(vals, null, 4), `vals`); - if (typeof vals === `string`) { + if (`err` in vals) { await lc.dialog.alert(`Enter the listing details`); return; } - console.log(JSON.stringify(vals, null, 4), `vals`); await carousel_next(`form_1`); } break; @@ -331,30 +352,36 @@ `The product location is missing`, ); return; + //@todo } const location_gcs_get = await lc.db.location_gcs_get({ id: location_gcs_kv_id, }); - if (typeof location_gcs_get === `string`) { + if (`err` in location_gcs_get) { + await lc.dialog.alert( + `The product location is missing`, + ); + preview_trade_product = undefined; + return; //@todo + } else if (location_gcs_get.results.length < 1) { await lc.dialog.alert( `The product location is missing`, ); preview_trade_product = undefined; return; + //@todo } - review_location_gcs = location_gcs_get[0]; - + review_location_gcs = location_gcs_get.results[0]; const vals = await validate_trade_product_vals({ kv_pref: fmt_id(), }); - if (typeof vals === `string`) { + if (`err` in vals) { await lc.dialog.alert(`The entry is incomplete`); - //@todo return; + //@todo } review_trade_product = vals; - await carousel_next(`form_1`); } break; @@ -407,7 +434,7 @@ const res = await lc.db.location_gcs_get({ list: [`all`], }); - if (typeof res !== `string`) ls_models_location_gcs = res; + if (`results` in res) ls_models_location_gcs = res.results; } catch (e) { console.log(`(error) fetch_models_models_location_gcs `, e); } @@ -416,7 +443,7 @@ const add_model_location_gcs = async (): Promise<void> => { try { loading_location_gcs = true; - await location_gcs_add(); + await location_gcs_add_current(); await fetch_models_models_location_gcs(); } catch (e) { console.log(`(error) add_model_location_gcs `, e); @@ -428,7 +455,6 @@ const submit = async (): Promise<void> => { try { loading_submit = true; - // await route(`/models/trade-product/add/preview`); } catch (e) { console.log(`(error) submit `, e); } finally { @@ -448,7 +474,7 @@ <div data-view={`form_1`} data-carousel-container={`form_1`} - class={`carousel-container carousel-container-trellis hidden`} + class={`hidden carousel-container carousel-container-trellis`} > <div data-carousel-item={`form_1`} @@ -1227,7 +1253,8 @@ await add_model_location_gcs(); } else if (val === `add-map`) { sel_location_gcs_id = ``; - await route(`/map/choose-location`); + view = `map`; + //await route(`/map/choose-location`); } }, }} @@ -1274,6 +1301,23 @@ </div> </div> </div> + <div + data-view={`map`} + class={`hidden flex flex-col h-full w-full justify-start items-start`} + > + <MapChooseLocation + basis={{ + classes_map: `map-trellis-1`, + loading: loading_map, + reset: async () => { + map_point_location_gcs_select = map_point_location_gcs; + }, + }} + bind:map_point_center={map_point_location_gcs} + bind:map_point_select={map_point_location_gcs_select} + bind:map_point_select_geoc={map_point_location_gcs_select_geoc} + /> + </div> </LayoutTrellis> </LayoutView> <Nav @@ -1298,14 +1342,26 @@ value: `${$t(`icu.add_*`, { value: `${$t(`common.product`)}` })}`, }, callback: async () => { - const el = el_id(fmt_id(`key_wrap`)); - el?.focus(); + if (view === `map`) { + view = `form_1`; + } else { + const geoloc = await lc.geo.current(); + if (`err` in geoloc) return; + else { + map_point_location_gcs = geoloc; + map_point_location_gcs_select = geoloc; + } + view = `map`; + } }, }, option: { loading: loading_submit, label: { - value: carousel_conf.get($carousel_index)?.label_next || ``, + value: + view === `map` + ? `Use Location` + : carousel_conf.get($carousel_index)?.label_next || ``, classes: `text-layer-1-glyph-hl`, glyph: $carousel_index > 0 && $carousel_index < $carousel_index_max @@ -1316,7 +1372,17 @@ : undefined, }, callback: async () => { - if ($carousel_index === $carousel_index_max) await submit(); + if (view === `map`) { + console.log( + JSON.stringify( + map_point_location_gcs_select_geoc, + null, + 4, + ), + `map_point_location_gcs_select_geoc`, + ); + } else if ($carousel_index === $carousel_index_max) + await submit(); else await handle_carousel_next(); }, }, diff --git a/src/routes/(conf)/init/+page.svelte b/src/routes/(conf)/init/+page.svelte @@ -91,9 +91,9 @@ secret_key, ); if (!ks_key_add) { - //@todo reset alert(`!ks_key_add`); return; + //@todo reset } const pref_key_add = await lc.preferences.set( @@ -101,35 +101,35 @@ public_key, ); if (!pref_key_add) { - //@todo reset alert(`!pref_key_add`); return; + //@todo reset } const nostr_profile_add = await lc.db.nostr_profile_add({ public_key, }); - if (typeof nostr_profile_add === `string`) { - // @todo reset - alert(nostr_profile_add); + if (`err` in nostr_profile_add) { + await lc.dialog.alert(nostr_profile_add.err); return; - } else if (Array.isArray(nostr_profile_add)) { - //@todo reset - alert(nostr_profile_add.join(` `)); + //@todo + } else if (`err_s` in nostr_profile_add) { + await lc.dialog.alert(nostr_profile_add.err_s.join(` `)); return; + //@todo } for (const url of PUBLIC_NOSTR_RELAY_DEFAULTS.split(",") || []) { const nostr_relay_add = await lc.db.nostr_relay_add({ url }); - if (typeof nostr_relay_add === `string`) { - // @todo reset - alert(nostr_relay_add); + if (`err` in nostr_relay_add) { + await lc.dialog.alert(nostr_relay_add.err); return; - } else if (Array.isArray(nostr_relay_add)) { - //@todo reset - alert(nostr_relay_add.join(` `)); + // @todo + } else if (`err_s` in nostr_relay_add) { + await lc.dialog.alert(nostr_relay_add.err_s.join(` `)); return; + //@todo } await lc.db.set_nostr_profile_relay({ nostr_profile: { diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte @@ -5,13 +5,14 @@ import { app_nostr_key, app_pwa_polyfills, - app_sqlite, app_th, app_thc, } from "$lib/stores"; import { defineCustomElements as pwaElements } from "@ionic/pwa-elements/loader"; import { app_config, + app_db, + app_geoc, app_notify, app_render, AppControls, @@ -62,24 +63,26 @@ lc.window.status_style(color_mode); }); - app_sqlite.subscribe((app_sqlite) => { - if (!app_sqlite) return; - console.log(`(app_sqlite) success`); + app_db.subscribe((_app_db) => { + if (!_app_db) return; + console.log(`(app_db) success`); + }); + + app_geoc.subscribe((_app_geoc) => { + if (!_app_geoc) return; + console.log(`(app_geoc) success`); }); app_config.subscribe(async (app_config) => { try { if (!app_config) return; console.log(`app_config!`); + const db_connected = await lc.db.connect(); - if (!db_connected) { - // @todo - } - app_sqlite.set(!!db_connected); + app_db.set(!!db_connected); - console.log(`connect geocoder!!`); const geoc_connected = await geoc.connect(); - console.log(`geoc_connected `, geoc_connected); + app_geoc.set(!!geoc_connected); const active_key_public = await lc.preferences.get( _conf.kv.nostr_key_active, @@ -148,4 +151,4 @@ <div class="hidden h-nav_base pt-h_nav_base pb-h_nav_base h-nav_lg pt-h_nav_lg pb-h_nav_lg h-tabs_base pt-h_tabs_base pb-h_tabs_base h-tabs_lg pt-h_tabs_lg pb-h_tabs_lg top-dim_map_offset_top_base top-dim_map_offset_top_lg" ></div> -<div class="hidden border-layer-1-surface-edge/40"></div> +<div class="hidden border-layer-1-surface-edge/40 text-blue-400"></div>