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:
parent
db2d86c5ee
commit
e593f46a35
@ -16,7 +16,8 @@ dioxus = "0.3.2"
|
||||
markdown = "1.0.0-alpha.7"
|
||||
dioxus-ssr = "0.3.0"
|
||||
rust-embed = { version = "6.6.1" }
|
||||
once_cell = "1.17.1"
|
||||
|
||||
[dependencies]
|
||||
void-be = { path = "./void-be" }
|
||||
rocket = { workspace = true }
|
||||
rocket = { workspace = true }
|
||||
|
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
@ -7,6 +7,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
void-fe = { path = "../void-fe" }
|
||||
dioxus-ssr = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
|
||||
# If you're unsure about why we're depending on a release candidate,
|
||||
# check the Rocket documentation:
|
||||
|
@ -8,15 +8,17 @@ extern crate rocket;
|
||||
/// A module that handles the backend for the site.
|
||||
pub mod web_app_backend {
|
||||
|
||||
use once_cell::sync::OnceCell;
|
||||
use rocket::fs::FileServer;
|
||||
use rocket::http::{Cookie, CookieJar};
|
||||
use rocket::response::Redirect;
|
||||
use rocket::{Build, Rocket};
|
||||
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::utils::user_prefs::*;
|
||||
static POEM_DATABASE: OnceCell<PoemDatabase> = OnceCell::new();
|
||||
|
||||
async fn get_user_prefs(cookies: &CookieJar<'_>) -> UserPrefs {
|
||||
let user_theme = match cookies.get("theme") {
|
||||
@ -74,7 +76,15 @@ pub mod web_app_backend {
|
||||
#[get("/")]
|
||||
async fn index(cookies: &CookieJar<'_>) -> Template {
|
||||
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 output = dioxus_ssr::render(&vdom);
|
||||
Template::render(
|
||||
@ -120,7 +130,15 @@ pub mod web_app_backend {
|
||||
#[get("/")]
|
||||
async fn poem_list(cookies: &CookieJar<'_>) -> Template {
|
||||
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 output = dioxus_ssr::render(&vdom);
|
||||
Template::render(
|
||||
@ -137,13 +155,15 @@ pub mod web_app_backend {
|
||||
#[get("/<entry>")]
|
||||
async fn poem(cookies: &CookieJar<'_>, entry: &str) -> Template {
|
||||
let user_prefs = get_user_prefs(cookies).await;
|
||||
let mut vdom = VirtualDom::new_with_props(
|
||||
void_app::PoemPage,
|
||||
PoemRequest {
|
||||
slug: format!("{entry}"),
|
||||
user_prefs,
|
||||
},
|
||||
);
|
||||
let void_props = VoidProps {
|
||||
slug: Some(entry.to_string()),
|
||||
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::PoemPage, void_props);
|
||||
let _ = vdom.rebuild();
|
||||
let output = dioxus_ssr::render(&vdom);
|
||||
Template::render(
|
||||
@ -159,6 +179,9 @@ pub mod web_app_backend {
|
||||
|
||||
/// This runs `rocket::build()` with the needed mounts and routes.
|
||||
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()
|
||||
.mount("/images", FileServer::from("public/images"))
|
||||
.mount("/styles", FileServer::from("public/styles"))
|
||||
|
@ -1,5 +1,5 @@
|
||||
# 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\
|
||||
Knowing things will end has always helped me feel like I'm free\
|
||||
|
@ -1,5 +1,5 @@
|
||||
# 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 bittersweet at the taste* \
|
||||
|
@ -1,5 +1,5 @@
|
||||
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 {
|
||||
cx.render(rsx! {
|
||||
@ -13,7 +13,12 @@ fn MutantStandardFooter(cx: Scope<UserPrefs>) -> Element {
|
||||
let user_font = cx.props.get_font_class();
|
||||
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}",
|
||||
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",
|
||||
"This site uses Mutant Standard emoji, which are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License"
|
||||
}
|
||||
|
@ -2,11 +2,10 @@ use crate::utils::prop_structs::PageChildren;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
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: "container space-y-4 mx-auto p-4",
|
||||
&cx.props.children
|
||||
}
|
||||
div { class: "container space-y-4 mx-auto p-4", &cx.props.children }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
use crate::components::void_buttons::*;
|
||||
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::*;
|
||||
|
||||
pub fn PoemList(cx: Scope<UserPrefs>) -> Element {
|
||||
let poem_list = helpers::get_poem_list();
|
||||
pub fn PoemList(cx: Scope<VoidProps>) -> Element {
|
||||
let poem_list = cx.props.poem_database.get_poem_list();
|
||||
cx.render(rsx! {
|
||||
ul { class: "flex flex-col space-y-4",
|
||||
poem_list.into_iter().map(|p| {
|
||||
let user_prefs = cx.props.clone();
|
||||
let slug = format!("/poems/{}", p.1);
|
||||
let slug = format!("/poems/{}", p.0);
|
||||
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 {
|
||||
let slug = String::from(cx.props.slug.clone().expect("No slug specified."));
|
||||
let (title, content, creation_date) = helpers::get_poem(slug.clone());
|
||||
pub fn GetPoem(cx: Scope<VoidProps>) -> Element {
|
||||
let poem_database = &cx.props.poem_database;
|
||||
let slug = String::from(&cx.props.slug.clone().expect("No slug specified."));
|
||||
let poem_struct = poem_database.get_poem(slug.clone());
|
||||
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{
|
||||
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 content = cx.props.content.clone().expect("No content specified.");
|
||||
let creation_date = cx
|
||||
let slug = cx
|
||||
.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
|
||||
.clone()
|
||||
.expect("No creation date specified.");
|
||||
.clone();
|
||||
#[cfg(any(target_family = "unix", target_family = "windows"))]
|
||||
return cx.render(rsx! {
|
||||
div { class: "flex p-2 mx-auto max-w-full justify-center",
|
||||
|
@ -62,19 +62,20 @@ pub mod void_app {
|
||||
}
|
||||
|
||||
/// Renders the app and returns the rendered Element.
|
||||
pub fn HomePage(cx: Scope<UserPrefs>) -> Element {
|
||||
let user_prefs = cx.props.clone();
|
||||
pub fn HomePage(cx: Scope<VoidProps>) -> Element {
|
||||
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 title = "A Letter to the Void".to_string();
|
||||
let page_title = "A Letter to the Void".to_string();
|
||||
cx.render(rsx!{
|
||||
div { class: "{user_theme} {user_font}",
|
||||
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() }
|
||||
ButtonGroup {
|
||||
NavigationButton { title: "See Latest Entry".to_string(), slug: helpers::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 A Random Entry".to_string(), slug: helpers::get_random_entry(), 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: poem_database.get_oldest_entry("".to_string()), 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() }
|
||||
}
|
||||
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.
|
||||
pub fn PoemListPage(cx: Scope<UserPrefs>) -> Element {
|
||||
let user_prefs = cx.props.clone();
|
||||
pub fn PoemListPage(cx: Scope<VoidProps>) -> Element {
|
||||
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);
|
||||
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.clone() }
|
||||
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() }
|
||||
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_theme, user_font) = user_prefs.get_pref_classes(ThemedComponent::Page);
|
||||
#[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")]
|
||||
let slug = String::from(
|
||||
dioxus_router::use_route(cx)
|
||||
@ -115,13 +118,13 @@ pub mod void_app {
|
||||
div { class: "{user_theme} {user_font}",
|
||||
PageBase {
|
||||
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 {
|
||||
NavigationButton { title: "Oldest".to_string(), slug: helpers::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: "Random".to_string(), slug: helpers::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: "Latest".to_string(), slug: helpers::get_latest_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: poem_database.get_previous_entry(slug.clone()), 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: poem_database.get_next_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() }
|
||||
Footer { theme: user_prefs.clone().get_theme(), font: user_prefs.get_font() }
|
||||
|
@ -1,15 +1,150 @@
|
||||
use markdown::Options;
|
||||
use rand::seq::SliceRandom;
|
||||
use rust_embed::RustEmbed;
|
||||
use std::collections::VecDeque;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
use super::prop_structs::{PoemDatabase, PoemStruct};
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "data/other"]
|
||||
struct OtherData;
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "data/poems"]
|
||||
struct Poems;
|
||||
pub struct Poems;
|
||||
|
||||
impl PoemDatabase {
|
||||
pub fn new() -> PoemDatabase {
|
||||
PoemDatabase {
|
||||
poem_list: Vec::<(String, String)>::new(),
|
||||
poem_hashmap: HashMap::<String, PoemStruct>::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// There's no need to actually make a database yet, but maybe in the future...
|
||||
pub async fn build_poem_database(&mut self) {
|
||||
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("Poem is valid UT8.")
|
||||
.lines();
|
||||
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_title_to_html_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();
|
||||
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| {
|
||||
(
|
||||
s.1.clone(),
|
||||
self.poem_hashmap
|
||||
.get(&s.1)
|
||||
.expect("Got poemstruct from database")
|
||||
.title
|
||||
.clone(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<(String, String)>>()
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub fn get_oldest_entry(&self, current: String) -> String {
|
||||
let mut poem_list = VecDeque::from_iter(self.poem_list.iter());
|
||||
let oldest = poem_list
|
||||
.pop_front()
|
||||
.expect("There is an entry in this list of poems.")
|
||||
.1
|
||||
.clone();
|
||||
if current == oldest {
|
||||
return format!("/poems/{current}#");
|
||||
}
|
||||
format!("/poems/{oldest}")
|
||||
}
|
||||
|
||||
pub fn get_latest_entry(&self, current: String) -> String {
|
||||
let mut poem_list = self.poem_list.clone();
|
||||
let latest = poem_list
|
||||
.pop()
|
||||
.expect("There is an entry in this list of poems.")
|
||||
.1
|
||||
.clone();
|
||||
if current == latest {
|
||||
return format!("/poems/{current}#");
|
||||
}
|
||||
format!("/poems/{latest}")
|
||||
}
|
||||
|
||||
pub fn get_previous_entry(&self, current: String) -> String {
|
||||
let poem_list = self.poem_list.clone();
|
||||
match poem_list.iter().enumerate().find_map(|(index, p)| {
|
||||
if p.1 == current {
|
||||
if index != 0 {
|
||||
Some(poem_list[index - 1].1.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
Some(entry) => format!("/poems/{entry}"),
|
||||
None => format!("/poems/{current}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_next_entry(&self, current: String) -> String {
|
||||
let poem_list = self.poem_list.clone();
|
||||
match poem_list.iter().enumerate().find_map(|(index, p)| {
|
||||
if p.1 == current {
|
||||
if index != poem_list.len() - 1 {
|
||||
Some(poem_list[index + 1].1.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
Some(entry) => format!("/poems/{entry}"),
|
||||
None => format!("/poems/{current}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_random_entry(&self) -> String {
|
||||
let poem_list = self.poem_list.clone();
|
||||
let mut rng = rand::thread_rng();
|
||||
let random_entry = poem_list
|
||||
.choose(&mut rng)
|
||||
.expect("Got a valid entry")
|
||||
.1
|
||||
.clone();
|
||||
format!("/poems/{random_entry}")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_homepage_paragraph() -> String {
|
||||
let homepage_paragraph_content =
|
||||
@ -21,112 +156,3 @@ pub fn get_homepage_paragraph() -> String {
|
||||
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");
|
||||
let creation_date =
|
||||
String::from(String::from("<br>Written on: ") + filename.split("_").next().unwrap());
|
||||
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 poem_title = poem_to_str.next().unwrap();
|
||||
let poem_content = poem_to_str.into_iter().collect::<Vec<&str>>().join("\n");
|
||||
let poem_title_to_html_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,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_poem_list() -> Vec<(String, String)> {
|
||||
let mut poem_list = Vec::new();
|
||||
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
|
||||
.pop_front()
|
||||
.expect("There is an entry in this list of poems.")
|
||||
.1;
|
||||
if current == oldest {
|
||||
return format!("/poems/{current}#");
|
||||
}
|
||||
format!("/poems/{oldest}")
|
||||
}
|
||||
|
||||
pub fn get_latest_entry(current: String) -> String {
|
||||
let mut poem_list = get_poem_list();
|
||||
let latest = poem_list
|
||||
.pop()
|
||||
.expect("There is an entry in this list of poems.")
|
||||
.1;
|
||||
if current == latest {
|
||||
return format!("/poems/{current}#");
|
||||
}
|
||||
format!("/poems/{latest}")
|
||||
}
|
||||
|
||||
pub fn get_previous_entry(current: String) -> String {
|
||||
let poem_list = get_poem_list();
|
||||
match poem_list.iter().enumerate().find_map(|(index, p)| {
|
||||
if p.1 == current {
|
||||
if index != 0 {
|
||||
Some(poem_list[index - 1].1.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
Some(entry) => format!("/poems/{entry}"),
|
||||
None => format!("/poems/{current}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_next_entry(current: String) -> String {
|
||||
let poem_list = get_poem_list();
|
||||
match poem_list.iter().enumerate().find_map(|(index, p)| {
|
||||
if p.1 == current {
|
||||
if index != poem_list.len() - 1 {
|
||||
Some(poem_list[index + 1].1.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
Some(entry) => format!("/poems/{entry}"),
|
||||
None => format!("/poems/{current}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_random_entry() -> String {
|
||||
let poem_list = get_poem_list();
|
||||
let mut rng = rand::thread_rng();
|
||||
let random_entry = poem_list
|
||||
.choose(&mut rng)
|
||||
.expect("Got a valid entry")
|
||||
.1
|
||||
.clone();
|
||||
format!("/poems/{random_entry}")
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
use crate::void_app::{Element, Props};
|
||||
|
||||
use super::user_prefs::UserPrefs;
|
||||
|
||||
#[derive(PartialEq, Props)]
|
||||
@ -29,14 +29,25 @@ pub struct ButtonProps {
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Props)]
|
||||
pub struct PoemData {
|
||||
pub title: Option<String>,
|
||||
pub content: Option<String>,
|
||||
pub creation_date: Option<String>,
|
||||
pub struct VoidProps {
|
||||
pub slug: Option<String>,
|
||||
pub poem_database: PoemDatabase,
|
||||
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.
|
||||
#[derive(Props)]
|
||||
pub struct PoemChildren<'a> {
|
||||
@ -51,4 +62,4 @@ pub struct PageChildren<'a> {
|
||||
#[derive(Props)]
|
||||
pub struct ContentChildren<'a> {
|
||||
pub children: Element<'a>,
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user