From 212a0f23bc894faf88e159560c113f504349cc05 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Tue, 29 Apr 2025 17:06:23 +0200 Subject: comiles again but still many logic holes --- ui/src/account/mod.rs | 83 ++++++++++++++++++++++++++++++++++++++++- ui/src/account/settings.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++++ ui/src/admin/log.rs | 10 +++++ ui/src/lib.rs | 1 - ui/src/settings.rs | 82 ----------------------------------------- ui/src/stats.rs | 16 +++++--- 6 files changed, 193 insertions(+), 91 deletions(-) create mode 100644 ui/src/account/settings.rs delete mode 100644 ui/src/settings.rs (limited to 'ui') diff --git a/ui/src/account/mod.rs b/ui/src/account/mod.rs index bc8d3ce..36a41c5 100644 --- a/ui/src/account/mod.rs +++ b/ui/src/account/mod.rs @@ -3,8 +3,55 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2025 metamuffin */ -use crate::locale::{Language, tr, trs}; -use jellycommon::routes::u_account_login; +pub mod settings; + +use crate::{ + Page, + locale::{Language, tr, trs}, +}; +use jellycommon::routes::{u_account_login, u_account_register}; + +impl Page for AccountLogin<'_> { + fn title(&self) -> String { + tr( + *self.lang, + if self.logged_in { + "account.login.switch" + } else { + "account.login" + }, + ) + .to_string() + } + + fn to_render(&self) -> markup::DynRender { + markup::new!(@self) + } +} +impl Page for AccountRegister<'_> { + fn title(&self) -> String { + tr(*self.lang, "account.register").to_string() + } + fn to_render(&self) -> markup::DynRender { + markup::new!(@self) + } +} +impl Page for AccountRegisterSuccess<'_> { + fn title(&self) -> String { + tr(*self.lang, "account.register").to_string() + } + fn to_render(&self) -> markup::DynRender { + markup::new!(@self) + } +} +impl Page for AccountLogout<'_> { + fn title(&self) -> String { + tr(*self.lang, "account.logout").to_string() + } + fn to_render(&self) -> markup::DynRender { + markup::new!(@self) + } +} markup::define! { AccountRegister<'a>(lang: &'a Language) { @@ -24,4 +71,36 @@ markup::define! { p { @trs(&lang, "account.register.login") " " a[href=u_account_login()] { @trs(&lang, "account.register.login_here") } } } } + AccountRegisterSuccess<'a>(lang: &'a Language, logged_in: bool) { + h1 { @trs(&lang, if *logged_in { + "account.register.success.switch" + } else { + "account.register.success" + })} + } + AccountLogin<'a>(lang: &'a Language, logged_in: bool) { + form.account[method="POST", action=""] { + h1 { @self.title() } + + label[for="inp-username"] { @trs(&lang, "account.username") } + input[type="text", id="inp-username", name="username"]; br; + label[for="inp-password"] { @trs(&lang, "account.password") } + input[type="password", id="inp-password", name="password"]; br; + + input[type="submit", value=&*tr(**lang, if *logged_in { "account.login.submit.switch" } else { "account.login.submit" })]; + + @if *logged_in { + p { @trs(&lang, "account.login.register.switch") " " a[href=u_account_register()] { @trs(&lang, "account.login.register_here") } } + } else { + p { @trs(&lang, "account.login.cookie_note") } + p { @trs(&lang, "account.login.register") " " a[href=u_account_register()] { @trs(&lang, "account.login.register_here") } } + } + } + } + AccountLogout<'a>(lang: &'a Language) { + form.account[method="POST", action=""] { + h1 { @trs(&lang, "account.logout") } + input[type="submit", value=&*tr(**lang, "account.logout.submit")]; + } + } } diff --git a/ui/src/account/settings.rs b/ui/src/account/settings.rs new file mode 100644 index 0000000..7c5a3b8 --- /dev/null +++ b/ui/src/account/settings.rs @@ -0,0 +1,92 @@ +/* + This file is part of jellything (https://codeberg.org/metamuffin/jellything) + which is licensed under the GNU Affero General Public License (version 3); see /COPYING. + Copyright (C) 2025 metamuffin +*/ +use crate::{ + Page, + locale::{Language, tr, trs}, + scaffold::SessionInfo, +}; +use jellycommon::{ + routes::{u_account_login, u_account_settings}, + user::{PlayerKind, Theme}, +}; +use markup::RenderAttributeValue; + +impl Page for SettingsPage<'_> { + fn title(&self) -> String { + format!("Settings") + } + fn to_render(&self) -> markup::DynRender { + markup::new!(@self) + } +} + +markup::define! { + SettingsPage<'a>(flash: Option>, session: &'a SessionInfo, lang: &'a Language) { + h1 { "Settings" } + @if let Some(flash) = &flash { + @match flash { + Ok(mesg) => { section.message { p.success { @mesg } } } + Err(err) => { section.message { p.error { @format!("{err}") } } } + } + } + h2 { @trs(&lang, "account") } + a.switch_account[href=u_account_login()] { "Switch Account" } + form[method="POST", action=u_account_settings()] { + label[for="username"] { @trs(&lang, "account.username") } + input[type="text", id="username", disabled, value=&session.user.name]; + input[type="submit", disabled, value=&*tr(**lang, "settings.immutable")]; + } + form[method="POST", action=u_account_settings()] { + label[for="display_name"] { @trs(lang, "account.display_name") } + input[type="text", id="display_name", name="display_name", value=&session.user.display_name]; + input[type="submit", value=&*tr(**lang, "settings.update")]; + } + form[method="POST", action=u_account_settings()] { + label[for="password"] { @trs(lang, "account.password") } + input[type="password", id="password", name="password"]; + input[type="submit", value=&*tr(**lang, "settings.update")]; + } + h2 { @trs(&lang, "settings.appearance") } + form[method="POST", action=u_account_settings()] { + fieldset { + legend { @trs(&lang, "settings.appearance.theme") } + @for theme in Theme::ALL { + label { input[type="radio", name="theme", value=A(*theme), checked=session.user.theme==*theme]; @trs(lang, &format!("theme.{theme}")) } br; + } + } + input[type="submit", value=&*tr(**lang, "settings.apply")]; + } + form[method="POST", action=u_account_settings()] { + fieldset { + legend { @trs(&lang, "settings.player_preference") } + @for kind in PlayerKind::ALL { + label { input[type="radio", name="player_preference", value=A(*kind), checked=session.user.player_preference==*kind]; @trs(lang, &format!("player_kind.{kind}")) } br; + } + } + input[type="submit", value=&*tr(**lang, "settings.apply")]; + } + form[method="POST", action=u_account_settings()] { + label[for="native_secret"] { "Native Secret" } + input[type="password", id="native_secret", name="native_secret"]; + input[type="submit", value=&*tr(**lang, "settings.update")]; + p { "The secret can be found in " code{"$XDG_CONFIG_HOME/jellynative_secret"} " or by clicking " a.button[href="jellynative://show-secret-v1"] { "Show Secret" } "." } + } + } +} + +struct A(pub T); +impl markup::Render for A { + fn render(&self, writer: &mut impl std::fmt::Write) -> std::fmt::Result { + writer.write_str(self.0.to_str()) + } +} +impl markup::Render for A { + fn render(&self, writer: &mut impl std::fmt::Write) -> std::fmt::Result { + writer.write_str(self.0.to_str()) + } +} +impl RenderAttributeValue for A {} +impl RenderAttributeValue for A {} diff --git a/ui/src/admin/log.rs b/ui/src/admin/log.rs index a69bdfa..3669571 100644 --- a/ui/src/admin/log.rs +++ b/ui/src/admin/log.rs @@ -4,6 +4,7 @@ Copyright (C) 2025 metamuffin */ +use crate::Page; use jellycommon::{ api::{LogLevel, LogLine}, routes::u_admin_log, @@ -11,6 +12,15 @@ use jellycommon::{ use markup::raw; use std::fmt::Write; +impl Page for ServerLogPage<'_> { + fn title(&self) -> String { + "Server Log".to_string() + } + fn to_render(&self) -> markup::DynRender { + markup::new!(@self) + } +} + markup::define! { ServerLogPage<'a>(warnonly: bool, messages: &'a [String]) { h1 { "Server Log" } diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 8a4b950..4f1901a 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -12,7 +12,6 @@ pub mod node_page; pub mod props; pub mod scaffold; pub mod search; -pub mod settings; pub mod stats; pub mod items; pub mod admin; diff --git a/ui/src/settings.rs b/ui/src/settings.rs deleted file mode 100644 index 5ff3946..0000000 --- a/ui/src/settings.rs +++ /dev/null @@ -1,82 +0,0 @@ -/* - This file is part of jellything (https://codeberg.org/metamuffin/jellything) - which is licensed under the GNU Affero General Public License (version 3); see /COPYING. - Copyright (C) 2025 metamuffin -*/ -use crate::{ - locale::{Language, tr, trs}, - scaffold::SessionInfo, -}; -use jellycommon::{ - routes::{u_account_login, u_account_settings}, - user::{PlayerKind, Theme}, -}; -use markup::RenderAttributeValue; - -markup::define! { - Settings<'a>(flash: Option>, session: &'a SessionInfo, lang: &'a Language) { - h1 { "Settings" } - @if let Some(flash) = &flash { - @match flash { - Ok(mesg) => { section.message { p.success { @mesg } } } - Err(err) => { section.message { p.error { @format!("{err}") } } } - } - } - h2 { @trs(&lang, "account") } - a.switch_account[href=u_account_login()] { "Switch Account" } - form[method="POST", action=u_account_settings()] { - label[for="username"] { @trs(&lang, "account.username") } - input[type="text", id="username", disabled, value=&session.user.name]; - input[type="submit", disabled, value=&*tr(**lang, "settings.immutable")]; - } - form[method="POST", action=u_account_settings()] { - label[for="display_name"] { @trs(lang, "account.display_name") } - input[type="text", id="display_name", name="display_name", value=&session.user.display_name]; - input[type="submit", value=&*tr(**lang, "settings.update")]; - } - form[method="POST", action=u_account_settings()] { - label[for="password"] { @trs(lang, "account.password") } - input[type="password", id="password", name="password"]; - input[type="submit", value=&*tr(**lang, "settings.update")]; - } - h2 { @trs(&lang, "settings.appearance") } - form[method="POST", action=u_account_settings()] { - fieldset { - legend { @trs(&lang, "settings.appearance.theme") } - @for theme in Theme::ALL { - label { input[type="radio", name="theme", value=A(*theme), checked=session.user.theme==*theme]; @trs(lang, &format!("theme.{theme}")) } br; - } - } - input[type="submit", value=&*tr(**lang, "settings.apply")]; - } - form[method="POST", action=u_account_settings()] { - fieldset { - legend { @trs(&lang, "settings.player_preference") } - @for kind in PlayerKind::ALL { - label { input[type="radio", name="player_preference", value=A(*kind), checked=session.user.player_preference==*kind]; @trs(lang, &format!("player_kind.{kind}")) } br; - } - } - input[type="submit", value=&*tr(**lang, "settings.apply")]; - } - form[method="POST", action=u_account_settings()] { - label[for="native_secret"] { "Native Secret" } - input[type="password", id="native_secret", name="native_secret"]; - input[type="submit", value=&*tr(**lang, "settings.update")]; - p { "The secret can be found in " code{"$XDG_CONFIG_HOME/jellynative_secret"} " or by clicking " a.button[href="jellynative://show-secret-v1"] { "Show Secret" } "." } - } - } -} - -struct A(pub T); -impl markup::Render for A { - fn render(&self, writer: &mut impl std::fmt::Write) -> std::fmt::Result { - writer.write_str(self.0.to_str()) - } -} -impl markup::Render for A { - fn render(&self, writer: &mut impl std::fmt::Write) -> std::fmt::Result { - writer.write_str(self.0.to_str()) - } -} -impl RenderAttributeValue for A {} -impl RenderAttributeValue for A {} diff --git a/ui/src/stats.rs b/ui/src/stats.rs index c3e5a14..11163f3 100644 --- a/ui/src/stats.rs +++ b/ui/src/stats.rs @@ -5,6 +5,7 @@ */ use crate::{ + Page, format::{format_duration, format_duration_long, format_kind, format_size}, locale::{Language, tr, trs}, }; @@ -14,6 +15,15 @@ use jellycommon::{ }; use markup::raw; +impl Page for StatsPage<'_> { + fn title(&self) -> String { + tr(*self.lang, "stats.title").to_string() + } + fn to_render(&self) -> markup::DynRender { + markup::new!(@self) + } +} + markup::define! { StatsPage<'a>(lang: &'a Language, r: ApiStatsResponse) { .page.stats { @@ -57,12 +67,6 @@ markup::define! { } } -impl StatsPage<'_> { - pub fn title(&self) -> String { - tr(*self.lang, "stats.title").to_string() - } -} - trait BinExt { fn average_runtime(&self) -> f64; fn average_size(&self) -> f64; -- cgit v1.2.3-70-g09d2