duckfn-docs-kit 0.1.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/AGENTS.md +689 -0
- package/LICENSE +21 -0
- package/README.md +107 -0
- package/dist/dom.d.ts +69 -0
- package/dist/home/DfkFeatures.d.ts +20 -0
- package/dist/home/DfkHero.d.ts +25 -0
- package/dist/home/DfkNextSteps.d.ts +16 -0
- package/dist/home/styles.d.ts +8 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +2 -0
- package/dist/register-DKLiYs-F.js +2324 -0
- package/dist/register.d.ts +10 -0
- package/dist/remark.d.ts +21 -0
- package/dist/remark.js +15 -0
- package/dist/runtimeConfig-Bokbb8VH.js +106 -0
- package/dist/sql/DfkSql.d.ts +7 -0
- package/dist/sql/PreviewTabs.d.ts +37 -0
- package/dist/sql/client.d.ts +1 -0
- package/dist/sql/client.js +4 -0
- package/dist/sql/editor.d.ts +16 -0
- package/dist/sql/extensions.d.ts +108 -0
- package/dist/sql/extensions.js +198 -0
- package/dist/sql/remark.d.ts +88 -0
- package/dist/sql/remark.js +69 -0
- package/dist/sql/renderers.d.ts +44 -0
- package/dist/sql/runtime.d.ts +105 -0
- package/dist/sql/runtimeConfig.d.ts +80 -0
- package/dist/sql/styles.d.ts +6 -0
- package/dist/toc-toggle/TocToggle.d.ts +46 -0
- package/dist/toc-toggle/TocToggle.js +69 -0
- package/dist/toc-toggle/client.d.ts +1 -0
- package/dist/toc-toggle/client.js +9 -0
- package/dist/toc-toggle/plugin.d.ts +36 -0
- package/dist/toc-toggle/plugin.js +13 -0
- package/dist/types.d.ts +42 -0
- package/package.json +73 -0
- package/src/dom.ts +109 -0
- package/src/home/DfkFeatures.ts +78 -0
- package/src/home/DfkHero.ts +128 -0
- package/src/home/DfkNextSteps.ts +73 -0
- package/src/home/home.css +520 -0
- package/src/home/styles.ts +28 -0
- package/src/index.ts +59 -0
- package/src/kit.css +19 -0
- package/src/register.ts +39 -0
- package/src/remark.ts +60 -0
- package/src/sql/DfkSql.css +226 -0
- package/src/sql/DfkSql.ts +620 -0
- package/src/sql/PreviewTabs.ts +169 -0
- package/src/sql/client.ts +16 -0
- package/src/sql/editor.ts +75 -0
- package/src/sql/extensions.ts +470 -0
- package/src/sql/remark.ts +213 -0
- package/src/sql/renderers.ts +916 -0
- package/src/sql/runtime.ts +348 -0
- package/src/sql/runtimeConfig.ts +249 -0
- package/src/sql/sql.css +397 -0
- package/src/sql/styles.ts +24 -0
- package/src/theme/tokens.css +75 -0
- package/src/toc-toggle/TocToggle.css +69 -0
- package/src/toc-toggle/TocToggle.ts +172 -0
- package/src/toc-toggle/client.ts +20 -0
- package/src/toc-toggle/plugin.ts +54 -0
- package/src/types.ts +47 -0
- package/src/vite-env.d.ts +8 -0
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Styles for the `dfk-*` home-page custom elements.
|
|
3
|
+
*
|
|
4
|
+
* This file is *not* part of the site's global stylesheet: Vite inlines it into
|
|
5
|
+
* the bundle (`styles.ts`, `?inline`) and each component adopts it as a
|
|
6
|
+
* constructed stylesheet on its shadow root. The site's own CSS cannot reach
|
|
7
|
+
* these rules, and these rules cannot leak out — which is why the class names
|
|
8
|
+
* still carry the `dfk-` prefix (it keeps the shadow trees self-describing and
|
|
9
|
+
* greppable, not because they could collide with the host page).
|
|
10
|
+
*
|
|
11
|
+
* Theme colours cross the shadow boundary through inheritance: the `--duckfn-*`
|
|
12
|
+
* tokens from `theme/tokens.css` and the site's `--ifm-*` variables are custom
|
|
13
|
+
* properties declared on `:root` / `[data-theme]`, and custom properties
|
|
14
|
+
* inherit into shadow trees, so dark mode works without a single `[data-theme]`
|
|
15
|
+
* selector in this file.
|
|
16
|
+
*
|
|
17
|
+
* Motion rules, deliberately:
|
|
18
|
+
*
|
|
19
|
+
* - all animations live inside `@media (prefers-reduced-motion: no-preference)`
|
|
20
|
+
* and no static declaration sets `opacity: 0`, so a reader who disabled
|
|
21
|
+
* animation sees the page complete rather than blank;
|
|
22
|
+
* - entrance animations fill `backwards` instead of `forwards`. The delay then
|
|
23
|
+
* holds the start frame, but once the animation ends the element goes back to
|
|
24
|
+
* its normal styles — which is what lets the `:hover` transforms on the cards
|
|
25
|
+
* work. With `forwards` the finished animation would keep overriding them.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/* --------------------------------------------------------------- host */
|
|
29
|
+
|
|
30
|
+
/* A custom element is `display: inline` by default; the shadow content is a
|
|
31
|
+
full-width section, so the host has to be a block box. */
|
|
32
|
+
:host {
|
|
33
|
+
display: block;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* The shadow-scoped box-sizing reset. The host page's universal selector
|
|
37
|
+
(Infima's `* { box-sizing: border-box }`) does not match into a shadow tree,
|
|
38
|
+
so without this every padded box in the components silently switches to
|
|
39
|
+
content-box — which is wide enough to push the feature grid from three
|
|
40
|
+
columns to four at the 72rem cap. The rules below are written against
|
|
41
|
+
border-box, so it is re-established here. */
|
|
42
|
+
*,
|
|
43
|
+
*::before,
|
|
44
|
+
*::after {
|
|
45
|
+
box-sizing: border-box;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* --------------------------------------------------------------- hero */
|
|
49
|
+
|
|
50
|
+
.dfk-hero {
|
|
51
|
+
position: relative;
|
|
52
|
+
/* Contains the glow pseudo-elements below without needing a z-index race, and
|
|
53
|
+
clips them on the horizontal axis only: their offsets (the 52rem circle centred
|
|
54
|
+
with `left: 50%`, and the warm one at `right: -10rem`) reach past the viewport,
|
|
55
|
+
which would otherwise widen the page and add a scrollbar.
|
|
56
|
+
`clip`, not `hidden`. Both keep the page narrow, but `hidden` also made this
|
|
57
|
+
section a scroll container and clipped the vertical axis, slicing the warm glow
|
|
58
|
+
in half along this section's bottom edge. `clip` leaves the other axis visible,
|
|
59
|
+
so the glow fades out over the next section instead of ending on a straight
|
|
60
|
+
line. It is also what makes the clip invisible: the horizontal cut lands on the
|
|
61
|
+
viewport edge, where there is nothing to see anyway. */
|
|
62
|
+
isolation: isolate;
|
|
63
|
+
overflow-x: clip;
|
|
64
|
+
padding: 4.5rem 1.5rem 4rem;
|
|
65
|
+
text-align: center;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Two soft pools of light: brand blue from above, a hint of the logo's beak
|
|
69
|
+
yellow from the lower right. Purely decorative. */
|
|
70
|
+
.dfk-hero::before,
|
|
71
|
+
.dfk-hero::after {
|
|
72
|
+
content: '';
|
|
73
|
+
position: absolute;
|
|
74
|
+
z-index: -1;
|
|
75
|
+
border-radius: 50%;
|
|
76
|
+
pointer-events: none;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.dfk-hero::before {
|
|
80
|
+
top: -18rem;
|
|
81
|
+
left: 50%;
|
|
82
|
+
width: 52rem;
|
|
83
|
+
height: 52rem;
|
|
84
|
+
transform: translateX(-50%);
|
|
85
|
+
background: radial-gradient(circle, var(--duckfn-glow), transparent 70%);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.dfk-hero::after {
|
|
89
|
+
right: -10rem;
|
|
90
|
+
bottom: -14rem;
|
|
91
|
+
width: 34rem;
|
|
92
|
+
height: 34rem;
|
|
93
|
+
background: radial-gradient(circle, var(--duckfn-glow-warm), transparent 70%);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.dfk-hero-inner {
|
|
97
|
+
max-width: 46rem;
|
|
98
|
+
margin: 0 auto;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.dfk-logo-stage {
|
|
102
|
+
display: inline-block;
|
|
103
|
+
line-height: 0;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* The logo is a vector, so this stays sharp at any density. */
|
|
107
|
+
.dfk-logo {
|
|
108
|
+
display: block;
|
|
109
|
+
width: clamp(7rem, 16vw, 10rem);
|
|
110
|
+
height: auto;
|
|
111
|
+
filter: drop-shadow(0 14px 28px var(--duckfn-glow));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.dfk-title {
|
|
115
|
+
margin: 1.5rem 0 0;
|
|
116
|
+
font-size: clamp(2.25rem, 5vw, 3.25rem);
|
|
117
|
+
font-weight: 700;
|
|
118
|
+
letter-spacing: -0.02em;
|
|
119
|
+
line-height: 1.1;
|
|
120
|
+
/* The plain colour is the fallback for the gradient below: without
|
|
121
|
+
`background-clip: text` a `transparent` colour would hide the name. */
|
|
122
|
+
color: var(--duckfn-blue);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@supports (-webkit-background-clip: text) or (background-clip: text) {
|
|
126
|
+
.dfk-title {
|
|
127
|
+
background-image: linear-gradient(
|
|
128
|
+
120deg,
|
|
129
|
+
var(--duckfn-blue-deep),
|
|
130
|
+
var(--duckfn-blue-bright)
|
|
131
|
+
);
|
|
132
|
+
-webkit-background-clip: text;
|
|
133
|
+
background-clip: text;
|
|
134
|
+
color: transparent;
|
|
135
|
+
/* Room for descenders, which the tight line box would otherwise clip. */
|
|
136
|
+
padding-bottom: 0.06em;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* The only yellow on this page, and it carries no text: a short rule under the
|
|
141
|
+
name that echoes the beak. See the note on the token in theme/tokens.css. */
|
|
142
|
+
.dfk-title::after {
|
|
143
|
+
content: '';
|
|
144
|
+
display: block;
|
|
145
|
+
width: 3rem;
|
|
146
|
+
height: 0.25rem;
|
|
147
|
+
margin: 1rem auto 0;
|
|
148
|
+
border-radius: 999px;
|
|
149
|
+
background-color: var(--duckfn-yellow);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.dfk-tagline {
|
|
153
|
+
max-width: 34rem;
|
|
154
|
+
margin: 1.25rem auto 0;
|
|
155
|
+
font-size: clamp(1.05rem, 2.2vw, 1.25rem);
|
|
156
|
+
line-height: 1.65;
|
|
157
|
+
color: var(--ifm-color-emphasis-700);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.dfk-actions {
|
|
161
|
+
display: flex;
|
|
162
|
+
flex-wrap: wrap;
|
|
163
|
+
justify-content: center;
|
|
164
|
+
gap: 0.75rem 1rem;
|
|
165
|
+
margin-top: 2.25rem;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.dfk-button-primary,
|
|
169
|
+
.dfk-button-secondary {
|
|
170
|
+
display: inline-flex;
|
|
171
|
+
align-items: center;
|
|
172
|
+
justify-content: center;
|
|
173
|
+
gap: 0.5rem;
|
|
174
|
+
padding: 0.7rem 1.6rem;
|
|
175
|
+
border: 1px solid transparent;
|
|
176
|
+
border-radius: 999px;
|
|
177
|
+
font-size: 1rem;
|
|
178
|
+
font-weight: 600;
|
|
179
|
+
line-height: 1.4;
|
|
180
|
+
text-decoration: none;
|
|
181
|
+
transition: background-color 0.2s var(--ifm-transition-timing-default),
|
|
182
|
+
border-color 0.2s var(--ifm-transition-timing-default),
|
|
183
|
+
color 0.2s var(--ifm-transition-timing-default),
|
|
184
|
+
box-shadow 0.2s var(--ifm-transition-timing-default);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.dfk-button-primary {
|
|
188
|
+
background-color: var(--duckfn-btn-bg);
|
|
189
|
+
border-color: var(--duckfn-btn-bg);
|
|
190
|
+
color: var(--duckfn-btn-fg);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.dfk-button-primary:hover,
|
|
194
|
+
.dfk-button-primary:focus-visible {
|
|
195
|
+
background-color: var(--duckfn-btn-bg-hover);
|
|
196
|
+
border-color: var(--duckfn-btn-bg-hover);
|
|
197
|
+
color: var(--duckfn-btn-fg);
|
|
198
|
+
box-shadow: var(--duckfn-shadow);
|
|
199
|
+
text-decoration: none;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.dfk-button-secondary {
|
|
203
|
+
background-color: transparent;
|
|
204
|
+
border-color: var(--duckfn-outline-border);
|
|
205
|
+
color: var(--duckfn-blue);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.dfk-button-secondary:hover,
|
|
209
|
+
.dfk-button-secondary:focus-visible {
|
|
210
|
+
background-color: var(--duckfn-blue-soft);
|
|
211
|
+
border-color: var(--duckfn-blue);
|
|
212
|
+
color: var(--duckfn-blue);
|
|
213
|
+
text-decoration: none;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* ------------------------------------------------------------ icons */
|
|
217
|
+
|
|
218
|
+
/* Icons are official `<iconify-icon>` web components: the glyph is fetched from
|
|
219
|
+
the public Iconify API and painted with `currentColor`, so these rules only
|
|
220
|
+
set the size (and, where needed, the colour the glyph inherits).
|
|
221
|
+
Size with `font-size`, not `width`/`height`: the component renders an inner
|
|
222
|
+
`<svg width="1em" height="1em">`, so the glyph follows the host's font-size.
|
|
223
|
+
A CSS `width`/`height` only grows the empty host box and leaves the glyph at
|
|
224
|
+
the inherited font-size. */
|
|
225
|
+
.dfk-button-icon {
|
|
226
|
+
font-size: 1.125rem;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.dfk-badges {
|
|
230
|
+
display: flex;
|
|
231
|
+
flex-wrap: wrap;
|
|
232
|
+
align-items: center;
|
|
233
|
+
justify-content: center;
|
|
234
|
+
gap: 0.5rem;
|
|
235
|
+
margin-top: 2rem;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.dfk-badge {
|
|
239
|
+
display: inline-flex;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.dfk-badge-image {
|
|
243
|
+
display: block;
|
|
244
|
+
width: auto;
|
|
245
|
+
height: 20px;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* ------------------------------------------------------------ sections */
|
|
249
|
+
|
|
250
|
+
.dfk-section {
|
|
251
|
+
padding: 4.5rem 0;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.dfk-section-inner {
|
|
255
|
+
max-width: 72rem;
|
|
256
|
+
margin: 0 auto;
|
|
257
|
+
padding: 0 1.5rem;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.dfk-section-title {
|
|
261
|
+
margin-bottom: 0;
|
|
262
|
+
text-align: center;
|
|
263
|
+
font-size: clamp(1.5rem, 3vw, 2rem);
|
|
264
|
+
letter-spacing: -0.01em;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* ------------------------------------------------------------ features */
|
|
268
|
+
|
|
269
|
+
.dfk-feature-grid {
|
|
270
|
+
display: grid;
|
|
271
|
+
/* min(17rem, 100%) rather than a bare 17rem: a track can then never be wider
|
|
272
|
+
than the viewport, which is what keeps the narrowest phones from scrolling
|
|
273
|
+
sideways. */
|
|
274
|
+
grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr));
|
|
275
|
+
gap: 1.25rem;
|
|
276
|
+
margin-top: 2.75rem;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.dfk-feature-card {
|
|
280
|
+
display: flex;
|
|
281
|
+
flex-direction: column;
|
|
282
|
+
padding: 1.5rem;
|
|
283
|
+
border: 1px solid var(--duckfn-card-border);
|
|
284
|
+
border-radius: 1rem;
|
|
285
|
+
background-color: var(--duckfn-card-bg);
|
|
286
|
+
transition: border-color 0.2s var(--ifm-transition-timing-default),
|
|
287
|
+
box-shadow 0.2s var(--ifm-transition-timing-default);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.dfk-feature-card:hover {
|
|
291
|
+
border-color: var(--duckfn-blue);
|
|
292
|
+
box-shadow: var(--duckfn-shadow);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.dfk-feature-icon-chip {
|
|
296
|
+
display: inline-flex;
|
|
297
|
+
align-items: center;
|
|
298
|
+
justify-content: center;
|
|
299
|
+
width: 2.5rem;
|
|
300
|
+
height: 2.5rem;
|
|
301
|
+
margin-bottom: 1rem;
|
|
302
|
+
border-radius: 0.75rem;
|
|
303
|
+
background-color: var(--duckfn-blue-soft);
|
|
304
|
+
color: var(--duckfn-blue);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.dfk-feature-icon {
|
|
308
|
+
font-size: 1.375rem;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.dfk-feature-title {
|
|
312
|
+
margin-bottom: 0.5rem;
|
|
313
|
+
font-size: 1.0625rem;
|
|
314
|
+
font-weight: 600;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.dfk-feature-details {
|
|
318
|
+
margin-bottom: 0;
|
|
319
|
+
font-size: 0.9375rem;
|
|
320
|
+
line-height: 1.7;
|
|
321
|
+
color: var(--ifm-color-emphasis-700);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/* ---------------------------------------------------------- next steps */
|
|
325
|
+
|
|
326
|
+
.dfk-next-grid {
|
|
327
|
+
display: grid;
|
|
328
|
+
grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
|
|
329
|
+
gap: 1rem;
|
|
330
|
+
max-width: 54rem;
|
|
331
|
+
margin: 2.75rem auto 0;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.dfk-next-card {
|
|
335
|
+
display: flex;
|
|
336
|
+
align-items: center;
|
|
337
|
+
gap: 1rem;
|
|
338
|
+
padding: 1.25rem 1.375rem;
|
|
339
|
+
border: 1px solid var(--duckfn-card-border);
|
|
340
|
+
border-radius: 0.875rem;
|
|
341
|
+
background-color: var(--duckfn-card-bg);
|
|
342
|
+
/* The card is the link, so it must not pick up the anchor colour. */
|
|
343
|
+
color: inherit;
|
|
344
|
+
text-decoration: none;
|
|
345
|
+
transition: border-color 0.2s var(--ifm-transition-timing-default),
|
|
346
|
+
box-shadow 0.2s var(--ifm-transition-timing-default);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.dfk-next-card:hover,
|
|
350
|
+
.dfk-next-card:focus-visible {
|
|
351
|
+
border-color: var(--duckfn-blue);
|
|
352
|
+
box-shadow: var(--duckfn-shadow);
|
|
353
|
+
color: inherit;
|
|
354
|
+
text-decoration: none;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.dfk-next-card-body {
|
|
358
|
+
display: flex;
|
|
359
|
+
flex: 1;
|
|
360
|
+
flex-direction: column;
|
|
361
|
+
gap: 0.25rem;
|
|
362
|
+
min-width: 0;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.dfk-next-card-title {
|
|
366
|
+
font-size: 1rem;
|
|
367
|
+
font-weight: 600;
|
|
368
|
+
color: var(--duckfn-blue);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.dfk-next-card-details {
|
|
372
|
+
font-size: 0.9rem;
|
|
373
|
+
line-height: 1.6;
|
|
374
|
+
color: var(--ifm-color-emphasis-700);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.dfk-next-card-arrow {
|
|
378
|
+
flex-shrink: 0;
|
|
379
|
+
font-size: 1.25rem;
|
|
380
|
+
color: var(--ifm-color-emphasis-500);
|
|
381
|
+
transition: color 0.2s var(--ifm-transition-timing-default);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.dfk-next-card:hover .dfk-next-card-arrow,
|
|
385
|
+
.dfk-next-card:focus-visible .dfk-next-card-arrow {
|
|
386
|
+
color: var(--duckfn-blue);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* -------------------------------------------------------------- motion */
|
|
390
|
+
|
|
391
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
392
|
+
.dfk-logo-stage,
|
|
393
|
+
.dfk-title,
|
|
394
|
+
.dfk-tagline,
|
|
395
|
+
.dfk-actions,
|
|
396
|
+
.dfk-badges {
|
|
397
|
+
animation: dfk-rise 0.6s var(--ifm-transition-timing-default) backwards;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.dfk-title {
|
|
401
|
+
animation-delay: 0.06s;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.dfk-tagline {
|
|
405
|
+
animation-delay: 0.12s;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.dfk-actions {
|
|
409
|
+
animation-delay: 0.18s;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.dfk-badges {
|
|
413
|
+
animation-delay: 0.24s;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* Two elements on purpose: `rise` plays once on the stage, `float` loops on
|
|
417
|
+
the image. One element cannot run two animations that both set transform. */
|
|
418
|
+
.dfk-logo {
|
|
419
|
+
animation: dfk-float 7s ease-in-out infinite;
|
|
420
|
+
will-change: transform;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.dfk-feature-card,
|
|
424
|
+
.dfk-next-card {
|
|
425
|
+
animation: dfk-rise 0.5s var(--ifm-transition-timing-default) backwards;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/* Cards arrive in reading order. Filling backwards keeps them invisible during
|
|
429
|
+
their delay and hands the element back to `:hover` when the animation ends. */
|
|
430
|
+
.dfk-feature-card:nth-child(2),
|
|
431
|
+
.dfk-next-card:nth-child(2) {
|
|
432
|
+
animation-delay: 0.06s;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.dfk-feature-card:nth-child(3),
|
|
436
|
+
.dfk-next-card:nth-child(3) {
|
|
437
|
+
animation-delay: 0.12s;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.dfk-feature-card:nth-child(4),
|
|
441
|
+
.dfk-next-card:nth-child(4) {
|
|
442
|
+
animation-delay: 0.18s;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.dfk-feature-card:nth-child(5) {
|
|
446
|
+
animation-delay: 0.24s;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.dfk-feature-card:nth-child(6) {
|
|
450
|
+
animation-delay: 0.3s;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.dfk-feature-card,
|
|
454
|
+
.dfk-next-card,
|
|
455
|
+
.dfk-next-card-arrow {
|
|
456
|
+
transition: transform 0.2s var(--ifm-transition-timing-default),
|
|
457
|
+
border-color 0.2s var(--ifm-transition-timing-default),
|
|
458
|
+
box-shadow 0.2s var(--ifm-transition-timing-default),
|
|
459
|
+
color 0.2s var(--ifm-transition-timing-default);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
.dfk-feature-card:hover {
|
|
463
|
+
transform: translateY(-4px);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.dfk-next-card:hover {
|
|
467
|
+
transform: translateY(-2px);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.dfk-next-card:hover .dfk-next-card-arrow {
|
|
471
|
+
transform: translateX(4px);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
@keyframes dfk-rise {
|
|
476
|
+
from {
|
|
477
|
+
opacity: 0;
|
|
478
|
+
transform: translateY(14px);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
to {
|
|
482
|
+
opacity: 1;
|
|
483
|
+
transform: translateY(0);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
@keyframes dfk-float {
|
|
488
|
+
0%,
|
|
489
|
+
100% {
|
|
490
|
+
transform: translateY(-4px);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
50% {
|
|
494
|
+
transform: translateY(4px);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/* -------------------------------------------------------- breakpoints */
|
|
499
|
+
|
|
500
|
+
@media screen and (max-width: 996px) {
|
|
501
|
+
.dfk-hero {
|
|
502
|
+
padding: 3rem 1.5rem;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.dfk-section {
|
|
506
|
+
padding: 3.5rem 0;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
@media screen and (max-width: 576px) {
|
|
511
|
+
.dfk-section-inner {
|
|
512
|
+
padding: 0 1rem;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/* Full-width buttons stack better than two pills on a phone. */
|
|
516
|
+
.dfk-actions {
|
|
517
|
+
flex-direction: column;
|
|
518
|
+
align-items: stretch;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// The home components' CSS as an inline string, bundled into the JS by Vite's
|
|
2
|
+
// `?inline` import (see `vite.config.ts`). The components inject it into their
|
|
3
|
+
// shadow roots, so a consuming site never imports `home.css` — the only CSS
|
|
4
|
+
// files that stay global source are `theme/tokens.css` (the `--duckfn-*`
|
|
5
|
+
// palette, which must live on `:root` / `[data-theme]`) and
|
|
6
|
+
// `toc-toggle/TocToggle.css` (light-DOM rules that have to sit inside
|
|
7
|
+
// `@layer docusaurus.theme-classic`).
|
|
8
|
+
//
|
|
9
|
+
// The type declaration lives in `vite-env.d.ts`; `tsc` never resolves the
|
|
10
|
+
// `?inline` suffix, so the module graph stays buildable without Vite running.
|
|
11
|
+
import homeCss from './home.css?inline';
|
|
12
|
+
|
|
13
|
+
let sheet: CSSStyleSheet | null = null;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The one parsed stylesheet shared by every `dfk-*` shadow root.
|
|
17
|
+
*
|
|
18
|
+
* Created lazily: Docusaurus imports this module into Node during
|
|
19
|
+
* prerendering, where `CSSStyleSheet` does not exist — only the browser ever
|
|
20
|
+
* calls this.
|
|
21
|
+
*/
|
|
22
|
+
export function homeStyles(): CSSStyleSheet {
|
|
23
|
+
if (!sheet) {
|
|
24
|
+
sheet = new CSSStyleSheet();
|
|
25
|
+
sheet.replaceSync(homeCss);
|
|
26
|
+
}
|
|
27
|
+
return sheet;
|
|
28
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type {HTMLAttributes} from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Browser entry for duckfn-docs-kit: the home-page custom elements and the
|
|
5
|
+
* value types their `set*` methods accept.
|
|
6
|
+
*
|
|
7
|
+
* The components are retained-mode (build once, then mutate held nodes) and
|
|
8
|
+
* expose named setters such as `setTitle()` / `setBadges()`. They render into
|
|
9
|
+
* shadow roots and inject their own stylesheet, so the consuming site imports
|
|
10
|
+
* only the global CSS the kit cannot host in a shadow (`src/kit.css`: brand
|
|
11
|
+
* tokens + TOC toggle, imported as `duckfn-docs-kit/src/kit.css`). Icons are
|
|
12
|
+
* rendered by the official `<iconify-icon>`
|
|
13
|
+
* web component, which `registerDfkElements()` registers as a side effect, so
|
|
14
|
+
* this package ships no icon data.
|
|
15
|
+
*
|
|
16
|
+
* `TocToggle` and the remark plugin keep their own subpaths
|
|
17
|
+
* (`duckfn-docs-kit/toc-toggle/TocToggle`, `duckfn-docs-kit/remark`) instead of
|
|
18
|
+
* being merged here: a Docusaurus config file must never pull browser code into
|
|
19
|
+
* Node, and a site that only wants the TOC collapse button should not pay for
|
|
20
|
+
* the bundled `iconify-icon`.
|
|
21
|
+
*/
|
|
22
|
+
export {DfkFeatures} from './home/DfkFeatures';
|
|
23
|
+
export {DfkHero} from './home/DfkHero';
|
|
24
|
+
export {DfkNextSteps} from './home/DfkNextSteps';
|
|
25
|
+
export {DfkSql} from './sql/DfkSql';
|
|
26
|
+
export {registerDfkElements} from './register';
|
|
27
|
+
export type {RunnableSqlConfig} from './sql/remark';
|
|
28
|
+
export type {
|
|
29
|
+
FeatureItem,
|
|
30
|
+
HeroAction,
|
|
31
|
+
HeroBadge,
|
|
32
|
+
HeroLink,
|
|
33
|
+
NextStepItem,
|
|
34
|
+
} from './types';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Props accepted by the `dfk-*` tags when they are created from React.
|
|
38
|
+
*
|
|
39
|
+
* The content is *not* passed as a prop — an object prop would never reach the
|
|
40
|
+
* component through hydration (React only reconciles strings onto custom
|
|
41
|
+
* elements). The caller mounts the element and drives it through its setters
|
|
42
|
+
* from a callback ref, so all React needs to know about is `ref`.
|
|
43
|
+
*
|
|
44
|
+
* The alias is exported (rather than written inline) because the emitted `.d.ts`
|
|
45
|
+
* for a module augmentation can only name types that are themselves reachable
|
|
46
|
+
* from the declaration file.
|
|
47
|
+
*/
|
|
48
|
+
export type DfkElementProps = HTMLAttributes<HTMLElement>;
|
|
49
|
+
|
|
50
|
+
declare module 'react' {
|
|
51
|
+
namespace JSX {
|
|
52
|
+
interface IntrinsicElements {
|
|
53
|
+
'dfk-hero': DfkElementProps;
|
|
54
|
+
'dfk-features': DfkElementProps;
|
|
55
|
+
'dfk-next-steps': DfkElementProps;
|
|
56
|
+
'dfk-sql': DfkElementProps;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
package/src/kit.css
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-line entry point for the CSS that must stay global: brand tokens + TOC
|
|
3
|
+
* toggle.
|
|
4
|
+
*
|
|
5
|
+
* The home components' CSS is deliberately *not* imported here. The `dfk-*`
|
|
6
|
+
* components render into shadow roots and inject their own styles from the JS
|
|
7
|
+
* bundle (see `home/styles.ts`), so a site that consumes the components gets
|
|
8
|
+
* their styles for free. What remains here is the CSS a shadow boundary cannot
|
|
9
|
+
* host: the `--duckfn-*` tokens (they must be declared on `:root` /
|
|
10
|
+
* `[data-theme]` so they can inherit *into* the shadow trees) and the TOC
|
|
11
|
+
* toggle (light-DOM rules that must sit inside
|
|
12
|
+
* `@layer docusaurus.theme-classic`).
|
|
13
|
+
*
|
|
14
|
+
* Each stylesheet lives in the feature folder it belongs to; this file only
|
|
15
|
+
* aggregates them for the consuming site's one-line `@import`.
|
|
16
|
+
*/
|
|
17
|
+
@import './theme/tokens.css';
|
|
18
|
+
@import './toc-toggle/TocToggle.css';
|
|
19
|
+
@import './sql/sql.css';
|
package/src/register.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Side-effect import: registers the official `<iconify-icon>` custom element,
|
|
2
|
+
// which the `dfk-*` components use for every glyph. It loads icon data on
|
|
3
|
+
// demand from the public Iconify API, so this package ships no icon sets.
|
|
4
|
+
import 'iconify-icon';
|
|
5
|
+
import {DfkFeatures} from './home/DfkFeatures';
|
|
6
|
+
import {DfkHero} from './home/DfkHero';
|
|
7
|
+
import {DfkNextSteps} from './home/DfkNextSteps';
|
|
8
|
+
import {DfkSql} from './sql/DfkSql';
|
|
9
|
+
|
|
10
|
+
const TAGS = {
|
|
11
|
+
hero: 'dfk-hero',
|
|
12
|
+
features: 'dfk-features',
|
|
13
|
+
nextSteps: 'dfk-next-steps',
|
|
14
|
+
sql: 'dfk-sql',
|
|
15
|
+
} as const;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Defines the `dfk-*` custom elements. Idempotent and SSR-safe: it is a no-op
|
|
19
|
+
* outside the browser, and re-running it never throws
|
|
20
|
+
* "already been registered with the custom element registry".
|
|
21
|
+
*
|
|
22
|
+
* Call it once at module scope in the docs site (and anywhere else that uses
|
|
23
|
+
* the components); importing the classes alone does not register anything.
|
|
24
|
+
*/
|
|
25
|
+
export function registerDfkElements(): void {
|
|
26
|
+
if (typeof customElements === 'undefined') {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
for (const [name, ctor] of Object.entries({
|
|
30
|
+
[TAGS.hero]: DfkHero,
|
|
31
|
+
[TAGS.features]: DfkFeatures,
|
|
32
|
+
[TAGS.nextSteps]: DfkNextSteps,
|
|
33
|
+
[TAGS.sql]: DfkSql,
|
|
34
|
+
})) {
|
|
35
|
+
if (!customElements.get(name)) {
|
|
36
|
+
customElements.define(name, ctor);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|