diff options
| author | metamuffin <metamuffin@disroot.org> | 2026-01-20 18:39:51 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2026-01-20 18:39:51 +0100 |
| commit | da27cc2f457f362f11f65b4e06e3d9eca09d1344 (patch) | |
| tree | 2580b47c22ff1af68e4c98eb200869cb13eb0272 /ui/src | |
| parent | 03f38fdc3bd45962be8555e50f18fd7761c17989 (diff) | |
| download | jellything-da27cc2f457f362f11f65b4e06e3d9eca09d1344.tar jellything-da27cc2f457f362f11f65b4e06e3d9eca09d1344.tar.bz2 jellything-da27cc2f457f362f11f65b4e06e3d9eca09d1344.tar.zst | |
nom nom nom
Diffstat (limited to 'ui/src')
| -rw-r--r-- | ui/src/node_page.rs | 31 | ||||
| -rw-r--r-- | ui/src/props.rs | 67 | ||||
| -rw-r--r-- | ui/src/scaffold.rs | 5 | ||||
| -rw-r--r-- | ui/src/search.rs | 12 | ||||
| -rw-r--r-- | ui/src/stats.rs | 35 |
5 files changed, 79 insertions, 71 deletions
diff --git a/ui/src/node_page.rs b/ui/src/node_page.rs index fa5c93b..f52ea5b 100644 --- a/ui/src/node_page.rs +++ b/ui/src/node_page.rs @@ -4,11 +4,12 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ -use crate::Page; +use crate::{Page, scaffold::RenderInfo}; use jellycommon::{ - jellyobject::{Object, Tag}, + jellyobject::{Object, Tag, TypedTag}, *, }; +use std::marker::PhantomData; impl Page for NodePage<'_> { fn title(&self) -> String { @@ -29,7 +30,7 @@ pub struct NodeUdata<'a> { markup::define! { NodePage<'a>( - ri: RenderInfo<'a>, + ri: &'a RenderInfo<'a>, node: NodeUdata<'a>, children: &'a [NodeUdata<'a>], parents: &'a [NodeUdata<'a>], @@ -184,9 +185,9 @@ markup::define! { } } -fn chapter_key_time(c: &Chapter, dur: f64) -> f64 { - let start = c.time_start.unwrap_or(0.); - let end = c.time_end.unwrap_or(dur); +fn chapter_key_time(c: Object, dur: f64) -> f64 { + let start = c.get(CH_START).unwrap_or(0.); + let end = c.get(CH_END).unwrap_or(dur); start * 0.8 + end * 0.2 } @@ -199,17 +200,17 @@ pub fn aspect_class(kind: Tag) -> &'static str { } } -fn external_id_url(key: IdentifierType, value: &str) -> Option<String> { - Some(match key { - IdentifierType::YoutubeVideo => format!("https://youtube.com/watch?v={value}"), - IdentifierType::YoutubeChannel => format!("https://youtube.com/channel/{value}"), - IdentifierType::YoutubeChannelHandle => format!("https://youtube.com/channel/@{value}"), - IdentifierType::MusicbrainzRelease => format!("https://musicbrainz.org/release/{value}"), - IdentifierType::MusicbrainzArtist => format!("https://musicbrainz.org/artist/{value}"), - IdentifierType::MusicbrainzReleaseGroup => { +fn external_id_url(key: Tag, value: &str) -> Option<String> { + Some(match TypedTag(key, PhantomData) { + IDENT_YOUTUBE_VIDEO => format!("https://youtube.com/watch?v={value}"), + IDENT_YOUTUBE_CHANNEL => format!("https://youtube.com/channel/{value}"), + IDENT_YOUTUBE_CHANNEL_HANDLE => format!("https://youtube.com/channel/@{value}"), + IDENT_MUSICBRAINZ_RELEASE => format!("https://musicbrainz.org/release/{value}"), + IDENT_MUSICBRAINZ_ARTIST => format!("https://musicbrainz.org/artist/{value}"), + IDENT_MUSICBRAINZ_RELEASE_GROUP => { format!("https://musicbrainz.org/release-group/{value}") } - IdentifierType::MusicbrainzRecording => { + IDENT_MUSICBRAINZ_RECORDING => { format!("https://musicbrainz.org/recording/{value}") } _ => return None, diff --git a/ui/src/props.rs b/ui/src/props.rs index 3547045..fe7f419 100644 --- a/ui/src/props.rs +++ b/ui/src/props.rs @@ -3,56 +3,61 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2026 metamuffin <metamuffin.org> */ + use crate::{ - format::{MediaInfoExt, format_count, format_duration}, + format::{format_count, format_duration}, locale::tr, + node_page::NodeUdata, + scaffold::RenderInfo, }; +use chrono::DateTime; +use jellycommon::{jellyobject::TypedTag, *}; +use std::marker::PhantomData; markup::define! { - Props<'a>(node: &'a Node, udata: &'a NodeUserData, full: bool, lang: &'a Language) { + Props<'a>(ri: &'a RenderInfo<'a>, nodeu: NodeUdata<'a>, full: bool) { .props { - @if let Some(m) = &node.media { - p { @format_duration(m.duration) } - p { @m.resolution_name() } + @if let Some(dur) = nodeu.node.get(NO_DURATION) { + p { @format_duration(dur) } } - @if let Some(d) = &node.release_date { + // @if let Some(res) = nodeu.node.get(NO_TRACK) { + // p { @m.resolution_name() } + // } + @if let Some(d) = nodeu.node.get(NO_RELEASEDATE) { p { @if *full { - @DateTime::from_timestamp_millis(*d).unwrap().naive_utc().to_string() + @DateTime::from_timestamp_millis(d).unwrap().naive_utc().to_string() } else { - @DateTime::from_timestamp_millis(*d).unwrap().date_naive().to_string() + @DateTime::from_timestamp_millis(d).unwrap().date_naive().to_string() }} } - @match node.visibility { - Visibility::Visible => {} - Visibility::Reduced => {p.visibility{@trs(lang, "prop.vis.reduced")}} - Visibility::Hidden => {p.visibility{@trs(lang, "prop.vis.hidden")}} + @match nodeu.node.get(NO_VISIBILITY).unwrap_or(VISI_VISIBLE) { + VISI_VISIBLE => {} + VISI_REDUCED => {p.visibility{@tr(ri.lang, "prop.vis.reduced")}} + VISI_HIDDEN => {p.visibility{@tr(ri.lang, "prop.vis.hidden")}} } // TODO // @if !node.children.is_empty() { // p { @format!("{} items", node.children.len()) } // } - @for (kind, value) in &node.ratings { - @match kind { - RatingType::YoutubeLikes => {p.likes{ @format_count(*value as usize) " Likes" }} - RatingType::YoutubeViews => {p{ @format_count(*value as usize) " Views" }} - RatingType::YoutubeFollowers => {p{ @format_count(*value as usize) " Subscribers" }} - RatingType::RottenTomatoes => {p.rating{ @value " Tomatoes" }} - RatingType::Metacritic if *full => {p{ "Metacritic Score: " @value }} - RatingType::Imdb => {p.rating{ "IMDb " @value }} - RatingType::Tmdb => {p.rating{ "TMDB " @format!("{:.01}", value) }} - RatingType::Trakt => {p.rating{ "Trakt " @format!("{:.01}", value) }} + @for (kind, value) in nodeu.node.get(NO_RATINGS).unwrap_or_default().entries::<f64>() { + @match TypedTag(kind, PhantomData) { + RTYP_YOUTUBE_LIKES => {p.likes{ @format_count(value as usize) " Likes" }} + RTYP_YOUTUBE_VIEWS => {p{ @format_count(value as usize) " Views" }} + RTYP_YOUTUBE_FOLLOWERS => {p{ @format_count(value as usize) " Subscribers" }} + RTYP_ROTTEN_TOMATOES => {p.rating{ @value " Tomatoes" }} + RTYP_METACRITIC if *full => {p{ "Metacritic Score: " @value }} + RTYP_IMDB => {p.rating{ "IMDb " @value }} + RTYP_TMDB => {p.rating{ "TMDB " @format!("{:.01}", value) }} + RTYP_TRAKT => {p.rating{ "Trakt " @format!("{:.01}", value) }} _ => {} } } - @if let Some(f) = &node.federated { - p.federation { @f } - } - @match udata.watched { - WatchedState::None => {} - WatchedState::Pending => { p.pending { @trs(lang, "prop.watched.pending") } } - WatchedState::Progress(x) => { p.progress { @tr(**lang, "prop.watched.progress").replace("{time}", &format_duration(x)) } } - WatchedState::Watched => { p.watched { @trs(lang, "prop.watched.watched") } } - } + // @match nodeu.udata.watched { + // WatchedState::None => {} + // WatchedState::Pending => { p.pending { @tr(ri.lang, "prop.watched.pending") } } + // WatchedState::Progress(x) => { p.progress { @tr(ri.lang, "prop.watched.progress").replace("{time}", &format_duration(x)) } } + // WatchedState::Watched => { p.watched { @tr(ri.lang, "prop.watched.watched") } } + // } } } } diff --git a/ui/src/scaffold.rs b/ui/src/scaffold.rs index 8b96f9f..82d6d5e 100644 --- a/ui/src/scaffold.rs +++ b/ui/src/scaffold.rs @@ -14,6 +14,7 @@ use jellycommon::{ 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_ADMIN, USER_NAME}, }; use markup::{Render, raw}; use std::sync::LazyLock; @@ -58,8 +59,8 @@ markup::define! { } div.account { @if let Some(user) = &ri.user { - span { @raw(tr(ri.lang, "nav.username").replace("{name}", &format!("<b class=\"username\">{}</b>", escape(&ri.user.display_name)))) } " " - @if session.user.admin { + span { @raw(tr(ri.lang, "nav.username").replace("{name}", &format!("<b class=\"username\">{}</b>", escape(user.get(USER_NAME).unwrap_or("nameless user"))))) } " " + @if user.has(USER_ADMIN.0) { a.admin.hybrid_button[href=u_admin_dashboard()] { p {@tr(ri.lang, "nav.admin")} } " " } a.settings.hybrid_button[href=u_account_settings()] { p {@tr(ri.lang, "nav.settings")} } " " diff --git a/ui/src/search.rs b/ui/src/search.rs index dd5aa0c..35ae82d 100644 --- a/ui/src/search.rs +++ b/ui/src/search.rs @@ -4,7 +4,7 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ -use crate::{Page, locale::tr, node_card::NodeCard}; +use crate::{Page, locale::tr, node_card::NodeCard, scaffold::RenderInfo}; use markup::DynRender; impl Page for SearchPage<'_> { @@ -20,15 +20,15 @@ impl Page for SearchPage<'_> { } markup::define! { - SearchPage<'a>(lang: &'a Language, r: Option<ApiSearchResponse>, query: &'a Option<String>) { - h1 { @trs(lang, "search.title") } + SearchPage<'a>(ri: &'a RenderInfo<'a>, r: Option<ApiSearchResponse>, query: &'a Option<String>) { + h1 { @tr(ri.lang, "search.title") } form[action="", method="GET"] { - input[type="text", name="query", placeholder=&*tr(**lang, "search.placeholder"), value=&query]; + input[type="text", name="query", placeholder=tr(ri.lang, "search.placeholder"), value=&query]; input[type="submit", value="Search"]; } @if let Some(r) = &r { - h2 { @trs(lang, "search.results.title") } - p.stats { @tr(**lang, "search.results.stats").replace("{count}", &r.count.to_string()).replace("{dur}", &format!("{:?}", r.duration)) } + h2 { @tr(ri.lang, "search.results.title") } + p.stats { @tr(ri.lang, "search.results.stats").replace("{count}", &r.count.to_string()).replace("{dur}", &format!("{:?}", r.duration)) } ul.children {@for (node, udata) in r.results.iter() { li { @NodeCard { node, udata, lang } } }} diff --git a/ui/src/stats.rs b/ui/src/stats.rs index c9001b0..d69f07e 100644 --- a/ui/src/stats.rs +++ b/ui/src/stats.rs @@ -8,13 +8,14 @@ use crate::{ Page, format::{format_duration, format_duration_long, format_kind, format_size}, locale::tr, + scaffold::RenderInfo, }; use jellycommon::routes::u_node_slug; use markup::raw; impl Page for StatsPage<'_> { fn title(&self) -> String { - tr(*self.lang, "stats.title").to_string() + tr(self.ri.lang, "stats.title").to_string() } fn to_render(&self) -> markup::DynRender<'_> { markup::new!(@self) @@ -22,35 +23,35 @@ impl Page for StatsPage<'_> { } markup::define! { - StatsPage<'a>(lang: &'a Language, r: ApiStatsResponse) { + StatsPage<'a>(ri: &'a RenderInfo<'a>, r: ApiStatsResponse) { .page.stats { - h1 { @trs(lang, "stats.title") } - p { @raw(tr(**lang, "stats.count") + h1 { @tr(ri.lang, "stats.title") } + p { @raw(tr(ri.lang, "stats.count") .replace("{count}", &format!("<b>{}</b>", r.total.count)) )} - p { @raw(tr(**lang, "stats.runtime") - .replace("{dur}", &format!("<b>{}</b>", format_duration_long(r.total.runtime, **lang))) + p { @raw(tr(ri.lang, "stats.runtime") + .replace("{dur}", &format!("<b>{}</b>", format_duration_long(r.total.runtime, ri.lang))) .replace("{size}", &format!("<b>{}</b>", format_size(r.total.size))) )} - p { @raw(tr(**lang, "stats.average") + p { @raw(tr(ri.lang, "stats.average") .replace("{dur}", &format!("<b>{}</b>", format_duration(r.total.average_runtime()))) .replace("{size}", &format!("<b>{}</b>", format_size(r.total.average_size() as u64))) )} - h2 { @trs(lang, "stats.by_kind.title") } + h2 { @tr(ri.lang, "stats.by_kind.title") } table.striped { tr { - th { @trs(lang, "stats.by_kind.kind") } - th { @trs(lang, "stats.by_kind.count") } - th { @trs(lang, "stats.by_kind.total_size") } - th { @trs(lang, "stats.by_kind.total_runtime") } - th { @trs(lang, "stats.by_kind.average_size") } - th { @trs(lang, "stats.by_kind.average_runtime") } - th { @trs(lang, "stats.by_kind.max_size") } - th { @trs(lang, "stats.by_kind.max_runtime") } + th { @tr(ri.lang, "stats.by_kind.kind") } + th { @tr(ri.lang, "stats.by_kind.count") } + th { @tr(ri.lang, "stats.by_kind.total_size") } + th { @tr(ri.lang, "stats.by_kind.total_runtime") } + th { @tr(ri.lang, "stats.by_kind.average_size") } + th { @tr(ri.lang, "stats.by_kind.average_runtime") } + th { @tr(ri.lang, "stats.by_kind.max_size") } + th { @tr(ri.lang, "stats.by_kind.max_runtime") } } @for (k,b) in &r.kinds { tr { - td { @format_kind(*k, **lang) } + td { @format_kind(*k, ri.lang) } td { @b.count } td { @format_size(b.size) } td { @format_duration(b.runtime) } |