diff --git a/Cargo.lock b/Cargo.lock index 11a5b2fc..af1b6a82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6219,6 +6219,7 @@ dependencies = [ "leptos_router", "log", "paginate", + "percent-encoding", "plotters-canvas", "reqwest", "serde", @@ -6233,7 +6234,6 @@ dependencies = [ "ultros-api-types", "ultros-charts", "ultros-db", - "urlencoding", "wasm-bindgen", "web-sys", "xiv-gen", @@ -6446,12 +6446,6 @@ dependencies = [ "serde", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "usvg" version = "0.33.0" diff --git a/ultros-frontend/ultros-app/Cargo.toml b/ultros-frontend/ultros-app/Cargo.toml index c6b9179c..99cee9b4 100644 --- a/ultros-frontend/ultros-app/Cargo.toml +++ b/ultros-frontend/ultros-app/Cargo.toml @@ -30,7 +30,6 @@ humantime = "2.1" colorsys = "0.6.6" thiserror = "1.0" log = "0.4" -urlencoding = "2.1.2" anyhow = "1.0.69" cookie = {version = "0.17", features = ["percent-encode"]} wasm-bindgen = {version = "0.2", optional = true} @@ -46,6 +45,7 @@ gloo-timers = {version = "0.3.0", features = ["futures"]} cfg-if.workspace = true paginate = "1.1.11" git-const.workspace = true +percent-encoding = "2.3.0" [features] default = ["ssr"] # this is mostly so if I run cargo check, it has a flavor to work on diff --git a/ultros-frontend/ultros-app/src/routes/item_explorer.rs b/ultros-frontend/ultros-app/src/routes/item_explorer.rs index ac468744..8c4c52fd 100644 --- a/ultros-frontend/ultros-app/src/routes/item_explorer.rs +++ b/ultros-frontend/ultros-app/src/routes/item_explorer.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::{collections::HashSet, str::FromStr}; use crate::components::{ @@ -8,8 +9,9 @@ use itertools::Itertools; use leptos::*; use leptos_icons::*; use leptos_router::*; +use log::info; use paginate::Pages; -use urlencoding::{decode, encode}; +use percent_encoding::percent_decode_str; use xiv_gen::{ClassJobCategory, Item, ItemId}; /// Displays buttons of categories @@ -32,9 +34,9 @@ fn CategoryView(category: u8) -> impl IntoView { {categories.into_iter() .map(|(_, name, id)| view! { - + - + }) .collect::>()} @@ -149,12 +151,14 @@ fn JobsList() -> impl IntoView { view! {
{jobs.into_iter() // .filter(|(_id, job)| job.class_job_parent.0 == 0) - .map(|(_id, job)| view!{ - // {&job.abbreviation} - - - - }).collect::>()} + .map(|(_id, job)| view!{ + + // {&job.abbreviation} + + + + + }).collect::>()}
} } @@ -165,11 +169,11 @@ pub fn CategoryItems() -> impl IntoView { let items = create_memo(move |_| { let cat = params() .get("category") - .and_then(|cat| decode(cat).ok()) + .and_then(|cat| percent_encoding::percent_decode_str(cat).decode_utf8().ok()) .and_then(|cat| { data.item_search_categorys .iter() - .find(|(_id, category)| category.name == cat) + .find(|(_id, category)| &category.name == &cat) }) .map(|(id, _)| { let items = data @@ -185,9 +189,8 @@ pub fn CategoryItems() -> impl IntoView { params() .get("category") .as_ref() - .and_then(|cat| decode(cat).ok()) - .map(|c| c.to_string()) - .unwrap_or("Category View".to_string()) + .and_then(|cat| percent_decode_str(cat).decode_utf8().ok()) + .unwrap_or(Cow::from("Category View")) .to_string() }); view! { @@ -341,6 +344,40 @@ pub fn QueryButton( }>{children} } } +/// A URL that copies the existing query string but replaces the path +#[component] +pub fn APersistQuery( + #[prop(into)] href: TextProp, + children: Box Fragment>, + #[prop(optional)] remove_values: &'static [&'static str], +) -> impl IntoView { + let location = use_location(); + let query = location.query; + let path = location.pathname; + let href_2 = href.clone(); + let query = create_memo(move |_| { + let mut query = query(); + for value in remove_values { + query.remove(value); + } + query + }); + let url = move || format!("{}{}", href_2.get(), query().to_query_string()); + let is_active = create_memo(move |_| { + let link_path = href.get(); + + path.with(|path| { + info!("{link_path} {path}"); + &escape(&link_path) == path + }) + }); + view! { + + {children} + + } +} + #[component] fn ItemList(items: Memo>) -> impl IntoView { let (page, _set_page) = create_query_signal::("page"); @@ -398,7 +435,12 @@ fn ItemList(items: Memo>) -> impl IntoView let items = move || { // now take a subslice of the items let page = pages().with_offset((page().unwrap_or_default() - 1).try_into().unwrap_or(0)); - items()[page.start..=page.end].to_vec() + items.with(|items| { + items + .get(page.start..=page.end) + .unwrap_or_default() + .to_vec() + }) }; view! {
diff --git a/ultros-frontend/ultros-app/src/routes/item_view.rs b/ultros-frontend/ultros-app/src/routes/item_view.rs index b5989f0b..3d69dd3f 100644 --- a/ultros-frontend/ultros-app/src/routes/item_view.rs +++ b/ultros-frontend/ultros-app/src/routes/item_view.rs @@ -9,6 +9,7 @@ use crate::global_state::LocalWorldData; use leptos::*; use leptos_meta::Link; use leptos_meta::Meta; +use leptos_router::escape; use leptos_router::*; use ultros_api_types::world_helper::AnyResult; use xiv_gen::ItemId; @@ -21,7 +22,7 @@ fn WorldButton<'a>(world: AnyResult<'a>, item_id: i32) -> impl IntoView { AnyResult::Datacenter(_d) => "bg-violet-800 hover:bg-violet-700", AnyResult::World(_w) => "bg-violet-600 hover:bg-violet-500", }; - view! { {world_name}} + view! { {world_name}} } #[component] @@ -30,7 +31,7 @@ fn WorldMenu(world_name: Memo, item_id: Memo) -> impl IntoView { let world_data = use_context::().unwrap().0.unwrap(); move || { let world = world_name(); - let world_name = urlencoding::decode(&world).unwrap_or_default(); + let world_name = escape(&world); if let Some(world) = world_data.lookup_world_by_name(&world_name) { let create_world_button = move |world| view! {}; match world {