recipes/frontend/src/lib.rs

149 lines
4.6 KiB
Rust

use common::ron_api;
use gloo::{console::log, events::EventListener, utils::window};
use utils::by_id;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
use web_sys::{HtmlElement, HtmlInputElement, HtmlSelectElement};
use crate::utils::selector;
mod calendar;
mod error;
mod modal_dialog;
mod on_click;
mod pages;
mod recipe_scheduler;
mod request;
mod shopping_list;
mod toast;
mod utils;
#[wasm_bindgen(start)]
pub fn main() -> Result<(), JsValue> {
console_error_panic_hook::set_once();
let lang = utils::get_current_lang();
let location = window().location().pathname()?;
let path: Vec<&str> = location
.split('/')
.skip(1)
.skip_while(|part| *part == lang)
.collect();
let mut location_without_lang = String::new();
for part in &path {
location_without_lang.push('/');
location_without_lang.push_str(part);
}
let is_user_logged = selector::<HtmlElement>("html")
.dataset()
.get("userLogged")
.map(|v| v == "true")
.unwrap_or_default();
let first_day_of_the_week = selector::<HtmlElement>("html")
.dataset()
.get("userFirstDayOfTheWeek")
.map(|v| v.parse().unwrap_or(chrono::Weekday::Mon))
.unwrap_or(chrono::Weekday::Mon);
match path[..] {
["recipe", "edit", id] => match id.parse::<i64>() {
Ok(id) => pages::recipe_edit::setup_page(id),
Err(error) => log!(format!("Error parsing recipe id: {}", error)),
},
["recipe", "view", id] => match id.parse::<i64>() {
Ok(id) => pages::recipe_view::setup_page(id, is_user_logged, first_day_of_the_week),
Err(error) => log!(format!("Error parsing recipe id: {}", error)),
},
["dev_panel"] => pages::dev_panel::setup_page(),
// Home.
[""] => pages::home::setup_page(is_user_logged, first_day_of_the_week),
_ => log!("Path unknown: ", location),
}
// Language handling.
let select_language: HtmlSelectElement = by_id("select-website-language");
EventListener::new(&select_language.clone(), "input", move |_event| {
let lang = select_language.value();
let body = ron_api::SetLang { lang: lang.clone() };
let location_without_lang = location_without_lang.clone();
spawn_local(async move {
let _ = request::put::<(), _>("lang", body).await;
window()
.location()
.set_href(&format!(
"/{}{}{}",
lang,
location_without_lang,
window().location().search().unwrap().as_str()
))
.unwrap();
});
})
.forget();
// Dark/light theme handling.
if get_cookie_dark_theme().is_none()
&& window()
.match_media("(prefers-color-scheme: dark)")
.map(|r| r.is_some())
.unwrap_or_default()
{
set_cookie_dark_theme(true);
window().location().reload().unwrap();
};
let toggle_theme: HtmlInputElement = selector("#toggle-theme input");
EventListener::new(&toggle_theme.clone(), "change", move |_event| {
set_cookie_dark_theme(!toggle_theme.checked());
window().location().reload().unwrap();
})
.forget();
Ok(())
}
/// `wasm_cookies::set` is specific for the wasm32 target architecture and Rust Analyzer says
/// it's an error, it's not possible to configure different target configurations into the same
/// workspace. Here is the issue:
/// https://users.rust-lang.org/t/can-i-configure-rust-analyzer-vscode-to-use-a-different-target-for-different-crates-in-my-workspce/123661
#[cfg(target_arch = "wasm32")]
fn set_cookie_dark_theme(dark_theme: bool) {
wasm_cookies::set(
common::consts::COOKIE_DARK_THEME,
&dark_theme.to_string(),
&wasm_cookies::CookieOptions {
path: Some("/"),
domain: None,
expires: None,
secure: false,
same_site: wasm_cookies::SameSite::Strict,
},
);
}
#[cfg(not(target_arch = "wasm32"))]
fn set_cookie_dark_theme(_dark_theme: bool) {}
#[cfg(target_arch = "wasm32")]
fn get_cookie_dark_theme() -> Option<bool> {
wasm_cookies::get(common::consts::COOKIE_DARK_THEME).map(|value| match value {
Ok(str) => match str.parse() {
Ok(v) => v,
Err(_) => {
set_cookie_dark_theme(false);
false
}
},
Err(_) => false,
})
}
#[cfg(not(target_arch = "wasm32"))]
fn get_cookie_dark_theme() -> Option<bool> {
Some(false)
}