commit 0415a98f25cec1fd5f8e391ee34420f1bc0f0759 parent ee2c24b958e889a8c7771d23b42b9e24bb4a7935 Author: triesap <137732411+triesap@users.noreply.github.com> Date: Thu, 26 Sep 2024 06:06:26 +0000 Add `@radroots/models`, add `nostr_profile` model, edit (conf) `/init` logic, update package scripts, edit _conf, styles, utils Diffstat:
22 files changed, 334 insertions(+), 86 deletions(-)
diff --git a/package.json b/package.json @@ -6,19 +6,17 @@ "scripts": { "build:dev": "vite build --mode development", "build:prod": "vite build --mode production", - "build:native": "npm run gen && npm run sql-wasm:rm && npm run build:prod", - "build:web": "npm run gen && npm run sql-wasm:cp && npm run build:prod", - "dev": "", - "dev:native": "npm run gen && npm run sql-wasm:rm && npm run serve:dev", - "dev:web": "npm run gen && npm run sql-wasm:cp && npm run serve:dev", - "serve:prod": "vite dev --mode production", + "prepare:native": "npm run gen && npm run sql:rm", + "prepare:web": "npm run gen && npm run sql:cp", "serve:dev": "vite dev --mode development --debug hmr", + "serve:prod": "vite dev --mode production", + "dev": "", + "gen": "", + "sql:cp": "rsync -u node_modules/sql.js/dist/sql-wasm.wasm static/assets", + "sql:rm": "rm -rf static/assets/sql-wasm.wasm", "preview": "vite preview", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "sql-wasm:cp": "rsync -u node_modules/sql.js/dist/sql-wasm.wasm static/assets", - "sql-wasm:rm": "rm -rf static/assets/sql-wasm.wasm", - "gen": "" + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" }, "devDependencies": { "@capacitor/cli": "^6.1.2", @@ -62,6 +60,7 @@ "@radroots/capacitor-sqlite": "workspace:*", "@radroots/capacitor-wifi": "workspace:*", "@radroots/client": "workspace:*", + "@radroots/models": "workspace:*", "@radroots/svelte-lib": "workspace:*", "@radroots/svelte-maplibre": "workspace:*", "@radroots/theme": "workspace:*", diff --git a/src/lib/client.ts b/src/lib/client.ts @@ -1,3 +1,15 @@ import { ClientCapacitor } from "@radroots/client"; - -export const lc = new ClientCapacitor(); +import { location_gcs_table, nostr_profile_table, trade_product_table } from "@radroots/models"; +export const lc = new ClientCapacitor({ + sqlite_upgrade: [ + { + toVersion: 1, + statements: [ + `PRAGMA foreign_keys = ON;`, + location_gcs_table, + trade_product_table, + nostr_profile_table + ] + } + ] +}); diff --git a/src/lib/conf.ts b/src/lib/conf.ts @@ -1,7 +1,5 @@ -import type { ColorMode } from "@radroots/theme"; -import { type NumberTuple } from "@radroots/utils"; -type Conf = { +/*type Conf = { app: Record<string, string>; pref: Record<string, string>; cmd: Record<string, string>; @@ -15,16 +13,22 @@ type Conf = { } } } -} +}*/ -export const _cf: Conf = { +import type { NumberTuple } from "@radroots/utils"; + +export const _conf = { app: { root_symbol: "ยป--`--,---", title: `Radroots`, description: `Creating networks between farmers, communities and small businesses that give customers greater access to natural foods and grow circular economies where profits are more fairly distributed. Radroots is built on the Nostr protocol and released under a copyleft open source license to provide transparency and give users the option to offer feedback and add or request new features.` }, - pref: { - key_active: `nostr:key:active` + const: { + load_delay: 321 + }, + kv: { + nostr_key: (public_key: string) => `nostr:key:${public_key}`, + nostr_key_active: `nostr:key:active`, }, cmd: { root_alert: `*-alert` @@ -38,7 +42,7 @@ export const _cf: Conf = { }, popup: { dot: { - offset: [0, -10] as const + offset: [0, -10] as NumberTuple } } } diff --git a/src/lib/stores.ts b/src/lib/stores.ts @@ -3,8 +3,8 @@ import { type NumberTuple } from "@radroots/utils"; import { writable } from "svelte/store"; export const app_tok = writable<string>(''); -export const app_thc = writable<ColorMode>(`light`); -export const app_th = writable<ThemeKey>(`earth`); +export const app_thc = writable<ColorMode>(`dark`); +export const app_th = writable<ThemeKey>(`os`); export const app_nostr_key = writable<string>(``); export const app_pwa_polyfills = writable<boolean>(false); diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts @@ -1,5 +1,5 @@ import { goto } from "$app/navigation"; -import { _cf } from "$lib/conf"; +import { _conf } from "$lib/conf"; import { kv } from "@radroots/svelte-lib"; import { lc } from "../client"; @@ -8,7 +8,7 @@ export const restart = async (route_to: true | string, alert_message?: string): await lc.window.splash_show(); if (alert_message) { await kv.set( - _cf.cmd.root_alert, + _conf.cmd.root_alert, alert_message ); } diff --git a/src/lib/utils/keystore.ts b/src/lib/utils/keystore.ts @@ -0,0 +1,14 @@ +import { lc } from "$lib/client"; + +export const keystore_reset = async (): Promise<void> => { + try { + const ks_keys = await lc.keystore.keys(); + console.log(JSON.stringify(ks_keys, null, 4), `ks_keys`); + if (!ks_keys) return; + for (const ks_key of ks_keys) { + await lc.keystore.remove(ks_key); + } + } catch (e) { + console.log(`(error) keystore_reset `, e); + } +}; +\ No newline at end of file diff --git a/src/lib/utils/location_gcs.ts b/src/lib/utils/location_gcs.ts @@ -35,6 +35,7 @@ export const location_gcs_add = async (): Promise<boolean> => { await lc.db.location_gcs_add( fields, ); + console.log(`exe_res `, exe_res) if ( typeof exe_res !== `string` && `id` in exe_res diff --git a/src/lib/utils/trade_product.ts b/src/lib/utils/trade_product.ts @@ -1,4 +1,4 @@ -import { parse_trade_product_form_keys, trade_product_form_fields, trade_product_form_vals, type TradeProductFormFields } from "@radroots/client"; +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"; export const trade_product_kv_vals = async (opts: { diff --git a/src/routes/(app)/+layout.ts b/src/routes/(app)/+layout.ts @@ -1,5 +1,5 @@ import { lc } from '$lib/client'; -import { _cf } from '$lib/conf'; +import { _conf } from '$lib/conf'; import { kv } from '@radroots/svelte-lib'; import type { LayoutLoad, LayoutLoadEvent } from '../$types'; @@ -7,9 +7,9 @@ export const load: LayoutLoad = async ({ url }: LayoutLoadEvent) => { try { console.log(`layout (app) `, url.pathname); if (url.pathname === `/`) { - const root_alert = await kv.get(_cf.cmd.root_alert); + const root_alert = await kv.get(_conf.cmd.root_alert); if (root_alert) { - await kv.delete(_cf.cmd.root_alert); + await kv.delete(_conf.cmd.root_alert); lc.dialog.alert(root_alert); } } diff --git a/src/routes/(app)/+page.svelte b/src/routes/(app)/+page.svelte @@ -41,6 +41,12 @@ weight: `fill`, }, { + route: `/models/nostr-profile`, + label: `Profiles`, + key: `address-book-tabs`, + weight: `fill`, + }, + { route: `/nostr/keys`, label: `Keys`, key: `key`, diff --git a/src/routes/(app)/models/location-gcs/+page.svelte b/src/routes/(app)/models/location-gcs/+page.svelte @@ -1,7 +1,7 @@ <script lang="ts"> import { lc } from "$lib/client"; import { location_gcs_add } from "$lib/utils/location_gcs"; - import { type LocationGcs } from "@radroots/client"; + import { type LocationGcs } from "@radroots/models"; import { app_tabs_visible, LayoutTrellis, diff --git a/src/routes/(app)/models/nostr-profile/+page.svelte b/src/routes/(app)/models/nostr-profile/+page.svelte @@ -0,0 +1,182 @@ +<script lang="ts"> + import { lc } from "$lib/client"; + import { location_gcs_add } from "$lib/utils/location_gcs"; + import { + nostr_profile_form_vals, + parse_nostr_profile_form_keys, + type NostrProfile, + } from "@radroots/models"; + import { + app_tabs_visible, + as_glyph_key, + LayoutTrellis, + LayoutView, + Nav, + t, + Trellis, + } from "@radroots/svelte-lib"; + import { onMount } from "svelte"; + + let models_list: NostrProfile[] = []; + let loading_models = false; + + onMount(async () => { + try { + app_tabs_visible.set(false); + await fetch_models(); + } catch (e) { + } finally { + } + }); + + const fetch_models = async (): Promise<void> => { + try { + loading_models = true; + const res = await lc.db.nostr_profile_get({ + list: [`all`], + }); + if (typeof res !== `string`) models_list = res; + } catch (e) { + console.log(`(error) fetch_models `, e); + } finally { + loading_models = false; + } + }; +</script> + +<LayoutView> + <LayoutTrellis> + {#if models_list.length} + {#each models_list as li} + <Trellis + basis={{ + args: { + layer: 1, + title: { + value: `Your Profiles`, + }, + list: [ + ...Object.keys(nostr_profile_form_vals).map( + (k) => ({ + hide_active: true, + touch: { + label: { + left: [ + { + classes: `capitalize`, + value: `${$t(`model_fields.${k}`, { default: k.replaceAll(`_`, ` `) })}`, + }, + ], + right: [ + { + classes: `font-[300] text-layer-1-glyph-shade`, + value: + Object.assign(li)[ + parse_nostr_profile_form_keys( + k, + ) + ] || "(none)", + }, + ], + }, + end: { + icon: { + key: as_glyph_key( + `caret-right`, + ), + }, + }, + callback: async () => {}, + }, + }), + ), + ], + + /*[ + { + hide_active: true, + touch: { + label: { + left: [ + { + value: `Public Key:`, + classes: `capitalize pr-2`, + }, + ], + right: [ + { + classes: `truncate`, + value: li.public_key, + }, + ], + }, + callback: async () => {}, + }, + }, + + ], + */ + }, + }} + /> + {/each} + {:else if !loading_models} + <div + class={`flex flex-col w-full justify-center items-center px-4 gap-3`} + > + <p class={`font-sans font-[400] text-layer-2-glyph`}> + {`No items to display.`} + </p> + + <button + class={`flex flex-row justify-center items-center`} + on:click={async () => { + const res = await location_gcs_add(); + if (res === true) await fetch_models(); + }} + > + <p + class={`font-sans font-[400] text-layer-2-glyph-hl text-sm`} + > + {`Click to add a new location`} + </p> + </button> + </div> + {/if} + </LayoutTrellis> +</LayoutView> +<Nav + basis={{ + prev: { + label: `Back`, + route: `/`, + }, + title: { + label: `Profiles`, + }, + option: models_list.length + ? { + label: { + value: `Add`, + classes: `tap-color`, + }, + callback: async () => { + //const res = await location_gcs_add(); + //if (res === true) await fetch_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 || []) { + console.log(`ks_key `, ks_key); + } + }, + } + : undefined, + }} +/> + +<style> + :global(.map-card) { + height: 100px; + width: 160px; + } +</style> diff --git a/src/routes/(app)/models/trade-product/+page.svelte b/src/routes/(app)/models/trade-product/+page.svelte @@ -1,7 +1,7 @@ <script lang="ts"> import { goto } from "$app/navigation"; import { lc } from "$lib/client"; - import { type TradeProduct } from "@radroots/client"; + import { type TradeProduct } from "@radroots/models"; import { app_tabs_visible, LayoutTrellis, diff --git a/src/routes/(app)/models/trade-product/add/+page.svelte b/src/routes/(app)/models/trade-product/add/+page.svelte @@ -12,7 +12,7 @@ mass_units, trade_product_form_fields, type LocationGcs, - } from "@radroots/client"; + } from "@radroots/models"; import { el_id, fmt_id, diff --git a/src/routes/(app)/models/trade-product/add/preview/+page.svelte b/src/routes/(app)/models/trade-product/add/preview/+page.svelte @@ -5,7 +5,7 @@ import { type LocationGcs, type TradeProductFormFields, - } from "@radroots/client"; + } from "@radroots/models"; import { Fill, Glyph, diff --git a/src/routes/(app)/nostr/keys/+page.svelte b/src/routes/(app)/nostr/keys/+page.svelte @@ -1,6 +1,6 @@ <script lang="ts"> import { lc } from "$lib/client"; - import { _cf } from "$lib/conf"; + import { _conf } from "$lib/conf"; import { LayoutTrellis, LayoutView, @@ -14,7 +14,9 @@ onMount(async () => { try { - const public_key = await lc.preferences.get(_cf.pref.key_active); + const public_key = await lc.preferences.get( + _conf.kv.nostr_key_active, + ); if (public_key) nostr_public_key = public_key; const secret_key = await lc.keystore.get(`nostr:key:${public_key}`); if (secret_key) nostr_secret_key = secret_key; diff --git a/src/routes/(app)/settings/+page.svelte b/src/routes/(app)/settings/+page.svelte @@ -1,6 +1,6 @@ <script lang="ts"> import { lc } from "$lib/client"; - import { _cf } from "$lib/conf"; + import { _conf } from "$lib/conf"; import { app_thc } from "$lib/stores"; import { restart } from "$lib/utils"; import { @@ -78,7 +78,7 @@ }, callback: async () => { const public_key = await lc.preferences.get( - _cf.pref.key_active, + _conf.kv.nostr_key_active, ); await lc.dialog.alert( `Hi! This is your nostr public key ${public_key}`, @@ -103,7 +103,7 @@ }, callback: async () => { const public_key = await lc.preferences.get( - _cf.pref.key_active, + _conf.kv.nostr_key_active, ); console.log(`public_key `, public_key); const secret_key = await lc.keystore.get( @@ -149,14 +149,14 @@ if (confirm) { const nostr_public_key = await lc.preferences.get( - _cf.pref.key_active, + _conf.kv.nostr_key_active, ); if (nostr_public_key) { await lc.keystore.remove( `nostr:key:${nostr_public_key}`, ); await lc.preferences.remove( - _cf.pref.key_active, + _conf.kv.nostr_key_active, ); await restart(true); } else { @@ -253,7 +253,7 @@ }, callback: async () => { const public_key = await lc.preferences.get( - _cf.pref.key_active, + _conf.kv.nostr_key_active, ); const npub = lc.nostr.lib.npub(public_key); const url = `https://primal.net/p/${npub}`; diff --git a/src/routes/(conf)/+layout.ts b/src/routes/(conf)/+layout.ts @@ -1,11 +1,11 @@ import { goto } from '$app/navigation'; import { lc } from '$lib/client'; -import { _cf } from '$lib/conf'; +import { _conf } from '$lib/conf'; import type { LayoutLoad, LayoutLoadEvent } from '../$types'; export const load: LayoutLoad = async ({ url }: LayoutLoadEvent) => { try { - const key_active = await lc.preferences.get(_cf.pref.key_active); + const key_active = await lc.preferences.get(_conf.kv.nostr_key_active); if (key_active) { const ks_keys = await lc.keystore.keys(); const active_nostr_key = ks_keys?.find( diff --git a/src/routes/(conf)/init/+page.svelte b/src/routes/(conf)/init/+page.svelte @@ -1,8 +1,10 @@ <script lang="ts"> import { lc } from "$lib/client"; - import { _cf } from "$lib/conf"; + import { _conf } from "$lib/conf"; import { restart } from "$lib/utils"; + import { keystore_reset } from "$lib/utils/keystore"; import { Glyph, LayoutView, sleep } from "@radroots/svelte-lib"; + import { onMount } from "svelte"; const SLIDE_DURATION = 600; @@ -15,6 +17,14 @@ }, }; + onMount(async () => { + try { + await keystore_reset(); + } catch (e) { + } finally { + } + }); + type View = `start` | `configure`; let view: View = `start`; @@ -33,7 +43,6 @@ const el = document.querySelector( `[data-carousel-container="${view}"]`, ); - console.log(`el get_slide_container`, el); return el ? el : undefined; }; @@ -70,24 +79,39 @@ slide_active = false; }; - const create_new_key = async (): Promise<void> => { + const configure_device = async (): Promise<void> => { try { - const sk_hex = lc.nostr.lib.generate_key(); - const pk_hex = lc.nostr.lib.public_key(sk_hex); - const new_key_added = await lc.keystore.set( - `nostr:key:${pk_hex}`, - sk_hex, + const secret_key = lc.nostr.lib.generate_key(); + const public_key = lc.nostr.lib.public_key(secret_key); + + const key_added = await lc.keystore.set( + _conf.kv.nostr_key(public_key), + secret_key, ); - if (new_key_added) { - await lc.preferences.set(_cf.pref.key_active, pk_hex); - await sleep(500); - await restart( - true, - `Welcome! To view your device configuration go to Settings > Keypairs.`, - ); + if (key_added) { + await lc.preferences.set(_conf.kv.nostr_key_active, public_key); + + const key_profile_added = await lc.db.nostr_profile_add({ + public_key, + }); + + if (typeof key_profile_added === `string`) { + // @todo + alert(key_profile_added); + } else if (Array.isArray(key_profile_added)) { + //@todo + alert(key_profile_added.join(` `)); + } else { + await sleep(_conf.const.load_delay); + await restart( + true, + `Welcome! Your device was configured. To view or change your configuration go to Settings > Configuration.`, + ); + return; + } } } catch (e) { - console.log(`(error) create_new_key `, e); + console.log(`(error) configure_device `, e); } }; </script> @@ -389,7 +413,7 @@ <button class={`flex flex-row gap-3 justify-center items-center active:opacity-80`} on:click={async () => { - await create_new_key(); + await configure_device(); }} > <p diff --git a/src/routes/(map)/map/+page.svelte b/src/routes/(map)/map/+page.svelte @@ -1,7 +1,7 @@ <script lang="ts"> import { lc } from "$lib/client"; import MapControlFull from "$lib/components/map_control_full.svelte"; - import { _cf } from "$lib/conf"; + import { _conf } from "$lib/conf"; import { app_thc } from "$lib/stores"; import { Fill, LoadingView, sleep } from "@radroots/svelte-lib"; import { MapLibre, Marker, Popup } from "@radroots/svelte-maplibre"; @@ -17,7 +17,7 @@ if (loc && typeof loc !== `string`) { map_coords = [loc.lng, loc.lat]; } - await sleep(321); + await sleep(_conf.const.load_delay); } catch (e) { console.log(`e `, e); } finally { @@ -31,7 +31,7 @@ center={map_coords} zoom={10} class={`map-full ${loading_layout ? `hidden` : ``}`} - style={_cf.map.styles.base[$app_thc]} + style={_conf.map.styles.base[$app_thc]} > <Marker lngLat={map_coords}> <div class="flex flex-row p-1"> @@ -45,7 +45,7 @@ </div> </div> </div> - <Popup offset={_cf.map.popup.dot.offset}> + <Popup offset={_conf.map.popup.dot.offset}> <button class={`flex flex-row justify-center items-center transition-all`} on:click={async () => {}} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte @@ -6,7 +6,7 @@ PUBLIC_NOSTR_RELAY_DEFAULTS, } from "$env/static/public"; import { lc } from "$lib/client"; - import { _cf } from "$lib/conf"; + import { _conf } from "$lib/conf"; import { app_nostr_key, app_pwa_polyfills, @@ -64,25 +64,27 @@ app_config.subscribe(async (app_config) => { try { if (!app_config) return; - app_sqlite.set(!!(await lc.db.connect(PUBLIC_DATABASE_NAME))); - const active_nostr_pk = await lc.preferences.get( - _cf.pref.key_active, - ); - console.log(`active_nostr_pk `, active_nostr_pk); - const active_nostr_sk = await lc.keystore.get( - `nostr:key:${active_nostr_pk}`, + const db_connected = await lc.db.connect(PUBLIC_DATABASE_NAME); + if (!db_connected) { + // @todo + } + app_sqlite.set(!!db_connected); + + const active_key_public = await lc.preferences.get( + _conf.kv.nostr_key_active, ); - console.log(`active_nostr_sk `, active_nostr_sk); - if ( - typeof active_nostr_sk === `string` && - active_nostr_sk && - active_nostr_pk - ) - app_nostr_key.set(active_nostr_pk); - else { - await lc.preferences.remove(_cf.pref.key_active); - await goto(`/init`); + if (active_key_public) { + const active_key_secret = await lc.keystore.get( + _conf.kv.nostr_key(active_key_public), + ); + if (active_key_secret) { + app_nostr_key.set(active_key_public); + return; + } } + + await lc.preferences.remove(_conf.kv.nostr_key_active); + await goto(`/init`); } catch (e) { console.log(`(app_config) error `, e); } finally { @@ -103,7 +105,7 @@ } console.log(`init_route `, init_route); await goto(init_route); - await sleep(321); + await sleep(_conf.const.load_delay); } catch (e) { console.log(`(app_render) error `, e); } finally { @@ -140,9 +142,9 @@ </script> <svelte:head> - <meta name="description" content={_cf.app.description} /> - <meta property="og:title" content={_cf.app.title} /> - <meta property="og:description" content={_cf.app.description} /> + <meta name="description" content={_conf.app.description} /> + <meta property="og:title" content={_conf.app.title} /> + <meta property="og:description" content={_conf.app.description} /> </svelte:head> {#if $app_render} <slot /> diff --git a/tailwind.config.ts b/tailwind.config.ts @@ -18,7 +18,8 @@ const heights = { }; const widths = { - line: `320px` + line: `320px`, + trellis_value: `180px` }; const dimensions = {