app

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

commit d09bbf957567a49a33a36d468a4c05d2c65b30b4
parent e2404b61557a9a8d358c4d5a1f15a04ec6aeb1cb
Author: triesap <triesap@radroots.dev>
Date:   Thu, 22 Jan 2026 22:45:14 +0000

app: refresh setup intro view

- add logo circle component for setup intro
- restructure intro layout into full-height sections
- wire intro tap to home navigation
- add app-view enter animation utilities

Diffstat:
Mapp/app.css | 34++++++++++++++++++++++++++++++++++
Mapp/package.json | 5+++--
Mapp/src/app.rs | 108++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Acrates/ui-tokens/assets/themes/theme_os_daisyui.css | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 200 insertions(+), 30 deletions(-)

diff --git a/app/app.css b/app/app.css @@ -4,6 +4,7 @@ @import "../crates/ui-tokens/assets/themes/layout.css"; @import "../crates/ui-tokens/assets/themes/screens.css"; @import "../crates/ui-tokens/assets/themes/theme_os.css"; +@import "../crates/ui-tokens/assets/themes/theme_os_daisyui.css"; @import "./stylesheets/daisyui.css"; @import "./stylesheets/apps-base.css"; @import "./stylesheets/apps-ui.css"; @@ -15,6 +16,10 @@ @source "./src/**/*.rs"; @source "../crates/**/*.rs"; +@plugin "daisyui" { + themes: os_light, os_dark; +} + @theme { --font-sans: "SF Pro Rounded", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --font-sansd: "SF Pro Display", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; @@ -114,6 +119,20 @@ } @layer components { + .app-view { + will-change: transform, opacity; + } + + .app-view-enter { + animation: app-view-enter 360ms var(--ease-ios) both; + } + + @media (prefers-reduced-motion: reduce) { + .app-view-enter { + animation: none; + } + } + .ui-surface { background: var(--bg-elevated); color: var(--text-primary); @@ -240,3 +259,18 @@ opacity: 0; } } + +@keyframes app-view-enter { + 0% { + opacity: 0; + transform: translateY(10px) scale(0.98); + } + 60% { + opacity: 1; + transform: translateY(-2px) scale(1.005); + } + 100% { + opacity: 1; + transform: translateY(0) scale(1); + } +} diff --git a/app/package.json b/app/package.json @@ -2,6 +2,6 @@ "name": "radroots-app", "private": true, "devDependencies": { - "daisyui": "^4.12.0" + "daisyui": "^5.5.14" } -} +} +\ No newline at end of file diff --git a/app/src/app.rs b/app/src/app.rs @@ -187,6 +187,22 @@ fn SplashPage() -> impl IntoView { } #[component] +fn LogoCircle() -> impl IntoView { + view! { + <div class="relative flex flex-col h-[196px] w-full justify-center items-center"> + <div class="relative flex flex-row h-36 w-36 justify-center items-center bg-ly2 rounded-full"> + <p class="font-sans font-[900] text-6xl text-ly0-gl -tracking-[0.4rem] -translate-x-[6px]"> + "\u{00BB}`," + </p> + <p class="font-sans font-[900] text-6xl text-ly0-gl translate-x-[8px]"> + "-" + </p> + </div> + </div> + } +} + +#[component] fn SetupPage() -> impl IntoView { let context = app_context(); let fallback_setup_required = RwSignal::new_local(None::<bool>); @@ -196,6 +212,7 @@ fn SetupPage() -> impl IntoView { .unwrap_or(fallback_setup_required); let navigate = use_navigate(); let navigate_guard = navigate.clone(); + let navigate_home = navigate.clone(); let setup_step = RwSignal::new_local(app_setup_step_default()); let key_choice_list = RadrootsAppUiList { id: Some("setup-key-choice".to_string()), @@ -263,36 +280,71 @@ fn SetupPage() -> impl IntoView { }); }; view! { - <main id="app-setup" data-app-scroll class="min-h-[100dvh] w-full px-6 pt-10 pb-16"> + <main + id="app-setup" + data-app-scroll + class="min-h-[100dvh] h-[100dvh] w-full flex flex-col" + > {move || match setup_step.get() { - RadrootsAppSetupStep::Intro => view! { - <section id="app-setup-intro" class="flex flex-col w-full gap-6"> - <header class="flex flex-col gap-3"> - <p class="font-sans text-sm uppercase tracking-[0.14em] text-ly0-gl-label"> - "Radroots" - </p> - <h1 class="font-sans font-[600] text-3xl text-ly0-gl"> - "Welcome to Radroots" - </h1> - <p class="font-sans text-line_d_e text-ly0-gl-label"> - "Set up your key and preferences to get started." - </p> - </header> - <div class="flex flex-col gap-3"> - <button - type="button" - class="button-submit rounded-touch px-6 py-3" - on:click=advance_step - > - <span class="font-sans font-[600] text-ly2-gl"> - "Get started" - </span> - </button> - </div> - </section> - }.into_any(), + RadrootsAppSetupStep::Intro => { + let navigate_home = navigate_home.clone(); + view! { + <section + id="app-setup-intro" + class="app-view app-view-enter relative flex flex-col h-[100dvh] w-full justify-start items-center" + > + <div class="flex flex-col h-full w-full justify-start items-center"> + <div class="relative flex flex-col h-full w-full justify-center items-center"> + <div class="flex flex-row w-full justify-start items-center -translate-y-16"> + <button + type="button" + class="flex flex-row w-full justify-center items-center" + on:click=move |_| navigate_home("/", Default::default()) + > + <LogoCircle /> + </button> + </div> + <div class="absolute bottom-0 left-0 flex flex-col h-[20rem] w-full px-10 gap-2 justify-start items-center"> + <div class="flex flex-row w-full justify-start items-center"> + <p class="font-sans font-[400] text-sm uppercase text-ly0-gl-label"> + "Configure" + </p> + </div> + <div class="flex flex-col w-full gap-2 justify-start items-center"> + <div class="flex flex-row w-full justify-start items-center"> + <p class="font-mono font-[400] text-[1.1rem] text-ly0-gl"> + "Welcome to Radroots!" + </p> + </div> + <div class="flex flex-row w-full justify-start items-center"> + <p class="font-mono font-[400] text-[1.1rem] text-ly0-gl"> + "Your device will be configured by the setup wizard." + </p> + </div> + </div> + </div> + </div> + </div> + <div class="z-10 absolute bottom-10 left-0 flex flex-col w-full justify-center items-center"> + <button + type="button" + class="button-submit rounded-touch px-6 py-3" + on:click=advance_step + > + <span class="font-sans font-[600] text-ly2-gl"> + "Get started" + </span> + </button> + </div> + </section> + } + .into_any() + }, RadrootsAppSetupStep::KeyChoice => view! { - <section id="app-setup-key-choice" class="flex flex-col w-full gap-4"> + <section + id="app-setup-key-choice" + class="app-view app-view-enter flex flex-col w-full gap-4 px-6 pt-10 pb-16" + > <header class="flex flex-col gap-2"> <p class="font-sans text-sm uppercase tracking-[0.14em] text-ly0-gl-label"> "Setup" diff --git a/crates/ui-tokens/assets/themes/theme_os_daisyui.css b/crates/ui-tokens/assets/themes/theme_os_daisyui.css @@ -0,0 +1,83 @@ +@plugin "daisyui/theme" { + name: "os_dark"; + default: false; + prefersdark: true; + color-scheme: dark; + --color-ly0: hsl(0, 0%, 7%); + --color-ly0-w: hsl(0, 0%, 7%); + --color-ly0-a: hsl(240, 2%, 23%); + --color-ly0-edge: hsl(274, 4%, 11%); + --color-ly0-blur: hsl(0, 0%, 12%); + --color-ly0-gl: hsl(230, 3%, 56%); + --color-ly0-gl-a: hsl(230, 3%, 51%); + --color-ly0-gl-pl: hsl(30, 1%, 99%); + --color-ly0-gl-hl: hsl(210, 100%, 52%); + --color-ly0-gl-hl-a: hsl(210, 91%, 21%); + --color-ly0-gl-shade: hsl(240, 3%, 57%); + --color-ly0-gl-label: hsl(240, 3%, 55%); + --color-ly1: hsl(240, 4%, 11%); + --color-ly1-a: hsl(240, 2%, 23%); + --color-ly1-edge: hsl(240, 3%, 19%); + --color-ly1-err: hsl(0, 0%, 0%); + --color-ly1-focus: hsl(240, 4%, 20%); + --color-ly1-gl: hsl(30, 100%, 100%); + --color-ly1-gl-a: hsl(30, 1%, 90%); + --color-ly1-gl-d: hsl(240, 1%, 82%); + --color-ly1-gl-pl: hsl(30, 1%, 99%); + --color-ly1-gl-hl: hsl(210, 100%, 52%); + --color-ly1-gl-hl-a: hsl(210, 100%, 62%); + --color-ly1-gl-shade: hsl(230, 4%, 61%); + --color-ly1-gl-label: hsl(30, 1%, 99%); + --color-ly2: hsl(240, 2%, 18%); + --color-ly2-a: hsl(240, 3%, 15%); + --color-ly2-edge: hsl(240, 2%, 23%); + --color-ly2-gl: hsl(240, 3%, 73%); + --color-ly2-gl-a: hsl(230, 4%, 51%); + --color-ly2-gl-d: hsl(240, 3%, 63%); + --color-ly2-gl-pl: hsl(240, 2%, 40%); + --color-ly2-gl-hl: hsl(210, 100%, 52%); + --color-ly2-gl-hl-a: hsl(210, 100%, 42%); + --color-ly2-gl-shade: hsl(230, 4%, 61%); +} + +@plugin "daisyui/theme" { + name: "os_light"; + default: false; + prefersdark: false; + color-scheme: light; + --color-ly0: hsl(240, 24%, 96%); + --color-ly0-w: hsl(248, 17%, 98%); + --color-ly0-a: hsl(240, 6%, 83%); + --color-ly0-edge: hsl(0, 0%, 87%); + --color-ly0-blur: hsl(179, 7%, 96%); + --color-ly0-gl: hsl(240, 2%, 55%); + --color-ly0-gl-a: hsl(240, 2%, 60%); + --color-ly0-gl-pl: hsl(240, 2%, 78%); + --color-ly0-gl-hl: hsl(219, 92%, 59%); + --color-ly0-gl-hl-a: hsl(211, 100%, 40%); + --color-ly0-gl-shade: hsl(230, 3%, 54%); + --color-ly0-gl-label: hsl(240, 2%, 53%); + --color-ly1: hsl(0, 0%, 100%); + --color-ly1-a: hsl(240, 6%, 83%); + --color-ly1-edge: hsl(274, 4%, 90%); + --color-ly1-err: hsl(0, 0%, 0%); + --color-ly1-focus: hsl(240, 15%, 94%); + --color-ly1-gl: hsl(0, 0%, 10%); + --color-ly1-gl-a: hsl(0, 0%, 10%); + --color-ly1-gl-d: hsl(0, 0%, 20%); + --color-ly1-gl-pl: hsl(240, 2%, 78%); + --color-ly1-gl-hl: hsl(211, 100%, 50%); + --color-ly1-gl-hl-a: hsl(211, 100%, 40%); + --color-ly1-gl-shade: hsl(240, 2%, 55%); + --color-ly1-gl-label: hsl(240, 2%, 53%); + --color-ly2: hsl(240, 5%, 90%); + --color-ly2-a: hsl(240, 5%, 95%); + --color-ly2-edge: hsl(242, 2%, 88%); + --color-ly2-gl: hsl(240, 2%, 55%); + --color-ly2-gl-a: hsl(240, 2%, 45%); + --color-ly2-gl-d: hsl(240, 2%, 65%); + --color-ly2-gl-pl: hsl(240, 2%, 78%); + --color-ly2-gl-hl: hsl(211, 100%, 50%); + --color-ly2-gl-hl-a: hsl(211, 100%, 40%); + --color-ly2-gl-shade: hsl(240, 2%, 55%); +}