commit 6738b56595c2154f0fcd70949ed0e14b00d95173
parent 7d56546a9d66db6ca73edf28458ef2919003677c
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:
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": {