tangled
alpha
login
or
join now
oppi.li
/
gleam-ci-tests
forked from
lesbian.skin/website
0
fork
atom
not my website
0
fork
atom
overview
issues
pulls
pipelines
CSS Refactor + Dark Mode
lesbian.skin
2 years ago
641d010a
e6d0ead2
+260
-82
5 changed files
expand all
collapse all
unified
split
index.html
src
ffi.mjs
website
common.gleam
style.gleam
website.gleam
+1
-1
index.html
···
13
13
<script type="module" src="/priv/static/website.mjs"></script>
14
14
</head>
15
15
16
16
-
<body>
16
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
3
+
}
4
4
+
5
5
+
export function prefers_dark_mode() {
6
6
+
return window.matchMedia('(prefers-color-scheme:dark)').matches
3
7
}
+74
-73
src/website.gleam
···
1
1
-
import birl.{type Day}
2
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
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
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
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
49
+
@external(javascript, "./ffi.mjs", "prefers_dark_mode")
50
50
+
fn prefers_dark_mode() -> Bool
51
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
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
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
97
+
ChangeDarkMode -> #(
98
98
+
Model(..model, dark_mode: !model.dark_mode),
99
99
+
effect.none(),
100
100
+
)
91
101
}
92
102
}
93
103
94
104
// View
95
105
96
106
fn view(model: Model) -> Element(Msg) {
97
97
-
let styles = [
98
98
-
#("margin-left", "25vh"),
99
99
-
#("margin-top", "3vh"),
100
100
-
#("margin-right", "25vh"),
101
101
-
#("font-family", "\"Inter\", sans-serif"),
102
102
-
#("font-weight", "400"),
103
103
-
#("font-style", "normal"),
104
104
-
]
105
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
114
-
ui.stack([attribute.style(styles)], [view_navbar(model), page])
115
115
+
ui.stack([attribute.style(style.page(model.dark_mode))], [
116
116
+
html.div([attribute.style(style.page_padding)], [view_navbar(model), page]),
117
117
+
])
115
118
}
116
119
117
117
-
const navbar_style: List(#(String, String)) = [
118
118
-
#("display", "flex"), #("background-color", "#cae4e7"),
119
119
-
#("border-radius", "1em"), #("padding", "1em"), #("margin-bottom", "3vh"),
120
120
-
#("justify-conten", "center"), #("align-items", "center"), #("gap", "1em"),
121
121
-
]
122
122
-
123
123
-
const navitem_style: List(#(String, String)) = [
124
124
-
#("text-decoration", "none"), #("background-color", "#b8cfd2"),
125
125
-
#("padding", "0.75em"), #("border-radius", "1em"), #("color", "black"),
126
126
-
]
120
120
+
fn view_navbar(model: Model) -> Element(Msg) {
121
121
+
let navitem_style = style.navitem(model.dark_mode)
122
122
+
let navbar_style = style.navbar(model.dark_mode)
127
123
128
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
135
-
cluster.of(html.nav, [attribute.style(navbar_style)], [
136
136
-
html.h1([attribute.style([#("margin", "0")])], [element.text("naomieow")]),
137
137
-
view_nav_item("", "Home"),
138
138
-
view_nav_item("projects", "Projects"),
139
139
-
view_nav_item("posts", "Posts"),
140
140
-
])
130
130
+
html.span(
131
131
+
[
132
132
+
attribute.style([
133
133
+
#("display", "flex"),
134
134
+
#("gap", "1em"),
135
135
+
#("width", "100%"),
136
136
+
]),
137
137
+
],
138
138
+
[
139
139
+
cluster.of(html.nav, [attribute.style(navbar_style)], [
140
140
+
html.h1([attribute.style([#("margin", "0"), #("color", "#f380b1")])], [
141
141
+
element.text("naomieow"),
142
142
+
]),
143
143
+
view_nav_item("", "Home"),
144
144
+
view_nav_item("projects", "Projects"),
145
145
+
view_nav_item("posts", "Posts"),
146
146
+
]),
147
147
+
ui.button(
148
148
+
[
149
149
+
attribute.style(style.button(model.dark_mode)),
150
150
+
event.on_click(ChangeDarkMode),
151
151
+
],
152
152
+
[
153
153
+
html.h1([attribute.style([#("margin", "0")])], [
154
154
+
case model.dark_mode {
155
155
+
True -> element.text("☀️")
156
156
+
False -> element.text("🌕")
157
157
+
},
158
158
+
]),
159
159
+
],
160
160
+
),
161
161
+
],
162
162
+
)
141
163
}
142
164
143
143
-
const home_style: List(#(String, String)) = [
144
144
-
#("background-color", "#cae4e7"), #("border-radius", "1em"),
145
145
-
#("padding", "1em"), #("margin-bottom", "1em"), #("font-size", "1.25em"),
146
146
-
]
165
165
+
fn view_home(model: Model) -> Element(Msg) {
166
166
+
let home_style = style.home(model.dark_mode)
147
167
148
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
200
-
// html.p([], [
219
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
207
-
const icon_style: List(#(String, String)) = [
208
208
-
#("max-width", "4em"), #("max-height", "4em"), #("border-radius", "1em"),
209
209
-
]
210
210
-
211
211
-
const project_style: List(#(String, String)) = [
212
212
-
#("background-color", "#cae4e7"), #("border-radius", "1em"),
213
213
-
#("padding", "1em"), #("margin-bottom", "1em"),
214
214
-
]
215
215
-
216
216
-
const project_bar_style: List(#(String, String)) = [
217
217
-
#("display", "flex"), #("align-items", "center"), #("gap", "1em"),
218
218
-
]
219
219
-
220
226
fn view_projects(model: Model) -> Element(Msg) {
227
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
227
-
cluster.of(html.div, [attribute.style(project_bar_style)], [
228
228
-
html.img([attribute.src(project.img), attribute.style(icon_style)]),
229
229
-
html.h1([], [
230
230
-
common.styled_link(project.title, "projects/" <> project.id),
231
231
-
]),
234
234
+
cluster.of(html.div, [attribute.style(style.project_bar)], [
235
235
+
html.img([attribute.src(project.img), attribute.style(style.icon)]),
236
236
+
html.h1([], [common.link(project.title, "projects/" <> project.id)]),
232
237
cluster.of(
233
238
html.div,
234
234
-
[attribute.style(project_bar_style)],
239
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
240
-
attribute.style(icon_style),
245
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
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
259
-
cluster.of(html.div, [attribute.style(project_bar_style)], [
260
260
-
html.img([attribute.src(project.img), attribute.style(icon_style)]),
265
265
+
cluster.of(html.div, [attribute.style(style.project_bar)], [
266
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
274
-
const post_style: List(#(String, String)) = [
275
275
-
#("background-color", "#cae4e7"), #("border-radius", "1em"),
276
276
-
#("padding", "1em"), #("margin-bottom", "1em"),
277
277
-
]
278
278
-
279
279
-
fn day_to_string(day: Day) -> String {
280
280
-
day.date |> int.to_string
281
281
-
<> "/"
282
282
-
<> day.month |> int.to_string
283
283
-
<> "/"
284
284
-
<> day.year |> int.to_string
285
285
-
}
280
280
+
fn view_posts(model: Model) -> Element(Msg) {
281
281
+
let post_style = style.post(model.dark_mode)
286
282
287
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
302
-
html.h1([], [common.styled_link(post.title, "posts/" <> post.id)]),
297
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
307
-
element.text("Date Posted: " <> post.date_posted |> day_to_string),
302
302
+
element.text(
303
303
+
"Date Posted: " <> post.date_posted |> common.day_to_string,
304
304
+
),
308
305
]),
309
306
],
310
307
),
···
315
312
}
316
313
317
314
fn view_post(model: Model, id: String) -> Element(Msg) {
315
315
+
let post_style = style.post(model.dark_mode)
316
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
338
-
element.text("Date Posted: " <> post.date_posted |> day_to_string),
337
337
+
element.text(
338
338
+
"Date Posted: " <> post.date_posted |> common.day_to_string,
339
339
+
),
339
340
]),
340
341
],
341
342
),
+12
-8
src/website/common.gleam
···
1
1
+
import birl.{type Day}
2
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
5
-
const link_style: List(#(String, String)) = [
6
6
-
#("text-decoration", "underline"), #("color", "black"),
7
7
-
]
8
8
-
9
9
-
pub fn styled_link(text: String, link: String) -> element.Element(a) {
10
10
-
html.a([attr.href(link), attr.style(link_style)], [element.text(text)])
7
7
+
pub fn link(text: String, link: String) -> element.Element(a) {
8
8
+
html.a([attr.href(link), attr.style([#("color", "#f380b1")])], [
9
9
+
element.text(text),
10
10
+
])
11
11
}
12
12
13
13
-
pub fn link(text: String, link: String) -> element.Element(a) {
14
14
-
html.a([attr.href(link)], [element.text(text)])
13
13
+
pub fn day_to_string(day: Day) -> String {
14
14
+
day.date |> int.to_string
15
15
+
<> "/"
16
16
+
<> day.month |> int.to_string
17
17
+
<> "/"
18
18
+
<> day.year |> int.to_string
15
19
}
+169
src/website/style.gleam
···
1
1
+
pub const page_padding: List(#(String, String)) = [
2
2
+
#("margin-left", "25vh"), #("margin-right", "25vh"),
3
3
+
]
4
4
+
5
5
+
pub fn page(dark_mode: Bool) -> List(#(String, String)) {
6
6
+
case dark_mode {
7
7
+
True -> [
8
8
+
#("font-family", "\"Inter\", sans-serif"),
9
9
+
#("font-weight", "400"),
10
10
+
#("font-style", "normal"),
11
11
+
#("min-height", "100vh"),
12
12
+
#("background-color", "#151515"),
13
13
+
#("padding", "3vh"),
14
14
+
]
15
15
+
False -> [
16
16
+
#("font-family", "\"Inter\", sans-serif"),
17
17
+
#("font-weight", "400"),
18
18
+
#("font-style", "normal"),
19
19
+
#("min-height", "100vh"),
20
20
+
#("padding", "3vh"),
21
21
+
]
22
22
+
}
23
23
+
}
24
24
+
25
25
+
pub fn navbar(dark_mode: Bool) -> List(#(String, String)) {
26
26
+
case dark_mode {
27
27
+
True -> [
28
28
+
#("display", "flex"),
29
29
+
#("background-color", "#1e1e1e"),
30
30
+
#("border-radius", "1em"),
31
31
+
#("padding", "1em"),
32
32
+
#("margin-bottom", "3vh"),
33
33
+
#("justify-conten", "center"),
34
34
+
#("align-items", "center"),
35
35
+
#("gap", "1em"),
36
36
+
#("border", "0"),
37
37
+
#("flex-grow", "1"),
38
38
+
]
39
39
+
False -> [
40
40
+
#("display", "flex"),
41
41
+
#("background-color", "#cae4e7"),
42
42
+
#("border-radius", "1em"),
43
43
+
#("padding", "1em"),
44
44
+
#("margin-bottom", "3vh"),
45
45
+
#("justify-conten", "center"),
46
46
+
#("align-items", "center"),
47
47
+
#("gap", "1em"),
48
48
+
#("border", "0"),
49
49
+
#("flex-grow", "1"),
50
50
+
]
51
51
+
}
52
52
+
}
53
53
+
54
54
+
pub fn button(dark_mode: Bool) -> List(#(String, String)) {
55
55
+
case dark_mode {
56
56
+
True -> [
57
57
+
#("background-color", "#1e1e1e"),
58
58
+
#("border-radius", "1em"),
59
59
+
#("padding", "1em"),
60
60
+
#("margin-bottom", "3vh"),
61
61
+
#("justify-conten", "center"),
62
62
+
#("align-items", "center"),
63
63
+
#("aspect-ratio", "1 / 1"),
64
64
+
#("border", "0"),
65
65
+
#("width", "6%")
66
66
+
]
67
67
+
False -> [
68
68
+
#("background-color", "#cae4e7"),
69
69
+
#("border-radius", "1em"),
70
70
+
#("padding", "1em"),
71
71
+
#("margin-bottom", "3vh"),
72
72
+
#("justify-conten", "center"),
73
73
+
#("align-items", "center"),
74
74
+
#("aspect-ratio", "1 / 1"),
75
75
+
#("border", "0"),
76
76
+
#("width", "6%")
77
77
+
]
78
78
+
}
79
79
+
}
80
80
+
81
81
+
pub fn navitem(dark_mode: Bool) -> List(#(String, String)) {
82
82
+
case dark_mode {
83
83
+
True -> [
84
84
+
#("text-decoration", "none"),
85
85
+
#("background-color", "#151515"),
86
86
+
#("padding", "0.75em"),
87
87
+
#("border-radius", "1em"),
88
88
+
#("color", "#dcdcdc"),
89
89
+
]
90
90
+
False -> [
91
91
+
#("text-decoration", "none"),
92
92
+
#("background-color", "#b8cfd2"),
93
93
+
#("padding", "0.75em"),
94
94
+
#("border-radius", "1em"),
95
95
+
#("color", "black"),
96
96
+
]
97
97
+
}
98
98
+
}
99
99
+
100
100
+
pub fn home(dark_mode: Bool) -> List(#(String, String)) {
101
101
+
case dark_mode {
102
102
+
True -> [
103
103
+
#("background-color", "#1e1e1e"),
104
104
+
#("border-radius", "1em"),
105
105
+
#("padding", "1em"),
106
106
+
#("margin-bottom", "1em"),
107
107
+
#("font-size", "1.25em"),
108
108
+
#("color", "#dcdcdc"),
109
109
+
]
110
110
+
False -> [
111
111
+
#("background-color", "#cae4e7"),
112
112
+
#("border-radius", "1em"),
113
113
+
#("padding", "1em"),
114
114
+
#("margin-bottom", "1em"),
115
115
+
#("font-size", "1.25em"),
116
116
+
]
117
117
+
}
118
118
+
}
119
119
+
120
120
+
pub const icon: List(#(String, String)) = [
121
121
+
#("max-width", "4em"), #("max-height", "4em"), #("border-radius", "1em"),
122
122
+
]
123
123
+
124
124
+
pub fn project(dark_mode: Bool) -> List(#(String, String)) {
125
125
+
case dark_mode {
126
126
+
True -> [
127
127
+
#("background-color", "#1e1e1e"),
128
128
+
#("border-radius", "1em"),
129
129
+
#("padding", "1em"),
130
130
+
#("margin-bottom", "1em"),
131
131
+
#("color", "#dcdcdc"),
132
132
+
]
133
133
+
False -> [
134
134
+
#("background-color", "#cae4e7"),
135
135
+
#("border-radius", "1em"),
136
136
+
#("padding", "1em"),
137
137
+
#("margin-bottom", "1em"),
138
138
+
]
139
139
+
}
140
140
+
}
141
141
+
142
142
+
pub const project_bar: List(#(String, String)) = [
143
143
+
#("display", "flex"), #("align-items", "center"), #("gap", "1em"),
144
144
+
]
145
145
+
146
146
+
pub fn post(dark_mode: Bool) -> List(#(String, String)) {
147
147
+
case dark_mode {
148
148
+
True -> [
149
149
+
#("background-color", "#1e1e1e"),
150
150
+
#("border-radius", "1em"),
151
151
+
#("padding", "1em"),
152
152
+
#("margin-bottom", "1em"),
153
153
+
#("color", "#dcdcdc"),
154
154
+
]
155
155
+
False -> [
156
156
+
#("background-color", "#cae4e7"),
157
157
+
#("border-radius", "1em"),
158
158
+
#("padding", "1em"),
159
159
+
#("margin-bottom", "1em"),
160
160
+
]
161
161
+
}
162
162
+
}
163
163
+
164
164
+
pub fn link(dark_mode: Bool) -> List(#(String, String)) {
165
165
+
case dark_mode {
166
166
+
True -> [#("text-decoration", "underline"), #("color", "#dcdcdc")]
167
167
+
False -> [#("text-decoration", "underline"), #("color", "black")]
168
168
+
}
169
169
+
}