Implemented user settings feature at a basic level, need to fix CSS for components.
This commit is contained in:
		
							parent
							
								
									9d46693ba8
								
							
						
					
					
						commit
						b78e2c2d57
					
				
					 24 changed files with 402 additions and 185 deletions
				
			
		
							
								
								
									
										6
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
{
 | 
			
		||||
    "rust-analyzer.linkedProjects": [
 | 
			
		||||
        "./void-fe/Cargo.toml",
 | 
			
		||||
        "./void-fe/Cargo.toml"
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								public/fonts/DejaVuSansMono.ttf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/fonts/DejaVuSansMono.ttf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2
									
								
								public/styles/tailwind.min.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								public/styles/tailwind.min.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										76
									
								
								rustfmt.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								rustfmt.toml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
max_width = 100
 | 
			
		||||
hard_tabs = false
 | 
			
		||||
tab_spaces = 4
 | 
			
		||||
newline_style = "Auto"
 | 
			
		||||
indent_style = "Block"
 | 
			
		||||
use_small_heuristics = "Default"
 | 
			
		||||
fn_call_width = 60
 | 
			
		||||
attr_fn_like_width = 70
 | 
			
		||||
struct_lit_width = 18
 | 
			
		||||
struct_variant_width = 35
 | 
			
		||||
array_width = 60
 | 
			
		||||
chain_width = 60
 | 
			
		||||
single_line_if_else_max_width = 50
 | 
			
		||||
wrap_comments = false
 | 
			
		||||
format_code_in_doc_comments = false
 | 
			
		||||
doc_comment_code_block_width = 100
 | 
			
		||||
comment_width = 80
 | 
			
		||||
normalize_comments = false
 | 
			
		||||
normalize_doc_attributes = false
 | 
			
		||||
format_strings = false
 | 
			
		||||
format_macro_matchers = false
 | 
			
		||||
format_macro_bodies = true
 | 
			
		||||
hex_literal_case = "Preserve"
 | 
			
		||||
empty_item_single_line = true
 | 
			
		||||
struct_lit_single_line = true
 | 
			
		||||
fn_single_line = false
 | 
			
		||||
where_single_line = false
 | 
			
		||||
imports_indent = "Block"
 | 
			
		||||
imports_layout = "Mixed"
 | 
			
		||||
imports_granularity = "Preserve"
 | 
			
		||||
group_imports = "Preserve"
 | 
			
		||||
reorder_imports = true
 | 
			
		||||
reorder_modules = true
 | 
			
		||||
reorder_impl_items = false
 | 
			
		||||
type_punctuation_density = "Wide"
 | 
			
		||||
space_before_colon = false
 | 
			
		||||
space_after_colon = true
 | 
			
		||||
spaces_around_ranges = false
 | 
			
		||||
binop_separator = "Front"
 | 
			
		||||
remove_nested_parens = true
 | 
			
		||||
combine_control_expr = true
 | 
			
		||||
short_array_element_width_threshold = 10
 | 
			
		||||
overflow_delimited_expr = false
 | 
			
		||||
struct_field_align_threshold = 0
 | 
			
		||||
enum_discrim_align_threshold = 0
 | 
			
		||||
match_arm_blocks = true
 | 
			
		||||
match_arm_leading_pipes = "Never"
 | 
			
		||||
force_multiline_blocks = false
 | 
			
		||||
# fn_params_layout = "Tall"
 | 
			
		||||
brace_style = "SameLineWhere"
 | 
			
		||||
control_brace_style = "AlwaysSameLine"
 | 
			
		||||
trailing_semicolon = true
 | 
			
		||||
trailing_comma = "Vertical"
 | 
			
		||||
match_block_trailing_comma = false
 | 
			
		||||
blank_lines_upper_bound = 1
 | 
			
		||||
blank_lines_lower_bound = 0
 | 
			
		||||
edition = "2021"
 | 
			
		||||
version = "One"
 | 
			
		||||
inline_attribute_width = 0
 | 
			
		||||
format_generated_files = true
 | 
			
		||||
merge_derives = true
 | 
			
		||||
use_try_shorthand = false
 | 
			
		||||
use_field_init_shorthand = false
 | 
			
		||||
force_explicit_abi = true
 | 
			
		||||
condense_wildcard_suffixes = false
 | 
			
		||||
color = "Auto"
 | 
			
		||||
# required_version = "1.5.1"
 | 
			
		||||
unstable_features = true
 | 
			
		||||
disable_all_formatting = false
 | 
			
		||||
skip_children = false
 | 
			
		||||
hide_parse_errors = false
 | 
			
		||||
error_on_line_overflow = false
 | 
			
		||||
error_on_unformatted = false
 | 
			
		||||
ignore = []
 | 
			
		||||
emit_mode = "Files"
 | 
			
		||||
make_backup = false
 | 
			
		||||
| 
						 | 
				
			
			@ -4,4 +4,4 @@ use void_be::web_app_backend;
 | 
			
		|||
async fn main() -> Result<(), rocket::Error> {
 | 
			
		||||
    let _rocket = web_app_backend::build_rocket().await.launch().await;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,30 +13,68 @@ pub mod web_app_backend {
 | 
			
		|||
    use rocket::response::Redirect;
 | 
			
		||||
    use rocket::{Build, Rocket};
 | 
			
		||||
    use rocket_dyn_templates::{context, Template};
 | 
			
		||||
    use void_fe::utils::prop_structs::PoemRequest;
 | 
			
		||||
    use void_fe::void_app::{self, VirtualDom};
 | 
			
		||||
    use void_fe::utils::prop_structs::{DarkModeProps, PoemRequest};
 | 
			
		||||
 | 
			
		||||
    use void_fe::utils::user_prefs::*;
 | 
			
		||||
 | 
			
		||||
    async fn get_user_prefs(cookies: &CookieJar<'_>) -> UserPrefs {
 | 
			
		||||
        let user_theme = match cookies.get("theme") {
 | 
			
		||||
            Some(c) => match c.value() {
 | 
			
		||||
                "auto" => ThemePref::Auto,
 | 
			
		||||
                "light" => ThemePref::Light,
 | 
			
		||||
                "dark" => ThemePref::Dark,
 | 
			
		||||
                _ => {
 | 
			
		||||
                    cookies.remove(Cookie::named("theme"));
 | 
			
		||||
                    cookies.add(Cookie::new("theme", "auto"));
 | 
			
		||||
                    ThemePref::Auto
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            None => {
 | 
			
		||||
                cookies.add(Cookie::new("theme", "auto"));
 | 
			
		||||
                ThemePref::Auto
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        let user_font = match cookies.get("font") {
 | 
			
		||||
            Some(c) => match c.value() {
 | 
			
		||||
                "nerd" => FontPref::NerdFont,
 | 
			
		||||
                "open" => FontPref::OpenDyslexic,
 | 
			
		||||
                _ => {
 | 
			
		||||
                    cookies.remove(Cookie::named("font"));
 | 
			
		||||
                    cookies.add(Cookie::new("font", "open"));
 | 
			
		||||
                    FontPref::OpenDyslexic
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            None => {
 | 
			
		||||
                cookies.add(Cookie::new("font", "open"));
 | 
			
		||||
                FontPref::OpenDyslexic
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        UserPrefs::new(user_theme, user_font)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn set_user_theme(cookies: &CookieJar<'_>, theme: &str) {
 | 
			
		||||
        if theme == "light" || theme == "dark" || theme == "auto" {
 | 
			
		||||
            cookies.remove(Cookie::named("theme"));
 | 
			
		||||
            cookies.add(Cookie::new("theme", format!("{theme}")));
 | 
			
		||||
        } else {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn set_user_font(cookies: &CookieJar<'_>, font: &str) {
 | 
			
		||||
        if font == "nerd" || font == "open" {
 | 
			
		||||
            cookies.remove(Cookie::named("font"));
 | 
			
		||||
            cookies.add(Cookie::new("font", format!("{font}")));
 | 
			
		||||
        } else {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[get("/")]
 | 
			
		||||
    async fn index(cookies: &CookieJar<'_>) -> Template {
 | 
			
		||||
        let dark_mode = match cookies.get("dark-mode") {
 | 
			
		||||
            Some(c) => {
 | 
			
		||||
                if c.value() == "true" {
 | 
			
		||||
                    true
 | 
			
		||||
                } else if c.value() == "false" {
 | 
			
		||||
                    false
 | 
			
		||||
                } else {
 | 
			
		||||
                    false
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            None => false,
 | 
			
		||||
        };
 | 
			
		||||
        let mut vdom = VirtualDom::new_with_props(
 | 
			
		||||
            void_app::HomePage,
 | 
			
		||||
            DarkModeProps {
 | 
			
		||||
                slug: Some("/".to_string()),
 | 
			
		||||
                dark_mode,
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
        let user_prefs = get_user_prefs(cookies).await;
 | 
			
		||||
        let mut vdom = VirtualDom::new_with_props(void_app::HomePage, user_prefs);
 | 
			
		||||
        let _ = vdom.rebuild();
 | 
			
		||||
        let output = dioxus_ssr::render(&vdom);
 | 
			
		||||
        Template::render(
 | 
			
		||||
| 
						 | 
				
			
			@ -45,45 +83,44 @@ pub mod web_app_backend {
 | 
			
		|||
                app_title: "A Letter to the Void",
 | 
			
		||||
                style_include: "<link href=/styles/tailwind.min.css rel=stylesheet />",
 | 
			
		||||
                test: &output,
 | 
			
		||||
                dark_mode: match dark_mode {
 | 
			
		||||
                    true => "dark",
 | 
			
		||||
                    false => ""
 | 
			
		||||
                },
 | 
			
		||||
                dark_mode: "",
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[get("/?dark_mode&<callback>")]
 | 
			
		||||
    async fn dark_mode(cookies: &CookieJar<'_>, callback: &str) -> Redirect {
 | 
			
		||||
        match cookies.get("dark-mode") {
 | 
			
		||||
            Some(_) => cookies.remove(Cookie::named("dark-mode")),
 | 
			
		||||
            None => cookies.add(Cookie::new("dark-mode", "true")),
 | 
			
		||||
        };
 | 
			
		||||
        let callback_uri = format!("{callback}");
 | 
			
		||||
        Redirect::to(callback_uri)
 | 
			
		||||
    #[get("/", rank = 3)]
 | 
			
		||||
    async fn settings(cookies: &CookieJar<'_>) -> Template {
 | 
			
		||||
        let user_prefs = get_user_prefs(cookies).await;
 | 
			
		||||
        let mut vdom = VirtualDom::new_with_props(void_app::SettingsPage, user_prefs);
 | 
			
		||||
        let _ = vdom.rebuild();
 | 
			
		||||
        let output = dioxus_ssr::render(&vdom);
 | 
			
		||||
        Template::render(
 | 
			
		||||
            "index",
 | 
			
		||||
            context! {
 | 
			
		||||
                app_title: "Settings",
 | 
			
		||||
                style_include: "<link href=/styles/tailwind.min.css rel=stylesheet />",
 | 
			
		||||
                test: &output,
 | 
			
		||||
                dark_mode: ""
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[get("/?<theme>", rank = 2)]
 | 
			
		||||
    async fn theme(cookies: &CookieJar<'_>, theme: &str) -> Redirect {
 | 
			
		||||
        set_user_theme(cookies, theme).await;
 | 
			
		||||
        Redirect::to("/settings")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[get("/?<font>")]
 | 
			
		||||
    async fn font(cookies: &CookieJar<'_>, font: &str) -> Redirect {
 | 
			
		||||
        set_user_font(cookies, font).await;
 | 
			
		||||
        Redirect::to("/settings")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[get("/")]
 | 
			
		||||
    async fn poem_list(cookies: &CookieJar<'_>) -> Template {
 | 
			
		||||
        let dark_mode = match cookies.get("dark-mode") {
 | 
			
		||||
            Some(c) => {
 | 
			
		||||
                if c.value() == "true" {
 | 
			
		||||
                    true
 | 
			
		||||
                } else if c.value() == "false" {
 | 
			
		||||
                    false
 | 
			
		||||
                } else {
 | 
			
		||||
                    false
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            None => false,
 | 
			
		||||
        };
 | 
			
		||||
        let mut vdom = VirtualDom::new_with_props(
 | 
			
		||||
            void_app::PoemListPage,
 | 
			
		||||
            DarkModeProps {
 | 
			
		||||
                slug: Some(String::from("/poems")),
 | 
			
		||||
                dark_mode,
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
        let user_prefs = get_user_prefs(cookies).await;
 | 
			
		||||
        let mut vdom = VirtualDom::new_with_props(void_app::PoemListPage, user_prefs);
 | 
			
		||||
        let _ = vdom.rebuild();
 | 
			
		||||
        let output = dioxus_ssr::render(&vdom);
 | 
			
		||||
        Template::render(
 | 
			
		||||
| 
						 | 
				
			
			@ -92,33 +129,19 @@ pub mod web_app_backend {
 | 
			
		|||
                app_title: "A Letter to the Void",
 | 
			
		||||
                style_include: "<link href=/styles/tailwind.min.css rel=stylesheet />",
 | 
			
		||||
                test: &output,
 | 
			
		||||
                dark_mode: match dark_mode {
 | 
			
		||||
                    true => "dark",
 | 
			
		||||
                    false => ""
 | 
			
		||||
                },
 | 
			
		||||
                dark_mode: "",
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[get("/<entry>")]
 | 
			
		||||
    async fn poem(cookies: &CookieJar<'_>, entry: &str) -> Template {
 | 
			
		||||
        let dark_mode = match cookies.get("dark-mode") {
 | 
			
		||||
            Some(c) => {
 | 
			
		||||
                if c.value() == "true" {
 | 
			
		||||
                    true
 | 
			
		||||
                } else if c.value() == "false" {
 | 
			
		||||
                    false
 | 
			
		||||
                } else {
 | 
			
		||||
                    false
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            None => false,
 | 
			
		||||
        };
 | 
			
		||||
        let user_prefs = get_user_prefs(cookies).await;
 | 
			
		||||
        let mut vdom = VirtualDom::new_with_props(
 | 
			
		||||
            void_app::PoemPage,
 | 
			
		||||
            PoemRequest {
 | 
			
		||||
                slug: format!("{entry}"),
 | 
			
		||||
                dark_mode: Some(dark_mode),
 | 
			
		||||
                user_prefs,
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
        let _ = vdom.rebuild();
 | 
			
		||||
| 
						 | 
				
			
			@ -129,10 +152,7 @@ pub mod web_app_backend {
 | 
			
		|||
                app_title: "A Letter to the Void",
 | 
			
		||||
                style_include: "<link href=/styles/tailwind.min.css rel=stylesheet />",
 | 
			
		||||
                test: &output,
 | 
			
		||||
                dark_mode: match dark_mode {
 | 
			
		||||
                    true => "dark",
 | 
			
		||||
                    false => ""
 | 
			
		||||
                },
 | 
			
		||||
                dark_mode: "",
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -144,7 +164,8 @@ pub mod web_app_backend {
 | 
			
		|||
            .mount("/styles", FileServer::from("public/styles"))
 | 
			
		||||
            .mount("/fonts", FileServer::from("public/fonts"))
 | 
			
		||||
            .mount("/poems", routes![poem_list, poem])
 | 
			
		||||
            .mount("/", routes![dark_mode, index])
 | 
			
		||||
            .mount("/settings", routes![settings, theme, font])
 | 
			
		||||
            .mount("/", routes![index])
 | 
			
		||||
            .attach(Template::fairing())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,23 +20,29 @@ title = "A Letter to the Void"
 | 
			
		|||
 | 
			
		||||
[web.watcher]
 | 
			
		||||
 | 
			
		||||
# when watcher trigger, regenerate the `index.html`
 | 
			
		||||
# when watcher triggers, regenerate the `index.html`
 | 
			
		||||
reload_html = true
 | 
			
		||||
 | 
			
		||||
# which files or dirs will be watcher monitoring
 | 
			
		||||
watch_path = ["src", "data", "../public", "tailwind.config.js", "Dioxus.toml", "Cargo.toml", "build.rs"]
 | 
			
		||||
 | 
			
		||||
# implement redirect on 404
 | 
			
		||||
index_on_404 = true
 | 
			
		||||
 | 
			
		||||
# include `assets` in web platform
 | 
			
		||||
[web.resource]
 | 
			
		||||
 | 
			
		||||
# CSS style file
 | 
			
		||||
style = ["styles/tailwind.min.css"]
 | 
			
		||||
style = ["/styles/tailwind.min.css"]
 | 
			
		||||
 | 
			
		||||
# Javascript code file
 | 
			
		||||
script = []
 | 
			
		||||
 | 
			
		||||
[web.resource.dev]
 | 
			
		||||
 | 
			
		||||
# CSS style file
 | 
			
		||||
style = ["/styles/tailwind.min.css"]
 | 
			
		||||
 | 
			
		||||
# Javascript code file
 | 
			
		||||
# serve: [dev-server] only
 | 
			
		||||
script = []
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,4 +17,4 @@ fn main() {
 | 
			
		|||
//     for f in std::fs::read_dir("../data/poems").unwrap() {
 | 
			
		||||
//         content.push(std::fs::read_to_string(f.unwrap().path()).unwrap());
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
// }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										7
									
								
								void-fe/data/other/homepage.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								void-fe/data/other/homepage.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
 | 
			
		||||
Welcome, and I hope you enjoy your stay!\
 | 
			
		||||
"A Letter to the Void" is a passion project of mine in which I wrote poems about my past life experiences, present, and hopes for the future throughout my transition.\
 | 
			
		||||
The topics range from my feelings through transitioning (of course), past abuse, mental health exploration, and an overall journey to grow and become a better creature.\
 | 
			
		||||
I hope you enjoy the time you spend here, and sincerely, thank you.\
 | 
			
		||||
\
 | 
			
		||||
🖤 Alice Icehart Werefox
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
pub mod void_poem;
 | 
			
		||||
pub mod void_buttons;
 | 
			
		||||
pub mod void_footer;
 | 
			
		||||
pub mod void_page;
 | 
			
		||||
pub mod void_poem;
 | 
			
		||||
pub mod void_title;
 | 
			
		||||
pub mod void_buttons;
 | 
			
		||||
pub mod void_content;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
use crate::utils::prop_structs::{ButtonProps, ContentChildren};
 | 
			
		||||
use dioxus::prelude::*;
 | 
			
		||||
use crate::utils::prop_structs::ButtonProps;
 | 
			
		||||
 | 
			
		||||
#[cfg(target_family = "wasm")]
 | 
			
		||||
use dioxus_router::Link;
 | 
			
		||||
| 
						 | 
				
			
			@ -7,8 +7,7 @@ use dioxus_router::Link;
 | 
			
		|||
pub fn BackToHomePage(cx: Scope) -> Element {
 | 
			
		||||
    #[cfg(any(target_family = "windows", target_family = "unix"))]
 | 
			
		||||
    return cx.render(rsx!{
 | 
			
		||||
        a { class: "flex justify-center p-4 text-xl text-center ring-2 bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark ring-alice-werefox-red-dark dark:ring-alice-werefox-red text-alice-werefox-grey-dark dark:text-alice-werefox-grey-light hover:text-alice-werefox-blue-dark dark:hover:text-alice-werefox-blue-light hover:ring-alice-werefox-blue dark:hover:ring-alice-werefox-blue hover:animate-yip transition",
 | 
			
		||||
            href: "/",
 | 
			
		||||
        a {href: "/",
 | 
			
		||||
            p {
 | 
			
		||||
                "Back to the homepage"
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -16,8 +15,7 @@ pub fn BackToHomePage(cx: Scope) -> Element {
 | 
			
		|||
    });
 | 
			
		||||
    #[cfg(target_family = "wasm")]
 | 
			
		||||
    return cx.render(rsx!{
 | 
			
		||||
        Link { class: "flex justify-center p-4 text-xl text-center ring-2 bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark ring-alice-werefox-red-dark dark:ring-alice-werefox-red text-alice-werefox-grey-dark dark:text-alice-werefox-grey-light hover:text-alice-werefox-blue-dark dark:hover:text-alice-werefox-blue-light hover:ring-alice-werefox-blue dark:hover:ring-alice-werefox-blue hover:animate-yip transition",
 | 
			
		||||
            to: "/",
 | 
			
		||||
        Link { to: "/",
 | 
			
		||||
            p {
 | 
			
		||||
                "Back to the homepage"
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -32,18 +30,24 @@ pub fn NavigationButton(cx: Scope<ButtonProps>) -> Element {
 | 
			
		|||
    let slug_ref = slug.as_str();
 | 
			
		||||
    #[cfg(any(target_family = "windows", target_family = "unix"))]
 | 
			
		||||
    return cx.render(rsx!{
 | 
			
		||||
        a { class: "flex mx-auto max-w-full justify-center p-4 ml-2 mr-2 text-xl text-center ring-2 bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark ring-alice-werefox-red-dark dark:ring-alice-werefox-red text-alice-werefox-grey-dark dark:text-alice-werefox-grey-light hover:text-alice-werefox-blue-dark dark:hover:text-alice-werefox-blue-light hover:ring-alice-werefox-blue dark:hover:ring-alice-werefox-blue hover:animate-yip transition",
 | 
			
		||||
            href: "{slug_ref}",
 | 
			
		||||
        a { href: "{slug_ref}",
 | 
			
		||||
            "{title_ref}"
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    #[cfg(target_family = "wasm")]
 | 
			
		||||
    return cx.render(rsx!{
 | 
			
		||||
        Link { class: "flex mx-auto max-w-full justify-center p-4 ml-2 mr-2 text-xl text-center ring-2 bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark ring-alice-werefox-red-dark dark:ring-alice-werefox-red text-alice-werefox-grey-dark dark:text-alice-werefox-grey-light hover:text-alice-werefox-blue-dark dark:hover:text-alice-werefox-blue-light hover:ring-alice-werefox-blue dark:hover:ring-alice-werefox-blue hover:animate-yip transition",
 | 
			
		||||
            to: "{slug_ref}",
 | 
			
		||||
        Link { to: "{slug_ref}",
 | 
			
		||||
            div {
 | 
			
		||||
                dangerous_inner_html: "{title_ref}",
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn ButtonGroup<'a>(cx: Scope<'a, ContentChildren<'a>>) -> Element {
 | 
			
		||||
    cx.render(rsx! {
 | 
			
		||||
        div { class: "grid md:grid-flow-col grid-flow-row gap-y-4",
 | 
			
		||||
            &cx.props.children
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								void-fe/src/components/void_content.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								void-fe/src/components/void_content.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
// Might wanna move stuff form `void_poem.rs` into here...
 | 
			
		||||
use crate::utils::prop_structs::{ContentProps};
 | 
			
		||||
use dioxus::prelude::*;
 | 
			
		||||
 | 
			
		||||
pub fn RenderContent(cx: Scope<ContentProps>) -> Element {
 | 
			
		||||
    let content = &cx.props.content;
 | 
			
		||||
    #[cfg(any(target_family = "windows", target_family = "unix"))]
 | 
			
		||||
    return cx.render(rsx!{
 | 
			
		||||
        div { class: "flex p-4 ml-2 mr-2 ring-4",
 | 
			
		||||
            "{content}",
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    #[cfg(target_family = "wasm")]
 | 
			
		||||
    return cx.render(rsx!{
 | 
			
		||||
        div { class: "flex p-4 ml-2 mr-2 ring-4",
 | 
			
		||||
            dangerous_inner_html: "{content}",
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,15 +1,19 @@
 | 
			
		|||
use dioxus::prelude::*;
 | 
			
		||||
use crate::components::void_buttons::NavigationButton;
 | 
			
		||||
 | 
			
		||||
pub fn Footer(cx: Scope) -> Element {
 | 
			
		||||
    cx.render(rsx!{
 | 
			
		||||
    cx.render(rsx! {
 | 
			
		||||
        MutantStandardFooter {}
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn MutantStandardFooter(cx: Scope) -> Element {
 | 
			
		||||
    cx.render(rsx!{
 | 
			
		||||
        div { class: "flex p-4 mx-auto max-w-full justify-center text-md text-center ring-4 bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark ring-alice-werefox-red-dark dark:ring-alice-werefox-red text-alice-werefox-grey-dark dark:text-alice-werefox-grey-light",
 | 
			
		||||
            "This site uses Mutant Standard emoji, which are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License"
 | 
			
		||||
        div {
 | 
			
		||||
            NavigationButton { title: "⚙️".to_string(), slug: "/settings".to_string() }
 | 
			
		||||
            div {
 | 
			
		||||
                "This site uses Mutant Standard emoji, which are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License"
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										13
									
								
								void-fe/src/components/void_page.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								void-fe/src/components/void_page.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
use crate::utils::prop_structs::PageChildren;
 | 
			
		||||
use dioxus::prelude::*;
 | 
			
		||||
 | 
			
		||||
pub fn PageBase<'a>(cx: Scope<'a, PageChildren<'a>>) -> Element {
 | 
			
		||||
    cx.render(rsx!{
 | 
			
		||||
        // div { class: "bg-alice-werefox-grey-lightest ring-alice-werefox-red-dark text-alice-werefox-grey-dark dark:bg-alice-werefox-grey-dark dark:ring-alice-werefox-red dark:text-alice-werefox-grey-light let button_classes hover:text-alice-werefox-blue-dark hover:ring-alice-werefox-blue dark:hover:text-alice-werefox-blue-light dark:hover:ring-alice-werefox-blue hover:animate-yip transition", hidden: true }
 | 
			
		||||
        div {
 | 
			
		||||
            div { class: "container space-y-4 mx-auto p-4",
 | 
			
		||||
                &cx.props.children
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,8 +1,9 @@
 | 
			
		|||
use dioxus::prelude::*;
 | 
			
		||||
use crate::utils::helpers;
 | 
			
		||||
use crate::utils::prop_structs::{PoemChildren, PoemData};
 | 
			
		||||
use crate::components::void_buttons::*;
 | 
			
		||||
use crate::components::void_title::*;
 | 
			
		||||
use crate::utils::helpers;
 | 
			
		||||
use crate::utils::prop_structs::{PoemChildren, PoemData};
 | 
			
		||||
use super::super::utils::user_prefs::*;
 | 
			
		||||
use dioxus::prelude::*;
 | 
			
		||||
 | 
			
		||||
pub fn PoemList(cx: Scope) -> Element {
 | 
			
		||||
    let poem_list = helpers::get_poem_list();
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +31,7 @@ pub fn GetPoem(cx: Scope<PoemData>) -> Element {
 | 
			
		|||
    let slug = String::from(cx.props.slug.clone().expect("No slug specified."));
 | 
			
		||||
    let (title, content, creation_date) = helpers::get_poem(slug.clone());
 | 
			
		||||
    cx.render(rsx! {
 | 
			
		||||
        Title { title: title, is_html: true }
 | 
			
		||||
        Title { title: title, is_html: true, user_prefs: UserPrefs::new(ThemePref::Auto, FontPref::OpenDyslexic)}
 | 
			
		||||
        MakePoem{
 | 
			
		||||
            PoemContent { content: content, creation_date: creation_date }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -47,8 +48,8 @@ pub fn PoemContent(cx: Scope<PoemData>) -> Element {
 | 
			
		|||
    #[cfg(any(target_family = "unix", target_family = "windows"))]
 | 
			
		||||
    return cx.render(rsx! {
 | 
			
		||||
        div { class: "flex p-2 mx-auto max-w-full justify-center",
 | 
			
		||||
            details { class: "group p-4 max-w-fit space-y-4 bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark ring-4 ring-alice-werefox-red-dark dark:ring-alice-werefox-red text-alice-werefox-grey-dark dark:text-alice-werefox-grey-light",
 | 
			
		||||
                summary { class: "group-open:before:content-['Close'] before:content-['Open'] flex justify-center p-2 ring-2 bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark ring-alice-werefox-red-dark dark:ring-alice-werefox-red text-alice-werefox-grey-dark dark:text-alice-werefox-grey-light hover:text-alice-werefox-blue-dark dark:hover:text-alice-werefox-blue-light hover:ring-alice-werefox-blue dark:hover:ring-alice-werefox-blue hover:animate-yip transition",
 | 
			
		||||
            details { class: "group p-4 max-w-fit space-y-4",
 | 
			
		||||
                summary { class: "group-open:before:content-['Close'] before:content-['Open'] flex justify-center p-2 ring-2",
 | 
			
		||||
                }
 | 
			
		||||
                div { class: "font-nerd flex flex-col space-y-4 py-4", "{content}{creation_date}"
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -58,8 +59,8 @@ pub fn PoemContent(cx: Scope<PoemData>) -> Element {
 | 
			
		|||
    #[cfg(target_family = "wasm")]
 | 
			
		||||
    return cx.render(rsx! {
 | 
			
		||||
        div { class: "flex p-2 mx-auto max-w-full justify-center",
 | 
			
		||||
            details { class: "group p-4 max-w-fit space-y-4 bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark ring-4 ring-alice-werefox-red-dark dark:ring-alice-werefox-red text-alice-werefox-grey-dark dark:text-alice-werefox-grey-light",
 | 
			
		||||
                summary { class: "group-open:before:content-['Close'] before:content-['Open'] flex justify-center p-2 ring-2 bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark ring-alice-werefox-red-dark dark:ring-alice-werefox-red text-alice-werefox-grey-dark dark:text-alice-werefox-grey-light hover:text-alice-werefox-blue-dark dark:hover:text-alice-werefox-blue-light hover:ring-alice-werefox-blue dark:hover:ring-alice-werefox-blue hover:animate-yip transition",
 | 
			
		||||
            details { class: "group p-4 max-w-fit space-y-4",
 | 
			
		||||
                summary { class: "group-open:before:content-['Close'] before:content-['Open'] flex justify-center p-2 ring-2",
 | 
			
		||||
                }
 | 
			
		||||
                div { class: "font-nerd flex flex-col space-y-4 py-4", 
 | 
			
		||||
                    dangerous_inner_html: "{content}{creation_date}",
 | 
			
		||||
| 
						 | 
				
			
			@ -67,4 +68,4 @@ pub fn PoemContent(cx: Scope<PoemData>) -> Element {
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,14 @@
 | 
			
		|||
use dioxus::prelude::*;
 | 
			
		||||
use crate::utils::prop_structs::TitleProps;
 | 
			
		||||
use dioxus::prelude::*;
 | 
			
		||||
 | 
			
		||||
pub fn Title(cx: Scope<TitleProps>) -> Element {
 | 
			
		||||
    let user_prefs = cx.props.user_prefs.clone();
 | 
			
		||||
    let title = cx.props.title.clone();
 | 
			
		||||
    let is_html = cx.props.is_html;
 | 
			
		||||
    cx.render(rsx!{
 | 
			
		||||
        div { class: "p-4 ring-4 bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark ring-alice-werefox-red-dark dark:ring-alice-werefox-red text-alice-werefox-grey-dark dark:text-alice-werefox-grey-light",
 | 
			
		||||
        div { class: "p-4 ring-4",
 | 
			
		||||
            span { class: "flex flex-row mx-auto max-w-full justify-center text-xl text-center",
 | 
			
		||||
                TitleHtml { title: title, is_html: is_html }
 | 
			
		||||
                TitleHtml { title: title, is_html: is_html, user_prefs: user_prefs }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
| 
						 | 
				
			
			@ -17,22 +18,22 @@ fn TitleHtml(cx: Scope<TitleProps>) -> Element {
 | 
			
		|||
    let title = cx.props.title.clone();
 | 
			
		||||
    if cx.props.is_html {
 | 
			
		||||
        #[cfg(any(target_family = "unix", target_family = "windows"))]
 | 
			
		||||
        return cx.render(rsx!{
 | 
			
		||||
        return cx.render(rsx! {
 | 
			
		||||
            span { class: "flex flex-row align-middle mx-auto max-w-full justify-center",
 | 
			
		||||
                "{title} "
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        #[cfg(target_family = "wasm")]
 | 
			
		||||
        return cx.render(rsx!{
 | 
			
		||||
        return cx.render(rsx! {
 | 
			
		||||
            span { class: "flex flex-row align-middle mx-auto max-w-full justify-center",
 | 
			
		||||
                div { dangerous_inner_html: "{title}", }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    } else {
 | 
			
		||||
        return cx.render(rsx!{
 | 
			
		||||
        return cx.render(rsx! {
 | 
			
		||||
            span {
 | 
			
		||||
                "{title}"
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,3 +6,8 @@
 | 
			
		|||
  font-family: "OpenDyslexic";
 | 
			
		||||
  src: url("/fonts/OpenDyslexic-Regular.otf");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@font-face {
 | 
			
		||||
  font-family: "DejaVuSansMono";
 | 
			
		||||
  src: url("/fonts/DejaVuSansMono.ttf");
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,50 +4,50 @@
 | 
			
		|||
 | 
			
		||||
#![allow(non_snake_case)]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
mod components;
 | 
			
		||||
pub mod utils;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// A module that handles the functions needed
 | 
			
		||||
/// to render the site.
 | 
			
		||||
pub mod void_app {
 | 
			
		||||
 | 
			
		||||
    // import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
 | 
			
		||||
    pub use dioxus::prelude::*;
 | 
			
		||||
    use rust_embed::RustEmbed;
 | 
			
		||||
 | 
			
		||||
    use crate::components::void_buttons::*;
 | 
			
		||||
    use crate::components::void_content::*;
 | 
			
		||||
    use crate::components::void_footer::*;
 | 
			
		||||
    use crate::components::void_page::PageBase;
 | 
			
		||||
    use crate::components::void_poem::*;
 | 
			
		||||
    use crate::components::void_title::*;
 | 
			
		||||
    use crate::utils::helpers;
 | 
			
		||||
    use crate::utils::prop_structs::*;
 | 
			
		||||
    use crate::utils::user_prefs::*;
 | 
			
		||||
 | 
			
		||||
    #[cfg(any(target_family = "wasm"))]
 | 
			
		||||
    use dioxus_helmet::Helmet;
 | 
			
		||||
    #[cfg(any(target_family = "wasm"))]
 | 
			
		||||
    use dioxus_router::{Link, Route, Router, Redirect};
 | 
			
		||||
    use dioxus_router::{Link, Redirect, Route, Router};
 | 
			
		||||
    #[cfg(any(target_family = "wasm"))]
 | 
			
		||||
    use dioxus_use_storage::use_local_storage;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    #[derive(RustEmbed)]
 | 
			
		||||
    #[folder = "data/poems"]
 | 
			
		||||
    pub struct Poems;
 | 
			
		||||
 | 
			
		||||
    #[cfg(target_family = "wasm")]
 | 
			
		||||
    pub fn DioxusApp(cx: Scope) -> Element {
 | 
			
		||||
        // use dioxus_router::Redirect;
 | 
			
		||||
 | 
			
		||||
        let user_prefs = UserPrefs::new(ThemePref::Auto, FontPref::OpenDyslexic);
 | 
			
		||||
 | 
			
		||||
        cx.render(rsx! {
 | 
			
		||||
            div { class: "bg-alice-werefox-grey-lightest ring-alice-werefox-red-dark text-alice-werefox-grey-dark dark:bg-alice-werefox-grey-dark dark:ring-alice-werefox-red dark:text-alice-werefox-grey-light let button_classes hover:text-alice-werefox-blue-dark hover:ring-alice-werefox-blue dark:hover:text-alice-werefox-blue-light dark:hover:ring-alice-werefox-blue hover:animate-yip transition" }
 | 
			
		||||
            Router {
 | 
			
		||||
                Route { to: "/", self::HomePage { dark_mode: true, } }
 | 
			
		||||
                Route { to: "/poems", 
 | 
			
		||||
                    PoemListPage { slug: "".to_string(), dark_mode: true, }
 | 
			
		||||
                }
 | 
			
		||||
                Route { to: "/poems/:slug", 
 | 
			
		||||
                    PoemPage { slug: "".to_string(), dark_mode: true, } 
 | 
			
		||||
                Route { to: "/",
 | 
			
		||||
                    self::HomePage { user_prefs }
 | 
			
		||||
                }
 | 
			
		||||
                Route { to: "/poems", PoemListPage { user_prefs } }
 | 
			
		||||
                Route { to: "/poems/:slug", PoemPage { slug: "".to_string(), user_prefs } }
 | 
			
		||||
                Route { to: "/settings", SettingsPage { user_prefs } }
 | 
			
		||||
                Route { to: "/settings/dark", SettingsPage { user_prefs } }
 | 
			
		||||
                Route { to: "/settings/font", SettingsPage { user_prefs } }
 | 
			
		||||
                Route { to: "", PageNotFound {} }
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
| 
						 | 
				
			
			@ -61,35 +61,22 @@ pub mod void_app {
 | 
			
		|||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /// Renders the app and returns the rendered Element.
 | 
			
		||||
    pub fn HomePage(cx: Scope<DarkModeProps>) -> Element {
 | 
			
		||||
        #[cfg(any(target_family = "unix", target_family = "windows"))]
 | 
			
		||||
        let slug = cx.props.slug.clone().expect("Slug for dark mode redirect.");
 | 
			
		||||
        #[cfg(target_family = "wasm")]
 | 
			
		||||
        let slug = "".to_string();
 | 
			
		||||
    pub fn HomePage(cx: Scope<UserPrefs>) -> Element {
 | 
			
		||||
        let user_prefs = cx.props.clone();
 | 
			
		||||
        let (user_theme, user_font) = user_prefs.get_prefs(false);
 | 
			
		||||
        let title = "A Letter to the Void".to_string();
 | 
			
		||||
        cx.render(rsx!{
 | 
			
		||||
            div { class: "min-h-screen font-nerd bg-alice-werefox-grey-light dark:bg-alice-werefox-grey",
 | 
			
		||||
                div { class: "container space-y-4 mx-auto p-4",
 | 
			
		||||
                    Title { title: title, is_html: false }
 | 
			
		||||
                    div { class: "flex p-4 ml-2 mr-2 ring-4 bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark ring-alice-werefox-red-dark dark:ring-alice-werefox-red text-alice-werefox-grey-dark dark:text-alice-werefox-grey-light",
 | 
			
		||||
                        p { class: "text-lg text-center",
 | 
			
		||||
                            "Welcome, and I hope you enjoy your stay!"
 | 
			
		||||
                            br {}
 | 
			
		||||
                            "\"A Letter to the Void\" is a passion project of mine in which I wrote poems about my past life experiences, present, and hopes for the future throughout my transition."
 | 
			
		||||
                            br {}
 | 
			
		||||
                            "The topics range from my feelings through transitioning (of course), past abuse, mental health exploration, and an overall journey to grow and become a better creature."
 | 
			
		||||
                            br {}
 | 
			
		||||
                            "I hope you enjoy the time you spend here, and sincerely, thank you."
 | 
			
		||||
                            br {}
 | 
			
		||||
                            br {}
 | 
			
		||||
                            "🖤 Alice Icehart Werefox"
 | 
			
		||||
                        }
 | 
			
		||||
            // div { class: "bg-alice-werefox-grey-lightest ring-alice-werefox-red-dark text-alice-werefox-grey-dark dark:bg-alice-werefox-grey-dark dark:ring-alice-werefox-red dark:text-alice-werefox-grey-light let button_classes hover:text-alice-werefox-blue-dark hover:ring-alice-werefox-blue dark:hover:text-alice-werefox-blue-light dark:hover:ring-alice-werefox-blue hover:animate-yip transition", hidden: true }
 | 
			
		||||
            div { class: "{user_theme} {user_font}",
 | 
			
		||||
                PageBase {
 | 
			
		||||
                    Title { title: title, is_html: false, user_prefs: user_prefs }
 | 
			
		||||
                    RenderContent { content: helpers::get_homepage_paragraph() }
 | 
			
		||||
                    ButtonGroup {
 | 
			
		||||
                        NavigationButton { title: "See Latest Entry".to_string(), slug: helpers::get_latest_entry("".to_string()) }
 | 
			
		||||
                        NavigationButton { title: "See Oldest Entry".to_string(), slug: helpers::get_oldest_entry("".to_string()) }
 | 
			
		||||
                        NavigationButton { title: "See All Entries".to_string(), slug: "/poems".to_string() }
 | 
			
		||||
                    }
 | 
			
		||||
                    NavigationButton { title: "See Latest Entry".to_string(), slug: helpers::get_latest_entry(slug.clone()) }
 | 
			
		||||
                    NavigationButton { title: "See Oldest Entry".to_string(), slug: helpers::get_oldest_entry(slug.clone()) }
 | 
			
		||||
                    NavigationButton { title: "See All Entries".to_string(), slug: "/poems".to_string() }
 | 
			
		||||
                    Footer {}
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -97,11 +84,13 @@ pub mod void_app {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /// Renders the app and returns the rendered Element.
 | 
			
		||||
    pub fn PoemListPage(cx: Scope<DarkModeProps>) -> Element {
 | 
			
		||||
        cx.render(rsx!{
 | 
			
		||||
            div { class: "min-h-screen font-nerd bg-alice-werefox-grey-light dark:bg-alice-werefox-grey",
 | 
			
		||||
                div { class: "container space-y-4 mx-auto p-4",
 | 
			
		||||
                    Title { title: "A Letter to the Void".to_string(), is_html: false }
 | 
			
		||||
    pub fn PoemListPage(cx: Scope<UserPrefs>) -> Element {
 | 
			
		||||
        let user_prefs = cx.props.clone();
 | 
			
		||||
        let (user_theme, user_font) = user_prefs.get_prefs(false);
 | 
			
		||||
        cx.render(rsx! {
 | 
			
		||||
            div { class: "{user_theme} {user_font}",
 | 
			
		||||
                PageBase {
 | 
			
		||||
                    Title { title: "A Letter to the Void".to_string(), is_html: false, user_prefs: user_prefs }
 | 
			
		||||
                    BackToHomePage {}
 | 
			
		||||
                    PoemList {}
 | 
			
		||||
                    BackToHomePage {}
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +101,8 @@ pub mod void_app {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn PoemPage(cx: Scope<PoemRequest>) -> Element {
 | 
			
		||||
        let user_prefs = cx.props.user_prefs.clone();
 | 
			
		||||
        let (user_theme, user_font) = user_prefs.get_prefs(false);
 | 
			
		||||
        #[cfg(any(target_family = "unix", target_family = "windows"))]
 | 
			
		||||
        let slug = cx.props.slug.clone();
 | 
			
		||||
        #[cfg(target_family = "wasm")]
 | 
			
		||||
| 
						 | 
				
			
			@ -120,17 +111,12 @@ pub mod void_app {
 | 
			
		|||
                .segment("slug")
 | 
			
		||||
                .expect("No slug specified."),
 | 
			
		||||
        );
 | 
			
		||||
        let dark_mode = cx
 | 
			
		||||
            .props
 | 
			
		||||
            .dark_mode
 | 
			
		||||
            .clone()
 | 
			
		||||
            .expect("Dark mode prop not passed.");
 | 
			
		||||
        cx.render(rsx!{
 | 
			
		||||
            div { class: "min-h-screen font-nerd bg-alice-werefox-grey-light dark:bg-alice-werefox-grey",
 | 
			
		||||
                div { class: "container space-y-4 mx-auto p-4",
 | 
			
		||||
            div { class: "{user_theme} {user_font}",
 | 
			
		||||
                PageBase {
 | 
			
		||||
                    BackToHomePage {}
 | 
			
		||||
                    GetPoem { slug: slug.clone(), dark_mode: dark_mode }
 | 
			
		||||
                    div { class: "grid md:grid-cols-4 md:grid-rows-1 grid-cols-1 grid-rows-4 gap-y-4",
 | 
			
		||||
                    GetPoem { slug: slug.clone() }
 | 
			
		||||
                    ButtonGroup {
 | 
			
		||||
                        NavigationButton { title: "Oldest".to_string(), slug: helpers::get_oldest_entry(slug.clone()) }
 | 
			
		||||
                        NavigationButton { title: "Previous".to_string(), slug: helpers::get_previous_entry(slug.clone()) }
 | 
			
		||||
                        NavigationButton { title: "Next".to_string(), slug: helpers::get_next_entry(slug.clone()) }
 | 
			
		||||
| 
						 | 
				
			
			@ -142,4 +128,33 @@ pub mod void_app {
 | 
			
		|||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn SettingsPage(cx: Scope<UserPrefs>) -> Element {
 | 
			
		||||
        let user_prefs = cx.props.clone();
 | 
			
		||||
        let (user_theme, user_font) = user_prefs.get_prefs(false);
 | 
			
		||||
        cx.render(rsx! {
 | 
			
		||||
            div { class: "{user_theme} {user_font}",
 | 
			
		||||
                PageBase {
 | 
			
		||||
                    Title { title: "Settings".to_string(), is_html: false, user_prefs: user_prefs }
 | 
			
		||||
                    BackToHomePage {}
 | 
			
		||||
                    div { class: "grid grid-flow-row space-y-4",
 | 
			
		||||
                        ButtonGroup {
 | 
			
		||||
                            NavigationButton { title: "Light".to_string(), slug: "/settings/?theme=light".to_string() }
 | 
			
		||||
                            NavigationButton { title: "Dark".to_string(), slug: "/settings/?theme=dark".to_string() }
 | 
			
		||||
                            NavigationButton { title: "Auto".to_string(), slug: "/settings/?theme=auto".to_string() }
 | 
			
		||||
                        }
 | 
			
		||||
                        ButtonGroup {
 | 
			
		||||
                            span { class: "font-nerd",
 | 
			
		||||
                                NavigationButton { title: "Nerd Font".to_string(), slug: "/settings/?font=nerd".to_string() }
 | 
			
		||||
                            }
 | 
			
		||||
                            span { class: "font-open",
 | 
			
		||||
                                NavigationButton { title: "Open Dyslexic".to_string(), slug: "/settings/?font=open".to_string() }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    BackToHomePage {}
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,3 @@
 | 
			
		|||
 | 
			
		||||
#[cfg(target_family = "wasm")]
 | 
			
		||||
use console_error_panic_hook;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,3 @@
 | 
			
		|||
pub mod helpers;
 | 
			
		||||
pub mod prop_structs;
 | 
			
		||||
pub mod user_prefs;
 | 
			
		||||
pub mod user_prefs;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,21 @@
 | 
			
		|||
use std::collections::VecDeque;
 | 
			
		||||
use crate::void_app::Poems;
 | 
			
		||||
use rust_embed::RustEmbed;
 | 
			
		||||
use markdown::Options;
 | 
			
		||||
use std::collections::VecDeque;
 | 
			
		||||
 | 
			
		||||
#[derive(RustEmbed)]
 | 
			
		||||
#[folder = "data/other"]
 | 
			
		||||
struct OtherData;
 | 
			
		||||
 | 
			
		||||
#[derive(RustEmbed)]
 | 
			
		||||
#[folder = "data/poems"]
 | 
			
		||||
struct Poems;
 | 
			
		||||
 | 
			
		||||
pub fn get_homepage_paragraph() -> String {
 | 
			
		||||
    let homepage_paragraph_content = OtherData::get("homepage.md").expect("Found homepage paragraph.");
 | 
			
		||||
    let homepage_paragraph_to_string = std::str::from_utf8(homepage_paragraph_content.data.as_ref()).expect("Homepage file is valid UTF-8");
 | 
			
		||||
    let test = markdown::to_html_with_options(homepage_paragraph_to_string, &Options::gfm()).unwrap();
 | 
			
		||||
    test
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn get_poem(slug: String) -> (String, String, String) {
 | 
			
		||||
    let filename = String::from(String::from(slug.clone()) + ".md");
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +31,11 @@ pub fn get_poem(slug: String) -> (String, String, String) {
 | 
			
		|||
        markdown::to_html_with_options(poem_title, &Options::gfm()).unwrap();
 | 
			
		||||
    let poem_content_to_html_string =
 | 
			
		||||
        markdown::to_html_with_options(poem_content.as_str(), &Options::gfm()).unwrap();
 | 
			
		||||
    (poem_title_to_html_string, poem_content_to_html_string, creation_date)
 | 
			
		||||
    (
 | 
			
		||||
        poem_title_to_html_string,
 | 
			
		||||
        poem_content_to_html_string,
 | 
			
		||||
        creation_date,
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn get_poem_list() -> Vec<(String, String)> {
 | 
			
		||||
| 
						 | 
				
			
			@ -94,4 +113,4 @@ pub fn get_next_entry(current: String) -> String {
 | 
			
		|||
        Some(entry) => format!("/poems/{entry}"),
 | 
			
		||||
        None => format!("/poems/{current}"),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,21 +1,23 @@
 | 
			
		|||
use crate::void_app::{Element, Props};
 | 
			
		||||
 | 
			
		||||
use super::user_prefs::UserPrefs;
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Props)]
 | 
			
		||||
pub struct PoemRequest {
 | 
			
		||||
    pub slug: String,
 | 
			
		||||
    pub dark_mode: Option<bool>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Props)]
 | 
			
		||||
pub struct DarkModeProps {
 | 
			
		||||
    pub dark_mode: bool,
 | 
			
		||||
    pub slug: Option<String>,
 | 
			
		||||
    pub user_prefs: UserPrefs,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Props)]
 | 
			
		||||
pub struct TitleProps {
 | 
			
		||||
    pub title: String,
 | 
			
		||||
    pub is_html: bool,
 | 
			
		||||
    pub user_prefs: UserPrefs,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Props)]
 | 
			
		||||
pub struct ContentProps {
 | 
			
		||||
    pub content: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Props)]
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +35,18 @@ pub struct PoemData {
 | 
			
		|||
    pub dark_mode: Option<bool>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// These next three should all just be one prop.
 | 
			
		||||
#[derive(Props)]
 | 
			
		||||
pub struct PoemChildren<'a> {
 | 
			
		||||
    pub children: Element<'a>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Props)]
 | 
			
		||||
pub struct PageChildren<'a> {
 | 
			
		||||
    pub children: Element<'a>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Props)]
 | 
			
		||||
pub struct ContentChildren<'a> {
 | 
			
		||||
    pub children: Element<'a>,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,24 +1,29 @@
 | 
			
		|||
use dioxus::prelude::*;
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Props, Clone)]
 | 
			
		||||
pub struct UserPrefs {
 | 
			
		||||
    theme: ThemePref,
 | 
			
		||||
    font: FontPref,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Clone)]
 | 
			
		||||
pub enum ThemePref {
 | 
			
		||||
    Light,
 | 
			
		||||
    Dark,
 | 
			
		||||
    Auto,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Clone)]
 | 
			
		||||
pub enum FontPref {
 | 
			
		||||
    NerdFont,
 | 
			
		||||
    OpenDyslexic,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl UserPrefs {
 | 
			
		||||
    pub fn new() -> UserPrefs {
 | 
			
		||||
    pub fn new(theme: ThemePref, font: FontPref) -> UserPrefs {
 | 
			
		||||
        UserPrefs {
 | 
			
		||||
            theme: ThemePref::Auto,
 | 
			
		||||
            font: FontPref::OpenDyslexic,
 | 
			
		||||
            theme,
 | 
			
		||||
            font,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,8 +41,8 @@ impl UserPrefs {
 | 
			
		|||
 | 
			
		||||
    pub fn get_font(&self) -> String {
 | 
			
		||||
        match &self.font {
 | 
			
		||||
            FontPref::OpenDyslexic => "...".to_string(),
 | 
			
		||||
            FontPref::NerdFont => "...".to_string(),
 | 
			
		||||
            FontPref::OpenDyslexic => "font-open".to_string(),
 | 
			
		||||
            FontPref::NerdFont => "font-nerd".to_string(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -77,10 +82,10 @@ impl UserPrefs {
 | 
			
		|||
    }
 | 
			
		||||
    fn auto_theme_classes(is_button: bool) -> String {
 | 
			
		||||
        format!(
 | 
			
		||||
            "{}{}",
 | 
			
		||||
            "{} {}",
 | 
			
		||||
            Self::light_theme_classes(is_button)
 | 
			
		||||
                .split(" ")
 | 
			
		||||
                .map(|c| if c == "transition" { "" } else { c })
 | 
			
		||||
                .map(|c| if c == "transition" { "".to_string() } else { format!("{c} ") })
 | 
			
		||||
                .collect::<String>(),
 | 
			
		||||
            Self::dark_theme_classes(is_button)
 | 
			
		||||
                .split(" ")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,8 @@ module.exports = {
 | 
			
		|||
  theme: {
 | 
			
		||||
    extend: {
 | 
			
		||||
      fontFamily: {
 | 
			
		||||
        nerd: ["OpenDyslexic"],
 | 
			
		||||
        nerd: ["DejaVuSansMono"],
 | 
			
		||||
        open: ["OpenDyslexic"],
 | 
			
		||||
      },
 | 
			
		||||
      colors: {
 | 
			
		||||
        "ada-werefox-cyan": {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue