Skip to content

Commit 04dc020

Browse files
committed
wip: replace AlpineJS with VueJS, add posts
1 parent 2c1862e commit 04dc020

File tree

7 files changed

+299
-129
lines changed

7 files changed

+299
-129
lines changed

Sources/Pages/HomePage.swift

Lines changed: 68 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,28 @@ import Elementary
55
import Foundation
66

77
public struct HomePage: Page {
8-
struct Style: Sendable, StyleSheet {
8+
struct Style: @unchecked Sendable, StyleSheet {
99
var body: some Rule {
1010
// TODO: Add Work-Sans font?
1111

12+
// General
1213
Pseudo(class: .root) => {
1314
BackgroundColor("#1c1c1c")
1415
Color("#fafafa")
15-
AnyProperty("font-family", "ui-sans-serif, -apple-system, Helvetica Neue, Helvetica, Arial, sans-serif")
1616
AnyProperty("font-optical-sizing", "auto")
1717
AnyProperty("font-style", "normal")
1818
}
1919

20-
// General
21-
2220
Element(.body) => {
21+
// AnyProperty("border-top", "1px solid #404040")
22+
// AnyProperty("border-bottom", "1px solid #404040")
23+
AnyProperty("margin-top", "2rem")
24+
AnyProperty("margin-bottom", "3rem")
25+
}
26+
27+
Element(.body) > All() => {
28+
// AnyProperty("border-left", "1px solid #404040")
29+
// AnyProperty("border-right", "1px solid #404040")
2330
AnyProperty("max-width", "40rem")
2431
AnyProperty("margin-right", "auto")
2532
AnyProperty("margin-left", "auto")
@@ -41,9 +48,13 @@ public struct HomePage: Page {
4148
AnyProperty("scale", "calc(100% * -1) 100%")
4249
}
4350

44-
/// Main
51+
/// Hero header
4552

46-
Element(.header) * Element(.p) => {
53+
Class("hero") => {
54+
AnyProperty("padding-bottom", "1.5rem")
55+
}
56+
57+
Class("hero") * Element(.p) => {
4758
Color(.hex("#D0D0D0"))
4859
}
4960

@@ -58,23 +69,31 @@ public struct HomePage: Page {
5869

5970
Class("post-tabs") > Element(.li) => {
6071
AnyProperty("float", "left")
72+
AnyProperty("margin-right", "0.25rem")
6173
}
6274

6375
Class("post-tabs") * Element(.button) => {
64-
AnyProperty("border-radius", "9999px")
65-
AnyProperty("background-color", "#2c2c2c")
76+
BackgroundColor("#3c3c3c")
6677
AnyProperty("color", "white")
67-
AnyProperty("padding", "0.25rem 0.75rem")
68-
AnyProperty("border-width", "1px")
78+
AnyProperty("border-color", "#505050")
79+
AnyProperty("border-radius", "9999px")
6980
AnyProperty("border-style", "solid")
70-
AnyProperty("border-color", "#606060")
81+
AnyProperty("border-width", "1.25px")
82+
AnyProperty("padding", "0.25rem 0.75rem")
7183
}
7284

73-
/// Post
85+
Class("post-tabs") * Element(.button) <> .attr("aria-selected", match: .exact, value: "true") => {
86+
AnyProperty("background-color", "#F0F0F0")
87+
AnyProperty("color", "#101010")
88+
AnyProperty("border-color", "#A0A0A0")
89+
}
90+
91+
/// Posts
7492

7593
Class("post") => {
7694
AnyProperty("margin-top", "0.75rem")
7795
AnyProperty("margin-bottom", "1.5rem")
96+
// AnyProperty("border-bottom", "1px dotted #404040")
7897
}
7998

8099
Class("post") > Element(.header) => {
@@ -83,19 +102,23 @@ public struct HomePage: Page {
83102
AnyProperty("font-weight", "600")
84103
}
85104

86-
Class("post") > Class("post-title") => {
105+
Class("post-title") => {
87106
AnyProperty("margin-top", "0.5rem")
88107
}
89108

90-
Class("post") > Class("post-content") * All() => {
109+
Class("post-content") * All() => {
91110
AnyProperty("margin", "revert")
92111
}
93112

94113
/// Code blocks
95-
Element(.pre) => {
114+
Class("post") * Element(.pre) => {
96115
AnyProperty("padding", "1rem")
97-
Background("#2F2F2F")
116+
Background("#242424")
117+
AnyProperty("border-color", "#3A3A3A")
118+
AnyProperty("border-style", "solid")
119+
AnyProperty("border-width", "1.5px")
98120
AnyProperty("border-radius", "0.75rem")
121+
AnyProperty("overflow-x", "auto")
99122
}
100123
}
101124
}
@@ -144,21 +167,21 @@ public struct HomePage: Page {
144167
)
145168
}
146169
style(self.styling)
147-
script(.src("https://cdn.jsdelivr.net/npm/alpinejs@3.14.8/dist/cdn.min.js"))
148170
script(.src("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"))
149171
script(.src("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/swift.min.js"))
150172
script { HTMLRaw("hljs.highlightAll();") }
173+
VueScript()
151174
}
152175
body {
153-
header(.ariaLabel("About")) {
176+
header(.class("hero"), .ariaLabel("About")) {
154177
hgroup {
155-
h1 { "Erik Bautista Santibanez" }
156-
p { "Swift & Web Developer" }
178+
h1(.class("hero-title")) { "Erik Bautista Santibanez" }
179+
p(.class("hero-subtitle")) { "Swift & Web Developer" }
157180

158181
let location = self.activityClient.location()
159182
let residency = location?.residency ?? .default
160183

161-
p {
184+
p(.class("hero-location")) {
162185
span(.ariaLabel("Residency")) {
163186
svg(.xmlns(), .fill("currentColor"), .viewBox("0 0 256 256"), .class("svg-icon"), .ariaLabel("Map pin icon")) {
164187
path(
@@ -189,29 +212,37 @@ public struct HomePage: Page {
189212
}
190213
}
191214
}
192-
main(.x.data("{ selection: undefined }")) {
215+
main(.v.scope("{ selection: undefined }")) {
193216
header {
194-
ul(.class("post-tabs")) {
195-
for kind in Post.Kind?.allCases {
196-
let value = if let kind {
197-
"'\(kind.rawValue)'"
198-
} else {
199-
"undefined"
200-
}
201-
li {
202-
button(
203-
.x.on(.click, "selection = \(value)"),
204-
.x.bind("aria-current", "selection == \(value) && 'tab'")
205-
) {
206-
kind?.tabTitle ?? "All"
217+
hgroup {
218+
h2 { "Posts" }
219+
ul(.class("post-tabs")) {
220+
for kind in Post.Kind?.allCases {
221+
let value = if let kind {
222+
"'\(kind.rawValue)'"
223+
} else {
224+
"undefined"
225+
}
226+
li {
227+
button(
228+
.v.on(.click, "selection = \(value)"),
229+
.v.bind("aria-selected", "selection == \(value)"),
230+
.ariaSelected(kind == nil)
231+
) {
232+
kind?.tabTitle ?? "All"
233+
}
207234
}
208235
}
209236
}
210237
}
238+
// p { "Selected {{ selection }}" }
211239
}
212240
section {
213241
for post in Post.allCases {
214-
article(.class("post"), .x.show("!selection || selection == '\(post.kind.rawValue)'")) {
242+
article(
243+
.class("post"),
244+
.v.show("!selection || selection == '\(post.kind.rawValue)'")
245+
) {
215246
header { post.dateFormatted }
216247
h3(.class("post-title")) { post.title }
217248
div(.class("post-content")) {
@@ -235,94 +266,4 @@ public struct HomePage: Page {
235266
}
236267
}
237268
}
238-
}
239-
240-
struct Post {
241-
let slug: String
242-
var hero: Hero?
243-
let title: String
244-
let content: HTMLMarkdown
245-
let date: Date
246-
let kind: Kind
247-
var actionButtons: [LinkButton]?
248-
249-
private static let dateCreatedFormatter = {
250-
let formatter = DateFormatter()
251-
formatter.locale = Locale(languageCode: .english, languageRegion: .unitedStates)
252-
formatter.timeZone = TimeZone(abbreviation: "PST") ?? formatter.timeZone
253-
formatter.dateFormat = "MMM, d yyyy"
254-
return formatter
255-
}()
256-
257-
var dateFormatted: String {
258-
Self.dateCreatedFormatter.string(from: self.date).uppercased()
259-
}
260-
261-
enum Hero {
262-
case link(URL)
263-
case image(String)
264-
case video(String)
265-
case code(HTMLMarkdown)
266-
}
267-
268-
struct LinkButton {
269-
let title: String
270-
let link: String
271-
}
272-
273-
enum Kind: String, Hashable, CaseIterable {
274-
case project
275-
case education
276-
case experience
277-
278-
var tabTitle: String {
279-
switch self {
280-
case .project: "Projects"
281-
case .education: "Education"
282-
case .experience: "Experiences"
283-
}
284-
}
285-
}
286-
}
287-
288-
extension Post: CaseIterable {
289-
static var allCases: [Self] {
290-
[
291-
Self(
292-
slug: "swift-cascadia",
293-
title: "A Swift DSL for type-safe CSS",
294-
content: """
295-
Since I started building this website using Swift, I used [elementary](https://github.com/sliemeobn/elementary "link to Swift library") to build \
296-
HTML pages.
297-
298-
```swift
299-
func test() -> Int {
300-
print("Hey, there!")
301-
return 0
302-
}
303-
```
304-
""",
305-
date: Date(timeIntervalSince1970: 1_738_483_200), // Feb 2, 2025
306-
kind: .project
307-
),
308-
Self(
309-
slug: "anime-now",
310-
title: "Anime Now! \u{2014} An iOS and macOS App",
311-
content: """
312-
TBD
313-
""",
314-
date: Date(timeIntervalSince1970: 1_663_225_200), // Sep 15, 2025
315-
kind: .project
316-
),
317-
Self(
318-
slug: "prism-ui",
319-
title: "PrismUI \u{2014} Controlling MSI RGB Keyboard on mac",
320-
content: """
321-
TBD
322-
""",
323-
date: Date(timeIntervalSince1970: 1_663_225_200),
324-
kind: .project
325-
),
326-
]
327-
}
328-
}
269+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import Foundation
2+
3+
extension Post: CaseIterable {
4+
static var allCases: [Self] {
5+
[
6+
Self(
7+
slug: "swift-cascadia-released",
8+
title: "A Swift DSL for type-safe CSS",
9+
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+
date: Date(timeIntervalSince1970: 1_738_483_200), // Feb 2, 2025
14+
kind: .project
15+
),
16+
Self(
17+
slug: "mochi-released",
18+
title: "Mochi \u{2014} Content Viewer for iOS and macOS",
19+
content: """
20+
TBD
21+
""",
22+
date: Date(timeIntervalSince1970: 1_663_225_200), // Sep 15, 2025
23+
kind: .project
24+
),
25+
Self(
26+
slug: "anime-now-released",
27+
title: "Anime Now! \u{2014} An iOS and macOS App",
28+
content: """
29+
TBD
30+
""",
31+
date: Date(timeIntervalSince1970: 1_663_225_200), // Sep 15, 2025
32+
kind: .project
33+
),
34+
Self(
35+
slug: "prism-ui-released",
36+
title: "PrismUI \u{2014} Controlling MSI RGB Keyboard on mac",
37+
content: """
38+
TBD
39+
""",
40+
date: Date(timeIntervalSince1970: 1_663_225_200),
41+
kind: .project
42+
),
43+
]
44+
}
45+
}

Sources/Pages/Models/Post.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import Foundation
2+
3+
struct Post {
4+
let slug: String
5+
var hero: Hero?
6+
let title: String
7+
let content: HTMLMarkdown
8+
let date: Date
9+
let kind: Kind
10+
var actionButtons: [LinkButton]?
11+
12+
private static let dateCreatedFormatter = {
13+
let formatter = DateFormatter()
14+
formatter.locale = Locale(languageCode: .english, languageRegion: .unitedStates)
15+
formatter.timeZone = TimeZone(abbreviation: "PST") ?? formatter.timeZone
16+
formatter.dateFormat = "MMM, d yyyy"
17+
return formatter
18+
}()
19+
20+
var dateFormatted: String {
21+
Self.dateCreatedFormatter.string(from: self.date).uppercased()
22+
}
23+
24+
enum Hero {
25+
case link(String)
26+
case image(String)
27+
case video(String)
28+
case code(HTMLMarkdown)
29+
}
30+
31+
struct LinkButton {
32+
let title: String
33+
let link: String
34+
}
35+
36+
enum Kind: String, Hashable, CaseIterable {
37+
case project
38+
case education
39+
case experience
40+
41+
var tabTitle: String {
42+
switch self {
43+
case .project: "Projects"
44+
case .education: "Education"
45+
case .experience: "Experiences"
46+
}
47+
}
48+
}
49+
}

0 commit comments

Comments
 (0)