Skip to content

Commit 1677efa

Browse files
committed
fix: allow changing languages based on expression variable
1 parent a99f95b commit 1677efa

File tree

9 files changed

+136
-104
lines changed

9 files changed

+136
-104
lines changed

Package.resolved

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ let package = Package(
99
],
1010
dependencies: [
1111
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.4.0"),
12-
.package(url: "https://github.com/erikbdev/swift-web.git", exact: "0.0.15"),
12+
.package(url: "https://github.com/erikbdev/swift-web.git", exact: "0.0.17"),
1313
.package(url: "https://github.com/hummingbird-project/hummingbird.git", exact: "2.5.0"),
1414
.package(url: "https://github.com/pointfreeco/swift-case-paths.git", from: "1.0.0"),
1515
.package(url: "https://github.com/pointfreeco/swift-url-routing.git", from: "0.6.2"),

Sources/App/Middlewares/SiteMiddleware.swift

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import ActivityClient
22
import Dependencies
3-
import class Foundation.JSONEncoder
43
import Hummingbird
54
import HummingbirdRouter
65
import HummingbirdURLRouting
@@ -9,6 +8,8 @@ import Pages
98
import PublicAssets
109
import Routes
1110

11+
import class Foundation.JSONEncoder
12+
1213
struct SiteMiddleware<Context: RequestContext>: RouterController {
1314
@Dependency(\.siteRouter) private var siteRouter
1415
@Dependency(\.activityClient) private var activityClient
@@ -31,13 +32,12 @@ struct SiteMiddleware<Context: RequestContext>: RouterController {
3132
URLRoutingMiddleware(self.siteRouter) { req, ctx, route in
3233
try withDependencies {
3334
$0.currentRoute = route
34-
$0.currentCodeLang = .swift
3535
} operation: {
3636
switch route {
3737
case .robots:
3838
return ""
3939
case .home:
40-
return HomePage()
40+
return HomePage(codeLang: .resolve(req))
4141
case .api(.activity(.all)):
4242
do {
4343
return try JSONEncoder().encode(self.activityClient.activity(), from: req, context: ctx)
@@ -77,8 +77,16 @@ private struct NotFoundMiddleware<Context: RequestContext>: RouterMiddleware {
7777
throw error
7878
}
7979

80-
return try NotFoundPage()
80+
return try NotFoundPage(codeLang: .resolve(input))
8181
.response(from: input, context: context, status: .notFound)
8282
}
8383
}
8484
}
85+
86+
fileprivate extension CodeLang {
87+
static func resolve(_ req: Request) -> CodeLang {
88+
req.uri.queryParameters["codeLang"]
89+
.flatMap { CodeLang(rawValue: $0.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()) }
90+
?? .swift
91+
}
92+
}

Sources/Pages/Components/HeaderView.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import HTML
44
import Vue
55

66
struct HeaderView: HTML {
7-
let selected: Vue.Expression
7+
let selected: Vue.Expression<CodeLang>
88

99
var body: some HTML {
1010
header {
@@ -31,10 +31,10 @@ struct HeaderView: HTML {
3131
}
3232

3333
private struct CodeSelector: HTML {
34-
let selected: Vue.Expression
34+
let selected: Vue.Expression<CodeLang>
3535

3636
var body: some HTML {
37-
#VueScope(false) { (visible: Vue.Expression) in
37+
#VueScope(false) { visible in
3838
button(
3939
.v.on(.click, visible.assign(!visible)),
4040
.v.bind(attrOrProp: "style", Expression(rawValue: "\(visible) ? { background: '#8A8A8A', color: '#080808' } : null"))
@@ -56,8 +56,7 @@ private struct CodeSelector: HTML {
5656
button(
5757
.v.on(.click, selected.assign(Expression(code))),
5858
.v.on(.click, modifiers: .prevent, visible.assign(!visible)),
59-
.v.bind(attrOrProp: "style", Expression(rawValue: "{ background: \(selected) == \(Expression(code)) ? '#3A3A3A' : undefined }")),
60-
.style("border-radius: 0.75rem")
59+
.v.bind(attrOrProp: "style", Expression(rawValue: "{ background: \(selected) == \(Expression(code)) ? '#3A3A3A' : undefined }"))
6160
) {
6261
p {
6362
code.title
@@ -69,6 +68,8 @@ private struct CodeSelector: HTML {
6968
.inlineStyle("display", "block")
7069
.inlineStyle("width", "100%")
7170
.inlineStyle("cursor", "pointer")
71+
.inlineStyle("border-radius", "0.75rem")
72+
.inlineStyle("background", "#4A4A4A", post: ":hover")
7273
}
7374
.inlineStyle("overflow", "hidden")
7475
}

Sources/Pages/Components/Page.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ extension Page {
2222
into output: inout Output
2323
) {
2424
withDependencies {
25-
$0.ssg = .class
25+
$0.ssg = .groupedStyles
2626
} operation: {
2727
BaseLayout._render(
2828
BaseLayout(

Sources/Pages/Components/SectionView.swift

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,24 @@
11
import HTML
22
import Models
33
import Dependencies
4+
import Vue
45

56
struct SectionView<Content: HTML>: HTML {
6-
@Dependency(\.currentCodeLang) var currentCodeLang
7-
87
let id: String
8+
let selectedCodeLang: Vue.Expression<CodeLang>
99
let codeHeader: @Sendable (CodeLang) -> String
1010
@HTMLBuilder let content: @Sendable () -> Content
1111

1212
var body: some HTML {
13-
let allCodeLangs = CodeLang.allCases.sorted(initial: currentCodeLang)
1413
section(.id(self.id)) {
1514
div {
1615
header {
1716
pre {
1817
a(.href("#\(self.id)")) {
19-
for (idx, lang) in allCodeLangs.enumerated() {
18+
CodeLang.conditionalCases(initial: selectedCodeLang) { lang in
2019
code {
2120
slugToFileName(lang)
2221
}
23-
.attribute("v-cloak", value: idx == allCodeLangs.startIndex ? nil : "")
24-
.attribute("v-if", value: idx == allCodeLangs.startIndex ? "selected == '\(lang.rawValue)'" : nil)
25-
.attribute("v-else-if", value: allCodeLangs.startIndex < idx && idx < allCodeLangs.index(before: allCodeLangs.endIndex) ? "selected == '\(lang.rawValue)'" : nil)
26-
.attribute("v-else", value: idx == allCodeLangs.index(before: allCodeLangs.endIndex) ? "" : nil)
2722
}
2823
}
2924
.inlineStyle("color", "#777")
@@ -34,24 +29,18 @@ struct SectionView<Content: HTML>: HTML {
3429
.inlineStyle("padding", "1.5rem 1.5rem 0")
3530

3631
pre {
37-
for (idx, lang) in allCodeLangs.enumerated() {
32+
CodeLang.conditionalCases(initial: selectedCodeLang) { lang in
3833
code(.class("hljs language-\(lang.rawValue)")) {
3934
"""
4035
// \(slugToFileName(lang))
4136
// Portfolio
4237
\(codeHeader(lang))
4338
"""
4439
}
45-
.attribute("v-cloak", value: idx == allCodeLangs.startIndex ? nil : "")
46-
.attribute("v-if", value: idx == allCodeLangs.startIndex ? "selected == '\(lang.rawValue)'" : nil)
47-
.attribute("v-else-if", value: allCodeLangs.startIndex < idx && idx < allCodeLangs.index(before: allCodeLangs.endIndex) ? "selected == '\(lang.rawValue)'" : nil)
48-
.attribute("v-else", value: idx == allCodeLangs.index(before: allCodeLangs.endIndex) ? "" : nil)
4940
}
5041
}
5142
.inlineStyle("padding", "0.75rem 1.5rem 1.5rem")
5243
}
53-
// .inlineStyle("background-image", "radial-gradient(#2A2A2A 1px, transparent 0)")
54-
// .inlineStyle("background-size", "12px 12px")
5544

5645
self.content()
5746
}

Sources/Pages/HomePage.swift

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,28 @@ import HTML
55
import Models
66
import Vue
77

8-
public struct HomePage: Page {
8+
public struct HomePage: Page {
99
public let title = "Erik Bautista Santibanez | Portfolio"
1010
public let lang = "en"
1111

12-
public init() {}
12+
let initialCodeLang: CodeLang
13+
14+
public init(codeLang: CodeLang = .swift) {
15+
self.initialCodeLang = codeLang
16+
}
1317

1418
public var head: some HTML { EmptyHTML() }
1519

1620
public var body: some HTML {
17-
#VueScope(CodeLang.swift) { (selected: Vue.Expression) in
18-
HeaderView(selected: selected)
19-
Spacer()
21+
#VueScope(initialCodeLang) { codeLang in
22+
HeaderView(selected: codeLang)
2023
main {
21-
UserView()
2224
Spacer()
23-
PostsView()
25+
UserView(selected: codeLang)
26+
Spacer()
27+
PostsView(selected: codeLang)
28+
Spacer()
2429
}
25-
Spacer()
2630
FooterView()
2731
}
2832
.inlineStyle("overflow-x", "hidden")
@@ -32,6 +36,8 @@ public struct HomePage: Page {
3236
private struct UserView: HTML {
3337
@Dependency(\.activityClient) private var activityClient
3438

39+
let selected: Vue.Expression<CodeLang>
40+
3541
var location: ActivityClient.Location? {
3642
self.activityClient.location()
3743
}
@@ -52,7 +58,7 @@ private struct UserView: HTML {
5258

5359
@HTMLBuilder
5460
var body: some HTML {
55-
SectionView(id: "user") { lang in
61+
SectionView(id: "user", selectedCodeLang: selected) { lang in
5662
switch lang {
5763
case .swift:
5864
"""
@@ -103,8 +109,9 @@ private struct UserView: HTML {
103109
}
104110

105111
private struct PostsView: HTML {
112+
let selected: Vue.Expression<CodeLang>
106113
var body: some HTML {
107-
SectionView(id: "dev-logs") { lang in
114+
SectionView(id: "dev-logs", selectedCodeLang: selected) { lang in
108115
switch lang {
109116
case .swift:
110117
"""
@@ -168,15 +175,15 @@ private struct PostsView: HTML {
168175
section {
169176
self.post.content
170177
}
171-
.inlineStyle("margin", "revert", post: "*")
172-
.inlineStyle("display", "block", post: "blockquote")
173-
.inlineStyle("background", "#2A2A2A", post: "blockquote")
174-
.inlineStyle("padding", "0.125rem 1rem", post: "blockquote")
175-
.inlineStyle("border", "1.5px solid #4A4A4A", post: "blockquote")
176-
.inlineStyle("border-radius", "0.125rem", post: "blockquote")
177-
.inlineStyle("margin-left", "0", post: "blockquote")
178-
.inlineStyle("margin-right", "0", post: "blockquote")
179178
.postCodeBlockStyling()
179+
.inlineStyle("margin", "revert", post: " *")
180+
.inlineStyle("display", "block", post: " blockquote")
181+
.inlineStyle("background", "#2A2A2A", post: " blockquote")
182+
.inlineStyle("padding", "0.125rem 1rem", post: " blockquote")
183+
.inlineStyle("border", "1.5px solid #4A4A4A", post: " blockquote")
184+
.inlineStyle("border-radius", "0.125rem", post: " blockquote")
185+
.inlineStyle("margin-left", "0", post: " blockquote")
186+
.inlineStyle("margin-right", "0", post: " blockquote")
180187

181188
if !self.post.links.isEmpty {
182189
section {
@@ -235,11 +242,11 @@ private struct PostsView: HTML {
235242
}
236243
}
237244
}
238-
.inlineStyle("width", "100%", post: "> *")
239-
.inlineStyle("margin-top", "1.25rem", post: "> *")
240-
.inlineStyle("margin-bottom", "1.25rem", post: "> *")
241-
.inlineStyle("border", "1.5px solid #3A3A3A", post: "> *")
242-
.inlineStyle("border-radius", "1rem", post: "> *")
245+
.inlineStyle("width", "100%", post: " > *")
246+
.inlineStyle("margin-top", "1.25rem", post: " > *")
247+
.inlineStyle("margin-bottom", "1.25rem", post: " > *")
248+
.inlineStyle("border", "1.5px solid #3A3A3A", post: " > *")
249+
.inlineStyle("border-radius", "1rem", post: " > *")
243250
.postCodeBlockStyling()
244251
}
245252
}
@@ -298,11 +305,11 @@ private extension HTML {
298305
}
299306

300307
func postCodeBlockStyling() -> HTMLInlineStyle<Self> {
301-
self.inlineStyle("padding", "0.75rem", post: "pre")
302-
.inlineStyle("background", "#242424", post: "pre")
303-
.inlineStyle("border", "1.5px solid #3A3A3A", post: "pre")
304-
.inlineStyle("border-radius", "0.75rem", post: "pre")
305-
.inlineStyle("overflow-x", "auto", post: "pre")
306-
.inlineStyle("font-size", "0.85em", post: "pre")
308+
self.inlineStyle("padding", "0.75rem", post: " pre")
309+
.inlineStyle("background", "#242424", post: " pre")
310+
.inlineStyle("border", "1.5px solid #3A3A3A", post: " pre")
311+
.inlineStyle("border-radius", "0.75rem", post: " pre")
312+
.inlineStyle("overflow-x", "auto", post: " pre")
313+
.inlineStyle("font-size", "0.85em", post: " pre")
307314
}
308315
}

Sources/Pages/Models/CodeLang.swift

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
import Dependencies
2+
import HTML
3+
import Vue
24

3-
public enum CodeLang: String, Hashable, Encodable, CaseIterable, Sendable {
5+
public enum CodeLang: String, Hashable, Encodable, CaseIterable, Sendable, RawRepresentable {
46
case swift
57
case rust
68
case typescript
79

10+
public init?(rawValue: String) {
11+
if let value = Self.allCases.first(where: { $0.rawValue == rawValue }) {
12+
self = value
13+
} else {
14+
return nil
15+
}
16+
}
17+
818
public var title: String {
919
switch self {
1020
case .swift: "Swift"
@@ -20,15 +30,32 @@ public enum CodeLang: String, Hashable, Encodable, CaseIterable, Sendable {
2030
case .typescript: "ts"
2131
}
2232
}
23-
}
2433

25-
private enum CurrentCodeLang: TestDependencyKey {
26-
static let testValue = CodeLang.swift
27-
}
28-
29-
extension DependencyValues {
30-
public var currentCodeLang: CodeLang {
31-
get { self[CurrentCodeLang.self] }
32-
set { self[CurrentCodeLang.self] = newValue }
34+
@HTMLBuilder static func conditionalCases<Content: HTML>(
35+
initial selected: Vue.Expression<CodeLang>,
36+
@HTMLBuilder content: (CodeLang) -> Content
37+
) -> some HTML {
38+
let allCodeLangs = [selected.initialValue] + Self.allCases.filter { $0 != selected.initialValue }
39+
for (idx, lang) in allCodeLangs.enumerated() {
40+
content(lang)
41+
.attribute(
42+
"v-cloak",
43+
value: idx == allCodeLangs.startIndex ? nil : ""
44+
)
45+
.attribute(
46+
"v-if",
47+
value: idx == allCodeLangs.startIndex ? (selected == Expression(lang)).rawValue : nil
48+
)
49+
.attribute(
50+
"v-else-if",
51+
value: allCodeLangs.startIndex < idx
52+
&& idx < allCodeLangs.index(before: allCodeLangs.endIndex)
53+
? (selected == Expression(lang)).rawValue : nil
54+
)
55+
.attribute(
56+
"v-else",
57+
value: idx == allCodeLangs.index(before: allCodeLangs.endIndex) ? "" : nil
58+
)
59+
}
3360
}
3461
}

0 commit comments

Comments
 (0)