Skip to content

Commit

Permalink
Worked on theming
Browse files Browse the repository at this point in the history
  • Loading branch information
Kanerix committed Jul 31, 2024
1 parent a90e949 commit 68bf8a4
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 58 deletions.
2 changes: 1 addition & 1 deletion src/pages/home.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ pub fn Home() -> impl IntoView {
<i class="fa-brands fa-twitter text-4xl
text-slate-600 dark:text-slate-400" />
</a>
<a href="https://www.linkedin.com/in/kasper-jonsson" aria-label="Checkout my LinkedIn">
<a href="https://linkedin.com/in/kasper-jonsson" aria-label="Checkout my LinkedIn">
<i class="fa-brands fa-linkedin text-4xl
text-slate-600 dark:text-slate-400" />
</a>
Expand Down
124 changes: 67 additions & 57 deletions src/theme.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use leptos::*;
use leptos_meta::{Body, Meta};
use serde::{Deserialize, Serialize};
use std::ops::Not;
use std::{ops::Not, str::FromStr};

#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
pub enum ColorMode {
Light,
#[default]
Dark,
Light,
}

#[derive(Clone, Copy, Debug)]
Expand All @@ -16,8 +16,20 @@ pub struct Theme(pub ReadSignal<ColorMode>, pub WriteSignal<ColorMode>);
impl AsRef<str> for ColorMode {
fn as_ref(&self) -> &str {
match self {
ColorMode::Light => "light",
ColorMode::Dark => "dark",
ColorMode::Light => "light",
}
}
}

impl FromStr for ColorMode {
type Err = ();

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"light" => Ok(ColorMode::Light),
"dark" => Ok(ColorMode::Dark),
_ => Err(()),
}
}
}
Expand All @@ -34,67 +46,72 @@ impl Not for ColorMode {
}

impl ColorMode {
pub fn to_fa_icon(&self) -> String {
pub fn to_fa_icon(&self) -> &str {
match self {
ColorMode::Light => "fa-sun".to_owned(),
ColorMode::Dark => "fa-moon".to_owned(),
ColorMode::Light => "fa-sun",
ColorMode::Dark => "fa-moon",
}
}
}

#[cfg(feature = "ssr")]
fn initial_color_mode() -> ColorMode {
use_context::<actix_web::HttpRequest>()
.and_then(|req| {
let cookies = req.cookies().ok();
cookies.and_then(|cookies| {
cookies
.iter()
.find(|cookie| cookie.name() == "color_mode")
.and_then(|cookie| match cookie.value() {
"dark" => Some(ColorMode::Dark),
"light" => Some(ColorMode::Light),
/// The initial color mode, loaded from the cookie.
///
/// This function is sever-side only. This is why we have
/// the `#[cfg(feature = "ssr")]` attribute to make sure it
/// is only used when server-side rendering.
#[cfg(feature = "ssr")]
fn initial_color_mode() -> ColorMode {
use_context::<actix_web::HttpRequest>()
.and_then(|req| {
let cookies = req.cookies().ok();
cookies.and_then(|cookies| {
cookies
.iter()
.find(|cookie| cookie.name() == "color_mode")
.and_then(|cookie| match cookie.value() {
"dark" => Some(ColorMode::Dark),
"light" => Some(ColorMode::Light),
_ => None,
})
})
})
.unwrap_or_default()
}

/// The initial color mode, loaded from the local storage.
///
/// This function is client-side only. This is why we have
/// the `#[cfg(not(feature = "ssr"))]` attribute to make sure
/// it is only used when client-side rendering.
#[cfg(not(feature = "ssr"))]
fn initial_color_mode() -> ColorMode {
window()
.local_storage()
.ok()
.and_then(|local_storage| {
local_storage
.and_then(|storage| storage.get_item("color_mode").ok())
.and_then(|color_mode| match color_mode.as_deref() {
Some("dark") => Some(ColorMode::Dark),
Some("light") => Some(ColorMode::Light),
_ => None,
})
})
})
.unwrap_or_default()
}

#[cfg(not(feature = "ssr"))]
fn initial_color_mode() -> ColorMode {
window()
.local_storage()
.ok()
.and_then(|local_storage| {
local_storage
.and_then(|storage| storage.get_item("color_mode").ok())
.and_then(|color_mode| match color_mode.as_deref() {
Some("dark") => Some(ColorMode::Dark),
Some("light") => Some(ColorMode::Light),
_ => None,
})
})
.unwrap_or_default()
.unwrap_or_default()
}
}

#[component]
pub fn ThemeProvider(children: Children) -> impl IntoView {
let initial_color_mode = initial_color_mode();
let initial_color_mode = ColorMode::initial_color_mode();
let (color_mode, set_color_mode) = create_signal(initial_color_mode);

provide_context(Theme(color_mode, set_color_mode));

let classes = create_memo(move |_| {
match color_mode.get() {
ColorMode::Light => "",
ColorMode::Dark => "dark",
}
.to_string()
});
let classes = create_memo(move |_| color_mode.get().as_ref().to_string());

create_effect(move |_| {
window().local_storage().ok().and_then(|local_storage| {
let local_storage = window().local_storage().ok();
local_storage.and_then(|local_storage| {
local_storage.and_then(|storage| {
storage
.set_item("color_mode", color_mode.get().as_ref())
Expand All @@ -103,7 +120,7 @@ pub fn ThemeProvider(children: Children) -> impl IntoView {
});
});

let set_color_scheme = move || color_mode.get().as_ref().to_owned();
let set_color_scheme = move || color_mode.get().as_ref().to_string();

view! {
<Meta name="color-scheme" content=set_color_scheme />
Expand All @@ -116,16 +133,9 @@ pub fn ThemeProvider(children: Children) -> impl IntoView {
#[component]
pub fn ToggleThemeButton() -> impl IntoView {
let Theme(color_mode, set_color_mode) = use_context::<Theme>().unwrap();
let fa_icon = create_memo(move |_| color_mode.get().to_fa_icon());
let fa_icon = create_memo(move |_| color_mode.get().to_fa_icon().to_string());

let toggle_color_mode = move |_| {
let color_mode = color_mode.get();
let new_color_mode = match color_mode {
ColorMode::Light => ColorMode::Dark,
ColorMode::Dark => ColorMode::Light,
};
set_color_mode.set(new_color_mode);
};
let toggle_color_mode = move |_| set_color_mode.set(!color_mode.get());

view! {
<button
Expand Down

0 comments on commit 68bf8a4

Please sign in to comment.