app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 9a7ec91ced32de23d7db1a9925c63bf6d9820be7
parent 53a7515db0d03d5bdfcea73203a576ac3da0c24d
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Fri,  6 Dec 2024 06:02:22 +0000

Add `/settings/profile`, edit `/settings/nostr`. Add image upload add photo component. Edit home page. Add/edit styles.

Diffstat:
Asrc/lib/components/image_upload_add_photo.svelte | 42++++++++++++++++++++++++++++++++++++++++++
Msrc/routes/(app)/+page.svelte | 30++++++++++++++++++++++++++++--
Msrc/routes/(app)/settings/nostr/+page.svelte | 2+-
Asrc/routes/(app)/settings/profile/+page.svelte | 232+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/routes/(cfg)/cfg/init/+page.svelte | 2+-
Mtailwind.config.ts | 1+
6 files changed, 305 insertions(+), 4 deletions(-)

diff --git a/src/lib/components/image_upload_add_photo.svelte b/src/lib/components/image_upload_add_photo.svelte @@ -0,0 +1,42 @@ +<script lang="ts"> + import { dialog } from "$lib/client"; + import { Glyph, t } from "@radroots/svelte-lib"; + + export let photo_path: string; + + const handle_photo_add = async (): Promise<void> => { + try { + const photo_paths_open = await dialog.open_photos(); + if (!photo_paths_open) return; + photo_path = photo_paths_open.results[0]; + } catch (e) { + console.log(`(error) handle_photo_add `, e); + } + }; +</script> + +<div class={`relative flex flex-row w-full justify-center items-center`}> + <button + class={`flex flex-row h-[5rem] w-[5rem] justify-center items-center bg-layer-0-surface/80 rounded-full`} + on:click={async () => { + await handle_photo_add(); + }} + > + <Glyph + basis={{ + classes: `text-[40px] text-layer-2-glyph`, + dim: `sm`, + key: `camera`, + }} + /> + <div + class={`absolute -bottom-[1.8rem] flex flex-row justify-start items-center`} + > + <p + class={`font-arch font-[600] text-sm text-layer-0-glyph capitalize`} + > + {`${$t(`icu.add_*`, { value: `${$t(`common.photo`)}` })}`} + </p> + </div> + </button> +</div> diff --git a/src/routes/(app)/+page.svelte b/src/routes/(app)/+page.svelte @@ -8,9 +8,12 @@ LayoutView, nav_prev, route, + t, } from "@radroots/svelte-lib"; import { onMount } from "svelte"; + $: device_metadata = device.metadata ? device.metadata.version : ``; + onMount(async () => { try { nav_prev.set([]); @@ -34,11 +37,11 @@ <p class={`font-mono font-[600] text-[1.3rem] text-layer-0-glyph`}> {`radRoots`} </p> - {#if device.metadata?.version} + {#if device_metadata} <p class={`font-mono font-[400] text-[1.3rem] text-layer-0-glyph`} > - {`/${device.metadata.version}`} + {`/${device_metadata}`} </p> {/if} </div> @@ -58,6 +61,29 @@ /> </button> </div> + <div + class={`flex flex-col w-full pt-2 px-6 gap-2 justify-center items-center`} + > + <div class={`flex flex-row w-full justify-start items-center`}> + <p class={`font-sans font-[600] text-2xl text-layer-0-glyph`}> + {`${$t(`common.general`)}`} + </p> + </div> + <div class={`flex flex-col w-full gap-5 justify-center items-center`}> + <button + class={`group flex flex-row h-[3.5rem] w-full justify-center items-center rounded-touch bg-layer-1-surface layer-1-active-surface layer-1-active-ring`} + on:click={async () => { + await route(`/settings/profile`); + }} + > + <p + class={`font-sans font-[600] text-xl text-layer-0-glyph capitalize tracking-wider opacity-active`} + > + {`${$t(`common.profile`)}`} + </p> + </button> + </div> + </div> </LayoutView> <EnvelopeLower basis={{ diff --git a/src/routes/(app)/settings/nostr/+page.svelte b/src/routes/(app)/settings/nostr/+page.svelte @@ -129,7 +129,7 @@ <Nav basis={{ prev: { - label: `Settings`, + label: `${$t(`common.settings`)}`, route: `/settings`, }, title: { diff --git a/src/routes/(app)/settings/profile/+page.svelte b/src/routes/(app)/settings/profile/+page.svelte @@ -0,0 +1,232 @@ +<script lang="ts"> + import { db, fs } from "$lib/client"; + import ImageUploadAddPhoto from "$lib/components/image_upload_add_photo.svelte"; + import { ascii } from "$lib/conf"; + import { kv_init_page } from "$lib/util/kv"; + import type { NostrProfile } from "@radroots/models"; + import { + app_nostr_key, + Glyph, + ImageBlob, + LayoutView, + Nav, + t, + } from "@radroots/svelte-lib"; + import { onMount } from "svelte"; + + type LoadData = { + nostr_profile: NostrProfile; + }; + let ld: LoadData | undefined = undefined; + + let opt_photo_path = ``; + let opt_display: `photos` | `following` | `followers` = `photos`; + + onMount(async () => { + try { + await init_page(); + } catch (e) { + } finally { + } + }); + + $: photo_overlay_visible = ld?.nostr_profile?.picture || opt_photo_path; + $: classes_photo_overlay_wrap = photo_overlay_visible + ? `bg-white/30 backdrop-blur-sm` + : ``; + $: classes_photo_overlay_glyph = photo_overlay_visible + ? `text-white` + : `text-layer-0-glyph`; + + $: classes_photo_overlay_glyph_d = photo_overlay_visible + ? `text-white/40` + : `text-layer-0-glyph`; + const init_page = async (): Promise<void> => { + try { + await kv_init_page(); + ld = await load_data(); + } catch (e) { + console.log(`(error) init_page `, e); + } + }; + + const load_data = async (): Promise<LoadData | undefined> => { + try { + let nostr_profile_get_one = await db.nostr_profile_get_one({ + public_key: $app_nostr_key, + }); + if (`err` in nostr_profile_get_one) return; + + const load: LoadData = { + nostr_profile: nostr_profile_get_one.result, + }; + return load; + } catch (e) { + console.log(`(error) load_data `, e); + } + }; +</script> + +<LayoutView> + <div + class={`relative flex flex-col min-h-[525px] h-[525px] w-full justify-center items-center bg-layer-2-surface`} + > + {#if opt_photo_path} + {#await fs.read_bin(opt_photo_path) then file_data} + <ImageBlob + basis={{ + data: file_data, + }} + /> + {/await} + {:else} + <div + class={`flex flex-row justify-start items-center -translate-y-8`} + > + <ImageUploadAddPhoto bind:photo_path={opt_photo_path} /> + </div> + {/if} + <div + class={`absolute bottom-0 left-0 flex flex-col h-[calc(100%-100%/1.618)] w-full px-6 gap-2 justify-end items-center ${classes_photo_overlay_wrap}`} + > + <div + class={`flex flex-col w-full gap-[2px] justify-center items-center`} + > + <div + class={`flex flex-row h-10 w-full justify-start items-center`} + > + <button + class={`group flex flex-row justify-center items-center`} + on:click={async () => {}} + > + <p + class={`font-sansd font-[600] text-[1.7rem] ${classes_photo_overlay_glyph} ${ld?.nostr_profile.display_name ? `` : `capitalize opacity-active`} el-re`} + > + {ld?.nostr_profile.display_name + ? ld.nostr_profile.display_name + : `+ ${`${$t(`icu.add_*`, { value: `${$t(`common.profile_name`)}` })}`}`} + </p> + </button> + </div> + <div + class={`flex flex-row w-full gap-[6px] justify-start items-center`} + > + <button + class={`group flex flex-row justify-center items-center`} + on:click={async () => {}} + > + <p + class={`font-sans font-[600] text-[1.1rem] ${classes_photo_overlay_glyph} ${ld?.nostr_profile.name ? `` : `capitalize opacity-active`} el-re`} + > + {ld?.nostr_profile.name + ? `@${ld.nostr_profile.name}` + : `+ ${`${$t(`icu.add_*`, { value: `${$t(`common.username`)}` })}`}`} + </p> + </button> + <p + class={`font-sans font-[400] ${classes_photo_overlay_glyph}`} + > + {ascii.bullet} + </p> + <button + class={`flex flex-row justify-center items-center`} + on:click={async () => { + alert(`@todo!`); + }} + > + <Glyph + basis={{ + classes: `${classes_photo_overlay_glyph}`, + dim: `xs`, + weight: `bold`, + key: `link-simple`, + }} + /> + </button> + </div> + <div class={`flex flex-row w-full justify-start items-center`}> + <button + class={`group flex flex-row justify-center items-center`} + on:click={async () => {}} + > + <p + class={`font-sans font-[400] text-[1.1rem] ${classes_photo_overlay_glyph} ${ld?.nostr_profile.about ? `` : `capitalize opacity-active`}`} + > + {ld?.nostr_profile.about + ? `@${ld.nostr_profile.about}` + : `+ ${`${$t(`icu.add_*`, { value: `${$t(`common.bio`)}` })}`}`} + </p> + </button> + </div> + </div> + <div + class={`flex flex-row w-full pt-2 pb-6 gap-2 justify-start items-center`} + > + <button + class={`flex flex-row justify-center items-center`} + on:click={async () => { + opt_display = `photos`; + }} + > + <p + class={`font-sans text-[1.1rem] font-[600] ${opt_display === `photos` ? `text-layer-1-glyph_d` : `text-layer-0-glyph`} el-re`} + > + {`Photos`} + </p> + </button> + <button + class={`flex flex-row justify-center items-center`} + on:click={async () => { + opt_display = `following`; + }} + > + <p + class={`font-sans text-[1.1rem] font-[600] ${opt_display === `following` ? `text-layer-1-glyph_d` : `text-layer-0-glyph`} el-re`} + > + {`Following`} + </p> + </button> + <button + class={`flex flex-row justify-center items-center`} + on:click={async () => { + opt_display = `followers`; + }} + > + <p + class={`font-sans text-[1.1rem] font-[600] ${opt_display === `followers` ? `text-layer-1-glyph_d` : `text-layer-0-glyph`} el-re`} + > + {`Followers`} + </p> + </button> + </div> + </div> + </div> + <div class={`flex flex-col w-full justify-start items-center`}> + {#if opt_display === `photos`} + <p class={`font-sans font-[400] text-layer-0-glyph`}> + {`photos `.repeat(500)} + </p> + {:else if opt_display === `following`} + <p class={`font-sans font-[400] text-layer-0-glyph`}> + {`following `.repeat(500)} + </p> + {:else if opt_display === `followers`} + <p class={`font-sans font-[400] text-layer-0-glyph`}> + {`followers `.repeat(500)} + </p> + {/if} + </div> +</LayoutView> +<Nav + basis={{ + prev: { + label: `${$t(`common.home`)}`, + route: `/`, + }, + title: { + label: { + value: `${$t(`common.profile`)}`, + }, + }, + }} +/> diff --git a/src/routes/(cfg)/cfg/init/+page.svelte b/src/routes/(cfg)/cfg/init/+page.svelte @@ -1132,7 +1132,7 @@ </p> {#if loading_submit} <div - class={`absolute right-0 flex flex-row justify-start items-center`} + class={`absolute right-2 flex flex-row justify-start items-center`} > <Loading basis={{ dim: `xs` }} /> </div> diff --git a/tailwind.config.ts b/tailwind.config.ts @@ -103,6 +103,7 @@ const config: Config = { }, fontFamily: { sans: [`SF Pro Rounded`, ...tw_font.sans], + sansd: [`SF Pro Display`], serif: [...tw_font.serif], mono: [...tw_font.mono], apercu: [`Apercu Mono Pro`],