commit fbf61316973df84f5f4ffff8d01f4e686280ec59
parent 19f4309617f7bb90cfbd57a50a57a37198c3da3b
Author: triesap <137732411+triesap@users.noreply.github.com>
Date: Sun, 1 Sep 2024 10:03:07 +0000
apps-lib: add input form component, add kv store, use cacheadapter with ndk store, edit types
Diffstat:
8 files changed, 203 insertions(+), 2 deletions(-)
diff --git a/apps-lib/src/lib/components/input_form.svelte b/apps-lib/src/lib/components/input_form.svelte
@@ -0,0 +1,42 @@
+<script lang="ts">
+ import { kv, type IInputFormBasis } from "$lib";
+ import type { ThemeLayer } from "@radroots/theme";
+ import { onMount } from "svelte";
+
+ export let basis: IInputFormBasis;
+ $: basis = basis;
+
+ let layer: ThemeLayer = 0;
+ $: layer = basis.layer;
+
+ let el: HTMLInputElement | null;
+
+ onMount(async () => {
+ try {
+ if (basis.sync) await $kv.set(basis.id, "");
+ } catch (e) {
+ console.log(`e `, e);
+ }
+ });
+</script>
+
+<input
+ bind:this={el}
+ type="text"
+ class={`form-input text-layer-${layer}-glyph placeholder:text-layer-${layer}-glyph_pl placeholder:font-[300] caret-layer-${layer}-glyph`}
+ id={basis.id}
+ placeholder={basis.placeholder || ""}
+ on:input={async ({ currentTarget: el }) => {
+ const val = el.value
+ .split("")
+ .filter((char) => basis.field.charset.test(char))
+ .join("");
+ if (!basis.field.validate.test(val) && basis.field.validateKeypress)
+ el.classList.add(`form-input-invalid`);
+ else el.classList.remove("form-entry-invalid");
+ el.value = val;
+ if (basis.sync) {
+ await $kv.set(basis.id, val);
+ }
+ }}
+/>
diff --git a/apps-lib/src/lib/global.d.ts b/apps-lib/src/lib/global.d.ts
@@ -0,0 +1,132 @@
+declare class Keyva {
+ /**
+ * An IDBKeyRange that has no upper or lower bounding.
+ */
+ static readonly unbound: IDBKeyRange;
+ /**
+ * Returns an IDBKeyRange that matches all keys that start
+ * with the specified string prefix.
+ */
+ static prefix(prefix: string): IDBKeyRange;
+ /**
+ * @returns An array of strings that contain the names of all
+ * Keyva-created IndexedDB databases.
+ */
+ static each(): Promise<string[]>;
+ /**
+ * Deletes Keyva-created IndexedDB databases with the
+ * specified names.
+ *
+ * @param names The names of the databases to delete.
+ * If no names are provided, all Keyva IndexedDB databases
+ * are deleted.
+ */
+ static delete(...names: string[]): Promise<void>;
+ /** Stores the prefix that is added to every IndexedDB database created by Keyva. */
+ private static readonly kvPrefix;
+ /**
+ * Creates a new IndexedDB-backed database
+ */
+ constructor(options?: Keyva.IConstructorOptions);
+ private readonly indexes;
+ private readonly name;
+ /**
+ * Get a value by its key.
+ * @param key The key of the value to get.
+ */
+ get<T = any>(key: Keyva.Key): Promise<T>;
+ /**
+ * Get a series of values from the keys specified.
+ * @param keys The key of the value to get.
+ */
+ get<T = any>(keys: Keyva.Key[]): Promise<T[]>;
+ /**
+ * Gets all keys and values from the Keyva database.
+ * @param key The key of the value to get.
+ */
+ each<T = any>(): Promise<[Keyva.Key, T][]>;
+ /**
+ * Gets a series of keys and values that match the specified
+ * set of options.
+ */
+ each<T = any>(options: Keyva.IQuery): Promise<[Keyva.Key, T][]>;
+ /**
+ * Gets a series of keys only that match the specified set of options.
+ */
+ each(options: Keyva.IQuery, only: "keys"): Promise<Keyva.Key[]>;
+ /**
+ * Gets a series of values only that match the specified set of options.
+ */
+ each<T = any>(options: Keyva.IQuery, only: "values"): Promise<T[]>;
+ /**
+ * Set a value with a key.
+ */
+ set(key: Keyva.Key, value: any): Promise<void>;
+ /**
+ * Set multiple values at once. This is faster than calling set() multiple times.
+ * It's also atomic – if one of the pairs can't be added, none will be added.
+ * @param entries Array of entries, where each entry is an array of `[key, value]`.
+ */
+ set(entries: [Keyva.Key, any][]): Promise<void>;
+ /**
+ * Deletes all objects from this Keyva database
+ * (but keeps the Keyva database itself is kept).
+ */
+ delete(): Promise<void>;
+ /**
+ * Delete a single object from the store with the specified key.
+ */
+ delete(range: IDBKeyRange): Promise<void>;
+ /**
+ * Delete a single object from the store with the specified key.
+ */
+ delete(key: Keyva.Key): Promise<void>;
+ /**
+ * Delete a series of objects from the store at once, with the specified keys.
+ */
+ delete(keys: Keyva.Key[]): Promise<void>;
+ /** */
+ private getStore;
+ /** */
+ private getDatabase;
+ private database;
+ /**
+ * Works around a Safari 14 bug.
+ *
+ * Safari has a bug where IDB requests can hang while the browser is
+ * starting up. https://bugs.webkit.org/show_bug.cgi?id=226547
+ * The only solution is to keep nudging it until it's awake.
+ */
+ private maybeFixSafari;
+ /** */
+ private static asPromise;
+}
+declare namespace Keyva {
+ /** */
+ interface IConstructorOptions {
+ /**
+ * Defines the name of the IndexedDB database as it is stored in the browser.
+ * Note that the name is prefixed with the Keyva database prefix constant.
+ */
+ name?: string | number;
+ /**
+ * Defines the name or names of the index or indexes to define on the database.
+ */
+ indexes?: string | string[];
+ }
+ /** */
+ interface IQuery {
+ /**
+ * A standard IDBKeyRange to use for the query. Worth noting that the methods
+ * in the static Keyva.* namespace contain utility functions to ease the creation
+ * of IDBKeyRange objects.
+ */
+ range?: IDBKeyRange;
+ /** The name of the index to use for the query. */
+ index?: string;
+ /** A number which indicates the maximum number of objects to return from a query. */
+ limit?: number;
+ }
+ /** */
+ type Key = string | number | Date | BufferSource;
+}
diff --git a/apps-lib/src/lib/index.ts b/apps-lib/src/lib/index.ts
@@ -1,4 +1,5 @@
export * from "./locales/i18n"
+export { default as input_form } from "./components/input_form.svelte"
export { default as tabs } from "./components/tabs.svelte"
export { default as trellis } from "./components/trellis.svelte"
export { default as trellis_default_label } from "./components/trellis_default_label.svelte"
diff --git a/apps-lib/src/lib/stores/client.ts b/apps-lib/src/lib/stores/client.ts
@@ -1,3 +1,7 @@
import { queryParameters } from "@radroots/sveltekit-search-params";
+import { writable } from "svelte/store";
export const app_qp = queryParameters();
+
+export const kv = writable<Keyva>();
+if (typeof window !== 'undefined') kv.set(new Keyva({ name: 'app-kv' }));
diff --git a/apps-lib/src/lib/stores/ndk.ts b/apps-lib/src/lib/stores/ndk.ts
@@ -7,7 +7,7 @@ let cacheAdapter: NDKCacheAdapter | undefined;
if (typeof window !== `undefined`) cacheAdapter = new NDKCacheAdapterDexie({ dbName: "-radroots-app-ndk" });
const _ndk = new NDKSvelte({
- //cacheAdapter,
+ cacheAdapter,
clientName: "»--`--,---",
});
diff --git a/apps-lib/src/lib/types/components.ts b/apps-lib/src/lib/types/components.ts
@@ -1,4 +1,4 @@
-import type { CallbackPromiseGeneric } from "./client";
+import type { CallbackPromiseGeneric, IClOpt, ILy } from "./client";
import type { GlyphKey, GlyphWeight } from "./ui";
export type ITabsBasisList = {
@@ -16,3 +16,19 @@ export type ITabsBasis = {
app_layout: string;
};
+export type IFormField = {
+ validate: RegExp;
+ charset: RegExp;
+ validateKeypress?: boolean;
+};
+
+export type IInputFormBasis = IClOpt & ILy & {
+ id: string;
+ placeholder?: string;
+ label?: string;
+ hidden?: boolean;
+ validate?: RegExp;
+ sync?: boolean;
+ field: IFormField
+};
+
diff --git a/apps-lib/src/lib/types/ui.ts b/apps-lib/src/lib/types/ui.ts
@@ -2,6 +2,7 @@ import type { ThemeLayer } from "@radroots/theme";
import type { GeometryCardinalDirection, GeometryGlyphDimension, ICbOpt } from "./client";
export type GlyphKey = |
+ `handbag-simple` |
`devices` |
`lock-key` |
`gear-fine` |
diff --git a/apps-lib/src/lib/utils/client.ts b/apps-lib/src/lib/utils/client.ts
@@ -63,4 +63,9 @@ export function parse_qp(param: string): NavigationRouteParamKey | undefined {
export function time_now_ms(): number {
return Math.floor(new Date().getTime() / 1000);
+};
+
+export const fmt_id = (id: string): string => {
+ const pref = location.pathname.slice(1, -1).replaceAll(`-`, `_`).replaceAll(`/`, `-`).replaceAll(`--`, `-`)
+ return `${pref}-${id}`
};
\ No newline at end of file