Skip to content

Commit c8d3bda

Browse files
committed
wip: improve rendering for posts, add links, and add headers
1 parent 071208b commit c8d3bda

File tree

5 files changed

+196
-56
lines changed

5 files changed

+196
-56
lines changed

Package.swift

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ let package = Package(
3030
.product(name: "Dependencies", package: "swift-dependencies"),
3131
]
3232
),
33+
.target(
34+
name: "ActivityClient",
35+
dependencies: [
36+
.product(name: "Dependencies", package: "swift-dependencies"),
37+
.product(name: "DependenciesMacros", package: "swift-dependencies"),
38+
]
39+
),
3340
.target(
3441
name: "Routes",
3542
dependencies: [
@@ -54,15 +61,6 @@ let package = Package(
5461
]
5562
),
5663

57-
/// Clients
58-
.target(
59-
name: "ActivityClient",
60-
dependencies: [
61-
.product(name: "Dependencies", package: "swift-dependencies"),
62-
.product(name: "DependenciesMacros", package: "swift-dependencies"),
63-
]
64-
),
65-
6664
/// Executable
6765
.executableTarget(
6866
name: "App",

Sources/App/Middlewares/SiteMiddleware.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ struct SiteMiddleware<Context: RequestContext>: RouterController {
1515
ReloadBrowserMiddleware()
1616
#endif
1717

18-
FileMiddleware("Public", searchForIndexHtml: false)
18+
FileMiddleware(
19+
"Public",
20+
urlBasePath: "/assets",
21+
searchForIndexHtml: false
22+
)
1923

2024
URLRoutingMiddleware(self.siteRouter) { req, ctx, route in
2125
try withDependencies {

Sources/Pages/HomePage.swift

Lines changed: 128 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public struct HomePage: Page {
1515
return formatter
1616
}()
1717

18-
let styling = Style()
18+
let styling: HomePage.Style = Style()
1919

2020
public var content: some HTML {
2121
HTMLRaw("<!DOCTYPE html>")
@@ -32,9 +32,9 @@ public struct HomePage: Page {
3232
script { HTMLRaw("hljs.highlightAll();") }
3333
VueScript()
3434
}
35-
body(.v.scope("{ showCode: true }")) {
35+
body(.v.scope("{ showCode: true, selection: undefined }")) {
3636
header(.class("wrapped")) {
37-
// TODO: Allow changing from swift-syntax based language to regular
37+
// TODO: Allow changing from swift-syntax based language to plain text, and other languages?
3838
div(.class("container"), .style("height: 3rem")) {}
3939
}
4040
main {
@@ -123,7 +123,7 @@ public struct HomePage: Page {
123123
.d("M128,16a88.1,88.1,0,0,0-88,88c0,75.3,80,132.17,83.41,134.55a8,8,0,0,0,9.18,0C136,236.17,216,179.3,216,104A88.1,88.1,0,0,0,128,16Zm0,56a32,32,0,1,1-32,32A32,32,0,0,1,128,72Z")
124124
)
125125
}
126-
"\(residency)"
126+
" \(residency)"
127127
}
128128

129129
@HTMLBuilder
@@ -143,7 +143,7 @@ public struct HomePage: Page {
143143
path(.d("M237.33,106.21,61.41,41l-.16-.05A16,16,0,0,0,40.9,61.25a1,1,0,0,0,.05.16l65.26,175.92A15.77,15.77,0,0,0,121.28,248h.3a15.77,15.77,0,0,0,15-11.29l.06-.2,21.84-78,78-21.84.2-.06a16,16,0,0,0,.62-30.38ZM149.84,144.3a8,8,0,0,0-5.54,5.54L121.3,232l-.06-.17L56,56l175.82,65.22.16.06Z"))
144144
}
145145

146-
"Currently in "
146+
" Currently in "
147147

148148
b {
149149
[location.city, location.state, location.region == "United States" ? nil : location.region]
@@ -161,7 +161,7 @@ public struct HomePage: Page {
161161

162162
private struct PostsSection: HTML {
163163
var content: some HTML {
164-
section(.id("posts"), .class("wrapped"), .v.scope("{ selection: undefined }")) {
164+
section(.id("posts"), .class("wrapped")) {
165165
div(.class("container")) {
166166
code(.class("code-tag")) { "Posts.swift" }
167167

@@ -196,24 +196,82 @@ public struct HomePage: Page {
196196
// }
197197
}
198198

199-
for (idx, post) in Post.allCases.enumerated() {
199+
for (idx, post) in Post.allCases.reversed().enumerated() {
200200
article(
201201
.class("post"),
202202
.v.show("!selection || selection == '\(post.kind.rawValue)'")
203203
) {
204204
header {
205-
div(.style("display: flex")) {
205+
section(.style("display: flex; align-items: baseline;")) {
206206
span(.class("post__date"), .style("flex-grow: 1")) { post.dateFormatted }
207207

208-
pre {
208+
pre {
209209
code(.class("hljs language-swift"), .style("font-size: 0.75em; color: #777; font-weight: 500")) {
210210
"post[\(idx)]"
211-
}
211+
}
212+
}
213+
}
214+
215+
if let postHeader = post.header {
216+
section {
217+
switch postHeader {
218+
case let .link(link):
219+
EmptyHTML()
220+
case let .image(src, label):
221+
img(.src(src), .class("post__header"), .custom(name: "alt", value: label), .aria.label(label))
222+
case let .video(src):
223+
video(
224+
.class("post__header"),
225+
.custom(name: "autoplay", value: ""),
226+
.custom(name: "playsinline", value: ""),
227+
.custom(name: "muted", value: ""),
228+
.custom(name: "controls", value: ""),
229+
.custom(name: "loop", value: "")
230+
) {
231+
source(.src(src))
232+
"Your browser does not support playing this video"
233+
}
234+
case let .code(rawCode, lang):
235+
pre(.class("post__header")) {
236+
code(.class("hljs language-\(lang.rawValue)")) {
237+
HTMLRaw(rawCode)
238+
}
239+
}
240+
}
212241
}
213242
}
214243
}
215-
h3(.class("post__time")) { post.title }
244+
h3(.class("post__title")) { post.title }
216245
section(.class("post__content")) { post.content }
246+
247+
if !post.links.isEmpty {
248+
section(.class("post__links")) {
249+
for link in post.links {
250+
a(
251+
.href(link.href),
252+
.target(.blank),
253+
.rel("noopener noreferrer"),
254+
.class("post__link-\(link.role.rawValue)")
255+
) {
256+
HTMLText(link.title)
257+
" "
258+
if link.isExternal {
259+
svg(.xmlns(), .fill("currentColor"), .viewBox("0 0 256 256"), .class("svg-icon"), .aria.label("external link icon")) {
260+
path(
261+
.d("M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z")
262+
)
263+
}
264+
} else {
265+
svg(.xmlns(), .fill("currentColor"), .viewBox("0 0 256 256"), .class("svg-icon"), .aria.label("external link icon")) {
266+
path(
267+
.d("M224.49,136.49l-72,72a12,12,0,0,1-17-17L187,140H40a12,12,0,0,1,0-24H187L135.51,64.48a12,12,0,0,1,17-17l72,72A12,12,0,0,1,224.49,136.49Z")
268+
)
269+
}
270+
}
271+
}
272+
}
273+
}
274+
}
217275
}
218276
}
219277
}
@@ -300,7 +358,7 @@ extension HomePage {
300358
}
301359

302360
Class("container") => {
303-
AnyProperty("max-width", "46rem")
361+
AnyProperty("max-width", "40rem")
304362
AnyProperty("margin-right", "auto")
305363
AnyProperty("margin-left", "auto")
306364
AnyProperty("border-left", "1px solid #303030")
@@ -334,7 +392,6 @@ extension HomePage {
334392
AnyProperty("bottom", "0.125em")
335393
AnyProperty("width", "1em")
336394
AnyProperty("height", "1em")
337-
AnyProperty("margin-right", "0.25rem")
338395
}
339396

340397
Class("reversed") => {
@@ -415,15 +472,71 @@ extension HomePage {
415472
AnyProperty("font-weight", "600")
416473
}
417474

418-
Class("post__time") => {
475+
Class("post__title") => {
419476
AnyProperty("margin-top", "0.5rem")
420477
}
421478

422479
Class("post__content") * All() => {
423480
AnyProperty("margin", "revert")
424481
}
425482

426-
Class("post__content") * Element(.pre) => {
483+
Class("post__content") * Element(.blockquote) => {
484+
// AnyProperty("all", "unset")
485+
AnyProperty("display", "block")
486+
AnyProperty("background", "#2A2A2A")
487+
AnyProperty("border", "1.5px solid #4A4A4A")
488+
AnyProperty("padding", "0.125rem 1rem")
489+
AnyProperty("margin-right", "0")
490+
AnyProperty("margin-left", "0")
491+
AnyProperty("border-radius", "0.5rem")
492+
}
493+
494+
Class("post__header") => {
495+
AnyProperty("width", "100%")
496+
AnyProperty("margin-top", "1.25rem")
497+
AnyProperty("margin-bottom", "1.25rem")
498+
AnyProperty("border-color", "#3A3A3A")
499+
AnyProperty("border-style", "solid")
500+
AnyProperty("border-width", "1.5px")
501+
AnyProperty("border-radius", "0.5rem")
502+
}
503+
504+
Class("post__links") => {
505+
AnyProperty("display", "flex")
506+
AnyProperty("gap", "0.75rem")
507+
AnyProperty("margin-top", "1.5rem")
508+
}
509+
510+
".post__link-primary, .post__link-secondary, .post__link-tertiary" => {
511+
AnyProperty("all", "unset")
512+
AnyProperty("font-size", "0.85em")
513+
AnyProperty("font-weight", "550")
514+
AnyProperty("align-content", "center")
515+
AnyProperty("min-height", "1.5rem")
516+
AnyProperty("min-width", "2rem")
517+
AnyProperty("padding", "0.375rem 0.75rem")
518+
AnyProperty("cursor", "pointer")
519+
AnyProperty("border-radius", "0.5rem")
520+
}
521+
522+
Class("post__link-primary") => {
523+
Color(.white)
524+
AnyProperty("background", "linear-gradient(to bottom, hsla(0, 0%, 24%, 1), hsla(0, 0%, 16%, 1))")
525+
AnyProperty("box-shadow", "inset 0 1px 1px rgba(255, 255, 255, 0.12)")
526+
}
527+
528+
Class("post__link-secondary") => {
529+
Color(.black)
530+
AnyProperty("box-shadow", "inset 0px -1px 2px 0px hsl(0 0% 50% / 0.5)")
531+
AnyProperty("background", "linear-gradient(to bottom, hsl(0deg 0% 100%), hsl(0deg 0% 92.91%))")
532+
}
533+
534+
Class("post__link-tertiary") => {
535+
Color(.white)
536+
AnyProperty("background", "hsla(0, 0%, 50%, 0.25)")
537+
}
538+
539+
".post__content pre, .post__header pre" => {
427540
AnyProperty("padding", "0.75rem")
428541
Background("#242424")
429542
AnyProperty("border-color", "#3A3A3A")

Sources/Pages/Models/Post+AllCases.swift

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,49 @@ extension Post: CaseIterable {
44
static var allCases: [Self] {
55
[
66
Self(
7-
slug: "swift-cascadia-released",
8-
title: "A Swift DSL for type-safe CSS",
7+
id: 1,
8+
title: "PrismUI \u{2014} Controlling MSI RGB Keyboard on mac",
99
content: """
10-
Since I started building this website using Swift, I used [elementary](https://github.com/sliemeobn/elementary "link to Swift library") to build \
11-
HTML pages.
12-
13-
```swift
14-
struct CustomSheet: StyleSheet {
15-
var body: some Rule {
16-
Class("books") => {
17-
Color(.red)
18-
BackgroundColor(.red)
19-
}
20-
}
21-
}
22-
```
10+
> TBD
2311
""",
24-
date: Date(timeIntervalSince1970: 1_738_483_200), // Feb 2, 2025
12+
date: Date(timeIntervalSince1970: 1_663_225_200),
2513
kind: .project
2614
),
2715
Self(
28-
slug: "mochi-released",
29-
title: "Mochi \u{2014} Content Viewer for iOS and macOS",
16+
id: 2,
17+
header: .image("/assets/projects/anime-now/an-discover.png", label: "Anime Now! discover image"),
18+
title: "Anime Now! \u{2014} An iOS and macOS App",
3019
content: """
3120
> TBD
3221
""",
3322
date: Date(timeIntervalSince1970: 1_663_225_200), // Sep 15, 2025
3423
kind: .project
3524
),
3625
Self(
37-
slug: "anime-now-released",
38-
title: "Anime Now! \u{2014} An iOS and macOS App",
26+
id: 3,
27+
title: "Mochi \u{2014} Content Viewer for iOS and macOS",
3928
content: """
4029
> TBD
4130
""",
4231
date: Date(timeIntervalSince1970: 1_663_225_200), // Sep 15, 2025
4332
kind: .project
4433
),
4534
Self(
46-
slug: "prism-ui-released",
47-
title: "PrismUI \u{2014} Controlling MSI RGB Keyboard on mac",
35+
id: 4,
36+
title: "Website Redesign!",
4837
content: """
49-
> TBD
38+
I finally decided to redesign my website. \
39+
To expand my skills with Swift, I decided to rebuild my portfolio in Swift.
5040
""",
51-
date: Date(timeIntervalSince1970: 1_663_225_200),
52-
kind: .project
41+
date: Date(timeIntervalSince1970: 1_738_483_200), // Feb 2, 2025
42+
kind: .blog,
43+
links: [
44+
Post.Link(
45+
title: "GitHub",
46+
href: "https://github.com/errorerrorerror/erikbautista.dev",
47+
role: .primary
48+
),
49+
]
5350
),
5451
]
5552
}

0 commit comments

Comments
 (0)