not my website

CSS Refactor + Dark Mode

+260 -82
+1 -1
index.html
··· 13 13 <script type="module" src="/priv/static/website.mjs"></script> 14 14 </head> 15 15 16 - <body> 16 + <body style="margin: 0;"> 17 17 <div id="app"></div> 18 18 </body> 19 19 </html>
+4
src/ffi.mjs
··· 1 1 export function get_route() { 2 2 return window.location.pathname 3 + } 4 + 5 + export function prefers_dark_mode() { 6 + return window.matchMedia('(prefers-color-scheme:dark)').matches 3 7 }
+74 -73
src/website.gleam
··· 1 - import birl.{type Day} 2 - import gleam/int 3 1 import gleam/list 4 2 import gleam/string 5 3 import gleam/uri.{type Uri} ··· 8 6 import lustre/effect.{type Effect} 9 7 import lustre/element.{type Element} 10 8 import lustre/element/html 9 + import lustre/event 11 10 import lustre/ui 12 11 import lustre/ui/layout/cluster 13 12 import modem 14 13 import website/common 15 14 import website/posts 16 15 import website/projects 16 + import website/style 17 17 18 18 // Main 19 19 ··· 31 31 current_route: Route, 32 32 posts: List(posts.Post(Msg)), 33 33 projects: List(projects.Project(Msg)), 34 + dark_mode: Bool, 34 35 ) 35 36 } 36 37 ··· 45 46 @external(javascript, "./ffi.mjs", "get_route") 46 47 fn do_get_route() -> String 47 48 49 + @external(javascript, "./ffi.mjs", "prefers_dark_mode") 50 + fn prefers_dark_mode() -> Bool 51 + 48 52 fn get_route() -> Route { 49 53 case do_get_route() |> string.split("/") { 50 54 ["", "projects", id] | ["", "project", id] -> Project(id) ··· 61 65 current_route: get_route(), 62 66 projects: projects.all(), 63 67 posts: posts.all(), 68 + dark_mode: prefers_dark_mode(), 64 69 ), 65 70 modem.init(on_route_change), 66 71 ) ··· 80 85 81 86 pub opaque type Msg { 82 87 OnRouteChange(Route) 88 + ChangeDarkMode 83 89 } 84 90 85 91 fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) { ··· 88 94 Model(..model, current_route: route), 89 95 effect.none(), 90 96 ) 97 + ChangeDarkMode -> #( 98 + Model(..model, dark_mode: !model.dark_mode), 99 + effect.none(), 100 + ) 91 101 } 92 102 } 93 103 94 104 // View 95 105 96 106 fn view(model: Model) -> Element(Msg) { 97 - let styles = [ 98 - #("margin-left", "25vh"), 99 - #("margin-top", "3vh"), 100 - #("margin-right", "25vh"), 101 - #("font-family", "\"Inter\", sans-serif"), 102 - #("font-weight", "400"), 103 - #("font-style", "normal"), 104 - ] 105 - 106 107 let page = case model.current_route { 107 108 Home -> view_home(model) 108 109 Projects -> view_projects(model) ··· 111 112 Post(id) -> view_post(model, id) 112 113 } 113 114 114 - ui.stack([attribute.style(styles)], [view_navbar(model), page]) 115 + ui.stack([attribute.style(style.page(model.dark_mode))], [ 116 + html.div([attribute.style(style.page_padding)], [view_navbar(model), page]), 117 + ]) 115 118 } 116 119 117 - const navbar_style: List(#(String, String)) = [ 118 - #("display", "flex"), #("background-color", "#cae4e7"), 119 - #("border-radius", "1em"), #("padding", "1em"), #("margin-bottom", "3vh"), 120 - #("justify-conten", "center"), #("align-items", "center"), #("gap", "1em"), 121 - ] 122 - 123 - const navitem_style: List(#(String, String)) = [ 124 - #("text-decoration", "none"), #("background-color", "#b8cfd2"), 125 - #("padding", "0.75em"), #("border-radius", "1em"), #("color", "black"), 126 - ] 120 + fn view_navbar(model: Model) -> Element(Msg) { 121 + let navitem_style = style.navitem(model.dark_mode) 122 + let navbar_style = style.navbar(model.dark_mode) 127 123 128 - fn view_navbar(_) -> Element(Msg) { 129 124 let view_nav_item = fn(path, text) { 130 125 html.a([attribute.href("/" <> path), attribute.style(navitem_style)], [ 131 126 element.text(text), 132 127 ]) 133 128 } 134 129 135 - cluster.of(html.nav, [attribute.style(navbar_style)], [ 136 - html.h1([attribute.style([#("margin", "0")])], [element.text("naomieow")]), 137 - view_nav_item("", "Home"), 138 - view_nav_item("projects", "Projects"), 139 - view_nav_item("posts", "Posts"), 140 - ]) 130 + html.span( 131 + [ 132 + attribute.style([ 133 + #("display", "flex"), 134 + #("gap", "1em"), 135 + #("width", "100%"), 136 + ]), 137 + ], 138 + [ 139 + cluster.of(html.nav, [attribute.style(navbar_style)], [ 140 + html.h1([attribute.style([#("margin", "0"), #("color", "#f380b1")])], [ 141 + element.text("naomieow"), 142 + ]), 143 + view_nav_item("", "Home"), 144 + view_nav_item("projects", "Projects"), 145 + view_nav_item("posts", "Posts"), 146 + ]), 147 + ui.button( 148 + [ 149 + attribute.style(style.button(model.dark_mode)), 150 + event.on_click(ChangeDarkMode), 151 + ], 152 + [ 153 + html.h1([attribute.style([#("margin", "0")])], [ 154 + case model.dark_mode { 155 + True -> element.text("☀️") 156 + False -> element.text("🌕") 157 + }, 158 + ]), 159 + ], 160 + ), 161 + ], 162 + ) 141 163 } 142 164 143 - const home_style: List(#(String, String)) = [ 144 - #("background-color", "#cae4e7"), #("border-radius", "1em"), 145 - #("padding", "1em"), #("margin-bottom", "1em"), #("font-size", "1.25em"), 146 - ] 165 + fn view_home(model: Model) -> Element(Msg) { 166 + let home_style = style.home(model.dark_mode) 147 167 148 - fn view_home(_model: Model) -> Element(Msg) { 149 168 html.div([attribute.style(home_style)], [ 150 169 html.p([], [ 151 170 element.text( ··· 197 216 ], 198 217 ), 199 218 ]), 200 - // html.p([], [ 219 + // html.p([], [ 201 220 // element.text("As of this coming September, I will be studying a BSc in Computer Games Programming @ "), 202 221 // common.link("Staffs", "https://staffs.ac.uk/") 203 222 // ]) 204 223 ]) 205 224 } 206 225 207 - const icon_style: List(#(String, String)) = [ 208 - #("max-width", "4em"), #("max-height", "4em"), #("border-radius", "1em"), 209 - ] 210 - 211 - const project_style: List(#(String, String)) = [ 212 - #("background-color", "#cae4e7"), #("border-radius", "1em"), 213 - #("padding", "1em"), #("margin-bottom", "1em"), 214 - ] 215 - 216 - const project_bar_style: List(#(String, String)) = [ 217 - #("display", "flex"), #("align-items", "center"), #("gap", "1em"), 218 - ] 219 - 220 226 fn view_projects(model: Model) -> Element(Msg) { 227 + let project_style = style.project(model.dark_mode) 221 228 let projects = 222 229 model.projects 223 230 |> list.map(fn(project: projects.Project(Msg)) { 224 231 ui.stack( 225 232 [attribute.id("project-" <> project.id), attribute.style(project_style)], 226 233 [ 227 - cluster.of(html.div, [attribute.style(project_bar_style)], [ 228 - html.img([attribute.src(project.img), attribute.style(icon_style)]), 229 - html.h1([], [ 230 - common.styled_link(project.title, "projects/" <> project.id), 231 - ]), 234 + cluster.of(html.div, [attribute.style(style.project_bar)], [ 235 + html.img([attribute.src(project.img), attribute.style(style.icon)]), 236 + html.h1([], [common.link(project.title, "projects/" <> project.id)]), 232 237 cluster.of( 233 238 html.div, 234 - [attribute.style(project_bar_style)], 239 + [attribute.style(style.project_bar)], 235 240 project.links 236 241 |> list.map(fn(link) { 237 242 html.a([attribute.href(link.url), attribute.alt(link.title)], [ 238 243 html.img([ 239 244 attribute.src(link.img), 240 - attribute.style(icon_style), 245 + attribute.style(style.icon), 241 246 ]), 242 247 ]) 243 248 }), ··· 251 256 } 252 257 253 258 fn view_project(model: Model, id: String) -> Element(Msg) { 259 + let project_style = style.project(model.dark_mode) 254 260 let project = 255 261 model.projects 256 262 |> list.find(fn(project) { project.id == id }) 257 263 html.div([attribute.style(project_style)], case project { 258 264 Ok(project) -> [ 259 - cluster.of(html.div, [attribute.style(project_bar_style)], [ 260 - html.img([attribute.src(project.img), attribute.style(icon_style)]), 265 + cluster.of(html.div, [attribute.style(style.project_bar)], [ 266 + html.img([attribute.src(project.img), attribute.style(style.icon)]), 261 267 html.h1([], [element.text(project.title)]), 262 268 ]), 263 269 html.p([], [project.summary]), ··· 271 277 }) 272 278 } 273 279 274 - const post_style: List(#(String, String)) = [ 275 - #("background-color", "#cae4e7"), #("border-radius", "1em"), 276 - #("padding", "1em"), #("margin-bottom", "1em"), 277 - ] 278 - 279 - fn day_to_string(day: Day) -> String { 280 - day.date |> int.to_string 281 - <> "/" 282 - <> day.month |> int.to_string 283 - <> "/" 284 - <> day.year |> int.to_string 285 - } 280 + fn view_posts(model: Model) -> Element(Msg) { 281 + let post_style = style.post(model.dark_mode) 286 282 287 - fn view_posts(model: Model) -> Element(Msg) { 288 283 let posts = 289 284 model.posts 290 285 |> list.map(fn(post: posts.Post(Msg)) { ··· 299 294 ]), 300 295 ], 301 296 [ 302 - html.h1([], [common.styled_link(post.title, "posts/" <> post.id)]), 297 + html.h1([], [common.link(post.title, "posts/" <> post.id)]), 303 298 html.p([attribute.style([#("color", "gray")])], [ 304 299 element.text("Author: " <> post.author), 305 300 ]), 306 301 html.p([attribute.style([#("color", "gray")])], [ 307 - element.text("Date Posted: " <> post.date_posted |> day_to_string), 302 + element.text( 303 + "Date Posted: " <> post.date_posted |> common.day_to_string, 304 + ), 308 305 ]), 309 306 ], 310 307 ), ··· 315 312 } 316 313 317 314 fn view_post(model: Model, id: String) -> Element(Msg) { 315 + let post_style = style.post(model.dark_mode) 316 + 318 317 let post = 319 318 model.posts 320 319 |> list.find(fn(post) { post.id == id }) ··· 335 334 element.text("Author: " <> post.author), 336 335 ]), 337 336 html.p([attribute.style([#("color", "gray")])], [ 338 - element.text("Date Posted: " <> post.date_posted |> day_to_string), 337 + element.text( 338 + "Date Posted: " <> post.date_posted |> common.day_to_string, 339 + ), 339 340 ]), 340 341 ], 341 342 ),
+12 -8
src/website/common.gleam
··· 1 + import birl.{type Day} 2 + import gleam/int 1 3 import lustre/attribute as attr 2 4 import lustre/element 3 5 import lustre/element/html 4 6 5 - const link_style: List(#(String, String)) = [ 6 - #("text-decoration", "underline"), #("color", "black"), 7 - ] 8 - 9 - pub fn styled_link(text: String, link: String) -> element.Element(a) { 10 - html.a([attr.href(link), attr.style(link_style)], [element.text(text)]) 7 + pub fn link(text: String, link: String) -> element.Element(a) { 8 + html.a([attr.href(link), attr.style([#("color", "#f380b1")])], [ 9 + element.text(text), 10 + ]) 11 11 } 12 12 13 - pub fn link(text: String, link: String) -> element.Element(a) { 14 - html.a([attr.href(link)], [element.text(text)]) 13 + pub fn day_to_string(day: Day) -> String { 14 + day.date |> int.to_string 15 + <> "/" 16 + <> day.month |> int.to_string 17 + <> "/" 18 + <> day.year |> int.to_string 15 19 }
+169
src/website/style.gleam
··· 1 + pub const page_padding: List(#(String, String)) = [ 2 + #("margin-left", "25vh"), #("margin-right", "25vh"), 3 + ] 4 + 5 + pub fn page(dark_mode: Bool) -> List(#(String, String)) { 6 + case dark_mode { 7 + True -> [ 8 + #("font-family", "\"Inter\", sans-serif"), 9 + #("font-weight", "400"), 10 + #("font-style", "normal"), 11 + #("min-height", "100vh"), 12 + #("background-color", "#151515"), 13 + #("padding", "3vh"), 14 + ] 15 + False -> [ 16 + #("font-family", "\"Inter\", sans-serif"), 17 + #("font-weight", "400"), 18 + #("font-style", "normal"), 19 + #("min-height", "100vh"), 20 + #("padding", "3vh"), 21 + ] 22 + } 23 + } 24 + 25 + pub fn navbar(dark_mode: Bool) -> List(#(String, String)) { 26 + case dark_mode { 27 + True -> [ 28 + #("display", "flex"), 29 + #("background-color", "#1e1e1e"), 30 + #("border-radius", "1em"), 31 + #("padding", "1em"), 32 + #("margin-bottom", "3vh"), 33 + #("justify-conten", "center"), 34 + #("align-items", "center"), 35 + #("gap", "1em"), 36 + #("border", "0"), 37 + #("flex-grow", "1"), 38 + ] 39 + False -> [ 40 + #("display", "flex"), 41 + #("background-color", "#cae4e7"), 42 + #("border-radius", "1em"), 43 + #("padding", "1em"), 44 + #("margin-bottom", "3vh"), 45 + #("justify-conten", "center"), 46 + #("align-items", "center"), 47 + #("gap", "1em"), 48 + #("border", "0"), 49 + #("flex-grow", "1"), 50 + ] 51 + } 52 + } 53 + 54 + pub fn button(dark_mode: Bool) -> List(#(String, String)) { 55 + case dark_mode { 56 + True -> [ 57 + #("background-color", "#1e1e1e"), 58 + #("border-radius", "1em"), 59 + #("padding", "1em"), 60 + #("margin-bottom", "3vh"), 61 + #("justify-conten", "center"), 62 + #("align-items", "center"), 63 + #("aspect-ratio", "1 / 1"), 64 + #("border", "0"), 65 + #("width", "6%") 66 + ] 67 + False -> [ 68 + #("background-color", "#cae4e7"), 69 + #("border-radius", "1em"), 70 + #("padding", "1em"), 71 + #("margin-bottom", "3vh"), 72 + #("justify-conten", "center"), 73 + #("align-items", "center"), 74 + #("aspect-ratio", "1 / 1"), 75 + #("border", "0"), 76 + #("width", "6%") 77 + ] 78 + } 79 + } 80 + 81 + pub fn navitem(dark_mode: Bool) -> List(#(String, String)) { 82 + case dark_mode { 83 + True -> [ 84 + #("text-decoration", "none"), 85 + #("background-color", "#151515"), 86 + #("padding", "0.75em"), 87 + #("border-radius", "1em"), 88 + #("color", "#dcdcdc"), 89 + ] 90 + False -> [ 91 + #("text-decoration", "none"), 92 + #("background-color", "#b8cfd2"), 93 + #("padding", "0.75em"), 94 + #("border-radius", "1em"), 95 + #("color", "black"), 96 + ] 97 + } 98 + } 99 + 100 + pub fn home(dark_mode: Bool) -> List(#(String, String)) { 101 + case dark_mode { 102 + True -> [ 103 + #("background-color", "#1e1e1e"), 104 + #("border-radius", "1em"), 105 + #("padding", "1em"), 106 + #("margin-bottom", "1em"), 107 + #("font-size", "1.25em"), 108 + #("color", "#dcdcdc"), 109 + ] 110 + False -> [ 111 + #("background-color", "#cae4e7"), 112 + #("border-radius", "1em"), 113 + #("padding", "1em"), 114 + #("margin-bottom", "1em"), 115 + #("font-size", "1.25em"), 116 + ] 117 + } 118 + } 119 + 120 + pub const icon: List(#(String, String)) = [ 121 + #("max-width", "4em"), #("max-height", "4em"), #("border-radius", "1em"), 122 + ] 123 + 124 + pub fn project(dark_mode: Bool) -> List(#(String, String)) { 125 + case dark_mode { 126 + True -> [ 127 + #("background-color", "#1e1e1e"), 128 + #("border-radius", "1em"), 129 + #("padding", "1em"), 130 + #("margin-bottom", "1em"), 131 + #("color", "#dcdcdc"), 132 + ] 133 + False -> [ 134 + #("background-color", "#cae4e7"), 135 + #("border-radius", "1em"), 136 + #("padding", "1em"), 137 + #("margin-bottom", "1em"), 138 + ] 139 + } 140 + } 141 + 142 + pub const project_bar: List(#(String, String)) = [ 143 + #("display", "flex"), #("align-items", "center"), #("gap", "1em"), 144 + ] 145 + 146 + pub fn post(dark_mode: Bool) -> List(#(String, String)) { 147 + case dark_mode { 148 + True -> [ 149 + #("background-color", "#1e1e1e"), 150 + #("border-radius", "1em"), 151 + #("padding", "1em"), 152 + #("margin-bottom", "1em"), 153 + #("color", "#dcdcdc"), 154 + ] 155 + False -> [ 156 + #("background-color", "#cae4e7"), 157 + #("border-radius", "1em"), 158 + #("padding", "1em"), 159 + #("margin-bottom", "1em"), 160 + ] 161 + } 162 + } 163 + 164 + pub fn link(dark_mode: Bool) -> List(#(String, String)) { 165 + case dark_mode { 166 + True -> [#("text-decoration", "underline"), #("color", "#dcdcdc")] 167 + False -> [#("text-decoration", "underline"), #("color", "black")] 168 + } 169 + }