Move away from SSG

+2 -1
.gitignore
··· 1 1 build/ 2 - out/ 2 + out/ 3 + priv/
+5 -4
gleam.toml
··· 1 1 name = "website" 2 + target = "javascript" 2 3 version = "1.0.0" 3 4 4 5 [dependencies] 5 6 gleam_stdlib = ">= 0.34.0 and < 2.0.0" 6 7 lustre = ">= 4.2.0 and < 5.0.0" 7 - birl = ">= 1.6.1 and < 2.0.0" 8 - sketch = ">= 2.1.0 and < 3.0.0" 8 + modem = ">= 1.1.0 and < 2.0.0" 9 + lustre_ui = ">= 0.6.0 and < 1.0.0" 10 + birl = ">= 1.7.0 and < 2.0.0" 9 11 10 12 [dev-dependencies] 11 13 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" 14 + lustre_dev_tools = ">= 1.3.2 and < 2.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>
+13 -13
manifest.toml
··· 3 3 4 4 packages = [ 5 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" }, 6 + { name = "birl", version = "1.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "B1FA529E7BE3FF12CADF32814AB8EC7294E74CEDEE8CC734505707B929A98985" }, 7 7 { name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" }, 8 8 { name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" }, 9 9 { name = "fs", version = "8.6.1", build_tools = ["rebar3"], requirements = [], otp_app = "fs", source = "hex", outer_checksum = "61EA2BDAEDAE4E2024D0D25C63E44DCCF65622D4402DB4A2DF12868D1546503F" }, ··· 12 12 { name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" }, 13 13 { name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, 14 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_javascript", version = "0.8.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_javascript", source = "hex", outer_checksum = "14D5B7E1A70681E0776BF0A0357F575B822167960C844D3D3FA114D3A75F05A8" }, 15 + { name = "gleam_httpc", version = "2.2.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "CF76C71002DEECF6DC5D9CA83D962728FAE166B57926BE442D827004D3C7DF1B" }, 16 16 { name = "gleam_json", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "9063D14D25406326C0255BDA0021541E797D8A7A12573D849462CAFED459F6EB" }, 17 17 { name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" }, 18 18 { 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" }, 19 19 { name = "gleam_stdlib", version = "0.37.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "5398BD6C2ABA17338F676F42F404B9B7BABE1C8DC7380031ACB05BBE1BCF3742" }, 20 - { name = "glearray", version = "0.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "908154F695D330E06A37FAB2C04119E8F315D643206F8F32B6A6C14A8709FFF4" }, 20 + { name = "glearray", version = "0.2.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "9C207E05F38D724F464FA921378DB3ABC2B0A2F5821116D8BC8B2CACC68930D5" }, 21 21 { name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" }, 22 22 { 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" }, 23 23 { name = "glisten", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "glisten", source = "hex", outer_checksum = "CF3A9383E9BA4A8CBAF2F7B799716290D02F2AC34E7A77556B49376B662B9314" }, 24 + { name = "gramps", version = "2.0.1", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "FBB7EA641C8A1EF02C0E938B6045A1360B925E5E65BAD0E228C4AEF6C6933722" }, 24 25 { name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" }, 25 - { name = "jot", version = "0.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "jot", source = "hex", outer_checksum = "B20A745707EE60B857249D4533656A52964EA024E844005C4AD8135ED432D66C" }, 26 26 { name = "logging", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "A996064F04EF6E67F0668FD0ACFB309830B05D0EE3A0C11BBBD2D4464334F792" }, 27 27 { 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" }, 28 - { 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" }, 29 - { 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" }, 28 + { name = "lustre_dev_tools", version = "1.3.2", build_tools = ["gleam"], requirements = ["argv", "filepath", "fs", "gleam_community_ansi", "gleam_erlang", "gleam_http", "gleam_httpc", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "glisten", "mist", "simplifile", "spinner", "term_size", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "CC8F46BCE51C1349862C5F6BA0075B0C68096B866ED1C520B60358FAAB398B60" }, 29 + { name = "lustre_ui", version = "0.6.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "FA1F9E89D89CDD5DF376ED86ABA8A38441CB2E664CD4D402F22A49DA4D7BB56D" }, 30 30 { name = "marceau", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "1AAD727A30BE0F95562C3403BB9B27C823797AD90037714255EEBF617B1CDA81" }, 31 - { 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" }, 32 - { name = "plinth", version = "0.2.0", build_tools = ["gleam"], requirements = ["gleam_javascript", "gleam_json", "gleam_stdlib"], otp_app = "plinth", source = "hex", outer_checksum = "83211E672D83F3CE14681D0ECD3AD883EE7588E423E7C9DDDB460014AD60AC24" }, 31 + { name = "mist", version = "1.2.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "109B4D64E68C104CC23BB3CC5441ECD479DD7444889DA01113B75C6AF0F0E17B" }, 32 + { name = "modem", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "lustre"], otp_app = "modem", source = "hex", outer_checksum = "4C6E448089B09A57C179455D44526A717E4E217D4000B91201617FD2D9F18E68" }, 33 33 { name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" }, 34 34 { name = "repeatedly", version = "2.1.1", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "38808C3EC382B0CD981336D5879C24ECB37FCB9C1D1BD128F7A80B0F74404D79" }, 35 35 { name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" }, 36 - { name = "sketch", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "lustre", "plinth"], otp_app = "sketch", source = "hex", outer_checksum = "47175BD019A00CFEAAF2851830825544E24ABA58168083A1D219FA8E06EF6713" }, 37 36 { name = "snag", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "54D32E16E33655346AA3E66CBA7E191DE0A8793D2C05284E3EFB90AD2CE92BCC" }, 38 37 { 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" }, 38 + { name = "term_size", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "term_size", source = "hex", outer_checksum = "D00BD2BC8FB3EBB7E6AE076F3F1FF2AC9D5ED1805F004D0896C784D06C6645F1" }, 39 39 { name = "thoas", version = "1.2.0", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "540C8CB7D9257F2AD0A14145DC23560F91ACDCA995F0CCBA779EB33AF5D859D1" }, 40 40 { name = "tom", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577" }, 41 41 { 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" }, 42 42 ] 43 43 44 44 [requirements] 45 - birl = { version = ">= 1.6.1 and < 2.0.0" } 45 + birl = { version = ">= 1.7.0 and < 2.0.0"} 46 46 gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" } 47 47 gleeunit = { version = ">= 1.0.0 and < 2.0.0" } 48 48 lustre = { version = ">= 4.2.0 and < 5.0.0" } 49 - lustre_dev_tools = { version = ">= 1.2.2 and < 2.0.0" } 50 - lustre_ssg = { version = ">= 0.6.1 and < 1.0.0" } 51 - sketch = { version = ">= 2.1.0 and < 3.0.0"} 49 + lustre_dev_tools = { version = ">= 1.3.2 and < 2.0.0" } 50 + lustre_ui = { version = ">= 0.6.0 and < 1.0.0" } 51 + modem = { version = ">= 1.1.0 and < 2.0.0" }
-50
src/build.gleam
··· 1 - import gleam/dict 2 - import gleam/io 3 - import gleam/list 4 - import lustre/ssg 5 - import sketch 6 - import sketch/lustre as sklustre 7 - import sketch/options as skoptions 8 - import website/data/posts 9 - import website/data/projects 10 - import website/page/blog 11 - import website/page/index 12 - import website/page/post 13 - import website/page/project 14 - 15 - pub fn main() { 16 - let assert Ok(cache) = 17 - skoptions.node() 18 - |> sklustre.setup() 19 - 20 - sketch.prepare(cache) 21 - 22 - let posts = 23 - dict.from_list({ 24 - use post <- list.map(posts.all()) 25 - #(post.id, post) 26 - }) 27 - 28 - let projects = 29 - dict.from_list({ 30 - use project <- list.map(projects.all()) 31 - #(project.id, project) 32 - }) 33 - 34 - let build = 35 - ssg.new("./out") 36 - |> ssg.add_static_route("/", index.view(cache)) 37 - |> ssg.add_static_route("/blog", blog.view(posts.all())) 38 - |> ssg.add_dynamic_route("/blog", posts, post.view) 39 - |> ssg.add_static_route("/projects", projects.view(projects.all(), cache)) 40 - |> ssg.add_dynamic_route("/projects", projects, project.view) 41 - |> ssg.build 42 - 43 - case build { 44 - Ok(_) -> io.println("Build successful!") 45 - Error(e) -> { 46 - io.debug(e) 47 - io.println("Build failed!") 48 - } 49 - } 50 - }
+3
src/ffi.mjs
··· 1 + export function get_route() { 2 + return window.location.pathname 3 + }
+152
src/website.gleam
··· 1 + import gleam/list 2 + import gleam/string 3 + import gleam/uri.{type Uri} 4 + import lustre 5 + import lustre/attribute 6 + import lustre/effect.{type Effect} 7 + import lustre/element.{type Element} 8 + import lustre/element/html 9 + import lustre/ui 10 + import lustre/ui/layout/cluster 11 + import modem 12 + import website/posts 13 + import website/projects 14 + import website/common 15 + 16 + // Main 17 + 18 + pub fn main() { 19 + let app = lustre.application(init, update, view) 20 + let assert Ok(dispatch) = lustre.start(app, "#app", Nil) 21 + 22 + dispatch 23 + } 24 + 25 + // Model 26 + 27 + type Model { 28 + Model( 29 + current_route: Route, 30 + posts: List(posts.Post), 31 + projects: List(projects.Project), 32 + ) 33 + } 34 + 35 + type Route { 36 + Home 37 + Posts 38 + Post(id: String) 39 + Projects 40 + Project(id: String) 41 + } 42 + 43 + @external(javascript, "./ffi.mjs", "get_route") 44 + fn do_get_route() -> String 45 + 46 + fn get_route() -> Route { 47 + case do_get_route() |> string.split("/") { 48 + ["", "projects", id] | ["", "project", id] -> Project(id) 49 + ["", "projects"] -> Projects 50 + ["", "posts", id] | ["", "post", id] -> Post(id) 51 + ["", "posts"] -> Posts 52 + _ -> Home 53 + } 54 + } 55 + 56 + fn init(_flags) -> #(Model, Effect(Msg)) { 57 + #( 58 + Model(current_route: get_route(), projects: projects.all(), posts: []), 59 + modem.init(on_route_change), 60 + ) 61 + } 62 + 63 + fn on_route_change(uri: Uri) -> Msg { 64 + case uri.path_segments(uri.path) { 65 + ["projects", id] | ["project", id] -> OnRouteChange(Project(id)) 66 + ["projects"] -> OnRouteChange(Projects) 67 + ["posts", id] | ["post", id] -> OnRouteChange(Post(id)) 68 + ["posts"] -> OnRouteChange(Posts) 69 + _ -> OnRouteChange(Home) 70 + } 71 + } 72 + 73 + // Update 74 + 75 + pub opaque type Msg { 76 + OnRouteChange(Route) 77 + } 78 + 79 + fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) { 80 + case msg { 81 + OnRouteChange(route) -> #( 82 + Model(..model, current_route: route), 83 + effect.none(), 84 + ) 85 + } 86 + } 87 + 88 + // View 89 + 90 + fn view(model: Model) -> Element(Msg) { 91 + let styles = [#("margin-left", "15vh"), #("margin-top", "5vh")] 92 + 93 + let page = case model.current_route { 94 + Home -> view_home(model) 95 + Projects -> view_projects(model) 96 + Project(id) -> view_project(model, id) 97 + Posts -> view_posts(model) 98 + _ -> view_home(model) 99 + } 100 + 101 + ui.stack([attribute.style(styles)], [view_navbar(model), page]) 102 + } 103 + 104 + fn view_navbar(_) -> Element(Msg) { 105 + let item_styles = [#("text-decoration", "underline")] 106 + 107 + let view_nav_item = fn(path, text) { 108 + html.a([attribute.href("/" <> path), attribute.style(item_styles)], [ 109 + element.text(text), 110 + ]) 111 + } 112 + 113 + cluster.of(html.nav, [], [ 114 + view_nav_item("", "Home"), 115 + view_nav_item("projects", "Projects"), 116 + view_nav_item("posts", "Posts"), 117 + ]) 118 + } 119 + 120 + fn view_home(model: Model) -> Element(Msg) { 121 + html.h1([], [element.text("Homepage")]) 122 + } 123 + 124 + fn icon_style() -> List(#(String, String)) { 125 + [ 126 + #("max-width", "4em"), 127 + #("max-height", "4em"), 128 + #("border-radius", "1em"), 129 + ] 130 + } 131 + 132 + fn view_projects(model: Model) -> Element(Msg) { 133 + let projects = 134 + model.projects 135 + |> list.map(fn(project: projects.Project) { 136 + html.div([], [ 137 + html.span([], [ 138 + html.img([attribute.src(project.img), attribute.style(icon_style())]), 139 + html.h1([], [common.link(project.title, "projects/" <> project.id)]) 140 + ]) 141 + ]) 142 + }) 143 + html.div([], projects) 144 + } 145 + 146 + fn view_project(model: Model, id: String) -> Element(Msg) { 147 + html.h1([], [element.text("Project: " <> id)]) 148 + } 149 + 150 + fn view_posts(model: Model) -> Element(Msg) { 151 + html.h1([], [element.text("Posts")]) 152 + }
+7
src/website/common.gleam
··· 1 + import lustre/attribute as attr 2 + import lustre/element 3 + import lustre/element/html 4 + 5 + pub fn link(text: String, link: String) -> element.Element(a) { 6 + html.a([attr.href(link)], [element.text(text)]) 7 + }
+5 -5
src/website/data/posts.gleam src/website/posts.gleam
··· 2 2 import lustre/attribute 3 3 import lustre/element 4 4 import lustre/element/html 5 - import website/page/index.{link} 5 + import website/common.{link} 6 6 7 7 pub type Post { 8 8 Post( ··· 13 13 summary: element.Element(String), 14 14 content: element.Element(String), 15 15 ) 16 + } 17 + 18 + pub fn all() -> List(Post) { 19 + [release_mystcraft_ages(), mystcraft_ages_alpha_2()] 16 20 } 17 21 18 22 fn mystcraft_short_descriptor() -> element.Element(String) { ··· 166 170 ]), 167 171 ) 168 172 } 169 - 170 - pub fn all() -> List(Post) { 171 - [release_mystcraft_ages(), mystcraft_ages_alpha_2()] 172 - }
+1 -74
src/website/data/projects.gleam src/website/projects.gleam
··· 1 - import gleam/list 2 - import lustre/attribute 3 1 import lustre/element 4 2 import lustre/element/html 5 - import sketch 6 - import sketch/lustre.{ssr} 7 - import sketch/size.{em, em_} 8 - import website/page/index.{link} 3 + import website/common.{link} 9 4 10 5 pub type Link { 11 6 Link(title: String, url: String, img: String) ··· 21 16 archived: Bool, 22 17 summary: element.Element(String), 23 18 ) 24 - } 25 - 26 - fn project_class(archived: Bool) -> attribute.Attribute(a) { 27 - let #(bg, bg_hov) = case archived { 28 - True -> #("#d36473", "#c55d6b") 29 - False -> #("#cae4e7", "#b8cfd2") 30 - } 31 - sketch.class([ 32 - sketch.background(bg), 33 - sketch.padding(em(1)), 34 - sketch.hover([sketch.background(bg_hov)]), 35 - sketch.margin_bottom(em_(0.5)), 36 - sketch.border_radius(em_(0.75)), 37 - ]) 38 - |> sketch.to_lustre 39 - } 40 - 41 - fn icon_class() -> attribute.Attribute(a) { 42 - sketch.class([ 43 - sketch.max_width(em_(3.5)), 44 - sketch.max_height(em_(3.5)), 45 - sketch.border_radius(em_(0.75)), 46 - ]) 47 - |> sketch.to_lustre 48 - } 49 - 50 - fn project_bar_class() -> attribute.Attribute(a) { 51 - sketch.class([ 52 - sketch.display("flex"), 53 - sketch.flex_direction("horizontal"), 54 - sketch.align_items("center"), 55 - sketch.gap(em(1)), 56 - ]) 57 - |> sketch.to_lustre 58 - } 59 - 60 - pub fn view( 61 - projects: List(Project), 62 - cache: sketch.Cache, 63 - ) -> element.Element(String) { 64 - projects 65 - |> list.map(fn(project) { 66 - let links = 67 - project.links 68 - |> list.map(fn(link) { 69 - html.a([attribute.href(link.url)], [ 70 - html.img([ 71 - attribute.alt(link.title), 72 - attribute.src(link.img), 73 - icon_class(), 74 - ]), 75 - ]) 76 - }) 77 - |> html.span([], _) 78 - |> ssr(cache) 79 - sketch.prepare(cache) 80 - html.div([project_class(project.archived)], [ 81 - html.span([project_bar_class()], [ 82 - html.img([attribute.src(project.img), icon_class()]), 83 - html.h2([], [element.text(project.title)]), 84 - links, 85 - ]), 86 - project.summary, 87 - ]) 88 - |> ssr(cache) 89 - }) 90 - |> html.div([], _) 91 - |> index.wrapper(cache) 92 19 } 93 20 94 21 pub fn all() -> List(Project) {
-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 - }
-49
src/website/page/index.gleam
··· 1 - import lustre/attribute 2 - import lustre/element 3 - import lustre/element/html 4 - import sketch 5 - import sketch/lustre.{ssr} 6 - import sketch/size.{em} 7 - 8 - pub fn link(text: String, url: String) -> element.Element(a) { 9 - html.a([attribute.href(url)], [element.text(text)]) 10 - } 11 - 12 - fn body_class() -> attribute.Attribute(a) { 13 - sketch.class([ 14 - sketch.margin_left(em(15)), 15 - sketch.margin_right(em(15)), 16 - sketch.font_family("\"Inter\", sans-serif"), 17 - sketch.font_weight("400"), 18 - sketch.font_style("normal"), 19 - ]) 20 - |> sketch.to_lustre 21 - } 22 - 23 - pub fn wrapper(inner: element.Element(a), cache) -> element.Element(a) { 24 - html.html([], [ 25 - html.head([], [ 26 - html.link([ 27 - attribute.rel("preconnect"), 28 - attribute.href("https://fonts.googleapis.com"), 29 - ]), 30 - html.link([ 31 - attribute.rel("preconnect"), 32 - attribute.href("https://fonts.gstatic.com"), 33 - ]), 34 - html.link([ 35 - attribute.href( 36 - "https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap", 37 - ), 38 - attribute.rel("stylesheet"), 39 - ]), 40 - ]), 41 - html.body([body_class()], [inner]), 42 - ]) 43 - |> ssr(cache) 44 - } 45 - 46 - pub fn view(cache: sketch.Cache) -> element.Element(a) { 47 - html.h1([], [element.text("Index")]) 48 - |> wrapper(cache) 49 - }
-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 - }
-10
src/website/page/project.gleam
··· 1 - import lustre/element 2 - import lustre/element/html 3 - import website/data/projects.{type Project} 4 - 5 - pub fn view(project: Project) -> element.Element(String) { 6 - html.div([], [ 7 - html.h1([], [element.text(project.title)]), 8 - html.p([], [project.summary]), 9 - ]) 10 - }