diff --git a/Cargo.toml b/Cargo.toml index 30e4027..95e6123 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,14 +22,16 @@ serde = { version = "1.0" } wasm-bindgen-futures = "0.4.50" serde_json = "1.0.143" +lsp-types = "0.97" +chrono = "0.4" + +yew-markdown = { git = "https://git.celesteflare.cc/i0uring/page_md.git", rev = "1e9840" } +yew-hooks = "0.3" +[patch.crates-io] +yew = { git = "https://github.com/yewstack/yew.git", rev = "21f373b", features = [ + "csr", +], optional = false } + [dependencies.web-sys] version = "0.3" -features = [ - 'HtmlCanvasElement', - 'WebGlBuffer', - 'WebGlProgram', - 'WebGlRenderingContext', - 'WebGl2RenderingContext', - 'WebGlShader', - 'WebGlUniformLocation', -] +features = ["HtmlCanvasElement", "WebGlBuffer", "WebGlProgram", "WebGlRenderingContext", "WebGl2RenderingContext", "WebGlShader", "WebGlUniformLocation", "Navigator", "Clipboard"] diff --git a/index.html b/index.html index 4de0ed2..e2497ee 100644 --- a/index.html +++ b/index.html @@ -10,6 +10,8 @@ + + @@ -31,7 +33,7 @@ - + diff --git a/main.scss b/main.scss index 585ae14..2da8c43 100644 --- a/main.scss +++ b/main.scss @@ -1,12 +1,17 @@ @charset "UTF-8"; +@font-face { + font-family: freemono; + src: url("freemono.ttf"); +} + @font-face { font-family: monocraft; src: url("monocraft.ttf"); } html * { - font-family: monocraft, monospace !important; + font-family: freemono, monocraft, monospace !important; scrollbar-color: hsla(232, 97%, 85%, 0.5) hsla(240, 21.05%, 14.9%, 0.7) !important; scrollbar-width: thin !important; scroll-behavior: smooth !important; @@ -47,14 +52,30 @@ a.navbar-item:hover { } ::-moz-selection { - background: hsla(232, 97%, 85%, 0.4125) !important; + background: #F5C2E740 !important; } ::selection { - background: hsla(232, 97%, 85%, 0.4125) !important; + background: #F5C2E740 !important; +} + +a { + color: #F5C2E7FF !important; + text-decoration: none !important; } a:hover { text-decoration: underline !important; filter: url("post.bloom.svg#process") !important; +} + +button { + background-color: transparent !important; + border-color: transparent !important; + color: white !important; +} + +button:hover { + text-decoration: underline !important; + filter: url("post.bloom.svg#process") !important; } \ No newline at end of file diff --git a/public/misc/freemono.ttf b/public/misc/freemono.ttf new file mode 100644 index 0000000..7485f9e Binary files /dev/null and b/public/misc/freemono.ttf differ diff --git a/src/main.rs b/src/main.rs index 378242d..faba7cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,6 @@ +#![feature(iter_intersperse)] +extern crate core; + use js_sys::Float32Array; use log::{info, warn}; use std::cell::RefCell; @@ -15,7 +18,7 @@ use crate::pages::blog::authors::Authors; use crate::pages::blog::entries::Entries; use crate::pages::blog::entry::Entry; use crate::pages::findme::FindMe; -use crate::pages::projects::Projects; +use crate::pages::projects::projects::Projects; use pages::not_found::PageNotFound; #[derive(Routable, PartialEq, Eq, Clone, Debug)] @@ -45,30 +48,15 @@ pub enum Route { pub struct App { node_ref: NodeRef, - navbar_active: bool, -} - -pub enum Msg { - ToggleNavbar, } impl Component for App { - type Message = Msg; + type Message = (); type Properties = (); fn create(_ctx: &Context) -> Self { Self { node_ref: NodeRef::default(), - navbar_active: false, - } - } - - fn update(&mut self, _ctx: &Context, msg: Self::Message) -> bool { - match msg { - Msg::ToggleNavbar => { - self.navbar_active = !self.navbar_active; - true - } } } @@ -86,10 +74,9 @@ impl Component for App { " ref={self.node_ref.clone()} />
-

{r"-»{ "}

- to={Route::About}> - {r"about"} - > - /*

{r"."}

- to={Route::Entries}> - {r"blog"} - >*/ -

{r"."}

- to={Route::FindMe}> - {r"findme"} - > -

{r"."}

- to={Route::Projects}> - {r"projects"} - > -

{r" }«-"}

+

{r"»[ "}

+

to={Route::About}>{r"about"}>

+

{r"|"}

+

to={Route::Entries}>{r"blog"}>

+

{r"|"}

+

to={Route::FindMe}>{r"findme"}>

+

{r"|"}

+

to={Route::Projects}>{r"projects"}>

+

{r" ]«"}

iouring wasm servfail dataforest fedora artix nixos void void rust csharp kotlin java aqueer } diff --git a/src/pages/about.rs b/src/pages/about.rs index e5cb014..b90cedc 100644 --- a/src/pages/about.rs +++ b/src/pages/about.rs @@ -47,7 +47,7 @@ impl Component for About { font-weight: bold !important; font-style: italic !important; font-size: xx-large !important; - ">{r"intro"}

{r">intro_"}

{r"hobbies"}

{r">hobbies_"}

-

-

{author.name.clone()}

-

- { for author.keywords.iter().map(|tag| html! {

{ tag }

}) } -

-
-
-

{r#"about me"#}

-
- { author.about.clone() } -
+
+

{ "about me" }

+
+

{ "my posts" }

+
{ for cards }
} } diff --git a/src/pages/blog/authorcard.rs b/src/pages/blog/authorcard.rs index 51a7e6e..9fe9ab1 100644 --- a/src/pages/blog/authorcard.rs +++ b/src/pages/blog/authorcard.rs @@ -32,32 +32,41 @@ impl Component for AuthorCard { fn view(&self, _ctx: &Context) -> Html { let Self { author } = self; + let keywords = author.keywords.iter().map(|keyword| html! { +

{*keyword}

+ }).collect::(); html! { - <> -
-
-
-
-
- this should normally show an image mew,, -
-
-
-

{ &author.name }

-

- { "I like " } - { author.keywords.join(", ") } -

-
-
+
+ insert pfp here +
+

+ to={Route::Author { id: author.id }}> + { &*author.name } + > +

+ { keywords }
-
- classes={classes!("card-footer-item")} to={Route::Author { id: author.id }}> - { "Profile" } - > -
- } } } diff --git a/src/pages/blog/authors.rs b/src/pages/blog/authors.rs index 855843e..e7586c7 100644 --- a/src/pages/blog/authors.rs +++ b/src/pages/blog/authors.rs @@ -1,31 +1,31 @@ use yew::prelude::*; use crate::pages::blog::authorcard::AuthorCard; +use crate::pages::blog::content::{Author, BlogEntry}; -/*pub enum Msg { - NextAuthors, -}*/ - -pub struct Authors { - ids: Vec, -} +pub struct Authors; impl Component for Authors { - type Message = (); //Msg; + type Message = (); type Properties = (); fn create(_ctx: &Context) -> Self { - Self { ids: vec![0], } + Self } - /*fn update(&mut self, _ctx: &Context, msg: Self::Message) -> bool { - match msg { Msg::NextAuthors => { self.ids = vec![0]; true } } - }*/ - fn view(&self, _: &Context) -> Html { html! { - { for self.ids.iter().map(|&id| { html! { - - } }) } +
{ for Author::AUTHORS.map(|author| { + let id = author.id; + html! { } + }) }
} } } diff --git a/src/pages/blog/content.rs b/src/pages/blog/content.rs index 7c581d7..3063948 100644 --- a/src/pages/blog/content.rs +++ b/src/pages/blog/content.rs @@ -1,58 +1,48 @@ -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct Author { pub id: u8, - pub image_url: String, - pub name: String, - pub keywords: Vec, - pub about: String, + pub image_url: &'static str, + pub name: &'static str, + pub keywords: &'static [&'static str], + pub about: &'static str, } + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct Post { + pub id: u8, + pub authors: &'static [u8], + pub title: &'static str, + pub utcdate: &'static str, + pub content: &'static str, +} + impl BlogEntry for Author { fn from_entry(entry: &mut Entry) -> Self { - match entry.id { - 0 => Self { - id: entry.id, - image_url: "profile.avif".to_string(), - name: "iouring".to_string(), - keywords: vec!["meow".to_string(), "mrrp".to_string(), "mew".to_string()], - about: "sup".to_string(), - }, - _ => Self { + *Self::AUTHORS + .get(entry.id as usize) + .cloned() + .unwrap_or(&Self { id: u8::MAX, - image_url: "".to_string(), - name: "not found".to_string(), - keywords: vec![], - about: "".to_string(), - }, - } + image_url: "", + name: "not found", + keywords: [].as_slice(), + about: "", + }) } } -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Post { - pub id: u8, - pub author: Author, - pub title: String, - pub content: Vec, -} impl BlogEntry for Post { fn from_entry(entry: &mut Entry) -> Self { - return match entry.id { - 0 => Self { - id: 0, - author: Author::from_id(0), - title: "meow".parse().unwrap(), - content: vec!["

meow

", "mrrp", "meow"] - .iter() - .map(|s| s.to_string()) - .collect(), - }, - _ => Self { + *Self::POSTS + .get(entry.id as usize) + .cloned() + .unwrap_or(&Self { id: u8::MAX, - author: Author::from_id(u8::MAX), - title: "not found".parse().unwrap(), - content: vec![], - }, - }; + authors: &[u8::MAX], + title: "not found", + utcdate: "1970-01-01", + content: "", + }) } } @@ -65,10 +55,170 @@ impl Entry { Self { id: seed } } } - pub trait BlogEntry: Sized { fn from_entry(entry: &mut Entry) -> Self; fn from_id(id: u8) -> Self { Self::from_entry(&mut Entry::from_id(id)) } + + const AUTHORS: [&'static Author; 2] = [ + &Author { + id: 0, + image_url: "profile.avif", + name: "lia", + keywords: &[ + "certified catgirl™", + "software engineer", + "professional yapper", + "neurospicy and disabled" + ], + about: "", + }, + &Author { + id: 1, + image_url: "", + name: "mreowww", + keywords: &["meow", "mrrp", "mew"], + about: "", + }, + ]; + + const POSTS: [&'static Post; 1] = [ + /*&Post { + id: 0, + authors: &[0], + title: "sweet little poison", + utcdate: "1970-01-01", + content: r#" +### this will be a future write-up how i set up iocaine with caddy and docker. +### here's my docker-compose.yml: + +```yml +services: + caddy: + image: caddy:alpine + container_name: proxy.caddy + hostname: proxy.caddy + restart: unless-stopped + cap_add: + - NET_ADMIN + ports: + - "80:80" + - "443:443" + - "443:443/udp" + networks: + - nginx + volumes: + - ./socks:/run/iocaine:ro + - ./nginx/pages:/var/www/html + - ./caddy/data:/data + - ./caddy/config:/config + - ./caddy/proxy:/etc/caddy/Caddyfile:ro + depends_on: + - iocaine + iocaine: + image: git.madhouse-project.org/iocaine/iocaine:2 + container_name: proxy.iocaine + hostname: proxy.iocaine + restart: unless-stopped + ports: + - "42069:42069" + networks: + - nginx + volumes: + - ./iocaine:/data + - ./socks:/run/iocaine:rw + # - iocainesocket:/run/iocaine/waow.socket:rw + environment: + # - IOCAINE__SERVER__BIND="0.0.0.0:42069" + - IOCAINE__SERVER__BIND="/run/iocaine/waow.socket" + - IOCAINE__SERVER__UNIX_LISTEN_ACCESS="everybody" + - IOCAINE__SERVER__REQUEST_HANDLER__PATH="/data" + - IOCAINE__SERVER__REQUEST_HANDLER__LANGUAGE="roto" + - IOCAINE__SERVER__CONTROL__BIND="/run/iocaine/listen.socket" + - IOCAINE__SERVER__CONTROL__UNIX_LISTEN_ACCESS="owner" + - IOCAINE__SOURCES__WORDS="/data/words.txt" + - IOCAINE__SOURCES__MARKOV=["/data/1984.txt", "/data/brave-new-world.txt"] + - IOCAINE__METRICS__ENABLE=false + command: --config-file /data/config.toml +networks: + nginx: + external: true +``` + +### my file-tree: + +```sh +services/proxy » tree iocaine +iocaine +├── 1984.txt +├── brave-new-world.txt +├── nam_shub_of_enki +│   ├── classify +│   │   └── mod.roto +│   ├── config.roto +│   ├── detect +│   │   └── mod.roto +│   ├── mod.roto +│   └── tests +│   └── mod.roto +├── nam-shub-of-enki-20250711.0.tar.zst +├── nam-shub-of-enki-latest.tar.zst +├── pkg.roto +├── robots.json +└── words.txt +``` + +### and my caddy-snippet with example: + + +```txt +(iocaine) { + @read method GET HEAD + @not-read not { + method GET HEAD + } + reverse_proxy @read unix//run/iocaine/waow.socket { + #reverse_proxy @read proxy.iocaine:42069 { + @fallback status 421 + handle_response @fallback { + {blocks.handler} + } + } + handle @not-read { + {blocks.default} + } +} + +example.com { + import iocaine { + handler { + reverse_proxy http://example:8080 + } + default { + respond 405 + } + } +} + +``` + "#, + }, + */&Post { + id: 0, + authors: &[0], + title: "haj, world!", + utcdate: "2025-08-24", + content: r#" +### my first blogpost +haj! and welcome to my first blogpost. +this blogpost won't have that much content. +fun fact: this post generates html from markdown :3 +so i can include images, formatted text, code and content much easier. +i also added a too overcomplicated blog backend that allows authors and posts by u8::MAX, cause why not. +won't post that much either way, so why bother with higher values. /srs +nonetheless... have a great day, evening, whatever daytime it's for you rn and stay safe. ♡s +"#, + }, + ]; } diff --git a/src/pages/blog/entries.rs b/src/pages/blog/entries.rs index dc76198..7d71134 100644 --- a/src/pages/blog/entries.rs +++ b/src/pages/blog/entries.rs @@ -1,7 +1,7 @@ use yew::prelude::*; -use crate::pages::blog::content::{Author, Post}; use crate::pages::blog::content::BlogEntry; +use crate::pages::blog::content::Post; use crate::pages::blog::entrycard::EntryCard; pub struct Entries {} @@ -10,15 +10,18 @@ impl Component for Entries { type Message = (); type Properties = (); - fn create(ctx: &Context) -> Self { + fn create(_ctx: &Context) -> Self { Self {} } fn view(&self, ctx: &Context) -> Html { html! {
-

{ "entries" }

-

{ "here are some things i yapped about" }

+

{ "entries" }

+

{ "here are some things i yapped about" }

{ self.view_posts(ctx) }
} @@ -26,12 +29,27 @@ impl Component for Entries { } impl Entries { fn view_posts(&self, _ctx: &Context) -> Html { - let cards: Vec<_> = (0..2) // TODO: ... | add var - .filter(|&id_offset| Post::from_id(id_offset).author.id != u8::MAX) - .map(|id_offset| { - html! {} + let cards: Vec<_> = (0..Post::POSTS.len()) // TODO: ... | add var + .filter(|&id_offset| { + Post::from_id(id_offset as u8) + .authors + .iter() + .all(|id| *id != u8::MAX) }) + .map(|id_offset| html! {}) .collect(); - html! { { for cards } } + html! { +
+ { for cards } +
+ } } } diff --git a/src/pages/blog/entry.rs b/src/pages/blog/entry.rs index 9c10747..2fa3c3a 100644 --- a/src/pages/blog/entry.rs +++ b/src/pages/blog/entry.rs @@ -1,10 +1,11 @@ use std::rc::Rc; use yew::prelude::*; +use yew_markdown::Markdown; use yew_router::prelude::*; use crate::pages::blog::content; -use crate::pages::blog::content::BlogEntry; +use crate::pages::blog::content::{Author, BlogEntry}; use crate::Route; #[derive(Clone, Debug, Eq, PartialEq, Properties)] @@ -47,18 +48,30 @@ pub fn Entry(props: &Props) -> Html { html! { <> -

- { &post.title } -

-

- { "by " } - to={Route::Author { id: post.author.id }}> - { &post.author.name } - > -

-
- { for post.content.iter() } +

{ &*post.title }

+
+

+ { "written by " } { + post.authors.iter().map(|id| { + let author = Author::from_id(*id); + html! { + to={crate::Route::Author { id: author.id }}> + { &*author.name } + > + } + }).intersperse(html! { ", " }).collect::() + } { format!(" on {}", &post.utcdate) } +

+ } } diff --git a/src/pages/blog/entrycard.rs b/src/pages/blog/entrycard.rs index bdafe9e..3195ee7 100644 --- a/src/pages/blog/entrycard.rs +++ b/src/pages/blog/entrycard.rs @@ -1,9 +1,8 @@ use std::rc::Rc; - use yew::prelude::*; use yew_router::components::Link; -use crate::pages::blog::content::{BlogEntry, Post}; +use crate::pages::blog::content::{Author, BlogEntry, Post}; use crate::Route; @@ -48,13 +47,52 @@ pub fn EntryCard(props: &PropsEntryCard) -> Html { let post = &post.inner; html! { -
- classes={classes!("title", "is-block")} to={Route::Entry { id: post.id }}> - { &post.title } - > - classes={classes!("subtitle", "is-block")} to={Route::Author { id: post.author.id }}> - { &post.author.name } +
+ to={Route::Entry { id: post.id }}> +

{ &*post.title }

> +

+ { format!("published {}", post.utcdate) } +

+
+

+ { "written by " } + { + post.authors.iter().map(|id| { + let author = Author::from_id(*id); + html! { + to={crate::Route::Author { id: author.id }}> + { &*author.name } + > + } + }).intersperse(html! { ", " }).collect::() + } +

+
} } diff --git a/src/pages/findme.rs b/src/pages/findme.rs index f5f310d..125195c 100644 --- a/src/pages/findme.rs +++ b/src/pages/findme.rs @@ -1,3 +1,4 @@ +use web_sys::window; use yew::prelude::*; pub struct FindMe; @@ -10,58 +11,128 @@ impl Component for FindMe { } fn view(&self, _ctx: &Context) -> Html { + let clipboard = window().expect("meow").navigator().clipboard(); + + let handle_copy_matrix = { + let clipboard = clipboard.clone(); + Callback::from(move |_| { + let _ = clipboard.write_text(&*"@iouring:hi.stellaris.fyi".to_string()); + }) + }; + + let handle_copy_telegram = { + let clipboard = clipboard.clone(); + Callback::from(move |_| { + let _ = clipboard.write_text(&*"@luc1ell3".to_string()); + }) + }; + + let handle_copy_discord = { + let clipboard = clipboard.clone(); + Callback::from(move |_| { + let _ = clipboard.write_text(&*"@donotusedisc0rdkthxbye".to_string()); + }) + }; + html! { - <> -

{r"follow us"}

{" × "}{r"fediverse"}
- {" × "}{r"bluesky"}
-

{r"write us"}

{r" × matrix » @iouring:hi.stellaris.fyi"}
- {r" × telegr » @luc1ell3"}
- {r" × ewcord » @donotusedisc0rdkthxbye"} -

{r"git gud"}

{" × "}{r"my own!!!"}
- {" × "}{r"the gay one"}
- {" × "}{r"git of fren"}
- {" × "}{r"a mountain what"} -

- +
+
+

{r"follow us"}

+

{" × "}{r"fediverse"}
+ {" × "}{r"bluesky"}
+

+
+
+

{r"write us"}

+

+ {"× "} + +
+ {"× "} + +
+ {"× "} + +

+
+
+

{r"git gud"}

+

{" × "}{r"my own!!!"}
+ {" × "}{r"the gay one"}
+ {" × "}{r"git of fren"}
+ {" × "}{r"a mountain what"} +

+
+
} } } diff --git a/src/pages/projects.rs b/src/pages/projects.rs deleted file mode 100644 index a896427..0000000 --- a/src/pages/projects.rs +++ /dev/null @@ -1,77 +0,0 @@ -use yew::prelude::*; - -pub struct Projects; -impl Component for Projects { - type Message = (); - type Properties = (); - - fn create(_ctx: &Context) -> Self { - Self - } - - fn view(&self, _ctx: &Context) -> Html { - html! { - <> -
- { self.view_projects_ongoing() } - { self.view_projects_finished() } -
- - } - } -} -impl Projects { - fn view_projects_ongoing(&self) -> Html { - html! { - <> -

{r#"ongoing projects"#}

-
-

- {r#"catnip"#} -

-

{r#"all-rounder ide in the making"#}

-
-
-

- {r#"neko chat"#} -

-

{r#"my planned matrix client"#}

-
- - } - } - - fn view_projects_finished(&self) -> Html { - html! { - <> -

{r#"finished projects"#}

-
-
-

- {r#"tiny events"#} -

-

{r#"a java seventeen (and up) event-sys that is able to be scaled in large systems."#}

-
-
-

- {r#"dotfiles"#} -

-

{r#"my personal set of configurations for different things"#}

-
-
-

- {r#"swingify"#} -

-

{r#"my java swing wrapper to simplify window creation for bogus-brains."#}

-
-
-

- {r#"modern netty"#} -

-

{r#"fabric mod that adds experimental iouring and kqueue support."#}

-
-
- - } - } -} diff --git a/src/pages/projects/content.rs b/src/pages/projects/content.rs new file mode 100644 index 0000000..e941dd2 --- /dev/null +++ b/src/pages/projects/content.rs @@ -0,0 +1,51 @@ +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct Project { + pub url: &'static str, + pub name: &'static str, + pub desc: &'static str, +} + +impl ProjectEntry for Project {} + +pub trait ProjectEntry: Sized { + const PROJECTS_ONGOING: [&'static Project; 3] = [ + &Project { + url: "https://git.celesteflare.cc/stellaris/mod_headsup", + name: "headsup mod", + desc: "extensible hud mc mod", + }, + &Project { + url: "https://git.celesteflare.cc/i0uring/app_catnip", + name: "catnip", + desc: "all-rounder ide in the making", + }, + &Project { + url: "https://git.celesteflare.cc/i0uring/app_nekochat", + name: "neko chat", + desc: "my planned matrix client", + }, + ]; + + const PROJECTS_FINISHED: [&'static Project; 4] = [ + &Project { + url: "https://git.celesteflare.cc/i0uring/lib_tinyevents", + name: "tiny events", + desc: "a java 21+ event-sys", + }, + &Project { + url: "https://git.celesteflare.cc/i0uring/dotfiles", + name: "dotfiles", + desc: "personal set of configurations", + }, + &Project { + url: "https://git.celesteflare.cc/i0uring/lib_swingify", + name: "tiny events", + desc: "simplifies java swing window creation", + }, + &Project { + url: "https://git.celesteflare.cc/i0uring/dotfiles", + name: "modern netty", + desc: "adds experimental netty handlers to mc", + }, + ]; +} diff --git a/src/pages/projects/mod.rs b/src/pages/projects/mod.rs new file mode 100644 index 0000000..70e4012 --- /dev/null +++ b/src/pages/projects/mod.rs @@ -0,0 +1,3 @@ +pub mod content; +pub mod projectcard; +pub mod projects; diff --git a/src/pages/projects/projectcard.rs b/src/pages/projects/projectcard.rs new file mode 100644 index 0000000..a23273a --- /dev/null +++ b/src/pages/projects/projectcard.rs @@ -0,0 +1,54 @@ +use yew::prelude::*; + +use crate::pages::projects::content::Project; + +#[derive(Clone, Debug, PartialEq, Eq, Properties)] +pub struct PropsAuthorCard { + pub project: Project, +} + +pub struct ProjectCard { + project: Project, +} + +impl Component for ProjectCard { + type Message = (); + type Properties = PropsAuthorCard; + + fn create(ctx: &Context) -> Self { + Self { + project: ctx.props().project, + } + } + + fn view(&self, _ctx: &Context) -> Html { + let Self { project } = self; + html! { +
+
+

+ { &*project.name } +

+

+ { &*project.desc } +

+
+
+ } + } +} diff --git a/src/pages/projects/projects.rs b/src/pages/projects/projects.rs new file mode 100644 index 0000000..30cbf34 --- /dev/null +++ b/src/pages/projects/projects.rs @@ -0,0 +1,54 @@ +use crate::pages::projects::content::{Project, ProjectEntry}; +use crate::pages::projects::projectcard::ProjectCard; +use yew::prelude::*; + +pub struct Projects; +impl Component for Projects { + type Message = (); + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self + } + + fn view(&self, _ctx: &Context) -> Html { + let projects_ongoing = Project::PROJECTS_ONGOING.map(|project| { + let project = *project; + html! { } + }); + + let projects_finished = Project::PROJECTS_FINISHED.map(|project| { + let project = *project; + html! { } + }); + + html! { +
+

{ "ongoing projects" }

+
{ for projects_ongoing }
+

{ "finished projects" }

+
{ for projects_finished }
+
+ } + } +}