Refactored poem selection so that a static hashmap and vector are ceated as a prop that is passed to each component in order to grab poem data more efficiently and cleanly.

This commit is contained in:
Ada Werefox 2023-04-18 19:33:44 -05:00
parent db2d86c5ee
commit e593f46a35
12 changed files with 257 additions and 172 deletions

View File

@ -16,6 +16,7 @@ dioxus = "0.3.2"
markdown = "1.0.0-alpha.7" markdown = "1.0.0-alpha.7"
dioxus-ssr = "0.3.0" dioxus-ssr = "0.3.0"
rust-embed = { version = "6.6.1" } rust-embed = { version = "6.6.1" }
once_cell = "1.17.1"
[dependencies] [dependencies]
void-be = { path = "./void-be" } void-be = { path = "./void-be" }

File diff suppressed because one or more lines are too long

View File

@ -7,6 +7,7 @@ edition = "2021"
[dependencies] [dependencies]
void-fe = { path = "../void-fe" } void-fe = { path = "../void-fe" }
dioxus-ssr = { workspace = true } dioxus-ssr = { workspace = true }
once_cell = { workspace = true }
# If you're unsure about why we're depending on a release candidate, # If you're unsure about why we're depending on a release candidate,
# check the Rocket documentation: # check the Rocket documentation:

View File

@ -8,15 +8,17 @@ 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 once_cell::sync::OnceCell;
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::utils::prop_structs::PoemRequest; use void_fe::utils::prop_structs::{PoemDatabase, VoidProps};
use void_fe::utils::user_prefs::*;
use void_fe::void_app::{self, VirtualDom}; use void_fe::void_app::{self, VirtualDom};
use void_fe::utils::user_prefs::*; static POEM_DATABASE: OnceCell<PoemDatabase> = OnceCell::new();
async fn get_user_prefs(cookies: &CookieJar<'_>) -> UserPrefs { async fn get_user_prefs(cookies: &CookieJar<'_>) -> UserPrefs {
let user_theme = match cookies.get("theme") { let user_theme = match cookies.get("theme") {
@ -74,7 +76,15 @@ pub mod web_app_backend {
#[get("/")] #[get("/")]
async fn index(cookies: &CookieJar<'_>) -> Template { async fn index(cookies: &CookieJar<'_>) -> Template {
let user_prefs = get_user_prefs(cookies).await; let user_prefs = get_user_prefs(cookies).await;
let mut vdom = VirtualDom::new_with_props(void_app::HomePage, user_prefs); let void_props = VoidProps {
slug: None,
poem_database: POEM_DATABASE
.get()
.expect("Poem database is not initialized")
.clone(),
user_prefs: user_prefs,
};
let mut vdom = VirtualDom::new_with_props(void_app::HomePage, void_props);
let _ = vdom.rebuild(); let _ = vdom.rebuild();
let output = dioxus_ssr::render(&vdom); let output = dioxus_ssr::render(&vdom);
Template::render( Template::render(
@ -120,7 +130,15 @@ pub mod web_app_backend {
#[get("/")] #[get("/")]
async fn poem_list(cookies: &CookieJar<'_>) -> Template { async fn poem_list(cookies: &CookieJar<'_>) -> Template {
let user_prefs = get_user_prefs(cookies).await; let user_prefs = get_user_prefs(cookies).await;
let mut vdom = VirtualDom::new_with_props(void_app::PoemListPage, user_prefs); let void_props = VoidProps {
slug: None,
poem_database: POEM_DATABASE
.get()
.expect("Poem database is not initialized")
.clone(),
user_prefs: user_prefs,
};
let mut vdom = VirtualDom::new_with_props(void_app::PoemListPage, void_props);
let _ = vdom.rebuild(); let _ = vdom.rebuild();
let output = dioxus_ssr::render(&vdom); let output = dioxus_ssr::render(&vdom);
Template::render( Template::render(
@ -137,13 +155,15 @@ pub mod web_app_backend {
#[get("/<entry>")] #[get("/<entry>")]
async fn poem(cookies: &CookieJar<'_>, entry: &str) -> Template { async fn poem(cookies: &CookieJar<'_>, entry: &str) -> Template {
let user_prefs = get_user_prefs(cookies).await; let user_prefs = get_user_prefs(cookies).await;
let mut vdom = VirtualDom::new_with_props( let void_props = VoidProps {
void_app::PoemPage, slug: Some(entry.to_string()),
PoemRequest { poem_database: POEM_DATABASE
slug: format!("{entry}"), .get()
user_prefs, .expect("Poem database is not initialized")
}, .clone(),
); user_prefs: user_prefs,
};
let mut vdom = VirtualDom::new_with_props(void_app::PoemPage, void_props);
let _ = vdom.rebuild(); let _ = vdom.rebuild();
let output = dioxus_ssr::render(&vdom); let output = dioxus_ssr::render(&vdom);
Template::render( Template::render(
@ -159,6 +179,9 @@ pub mod web_app_backend {
/// This runs `rocket::build()` with the needed mounts and routes. /// This runs `rocket::build()` with the needed mounts and routes.
pub async fn build_rocket() -> Rocket<Build> { pub async fn build_rocket() -> Rocket<Build> {
let mut poem_database = PoemDatabase::new();
poem_database.build_poem_database().await;
POEM_DATABASE.set(poem_database).expect("Could not initialize poem database.");
rocket::build() rocket::build()
.mount("/images", FileServer::from("public/images")) .mount("/images", FileServer::from("public/images"))
.mount("/styles", FileServer::from("public/styles")) .mount("/styles", FileServer::from("public/styles"))

View File

@ -1,5 +1,5 @@
# im on repeat # im on repeat
[Audio reading](https://cloud.werefox.dev/s/dq5ccm5QqmMF4GB) *Author's note: Unfortunately, I've lost the audio reading for this.*
Death is like a memory. Ceaseless, and comforting\ Death is like a memory. Ceaseless, and comforting\
Knowing things will end has always helped me feel like I'm free\ Knowing things will end has always helped me feel like I'm free\

View File

@ -1,5 +1,5 @@
# Iced Coffee # Iced Coffee
[Listen to the song on Soundcloud](https://soundcloud.com/alexis-werefox/iced-coffee/s-5SgBwPrLwyR) <a href="https://soundcloud.com/alexis-werefox/iced-coffee/s-5SgBwPrLwyR">Listen to the song on Soundcloud</a>
*Iced coffee on a cold Winter's day* \ *Iced coffee on a cold Winter's day* \
*Iced coffee bittersweet at the taste* \ *Iced coffee bittersweet at the taste* \

View File

@ -1,5 +1,5 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use crate::{components::void_buttons::NavigationButton, utils::user_prefs::{UserPrefs, ThemedComponent}}; use crate::{components::void_buttons::{ButtonGroup, NavigationButton}, utils::user_prefs::{UserPrefs, ThemedComponent}};
pub fn Footer(cx: Scope<UserPrefs>) -> Element { pub fn Footer(cx: Scope<UserPrefs>) -> Element {
cx.render(rsx! { cx.render(rsx! {
@ -13,7 +13,12 @@ fn MutantStandardFooter(cx: Scope<UserPrefs>) -> Element {
let user_font = cx.props.get_font_class(); let user_font = cx.props.get_font_class();
cx.render(rsx!{ cx.render(rsx!{
div { class: "p-4 flex flex-col space-y-4 mx-auto max-w-full justify-center ring-4 {user_theme} {user_font}", div { class: "p-4 flex flex-col space-y-4 mx-auto max-w-full justify-center ring-4 {user_theme} {user_font}",
NavigationButton { title: "⚙️ Settings".to_string(), slug: "/settings".to_string(), user_prefs: user_prefs } ButtonGroup{
NavigationButton { title: "⚙️ Settings".to_string(), slug: "/settings".to_string(), user_prefs: user_prefs.clone() }
span { class: "font-nerd contents",
NavigationButton { title: " /src".to_string(), slug: "https://gitea.werefox.cafe/ada/void-werefox-cafe".to_string(), user_prefs: user_prefs }
}
}
div { class: "flex mx-auto max-w-full justify-center text-md text-center", div { class: "flex mx-auto max-w-full justify-center text-md text-center",
"This site uses Mutant Standard emoji, which are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License" "This site uses Mutant Standard emoji, which are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License"
} }

View File

@ -3,10 +3,9 @@ use dioxus::prelude::*;
pub fn PageBase<'a>(cx: Scope<'a, PageChildren<'a>>) -> Element { pub fn PageBase<'a>(cx: Scope<'a, PageChildren<'a>>) -> Element {
cx.render(rsx! { cx.render(rsx! {
a { rel: "me", href: "https://yiff.life/@werefox", hidden: true, "Mastodon" }
div { class: "min-h-screen", div { class: "min-h-screen",
div { class: "container space-y-4 mx-auto p-4", div { class: "container space-y-4 mx-auto p-4", &cx.props.children }
&cx.props.children
}
} }
}) })
} }

View File

@ -1,17 +1,17 @@
use crate::components::void_buttons::*; use crate::components::void_buttons::*;
use crate::components::void_title::*; use crate::components::void_title::*;
use crate::utils::{helpers, prop_structs::{PoemChildren, PoemData}, user_prefs::{UserPrefs, ThemedComponent} }; use crate::utils::prop_structs::VoidProps;
use crate::utils::{prop_structs::PoemChildren, user_prefs::ThemedComponent};
use dioxus::prelude::*; use dioxus::prelude::*;
pub fn PoemList(cx: Scope<UserPrefs>) -> Element { pub fn PoemList(cx: Scope<VoidProps>) -> Element {
let poem_list = helpers::get_poem_list(); let poem_list = cx.props.poem_database.get_poem_list();
cx.render(rsx! { cx.render(rsx! {
ul { class: "flex flex-col space-y-4", ul { class: "flex flex-col space-y-4",
poem_list.into_iter().map(|p| { poem_list.into_iter().map(|p| {
let user_prefs = cx.props.clone(); let slug = format!("/poems/{}", p.0);
let slug = format!("/poems/{}", p.1);
rsx!{ rsx!{
NavigationButton { title: p.0, slug: slug, user_prefs: user_prefs.clone() } NavigationButton { title: p.1, slug: slug, user_prefs: cx.props.user_prefs.clone() }
} }
}) })
} }
@ -26,25 +26,41 @@ pub fn MakePoem<'a>(cx: Scope<'a, PoemChildren<'a>>) -> Element {
}) })
} }
pub fn GetPoem(cx: Scope<PoemData>) -> Element { pub fn GetPoem(cx: Scope<VoidProps>) -> Element {
let slug = String::from(cx.props.slug.clone().expect("No slug specified.")); let poem_database = &cx.props.poem_database;
let (title, content, creation_date) = helpers::get_poem(slug.clone()); let slug = String::from(&cx.props.slug.clone().expect("No slug specified."));
let poem_struct = poem_database.get_poem(slug.clone());
cx.render(rsx! { cx.render(rsx! {
Title { title: title, is_html: true, user_prefs: cx.props.user_prefs.clone() } Title { title: poem_struct.title.clone(), is_html: true, user_prefs: cx.props.user_prefs.clone() }
MakePoem{ MakePoem{
PoemContent { content: content, creation_date: creation_date, user_prefs: cx.props.user_prefs.clone() } PoemContent { slug: slug, poem_database: poem_database.clone(), user_prefs: cx.props.user_prefs.clone() }
} }
}) })
} }
pub fn PoemContent(cx: Scope<PoemData>) -> Element { pub fn PoemContent(cx: Scope<VoidProps>) -> Element {
let (user_theme, user_font) = cx.props.user_prefs.get_pref_classes(ThemedComponent::Card); let (user_theme, user_font) = cx.props.user_prefs.get_pref_classes(ThemedComponent::Card);
let content = cx.props.content.clone().expect("No content specified."); let slug = cx
let creation_date = cx
.props .props
.slug
.as_ref()
.expect("Received slug for poem selection.");
let content = &cx
.props
.poem_database
.poem_hashmap
.get(slug)
.expect("Grabbed poem stuct from databse.")
.content
.clone();
let creation_date = &cx
.props
.poem_database
.poem_hashmap
.get(slug)
.expect("Grabbed poem struct from database.")
.creation_date .creation_date
.clone() .clone();
.expect("No creation date specified.");
#[cfg(any(target_family = "unix", target_family = "windows"))] #[cfg(any(target_family = "unix", target_family = "windows"))]
return cx.render(rsx! { return cx.render(rsx! {
div { class: "flex p-2 mx-auto max-w-full justify-center", div { class: "flex p-2 mx-auto max-w-full justify-center",

View File

@ -62,19 +62,20 @@ pub mod void_app {
} }
/// Renders the app and returns the rendered Element. /// Renders the app and returns the rendered Element.
pub fn HomePage(cx: Scope<UserPrefs>) -> Element { pub fn HomePage(cx: Scope<VoidProps>) -> Element {
let user_prefs = cx.props.clone(); let poem_database = &cx.props.poem_database;
let user_prefs = cx.props.user_prefs.clone();
let (user_theme, user_font) = user_prefs.get_pref_classes(ThemedComponent::Page); let (user_theme, user_font) = user_prefs.get_pref_classes(ThemedComponent::Page);
let title = "A Letter to the Void".to_string(); let page_title = "A Letter to the Void".to_string();
cx.render(rsx!{ cx.render(rsx!{
div { class: "{user_theme} {user_font}", div { class: "{user_theme} {user_font}",
PageBase { PageBase {
Title { title: title, is_html: false, user_prefs: user_prefs.clone() } Title { title: page_title, is_html: false, user_prefs: user_prefs.clone() }
RenderContent { content: helpers::get_homepage_paragraph(), user_prefs: user_prefs.clone() } RenderContent { content: helpers::get_homepage_paragraph(), user_prefs: user_prefs.clone() }
ButtonGroup { ButtonGroup {
NavigationButton { title: "See Latest Entry".to_string(), slug: helpers::get_latest_entry("".to_string()), user_prefs: user_prefs.clone() } NavigationButton { title: "See Latest Entry".to_string(), slug: poem_database.get_latest_entry("".to_string()), user_prefs: user_prefs.clone() }
NavigationButton { title: "See Oldest Entry".to_string(), slug: helpers::get_oldest_entry("".to_string()), user_prefs: user_prefs.clone() } NavigationButton { title: "See Oldest Entry".to_string(), slug: poem_database.get_oldest_entry("".to_string()), user_prefs: user_prefs.clone() }
NavigationButton { title: "See A Random Entry".to_string(), slug: helpers::get_random_entry(), user_prefs: user_prefs.clone() } NavigationButton { title: "See A Random Entry".to_string(), slug: poem_database.get_random_entry(), user_prefs: user_prefs.clone() }
NavigationButton { title: "See All Entries".to_string(), slug: "/poems".to_string(), user_prefs: user_prefs.clone() } NavigationButton { title: "See All Entries".to_string(), slug: "/poems".to_string(), user_prefs: user_prefs.clone() }
} }
Footer { theme: user_prefs.clone().get_theme(), font: user_prefs.get_font() } Footer { theme: user_prefs.clone().get_theme(), font: user_prefs.get_font() }
@ -84,15 +85,16 @@ pub mod void_app {
} }
/// Renders the app and returns the rendered Element. /// Renders the app and returns the rendered Element.
pub fn PoemListPage(cx: Scope<UserPrefs>) -> Element { pub fn PoemListPage(cx: Scope<VoidProps>) -> Element {
let user_prefs = cx.props.clone(); let poem_database = &cx.props.poem_database;
let user_prefs = cx.props.user_prefs.clone();
let (user_theme, user_font) = user_prefs.get_pref_classes(ThemedComponent::Page); let (user_theme, user_font) = user_prefs.get_pref_classes(ThemedComponent::Page);
cx.render(rsx! { cx.render(rsx! {
div { class: "{user_theme} {user_font}", div { class: "{user_theme} {user_font}",
PageBase { PageBase {
Title { title: "A Letter to the Void".to_string(), is_html: false, user_prefs: user_prefs.clone() } Title { title: "A Letter to the Void".to_string(), is_html: false, user_prefs: user_prefs.clone() }
BackToHomePage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() } BackToHomePage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() }
PoemList { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() } PoemList { poem_database: poem_database.clone(), user_prefs: user_prefs.clone() }
BackToHomePage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() } BackToHomePage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() }
Footer { theme: user_prefs.clone().get_theme(), font: user_prefs.get_font() } Footer { theme: user_prefs.clone().get_theme(), font: user_prefs.get_font() }
} }
@ -100,11 +102,12 @@ pub mod void_app {
}) })
} }
pub fn PoemPage(cx: Scope<PoemRequest>) -> Element { pub fn PoemPage(cx: Scope<VoidProps>) -> Element {
let poem_database = &cx.props.poem_database;
let user_prefs = cx.props.user_prefs.clone(); let user_prefs = cx.props.user_prefs.clone();
let (user_theme, user_font) = user_prefs.get_pref_classes(ThemedComponent::Page); let (user_theme, user_font) = user_prefs.get_pref_classes(ThemedComponent::Page);
#[cfg(any(target_family = "unix", target_family = "windows"))] #[cfg(any(target_family = "unix", target_family = "windows"))]
let slug = cx.props.slug.clone(); let slug = &cx.props.slug.as_ref().expect("A slug was given in the pops.").clone();
#[cfg(target_family = "wasm")] #[cfg(target_family = "wasm")]
let slug = String::from( let slug = String::from(
dioxus_router::use_route(cx) dioxus_router::use_route(cx)
@ -115,13 +118,13 @@ pub mod void_app {
div { class: "{user_theme} {user_font}", div { class: "{user_theme} {user_font}",
PageBase { PageBase {
BackToHomePage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() } BackToHomePage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() }
GetPoem { slug: slug.clone(), user_prefs: user_prefs.clone() } GetPoem { slug: slug.clone(), poem_database: poem_database.clone(), user_prefs: user_prefs.clone() }
ButtonGroup { ButtonGroup {
NavigationButton { title: "Oldest".to_string(), slug: helpers::get_oldest_entry(slug.clone()), user_prefs: user_prefs.clone() } NavigationButton { title: "Oldest".to_string(), slug: poem_database.get_oldest_entry(slug.clone()), user_prefs: user_prefs.clone() }
NavigationButton { title: "Previous".to_string(), slug: helpers::get_previous_entry(slug.clone()), user_prefs: user_prefs.clone() } NavigationButton { title: "Previous".to_string(), slug: poem_database.get_previous_entry(slug.clone()), user_prefs: user_prefs.clone() }
NavigationButton { title: "Random".to_string(), slug: helpers::get_random_entry(), user_prefs: user_prefs.clone() } NavigationButton { title: "Random".to_string(), slug: poem_database.get_random_entry(), user_prefs: user_prefs.clone() }
NavigationButton { title: "Next".to_string(), slug: helpers::get_next_entry(slug.clone()), user_prefs: user_prefs.clone() } NavigationButton { title: "Next".to_string(), slug: poem_database.get_next_entry(slug.clone()), user_prefs: user_prefs.clone() }
NavigationButton { title: "Latest".to_string(), slug: helpers::get_latest_entry(slug.clone()), user_prefs: user_prefs.clone() } NavigationButton { title: "Latest".to_string(), slug: poem_database.get_latest_entry(slug.clone()), user_prefs: user_prefs.clone() }
} }
BackToHomePage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() } BackToHomePage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() }
Footer { theme: user_prefs.clone().get_theme(), font: user_prefs.get_font() } Footer { theme: user_prefs.clone().get_theme(), font: user_prefs.get_font() }

View File

@ -1,91 +1,105 @@
use markdown::Options; use markdown::Options;
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use rust_embed::RustEmbed; use rust_embed::RustEmbed;
use std::collections::VecDeque; use std::collections::{HashMap, VecDeque};
use super::prop_structs::{PoemDatabase, PoemStruct};
#[derive(RustEmbed)] #[derive(RustEmbed)]
#[folder = "data/other"] #[folder = "data/other"]
struct OtherData; struct OtherData;
#[derive(RustEmbed)] #[derive(RustEmbed)]
#[folder = "data/poems"] #[folder = "data/poems"]
struct Poems; pub struct Poems;
pub fn get_homepage_paragraph() -> String { impl PoemDatabase {
let homepage_paragraph_content = pub fn new() -> PoemDatabase {
OtherData::get("homepage.md").expect("Found homepage paragraph."); PoemDatabase {
let homepage_paragraph_to_string = poem_list: Vec::<(String, String)>::new(),
std::str::from_utf8(homepage_paragraph_content.data.as_ref()) poem_hashmap: HashMap::<String, PoemStruct>::new(),
.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) { // There's no need to actually make a database yet, but maybe in the future...
let filename = String::from(String::from(slug.clone()) + ".md"); pub async fn build_poem_database(&mut self) {
let creation_date = for p in Poems::iter() {
String::from(String::from("<br>Written on: ") + filename.split("_").next().unwrap()); let filename = p.to_string();
let poem_content = Poems::get(&filename).expect("Found poem {filename:?}"); let poem_content = Poems::get(&filename).expect("Found poem {filename:?}");
let mut poem_to_str = std::str::from_utf8(poem_content.data.as_ref()) let mut poem_to_str = std::str::from_utf8(poem_content.data.as_ref())
.expect("Title is valid UT8.") .expect("Poem is valid UT8.")
.lines(); .lines();
let poem_title = poem_to_str.next().unwrap(); let poem_title = poem_to_str.next().expect("No title specified.");
let poem_content = poem_to_str.into_iter().collect::<Vec<&str>>().join("\n"); let poem_content = poem_to_str.into_iter().collect::<Vec<&str>>().join("\n");
let poem_title_to_html_string = let poem_title_to_html_string =
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();
let mut split_filename = filename.trim_end_matches(".md").split("_");
let creation_date = split_filename.next().expect("Obtained creation date");
let slug = split_filename.next().expect("Obtained slug");
self.poem_list
.push((creation_date.to_string(), slug.to_string()));
let poem_struct = PoemStruct {
title: poem_title_to_html_string.to_string(),
content: poem_content_to_html_string,
creation_date: creation_date.to_string(),
};
self.poem_hashmap.insert(slug.to_string(), poem_struct);
}
self.poem_list.sort_by_key(|k| k.0.clone())
}
pub fn get_poem(&self, slug: String) -> PoemStruct {
self.poem_hashmap
.get(slug.as_str())
.expect("Grabbed poem from database")
.clone()
}
pub fn get_poem_list(&self) -> Vec<(String, String)> {
self.poem_list
.iter()
.map(|s| {
( (
poem_title_to_html_string, s.1.clone(),
poem_content_to_html_string, self.poem_hashmap
creation_date, .get(&s.1)
.expect("Got poemstruct from database")
.title
.clone(),
) )
})
.collect::<Vec<(String, String)>>()
.clone()
} }
pub fn get_poem_list() -> Vec<(String, String)> { pub fn get_oldest_entry(&self, current: String) -> String {
let mut poem_list = Vec::new(); let mut poem_list = VecDeque::from_iter(self.poem_list.iter());
for p in Poems::iter() {
let filename = p.to_string();
let poem_content = Poems::get(&filename).expect("Found poem {filename:?}");
let mut poem_to_str = std::str::from_utf8(poem_content.data.as_ref())
.expect("Title is valid UT8.")
.lines();
let title_markdown = poem_to_str.next().expect("No title specified.");
let title = markdown::to_html_with_options(title_markdown, &Options::gfm()).unwrap();
let slug = String::from(filename.trim_end_matches(".md"));
poem_list.push((title.clone(), slug.clone()));
}
log::trace!("{poem_list:?}");
poem_list
}
pub fn get_oldest_entry(current: String) -> String {
let mut poem_list = VecDeque::from(get_poem_list());
let oldest = poem_list let oldest = poem_list
.pop_front() .pop_front()
.expect("There is an entry in this list of poems.") .expect("There is an entry in this list of poems.")
.1; .1
.clone();
if current == oldest { if current == oldest {
return format!("/poems/{current}#"); return format!("/poems/{current}#");
} }
format!("/poems/{oldest}") format!("/poems/{oldest}")
} }
pub fn get_latest_entry(current: String) -> String { pub fn get_latest_entry(&self, current: String) -> String {
let mut poem_list = get_poem_list(); let mut poem_list = self.poem_list.clone();
let latest = poem_list let latest = poem_list
.pop() .pop()
.expect("There is an entry in this list of poems.") .expect("There is an entry in this list of poems.")
.1; .1
.clone();
if current == latest { if current == latest {
return format!("/poems/{current}#"); return format!("/poems/{current}#");
} }
format!("/poems/{latest}") format!("/poems/{latest}")
} }
pub fn get_previous_entry(current: String) -> String { pub fn get_previous_entry(&self, current: String) -> String {
let poem_list = get_poem_list(); let poem_list = self.poem_list.clone();
match poem_list.iter().enumerate().find_map(|(index, p)| { match poem_list.iter().enumerate().find_map(|(index, p)| {
if p.1 == current { if p.1 == current {
if index != 0 { if index != 0 {
@ -102,8 +116,8 @@ pub fn get_previous_entry(current: String) -> String {
} }
} }
pub fn get_next_entry(current: String) -> String { pub fn get_next_entry(&self, current: String) -> String {
let poem_list = get_poem_list(); let poem_list = self.poem_list.clone();
match poem_list.iter().enumerate().find_map(|(index, p)| { match poem_list.iter().enumerate().find_map(|(index, p)| {
if p.1 == current { if p.1 == current {
if index != poem_list.len() - 1 { if index != poem_list.len() - 1 {
@ -120,8 +134,8 @@ pub fn get_next_entry(current: String) -> String {
} }
} }
pub fn get_random_entry() -> String { pub fn get_random_entry(&self) -> String {
let poem_list = get_poem_list(); let poem_list = self.poem_list.clone();
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let random_entry = poem_list let random_entry = poem_list
.choose(&mut rng) .choose(&mut rng)
@ -130,3 +144,15 @@ pub fn get_random_entry() -> String {
.clone(); .clone();
format!("/poems/{random_entry}") format!("/poems/{random_entry}")
} }
}
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
}

View File

@ -1,5 +1,5 @@
use std::collections::HashMap;
use crate::void_app::{Element, Props}; use crate::void_app::{Element, Props};
use super::user_prefs::UserPrefs; use super::user_prefs::UserPrefs;
#[derive(PartialEq, Props)] #[derive(PartialEq, Props)]
@ -29,14 +29,25 @@ pub struct ButtonProps {
} }
#[derive(PartialEq, Props)] #[derive(PartialEq, Props)]
pub struct PoemData { pub struct VoidProps {
pub title: Option<String>,
pub content: Option<String>,
pub creation_date: Option<String>,
pub slug: Option<String>, pub slug: Option<String>,
pub poem_database: PoemDatabase,
pub user_prefs: UserPrefs, pub user_prefs: UserPrefs,
} }
#[derive(PartialEq, Props, Clone, Debug)]
pub struct PoemDatabase {
pub poem_list: Vec<(String, String)>,
pub poem_hashmap: HashMap<String, PoemStruct>,
}
#[derive(PartialEq, Clone, Debug)]
pub struct PoemStruct {
pub title: String,
pub content: String,
pub creation_date: String,
}
// These next three should all just be one prop. // These next three should all just be one prop.
#[derive(Props)] #[derive(Props)]
pub struct PoemChildren<'a> { pub struct PoemChildren<'a> {