11import ConcurrencyExtras
22import Dependencies
3- import Elementary
3+ import HTML
44import Hummingbird
5+ import Vue
56
6- public protocol Page : Sendable , HTML , ResponseGenerator {
7- associatedtype Head : HTML
8- associatedtype Body : HTML
9-
10- @HTMLBuilder var head : Head { get }
11- @HTMLBuilder var body : Body { get }
12-
7+ public protocol Page : Sendable , HTMLDocument , ResponseGenerator {
138 var title : String { get }
149 var lang : String { get }
1510
1611 var chunkSize : Int { get }
1712 var headers : HTTPFields { get }
1813}
1914
20- public extension Page {
21- var lang : String { " en " }
22- var chunkSize : Int { 1024 }
23- var headers : HTTPFields { [ . contentType: " text/html; charset=utf-8 " ] }
15+ extension Page {
16+ public var lang : String { " en " }
17+ public var chunkSize : Int { 1024 }
18+ public var headers : HTTPFields { [ . contentType: " text/html; charset=utf-8 " ] }
2419
25- @HTMLBuilder var content : some HTML {
20+ public static func _render< Output: HTMLByteStream > (
21+ _ document: consuming Self ,
22+ into output: inout Output
23+ ) {
2624 withDependencies {
27- $0. styleSheetGenerator = . liveValue
25+ $0. ssg = . class
2826 } operation: {
29- HTMLBuilder . builder {
30- @Dependency ( \. styleSheetGenerator) var generator
31-
32- let _ = generator. addElements {
33- Elementary . body {
34- self . body
35- VueScript ( )
27+ BaseLayout . _render (
28+ BaseLayout (
29+ head: HTMLGroup {
30+ meta ( . charset( . utf8) )
31+ tag ( " title " ) { document. title }
32+ meta ( . name( " viewport " ) , . content( " width=device-width, initial-scale=1.0 " ) )
33+ style { HTMLRaw ( " /*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize */*,::after,::before{box-sizing:border-box}html{font-family:system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji';line-height:1.15;-webkit-text-size-adjust:100%;tab-size:4}body{margin:0}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Consolas,'Liberation Mono',Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-color:currentcolor}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item} " ) }
34+ style {
35+ HTMLRaw (
36+ """
37+ @font-face {
38+ font-family: " CommitMono " ;
39+ src: url( " https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ecd81cdbd7f7eb2acaaa2f2f7e1a585676f9beff/src/fonts/fontlab/CommitMonoV143-VF.woff2 " );
40+ font-style: normal;
41+ font-weight: 400;
42+ font-display: swap;
43+ }
44+ html {
45+ line-height: 1.5;
46+ }
47+ pre a {
48+ text-decoration: none;
49+ }
50+ h1, h2, h3, h4, h5, figure, p, ol, ul, pre {
51+ margin: 0;
52+ }
53+ ol[role= " list " ], ul[role= " list " ] {
54+ list-style: none;
55+ padding-inline: 0;
56+ }
57+ img, video {
58+ display: block;
59+ max-inline-size: 100%;
60+ }
61+ code {
62+ font-family: " CommitMono " , monospace;
63+ font-feature-settings " , " ss03 " , " ss04 " , " ss05 " ;
64+ line-height: 1;
65+ }
66+ """
67+ )
3668 }
69+ /// Xcode Styling
70+ style { HTMLRaw ( " .xml .hljs-meta{color:#6C7986}.hljs-comment,.hljs-quote{color:#6C7986}.hljs-tag,.hljs-attribute,.hljs-keyword,.hljs-selector-tag,.hljs-literal,.hljs-name{color:#FC5FA3}.hljs-variable,.hljs-template-variable{color:#FC5FA3}.hljs-code,.hljs-string,.hljs-meta-string{color:#FC6A5D}.hljs-regexp,.hljs-link{color:#5482FF}.hljs-title,.hljs-symbol,.hljs-bullet,.hljs-number{color:#41A1C0}.hljs-section,.hljs-meta{color:#FC5FA3}.hljs-class .hljs-title,.hljs-type,.hljs-built_in,.hljs-builtin-name,.hljs-params{color:#D0A8FF}.hljs-attr{color:#BF8555}.hljs-subst{color:#FFF}.hljs-formula{font-style:italic}.hljs-selector-id,.hljs-selector-class{color:#9b703f}.hljs-doctag,.hljs-strong{font-weight:bold}.hljs-emphasis{font-style:italic} " ) }
71+ script ( . src( " https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js " ) , . defer) { }
72+ script ( . src( " https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/swift.min.js " ) , . defer) { }
73+ script ( . src( " https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/rust.min.js " ) , . defer) { }
74+ script ( . src( " https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/javascript.min.js " ) , . defer) { }
75+ script ( . src( " https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/typescript.min.js " ) , . defer) { }
76+ script ( . type( . module) ) { HTMLRaw ( " hljs.highlightAll(); " ) }
77+
78+ document. head
79+ } ,
80+ body: HTMLGroup {
81+ document. body
3782 . inlineStyle ( " background-color " , " #1c1c1c " )
3883 . inlineStyle ( " color " , " #fafafa " )
3984 . inlineStyle ( " font-optical-sizing " , " auto " )
4085 . inlineStyle ( " font-size " , " 0.7em " )
4186 . inlineStyle ( " font-size " , " 0.8em " , media: . minWidth( 390 ) )
4287 . inlineStyle ( " font-size " , " 0.9em " , media: . minWidth( 480 ) )
43- }
4488
45- HTMLRaw ( " <!DOCTYPE html> " )
46- html {
47- Elementary . head {
48- meta ( . charset( . utf8) )
49- Elementary . title { self . title }
50- meta ( name: . viewport, content: " width=device-width, initial-scale=1.0 " )
51- style { HTMLRaw ( " /*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize */*,::after,::before{box-sizing:border-box}html{font-family:system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji';line-height:1.15;-webkit-text-size-adjust:100%;tab-size:4}body{margin:0}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Consolas,'Liberation Mono',Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-color:currentcolor}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item} " ) }
52- style {
53- HTMLRaw (
54- """
55- @font-face {
56- font-family: " CommitMono " ;
57- src: url( " https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ecd81cdbd7f7eb2acaaa2f2f7e1a585676f9beff/src/fonts/fontlab/CommitMonoV143-VF.woff2 " );
58- font-style: normal;
59- font-weight: 400;
60- font-display: swap;
61- }
62- html {
63- line-height: 1.5;
64- }
65- pre a {
66- text-decoration: none;
67- }
68- h1, h2, h3, h4, h5, figure, p, ol, ul, pre {
69- margin: 0;
70- }
71- ol[role= " list " ], ul[role= " list " ] {
72- list-style: none;
73- padding-inline: 0;
74- }
75- img, video {
76- display: block;
77- max-inline-size: 100%;
78- }
79- code {
80- font-family: " CommitMono " , monospace;
81- font-feature-settings " , " ss03 " , " ss04 " , " ss05 " ;
82- line-height: 1;
83- }
84- """
85- )
86- }
87- /// Xcode Styling
88- style { HTMLRaw ( " .xml .hljs-meta{color:#6C7986}.hljs-comment,.hljs-quote{color:#6C7986}.hljs-tag,.hljs-attribute,.hljs-keyword,.hljs-selector-tag,.hljs-literal,.hljs-name{color:#FC5FA3}.hljs-variable,.hljs-template-variable{color:#FC5FA3}.hljs-code,.hljs-string,.hljs-meta-string{color:#FC6A5D}.hljs-regexp,.hljs-link{color:#5482FF}.hljs-title,.hljs-symbol,.hljs-bullet,.hljs-number{color:#41A1C0}.hljs-section,.hljs-meta{color:#FC5FA3}.hljs-class .hljs-title,.hljs-type,.hljs-built_in,.hljs-builtin-name,.hljs-params{color:#D0A8FF}.hljs-attr{color:#BF8555}.hljs-subst{color:#FFF}.hljs-formula{font-style:italic}.hljs-selector-id,.hljs-selector-class{color:#9b703f}.hljs-doctag,.hljs-strong{font-weight:bold}.hljs-emphasis{font-style:italic} " ) }
89- script ( . src( " https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js " ) , . defer)
90- script ( . src( " https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/swift.min.js " ) , . defer)
91- script ( . src( " https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/rust.min.js " ) , . defer)
92- script ( . src( " https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/javascript.min.js " ) , . defer)
93- script ( . src( " https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/typescript.min.js " ) , . defer)
94- script ( . type( . module) ) { HTMLRaw ( " hljs.highlightAll(); " ) }
95- style {
96- HTMLRaw ( generator. renderStyleSheet ( ) )
97- }
98- self . head
99- }
100-
101- HTMLRaw ( generator. renderedElements ( ) )
89+ VueScript ( )
10290 }
103- . attributes ( . lang( self . lang) )
104- }
91+ . attribute ( " lang " , value: document. lang)
92+ ) ,
93+ into: & output
94+ )
10595 }
10696 }
10797}
10898
109- private extension HTMLBuilder {
110- static func builder< R: HTML > ( @HTMLBuilder operation: ( ) -> R ) -> R {
111- operation ( )
112- }
113- }
99+ private struct BaseLayout < Head: HTML , Body: HTML > : HTMLDocument {
100+ var head : Head
101+ var body : Body
102+ }
0 commit comments