diff options
author | metamuffin <metamuffin@disroot.org> | 2025-04-29 11:10:21 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-04-29 11:10:21 +0200 |
commit | f62c7f2a8cc143454779dc99334ca9fc80ddabd5 (patch) | |
tree | f31dbb908715d2deb2860e2097fa13dd41d759d5 /ui/src | |
parent | 73d2d5eb01fceae9e0b1c58afb648822000c878a (diff) | |
download | jellything-f62c7f2a8cc143454779dc99334ca9fc80ddabd5.tar jellything-f62c7f2a8cc143454779dc99334ca9fc80ddabd5.tar.bz2 jellything-f62c7f2a8cc143454779dc99334ca9fc80ddabd5.tar.zst |
still just moving code around
Diffstat (limited to 'ui/src')
-rw-r--r-- | ui/src/admin/mod.rs | 7 | ||||
-rw-r--r-- | ui/src/admin/user.rs | 55 | ||||
-rw-r--r-- | ui/src/home.rs | 2 | ||||
-rw-r--r-- | ui/src/items.rs | 46 | ||||
-rw-r--r-- | ui/src/lib.rs | 48 | ||||
-rw-r--r-- | ui/src/scaffold.rs | 32 | ||||
-rw-r--r-- | ui/src/settings.rs | 7 | ||||
-rw-r--r-- | ui/src/stats.rs | 9 |
8 files changed, 186 insertions, 20 deletions
diff --git a/ui/src/admin/mod.rs b/ui/src/admin/mod.rs new file mode 100644 index 0000000..292e445 --- /dev/null +++ b/ui/src/admin/mod.rs @@ -0,0 +1,7 @@ +/* + 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 <metamuffin.org> +*/ + +pub mod user; diff --git a/ui/src/admin/user.rs b/ui/src/admin/user.rs new file mode 100644 index 0000000..9878803 --- /dev/null +++ b/ui/src/admin/user.rs @@ -0,0 +1,55 @@ +/* + 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 <metamuffin.org> +*/ + +use crate::{locale::Language, scaffold::FlashDisplay}; +use jellycommon::{ + routes::{u_admin_user_permission, u_admin_user_remove, u_admin_users}, + user::{PermissionSet, User, UserPermission}, +}; + +markup::define! { + AdminUserPage<'a>(lang: &'a Language, user: &'a User, flash: Option<Result<String, String>>) { + h1 { @format!("{:?}", user.display_name) " (" @user.name ")" } + a[href=u_admin_users()] "Back to the User List" + @FlashDisplay { flash: flash.clone() } + form[method="POST", action=u_admin_user_remove(&user.name)] { + // input[type="text", name="name", value=&user.name, hidden]; + input.danger[type="submit", value="Remove user(!)"]; + } + + h2 { "Permissions" } + @PermissionDisplay { perms: &user.permissions } + + form[method="POST", action=u_admin_user_permission(&user.name)] { + // input[type="text", name="name", value=&user.name, hidden]; + fieldset.perms { + legend { "Permission" } + @for p in UserPermission::ALL_ENUMERABLE { + label { + input[type="radio", name="permission", value=serde_json::to_string(p).unwrap()]; + @format!("{p}") + } br; + } + } + fieldset.perms { + legend { "Permission" } + label { input[type="radio", name="action", value="unset"]; "Unset" } br; + label { input[type="radio", name="action", value="grant"]; "Grant" } br; + label { input[type="radio", name="action", value="revoke"]; "Revoke" } br; + } + input[type="submit", value="Update"]; + } + } + PermissionDisplay<'a>(perms: &'a PermissionSet) { + ul { @for (perm,grant) in &perms.0 { + @if *grant { + li[class="perm-grant"] { @format!("Allow {}", perm) } + } else { + li[class="perm-revoke"] { @format!("Deny {}", perm) } + } + }} + } +} diff --git a/ui/src/home.rs b/ui/src/home.rs index ec0c634..53055e8 100644 --- a/ui/src/home.rs +++ b/ui/src/home.rs @@ -12,7 +12,7 @@ use jellycommon::api::ApiHomeResponse; use markup::DynRender; markup::define! { - HomePage<'a>(lang: &'a Language, r: &'a ApiHomeResponse) { + HomePage<'a>(lang: &'a Language, r: ApiHomeResponse) { h2 { @trs(lang, "home.bin.root") } //.replace("{title}", &CONF.brand) } ul.children.hlist {@for (node, udata) in &r.toplevel { li { @NodeCard { node, udata, lang: &lang } } diff --git a/ui/src/items.rs b/ui/src/items.rs new file mode 100644 index 0000000..29bc78c --- /dev/null +++ b/ui/src/items.rs @@ -0,0 +1,46 @@ +/* + 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 <metamuffin.org> +*/ +use crate::{ + Page, + filter_sort::NodeFilterSortForm, + locale::{Language, tr, trs}, + node_card::NodeCard, +}; +use jellycommon::{ + api::{ApiItemsResponse, NodeFilterSort}, + routes::u_items_filter, +}; +use markup::DynRender; + +markup::define! { + ItemsPage<'a>(lang: &'a Language, r: ApiItemsResponse, filter: &'a NodeFilterSort, page: usize) { + .page.dir { + h1 { "All Items" } + @NodeFilterSortForm { f: &filter, lang: &lang } + ul.children { @for (node, udata) in &r.items { + li {@NodeCard { node, udata, lang: &lang }} + }} + p.pagecontrols { + span.current { @tr(**lang, "page.curr").replace("{cur}", &(page + 1).to_string()).replace("{max}", &r.pages.to_string()) " " } + @if *page > 0 { + a.prev[href=u_items_filter(page - 1, filter)] { @trs(&lang, "page.prev") } " " + } + @if page + 1 < r.pages { + a.next[href=u_items_filter(page + 1, filter)] { @trs(&lang, "page.next") } + } + } + } + } +} + +impl Page for ItemsPage<'_> { + fn title(&self) -> String { + tr(*self.lang, "home").to_string() + } + fn to_render(&self) -> DynRender { + markup::new!(@self) + } +} diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 67dc067..2521054 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -14,6 +14,34 @@ pub mod scaffold; pub mod search; pub mod settings; pub mod stats; +pub mod items; +pub mod admin; + +use locale::Language; +use markup::DynRender; +use scaffold::{RenderInfo, Scaffold}; +use serde::{Deserialize, Serialize}; +use std::{ + path::PathBuf, + sync::{LazyLock, Mutex}, +}; + +#[rustfmt::skip] +#[derive(Debug, Deserialize, Serialize, Default)] +pub struct Config { + brand: String, + slogan: String, + asset_path: PathBuf, +} + +static CONF: LazyLock<Config> = LazyLock::new(|| { + CONF_PRELOAD + .lock() + .unwrap() + .take() + .expect("cache config not preloaded. logic error") +}); +static CONF_PRELOAD: Mutex<Option<Config>> = Mutex::new(None); /// render as supertrait would be possible but is not /// dyn compatible and I really dont want to expose generics @@ -26,16 +54,26 @@ pub trait Page { } } -use markup::DynRender; -use scaffold::Scaffold; - -pub fn render_page(page: &dyn Page) -> String { +pub fn render_page(page: &dyn Page, renderinfo: RenderInfo, lang: Language) -> String { Scaffold { lang, - context, + renderinfo, class: page.class().unwrap_or("aaaa"), title: page.title(), main: page.to_render(), } .to_string() } + +pub struct CustomPage { + pub title: String, + pub body: String, +} +impl Page for CustomPage { + fn title(&self) -> String { + self.title.clone() + } + fn to_render(&self) -> DynRender { + markup::new!(@markup::raw(&self.body)) + } +} diff --git a/ui/src/scaffold.rs b/ui/src/scaffold.rs index bcff54c..461a9f1 100644 --- a/ui/src/scaffold.rs +++ b/ui/src/scaffold.rs @@ -4,18 +4,32 @@ Copyright (C) 2025 metamuffin <metamuffin.org> */ -use crate::locale::{Language, escape, tr, trs}; -use jellycommon::routes::{ - u_account_login, u_account_logout, u_account_register, u_account_settings, u_admin_dashboard, - u_home, u_items, u_node_slug, u_search, u_stats, +use crate::{ + CONF, + locale::{Language, escape, tr, trs}, +}; +use jellycommon::{ + routes::{ + u_account_login, u_account_logout, u_account_register, u_account_settings, + u_admin_dashboard, u_home, u_items, u_node_slug, u_search, u_stats, + }, + user::User, }; use markup::{Render, raw}; use std::sync::LazyLock; static LOGO_ENABLED: LazyLock<bool> = LazyLock::new(|| CONF.asset_path.join("logo.svg").exists()); +pub struct RenderInfo { + pub session: Option<SessionInfo>, + pub importing: bool, +} +pub struct SessionInfo { + pub user: User, +} + markup::define! { - Scaffold<'a, Main: Render>(title: String, main: Main, class: &'a str, session: Option<Session>, lang: Language) { + Scaffold<'a, Main: Render>(title: String, main: Main, class: &'a str, renderinfo: RenderInfo, lang: Language) { @markup::doctype() html { head { @@ -26,16 +40,16 @@ markup::define! { } body[class=class] { nav { - h1 { a[href=if session.is_some() {u_home()} else {"/".to_string()}] { @if *LOGO_ENABLED { img.logo[src="/assets/logo.svg"]; } else { @CONF.brand } } } " " - @if let Some(_) = session { + h1 { a[href=if renderinfo.session.is_some() {u_home()} else {"/".to_string()}] { @if *LOGO_ENABLED { img.logo[src="/assets/logo.svg"]; } else { @CONF.brand } } } " " + @if let Some(_) = &renderinfo.session { a.library[href=u_node_slug("library")] { @trs(lang, "nav.root") } " " a.library[href=u_items()] { @trs(lang, "nav.all") } " " a.library[href=u_search()] { @trs(lang, "nav.search") } " " a.library[href=u_stats()] { @trs(lang, "nav.stats") } " " + @if renderinfo.importing { span.warn { "Library database is updating..." } } } - @if is_importing() { span.warn { "Library database is updating..." } } div.account { - @if let Some(session) = session { + @if let Some(session) = &renderinfo.session { span { @raw(tr(*lang, "nav.username").replace("{name}", &format!("<b class=\"username\">{}</b>", escape(&session.user.display_name)))) } " " @if session.user.admin { a.admin.hybrid_button[href=u_admin_dashboard()] { p {@trs(lang, "nav.admin")} } " " diff --git a/ui/src/settings.rs b/ui/src/settings.rs index fb4ef0f..5ff3946 100644 --- a/ui/src/settings.rs +++ b/ui/src/settings.rs @@ -3,7 +3,10 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2025 metamuffin <metamuffin.org> */ -use crate::locale::{Language, tr, trs}; +use crate::{ + locale::{Language, tr, trs}, + scaffold::SessionInfo, +}; use jellycommon::{ routes::{u_account_login, u_account_settings}, user::{PlayerKind, Theme}, @@ -11,7 +14,7 @@ use jellycommon::{ use markup::RenderAttributeValue; markup::define! { - Settings<'a>(flash: Option<Result<String, String>>, lang: &'a Language) { + Settings<'a>(flash: Option<Result<String, String>>, session: &'a SessionInfo, lang: &'a Language) { h1 { "Settings" } @if let Some(flash) = &flash { @match flash { diff --git a/ui/src/stats.rs b/ui/src/stats.rs index 3655245..c3e5a14 100644 --- a/ui/src/stats.rs +++ b/ui/src/stats.rs @@ -8,7 +8,10 @@ use crate::{ format::{format_duration, format_duration_long, format_kind, format_size}, locale::{Language, tr, trs}, }; -use jellycommon::api::{ApiStatsResponse, StatsBin}; +use jellycommon::{ + api::{ApiStatsResponse, StatsBin}, + routes::u_node_slug, +}; use markup::raw; markup::define! { @@ -46,8 +49,8 @@ markup::define! { td { @format_duration(b.runtime) } td { @format_size(b.average_size() as u64) } td { @format_duration(b.average_runtime()) } - td { @if b.max_size.0 > 0 { a[href=uri!(r_library_node(&b.max_size.1))]{ @format_size(b.max_size.0) }}} - td { @if b.max_runtime.0 > 0. { a[href=uri!(r_library_node(&b.max_runtime.1))]{ @format_duration(b.max_runtime.0) }}} + td { @if b.max_size.0 > 0 { a[href=u_node_slug(&b.max_size.1)]{ @format_size(b.max_size.0) }}} + td { @if b.max_runtime.0 > 0. { a[href=u_node_slug(&b.max_runtime.1)]{ @format_duration(b.max_runtime.0) }}} }} } } |