commit bbd361944443f3f51eeba4b7ad41705f3f300828
parent 5e2557629ba6666a5fdd22bc3bdde4f541e71ad1
Author: triesap <137732411+triesap@users.noreply.github.com>
Date: Sun, 1 Sep 2024 10:13:50 +0000
Add `models/trade-product`, edit app root page, edit models routes, edit nostr routes, add css
Diffstat:
19 files changed, 671 insertions(+), 173 deletions(-)
diff --git a/src/app.css b/src/app.css
@@ -7,6 +7,28 @@
@tailwind utilities;
@layer components {
+ .form-select-e {
+ @apply select select-sm border-0 focus:border-0 outline-0 focus:outline-0;
+ }
+
+ .form-line-e {
+ @apply pl-4 justify-center items-center;
+ }
+
+ .form-select-e,
+ .form-line-e,
+ .form-line {
+ @apply flex flex-row h-form_line w-full;
+ }
+
+ .form-input {
+ @apply input flex flex-row w-full p-0 border-0 focus:border-0 outline-0 focus:outline-0 placeholder:font-[300] bg-transparent;
+ }
+
+ .form-input-invalid {
+ @apply outline outline-[2px] outline-red-300/70;
+ }
+
.taps {
@apply active:scale-[94%] active:opacity-80 transition-all;
}
@@ -23,9 +45,16 @@
@apply h-line w-line;
}
+ .button-base
+ .button-simple,
+ .button-submit {
+ @apply flex flex-row justify-center items-center font-mono text-sm lowercase transition-all select-none cursor-none;
+ }
+
+ .surface-1,
.button-simple,
.button-submit {
- @apply flex flex-row justify-center items-center bg-layer-1-surface font-mono text-sm lowercase text-layer-2-glyph transition-all select-none cursor-none;
+ @apply bg-layer-1-surface text-layer-2-glyph;
}
.flex-fill {
@@ -68,6 +97,10 @@
@apply select-none cursor-none;
}
+ pre {
+ @apply select-none cursor-none;
+ }
+
@font-face {
font-family: 'SFProDisplay';
src: url('/webfonts/sf-pro-display/SFProDisplay-BlackItalic.woff2') format('woff2'),
diff --git a/src/app.html b/src/app.html
@@ -9,6 +9,8 @@
<link rel="stylesheet" type="text/css" href="/phosphor-icons/light.css" />
<link rel="stylesheet" type="text/css" href="/phosphor-icons/regular.css" />
+ <script src="/assets/keyva.min.js"></script>
+
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no viewport-fit=cover" />
%sveltekit.head%
diff --git a/src/lib/client.ts b/src/lib/client.ts
@@ -1,3 +1,3 @@
import { ClientCapacitor } from "@radroots/client";
-export const cl = new ClientCapacitor();
+export const lc = new ClientCapacitor();
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
@@ -1,15 +0,0 @@
-import { goto } from "$app/navigation";
-import { cl } from "./client";
-
-export const restart = async (route_to: true | string): Promise<void> => {
- try {
- await cl.window.splash_show();
- if (route_to) {
- if (route_to === true) await goto(`/`);
- else await goto(route_to)
- }
- location.reload();
- } catch (e) {
- console.log(`(error) restart `, e);
- }
-};
-\ No newline at end of file
diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts
@@ -0,0 +1,15 @@
+import { goto } from "$app/navigation";
+import { lc } from "../client";
+
+export const restart = async (route_to?: true | string): Promise<void> => {
+ try {
+ await lc.window.splash_show();
+ if (route_to) {
+ if (route_to === true) await goto(`/`);
+ else await goto(route_to)
+ }
+ location.reload();
+ } catch (e) {
+ console.log(`(error) restart `, e);
+ }
+};
+\ No newline at end of file
diff --git a/src/lib/utils/models.ts b/src/lib/utils/models.ts
@@ -0,0 +1,76 @@
+import { lc } from "$lib/client";
+import { location_geohash } from "@radroots/utils";
+
+export const location_gcs_add = async (): Promise<boolean> => {
+ 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;
+
+ const { lat, lng } = loc_gcs;
+ const geohash = location_geohash(
+ lat,
+ lng,
+ );
+ const fields = {
+ lat: lat.toString(),
+ lng: lng.toString(),
+ geohash,
+ label: loc_gcs_label,
+ };
+ const exe_res =
+ await lc.db.location_gcs_add(
+ fields,
+ );
+ 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 dcf_res = await lc.dialog.confirm(
+ `Location permissions are required to read geolocation.`,
+ );
+ if (dcf_res) {
+ await lc.settings.open(
+ lc.platform === `ios`
+ ? {
+ ios: {
+ setting: `LocationServices`,
+ },
+ }
+ : {
+ android: {
+ setting: `Location`,
+ },
+ },
+ );
+ }
+ }
+ return false;
+ } catch (e) {
+ console.log(`(error) location_gcs_add `, e);
+ return false;
+ }
+};
+\ No newline at end of file
diff --git a/src/routes/(app)/+page.svelte b/src/routes/(app)/+page.svelte
@@ -1,9 +1,17 @@
<script lang="ts">
import { goto } from "$app/navigation";
- import { cl } from "$lib/client";
+ import { lc } from "$lib/client";
+ import LayoutView from "$lib/components/layout-view.svelte";
+ import { _cf } from "$lib/conf";
import { app_tab_active, app_tabs_visible } from "$lib/stores";
import { NDKKind } from "@nostr-dev-kit/ndk";
- import { ndk, ndk_event, ndk_user, t } from "@radroots/svelte-lib";
+ import {
+ glyph as Glyph,
+ ndk,
+ ndk_event,
+ ndk_user,
+ type GlyphKey,
+ } from "@radroots/svelte-lib";
import { onMount } from "svelte";
onMount(async () => {
@@ -28,28 +36,115 @@
});
console.log(JSON.stringify(ev, null, 4), `ev`);
if (ev) await ev.publish();
- cl.dialog.alert(`Published content ${JSON.stringify(content)}`);
+ lc.dialog.alert(`Published content ${JSON.stringify(content)}`);
} catch (e) {
console.log(`(error) nostr_note_pub `, e);
}
};
+
+ /*
+<div class={`grid grid-cols-12 w-full gap-8 pt-6 px-6`}>
+ <button
+ class={`button-base surface-1 col-span-6 h-24 rounded-2xl font-[500] text-lg font-mono`}
+ on:click={async () => {
+ await goto(`/models/location-gcs`);
+ }}
+ >
+ {`Post `}
+ </button>
+ <button
+ class={`button-base surface-1 col-span-6 h-32 rounded-2xl font-[500] text-lg font-mono`}
+ on:click={async () => {
+ await goto(`/models/location-gcs`);
+ }}
+ >
+ {`Post `}
+ </button>
+ <button
+ class={`button-base surface-1 col-span-6 h-32 rounded-2xl font-[500] text-lg font-mono`}
+ on:click={async () => {
+ await goto(`/models/location-gcs`);
+ }}
+ >
+ {`Post `}
+ </button>
+
+ </div>
+ */
+
+ let buttons: { route: string; label: string; key: GlyphKey }[] = [
+ {
+ route: `/models/trade-product/add`,
+ label: `Post Goods`,
+ key: `handbag-simple`,
+ },
+ ];
</script>
-<div class={`flex flex-col w-full pt-16 gap-8 justify-center items-center`}>
- <button
- class={`button-simple`}
- on:click={async () => {
- await cl.dialog.alert(`Hi! You're platform is ${cl.platform}`);
- }}
- >
- {$t(`app.name`)}
- </button>
- <button
- class={`button-simple`}
- on:click={async () => {
- await goto(`/models/location-gcs`);
- }}
+<LayoutView>
+ <div
+ class={`flex flex-col w-full justify-start items-start pt-6 gap-6 px-6`}
>
- {"models geolocation"}
- </button>
-</div>
+ <div class={`flex flex-row w-full px-1 justify-start items-center`}>
+ <p class={`font-mono font-[500] text-layer-2-glyph text-lg`}>
+ {`radroots ${_cf.root_symbol}`}
+ </p>
+ </div>
+ <button
+ class={`flex flex-row w-full h-8 px-4 gap-2 justify-start items-center surface-1 rounded-xl active:bg-layer-1-surface_a transition-all`}
+ >
+ <Glyph
+ basis={{
+ key: `magnifying-glass`,
+ dim: `sm-`,
+ weight: `bold`,
+ }}
+ />
+ <p class={`font-sans font-[500] text-layer-2-glyph/70`}>
+ {`Search`}
+ </p>
+ </button>
+ <div
+ class={`grid grid-cols-12 flex flex-row w-full gap-4 justify-start items-center`}
+ >
+ {#each buttons as btn}
+ <button
+ class={`surface-1 col-span-6 flex flex-col h-20 py-2 px-3 justify-between rounded-2xl font-[500] text-lg font-mono active:bg-layer-1-surface_a transition-all`}
+ on:click={async () => {
+ await goto(btn.route);
+ }}
+ >
+ <div
+ class={`flex flex-row w-full justify-between items-center`}
+ >
+ <div class={`flex flex-row justify-start items-center`}>
+ <Glyph
+ basis={{
+ key: btn.key,
+ dim: `md`,
+ weight: `bold`,
+ }}
+ />
+ </div>
+ <div class={`flex flex-row justify-start items-center`}>
+ <Glyph
+ basis={{
+ key: `caret-right`,
+ dim: `sm`,
+ weight: `bold`,
+ }}
+ />
+ </div>
+ </div>
+ <div
+ class={`flex flex-row w-full justify-start items-center`}
+ >
+ <div class={`flex flex-row justify-start items-center`}>
+ {btn.label}
+ </div>
+ </div>
+ </button>
+ {/each}
+ </div>
+ </div>
+</LayoutView>
diff --git a/src/routes/(app)/models/location-gcs/+page.svelte b/src/routes/(app)/models/location-gcs/+page.svelte
@@ -1,15 +1,15 @@
<script lang="ts">
- import { cl } from "$lib/client";
+ import { lc } from "$lib/client";
import LayoutTrellis from "$lib/components/layout-trellis.svelte";
import LayoutView from "$lib/components/layout-view.svelte";
import Nav from "$lib/components/nav.svelte";
import { app_tabs_visible } from "$lib/stores";
+ import { location_gcs_add } from "$lib/utils/models";
import { type LocationGcs } from "@radroots/client";
import { trellis as Trellis } from "@radroots/svelte-lib";
- import { location_geohash } from "@radroots/utils";
import { onMount } from "svelte";
- let locations_all: LocationGcs[] = [];
+ let models_list: LocationGcs[] = [];
onMount(async () => {
try {
@@ -22,10 +22,10 @@
const fetch_models = async (): Promise<void> => {
try {
- const res = await cl.db.location_gcs_get({
+ const res = await lc.db.location_gcs_get({
list: [`all`],
});
- if (typeof res !== `string`) locations_all = res;
+ if (typeof res !== `string`) models_list = res;
} catch (e) {
console.log(`(error) fetch_models `, e);
}
@@ -53,75 +53,12 @@
],
},
callback: async () => {
- const loc_gcs = await cl.geo.current();
- if (
- loc_gcs &&
- typeof loc_gcs !== `string`
- ) {
- const loc_gcs_label =
- await cl.dialog.prompt({
- title: `Geolocation Label`,
- message: `What is the name of the location.`,
- input_placeholder: `Enter location name`,
- });
- if (loc_gcs_label === false) return;
-
- const { lat, lng } = loc_gcs;
- const geohash = location_geohash(
- lat,
- lng,
- );
- const fields = {
- lat: lat.toString(),
- lng: lng.toString(),
- geohash,
- label: loc_gcs_label,
- };
- const exe_res =
- await cl.db.location_gcs_add(
- fields,
- );
- if (
- typeof exe_res !== `string` &&
- `id` in exe_res
- ) {
- await fetch_models();
- } else if (
- typeof exe_res === `string` &&
- exe_res ===
- `*-location-gcs-geohash-unique`
- ) {
- await cl.dialog.alert(
- `This location has already been added.`,
- );
- }
- } else if (
- loc_gcs &&
- typeof loc_gcs === `string`
- ) {
- const dcf_res = await cl.dialog.confirm(
- `Enable location permission is required.`,
- );
- if (dcf_res) {
- await cl.settings.open(
- cl.platform === `ios`
- ? {
- ios: {
- setting: `LocationServices`,
- },
- }
- : {
- android: {
- setting: `Location`,
- },
- },
- );
- }
- }
+ const res = await location_gcs_add();
+ if (res === true) await fetch_models();
},
},
},
- locations_all.length
+ models_list.length
? {
touch: {
label: {
@@ -143,15 +80,15 @@
}}
/>
<div class={`flex flex-col justify-center items-center pt-4 px-4`}>
- {#if locations_all.length > 0}
+ {#if models_list.length > 0}
<p class={`font-sans font-[400] text-layer-0-glyph text-xs`}>
{"Your locations:"}
</p>
- {#each locations_all as location}
+ {#each models_list as li}
<div class={`flex flex-col justify-center items-center`}>
<pre
class={`font-sans font-[400] text-layer-0-glyph text-xs`}>{JSON.stringify(
- location,
+ li,
null,
4,
)}
diff --git a/src/routes/(app)/models/trade-product/+page.svelte b/src/routes/(app)/models/trade-product/+page.svelte
@@ -0,0 +1,113 @@
+<script lang="ts">
+ import { goto } from "$app/navigation";
+ import { lc } from "$lib/client";
+ import LayoutTrellis from "$lib/components/layout-trellis.svelte";
+ import LayoutView from "$lib/components/layout-view.svelte";
+ import Nav from "$lib/components/nav.svelte";
+ import { app_tabs_visible } from "$lib/stores";
+ import { type TradeProduct } from "@radroots/client";
+ import { trellis as Trellis } from "@radroots/svelte-lib";
+ import { onMount } from "svelte";
+
+ let models_list: TradeProduct[] = [];
+
+ onMount(async () => {
+ try {
+ app_tabs_visible.set(false);
+ await fetch_models();
+ } catch (e) {
+ } finally {
+ }
+ });
+
+ const fetch_models = async (): Promise<void> => {
+ try {
+ const res = await lc.db.trade_product_get({
+ list: [`all`],
+ });
+ if (typeof res !== `string`) models_list = res;
+ } catch (e) {
+ console.log(`(error) fetch_models `, e);
+ }
+ };
+</script>
+
+<LayoutView>
+ <LayoutTrellis>
+ <Trellis
+ basis={{
+ args: {
+ layer: 1,
+ title: {
+ value: `Trade Products`,
+ },
+ list: [
+ {
+ touch: {
+ label: {
+ left: [
+ {
+ value: `Add new product`,
+ classes: `capitalize`,
+ },
+ ],
+ },
+ callback: async () => {
+ await goto(`/models/trade-product/add`);
+ },
+ end: {
+ icon: {
+ key: `caret-right`,
+ },
+ },
+ },
+ },
+ ],
+ },
+ }}
+ />
+ <div class={`flex flex-col justify-center items-center pt-4 px-4`}>
+ {#if models_list.length > 0}
+ <p class={`font-sans font-[400] text-layer-0-glyph text-xs`}>
+ {"Your products:"}
+ </p>
+ {#each models_list as li}
+ <div class={`flex flex-col justify-center items-center`}>
+ <pre
+ class={`font-sans font-[400] text-layer-0-glyph text-xs`}>{JSON.stringify(
+ li,
+ null,
+ 4,
+ )}
+ </pre>
+ </div>
+ {/each}
+ {:else}
+ <p class={`font-sans font-[400] text-layer-0-glyph text-xs`}>
+ {"No products saved"}
+ </p>
+ {/if}
+ </div>
+ </LayoutTrellis>
+</LayoutView>
+<Nav
+ basis={{
+ prev: {
+ label: `Home`,
+ route: `/`,
+ },
+ title: {
+ label: `Products`,
+ },
+ option: {
+ glyph: {
+ key: `arrow-counter-clockwise`,
+ dim: `md`,
+ classes: `text-layer-1-glyph-hl taps`,
+ },
+ callback: async () => {
+ await fetch_models();
+ },
+ },
+ }}
+/>
diff --git a/src/routes/(app)/models/trade-product/add/+page.svelte b/src/routes/(app)/models/trade-product/add/+page.svelte
@@ -0,0 +1,232 @@
+<script lang="ts">
+ import { goto } from "$app/navigation";
+ import { lc } from "$lib/client";
+ import ButtonSubmit from "$lib/components/button-submit.svelte";
+ import LayoutTrellis from "$lib/components/layout-trellis.svelte";
+ import LayoutView from "$lib/components/layout-view.svelte";
+ import Nav from "$lib/components/nav.svelte";
+ import { location_gcs_add } from "$lib/utils/models";
+ import {
+ parse_trade_product_form_keys,
+ trade_product_form_fields,
+ trade_product_form_vals,
+ type LocationGcs,
+ } from "@radroots/client";
+ import {
+ fmt_id,
+ input_form as InputForm,
+ kv,
+ loading as Loading,
+ } from "@radroots/svelte-lib";
+ import { onMount } from "svelte";
+
+ const texts_key = {
+ opt_lcs_add: `location_gcs-add-current`,
+ };
+
+ const texts = {
+ 1: `No locations saved`,
+ 2: `Add new location`,
+ };
+
+ const texts_kv: Record<string, string> = {
+ key: `Name`,
+ };
+
+ let loading = false;
+ let loading_location = false;
+
+ let ls_model_location_gcs: LocationGcs[] = [];
+ let val_model_location_gcs_selected = ``;
+
+ $: {
+ if (ls_model_location_gcs.length && !val_model_location_gcs_selected)
+ val_model_location_gcs_selected = ls_model_location_gcs[0].id;
+ }
+
+ onMount(async () => {
+ try {
+ await fetch_models_location_gcs();
+ } catch (e) {
+ } finally {
+ }
+ });
+
+ const fetch_models_location_gcs = async (): Promise<void> => {
+ try {
+ const res = await lc.db.location_gcs_get({
+ list: [`all`],
+ });
+ if (typeof res !== `string`) ls_model_location_gcs = res;
+ } catch (e) {
+ console.log(`(error) fetch_models_location_gcs `, e);
+ }
+ };
+
+ const add_model_location_gcs = async (): Promise<void> => {
+ try {
+ loading_location = true;
+ await location_gcs_add();
+ await fetch_models_location_gcs();
+ } catch (e) {
+ console.log(`(error) add_model_location_gcs `, e);
+ } finally {
+ loading_location = false;
+ }
+ };
+
+ const submit = async (): Promise<void> => {
+ try {
+ loading = true;
+ const vals = trade_product_form_vals;
+ for (const [k, field] of Object.entries(
+ trade_product_form_fields,
+ )) {
+ const field_k = parse_trade_product_form_keys(k);
+ if (!field_k) continue;
+ const field_id = fmt_id(field_k);
+ const field_val = await $kv.get(field_id);
+
+ if (
+ (!field.optional && !field.validation.test(field_val)) ||
+ (field.optional &&
+ field_val &&
+ !field.validation.test(field_val))
+ ) {
+ loading = false;
+ await lc.dialog.alert(
+ `Invalid product ${texts_kv[field_k]?.toLowerCase() || field_k} value.`,
+ );
+ return;
+ }
+ vals[field_k] = field_val;
+ }
+ const res = await lc.db.trade_product_add(vals);
+ if (typeof res !== `string` && !Array.isArray(res)) {
+ await goto(`/models/trade-product`);
+ }
+ } catch (e) {
+ console.log(`(error) submit `, e);
+ } finally {
+ loading = false;
+ }
+ };
+</script>
+
+<LayoutView>
+ <LayoutTrellis>
+ <div
+ class={`flex flex-col w-full px-4 gap-3 justify-center items-center`}
+ >
+ {#each Object.entries(trade_product_form_fields) as [field_k, field], field_i}
+ {#if field_i === 1}
+ <div
+ class={`flex flex-col w-full gap-1 justify-start items-start`}
+ >
+ <div
+ class={`flex flex-row w-full px-2 justify-start items-center`}
+ >
+ <p
+ class={`font-sans font-[400] uppercase text-layer-2-glyph text-sm`}
+ >
+ {`Product - Location`}
+ </p>
+ </div>
+ {#if loading_location}
+ <div
+ class={`form-line surface-1 flex flex-row justify-center items-center rounded-xl`}
+ >
+ <Loading basis={{ dim: `xs-` }} />
+ </div>
+ {:else}
+ <select
+ class={`form-select-e w-full bg-layer-1-surface rounded-xl text-layer-2-glyph`}
+ bind:value={val_model_location_gcs_selected}
+ on:change={async ({ currentTarget: el }) => {
+ const val = el.value;
+ if (val === texts_key.opt_lcs_add) {
+ val_model_location_gcs_selected = ``;
+ await add_model_location_gcs();
+ }
+ }}
+ >
+ {#if ls_model_location_gcs.length}
+ {#each ls_model_location_gcs as li}
+ <option value={li.id}>
+ {li.label}
+ </option>
+ {/each}
+ {:else}
+ <option disabled selected={true}>
+ {texts[1]}
+ </option>
+ {/if}
+ <option value={texts_key.opt_lcs_add}>
+ {texts[2]}
+ </option>
+ </select>
+ {/if}
+ </div>
+ {/if}
+ <div
+ class={`flex flex-col w-full gap-1 justify-start items-start`}
+ >
+ <div
+ class={`flex flex-row w-full px-2 justify-start items-center`}
+ >
+ <p
+ class={`font-sans font-[400] uppercase text-layer-2-glyph text-sm`}
+ >
+ {`Product - ${texts_kv[field_k] || field_k}`}
+ </p>
+ </div>
+ <div class={`form-line-e bg-layer-1-surface rounded-xl`}>
+ <InputForm
+ basis={{
+ id: fmt_id(field_k),
+ layer: 1,
+ sync: true,
+ field: {
+ charset: field.charset,
+ validate: field.validation,
+ },
+ }}
+ />
+ </div>
+ </div>
+ {/each}
+ <div class={`flex flex-row w-full pt-4 justify-end items-center`}>
+ <ButtonSubmit
+ basis={{
+ callback: async () => {
+ await submit();
+ },
+ loading,
+ }}
+ />
+ </div>
+ </div>
+ </LayoutTrellis>
+</LayoutView>
+<Nav
+ basis={{
+ prev: {
+ label: `Products`,
+ route: `/models/trade-product`,
+ },
+ title: {
+ label: `Trade Product`,
+ },
+ option: {
+ glyph: {
+ key: `info`,
+ dim: `md`,
+ classes: `text-layer-1-glyph-hl taps`,
+ },
+ callback: async () => {
+ //await fetch_models();
+ alert(`Todo!`);
+ },
+ },
+ }}
+/>
diff --git a/src/routes/(app)/nostr/keys/+page.svelte b/src/routes/(app)/nostr/keys/+page.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
- import { cl } from "$lib/client";
+ import { lc } from "$lib/client";
import LayoutTrellis from "$lib/components/layout-trellis.svelte";
import LayoutView from "$lib/components/layout-view.svelte";
import Nav from "$lib/components/nav.svelte";
@@ -12,9 +12,9 @@
onMount(async () => {
try {
- const public_key = await cl.preferences.get(_cf.pref_key_active);
+ const public_key = await lc.preferences.get(_cf.pref_key_active);
if (public_key) nostr_public_key = public_key;
- const secret_key = await cl.keystore.get(`nostr:key:${public_key}`);
+ const secret_key = await lc.keystore.get(`nostr:key:${public_key}`);
if (secret_key) nostr_secret_key = secret_key;
} catch (e) {
} finally {
@@ -23,7 +23,7 @@
async function copyToClipboard(text: string) {
navigator.clipboard.writeText(text).then(async () => {
- await cl.dialog.alert(
+ await lc.dialog.alert(
`Copied nostr key "${text.slice(0, 12)}..." to clipboard.`,
);
});
@@ -60,7 +60,7 @@
label: {
left: [
{
- value: cl.nostr.lib.npub(
+ value: lc.nostr.lib.npub(
nostr_public_key,
),
},
@@ -69,7 +69,7 @@
callback: async () => {
await copyToClipboard(
- cl.nostr.lib.npub(nostr_public_key),
+ lc.nostr.lib.npub(nostr_public_key),
);
},
},
@@ -106,7 +106,7 @@
label: {
left: [
{
- value: cl.nostr.lib.nsec(
+ value: lc.nostr.lib.nsec(
nostr_secret_key,
),
},
@@ -115,7 +115,7 @@
callback: async () => {
await copyToClipboard(
- cl.nostr.lib.nsec(nostr_secret_key),
+ lc.nostr.lib.nsec(nostr_secret_key),
);
},
},
diff --git a/src/routes/(app)/nostr/notes/post/+page.svelte b/src/routes/(app)/nostr/notes/post/+page.svelte
@@ -1,6 +1,6 @@
<script lang="ts">
import { goto } from "$app/navigation";
- import { cl } from "$lib/client";
+ import { lc } from "$lib/client";
import ButtonSubmit from "$lib/components/button-submit.svelte";
import LayoutTrellis from "$lib/components/layout-trellis.svelte";
import LayoutView from "$lib/components/layout-view.svelte";
@@ -14,7 +14,7 @@
const nostr_note_publish = async (): Promise<void> => {
try {
if (!value_note_content) {
- await cl.dialog.alert(`You must write something to post.`);
+ await lc.dialog.alert(`You must write something to post.`);
return;
}
diff --git a/src/routes/(app)/nostr/profile/+page.svelte b/src/routes/(app)/nostr/profile/+page.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
- import { cl } from "$lib/client";
+ import { lc } from "$lib/client";
import LayoutTrellis from "$lib/components/layout-trellis.svelte";
import LayoutView from "$lib/components/layout-view.svelte";
import Nav from "$lib/components/nav.svelte";
@@ -53,28 +53,28 @@
const nostr_metadata_publish = async (): Promise<void> => {
try {
- const kind0_name = await cl.dialog.prompt({
+ const kind0_name = await lc.dialog.prompt({
title: `Name`,
message: `What is your personal name.`,
input_placeholder: `Enter your name`,
});
if (kind0_name === false) return;
- const kind0_display_name = await cl.dialog.prompt({
+ const kind0_display_name = await lc.dialog.prompt({
title: `Profile Name`,
message: `What is your profile name.`,
input_placeholder: `Enter profile name`,
});
if (kind0_display_name === false) return;
- const kind0_about = await cl.dialog.prompt({
+ const kind0_about = await lc.dialog.prompt({
title: `About`,
message: `What is your about me blurb.`,
input_placeholder: `Enter about me`,
});
if (kind0_about === false) return;
- const kind0_website = await cl.dialog.prompt({
+ const kind0_website = await lc.dialog.prompt({
title: `About`,
message: `What is your website.`,
input_placeholder: `Enter website`,
@@ -89,7 +89,7 @@
if (kind0_website) content.website = kind0_website;
if (Object.keys(content).length === 0) {
- await cl.dialog.alert(
+ await lc.dialog.alert(
`You must specify at least one profile field.`,
);
return;
diff --git a/src/routes/(app)/settings/+page.svelte b/src/routes/(app)/settings/+page.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
- import { cl } from "$lib/client";
+ import { lc } from "$lib/client";
import LayoutTrellis from "$lib/components/layout-trellis.svelte";
import LayoutView from "$lib/components/layout-view.svelte";
import Nav from "$lib/components/nav.svelte";
@@ -43,7 +43,7 @@
],
},
callback: async () => {
- await cl.haptics.impact();
+ await lc.haptics.impact();
app_thc.set(toggle_color_mode($app_thc));
},
},
@@ -76,10 +76,10 @@
},
},
callback: async () => {
- const public_key = await cl.preferences.get(
+ const public_key = await lc.preferences.get(
_cf.pref_key_active,
);
- await cl.dialog.alert(
+ await lc.dialog.alert(
`Hi! This is your nostr public key ${public_key}`,
);
},
@@ -101,14 +101,14 @@
},
},
callback: async () => {
- const public_key = await cl.preferences.get(
+ const public_key = await lc.preferences.get(
_cf.pref_key_active,
);
console.log(`public_key `, public_key);
- const secret_key = await cl.keystore.get(
+ const secret_key = await lc.keystore.get(
`nostr:key:${public_key}`,
);
- await cl.dialog.alert(
+ await lc.dialog.alert(
`Hi! This is your nostr secret key ${secret_key}`,
);
},
@@ -142,24 +142,24 @@
},
},
callback: async () => {
- const confirm = await cl.dialog.confirm(
+ const confirm = await lc.dialog.confirm(
`Hi! This will delete your saved keys.`,
);
if (confirm) {
const nostr_public_key =
- await cl.preferences.get(
+ await lc.preferences.get(
_cf.pref_key_active,
);
if (nostr_public_key) {
- await cl.keystore.remove(
+ await lc.keystore.remove(
`nostr:key:${nostr_public_key}`,
);
- await cl.preferences.remove(
+ await lc.preferences.remove(
_cf.pref_key_active,
);
await restart();
} else {
- await cl.dialog.alert(
+ await lc.dialog.alert(
`There is no public key preference saved.`,
);
}
@@ -190,8 +190,8 @@
],
},
callback: async () => {
- const pos = await cl.geo.current();
- await cl.dialog.alert(JSON.stringify(pos));
+ const pos = await lc.geo.current();
+ await lc.dialog.alert(JSON.stringify(pos));
},
},
},
@@ -218,7 +218,7 @@
},
callback: async () => {
const url = `https://radroots.org`;
- await cl.browser.open(url);
+ await lc.browser.open(url);
},
},
},
@@ -232,7 +232,7 @@
],
},
callback: async () => {
- await cl.share.open({
+ await lc.share.open({
title: `Radroots Home Page`,
text: `Find farmers around the world.`,
url: `https://radroots.org`,
@@ -251,12 +251,12 @@
],
},
callback: async () => {
- const public_key = await cl.preferences.get(
+ const public_key = await lc.preferences.get(
_cf.pref_key_active,
);
- const npub = cl.nostr.lib.npub(public_key);
+ const npub = lc.nostr.lib.npub(public_key);
const url = `https://primal.net/p/${npub}`;
- await cl.browser.open(url);
+ await lc.browser.open(url);
},
},
},
@@ -282,8 +282,8 @@
],
},
callback: async () => {
- const data = await cl.device.info();
- await cl.dialog.alert(JSON.stringify(data));
+ const data = await lc.device.info();
+ await lc.dialog.alert(JSON.stringify(data));
},
},
},
@@ -297,8 +297,8 @@
],
},
callback: async () => {
- const data = await cl.device.battery();
- await cl.dialog.alert(JSON.stringify(data));
+ const data = await lc.device.battery();
+ await lc.dialog.alert(JSON.stringify(data));
},
},
},
@@ -330,7 +330,7 @@
},
},
callback: async () => {
- await cl.haptics.impact("less");
+ await lc.haptics.impact("less");
},
},
},
@@ -350,7 +350,7 @@
},
},
callback: async () => {
- await cl.haptics.impact("more");
+ await lc.haptics.impact("more");
},
},
},
@@ -370,7 +370,7 @@
},
},
callback: async () => {
- await cl.haptics.vibrate(500);
+ await lc.haptics.vibrate(500);
},
},
},
diff --git a/src/routes/(conf)/+layout.ts b/src/routes/(conf)/+layout.ts
@@ -1,13 +1,13 @@
import { goto } from '$app/navigation';
-import { cl } from '$lib/client';
+import { lc } from '$lib/client';
import { _cf } from '$lib/conf';
import type { LayoutLoad, LayoutLoadEvent } from '../$types';
export const load: LayoutLoad = async ({ url }: LayoutLoadEvent) => {
try {
- const key_active = await cl.preferences.get(_cf.pref_key_active);
+ const key_active = await lc.preferences.get(_cf.pref_key_active);
if (key_active) {
- const ks_keys = await cl.keystore.keys();
+ const ks_keys = await lc.keystore.keys();
const active_nostr_key = ks_keys?.find(
(i) => i === `nostr:key:${key_active}`,
);
@@ -17,7 +17,7 @@ export const load: LayoutLoad = async ({ url }: LayoutLoadEvent) => {
}
}
} catch (e) { } finally {
- await cl.window.splash_hide();
+ await lc.window.splash_hide();
return {};
};
};
diff --git a/src/routes/(conf)/conf/nostr/+page.svelte b/src/routes/(conf)/conf/nostr/+page.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
- import { cl } from "$lib/client";
+ import { lc } from "$lib/client";
import { _cf } from "$lib/conf";
import { restart } from "$lib/utils";
import { sleep } from "@radroots/svelte-lib";
@@ -9,14 +9,14 @@
<button
class={`flex flex-row justify-center items-center text-white`}
on:click={async () => {
- const sk_hex = cl.nostr.lib.generate_key();
- const pk_hex = cl.nostr.lib.public_key(sk_hex);
- const new_key_added = await cl.keystore.set(
+ 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,
);
if (new_key_added) {
- await cl.preferences.set(_cf.pref_key_active, pk_hex);
+ await lc.preferences.set(_cf.pref_key_active, pk_hex);
await sleep(500);
await restart(true);
}
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
@@ -5,7 +5,7 @@
PUBLIC_DATABASE_NAME,
PUBLIC_NOSTR_RELAY_DEFAULTS,
} from "$env/static/public";
- import { cl } from "$lib/client";
+ import { lc } from "$lib/client";
import LayoutWindow from "$lib/components/layout-window.svelte";
import { _cf } from "$lib/conf";
import {
@@ -35,7 +35,7 @@
import { onMount } from "svelte";
import "../app.css";
- let render_pwa = browser && cl.platform === `web`;
+ let render_pwa = browser && lc.platform === `web`;
if (render_pwa) {
const el = document.createElement(`jeep-sqlite`);
document.body.appendChild(el);
@@ -73,13 +73,13 @@
app_thc.subscribe((app_thc) => {
const color_mode = parse_color_mode(app_thc);
theme_set(parse_theme_key($app_thm), color_mode);
- cl.window.status_style(color_mode);
+ lc.window.status_style(color_mode);
});
app_thm.subscribe((app_thm) => {
const color_mode = parse_color_mode($app_thc);
theme_set(parse_theme_key(app_thm), color_mode);
- cl.window.status_style(color_mode);
+ lc.window.status_style(color_mode);
});
app_sqlite.subscribe((app_sqlite) => {
@@ -90,7 +90,7 @@
app_nostr_key.subscribe(async (app_nostr_key) => {
try {
if (!app_nostr_key) return;
- const private_key = await cl.keystore.get(
+ const private_key = await lc.keystore.get(
`nostr:key:${app_nostr_key}`,
);
if (private_key) {
@@ -117,12 +117,12 @@
app_config.subscribe(async (app_config) => {
try {
if (!app_config) return;
- app_sqlite.set(!!(await cl.db.connect(PUBLIC_DATABASE_NAME)));
- const active_nostr_pk = await cl.preferences.get(
+ 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 cl.keystore.get(
+ const active_nostr_sk = await lc.keystore.get(
`nostr:key:${active_nostr_pk}`,
);
console.log(`active_nostr_sk `, active_nostr_sk);
@@ -133,7 +133,7 @@
)
app_nostr_key.set(active_nostr_pk);
else {
- await cl.preferences.remove(_cf.pref_key_active);
+ await lc.preferences.remove(_cf.pref_key_active);
await goto(`/conf/nostr`);
}
} catch (e) {
@@ -158,7 +158,7 @@
} catch (e) {
console.log(`(app_render) error `, e);
} finally {
- await cl.window.splash_hide();
+ await lc.window.splash_hide();
}
});
</script>
diff --git a/static/assets/keyva.min.js b/static/assets/keyva.min.js
@@ -0,0 +1 @@
+"use strict"; class Keyva { static unbound = IDBKeyRange.lowerBound(Number.MIN_SAFE_INTEGER); static prefix(prefix) { return IDBKeyRange.bound(prefix, prefix + "") } static async each() { const databases = await indexedDB.databases(); return databases.map((db => db.name)).filter((s => !!s && s.startsWith(this.kvPrefix))) } static async delete(...names) { names = names.length ? names.map((n => n.startsWith(this.kvPrefix) ? n : this.kvPrefix + n)) : await this.each(); Promise.all(names.map((n => this.asPromise(indexedDB.deleteDatabase(n))))) } static kvPrefix = "-radroots-"; constructor(options = {}) { const idx = options.indexes || []; this.indexes = (Array.isArray(idx) ? idx : [idx]).sort(); this.name = Keyva.kvPrefix + (options.name || "") } indexes; name; async get(k) { const store = await this.getStore("readonly"); return Array.isArray(k) ? Promise.all(k.map((key => Keyva.asPromise(store.get(key))))) : Keyva.asPromise(store.get(k)) } async each(options = {}, only) { const store = await this.getStore("readonly"); const target = options.index ? store.index(options.index) : store; const limit = options.limit; const range = options.range; if (only === "keys") return Keyva.asPromise(target.getAllKeys(range, limit)); if (only === "values") return Keyva.asPromise(target.getAll(range, limit)); let keys = []; let values = []; await Promise.allSettled([new Promise((async r => { const results = await Keyva.asPromise(target.getAllKeys(range, limit)); keys.push(...results); r() })), new Promise((async r => { const results = await Keyva.asPromise(target.getAll(range, limit)); values.push(...results); r() }))]); const tuples = []; for (let i = -1; ++i < keys.length;)tuples.push([keys[i], values[i]]); return tuples } async set(a, b) { const store = await this.getStore("readwrite"); if (Array.isArray(a)) { for (const entry of a) store.put(entry[1], entry[0]); return Keyva.asPromise(store.transaction) } store.put(b, a); return Keyva.asPromise(store.transaction) } async delete(arg) { const store = await this.getStore("readwrite"); arg ??= Keyva.unbound; if (Array.isArray(arg)) { for (const key of arg) store.delete(key) } else store.delete(arg); return Keyva.asPromise(store.transaction) } async getStore(mode) { const db = await this.getDatabase(); return db.transaction(this.name, mode).objectStore(this.name) } async getDatabase() { if (!this.database) { await this.maybeFixSafari(); let quit = false; let version; let indexNamesAdded = []; let indexNamesRemoved = []; for (; ;) { const request = indexedDB.open(this.name, version); request.onupgradeneeded = () => { const db = request.result; const tx = request.transaction; const store = tx.objectStoreNames.contains(this.name) ? tx.objectStore(this.name) : db.createObjectStore(this.name); for (const index of indexNamesAdded) store.createIndex(index, index); for (const index of indexNamesRemoved) store.deleteIndex(index) }; this.database = await Keyva.asPromise(request); if (quit) break; const tx = this.database.transaction(this.name, "readonly"); const store = tx.objectStore(this.name); const indexNames = Array.from(store.indexNames).sort(); tx.abort(); indexNamesAdded = this.indexes.filter((n => !indexNames.includes(n))); indexNamesRemoved = indexNames.filter((n => !this.indexes.includes(n))); if (indexNamesAdded.length + indexNamesRemoved.length === 0) break; quit = true; this.database.close(); version = this.database.version + 1 } } return this.database } database = null; async maybeFixSafari() { if (!/Version\/14\.\d*\s*Safari\//.test(navigator.userAgent)) return; let id = 0; return new Promise((resolve => { const hit = () => indexedDB.databases().finally(resolve); id = setInterval(hit, 50); hit() })).finally((() => clearInterval(id))) } static asPromise(request) { return new Promise(((resolve, reject) => { request.oncomplete = request.onsuccess = () => resolve(request.result); request.onabort = request.onerror = () => reject(request.error) })) } } if (typeof module === "object") Object.assign(module.exports, { Keyva: Keyva });
diff --git a/tailwind.config.ts b/tailwind.config.ts
@@ -4,6 +4,10 @@ import type { Config } from "tailwindcss";
import tailwind_default from "tailwindcss/defaultTheme";
const { fontFamily: tw_font } = tailwind_default;
+const heights_form = {
+ line: "42px",
+};
+
const heights = {
line: `46px`,
tabs_base: `64px`,
@@ -41,6 +45,7 @@ const config: Config = {
},
height: {
...heights,
+ ...Object.fromEntries(Object.entries(heights_form).map(([k, v]) => [`form_${k}`, v])),
},
width: {
...widths,
@@ -68,6 +73,9 @@ const config: Config = {
borderWidth: {
"line": "1px"
},
+ borderRadius: {
+ input_form: "8px",
+ },
}
},
plugins: [