aboutsummaryrefslogtreecommitdiff
path: root/ui/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'ui/src/components')
-rw-r--r--ui/src/components/admin.rs37
-rw-r--r--ui/src/components/admin_log.rs6
-rw-r--r--ui/src/components/home.rs38
-rw-r--r--ui/src/components/items.rs22
-rw-r--r--ui/src/components/login.rs15
-rw-r--r--ui/src/components/message.rs6
-rw-r--r--ui/src/components/mod.rs61
-rw-r--r--ui/src/components/node_card.rs18
-rw-r--r--ui/src/components/node_list.rs47
-rw-r--r--ui/src/components/node_page.rs29
-rw-r--r--ui/src/components/props.rs9
-rw-r--r--ui/src/components/stats.rs36
-rw-r--r--ui/src/components/user.rs7
13 files changed, 153 insertions, 178 deletions
diff --git a/ui/src/components/admin.rs b/ui/src/components/admin.rs
index 3cb45d6..76dfe6a 100644
--- a/ui/src/components/admin.rs
+++ b/ui/src/components/admin.rs
@@ -4,9 +4,8 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
-use crate::RenderInfo;
+use crate::{RenderInfo, page};
use jellycommon::{
- jellyobject::Object,
routes::{
u_admin_import, u_admin_import_post, u_admin_log, u_admin_new_user, u_admin_user,
u_admin_user_remove, u_admin_users,
@@ -15,6 +14,16 @@ use jellycommon::{
};
use jellyui_locale::tr;
+page!(AdminDashboard<'_>, |x| tr(x.ri.lang, "admin.dashboard"));
+page!(AdminImport<'_>, |x| tr(x.ri.lang, "admin.import"));
+page!(AdminUserList<'_>, |x| tr(x.ri.lang, "admin.users"));
+page!(AdminUser<'_>, |x| x
+ .user
+ .get(USER_NAME)
+ .unwrap_or("nameless user")
+ .to_string()
+ .into());
+
markup::define!(
AdminDashboard<'a>(ri: &'a RenderInfo<'a>) {
h1 { @tr(ri.lang, "admin.dashboard") }
@@ -22,23 +31,22 @@ markup::define!(
li{a[href=u_admin_log(true)] { @tr(ri.lang, "admin.log.warnonly") }}
li{a[href=u_admin_log(false)] { @tr(ri.lang, "admin.log.full") }}
}
-
a[href=u_admin_import()] { h2 { @tr(ri.lang, "admin.import") }}
a[href=u_admin_users()] { h2 { @tr(ri.lang, "admin.users") }}
}
- AdminImport<'a>(ri: &'a RenderInfo<'a>, data: Object<'a>) {
- @if data.has(ADMIN_IMPORT_BUSY.0) {
+ AdminImport<'a>(ri: &'a RenderInfo<'a>, errors: &'a [&'a str], busy: bool) {
+ @if *busy {
h1 { @tr(ri.lang, "admin.import.running") }
noscript { "Live import progress needs javascript." }
div[id="admin_import"] {}
} else {
h1 { @tr(ri.lang, "admin.import") }
- @if data.has(ADMIN_IMPORT_ERROR.0) {
+ @if !errors.is_empty() {
section.message.error {
details {
- summary { p.error { @tr(ri.lang, "admin.import_errors").replace("{n}", &data.iter(ADMIN_IMPORT_ERROR).count().to_string()) } }
- ol { @for e in data.iter(ADMIN_IMPORT_ERROR) {
+ summary { p.error { @tr(ri.lang, "admin.import_errors").replace("{n}", &errors.len().to_string()) } }
+ ol { @for e in *errors {
li.error { pre.error { @e } }
}}
}
@@ -53,24 +61,19 @@ markup::define!(
}
}
- AdminInfo<'a>(ri: &'a RenderInfo<'a>, data: Object<'a>) {
- @let _ = ri;
- h2 { @data.get(ADMIN_INFO_TITLE) }
- pre { @data.get(ADMIN_INFO_TEXT) }
- }
-
- AdminUserList<'a>(ri: &'a RenderInfo<'a>, data: Object<'a>) {
+ AdminUserList<'a>(ri: &'a RenderInfo<'a>, users: &'a [User<'a>]) {
h1 { @tr(ri.lang, "admin.users") }
form[method="POST", action=u_admin_new_user()] {
label[for="login"] { "Login: " }
input[type="text", id="login", name="login"]; br;
input[type="submit", value="Create new user"];
}
- ul { @for u in data.iter(ADMIN_USER_LIST_ITEM) {
+ ul { @for u in *users {
li { a[href=u_admin_user(u.get(USER_LOGIN).unwrap_or_default())] { @u.get(USER_LOGIN) } }
}}
}
- AdminUser<'a>(ri: &'a RenderInfo<'a>, user: Object<'a>) {
+
+ AdminUser<'a>(ri: &'a RenderInfo<'a>, user: User<'a>) {
h2 { @user.get(USER_NAME).unwrap_or("nameless user") }
p { @tr(ri.lang, "tag.Ulgn") ": " @user.get(USER_LOGIN) }
form[method="POST", action=u_admin_user_remove(user.get(USER_LOGIN).unwrap())] {
diff --git a/ui/src/components/admin_log.rs b/ui/src/components/admin_log.rs
index abec7fe..f521aae 100644
--- a/ui/src/components/admin_log.rs
+++ b/ui/src/components/admin_log.rs
@@ -4,6 +4,7 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
+use crate::{RenderInfo, page};
use jellycommon::{
internal::{LogLevel, LogLine},
routes::u_admin_log,
@@ -11,8 +12,11 @@ use jellycommon::{
use markup::raw;
use std::fmt::Write;
+page!(ServerLogPage<'_>, |_| "Server Log".into());
+
markup::define! {
- ServerLogPage<'a>(warnonly: bool, messages: &'a [String]) {
+ ServerLogPage<'a>(ri: &'a RenderInfo<'a>, warnonly: bool, messages: &'a [String]) {
+ @let _ = ri;
h1 { "Server Log" }
a[href=u_admin_log(!warnonly)] { @if *warnonly { "Show everything" } else { "Show only warnings" }}
code.log[id="log"] {
diff --git a/ui/src/components/home.rs b/ui/src/components/home.rs
new file mode 100644
index 0000000..5ae6a66
--- /dev/null
+++ b/ui/src/components/home.rs
@@ -0,0 +1,38 @@
+/*
+ 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) 2026 metamuffin <metamuffin.org>
+*/
+
+use crate::{
+ RenderInfo,
+ components::node_card::{NodeCard, NodeCardHightlight},
+ page,
+};
+use jellycommon::Nku;
+use jellyui_locale::tr;
+
+pub enum HomeRow {
+ Inline(Vec<Nku<'a>>),
+ Highlight(Nku<'a>),
+}
+
+page!(Home<'_>, |x| tr(x.ri.lang, "home"));
+
+markup::define! {
+ Home<'a>(ri: &'a RenderInfo<'a>, rows: &'a [(&'a str, HomeRow<'a>)]) {
+ @for (title, row) in *rows {
+ h2 { @tr(ri.lang, title) }
+ @match row {
+ HomeRow::Inline(nkus) => {
+ ul.nl.inline { @for nku in nkus {
+ li { @NodeCard { ri, nku } }
+ }}
+ }
+ HomeRow::Highlight(nku) => {
+ @NodeCardHightlight { ri, nku }
+ }
+ }
+ }
+ }
+}
diff --git a/ui/src/components/items.rs b/ui/src/components/items.rs
new file mode 100644
index 0000000..c9e0d41
--- /dev/null
+++ b/ui/src/components/items.rs
@@ -0,0 +1,22 @@
+/*
+ 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) 2026 metamuffin <metamuffin.org>
+*/
+
+use crate::{RenderInfo, components::node_card::NodeCard, page};
+use jellycommon::{Nku, routes::u_items_cont};
+use jellyui_locale::tr;
+
+page!(Items<'_>, |x| tr(x.ri.lang, "items"));
+
+markup::define! {
+ Items<'a>(ri: &'a RenderInfo<'a>, items: &'a [Nku<'a>], cont: Option<String>) {
+ ul.nl.grid { @for nku in *items {
+ li { @NodeCard { ri, nku } }
+ }}
+ @if let Some(cont) = cont {
+ a.next_page[href=u_items_cont(cont)] { button { "Show more" } }
+ }
+ }
+}
diff --git a/ui/src/components/login.rs b/ui/src/components/login.rs
index d291165..7d19a38 100644
--- a/ui/src/components/login.rs
+++ b/ui/src/components/login.rs
@@ -4,19 +4,24 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
-use jellycommon::{SETPW_PASSWORD, SETPW_USERNAME, jellyobject::Object};
+use crate::{RenderInfo, page};
use jellyui_locale::tr;
-use crate::RenderInfo;
+page!(AccountLogin<'_>, |x| tr(x.ri.lang, "account.login"));
+page!(AccountLogout<'_>, |x| tr(x.ri.lang, "account.logout"));
+page!(AccountSetPassword<'_>, |x| tr(
+ x.ri.lang,
+ "account.login.set_password"
+));
markup::define! {
- AccountSetPassword<'a>(ri: &'a RenderInfo<'a>, data: Object<'a>) {
+ AccountSetPassword<'a>(ri: &'a RenderInfo<'a>, username: &'a str, password: &'a str) {
form.account[method="POST", action=""] {
h1 { @tr(ri.lang, "account.login.set_password") }
p { @tr(ri.lang, "account.login.set_password.par") }
- input[type="hidden", name="username", value=data.get(SETPW_USERNAME)];
- input[type="hidden", name="password", value=data.get(SETPW_PASSWORD)];
+ input[type="hidden", name="username", value=username];
+ input[type="hidden", name="password", value=password];
label[for="password"] { @tr(ri.lang, "account.new_password") }
input[type="password", id="password", name="new_password"]; br;
diff --git a/ui/src/components/message.rs b/ui/src/components/message.rs
index a271d40..b4499ed 100644
--- a/ui/src/components/message.rs
+++ b/ui/src/components/message.rs
@@ -4,14 +4,12 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
use crate::RenderInfo;
-use jellycommon::{MESSAGE_KIND, MESSAGE_TEXT, jellyobject::Object};
use markup::define;
define! {
- Message<'a>(ri: &'a RenderInfo<'a>, message: Object<'a>) {
+ Message<'a>(ri: &'a RenderInfo<'a>, kind: &'a str, text: &'a str) {
@let _ = ri;
- @let text = message.get(MESSAGE_TEXT).unwrap_or_default();
- @match message.get(MESSAGE_KIND).unwrap_or("neutral") {
+ @match *kind {
"success" => { section.message { p.success { @text } } }
"error" => { section.message { p.error { @text } } }
"neutral" | _ => { section.message { p { @text } } }
diff --git a/ui/src/components/mod.rs b/ui/src/components/mod.rs
index d87efab..6c4cc9d 100644
--- a/ui/src/components/mod.rs
+++ b/ui/src/components/mod.rs
@@ -9,66 +9,9 @@ pub mod admin_log;
pub mod login;
pub mod message;
pub mod node_card;
-pub mod node_list;
pub mod node_page;
pub mod props;
pub mod stats;
pub mod user;
-
-use crate::{
- RenderInfo,
- components::{
- admin::{AdminDashboard, AdminImport, AdminInfo, AdminUser, AdminUserList},
- login::{AccountLogin, AccountLogout, AccountSetPassword},
- message::Message,
- node_list::NodeList,
- node_page::{NodePage, Player},
- user::UserSettings,
- },
-};
-use jellycommon::{jellyobject::Object, *};
-use markup::define;
-
-define! {
- View<'a>(ri: &'a RenderInfo<'a>, view: Object<'a>) {
- @if let Some(message) = view.get(VIEW_MESSAGE) {
- @Message { ri, message }
- }
- @if let Some(nku) = view.get(VIEW_NODE_PAGE) {
- @NodePage { ri, nku }
- }
- @if let Some(nku) = view.get(VIEW_PLAYER) {
- @Player { ri, nku }
- }
- @for nl in view.iter(VIEW_NODE_LIST) {
- @NodeList { ri, nl }
- }
- @if let Some(()) = view.get(VIEW_ACCOUNT_LOGIN) {
- @AccountLogin { ri }
- }
- @if let Some(()) = view.get(VIEW_ACCOUNT_LOGOUT) {
- @AccountLogout{ ri }
- }
- @if let Some(data) = view.get(VIEW_ACCOUNT_SET_PASSWORD) {
- @AccountSetPassword { ri, data }
- }
- @if let Some(()) = view.get(VIEW_ADMIN_DASHBOARD) {
- @AdminDashboard { ri }
- }
- @if let Some(data) = view.get(VIEW_ADMIN_IMPORT) {
- @AdminImport { ri, data }
- }
- @if let Some(data) = view.get(VIEW_ADMIN_INFO) {
- @AdminInfo { ri, data }
- }
- @if let Some(user) = view.get(VIEW_USER_SETTINGS) {
- @UserSettings { ri, user }
- }
- @if let Some(data) = view.get(VIEW_ADMIN_USER_LIST) {
- @AdminUserList { ri, data }
- }
- @if let Some(user) = view.get(VIEW_ADMIN_USER) {
- @AdminUser { ri, user }
- }
- }
-}
+pub mod items;
+pub mod home;
diff --git a/ui/src/components/node_card.rs b/ui/src/components/node_card.rs
index d93825b..e1baec1 100644
--- a/ui/src/components/node_card.rs
+++ b/ui/src/components/node_card.rs
@@ -15,8 +15,8 @@ use jellycommon::{
};
markup::define! {
- NodeCard<'a>(ri: &'a RenderInfo<'a>, nku: Object<'a>) {
- @let node = nku.get(NKU_NODE).unwrap_or_default();
+ NodeCard<'a>(ri: &'a RenderInfo<'a>, nku: &'a Nku<'a>) {
+ @let node = nku.node;
@let slug = node.get(NO_SLUG).unwrap_or_default();
div[class=&format!("card {}", aspect_class(node))] {
.poster {
@@ -27,7 +27,7 @@ markup::define! {
@if node.has(NO_TRACK.0) {
a.play.icon[href=u_node_slug_player(&slug)] { "play_arrow" }
}
- @Props { ri, nku: *nku, full: false }
+ @Props { ri, nku, full: false }
}
}
div.title {
@@ -37,14 +37,14 @@ markup::define! {
}
div.subtitle {
span {
- @nku.get(NKU_ROLE).or(node.get(NO_SUBTITLE))
+ @nku.role.or(node.get(NO_SUBTITLE))
}
}
}
}
- NodeCardWide<'a>(ri: &'a RenderInfo<'a>, nku: Object<'a>) {
- @let node = nku.get(NKU_NODE).unwrap_or_default();
+ NodeCardWide<'a>(ri: &'a RenderInfo<'a>, nku: Nku<'a>) {
+ @let node = nku.node;
@let slug = node.get(NO_SLUG).unwrap_or_default();
div[class="card wide"] {
div[class=&format!("poster {}", aspect_class(node))] {
@@ -59,14 +59,14 @@ markup::define! {
}
div.details {
a.title[href=u_node_slug(&slug)] { @node.get(NO_TITLE) }
- @Props { ri, nku: *nku ,full: false }
+ @Props { ri, nku ,full: false }
span.overview { @node.get(NO_DESCRIPTION) }
}
}
}
- NodeCardHightlight<'a>(ri: &'a RenderInfo<'a>, nku: Object<'a>) {
- @let node = nku.get(NKU_NODE).unwrap_or_default();
+ NodeCardHightlight<'a>(ri: &'a RenderInfo<'a>, nku: &'a Nku<'a>) {
+ @let node = nku.node;
@let slug = node.get(NO_SLUG).unwrap_or_default();
@let backdrop = u_image(node.get(NO_PICTURES).unwrap_or_default().get(PICT_BACKDROP).unwrap_or_default(), 2048);
div[class="card highlight", style=format!("background-image: url(\"{backdrop}\")")] {
diff --git a/ui/src/components/node_list.rs b/ui/src/components/node_list.rs
deleted file mode 100644
index df405ea..0000000
--- a/ui/src/components/node_list.rs
+++ /dev/null
@@ -1,47 +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) 2026 metamuffin <metamuffin.org>
-*/
-
-use crate::{
- RenderInfo,
- components::node_card::{NodeCard, NodeCardHightlight, NodeCardWide},
-};
-use jellycommon::{jellyobject::Object, routes::u_items_cont, *};
-use jellyui_locale::tr;
-
-markup::define! {
- NodeList<'a>(ri: &'a RenderInfo<'a>, nl: Object<'a>) {
- @let ds = nl.get(NODELIST_DISPLAYSTYLE).unwrap_or(NLSTYLE_GRID);
- @if let Some(title) = nl.get(NODELIST_TITLE) {
- h2 { @tr(ri.lang, title) }
- }
- @match ds {
- NLSTYLE_GRID => {
- ul.nl.grid { @for nku in nl.iter(NODELIST_ITEM) {
- li { @NodeCard { ri, nku } }
- }}
- }
- NLSTYLE_INLINE => {
- ul.nl.inline { @for nku in nl.iter(NODELIST_ITEM) {
- li { @NodeCard { ri, nku } }
- }}
- }
- NLSTYLE_LIST => {
- ol.nl.list { @for nku in nl.iter(NODELIST_ITEM) {
- li { @NodeCardWide { ri, nku } }
- }}
- }
- NLSTYLE_HIGHLIGHT => {
- @if let Some(nku) = nl.get(NODELIST_ITEM) {
- @NodeCardHightlight { ri, nku }
- }
- }
- _ => {}
- }
- @if let Some(cont) = nl.get(NODELIST_CONTINUATION) {
- a[href=u_items_cont(cont)] { button { "Show more" } }
- }
- }
-}
diff --git a/ui/src/components/node_page.rs b/ui/src/components/node_page.rs
index f40aa73..5cd71ce 100644
--- a/ui/src/components/node_page.rs
+++ b/ui/src/components/node_page.rs
@@ -4,7 +4,7 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
-use crate::{RenderInfo, components::props::Props};
+use crate::{RenderInfo, components::props::Props, page};
use jellycommon::{
jellyobject::{Object, Tag, TypedTag},
routes::{u_image, u_node_slug_player},
@@ -13,9 +13,24 @@ use jellycommon::{
use jellyui_locale::tr;
use std::marker::PhantomData;
+page!(NodePage<'_>, |x| x
+ .nku
+ .node
+ .get(NO_TITLE)
+ .unwrap_or_default()
+ .to_string()
+ .into());
+page!(Player<'_>, |x| x
+ .nku
+ .node
+ .get(NO_TITLE)
+ .unwrap_or_default()
+ .to_string()
+ .into());
+
markup::define! {
- NodePage<'a>(ri: &'a RenderInfo<'a>, nku: Object<'a>) {
- @let node = nku.get(NKU_NODE).unwrap_or_default();
+ NodePage<'a>(ri: &'a RenderInfo<'a>, nku: Nku<'a>) {
+ @let node = nku.node;
@let slug = node.get(NO_SLUG).unwrap_or_default();
@let pics = node.get(NO_PICTURES).unwrap_or_default();
@if let Some(path) = pics.get(PICT_BACKDROP) {
@@ -59,7 +74,7 @@ markup::define! {
}
}
.details {
- @Props { ri, nku: *nku, full: true }
+ @Props { ri, nku, full: true }
h3 { @node.get(NO_TAGLINE).unwrap_or_default() }
@if let Some(description) = &node.get(NO_DESCRIPTION) {
p { @for line in description.lines() { @line br; } }
@@ -141,13 +156,11 @@ markup::define! {
// }
}
- Player<'a>(ri: &'a RenderInfo<'a>, nku: Object<'a>) {
+ Player<'a>(ri: &'a RenderInfo<'a>, nku: Nku<'a>) {
@let _ = ri;
- @let node = nku.get(NKU_NODE).unwrap_or_default();
- @let pics = node.get(NO_PICTURES).unwrap_or_default();
+ @let pics = nku.node.get(NO_PICTURES).unwrap_or_default();
video[id="player", poster=pics.get(PICT_COVER).map(|p| u_image(p, 2048))] {}
}
-
}
// fn chapter_key_time(c: Object, dur: f64) -> f64 {
diff --git a/ui/src/components/props.rs b/ui/src/components/props.rs
index 5fa9d3e..e672919 100644
--- a/ui/src/components/props.rs
+++ b/ui/src/components/props.rs
@@ -9,16 +9,13 @@ use crate::{
format::{format_count, format_duration},
};
use chrono::DateTime;
-use jellycommon::{
- jellyobject::{Object, TypedTag},
- *,
-};
+use jellycommon::{jellyobject::TypedTag, *};
use jellyui_locale::tr;
use std::marker::PhantomData;
markup::define! {
- Props<'a>(ri: &'a RenderInfo<'a>, nku: Object<'a>, full: bool) {
- @let node = nku.get(NKU_NODE).unwrap_or_default();
+ Props<'a>(ri: &'a RenderInfo<'a>, nku: &'a Nku<'a>, full: bool) {
+ @let node = nku.node;
.props {
@if let Some(dur) = node.get(NO_DURATION) {
p { @format_duration(dur) }
diff --git a/ui/src/components/stats.rs b/ui/src/components/stats.rs
index 698430b..ce06843 100644
--- a/ui/src/components/stats.rs
+++ b/ui/src/components/stats.rs
@@ -8,27 +8,25 @@ use crate::{
RenderInfo,
format::{format_duration, format_duration_long, format_size},
};
-use jellycommon::{jellyobject::Object, *};
+use jellycommon::*;
use jellyui_locale::tr;
use markup::raw;
markup::define! {
- StatText<'a>(ri: &'a RenderInfo<'a>, stat: Object<'a>) {
+ StatText<'a>(ri: &'a RenderInfo<'a>, stats: &'a Stats) {
h1 { @tr(ri.lang, "stats.title") }
p { @raw(tr(ri.lang, "stats.count")
- .replace("{count}", &format!("<b>{}</b>", stat.get(STAT_COUNT).unwrap_or_default()))
+ .replace("{count}", &format!("<b>{}</b>", stats.all.count))
)}
p { @raw(tr(ri.lang, "stats.runtime")
- .replace("{dur}", &format!("<b>{}</b>", format_duration_long(ri.lang, stat.get(STAT_TOTAL_DURATION).unwrap_or_default())))
- .replace("{size}", &format!("<b>{}</b>", format_size(stat.get(STAT_TOTAL_SIZE).unwrap_or_default())))
+ .replace("{dur}", &format!("<b>{}</b>", format_duration_long(ri.lang, stats.all.sum_duration)))
+ .replace("{size}", &format!("<b>{}</b>", format_size(stats.all.sum_size)))
)}
p { @raw(tr(ri.lang, "stats.average")
- .replace("{dur}", &format!("<b>{}</b>", format_duration(stat.get(STAT_TOTAL_DURATION).unwrap_or_default() / stat.get(STAT_COUNT).unwrap_or_default() as f64)))
- .replace("{size}", &format!("<b>{}</b>", format_size(stat.get(STAT_TOTAL_SIZE).unwrap_or_default() / stat.get(STAT_COUNT).unwrap_or_default())))
+ .replace("{dur}", &format!("<b>{}</b>", format_duration(stats.all.sum_duration / stats.all.count as f64)))
+ .replace("{size}", &format!("<b>{}</b>", format_size(stats.all.sum_size / stats.all.count as u64)))
)}
- }
- StatGroup<'a>(ri: &'a RenderInfo<'a>, statgroup: Object<'a>) {
- h2 { @tr(ri.lang, statgroup.get(STATGROUP_TITLE).unwrap_or_default()) }
+ h2 { @tr(ri.lang, "stats.by_kind") }
table.striped {
tr {
th { @tr(ri.lang, "stats.by_kind.kind") }
@@ -40,15 +38,15 @@ markup::define! {
th { @tr(ri.lang, "stats.by_kind.max_size") }
th { @tr(ri.lang, "stats.by_kind.max_runtime") }
}
- @for stat in statgroup.iter(STATGROUP_BIN) { tr {
- td { @tr(ri.lang, stat.get(STAT_NAME).unwrap_or_default()) }
- td { @stat.get(STAT_COUNT).unwrap_or_default() }
- td { @format_size(stat.get(STAT_TOTAL_SIZE).unwrap_or_default()) }
- td { @format_duration(stat.get(STAT_TOTAL_DURATION).unwrap_or_default()) }
- td { @format_size(stat.get(STAT_TOTAL_SIZE).unwrap_or_default() / stat.get(STAT_COUNT).unwrap_or_default()) }
- td { @format_duration(stat.get(STAT_TOTAL_DURATION).unwrap_or_default() / stat.get(STAT_COUNT).unwrap_or_default() as f64) }
- td { @format_size(stat.get(STAT_MAX_SIZE).unwrap_or_default()) }
- td { @format_duration(stat.get(STAT_MAX_DURATION).unwrap_or_default()) }
+ @for (kind, stat) in &stats.by_kind { tr {
+ td { @tr(ri.lang, &format!("tag.kind.{kind}")) }
+ td { @stat.count }
+ td { @format_size(stat.sum_size) }
+ td { @format_duration(stat.sum_duration) }
+ td { @format_size(stat.sum_size / stat.count as u64) }
+ td { @format_duration(stat.sum_duration / stat.count as f64) }
+ td { @format_size(stat.max_size) }
+ td { @format_duration(stat.max_duration) }
}}
}
}
diff --git a/ui/src/components/user.rs b/ui/src/components/user.rs
index 22b296e..9dabffc 100644
--- a/ui/src/components/user.rs
+++ b/ui/src/components/user.rs
@@ -4,16 +4,17 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
-use crate::RenderInfo;
+use crate::{RenderInfo, page};
use jellycommon::{
- jellyobject::Object,
routes::{u_account_login, u_account_logout, u_account_settings},
*,
};
use jellyui_locale::tr;
+page!(UserSettings<'_>, |x| tr(x.ri.lang, "settings"));
+
markup::define! {
- UserSettings<'a>(ri: &'a RenderInfo<'a>, user: Object<'a>) {
+ UserSettings<'a>(ri: &'a RenderInfo<'a>, user: User<'a>) {
h1 { @tr(ri.lang, "settings") }
h2 { @tr(ri.lang, "settings.account") }