kitfly 0.1.2 → 0.2.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.
- package/CHANGELOG.md +46 -0
- package/README.md +63 -16
- package/VERSION +1 -1
- package/dist/_raw/content/deployment/preflight.md +134 -0
- package/dist/_raw/content/deployment/recipes/aws-s3.md +128 -0
- package/dist/_raw/content/deployment/recipes/cloudflare-pages.md +73 -0
- package/dist/_raw/content/deployment/recipes/cloudflare-r2.md +156 -0
- package/dist/_raw/content/deployment/recipes/fly-io.md +57 -0
- package/dist/_raw/content/deployment/recipes/github-pages.md +112 -0
- package/dist/_raw/content/deployment/recipes/netlify.md +99 -0
- package/dist/_raw/content/deployment/recipes/vercel.md +88 -0
- package/dist/_raw/content/deployment/secrets-and-env-vars.md +75 -0
- package/dist/_raw/content/deployment.md +128 -0
- package/dist/_raw/content/guide/approaches.md +182 -0
- package/dist/_raw/content/guide/features.md +121 -0
- package/dist/_raw/content/guide/getting-started.md +112 -0
- package/dist/_raw/content/guide/kitfly-overview.md +209 -0
- package/dist/_raw/content/reference/configuration.md +259 -0
- package/dist/_raw/content/reference/design-catalog.md +167 -0
- package/dist/_raw/content/reference/environment-variables.md +66 -0
- package/dist/_raw/content/reference/glossary.md +92 -0
- package/dist/_raw/content/reference/key-concepts.md +118 -0
- package/dist/_raw/content/reference/plugins.md +220 -0
- package/dist/_raw/content/reference/slides-authoring-guidelines.md +129 -0
- package/dist/_raw/content/reference/structure.md +166 -0
- package/dist/_raw/content/reference.md +20 -0
- package/dist/_raw/content/templates/crucible.md +192 -0
- package/dist/_raw/content/templates/handbook.md +83 -0
- package/dist/_raw/content/templates/minimal.md +138 -0
- package/dist/_raw/content/templates/overview.md +187 -0
- package/dist/_raw/content/templates/pipeline.md +151 -0
- package/dist/_raw/content/templates/productbook.md +187 -0
- package/dist/_raw/content/templates/runbook.md +193 -0
- package/dist/_raw/content/templates/servicebook.md +163 -0
- package/dist/_raw/docs/decisions/ADR-0001-minimalist-site-code.md +118 -0
- package/dist/_raw/docs/decisions/ADR-0002-ai-accessibility.md +153 -0
- package/dist/_raw/docs/decisions/ADR-0003-single-file-bundle.md +93 -0
- package/dist/_raw/docs/decisions/ADR-0004-bun-runtime.md +98 -0
- package/dist/_raw/docs/decisions/ADR-0005-plugin-contract-and-distribution.md +110 -0
- package/dist/_raw/docs/decisions/DDR-0001-viewport-locked-layout.md +111 -0
- package/dist/_raw/docs/decisions/DDR-0002-theme-system.md +131 -0
- package/dist/_raw/docs/decisions/DDR-0003-bounded-logo-slot.md +106 -0
- package/dist/_raw/docs/decisions/DDR-0004-slides-rendering-model.md +113 -0
- package/dist/_raw/docs/decisions/DDR-0005-deterministic-layout-boundary.md +107 -0
- package/dist/_raw/docs/userguide/cli/build.md +85 -0
- package/dist/_raw/docs/userguide/cli/bundle.md +81 -0
- package/dist/_raw/docs/userguide/cli/dev.md +92 -0
- package/dist/_raw/docs/userguide/cli/init.md +116 -0
- package/dist/_raw/docs/userguide/cli/servers.md +69 -0
- package/dist/_raw/docs/userguide/cli/stop.md +76 -0
- package/dist/_raw/docs/userguide/cli/update.md +78 -0
- package/dist/_raw/docs/userguide/cli/version.md +65 -0
- package/dist/_raw/docs/userguide/cli.md +34 -0
- package/dist/_raw/docs/userguide/sharing.md +94 -0
- package/dist/_raw/schemas/plugin-schemas-notes.md +71 -0
- package/dist/_raw/schemas.md +42 -0
- package/dist/assets/brand/kitfly-favicon-32.png +0 -0
- package/dist/assets/brand/kitfly-icon-64.png +0 -0
- package/dist/assets/brand/kitfly-logo-128.png +0 -0
- package/dist/assets/brand/kitfly-logo-512.png +0 -0
- package/dist/assets/brand/kitfly-logo.svg +12132 -0
- package/dist/assets/brand/kitfly-neon-128.png +0 -0
- package/dist/assets/brand/kitfly-neon-192.png +0 -0
- package/dist/assets/brand/kitfly-neon-256.png +0 -0
- package/dist/assets/brand/kitfly-neon.png +0 -0
- package/dist/assets/brand/palette.md +75 -0
- package/dist/content/deployment/index.html +11 -0
- package/dist/content/deployment/preflight.html +418 -0
- package/dist/content/deployment/recipes/aws-s3.html +421 -0
- package/dist/content/deployment/recipes/cloudflare-pages.html +372 -0
- package/dist/content/deployment/recipes/cloudflare-r2.html +443 -0
- package/dist/content/deployment/recipes/fly-io.html +356 -0
- package/dist/content/deployment/recipes/github-pages.html +414 -0
- package/dist/content/deployment/recipes/index.html +11 -0
- package/dist/content/deployment/recipes/netlify.html +394 -0
- package/dist/content/deployment/recipes/vercel.html +382 -0
- package/dist/content/deployment/secrets-and-env-vars.html +380 -0
- package/dist/content/deployment.html +426 -0
- package/dist/content/guide/approaches.html +501 -0
- package/dist/content/guide/features.html +436 -0
- package/dist/content/guide/getting-started.html +403 -0
- package/dist/content/guide/index.html +11 -0
- package/dist/content/guide/kitfly-overview.html +544 -0
- package/dist/content/index.html +11 -0
- package/dist/content/reference/configuration.html +580 -0
- package/dist/content/reference/design-catalog.html +449 -0
- package/dist/content/reference/environment-variables.html +367 -0
- package/dist/content/reference/glossary.html +368 -0
- package/dist/content/reference/index.html +11 -0
- package/dist/content/reference/key-concepts.html +399 -0
- package/dist/content/reference/plugins.html +491 -0
- package/dist/content/reference/slides-authoring-guidelines.html +418 -0
- package/dist/content/reference/structure.html +463 -0
- package/dist/content/reference.html +335 -0
- package/dist/content/templates/crucible.html +546 -0
- package/dist/content/templates/handbook.html +405 -0
- package/dist/content/templates/index.html +11 -0
- package/dist/content/templates/minimal.html +447 -0
- package/dist/content/templates/overview.html +558 -0
- package/dist/content/templates/pipeline.html +494 -0
- package/dist/content/templates/productbook.html +540 -0
- package/dist/content/templates/runbook.html +543 -0
- package/dist/content/templates/servicebook.html +523 -0
- package/dist/content-index.json +549 -0
- package/dist/docs/decisions/ADR-0001-minimalist-site-code.html +491 -0
- package/dist/docs/decisions/ADR-0002-ai-accessibility.html +434 -0
- package/dist/docs/decisions/ADR-0003-single-file-bundle.html +412 -0
- package/dist/docs/decisions/ADR-0004-bun-runtime.html +409 -0
- package/dist/docs/decisions/ADR-0005-plugin-contract-and-distribution.html +402 -0
- package/dist/docs/decisions/DDR-0001-viewport-locked-layout.html +459 -0
- package/dist/docs/decisions/DDR-0002-theme-system.html +452 -0
- package/dist/docs/decisions/DDR-0003-bounded-logo-slot.html +423 -0
- package/dist/docs/decisions/DDR-0004-slides-rendering-model.html +399 -0
- package/dist/docs/decisions/DDR-0005-deterministic-layout-boundary.html +422 -0
- package/dist/docs/decisions/index.html +11 -0
- package/dist/docs/userguide/cli/build.html +408 -0
- package/dist/docs/userguide/cli/bundle.html +419 -0
- package/dist/docs/userguide/cli/dev.html +428 -0
- package/dist/docs/userguide/cli/index.html +11 -0
- package/dist/docs/userguide/cli/init.html +436 -0
- package/dist/docs/userguide/cli/servers.html +393 -0
- package/dist/docs/userguide/cli/stop.html +408 -0
- package/dist/docs/userguide/cli/update.html +406 -0
- package/dist/docs/userguide/cli/version.html +406 -0
- package/dist/docs/userguide/cli.html +386 -0
- package/dist/docs/userguide/index.html +11 -0
- package/dist/docs/userguide/sharing.html +465 -0
- package/dist/index.html +387 -0
- package/dist/llms.txt +18 -0
- package/dist/provenance.json +7 -0
- package/dist/schemas/index.html +11 -0
- package/dist/schemas/plugin-registry.schema.html +327 -0
- package/dist/schemas/plugin-schemas-notes.html +364 -0
- package/dist/schemas/plugin.schema.html +327 -0
- package/dist/schemas/plugins.schema.html +327 -0
- package/dist/schemas/v0/common.schema.html +386 -0
- package/dist/schemas/v0/index.html +11 -0
- package/dist/schemas/v0/plugin-registry.schema.html +547 -0
- package/dist/schemas/v0/plugin.schema.html +497 -0
- package/dist/schemas/v0/plugins.schema.html +406 -0
- package/dist/schemas/v0/site.schema.html +541 -0
- package/dist/schemas/v0/theme.schema.html +615 -0
- package/dist/schemas.html +351 -0
- package/dist/styles.css +1262 -0
- package/package.json +4 -2
- package/plugins-dist/callouts.css +32 -0
- package/plugins-dist/callouts.js +46 -0
- package/plugins-dist/slides-visuals.css +390 -0
- package/plugins-dist/slides-visuals.js +689 -0
- package/registry/plugins.yaml +35 -0
- package/schemas/README.md +10 -0
- package/schemas/plugin-registry.schema.json +5 -0
- package/schemas/plugin-schemas-notes.md +71 -0
- package/schemas/plugin.schema.json +5 -0
- package/schemas/plugins.schema.json +5 -0
- package/schemas/v0/common.schema.json +64 -0
- package/schemas/v0/plugin-registry.schema.json +225 -0
- package/schemas/v0/plugin.schema.json +175 -0
- package/schemas/v0/plugins.schema.json +84 -0
- package/schemas/v0/site.schema.json +56 -9
- package/schemas/v0/theme.schema.json +105 -22
- package/scripts/build.ts +158 -3
- package/scripts/bundle.ts +261 -95
- package/scripts/dev.ts +301 -11
- package/src/__tests__/build.test.ts +220 -1
- package/src/__tests__/bundle.test.ts +31 -0
- package/src/__tests__/cli.test.ts +14 -3
- package/src/__tests__/dev-plugin-errors.test.ts +20 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/bad-list-indent.md +5 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/blank-line.md +5 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/compare-object-items.md +9 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/flow-branching-no-source.md +5 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/flow-converging-no-target.md +6 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/indented-fence.md +4 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/staircase-empty-steps.md +3 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/stat-grid-missing-fields.md +5 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/timeline-horizontal-no-events.md +2 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/unknown-type.md +3 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/compare.md +10 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/comparison-table.md +14 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/flow-branching-no-split.md +7 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/flow-branching.md +8 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/flow-converging-no-merge.md +7 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/flow-converging.md +8 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/funnel.md +7 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/kpi.md +5 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/layer-cake.md +6 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/pyramid.md +6 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/quadrant-grid.md +8 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/scorecard.md +13 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/staircase-down.md +7 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/staircase.md +8 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/stat-grid.md +8 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/timeline-horizontal.md +9 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/timeline-vertical.md +10 -0
- package/src/__tests__/init.test.ts +35 -0
- package/src/__tests__/plugin-loader.test.ts +221 -0
- package/src/__tests__/shared.test.ts +451 -0
- package/src/__tests__/slides-visuals-fence-contract.test.ts +28 -0
- package/src/__tests__/slides-visuals-runtime-regressions.bun.test.ts +147 -0
- package/src/__tests__/styles.test.ts +35 -0
- package/src/cli.ts +9 -4
- package/src/plugin-loader.ts +245 -0
- package/src/shared.ts +650 -7
- package/src/site/styles.css +331 -0
- package/src/site/template.html +66 -5
- package/src/templates/deck.ts +186 -0
- package/src/templates/driver.ts +11 -1
- package/src/templates/minimal.ts +1 -0
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Pipeline Template - Kitfly Docs</title>
|
|
7
|
+
<link rel="icon" type="image/png" sizes="32x32" href="../../assets/brand/kitfly-favicon-32.png">
|
|
8
|
+
<link rel="icon" type="image/png" sizes="64x64" href="../../assets/brand/kitfly-neon-256.png">
|
|
9
|
+
<link rel="stylesheet" href="../../styles.css">
|
|
10
|
+
<style id="kitfly-theme">
|
|
11
|
+
:root { --color-bg: #ffffff;
|
|
12
|
+
--color-bg-sidebar: #f5f7f8;
|
|
13
|
+
--color-text: #374151;
|
|
14
|
+
--color-text-muted: #6b7280;
|
|
15
|
+
--color-border: #e5e7eb;
|
|
16
|
+
--color-link: #007182;
|
|
17
|
+
--color-link-hover: #0a6172;
|
|
18
|
+
--color-accent: #152F46;
|
|
19
|
+
--color-code-bg: #f5f7f8;
|
|
20
|
+
--color-logo: #152F46;
|
|
21
|
+
--sidebar-width: 280px;
|
|
22
|
+
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
23
|
+
--font-headings: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
24
|
+
--font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; }
|
|
25
|
+
html { font-size: 16px; }
|
|
26
|
+
@media (prefers-color-scheme: dark) {
|
|
27
|
+
:root:not([data-theme="light"]) { --color-bg: #0d1117;
|
|
28
|
+
--color-bg-sidebar: #152F46;
|
|
29
|
+
--color-text: #e5e7eb;
|
|
30
|
+
--color-text-muted: #9ca3af;
|
|
31
|
+
--color-border: #374151;
|
|
32
|
+
--color-link: #709EA6;
|
|
33
|
+
--color-link-hover: #8fb5bc;
|
|
34
|
+
--color-accent: #f9fafb;
|
|
35
|
+
--color-code-bg: #152F46;
|
|
36
|
+
--color-logo: #f9fafb; }
|
|
37
|
+
}
|
|
38
|
+
[data-theme="dark"] { --color-bg: #0d1117;
|
|
39
|
+
--color-bg-sidebar: #152F46;
|
|
40
|
+
--color-text: #e5e7eb;
|
|
41
|
+
--color-text-muted: #9ca3af;
|
|
42
|
+
--color-border: #374151;
|
|
43
|
+
--color-link: #709EA6;
|
|
44
|
+
--color-link-hover: #8fb5bc;
|
|
45
|
+
--color-accent: #f9fafb;
|
|
46
|
+
--color-code-bg: #152F46;
|
|
47
|
+
--color-logo: #f9fafb; }
|
|
48
|
+
[data-theme="light"] { --color-bg: #ffffff;
|
|
49
|
+
--color-bg-sidebar: #f5f7f8;
|
|
50
|
+
--color-text: #374151;
|
|
51
|
+
--color-text-muted: #6b7280;
|
|
52
|
+
--color-border: #e5e7eb;
|
|
53
|
+
--color-link: #007182;
|
|
54
|
+
--color-link-hover: #0a6172;
|
|
55
|
+
--color-accent: #152F46;
|
|
56
|
+
--color-code-bg: #f5f7f8;
|
|
57
|
+
--color-logo: #152F46;
|
|
58
|
+
--sidebar-width: 280px;
|
|
59
|
+
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
60
|
+
--font-headings: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
61
|
+
--font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; }
|
|
62
|
+
</style>
|
|
63
|
+
<!-- Syntax highlighting - Prism.js -->
|
|
64
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1/themes/prism.min.css" id="prism-light">
|
|
65
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1/themes/prism-okaidia.min.css" id="prism-dark" disabled>
|
|
66
|
+
|
|
67
|
+
<script>
|
|
68
|
+
// Apply saved theme immediately to prevent flash
|
|
69
|
+
(function() {
|
|
70
|
+
const saved = localStorage.getItem('theme');
|
|
71
|
+
if (saved) {
|
|
72
|
+
document.documentElement.setAttribute('data-theme', saved);
|
|
73
|
+
}
|
|
74
|
+
// Set Prism theme based on saved or system preference
|
|
75
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
76
|
+
const isDark = saved === 'dark' || (!saved && prefersDark);
|
|
77
|
+
if (isDark) {
|
|
78
|
+
document.getElementById('prism-light')?.setAttribute('disabled', '');
|
|
79
|
+
document.getElementById('prism-dark')?.removeAttribute('disabled');
|
|
80
|
+
}
|
|
81
|
+
})();
|
|
82
|
+
</script>
|
|
83
|
+
</head>
|
|
84
|
+
<body class="mode-docs">
|
|
85
|
+
<div class="mobile-header">
|
|
86
|
+
<button class="nav-toggle" onclick="toggleNav()" aria-label="Toggle navigation">
|
|
87
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
88
|
+
<path d="M3 12h18M3 6h18M3 18h18"/>
|
|
89
|
+
</svg>
|
|
90
|
+
</button>
|
|
91
|
+
<a href="../../" class="mobile-logo" title="Home" data-initial="K">
|
|
92
|
+
<img src="../../assets/brand/kitfly-neon-256.png" alt="Kitfly" class="logo-img logo-icon" onerror="this.onerror=null;this.style.display='none';this.parentElement.classList.add('logo-fallback')"/>
|
|
93
|
+
</a>
|
|
94
|
+
<button class="mobile-theme-toggle" onclick="toggleTheme()" title="Toggle theme" aria-label="Toggle theme">
|
|
95
|
+
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
96
|
+
<circle cx="12" cy="12" r="5"/>
|
|
97
|
+
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
|
|
98
|
+
</svg>
|
|
99
|
+
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
100
|
+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
|
101
|
+
</svg>
|
|
102
|
+
</button>
|
|
103
|
+
</div>
|
|
104
|
+
<div class="layout">
|
|
105
|
+
<nav class="sidebar">
|
|
106
|
+
<div class="sidebar-header">
|
|
107
|
+
<div class="logo logo-icon">
|
|
108
|
+
<a href="/" class="logo-icon" data-initial="K">
|
|
109
|
+
<img src="../../assets/brand/kitfly-neon-256.png" alt="Kitfly" class="logo-img" onerror="this.onerror=null;this.style.display='none';this.parentElement.classList.add('logo-fallback')"/>
|
|
110
|
+
</a>
|
|
111
|
+
<span class="logo-text">
|
|
112
|
+
<a href="/" class="brand">Kitfly</a>
|
|
113
|
+
<a href="../../" class="product">Kitfly Docs</a>
|
|
114
|
+
</span>
|
|
115
|
+
</div>
|
|
116
|
+
<div class="header-tools">
|
|
117
|
+
<button class="theme-toggle" onclick="toggleTheme()" title="Toggle theme" aria-label="Toggle theme">
|
|
118
|
+
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
119
|
+
<circle cx="12" cy="12" r="5"/>
|
|
120
|
+
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
|
|
121
|
+
</svg>
|
|
122
|
+
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
123
|
+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
|
124
|
+
</svg>
|
|
125
|
+
</button>
|
|
126
|
+
<div class="sidebar-meta">
|
|
127
|
+
<span class="meta-version">v0.2.1</span>
|
|
128
|
+
<span class="meta-branch">HEAD</span>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
<div class="sidebar-nav">
|
|
133
|
+
<ul><li><a href="../../index.html" class="nav-home">Home</a></li><li><span class="nav-section">Guide</span><ul><li><a href="../../content/guide/approaches.html">approaches</a></li><li><a href="../../content/guide/features.html">features</a></li><li><a href="../../content/guide/getting-started.html">getting-started</a></li><li><a href="../../content/guide/kitfly-overview.html">kitfly-overview</a></li></ul></li><li><span class="nav-section">Templates</span><ul><li><a href="../../content/templates/crucible.html">crucible</a></li><li><a href="../../content/templates/handbook.html">handbook</a></li><li><a href="../../content/templates/minimal.html">minimal</a></li><li><a href="../../content/templates/overview.html">overview</a></li><li><a href="../../content/templates/pipeline.html" class="active">pipeline</a></li><li><a href="../../content/templates/productbook.html">productbook</a></li><li><a href="../../content/templates/runbook.html">runbook</a></li><li><a href="../../content/templates/servicebook.html">servicebook</a></li></ul></li><li><a href="../../content/reference.html" class="nav-section">Reference</a><ul><li><a href="../../content/reference/configuration.html">configuration</a></li><li><a href="../../content/reference/design-catalog.html">design-catalog</a></li><li><a href="../../content/reference/environment-variables.html">environment-variables</a></li><li><a href="../../content/reference/glossary.html">glossary</a></li><li><a href="../../content/reference/key-concepts.html">key-concepts</a></li><li><a href="../../content/reference/plugins.html">plugins</a></li><li><a href="../../content/reference/slides-authoring-guidelines.html">slides-authoring-guidelines</a></li><li><a href="../../content/reference/structure.html">structure</a></li></ul></li><li><a href="../../content/deployment.html" class="nav-section">Deployment</a><ul><li><a href="../../content/deployment/preflight.html">preflight</a></li><li><details><summary class="nav-group">recipes</summary><ul><li><a href="../../content/deployment/recipes/aws-s3.html">aws-s3</a></li><li><a href="../../content/deployment/recipes/cloudflare-pages.html">cloudflare-pages</a></li><li><a href="../../content/deployment/recipes/cloudflare-r2.html">cloudflare-r2</a></li><li><a href="../../content/deployment/recipes/fly-io.html">fly-io</a></li><li><a href="../../content/deployment/recipes/github-pages.html">github-pages</a></li><li><a href="../../content/deployment/recipes/netlify.html">netlify</a></li><li><a href="../../content/deployment/recipes/vercel.html">vercel</a></li></ul></details></li><li><a href="../../content/deployment/secrets-and-env-vars.html">secrets-and-env-vars</a></li></ul></li><li><span class="nav-section">User Guide</span><ul><li><details><summary class="nav-group"><a href="../../docs/userguide/cli.html">cli</a></summary><ul><li><a href="../../docs/userguide/cli/build.html">build</a></li><li><a href="../../docs/userguide/cli/bundle.html">bundle</a></li><li><a href="../../docs/userguide/cli/dev.html">dev</a></li><li><a href="../../docs/userguide/cli/init.html">init</a></li><li><a href="../../docs/userguide/cli/servers.html">servers</a></li><li><a href="../../docs/userguide/cli/stop.html">stop</a></li><li><a href="../../docs/userguide/cli/update.html">update</a></li><li><a href="../../docs/userguide/cli/version.html">version</a></li></ul></details></li><li><a href="../../docs/userguide/sharing.html">sharing</a></li></ul></li><li><span class="nav-section">Decisions</span><ul><li><a href="../../docs/decisions/ADR-0001-minimalist-site-code.html">ADR-0001-minimalist-site-code</a></li><li><a href="../../docs/decisions/ADR-0002-ai-accessibility.html">ADR-0002-ai-accessibility</a></li><li><a href="../../docs/decisions/ADR-0003-single-file-bundle.html">ADR-0003-single-file-bundle</a></li><li><a href="../../docs/decisions/ADR-0004-bun-runtime.html">ADR-0004-bun-runtime</a></li><li><a href="../../docs/decisions/ADR-0005-plugin-contract-and-distribution.html">ADR-0005-plugin-contract-and-distribution</a></li><li><a href="../../docs/decisions/DDR-0001-viewport-locked-layout.html">DDR-0001-viewport-locked-layout</a></li><li><a href="../../docs/decisions/DDR-0002-theme-system.html">DDR-0002-theme-system</a></li><li><a href="../../docs/decisions/DDR-0003-bounded-logo-slot.html">DDR-0003-bounded-logo-slot</a></li><li><a href="../../docs/decisions/DDR-0004-slides-rendering-model.html">DDR-0004-slides-rendering-model</a></li><li><a href="../../docs/decisions/DDR-0005-deterministic-layout-boundary.html">DDR-0005-deterministic-layout-boundary</a></li></ul></li><li><a href="../../schemas.html" class="nav-section">Schemas</a><ul><li><a href="../../schemas/plugin-registry.schema.html">plugin-registry.schema</a></li><li><a href="../../schemas/plugin-schemas-notes.html">plugin-schemas-notes</a></li><li><a href="../../schemas/plugin.schema.html">plugin.schema</a></li><li><a href="../../schemas/plugins.schema.html">plugins.schema</a></li><li><details><summary class="nav-group">v0</summary><ul><li><a href="../../schemas/v0/common.schema.html">common.schema</a></li><li><a href="../../schemas/v0/plugin-registry.schema.html">plugin-registry.schema</a></li><li><a href="../../schemas/v0/plugin.schema.html">plugin.schema</a></li><li><a href="../../schemas/v0/plugins.schema.html">plugins.schema</a></li><li><a href="../../schemas/v0/site.schema.html">site.schema</a></li><li><a href="../../schemas/v0/theme.schema.html">theme.schema</a></li></ul></details></li></ul></li></ul>
|
|
134
|
+
</div>
|
|
135
|
+
</nav>
|
|
136
|
+
<main class="content">
|
|
137
|
+
<article class="prose">
|
|
138
|
+
<nav class="breadcrumbs"><a href="../../content/guide/approaches.html">Content</a><span class="separator">›</span><a href="../../content/templates/crucible.html">Templates</a><span class="separator">›</span><span>pipeline</span></nav>
|
|
139
|
+
|
|
140
|
+
<h1 id="pipeline-template">Pipeline Template</h1>
|
|
141
|
+
<p>The <code>pipeline</code> template creates a structured site for data pipeline operations. It extends <code>minimal</code> with sections designed for teams that build, run, and maintain data pipelines — index builds, content extraction, transfer/reflow, and validation.</p>
|
|
142
|
+
<h2 id="when-to-use">When to Use</h2>
|
|
143
|
+
<ul>
|
|
144
|
+
<li>Data pipeline operational documentation</li>
|
|
145
|
+
<li>ETL/ELT process runbooks</li>
|
|
146
|
+
<li>Data migration projects</li>
|
|
147
|
+
<li>Batch processing operations</li>
|
|
148
|
+
<li>Any workflow with sequential stages moving data from sources to destinations</li>
|
|
149
|
+
</ul>
|
|
150
|
+
<h2 id="what-you-get">What You Get</h2>
|
|
151
|
+
<p>Everything from <code>minimal</code>, plus:</p>
|
|
152
|
+
<pre><code>my-pipeline/
|
|
153
|
+
├── site.yaml # Configured with pipeline sections
|
|
154
|
+
├── index.md # Pipeline status dashboard with quick links
|
|
155
|
+
├── CUSTOMIZING.md # How to customize (AI + human friendly)
|
|
156
|
+
├── content/
|
|
157
|
+
│ ├── pipeline/
|
|
158
|
+
│ │ ├── overview.md # End-to-end dataflow
|
|
159
|
+
│ │ ├── index-build.md # Index build stage
|
|
160
|
+
│ │ ├── extract.md # Content extraction stage
|
|
161
|
+
│ │ ├── transfer.md # Transfer / reflow stage
|
|
162
|
+
│ │ └── validate.md # Validation stage
|
|
163
|
+
│ ├── sources/
|
|
164
|
+
│ │ └── index.md # Source system catalog
|
|
165
|
+
│ ├── destinations/
|
|
166
|
+
│ │ └── index.md # Destination catalog
|
|
167
|
+
│ ├── operations/
|
|
168
|
+
│ │ ├── run-pipeline.md # Full execution procedure
|
|
169
|
+
│ │ └── schedules.md # Pipeline schedule table
|
|
170
|
+
│ ├── troubleshooting/
|
|
171
|
+
│ │ └── common-issues.md # Pipeline-specific issues
|
|
172
|
+
│ └── reference/
|
|
173
|
+
│ ├── manifests/
|
|
174
|
+
│ │ └── index.md # Job manifest YAML templates
|
|
175
|
+
│ ├── field-mappings/
|
|
176
|
+
│ │ └── index.md # Source → destination mappings
|
|
177
|
+
│ ├── metrics/
|
|
178
|
+
│ │ └── index.md # Pipeline KPIs and SLAs
|
|
179
|
+
│ ├── checklists/
|
|
180
|
+
│ │ └── pre-run.md # Pre-run verification
|
|
181
|
+
│ └── contacts/
|
|
182
|
+
│ └── directory.md # Team contacts and escalation
|
|
183
|
+
└── ...
|
|
184
|
+
</code></pre>
|
|
185
|
+
<h2 id="sections">Sections</h2>
|
|
186
|
+
<table>
|
|
187
|
+
<thead>
|
|
188
|
+
<tr>
|
|
189
|
+
<th>Section</th>
|
|
190
|
+
<th>Purpose</th>
|
|
191
|
+
<th>Typical Content</th>
|
|
192
|
+
</tr>
|
|
193
|
+
</thead>
|
|
194
|
+
<tbody><tr>
|
|
195
|
+
<td><strong>Pipeline</strong></td>
|
|
196
|
+
<td>Core dataflow documentation</td>
|
|
197
|
+
<td>Stage definitions, data movement, processing logic</td>
|
|
198
|
+
</tr>
|
|
199
|
+
<tr>
|
|
200
|
+
<td><strong>Sources</strong></td>
|
|
201
|
+
<td>Input systems</td>
|
|
202
|
+
<td>Connection details, schemas, auth profiles, data formats</td>
|
|
203
|
+
</tr>
|
|
204
|
+
<tr>
|
|
205
|
+
<td><strong>Destinations</strong></td>
|
|
206
|
+
<td>Output systems</td>
|
|
207
|
+
<td>Target structures, path layouts, landing zones</td>
|
|
208
|
+
</tr>
|
|
209
|
+
<tr>
|
|
210
|
+
<td><strong>Operations</strong></td>
|
|
211
|
+
<td>Run procedures</td>
|
|
212
|
+
<td>Execution steps, schedules, checkpoint/resume</td>
|
|
213
|
+
</tr>
|
|
214
|
+
<tr>
|
|
215
|
+
<td><strong>Troubleshooting</strong></td>
|
|
216
|
+
<td>Problem resolution</td>
|
|
217
|
+
<td>Auth expiry, index locks, duplicate conflicts, collision handling</td>
|
|
218
|
+
</tr>
|
|
219
|
+
<tr>
|
|
220
|
+
<td><strong>Reference</strong></td>
|
|
221
|
+
<td>Supporting materials</td>
|
|
222
|
+
<td>Manifests, field mappings, metrics, checklists, contacts</td>
|
|
223
|
+
</tr>
|
|
224
|
+
</tbody></table>
|
|
225
|
+
<h3 id="pipeline-vs-runbook">Pipeline vs. Runbook</h3>
|
|
226
|
+
<p>Both are operational templates, but they serve different shapes of work:</p>
|
|
227
|
+
<table>
|
|
228
|
+
<thead>
|
|
229
|
+
<tr>
|
|
230
|
+
<th>Aspect</th>
|
|
231
|
+
<th>Runbook</th>
|
|
232
|
+
<th>Pipeline</th>
|
|
233
|
+
</tr>
|
|
234
|
+
</thead>
|
|
235
|
+
<tbody><tr>
|
|
236
|
+
<td><strong>Focus</strong></td>
|
|
237
|
+
<td>Service operations</td>
|
|
238
|
+
<td>Data movement</td>
|
|
239
|
+
</tr>
|
|
240
|
+
<tr>
|
|
241
|
+
<td><strong>Structure</strong></td>
|
|
242
|
+
<td>Procedures + incidents</td>
|
|
243
|
+
<td>Sequential stages + sources/destinations</td>
|
|
244
|
+
</tr>
|
|
245
|
+
<tr>
|
|
246
|
+
<td><strong>Key question</strong></td>
|
|
247
|
+
<td>"What do I do when X breaks?"</td>
|
|
248
|
+
<td>"How does data flow from A to B?"</td>
|
|
249
|
+
</tr>
|
|
250
|
+
<tr>
|
|
251
|
+
<td><strong>Reference model</strong></td>
|
|
252
|
+
<td>Interfaces, contacts, checklists</td>
|
|
253
|
+
<td>Manifests, field mappings, metrics</td>
|
|
254
|
+
</tr>
|
|
255
|
+
</tbody></table>
|
|
256
|
+
<h2 id="usage">Usage</h2>
|
|
257
|
+
<pre><code class="language-bash">kitfly init data-ops --template pipeline
|
|
258
|
+
kitfly init data-ops --template pipeline --brand "Data Platform"
|
|
259
|
+
|
|
260
|
+
# With AI assistance instrumentation
|
|
261
|
+
kitfly init data-ops --template pipeline --standalone --ai-assist
|
|
262
|
+
</code></pre>
|
|
263
|
+
<h2 id="the-pipeline-section">The Pipeline Section</h2>
|
|
264
|
+
<p>The core of this template. Each stage is documented with:</p>
|
|
265
|
+
<ul>
|
|
266
|
+
<li><strong>Objective</strong> — what the stage accomplishes</li>
|
|
267
|
+
<li><strong>Prerequisites</strong> — what must be in place before running</li>
|
|
268
|
+
<li><strong>Procedure</strong> — step-by-step execution</li>
|
|
269
|
+
<li><strong>Verification</strong> — how to confirm success</li>
|
|
270
|
+
</ul>
|
|
271
|
+
<p>The default stages follow a common data pipeline pattern:</p>
|
|
272
|
+
<pre><code>Source → Index Build → Content Extraction → Transfer/Reflow → Validation → Destination
|
|
273
|
+
</code></pre>
|
|
274
|
+
<p>Adapt these to your actual pipeline. Add, remove, or rename stages as needed.</p>
|
|
275
|
+
<h2 id="growing-your-pipeline-docs">Growing Your Pipeline Docs</h2>
|
|
276
|
+
<p>As your pipeline matures, consider expanding:</p>
|
|
277
|
+
<p><strong>Multiple pipelines</strong> — add subdirectories under <code>content/pipeline/</code>:</p>
|
|
278
|
+
<pre><code>content/pipeline/
|
|
279
|
+
├── overview.md
|
|
280
|
+
├── daily-sync/
|
|
281
|
+
│ ├── index.md
|
|
282
|
+
│ ├── extract.md
|
|
283
|
+
│ └── validate.md
|
|
284
|
+
└── quarterly-migration/
|
|
285
|
+
├── index.md
|
|
286
|
+
└── stages.md
|
|
287
|
+
</code></pre>
|
|
288
|
+
<p>The sidebar automatically organizes these into collapsible groups — each subdirectory becomes an expandable section in the navigation.</p>
|
|
289
|
+
<p><strong>Multiple sources/destinations</strong> — add a page per system:</p>
|
|
290
|
+
<pre><code>content/sources/
|
|
291
|
+
├── index.md # Catalog table
|
|
292
|
+
├── salesforce.md # Source details
|
|
293
|
+
└── data-warehouse.md # Source details
|
|
294
|
+
</code></pre>
|
|
295
|
+
<h2 id="example-use-cases">Example Use Cases</h2>
|
|
296
|
+
<p><strong>Cloud Data Migration</strong></p>
|
|
297
|
+
<ul>
|
|
298
|
+
<li>Pipeline: S3 scan → content probe → key rewrite → validation</li>
|
|
299
|
+
<li>Sources: AWS S3 buckets with legacy key structure</li>
|
|
300
|
+
<li>Destinations: GCS with date-partitioned layout</li>
|
|
301
|
+
<li>Operations: Weekly full sync, daily incremental</li>
|
|
302
|
+
<li>Reference/Manifests: Job definitions per source bucket</li>
|
|
303
|
+
</ul>
|
|
304
|
+
<p><strong>ETL for Analytics</strong></p>
|
|
305
|
+
<ul>
|
|
306
|
+
<li>Pipeline: Extract from APIs → transform/enrich → load to warehouse</li>
|
|
307
|
+
<li>Sources: REST APIs, SFTP drops, webhook events</li>
|
|
308
|
+
<li>Destinations: Snowflake tables, Parquet files in S3</li>
|
|
309
|
+
<li>Troubleshooting: Rate limits, schema drift, partial loads</li>
|
|
310
|
+
<li>Reference/Metrics: Row counts, freshness SLAs, error rates</li>
|
|
311
|
+
</ul>
|
|
312
|
+
|
|
313
|
+
</article>
|
|
314
|
+
<aside class="toc"><span class="toc-title">On this page</span><ul><li><a href="#when-to-use">When to Use</a></li><li><a href="#what-you-get">What You Get</a></li><li><a href="#sections">Sections</a></li><li class="toc-h3"><a href="#pipeline-vs-runbook">Pipeline vs. Runbook</a></li><li><a href="#usage">Usage</a></li><li><a href="#the-pipeline-section">The Pipeline Section</a></li><li><a href="#growing-your-pipeline-docs">Growing Your Pipeline Docs</a></li><li><a href="#example-use-cases">Example Use Cases</a></li></ul></aside>
|
|
315
|
+
</main>
|
|
316
|
+
</div>
|
|
317
|
+
|
|
318
|
+
<footer class="site-footer">
|
|
319
|
+
<div class="footer-content">
|
|
320
|
+
<div class="footer-left">
|
|
321
|
+
<span class="footer-version">v0.2.1</span>
|
|
322
|
+
<span class="footer-separator">·</span>
|
|
323
|
+
<span class="footer-commit" title="Commit: 30dfc01">Published 2026-02-15</span>
|
|
324
|
+
</div>
|
|
325
|
+
<div class="footer-center">
|
|
326
|
+
<span class="footer-copyright"><a href="https://3leaps.net" class="footer-link">© 2026 3 Leaps, LLC</a></span>
|
|
327
|
+
<span class="footer-separator">·</span><a href="/" class="footer-link">Kitfly</a>
|
|
328
|
+
</div>
|
|
329
|
+
<div class="footer-right">
|
|
330
|
+
<a href="https://kitfly.dev" class="footer-link">Built with Kitfly</a>
|
|
331
|
+
</div>
|
|
332
|
+
</div>
|
|
333
|
+
</footer>
|
|
334
|
+
<!-- Syntax highlighting - Prism.js -->
|
|
335
|
+
<script src="https://cdn.jsdelivr.net/npm/prismjs@1/components/prism-core.min.js"></script>
|
|
336
|
+
<script src="https://cdn.jsdelivr.net/npm/prismjs@1/plugins/autoloader/prism-autoloader.min.js"></script>
|
|
337
|
+
<!-- Mermaid diagram support -->
|
|
338
|
+
<script type="module">
|
|
339
|
+
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
|
340
|
+
|
|
341
|
+
function getMermaidTheme() {
|
|
342
|
+
const theme = document.documentElement.getAttribute('data-theme');
|
|
343
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
344
|
+
const isDark = theme === 'dark' || (!theme && prefersDark);
|
|
345
|
+
return isDark ? 'dark' : 'neutral';
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
mermaid.initialize({
|
|
349
|
+
startOnLoad: true,
|
|
350
|
+
theme: getMermaidTheme()
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
// Re-render mermaid diagrams when theme changes
|
|
354
|
+
window.reinitMermaid = async function() {
|
|
355
|
+
mermaid.initialize({ startOnLoad: false, theme: getMermaidTheme() });
|
|
356
|
+
const diagrams = document.querySelectorAll('.mermaid');
|
|
357
|
+
for (const el of diagrams) {
|
|
358
|
+
const code = el.getAttribute('data-mermaid-source');
|
|
359
|
+
if (code) {
|
|
360
|
+
el.innerHTML = code;
|
|
361
|
+
el.removeAttribute('data-processed');
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
await mermaid.run({ nodes: diagrams });
|
|
365
|
+
};
|
|
366
|
+
</script>
|
|
367
|
+
|
|
368
|
+
<script>
|
|
369
|
+
function toggleTheme() {
|
|
370
|
+
const html = document.documentElement;
|
|
371
|
+
const current = html.getAttribute('data-theme');
|
|
372
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
373
|
+
|
|
374
|
+
let next;
|
|
375
|
+
if (current === 'dark') {
|
|
376
|
+
next = 'light';
|
|
377
|
+
} else if (current === 'light') {
|
|
378
|
+
next = 'dark';
|
|
379
|
+
} else {
|
|
380
|
+
// No explicit theme set, toggle from system preference
|
|
381
|
+
next = prefersDark ? 'light' : 'dark';
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
html.setAttribute('data-theme', next);
|
|
385
|
+
localStorage.setItem('theme', next);
|
|
386
|
+
|
|
387
|
+
// Switch Prism theme
|
|
388
|
+
const prismLight = document.getElementById('prism-light');
|
|
389
|
+
const prismDark = document.getElementById('prism-dark');
|
|
390
|
+
if (next === 'dark') {
|
|
391
|
+
prismLight?.setAttribute('disabled', '');
|
|
392
|
+
prismDark?.removeAttribute('disabled');
|
|
393
|
+
} else {
|
|
394
|
+
prismLight?.removeAttribute('disabled');
|
|
395
|
+
prismDark?.setAttribute('disabled', '');
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Re-render mermaid diagrams with new theme
|
|
399
|
+
if (window.reinitMermaid) {
|
|
400
|
+
window.reinitMermaid();
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Slides mode hash routing
|
|
405
|
+
(function initSlidesMode() {
|
|
406
|
+
const shell = document.querySelector('.slides-shell');
|
|
407
|
+
if (!shell) return;
|
|
408
|
+
|
|
409
|
+
const slides = Array.from(document.querySelectorAll('.slide'));
|
|
410
|
+
if (!slides.length) return;
|
|
411
|
+
|
|
412
|
+
const prevBtn = document.querySelector('.slide-prev');
|
|
413
|
+
const nextBtn = document.querySelector('.slide-next');
|
|
414
|
+
const counter = document.querySelector('.slide-counter');
|
|
415
|
+
const progressBar = document.querySelector('.slide-progress-bar');
|
|
416
|
+
const navLinks = Array.from(document.querySelectorAll('.sidebar-nav a[href^="#slide-"]'));
|
|
417
|
+
let current = 0;
|
|
418
|
+
|
|
419
|
+
function setActive(n) {
|
|
420
|
+
current = Math.max(0, Math.min(n, slides.length - 1));
|
|
421
|
+
slides.forEach((slide, idx) => slide.classList.toggle('active', idx === current));
|
|
422
|
+
navLinks.forEach((link) => {
|
|
423
|
+
const active = link.getAttribute('href') === '#' + slides[current].id;
|
|
424
|
+
link.classList.toggle('active', active);
|
|
425
|
+
});
|
|
426
|
+
if (counter) counter.textContent = (current + 1) + ' / ' + slides.length;
|
|
427
|
+
if (progressBar) progressBar.style.width = (((current + 1) / slides.length) * 100) + '%';
|
|
428
|
+
if (prevBtn) prevBtn.disabled = current === 0;
|
|
429
|
+
if (nextBtn) nextBtn.disabled = current === slides.length - 1;
|
|
430
|
+
history.replaceState(null, '', '#' + slides[current].id);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function setFromHash() {
|
|
434
|
+
const hash = window.location.hash || '';
|
|
435
|
+
const idx = slides.findIndex((s) => '#' + s.id === hash);
|
|
436
|
+
if (idx >= 0) setActive(idx);
|
|
437
|
+
else setActive(0);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
prevBtn?.addEventListener('click', () => setActive(current - 1));
|
|
441
|
+
nextBtn?.addEventListener('click', () => setActive(current + 1));
|
|
442
|
+
|
|
443
|
+
document.addEventListener('keydown', (e) => {
|
|
444
|
+
if (e.key === 'ArrowRight' || e.key === ' ') {
|
|
445
|
+
e.preventDefault();
|
|
446
|
+
setActive(current + 1);
|
|
447
|
+
} else if (e.key === 'ArrowLeft') {
|
|
448
|
+
e.preventDefault();
|
|
449
|
+
setActive(current - 1);
|
|
450
|
+
} else if (e.key === 'Home') {
|
|
451
|
+
e.preventDefault();
|
|
452
|
+
setActive(0);
|
|
453
|
+
} else if (e.key === 'End') {
|
|
454
|
+
e.preventDefault();
|
|
455
|
+
setActive(slides.length - 1);
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
window.addEventListener('hashchange', setFromHash);
|
|
460
|
+
setFromHash();
|
|
461
|
+
})();
|
|
462
|
+
|
|
463
|
+
// Copy code button
|
|
464
|
+
document.querySelectorAll('.prose pre code').forEach(block => {
|
|
465
|
+
const button = document.createElement('button');
|
|
466
|
+
button.className = 'copy-button';
|
|
467
|
+
button.textContent = 'Copy';
|
|
468
|
+
button.onclick = async () => {
|
|
469
|
+
await navigator.clipboard.writeText(block.textContent);
|
|
470
|
+
button.textContent = 'Copied!';
|
|
471
|
+
setTimeout(() => button.textContent = 'Copy', 2000);
|
|
472
|
+
};
|
|
473
|
+
block.parentElement.appendChild(button);
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
// Mobile nav toggle
|
|
477
|
+
function toggleNav() {
|
|
478
|
+
document.querySelector('.sidebar').classList.toggle('open');
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Close nav when clicking outside on mobile
|
|
482
|
+
document.addEventListener('click', (e) => {
|
|
483
|
+
const sidebar = document.querySelector('.sidebar');
|
|
484
|
+
const toggle = document.querySelector('.nav-toggle');
|
|
485
|
+
if (sidebar.classList.contains('open') &&
|
|
486
|
+
!sidebar.contains(e.target) &&
|
|
487
|
+
!toggle.contains(e.target)) {
|
|
488
|
+
sidebar.classList.remove('open');
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
</script>
|
|
492
|
+
|
|
493
|
+
</body>
|
|
494
|
+
</html>
|