My personal website, in gleam+lustre!
0
fork

Configure Feed

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

Lumina Liveblog!?! (also working out how liveblogs work)


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

+132 -12
+89 -8
src/homepage.gleam
··· 10 10 /// - `.creative-art` and `.creative-writings` split the creative works 11 11 /// themselves into seperated subblogs 12 12 /// - `.archived`, similar to `.unlisted`, but with a button(?). Yet unimplemented. 13 + /// 14 + /// Posts with ID 880 to 900 are imported from the old website. I'll have to skip those once you hit 880+ posts xD 15 + /// 16 + /// OH, future me, ID's are used to generate (perma)-links. Do NOT edit them post-pushes. 13 17 fn posts() { 14 18 [ 19 + Post( 20 + 2, 21 + category: "Devlog", 22 + title: "Liveblog Start", 23 + summary: "A liveblog of my longest-running and definitely most ambitious project.", 24 + published: Date(2026, March, 27), 25 + revised: None, 26 + body: File(Djot, "./written-contents/blog/devblog/lumina/2.dj"), 27 + tags: [ 28 + ".unlisted", 29 + ], 30 + aliases: [], 31 + comments: CommentsDisable, 32 + ), 33 + Post( 34 + 1, 35 + category: "Devlog", 36 + title: "[Liveblog] The Lumina-Peonies project", 37 + summary: "A liveblog of my longest-running and definitely most ambitious project.", 38 + published: Date(2026, March, 27), 39 + revised: None, 40 + body: LiveBlog([#(2, "Start of a Journey")]), 41 + tags: [ 42 + "gleam", 43 + "rust", 44 + "website development", 45 + "web development", 46 + "programming", 47 + "coding", 48 + "software engineering", 49 + "technology", 50 + "personal blog", 51 + ".blog-personal", 52 + ], 53 + aliases: ["lumina-blog"], 54 + comments: CommentsDisable, 55 + ), 15 56 Post( 16 57 id: 900, 17 58 title: "New site, who dis?", ··· 611 652 type Badge, type Entry, type FeedEntry, type Model, type Msg, 612 653 type NormalizedPost, type Post, type Route, AllAndEverything, Badge, Category, 613 654 CommentsDisable, CuriculumVitae, Djot, Entry, FeedEntry, File, HTML, Index, 614 - Inline, Links, Lustre, MastodonStatusLink, Me, Model, NormalizedPost, NotFound, 615 - PersonalStartPage, Plain, Portfolio, Post, PostById, Posts, Sitemap, Tagged, 616 - UserNavigatedTo, 655 + Inline, Links, LiveBlog, Lustre, MastodonStatusLink, Me, Model, NormalizedPost, 656 + NotFound, PersonalStartPage, Plain, Portfolio, Post, PostById, Posts, Sitemap, 657 + Tagged, UserNavigatedTo, 617 658 } 618 659 import homepage/stuff/prestyled_elements.{ 619 660 codeforges_links, leading, paragraph, socials, subsubtitle, subtitle, title, ··· 805 846 ) 806 847 } 807 848 808 - fn post_body_normalize(takes: Post) { 849 + fn post_body_normalize(takes: Post) -> Element(Msg) { 809 850 case takes.body { 851 + LiveBlog(items) -> { 852 + let wrap = fn(label: String, content: List(Element(Msg)), date: String) -> Element( 853 + Msg, 854 + ) { 855 + [ 856 + html.span([attribute.class("text-sm float-right")], [ 857 + element.text(date), 858 + ]), 859 + subtitle(label), 860 + html.div( 861 + [ 862 + attribute.class( 863 + "bg-primary/25 rounded-sm mt-4 py-3 px-6 w-full subpage", 864 + ), 865 + ], 866 + content, 867 + ), 868 + ] 869 + |> element.fragment 870 + } 871 + list.map(items, fn(item) { 872 + let #(id, title) = item 873 + let sub_item = 874 + posts() 875 + |> list.find(fn(post) { post.id == id }) 876 + |> result.map(fn(sub_item) { 877 + #( 878 + sub_item.published |> date_to_yyyy_mm_dd(), 879 + sub_item |> post_body_normalize() |> list.wrap(), 880 + ) 881 + }) 882 + |> result.unwrap(#("", [element.text("Could not load this update.")])) 883 + wrap(title, sub_item.1, sub_item.0) 884 + }) 885 + |> element.fragment() 886 + } 887 + 810 888 Lustre(a) -> a 811 889 File(markup:, path:) -> { 812 890 let assert Ok(inner) = data.files() |> dict.get(path) ··· 816 894 // The actual thing 817 895 Inline(Djot, string:) -> 818 896 djotparse.djot_to_html(string) 819 - |> element.unsafe_raw_html("", "div", [], _) 820 - Inline(markup: Plain, string:) -> html.pre([], [element.text(string)]) 897 + |> element.unsafe_raw_html("", "div", [attribute.class("postfield")], _) 898 + Inline(markup: Plain, string:) -> 899 + html.pre([attribute.class("postfield")], [element.text(string)]) 821 900 Inline(markup: HTML, string:) -> 822 - element.unsafe_raw_html("", "div", [], string) 901 + element.unsafe_raw_html("", "div", [attribute.class("postfield")], string) 823 902 } 824 903 } 825 904 ··· 1814 1893 ), 1815 1894 1816 1895 html.p([attribute.class("mt-1")], [ 1817 - html.text(post.summary), 1896 + html.span([attribute.class("postfield")], [ 1897 + html.text(post.summary), 1898 + ]), 1818 1899 html.hr([attribute.class("my-4")]), 1819 1900 link(PostById(post.id), "Read more ->"), 1820 1901 ]),
+5 -4
src/homepage/djotparse.gleam
··· 19 19 |> preprocess_codeblocks 20 20 |> preprocess_tables 21 21 |> jot.to_html 22 - |> string.replace("<p>", "<p class=\"mt-8\">") 23 - |> string.replace("<li", "<li class=\"mt-4\"") 22 + |> string.replace("<p>", "<p class=\"mt-4\">") 23 + |> string.replace("<li", "<li class=\"mt-2\"") 24 + |> string.replace("<h4", "<h5 class=\"text-lg text-accent font-light mt-8\"") 25 + |> string.replace("<h3", "<h4 class=\"text-xl font-light mt-10\"") 26 + |> string.replace("<h2", "<h3 class=\"text-2xl font-light mt-12\"") 24 27 |> string.replace("<h1", "<h2 class=\"text-3xl font-light mt-14\"") 25 - |> string.replace("<h2", "<h3 class=\"text-2xl font-light mt-14\"") 26 - |> string.replace("<h3", "<h4 class=\"text-xl font-light mt-12\"") 27 28 |> string.replace("<a ", "<a class=\"link link-accent\" ") 28 29 |> string.replace("<strong", "<strong class=\"font-bold\"") 29 30 |> string.replace("<em", "<em class=\"italic\"")
+2
src/homepage/stuff.gleam
··· 85 85 Lustre(Element) 86 86 File(markup: Markup, path: String) 87 87 Inline(markup: Markup, string: String) 88 + /// List of post id's and their 'update: '-titles 89 + LiveBlog(List(#(Int, String))) 88 90 } 89 91 90 92 pub type Markup {
+36
written-contents/blog/devblog/lumina/2.dj
··· 1 + Lumina/Peonies is a project that has been on the drawing board for as long as I have been rebellous, which is not nearly as long as other people have been rebellous, but- it's a project I started on during my teenage years. 2 + 3 + It's not an unambitous project, it's also not as unique as it used to be. Nowadays Mastodon and Bluesky and many others drive on decentralised infrastructure... (well, some more, some less... it could be more decentralised!) 4 + 5 + Lumina is a social media platform, for those who haven't made that up from the context yet. It has gone through many iterations, and taken up some inspirations. 6 + 7 + ### "FNew/Ephew" 8 + 9 + The original idea started as a simple pinboard, which teen me cleverly threw together in PHP and served from my raspberry pi, this could have been the end of that. 10 + ... but of course not! I wanted moderation, but I knew how moderation went wrong sometimes (the highschool class whatsapp was pretty self-evident), I also knew my pi would 11 + defenitely be plugged out at times whenever my mom would be asking what the 'thingy on the wall' was. The concept of Federation as a whole had not hit me, however I did get invested in things like the ZeroNet. 12 + 13 + The people on ZeroNet did not appreciate me linking to my pinboard, as it could "expose" them by letting their PC's hit the untorrented internet. Valid, but back then I was of course terrified from their anger and criticism. 14 + 15 + I started a much bigger and more ambitious approach, still not sure how to solve the moderation and the outage issues. This development was slow, as I was trying to adapt to PHP7 while it 16 + was coming out, but didn't know how to properly look up the changed docs. At some point, my life took some turns and I stopped development entirely, deleting the project (grave mistake) and 17 + focussing on social work (healthcare) and activism instead of software. 18 + 19 + ### "Lumina" 20 + 21 + Then, 2019, news broke that Elon Musk wanted to buy Twitter. Do note that Twitter had at that point become my biggest base of operations, and that I'd never even thought about it being a company. -- let alone be a sellable company 22 + 23 + Before news even broke that he actually bought it, I was fully back into development. The earlier defined plans looked a lot like platforms I had now grown comfortable with: Tumblr, Twitter, Facebook, Reddit... And Mastodon. 24 + The moderation issue, I decided on, could be solved by keeping things open. "If you do everything openly and make it so transparent that abuse is immediately punished, what could be left?" -- A lot, but the basic idea worked! 25 + 26 + Development in PHP stranded, this time on me burning out and PHP8... Yeah. 27 + 28 + ### "Lumina/Peonies" 29 + 30 + It took a little over two years until I got back into the project, now in a world that was vastly different, and with social media's around the world becoming an opposite of my ideals for digital connection. 31 + Not just unaligned, opposites. 32 + 33 + Now with knowledge and skills I didn't have before (but, being adult is expensive, less resources), I started two quick iterations of the Lumina/Peonies. One of them quickly getting me accustomed 34 + with what Lumina as a project could look like. 35 + 36 + The second iteration is the most structured one yet, and... It's the current one. This liveblog will hopefully track big updates about and around the Lumina project and someday... hopefully, it's launch :)