web


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

commit 59117e9a992dc37f2d066d910c89270787697003
parent e0091963d6ea1b95f76534d4fdf1526437bf8310
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Fri,  7 Mar 2025 13:49:35 +0000

Add `/profile` page basis. Add nostr sync service. Edit `/init` handlers. Edit utils, styles.

Diffstat:
Mapp/src/lib/util/index.ts | 9++++++---
Mapp/src/lib/util/routes.ts | 4++++
Aapp/src/routes/(app)/profile/+page.svelte | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapp/src/routes/(app)/profile/edit/+page.svelte | 14++++++++++++++
Mapp/src/routes/(cfg)/init/+page.svelte | 10++++++----
Mapp/tailwind.config.ts | 2+-
Mpnpm-lock.yaml | 3+++
Mturbo.json | 2+-
8 files changed, 129 insertions(+), 9 deletions(-)

diff --git a/app/src/lib/util/index.ts b/app/src/lib/util/index.ts @@ -1,11 +1,12 @@ +import { browser } from "$app/environment"; import { goto } from "$app/navigation"; import { PUBLIC_RADROOTS_URL } from "$env/static/public"; import { ls } from "$lib/locale/i18n"; import { TauriClientDatabase, TauriClientDatastore, TauriClientFs, TauriClientGeolocation, TauriClientGui, TauriClientHttp, TauriClientKeys, TauriClientRadroots } from "@radroots/client"; import { Geocoder } from "@radroots/geocoder"; -import { app_notify, get_store, handle_err } from "@radroots/lib-app"; +import { app_notify, get_store, handle_err, NostrSyncService } from "@radroots/lib-app"; import { NostrEventService, NostrKeyService } from "@radroots/nostr-util"; -import { encode_qp_route, type CallbackPromise, type NavigationParamTuple } from "@radroots/util"; +import { encode_route, type CallbackPromise, type NavigationParamTuple } from "@radroots/util"; import type { NavigationRoute } from "./routes"; export const db = new TauriClientDatabase(); @@ -20,10 +21,12 @@ export const radroots = new TauriClientRadroots(PUBLIC_RADROOTS_URL); export const geoc = new Geocoder(); export const nostrkey = new NostrKeyService(); export const nostre = new NostrEventService(); +export let nostrsync: NostrSyncService +if (browser) nostrsync = new NostrSyncService(); export const route = async (nav_route: NavigationRoute, params: NavigationParamTuple[] = []): Promise<void> => { try { - if (params.length) await goto(encode_qp_route<NavigationRoute>(nav_route, params)); + if (params.length) await goto(encode_route<NavigationRoute>(nav_route, params)); else await goto(nav_route); } catch (e) { await handle_err(e, `route`); diff --git a/app/src/lib/util/routes.ts b/app/src/lib/util/routes.ts @@ -1,10 +1,14 @@ export type NavigationRoute = | "/" + | "/profile" + | "/profile/edit" | "/init"; export function parse_route(route: string): NavigationRoute { switch (route) { case "/": + case "/profile": + case "/profile/edit": case "/init": return route; default: diff --git a/app/src/routes/(app)/profile/+page.svelte b/app/src/routes/(app)/profile/+page.svelte @@ -0,0 +1,94 @@ +<script lang="ts"> + import { ls } from "$lib/locale/i18n"; + import { db, fs, gui, nostrsync, route } from "$lib/util"; + import { handle_err, ndk_user, Profile } from "@radroots/lib-app"; + import { throw_err } from "@radroots/util"; + + let loading_photo_upload = $state(false); + let photo_path_opt = $state(``); +</script> + +<Profile + bind:photo_path_opt + {ls} + basis={{ + loading_photo_upload, + lc_on_destroy: async () => { + try { + const tb_nostrprofile = await db.nostr_profile_read({ + public_key: $ndk_user.pubkey, + }); + if (`err` in tb_nostrprofile) throw_err(tb_nostrprofile.err); //@todo + const ev_metadata = await nostrsync.metadata({ + metadata: tb_nostrprofile.result, + }); + if (`err` in ev_metadata) + throw_err(`error.nostr.sync.missing_metadata_event`); + await ev_metadata.publish(); + } catch (e) { + await handle_err(e, `lc_on_destroy`); + } + }, + lc_handle_back: async () => { + try { + if (photo_path_opt) { + const confirm = await gui.confirm({ + message: `${$ls(`notification.profile.update_name_confirmation_on_route_previous`)}`, + ok: `${$ls(`common.upload_photo`)}`, + cancel: `${$ls(`common.keep_previous`)}`, + }); + if (!confirm) return void (await route(`/`)); + // @todo upload photo + } + await route(`/`); + } catch (e) { + await handle_err(e, `lc_handle_back`); + } + }, + lc_handle_edit_profile_field: async ({ field }) => { + try { + //@todo + if (field === `name`) { + const confirm = await gui.confirm({ + message: `${$ls(`notification.profile.update_name_confirmation`)}. ${$ls(`common.do_you_want_to_continue_q`)}`, + ok: `${$ls(`common.continue`)}`, + cancel: `${$ls(`common.cancel`)}`, + }); + if (!confirm) return; + } + await route(`/profile/edit`, [ + [`key_nostr`, $ndk_user.pubkey], + [`field`, field], + ]); + } catch (e) { + await handle_err(e, `lc_handle_edit_profile_field`); + } + }, + lc_handle_photo_add: async () => { + try { + loading_photo_upload = true; + const photo_paths_open = await gui.open_photos(); + if (!photo_paths_open) return; + const photo_path_add = photo_paths_open.results[0]; + if (photo_path_add) return photo_path_add; + } catch (e) { + await handle_err(e, `lc_handle_photo_add`); + } finally { + loading_photo_upload = false; + } + }, + lc_handle_photo_options: async () => { + try { + } catch (e) { + await handle_err(e, `lc_handle_photo_options`); + } + }, + lc_fs_read_bin: async (file_path) => { + try { + return await fs.read_bin(file_path); + } catch (e) { + await handle_err(e, `lc_fs_read_bin`); + } + }, + }} +/> diff --git a/app/src/routes/(app)/profile/edit/+page.svelte b/app/src/routes/(app)/profile/edit/+page.svelte @@ -0,0 +1,14 @@ +<script lang="ts"> + import { goto } from "$app/navigation"; +</script> + +<div class={`flex flex-col w-full pt-32 justify-center items-center`}> + <button + class={`flex flex-row justify-center items-center`} + onclick={async () => { + await goto(`/`); + }} + > + profile edit + </button> +</div> diff --git a/app/src/routes/(cfg)/init/+page.svelte b/app/src/routes/(cfg)/init/+page.svelte @@ -24,7 +24,7 @@ LogoCircle, view_effect, } from "@radroots/lib-app"; - import { el_id, form_fields, sleep } from "@radroots/util"; + import { el_id, form_fields, sleep, type ResultPass } from "@radroots/util"; import { onMount } from "svelte"; type IdbKey = `nostr:key:add` | `nostr:profile` | `#key_nostrp`; @@ -156,7 +156,7 @@ const configure_device = async ( public_key: string, profile_name?: string, - ): Promise<void> => { + ): Promise<ResultPass | void> => { const nostr_profile_add = await db.nostr_profile_create({ public_key, name: profile_name ? profile_name : undefined, @@ -183,6 +183,7 @@ }); } await key_add_keystore(public_key); + return { pass: true }; }; const handle_choose_key_gen_or_add = async (): Promise<void> => { @@ -341,11 +342,12 @@ secret_key: key_nostr_read.secret_key, }); //@todo } - await configure_device( + const configuration_result = await configure_device( kv_keynostrp, await kv.read(`nostr:profile`), ); - app_notify.set(`${$ls(`notification.init.on_complete`)}`); + if (configuration_result && `pass` in configuration_result) + app_notify.set(`${$ls(`notification.init.on_complete`)}`); } catch (e) { await handle_err(e, `submit`); } finally { diff --git a/app/tailwind.config.ts b/app/tailwind.config.ts @@ -9,7 +9,7 @@ const heights_responsive: Record<AppHeightsResponsiveIOS, string> = { nav_tabs_ios0: `80px`, nav_tabs_ios1: `120px`, nav_page_toolbar_ios0: `72px`, - nav_page_toolbar_ios1: `54px`, + nav_page_toolbar_ios1: `160px`, nav_page_header_ios0: `62px`, nav_page_header_ios1: `54px`, lo_bottom_button_ios0: `90px`, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml @@ -206,6 +206,9 @@ importers: '@radroots/locales': specifier: workspace:* version: link:../locales + '@radroots/nostr-util': + specifier: workspace:* + version: link:../nostr-util '@radroots/theme': specifier: workspace:* version: link:../theme diff --git a/turbo.json b/turbo.json @@ -1,5 +1,5 @@ { - "$schema": "https://turbo.build/schema.json", + "$schema": "./node_modules/turbo/schema.json", "ui": "tui", "globalEnv": [], "tasks": {