Implemented user settings feature at a basic level, need to fix CSS for components.
This commit is contained in:
parent
9d46693ba8
commit
b78e2c2d57
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 New Issue
Block a user