@apisurf/canonui 0.1.1

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.
@@ -0,0 +1,543 @@
1
+ /*
2
+ * The default theme.
3
+ *
4
+ * One stylesheet, no framework, no build step of its own. It is meant to be
5
+ * legible first and replaceable second: every rule here is scoped to a class
6
+ * the layout puts on the page, so a site that wants its own look overrides
7
+ * the classes rather than fighting a cascade.
8
+ *
9
+ * Colours are tokens on :root and the theme is light in every context. Paper
10
+ * rather than white and ink rather than black: the pages are read for minutes
11
+ * at a time, and the lower contrast of a warm ground is the difference between
12
+ * comfortable and glaring. A site that wants a dark theme overrides the
13
+ * tokens; nothing here switches on its own, because the output is a folder of
14
+ * files served from anywhere with no runtime to ask the viewer.
15
+ */
16
+
17
+ :root {
18
+ color-scheme: light;
19
+
20
+ --bg: #fbfaf7;
21
+ --surface: #f2f0ea;
22
+ --border: #e3e0d7;
23
+ --ink: #24231f;
24
+ --ink-muted: #6a6760;
25
+ --accent: #2a5cb8;
26
+ --accent-soft: #e9eefa;
27
+ --code-bg: #efece3;
28
+ --radius: 6px;
29
+ /* The reading column. Wide enough that a code block or a three-column
30
+ table is not the first thing to overflow it. */
31
+ --measure: 44rem;
32
+ --rail: 12rem;
33
+ --gutter: 3rem;
34
+ --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
35
+ --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
36
+ }
37
+
38
+ * {
39
+ box-sizing: border-box;
40
+ }
41
+
42
+ body {
43
+ margin: 0;
44
+ background: var(--bg);
45
+ color: var(--ink);
46
+ font-family: var(--font);
47
+ font-size: 17px;
48
+ line-height: 1.7;
49
+ -webkit-text-size-adjust: 100%;
50
+ -webkit-font-smoothing: antialiased;
51
+ -moz-osx-font-smoothing: grayscale;
52
+ }
53
+
54
+ ::selection {
55
+ background: var(--accent-soft);
56
+ }
57
+
58
+ a {
59
+ color: var(--accent);
60
+ text-decoration-thickness: 1px;
61
+ text-underline-offset: 2px;
62
+ }
63
+
64
+ /* Keyboard users get the link; everyone else never sees it. */
65
+ .skip {
66
+ position: absolute;
67
+ left: -9999px;
68
+ }
69
+ .skip:focus {
70
+ left: 1rem;
71
+ top: 1rem;
72
+ padding: 0.5rem 0.75rem;
73
+ background: var(--accent-soft);
74
+ border-radius: var(--radius);
75
+ z-index: 10;
76
+ }
77
+
78
+ /* -----------------------------------------------------------------------------
79
+ * The shell
80
+ *
81
+ * Two columns, centred as a whole: the document, and what is in it. The rail
82
+ * keeps its column whether or not it has contents to draw, so the measure is
83
+ * the same for every document.
84
+ * -------------------------------------------------------------------------- */
85
+
86
+ .shell {
87
+ max-width: calc(var(--measure) + var(--gutter) + var(--rail) + 2.5rem);
88
+ margin: 0 auto;
89
+ padding: 0 1.25rem;
90
+ display: grid;
91
+ grid-template-columns: minmax(0, 1fr) var(--rail);
92
+ column-gap: var(--gutter);
93
+ align-items: start;
94
+ }
95
+
96
+ .site-main {
97
+ min-width: 0;
98
+ max-width: var(--measure);
99
+ width: 100%;
100
+ margin: 0 auto;
101
+ padding: 3rem 0 4rem;
102
+ }
103
+
104
+ .site-rail {
105
+ position: sticky;
106
+ top: 2.25rem;
107
+ max-height: calc(100vh - 4.5rem);
108
+ overflow-y: auto;
109
+ padding: 3rem 0 2rem;
110
+ overscroll-behavior: contain;
111
+ }
112
+
113
+ .site-footer {
114
+ margin-top: 3rem;
115
+ padding-top: 1.25rem;
116
+ border-top: 1px solid var(--border);
117
+ color: var(--ink-muted);
118
+ font-size: 0.8125rem;
119
+ }
120
+
121
+ .site-footer p {
122
+ margin: 0;
123
+ }
124
+
125
+ /* -----------------------------------------------------------------------------
126
+ * On this page
127
+ * -------------------------------------------------------------------------- */
128
+
129
+ .toc {
130
+ font-size: 0.8125rem;
131
+ border-left: 1px solid var(--border);
132
+ padding-left: 1rem;
133
+ }
134
+
135
+ .toc-title {
136
+ margin: 0 0 0.5rem;
137
+ font-size: 0.6875rem;
138
+ letter-spacing: 0.08em;
139
+ text-transform: uppercase;
140
+ color: var(--ink-muted);
141
+ }
142
+
143
+ .toc-list {
144
+ list-style: none;
145
+ margin: 0;
146
+ padding: 0;
147
+ display: grid;
148
+ gap: 0.3rem;
149
+ }
150
+
151
+ .toc-list a {
152
+ color: var(--ink-muted);
153
+ text-decoration: none;
154
+ display: block;
155
+ }
156
+
157
+ .toc-list a:hover {
158
+ color: var(--ink);
159
+ }
160
+
161
+ .toc-list a[aria-current] {
162
+ color: var(--accent);
163
+ }
164
+
165
+ .toc-depth-2 {
166
+ padding-left: 0.85rem;
167
+ }
168
+
169
+ /* -----------------------------------------------------------------------------
170
+ * Page furniture
171
+ * -------------------------------------------------------------------------- */
172
+
173
+ h1 {
174
+ font-size: 2rem;
175
+ line-height: 1.25;
176
+ margin: 0 0 0.6rem;
177
+ letter-spacing: -0.015em;
178
+ }
179
+
180
+ .lede {
181
+ font-size: 1.15rem;
182
+ line-height: 1.6;
183
+ color: var(--ink-muted);
184
+ margin: 0 0 1.75rem;
185
+ }
186
+
187
+ .page-header {
188
+ margin-bottom: 2rem;
189
+ }
190
+
191
+ /* -----------------------------------------------------------------------------
192
+ * Blocks and prose
193
+ * -------------------------------------------------------------------------- */
194
+
195
+ .block {
196
+ margin: 0 0 2.5rem;
197
+ }
198
+
199
+ .block-title {
200
+ font-size: 1.35rem;
201
+ line-height: 1.3;
202
+ letter-spacing: -0.01em;
203
+ margin: 0 0 0.75rem;
204
+ }
205
+
206
+ /*
207
+ * A heading is a link to itself, and looks like neither until it is hovered.
208
+ * The `#` is drawn in the margin so turning it on does not move the text.
209
+ */
210
+ .anchor {
211
+ color: inherit;
212
+ text-decoration: none;
213
+ /* Containing block for the `#`, so it hangs off this heading and not off
214
+ whatever happens to be positioned further up the tree. */
215
+ position: relative;
216
+ }
217
+
218
+ .anchor::before {
219
+ content: "#";
220
+ position: absolute;
221
+ left: -1.1em;
222
+ color: var(--ink-muted);
223
+ opacity: 0;
224
+ font-weight: 400;
225
+ }
226
+
227
+ .anchor:hover::before,
228
+ :hover > .anchor::before,
229
+ .anchor:focus-visible::before {
230
+ opacity: 1;
231
+ }
232
+
233
+ .prose > :first-child {
234
+ margin-top: 0;
235
+ }
236
+
237
+ .prose > :last-child {
238
+ margin-bottom: 0;
239
+ }
240
+
241
+ .prose h2 {
242
+ font-size: 1.35rem;
243
+ line-height: 1.3;
244
+ letter-spacing: -0.01em;
245
+ margin: 2.5rem 0 0.7rem;
246
+ }
247
+
248
+ .prose h3 {
249
+ font-size: 1.1rem;
250
+ line-height: 1.35;
251
+ margin: 2rem 0 0.5rem;
252
+ }
253
+
254
+ /* Paragraph rhythm follows the leading: loose text needs loose gaps to keep
255
+ the block boundaries visible. */
256
+ .prose p,
257
+ .prose ul,
258
+ .prose ol {
259
+ margin: 0 0 1.15em;
260
+ }
261
+
262
+ .prose li + li {
263
+ margin-top: 0.35em;
264
+ }
265
+
266
+ .prose li > ul,
267
+ .prose li > ol {
268
+ margin: 0.35em 0 0;
269
+ }
270
+
271
+ .prose code {
272
+ font-family: var(--mono);
273
+ font-size: 0.85em;
274
+ padding: 0.1em 0.35em;
275
+ background: var(--code-bg);
276
+ border-radius: 4px;
277
+ }
278
+
279
+ /* Wide content scrolls inside its own box; the page body never does. */
280
+ .prose pre {
281
+ overflow-x: auto;
282
+ padding: 0.95rem 1.1rem;
283
+ margin: 0 0 1.5rem;
284
+ background: var(--surface);
285
+ border: 1px solid var(--border);
286
+ border-radius: var(--radius);
287
+ font-size: 0.85em;
288
+ line-height: 1.6;
289
+ }
290
+
291
+ .prose pre code {
292
+ padding: 0;
293
+ background: none;
294
+ }
295
+
296
+ .prose blockquote {
297
+ margin: 1.5rem 0;
298
+ padding-left: 1.1rem;
299
+ border-left: 3px solid var(--border);
300
+ color: var(--ink-muted);
301
+ }
302
+
303
+ .prose table {
304
+ width: 100%;
305
+ border-collapse: collapse;
306
+ display: block;
307
+ overflow-x: auto;
308
+ margin: 0 0 1.5rem;
309
+ font-size: 0.9375em;
310
+ }
311
+
312
+ .prose th,
313
+ .prose td {
314
+ border: 1px solid var(--border);
315
+ padding: 0.45rem 0.7rem;
316
+ text-align: left;
317
+ }
318
+
319
+ .prose th {
320
+ background: var(--surface);
321
+ font-weight: 600;
322
+ }
323
+
324
+ figure {
325
+ margin: 0;
326
+ }
327
+
328
+ figure img {
329
+ max-width: 100%;
330
+ height: auto;
331
+ border-radius: var(--radius);
332
+ }
333
+
334
+ figcaption {
335
+ margin-top: 0.5rem;
336
+ color: var(--ink-muted);
337
+ font-size: 0.875rem;
338
+ }
339
+
340
+ pre.mermaid {
341
+ background: none;
342
+ border: none;
343
+ padding: 0;
344
+ text-align: center;
345
+ /* Until the client script swaps the source for an SVG there is nothing worth
346
+ showing, and a wall of diagram source is worse than a gap. */
347
+ visibility: hidden;
348
+ }
349
+
350
+ pre.mermaid[data-processed="true"] {
351
+ visibility: visible;
352
+ }
353
+
354
+ .empty,
355
+ .block-unknown {
356
+ padding: 0.9rem 1rem;
357
+ border: 1px dashed var(--border);
358
+ border-radius: var(--radius);
359
+ color: var(--ink-muted);
360
+ }
361
+
362
+ /* -----------------------------------------------------------------------------
363
+ * Copy as markdown
364
+ *
365
+ * One button, under the title where the document begins. Quiet — an outline
366
+ * and muted ink, no fill — because the reader came for the prose and this is a
367
+ * tool beside it.
368
+ * -------------------------------------------------------------------------- */
369
+
370
+ .copy {
371
+ display: inline-flex;
372
+ align-items: center;
373
+ gap: 0.35rem;
374
+ padding: 0.25rem 0.6rem;
375
+ border: 1px solid var(--border);
376
+ border-radius: 999px;
377
+ background: transparent;
378
+ color: var(--ink-muted);
379
+ font-family: inherit;
380
+ font-size: 0.8125rem;
381
+ line-height: 1.5;
382
+ cursor: pointer;
383
+ transition:
384
+ color 120ms ease,
385
+ border-color 120ms ease,
386
+ background-color 120ms ease;
387
+ }
388
+
389
+ .copy:hover,
390
+ .copy:focus-visible {
391
+ color: var(--ink);
392
+ border-color: var(--accent);
393
+ background: var(--surface);
394
+ }
395
+
396
+ .copy[data-state="done"] {
397
+ color: var(--accent);
398
+ border-color: var(--accent);
399
+ background: var(--accent-soft);
400
+ }
401
+
402
+ .copy-icon {
403
+ display: none;
404
+ }
405
+
406
+ .copy[data-state="idle"] .copy-icon-idle,
407
+ .copy[data-state="failed"] .copy-icon-idle,
408
+ .copy[data-state="done"] .copy-icon-done {
409
+ display: inline;
410
+ }
411
+
412
+ /*
413
+ * All three labels are stacked in one grid cell, so the button is as wide as
414
+ * the longest of them and saying "Copied" does not resize it mid-click. They
415
+ * are hidden rather than removed for the same reason — a removed label takes
416
+ * its width with it.
417
+ */
418
+ .copy-label {
419
+ display: grid;
420
+ }
421
+
422
+ .copy-text {
423
+ grid-area: 1 / 1;
424
+ white-space: nowrap;
425
+ visibility: hidden;
426
+ }
427
+
428
+ .copy[data-state="idle"] .copy-text-idle,
429
+ .copy[data-state="done"] .copy-text-done,
430
+ .copy[data-state="failed"] .copy-text-failed {
431
+ visibility: visible;
432
+ }
433
+
434
+ /* The lede above it already sets the gap; a document without one gets the h1's. */
435
+ .page-actions {
436
+ margin: 0;
437
+ }
438
+
439
+ /* -----------------------------------------------------------------------------
440
+ * Narrower screens
441
+ *
442
+ * The rail goes: it is the column whose job the reader can do by scrolling.
443
+ * -------------------------------------------------------------------------- */
444
+
445
+ @media (max-width: 60rem) {
446
+ .shell {
447
+ grid-template-columns: minmax(0, 1fr);
448
+ }
449
+
450
+ .site-rail {
451
+ display: none;
452
+ }
453
+ }
454
+
455
+ @media (max-width: 52rem) {
456
+ .site-main {
457
+ padding: 2rem 0 3rem;
458
+ }
459
+ }
460
+
461
+ /* -----------------------------------------------------------------------------
462
+ * The wide view
463
+ *
464
+ * One mode for the page rather than an escape hatch per block. The rail goes,
465
+ * the gutters tighten and the measure comes off, so the content is bounded by
466
+ * the window and nothing else. Everything here is a class on
467
+ * the root element, so the whole layout switches in one place and every rule
468
+ * that draws the narrow page is left exactly as it was.
469
+ * -------------------------------------------------------------------------- */
470
+
471
+ .wide-toggle {
472
+ position: fixed;
473
+ right: 1rem;
474
+ bottom: 1rem;
475
+ z-index: 5;
476
+ display: inline-flex;
477
+ align-items: center;
478
+ gap: 0.35rem;
479
+ padding: 0.3rem 0.65rem;
480
+ border: 1px solid var(--border);
481
+ border-radius: 999px;
482
+ background: var(--bg);
483
+ color: var(--ink-muted);
484
+ font-family: inherit;
485
+ font-size: 0.8125rem;
486
+ line-height: 1.5;
487
+ cursor: pointer;
488
+ box-shadow: 0 2px 10px rgb(36 35 31 / 8%);
489
+ /* Chrome, not content: quiet until the reader goes looking for it. */
490
+ opacity: 0.65;
491
+ transition:
492
+ opacity 120ms ease,
493
+ color 120ms ease,
494
+ border-color 120ms ease;
495
+ }
496
+
497
+ .wide-toggle:hover,
498
+ .wide-toggle:focus-visible {
499
+ opacity: 1;
500
+ color: var(--ink);
501
+ border-color: var(--accent);
502
+ }
503
+
504
+ .wide-icon,
505
+ .wide-label {
506
+ display: none;
507
+ }
508
+
509
+ .wide-icon-out,
510
+ .wide-label-out {
511
+ display: inline;
512
+ }
513
+
514
+ .wide .wide-icon-out,
515
+ .wide .wide-label-out {
516
+ display: none;
517
+ }
518
+
519
+ .wide .wide-icon-in,
520
+ .wide .wide-label-in {
521
+ display: inline;
522
+ }
523
+
524
+ .wide .site-rail {
525
+ display: none;
526
+ }
527
+
528
+ .wide .site-main {
529
+ max-width: none;
530
+ }
531
+
532
+ .wide .shell {
533
+ max-width: none;
534
+ grid-template-columns: minmax(0, 1fr);
535
+ }
536
+
537
+ /* Mermaid writes onto the diagram the pixel width that fitted the measure.
538
+ There is more room now, so let it take it. */
539
+ .wide pre.mermaid svg {
540
+ max-width: 100%;
541
+ width: 100%;
542
+ height: auto;
543
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "astro/tsconfigs/strict",
3
+ "include": [".astro/types.d.ts", "theme/**/*", "astro.config.mjs"],
4
+ "exclude": ["dist", "src", "test"]
5
+ }