Implemented user settings feature at a basic level, need to fix CSS for components.

This commit is contained in:
Ada Werefox 2023-04-16 21:46:10 -05:00
parent 9d46693ba8
commit b78e2c2d57
24 changed files with 402 additions and 185 deletions

6
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,6 @@
{
"rust-analyzer.linkedProjects": [
"./void-fe/Cargo.toml",
"./void-fe/Cargo.toml"
]
}

Binary file not shown.

File diff suppressed because one or more lines are too long

76
rustfmt.toml Normal file
View 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

View File

@ -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(())
}
}

View File

@ -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())
}
}

View File

@ -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 = []

View File

@ -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());
// }
// }
// }

View 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

View File

@ -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;

View File

@ -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
}
})
}

View 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}",
}
});
}

View File

@ -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"
}
}
})
}
}

View 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
}
}
})
}

View File

@ -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 {
}
}
});
}
}

View File

@ -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}&nbsp;"
}
});
#[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}"
}
})
});
}
}
}

View File

@ -6,3 +6,8 @@
font-family: "OpenDyslexic";
src: url("/fonts/OpenDyslexic-Regular.otf");
}
@font-face {
font-family: "DejaVuSansMono";
src: url("/fonts/DejaVuSansMono.ttf");
}

View File

@ -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 {}
}
}
})
}
}

View File

@ -1,4 +1,3 @@
#[cfg(target_family = "wasm")]
use console_error_panic_hook;

View File

@ -1,3 +1,3 @@
pub mod helpers;
pub mod prop_structs;
pub mod user_prefs;
pub mod user_prefs;

View File

@ -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}"),
}
}
}

View File

@ -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>,
}

View File

@ -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(" ")

View File

@ -8,7 +8,8 @@ module.exports = {
theme: {
extend: {
fontFamily: {
nerd: ["OpenDyslexic"],
nerd: ["DejaVuSansMono"],
open: ["OpenDyslexic"],
},
colors: {
"ada-werefox-cyan": {