✨ readd btns
🐛 fixed some blog stuff
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@ dist/
|
|||||||
pkg/
|
pkg/
|
||||||
target/
|
target/
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
static/
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ log = { version = "0.4" }
|
|||||||
wasm-logger = { version = "0.2" }
|
wasm-logger = { version = "0.2" }
|
||||||
|
|
||||||
serde = { version = "1.0" }
|
serde = { version = "1.0" }
|
||||||
|
wasm-bindgen-futures = "0.4.50"
|
||||||
|
serde_json = "1.0.143"
|
||||||
|
|
||||||
[dependencies.web-sys]
|
[dependencies.web-sys]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
|
|||||||
244
src/main.rs
244
src/main.rs
@@ -85,14 +85,46 @@ impl Component for App {
|
|||||||
z-index: 0 !important;
|
z-index: 0 !important;
|
||||||
" ref={self.node_ref.clone()} />
|
" ref={self.node_ref.clone()} />
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
|
<header style="
|
||||||
|
z-index: 1 !important;
|
||||||
|
display: flex !important;
|
||||||
|
color: white !important;
|
||||||
|
font-family: monospace !important;
|
||||||
|
flex-direction: row !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
max-width: 100vw !important;
|
||||||
|
min-height: 20px !important;
|
||||||
|
height: 20px !important;
|
||||||
|
max-height: 20px !important;
|
||||||
|
filter: url(post.bloom.svg#process) !important;
|
||||||
|
">
|
||||||
|
<p>{r"-»{ "}</p>
|
||||||
|
<Link<Route> to={Route::About}>
|
||||||
|
<a style="color: #CBA6F7FF !important;">{r"about"}</a>
|
||||||
|
</Link<Route>>
|
||||||
|
/*<p>{r"."}</p>
|
||||||
|
<Link<Route> to={Route::Entries}>
|
||||||
|
<a style="color: #CBA6F7FF !important;">{r"blog"}</a>
|
||||||
|
</Link<Route>>*/
|
||||||
|
<p>{r"."}</p>
|
||||||
|
<Link<Route> to={Route::FindMe}>
|
||||||
|
<a style="color: #CBA6F7FF !important;">{r"findme"}</a>
|
||||||
|
</Link<Route>>
|
||||||
|
<p>{r"."}</p>
|
||||||
|
<Link<Route> to={Route::Projects}>
|
||||||
|
<a style="color: #CBA6F7FF !important;">{r"projects"}</a>
|
||||||
|
</Link<Route>>
|
||||||
|
<p>{r" }«-"}</p>
|
||||||
|
</header>
|
||||||
<main style="
|
<main style="
|
||||||
z-index: 1 !important;
|
z-index: 1 !important;
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
color: white !important;
|
color: white !important;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
flex-direction: column !important;
|
flex-direction: column !important;
|
||||||
height: calc(100vh - 18px) !important;
|
min-width: fit-content !important;
|
||||||
width: 70% !important;
|
width: calc(100vw - 18 px) !important;
|
||||||
font-family: monospace !important;
|
font-family: monospace !important;
|
||||||
flex-wrap: nowrap !important;
|
flex-wrap: nowrap !important;
|
||||||
justify-content: space-between !important;
|
justify-content: space-between !important;
|
||||||
@@ -101,52 +133,37 @@ impl Component for App {
|
|||||||
align-self: center !important;
|
align-self: center !important;
|
||||||
margin-left: auto !important;
|
margin-left: auto !important;
|
||||||
margin-right: auto !important;
|
margin-right: auto !important;
|
||||||
|
overflow-x: hidden !important;
|
||||||
|
overflow-y: auto !important;
|
||||||
|
height: fit-content !important;
|
||||||
|
max-height: calc(100vh - 42px) !important;
|
||||||
">
|
">
|
||||||
|
/*
|
||||||
<nav class="navbar" style="
|
min-height: 70vh !important;
|
||||||
z-index: 1 !important;
|
height: 80vw !important;
|
||||||
display: flex !important;
|
*/
|
||||||
flex-direction: row !important;
|
|
||||||
align-items: center;
|
|
||||||
max-width: 100vw !important;
|
|
||||||
filter: url(post.bloom.svg#process) !important;
|
|
||||||
">
|
|
||||||
<p>{r"-»{ "}</p>
|
|
||||||
<Link<Route> to={Route::About}>
|
|
||||||
<a style="color: #CBA6F7FF !important;">{r"about"}</a>
|
|
||||||
</Link<Route>>
|
|
||||||
/*<p>{r"."}</p>
|
|
||||||
<Link<Route> to={Route::Entries}>
|
|
||||||
<a style="color: #CBA6F7FF !important;">{r"blog"}</a>
|
|
||||||
</Link<Route>>*/
|
|
||||||
<p>{r"."}</p>
|
|
||||||
<Link<Route> to={Route::FindMe}>
|
|
||||||
<a style="color: #CBA6F7FF !important;">{r"findme"}</a>
|
|
||||||
</Link<Route>>
|
|
||||||
<p>{r"."}</p>
|
|
||||||
<Link<Route> to={Route::Projects}>
|
|
||||||
<a style="color: #CBA6F7FF !important;">{r"projects"}</a>
|
|
||||||
</Link<Route>>
|
|
||||||
<p>{r" }«-"}</p>
|
|
||||||
</nav>
|
|
||||||
<div style="
|
<div style="
|
||||||
background-color: rgba(0, 0, 0, 0.3125) !important;
|
background-color: rgba(0, 0, 0, 0.3125) !important;
|
||||||
backdrop-filter: blur(4px) !important;
|
backdrop-filter: blur(6px) !important;
|
||||||
padding: 4px 0px 0px 4px !important;
|
padding: 4px 0px 0px 4px !important;
|
||||||
border-radius: 1.0rem !important;
|
border-radius: 1.0rem !important;
|
||||||
border-style: solid !important;
|
border-style: solid !important;
|
||||||
border-color: black !important;
|
border-color: black !important;
|
||||||
border-width: 1px !important;
|
border-width: 1px !important;
|
||||||
z-index: 1 !important;
|
z-index: 1 !important;
|
||||||
overflow-x: auto !important;
|
overflow-x: hidden !important;
|
||||||
overflow-y: auto !important;
|
overflow-y: auto !important;
|
||||||
min-width: 70vw !important;
|
min-width: 70vw !important;
|
||||||
width: 70vh !important;
|
width: 70vh !important;
|
||||||
max-width: 100vw !important;
|
max-width: calc(100vw - 18px) !important;
|
||||||
min-height: 70vh !important;
|
height: 100% !important;
|
||||||
height: 80vw !important;
|
margin-top: auto !important;
|
||||||
max-height: 100vh !important;
|
margin-bottom: auto !important;
|
||||||
"><Switch<Route> render={switch} /></div>
|
scrollbar-width: thin !important;
|
||||||
|
scrollbar-color: transparent transparent !important;
|
||||||
|
"><Switch<Route> render={switch} />
|
||||||
|
{self.view_buttons()}
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</>
|
</>
|
||||||
@@ -170,13 +187,13 @@ fn switch(routes: Route) -> Html {
|
|||||||
html! { <Entries /> }
|
html! { <Entries /> }
|
||||||
}
|
}
|
||||||
Route::Entry { id } => {
|
Route::Entry { id } => {
|
||||||
html! { <Entry seed={id as u8} /> }
|
html! { <Entry id={id as u8} /> }
|
||||||
}
|
}
|
||||||
Route::Authors => {
|
Route::Authors => {
|
||||||
html! { <Authors /> }
|
html! { <Authors /> }
|
||||||
}
|
}
|
||||||
Route::Author { id } => {
|
Route::Author { id } => {
|
||||||
html! { <Author seed={id as u8} /> }
|
html! { <Author id={id as u8} /> }
|
||||||
}
|
}
|
||||||
|
|
||||||
Route::FindMe => {
|
Route::FindMe => {
|
||||||
@@ -193,88 +210,79 @@ fn switch(routes: Route) -> Html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
fn view_list(&self, _ctx: &Context<Self>) -> Html {
|
|
||||||
html! {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view_buttons(&self) -> Html {
|
fn view_buttons(&self) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<>
|
<div style="
|
||||||
<div style="
|
z-index: 1 !important;
|
||||||
backdrop-filter: blur(4px);
|
display: flex !important;
|
||||||
width: 100vw !important;
|
flex-wrap: wrap !important;
|
||||||
text-align: left !important;
|
flex-direction: row !important;
|
||||||
vertical-align: middle !important;
|
justify-content: center !important;
|
||||||
height: 40px !important; max-height: 40px !important;
|
min-width: 70vw !important;
|
||||||
image-rendering: pixelated !important;
|
width: 70vh !important;
|
||||||
">
|
max-width: calc(100vw - 18px) !important;
|
||||||
<div style="
|
height: fit-content !important;
|
||||||
width: 100% !important;
|
overflow: hidden !important;
|
||||||
min-height: 40px !important;
|
margin-right: auto !important;
|
||||||
height: 40px !important;
|
margin-left: auto !important;
|
||||||
max-height: 40px !important;
|
">
|
||||||
overflow-y: hidden !important;
|
<a style="
|
||||||
overflow-x: auto !important;
|
width: 88px !important;
|
||||||
">
|
height: 31px !important
|
||||||
<a class="mt-1 mb-1 mr-1 ml-0" style="
|
" href="https://i0ur.ing/"><img loading="eager" alt="iouring" src="iouring.png" /></a>
|
||||||
width: 88px !important;
|
<a style="
|
||||||
height: 31px !important
|
width: 88px !important;
|
||||||
" href="https://i0ur.ing/"><img loading="eager" alt="iouring" src="iouring.png" /></a>
|
height: 31px !important
|
||||||
<a class="mt-1 mb-1 mr-1 ml-0" style="
|
" href="https://webassembly.org/"><img loading="eager" alt="wasm" src="wasm.png" /></a>
|
||||||
width: 88px !important;
|
<a style="
|
||||||
height: 31px !important
|
width: 88px !important;
|
||||||
" href="https://webassembly.org/"><img loading="eager" alt="wasm" src="wasm.png" /></a>
|
height: 31px !important
|
||||||
<a class="mt-1 mb-1 mr-1 ml-0" style="
|
" href="https://beta.servfail.network/"><img loading="eager" alt="servfail" src="servfail.png" /></a>
|
||||||
width: 88px !important;
|
<a style="
|
||||||
height: 31px !important
|
width: 88px !important;
|
||||||
" href="https://beta.servfail.network/"><img loading="eager" alt="servfail" src="servfail.png" /></a>
|
height: 31px !important
|
||||||
<a class="mt-1 mb-1 mr-1 ml-0" style="
|
" href="https://www.dataforest.net/en/"><img loading="eager" alt="dataforest" src="dataforest.png" /></a>
|
||||||
width: 88px !important;
|
<a style="
|
||||||
height: 31px !important
|
width: 88px !important;
|
||||||
" href="https://www.dataforest.net/en/"><img loading="eager" alt="dataforest" src="dataforest.png" /></a>
|
height: 31px !important
|
||||||
<a class="mt-1 mb-1 mr-1 ml-0" style="
|
" href="https://fedoraproject.org/"><img loading="eager" alt="fedora" src="fedora.png" /></a>
|
||||||
width: 88px !important;
|
<a style="
|
||||||
height: 31px !important
|
width: 88px !important;
|
||||||
" href="https://fedoraproject.org/"><img loading="eager" alt="fedora" src="fedora.png" /></a>
|
height: 31px !important
|
||||||
<a class="mt-1 mb-1 mr-1 ml-0" style="
|
" href="https://artixlinux.org/"><img loading="eager" alt="artix" src="artix.png" /></a>
|
||||||
width: 88px !important;
|
<a style="
|
||||||
height: 31px !important
|
width: 88px !important;
|
||||||
" href="https://artixlinux.org/"><img loading="eager" alt="artix" src="artix.png" /></a>
|
height: 31px !important
|
||||||
<a class="mt-1 mb-1 mr-1 ml-0" style="
|
" href="https://nixos.org/"><img loading="eager" alt="nixos" src="nixos.png" /></a>
|
||||||
width: 88px !important;
|
<a style="
|
||||||
height: 31px !important
|
width: 88px !important;
|
||||||
" href="https://nixos.org/"><img loading="eager" alt="nixos" src="nixos.png" /></a>
|
height: 31px !important
|
||||||
<a class="mt-1 mb-1 mr-1 ml-0" style="
|
" href="https://chimera-linux.org/"><img loading="eager" alt="void" src="chimera.png" /></a>
|
||||||
width: 88px !important;
|
<a style="
|
||||||
height: 31px !important
|
width: 88px !important;
|
||||||
" href="https://chimera-linux.org/"><img loading="eager" alt="void" src="chimera.png" /></a>
|
height: 31px !important
|
||||||
<a class="mt-1 mb-1 mr-1 ml-0" style="
|
" href="https://voidlinux.org/"><img loading="eager" alt="void" src="void.png" /></a>
|
||||||
width: 88px !important;
|
<a style="
|
||||||
height: 31px !important
|
width: 88px !important;
|
||||||
" href="https://voidlinux.org/"><img loading="eager" alt="void" src="void.png" /></a>
|
height: 31px !important
|
||||||
<a class="mt-1 mb-1 mr-1 ml-0" style="
|
" href="https://www.rust-lang.org/"><img loading="eager" alt="rust" src="rust.png" /></a>
|
||||||
width: 88px !important;
|
<a style="
|
||||||
height: 31px !important
|
width: 88px !important;
|
||||||
" href="https://www.rust-lang.org/"><img loading="eager" alt="rust" src="rust.png" /></a>
|
height: 31px !important
|
||||||
<a class="mt-1 mb-1 mr-1 ml-0" style="
|
" href="https://dotnet.microsoft.com/en-us/"><img loading="eager" alt="csharp" src="csharp.png" /></a>
|
||||||
width: 88px !important;
|
<a style="
|
||||||
height: 31px !important
|
width: 88px !important;
|
||||||
" href="https://dotnet.microsoft.com/en-us/"><img loading="eager" alt="csharp" src="csharp.png" /></a>
|
height: 31px !important
|
||||||
<a class="mt-1 mb-1 mr-1 ml-0" style="
|
" href="https://kotlinlang.org/"><img loading="eager" alt="kotlin" src="kotlin.png" /></a>
|
||||||
width: 88px !important;
|
<a style="
|
||||||
height: 31px !important
|
width: 88px !important;
|
||||||
" href="https://kotlinlang.org/"><img loading="eager" alt="kotlin" src="kotlin.png" /></a>
|
height: 31px !important
|
||||||
<a class="mt-1 mb-1 mr-1 ml-0" style="
|
" href="https://www.java.com/"><img loading="eager" alt="java" src="java.png" /></a>
|
||||||
width: 88px !important;
|
<a style="
|
||||||
height: 31px !important
|
width: 88px !important;
|
||||||
" href="https://www.java.com/"><img loading="eager" alt="java" src="java.png" /></a>
|
height: 31px !important
|
||||||
<a class="mt-1 mb-1 mr-1 ml-0" style="
|
"><img loading="eager" alt="aqueer" src="aqueer.png" /></a>
|
||||||
width: 88px !important;
|
</div>
|
||||||
height: 31px !important
|
|
||||||
"><img loading="eager" alt="aqueer" src="aqueer.png" /></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use yew::prelude::*;
|
|
||||||
use crate::pages::blog::content;
|
use crate::pages::blog::content;
|
||||||
use crate::pages::blog::content::BlogEntry;
|
use crate::pages::blog::content::BlogEntry;
|
||||||
|
use yew::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Properties)]
|
#[derive(Clone, Debug, Eq, PartialEq, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
pub seed: u8,
|
pub id: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Author {
|
pub struct Author {
|
||||||
@@ -15,68 +15,33 @@ impl Component for Author {
|
|||||||
type Properties = Props;
|
type Properties = Props;
|
||||||
|
|
||||||
fn create(ctx: &Context<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
Self { author: content::Author::from_seed(ctx.props().seed), }
|
Self {
|
||||||
|
author: content::Author::from_id(ctx.props().id),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {
|
fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {
|
||||||
self.author = content::Author::from_seed(ctx.props().seed);
|
self.author = content::Author::from_id(ctx.props().id);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
let Self { author } = self;
|
let Self { author } = self;
|
||||||
html! {
|
html! {
|
||||||
<div class="tile is-parent container box is-small is-flex-shrink-5 mb-5 mt-5">
|
<div>
|
||||||
<img alt="insert pfp here" loading="eager" class="image is-128x128 is-square is-inline-block mg-small" src={author.image_url.clone()} />
|
<img alt="insert pfp here" loading="eager" src={author.image_url.clone()} />
|
||||||
<div class="columns is-narrow ml-3 is-inline-block is-vcentered is-centered is-gapless is-multiline is-0 mt-4" style="vertical-align: top !important;">
|
<div style="vertical-align: top !important;">
|
||||||
<p class="column is-narrow" style="filter: url(post.bloom.svg#process) !important; color: #B4BEFE !important;">{author.name.clone()}</p>
|
<p style="filter: url(post.bloom.svg#process) !important; color: #B4BEFE !important;">{author.name.clone()}</p>
|
||||||
<p class="column is-narrow" style="background-clip: text !important; background-image: linear-gradient(45deg, #5BCEFAFF, #F5A9B8FF, #FFFFFFFF) !important;">
|
<p style="background-clip: text !important; background-image: linear-gradient(45deg, #5BCEFAFF, #F5A9B8FF, #FFFFFFFF) !important;">
|
||||||
{ for author.keywords.iter().map(|tag| html! { <p>{ tag }</p> }) }
|
{ for author.keywords.iter().map(|tag| html! { <p>{ tag }</p> }) }
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<hr style="background-color: #B4BEFE60 !important;" />
|
<hr style="background-color: #B4BEFE60 !important;" />
|
||||||
<p class="subtitle">{r#"about me"#}</p>
|
<p>{r#"about me"#}</p>
|
||||||
<div class="content is-size-7">
|
<div>
|
||||||
{ author.about.clone() }
|
{ author.about.clone() }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
<div class="section container">
|
|
||||||
<div class="tile is-ancestor is-vertical">
|
|
||||||
<div class="tile is-parent">
|
|
||||||
<article class="tile is-child notification is-light">
|
|
||||||
<p class="title">{ &author.name }</p>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
<div class="tile">
|
|
||||||
<div class="tile is-parent is-3">
|
|
||||||
<article class="tile is-child notification">
|
|
||||||
<p class="title">{ "Interests" }</p>
|
|
||||||
<div class="tags">
|
|
||||||
{ for author.keywords.iter().map(|tag| html! { <span class="tag is-info">{ tag }</span> }) }
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
<div class="tile is-parent">
|
|
||||||
<figure class="tile is-child image is-square">
|
|
||||||
<img alt="The author's profile picture." src={author.image_url.clone()} />
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
<div class="tile is-parent">
|
|
||||||
<article class="tile is-child notification is-info">
|
|
||||||
<div class="content">
|
|
||||||
<p class="title">{ "About me" }</p>
|
|
||||||
<div class="content">
|
|
||||||
{ author.about.clone() }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
*/
|
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew_router::components::Link;
|
use yew_router::components::Link;
|
||||||
|
|
||||||
use crate::pages::blog::content::BlogEntry;
|
|
||||||
use crate::pages::blog::content::Author;
|
use crate::pages::blog::content::Author;
|
||||||
|
use crate::pages::blog::content::BlogEntry;
|
||||||
|
|
||||||
use crate::Route;
|
use crate::Route;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Properties)]
|
#[derive(Clone, Debug, PartialEq, Eq, Properties)]
|
||||||
pub struct PropsAuthorCard {
|
pub struct PropsAuthorCard {
|
||||||
pub seed: u8,
|
pub id: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AuthorCard {
|
pub struct AuthorCard {
|
||||||
@@ -20,11 +20,13 @@ impl Component for AuthorCard {
|
|||||||
type Properties = PropsAuthorCard;
|
type Properties = PropsAuthorCard;
|
||||||
|
|
||||||
fn create(ctx: &Context<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
Self { author: Author::from_seed(ctx.props().seed), }
|
Self {
|
||||||
|
author: Author::from_id(ctx.props().id),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {
|
fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {
|
||||||
self.author = Author::from_seed(ctx.props().seed);
|
self.author = Author::from_id(ctx.props().id);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,16 +34,16 @@ impl Component for AuthorCard {
|
|||||||
let Self { author } = self;
|
let Self { author } = self;
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<div class="card">
|
<div>
|
||||||
<div class="card-content">
|
<div>
|
||||||
<div class="media">
|
<div>
|
||||||
<div class="media-left">
|
<div>
|
||||||
<figure class="image is-128x128">
|
<figure>
|
||||||
<img alt="this should normally show an image mew,," src={author.image_url.clone()} />
|
<img alt="this should normally show an image mew,," src={author.image_url.clone()} />
|
||||||
</figure>
|
</figure>
|
||||||
</div>
|
</div>
|
||||||
<div class="media-content">
|
<div>
|
||||||
<p class="title is-3">{ &author.name }</p>
|
<p>{ &author.name }</p>
|
||||||
<p>
|
<p>
|
||||||
{ "I like " }
|
{ "I like " }
|
||||||
<b>{ author.keywords.join(", ") }</b>
|
<b>{ author.keywords.join(", ") }</b>
|
||||||
@@ -49,8 +51,8 @@ impl Component for AuthorCard {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer class="card-footer">
|
<footer>
|
||||||
<Link<Route> classes={classes!("card-footer-item")} to={Route::Author { id: author.seed }}>
|
<Link<Route> classes={classes!("card-footer-item")} to={Route::Author { id: author.id }}>
|
||||||
{ "Profile" }
|
{ "Profile" }
|
||||||
</Link<Route>>
|
</Link<Route>>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -7,24 +7,24 @@ use crate::pages::blog::authorcard::AuthorCard;
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
pub struct Authors {
|
pub struct Authors {
|
||||||
seeds: Vec<u8>,
|
ids: Vec<u8>,
|
||||||
}
|
}
|
||||||
impl Component for Authors {
|
impl Component for Authors {
|
||||||
type Message = (); //Msg;
|
type Message = (); //Msg;
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_ctx: &Context<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
Self { seeds: vec![0], }
|
Self { ids: vec![0], }
|
||||||
}
|
}
|
||||||
|
|
||||||
/*fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
/*fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg { Msg::NextAuthors => { self.seeds = vec![0]; true } }
|
match msg { Msg::NextAuthors => { self.ids = vec![0]; true } }
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
fn view(&self, _: &Context<Self>) -> Html {
|
fn view(&self, _: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
{ for self.seeds.iter().map(|&seed| { html! {
|
{ for self.ids.iter().map(|&id| { html! {
|
||||||
<AuthorCard {seed} />
|
<AuthorCard {id} />
|
||||||
} }) }
|
} }) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,144 +1,74 @@
|
|||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Author {
|
pub struct Author {
|
||||||
pub seed: u8,
|
pub id: u8,
|
||||||
|
pub image_url: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub keywords: Vec<String>,
|
pub keywords: Vec<String>,
|
||||||
pub image_url: String,
|
pub about: String,
|
||||||
pub about: String
|
|
||||||
}
|
}
|
||||||
impl BlogEntry for Author {
|
impl BlogEntry for Author {
|
||||||
fn from_entry(entry: &mut Entry) -> Self {
|
fn from_entry(entry: &mut Entry) -> Self {
|
||||||
return match entry.seed {
|
match entry.id {
|
||||||
0 => Self {
|
0 => Self {
|
||||||
seed: entry.seed,
|
id: entry.id,
|
||||||
name: "iouring".to_string(),
|
|
||||||
image_url: "profile.avif".to_string(),
|
image_url: "profile.avif".to_string(),
|
||||||
about: "sup".to_string(),
|
name: "iouring".to_string(),
|
||||||
keywords: vec![
|
|
||||||
"meow".to_string(),
|
|
||||||
"mrrp".to_string(),
|
|
||||||
"mew".to_string()
|
|
||||||
]
|
|
||||||
},
|
|
||||||
_ => Self {
|
|
||||||
seed: u8::MAX,
|
|
||||||
name: "not found".to_string(),
|
|
||||||
image_url: "".to_string(),
|
|
||||||
about: "".to_string(),
|
|
||||||
keywords: vec![]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub struct PostMeta {
|
|
||||||
pub seed: u8,
|
|
||||||
pub title: String,
|
|
||||||
pub author: Author,
|
|
||||||
pub keywords: Vec<String>,
|
|
||||||
pub image_url: String,
|
|
||||||
}
|
|
||||||
impl BlogEntry for PostMeta {
|
|
||||||
fn from_entry(entry: &mut Entry) -> Self {
|
|
||||||
return match entry.seed {
|
|
||||||
0 => Self {
|
|
||||||
seed: entry.seed,
|
|
||||||
title: "awawa title".to_string(),
|
|
||||||
author: Author::from_entry(entry),
|
|
||||||
keywords: vec!["meow".to_string(), "mrrp".to_string(), "mew".to_string()],
|
keywords: vec!["meow".to_string(), "mrrp".to_string(), "mew".to_string()],
|
||||||
image_url: "testimage.jpg".to_string()
|
about: "sup".to_string(),
|
||||||
},
|
},
|
||||||
_ => Self {
|
_ => Self {
|
||||||
seed: entry.seed,
|
id: u8::MAX,
|
||||||
title: "not found".to_string(),
|
image_url: "".to_string(),
|
||||||
author: Author::from_entry(entry),
|
name: "not found".to_string(),
|
||||||
keywords: vec![],
|
keywords: vec![],
|
||||||
image_url: "".to_string()
|
about: "".to_string(),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Post {
|
pub struct Post {
|
||||||
pub meta: PostMeta,
|
pub id: u8,
|
||||||
pub content: Vec<PostPart>,
|
pub author: Author,
|
||||||
|
pub title: String,
|
||||||
|
pub content: Vec<String>,
|
||||||
}
|
}
|
||||||
impl BlogEntry for Post {
|
impl BlogEntry for Post {
|
||||||
fn from_entry(entry: &mut Entry) -> Self {
|
fn from_entry(entry: &mut Entry) -> Self {
|
||||||
return Self {
|
return match entry.id {
|
||||||
meta: PostMeta::from_entry(entry),
|
|
||||||
content: vec![PostPart::from_entry(entry)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub enum PostPart {
|
|
||||||
Section(Section),
|
|
||||||
Quote(Quote),
|
|
||||||
}
|
|
||||||
impl BlogEntry for PostPart {
|
|
||||||
fn from_entry(entry: &mut Entry) -> Self {
|
|
||||||
// TODO: ... | add proper logic
|
|
||||||
|
|
||||||
return Self::Section(Section::from_entry(entry))
|
|
||||||
// return Self::Quote(Quote::from_entry(entry))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub struct Section {
|
|
||||||
pub title: String,
|
|
||||||
pub paragraphs: Vec<String>,
|
|
||||||
pub image_url: String,
|
|
||||||
}
|
|
||||||
impl BlogEntry for Section {
|
|
||||||
fn from_entry(entry: &mut Entry) -> Self {
|
|
||||||
return match entry.seed {
|
|
||||||
0 => Self {
|
0 => Self {
|
||||||
title: "awawa title".to_string(),
|
id: 0,
|
||||||
image_url: "".to_string(),
|
author: Author::from_id(0),
|
||||||
paragraphs: vec![
|
title: "meow".parse().unwrap(),
|
||||||
"meow 1".to_string(),
|
content: vec!["<h1>meow</h1>", "mrrp", "meow"]
|
||||||
"mrrp 2".to_string(),
|
.iter()
|
||||||
"mew 3".to_string()
|
.map(|s| s.to_string())
|
||||||
]
|
.collect(),
|
||||||
},
|
},
|
||||||
_ => Self {
|
_ => Self {
|
||||||
title: "not found".to_string(),
|
id: u8::MAX,
|
||||||
image_url: "".to_string(),
|
author: Author::from_id(u8::MAX),
|
||||||
paragraphs: vec![]
|
title: "not found".parse().unwrap(),
|
||||||
|
content: vec![],
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub struct Quote {
|
|
||||||
pub author: Author,
|
|
||||||
pub content: String,
|
|
||||||
}
|
|
||||||
impl BlogEntry for Quote {
|
|
||||||
fn from_entry(entry: &mut Entry) -> Self {
|
|
||||||
return Self { author: Author::from_seed(entry.seed), content: "awawa content".to_string() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Entry {
|
pub struct Entry {
|
||||||
pub seed: u8
|
pub id: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Entry {
|
impl Entry {
|
||||||
pub fn from_seed(seed: u8) -> Self {
|
pub fn from_id(seed: u8) -> Self {
|
||||||
Self { seed }
|
Self { id: seed }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BlogEntry: Sized {
|
pub trait BlogEntry: Sized {
|
||||||
fn from_entry(entry: &mut Entry) -> Self;
|
fn from_entry(entry: &mut Entry) -> Self;
|
||||||
fn from_seed(seed: u8) -> Self {
|
fn from_id(id: u8) -> Self {
|
||||||
Self::from_entry(&mut Entry::from_seed(seed))
|
Self::from_entry(&mut Entry::from_id(id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,91 +1,37 @@
|
|||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew_router::prelude::*;
|
|
||||||
|
|
||||||
use crate::pages::blog::content::Author;
|
use crate::pages::blog::content::{Author, Post};
|
||||||
use crate::pages::blog::content::BlogEntry;
|
use crate::pages::blog::content::BlogEntry;
|
||||||
use crate::pages::blog::entrycard::EntryCard;
|
use crate::pages::blog::entrycard::EntryCard;
|
||||||
use crate::pages::blog::navigation::{PageQuery, Pagination};
|
|
||||||
use crate::Route;
|
|
||||||
|
|
||||||
const ITEMS_PER_PAGE: u8 = 10;
|
pub struct Entries {}
|
||||||
const TOTAL_PAGES: u8 = 1;
|
|
||||||
|
|
||||||
pub enum Msg {
|
|
||||||
PageUpdated,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Entries {
|
|
||||||
page: u8,
|
|
||||||
_listener: LocationHandle,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current_page(ctx: &Context<Entries>) -> u8 {
|
|
||||||
let location = ctx.link().location().unwrap();
|
|
||||||
|
|
||||||
location.query::<PageQuery>().map(|it| it.page as u8).unwrap_or(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Component for Entries {
|
impl Component for Entries {
|
||||||
type Message = Msg;
|
type Message = ();
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(ctx: &Context<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
let link = ctx.link().clone();
|
Self {}
|
||||||
let listener = ctx
|
|
||||||
.link()
|
|
||||||
.add_location_listener(link.callback(move |_| Msg::PageUpdated))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
page: current_page(ctx),
|
|
||||||
_listener: listener,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
|
||||||
match msg {
|
|
||||||
Msg::PageUpdated => self.page = current_page(ctx),
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
let page = self.page;
|
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div class="section container">
|
<div>
|
||||||
<h1 class="title">{ "entries" }</h1>
|
<h1>{ "entries" }</h1>
|
||||||
<h2 class="subtitle">{ "here are some things i yapped about" }</h2>
|
<h2>{ "here are some things i yapped about" }</h2>
|
||||||
{ self.view_posts(ctx) }
|
{ self.view_posts(ctx) }
|
||||||
<Pagination
|
|
||||||
{page}
|
|
||||||
total_pages={TOTAL_PAGES}
|
|
||||||
route_to_page={Route::Entries}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Entries {
|
impl Entries {
|
||||||
fn view_posts(&self, _ctx: &Context<Self>) -> Html {
|
fn view_posts(&self, _ctx: &Context<Self>) -> Html {
|
||||||
let start_seed = (self.page - 1) * ITEMS_PER_PAGE;
|
let cards: Vec<_> = (0..2) // TODO: ... | add var
|
||||||
let cards: Vec<_> = (0..ITEMS_PER_PAGE)
|
.filter(|&id_offset| Post::from_id(id_offset).author.id != u8::MAX)
|
||||||
.filter(|&seed_offset| Author::from_seed(seed_offset).seed != u8::MAX)
|
.map(|id_offset| {
|
||||||
.map(|seed_offset| {
|
html! {<EntryCard id={id_offset} />}
|
||||||
html! {
|
})
|
||||||
<li class="list-item mb-5">
|
.collect();
|
||||||
<EntryCard seed={start_seed + seed_offset} />
|
html! { { for cards } }
|
||||||
</li>
|
|
||||||
}
|
|
||||||
}).collect();
|
|
||||||
html! {
|
|
||||||
<div class="columns">
|
|
||||||
<div class="column">
|
|
||||||
<ul class="list">
|
|
||||||
{ for cards }
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,13 +3,13 @@ use std::rc::Rc;
|
|||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew_router::prelude::*;
|
use yew_router::prelude::*;
|
||||||
|
|
||||||
use crate::Route;
|
|
||||||
use crate::pages::blog::content;
|
use crate::pages::blog::content;
|
||||||
use crate::pages::blog::content::BlogEntry;
|
use crate::pages::blog::content::BlogEntry;
|
||||||
|
use crate::Route;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Properties)]
|
#[derive(Clone, Debug, Eq, PartialEq, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
pub seed: u8,
|
pub id: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
@@ -20,132 +20,44 @@ pub struct PostState {
|
|||||||
impl Reducible for PostState {
|
impl Reducible for PostState {
|
||||||
type Action = u8;
|
type Action = u8;
|
||||||
fn reduce(self: Rc<Self>, action: u8) -> Rc<Self> {
|
fn reduce(self: Rc<Self>, action: u8) -> Rc<Self> {
|
||||||
Self { inner: content::Post::from_seed(action.into()), }.into()
|
Self {
|
||||||
|
inner: content::Post::from_id(action.into()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[function_component]
|
#[function_component]
|
||||||
pub fn Entry(props: &Props) -> Html {
|
pub fn Entry(props: &Props) -> Html {
|
||||||
let seed = props.seed;
|
let id = props.id;
|
||||||
|
|
||||||
let post = use_reducer(|| PostState {
|
let post = use_reducer(|| PostState {
|
||||||
inner: content::Post::from_seed(seed.into()),
|
inner: content::Post::from_id(id.into()),
|
||||||
});
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
let post_dispatcher = post.dispatcher();
|
let post_dispatcher = post.dispatcher();
|
||||||
use_effect_with(seed, move |seed| {
|
use_effect_with(id, move |id| {
|
||||||
post_dispatcher.dispatch(*seed);
|
post_dispatcher.dispatch(*id);
|
||||||
|
|
||||||
|| {}
|
|| {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let post = &post.inner;
|
let post = &post.inner;
|
||||||
|
|
||||||
let render_quote = |quote: &content::Quote| {
|
|
||||||
html! {
|
|
||||||
<article class="media block box my-6">
|
|
||||||
<figure class="media-left">
|
|
||||||
<p class="image is-64x64">
|
|
||||||
<img alt="The author's profile" src={quote.author.image_url.clone()} loading="lazy" />
|
|
||||||
</p>
|
|
||||||
</figure>
|
|
||||||
<div class="media-content">
|
|
||||||
<div class="content">
|
|
||||||
<Link<Route> classes={classes!("is-size-5")} to={Route::Author { id: quote.author.seed }}>
|
|
||||||
<strong>{ "e.author.name }</strong>
|
|
||||||
</Link<Route>>
|
|
||||||
<p class="is-family-secondary">
|
|
||||||
{ "e.content }
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let render_section_hero = |section: &content::Section| {
|
|
||||||
html! {
|
|
||||||
<section class="hero is-dark has-background mt-6 mb-3">
|
|
||||||
<img alt="This section's image" class="hero-background is-transparent" src={section.image_url.clone()} loading="lazy" />
|
|
||||||
<div class="hero-body">
|
|
||||||
<div class="container">
|
|
||||||
<h2 class="subtitle">{ §ion.title }</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let render_section = |section, show_hero| {
|
|
||||||
let hero = if show_hero {
|
|
||||||
render_section_hero(section)
|
|
||||||
} else {
|
|
||||||
html! {}
|
|
||||||
};
|
|
||||||
let paragraphs = section.paragraphs.iter().map(|paragraph| {
|
|
||||||
html! {
|
|
||||||
<p>{ paragraph }</p>
|
|
||||||
}
|
|
||||||
});
|
|
||||||
html! {
|
|
||||||
<section>
|
|
||||||
{ hero }
|
|
||||||
<div>{ for paragraphs }</div>
|
|
||||||
</section>
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let view_content = {
|
|
||||||
// don't show hero for the first section
|
|
||||||
let mut show_hero = false;
|
|
||||||
|
|
||||||
let parts = post.content.iter().map(|part| match part {
|
|
||||||
content::PostPart::Section(section) => {
|
|
||||||
let html = render_section(section, show_hero);
|
|
||||||
// show hero between sections
|
|
||||||
show_hero = true;
|
|
||||||
html
|
|
||||||
}
|
|
||||||
content::PostPart::Quote(quote) => {
|
|
||||||
// don't show hero after a quote
|
|
||||||
show_hero = false;
|
|
||||||
render_quote("e)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
html! {{for parts}}
|
|
||||||
};
|
|
||||||
|
|
||||||
let keywords = post
|
|
||||||
.meta
|
|
||||||
.keywords
|
|
||||||
.iter()
|
|
||||||
.map(|keyword| html! { <span class="tag is-info">{ keyword }</span> });
|
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<section class="hero is-medium is-light has-background">
|
<h1>
|
||||||
<img alt="The hero's background" class="hero-background is-transparent" src={post.meta.image_url.clone()} />
|
{ &post.title }
|
||||||
<div class="hero-body">
|
</h1>
|
||||||
<div class="container">
|
<h2>
|
||||||
<h1 class="title">
|
{ "by " }
|
||||||
{ &post.meta.title }
|
<Link<Route> to={Route::Author { id: post.author.id }}>
|
||||||
</h1>
|
{ &post.author.name }
|
||||||
<h2 class="subtitle">
|
</Link<Route>>
|
||||||
{ "by " }
|
</h2>
|
||||||
<Link<Route> classes={classes!("has-text-weight-semibold")} to={Route::Author { id: post.meta.author.seed }}>
|
<div>
|
||||||
{ &post.meta.author.name }
|
{ for post.content.iter() }
|
||||||
</Link<Route>>
|
|
||||||
</h2>
|
|
||||||
<div class="tags">
|
|
||||||
{ for keywords }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<div class="section container">
|
|
||||||
{ view_content }
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,41 +3,43 @@ use std::rc::Rc;
|
|||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew_router::components::Link;
|
use yew_router::components::Link;
|
||||||
|
|
||||||
use crate::pages::blog::content::BlogEntry;
|
use crate::pages::blog::content::{BlogEntry, Post};
|
||||||
use crate::pages::blog::content::PostMeta;
|
|
||||||
|
|
||||||
use crate::Route;
|
use crate::Route;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Properties)]
|
#[derive(Clone, Debug, PartialEq, Eq, Properties)]
|
||||||
pub struct PropsEntryCard {
|
pub struct PropsEntryCard {
|
||||||
pub seed: u8,
|
pub id: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub struct PostMetaState {
|
pub struct PostState {
|
||||||
inner: PostMeta,
|
inner: Post,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Reducible for PostMetaState {
|
impl Reducible for PostState {
|
||||||
type Action = u8;
|
type Action = u8;
|
||||||
|
|
||||||
fn reduce(self: Rc<Self>, action: u8) -> Rc<Self> {
|
fn reduce(self: Rc<Self>, action: u8) -> Rc<Self> {
|
||||||
Self { inner: PostMeta::from_seed(action.into()), }.into()
|
Self {
|
||||||
|
inner: Post::from_id(action.into()),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[function_component]
|
#[function_component]
|
||||||
pub fn EntryCard(props: &PropsEntryCard) -> Html {
|
pub fn EntryCard(props: &PropsEntryCard) -> Html {
|
||||||
let seed = props.seed;
|
let id = props.id;
|
||||||
|
|
||||||
let post = use_reducer_eq(|| PostMetaState {
|
let post = use_reducer_eq(|| PostState {
|
||||||
inner: PostMeta::from_seed(seed.into()),
|
inner: Post::from_id(id.into()),
|
||||||
});
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
let post_dispatcher = post.dispatcher();
|
let post_dispatcher = post.dispatcher();
|
||||||
use_effect_with(seed, move |seed| {
|
use_effect_with(id, move |id| {
|
||||||
post_dispatcher.dispatch(*seed);
|
post_dispatcher.dispatch(*id);
|
||||||
|
|
||||||
|| {}
|
|| {}
|
||||||
});
|
});
|
||||||
@@ -46,23 +48,13 @@ pub fn EntryCard(props: &PropsEntryCard) -> Html {
|
|||||||
let post = &post.inner;
|
let post = &post.inner;
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div class="card" style="height: 300px !important; max-height: 300px !important;">
|
<div style="height: fit-content !important; width: fit-content !important;">
|
||||||
<img loading="eager" class="card-image image is-2by1" src={post.image_url.clone()} alt="blog image" style="
|
<Link<Route> classes={classes!("title", "is-block")} to={Route::Entry { id: post.id }}>
|
||||||
object-fit: cover !important;
|
{ &post.title }
|
||||||
width: 100% !important;
|
</Link<Route>>
|
||||||
max-width: 100% !important;
|
<Link<Route> classes={classes!("subtitle", "is-block")} to={Route::Author { id: post.author.id }}>
|
||||||
height: 200px !important;
|
{ &post.author.name }
|
||||||
max-height: 200px !important;
|
</Link<Route>>
|
||||||
filter: blur(6px) !important;
|
|
||||||
" />
|
|
||||||
<div class="card-content" style="height: fit-content !important; width: fit-content !important;">
|
|
||||||
<Link<Route> classes={classes!("title", "is-block")} to={Route::Entry { id: post.seed }}>
|
|
||||||
{ &post.title }
|
|
||||||
</Link<Route>>
|
|
||||||
<Link<Route> classes={classes!("subtitle", "is-block")} to={Route::Author { id: post.author.seed }}>
|
|
||||||
{ &post.author.name }
|
|
||||||
</Link<Route>>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
|
pub mod author;
|
||||||
|
pub mod authorcard;
|
||||||
|
pub mod authors;
|
||||||
pub mod content;
|
pub mod content;
|
||||||
pub mod entries;
|
pub mod entries;
|
||||||
pub mod entry;
|
pub mod entry;
|
||||||
pub mod entrycard;
|
pub mod entrycard;
|
||||||
pub mod authors;
|
|
||||||
pub mod author;
|
|
||||||
pub mod authorcard;
|
|
||||||
pub mod navigation;
|
|
||||||
|
|||||||
@@ -1,213 +0,0 @@
|
|||||||
use std::ops::Range;
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use yew::prelude::*;
|
|
||||||
use yew_router::components::Link;
|
|
||||||
|
|
||||||
use crate::Route;
|
|
||||||
|
|
||||||
const ELLIPSIS: &str = "\u{02026}";
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
|
|
||||||
pub struct PageQuery {
|
|
||||||
pub page: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Properties)]
|
|
||||||
pub struct PropsNavigation {
|
|
||||||
pub page: u8,
|
|
||||||
pub total_pages: u8,
|
|
||||||
pub route_to_page: Route,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[function_component]
|
|
||||||
pub fn RelNavButtons(props: &PropsNavigation) -> Html {
|
|
||||||
let PropsNavigation {
|
|
||||||
page,
|
|
||||||
total_pages,
|
|
||||||
route_to_page: to,
|
|
||||||
} = props.clone();
|
|
||||||
|
|
||||||
html! {
|
|
||||||
<>
|
|
||||||
<Link<Route, PageQuery>
|
|
||||||
classes={classes!("pagination-previous")}
|
|
||||||
disabled={page==1}
|
|
||||||
query={Some(PageQuery{page: page - 1})}
|
|
||||||
to={to.clone()}
|
|
||||||
>
|
|
||||||
{ "Previous" }
|
|
||||||
</Link<Route, PageQuery>>
|
|
||||||
<Link<Route, PageQuery>
|
|
||||||
classes={classes!("pagination-next")}
|
|
||||||
disabled={page==total_pages}
|
|
||||||
query={Some(PageQuery{page: page + 1})}
|
|
||||||
{to}
|
|
||||||
>
|
|
||||||
{ "Next page" }
|
|
||||||
</Link<Route, PageQuery>>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Properties, Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub struct RenderLinksProps {
|
|
||||||
range: Range<u8>,
|
|
||||||
len: usize,
|
|
||||||
max_links: usize,
|
|
||||||
props: PropsNavigation,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[function_component]
|
|
||||||
pub fn RenderLinks(props: &RenderLinksProps) -> Html {
|
|
||||||
let RenderLinksProps {
|
|
||||||
range,
|
|
||||||
len,
|
|
||||||
max_links,
|
|
||||||
props,
|
|
||||||
} = props.clone();
|
|
||||||
|
|
||||||
let mut range = range;
|
|
||||||
|
|
||||||
if len > max_links {
|
|
||||||
let last_link =
|
|
||||||
html! {<RenderLink to_page={range.next_back().unwrap()} props={props.clone()} />};
|
|
||||||
let links = range
|
|
||||||
.take(max_links - 2)
|
|
||||||
.map(|page| html! {<RenderLink to_page={page} props={props.clone()} />});
|
|
||||||
html! {
|
|
||||||
<>
|
|
||||||
{ for links }
|
|
||||||
<li><span class="pagination-ellipsis">{ ELLIPSIS }</span></li>
|
|
||||||
{ last_link }
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
html! {
|
|
||||||
for page in range {
|
|
||||||
<RenderLink to_page={page} props={props.clone()} />
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Properties, Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub struct RenderLinkProps {
|
|
||||||
to_page: u8,
|
|
||||||
props: PropsNavigation,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[function_component]
|
|
||||||
pub fn RenderLink(props: &RenderLinkProps) -> Html {
|
|
||||||
let RenderLinkProps { to_page, props } = props.clone();
|
|
||||||
|
|
||||||
let PropsNavigation {
|
|
||||||
page,
|
|
||||||
route_to_page,
|
|
||||||
..
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
let is_current_class = if to_page == page { "is-current" } else { "" };
|
|
||||||
|
|
||||||
html! {
|
|
||||||
<li>
|
|
||||||
<Link<Route, PageQuery>
|
|
||||||
classes={classes!("pagination-link", is_current_class)}
|
|
||||||
to={route_to_page}
|
|
||||||
query={Some(PageQuery{page: to_page})}
|
|
||||||
>
|
|
||||||
{ to_page }
|
|
||||||
</Link<Route, PageQuery>>
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[function_component]
|
|
||||||
pub fn Links(props: &PropsNavigation) -> Html {
|
|
||||||
const LINKS_PER_SIDE: usize = 3;
|
|
||||||
|
|
||||||
let PropsNavigation {
|
|
||||||
page, total_pages, ..
|
|
||||||
} = *props;
|
|
||||||
|
|
||||||
let pages_prev = page.checked_sub(1).unwrap_or_default() as usize;
|
|
||||||
let pages_next = (total_pages - page) as usize;
|
|
||||||
|
|
||||||
let links_left = LINKS_PER_SIDE.min(pages_prev)
|
|
||||||
// if there are less than `LINKS_PER_SIDE` to the right, we add some more on the left.
|
|
||||||
+ LINKS_PER_SIDE.checked_sub(pages_next).unwrap_or_default();
|
|
||||||
let links_right = 2 * LINKS_PER_SIDE - links_left;
|
|
||||||
|
|
||||||
html! {
|
|
||||||
<>
|
|
||||||
<RenderLinks range={ 1..page } len={pages_prev} max_links={links_left} props={props.clone()} />
|
|
||||||
<RenderLink to_page={page} props={props.clone()} />
|
|
||||||
<RenderLinks range={ page + 1..total_pages + 1 } len={pages_next} max_links={links_right} props={props.clone()} />
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[function_component]
|
|
||||||
pub fn Pagination(props: &PropsNavigation) -> Html {
|
|
||||||
html! {
|
|
||||||
<nav class="pagination is-right" role="navigation" aria-label="pagination">
|
|
||||||
<RelNavButtons ..{props.clone()} />
|
|
||||||
<ul class="pagination-list">
|
|
||||||
<Links ..{props.clone()} />
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[function_component]
|
|
||||||
pub fn Nav() -> Html {
|
|
||||||
let navbar_active = use_state_eq(|| false);
|
|
||||||
|
|
||||||
let toggle_navbar = {
|
|
||||||
let navbar_active = navbar_active.clone();
|
|
||||||
|
|
||||||
Callback::from(move |_| {
|
|
||||||
navbar_active.set(!*navbar_active);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
let active_class = if !*navbar_active { "is-active" } else { "" };
|
|
||||||
|
|
||||||
html! {
|
|
||||||
<nav class="navbar is-primary" role="navigation" aria-label="main navigation">
|
|
||||||
<div class="navbar-brand">
|
|
||||||
<h1 class="navbar-item is-size-3">{ "Yew Blog" }</h1>
|
|
||||||
|
|
||||||
<button class={classes!("navbar-burger", "burger", active_class)}
|
|
||||||
aria-label="menu" aria-expanded="false"
|
|
||||||
onclick={toggle_navbar}
|
|
||||||
>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class={classes!("navbar-menu", active_class)}>
|
|
||||||
<div class="navbar-start">
|
|
||||||
<Link<Route> classes={classes!("navbar-item")} to={Route::Entries}> // TODO: ...
|
|
||||||
{ "Home" }
|
|
||||||
</Link<Route>>
|
|
||||||
<Link<Route> classes={classes!("navbar-item")} to={Route::Entries}>
|
|
||||||
{ "Posts" }
|
|
||||||
</Link<Route>>
|
|
||||||
|
|
||||||
<div class="navbar-item has-dropdown is-hoverable">
|
|
||||||
<div class="navbar-link">
|
|
||||||
{ "More" }
|
|
||||||
</div>
|
|
||||||
<div class="navbar-dropdown">
|
|
||||||
<Link<Route> classes={classes!("navbar-item")} to={Route::Authors}>
|
|
||||||
{ "Meet the authors" }
|
|
||||||
</Link<Route>>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,9 +12,19 @@ impl Component for PageNotFound {
|
|||||||
|
|
||||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div style="">
|
<div style="
|
||||||
<img loading="eager" alt="huh" class="image is-96x96" src="404.png" />
|
display: flex !important;
|
||||||
<h1 class="title">{ "what" }</h1>
|
text-align: center !important;
|
||||||
|
flex-direction: row !important;
|
||||||
|
align-items: center !important;
|
||||||
|
flex-wrap: wrap !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
">
|
||||||
|
<img loading="eager" alt="huh" style="
|
||||||
|
width: 96px !important;
|
||||||
|
height: 96px !important;
|
||||||
|
" width="96" height="96" src="404.png" />
|
||||||
|
<h1>{ "what" }</h1>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ impl Component for Projects {
|
|||||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<div class="tile is-parent container mb-5 mt-5" style="height: auto !important;">
|
<div style="height: auto !important;">
|
||||||
{ self.view_projects_ongoing() }
|
{ self.view_projects_ongoing() }
|
||||||
{ self.view_projects_finished() }
|
{ self.view_projects_finished() }
|
||||||
</div>
|
</div>
|
||||||
@@ -24,20 +24,18 @@ impl Projects {
|
|||||||
fn view_projects_ongoing(&self) -> Html {
|
fn view_projects_ongoing(&self) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<p class="title ml-2 is-size-4">{r#"ongoing projects"#}</p>
|
<p>{r#"ongoing projects"#}</p>
|
||||||
<div class="columns is-size-7 ml-3 mr-3">
|
<div>
|
||||||
<div class="column box mb-5 mr-1">
|
<p><a href="https://git.celesteflare.cc/i0uring/app_catnip">
|
||||||
<p class="subtitle is-inline-block mb-0"><a href="https://git.celesteflare.cc/i0uring/app_catnip">
|
{r#"catnip"#}
|
||||||
{r#"catnip"#}
|
</a></p>
|
||||||
</a></p>
|
<p>{r#"all-rounder ide in the making"#}</p>
|
||||||
<p class="content">{r#"all-rounder ide in the making"#}</p>
|
</div>
|
||||||
</div>
|
<div>
|
||||||
<div class="column box mb-5 ml-1">
|
<p><a href="https://git.celesteflare.cc/i0uring/app_nekochat">
|
||||||
<p class="subtitle is-inline-block mb-0"><a href="https://git.celesteflare.cc/i0uring/app_nekochat">
|
{r#"neko chat"#}
|
||||||
{r#"neko chat"#}
|
</a></p>
|
||||||
</a></p>
|
<p>{r#"my planned matrix client"#}</p>
|
||||||
<p class="content">{r#"my planned matrix client"#}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
@@ -46,31 +44,31 @@ impl Projects {
|
|||||||
fn view_projects_finished(&self) -> Html {
|
fn view_projects_finished(&self) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<p class="title ml-2 is-size-4">{r#"finished projects"#}</p>
|
<p>{r#"finished projects"#}</p>
|
||||||
<div class="columns is-size-7 ml-3 mr-3">
|
<div>
|
||||||
<div class="column box mb-5 mr-1">
|
<div>
|
||||||
<p class="subtitle is-inline-block mb-0"><a href="https://git.celesteflare.cc/i0uring/lib_tinyevents">
|
<p><a href="https://git.celesteflare.cc/i0uring/lib_tinyevents">
|
||||||
{r#"tiny events"#}
|
{r#"tiny events"#}
|
||||||
</a></p>
|
</a></p>
|
||||||
<p class="content">{r#"a java seventeen (and up) event-sys that is able to be scaled in large systems."#}</p>
|
<p>{r#"a java seventeen (and up) event-sys that is able to be scaled in large systems."#}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column box mb-5 ml-1 mr-2">
|
<div>
|
||||||
<p class="subtitle is-inline-block mb-0"><a href="https://git.celesteflare.cc/i0uring/dotfiles">
|
<p><a href="https://git.celesteflare.cc/i0uring/dotfiles">
|
||||||
{r#"dotfiles"#}
|
{r#"dotfiles"#}
|
||||||
</a></p>
|
</a></p>
|
||||||
<p class="content">{r#"my personal set of configurations for different things"#}</p>
|
<p>{r#"my personal set of configurations for different things"#}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column box mb-5 mr-1">
|
<div>
|
||||||
<p class="subtitle is-inline-block mb-0"><a href="https://git.celesteflare.cc/i0uring/lib_swingify">
|
<p><a href="https://git.celesteflare.cc/i0uring/lib_swingify">
|
||||||
{r#"swingify"#}
|
{r#"swingify"#}
|
||||||
</a></p>
|
</a></p>
|
||||||
<p class="content">{r#"my java swing wrapper to simplify window creation for bogus-brains."#}</p>
|
<p>{r#"my java swing wrapper to simplify window creation for bogus-brains."#}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column box mb-5 ml-1">
|
<div>
|
||||||
<p class="subtitle is-inline-block mb-0"><a href="https://git.celesteflare.cc/stellaris/mod_mnet">
|
<p><a href="https://git.celesteflare.cc/stellaris/mod_mnet">
|
||||||
{r#"modern netty"#}
|
{r#"modern netty"#}
|
||||||
</a></p>
|
</a></p>
|
||||||
<p class="content">{r#"fabric mod that adds experimental iouring and kqueue support."#}</p>
|
<p>{r#"fabric mod that adds experimental iouring and kqueue support."#}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user