diff --git a/web/src/lib.rs b/web/src/lib.rs index 93d62d1..2628d50 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -14,6 +14,8 @@ use seed::{prelude::*, *}; use serde::de::Deserialize; use wasm_timer::Instant; +const SEARCH_RESULTS_PER_PAGE: usize = 20; + // ------ ------ // Init // ------ ------ @@ -32,12 +34,23 @@ fn init(url: Url, orders: &mut impl Orders) -> Model { orders.send_msg(Msg::ShowPrettyRequest(tid)); } Some("s") => { - query = url.next_hash_path_part().unwrap_or("").to_string(); - orders.send_msg(Msg::SearchRequest(query.clone())); + query = url + .next_hash_path_part() + .map(|q| Url::decode_uri_component(q).unwrap_or("".to_string())) + .unwrap_or("".to_string()); + orders.send_msg(Msg::SearchRequest { + query: query.to_string(), + page: 0, + results_per_page: SEARCH_RESULTS_PER_PAGE, + }); } p => { log!(p); - orders.send_msg(Msg::SearchRequest("".to_string())); + orders.send_msg(Msg::SearchRequest { + query: "".to_string(), + page: 0, + results_per_page: SEARCH_RESULTS_PER_PAGE, + }); } }; orders.subscribe(|uc: subs::UrlChanged| { @@ -85,7 +98,11 @@ enum Msg { Noop, RefreshStart, RefreshDone(Option), - SearchRequest(String), + SearchRequest { + query: String, + page: usize, + results_per_page: usize, + }, SearchResult(fetch::Result), ShowRequest(String), ShowResult(fetch::Result), @@ -111,14 +128,18 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { }; } - Msg::SearchRequest(query) => { - info!("searching for '{query}'"); + Msg::SearchRequest { + query, + page, + results_per_page, + } => { + info!("searching for '{query}' pg {page} # / pg {results_per_page}"); model.query = query.clone(); let url = Url::new().set_hash_path(["s", &query]); orders.request_url(url); - orders - .skip() - .perform_cmd(async move { Msg::SearchResult(search_request(&query).await) }); + orders.skip().perform_cmd(async move { + Msg::SearchResult(search_request(&query, page, results_per_page).await) + }); } Msg::SearchResult(Ok(response_data)) => { debug!("fetch ok {:#?}", response_data); @@ -160,12 +181,11 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { Msg::NextPage => { match &model.context { Context::Search(sr) => { - orders.send_msg(Msg::SearchRequest(format!( - "{}?page={}&results_per_page={}", - Url::encode_uri_component(&sr.query), - sr.page + 1, - sr.results_per_page - ))); + orders.send_msg(Msg::SearchRequest { + query: sr.query.clone(), + page: sr.page + 1, + results_per_page: sr.results_per_page, + }); } Context::Thread(_) => (), // do nothing (yet?) Context::None => (), // do nothing (yet?) @@ -174,12 +194,11 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { Msg::PreviousPage => { match &model.context { Context::Search(sr) => { - orders.send_msg(Msg::SearchRequest(format!( - "{}?page={}&results_per_page={}", - Url::encode_uri_component(&sr.query), - sr.page.saturating_sub(1), - sr.results_per_page - ))); + orders.send_msg(Msg::SearchRequest { + query: sr.query.clone(), + page: sr.page.saturating_sub(1), + results_per_page: sr.results_per_page, + }); } Context::Thread(_) => (), // do nothing (yet?) Context::None => (), // do nothing (yet?) @@ -188,8 +207,12 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { } } -async fn search_request(query: &str) -> fetch::Result { - Request::new(api::search(query)) +async fn search_request( + query: &str, + page: usize, + results_per_page: usize, +) -> fetch::Result { + Request::new(api::search(query, page, results_per_page)) .method(Method::Get) .fetch() .await? @@ -199,12 +222,15 @@ async fn search_request(query: &str) -> fetch::Result { } mod api { + use seed::Url; + const BASE_URL: &str = "/api"; pub fn refresh() -> String { format!("{BASE_URL}/refresh") } - pub fn search(query: &str) -> String { - format!("{BASE_URL}/search/{query}") + pub fn search(query: &str, page: usize, results_per_page: usize) -> String { + let query = Url::encode_uri_component(query); + format!("{BASE_URL}/search/{query}?page={page}&results_per_page={results_per_page}") } pub fn show(tid: &str) -> String { format!("{BASE_URL}/show/{tid}") @@ -400,9 +426,11 @@ fn tags_chiclet(tags: &[String], is_mobile: bool) -> impl Iterator span![classes, style, i![C!["fa-solid", "fa-reply"]]], _ => span![classes, style, &tag], }, - ev(Ev::Click, move |_| Msg::SearchRequest( - Url::encode_uri_component(format!("tag:{tag}")) - )), + ev(Ev::Click, move |_| Msg::SearchRequest { + query: format!("tag:{tag}"), + page: 0, + results_per_page: SEARCH_RESULTS_PER_PAGE, + }) ] }) } @@ -621,12 +649,20 @@ fn view_header(query: &str, refresh_request: &RefreshingState) -> Node { a![ C!["navbar-item", "button"], "Unread", - ev(Ev::Click, |_| Msg::SearchRequest("is:unread".to_string())), + ev(Ev::Click, |_| Msg::SearchRequest { + query: "is:unread".to_string(), + page: 0, + results_per_page: SEARCH_RESULTS_PER_PAGE, + }), ], a![ C!["navbar-item", "button"], "All", - ev(Ev::Click, |_| Msg::SearchRequest("".to_string())), + ev(Ev::Click, |_| Msg::SearchRequest { + query: "".to_string(), + page: 0, + results_per_page: SEARCH_RESULTS_PER_PAGE, + }), ], input![ C!["navbar-item", "input"], @@ -635,12 +671,18 @@ fn view_header(query: &str, refresh_request: &RefreshingState) -> Node { At::AutoFocus => true.as_at_value(); At::Value => query, }, - input_ev(Ev::Input, |q| Msg::SearchRequest( - Url::encode_uri_component(q) - )), + input_ev(Ev::Input, |q| Msg::SearchRequest { + query: Url::encode_uri_component(q), + page: 0, + results_per_page: SEARCH_RESULTS_PER_PAGE, + }), // Resend search on enter. keyboard_ev(Ev::KeyUp, move |e| if e.key_code() == 0x0d { - Msg::SearchRequest(Url::encode_uri_component(query)) + Msg::SearchRequest { + query: Url::encode_uri_component(query), + page: 0, + results_per_page: SEARCH_RESULTS_PER_PAGE, + } } else { Msg::Noop }),