Files
tavernworks/bard/src/components.rs
Myrddin Dundragon 9db5a5ea3d Adding some routing.
Moving more of the Blog pieces into the Blog library.
2025-09-08 10:01:02 -04:00

347 lines
6.2 KiB
Rust

use dioxus::prelude::*;
use tavern::{Adventurer, Legend, Lore, Tale};
use crate::page::Page;
use crate::server::*;
const AUTHOR_CSS: Asset = asset!("/assets/css/blog_author.css");
const LIST_CSS: Asset = asset!("/assets/css/blog_list.css");
const NAV_CSS: Asset = asset!("/assets/css/blog_nav.css");
const POST_CSS: Asset = asset!("/assets/css/blog_post.css");
const TAG_CSS: Asset = asset!("/assets/css/blog_tag.css");
#[derive(Clone, Copy, PartialEq)]
pub enum TagStyle
{
Regular,
Easy,
Medium,
Hard
}
#[derive(Clone, Copy, PartialEq)]
pub enum Tag
{
LeetCode,
Embedded,
Simulation,
Web
}
#[component]
pub fn TagItem(tag: Tag, style: TagStyle) -> Element
{
let text = match tag
{
Tag::LeetCode => { "LeetCode" }
Tag::Embedded => { "Embedded" }
Tag::Simulation => { "Simulation" }
Tag::Web => { "Web" }
};
let tag_style = match style
{
TagStyle::Regular => { "none" }
TagStyle::Easy => { "easy" }
TagStyle::Medium => { "medium" }
TagStyle::Hard => { "hard" }
};
rsx!
{
li
{
class: "tag_item",
a { class: "{tag_style}", "{text}" }
}
}
}
#[component]
pub fn TagList(children: Element) -> Element
{
rsx!
{
document::Link { rel: "stylesheet", href: TAG_CSS }
h5
{
class: "blog_tag_style",
ul
{
class: "tag_list",
{children}
}
}
}
}
#[component]
pub fn BlogAuthor() -> Element
{
rsx!
{
document::Link { rel: "stylesheet", href: AUTHOR_CSS }
section
{
class: "blog_author_style",
}
}
}
#[component]
pub fn BlogItem(title: String, slug: String, author: String,
summary: String, tags: Vec<(Tag, TagStyle)>) -> Element
{
rsx!
{
li
{
class: "blog_item",
Link
{
to: Page::Post { slug: slug },
h1 { "{title}" }
}
TagList
{
for (tag, style) in tags
{
TagItem
{
tag: tag,
style: style
}
}
}
h4 { "Author: {author}" }
p { "{summary}" }
}
}
}
#[component]
pub fn BlogList(tags: Vec<String>, children: Element) -> Element
{
let summaries = use_server_future(move ||
{
let categories = tags.clone();
async move
{
get_blog_list(categories).await
}
})?;
rsx!
{
document::Link { rel: "stylesheet", href: LIST_CSS }
section
{
class: "blog_list_style",
ul
{
class: "blog_list",
{children}
}
}
}
}
#[component]
pub fn BlogNav() -> Element
{
let tags = use_server_future(move ||
{
async move
{
get_tags().await
}
})?;
rsx!
{
document::Link { rel: "stylesheet", href: NAV_CSS }
section
{
class: "blog_nav_style",
div
{
class: "tag_style",
h3 { "Categories" }
ul
{
class: "tag_list",
li
{
class: "tag_item",
a { href: "/blog/LeetCode", "LeetCode" }
}
li
{
class: "tag_item",
a { href: "/blog/Embedded", "Embedded" }
}
li
{
class: "tag_item",
a { href: "/blog/Simulation", "Simulation" }
}
li
{
class: "tag_item",
a { href: "/blog/Web", "Web" }
}
}
}
}
}
}
#[component]
pub fn PostHeaderAuthor(name: String, handle: String, profile_link: String) -> Element
{
rsx!
{
h4 { "Author: ", a { href: "{profile_link}", "{name} @{handle}" } }
}
}
#[component]
pub fn PostHeader(title: String, author: String, tags: Vec<String>) -> Element
{
let author = use_server_future(move ||
{
let target_author = author.clone();
async move
{
get_author(target_author).await
}
})?;
rsx!
{
h1 { "{title}" }
TagList
{
for category in tags
{
TagItem
{
tag: Tag::LeetCode,
style: TagStyle::Regular
}
}
}
match &*author.read()
{
Some(Ok(author)) =>
{
rsx!
{
PostHeaderAuthor
{
name: author.name.clone(),
handle: author.handle.clone(),
profile_link: author.legend.profile.clone()
}
}
}
Some(Err(e)) =>
{
rsx!
{
p { "Unable to show post header." }
p { "{e}" }
}
}
None =>
{
rsx!
{
p { "Loading..." }
}
}
}
}
}
#[component]
pub fn BlogPost(slug: String, children: Element) -> Element
{
let post = use_server_future(move ||
{
let url_slug = slug.clone();
async move
{
get_blog_post(url_slug).await
}
})?;
rsx!
{
document::Link { rel: "stylesheet", href: POST_CSS }
article
{
class: "blog_post_style",
match &*post.read()
{
Some(Ok(post)) =>
{
rsx!
{
PostHeader
{
title: post.lore.title.clone(),
author: post.lore.author.clone(),
tags: post.lore.tags.clone()
}
div { dangerous_inner_html: "{post.story}" }
}
}
Some(Err(e)) =>
{
rsx!
{
p { "Unable to show desired post." }
p { "{e}" }
}
}
None =>
{
rsx!
{
p { "Loading..." }
}
}
}
{children}
}
}
}