use std::time::Duration; use feshared::daemon::DaemonState; use leptos::logging::log; use leptos::{prelude::*, reactive::spawn_local}; use leptos_router::{ components::{Route, Router, Routes}, path, }; use serde::{Deserialize, Serialize}; use wasm_bindgen::{prelude::Closure, JsValue}; use crate::bridge::{invoke, listen}; use crate::popup::PopupView; pub const BTN_PRIMARY: &str = "bg-slate-300 hover:bg-slate-400 dark:bg-slate-800 hover:dark-bg-slate-700 px-4 py-2 rounded-md"; #[component] pub fn App() -> impl IntoView { view! { } } #[component] fn Dashboard() -> impl IntoView { let on_click = move |_ev: leptos::ev::MouseEvent| { spawn_local(async move { let empty_args = serde_wasm_bindgen::to_value(&serde_json::json!({})).unwrap(); invoke("toggle_popup", empty_args).await; }); }; let toggle_dark_mode = |_ev: leptos::ev::MouseEvent| { spawn_local(async { let _ = invoke("toggle_dark_mode", JsValue::UNDEFINED).await; }); }; view! {
} } #[component] pub fn DarkModeToggle() -> impl IntoView { let toggle_dark_mode = |_ev: leptos::ev::MouseEvent| { spawn_local(async { let _ = invoke("toggle_dark_mode", JsValue::UNDEFINED).await; }); }; view! {
} } #[component] pub fn DaemonStatusIndicator() -> impl IntoView { let (poll_count, set_pool_count) = signal(0); set_interval( move || set_pool_count.update(|v| *v += 1), Duration::from_secs(1), ); let status = LocalResource::new(move || async move { poll_count.get(); let val = invoke("daemon_state", JsValue::NULL).await; let s: DaemonState = serde_wasm_bindgen::from_value(val).unwrap(); s }); let f = |state: Option| { let color = match state.clone() { Some(s) => match s.is_ok { true => "bg-green-600", false => "bg-red-600", }, None => "bg-yellow-600", }; let text = match state { Some(s) => match s.error { Some(err) => err, None => s.message.unwrap_or(String::from("")), }, None => String::from("Loading..."), }; view! {
{ text }
} }; view! {
{move || f(status.get())}
} } #[component] pub fn DaemonProvider(children: ChildrenFn) -> impl IntoView { let (poll_count, set_pool_count) = signal(0); set_interval( move || set_pool_count.update(|v| *v += 1), Duration::from_secs(1), ); let status_res = LocalResource::new(move || async move { poll_count.get(); let val = invoke("daemon_state", JsValue::NULL).await; let s: DaemonState = serde_wasm_bindgen::from_value(val).unwrap(); s }); let is_daemon_ok = Memo::new(move |_| status_res.get().map(|s| (s.is_ok, s.error))); provide_context(status_res); move || match is_daemon_ok.get() { Some((true, _)) => children().into_any(), Some((false, err)) => view! { }.into_any(), None => view! {

Connecting...

}.into_any(), } } #[component] fn DaemonErrorStatus(error: Option) -> impl IntoView { view! {

{ error.unwrap_or("Daemon error!".to_string()) }

} } #[derive(Deserialize, Serialize, Clone)] struct DarkMode { is_dark_mode: bool, } #[component] pub fn ThemeProvider(children: Children) -> impl IntoView { let (is_dark, set_dark) = signal(false); Effect::new(move |_| { spawn_local(async move { let handler = Closure::wrap(Box::new(move |evt: JsValue| { log!("Received!!!"); #[derive(Deserialize)] struct TauriEvent { payload: T, } if let Ok(wrapper) = serde_wasm_bindgen::from_value::>(evt) { set_dark.set(wrapper.payload.is_dark_mode); } }) as Box); let unlisten = listen("dark-mode-changed", &handler).await; // TODO use on_cleanup to call the unlisten JS function. handler.forget() }); }); Effect::new(move |_| { let el = document() .document_element() .expect("HTML element not found!"); if is_dark.get() { let _ = el.set_attribute("class", "dark"); } else { let _ = el.set_attribute("class", ""); } }); view! { {children()} } }