use crate::*;
pub(crate) fn use_theme(mobile_signal: Signal<bool>) -> ThemeState {
let theme: Signal<String> = use_signal(|| THEME_LIGHT.to_string());
let initial_mobile: bool = mobile_signal.get();
let initial_root: &'static str = if initial_mobile {
c_mobile_app_root().get_name()
} else {
c_app_root().get_name()
};
let root_class: Signal<String> = use_signal(|| {
format!(
"{initial_root} {theme_class}",
theme_class = theme_class_name(THEME_LIGHT)
)
});
watch!(mobile_signal, theme, |mobile: bool, theme_value: String| {
let root: &'static str = if mobile {
c_mobile_app_root().get_name()
} else {
c_app_root().get_name()
};
root_class.set(format!(
"{root} {theme_class}",
theme_class = theme_class_name(&theme_value)
));
});
ThemeState { theme, root_class }
}
const THEME_SWITCHING_CLASS: &str = "euv-theme-switching";
pub(crate) fn toggle_theme(theme_signal: Signal<String>) -> Option<Rc<dyn Fn(Event)>> {
Some(Rc::new(move |_event: Event| {
suppress_theme_transitions();
let current: String = theme_signal.get();
if current == THEME_LIGHT {
theme_signal.set(THEME_DARK.to_string());
} else {
theme_signal.set(THEME_LIGHT.to_string());
}
restore_theme_transitions();
}))
}
fn document_root_element() -> Option<Element> {
window()?.document()?.document_element()
}
fn suppress_theme_transitions() {
if let Some(root) = document_root_element() {
let _ = root.class_list().add_1(THEME_SWITCHING_CLASS);
}
}
fn restore_theme_transitions() {
let Some(outer_window) = window() else {
return;
};
let outer_closure: Closure<dyn FnMut()> = Closure::wrap(Box::new(move || {
let Some(inner_window) = window() else {
return;
};
let inner_closure: Closure<dyn FnMut()> = Closure::wrap(Box::new(move || {
if let Some(root) = document_root_element() {
let _ = root.class_list().remove_1(THEME_SWITCHING_CLASS);
}
}) as Box<dyn FnMut()>);
let _ = inner_window.request_animation_frame(inner_closure.as_ref().unchecked_ref());
inner_closure.forget();
}) as Box<dyn FnMut()>);
let _ = outer_window.request_animation_frame(outer_closure.as_ref().unchecked_ref());
outer_closure.forget();
}
pub(crate) fn theme_class_name(theme: &str) -> &'static str {
if theme == THEME_DARK {
c_theme_dark().get_name()
} else {
c_theme_light().get_name()
}
}