commit d5c9d86649f174c96f37f559fa24316915334a99
parent af35fb75a82f87f59f29f60d82e526e257696147
Author: triesap <137732411+triesap@users.noreply.github.com>
Date: Thu, 26 Sep 2024 20:25:13 +0000
apps-lib: edit nav component option features, edit app config component, add toast ui, edit locales, stores, types, utils
Diffstat:
13 files changed, 241 insertions(+), 58 deletions(-)
diff --git a/apps-lib/src/lib/components/app_config.svelte b/apps-lib/src/lib/components/app_config.svelte
@@ -1,12 +1,52 @@
+<script lang="ts" context="module">
+ const toast_ms = 1500;
+
+ export const init_toast = (): void => {
+ app_toast.set(false);
+ };
+
+ export const show_toast = async (opts: {
+ args: IToast | string;
+ callback?: CallbackPromise;
+ }): Promise<void> => {
+ try {
+ const basis: IToast =
+ typeof opts.args === `string`
+ ? {
+ layer: 1,
+ label: {
+ value: opts.args,
+ },
+ }
+ : opts.args;
+ app_toast.set(basis);
+ await sleep(toast_ms);
+ init_toast();
+ if (opts.callback) await opts.callback();
+ } catch (e) {
+ console.log(`(error) show_toast `, e);
+ }
+ };
+</script>
+
<script lang="ts">
- import { app_config, app_layout, app_win } from "$lib";
+ import {
+ app_config,
+ app_layout,
+ app_toast,
+ app_win,
+ sleep,
+ type CallbackPromise,
+ type IToast,
+ } from "$lib";
+ import Toast from "$lib/ui/toast.svelte";
import { onMount } from "svelte";
onMount(async () => {
try {
app_win.set([window.innerHeight, window.innerWidth]);
-
app_config.set(true);
+ app_toast.set(false);
} catch (e) {
console.log(`(layout mount) `, e);
} finally {
@@ -17,3 +57,7 @@
if (win_h > 800) app_layout.set("lg");
});
</script>
+
+{#if $app_toast}
+ <Toast basis={$app_toast} />
+{/if}
diff --git a/apps-lib/src/lib/components/nav.svelte b/apps-lib/src/lib/components/nav.svelte
@@ -11,8 +11,8 @@
nav_visible,
type INavBasis,
} from "$lib";
- import Loading from "$lib/ui/loading.svelte";
import { onDestroy, onMount } from "svelte";
+ import NavOption from "./nav_option.svelte";
export let basis: INavBasis;
$: basis = basis;
@@ -20,9 +20,12 @@
let el: HTMLElement | null;
let el_inner: HTMLElement | null;
+ let nav_prev_label = ``;
+
onMount(async () => {
try {
nav_visible.set(true);
+ if ($nav_prev.length) nav_prev_label = $nav_prev[0].label || ``;
} catch (e) {
} finally {
}
@@ -52,7 +55,6 @@
class={`group col-span-4 flex flex-row h-full pl-2 justify-start items-center`}
on:click={async () => {
if (basis.prev.callback) await basis.prev.callback();
- console.log(`basis.prev.route `, basis.prev.route);
let route_to =
typeof basis.prev.route === `string`
? basis.prev.route
@@ -60,18 +62,14 @@
basis.prev.route[0],
basis.prev.route[1],
);
- console.log(`route_to `, route_to);
if ($nav_prev.length) {
- const nav_prev_param = $nav_prev.pop();
- console.log(`nav_prev_param `, nav_prev_param);
- if (nav_prev_param)
+ const nav_prev_li = $nav_prev.pop();
+ if (nav_prev_li)
route_to = encode_qp_route(
- nav_prev_param.route,
- nav_prev_param.params,
+ nav_prev_li.route,
+ nav_prev_li.params,
);
}
-
- console.log(`route_to `, route_to);
await goto(route_to);
}}
>
@@ -83,11 +81,11 @@
classes: `text-layer-1-glyph-hl group-active:opacity-70 transition-opacity`,
}}
/>
- {#if basis.prev.label}
+ {#if nav_prev_label || basis.prev.label}
<p
class={`font-sans text-navPrevious text-layer-1-glyph-hl group-active:opacity-60 transition-opacity`}
>
- {basis.prev.label}
+ {nav_prev_label || basis.prev.label}
</p>
{:else}
<Fill />
@@ -118,36 +116,7 @@
class={`col-span-4 flex flex-row h-full justify-end items-center`}
>
{#if basis.option}
- {#if basis.option.loading}
- <div
- class={`flex flex-row pr-4 justify-center items-center`}
- >
- <Loading />
- </div>
- {:else}
- <button
- class={`group col-span-4 flex flex-row h-full pr-6 gap-2 justify-end items-center`}
- on:click={async () => {
- await basis.option?.callback();
- }}
- >
- {#if `glyph` in basis.option && basis.option.glyph}
- <Glyph
- basis={{
- classes: `group-active:opacity-70 ${basis.option.glyph.classes}`,
- ...basis.option.glyph,
- }}
- />
- {/if}
- {#if `label` in basis.option && basis.option.label}
- <p
- class={`${fmt_cl(basis.option.label.classes)} font-sans text-navPrevious text-layer-1-glyph-hl group-active:opacity-60 transition-opacity`}
- >
- {basis.option.label.value}
- </p>
- {/if}
- </button>
- {/if}
+ <NavOption basis={basis.option} />
{:else}
<Fill />
{/if}
diff --git a/apps-lib/src/lib/components/nav_option.svelte b/apps-lib/src/lib/components/nav_option.svelte
@@ -0,0 +1,63 @@
+<!-- svelte-ignore a11y-label-has-associated-control -->
+<script lang="ts">
+ import { fmt_cl, Glyph, Loading, type INavBasisOption } from "$lib";
+
+ let el_swap: HTMLLabelElement | null = null;
+
+ export let basis: INavBasisOption;
+ $: basis = basis;
+
+ $: classes_swap = ``;
+
+ let layer = 1;
+</script>
+
+{#if basis.loading}
+ <div class={`flex flex-row pr-4 justify-center items-center`}>
+ <Loading />
+ </div>
+{:else}
+ <button
+ class={`group col-span-4 flex flex-row h-full pr-6 gap-2 justify-end items-center`}
+ on:click={async () => {
+ await basis.callback([classes_swap ? false : true, el_swap]);
+ if (classes_swap) classes_swap = ``;
+ else classes_swap = ` swap-active`;
+ }}
+ >
+ {#if `glyph` in basis && basis.glyph}
+ <Glyph
+ basis={{
+ classes: `group-active:opacity-70 ${basis.glyph.classes}`,
+ ...basis.glyph,
+ }}
+ />
+ {/if}
+ {#if `label` in basis && basis.label}
+ {#if basis.label.swap}
+ <label bind:this={el_swap} class={`swap${classes_swap}`}>
+ <div class="swap-off">
+ <p
+ class={`${fmt_cl(basis.label.classes)} font-sans text-navPrevious text-layer-${layer}-glyph-hl -translate-y-[1px] transition-all`}
+ >
+ {basis.label.value}
+ </p>
+ </div>
+ <div class="swap-on">
+ <p
+ class={`${fmt_cl(basis.label.classes)} font-sans text-navPrevious text-layer-${layer}-glyph-hl group-active:opacity-60 -translate-y-[1px] transition-all`}
+ >
+ {basis.label.swap}
+ </p>
+ </div>
+ </label>
+ {:else}
+ <p
+ class={`${fmt_cl(basis.label.classes)} font-sans text-navPrevious text-layer-1-glyph-hl group-active:opacity-60 transition-opacity`}
+ >
+ {basis.label.value}
+ </p>
+ {/if}
+ {/if}
+ </button>
+{/if}
diff --git a/apps-lib/src/lib/index.ts b/apps-lib/src/lib/index.ts
@@ -1,5 +1,4 @@
-export * from "./locales/i18n"
-export { default as AppConfig } from "./components/app_config.svelte"
+export { default as AppConfig, show_toast } from "./components/app_config.svelte"
export { default as ButtonLoading } from "./components/button_loading.svelte"
export { default as Envelope } from "./components/envelope.svelte"
export { default as EnvelopeLower } from "./components/envelope_lower.svelte"
@@ -12,6 +11,7 @@ export { default as LayoutView } from "./components/layout_view.svelte"
export { default as LayoutWindow } from "./components/layout_window.svelte"
export { default as LoadingView } from "./components/loading_view.svelte"
export { default as Nav } from "./components/nav.svelte"
+export { default as NavOption } from "./components/nav_option.svelte"
export { default as NotifyGlyph } from "./components/notify_glyph.svelte"
export { default as Tabs } from "./components/tabs.svelte"
export { default as Trellis } from "./components/trellis.svelte"
@@ -23,6 +23,7 @@ export { default as TrellisRowDisplayValue } from "./components/trellis_row_disp
export { default as TrellisRowLabel } from "./components/trellis_row_label.svelte"
export { default as TrellisTitle } from "./components/trellis_title.svelte"
export { default as TrellisTouch } from "./components/trellis_touch.svelte"
+export * from "./locales/i18n"
export * from "./stores/client"
export * from "./stores/ndk"
export * from "./types/client"
@@ -36,9 +37,11 @@ export { default as Glyph } from "./ui/glyph.svelte"
export { default as InputElement } from "./ui/input_element.svelte"
export { default as Loading } from "./ui/loading.svelte"
export { default as SelectElement } from "./ui/select_element.svelte"
+export { default as Toast } from "./ui/toast.svelte"
export * from "./utils/client"
export * from "./utils/dom"
export * from "./utils/geo"
export * from "./utils/ndk"
export * from "./utils/routes"
export * from "./utils/time"
+
diff --git a/apps-lib/src/lib/locales/en/common.json b/apps-lib/src/lib/locales/en/common.json
@@ -1,4 +1,11 @@
{
+ "done": "Done",
+ "unlock": "Unlock",
+ "nsec": "Nsec",
+ "npub": "Npub",
+ "hex": "Hex",
+ "public_key": "Public key",
+ "keys": "Keys",
"settings": "Settings",
"products": "Products",
"locations": "Locations",
diff --git a/apps-lib/src/lib/locales/en/icu.json b/apps-lib/src/lib/locales/en/icu.json
@@ -1,4 +1,6 @@
{
+ "your": "Your {value}",
+ "nostr": "Nostr {value}",
"invalid_entry": "Invalid {value} entry",
"enter_new": "Enter new {value}",
"enter": "Enter {value}",
diff --git a/apps-lib/src/lib/stores/client.ts b/apps-lib/src/lib/stores/client.ts
@@ -1,4 +1,4 @@
-import { type AppLayoutKey, type NavigationPreviousParam } from "$lib";
+import { type AppLayoutKey, type IToast, type NavigationPreviousParam } from "$lib";
import { writable } from "svelte/store";
import { queryParam, queryParameters } from "sveltekit-search-params";
@@ -18,6 +18,7 @@ export const app_config = writable<boolean>(false);
export const app_render = writable<boolean>(false);
export const app_win = writable<[number, number]>([0, 0]);
export const app_notify = writable<string>(``);
+export const app_toast = writable<IToast | false>(false);
export const nav_visible = writable<boolean>(false);
export const nav_blur = writable<boolean>(false);
diff --git a/apps-lib/src/lib/types/client.ts b/apps-lib/src/lib/types/client.ts
@@ -137,3 +137,11 @@ export type ILableFields = IGlOpt & {
export type LabelFieldKind = `link` | `on` | `shade`;
+export type IToastKind = `simple`;
+
+export type IToast = IClOpt &
+ ILabel & IGlOpt & {
+ styles?: IToastKind[];
+ layer?: ThemeLayer;
+ position?: GeometryScreenPosition;
+ };
+\ No newline at end of file
diff --git a/apps-lib/src/lib/types/components.ts b/apps-lib/src/lib/types/components.ts
@@ -1,5 +1,5 @@
import type { NavigationRoute } from "$lib/utils/routes";
-import type { CallbackPromise, CallbackPromiseGeneric, ICb, ICbGOpt, ICbOpt, IClOpt, IGl, IGlOpt, ILabel, ILabelFieldsOpt, ILabelOpt, ILabelOptFieldsOpt, ILyOpt, ILyOptTs, NavigationParamTuple } from "./client";
+import type { CallbackPromise, CallbackPromiseGeneric, ICb, ICbG, ICbGOpt, ICbOpt, IClOpt, IGl, IGlOpt, ILabel, ILabelFieldsOpt, ILabelOpt, ILabelOptFieldsOpt, ILyOpt, ILyOptTs, NavigationParamTuple } from "./client";
import type { GlyphKey, GlyphWeight, IGlyph } from "./ui";
export type ITabsBasisList = {
@@ -80,14 +80,17 @@ export type IEnvelopeTitledBasis = {
}
};
+export type INavBasisOption = ICbG<
+ [boolean, HTMLLabelElement | null]
+> & IGlOpt & ILabelOpt & {
+ loading?: boolean;
+};
export type INavBasis = {
prev: ICbOpt & {
label?: string;
route: NavigationRoute | [NavigationRoute, NavigationParamTuple[]];
};
title?: ICbOpt & ILabel;
- option?: ICb & IGlOpt & ILabelOpt & {
- loading?: boolean;
- };
+ option?: INavBasisOption;
};
diff --git a/apps-lib/src/lib/types/ui.ts b/apps-lib/src/lib/types/ui.ts
@@ -132,5 +132,5 @@ export type IInputElement = IClOpt & ILyOptTs & {
};*/
callback?: CallbackPromiseGeneric<{ val: string; pass: boolean; }>;
callback_keydown?: CallbackPromiseGeneric<{ key: string; }>;
- on_mount?: CallbackPromiseGeneric<HTMLElement>;
+ on_mount?: CallbackPromiseGeneric<HTMLInputElement>;
};
\ No newline at end of file
diff --git a/apps-lib/src/lib/ui/toast.svelte b/apps-lib/src/lib/ui/toast.svelte
@@ -0,0 +1,71 @@
+<script lang="ts">
+ import {
+ app_layout,
+ fmt_cl,
+ get_layout,
+ parse_layer,
+ type AppLayoutKey,
+ type IToast,
+ type IToastKind,
+ } from "$lib";
+ import Glyph from "./glyph.svelte";
+
+ export const layout_toast_map: Map<AppLayoutKey, string> = new Map([
+ [`base`, `pt-8`],
+ [`lg`, `pt-16`],
+ /*[
+ `mobile-xl`, `pt-12`
+ ]*/
+ ]);
+
+ const lm: Map<IToastKind, { inner: string; outer: string }> = new Map([
+ [
+ `simple`,
+ {
+ inner: `justify-center`,
+ outer: `min-h-cover1 w-full px-4 rounded-2xl shadow-sm`,
+ },
+ ],
+ ]);
+
+ export let basis: IToast;
+ $: basis = basis;
+
+ let styles: IToastKind[] = basis.styles || [`simple`];
+ $: styles = styles;
+ let layer = parse_layer(basis.layer || 1);
+ $: layer = layer;
+ $: layout = get_layout($app_layout);
+</script>
+
+<div
+ class={`${fmt_cl(layout_toast_map.get(layout))} z-[1000] h-[100vh] toast w-full ${basis.position || `top-center`} `}
+>
+ <div class={`flex flex-row w-full h-max justify-center pb-2`}>
+ <div
+ class={`${fmt_cl(basis.classes)} relative grid grid-cols-12 h-max items-center justify-center ${styles.includes(`simple`) ? `bg-layer-${layer}-surface` : ``} ${fmt_cl(styles.map((style) => fmt_cl(lm.get(style)?.outer)).join(` `))}`}
+ >
+ <div
+ class={`absolute top-0 left-4 flex flex-row h-full items-center`}
+ >
+ <Glyph
+ basis={{
+ key: `info`,
+ weight: `regular`,
+ dim: `md`,
+ ...basis.glyph,
+ }}
+ />
+ </div>
+ <div
+ class={`col-span-12 flex flex-row pl-1 ${fmt_cl(styles.map((style) => fmt_cl(lm.get(style)?.inner)).join(` `))}`}
+ >
+ <p
+ class={`font-sans font-[500] truncate text-layer-${layer}-glyph -translate-y-[1px]`}
+ >
+ {basis.label.value}
+ </p>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/apps-lib/src/lib/utils/client.ts b/apps-lib/src/lib/utils/client.ts
@@ -1,6 +1,6 @@
import { goto } from "$app/navigation";
import type { GlyphKey, NavigationRoute } from "$lib";
-import type { AnchorRoute, CallbackPromiseGeneric, LabelFieldKind, NavigationParamTuple, NavigationRouteParamKey } from "$lib/types/client";
+import type { AnchorRoute, AppLayoutKey, CallbackPromiseGeneric, LabelFieldKind, NavigationParamTuple, NavigationRouteParamKey } from "$lib/types/client";
import type { ColorMode, ThemeKey, ThemeLayer } from "@radroots/theme";
export const sleep = async (ms: number): Promise<void> => {
@@ -46,7 +46,7 @@ export const encode_qp = (params_list?: NavigationParamTuple[]): string => {
};
export const encode_qp_route = (route: NavigationRoute, params_list?: NavigationParamTuple[]): string => {
- return `${route}/${encode_qp(params_list)}`
+ return `${route}/${encode_qp(params_list)}`.replaceAll(`//`, `/`)
};
export const decode_qp = (query_param: string): AnchorRoute => {
@@ -92,10 +92,10 @@ export const int_step = (num: number, op: `+` | `-`, bounds?: number): number =>
return Math.max(int_num - 1, bounds || 0);
};
-export const clipboard_copy = async (text: string, callback: CallbackPromiseGeneric<string>): Promise<void> => {
+export const clipboard_copy = async (text: string, callback?: CallbackPromiseGeneric<string>): Promise<void> => {
try {
navigator.clipboard.writeText(text).then(async () => {
- await callback(text);
+ if (callback) await callback(text);
});
} catch (e) {
console.log(`(error) clipboard_copy `, e);
@@ -113,4 +113,14 @@ export const route = async (route: NavigationRoute, params_list?: NavigationPara
} catch (e) {
console.log(`(error) route `, e);
}
-}
-\ No newline at end of file
+}
+
+export const get_layout = (val: string | false): AppLayoutKey => {
+ switch (val) {
+ case `base`:
+ case `lg`:
+ return val;
+ default:
+ return `base`;
+ };
+};
diff --git a/apps-lib/src/lib/utils/routes.ts b/apps-lib/src/lib/utils/routes.ts
@@ -4,6 +4,7 @@ export type NavigationRoute =
| "/models/location-gcs/view-map"
| "/models/nostr-profile"
| "/models/nostr-profile/edit/field"
+ | "/models/nostr-profile/view"
| "/models/trade-product"
| "/models/trade-product/add"
| "/models/trade-product/add/preview"
@@ -24,6 +25,7 @@ export function parse_route(route: string): NavigationRoute {
case "/models/location-gcs/view-map":
case "/models/nostr-profile":
case "/models/nostr-profile/edit/field":
+ case "/models/nostr-profile/view":
case "/models/trade-product":
case "/models/trade-product/add":
case "/models/trade-product/add/preview":