web


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

commit 9cdc2995c625bdb5d61e145b52bc2acd252eae7a
parent f6dab854cca2c013af04692006fe261ccf677e8d
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Sat, 31 Aug 2024 13:50:31 +0000

Use svelte version 4, add `/nostr/keys`, add css, update nostr routes, update dependencies

Diffstat:
Mandroid/app/capacitor.build.gradle | 1+
Mandroid/capacitor.settings.gradle | 3+++
Mios/App/App.xcodeproj/project.pbxproj | 4++++
Mios/App/Podfile | 1+
Mios/App/Podfile.lock | 8+++++++-
Aios/App/PrivacyInfo.xcprivacy | 18++++++++++++++++++
Mpackage.json | 12+++++++-----
Msrc/app.css | 19++++++++++++++++++-
Asrc/lib/components/button-submit.svelte | 23+++++++++++++++++++++++
Msrc/lib/components/layout-trellis.svelte | 9+--------
Msrc/lib/components/layout-view.svelte | 51+++++++++++++++++++++++++++++++++++----------------
Msrc/lib/components/layout-window.svelte | 8+-------
Msrc/lib/components/nav.svelte | 31+++++++++++++++++++------------
Msrc/lib/components/tabs.svelte | 11++++-------
Asrc/lib/css/spinner-12.css | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/css/spinner-6.css | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/css/spinner.css | 20++++++++++++++++++++
Msrc/lib/stores.ts | 2++
Msrc/routes/(app)/+layout.svelte | 7++-----
Msrc/routes/(app)/+page.svelte | 26+++++++++++---------------
Msrc/routes/(app)/models/location-gcs/+page.svelte | 122++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/routes/(app)/nostr/+page.svelte | 37+++++++++++++++++++++++++++++++++++--
Asrc/routes/(app)/nostr/keys/+page.svelte | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/routes/(app)/nostr/notes/+page.svelte | 204+++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Asrc/routes/(app)/nostr/notes/post/+page.svelte | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/routes/(app)/nostr/profile/+page.svelte | 128+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/routes/(app)/settings/+page.svelte | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/routes/(conf)/conf/nostr/+page.svelte | 2+-
Msrc/routes/+layout.svelte | 100++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msvelte.config.js | 5-----
30 files changed, 1036 insertions(+), 271 deletions(-)

diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle @@ -11,6 +11,7 @@ apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" dependencies { implementation project(':capacitor-browser') implementation project(':capacitor-dialog') + implementation project(':capacitor-device') implementation project(':capacitor-geolocation') implementation project(':capacitor-haptics') implementation project(':capacitor-preferences') diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle @@ -8,6 +8,9 @@ project(':capacitor-browser').projectDir = new File('../../../node_modules/.pnpm include ':capacitor-dialog' project(':capacitor-dialog').projectDir = new File('../../../node_modules/.pnpm/@capacitor+dialog@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/dialog/android') +include ':capacitor-device' +project(':capacitor-device').projectDir = new File('../../../node_modules/.pnpm/@capacitor+device@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/device/android') + include ':capacitor-geolocation' project(':capacitor-geolocation').projectDir = new File('../../../node_modules/.pnpm/@capacitor+geolocation@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/geolocation/android') diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; }; 50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; }; A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; }; + C11106072C8353B800B825E4 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = C11106062C8353B800B825E4 /* PrivacyInfo.xcprivacy */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -29,6 +30,7 @@ 50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = "<group>"; }; AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; }; AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = "<group>"; }; + C11106062C8353B800B825E4 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; }; FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = "<group>"; }; /* End PBXFileReference section */ @@ -55,6 +57,7 @@ 504EC2FB1FED79650016851F = { isa = PBXGroup; children = ( + C11106062C8353B800B825E4 /* PrivacyInfo.xcprivacy */, 504EC3061FED79650016851F /* App */, 504EC3051FED79650016851F /* Products */, 7F8756D8B27F46E3366F6CEA /* Pods */, @@ -158,6 +161,7 @@ buildActionMask = 2147483647; files = ( 504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */, + C11106072C8353B800B825E4 /* PrivacyInfo.xcprivacy in Resources */, 50B271D11FEDC1A000F3C39B /* public in Resources */, 504EC30F1FED79650016851F /* Assets.xcassets in Resources */, 50379B232058CBB4000EE86E /* capacitor.config.json in Resources */, diff --git a/ios/App/Podfile b/ios/App/Podfile @@ -13,6 +13,7 @@ def capacitor_pods pod 'CapacitorCordova', :path => '../../../../node_modules/.pnpm/@capacitor+ios@6.1.2_@capacitor+core@6.1.2/node_modules/@capacitor/ios' pod 'CapacitorBrowser', :path => '../../../../node_modules/.pnpm/@capacitor+browser@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/browser' pod 'CapacitorDialog', :path => '../../../../node_modules/.pnpm/@capacitor+dialog@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/dialog' + pod 'CapacitorDevice', :path => '../../../../node_modules/.pnpm/@capacitor+device@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/device' pod 'CapacitorGeolocation', :path => '../../../../node_modules/.pnpm/@capacitor+geolocation@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/geolocation' pod 'CapacitorHaptics', :path => '../../../../node_modules/.pnpm/@capacitor+haptics@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/haptics' pod 'CapacitorPreferences', :path => '../../../../node_modules/.pnpm/@capacitor+preferences@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/preferences' diff --git a/ios/App/Podfile.lock b/ios/App/Podfile.lock @@ -4,6 +4,8 @@ PODS: - CapacitorBrowser (6.0.2): - Capacitor - CapacitorCordova (6.1.2) + - CapacitorDevice (6.0.1): + - Capacitor - CapacitorDialog (6.0.1): - Capacitor - CapacitorGeolocation (6.0.1): @@ -41,6 +43,7 @@ DEPENDENCIES: - "Capacitor (from `../../../../node_modules/.pnpm/@capacitor+ios@6.1.2_@capacitor+core@6.1.2/node_modules/@capacitor/ios`)" - "CapacitorBrowser (from `../../../../node_modules/.pnpm/@capacitor+browser@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/browser`)" - "CapacitorCordova (from `../../../../node_modules/.pnpm/@capacitor+ios@6.1.2_@capacitor+core@6.1.2/node_modules/@capacitor/ios`)" + - "CapacitorDevice (from `../../../../node_modules/.pnpm/@capacitor+device@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/device`)" - "CapacitorDialog (from `../../../../node_modules/.pnpm/@capacitor+dialog@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/dialog`)" - "CapacitorGeolocation (from `../../../../node_modules/.pnpm/@capacitor+geolocation@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/geolocation`)" - "CapacitorHaptics (from `../../../../node_modules/.pnpm/@capacitor+haptics@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/haptics`)" @@ -66,6 +69,8 @@ EXTERNAL SOURCES: :path: "../../../../node_modules/.pnpm/@capacitor+browser@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/browser" CapacitorCordova: :path: "../../../../node_modules/.pnpm/@capacitor+ios@6.1.2_@capacitor+core@6.1.2/node_modules/@capacitor/ios" + CapacitorDevice: + :path: "../../../../node_modules/.pnpm/@capacitor+device@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/device" CapacitorDialog: :path: "../../../../node_modules/.pnpm/@capacitor+dialog@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/dialog" CapacitorGeolocation: @@ -93,6 +98,7 @@ SPEC CHECKSUMS: Capacitor: 679f9673fdf30597493a6362a5d5bf233d46abc2 CapacitorBrowser: 83ec661a9ccd56c28a6851e4dd1ac33b181227ec CapacitorCordova: f48c89f96c319101cd2f0ce8a2b7449b5fb8b3dd + CapacitorDevice: 7097a1deb4224b77fd13a6e60a355d0062a5d772 CapacitorDialog: ad752191fdb22a8d0ac199b0754b8a021d86dbf9 CapacitorGeolocation: 39dca51d755f08ed1d43e51be55291a402cdc64f CapacitorHaptics: fe689ade56ef20ec9b041a753c6da70c5d8ec9a9 @@ -108,6 +114,6 @@ SPEC CHECKSUMS: SQLCipher: 77fbe633cd84db04b07876dd50766b4924b57d61 ZIPFoundation: b8c29ea7ae353b309bc810586181fd073cb3312c -PODFILE CHECKSUM: c6c1e7d552d32beb42585f968d80f8b142e3fef4 +PODFILE CHECKSUM: 37b4ea0a5a13844ab526c251f4635f95ea68eb09 COCOAPODS: 1.15.2 diff --git a/ios/App/PrivacyInfo.xcprivacy b/ios/App/PrivacyInfo.xcprivacy @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> + <dict> + <key>NSPrivacyAccessedAPITypes</key> + <array> + <dict> + <key>NSPrivacyAccessedAPIType</key> + <string>NSPrivacyAccessedAPICategoryDiskSpace</string> + <key>NSPrivacyAccessedAPITypeReasons</key> + <array> + <string>85F4.1</string> + </array> + </dict> + </array> + </dict> +</plist> +\ No newline at end of file diff --git a/package.json b/package.json @@ -17,7 +17,7 @@ "sql:wasm:rm": "rm -rf static/assets/sql-wasm.wasm" }, "devDependencies": { - "@capacitor/cli": "^6.0.0", + "@capacitor/cli": "^6.1.2", "@sveltejs/adapter-static": "^3.0.0", "@sveltejs/kit": "^2.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0", @@ -25,8 +25,8 @@ "autoprefixer": "^10.4.19", "daisyui": "^4.10.0", "postcss": "^8.4.38", - "svelte": "^5.0.0-next.1", - "svelte-check": "^3.6.0", + "svelte": "^4.2.19", + "svelte-check": "^3.8.6", "tailwindcss": "^3.4.3", "tslib": "^2.4.1", "typescript": "^5.3.3", @@ -34,19 +34,21 @@ }, "type": "module", "dependencies": { - "@capacitor/android": "^6.0.0", + "@capacitor/android": "^6.1.2", "@capacitor/browser": "^6.0.0", "@capacitor/core": "^6.1.2", "@capacitor/dialog": "^6.0.0", + "@capacitor/device": "^6.0.0", "@capacitor/geolocation": "^6.0.0", "@capacitor/haptics": "^6.0.0", - "@capacitor/ios": "^6.0.0", + "@capacitor/ios": "^6.1.2", "@capacitor/preferences": "^6.0.0", "@capacitor/share": "^6.0.0", "@capacitor/splash-screen": "^6.0.0", "@capacitor/status-bar": "^6.0.0", "@ionic/pwa-elements": "^3.3.0", "@nostr-dev-kit/ndk": "^2.7.1", + "@nostr-dev-kit/ndk-svelte": "^2.2.18", "@nostr-dev-kit/ndk-cache-dexie": "^2.3.1", "@radroots/capacitor-native-settings": "workspace:*", "@radroots/capacitor-secure-storage": "workspace:*", diff --git a/src/app.css b/src/app.css @@ -1,10 +1,27 @@ +@import "./lib/css/spinner.css"; +@import "./lib/css/spinner-6.css"; +@import "./lib/css/spinner-12.css"; + @tailwind base; @tailwind components; @tailwind utilities; @layer components { + .input-simple { + @apply input flex flex-row w-full h-fit p-0 border-0 focus:border-0 outline-0 focus:outline-0 placeholder:font-[300] bg-layer-1-surface font-mono text-sm text-layer-2-glyph; + } + + .button-submit { + @apply h-[32px] min-w-[82px] w-fit rounded-xl active:bg-layer-1-surface_a; + } + .button-simple { - @apply flex flex-row h-line w-line justify-center items-center bg-layer-1-surface font-mono text-sm lowercase text-layer-2-glyph; + @apply h-line w-line; + } + + .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; } .flex-fill { diff --git a/src/lib/components/button-submit.svelte b/src/lib/components/button-submit.svelte @@ -0,0 +1,23 @@ +<script lang="ts"> + import type { CallbackPromise } from "@radroots/svelte-lib"; + import { loading as Loading, t } from "@radroots/svelte-lib"; + + export let basis: { + callback: CallbackPromise; + loading?: boolean; + }; + $: basis = basis; +</script> + +<button + class={`button-submit`} + on:click={async () => { + await basis.callback(); + }} +> + {#if basis.loading} + <Loading basis={{ dim: `xs` }} /> + {:else} + {`${$t(`common.submit`, { default: `submit` })}`} + {/if} +</button> diff --git a/src/lib/components/layout-trellis.svelte b/src/lib/components/layout-trellis.svelte @@ -1,10 +1,3 @@ -<script lang="ts"> - import type { PropChildren } from "@radroots/svelte-lib"; - - let { children }: PropChildren = $props(); -</script> - - <div class={`flex flex-col w-full pt-4 px-4 pb-12 gap-4`}> - {@render children()} + <slot /> </div> diff --git a/src/lib/components/layout-view.svelte b/src/lib/components/layout-view.svelte @@ -1,21 +1,46 @@ <script lang="ts"> - import { app_layout, app_nav_blur, app_nav_visible, app_tabs_blur, app_tabs_visible } from "$lib/stores"; - import { type AppLayoutKey, type PropChildren } from "@radroots/svelte-lib"; + import { + app_layout, + app_nav_blur, + app_nav_visible, + app_tabs_blur, + app_tabs_visible, + } from "$lib/stores"; + import { type AppLayoutKey } from "@radroots/svelte-lib"; + import { onDestroy, onMount } from "svelte"; const styles: Record<AppLayoutKey, string> = { - base: 'pt-2', - lg:'pt-16' + base: "pt-2", + lg: "pt-16", }; - let { children, basis }: PropChildren & { basis?: { fade?: boolean; }} = $props(); + export let basis: { fade?: boolean } | undefined = undefined; + $: basis = basis; let el: HTMLElement | null; - let classes_nav = $derived($app_nav_visible ? `pt-h_nav_${$app_layout}` : `${styles[$app_layout]}`) - let classes_tabs = $derived($app_tabs_visible ? `pb-h_tabs_${$app_layout}` : ``) - let classes_fade = $derived(basis?.fade ? `fade-in` : ``) + onMount(async () => { + try { + el?.addEventListener("scroll", scrollChange); + } catch (e) { + } finally { + } + }); + + onDestroy(async () => { + try { + el?.removeEventListener("scroll", scrollChange); + } catch (e) { + } finally { + } + }); + + $: classes_nav = $app_nav_visible + ? `pt-h_nav_${$app_layout}` + : `${styles[$app_layout]}`; + $: classes_tabs = $app_tabs_visible ? `pb-h_tabs_${$app_layout}` : ``; + $: classes_fade = basis?.fade ? `fade-in` : ``; - const scrollChange = (): void => { if (Math.max(el?.scrollTop || 0, 0) > 10) app_nav_blur.set(true); else app_nav_blur.set(false); @@ -23,17 +48,11 @@ if (Math.max(el?.scrollTop || 0, 0) > 10) app_tabs_blur.set(true); else app_tabs_blur.set(false); }; - - $effect(() => { - el?.addEventListener("scroll", scrollChange); - - return () => el?.removeEventListener("scroll", scrollChange); - }); </script> <div bind:this={el} class={`absolute top-0 left-0 flex flex-col h-[100vh] w-full overflow-y-scroll scroll-hide ${classes_nav} ${classes_tabs} ${classes_fade}`} > - {@render children()} + <slot /> </div> diff --git a/src/lib/components/layout-window.svelte b/src/lib/components/layout-window.svelte @@ -1,13 +1,7 @@ -<script lang="ts"> - import type { PropChildren } from "@radroots/svelte-lib"; - - let { children }: PropChildren = $props(); -</script> - <div class={`relative flex flex-col h-[100vh] w-full overflow-x-hidden overflow-y-hidden bg-layer-0-surface`} > <div class={`flex flex-col h-full w-full`}> - {@render children()} + <slot /> </div> </div> diff --git a/src/lib/components/nav.svelte b/src/lib/components/nav.svelte @@ -4,21 +4,28 @@ import type { INavBasis } from "$lib/types"; import { restart } from "$lib/utils"; import { fill as Fill, glyph as Glyph } from "@radroots/svelte-lib"; + import { onDestroy, onMount } from "svelte"; - let { - basis, - }: { - basis: INavBasis; - } = $props(); + export let basis: INavBasis; + $: basis = basis; let el: HTMLElement | null; let el_inner: HTMLElement | null; - $effect(() => { - app_nav_visible.set(true); - return () => { + onMount(async () => { + try { + app_nav_visible.set(true); + } catch (e) { + } finally { + } + }); + + onDestroy(async () => { + try { app_nav_visible.set(false); - }; + } catch (e) { + } finally { + } }); </script> @@ -35,7 +42,7 @@ > <button class={`col-span-4 flex flex-row h-full pl-2 justify-start items-center`} - onclick={async () => { + on:click={async () => { await goto(basis.prev.route); }} > @@ -63,7 +70,7 @@ {#if basis.title} <button class={`flex flex-row justify-center items-center`} - onclick={async () => { + on:click={async () => { await restart(); }} > @@ -83,7 +90,7 @@ {#if basis.option} <button class={`col-span-4 flex flex-row h-full pr-6 justify-end items-center`} - onclick={async () => { + on:click={async () => { await basis.option?.callback(); }} > diff --git a/src/lib/components/tabs.svelte b/src/lib/components/tabs.svelte @@ -2,13 +2,10 @@ import { app_layout, app_tab_active, app_tabs_blur } from "$lib/stores"; import { glyph as Glyph, type ITabsBasis } from "@radroots/svelte-lib"; - let { - basis, - }: { - basis: ITabsBasis; - } = $props(); + export let basis: ITabsBasis; + $: basis = basis; - let classes_blur = $derived($app_tabs_blur ? `bg-layer-1-surface/30` : ``); + $: classes_blur = $app_tabs_blur ? `bg-layer-1-surface/30` : ``; let el: HTMLElement | null; let el_inner: HTMLElement | null; @@ -28,7 +25,7 @@ {#each basis.list as tab, tab_i} <button class={`col-span-3 flex flex-col h-full justify-start items-center transition-all`} - onclick={async () => { + on:click={async () => { app_tab_active.set(tab_i); await tab.callback(tab_i); }} diff --git a/src/lib/css/spinner-12.css b/src/lib/css/spinner-12.css @@ -0,0 +1,89 @@ +@layer base { + .spinner12 { + position: relative; + display: inline-block; + width: 1em; + height: 1em; + } + + .spinner12.center { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; + } + + .spinner12 .spinner12-blade { + position: absolute; + left: 0.4629em; + bottom: 0; + width: 0.074em; + height: 0.2777em; + border-radius: 0.0555em; + background-color: transparent; + transform-origin: center -0.2222em; + animation: spinner-fade-base 1s infinite linear; + } + + .spinner12 .spinner12-blade:nth-child(1) { + animation-delay: 0s; + transform: rotate(0deg); + } + + .spinner12 .spinner12-blade:nth-child(2) { + animation-delay: 0.083s; + transform: rotate(30deg); + } + + .spinner12 .spinner12-blade:nth-child(3) { + animation-delay: 0.166s; + transform: rotate(60deg); + } + + .spinner12 .spinner12-blade:nth-child(4) { + animation-delay: 0.249s; + transform: rotate(90deg); + } + + .spinner12 .spinner12-blade:nth-child(5) { + animation-delay: 0.332s; + transform: rotate(120deg); + } + + .spinner12 .spinner12-blade:nth-child(6) { + animation-delay: 0.415s; + transform: rotate(150deg); + } + + .spinner12 .spinner12-blade:nth-child(7) { + animation-delay: 0.498s; + transform: rotate(180deg); + } + + .spinner12 .spinner12-blade:nth-child(8) { + animation-delay: 0.581s; + transform: rotate(210deg); + } + + .spinner12 .spinner12-blade:nth-child(9) { + animation-delay: 0.664s; + transform: rotate(240deg); + } + + .spinner12 .spinner12-blade:nth-child(10) { + animation-delay: 0.747s; + transform: rotate(270deg); + } + + .spinner12 .spinner12-blade:nth-child(11) { + animation-delay: 0.83s; + transform: rotate(300deg); + } + + .spinner12 .spinner12-blade:nth-child(12) { + animation-delay: 0.913s; + transform: rotate(330deg); + } +} +\ No newline at end of file diff --git a/src/lib/css/spinner-6.css b/src/lib/css/spinner-6.css @@ -0,0 +1,59 @@ +@layer base { + .spinner6 { + position: relative; + display: inline-block; + width: 1em; + height: 1em; + } + + .spinner6.center { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; + } + + .spinner6 .spinner6-blade { + position: absolute; + left: 0.4629em; + bottom: 0; + width: 0.074em; + height: 0.2777em; + border-radius: 0.0555em; + background-color: transparent; + transform-origin: center -0.2222em; + animation: spinner-fade-base 1s infinite linear; + } + + .spinner6 .spinner6-blade:nth-child(1) { + animation-delay: 0s; + transform: rotate(0deg); + } + + .spinner6 .spinner6-blade:nth-child(2) { + animation-delay: 0.1s; + transform: rotate(60deg); + } + + .spinner6 .spinner6-blade:nth-child(3) { + animation-delay: 0.2s; + transform: rotate(120deg); + } + + .spinner6 .spinner6-blade:nth-child(4) { + animation-delay: 0.3s; + transform: rotate(180deg); + } + + .spinner6 .spinner6-blade:nth-child(5) { + animation-delay: 0.4s; + transform: rotate(240deg); + } + + .spinner6 .spinner6-blade:nth-child(6) { + animation-delay: 0.5s; + transform: rotate(300deg); + } +} +\ No newline at end of file diff --git a/src/lib/css/spinner.css b/src/lib/css/spinner.css @@ -0,0 +1,19 @@ +@layer base { + @keyframes spinner-fade-white { + 0% { + background-color: white; + } + 100% { + background-color: transparent; + } + } + + @keyframes spinner-fade-base { + 0% { + background-color: hsl(var(--layer-2-glyph)); + } + 100% { + background-color: transparent; + } + } +} +\ No newline at end of file diff --git a/src/lib/stores.ts b/src/lib/stores.ts @@ -23,3 +23,5 @@ export const app_sqlite = writable<boolean>(false); export const app_nav_visible = writable<boolean>(false); //export const app_nav_prev = writable<NavParamPrev>([]); //export const app_nav_title = writable<NavParamTitle | false>(false); + +export const app_init_route = writable<string>(``); diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte @@ -2,14 +2,11 @@ import { goto } from "$app/navigation"; import Tabs from "$lib/components/tabs.svelte"; import { app_layout, app_tab_active, app_tabs_visible } from "$lib/stores"; - import { type PropChildren } from "@radroots/svelte-lib"; - let { children }: PropChildren = $props(); - </script> -{@render children()} +<slot /> {#if $app_tabs_visible} - <Tabs + <Tabs basis={{ tab_active: $app_tab_active, app_layout: $app_layout, diff --git a/src/routes/(app)/+page.svelte b/src/routes/(app)/+page.svelte @@ -4,11 +4,15 @@ 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 { onMount } from "svelte"; - $effect(() => { - //app_nav_visible.set(false); - app_tabs_visible.set(true); - app_tab_active.set(0); + onMount(async () => { + try { + app_tabs_visible.set(true); + app_tab_active.set(0); + } catch (e) { + } finally { + } }); const nostr_note_pub = async (): Promise<void> => { @@ -34,7 +38,7 @@ <div class={`flex flex-col w-full pt-16 gap-8 justify-center items-center`}> <button class={`button-simple`} - onclick={async () => { + on:click={async () => { await cl.dialog.alert(`Hi! You're platform is ${cl.platform}`); }} > @@ -42,18 +46,10 @@ </button> <button class={`button-simple`} - onclick={async () => { + on:click={async () => { await goto(`/models/location-gcs`); }} > - {"models location_gcs"} - </button> - <button - class={`button-simple`} - onclick={async () => { - await nostr_note_pub(); - }} - > - {"publish test note"} + {"models geolocation"} </button> </div> diff --git a/src/routes/(app)/models/location-gcs/+page.svelte b/src/routes/(app)/models/location-gcs/+page.svelte @@ -2,30 +2,39 @@ import { cl } 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 LocationGcs, type LocationGcsFormFields } from "@radroots/client"; + 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 = $state<LocationGcs[]>([]); + let locations_all: LocationGcs[] = []; - $effect(() => { - app_tabs_visible.set(false); - (async () => { - try { + onMount(async () => { + try { + app_tabs_visible.set(false); + await fetch_models(); + } catch (e) { + } finally { + } + }); + + const fetch_models = async (): Promise<void> => { + try { const res = await cl.db.location_gcs_get({ list: [`all`], }); - if(typeof res !== `string`) locations_all = res; - } catch (e) { } - })(); - }); + if (typeof res !== `string`) locations_all = res; + } catch (e) { + console.log(`(error) fetch_models `, e); + } + }; </script> - <LayoutView> <LayoutTrellis> - <Trellis + <Trellis basis={{ args: { layer: 1, @@ -45,36 +54,67 @@ }, 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; - + 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: LocationGcsFormFields = { + const geohash = location_geohash( + lat, + lng, + ); + const fields = { lat: lat.toString(), lng: lng.toString(), geohash, - label: loc_gcs_label + label: loc_gcs_label, }; - const exe_res = await cl.db.location_gcs_add(fields); - if(typeof exe_res !== `string` && `id` in exe_res) { - await cl.dialog.alert(`Added new location (${exe_res.id})`); - } else if(typeof exe_res === `string` && exe_res === `*-location-gcs-geohash-unique`) { - await cl.dialog.alert(`This location has already been added.`); + 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.`); + } 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` } }, + ? { + ios: { + setting: `LocationServices`, + }, + } + : { + android: { + setting: `Location`, + }, + }, ); } } @@ -95,8 +135,8 @@ const res = await cl.db.location_gcs_get({ list: [`all`], }); - if(typeof res !== `string`) locations_all = res; - + if (typeof res !== `string`) + locations_all = res; }, }, }, @@ -111,7 +151,8 @@ </p> {#each locations_all as location} <div class={`flex flex-col justify-center items-center`}> - <pre class={`font-sans font-[400] text-layer-0-glyph text-xs`}>{JSON.stringify( + <pre + class={`font-sans font-[400] text-layer-0-glyph text-xs`}>{JSON.stringify( location, null, 4, @@ -127,3 +168,14 @@ </div> </LayoutTrellis> </LayoutView> +<Nav + basis={{ + prev: { + label: `Home`, + route: `/`, + }, + title: { + label: `Locations`, + }, + }} +/> diff --git a/src/routes/(app)/nostr/+page.svelte b/src/routes/(app)/nostr/+page.svelte @@ -22,13 +22,38 @@ label: { left: [ { - value: `View Profile`, + value: `View Your Keys`, + }, + ], + }, + callback: async () => { + await goto(`/nostr/keys`); + }, + end: { + icon: { + key: `caret-right`, + }, + }, + }, + }, + { + hide_active: true, + touch: { + label: { + left: [ + { + value: `View Your Profile`, }, ], }, callback: async () => { await goto(`/nostr/profile`); }, + end: { + icon: { + key: `caret-right`, + }, + }, }, }, { @@ -37,13 +62,18 @@ label: { left: [ { - value: `View Notes`, + value: `View Your Notes`, }, ], }, callback: async () => { await goto(`/nostr/notes`); }, + end: { + icon: { + key: `caret-right`, + }, + }, }, }, ], @@ -58,5 +88,8 @@ label: `Home`, route: `/`, }, + title: { + label: `Nostr`, + }, }} /> diff --git a/src/routes/(app)/nostr/keys/+page.svelte b/src/routes/(app)/nostr/keys/+page.svelte @@ -0,0 +1,139 @@ +<script lang="ts"> + import { cl } 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 { _cf } from "$lib/conf"; + import { trellis as Trellis } from "@radroots/svelte-lib"; + import { onMount } from "svelte"; + + let nostr_public_key = ``; + let nostr_secret_key = ``; + + onMount(async () => { + try { + const public_key = await cl.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}`); + if (secret_key) nostr_secret_key = secret_key; + } catch (e) { + } finally { + } + }); + + async function copyToClipboard(text: string) { + navigator.clipboard.writeText(text).then(async () => { + await cl.dialog.alert( + `Copied nostr key "${text.slice(0, 12)}..." to clipboard.`, + ); + }); + } +</script> + +<LayoutView basis={{ fade: true }}> + <LayoutTrellis> + <Trellis + basis={{ + args: { + layer: 1, + title: { + value: `Public Key`, + }, + list: [ + { + touch: { + label: { + left: [ + { + value: nostr_public_key, + }, + ], + }, + + callback: async () => { + await copyToClipboard(nostr_public_key); + }, + }, + }, + { + touch: { + label: { + left: [ + { + value: cl.nostr.lib.npub( + nostr_public_key, + ), + }, + ], + }, + + callback: async () => { + await copyToClipboard( + cl.nostr.lib.npub(nostr_public_key), + ); + }, + }, + }, + ], + }, + }} + /> + <Trellis + basis={{ + args: { + layer: 1, + title: { + value: `Secret Key`, + }, + list: [ + { + touch: { + label: { + left: [ + { + value: nostr_secret_key, + }, + ], + }, + + callback: async () => { + await copyToClipboard(nostr_secret_key); + }, + }, + }, + { + touch: { + label: { + left: [ + { + value: cl.nostr.lib.nsec( + nostr_secret_key, + ), + }, + ], + }, + + callback: async () => { + await copyToClipboard( + cl.nostr.lib.nsec(nostr_secret_key), + ); + }, + }, + }, + ], + }, + }} + /> + </LayoutTrellis> +</LayoutView> +<Nav + basis={{ + prev: { + label: `Nostr`, + route: `/nostr`, + }, + title: { + label: `Keys`, + }, + }} +/> diff --git a/src/routes/(app)/nostr/notes/+page.svelte b/src/routes/(app)/nostr/notes/+page.svelte @@ -1,83 +1,151 @@ <script lang="ts"> - import { cl } from "$lib/client"; + import { goto } from "$app/navigation"; 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_nostr_key } from "$lib/stores"; - import { NDKEvent, NDKKind } from "@nostr-dev-kit/ndk"; - import { ndk, trellis as Trellis } from "@radroots/svelte-lib"; - import { writable } from "svelte/store"; + import { NDKEvent, NDKKind, type NDKFilter } from "@nostr-dev-kit/ndk"; + import type { + ExtendedBaseType, + NDKEventStore, + } from "@nostr-dev-kit/ndk-svelte"; + import { + locale, + ndk, + time_fmt_nostr_event, + trellis as Trellis, + type ITrellisKindTouch, + } from "@radroots/svelte-lib"; + import { onDestroy } from "svelte"; - let ndk_sub = $ndk.subscribe( - { + let events_store: NDKEventStore<ExtendedBaseType<NDKEvent>>; + + $: { + let authors = [$app_nostr_key]; + let ndk_filter: NDKFilter = { kinds: [NDKKind.Text], - authors: [$app_nostr_key], - }, - { - closeOnEose: false, - }, - ); - const events_list = writable<NDKEvent[]>([]); + ...{ authors }, + }; - events_list.subscribe((events_list) => { - console.log( - `events_list `, - JSON.stringify(events_list.map((i) => i.content)), - ); - }); + fetch_events(ndk_filter).then(() => { + events_store?.startSubscription(); + }); + } - ndk_sub.on("event", (event) => { - events_list.set([...$events_list, event]); + async function fetch_events(filter: NDKFilter) { + try { + events_store = $ndk.storeSubscribe(filter, { + closeOnEose: true, + groupable: false, + autoStart: false, + }); + if (events_store) { + events_store.onEose(() => {}); + } + } catch (error) { + console.error(error); + } + } + + onDestroy(() => { + events_store?.unsubscribe(); }); + + const parse_nostr_text_note = (ev: NDKEvent): ITrellisKindTouch[] => { + const trellis_list: ITrellisKindTouch[] = []; + + trellis_list.push({ + touch: { + label: { + left: [ + { + value: ev.content, + }, + ], + }, + callback: async () => { + await goto(`/nostr/notes/post`); + }, + }, + }); + + trellis_list.push({ + hide_active: true, + touch: { + label: { + left: [ + { + value: `Published At:`, + }, + ], + right: [ + { + value: time_fmt_nostr_event($locale, ev.created_at), + }, + ], + }, + }, + }); + + for (const tags of Object.entries(ev.tags)) { + console.log(`tags `, tags); + } + return trellis_list; + }; </script> <LayoutView basis={{ fade: true }}> <LayoutTrellis> - <Trellis - basis={{ - args: { - layer: 1, - title: { - value: `Nostr Profile`, + {#if $events_store.length} + {#each $events_store as ev, ev_i (ev.id)} + <Trellis + basis={{ + args: { + layer: 1, + title: + ev_i === 0 + ? { + value: `Your Notes`, + } + : undefined, + list: parse_nostr_text_note(ev), + }, + }} + /> + {/each} + {:else} + <Trellis + basis={{ + args: { + layer: 1, + title: { + value: `Your Notes`, + }, + list: [ + { + touch: { + label: { + left: [ + { + value: `Add Note`, + }, + ], + }, + end: { + icon: { + key: `caret-right`, + }, + }, + callback: async () => { + await goto(`/nostr/notes/post`); + }, + }, + }, + ], }, - list: $events_list.length - ? $events_list.map((ev) => ({ - hide_active: true, - touch: { - label: { - left: [ - { - value: ev.content, - }, - ], - }, - callback: async () => {}, - }, - })) - : [ - { - touch: { - label: { - left: [ - { - value: `Add Note`, - }, - ], - }, - end: { - icon: { - key: `caret-right`, - }, - }, - callback: async () => { - await cl.dialog.alert(`Todo!`); - }, - }, - }, - ], - }, - }} - /> + }} + /> + {/if} </LayoutTrellis> </LayoutView> <Nav @@ -89,11 +157,11 @@ title: { label: `Notes`, }, - option: $events_list.length + option: $events_store.length ? { - label: `Edit`, + label: `Post`, callback: async () => { - await cl.dialog.alert(`Todo!`); + await goto(`/nostr/notes/post`); }, } : undefined, diff --git a/src/routes/(app)/nostr/notes/post/+page.svelte b/src/routes/(app)/nostr/notes/post/+page.svelte @@ -0,0 +1,74 @@ +<script lang="ts"> + import { goto } from "$app/navigation"; + import { cl } 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 { NDKKind } from "@nostr-dev-kit/ndk"; + import { ndk, ndk_event, ndk_user } from "@radroots/svelte-lib"; + + let loading = false; + let value_note_content = ``; + + const nostr_note_publish = async (): Promise<void> => { + try { + if (!value_note_content) { + await cl.dialog.alert(`You must write something to post.`); + return; + } + + loading = true; + + const ev = await ndk_event({ + $ndk, + $ndk_user, + basis: { + kind: NDKKind.Text, + content: value_note_content, + }, + }); + if (ev) { + await ev.publish(); + await goto(`/nostr/notes`); + } + } catch (e) { + console.log(`(error) nostr_note_publish `, e); + } finally { + loading = false; + } + }; +</script> + +<LayoutView basis={{ fade: true }}> + <LayoutTrellis> + <div class={`flex flex-col w-full gap-3 justify-center items-center`}> + <textarea + class="input-simple p-4 h-44 rounded-xl" + placeholder="Write your note here" + bind:value={value_note_content} + /> + <div class={`flex flex-row w-full justify-end items-center`}> + <ButtonSubmit + basis={{ + callback: async () => { + await nostr_note_publish(); + }, + loading, + }} + /> + </div> + </div> + </LayoutTrellis> +</LayoutView> +<Nav + basis={{ + prev: { + label: `Notes`, + route: `/nostr/notes`, + }, + title: { + label: `Post New`, + }, + }} +/> diff --git a/src/routes/(app)/nostr/profile/+page.svelte b/src/routes/(app)/nostr/profile/+page.svelte @@ -4,13 +4,11 @@ import LayoutView from "$lib/components/layout-view.svelte"; import Nav from "$lib/components/nav.svelte"; import { app_nostr_key } from "$lib/stores"; - import { restart } from "$lib/utils"; - import { - NDKEvent, - NDKKind, - type NDKFilter, - type NDKSubscriptionOptions, - } from "@nostr-dev-kit/ndk"; + import { NDKEvent, NDKKind, type NDKFilter } from "@nostr-dev-kit/ndk"; + import type { + ExtendedBaseType, + NDKEventStore, + } from "@nostr-dev-kit/ndk-svelte"; import { ndk, ndk_event, @@ -18,56 +16,84 @@ t, trellis as Trellis, } from "@radroots/svelte-lib"; - import { writable } from "svelte/store"; + import { onDestroy } from "svelte"; - const ndk_filter: NDKFilter = { - kinds: [NDKKind.Metadata], - authors: [$app_nostr_key], - }; - const ndk_opts: NDKSubscriptionOptions = { - closeOnEose: false, - }; - const ndk_sub = $ndk.subscribe(ndk_filter, ndk_opts); + let events_store: NDKEventStore<ExtendedBaseType<NDKEvent>>; - const events_list = writable<NDKEvent[]>([]); + $: { + let authors = [$app_nostr_key]; + let ndk_filter: NDKFilter = { + kinds: [NDKKind.Metadata], + ...{ authors }, + }; - events_list.subscribe((events_list) => { - console.log( - `events_list `, - JSON.stringify(events_list.map((i) => i.content)), - ); - }); + fetch_events(ndk_filter).then(() => { + events_store?.startSubscription(); + }); + } + + async function fetch_events(filter: NDKFilter) { + try { + events_store = $ndk.storeSubscribe(filter, { + closeOnEose: true, + groupable: false, + autoStart: false, + }); + if (events_store) { + events_store.onEose(() => {}); + } + } catch (error) { + console.error(error); + } + } - ndk_sub.on("event", (event) => { - events_list.set( - [...$events_list, event].sort( - (a, b) => - parseInt(cl.nostr.ev.first_tag_value(b, "published_at")) - - parseInt(cl.nostr.ev.first_tag_value(a, "published_at")), - ), - ); + onDestroy(() => { + events_store?.unsubscribe(); }); const nostr_metadata_publish = async (): Promise<void> => { try { - const profile_name = await cl.dialog.prompt({ + const kind0_name = await cl.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({ title: `Profile Name`, message: `What is your profile name.`, input_placeholder: `Enter profile name`, }); - if (profile_name === false) return; + if (kind0_display_name === false) return; + + const kind0_about = await cl.dialog.prompt({ + title: `About`, + message: `What is your about me blurb.`, + input_placeholder: `Enter about me`, + }); + if (kind0_about === false) return; - const display_name = await cl.dialog.prompt({ - title: `Display Name`, - message: `What is your display name.`, - input_placeholder: `Enter display name`, + const kind0_website = await cl.dialog.prompt({ + title: `About`, + message: `What is your website.`, + input_placeholder: `Enter website`, }); - if (display_name === false) return; + if (kind0_website === false) return; + + const content: Record<string, string> = {}; + + if (kind0_name) content.name = kind0_name; + if (kind0_display_name) content.display_name = kind0_display_name; + if (kind0_about) content.about = kind0_about; + if (kind0_website) content.website = kind0_website; - const content = { - name: profile_name, - display_name, - }; + if (Object.keys(content).length === 0) { + await cl.dialog.alert( + `You must specify at least one profile field.`, + ); + return; + } const ev = await ndk_event({ $ndk, $ndk_user, @@ -78,7 +104,8 @@ }); if (ev) { await ev.publish(); - await restart(); + events_store?.unsubscribe(); + events_store?.startSubscription(); } } catch (e) { console.log(`(error) nostr_metadata_pub `, e); @@ -93,21 +120,26 @@ args: { layer: 1, title: { - value: `Nostr Profile`, + value: `Profile Metadata`, }, - list: $events_list.length + list: $events_store.length ? Object.entries( - JSON.parse($events_list[0].content), + JSON.parse($events_store[0].content), ).map(([entry_key, entry_val]) => ({ hide_active: true, touch: { label: { left: [ { - value: `${$t(`common.${entry_key}`, { default: `${entry_key.replace(`_`, ` `)}` })}: ${entry_val}`, + value: `${$t(`common.${entry_key}`, { default: `${entry_key.replace(`_`, ` `)}` })}:`, classes: `capitalize`, }, ], + right: [ + { + value: `${entry_val}`, + }, + ], }, callback: async () => {}, }, @@ -147,7 +179,7 @@ title: { label: `Profile`, }, - option: $events_list.length + option: $events_store.length ? { label: `Edit`, callback: async () => { diff --git a/src/routes/(app)/settings/+page.svelte b/src/routes/(app)/settings/+page.svelte @@ -10,10 +10,14 @@ toggle_color_mode, trellis as Trellis, } from "@radroots/svelte-lib"; + import { onMount } from "svelte"; - $effect(() => { - //app_nav_visible.set(true); - app_tabs_visible.set(false); + onMount(async () => { + try { + app_tabs_visible.set(false); + } catch (e) { + } finally { + } }); </script> @@ -200,7 +204,7 @@ args: { layer: 1, title: { - value: `Tests`, + value: `Web`, }, list: [ { @@ -208,7 +212,7 @@ label: { left: [ { - value: `Radroots Homepage (Open)`, + value: `Radroots.Org (Open Homepage)`, }, ], }, @@ -223,7 +227,7 @@ label: { left: [ { - value: `Radroots Homepage (Share)`, + value: `Radroots.Org (Share Homepage)`, }, ], }, @@ -242,6 +246,79 @@ label: { left: [ { + value: `Primal.Net (Open Profile)`, + }, + ], + }, + callback: async () => { + const public_key = await cl.preferences.get( + _cf.pref_key_active, + ); + const npub = cl.nostr.lib.npub(public_key); + const url = `https://primal.net/p/${npub}`; + await cl.browser.open(url); + }, + }, + }, + ], + }, + }} + /> + <Trellis + basis={{ + args: { + layer: 1, + title: { + value: `Device`, + }, + list: [ + { + touch: { + label: { + left: [ + { + value: `Device (Info)`, + }, + ], + }, + callback: async () => { + const data = await cl.device.info(); + await cl.dialog.alert(JSON.stringify(data)); + }, + }, + }, + { + touch: { + label: { + left: [ + { + value: `Device (Battery)`, + }, + ], + }, + callback: async () => { + const data = await cl.device.battery(); + await cl.dialog.alert(JSON.stringify(data)); + }, + }, + }, + ], + }, + }} + /> + <Trellis + basis={{ + args: { + layer: 1, + title: { + value: `Tests`, + }, + list: [ + { + touch: { + label: { + left: [ + { value: `Haptics Touch (less)`, classes: `capitalize`, }, @@ -309,5 +386,8 @@ label: `Home`, route: `/`, }, + title: { + label: `Settings`, + }, }} /> diff --git a/src/routes/(conf)/conf/nostr/+page.svelte b/src/routes/(conf)/conf/nostr/+page.svelte @@ -7,7 +7,7 @@ <div class={`flex flex-col w-full pt-16 justify-center items-center`}> <button class={`flex flex-row justify-center items-center text-white`} - onclick={async () => { + 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( diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte @@ -1,11 +1,25 @@ <script lang="ts"> import { browser } from "$app/environment"; import { goto } from "$app/navigation"; - import { PUBLIC_DATABASE_NAME, PUBLIC_NOSTR_RELAY_DEFAULTS } from "$env/static/public"; + import { + PUBLIC_DATABASE_NAME, + PUBLIC_NOSTR_RELAY_DEFAULTS, + } from "$env/static/public"; import { cl } from "$lib/client"; import LayoutWindow from "$lib/components/layout-window.svelte"; import { _cf } from "$lib/conf"; - import { app_config, app_layout, app_nostr_key, app_pwa_polyfills, app_render, app_sqlite, app_thc, app_thm, app_win } from "$lib/stores"; + import { + app_config, + app_init_route, + app_layout, + app_nostr_key, + app_pwa_polyfills, + app_render, + app_sqlite, + app_thc, + app_thm, + app_win, + } from "$lib/stores"; import { css_static as CssStatic, ndk, @@ -13,13 +27,14 @@ ndk_user, sleep, theme_set, - type PropChildren } from "@radroots/svelte-lib"; - import { parse_color_mode, parse_theme_key } from "@radroots/theme/src/utils"; + import { + parse_color_mode, + parse_theme_key, + } from "@radroots/theme/src/utils"; + import { onMount } from "svelte"; import "../app.css"; - let { children }: PropChildren = $props(); - let render_pwa = browser && cl.platform === `web`; if (render_pwa) { const el = document.createElement(`jeep-sqlite`); @@ -35,15 +50,20 @@ }); } - $effect(() => { - app_win.set([window.innerHeight, window.innerWidth]); + onMount(async () => { + try { + app_win.set([window.innerHeight, window.innerWidth]); - const prefers_dark = window.matchMedia( - `(prefers-color-scheme: dark)`, - ).matches; + const prefers_dark = window.matchMedia( + `(prefers-color-scheme: dark)`, + ).matches; - if (prefers_dark) app_thc.set(`dark`); - app_config.set(true); + if (prefers_dark) app_thc.set(`dark`); + app_config.set(true); + } catch (e) { + console.log(`(layout mount) `, e); + } finally { + } }); app_win.subscribe(([win_h, win_w]) => { @@ -63,16 +83,19 @@ }); app_sqlite.subscribe((app_sqlite) => { - if(!app_sqlite) return; + if (!app_sqlite) return; console.log(`(app_sqlite) connected`); }); app_nostr_key.subscribe(async (app_nostr_key) => { try { - if(!app_nostr_key) return; - const private_key = await cl.keystore.get(`nostr:key:${app_nostr_key}`); + if (!app_nostr_key) return; + const private_key = await cl.keystore.get( + `nostr:key:${app_nostr_key}`, + ); if (private_key) { - for (const url of PUBLIC_NOSTR_RELAY_DEFAULTS.split(',')) $ndk.addExplicitRelay(url); + for (const url of PUBLIC_NOSTR_RELAY_DEFAULTS.split(",")) + $ndk.addExplicitRelay(url); await $ndk.connect().then(() => { console.log(`(ndk) connected`); }); @@ -86,20 +109,29 @@ console.log(`(ndk_user) connected`); } } - } catch(e) { + } catch (e) { console.log(`(app_nostr_key) error `, e); - }; - }) + } + }); 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(_cf.pref_key_active); - console.log(`active_nostr_pk `, active_nostr_pk) - const active_nostr_sk = await cl.keystore.get(`nostr:key:${active_nostr_pk}`); - 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); + const active_nostr_pk = await cl.preferences.get( + _cf.pref_key_active, + ); + console.log(`active_nostr_pk `, active_nostr_pk); + const active_nostr_sk = await cl.keystore.get( + `nostr:key:${active_nostr_pk}`, + ); + 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 cl.preferences.remove(_cf.pref_key_active); await goto(`/conf/nostr`); @@ -113,20 +145,30 @@ app_render.subscribe(async (app_render) => { try { + console.log(`app_render `, app_render); if (!app_render) return; - await goto(`/`); + let init_route = `/`; + if ($app_init_route) { + init_route = $app_init_route; + app_init_route.set(`/`); + } + console.log(`init_route `, init_route); + await goto(init_route); await sleep(321); + await cl.window.splash_hide(); } catch (e) { console.log(`(app_render) error `, e); } finally { - await cl.window.splash_hide(); } }); </script> + {#if $app_render} <LayoutWindow> - {@render children()} + <slot /> </LayoutWindow> {/if} <CssStatic /> -<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"></div> +<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" +></div> diff --git a/svelte.config.js b/svelte.config.js @@ -7,11 +7,6 @@ const config = { kit: { adapter: adapter(), }, - compilerOptions: { - compatibility: { - componentApi: 5 - } - } }; export default config; \ No newline at end of file