Create basic blog pages

+1
.gitignore
··· 1 + build/
+13
gleam.toml
··· 1 + name = "website" 2 + target = "javascript" 3 + version = "1.0.0" 4 + 5 + [dependencies] 6 + gleam_stdlib = ">= 0.34.0 and < 2.0.0" 7 + lustre = ">= 4.2.0 and < 5.0.0" 8 + birl = ">= 1.6.1 and < 2.0.0" 9 + 10 + [dev-dependencies] 11 + gleeunit = ">= 1.0.0 and < 2.0.0" 12 + lustre_dev_tools = ">= 1.2.2 and < 2.0.0" 13 + lustre_ssg = ">= 0.6.1 and < 1.0.0"
+15
index.html
··· 1 + <!doctype html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8" /> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 + 7 + <title>🚧 website</title> 8 + 9 + <script type="module" src="./priv/static/website.mjs"></script> 10 + </head> 11 + 12 + <body> 13 + <div id="app"></div> 14 + </body> 15 + </html>
+47
manifest.toml
··· 1 + # This file was generated by Gleam 2 + # You typically do not need to edit this file 3 + 4 + packages = [ 5 + { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, 6 + { name = "birl", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "976CFF85D34D50F7775896615A71745FBE0C325E50399787088F941B539A0497" }, 7 + { name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" }, 8 + { name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" }, 9 + { name = "fs", version = "8.6.1", build_tools = ["rebar3"], requirements = [], otp_app = "fs", source = "hex", outer_checksum = "61EA2BDAEDAE4E2024D0D25C63E44DCCF65622D4402DB4A2DF12868D1546503F" }, 10 + { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, 11 + { name = "gleam_community_colour", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "795964217EBEDB3DA656F5EB8F67D7AD22872EB95182042D3E7AFEF32D3FD2FE" }, 12 + { name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" }, 13 + { name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, 14 + { name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" }, 15 + { name = "gleam_json", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "9063D14D25406326C0255BDA0021541E797D8A7A12573D849462CAFED459F6EB" }, 16 + { name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" }, 17 + { name = "gleam_package_interface", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "52A721BCA972C8099BB881195D821AAA64B9F2655BECC102165D5A1097731F01" }, 18 + { name = "gleam_stdlib", version = "0.37.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "5398BD6C2ABA17338F676F42F404B9B7BABE1C8DC7380031ACB05BBE1BCF3742" }, 19 + { name = "glearray", version = "0.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "908154F695D330E06A37FAB2C04119E8F315D643206F8F32B6A6C14A8709FFF4" }, 20 + { name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" }, 21 + { name = "glint", version = "0.18.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "5FB54D7732B4105E4AF4D89A7EE6D5E8CF33DA13A3575D0C6ECE470B97958454" }, 22 + { name = "glisten", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "glisten", source = "hex", outer_checksum = "CF3A9383E9BA4A8CBAF2F7B799716290D02F2AC34E7A77556B49376B662B9314" }, 23 + { name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" }, 24 + { name = "jot", version = "0.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "jot", source = "hex", outer_checksum = "B20A745707EE60B857249D4533656A52964EA024E844005C4AD8135ED432D66C" }, 25 + { name = "logging", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "A996064F04EF6E67F0668FD0ACFB309830B05D0EE3A0C11BBBD2D4464334F792" }, 26 + { name = "lustre", version = "4.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "258F876CD7AB12C2C773F1A30F76DFC0A0ED989B720070DF32FC0717A6A0E60C" }, 27 + { name = "lustre_dev_tools", version = "1.2.2", build_tools = ["gleam"], requirements = ["argv", "filepath", "fs", "gleam_community_ansi", "gleam_erlang", "gleam_http", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "glisten", "mist", "simplifile", "spinner", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "6F8A671F6021640F2F8F68C227375C601D3D12D0139EDDBCD1980B3560E99C18" }, 28 + { name = "lustre_ssg", version = "0.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "jot", "lustre", "simplifile", "tom"], otp_app = "lustre_ssg", source = "hex", outer_checksum = "2C55F49F597DF8FC3FDD651349026FADFD2394763C34BB88BB8A57549E30ECFA" }, 29 + { name = "marceau", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "1AAD727A30BE0F95562C3403BB9B27C823797AD90037714255EEBF617B1CDA81" }, 30 + { name = "mist", version = "1.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "7765E53DCC9ACCACF217B8E0CA3DE7E848C783BFAE5118B75011E81C2C80385C" }, 31 + { name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" }, 32 + { name = "repeatedly", version = "2.1.1", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "38808C3EC382B0CD981336D5879C24ECB37FCB9C1D1BD128F7A80B0F74404D79" }, 33 + { name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" }, 34 + { name = "snag", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "54D32E16E33655346AA3E66CBA7E191DE0A8793D2C05284E3EFB90AD2CE92BCC" }, 35 + { name = "spinner", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "glearray", "repeatedly"], otp_app = "spinner", source = "hex", outer_checksum = "200BA3D4A04D468898E63C0D316E23F526E02514BC46454091975CB5BAE41E8F" }, 36 + { name = "thoas", version = "1.2.0", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "540C8CB7D9257F2AD0A14145DC23560F91ACDCA995F0CCBA779EB33AF5D859D1" }, 37 + { name = "tom", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577" }, 38 + { name = "wisp", version = "0.14.0", build_tools = ["gleam"], requirements = ["exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "9F5453AF1F9275E6F8707BC815D6A6A9DF41551921B16FBDBA52883773BAE684" }, 39 + ] 40 + 41 + [requirements] 42 + birl = { version = ">= 1.6.1 and < 2.0.0"} 43 + gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" } 44 + gleeunit = { version = ">= 1.0.0 and < 2.0.0" } 45 + lustre = { version = ">= 4.2.0 and < 5.0.0" } 46 + lustre_dev_tools = { version = ">= 1.2.2 and < 2.0.0" } 47 + lustre_ssg = { version = ">= 0.6.1 and < 1.0.0" }
+31
src/build.gleam
··· 1 + import gleam/dict 2 + import gleam/io 3 + import gleam/list 4 + import lustre/ssg 5 + import website/data/posts 6 + import website/page/blog 7 + import website/page/index 8 + import website/page/post 9 + 10 + pub fn main() { 11 + let posts = 12 + dict.from_list({ 13 + use post <- list.map(posts.all()) 14 + #(post.id, post) 15 + }) 16 + 17 + let build = 18 + ssg.new("./pages") 19 + |> ssg.add_static_route("/", index.view()) 20 + |> ssg.add_static_route("/blog", blog.view(posts.all())) 21 + |> ssg.add_dynamic_route("/blog", posts, post.view) 22 + |> ssg.build 23 + 24 + case build { 25 + Ok(_) -> io.println("Build successful!") 26 + Error(e) -> { 27 + io.debug(e) 28 + io.println("Build failed!") 29 + } 30 + } 31 + }
+175
src/website/data/posts.gleam
··· 1 + import birl.{type Day} 2 + import lustre/attribute 3 + import lustre/element 4 + import lustre/element/html 5 + 6 + pub type Post { 7 + Post( 8 + id: String, 9 + title: String, 10 + author: String, 11 + date_posted: Day, 12 + summary: element.Element(String), 13 + content: element.Element(String), 14 + ) 15 + } 16 + 17 + fn link(text: String, url: String) -> element.Element(a) { 18 + html.a([attribute.href(url)], [element.text(text)]) 19 + } 20 + 21 + fn mystcraft_short_descriptor() -> element.Element(String) { 22 + html.p([], [ 23 + element.text("A modern reimagining of the original "), 24 + link("Mystcraft", "https://www.curseforge.com/minecraft/mc-mods/mystcraft"), 25 + element.text(" mod!"), 26 + ]) 27 + } 28 + 29 + fn release_mystcraft_ages() -> Post { 30 + Post( 31 + id: "mystcraft-ages-alpha-1", 32 + title: "Mystcraft: Ages", 33 + author: "naomieow", 34 + date_posted: birl.Day(2023, 09, 30), 35 + summary: mystcraft_short_descriptor(), 36 + content: html.div([], [ 37 + html.h2([], [element.text("Alpha 1")]), 38 + html.p([], [ 39 + element.text( 40 + "This is an alpha release, the mod is nowhere near complete and some bugs may exist. If you do find any bugs please report them on ", 41 + ), 42 + link( 43 + "the bug tracker", 44 + "https://codeberg.org/naomi/mystcraft-ages/issues", 45 + ), 46 + ]), 47 + html.h3([], [element.text("Developer Notes")]), 48 + html.p([], [ 49 + element.text( 50 + "It's been a while since I said I was gonna start this project and after over 60 hours of work 😅 you now have a semi-functioning proof-of-concept! I'm very efficient I know 😔", 51 + ), 52 + ]), 53 + html.p([], [ 54 + element.text( 55 + "Jokes aside, the (albeit limited) content list/changelog is below!", 56 + ), 57 + ]), 58 + html.h3([], [element.text("Changelog")]), 59 + html.ul([], [html.li([], [element.text("Linking Books")])]), 60 + html.p([], [ 61 + element.text( 62 + "These are the main attraction of this alpha, and using one can link it so wherever you are standing. There are a few known bugs with these so please check before reporting.", 63 + ), 64 + ]), 65 + html.ul([], [html.li([], [element.text("Book Receptacle")])]), 66 + html.p([], [ 67 + element.text( 68 + "These are small, lectern-like blocks that you can place Linked Books into. (Currently) they allow multiple people to use the same book, but the book will not travel with you.", 69 + ), 70 + ]), 71 + html.ul([], [html.li([], [element.text("Writing Stand")])]), 72 + html.p([], [ 73 + element.text( 74 + "This is where most of the development time has gone and is the place where you can create your Linking Books. It requires you to provide it with an ink supply.", 75 + ), 76 + ]), 77 + html.ul([], [html.li([], [element.text("Ink Vials")])]), 78 + html.p([], [ 79 + element.text("A slightly more efficient ink than regular ink sacs."), 80 + ]), 81 + html.h3([], [element.text("Links")]), 82 + html.p([], [ 83 + link( 84 + "CurseForge", 85 + "https://legacy.curseforge.com/minecraft/mc-mods/mystcraft-ages", 86 + ), 87 + ]), 88 + html.p([], [link("Modrinth", "https://modrinth.com/mod/ages")]), 89 + ]), 90 + ) 91 + } 92 + 93 + fn mystcraft_ages_alpha_2() -> Post { 94 + Post( 95 + id: "mystcraft-ages-alpha-2", 96 + title: "UPDATE: Mystcraft: Ages", 97 + author: "naomieow", 98 + date_posted: birl.Day(2023, 11, 30), 99 + summary: mystcraft_short_descriptor(), 100 + content: html.div([], [ 101 + html.h2([], [element.text("Alpha 2")]), 102 + html.p([], [ 103 + element.text( 104 + "This is an alpha release, the mod is nowhere near complete and some bugs may exist. If you do find any bugs please report them on ", 105 + ), 106 + link( 107 + "the bug tracker", 108 + "https://codeberg.org/naomi/mystcraft-ages/issues", 109 + ), 110 + ]), 111 + html.h3([], [element.text("Developer Notes")]), 112 + html.p([], [element.text("I hate entities.")]), 113 + html.h3([], [element.text("Changelog")]), 114 + html.ul([], [ 115 + html.li([], [ 116 + element.text("Linking Books ["), 117 + link("MA26", "https://codeberg.org/naomi/mystcraft-ages/issues/26"), 118 + element.text("]"), 119 + ]), 120 + ]), 121 + html.p([], [ 122 + element.text( 123 + "They no longer directly teleport you, they will summon a Book entity on the ground", 124 + ), 125 + ]), 126 + html.ul([], [ 127 + html.li([], [ 128 + element.text("Book Entities ["), 129 + link("MA26", "https://codeberg.org/naomi/mystcraft-ages/issues/26"), 130 + element.text("]"), 131 + ]), 132 + ]), 133 + html.p([], [ 134 + element.text( 135 + "These are entities (wow) that are books (wow!!). They replace the teleportation function that the previous iteration of Linking Books has, to see the contained book, Crouch + Interact, to teleport just Interact. THERE IS CURRENTLY NO WAY TO PICK THEM UP", 136 + ), 137 + ]), 138 + html.ul([], [ 139 + html.li([], [ 140 + element.text("Writing Stand Recipes ["), 141 + link("MA31", "https://codeberg.org/naomi/mystcraft-ages/issues/31"), 142 + element.text("]"), 143 + ]), 144 + ]), 145 + html.p([], [ 146 + element.text( 147 + "The recipes in the writing stand have been updated, now requireing an additional item. Unlinked Books require an enderpearl.", 148 + ), 149 + ]), 150 + html.ul([], [ 151 + html.li([], [ 152 + element.text("Book Receptacle ["), 153 + link("MA21", "https://codeberg.org/naomi/mystcraft-ages/issues/21"), 154 + element.text("]"), 155 + ]), 156 + ]), 157 + html.p([], [element.text("The book now renders correctly. I'm so cool.")]), 158 + html.h3([], [element.text("Links")]), 159 + html.ul([], [ 160 + html.li([], [link("Modrinth", "https://modrinth.com/mod/ages")]), 161 + html.li([], [ 162 + link( 163 + "CurseForge", 164 + "https://legacy.curseforge.com/minecraft/mc-mods/mystcraft-ages", 165 + ), 166 + ]), 167 + html.li([], [link("Source Code", "https://modrinth.com/mod/ages")]), 168 + ]), 169 + ]), 170 + ) 171 + } 172 + 173 + pub fn all() -> List(Post) { 174 + [release_mystcraft_ages(), mystcraft_ages_alpha_2()] 175 + }
+40
src/website/page/blog.gleam
··· 1 + import birl 2 + import gleam/int 3 + import gleam/list 4 + import lustre/attribute 5 + import lustre/element 6 + import lustre/element/html 7 + import website/data/posts.{type Post} 8 + 9 + pub fn view(posts: List(Post)) -> element.Element(String) { 10 + posts 11 + |> list.reverse 12 + |> list.map(fn(post: Post) { 13 + html.a([attribute.href("./blog/" <> post.id <> ".html")], [ 14 + html.div([], [ 15 + html.h1([], [element.text(post.title)]), 16 + html.p([], [ 17 + element.text( 18 + "Date posted: " 19 + <> post.date_posted 20 + |> day_to_string, 21 + ), 22 + element.text("Author: " <> post.author), 23 + ]), 24 + html.p([], [element.text(post.summary.children)]), 25 + ]), 26 + ]) 27 + }) 28 + |> html.div([], _) 29 + } 30 + 31 + fn day_to_string(day: birl.Day) -> String { 32 + day.date 33 + |> int.to_string 34 + <> "-" 35 + <> day.month 36 + |> int.to_string 37 + <> "-" 38 + <> day.year 39 + |> int.to_string 40 + }
+6
src/website/page/index.gleam
··· 1 + import lustre/element 2 + import lustre/element/html 3 + 4 + pub fn view() -> element.Element(a) { 5 + html.h1([], [element.text("Index")]) 6 + }
+11
src/website/page/post.gleam
··· 1 + import lustre/element 2 + import lustre/element/html 3 + import website/data/posts.{type Post} 4 + 5 + pub fn view(post: Post) -> element.Element(String) { 6 + html.div([], [ 7 + html.h1([], [element.text(post.title)]), 8 + html.p([], [post.summary]), 9 + html.p([], [post.content]), 10 + ]) 11 + }
+12
test/website_test.gleam
··· 1 + import gleeunit 2 + import gleeunit/should 3 + 4 + pub fn main() { 5 + gleeunit.main() 6 + } 7 + 8 + // gleeunit test functions end in `_test` 9 + pub fn hello_world_test() { 10 + 1 11 + |> should.equal(1) 12 + }