void-plugin-hono-jsx 0.1.0-rc.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +29 -23
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/dist/plugins/hono-islands.d.ts.map +1 -1
- package/dist/plugins/hono-islands.js +11 -3
- package/dist/plugins/hono-islands.js.map +1 -1
- package/dist/plugins/hono-markdown.d.ts +3 -1
- package/dist/plugins/hono-markdown.d.ts.map +1 -1
- package/dist/plugins/hono-markdown.js +13 -6
- package/dist/plugins/hono-markdown.js.map +1 -1
- package/dist/plugins/markdown-compiler.d.ts +65 -2
- package/dist/plugins/markdown-compiler.d.ts.map +1 -1
- package/dist/plugins/markdown-compiler.js +54 -40
- package/dist/plugins/markdown-compiler.js.map +1 -1
- package/dist/plugins/markdown-copy.d.ts +3 -0
- package/dist/plugins/markdown-copy.d.ts.map +1 -0
- package/dist/plugins/markdown-copy.js +31 -0
- package/dist/plugins/markdown-copy.js.map +1 -0
- package/dist/plugins/markdown-features.d.ts +12 -0
- package/dist/plugins/markdown-features.d.ts.map +1 -0
- package/dist/plugins/markdown-features.js +56 -0
- package/dist/plugins/markdown-features.js.map +1 -0
- package/dist/theme/code.css +202 -0
- package/dist/theme/containers.css +125 -0
- package/dist/theme/content.css +4 -0
- package/dist/theme/index.css +7 -0
- package/dist/theme/prose.css +294 -0
- package/dist/theme/reset.css +100 -0
- package/package.json +20 -2
- package/src/plugins/hono-islands.ts +11 -3
- package/src/plugins/hono-markdown.ts +15 -8
- package/src/plugins/markdown-compiler.ts +46 -30
- package/src/plugins/markdown-copy.ts +30 -0
- package/src/plugins/markdown-features.ts +57 -0
- package/src/theme/code.css +202 -0
- package/src/theme/containers.css +125 -0
- package/src/theme/content.css +4 -0
- package/src/theme/index.css +7 -0
- package/src/theme/prose.css +294 -0
- package/src/theme/reset.css +100 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/* Void Markdown — Containers & GitHub Alerts */
|
|
2
|
+
|
|
3
|
+
.void-md .custom-block {
|
|
4
|
+
margin: 1em 0;
|
|
5
|
+
padding: 1em 1.25em;
|
|
6
|
+
border-radius: 8px;
|
|
7
|
+
border-left: 4px solid;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.void-md .custom-block-title {
|
|
11
|
+
font-weight: 600;
|
|
12
|
+
margin-bottom: 0.5em;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.void-md .custom-block > :last-child {
|
|
16
|
+
margin-bottom: 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Tip */
|
|
20
|
+
.void-md .tip {
|
|
21
|
+
border-color: #10b981;
|
|
22
|
+
background: rgba(16, 185, 129, 0.08);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.void-md .tip .custom-block-title {
|
|
26
|
+
color: #10b981;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Info / Note */
|
|
30
|
+
.void-md .info,
|
|
31
|
+
.void-md .note {
|
|
32
|
+
border-color: #3b82f6;
|
|
33
|
+
background: rgba(59, 130, 246, 0.08);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.void-md .info .custom-block-title,
|
|
37
|
+
.void-md .note .custom-block-title {
|
|
38
|
+
color: #3b82f6;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Warning / Important */
|
|
42
|
+
.void-md .warning,
|
|
43
|
+
.void-md .important {
|
|
44
|
+
border-color: #eab308;
|
|
45
|
+
background: rgba(234, 179, 8, 0.08);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.void-md .warning .custom-block-title,
|
|
49
|
+
.void-md .important .custom-block-title {
|
|
50
|
+
color: #ca8a04;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Danger / Caution */
|
|
54
|
+
.void-md .danger,
|
|
55
|
+
.void-md .caution {
|
|
56
|
+
border-color: #ef4444;
|
|
57
|
+
background: rgba(239, 68, 68, 0.08);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.void-md .danger .custom-block-title,
|
|
61
|
+
.void-md .caution .custom-block-title {
|
|
62
|
+
color: #ef4444;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Details (collapsible) */
|
|
66
|
+
.void-md details.custom-block {
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.void-md details.custom-block summary {
|
|
71
|
+
font-weight: 600;
|
|
72
|
+
cursor: pointer;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.void-md details.custom-block[open] summary {
|
|
76
|
+
margin-bottom: 0.5em;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* Dark mode adjustments */
|
|
80
|
+
@media (prefers-color-scheme: dark) {
|
|
81
|
+
:root:not([data-theme='light']) .void-md .tip {
|
|
82
|
+
background: rgba(16, 185, 129, 0.12);
|
|
83
|
+
}
|
|
84
|
+
:root:not([data-theme='light']) .void-md .info,
|
|
85
|
+
:root:not([data-theme='light']) .void-md .note {
|
|
86
|
+
background: rgba(59, 130, 246, 0.12);
|
|
87
|
+
}
|
|
88
|
+
:root:not([data-theme='light']) .void-md .warning,
|
|
89
|
+
:root:not([data-theme='light']) .void-md .important {
|
|
90
|
+
background: rgba(234, 179, 8, 0.12);
|
|
91
|
+
}
|
|
92
|
+
:root:not([data-theme='light']) .void-md .warning .custom-block-title,
|
|
93
|
+
:root:not([data-theme='light']) .void-md .important .custom-block-title {
|
|
94
|
+
color: #eab308;
|
|
95
|
+
}
|
|
96
|
+
:root:not([data-theme='light']) .void-md .danger,
|
|
97
|
+
:root:not([data-theme='light']) .void-md .caution {
|
|
98
|
+
background: rgba(239, 68, 68, 0.12);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
:root[data-theme='dark'] .void-md .tip {
|
|
103
|
+
background: rgba(16, 185, 129, 0.12);
|
|
104
|
+
}
|
|
105
|
+
:root[data-theme='dark'] .void-md .info,
|
|
106
|
+
:root[data-theme='dark'] .void-md .note {
|
|
107
|
+
background: rgba(59, 130, 246, 0.12);
|
|
108
|
+
}
|
|
109
|
+
:root[data-theme='dark'] .void-md .warning,
|
|
110
|
+
:root[data-theme='dark'] .void-md .important {
|
|
111
|
+
background: rgba(234, 179, 8, 0.12);
|
|
112
|
+
}
|
|
113
|
+
:root[data-theme='dark'] .void-md .warning .custom-block-title,
|
|
114
|
+
:root[data-theme='dark'] .void-md .important .custom-block-title {
|
|
115
|
+
color: #eab308;
|
|
116
|
+
}
|
|
117
|
+
:root[data-theme='dark'] .void-md .danger,
|
|
118
|
+
:root[data-theme='dark'] .void-md .caution {
|
|
119
|
+
background: rgba(239, 68, 68, 0.12);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* GitHub Alerts */
|
|
123
|
+
.void-md .github-alert {
|
|
124
|
+
border-left-width: 4px;
|
|
125
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/* Void Markdown — Full Theme (reset + baseline + content)
|
|
2
|
+
*
|
|
3
|
+
* Use this entry for standalone markdown sites that need a complete stylesheet.
|
|
4
|
+
* For embedding markdown in an existing app, use content.css instead.
|
|
5
|
+
*/
|
|
6
|
+
@import './reset.css';
|
|
7
|
+
@import './content.css';
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/* Void Markdown — Prose Typography */
|
|
2
|
+
|
|
3
|
+
.void-md {
|
|
4
|
+
--vmd-font-body: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
5
|
+
--vmd-font-mono: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, monospace;
|
|
6
|
+
--vmd-text: #1a1a2e;
|
|
7
|
+
--vmd-text-muted: #64748b;
|
|
8
|
+
--vmd-link: #2563eb;
|
|
9
|
+
--vmd-link-hover: #1d4ed8;
|
|
10
|
+
--vmd-border: #e2e8f0;
|
|
11
|
+
--vmd-bg-soft: #f8fafc;
|
|
12
|
+
--vmd-line-height: 1.75;
|
|
13
|
+
|
|
14
|
+
font-family: var(--vmd-font-body);
|
|
15
|
+
color: var(--vmd-text);
|
|
16
|
+
line-height: var(--vmd-line-height);
|
|
17
|
+
word-wrap: break-word;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@media (prefers-color-scheme: dark) {
|
|
21
|
+
:root:not([data-theme='light']) .void-md {
|
|
22
|
+
--vmd-text: #e2e8f0;
|
|
23
|
+
--vmd-text-muted: #94a3b8;
|
|
24
|
+
--vmd-link: #60a5fa;
|
|
25
|
+
--vmd-link-hover: #93bbfd;
|
|
26
|
+
--vmd-border: #334155;
|
|
27
|
+
--vmd-bg-soft: #1e293b;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
:root[data-theme='dark'] .void-md {
|
|
32
|
+
--vmd-text: #e2e8f0;
|
|
33
|
+
--vmd-text-muted: #94a3b8;
|
|
34
|
+
--vmd-link: #60a5fa;
|
|
35
|
+
--vmd-link-hover: #93bbfd;
|
|
36
|
+
--vmd-border: #334155;
|
|
37
|
+
--vmd-bg-soft: #1e293b;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* Headings */
|
|
41
|
+
.void-md h1,
|
|
42
|
+
.void-md h2,
|
|
43
|
+
.void-md h3,
|
|
44
|
+
.void-md h4,
|
|
45
|
+
.void-md h5,
|
|
46
|
+
.void-md h6 {
|
|
47
|
+
font-weight: 600;
|
|
48
|
+
line-height: 1.3;
|
|
49
|
+
margin-top: 1.5em;
|
|
50
|
+
margin-bottom: 0.5em;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.void-md h1 {
|
|
54
|
+
font-size: 2em;
|
|
55
|
+
margin-top: 0;
|
|
56
|
+
}
|
|
57
|
+
.void-md h2 {
|
|
58
|
+
font-size: 1.5em;
|
|
59
|
+
padding-bottom: 0.3em;
|
|
60
|
+
border-bottom: 1px solid var(--vmd-border);
|
|
61
|
+
}
|
|
62
|
+
.void-md h3 {
|
|
63
|
+
font-size: 1.25em;
|
|
64
|
+
}
|
|
65
|
+
.void-md h4 {
|
|
66
|
+
font-size: 1em;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Paragraphs */
|
|
70
|
+
.void-md p {
|
|
71
|
+
margin-top: 0;
|
|
72
|
+
margin-bottom: 1em;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Links */
|
|
76
|
+
.void-md a {
|
|
77
|
+
color: var(--vmd-link);
|
|
78
|
+
text-decoration: none;
|
|
79
|
+
font-weight: 500;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.void-md a:hover {
|
|
83
|
+
color: var(--vmd-link-hover);
|
|
84
|
+
text-decoration: underline;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* Lists */
|
|
88
|
+
.void-md ul,
|
|
89
|
+
.void-md ol {
|
|
90
|
+
padding-left: 1.5em;
|
|
91
|
+
margin-top: 0;
|
|
92
|
+
margin-bottom: 1em;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.void-md li {
|
|
96
|
+
margin-bottom: 0.25em;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.void-md li > p {
|
|
100
|
+
margin-bottom: 0.5em;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* Blockquotes */
|
|
104
|
+
.void-md blockquote {
|
|
105
|
+
margin: 0 0 1em;
|
|
106
|
+
padding: 0.5em 1em;
|
|
107
|
+
border-left: 4px solid var(--vmd-border);
|
|
108
|
+
color: var(--vmd-text-muted);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.void-md blockquote > :last-child {
|
|
112
|
+
margin-bottom: 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Tables */
|
|
116
|
+
.void-md table {
|
|
117
|
+
width: 100%;
|
|
118
|
+
border-collapse: collapse;
|
|
119
|
+
margin-bottom: 1em;
|
|
120
|
+
display: block;
|
|
121
|
+
overflow-x: auto;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.void-md th,
|
|
125
|
+
.void-md td {
|
|
126
|
+
padding: 0.5em 1em;
|
|
127
|
+
border: 1px solid var(--vmd-border);
|
|
128
|
+
text-align: left;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.void-md th {
|
|
132
|
+
font-weight: 600;
|
|
133
|
+
background: var(--vmd-bg-soft);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* Inline code */
|
|
137
|
+
.void-md :not(pre) > code {
|
|
138
|
+
font-family: var(--vmd-font-mono);
|
|
139
|
+
font-size: 0.875em;
|
|
140
|
+
padding: 0.15em 0.4em;
|
|
141
|
+
border-radius: 4px;
|
|
142
|
+
background: var(--vmd-bg-soft);
|
|
143
|
+
border: 1px solid var(--vmd-border);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* Horizontal rule */
|
|
147
|
+
.void-md hr {
|
|
148
|
+
border: none;
|
|
149
|
+
border-top: 1px solid var(--vmd-border);
|
|
150
|
+
margin: 2em 0;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* Images */
|
|
154
|
+
.void-md img {
|
|
155
|
+
max-width: 100%;
|
|
156
|
+
height: auto;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* Strong / emphasis */
|
|
160
|
+
.void-md strong {
|
|
161
|
+
font-weight: 600;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* Anchor links */
|
|
165
|
+
.void-md .header-anchor {
|
|
166
|
+
float: left;
|
|
167
|
+
margin-left: -0.87em;
|
|
168
|
+
padding-right: 0.23em;
|
|
169
|
+
font-weight: 500;
|
|
170
|
+
opacity: 0;
|
|
171
|
+
transition: opacity 0.15s;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.void-md h1:hover .header-anchor,
|
|
175
|
+
.void-md h2:hover .header-anchor,
|
|
176
|
+
.void-md h3:hover .header-anchor,
|
|
177
|
+
.void-md h4:hover .header-anchor,
|
|
178
|
+
.void-md h5:hover .header-anchor,
|
|
179
|
+
.void-md h6:hover .header-anchor {
|
|
180
|
+
opacity: 1;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* Task lists */
|
|
184
|
+
.void-md ul.contains-task-list {
|
|
185
|
+
list-style: none;
|
|
186
|
+
padding-left: 0;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.void-md .task-list-item {
|
|
190
|
+
display: flex;
|
|
191
|
+
align-items: baseline;
|
|
192
|
+
gap: 0.5em;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.void-md .task-list-item input[type='checkbox'] {
|
|
196
|
+
margin: 0;
|
|
197
|
+
flex-shrink: 0;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* Nested task lists */
|
|
201
|
+
.void-md .task-list-item ul.contains-task-list {
|
|
202
|
+
margin-top: 0.25em;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* Keyboard input */
|
|
206
|
+
.void-md kbd {
|
|
207
|
+
font-family: var(--vmd-font-mono);
|
|
208
|
+
font-size: 0.875em;
|
|
209
|
+
padding: 0.1em 0.4em;
|
|
210
|
+
border-radius: 4px;
|
|
211
|
+
border: 1px solid var(--vmd-border);
|
|
212
|
+
box-shadow: 0 1px 0 var(--vmd-border);
|
|
213
|
+
background: var(--vmd-bg-soft);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* Highlighted text */
|
|
217
|
+
.void-md mark {
|
|
218
|
+
background: rgba(234, 179, 8, 0.3);
|
|
219
|
+
padding: 0.1em 0.2em;
|
|
220
|
+
border-radius: 2px;
|
|
221
|
+
color: inherit;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* Definition lists */
|
|
225
|
+
.void-md dl {
|
|
226
|
+
margin-bottom: 1em;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.void-md dt {
|
|
230
|
+
font-weight: 600;
|
|
231
|
+
margin-top: 0.5em;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.void-md dd {
|
|
235
|
+
margin-left: 1.5em;
|
|
236
|
+
margin-bottom: 0.5em;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/* Abbreviations */
|
|
240
|
+
.void-md abbr[title] {
|
|
241
|
+
text-decoration: underline dotted;
|
|
242
|
+
cursor: help;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/* Subscript / Superscript */
|
|
246
|
+
.void-md sub,
|
|
247
|
+
.void-md sup {
|
|
248
|
+
font-size: 0.75em;
|
|
249
|
+
line-height: 0;
|
|
250
|
+
position: relative;
|
|
251
|
+
vertical-align: baseline;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.void-md sup {
|
|
255
|
+
top: -0.5em;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.void-md sub {
|
|
259
|
+
bottom: -0.25em;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/* Footnotes */
|
|
263
|
+
.void-md section.footnotes {
|
|
264
|
+
margin-top: 2em;
|
|
265
|
+
padding-top: 1em;
|
|
266
|
+
border-top: 1px solid var(--vmd-border);
|
|
267
|
+
font-size: 0.875em;
|
|
268
|
+
color: var(--vmd-text-muted);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.void-md .footnote-ref a {
|
|
272
|
+
font-size: 0.75em;
|
|
273
|
+
vertical-align: super;
|
|
274
|
+
line-height: 0;
|
|
275
|
+
margin-left: 0.1em;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.void-md .footnote-backref {
|
|
279
|
+
font-family: initial;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* Table of contents */
|
|
283
|
+
.void-md .table-of-contents {
|
|
284
|
+
margin-bottom: 1em;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.void-md .table-of-contents ul {
|
|
288
|
+
list-style: none;
|
|
289
|
+
padding-left: 1em;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.void-md .table-of-contents > ul {
|
|
293
|
+
padding-left: 0;
|
|
294
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/* Void Markdown — Reset & Baseline
|
|
2
|
+
*
|
|
3
|
+
* Opinionated modern reset for markdown-driven sites.
|
|
4
|
+
* Imported by index.css — not intended for standalone use.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/* Box sizing */
|
|
8
|
+
*,
|
|
9
|
+
*::before,
|
|
10
|
+
*::after {
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* Remove default margins */
|
|
15
|
+
* {
|
|
16
|
+
margin: 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Document */
|
|
20
|
+
html {
|
|
21
|
+
line-height: 1.5;
|
|
22
|
+
-webkit-text-size-adjust: 100%;
|
|
23
|
+
-moz-tab-size: 4;
|
|
24
|
+
tab-size: 4;
|
|
25
|
+
scroll-behavior: smooth;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Body */
|
|
29
|
+
body {
|
|
30
|
+
min-height: 100dvh;
|
|
31
|
+
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
32
|
+
-webkit-font-smoothing: antialiased;
|
|
33
|
+
-moz-osx-font-smoothing: grayscale;
|
|
34
|
+
text-rendering: optimizeLegibility;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Typography */
|
|
38
|
+
h1,
|
|
39
|
+
h2,
|
|
40
|
+
h3,
|
|
41
|
+
h4,
|
|
42
|
+
h5,
|
|
43
|
+
h6 {
|
|
44
|
+
overflow-wrap: break-word;
|
|
45
|
+
text-wrap: balance;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
p {
|
|
49
|
+
overflow-wrap: break-word;
|
|
50
|
+
text-wrap: pretty;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Media */
|
|
54
|
+
img,
|
|
55
|
+
picture,
|
|
56
|
+
video,
|
|
57
|
+
canvas,
|
|
58
|
+
svg {
|
|
59
|
+
display: block;
|
|
60
|
+
max-width: 100%;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
img,
|
|
64
|
+
video {
|
|
65
|
+
height: auto;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Forms */
|
|
69
|
+
input,
|
|
70
|
+
button,
|
|
71
|
+
textarea,
|
|
72
|
+
select {
|
|
73
|
+
font: inherit;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Monospace */
|
|
77
|
+
code,
|
|
78
|
+
kbd,
|
|
79
|
+
samp,
|
|
80
|
+
pre {
|
|
81
|
+
font-family:
|
|
82
|
+
ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
|
|
83
|
+
font-size: 1em;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Links */
|
|
87
|
+
a {
|
|
88
|
+
color: inherit;
|
|
89
|
+
text-decoration: inherit;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* Tables */
|
|
93
|
+
table {
|
|
94
|
+
border-collapse: collapse;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Horizontal rule */
|
|
98
|
+
hr {
|
|
99
|
+
border: none;
|
|
100
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "void-plugin-hono-jsx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Hono JSX Pages adapter for Void",
|
|
6
6
|
"type": "module",
|
|
@@ -36,6 +36,12 @@
|
|
|
36
36
|
"./markdown": {
|
|
37
37
|
"types": "./dist/server/markdown.d.ts",
|
|
38
38
|
"default": "./dist/server/markdown.js"
|
|
39
|
+
},
|
|
40
|
+
"./theme.css": {
|
|
41
|
+
"default": "./dist/theme/index.css"
|
|
42
|
+
},
|
|
43
|
+
"./theme-content.css": {
|
|
44
|
+
"default": "./dist/theme/content.css"
|
|
39
45
|
}
|
|
40
46
|
},
|
|
41
47
|
"peerDependencies": {
|
|
@@ -43,7 +49,10 @@
|
|
|
43
49
|
"void": ">=1.1.11 <1.2.0",
|
|
44
50
|
"vite": ">=8.0.16 <9.0.0",
|
|
45
51
|
"markdown-exit": ">=1.3.0 <2.0.0",
|
|
46
|
-
"yaml": ">=2.9.1 <3.0.0"
|
|
52
|
+
"yaml": ">=2.9.1 <3.0.0",
|
|
53
|
+
"markdown-it-container": ">=4.0.0 <5.0.0",
|
|
54
|
+
"shiki": ">=4.5.0 <5.0.0",
|
|
55
|
+
"@shikijs/transformers": ">=4.5.0 <5.0.0"
|
|
47
56
|
},
|
|
48
57
|
"repository": {
|
|
49
58
|
"type": "git",
|
|
@@ -72,6 +81,15 @@
|
|
|
72
81
|
},
|
|
73
82
|
"yaml": {
|
|
74
83
|
"optional": true
|
|
84
|
+
},
|
|
85
|
+
"markdown-it-container": {
|
|
86
|
+
"optional": true
|
|
87
|
+
},
|
|
88
|
+
"shiki": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"@shikijs/transformers": {
|
|
92
|
+
"optional": true
|
|
75
93
|
}
|
|
76
94
|
}
|
|
77
95
|
}
|
|
@@ -2,7 +2,7 @@ import { readFileSync, realpathSync } from 'node:fs';
|
|
|
2
2
|
import { join, relative, resolve, dirname, basename } from 'node:path';
|
|
3
3
|
import { normalizePath, parseSync, type Plugin } from 'vite';
|
|
4
4
|
import { scanPages, resolveEffectiveLayoutChain, resolvePagesDir, type PageScanResult } from 'void/pages';
|
|
5
|
-
import { findIslandImports, editIslandSource, computePagesNeedingClientJS, ISLANDS_RENDERER_ID, ISLANDS_CLIENT_ENTRY_ID } from 'void/pages-islands-plugin';
|
|
5
|
+
import { findIslandImports, findStaticCssImports, rewriteCssImportForVirtualModule, editIslandSource, computePagesNeedingClientJS, ISLANDS_RENDERER_ID, ISLANDS_CLIENT_ENTRY_ID } from 'void/pages-islands-plugin';
|
|
6
6
|
|
|
7
7
|
import { resolveComponent } from './resolve-component.ts';
|
|
8
8
|
|
|
@@ -15,6 +15,7 @@ export function honoIslands(): Plugin {
|
|
|
15
15
|
const islands = new Map<string, string>();
|
|
16
16
|
const pageFiles = new Set<string>();
|
|
17
17
|
let dependencyFiles = new Set<string>();
|
|
18
|
+
let cssImports: string[] = [];
|
|
18
19
|
const graph = new Map<string, Set<string>>();
|
|
19
20
|
const directlyInteractive = new Set<string>();
|
|
20
21
|
const interactivePages = new Set<string>();
|
|
@@ -123,6 +124,10 @@ export function honoIslands(): Plugin {
|
|
|
123
124
|
for (const page of scan.pages.filter((page) => !page.island)) {
|
|
124
125
|
for (const file of [page.componentPath, ...resolveEffectiveLayoutChain(page, scan.layouts, scan.namedLayouts).map((layout) => layout.filePath)]) validateInteractive(join(pagesDir, file));
|
|
125
126
|
}
|
|
127
|
+
// Match the official adapters: retain static-layout CSS in the client build
|
|
128
|
+
// even when the document itself needs no client-side JavaScript. Reuse the
|
|
129
|
+
// analysis snapshot rather than rereading modules during entry generation.
|
|
130
|
+
cssImports = [...new Set([...pageFiles].flatMap(file => findStaticCssImports(analyses.get(file)!.code, file).map(item => rewriteCssImportForVirtualModule(item.statement, item.specifier, file))))];
|
|
126
131
|
dependencyFiles = watched;
|
|
127
132
|
const needsJS = new Set(directlyInteractive);
|
|
128
133
|
let changed = true;
|
|
@@ -210,9 +215,12 @@ export function renderIslandPage(page, assets) {
|
|
|
210
215
|
}`;
|
|
211
216
|
}
|
|
212
217
|
if (id === `\0${ISLANDS_CLIENT_ENTRY_ID}`) {
|
|
213
|
-
|
|
218
|
+
// Void owns dev first-paint CSS. Production needs the static imports
|
|
219
|
+
// so its shared manifest asset collector can emit stylesheet links.
|
|
220
|
+
const styles = this.environment?.mode === 'dev' ? '' : cssImports.join('\n');
|
|
221
|
+
if (!islands.size || !interactivePages.size) return styles || 'export {};';
|
|
214
222
|
const loaders = [...islands].map(([name, path]) => `${JSON.stringify(name)}: () => import(${JSON.stringify(path)})`).join(',\n');
|
|
215
|
-
return `${markdown ? "import { MarkdownContext } from 'void-plugin-hono-jsx/markdown';" : ''}
|
|
223
|
+
return `${styles}\n${markdown ? "import { MarkdownContext } from 'void-plugin-hono-jsx/markdown';" : ''}
|
|
216
224
|
import { initIslands } from 'void/pages-client';
|
|
217
225
|
import { jsx } from 'hono/jsx/dom/jsx-runtime';
|
|
218
226
|
import { render } from 'hono/jsx/dom';
|
|
@@ -3,7 +3,10 @@ import { join, relative, dirname } from 'node:path';
|
|
|
3
3
|
import { normalizePath, type Plugin } from 'vite';
|
|
4
4
|
import { resolvePagesDir } from 'void/pages';
|
|
5
5
|
import { resolveComponent } from './resolve-component.ts';
|
|
6
|
-
import {
|
|
6
|
+
import { createMarkdownCompiler, renderChunks } from './markdown-compiler.ts';
|
|
7
|
+
import type { HonoMarkdownOptions } from './markdown-features.ts';
|
|
8
|
+
import { markdownCopyId, markdownCopyCode } from './markdown-copy.ts';
|
|
9
|
+
export type { HonoMarkdownOptions } from './markdown-features.ts';
|
|
7
10
|
import type { HonoMarkdownApi } from './markdown-api.ts';
|
|
8
11
|
|
|
9
12
|
const clientId = 'virtual:void-hono-markdown-client';
|
|
@@ -11,22 +14,24 @@ const scriptQuery = '?hono-markdown-script';
|
|
|
11
14
|
const literal = (value: unknown) => `JSON.parse(${JSON.stringify(JSON.stringify(value))})`;
|
|
12
15
|
|
|
13
16
|
/** Optional authored Markdown compiler; independent of @void/md private files. */
|
|
14
|
-
export function voidHonoMarkdown(): Plugin {
|
|
17
|
+
export function voidHonoMarkdown(options: HonoMarkdownOptions = {}): Plugin {
|
|
18
|
+
const compiler = createMarkdownCompiler(options);
|
|
15
19
|
let root = process.cwd();
|
|
16
20
|
let pagesDir = resolvePagesDir(root);
|
|
17
21
|
let scripts = new Map<string, string>();
|
|
18
22
|
let files = new Map<string, string>();
|
|
19
|
-
let sources = new Map<string, ReturnType<typeof
|
|
23
|
+
let sources = new Map<string, ReturnType<typeof compiler.parse>>();
|
|
20
24
|
function rescan() {
|
|
21
25
|
const nextScripts = new Map<string, string>();
|
|
22
26
|
const nextFiles = new Map<string, string>();
|
|
23
|
-
const nextSources = new Map<string, ReturnType<typeof
|
|
27
|
+
const nextSources = new Map<string, ReturnType<typeof compiler.parse>>();
|
|
24
28
|
for (const entry of existsSync(pagesDir) ? readdirSync(pagesDir, { recursive: true, withFileTypes: true }) : []) {
|
|
25
29
|
if (!entry.isFile() || !entry.name.endsWith('.md')) continue;
|
|
26
30
|
const file = join(entry.parentPath, entry.name);
|
|
27
31
|
const id = normalizePath(relative(pagesDir, file)).replace(/\.md$/, '').replace(/\.island$/, '').replace(/\/index$/, '').replace(/^index$/, '') || 'index';
|
|
28
32
|
const canonical = realpathSync(file);
|
|
29
|
-
const extracted = nextSources.get(canonical) ??
|
|
33
|
+
const extracted = nextSources.get(canonical) ?? compiler.parse(readFileSync(canonical, 'utf8'));
|
|
34
|
+
if (!nextSources.has(canonical) && extracted.hasCode) extracted.clientCode = `import ${JSON.stringify(markdownCopyId)};\n` + extracted.clientCode;
|
|
30
35
|
nextSources.set(canonical, extracted);
|
|
31
36
|
if (extracted.clientCode) { nextScripts.set(id, extracted.clientCode); nextFiles.set(id, file); }
|
|
32
37
|
}
|
|
@@ -51,8 +56,9 @@ export function voidHonoMarkdown(): Plugin {
|
|
|
51
56
|
const entry = this.environment.moduleGraph.getModuleById(`\0${clientId}`);
|
|
52
57
|
if (entry) this.environment.moduleGraph.invalidateModule(entry, new Set(), timestamp, true);
|
|
53
58
|
},
|
|
54
|
-
resolveId(id) { if (id === clientId) return `\0${id}`; },
|
|
59
|
+
resolveId(id) { if (id === clientId || id === markdownCopyId) return `\0${id}`; },
|
|
55
60
|
load(id) {
|
|
61
|
+
if (id === `\0${markdownCopyId}`) return markdownCopyCode;
|
|
56
62
|
if (id.endsWith(scriptQuery)) return source(id.slice(0, -scriptQuery.length)).clientCode || 'export {};';
|
|
57
63
|
if (id !== `\0${clientId}`) return;
|
|
58
64
|
if (!files.size) return 'export {};';
|
|
@@ -62,8 +68,9 @@ if (id && scripts[id]) await scripts[id]();`;
|
|
|
62
68
|
},
|
|
63
69
|
transform: {
|
|
64
70
|
filter: { id: /\.md$/ },
|
|
65
|
-
handler(source, id) {
|
|
66
|
-
const
|
|
71
|
+
async handler(source, id) {
|
|
72
|
+
const cached = sources.get(realpathSync(id));
|
|
73
|
+
const result = await compiler.render(cached?.source === source ? cached : compiler.parse(source));
|
|
67
74
|
const imports = result.imports.map((entry, index) => {
|
|
68
75
|
const target = resolveComponent(entry.specifier, dirname(id), ['.tsx', '.jsx']);
|
|
69
76
|
if (!target || !entry.specifier.startsWith('.')) throw new Error(`Hono Markdown: cannot resolve relative TSX/JSX island ${entry.specifier} in ${id}.`);
|