diff options
| author | metamuffin <metamuffin@disroot.org> | 2026-03-18 17:56:11 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2026-03-18 17:56:11 +0100 |
| commit | bef95130a2bdabd196f595a1129ac07bd3f5054b (patch) | |
| tree | 705b284ac4a0c2d6cc2ed893d8c992a507073f3c | |
| parent | 53b0268eaa850d0a7250c94373d76906a7b28250 (diff) | |
| download | jellything-bef95130a2bdabd196f595a1129ac07bd3f5054b.tar jellything-bef95130a2bdabd196f595a1129ac07bd3f5054b.tar.bz2 jellything-bef95130a2bdabd196f595a1129ac07bd3f5054b.tar.zst | |
send page title with header when jst
| -rw-r--r-- | server/src/request_info.rs | 14 | ||||
| -rw-r--r-- | server/src/responders/mod.rs | 9 | ||||
| -rw-r--r-- | server/src/responders/ui_page.rs | 21 | ||||
| -rw-r--r-- | server/src/routes/account/mod.rs | 9 | ||||
| -rw-r--r-- | server/src/routes/account/settings.rs | 8 | ||||
| -rw-r--r-- | server/src/routes/admin/import.rs | 9 | ||||
| -rw-r--r-- | server/src/routes/admin/log.rs | 5 | ||||
| -rw-r--r-- | server/src/routes/admin/mod.rs | 8 | ||||
| -rw-r--r-- | server/src/routes/admin/users.rs | 10 | ||||
| -rw-r--r-- | server/src/routes/assets.rs | 2 | ||||
| -rw-r--r-- | server/src/routes/error.rs | 9 | ||||
| -rw-r--r-- | server/src/routes/home.rs | 6 | ||||
| -rw-r--r-- | server/src/routes/items.rs | 5 | ||||
| -rw-r--r-- | server/src/routes/node.rs | 6 | ||||
| -rw-r--r-- | server/src/routes/player.rs | 6 | ||||
| -rw-r--r-- | server/src/routes/playersync.rs | 9 | ||||
| -rw-r--r-- | server/src/routes/search.rs | 6 | ||||
| -rw-r--r-- | server/src/routes/stats.rs | 2 | ||||
| -rw-r--r-- | ui/client-scripts/src/transition.ts | 6 |
19 files changed, 97 insertions, 53 deletions
diff --git a/server/src/request_info.rs b/server/src/request_info.rs index aa0665d..c7389d8 100644 --- a/server/src/request_info.rs +++ b/server/src/request_info.rs @@ -7,6 +7,7 @@ use crate::{ State, auth::token_to_user, + responders::UiPage, routes::error::{MyError, MyResult}, }; use anyhow::anyhow; @@ -16,7 +17,6 @@ use rocket::{ Request, async_trait, http::MediaType, request::{FromRequest, Outcome}, - response::content::RawHtml, }; use std::sync::Arc; @@ -74,11 +74,17 @@ impl<'a> RequestInfo<'a> { message: self.flash.as_ref().map(|f| (f.kind, f.message)), } } - pub fn respond_ui(&self, page: &dyn Page) -> RawHtml<String> { + pub fn respond_ui(&self, page: &dyn Page) -> UiPage { if self.no_scaffold { - RawHtml(page.render().to_string()) + UiPage { + html: page.render().to_string(), + title: Some(page.title().to_string()), + } } else { - RawHtml(Scaffold { page }.to_string()) + UiPage { + html: Scaffold { page }.to_string(), + title: None, + } } } } diff --git a/server/src/responders/mod.rs b/server/src/responders/mod.rs index b62fe40..cdb6c85 100644 --- a/server/src/responders/mod.rs +++ b/server/src/responders/mod.rs @@ -4,5 +4,10 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ -pub mod cache; -pub mod cors; +mod cache; +mod cors; +mod ui_page; + +pub use cache::{CacheControlFile, CacheControlImage}; +pub use cors::Cors; +pub use ui_page::UiPage; diff --git a/server/src/responders/ui_page.rs b/server/src/responders/ui_page.rs new file mode 100644 index 0000000..5a7a4b3 --- /dev/null +++ b/server/src/responders/ui_page.rs @@ -0,0 +1,21 @@ +/* + 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 rocket::response::{Responder, content::RawHtml}; + +pub struct UiPage { + pub title: Option<String>, + pub html: String, +} +impl<'r, 'o: 'r> Responder<'r, 'o> for UiPage { + fn respond_to(self, request: &'r rocket::Request<'_>) -> rocket::response::Result<'o> { + let mut r = RawHtml(self.html).respond_to(request)?; + if let Some(title) = self.title { + r.adjoin_raw_header("x-title", title); + } + Ok(r) + } +} diff --git a/server/src/routes/account/mod.rs b/server/src/routes/account/mod.rs index 1ca0ce1..beea214 100644 --- a/server/src/routes/account/mod.rs +++ b/server/src/routes/account/mod.rs @@ -10,6 +10,7 @@ pub mod settings; use crate::{ auth::{hash_password, login}, request_info::RequestInfo, + responders::UiPage, routes::error::MyResult, }; use jellycommon::{ @@ -25,19 +26,19 @@ use rocket::{ get, http::{Cookie, CookieJar}, post, - response::{Flash, Redirect, content::RawHtml}, + response::{Flash, Redirect}, }; use serde::{Deserialize, Serialize}; #[get("/account/login")] -pub async fn r_account_login(ri: RequestInfo<'_>) -> RawHtml<String> { +pub async fn r_account_login(ri: RequestInfo<'_>) -> UiPage { ri.respond_ui(&AccountLogin { ri: &ri.render_info(), }) } #[get("/account/logout")] -pub fn r_account_logout(ri: RequestInfo<'_>) -> RawHtml<String> { +pub fn r_account_logout(ri: RequestInfo<'_>) -> UiPage { ri.respond_ui(&AccountLogout { ri: &ri.render_info(), }) @@ -63,7 +64,7 @@ pub fn r_account_login_post( ri: RequestInfo<'_>, jar: &CookieJar, form: Form<Contextual<LoginForm>>, -) -> MyResult<Either<Redirect, Either<Flash<Redirect>, RawHtml<String>>>> { +) -> MyResult<Either<Redirect, Either<Flash<Redirect>, UiPage>>> { let form = match &form.value { Some(v) => v, None => { diff --git a/server/src/routes/account/settings.rs b/server/src/routes/account/settings.rs index 54ecf22..3fe444c 100644 --- a/server/src/routes/account/settings.rs +++ b/server/src/routes/account/settings.rs @@ -4,7 +4,9 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ use super::format_form_error; -use crate::{auth::hash_password, request_info::RequestInfo, routes::error::MyResult}; +use crate::{ + auth::hash_password, request_info::RequestInfo, responders::UiPage, routes::error::MyResult, +}; use anyhow::anyhow; use jellycommon::{ jellyobject::{Object, Path, Tag}, @@ -17,7 +19,7 @@ use rocket::{ FromForm, form::{self, Contextual, Form, validate::len}, get, post, - response::{Flash, Redirect, content::RawHtml}, + response::{Flash, Redirect}, }; use std::ops::Range; @@ -36,7 +38,7 @@ fn option_len<'v>(value: &Option<String>, range: Range<usize>) -> form::Result<' } #[get("/account/settings")] -pub fn r_account_settings(ri: RequestInfo) -> MyResult<RawHtml<String>> { +pub fn r_account_settings(ri: RequestInfo) -> MyResult<UiPage> { let user = ri.require_user()?; Ok(ri.respond_ui(&UserSettings { ri: &ri.render_info(), diff --git a/server/src/routes/admin/import.rs b/server/src/routes/admin/import.rs index f58901a..5185c8c 100644 --- a/server/src/routes/admin/import.rs +++ b/server/src/routes/admin/import.rs @@ -4,23 +4,20 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ -use crate::{request_info::RequestInfo, routes::error::MyResult}; +use crate::{request_info::RequestInfo, responders::UiPage, routes::error::MyResult}; use jellycommon::routes::u_admin_import; use jellyimport::{ ImportConfig, import_wrap, is_importing, reporting::{IMPORT_ERRORS, IMPORT_PROGRESS}, }; use jellyui::components::admin::AdminImport; -use rocket::{ - get, post, - response::{Redirect, content::RawHtml}, -}; +use rocket::{get, post, response::Redirect}; use rocket_ws::{Message, Stream, WebSocket}; use std::time::Duration; use tokio::{spawn, time::sleep}; #[get("/admin/import", rank = 2)] -pub async fn r_admin_import(ri: RequestInfo<'_>) -> MyResult<RawHtml<String>> { +pub async fn r_admin_import(ri: RequestInfo<'_>) -> MyResult<UiPage> { ri.require_admin()?; let last_import_err = IMPORT_ERRORS.read().await.clone(); diff --git a/server/src/routes/admin/log.rs b/server/src/routes/admin/log.rs index bf8126a..242681d 100644 --- a/server/src/routes/admin/log.rs +++ b/server/src/routes/admin/log.rs @@ -6,15 +6,16 @@ use crate::{ logger::{get_log_buffer, get_log_stream}, request_info::RequestInfo, + responders::UiPage, routes::error::MyResult, }; use jellyui::components::admin_log::{ServerLogPage, render_log_line}; -use rocket::{get, response::content::RawHtml}; +use rocket::get; use rocket_ws::{Message, Stream, WebSocket}; use serde_json::json; #[get("/admin/log?<warnonly>", rank = 2)] -pub fn r_admin_log(ri: RequestInfo, warnonly: bool) -> MyResult<RawHtml<String>> { +pub fn r_admin_log(ri: RequestInfo, warnonly: bool) -> MyResult<UiPage> { ri.require_admin()?; let messages = get_log_buffer(warnonly) .into_iter() diff --git a/server/src/routes/admin/mod.rs b/server/src/routes/admin/mod.rs index 714b574..0c918ec 100644 --- a/server/src/routes/admin/mod.rs +++ b/server/src/routes/admin/mod.rs @@ -9,13 +9,13 @@ pub mod log; pub mod users; use super::error::MyResult; -use crate::request_info::RequestInfo; +use crate::{request_info::RequestInfo, responders::UiPage}; use jellyui::components::admin::{AdminDashboard, AdminDebug}; -use rocket::{get, response::content::RawHtml}; +use rocket::get; use std::fmt::Write; #[get("/admin/dashboard")] -pub async fn r_admin_dashboard(ri: RequestInfo<'_>) -> MyResult<RawHtml<String>> { +pub async fn r_admin_dashboard(ri: RequestInfo<'_>) -> MyResult<UiPage> { ri.require_admin()?; // let mut db_debug = String::new(); @@ -30,7 +30,7 @@ pub async fn r_admin_dashboard(ri: RequestInfo<'_>) -> MyResult<RawHtml<String>> } #[get("/admin/debug")] -pub async fn r_admin_debug(ri: RequestInfo<'_>) -> MyResult<RawHtml<String>> { +pub async fn r_admin_debug(ri: RequestInfo<'_>) -> MyResult<UiPage> { ri.require_admin()?; let mut o = String::new(); writeln!(o, "===== DATABASE =====")?; diff --git a/server/src/routes/admin/users.rs b/server/src/routes/admin/users.rs index 01a6403..ee8a0c9 100644 --- a/server/src/routes/admin/users.rs +++ b/server/src/routes/admin/users.rs @@ -6,7 +6,9 @@ use std::str::FromStr; -use crate::{auth::hash_password, request_info::RequestInfo, routes::error::MyResult}; +use crate::{ + auth::hash_password, request_info::RequestInfo, responders::UiPage, routes::error::MyResult, +}; use anyhow::anyhow; use base64::{Engine, prelude::BASE64_URL_SAFE}; use jellycommon::{ @@ -24,11 +26,11 @@ use rocket::{ FromForm, form::Form, get, post, - response::{Flash, Redirect, content::RawHtml}, + response::{Flash, Redirect}, }; #[get("/admin/users")] -pub fn r_admin_users(ri: RequestInfo) -> MyResult<RawHtml<String>> { +pub fn r_admin_users(ri: RequestInfo) -> MyResult<UiPage> { ri.require_admin()?; let mut users = Vec::new(); @@ -78,7 +80,7 @@ pub fn r_admin_new_user(ri: RequestInfo, form: Form<NewUser>) -> MyResult<Flash< } #[get("/admin/user/<name>")] -pub fn r_admin_user(ri: RequestInfo<'_>, name: &str) -> MyResult<RawHtml<String>> { +pub fn r_admin_user(ri: RequestInfo<'_>, name: &str) -> MyResult<UiPage> { ri.require_admin()?; let mut user = None; ri.state.database.transaction(&mut |txn| { diff --git a/server/src/routes/assets.rs b/server/src/routes/assets.rs index 089f293..41760a1 100644 --- a/server/src/routes/assets.rs +++ b/server/src/routes/assets.rs @@ -4,7 +4,7 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ use super::error::MyResult; -use crate::{request_info::RequestInfo, responders::cache::CacheControlImage}; +use crate::{request_info::RequestInfo, responders::CacheControlImage}; use anyhow::Context; use jellycache::HashKey; use jellycommon::routes::u_image; diff --git a/server/src/routes/error.rs b/server/src/routes/error.rs index 6330b27..768d242 100644 --- a/server/src/routes/error.rs +++ b/server/src/routes/error.rs @@ -3,22 +3,21 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2026 metamuffin <metamuffin.org> */ +use crate::{request_info::RequestInfo, responders::UiPage}; use jellyui::components::message::Message; use rocket::{ Request, catch, http::Status, - response::{self, Responder, content::RawHtml}, + response::{self, Responder}, }; use serde_json::{Value, json}; use thiserror::Error; -use crate::request_info::RequestInfo; - #[catch(default)] -pub fn r_catch(status: Status, request: &Request) -> RawHtml<String> { +pub fn r_catch(status: Status, request: &Request) -> UiPage { catch_with_message(&RequestInfo::from_request_ut(request), format!("{status}")) } -fn catch_with_message(ri: &RequestInfo, message: String) -> RawHtml<String> { +fn catch_with_message(ri: &RequestInfo, message: String) -> UiPage { ri.respond_ui(&Message { ri: &ri.render_info(), kind: "error", diff --git a/server/src/routes/home.rs b/server/src/routes/home.rs index cb3fffd..5453b3a 100644 --- a/server/src/routes/home.rs +++ b/server/src/routes/home.rs @@ -5,15 +5,15 @@ */ use super::error::MyResult; -use crate::{request_info::RequestInfo, routes::node::create_nku}; +use crate::{request_info::RequestInfo, responders::UiPage, routes::node::create_nku}; use anyhow::{Context, Result}; use jellydb::{Query, helper::DatabaseReturnExt}; use jellyui::components::home::{Home, HomeRow}; -use rocket::{get, response::content::RawHtml}; +use rocket::get; use std::str::FromStr; #[get("/home")] -pub fn r_home(ri: RequestInfo<'_>) -> MyResult<RawHtml<String>> { +pub fn r_home(ri: RequestInfo<'_>) -> MyResult<UiPage> { ri.require_user()?; let mut rows = Vec::new(); diff --git a/server/src/routes/items.rs b/server/src/routes/items.rs index 8db60da..e841d1b 100644 --- a/server/src/routes/items.rs +++ b/server/src/routes/items.rs @@ -6,6 +6,7 @@ use crate::{ request_info::RequestInfo, + responders::UiPage, routes::{error::MyResult, node::create_nku}, }; use anyhow::anyhow; @@ -13,10 +14,10 @@ use base64::{Engine, prelude::BASE64_URL_SAFE}; use jellycommon::{jellyobject::Path, *}; use jellydb::{Filter, MultiBehaviour, Query, Sort, SortOrder, ValueSort}; use jellyui::components::items::Items; -use rocket::{get, response::content::RawHtml}; +use rocket::get; #[get("/items?<cont>")] -pub fn r_items(ri: RequestInfo, cont: Option<&str>) -> MyResult<RawHtml<String>> { +pub fn r_items(ri: RequestInfo, cont: Option<&str>) -> MyResult<UiPage> { let cont_in = cont .map(|s| BASE64_URL_SAFE.decode(s)) .transpose() diff --git a/server/src/routes/node.rs b/server/src/routes/node.rs index 240486e..d7a585a 100644 --- a/server/src/routes/node.rs +++ b/server/src/routes/node.rs @@ -5,7 +5,7 @@ */ use super::error::MyResult; -use crate::request_info::RequestInfo; +use crate::{request_info::RequestInfo, responders::UiPage}; use anyhow::{Result, anyhow}; use jellycommon::{ jellyobject::{EMPTY, Object, Path, Tag}, @@ -16,11 +16,11 @@ use jellyui::components::{ node_list::{NodeFilterInfo, NodeListData}, node_page::NodePage, }; -use rocket::{get, response::content::RawHtml}; +use rocket::get; use std::{borrow::Cow, collections::BTreeMap}; #[get("/n/<slug>")] -pub fn r_node(ri: RequestInfo<'_>, slug: &str) -> MyResult<RawHtml<String>> { +pub fn r_node(ri: RequestInfo<'_>, slug: &str) -> MyResult<UiPage> { ri.require_user()?; let filter = NodeFilter { kind: None }; diff --git a/server/src/routes/player.rs b/server/src/routes/player.rs index 45fd6de..40b584c 100644 --- a/server/src/routes/player.rs +++ b/server/src/routes/player.rs @@ -4,12 +4,12 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ use super::error::MyResult; -use crate::{request_info::RequestInfo, routes::node::create_nku}; +use crate::{request_info::RequestInfo, responders::UiPage, routes::node::create_nku}; use anyhow::anyhow; use jellycommon::{jellyobject::Path, *}; use jellydb::{Filter, Query}; use jellyui::components::node_page::Player; -use rocket::{get, response::content::RawHtml}; +use rocket::get; // fn jellynative_url(action: &str, seek: f64, secret: &str, node: &str, session: &str) -> String { // let protocol = if CONF.tls { "https" } else { "http" }; @@ -25,7 +25,7 @@ use rocket::{get, response::content::RawHtml}; // } #[get("/n/<slug>/player?<t>", rank = 4)] -pub fn r_player(ri: RequestInfo<'_>, t: Option<f64>, slug: &str) -> MyResult<RawHtml<String>> { +pub fn r_player(ri: RequestInfo<'_>, t: Option<f64>, slug: &str) -> MyResult<UiPage> { ri.require_user()?; let _ = t; diff --git a/server/src/routes/playersync.rs b/server/src/routes/playersync.rs index 71e2809..bf36f04 100644 --- a/server/src/routes/playersync.rs +++ b/server/src/routes/playersync.rs @@ -1,3 +1,10 @@ +/* + 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::responders::Cors; use anyhow::bail; use chashmap::CHashMap; use futures::{SinkExt, StreamExt}; @@ -7,8 +14,6 @@ use rocket_ws::{Channel, Message, WebSocket, stream::DuplexStream}; use serde::{Deserialize, Serialize}; use tokio::sync::broadcast::{self, Sender}; -use crate::responders::cors::Cors; - #[derive(Default)] pub struct PlayersyncChannels { channels: CHashMap<String, broadcast::Sender<Message>>, diff --git a/server/src/routes/search.rs b/server/src/routes/search.rs index 1339b5d..6e7bab1 100644 --- a/server/src/routes/search.rs +++ b/server/src/routes/search.rs @@ -5,16 +5,16 @@ */ use super::error::MyResult; -use crate::{request_info::RequestInfo, routes::node::create_nku}; +use crate::{request_info::RequestInfo, responders::UiPage, routes::node::create_nku}; use jellycommon::{jellyobject::Path, *}; use jellydb::{Filter, Query, Sort}; use jellyui::components::search::Search; use log::info; -use rocket::{get, response::content::RawHtml}; +use rocket::get; use std::time::Instant; #[get("/search?<q>")] -pub async fn r_search(ri: RequestInfo<'_>, q: Option<&str>) -> MyResult<RawHtml<String>> { +pub async fn r_search(ri: RequestInfo<'_>, q: Option<&str>) -> MyResult<UiPage> { ri.require_user()?; let mut items = Vec::new(); diff --git a/server/src/routes/stats.rs b/server/src/routes/stats.rs index 387ca63..f8afe55 100644 --- a/server/src/routes/stats.rs +++ b/server/src/routes/stats.rs @@ -7,6 +7,6 @@ use crate::{request_info::RequestInfo, ui::error::MyResult}; use rocket::{get, response::content::RawHtml}; #[get("/stats")] -pub fn r_stats(ri: RequestInfo) -> MyResult<RawHtml<String>> { +pub fn r_stats(ri: RequestInfo) -> MyResult<UiPage> { todo!() } diff --git a/ui/client-scripts/src/transition.ts b/ui/client-scripts/src/transition.ts index d68444a..deeecd8 100644 --- a/ui/client-scripts/src/transition.ts +++ b/ui/client-scripts/src/transition.ts @@ -60,8 +60,9 @@ function prepare_load(href: string, state?: HistoryState) { const r_promise = fetch(href_url, { headers: { accept: "text/html" }, redirect: "manual" }) return async () => { let rt = "" + let r try { - const r = await r_promise + r = await r_promise if (r.type == "opaqueredirect") { globalThis.location.href = href show_message("Native Player Started.", "success") @@ -77,7 +78,10 @@ function prepare_load(href: string, state?: HistoryState) { globalThis.history.replaceState({ top: globalThis.scrollY, index: i++ } as HistoryState, "") if (!state) globalThis.history.pushState({}, "", href) clear_spinner() + + document.title = r.headers.get("x-title") ?? "" document.getElementById("main")!.innerHTML = rt + globalThis.dispatchEvent(new Event("DOMContentLoaded")) globalThis.scrollTo({ top: state?.top ?? 0 }); fade(true) |