previous and next entries, major refactoring on Dioxus frontend, more reliable routing on backend, some minor style adjustments.
This commit is contained in:
parent
c5e4cd605d
commit
4830f0a600
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
FROM rust:alpine
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
RUN apk add git musl-dev
|
||||||
|
|
||||||
|
COPY public/ public/
|
||||||
|
COPY void-be/ void-be/
|
||||||
|
|
||||||
|
# We don't need all the front end directory files
|
||||||
|
RUN mkdir void-fe
|
||||||
|
COPY void-fe/src/ void-fe/src/
|
||||||
|
COPY void-fe/data/ void-fe/data/
|
||||||
|
COPY void-fe/Cargo.toml void-fe/Cargo.toml
|
||||||
|
|
||||||
|
COPY src/ src/
|
||||||
|
COPY templates/ templates/
|
||||||
|
COPY Cargo.toml .
|
||||||
|
COPY Rocket.toml .
|
||||||
|
|
||||||
|
RUN cargo install --config "net.git-fetch-with-cli=true" --path .
|
||||||
|
|
||||||
|
ENV RUST_ADDRESS=0.0.0.0
|
||||||
|
|
||||||
|
CMD ["cargo", "run", "--release"]
|
@ -1,5 +1,5 @@
|
|||||||
[default]
|
[default]
|
||||||
port = 3469
|
port = 8345
|
||||||
# workers = 16
|
# workers = 16
|
||||||
# max_blocking = 512
|
# max_blocking = 512
|
||||||
# keep_alive = 5
|
# keep_alive = 5
|
||||||
|
10
docker-compose.yml
Normal file
10
docker-compose.yml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: void-werefox-cafe:latest
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
ports:
|
||||||
|
- "8345:8345"
|
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
@ -8,24 +8,34 @@ extern crate rocket;
|
|||||||
/// A module that handles the backend for the site.
|
/// A module that handles the backend for the site.
|
||||||
pub mod web_app_backend {
|
pub mod web_app_backend {
|
||||||
|
|
||||||
use std::path::{PathBuf, Path};
|
|
||||||
|
|
||||||
use rocket::fs::FileServer;
|
use rocket::fs::FileServer;
|
||||||
use rocket::http::{Cookie, CookieJar};
|
use rocket::http::{Cookie, CookieJar};
|
||||||
use rocket::response::Redirect;
|
use rocket::response::Redirect;
|
||||||
use rocket::{Build, Rocket};
|
use rocket::{Build, Rocket};
|
||||||
use rocket_dyn_templates::{context, Template};
|
use rocket_dyn_templates::{context, Template};
|
||||||
use void_fe::void_app::{self, PoemRequest, VirtualDom, HomeProps};
|
use void_fe::void_app::{self, DarkModeProps, PoemRequest, VirtualDom};
|
||||||
|
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
async fn index(cookies: &CookieJar<'_>) -> Template {
|
async fn index(cookies: &CookieJar<'_>) -> Template {
|
||||||
let dark_mode = match cookies.get("dark-mode") {
|
let dark_mode = match cookies.get("dark-mode") {
|
||||||
Some(_) => true,
|
Some(c) => {
|
||||||
|
if c.value() == "true" {
|
||||||
|
true
|
||||||
|
} else if c.value() == "false" {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
None => false,
|
None => false,
|
||||||
};
|
};
|
||||||
let mut vdom = VirtualDom::new_with_props(void_app::HomePage, HomeProps {
|
let mut vdom = VirtualDom::new_with_props(
|
||||||
dark_mode: dark_mode,
|
void_app::HomePage,
|
||||||
});
|
DarkModeProps {
|
||||||
|
slug: Some(String::new()),
|
||||||
|
dark_mode,
|
||||||
|
},
|
||||||
|
);
|
||||||
let _ = vdom.rebuild();
|
let _ = vdom.rebuild();
|
||||||
let output = dioxus_ssr::render(&vdom);
|
let output = dioxus_ssr::render(&vdom);
|
||||||
Template::render(
|
Template::render(
|
||||||
@ -42,7 +52,7 @@ pub mod web_app_backend {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/?set-dark-mode")]
|
#[get("/toggle-dark-mode")]
|
||||||
async fn dark_mode_root(cookies: &CookieJar<'_>) -> Redirect {
|
async fn dark_mode_root(cookies: &CookieJar<'_>) -> Redirect {
|
||||||
match cookies.get("dark-mode") {
|
match cookies.get("dark-mode") {
|
||||||
Some(_) => cookies.remove(Cookie::named("dark-mode")),
|
Some(_) => cookies.remove(Cookie::named("dark-mode")),
|
||||||
@ -51,15 +61,27 @@ pub mod web_app_backend {
|
|||||||
Redirect::to("/")
|
Redirect::to("/")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/poems")]
|
#[get("/")]
|
||||||
async fn poem_list(cookies: &CookieJar<'_>) -> Template {
|
async fn poem_list(cookies: &CookieJar<'_>) -> Template {
|
||||||
let dark_mode = match cookies.get("dark-mode") {
|
let dark_mode = match cookies.get("dark-mode") {
|
||||||
Some(_) => true,
|
Some(c) => {
|
||||||
|
if c.value() == "true" {
|
||||||
|
true
|
||||||
|
} else if c.value() == "false" {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
None => false,
|
None => false,
|
||||||
};
|
};
|
||||||
let mut vdom = VirtualDom::new_with_props(void_app::PoemListPage, HomeProps {
|
let mut vdom = VirtualDom::new_with_props(
|
||||||
dark_mode: dark_mode,
|
void_app::PoemListPage,
|
||||||
});
|
DarkModeProps {
|
||||||
|
slug: Some(String::from("/poems")),
|
||||||
|
dark_mode,
|
||||||
|
},
|
||||||
|
);
|
||||||
let _ = vdom.rebuild();
|
let _ = vdom.rebuild();
|
||||||
let output = dioxus_ssr::render(&vdom);
|
let output = dioxus_ssr::render(&vdom);
|
||||||
Template::render(
|
Template::render(
|
||||||
@ -76,45 +98,65 @@ pub mod web_app_backend {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/poems?set-dark-mode")]
|
#[get("/toggle-dark-mode")]
|
||||||
async fn poems_dark_mode(cookies: &CookieJar<'_>) -> Redirect {
|
async fn poems_dark_mode(cookies: &CookieJar<'_>) -> Redirect {
|
||||||
dark_mode(cookies, PathBuf::new()).await
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[get("/poems/<entry>?set-dark-mode")]
|
|
||||||
async fn entry_dark_mode(cookies: &CookieJar<'_>, entry: PathBuf) -> Redirect {
|
|
||||||
dark_mode(cookies, entry).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn dark_mode(cookies: &CookieJar<'_>, entry: PathBuf) -> Redirect {
|
|
||||||
match cookies.get("dark-mode") {
|
match cookies.get("dark-mode") {
|
||||||
Some(_) => cookies.remove(Cookie::named("dark-mode")),
|
Some(_) => cookies.remove(Cookie::named("dark-mode")),
|
||||||
None => cookies.add(Cookie::new("dark-mode", "true")),
|
None => cookies.add(Cookie::new("dark-mode", "true")),
|
||||||
};
|
};
|
||||||
let path_str = String::from(Path::new("/poems/").join(entry).to_str().expect("valid path"));
|
Redirect::to("/poems/")
|
||||||
let _angy = path_str.as_str().to_owned();
|
|
||||||
Redirect::to(path_str.as_str().to_owned().clone())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/poems/latest")]
|
#[get("/<entry>/toggle-dark-mode")]
|
||||||
|
async fn entry_dark_mode(cookies: &CookieJar<'_>, entry: &str) -> Redirect {
|
||||||
|
match cookies.get("dark-mode") {
|
||||||
|
Some(_) => cookies.remove(Cookie::named("dark-mode")),
|
||||||
|
None => cookies.add(Cookie::new("dark-mode", "true")),
|
||||||
|
};
|
||||||
|
Redirect::to(format!("/poems/{entry}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
async fn latest_entry() -> Redirect {
|
async fn latest_entry() -> Redirect {
|
||||||
let slug = void_app::get_latest_entry();
|
let slug = void_app::get_latest_entry();
|
||||||
let uri = String::from("/poems/".to_string() + slug.as_str());
|
let uri = String::from("/poems/".to_string() + slug.as_str());
|
||||||
Redirect::to(uri)
|
Redirect::to(uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/poems/oldest")]
|
#[get("/")]
|
||||||
async fn oldest_entry() -> Redirect {
|
async fn oldest_entry() -> Redirect {
|
||||||
let slug = void_app::get_oldest_entry();
|
let slug = void_app::get_oldest_entry();
|
||||||
let uri = String::from("/poems/".to_string() + slug.as_str());
|
let uri = String::from("/poems/".to_string() + slug.as_str());
|
||||||
Redirect::to(uri)
|
Redirect::to(uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/poems/<entry>")]
|
#[get("/?<current>")]
|
||||||
|
async fn previous_entry(current: &str) -> Redirect {
|
||||||
|
let previous =
|
||||||
|
void_app::get_previous_entry(current.to_string()).expect("There is a previous entry.");
|
||||||
|
let uri = String::from("/poems/".to_string() + previous.as_str());
|
||||||
|
Redirect::to(uri)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/?<current>")]
|
||||||
|
async fn next_entry(current: &str) -> Redirect {
|
||||||
|
let next = void_app::get_next_entry(current.to_string()).expect("There is a next entry.");
|
||||||
|
let uri = String::from("/poems/".to_string() + next.as_str());
|
||||||
|
Redirect::to(uri)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/<entry>")]
|
||||||
async fn poem(cookies: &CookieJar<'_>, entry: &str) -> Template {
|
async fn poem(cookies: &CookieJar<'_>, entry: &str) -> Template {
|
||||||
let dark_mode = match cookies.get("dark-mode") {
|
let dark_mode = match cookies.get("dark-mode") {
|
||||||
Some(_) => true,
|
Some(c) => {
|
||||||
|
if c.value() == "true" {
|
||||||
|
true
|
||||||
|
} else if c.value() == "false" {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
None => false,
|
None => false,
|
||||||
};
|
};
|
||||||
let mut vdom = VirtualDom::new_with_props(
|
let mut vdom = VirtualDom::new_with_props(
|
||||||
@ -146,7 +188,15 @@ pub mod web_app_backend {
|
|||||||
.mount("/images", FileServer::from("public/images"))
|
.mount("/images", FileServer::from("public/images"))
|
||||||
.mount("/styles", FileServer::from("public/styles"))
|
.mount("/styles", FileServer::from("public/styles"))
|
||||||
.mount("/fonts", FileServer::from("public/fonts"))
|
.mount("/fonts", FileServer::from("public/fonts"))
|
||||||
.mount("/", routes![dark_mode_root, index, poems_dark_mode, poem_list, latest_entry, oldest_entry, entry_dark_mode, poem])
|
.mount("/poems/oldest", routes![oldest_entry])
|
||||||
|
.mount("/poems/previous", routes![previous_entry])
|
||||||
|
.mount("/poems/next", routes![next_entry])
|
||||||
|
.mount("/poems/latest", routes![latest_entry])
|
||||||
|
.mount(
|
||||||
|
"/poems",
|
||||||
|
routes![poems_dark_mode, poem_list, entry_dark_mode, poem],
|
||||||
|
)
|
||||||
|
.mount("/", routes![dark_mode_root, index])
|
||||||
.attach(Template::fairing())
|
.attach(Template::fairing())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
void-fe/.vscode/settings.json
vendored
Normal file
5
void-fe/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"rust-analyzer.linkedProjects": [
|
||||||
|
"./Cargo.toml"
|
||||||
|
]
|
||||||
|
}
|
0
void-fe/src/components/MakePoem.rs
Normal file
0
void-fe/src/components/MakePoem.rs
Normal file
@ -9,9 +9,9 @@
|
|||||||
pub mod void_app {
|
pub mod void_app {
|
||||||
// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
|
// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
|
||||||
pub use dioxus::prelude::*;
|
pub use dioxus::prelude::*;
|
||||||
use std::collections::VecDeque;
|
|
||||||
use markdown::{self, Options};
|
use markdown::{self, Options};
|
||||||
use rust_embed::RustEmbed;
|
use rust_embed::RustEmbed;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
#[cfg(any(target_family = "wasm"))]
|
#[cfg(any(target_family = "wasm"))]
|
||||||
use dioxus_helmet::Helmet;
|
use dioxus_helmet::Helmet;
|
||||||
@ -25,8 +25,15 @@ pub mod void_app {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Props)]
|
#[derive(PartialEq, Props)]
|
||||||
pub struct HomeProps {
|
pub struct DarkModeProps {
|
||||||
pub dark_mode: bool,
|
pub dark_mode: bool,
|
||||||
|
pub slug: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Props)]
|
||||||
|
struct ButtonProps {
|
||||||
|
title: String,
|
||||||
|
slug: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Props)]
|
#[derive(PartialEq, Props)]
|
||||||
@ -38,6 +45,11 @@ pub mod void_app {
|
|||||||
dark_mode: Option<bool>,
|
dark_mode: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Props)]
|
||||||
|
struct PoemChildren<'a> {
|
||||||
|
children: Element<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(RustEmbed)]
|
#[derive(RustEmbed)]
|
||||||
#[folder = "data/poems"]
|
#[folder = "data/poems"]
|
||||||
pub struct Poems;
|
pub struct Poems;
|
||||||
@ -64,39 +76,173 @@ pub mod void_app {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn MutantStandardFooter(cx: Scope) -> Element {
|
||||||
|
cx.render(rsx!{
|
||||||
|
div { class: "flex p-4 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"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_family = "windows", target_family = "unix"))]
|
||||||
|
fn BackToHomePage(cx: Scope) -> Element {
|
||||||
|
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: "/",
|
||||||
|
p {
|
||||||
|
"Back to the homepage"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
fn BackToHomePage(cx: Scope) -> Element {
|
||||||
|
cx.render(rsx!{
|
||||||
|
Link { to: "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: "/",
|
||||||
|
p {
|
||||||
|
"Back to the homepage"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_family = "windows", target_family = "unix"))]
|
||||||
|
fn NavigationButton(cx: Scope<ButtonProps>) -> Element {
|
||||||
|
let title = cx.props.title.clone();
|
||||||
|
let title_ref = title.as_str();
|
||||||
|
let slug = cx.props.slug.clone();
|
||||||
|
let slug_ref = slug.as_str();
|
||||||
|
cx.render(rsx!{
|
||||||
|
a { class: "flex mx-auto max-w-full justify-center p-4 ml-6 mr-6 text-xl 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 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}",
|
||||||
|
"{title_ref}"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
fn NavigationButton(cx: Scope<ButtonProps>) -> Element {
|
||||||
|
let title = cx.props.title.clone();
|
||||||
|
let title_ref = title.as_str();
|
||||||
|
let slug = cx.props.slug.clone();
|
||||||
|
let slug_ref = slug.as_str();
|
||||||
|
cx.render(rsx!{
|
||||||
|
Link { class: "flex mx-auto max-w-full justify-center p-4 text-xl 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 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,
|
||||||
|
title_ref
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_family = "windows", target_family = "unix"))]
|
||||||
|
fn DarkModeButton(cx: Scope<DarkModeProps>) -> Element {
|
||||||
|
let slug = cx
|
||||||
|
.props
|
||||||
|
.slug
|
||||||
|
.clone()
|
||||||
|
.expect("Slug found to know where to redirect after dark mode setting.");
|
||||||
|
let slug_ref = slug.as_str();
|
||||||
|
let dark_mode = cx.props.dark_mode;
|
||||||
|
cx.render(rsx! {
|
||||||
|
a { href: "{slug_ref}/toggle-dark-mode",
|
||||||
|
match dark_mode {
|
||||||
|
true => {
|
||||||
|
rsx! {
|
||||||
|
img { src: "/images/white_square_button.png",
|
||||||
|
alt: "A white square button that can toggle dark mode.",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false => {
|
||||||
|
rsx! {
|
||||||
|
img { src: "/images/black_square_button.png",
|
||||||
|
alt: "A black square button that can toggle dark mode.",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
fn DarkModeButton(cx: Scope<DarkModeProps>) -> Element {
|
||||||
|
let slug = cx
|
||||||
|
.props
|
||||||
|
.slug
|
||||||
|
.clone()
|
||||||
|
.expect("Slug found to know where to redirect after dark mode setting.");
|
||||||
|
let slug_ref = slug.as_str();
|
||||||
|
let dark_mode = cx.props.dark_mode;
|
||||||
|
cx.render(rsx! {
|
||||||
|
Link { to: "{slug_ref}/toggle-dark-mode",
|
||||||
|
match dark_mode {
|
||||||
|
true => {
|
||||||
|
rsx! {
|
||||||
|
img { src: "/images/white_square_button.png",
|
||||||
|
alt: "A white square button that can toggle dark mode.",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false => {
|
||||||
|
rsx! {
|
||||||
|
img { src: "/images/black_square_button.png",
|
||||||
|
alt: "A black square button that can toggle dark mode.",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_family = "unix", target_family = "windows"))]
|
||||||
|
fn PoemButton(cx: Scope<ButtonProps>) -> Element {
|
||||||
|
let title = cx.props.title.clone();
|
||||||
|
let title_ref = title.as_str();
|
||||||
|
let slug = cx.props.slug.clone();
|
||||||
|
let slug_ref = slug.as_str();
|
||||||
|
cx.render(rsx!{
|
||||||
|
a { href: "/poems/{slug_ref}",
|
||||||
|
li { class: "p-4 ml-6 mr-6 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",
|
||||||
|
"{title_ref}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
fn PoemButton(cx: Scope<ButtonProps>) -> Element {
|
||||||
|
let title = cx.props.title.clone();
|
||||||
|
let title_ref = title.as_str();
|
||||||
|
let slug = cx.props.slug.clone();
|
||||||
|
let slug_ref = slug.as_str();
|
||||||
|
cx.render(rsx!{
|
||||||
|
Link { to: "/poems/{slug_ref}",
|
||||||
|
li { class: "p-4 ml-6 mr-6 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",
|
||||||
|
dangerous_inner_html: "{title_ref}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Renders the app and returns the rendered Element.
|
/// Renders the app and returns the rendered Element.
|
||||||
pub fn HomePage(cx: Scope<HomeProps>) -> Element {
|
pub fn HomePage(cx: Scope<DarkModeProps>) -> Element {
|
||||||
|
let slug = cx.props.slug.clone().expect("Slug for dark mode redirect.");
|
||||||
|
// let slug_ref = slug.as_str();
|
||||||
let dark_mode = cx.props.dark_mode.clone();
|
let dark_mode = cx.props.dark_mode.clone();
|
||||||
cx.render(rsx!{
|
cx.render(rsx!{
|
||||||
div { class: "min-h-screen font-nerd bg-alice-werefox-grey-light dark:bg-alice-werefox-grey",
|
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: "container space-y-4 mx-auto p-4",
|
||||||
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-red-dark dark:text-alice-werefox-red-light",
|
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",
|
||||||
p { class: "flex flex-row mx-auto max-w-full justify-center text-xl text-center",
|
p { class: "flex flex-row mx-auto max-w-full justify-center text-xl text-center",
|
||||||
"A Letter to the Void "
|
"A Letter to the Void "
|
||||||
a { class: "max-h-sm",
|
DarkModeButton { slug: slug, dark_mode: dark_mode }
|
||||||
href: "?set-dark-mode",
|
|
||||||
match dark_mode {
|
|
||||||
true => {
|
|
||||||
rsx! {
|
|
||||||
img { class: "",
|
|
||||||
src: "/images/white_square_button.png",
|
|
||||||
alt: "A white square button that can toggle dark mode.",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false => {
|
|
||||||
rsx! {
|
|
||||||
img { class: "",
|
|
||||||
src: "/images/black_square_button.png",
|
|
||||||
alt: "A black square button that can toggle dark mode.",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
div { class: "flex p-4 ml-6 mr-6 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-red-dark dark:text-alice-werefox-red-light",
|
div { class: "flex p-4 ml-6 mr-6 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",
|
p { class: "text-lg text-center",
|
||||||
"Welcome, and I hope you enjoy your stay!"
|
"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."
|
"\"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."
|
||||||
@ -108,39 +254,10 @@ pub mod void_app {
|
|||||||
"🖤 Alice Icehart Werefox"
|
"🖤 Alice Icehart Werefox"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
div { class: "flex mx-auto max-w-full justify-center",
|
NavigationButton { title: "See Earliest Entry".to_string(), slug: "/poems/latest".to_string() }
|
||||||
a { 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-red-dark dark:text-alice-werefox-red-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",
|
NavigationButton { title: "See Oldest Entry".to_string(), slug: "/poems/oldest".to_string() }
|
||||||
href: "/poems/latest",
|
NavigationButton { title: "See All Entries".to_string(), slug: "/poems".to_string() }
|
||||||
div { class: "",
|
MutantStandardFooter {}
|
||||||
p { class: "text-xl text-center",
|
|
||||||
"See Latest Entry"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div { class: "flex mx-auto max-w-full justify-center",
|
|
||||||
a { 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-red-dark dark:text-alice-werefox-red-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: "/poems/oldest",
|
|
||||||
div { class: "",
|
|
||||||
p { class: "text-xl text-center",
|
|
||||||
"See Oldest Entry"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div { class: "flex mx-auto max-w-full justify-center",
|
|
||||||
a { 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-red-dark dark:text-alice-werefox-red-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: "/poems",
|
|
||||||
div { class: "",
|
|
||||||
p { class: "text-xl text-center",
|
|
||||||
"See All Entries"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div { class: "flex p-4 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-red-dark dark:text-alice-werefox-red-light",
|
|
||||||
"This site uses Mutant Standard emoji, which are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -165,66 +282,66 @@ pub mod void_app {
|
|||||||
|
|
||||||
pub fn get_oldest_entry() -> String {
|
pub fn get_oldest_entry() -> String {
|
||||||
let mut poem_list = VecDeque::from(get_poem_list());
|
let mut poem_list = VecDeque::from(get_poem_list());
|
||||||
poem_list.pop_front().expect("There is an entry in this list of poems.").1
|
poem_list
|
||||||
|
.pop_front()
|
||||||
|
.expect("There is an entry in this list of poems.")
|
||||||
|
.1
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_latest_entry() -> String {
|
pub fn get_latest_entry() -> String {
|
||||||
let mut poem_list = get_poem_list();
|
let mut poem_list = get_poem_list();
|
||||||
poem_list.pop().expect("There is an entry in this list of poems.").1
|
poem_list
|
||||||
|
.pop()
|
||||||
|
.expect("There is an entry in this list of poems.")
|
||||||
|
.1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_previous_entry(slug: String) -> Option<String> {
|
||||||
|
let poem_list = get_poem_list();
|
||||||
|
poem_list.iter().enumerate().find_map(|(index, p)| {
|
||||||
|
if p.1 == slug {
|
||||||
|
if index != 0 {
|
||||||
|
Some(poem_list[index - 1].1.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_next_entry(slug: String) -> Option<String> {
|
||||||
|
let poem_list = get_poem_list();
|
||||||
|
poem_list.iter().enumerate().find_map(|(index, p)| {
|
||||||
|
if p.1 == slug {
|
||||||
|
if index != poem_list.len() - 1 {
|
||||||
|
Some(poem_list[index + 1].1.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
/// Renders the app and returns the rendered Element.
|
/// Renders the app and returns the rendered Element.
|
||||||
pub fn PoemListPage(cx: Scope<HomeProps>) -> Element {
|
pub fn PoemListPage(cx: Scope<DarkModeProps>) -> Element {
|
||||||
|
let slug = cx.props.slug.clone().expect("Slug for dark mode redirect.");
|
||||||
let dark_mode = cx.props.dark_mode.clone();
|
let dark_mode = cx.props.dark_mode.clone();
|
||||||
cx.render(rsx!{
|
cx.render(rsx!{
|
||||||
div { class: "min-h-screen font-nerd bg-alice-werefox-grey-light dark:bg-alice-werefox-grey",
|
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: "container space-y-4 mx-auto p-4",
|
||||||
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-red-dark dark:text-alice-werefox-red-light",
|
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",
|
||||||
p { class: "flex flex-row mx-auto max-w-full justify-center text-lg text-center",
|
p { class: "flex flex-row mx-auto max-w-full justify-center text-lg text-center",
|
||||||
"A Letter to the Void "
|
"A Letter to the Void "
|
||||||
a { class: "max-h-sm",
|
DarkModeButton { slug: slug, dark_mode: dark_mode }
|
||||||
href: "?set-dark-mode",
|
|
||||||
match dark_mode {
|
|
||||||
true => {
|
|
||||||
rsx! {
|
|
||||||
img { class: "",
|
|
||||||
src: "/images/white_square_button.png",
|
|
||||||
alt: "A white square button that can toggle dark mode.",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false => {
|
|
||||||
rsx! {
|
|
||||||
img { class: "",
|
|
||||||
src: "/images/black_square_button.png",
|
|
||||||
alt: "A black square button that can toggle dark mode.",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
a { class: "flex 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-red-dark dark:text-alice-werefox-red-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",
|
BackToHomePage {}
|
||||||
href: "/",
|
|
||||||
div { class: "mx-auto max-w-full justify-center",
|
|
||||||
p { class: "text-lg text-center",
|
|
||||||
"Back to the homepage"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PoemList {}
|
PoemList {}
|
||||||
a { class: "flex 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-red-dark dark:text-alice-werefox-red-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",
|
BackToHomePage {}
|
||||||
href: "/",
|
MutantStandardFooter {}
|
||||||
div { class: "mx-auto max-w-full justify-center",
|
|
||||||
p { class: "text-lg text-center",
|
|
||||||
"Back to the homepage"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div { class: "flex p-4 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-red-dark dark:text-alice-werefox-red-light",
|
|
||||||
"This site uses Mutant Standard emoji, which are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -233,10 +350,10 @@ pub mod void_app {
|
|||||||
fn PoemList(cx: Scope) -> Element {
|
fn PoemList(cx: Scope) -> Element {
|
||||||
let poem_list = get_poem_list();
|
let poem_list = get_poem_list();
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
ul { class: "space-y-4",
|
ul { class: "flex flex-col space-y-4",
|
||||||
poem_list.into_iter().map(|p| {
|
poem_list.into_iter().map(|p| {
|
||||||
rsx!{
|
rsx!{
|
||||||
div { PoemButton { title: p.0, slug: p.1 } }
|
PoemButton { title: p.0, slug: p.1 }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -245,31 +362,41 @@ pub mod void_app {
|
|||||||
|
|
||||||
#[cfg(any(target_family = "unix", target_family = "windows"))]
|
#[cfg(any(target_family = "unix", target_family = "windows"))]
|
||||||
pub fn PoemPage(cx: Scope<PoemRequest>) -> Element {
|
pub fn PoemPage(cx: Scope<PoemRequest>) -> Element {
|
||||||
let slug = String::from(cx.props.slug.clone());
|
let slug = cx.props.slug.clone();
|
||||||
let dark_mode = cx.props.dark_mode.clone().expect("Dark mode prop not passed.");
|
let mut oldest_uri = "#".to_string();
|
||||||
|
if get_oldest_entry() != slug.to_string() {
|
||||||
|
oldest_uri = format!("/poems/oldest");
|
||||||
|
}
|
||||||
|
let mut previous_uri = "#".to_string();
|
||||||
|
if let Some(_) = get_previous_entry(slug.clone()) {
|
||||||
|
previous_uri = format!("/poems/previous/?current={slug}");
|
||||||
|
}
|
||||||
|
let mut next_uri = "#".to_string();
|
||||||
|
if let Some(_) = get_next_entry(slug.clone()) {
|
||||||
|
next_uri = format!("/poems/next/?current={slug}");
|
||||||
|
}
|
||||||
|
let mut latest_uri = "#".to_string();
|
||||||
|
if get_latest_entry() != slug.to_string() {
|
||||||
|
latest_uri = format!("/poems/latest");
|
||||||
|
}
|
||||||
|
let dark_mode = cx
|
||||||
|
.props
|
||||||
|
.dark_mode
|
||||||
|
.clone()
|
||||||
|
.expect("Dark mode prop not passed.");
|
||||||
cx.render(rsx!{
|
cx.render(rsx!{
|
||||||
div { class: "min-h-screen font-nerd bg-alice-werefox-grey-light dark:bg-alice-werefox-grey",
|
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: "container space-y-4 mx-auto p-4",
|
||||||
a { class: "flex 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-red-dark dark:text-alice-werefox-red-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",
|
BackToHomePage {}
|
||||||
href: "/",
|
|
||||||
div { class: "mx-auto max-w-full justify-center",
|
|
||||||
p { class: "text-lg text-center",
|
|
||||||
"Back to the homepage"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GetPoem { slug: slug, dark_mode: dark_mode }
|
GetPoem { slug: slug, dark_mode: dark_mode }
|
||||||
a { class: "flex 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-red-dark dark:text-alice-werefox-red-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",
|
div { class: "grid md:grid-cols-4 md:grid-rows-1 grid-cols-1 grid-rows-4 gap-y-4",
|
||||||
href: "/",
|
NavigationButton { title: "Oldest".to_string(), slug: oldest_uri }
|
||||||
div { class: "mx-auto max-w-full justify-center",
|
NavigationButton { title: "Previous".to_string(), slug: previous_uri }
|
||||||
p { class: "text-lg text-center",
|
NavigationButton { title: "Next".to_string(), slug: next_uri }
|
||||||
"Back to the homepage"
|
NavigationButton { title: "Latest".to_string(), slug: latest_uri }
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div { class: "p-4 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-red-dark dark:text-alice-werefox-red-light",
|
|
||||||
"This site uses Mutant Standard emoji, which are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License"
|
|
||||||
}
|
}
|
||||||
|
BackToHomePage {}
|
||||||
|
MutantStandardFooter {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -282,61 +409,56 @@ pub mod void_app {
|
|||||||
.segment("slug")
|
.segment("slug")
|
||||||
.expect("No slug specified."),
|
.expect("No slug specified."),
|
||||||
);
|
);
|
||||||
let dark_mode = cx.props.dark_mode.clone().expect("Dark mode prop not passed.");
|
let dark_mode = cx
|
||||||
|
.props
|
||||||
|
.dark_mode
|
||||||
|
.clone()
|
||||||
|
.expect("Dark mode prop not passed.");
|
||||||
cx.render(rsx!{
|
cx.render(rsx!{
|
||||||
div { class: "min-h-screen font-nerd bg-alice-werefox-grey-light dark:bg-alice-werefox-grey",
|
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: "container space-y-4 mx-auto p-4",
|
||||||
Link { to: "/"
|
BackToHomePage {}
|
||||||
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-red-dark dark:text-alice-werefox-red-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",
|
|
||||||
p { class: "text-lg text-center",
|
|
||||||
"Back to the homepage"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GetPoem { slug: slug, dark_mode: dark_mode }
|
GetPoem { slug: slug, dark_mode: dark_mode }
|
||||||
div { class: "p-4 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-red-dark dark:text-alice-werefox-red-light",
|
BackToHomePage {}
|
||||||
"This site uses Mutant Standard emoji, which are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License"
|
MutantStandardFooter {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_family = "unix", target_family = "windows"))]
|
// fn PoemButton(cx: Scope<PoemData>) -> Element {
|
||||||
fn PoemButton(cx: Scope<PoemData>) -> Element {
|
// let title = cx.props.title.clone().expect("No title specified.");
|
||||||
let title = cx.props.title.clone().expect("No title specified.");
|
// let slug = cx.props.slug.clone().expect("No slug specified.");
|
||||||
let slug = cx.props.slug.clone().expect("No slug specified.");
|
// let class = String::from("p-4 ml-6 mr-6 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");
|
||||||
let slug_ref = slug.as_str();
|
// cx.render(rsx!{
|
||||||
cx.render(rsx!{
|
// PoemButtonLink { title: title, slug: slug, classes: class }
|
||||||
a { href: "/poems/{slug_ref}",
|
// })
|
||||||
li { class: "p-4 ml-6 mr-6 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-red-dark dark:text-alice-werefox-red-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",
|
// }
|
||||||
div { class: "text-xl text-center", "{title}" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_family = "wasm")]
|
// fn PoemButton(cx: Scope<PoemData>) -> Element {
|
||||||
fn PoemButton(cx: Scope<PoemData>) -> Element {
|
// let title = cx.props.title.clone().expect("No title specified.");
|
||||||
let title = cx.props.title.clone().expect("No title specified.");
|
// let slug = cx.props.slug.clone().expect("No slug specified.");
|
||||||
let slug = cx.props.slug.clone().expect("No slug specified.");
|
// let slug_ref = slug.as_str();
|
||||||
let slug_ref = slug.as_str();
|
// cx.render(rsx!{
|
||||||
cx.render(rsx!{
|
// Link { to: "/poems/{slug_ref}",
|
||||||
Link { to: "/poems/{slug_ref}",
|
// li { class: "p-4 ml-6 mr-6 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",
|
||||||
li { class: "p-4 ml-6 mr-6 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-red-dark dark:text-alice-werefox-red-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",
|
// div { class: "mx-auto max-w-fit flex justify-center text-lg text-center",
|
||||||
div { class: "mx-auto max-w-fit flex justify-center text-lg text-center",
|
// dangerous_inner_html: "{title}"
|
||||||
dangerous_inner_html: "{title}"
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// })
|
||||||
})
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
fn GetPoem(cx: Scope<PoemData>) -> Element {
|
fn GetPoem(cx: Scope<PoemData>) -> Element {
|
||||||
let dark_mode = cx.props.dark_mode.clone().expect("Dark mode prop not passed.");
|
// It would be good to implement some kind of "get_poem_data" or "into" functionality for the struct, so I don't have to write all this here.
|
||||||
|
let dark_mode = cx
|
||||||
|
.props
|
||||||
|
.dark_mode
|
||||||
|
.clone()
|
||||||
|
.expect("Dark mode prop not passed.");
|
||||||
let slug = String::from(cx.props.slug.clone().expect("No slug specified."));
|
let slug = String::from(cx.props.slug.clone().expect("No slug specified."));
|
||||||
let filename =
|
let filename = String::from(String::from(slug.clone()) + ".md");
|
||||||
String::from(String::from(slug.clone()) + ".md");
|
|
||||||
let creation_date =
|
let creation_date =
|
||||||
String::from(String::from("<br>Written on: ") + filename.split("_").next().unwrap());
|
String::from(String::from("<br>Written on: ") + filename.split("_").next().unwrap());
|
||||||
let poem_content = Poems::get(&filename).expect("Found poem {filename:?}");
|
let poem_content = Poems::get(&filename).expect("Found poem {filename:?}");
|
||||||
@ -349,82 +471,75 @@ pub mod void_app {
|
|||||||
markdown::to_html_with_options(poem_title, &Options::gfm()).unwrap();
|
markdown::to_html_with_options(poem_title, &Options::gfm()).unwrap();
|
||||||
let poem_content_to_html_string =
|
let poem_content_to_html_string =
|
||||||
markdown::to_html_with_options(poem_content.as_str(), &Options::gfm()).unwrap();
|
markdown::to_html_with_options(poem_content.as_str(), &Options::gfm()).unwrap();
|
||||||
cx.render(rsx!{
|
cx.render(rsx! {
|
||||||
MakePoem{ title: poem_title_to_html_string, content: poem_content_to_html_string, creation_date: creation_date, slug: slug, dark_mode: dark_mode } }
|
MakePoem{
|
||||||
)
|
// data: PoemData{
|
||||||
|
// title: None,
|
||||||
|
// content: Some(poem_content_to_html_string.clone()),
|
||||||
|
// creation_date: Some(creation_date.clone()),
|
||||||
|
// slug: Some(slug.clone()),
|
||||||
|
// dark_mode: Some(dark_mode),
|
||||||
|
// },
|
||||||
|
RenderPoemTitle { title: poem_title_to_html_string, slug: slug, dark_mode: dark_mode }
|
||||||
|
RenderPoemElement { content: poem_content_to_html_string, creation_date: creation_date }
|
||||||
|
}})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_family = "unix", target_family = "windows"))]
|
// #[cfg(any(target_family = "unix", target_family = "windows"))]
|
||||||
fn RenderPoemTitle(cx: Scope<PoemData>) -> Element {
|
fn RenderPoemTitle(cx: Scope<PoemData>) -> Element {
|
||||||
let slug = cx.props.slug.clone().expect("Slug prop was not passed.");
|
let slug = cx.props.slug.clone().expect("Slug prop was not passed.");
|
||||||
let dark_mode = cx.props.dark_mode.clone().expect("Dark mode prop not passed.");
|
let dark_mode = cx
|
||||||
|
.props
|
||||||
|
.dark_mode
|
||||||
|
.clone()
|
||||||
|
.expect("Dark mode prop not passed.");
|
||||||
let title = cx.props.title.clone().expect("No title specified.");
|
let title = cx.props.title.clone().expect("No title specified.");
|
||||||
cx.render(rsx!{
|
cx.render(rsx!{
|
||||||
span { class: "p-4 ml-4 mr-4 flex text-xl 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-red-dark dark:text-alice-werefox-red-light",
|
span { class: "p-4 ml-4 mr-4 flex text-xl 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",
|
||||||
span { class: "flex flex-row align-middle mx-auto max-w-full justify-center",
|
span { class: "flex flex-row align-middle mx-auto max-w-full justify-center",
|
||||||
"{title} "
|
"{title} "
|
||||||
a { class: "",
|
DarkModeButton { slug: slug, dark_mode: dark_mode }
|
||||||
href: "/poems/{slug}?set-dark-mode",
|
|
||||||
match dark_mode {
|
|
||||||
true => {
|
|
||||||
rsx! {
|
|
||||||
img { class: "",
|
|
||||||
src: "/images/white_square_button.png",
|
|
||||||
alt: "A white square button that can toggle dark mode.",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false => {
|
|
||||||
rsx! {
|
|
||||||
img { class: "",
|
|
||||||
src: "/images/black_square_button.png",
|
|
||||||
alt: "A black square button that can toggle dark mode.",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_family = "wasm")]
|
// #[cfg(target_family = "wasm")]
|
||||||
fn RenderPoemTitle(cx: Scope<PoemData>) -> Element {
|
// fn RenderPoemTitle(cx: Scope<PoemData>) -> Element {
|
||||||
let slug = cx.props.slug.clone().expect("Slug prop was not passed.");
|
// let slug = cx.props.slug.clone().expect("Slug prop was not passed.");
|
||||||
let dark_mode = cx.props.dark_mode.clone().expect("Dark mode prop not passed.");
|
// let dark_mode = cx.props.dark_mode.clone().expect("Dark mode prop not passed.");
|
||||||
let title = cx
|
// let title = cx
|
||||||
.props
|
// .props
|
||||||
.title
|
// .title
|
||||||
.clone()
|
// .clone()
|
||||||
.expect("This poem has an empty title.");
|
// .expect("This poem has an empty title.");
|
||||||
cx.render(rsx!{
|
// cx.render(rsx!{
|
||||||
p { class: "mx-auto max-w-fit flex flex-row justify-center bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark ring-alice-werefox-red-dark dark:ring-alice-werefox-red text-alice-werefox-red-dark dark:text-alice-werefox-red-light p-4",
|
// p { class: "mx-auto max-w-fit flex flex-row justify-center 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-4",
|
||||||
dangerous_inner_html: "{title} ",
|
// dangerous_inner_html: "{title} ",
|
||||||
a { class: "",
|
// a { class: "",
|
||||||
href: "/poems/{slug}?set-dark-mode",
|
// href: "/poems/{slug}/toggle-dark-mode",
|
||||||
match dark_mode {
|
// match dark_mode {
|
||||||
true => {
|
// true => {
|
||||||
rsx! {
|
// rsx! {
|
||||||
img { class: "",
|
// img { class: "",
|
||||||
src: "/images/white_square_button.png",
|
// src: "/images/white_square_button.png",
|
||||||
alt: "A white square button that can toggle dark mode.",
|
// alt: "A white square button that can toggle dark mode.",
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
false => {
|
// false => {
|
||||||
rsx! {
|
// rsx! {
|
||||||
img { class: "",
|
// img { class: "",
|
||||||
src: "/images/black_square_button.png",
|
// src: "/images/black_square_button.png",
|
||||||
alt: "A black square button that can toggle dark mode.",
|
// alt: "A black square button that can toggle dark mode.",
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[cfg(any(target_family = "unix", target_family = "windows"))]
|
#[cfg(any(target_family = "unix", target_family = "windows"))]
|
||||||
fn RenderPoemElement(cx: Scope<PoemData>) -> Element {
|
fn RenderPoemElement(cx: Scope<PoemData>) -> Element {
|
||||||
@ -435,7 +550,13 @@ pub mod void_app {
|
|||||||
.clone()
|
.clone()
|
||||||
.expect("No creation date specified.");
|
.expect("No creation date specified.");
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div { class: "font-nerd flex flex-col space-y-4 mx-4 py-4", "{content}{creation_date} "
|
div { class: "flex p-4 ml-6 mr-6 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-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 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",
|
||||||
|
}
|
||||||
|
div { class: "font-nerd flex flex-col space-y-4 mx-4 py-4", "{content}{creation_date}"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -456,26 +577,10 @@ pub mod void_app {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn MakePoem(cx: Scope<PoemData>) -> Element {
|
fn MakePoem<'a>(cx: Scope<'a, PoemChildren<'a>>) -> Element {
|
||||||
let slug = String::from(cx.props.slug.clone().expect("Slug prop was not passed."));
|
cx.render(rsx! {
|
||||||
let dark_mode = cx.props.dark_mode.clone().expect("Dark mode prop not passed.");
|
|
||||||
let title = cx.props.title.clone().expect("No title specified.");
|
|
||||||
let creation_date = cx
|
|
||||||
.props
|
|
||||||
.creation_date
|
|
||||||
.clone()
|
|
||||||
.expect("No creation date specified.");
|
|
||||||
let content = cx.props.content.clone().expect("No content specified.");
|
|
||||||
cx.render(rsx!{
|
|
||||||
div { class: "flex-col space-y-4",
|
div { class: "flex-col space-y-4",
|
||||||
RenderPoemTitle { title: title.clone(), slug: slug, dark_mode: dark_mode }
|
&cx.props.children
|
||||||
div { class: "flex p-4 ml-6 mr-6 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-red-dark dark:text-alice-werefox-red-light",
|
|
||||||
summary { class: "group-open:before:content-['Close'] before:content-['Open'] flex justify-center 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-red-dark dark:text-alice-werefox-red-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",
|
|
||||||
}
|
|
||||||
RenderPoemElement { content: content.clone(), creation_date: creation_date.clone() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
0
void-fe/src/utils/file_management.rs
Normal file
0
void-fe/src/utils/file_management.rs
Normal file
Loading…
Reference in New Issue
Block a user