Skip to content

Commit e179006

Browse files
committed
wip: improve 404 error
1 parent 8c74dd5 commit e179006

File tree

8 files changed

+154
-125
lines changed

8 files changed

+154
-125
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import Elementary
2+
import Foundation
3+
4+
struct FooterView: HTML {
5+
private static let copyrightDateFormatter = {
6+
let formatter = DateFormatter()
7+
formatter.locale = Locale(languageCode: .english, languageRegion: .unitedStates)
8+
formatter.timeZone = TimeZone(abbreviation: "PST") ?? formatter.timeZone
9+
formatter.dateFormat = "yyyy"
10+
return formatter
11+
}()
12+
13+
var content: some HTML {
14+
footer {
15+
div {
16+
p { "©\(Self.copyrightDateFormatter.string(from: Date.now)) Erik Bautista Santibanez" }
17+
p {
18+
"Made with \u{2764} using "
19+
a(.target(.blank), .rel("noopener noreferrer"), .href("https://swift.org")) { "Swift" }
20+
" + "
21+
a(.target(.blank), .rel("noopener noreferrer"), .href("https://hummingbird.codes")) { "Hummingbird" }
22+
"."
23+
}
24+
}
25+
.inlineStyle("padding", "1rem 1.5rem")
26+
.containerStyling()
27+
}
28+
.inlineStyle("text-align", "center")
29+
.wrappedStyling()
30+
}
31+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Elementary
2+
3+
struct HeaderView: HTML {
4+
var content: some HTML {
5+
EmptyHTML()
6+
}
7+
}

Sources/Pages/Components/Page.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ public extension Page {
2424

2525
@HTMLBuilder var content: some HTML {
2626
withDependencies {
27-
$0.styleSheetGenerator = StyleSheetGenerator()
27+
$0.styleSheetGenerator = .liveValue
2828
} operation: {
2929
HTMLBuilder.builder {
3030
@Dependency(\.styleSheetGenerator) var generator
31+
3132
let _ = generator.addElements {
3233
Elementary.body {
3334
self.body

Sources/Pages/Components/Spacer.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import Elementary
2+
3+
struct Spacer: HTML {
4+
var content: some HTML {
5+
div {
6+
div {}
7+
.inlineStyle("height", "0.85rem")
8+
.inlineStyle("background", "repeating-linear-gradient(45deg, transparent 0% 35%, #333 35% 50%, transparent 50% 85%, #333 85% 100%)")
9+
.inlineStyle("background-size", "5px 5px")
10+
.containerStyling()
11+
}
12+
.wrappedStyling()
13+
}
14+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import Elementary
2+
3+
extension HTML where Tag: HTMLTrait.Attributes.Global {
4+
func wrappedStyling() -> _HTMLInlineStyle<Self> {
5+
self.inlineStyle("border-top", "1px solid #303030")
6+
}
7+
8+
func containerStyling() -> _HTMLInlineStyle<Self> {
9+
self.inlineStyle("max-width", "40rem", media: .minWidth(688))
10+
.inlineStyle("margin-right", "auto")
11+
.inlineStyle("margin-left", "auto")
12+
.inlineStyle("border-left", "1px solid #303030", media: .minWidth(640))
13+
.inlineStyle("border-right", "1px solid #303030", media: .minWidth(640))
14+
}
15+
}

Sources/Pages/HomePage.swift

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -27,41 +27,6 @@ public struct HomePage: Page {
2727
}
2828
.inlineStyle("overflow-x", "hidden")
2929
}
30-
31-
struct HeaderView: HTML {
32-
var content: some HTML {
33-
EmptyHTML()
34-
}
35-
}
36-
37-
struct FooterView: HTML {
38-
private static let copyrightDateFormatter = {
39-
let formatter = DateFormatter()
40-
formatter.locale = Locale(languageCode: .english, languageRegion: .unitedStates)
41-
formatter.timeZone = TimeZone(abbreviation: "PST") ?? formatter.timeZone
42-
formatter.dateFormat = "yyyy"
43-
return formatter
44-
}()
45-
46-
var content: some HTML {
47-
footer {
48-
div {
49-
p { "©\(Self.copyrightDateFormatter.string(from: Date.now)) Erik Bautista Santibanez" }
50-
p {
51-
"Made with \u{2764} using "
52-
a(.target(.blank), .rel("noopener noreferrer"), .href("https://swift.org")) { "Swift" }
53-
" + "
54-
a(.target(.blank), .rel("noopener noreferrer"), .href("https://hummingbird.codes")) { "Hummingbird" }
55-
"."
56-
}
57-
}
58-
.inlineStyle("padding", "1rem 1.5rem")
59-
.containerStyling()
60-
}
61-
.inlineStyle("text-align", "center")
62-
.wrappedStyling()
63-
}
64-
}
6530
}
6631

6732
private struct SectionView<Body: HTML>: HTML {
@@ -132,19 +97,6 @@ private struct SectionView<Body: HTML>: HTML {
13297
}
13398
}
13499

135-
private struct Spacer: HTML {
136-
var content: some HTML {
137-
div {
138-
div {}
139-
.inlineStyle("height", "0.85rem")
140-
.inlineStyle("background", "repeating-linear-gradient(45deg, transparent 0% 35%, #333 35% 50%, transparent 50% 85%, #333 85% 100%)")
141-
.inlineStyle("background-size", "5px 5px")
142-
.containerStyling()
143-
}
144-
.wrappedStyling()
145-
}
146-
}
147-
148100
private struct UserView: HTML {
149101
@Dependency(\.activityClient) private var activityClient
150102

@@ -375,18 +327,6 @@ private struct PostsView: HTML {
375327
}
376328

377329
private extension HTML where Tag: HTMLTrait.Attributes.Global {
378-
func wrappedStyling() -> _HTMLInlineStyle<Self> {
379-
self.inlineStyle("border-top", "1px solid #303030")
380-
}
381-
382-
func containerStyling() -> _HTMLInlineStyle<Self> {
383-
self.inlineStyle("max-width", "40rem")
384-
.inlineStyle("margin-right", "auto")
385-
.inlineStyle("margin-left", "auto")
386-
.inlineStyle("border-left", "1px solid #303030")
387-
.inlineStyle("border-right", "1px solid #303030")
388-
}
389-
390330
func svgIconStyling() -> _HTMLInlineStyle<Self> {
391331
self.inlineStyle("display", "inline-block")
392332
.inlineStyle("vertical-align", "middle")

Sources/Pages/NotFoundPage.swift

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Elementary
22

33
public struct NotFoundPage: Page {
4-
public let title = "Erik Bautista Santibanez | Portfolio"
4+
public let title = "Erik Bautista Santibanez | Not Found"
55
public let lang = "en"
66

77
public init() {}
@@ -12,7 +12,35 @@ public struct NotFoundPage: Page {
1212

1313
public var body: some HTML {
1414
div {
15-
15+
HeaderView()
16+
Spacer()
17+
main {
18+
section {
19+
div {
20+
div {
21+
h2 { "404 Error | Page Not Found" }
22+
.inlineStyle("margin-bottom", "0.5rem")
23+
pre {
24+
code(.class("hljs language-swift")) {
25+
"""
26+
throw Error.pageNotFound
27+
"""
28+
}
29+
}
30+
}
31+
}
32+
.containerStyling()
33+
.inlineStyle("display", "flex")
34+
.inlineStyle("flex-direction", "column")
35+
.inlineStyle("justify-content", "center")
36+
.inlineStyle("align-items", "center")
37+
.inlineStyle("padding", "120px 16px")
38+
.inlineStyle("gap", "1.5rem")
39+
}
40+
.wrappedStyling()
41+
}
42+
Spacer()
43+
FooterView()
1644
}
1745
}
18-
}
46+
}

Sources/Pages/Utils/Elementary+InlineStyle.swift

Lines changed: 54 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -137,87 +137,80 @@ extension HTML where Tag: HTMLTrait.Attributes.Global {
137137
}
138138
}
139139

140-
struct StyleSheetGenerator: Sendable {
141-
private struct Storage {
142-
var styles = OrderedSet<InlineStyle>()
143-
var rulesets = OrderedDictionary<InlineStyle.MediaQuery?, OrderedDictionary<String, String>>()
144-
var render: _SendableAnyHTMLBox?
145-
var rendered: String?
146-
}
140+
struct StyleSheetGenerator: Sendable, DependencyKey {
141+
let generateClassName: @Sendable (InlineStyle) -> String
142+
let renderStyleSheet: @Sendable () -> String
143+
let addElements: @Sendable (@Sendable () -> any HTML) -> Void
144+
let renderedElements: @Sendable () -> String
145+
146+
static var liveValue: StyleSheetGenerator {
147+
struct Storage {
148+
var styles = OrderedSet<InlineStyle>()
149+
var rulesets = OrderedDictionary<InlineStyle.MediaQuery?, OrderedDictionary<String, String>>()
150+
var render: _SendableAnyHTMLBox?
151+
var rendered: String?
152+
}
147153

148-
private let storage = LockIsolated(Storage())
154+
let storage = LockIsolated(Storage())
149155

150-
@Sendable
151-
fileprivate func generateClassName(_ style: InlineStyle) -> String {
152-
self.storage.withValue { `self` in
153-
let index = self.styles.firstIndex(of: style) ?? self.styles.append(style).index
154-
#if DEBUG
155-
let className = "\(style.property)-\(index)"
156-
#else
157-
let className = "c\(index)"
158-
#endif
156+
return StyleSheetGenerator { style in
157+
storage.withValue { `self` in
158+
let index = self.styles.firstIndex(of: style) ?? self.styles.append(style).index
159+
#if DEBUG
160+
let className = "\(style.property)-\(index)"
161+
#else
162+
let className = "c\(index)"
163+
#endif
159164

160-
let selector = "\(style.pre.flatMap { $0 + " " } ?? "").\(className)\(style.pseudo?.rawValue ?? "")\(style.post.flatMap { " " + $0 } ?? "")"
165+
let selector = "\(style.pre.flatMap { $0 + " " } ?? "").\(className)\(style.pseudo?.rawValue ?? "")\(style.post.flatMap { " " + $0 } ?? "")"
161166

162-
if self.rulesets[style.media, default: [:]][selector] == nil {
163-
self.rulesets[style.media, default: [:]][selector] = "\(style.property):\(style.value);"
164-
}
167+
if self.rulesets[style.media, default: [:]][selector] == nil {
168+
self.rulesets[style.media, default: [:]][selector] = "\(style.property):\(style.value);"
169+
}
165170

166-
return className
167-
}
168-
}
171+
return className
172+
}
173+
} renderStyleSheet: {
174+
guard let rendered = storage.render?.tryTake()?.render() else {
175+
return ""
176+
}
169177

170-
@Sendable
171-
func renderStyleSheet() -> String {
172-
guard let rendered = storage.render?.tryTake()?.render() else {
173-
return ""
174-
}
178+
storage.withValue { $0.rendered = rendered }
175179

176-
self.storage.withValue { $0.rendered = rendered }
180+
var sheet = ""
181+
for (mediaQuery, styles) in storage.rulesets.sorted(by: { $0.key == nil ? $1.key != nil : false }) {
182+
if let mediaQuery {
183+
sheet.append("@media \(mediaQuery.rawValue){")
184+
}
177185

178-
var sheet = ""
179-
for (mediaQuery, styles) in storage.rulesets.sorted(by: { $0.key == nil ? $1.key != nil : false }) {
180-
if let mediaQuery {
181-
sheet.append("@media \(mediaQuery.rawValue){")
182-
}
186+
defer {
187+
if mediaQuery != nil {
188+
sheet.append("}")
189+
}
190+
}
183191

184-
defer {
185-
if mediaQuery != nil {
186-
sheet.append("}")
192+
for (className, style) in styles {
193+
sheet.append("\(className){\(style)}")
194+
}
187195
}
196+
return sheet
197+
} addElements: { html in
198+
storage.withValue { `self` in
199+
self.render = _SendableAnyHTMLBox(html())
188200
}
189-
190-
for (className, style) in styles {
191-
sheet.append("\(className){\(style)}")
192-
}
193-
}
194-
return sheet
195-
}
196-
197-
func addElements(@HTMLBuilder _ html: @Sendable () -> some HTML) {
198-
self.storage.withValue { `self` in
199-
self.render = _SendableAnyHTMLBox(html())
200-
}
201-
}
202-
203-
func renderedElements() -> String {
204-
self.storage.withValue { `self` in
205-
self.rendered ?? ""
201+
} renderedElements: {
202+
storage.rendered ?? ""
206203
}
207204
}
208205
}
209206

210207
extension DependencyValues {
211208
var styleSheetGenerator: StyleSheetGenerator {
212-
get { self[StyleSheetGeneratorKey.self] }
213-
set { self[StyleSheetGeneratorKey.self] = newValue }
209+
get { self[StyleSheetGenerator.self] }
210+
set { self[StyleSheetGenerator.self] = newValue }
214211
}
215212
}
216213

217-
private enum StyleSheetGeneratorKey: DependencyKey {
218-
static var liveValue: StyleSheetGenerator { StyleSheetGenerator() }
219-
}
220-
221214
struct InlineStyle: Sendable, Hashable {
222215
let property: String
223216
let value: String

0 commit comments

Comments
 (0)