@@ -8,6 +8,11 @@ public enum ScriptAttribute: String {
8
8
case async
9
9
}
10
10
11
+ public struct Script {
12
+ let src : String
13
+ let attribute : ScriptAttribute ?
14
+ }
15
+
11
16
/// Represents an immutable HTML document with metadata and content.
12
17
public struct Document {
13
18
private let logger = Logger ( label: " com.webui.document " )
@@ -17,7 +22,7 @@ public struct Document {
17
22
public var stylesheets : [ String ] ?
18
23
public var theme : Theme ?
19
24
public let head : String ?
20
- private let contentBuilder : ( ) -> [ any HTML ]
25
+ public let contentBuilder : ( ) -> [ any HTML ]
21
26
22
27
/// Computed HTML content from the content builder.
23
28
var content : [ any HTML ] {
@@ -69,91 +74,39 @@ public struct Document {
69
74
logger. debug ( " Rendering document: \( path ?? " index " ) " )
70
75
logger. trace ( " Starting metadata rendering " )
71
76
72
- var optionalMetaTags : [ String ] = [ ]
73
- if let image = metadata. image, !image. isEmpty {
74
- logger. trace ( " Adding og:image meta tag: \( image) " )
75
- optionalMetaTags. append (
76
- " <meta property= \" og:image \" content= \" \( image) \" > "
77
- )
78
- }
79
- if let author = metadata. author, !author. isEmpty {
80
- logger. trace ( " Adding author meta tag: \( author) " )
81
- optionalMetaTags. append ( " <meta name= \" author \" content= \" \( author) \" > " )
82
- }
83
- if let twitter = metadata. twitter, !twitter. isEmpty {
84
- logger. trace ( " Adding twitter meta tag: \( twitter) " )
85
- optionalMetaTags. append (
86
- " <meta name= \" twitter:creator \" content= \" @ \( twitter) \" > "
87
- )
88
- }
89
- if let keywords = metadata. keywords, !keywords. isEmpty {
90
- logger. trace ( " Adding keywords meta tag with \( keywords. count) keywords " )
91
- optionalMetaTags. append (
92
- " <meta name= \" keywords \" content= \" \( keywords. joined ( separator: " , " ) ) \" > "
93
- )
94
- }
95
- if let themeColor = metadata. themeColor {
96
- logger. trace ( " Adding theme-color meta tags " )
97
- optionalMetaTags. append (
98
- " <meta name= \" theme-color \" content= \" \( themeColor. light) \" media= \" (prefers-color-scheme: light) \" > "
99
- )
100
- optionalMetaTags. append (
101
- " <meta name= \" theme-color \" content= \" \( themeColor. dark) \" media= \" (prefers-color-scheme: dark) \" > "
102
- )
103
- }
77
+ var optionalTags : [ String ] = metadata. tags + [ ]
104
78
if let scripts = scripts {
105
79
logger. trace ( " Adding \( scripts. count) script tags " )
106
80
for script in scripts {
107
- optionalMetaTags . append (
81
+ optionalTags . append (
108
82
" <script \( script. value? . rawValue ?? " " ) src= \" \( script. key) \" ></script> "
109
83
)
110
84
}
111
85
}
112
86
if let stylesheets = stylesheets {
113
87
logger. trace ( " Adding \( stylesheets. count) stylesheet links " )
114
88
for stylesheet in stylesheets {
115
- optionalMetaTags . append (
89
+ optionalTags . append (
116
90
" <link rel= \" stylesheet \" href= \" \( stylesheet) \" > "
117
91
)
118
92
}
119
93
}
120
94
121
- logger. trace ( " Building head section " )
122
- let headSection = """
95
+ logger. debug ( " Document rendered successfully: \( metadata. pageTitle) " )
96
+
97
+ return """
98
+ <!DOCTYPE html>
99
+ <html lang= " \( metadata. locale. rawValue) " >
123
100
<head>
124
101
<meta charset= " UTF-8 " >
125
102
<meta name= " viewport " content= " width=device-width, initial-scale=1.0 " >
126
103
<title> \( metadata. pageTitle) </title>
127
- <meta property= " og:title " content= " \( metadata. pageTitle) " >
128
- <meta name= " description " content= " \( metadata. description) " >
129
- <meta property= " og:description " content= " \( metadata. description) " >
130
- " <meta property= \" og:type \" content= \" \( metadata. type. rawValue) \" > "
131
- <meta name= " twitter:card " content= " summary_large_image " >
132
- \( optionalMetaTags. joined ( separator: " \n " ) )
104
+ \( optionalTags. joined ( separator: " \n " ) )
133
105
<script src= " https://unpkg.com/@tailwindcss/browser@4 " ></script>
134
- <style type= " text/tailwindcss " >
135
- @theme {
136
- --breakpoint-xs: 30rem;
137
- --breakpoint-3xl: 120rem;
138
- --breakpoint-4xl: 160rem;
139
- \( theme? . generateCSS ( ) ?? " " )
140
- @custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
141
- }
142
- </style>
143
106
\( head ?? " " )
144
- </head>
145
- """
146
-
147
- logger. trace ( " Rendering content elements " )
148
- let contentElements = content. map { $0. render ( ) } . joined ( )
149
- logger. debug ( " Document rendered successfully: \( metadata. pageTitle) " )
150
-
151
- return """
152
- <!DOCTYPE html>
153
- <html lang= " \( metadata. locale. rawValue) " >
154
- \( headSection)
107
+ </head>
155
108
<body>
156
- \( contentElements )
109
+ \( content . map { $0 . render ( ) } . joined ( ) )
157
110
</body>
158
111
</html>
159
112
"""
0 commit comments