@opentf/web-docs 0.1.0 → 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/build/blog-posts-plugin.js +127 -0
- package/build/docs-nav-plugin.js +17 -10
- package/build/feed.js +78 -0
- package/build/index.js +4 -0
- package/build/last-updated-plugin.js +98 -0
- package/build/last-updated.js +45 -0
- package/build/pagefind.js +58 -0
- package/build/reading-time.js +16 -0
- package/components/BlogLayout.jsx +77 -0
- package/components/Breadcrumbs.jsx +30 -27
- package/components/Callout.jsx +7 -7
- package/components/Card.jsx +21 -0
- package/components/Cards.jsx +11 -0
- package/components/CodeBlock.jsx +39 -0
- package/components/DocsLayout.jsx +66 -6
- package/components/LastUpdated.jsx +22 -0
- package/components/NavIcon.jsx +34 -0
- package/components/Navbar.jsx +34 -22
- package/components/NavbarLink.jsx +33 -0
- package/components/Pagination.jsx +37 -33
- package/components/PostBanner.jsx +25 -0
- package/components/PostCard.jsx +19 -0
- package/components/PostList.jsx +17 -0
- package/components/PostMeta.jsx +28 -0
- package/components/ReadingTime.jsx +6 -0
- package/components/Search.jsx +211 -0
- package/components/SearchTrigger.jsx +14 -3
- package/components/Sidebar.jsx +111 -9
- package/components/SidebarNode.jsx +1 -0
- package/components/SidebarToggle.jsx +47 -0
- package/components/Steps.jsx +14 -0
- package/components/Tabs.jsx +4 -2
- package/components/ThemeToggle.jsx +150 -25
- package/components/Tooltip.jsx +19 -0
- package/components/format.js +11 -0
- package/config.js +25 -1
- package/index.js +29 -2
- package/nav-virtual.js +6 -4
- package/package.json +15 -1
- package/posts-virtual.js +17 -0
- package/theme/index.css +1034 -58
- package/updated-virtual.js +9 -0
- package/components/CodeGroup.jsx +0 -28
package/theme/index.css
CHANGED
|
@@ -65,22 +65,33 @@ body {
|
|
|
65
65
|
/* Custom elements are inline by default. Structural hosts become block-level grid
|
|
66
66
|
* items; pure wrapper hosts (a link, a list node) become layout-transparent
|
|
67
67
|
* (`display: contents`) so their inner semantic element participates directly in the
|
|
68
|
-
* surrounding flex/grid/list.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
web-
|
|
72
|
-
web-toc,
|
|
73
|
-
web-footer,
|
|
74
|
-
web-breadcrumbs,
|
|
75
|
-
web-pagination,
|
|
76
|
-
web-callout,
|
|
77
|
-
web-tabs,
|
|
78
|
-
web-code-group,
|
|
79
|
-
web-table {
|
|
68
|
+
* surrounding flex/grid/list. Hosts are addressed by the stable `web-<kebab>` class
|
|
69
|
+
* the compiler stamps on every component (the element tag itself is module-hashed
|
|
70
|
+
* to stay collision-free, so it is not a reliable selector). */
|
|
71
|
+
.web-docs-layout,
|
|
72
|
+
.web-toc,
|
|
73
|
+
.web-footer,
|
|
74
|
+
.web-breadcrumbs,
|
|
75
|
+
.web-pagination,
|
|
76
|
+
.web-callout,
|
|
77
|
+
.web-tabs,
|
|
78
|
+
.web-code-group,
|
|
79
|
+
.web-table {
|
|
80
80
|
display: block;
|
|
81
81
|
}
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
/* The navbar host must be transparent so its sticky <header> sticks to the page
|
|
83
|
+
* scroll container, not to its own wrapper. Link hosts are transparent so the inner
|
|
84
|
+
* <a> participates directly in the navbar/list flex layout. The sidebar host (and its
|
|
85
|
+
* shell wrapper) are transparent so the inner <aside> is the docs-grid column on
|
|
86
|
+
* desktop and a fixed off-canvas drawer on mobile; the burger host so the button sits
|
|
87
|
+
* directly in the navbar lead flow. */
|
|
88
|
+
.web-navbar,
|
|
89
|
+
.web-navbar-link,
|
|
90
|
+
.web-link,
|
|
91
|
+
.web-sidebar-node,
|
|
92
|
+
.web-sidebar,
|
|
93
|
+
.web-sidebar-toggle,
|
|
94
|
+
.otfw-sidebar-shell {
|
|
84
95
|
display: contents;
|
|
85
96
|
}
|
|
86
97
|
|
|
@@ -109,6 +120,19 @@ web-sidebar-node {
|
|
|
109
120
|
max-width: 90rem;
|
|
110
121
|
margin: 0 auto;
|
|
111
122
|
padding: 0 1.5rem;
|
|
123
|
+
/* Three zones: brand (left) · search (centered) · nav + actions (right). The auto
|
|
124
|
+
* center column keeps the search trigger centered in the bar regardless of how wide
|
|
125
|
+
* the side zones are. */
|
|
126
|
+
display: grid;
|
|
127
|
+
grid-template-columns: 1fr auto 1fr;
|
|
128
|
+
align-items: center;
|
|
129
|
+
gap: 1.5rem;
|
|
130
|
+
}
|
|
131
|
+
.otfw-navbar-search {
|
|
132
|
+
justify-self: center;
|
|
133
|
+
}
|
|
134
|
+
.otfw-navbar-right {
|
|
135
|
+
justify-self: end;
|
|
112
136
|
display: flex;
|
|
113
137
|
align-items: center;
|
|
114
138
|
gap: 1.5rem;
|
|
@@ -126,38 +150,256 @@ web-sidebar-node {
|
|
|
126
150
|
width: 1.75rem;
|
|
127
151
|
height: 1.75rem;
|
|
128
152
|
}
|
|
153
|
+
.otfw-navbar-version {
|
|
154
|
+
display: inline-flex;
|
|
155
|
+
align-items: center;
|
|
156
|
+
line-height: 1;
|
|
157
|
+
padding: 0.22rem 0.45rem;
|
|
158
|
+
border-radius: 0.4rem;
|
|
159
|
+
border: 1px solid var(--otfw-border);
|
|
160
|
+
background: var(--otfw-bg-surface);
|
|
161
|
+
color: var(--otfw-text-muted);
|
|
162
|
+
font-size: 0.62rem;
|
|
163
|
+
font-weight: 700;
|
|
164
|
+
letter-spacing: 0.03em;
|
|
165
|
+
text-transform: uppercase;
|
|
166
|
+
}
|
|
167
|
+
/* Brand sits at the start of the left grid zone. */
|
|
168
|
+
.otfw-navbar-brand {
|
|
169
|
+
justify-self: start;
|
|
170
|
+
}
|
|
129
171
|
.otfw-navbar-nav {
|
|
130
172
|
display: flex;
|
|
131
|
-
|
|
132
|
-
|
|
173
|
+
align-items: center;
|
|
174
|
+
gap: 1.5rem;
|
|
133
175
|
font-size: 0.9rem;
|
|
134
176
|
}
|
|
135
177
|
.otfw-navbar-link {
|
|
178
|
+
position: relative;
|
|
179
|
+
display: inline-flex;
|
|
180
|
+
align-items: center;
|
|
181
|
+
gap: 0.4rem;
|
|
136
182
|
color: var(--otfw-text-muted);
|
|
137
183
|
text-decoration: none;
|
|
138
184
|
font-weight: 500;
|
|
139
185
|
transition: color 0.15s;
|
|
140
186
|
}
|
|
187
|
+
/* Subtle accent underline beneath the link; scales in on the active route (and
|
|
188
|
+
* faintly on hover). */
|
|
189
|
+
.otfw-navbar-link::after {
|
|
190
|
+
content: "";
|
|
191
|
+
position: absolute;
|
|
192
|
+
left: 0;
|
|
193
|
+
right: 0;
|
|
194
|
+
bottom: -0.45rem;
|
|
195
|
+
height: 2px;
|
|
196
|
+
border-radius: 2px;
|
|
197
|
+
background: var(--otfw-accent);
|
|
198
|
+
transform: scaleX(0);
|
|
199
|
+
transition: transform 0.18s ease, opacity 0.18s ease;
|
|
200
|
+
}
|
|
141
201
|
.otfw-navbar-link:hover {
|
|
142
202
|
color: var(--otfw-text);
|
|
143
203
|
}
|
|
204
|
+
.otfw-navbar-link:hover::after {
|
|
205
|
+
transform: scaleX(1);
|
|
206
|
+
opacity: 0.35;
|
|
207
|
+
}
|
|
208
|
+
.otfw-navbar-link.otfw-active {
|
|
209
|
+
color: var(--otfw-text);
|
|
210
|
+
font-weight: 600;
|
|
211
|
+
}
|
|
212
|
+
.otfw-navbar-link.otfw-active::after {
|
|
213
|
+
transform: scaleX(1);
|
|
214
|
+
opacity: 1;
|
|
215
|
+
}
|
|
216
|
+
.otfw-nav-icon {
|
|
217
|
+
display: inline-flex;
|
|
218
|
+
}
|
|
219
|
+
.otfw-nav-icon svg {
|
|
220
|
+
display: block;
|
|
221
|
+
}
|
|
144
222
|
.otfw-navbar-actions {
|
|
145
223
|
display: flex;
|
|
146
224
|
align-items: center;
|
|
147
225
|
gap: 0.5rem;
|
|
148
226
|
}
|
|
227
|
+
/* GitHub link and theme toggle are uniform ghost icon buttons (no border/fill, subtle
|
|
228
|
+
* hover background), so the whole right cluster (links + icons) reads as one aligned
|
|
229
|
+
* row. */
|
|
149
230
|
.otfw-navbar-icon {
|
|
150
231
|
display: inline-flex;
|
|
151
|
-
|
|
232
|
+
align-items: center;
|
|
233
|
+
justify-content: center;
|
|
234
|
+
width: 2rem;
|
|
235
|
+
height: 2rem;
|
|
236
|
+
padding: 0;
|
|
237
|
+
border: none;
|
|
238
|
+
background: none;
|
|
152
239
|
border-radius: 0.5rem;
|
|
153
240
|
color: var(--otfw-text-muted);
|
|
241
|
+
cursor: pointer;
|
|
242
|
+
font-family: inherit;
|
|
243
|
+
/* Icons compile to inline custom-element hosts with the inherited 1.5 line-height,
|
|
244
|
+
* which baseline-aligns the SVG and pushes it a few px above center. Zero the line
|
|
245
|
+
* box so the flex centering is exact. */
|
|
246
|
+
line-height: 0;
|
|
247
|
+
}
|
|
248
|
+
.otfw-navbar-icon > * {
|
|
249
|
+
display: inline-flex;
|
|
250
|
+
align-items: center;
|
|
154
251
|
}
|
|
155
252
|
.otfw-navbar-icon:hover {
|
|
156
253
|
color: var(--otfw-text);
|
|
157
254
|
background: var(--otfw-bg-surface);
|
|
158
255
|
}
|
|
159
256
|
|
|
160
|
-
.
|
|
257
|
+
/* Left zone of the navbar: an optional mobile drawer burger followed by the brand. */
|
|
258
|
+
.otfw-navbar-lead {
|
|
259
|
+
justify-self: start;
|
|
260
|
+
display: flex;
|
|
261
|
+
align-items: center;
|
|
262
|
+
gap: 0.5rem;
|
|
263
|
+
min-width: 0;
|
|
264
|
+
}
|
|
265
|
+
/* The burger reuses `.otfw-navbar-icon` styling; this rule (after it, so it wins the
|
|
266
|
+
* display cascade) hides it except on small screens that actually have a sidebar
|
|
267
|
+
* mounted — the <Sidebar> sets `data-otfw-has-sidebar` on the root while present. */
|
|
268
|
+
.otfw-navbar-burger {
|
|
269
|
+
display: none;
|
|
270
|
+
}
|
|
271
|
+
@media (max-width: 767px) {
|
|
272
|
+
:root[data-otfw-has-sidebar] .otfw-navbar-burger {
|
|
273
|
+
display: inline-flex;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/* ── Navbar: mobile layout ─────────────────────────────────────────────────── */
|
|
278
|
+
/* Below the sidebar breakpoint the centered three-column grid gets cramped, so the bar
|
|
279
|
+
* becomes a simple flex row: brand (with burger) at the start, a compact action cluster
|
|
280
|
+
* (search · GitHub · theme) at the end. On pages that have a sidebar the top-level links
|
|
281
|
+
* move into the drawer (see `.otfw-drawer-links`), so they're dropped from the bar here. */
|
|
282
|
+
@media (max-width: 767px) {
|
|
283
|
+
.otfw-navbar-inner {
|
|
284
|
+
display: flex;
|
|
285
|
+
align-items: center;
|
|
286
|
+
gap: 0.5rem;
|
|
287
|
+
padding: 0 1rem;
|
|
288
|
+
}
|
|
289
|
+
.otfw-navbar-lead {
|
|
290
|
+
margin-right: auto; /* push the action cluster to the far end */
|
|
291
|
+
}
|
|
292
|
+
.otfw-navbar-search {
|
|
293
|
+
justify-self: auto;
|
|
294
|
+
}
|
|
295
|
+
.otfw-navbar-right {
|
|
296
|
+
gap: 0.5rem;
|
|
297
|
+
}
|
|
298
|
+
.otfw-navbar-version {
|
|
299
|
+
display: none; /* reclaim brand width on small screens */
|
|
300
|
+
}
|
|
301
|
+
:root[data-otfw-has-sidebar] .otfw-navbar-nav {
|
|
302
|
+
display: none; /* surfaced in the drawer instead */
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/* Theme switcher: trigger reuses `.otfw-navbar-icon` so it matches the GitHub button;
|
|
307
|
+
* it just grows a little to fit the System-mode pair of icons, and anchors the menu. */
|
|
308
|
+
.otfw-theme {
|
|
309
|
+
position: relative;
|
|
310
|
+
display: inline-flex;
|
|
311
|
+
}
|
|
312
|
+
.otfw-theme-trigger {
|
|
313
|
+
width: auto;
|
|
314
|
+
min-width: 2rem;
|
|
315
|
+
padding: 0 0.3rem;
|
|
316
|
+
}
|
|
317
|
+
.otfw-theme-trigger-system {
|
|
318
|
+
display: inline-flex;
|
|
319
|
+
align-items: center;
|
|
320
|
+
gap: 0.3rem;
|
|
321
|
+
}
|
|
322
|
+
.otfw-theme-trigger-badge {
|
|
323
|
+
display: inline-flex;
|
|
324
|
+
align-items: center;
|
|
325
|
+
padding-left: 0.3rem;
|
|
326
|
+
border-left: 1px solid var(--otfw-border);
|
|
327
|
+
opacity: 0.85;
|
|
328
|
+
}
|
|
329
|
+
.otfw-theme-menu {
|
|
330
|
+
position: absolute;
|
|
331
|
+
top: calc(100% + 0.4rem);
|
|
332
|
+
right: 0;
|
|
333
|
+
z-index: 60;
|
|
334
|
+
min-width: 9rem;
|
|
335
|
+
padding: 0.3rem;
|
|
336
|
+
display: flex;
|
|
337
|
+
flex-direction: column;
|
|
338
|
+
gap: 0.1rem;
|
|
339
|
+
background: var(--otfw-bg-elevated);
|
|
340
|
+
border: 1px solid var(--otfw-border);
|
|
341
|
+
border-radius: 0.6rem;
|
|
342
|
+
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.18);
|
|
343
|
+
}
|
|
344
|
+
.otfw-theme-item {
|
|
345
|
+
display: flex;
|
|
346
|
+
width: 100%;
|
|
347
|
+
align-items: center;
|
|
348
|
+
gap: 0.55rem;
|
|
349
|
+
padding: 0.45rem 0.6rem;
|
|
350
|
+
border: none;
|
|
351
|
+
background: none;
|
|
352
|
+
border-radius: 0.4rem;
|
|
353
|
+
color: var(--otfw-text-muted);
|
|
354
|
+
font: inherit;
|
|
355
|
+
font-size: 0.85rem;
|
|
356
|
+
text-align: left;
|
|
357
|
+
cursor: pointer;
|
|
358
|
+
}
|
|
359
|
+
.otfw-theme-item:hover {
|
|
360
|
+
background: var(--otfw-bg-surface);
|
|
361
|
+
color: var(--otfw-text);
|
|
362
|
+
}
|
|
363
|
+
.otfw-theme-item.is-active {
|
|
364
|
+
color: var(--otfw-accent);
|
|
365
|
+
font-weight: 600;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/* Tooltip (hover/focus) — a small contrasting bubble. */
|
|
369
|
+
.otfw-tooltip {
|
|
370
|
+
position: relative;
|
|
371
|
+
display: inline-flex;
|
|
372
|
+
}
|
|
373
|
+
.otfw-tooltip-bubble {
|
|
374
|
+
position: absolute;
|
|
375
|
+
left: 50%;
|
|
376
|
+
transform: translateX(-50%) translateY(3px);
|
|
377
|
+
white-space: nowrap;
|
|
378
|
+
padding: 0.28rem 0.5rem;
|
|
379
|
+
border-radius: 0.4rem;
|
|
380
|
+
background: var(--otfw-text);
|
|
381
|
+
color: var(--otfw-bg);
|
|
382
|
+
font-size: 0.72rem;
|
|
383
|
+
font-weight: 500;
|
|
384
|
+
opacity: 0;
|
|
385
|
+
pointer-events: none;
|
|
386
|
+
transition: opacity 0.12s ease, transform 0.12s ease;
|
|
387
|
+
z-index: 70;
|
|
388
|
+
}
|
|
389
|
+
.otfw-tooltip-bottom .otfw-tooltip-bubble {
|
|
390
|
+
top: 100%;
|
|
391
|
+
margin-top: 0.45rem;
|
|
392
|
+
}
|
|
393
|
+
.otfw-tooltip-top .otfw-tooltip-bubble {
|
|
394
|
+
bottom: 100%;
|
|
395
|
+
margin-bottom: 0.45rem;
|
|
396
|
+
}
|
|
397
|
+
.otfw-tooltip:hover .otfw-tooltip-bubble,
|
|
398
|
+
.otfw-tooltip:focus-within .otfw-tooltip-bubble {
|
|
399
|
+
opacity: 1;
|
|
400
|
+
transform: translateX(-50%) translateY(0);
|
|
401
|
+
}
|
|
402
|
+
|
|
161
403
|
.otfw-search-trigger {
|
|
162
404
|
display: inline-flex;
|
|
163
405
|
align-items: center;
|
|
@@ -168,25 +410,30 @@ web-sidebar-node {
|
|
|
168
410
|
border-radius: 0.5rem;
|
|
169
411
|
cursor: pointer;
|
|
170
412
|
font-family: inherit;
|
|
413
|
+
padding: 0.4rem 0.65rem;
|
|
414
|
+
font-size: 0.82rem;
|
|
171
415
|
}
|
|
172
|
-
.otfw-theme-toggle {
|
|
173
|
-
padding: 0.4rem;
|
|
174
|
-
}
|
|
175
|
-
.otfw-theme-toggle:hover,
|
|
176
416
|
.otfw-search-trigger:hover {
|
|
177
417
|
color: var(--otfw-accent);
|
|
178
418
|
border-color: var(--otfw-accent);
|
|
179
419
|
}
|
|
180
|
-
.otfw-search-trigger {
|
|
181
|
-
padding: 0.4rem 0.65rem;
|
|
182
|
-
font-size: 0.82rem;
|
|
183
|
-
}
|
|
184
420
|
.otfw-search-kbd {
|
|
421
|
+
display: none;
|
|
422
|
+
align-items: center;
|
|
423
|
+
height: 1.25rem;
|
|
424
|
+
padding: 0 0.35rem;
|
|
185
425
|
border: 1px solid var(--otfw-border);
|
|
186
426
|
border-radius: 0.3rem;
|
|
187
|
-
|
|
188
|
-
|
|
427
|
+
background: var(--otfw-bg);
|
|
428
|
+
color: var(--otfw-text-muted);
|
|
189
429
|
font-family: var(--otfw-mono);
|
|
430
|
+
font-size: 0.68rem;
|
|
431
|
+
line-height: 1;
|
|
432
|
+
}
|
|
433
|
+
@media (min-width: 768px) {
|
|
434
|
+
.otfw-search-kbd {
|
|
435
|
+
display: inline-flex;
|
|
436
|
+
}
|
|
190
437
|
}
|
|
191
438
|
.otfw-search-label {
|
|
192
439
|
display: none;
|
|
@@ -197,6 +444,147 @@ web-sidebar-node {
|
|
|
197
444
|
}
|
|
198
445
|
}
|
|
199
446
|
|
|
447
|
+
/* ── Search modal (Pagefind) ───────────────────────────────────────────────── */
|
|
448
|
+
.web-search {
|
|
449
|
+
display: contents;
|
|
450
|
+
}
|
|
451
|
+
.otfw-search-modal {
|
|
452
|
+
position: fixed;
|
|
453
|
+
inset: 0;
|
|
454
|
+
z-index: 100;
|
|
455
|
+
display: none;
|
|
456
|
+
align-items: flex-start;
|
|
457
|
+
justify-content: center;
|
|
458
|
+
padding: 12vh 1rem 1rem;
|
|
459
|
+
background: color-mix(in srgb, #000 45%, transparent);
|
|
460
|
+
backdrop-filter: blur(2px);
|
|
461
|
+
}
|
|
462
|
+
.otfw-search-modal.is-open {
|
|
463
|
+
display: flex;
|
|
464
|
+
}
|
|
465
|
+
.otfw-search-panel {
|
|
466
|
+
width: 100%;
|
|
467
|
+
max-width: 36rem;
|
|
468
|
+
max-height: 70vh;
|
|
469
|
+
display: flex;
|
|
470
|
+
flex-direction: column;
|
|
471
|
+
background: var(--otfw-bg-elevated);
|
|
472
|
+
border: 1px solid var(--otfw-border);
|
|
473
|
+
border-radius: 0.9rem;
|
|
474
|
+
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
|
|
475
|
+
overflow: hidden;
|
|
476
|
+
}
|
|
477
|
+
.otfw-search-field {
|
|
478
|
+
display: flex;
|
|
479
|
+
align-items: center;
|
|
480
|
+
gap: 0.6rem;
|
|
481
|
+
padding: 0.85rem 1rem;
|
|
482
|
+
border-bottom: 1px solid var(--otfw-border);
|
|
483
|
+
color: var(--otfw-text-muted);
|
|
484
|
+
}
|
|
485
|
+
.otfw-search-input-field {
|
|
486
|
+
flex: 1;
|
|
487
|
+
min-width: 0;
|
|
488
|
+
border: none;
|
|
489
|
+
background: none;
|
|
490
|
+
outline: none;
|
|
491
|
+
font: inherit;
|
|
492
|
+
font-size: 1rem;
|
|
493
|
+
color: var(--otfw-text);
|
|
494
|
+
}
|
|
495
|
+
/* Keyboard hint row beneath the input / results. */
|
|
496
|
+
.otfw-search-hint {
|
|
497
|
+
display: flex;
|
|
498
|
+
flex-wrap: wrap;
|
|
499
|
+
gap: 1rem;
|
|
500
|
+
padding: 0.6rem 1rem;
|
|
501
|
+
border-top: 1px solid var(--otfw-border);
|
|
502
|
+
color: var(--otfw-text-muted);
|
|
503
|
+
font-size: 0.72rem;
|
|
504
|
+
}
|
|
505
|
+
.otfw-search-hint-item {
|
|
506
|
+
display: inline-flex;
|
|
507
|
+
align-items: center;
|
|
508
|
+
gap: 0.3rem;
|
|
509
|
+
}
|
|
510
|
+
.otfw-search-hint kbd {
|
|
511
|
+
display: inline-flex;
|
|
512
|
+
align-items: center;
|
|
513
|
+
justify-content: center;
|
|
514
|
+
min-width: 1.3rem;
|
|
515
|
+
height: 1.3rem;
|
|
516
|
+
padding: 0 0.35rem;
|
|
517
|
+
border: 1px solid var(--otfw-border);
|
|
518
|
+
border-bottom-width: 2px;
|
|
519
|
+
border-radius: 0.3rem;
|
|
520
|
+
background: var(--otfw-bg-surface);
|
|
521
|
+
color: var(--otfw-text);
|
|
522
|
+
font-family: var(--otfw-mono);
|
|
523
|
+
font-size: 0.7rem;
|
|
524
|
+
line-height: 1;
|
|
525
|
+
}
|
|
526
|
+
.otfw-search-results {
|
|
527
|
+
list-style: none;
|
|
528
|
+
margin: 0;
|
|
529
|
+
padding: 0.4rem;
|
|
530
|
+
overflow-y: auto;
|
|
531
|
+
}
|
|
532
|
+
.otfw-search-result {
|
|
533
|
+
display: block;
|
|
534
|
+
padding: 0.6rem 0.75rem;
|
|
535
|
+
border-radius: 0.5rem;
|
|
536
|
+
text-decoration: none;
|
|
537
|
+
color: var(--otfw-text);
|
|
538
|
+
}
|
|
539
|
+
.otfw-search-result.is-active {
|
|
540
|
+
background: var(--otfw-accent-soft);
|
|
541
|
+
}
|
|
542
|
+
.otfw-search-result-crumb {
|
|
543
|
+
display: block;
|
|
544
|
+
font-size: 0.72rem;
|
|
545
|
+
color: var(--otfw-text-muted);
|
|
546
|
+
letter-spacing: 0.01em;
|
|
547
|
+
margin-bottom: 0.1rem;
|
|
548
|
+
}
|
|
549
|
+
.otfw-search-result-title {
|
|
550
|
+
display: block;
|
|
551
|
+
font-weight: 600;
|
|
552
|
+
font-size: 0.9rem;
|
|
553
|
+
}
|
|
554
|
+
/* The matched section heading, under the page/post title. */
|
|
555
|
+
.otfw-search-result-section {
|
|
556
|
+
display: flex;
|
|
557
|
+
align-items: center;
|
|
558
|
+
gap: 0.3rem;
|
|
559
|
+
font-size: 0.8rem;
|
|
560
|
+
color: var(--otfw-text-muted);
|
|
561
|
+
margin-top: 0.05rem;
|
|
562
|
+
}
|
|
563
|
+
.otfw-search-result-section::before {
|
|
564
|
+
content: "#";
|
|
565
|
+
color: var(--otfw-accent);
|
|
566
|
+
font-weight: 700;
|
|
567
|
+
}
|
|
568
|
+
.otfw-search-result-excerpt {
|
|
569
|
+
display: block;
|
|
570
|
+
font-size: 0.8rem;
|
|
571
|
+
color: var(--otfw-text-muted);
|
|
572
|
+
margin-top: 0.15rem;
|
|
573
|
+
line-height: 1.5;
|
|
574
|
+
}
|
|
575
|
+
.otfw-search-result-excerpt mark {
|
|
576
|
+
background: var(--otfw-accent-soft);
|
|
577
|
+
color: var(--otfw-accent);
|
|
578
|
+
border-radius: 0.2rem;
|
|
579
|
+
padding: 0 0.1rem;
|
|
580
|
+
}
|
|
581
|
+
.otfw-search-empty {
|
|
582
|
+
padding: 1.5rem 1rem;
|
|
583
|
+
text-align: center;
|
|
584
|
+
color: var(--otfw-text-muted);
|
|
585
|
+
font-size: 0.9rem;
|
|
586
|
+
}
|
|
587
|
+
|
|
200
588
|
/* ── Docs grid ─────────────────────────────────────────────────────────────── */
|
|
201
589
|
.otfw-docs {
|
|
202
590
|
max-width: 90rem;
|
|
@@ -218,20 +606,92 @@ web-sidebar-node {
|
|
|
218
606
|
}
|
|
219
607
|
|
|
220
608
|
/* ── Sidebar ───────────────────────────────────────────────────────────────── */
|
|
609
|
+
/* Mobile-first: the sidebar is an off-canvas drawer below the navbar, slid in over a
|
|
610
|
+
* backdrop. It sits *under* the navbar (z < navbar's 50) so the burger stays tappable
|
|
611
|
+
* to toggle it. The desktop block below turns it back into the sticky grid column. */
|
|
221
612
|
.otfw-sidebar {
|
|
222
|
-
|
|
613
|
+
position: fixed;
|
|
614
|
+
top: var(--otfw-navbar-height);
|
|
615
|
+
bottom: 0;
|
|
616
|
+
left: 0;
|
|
617
|
+
z-index: 40;
|
|
618
|
+
width: min(19rem, 80vw);
|
|
619
|
+
padding: 1.25rem 1.1rem 2rem;
|
|
620
|
+
overflow-y: auto;
|
|
621
|
+
overscroll-behavior: contain;
|
|
622
|
+
background: var(--otfw-bg);
|
|
623
|
+
border-right: 1px solid var(--otfw-border);
|
|
624
|
+
transform: translateX(-100%);
|
|
625
|
+
visibility: hidden;
|
|
626
|
+
transition: transform 0.25s ease, visibility 0.25s ease;
|
|
627
|
+
}
|
|
628
|
+
.otfw-sidebar.is-open {
|
|
629
|
+
transform: translateX(0);
|
|
630
|
+
visibility: visible;
|
|
631
|
+
}
|
|
632
|
+
.otfw-sidebar-backdrop {
|
|
633
|
+
position: fixed;
|
|
634
|
+
top: var(--otfw-navbar-height);
|
|
635
|
+
inset-inline: 0;
|
|
636
|
+
bottom: 0;
|
|
637
|
+
z-index: 39;
|
|
638
|
+
background: color-mix(in srgb, var(--otfw-text) 45%, transparent);
|
|
639
|
+
opacity: 0;
|
|
640
|
+
pointer-events: none;
|
|
641
|
+
transition: opacity 0.25s ease;
|
|
642
|
+
}
|
|
643
|
+
.otfw-sidebar-backdrop.is-open {
|
|
644
|
+
opacity: 1;
|
|
645
|
+
pointer-events: auto;
|
|
223
646
|
}
|
|
224
647
|
@media (min-width: 768px) {
|
|
225
648
|
.otfw-sidebar {
|
|
226
|
-
display: block;
|
|
227
649
|
position: sticky;
|
|
228
650
|
top: var(--otfw-navbar-height);
|
|
651
|
+
bottom: auto;
|
|
652
|
+
left: auto;
|
|
653
|
+
z-index: auto;
|
|
654
|
+
width: auto;
|
|
229
655
|
align-self: start;
|
|
230
656
|
max-height: calc(100vh - var(--otfw-navbar-height));
|
|
231
657
|
overflow-y: auto;
|
|
232
658
|
padding: 2rem 0.5rem 2rem 0;
|
|
659
|
+
background: none;
|
|
660
|
+
border-right: none;
|
|
661
|
+
transform: none;
|
|
662
|
+
visibility: visible;
|
|
663
|
+
}
|
|
664
|
+
.otfw-sidebar-backdrop {
|
|
665
|
+
display: none;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
@media (prefers-reduced-motion: reduce) {
|
|
669
|
+
.otfw-sidebar,
|
|
670
|
+
.otfw-sidebar-backdrop {
|
|
671
|
+
transition: none;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/* Top-level site links shown at the top of the mobile drawer (the navbar hides its own
|
|
676
|
+
* copy there). Hidden on desktop, where those links stay in the navbar and the sidebar
|
|
677
|
+
* shows only the section tree. The links are NavbarLink elements, stacked into a column
|
|
678
|
+
* and separated from the tree by a divider. */
|
|
679
|
+
.otfw-drawer-links {
|
|
680
|
+
display: none;
|
|
681
|
+
}
|
|
682
|
+
@media (max-width: 767px) {
|
|
683
|
+
.otfw-drawer-links {
|
|
684
|
+
display: flex;
|
|
685
|
+
flex-direction: column;
|
|
686
|
+
align-items: flex-start;
|
|
687
|
+
gap: 0.9rem;
|
|
688
|
+
margin-bottom: 1.25rem;
|
|
689
|
+
padding-bottom: 1.25rem;
|
|
690
|
+
border-bottom: 1px solid var(--otfw-border);
|
|
691
|
+
font-size: 0.95rem;
|
|
233
692
|
}
|
|
234
693
|
}
|
|
694
|
+
|
|
235
695
|
.otfw-sidebar-list,
|
|
236
696
|
.otfw-sidebar-sublist {
|
|
237
697
|
list-style: none;
|
|
@@ -256,23 +716,40 @@ web-sidebar-node {
|
|
|
256
716
|
color: var(--otfw-text-muted);
|
|
257
717
|
}
|
|
258
718
|
.otfw-sidebar-link {
|
|
259
|
-
display:
|
|
260
|
-
|
|
719
|
+
display: flex;
|
|
720
|
+
align-items: center;
|
|
721
|
+
gap: 0.6rem;
|
|
722
|
+
padding: 0.35rem 0.6rem;
|
|
261
723
|
border-radius: 0.45rem;
|
|
262
724
|
font-size: 0.875rem;
|
|
263
725
|
color: var(--otfw-text-muted);
|
|
264
726
|
text-decoration: none;
|
|
265
727
|
transition: color 0.12s, background 0.12s;
|
|
266
728
|
}
|
|
729
|
+
.otfw-sidebar-dot {
|
|
730
|
+
flex: none;
|
|
731
|
+
width: 5px;
|
|
732
|
+
height: 5px;
|
|
733
|
+
border-radius: 99px;
|
|
734
|
+
background: currentColor;
|
|
735
|
+
opacity: 0.35;
|
|
736
|
+
transition: opacity 0.12s;
|
|
737
|
+
}
|
|
267
738
|
.otfw-sidebar-link:hover {
|
|
268
739
|
color: var(--otfw-text);
|
|
269
740
|
background: var(--otfw-bg-surface);
|
|
270
741
|
}
|
|
742
|
+
.otfw-sidebar-link:hover .otfw-sidebar-dot {
|
|
743
|
+
opacity: 0.6;
|
|
744
|
+
}
|
|
271
745
|
.otfw-sidebar-link.otfw-active {
|
|
272
746
|
color: var(--otfw-accent);
|
|
273
747
|
background: var(--otfw-accent-soft);
|
|
274
748
|
font-weight: 600;
|
|
275
749
|
}
|
|
750
|
+
.otfw-sidebar-link.otfw-active .otfw-sidebar-dot {
|
|
751
|
+
opacity: 1;
|
|
752
|
+
}
|
|
276
753
|
|
|
277
754
|
/* ── Content ───────────────────────────────────────────────────────────────── */
|
|
278
755
|
.otfw-content {
|
|
@@ -302,10 +779,55 @@ web-sidebar-node {
|
|
|
302
779
|
font-weight: 700;
|
|
303
780
|
margin: 2rem 0 0.75rem;
|
|
304
781
|
}
|
|
782
|
+
.otfw-prose h4 {
|
|
783
|
+
font-size: 1.05rem;
|
|
784
|
+
font-weight: 700;
|
|
785
|
+
margin: 1.6rem 0 0.6rem;
|
|
786
|
+
}
|
|
787
|
+
.otfw-prose h5 {
|
|
788
|
+
font-size: 0.95rem;
|
|
789
|
+
font-weight: 700;
|
|
790
|
+
margin: 1.4rem 0 0.5rem;
|
|
791
|
+
}
|
|
792
|
+
.otfw-prose h6 {
|
|
793
|
+
font-size: 0.85rem;
|
|
794
|
+
font-weight: 700;
|
|
795
|
+
text-transform: uppercase;
|
|
796
|
+
letter-spacing: 0.04em;
|
|
797
|
+
color: var(--otfw-text-muted);
|
|
798
|
+
margin: 1.3rem 0 0.5rem;
|
|
799
|
+
}
|
|
800
|
+
.otfw-prose h1,
|
|
305
801
|
.otfw-prose h2,
|
|
306
|
-
.otfw-prose h3
|
|
802
|
+
.otfw-prose h3,
|
|
803
|
+
.otfw-prose h4,
|
|
804
|
+
.otfw-prose h5,
|
|
805
|
+
.otfw-prose h6 {
|
|
307
806
|
scroll-margin-top: calc(var(--otfw-navbar-height) + 1rem);
|
|
308
807
|
}
|
|
808
|
+
|
|
809
|
+
/* Self-linking heading anchor (the hover `#`). Hidden until the heading is
|
|
810
|
+
hovered or the anchor itself is focused, so it doesn't clutter the page. */
|
|
811
|
+
.otfw-heading-anchor {
|
|
812
|
+
margin-left: 0.4rem;
|
|
813
|
+
color: var(--otfw-text-muted);
|
|
814
|
+
font-weight: 400;
|
|
815
|
+
text-decoration: none;
|
|
816
|
+
opacity: 0;
|
|
817
|
+
transition: opacity 0.12s ease;
|
|
818
|
+
}
|
|
819
|
+
/* The `#` is presentational only — drawn here, not as a DOM text node, so it never
|
|
820
|
+
leaks into heading text read by the TOC or the search index. */
|
|
821
|
+
.otfw-heading-anchor::before {
|
|
822
|
+
content: "#";
|
|
823
|
+
}
|
|
824
|
+
.otfw-prose :is(h1, h2, h3, h4, h5, h6):hover .otfw-heading-anchor,
|
|
825
|
+
.otfw-heading-anchor:focus-visible {
|
|
826
|
+
opacity: 1;
|
|
827
|
+
}
|
|
828
|
+
.otfw-heading-anchor:hover {
|
|
829
|
+
color: var(--otfw-accent);
|
|
830
|
+
}
|
|
309
831
|
.otfw-prose p,
|
|
310
832
|
.otfw-prose ul,
|
|
311
833
|
.otfw-prose ol {
|
|
@@ -317,9 +839,83 @@ web-sidebar-node {
|
|
|
317
839
|
.otfw-prose ol {
|
|
318
840
|
padding-left: 1.4rem;
|
|
319
841
|
}
|
|
842
|
+
/* Restore list markers: the Tailwind preflight reset (@import "tailwindcss") sets
|
|
843
|
+
* `list-style: none` on every ul/ol, which strips bullets and numbers from prose. */
|
|
844
|
+
.otfw-prose ul {
|
|
845
|
+
list-style: disc;
|
|
846
|
+
}
|
|
847
|
+
.otfw-prose ul ul {
|
|
848
|
+
list-style: circle;
|
|
849
|
+
}
|
|
850
|
+
.otfw-prose ol {
|
|
851
|
+
list-style: decimal;
|
|
852
|
+
}
|
|
320
853
|
.otfw-prose li {
|
|
321
854
|
margin: 0.35rem 0;
|
|
322
855
|
}
|
|
856
|
+
/* Loose list items wrap their content in <p>; keep that from adding block spacing. */
|
|
857
|
+
.otfw-prose li > p {
|
|
858
|
+
margin: 0;
|
|
859
|
+
}
|
|
860
|
+
/* GFM task list: drop the bullet and keep the checkbox inline with its label
|
|
861
|
+
* (the label is a block <p>, which would otherwise wrap to the next line). */
|
|
862
|
+
.otfw-prose li:has(> input[type="checkbox"]) {
|
|
863
|
+
list-style: none;
|
|
864
|
+
}
|
|
865
|
+
.otfw-prose li:has(> input[type="checkbox"]) > p {
|
|
866
|
+
display: inline;
|
|
867
|
+
}
|
|
868
|
+
/* Custom checkbox so checked vs. unchecked read at a glance (the native disabled
|
|
869
|
+
* box is nearly identical in both states). Unchecked is an empty bordered box;
|
|
870
|
+
* checked fills with the accent and draws a white tick. */
|
|
871
|
+
.otfw-prose li > input[type="checkbox"] {
|
|
872
|
+
appearance: none;
|
|
873
|
+
-webkit-appearance: none;
|
|
874
|
+
width: 1.05rem;
|
|
875
|
+
height: 1.05rem;
|
|
876
|
+
margin: 0 0.55em 0 0;
|
|
877
|
+
border: 1.5px solid var(--otfw-border);
|
|
878
|
+
border-radius: 0.3rem;
|
|
879
|
+
background: var(--otfw-bg-surface);
|
|
880
|
+
vertical-align: -0.18em;
|
|
881
|
+
position: relative;
|
|
882
|
+
opacity: 1; /* override the browser's disabled-input dimming */
|
|
883
|
+
cursor: default;
|
|
884
|
+
}
|
|
885
|
+
.otfw-prose li > input[type="checkbox"]:checked {
|
|
886
|
+
background: var(--otfw-accent);
|
|
887
|
+
border-color: var(--otfw-accent);
|
|
888
|
+
}
|
|
889
|
+
.otfw-prose li > input[type="checkbox"]:checked::after {
|
|
890
|
+
content: "";
|
|
891
|
+
position: absolute;
|
|
892
|
+
left: 0.34rem;
|
|
893
|
+
top: 0.13rem;
|
|
894
|
+
width: 0.26rem;
|
|
895
|
+
height: 0.52rem;
|
|
896
|
+
border: solid #fff;
|
|
897
|
+
border-width: 0 2px 2px 0;
|
|
898
|
+
transform: rotate(45deg);
|
|
899
|
+
}
|
|
900
|
+
/* Completed items: mute the label (the filled check already marks it done). */
|
|
901
|
+
.otfw-prose li:has(> input[type="checkbox"]:checked) > p {
|
|
902
|
+
color: var(--otfw-text-muted);
|
|
903
|
+
}
|
|
904
|
+
/* An unclassed <button> in prose (e.g. an inline interactive demo). Component
|
|
905
|
+
* buttons carry their own class, so this only catches bare demo buttons. */
|
|
906
|
+
.otfw-prose button:not([class]) {
|
|
907
|
+
font: inherit;
|
|
908
|
+
cursor: pointer;
|
|
909
|
+
padding: 0.4rem 0.9rem;
|
|
910
|
+
border: 1px solid var(--otfw-border);
|
|
911
|
+
border-radius: 0.5rem;
|
|
912
|
+
background: var(--otfw-bg-surface);
|
|
913
|
+
color: inherit;
|
|
914
|
+
transition: border-color 0.15s ease, background 0.15s ease;
|
|
915
|
+
}
|
|
916
|
+
.otfw-prose button:not([class]):hover {
|
|
917
|
+
border-color: var(--otfw-accent);
|
|
918
|
+
}
|
|
323
919
|
.otfw-prose a {
|
|
324
920
|
color: var(--otfw-accent);
|
|
325
921
|
text-decoration: none;
|
|
@@ -356,6 +952,80 @@ web-sidebar-node {
|
|
|
356
952
|
padding: 0;
|
|
357
953
|
font-size: inherit;
|
|
358
954
|
}
|
|
955
|
+
/* Titled code block (built by the MDX front-end): a header bar — language label,
|
|
956
|
+
* optional filename, and a copy button on the right — above the highlighted <pre>.
|
|
957
|
+
* The wrapper owns the radius and clips the corners of the dark header and code. */
|
|
958
|
+
.otfw-code {
|
|
959
|
+
margin: 0 0 1.4rem;
|
|
960
|
+
border: 1px solid var(--otfw-border);
|
|
961
|
+
border-radius: var(--otfw-radius);
|
|
962
|
+
overflow: hidden;
|
|
963
|
+
background: #2b303b;
|
|
964
|
+
}
|
|
965
|
+
.otfw-code-head {
|
|
966
|
+
display: flex;
|
|
967
|
+
align-items: center;
|
|
968
|
+
gap: 0.55rem;
|
|
969
|
+
padding: 0.4rem 0.5rem 0.4rem 0.95rem;
|
|
970
|
+
background: #23272f;
|
|
971
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.07);
|
|
972
|
+
}
|
|
973
|
+
.otfw-code-lang {
|
|
974
|
+
text-transform: uppercase;
|
|
975
|
+
letter-spacing: 0.05em;
|
|
976
|
+
font-size: 0.66rem;
|
|
977
|
+
font-weight: 700;
|
|
978
|
+
color: rgba(255, 255, 255, 0.45);
|
|
979
|
+
}
|
|
980
|
+
.otfw-code-name {
|
|
981
|
+
font-family: var(--otfw-mono);
|
|
982
|
+
font-size: 0.78rem;
|
|
983
|
+
color: rgba(255, 255, 255, 0.82);
|
|
984
|
+
}
|
|
985
|
+
.otfw-code pre {
|
|
986
|
+
margin: 0;
|
|
987
|
+
border: none;
|
|
988
|
+
border-radius: 0;
|
|
989
|
+
/* Readable default for blocks without build-time highlighting (e.g. string content
|
|
990
|
+
* rendered by Tabs via CodeBlock). Fenced blocks carry inline syntect
|
|
991
|
+
* colors, which override this. */
|
|
992
|
+
color: #e2e8f0;
|
|
993
|
+
}
|
|
994
|
+
.otfw-copy {
|
|
995
|
+
margin-left: auto;
|
|
996
|
+
display: inline-flex;
|
|
997
|
+
align-items: center;
|
|
998
|
+
gap: 0.35rem;
|
|
999
|
+
padding: 0.28rem 0.6rem;
|
|
1000
|
+
border: 1px solid rgba(255, 255, 255, 0.16);
|
|
1001
|
+
border-radius: 999px;
|
|
1002
|
+
background: rgba(255, 255, 255, 0.06);
|
|
1003
|
+
color: rgba(255, 255, 255, 0.78);
|
|
1004
|
+
font-family: var(--otfw-font);
|
|
1005
|
+
font-size: 0.72rem;
|
|
1006
|
+
font-weight: 600;
|
|
1007
|
+
line-height: 1;
|
|
1008
|
+
cursor: pointer;
|
|
1009
|
+
transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
|
|
1010
|
+
}
|
|
1011
|
+
.otfw-copy:hover {
|
|
1012
|
+
background: rgba(255, 255, 255, 0.14);
|
|
1013
|
+
color: #fff;
|
|
1014
|
+
}
|
|
1015
|
+
.otfw-copy.is-copied {
|
|
1016
|
+
background: color-mix(in srgb, #10b981 22%, transparent);
|
|
1017
|
+
border-color: color-mix(in srgb, #10b981 55%, transparent);
|
|
1018
|
+
color: #34d399;
|
|
1019
|
+
}
|
|
1020
|
+
.otfw-copy .otfw-check-icon {
|
|
1021
|
+
display: none;
|
|
1022
|
+
}
|
|
1023
|
+
.otfw-copy.is-copied .otfw-copy-icon {
|
|
1024
|
+
display: none;
|
|
1025
|
+
}
|
|
1026
|
+
.otfw-copy.is-copied .otfw-check-icon {
|
|
1027
|
+
display: inline;
|
|
1028
|
+
}
|
|
359
1029
|
.otfw-prose blockquote {
|
|
360
1030
|
margin: 0 0 1.2rem;
|
|
361
1031
|
padding: 0.25rem 1.1rem;
|
|
@@ -467,6 +1137,43 @@ web-sidebar-node {
|
|
|
467
1137
|
color: var(--otfw-accent);
|
|
468
1138
|
}
|
|
469
1139
|
|
|
1140
|
+
/* ── Page meta (last updated · edit link) ──────────────────────────────────── */
|
|
1141
|
+
.otfw-page-meta {
|
|
1142
|
+
display: flex;
|
|
1143
|
+
align-items: center;
|
|
1144
|
+
justify-content: space-between;
|
|
1145
|
+
gap: 1rem;
|
|
1146
|
+
flex-wrap: wrap;
|
|
1147
|
+
margin-top: 2.5rem;
|
|
1148
|
+
}
|
|
1149
|
+
/* Empty when a page has neither bit of meta — collapse the top margin then. */
|
|
1150
|
+
.otfw-page-meta:empty {
|
|
1151
|
+
margin-top: 0;
|
|
1152
|
+
}
|
|
1153
|
+
.otfw-last-updated {
|
|
1154
|
+
font-size: 0.8rem;
|
|
1155
|
+
color: var(--otfw-text-muted);
|
|
1156
|
+
}
|
|
1157
|
+
.otfw-last-updated-time {
|
|
1158
|
+
font-weight: 600;
|
|
1159
|
+
color: var(--otfw-text);
|
|
1160
|
+
}
|
|
1161
|
+
.otfw-edit-page {
|
|
1162
|
+
display: inline-flex;
|
|
1163
|
+
align-items: center;
|
|
1164
|
+
gap: 0.35rem;
|
|
1165
|
+
font-size: 0.8rem;
|
|
1166
|
+
font-weight: 500;
|
|
1167
|
+
color: var(--otfw-text-muted);
|
|
1168
|
+
text-decoration: none;
|
|
1169
|
+
}
|
|
1170
|
+
.otfw-edit-page:hover {
|
|
1171
|
+
color: var(--otfw-accent);
|
|
1172
|
+
}
|
|
1173
|
+
.otfw-page-meta + .otfw-pagination {
|
|
1174
|
+
margin-top: 1.5rem;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
470
1177
|
/* ── Pagination ────────────────────────────────────────────────────────────── */
|
|
471
1178
|
.otfw-pagination {
|
|
472
1179
|
display: flex;
|
|
@@ -536,58 +1243,79 @@ web-sidebar-node {
|
|
|
536
1243
|
}
|
|
537
1244
|
|
|
538
1245
|
/* ── Callout ───────────────────────────────────────────────────────────────── */
|
|
1246
|
+
/* Per-type accent color `--c` drives a tinted fill, border, title color and a
|
|
1247
|
+
* filled icon chip — all derived from the one color via color-mix, so the same
|
|
1248
|
+
* rule adapts to light and dark automatically. */
|
|
539
1249
|
.otfw-callout {
|
|
1250
|
+
--c: var(--otfw-text-muted);
|
|
1251
|
+
display: grid;
|
|
1252
|
+
grid-template-columns: auto 1fr;
|
|
1253
|
+
gap: 0.85rem;
|
|
540
1254
|
margin: 1.5rem 0;
|
|
541
1255
|
padding: 1rem 1.1rem;
|
|
542
|
-
border: 1px solid var(--otfw-border);
|
|
543
|
-
border-left
|
|
544
|
-
border-radius:
|
|
545
|
-
background: var(--otfw-bg
|
|
1256
|
+
border: 1px solid color-mix(in srgb, var(--c) 28%, var(--otfw-border));
|
|
1257
|
+
border-left: 3px solid var(--c);
|
|
1258
|
+
border-radius: 0.75rem;
|
|
1259
|
+
background: color-mix(in srgb, var(--c) 7%, var(--otfw-bg));
|
|
1260
|
+
}
|
|
1261
|
+
/* Plain icon (design default): the glyph is tinted with the accent, no filled chip. */
|
|
1262
|
+
.otfw-callout-icon {
|
|
1263
|
+
display: grid;
|
|
1264
|
+
place-items: center;
|
|
1265
|
+
flex: none;
|
|
1266
|
+
width: 1.65rem;
|
|
1267
|
+
height: 1.65rem;
|
|
1268
|
+
color: var(--c);
|
|
1269
|
+
font-size: 1.15rem;
|
|
1270
|
+
line-height: 1;
|
|
546
1271
|
}
|
|
547
1272
|
.otfw-callout-title {
|
|
548
|
-
display: flex;
|
|
549
|
-
align-items: center;
|
|
550
|
-
gap: 0.5rem;
|
|
551
1273
|
font-weight: 700;
|
|
552
|
-
|
|
1274
|
+
font-size: 0.9rem;
|
|
1275
|
+
color: color-mix(in srgb, var(--c) 60%, var(--otfw-text));
|
|
1276
|
+
margin-bottom: 0.25rem;
|
|
1277
|
+
}
|
|
1278
|
+
.otfw-callout-content {
|
|
1279
|
+
min-width: 0;
|
|
1280
|
+
}
|
|
1281
|
+
.otfw-callout-body {
|
|
1282
|
+
font-size: 0.92rem;
|
|
1283
|
+
line-height: 1.65;
|
|
553
1284
|
}
|
|
554
1285
|
.otfw-callout-body > :last-child {
|
|
555
1286
|
margin-bottom: 0;
|
|
556
1287
|
}
|
|
557
1288
|
.otfw-callout-note {
|
|
558
|
-
|
|
1289
|
+
--c: var(--otfw-text-muted);
|
|
559
1290
|
}
|
|
560
1291
|
.otfw-callout-tip {
|
|
561
|
-
|
|
1292
|
+
--c: #10b981;
|
|
562
1293
|
}
|
|
563
1294
|
.otfw-callout-info {
|
|
564
|
-
|
|
1295
|
+
--c: #3b82f6;
|
|
565
1296
|
}
|
|
566
1297
|
.otfw-callout-warning {
|
|
567
|
-
|
|
1298
|
+
--c: #f59e0b;
|
|
568
1299
|
}
|
|
569
1300
|
.otfw-callout-danger {
|
|
570
|
-
|
|
1301
|
+
--c: #ef4444;
|
|
571
1302
|
}
|
|
572
1303
|
|
|
573
|
-
/* ── Tabs
|
|
574
|
-
.otfw-tabs
|
|
575
|
-
.otfw-codegroup {
|
|
1304
|
+
/* ── Tabs ──────────────────────────────────────────────────────────────────── */
|
|
1305
|
+
.otfw-tabs {
|
|
576
1306
|
margin: 1.5rem 0;
|
|
577
1307
|
border: 1px solid var(--otfw-border);
|
|
578
1308
|
border-radius: var(--otfw-radius);
|
|
579
1309
|
overflow: hidden;
|
|
580
1310
|
}
|
|
581
|
-
.otfw-tabs-list
|
|
582
|
-
.otfw-codegroup-tabs {
|
|
1311
|
+
.otfw-tabs-list {
|
|
583
1312
|
display: flex;
|
|
584
1313
|
gap: 0.25rem;
|
|
585
1314
|
padding: 0.4rem;
|
|
586
1315
|
background: var(--otfw-bg-surface);
|
|
587
1316
|
border-bottom: 1px solid var(--otfw-border);
|
|
588
1317
|
}
|
|
589
|
-
.otfw-tab
|
|
590
|
-
.otfw-codegroup-tab {
|
|
1318
|
+
.otfw-tab {
|
|
591
1319
|
padding: 0.35rem 0.85rem;
|
|
592
1320
|
border: none;
|
|
593
1321
|
border-radius: 0.4rem;
|
|
@@ -598,25 +1326,69 @@ web-sidebar-node {
|
|
|
598
1326
|
font-weight: 600;
|
|
599
1327
|
cursor: pointer;
|
|
600
1328
|
}
|
|
601
|
-
.otfw-tab.otfw-active
|
|
602
|
-
.otfw-codegroup-tab.otfw-active {
|
|
1329
|
+
.otfw-tab.otfw-active {
|
|
603
1330
|
background: var(--otfw-bg);
|
|
604
1331
|
color: var(--otfw-accent);
|
|
605
1332
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
|
|
606
1333
|
}
|
|
607
|
-
.otfw-tabs-panels
|
|
608
|
-
.otfw-codegroup-panel {
|
|
1334
|
+
.otfw-tabs-panels {
|
|
609
1335
|
padding: 1rem 1.1rem;
|
|
610
1336
|
}
|
|
611
|
-
.otfw-codegroup-panel pre,
|
|
612
1337
|
.otfw-tabs-panels pre {
|
|
613
1338
|
margin: 0;
|
|
614
1339
|
border: none;
|
|
615
1340
|
}
|
|
1341
|
+
/* A CodeBlock filling a panel shouldn't add its own trailing margin on top of the
|
|
1342
|
+
* panel's padding. */
|
|
1343
|
+
.otfw-tab-panel > .otfw-code {
|
|
1344
|
+
margin: 0;
|
|
1345
|
+
}
|
|
616
1346
|
.otfw-hidden {
|
|
617
1347
|
display: none;
|
|
618
1348
|
}
|
|
619
1349
|
|
|
1350
|
+
/* ── Steps ─────────────────────────────────────────────────────────────────── */
|
|
1351
|
+
.otfw-steps {
|
|
1352
|
+
counter-reset: otfw-step;
|
|
1353
|
+
margin: 1.5rem 0;
|
|
1354
|
+
padding-left: 1.75rem;
|
|
1355
|
+
border-left: 1px solid var(--otfw-border);
|
|
1356
|
+
}
|
|
1357
|
+
.otfw-steps > h3,
|
|
1358
|
+
.otfw-steps > h4 {
|
|
1359
|
+
position: relative;
|
|
1360
|
+
counter-increment: otfw-step;
|
|
1361
|
+
margin-top: 1.6rem;
|
|
1362
|
+
font-size: 1.05rem;
|
|
1363
|
+
}
|
|
1364
|
+
.otfw-steps > h3:first-child,
|
|
1365
|
+
.otfw-steps > h4:first-child {
|
|
1366
|
+
margin-top: 0;
|
|
1367
|
+
}
|
|
1368
|
+
.otfw-steps > h3::before,
|
|
1369
|
+
.otfw-steps > h4::before {
|
|
1370
|
+
content: counter(otfw-step);
|
|
1371
|
+
position: absolute;
|
|
1372
|
+
left: calc(-1.75rem - 1px);
|
|
1373
|
+
top: 50%;
|
|
1374
|
+
transform: translate(-50%, -50%);
|
|
1375
|
+
display: grid;
|
|
1376
|
+
place-items: center;
|
|
1377
|
+
width: 1.7rem;
|
|
1378
|
+
height: 1.7rem;
|
|
1379
|
+
border-radius: 999px;
|
|
1380
|
+
background: var(--otfw-bg);
|
|
1381
|
+
border: 1px solid var(--otfw-border);
|
|
1382
|
+
color: var(--otfw-text-muted);
|
|
1383
|
+
font-size: 0.8rem;
|
|
1384
|
+
font-weight: 700;
|
|
1385
|
+
}
|
|
1386
|
+
.otfw-steps > h3:hover::before,
|
|
1387
|
+
.otfw-steps > h4:hover::before {
|
|
1388
|
+
border-color: var(--otfw-accent);
|
|
1389
|
+
color: var(--otfw-accent);
|
|
1390
|
+
}
|
|
1391
|
+
|
|
620
1392
|
/* ── Table wrapper ─────────────────────────────────────────────────────────── */
|
|
621
1393
|
.otfw-table-wrap {
|
|
622
1394
|
overflow-x: auto;
|
|
@@ -637,3 +1409,207 @@ web-sidebar-node {
|
|
|
637
1409
|
background: var(--otfw-bg-surface);
|
|
638
1410
|
font-weight: 600;
|
|
639
1411
|
}
|
|
1412
|
+
|
|
1413
|
+
/* ── Cards (index grids, e.g. the API overview) ────────────────────────────── */
|
|
1414
|
+
.otfw-cards {
|
|
1415
|
+
display: grid;
|
|
1416
|
+
grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
|
|
1417
|
+
gap: 1rem;
|
|
1418
|
+
margin: 1.5rem 0;
|
|
1419
|
+
}
|
|
1420
|
+
.otfw-card {
|
|
1421
|
+
display: flex;
|
|
1422
|
+
flex-direction: column;
|
|
1423
|
+
gap: 0.35rem;
|
|
1424
|
+
padding: 1.1rem 1.25rem;
|
|
1425
|
+
border: 1px solid var(--otfw-border);
|
|
1426
|
+
border-radius: 0.75rem;
|
|
1427
|
+
background: var(--otfw-bg-surface);
|
|
1428
|
+
text-decoration: none;
|
|
1429
|
+
transition: border-color 0.15s, transform 0.15s;
|
|
1430
|
+
}
|
|
1431
|
+
.otfw-card:hover {
|
|
1432
|
+
border-color: var(--otfw-accent);
|
|
1433
|
+
transform: translateY(-2px);
|
|
1434
|
+
}
|
|
1435
|
+
.otfw-card-title {
|
|
1436
|
+
font-weight: 700;
|
|
1437
|
+
color: var(--otfw-text);
|
|
1438
|
+
}
|
|
1439
|
+
.otfw-card-desc {
|
|
1440
|
+
font-size: 0.85rem;
|
|
1441
|
+
line-height: 1.5;
|
|
1442
|
+
color: var(--otfw-text-muted);
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
/* ── Blog ──────────────────────────────────────────────────────────────────── */
|
|
1446
|
+
.otfw-blog {
|
|
1447
|
+
max-width: 90rem;
|
|
1448
|
+
margin: 0 auto;
|
|
1449
|
+
padding: 0 1.5rem;
|
|
1450
|
+
}
|
|
1451
|
+
.otfw-blog-main {
|
|
1452
|
+
width: 100%;
|
|
1453
|
+
max-width: var(--otfw-content-max);
|
|
1454
|
+
margin: 0 auto;
|
|
1455
|
+
padding: 3rem 0;
|
|
1456
|
+
}
|
|
1457
|
+
/* A post gets content + a sticky "On this page" TOC on wide screens. */
|
|
1458
|
+
.otfw-blog-post {
|
|
1459
|
+
display: grid;
|
|
1460
|
+
grid-template-columns: 1fr;
|
|
1461
|
+
gap: 2.5rem;
|
|
1462
|
+
}
|
|
1463
|
+
@media (min-width: 1280px) {
|
|
1464
|
+
.otfw-blog-post {
|
|
1465
|
+
grid-template-columns: minmax(0, 1fr) var(--otfw-toc-width);
|
|
1466
|
+
/* No `align-items: start` — the TOC column is a <web-toc> custom element that
|
|
1467
|
+
must stretch to the row height so its inner `position: sticky` nav has travel
|
|
1468
|
+
room (mirrors `.otfw-docs`). With `start` the host shrinks to content and the
|
|
1469
|
+
TOC scrolls away with the page. */
|
|
1470
|
+
}
|
|
1471
|
+
.otfw-blog-post .otfw-blog-main {
|
|
1472
|
+
margin: 0;
|
|
1473
|
+
justify-self: end;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
.otfw-blog-back {
|
|
1477
|
+
display: inline-block;
|
|
1478
|
+
margin-bottom: 1.5rem;
|
|
1479
|
+
font-size: 0.85rem;
|
|
1480
|
+
color: var(--otfw-text-muted);
|
|
1481
|
+
text-decoration: none;
|
|
1482
|
+
}
|
|
1483
|
+
.otfw-blog-back:hover {
|
|
1484
|
+
color: var(--otfw-text);
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
/* Post banner (title + description + meta). */
|
|
1488
|
+
.otfw-post-banner {
|
|
1489
|
+
margin-bottom: 2.5rem;
|
|
1490
|
+
padding-bottom: 1.75rem;
|
|
1491
|
+
border-bottom: 1px solid var(--otfw-border);
|
|
1492
|
+
}
|
|
1493
|
+
.otfw-post-title {
|
|
1494
|
+
font-size: clamp(2rem, 5vw, 2.75rem);
|
|
1495
|
+
font-weight: 800;
|
|
1496
|
+
letter-spacing: -0.02em;
|
|
1497
|
+
line-height: 1.1;
|
|
1498
|
+
color: var(--otfw-text);
|
|
1499
|
+
}
|
|
1500
|
+
.otfw-post-desc {
|
|
1501
|
+
margin-top: 0.75rem;
|
|
1502
|
+
font-size: 1.15rem;
|
|
1503
|
+
color: var(--otfw-text-muted);
|
|
1504
|
+
line-height: 1.5;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
/* Meta row: date · author · reading time. */
|
|
1508
|
+
.otfw-post-meta {
|
|
1509
|
+
display: flex;
|
|
1510
|
+
flex-wrap: wrap;
|
|
1511
|
+
align-items: center;
|
|
1512
|
+
gap: 0.75rem;
|
|
1513
|
+
margin-top: 1rem;
|
|
1514
|
+
font-size: 0.85rem;
|
|
1515
|
+
color: var(--otfw-text-muted);
|
|
1516
|
+
}
|
|
1517
|
+
.otfw-post-meta > * + *::before {
|
|
1518
|
+
content: "·";
|
|
1519
|
+
margin-right: 0.75rem;
|
|
1520
|
+
color: var(--otfw-border);
|
|
1521
|
+
}
|
|
1522
|
+
.otfw-reading-time,
|
|
1523
|
+
.otfw-post-author,
|
|
1524
|
+
.otfw-post-date {
|
|
1525
|
+
white-space: nowrap;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
/* Tags. */
|
|
1529
|
+
.otfw-post-tags {
|
|
1530
|
+
display: flex;
|
|
1531
|
+
flex-wrap: wrap;
|
|
1532
|
+
gap: 0.5rem;
|
|
1533
|
+
margin-top: 1rem;
|
|
1534
|
+
}
|
|
1535
|
+
.otfw-post-tag {
|
|
1536
|
+
padding: 0.15rem 0.6rem;
|
|
1537
|
+
border-radius: 9999px;
|
|
1538
|
+
background: var(--otfw-bg-surface);
|
|
1539
|
+
border: 1px solid var(--otfw-border);
|
|
1540
|
+
font-size: 0.72rem;
|
|
1541
|
+
font-weight: 600;
|
|
1542
|
+
color: var(--otfw-text-muted);
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
/* Index listing. */
|
|
1546
|
+
.otfw-post-list {
|
|
1547
|
+
display: flex;
|
|
1548
|
+
flex-direction: column;
|
|
1549
|
+
}
|
|
1550
|
+
.otfw-post-card {
|
|
1551
|
+
display: block;
|
|
1552
|
+
padding: 1.6rem 0;
|
|
1553
|
+
border-top: 1px solid var(--otfw-border);
|
|
1554
|
+
text-decoration: none;
|
|
1555
|
+
transition: opacity 0.15s;
|
|
1556
|
+
}
|
|
1557
|
+
.otfw-post-card:hover .otfw-post-card-title {
|
|
1558
|
+
color: var(--otfw-accent);
|
|
1559
|
+
}
|
|
1560
|
+
.otfw-post-card .otfw-post-meta {
|
|
1561
|
+
margin-top: 0;
|
|
1562
|
+
}
|
|
1563
|
+
.otfw-post-card-title {
|
|
1564
|
+
margin-top: 0.4rem;
|
|
1565
|
+
font-size: 1.35rem;
|
|
1566
|
+
font-weight: 700;
|
|
1567
|
+
color: var(--otfw-text);
|
|
1568
|
+
transition: color 0.15s;
|
|
1569
|
+
}
|
|
1570
|
+
.otfw-post-card-desc {
|
|
1571
|
+
margin-top: 0.4rem;
|
|
1572
|
+
color: var(--otfw-text-muted);
|
|
1573
|
+
line-height: 1.5;
|
|
1574
|
+
}
|
|
1575
|
+
.otfw-post-empty {
|
|
1576
|
+
padding: 2rem 0;
|
|
1577
|
+
color: var(--otfw-text-muted);
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
/* ── Blog: cover images & author ───────────────────────────────────────────── */
|
|
1581
|
+
.otfw-post-cover {
|
|
1582
|
+
display: block;
|
|
1583
|
+
width: 100%;
|
|
1584
|
+
aspect-ratio: 16 / 7;
|
|
1585
|
+
object-fit: cover;
|
|
1586
|
+
border-radius: 0.85rem;
|
|
1587
|
+
border: 1px solid var(--otfw-border);
|
|
1588
|
+
margin-bottom: 1.75rem;
|
|
1589
|
+
}
|
|
1590
|
+
.otfw-post-author {
|
|
1591
|
+
display: inline-flex;
|
|
1592
|
+
align-items: center;
|
|
1593
|
+
gap: 0.4rem;
|
|
1594
|
+
}
|
|
1595
|
+
.otfw-post-avatar {
|
|
1596
|
+
width: 1.4rem;
|
|
1597
|
+
height: 1.4rem;
|
|
1598
|
+
border-radius: 9999px;
|
|
1599
|
+
object-fit: cover;
|
|
1600
|
+
border: 1px solid var(--otfw-border);
|
|
1601
|
+
}
|
|
1602
|
+
.otfw-post-author-role {
|
|
1603
|
+
color: var(--otfw-text-muted);
|
|
1604
|
+
opacity: 0.8;
|
|
1605
|
+
}
|
|
1606
|
+
/* Cards with a cover use a media + body two-row layout. */
|
|
1607
|
+
.otfw-post-card-cover {
|
|
1608
|
+
display: block;
|
|
1609
|
+
width: 100%;
|
|
1610
|
+
aspect-ratio: 16 / 8;
|
|
1611
|
+
object-fit: cover;
|
|
1612
|
+
border-radius: 0.6rem;
|
|
1613
|
+
border: 1px solid var(--otfw-border);
|
|
1614
|
+
margin-bottom: 1rem;
|
|
1615
|
+
}
|