My personal website, in gleam+lustre!
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge my changes with what I forgot to push from Fennekin


Signed-off-by: MLC Bloeiman <mar@strawmelonjuice.com>

+87 -34
+28 -26
dev/homepage/prepare.gleam
··· 15 15 import gleam/time/timestamp 16 16 import glentities 17 17 import homepage 18 - import homepage/stuff.{type Entry, type Model, type Route, Entry, Index, Model} 18 + import homepage/stuff.{type Entry, type Model, type Route, Entry, Model} 19 19 import lustre/element 20 20 import simplifile 21 21 import webls/rss ··· 89 89 } 90 90 } 91 91 92 + /// I used to just replace with self+new but this seems more neat 93 + /// need to see what is actually more efficient, I doubt it makes much difference though. 94 + /// 95 + /// The final string is either stored within an Ok (if been appended), or within an Error 96 + /// (if the string remained the same), which is where it may be an improvement over my 97 + /// replacement approach 98 + fn string_insert_after( 99 + in string: String, 100 + on pattern: String, 101 + with new: String, 102 + ) -> Result(String, String) { 103 + case string.split_once(string, on: pattern) { 104 + Error(Nil) -> Error(string) 105 + Ok(#(before, after)) -> { 106 + Ok(before <> new <> after) 107 + } 108 + } 109 + } 110 + 92 111 fn prepopulate_html() { 93 112 use main_index_html: String <- try_annot( 94 113 simplifile.read("./dist/index.html"), 95 114 "Prepopulation mode expects that the site already be built, but could not load ./dist/index.html", 96 115 ) 116 + use _ <- try_annot( 117 + simplifile.write(to: "./dist/unpopulated.html", contents: main_index_html), 118 + "Could not write html to ./dist/unpopulated.html", 119 + ) 120 + io.println("✅\tWrote: `./dist/unpopulated.html`") 97 121 let main_model: Model = homepage.init() 98 122 let map_entries = fn(cb: fn(Entry) -> Result(Nil, String)) -> Result( 99 123 Nil, ··· 108 132 |> element.to_string() 109 133 let meta_description_tag: String = 110 134 "<meta name=\"description\" content=\"" <> entry.description <> "\">" 111 - let link_canonical = case entry.route { 112 - Index -> "" 113 - _ -> 114 - "<link rel=\"canonical\" href=\"" <> to_canonical(entry.route) <> "\" />" 115 - } 135 + let link_canonical = 136 + "<link rel=\"canonical\" href=\"" <> to_canonical(entry.route) <> "\" />" 116 137 let title = 117 138 homepage.to_title(entry.route) 118 139 |> glentities.encode(glentities.Hex) ··· 137 158 ) 138 159 139 160 use _ <- try_annot( 140 - simplifile.write(html, html_file_path), 161 + simplifile.write(to: html_file_path, contents: html), 141 162 "Could not write html to " <> html_file_path, 142 163 ) 143 164 Ok(io.println("✅\tWrote: `" <> html_file_path <> "`")) 144 - } 145 - 146 - /// I used to just replace with self+new but this seems more neat 147 - /// need to see what is actually more efficient, I doubt it makes much difference though. 148 - /// 149 - /// The final string is either stored within an Ok (if been appended), or within an Error 150 - /// (if the string remained the same), which is where it may be an improvement over my 151 - /// replacement approach 152 - fn string_insert_after( 153 - in string: String, 154 - on pattern: String, 155 - with new: String, 156 - ) -> Result(String, String) { 157 - case string.split_once(string, on: pattern) { 158 - Error(Nil) -> Error(string) 159 - Ok(#(before, after)) -> { 160 - Ok(before <> new <> after) 161 - } 162 - } 163 165 } 164 166 165 167 fn to_canonical(route: Route) {
+57 -6
src/homepage.gleam
··· 1 - import gleam/bool 2 - 3 1 /// Post data ------------------------------------------------------------------- 4 2 /// 5 3 /// Some special tags: ··· 433 431 const highlighted_posts = [900] 434 432 435 433 const pages = [ 436 - // If index isn't first, things break. 434 + Entry( 435 + Index, 436 + "Homepage", 437 + Date(2026, March, 16), 438 + NotFound(uri.empty), 439 + "Welcome to my personal site!", 440 + ), 441 + Entry( 442 + Me, 443 + "About me", 444 + Date(2026, March, 16), 445 + Index, 446 + "My about-me page, on here I try to describe myself a bit", 447 + ), 448 + Entry( 449 + Portfolio, 450 + "Portfolio", 451 + Date(2026, March, 16), 452 + Me, 453 + "On this page you'll find my portfolio and some active projects!", 454 + ), 455 + Entry( 456 + Links, 457 + "Links", 458 + Date(2026, March, 16), 459 + Me, 460 + "Some links to places I can be found on the internet!", 461 + ), 462 + Entry( 463 + Posts, 464 + "Posts", 465 + Date(2026, March, 16), 466 + Index, 467 + "Mostly blog posts from Mar Bloeiman (@strawmelonjuice)", 468 + ), 469 + Entry( 470 + Sitemap, 471 + "Sitemap", 472 + Date(2026, March, 16), 473 + Index, 474 + "Visual sitemap for strawmelonjuice.com.", 475 + ), 476 + Entry( 477 + AllAndEverything, 478 + "/everything page", 479 + Date(2026, March, 16), 480 + Index, 481 + "A collection of content from all visible pages and posts on strawmelonjuice.com, useful for quickly finding specific sentences etc.", 482 + ), 437 483 Entry( 438 484 Index, 439 485 "Homepage", ··· 504 550 "Ollie", 505 551 "https://nuv.sh", 506 552 "https://avatar.tangled.sh/7e06ae27ffa435ccb999e6852c3bdf4172bbfe5de27f40c851a1a8ae222b6962/did:plc:cezmtk5bb4zipkps3abnjjl6", 553 + "", 507 554 ), 508 - #("Gleam", "https://gleam.run/", "https://gleam.run/images/lucy/lucy.svg"), 555 + #("Gleam", "https://gleam.run/", "https://gleam.run/images/lucy/lucy.svg", ""), 509 556 #( 510 557 "Tangled.sh", 511 558 "https://blog.tangled.org", 512 559 "https://tangled.org/static/logos/dolly.svg", 560 + "bg-black", 513 561 ), 514 562 ] 515 563 ··· 582 630 ), 583 631 Badge( 584 632 img_url: "/img/badges/blinkiesCafe-L1.gif", 585 - img_alt: "Blinkies Cafe", 633 + img_alt: "the autism badge", 586 634 img_title: "I GOT AUTISM", 587 635 clickable_url: "self", 588 636 text_badge: "", ··· 677 725 678 726 import chilp 679 727 import chilp/widget 728 + import gleam/bool 680 729 import gleam/dict 681 730 import gleam/function 682 731 import gleam/int ··· 2227 2276 ], 2228 2277 [ 2229 2278 html.img([ 2230 - attribute.class("w-full h-full rounded-full object-cover"), 2279 + attribute.class( 2280 + "w-full h-full rounded-full object-cover " <> person.3, 2281 + ), 2231 2282 attribute.alt("profile icon"), 2232 2283 attribute.src(person.2), 2233 2284 ]),
+2 -2
src/homepage/stuff.gleam
··· 194 194 AllAndEverything -> "/everything" 195 195 PersonalStartPage -> "/startpage" 196 196 NotFound(_) -> "/404" 197 - Tagged(v) -> "/posts/tagged/" <> v 198 - Category(c) -> "/posts/category/" <> c 197 + Tagged(v) -> "/posts/tagged/" <> uri.percent_encode(v) 198 + Category(c) -> "/posts/category/" <> uri.percent_encode(c) 199 199 Sitemap -> "/sitemap" 200 200 CuriculumVitae(False) -> "/cv/en" 201 201 CuriculumVitae(True) -> "/cv/nl"