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.
Files changed (209) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +63 -16
  3. package/VERSION +1 -1
  4. package/dist/_raw/content/deployment/preflight.md +134 -0
  5. package/dist/_raw/content/deployment/recipes/aws-s3.md +128 -0
  6. package/dist/_raw/content/deployment/recipes/cloudflare-pages.md +73 -0
  7. package/dist/_raw/content/deployment/recipes/cloudflare-r2.md +156 -0
  8. package/dist/_raw/content/deployment/recipes/fly-io.md +57 -0
  9. package/dist/_raw/content/deployment/recipes/github-pages.md +112 -0
  10. package/dist/_raw/content/deployment/recipes/netlify.md +99 -0
  11. package/dist/_raw/content/deployment/recipes/vercel.md +88 -0
  12. package/dist/_raw/content/deployment/secrets-and-env-vars.md +75 -0
  13. package/dist/_raw/content/deployment.md +128 -0
  14. package/dist/_raw/content/guide/approaches.md +182 -0
  15. package/dist/_raw/content/guide/features.md +121 -0
  16. package/dist/_raw/content/guide/getting-started.md +112 -0
  17. package/dist/_raw/content/guide/kitfly-overview.md +209 -0
  18. package/dist/_raw/content/reference/configuration.md +259 -0
  19. package/dist/_raw/content/reference/design-catalog.md +167 -0
  20. package/dist/_raw/content/reference/environment-variables.md +66 -0
  21. package/dist/_raw/content/reference/glossary.md +92 -0
  22. package/dist/_raw/content/reference/key-concepts.md +118 -0
  23. package/dist/_raw/content/reference/plugins.md +220 -0
  24. package/dist/_raw/content/reference/slides-authoring-guidelines.md +129 -0
  25. package/dist/_raw/content/reference/structure.md +166 -0
  26. package/dist/_raw/content/reference.md +20 -0
  27. package/dist/_raw/content/templates/crucible.md +192 -0
  28. package/dist/_raw/content/templates/handbook.md +83 -0
  29. package/dist/_raw/content/templates/minimal.md +138 -0
  30. package/dist/_raw/content/templates/overview.md +187 -0
  31. package/dist/_raw/content/templates/pipeline.md +151 -0
  32. package/dist/_raw/content/templates/productbook.md +187 -0
  33. package/dist/_raw/content/templates/runbook.md +193 -0
  34. package/dist/_raw/content/templates/servicebook.md +163 -0
  35. package/dist/_raw/docs/decisions/ADR-0001-minimalist-site-code.md +118 -0
  36. package/dist/_raw/docs/decisions/ADR-0002-ai-accessibility.md +153 -0
  37. package/dist/_raw/docs/decisions/ADR-0003-single-file-bundle.md +93 -0
  38. package/dist/_raw/docs/decisions/ADR-0004-bun-runtime.md +98 -0
  39. package/dist/_raw/docs/decisions/ADR-0005-plugin-contract-and-distribution.md +110 -0
  40. package/dist/_raw/docs/decisions/DDR-0001-viewport-locked-layout.md +111 -0
  41. package/dist/_raw/docs/decisions/DDR-0002-theme-system.md +131 -0
  42. package/dist/_raw/docs/decisions/DDR-0003-bounded-logo-slot.md +106 -0
  43. package/dist/_raw/docs/decisions/DDR-0004-slides-rendering-model.md +113 -0
  44. package/dist/_raw/docs/decisions/DDR-0005-deterministic-layout-boundary.md +107 -0
  45. package/dist/_raw/docs/userguide/cli/build.md +85 -0
  46. package/dist/_raw/docs/userguide/cli/bundle.md +81 -0
  47. package/dist/_raw/docs/userguide/cli/dev.md +92 -0
  48. package/dist/_raw/docs/userguide/cli/init.md +116 -0
  49. package/dist/_raw/docs/userguide/cli/servers.md +69 -0
  50. package/dist/_raw/docs/userguide/cli/stop.md +76 -0
  51. package/dist/_raw/docs/userguide/cli/update.md +78 -0
  52. package/dist/_raw/docs/userguide/cli/version.md +65 -0
  53. package/dist/_raw/docs/userguide/cli.md +34 -0
  54. package/dist/_raw/docs/userguide/sharing.md +94 -0
  55. package/dist/_raw/schemas/plugin-schemas-notes.md +71 -0
  56. package/dist/_raw/schemas.md +42 -0
  57. package/dist/assets/brand/kitfly-favicon-32.png +0 -0
  58. package/dist/assets/brand/kitfly-icon-64.png +0 -0
  59. package/dist/assets/brand/kitfly-logo-128.png +0 -0
  60. package/dist/assets/brand/kitfly-logo-512.png +0 -0
  61. package/dist/assets/brand/kitfly-logo.svg +12132 -0
  62. package/dist/assets/brand/kitfly-neon-128.png +0 -0
  63. package/dist/assets/brand/kitfly-neon-192.png +0 -0
  64. package/dist/assets/brand/kitfly-neon-256.png +0 -0
  65. package/dist/assets/brand/kitfly-neon.png +0 -0
  66. package/dist/assets/brand/palette.md +75 -0
  67. package/dist/content/deployment/index.html +11 -0
  68. package/dist/content/deployment/preflight.html +418 -0
  69. package/dist/content/deployment/recipes/aws-s3.html +421 -0
  70. package/dist/content/deployment/recipes/cloudflare-pages.html +372 -0
  71. package/dist/content/deployment/recipes/cloudflare-r2.html +443 -0
  72. package/dist/content/deployment/recipes/fly-io.html +356 -0
  73. package/dist/content/deployment/recipes/github-pages.html +414 -0
  74. package/dist/content/deployment/recipes/index.html +11 -0
  75. package/dist/content/deployment/recipes/netlify.html +394 -0
  76. package/dist/content/deployment/recipes/vercel.html +382 -0
  77. package/dist/content/deployment/secrets-and-env-vars.html +380 -0
  78. package/dist/content/deployment.html +426 -0
  79. package/dist/content/guide/approaches.html +501 -0
  80. package/dist/content/guide/features.html +436 -0
  81. package/dist/content/guide/getting-started.html +403 -0
  82. package/dist/content/guide/index.html +11 -0
  83. package/dist/content/guide/kitfly-overview.html +544 -0
  84. package/dist/content/index.html +11 -0
  85. package/dist/content/reference/configuration.html +580 -0
  86. package/dist/content/reference/design-catalog.html +449 -0
  87. package/dist/content/reference/environment-variables.html +367 -0
  88. package/dist/content/reference/glossary.html +368 -0
  89. package/dist/content/reference/index.html +11 -0
  90. package/dist/content/reference/key-concepts.html +399 -0
  91. package/dist/content/reference/plugins.html +491 -0
  92. package/dist/content/reference/slides-authoring-guidelines.html +418 -0
  93. package/dist/content/reference/structure.html +463 -0
  94. package/dist/content/reference.html +335 -0
  95. package/dist/content/templates/crucible.html +546 -0
  96. package/dist/content/templates/handbook.html +405 -0
  97. package/dist/content/templates/index.html +11 -0
  98. package/dist/content/templates/minimal.html +447 -0
  99. package/dist/content/templates/overview.html +558 -0
  100. package/dist/content/templates/pipeline.html +494 -0
  101. package/dist/content/templates/productbook.html +540 -0
  102. package/dist/content/templates/runbook.html +543 -0
  103. package/dist/content/templates/servicebook.html +523 -0
  104. package/dist/content-index.json +549 -0
  105. package/dist/docs/decisions/ADR-0001-minimalist-site-code.html +491 -0
  106. package/dist/docs/decisions/ADR-0002-ai-accessibility.html +434 -0
  107. package/dist/docs/decisions/ADR-0003-single-file-bundle.html +412 -0
  108. package/dist/docs/decisions/ADR-0004-bun-runtime.html +409 -0
  109. package/dist/docs/decisions/ADR-0005-plugin-contract-and-distribution.html +402 -0
  110. package/dist/docs/decisions/DDR-0001-viewport-locked-layout.html +459 -0
  111. package/dist/docs/decisions/DDR-0002-theme-system.html +452 -0
  112. package/dist/docs/decisions/DDR-0003-bounded-logo-slot.html +423 -0
  113. package/dist/docs/decisions/DDR-0004-slides-rendering-model.html +399 -0
  114. package/dist/docs/decisions/DDR-0005-deterministic-layout-boundary.html +422 -0
  115. package/dist/docs/decisions/index.html +11 -0
  116. package/dist/docs/userguide/cli/build.html +408 -0
  117. package/dist/docs/userguide/cli/bundle.html +419 -0
  118. package/dist/docs/userguide/cli/dev.html +428 -0
  119. package/dist/docs/userguide/cli/index.html +11 -0
  120. package/dist/docs/userguide/cli/init.html +436 -0
  121. package/dist/docs/userguide/cli/servers.html +393 -0
  122. package/dist/docs/userguide/cli/stop.html +408 -0
  123. package/dist/docs/userguide/cli/update.html +406 -0
  124. package/dist/docs/userguide/cli/version.html +406 -0
  125. package/dist/docs/userguide/cli.html +386 -0
  126. package/dist/docs/userguide/index.html +11 -0
  127. package/dist/docs/userguide/sharing.html +465 -0
  128. package/dist/index.html +387 -0
  129. package/dist/llms.txt +18 -0
  130. package/dist/provenance.json +7 -0
  131. package/dist/schemas/index.html +11 -0
  132. package/dist/schemas/plugin-registry.schema.html +327 -0
  133. package/dist/schemas/plugin-schemas-notes.html +364 -0
  134. package/dist/schemas/plugin.schema.html +327 -0
  135. package/dist/schemas/plugins.schema.html +327 -0
  136. package/dist/schemas/v0/common.schema.html +386 -0
  137. package/dist/schemas/v0/index.html +11 -0
  138. package/dist/schemas/v0/plugin-registry.schema.html +547 -0
  139. package/dist/schemas/v0/plugin.schema.html +497 -0
  140. package/dist/schemas/v0/plugins.schema.html +406 -0
  141. package/dist/schemas/v0/site.schema.html +541 -0
  142. package/dist/schemas/v0/theme.schema.html +615 -0
  143. package/dist/schemas.html +351 -0
  144. package/dist/styles.css +1262 -0
  145. package/package.json +4 -2
  146. package/plugins-dist/callouts.css +32 -0
  147. package/plugins-dist/callouts.js +46 -0
  148. package/plugins-dist/slides-visuals.css +390 -0
  149. package/plugins-dist/slides-visuals.js +689 -0
  150. package/registry/plugins.yaml +35 -0
  151. package/schemas/README.md +10 -0
  152. package/schemas/plugin-registry.schema.json +5 -0
  153. package/schemas/plugin-schemas-notes.md +71 -0
  154. package/schemas/plugin.schema.json +5 -0
  155. package/schemas/plugins.schema.json +5 -0
  156. package/schemas/v0/common.schema.json +64 -0
  157. package/schemas/v0/plugin-registry.schema.json +225 -0
  158. package/schemas/v0/plugin.schema.json +175 -0
  159. package/schemas/v0/plugins.schema.json +84 -0
  160. package/schemas/v0/site.schema.json +56 -9
  161. package/schemas/v0/theme.schema.json +105 -22
  162. package/scripts/build.ts +158 -3
  163. package/scripts/bundle.ts +261 -95
  164. package/scripts/dev.ts +301 -11
  165. package/src/__tests__/build.test.ts +220 -1
  166. package/src/__tests__/bundle.test.ts +31 -0
  167. package/src/__tests__/cli.test.ts +14 -3
  168. package/src/__tests__/dev-plugin-errors.test.ts +20 -0
  169. package/src/__tests__/fixtures/fences/slides-visuals/invalid/bad-list-indent.md +5 -0
  170. package/src/__tests__/fixtures/fences/slides-visuals/invalid/blank-line.md +5 -0
  171. package/src/__tests__/fixtures/fences/slides-visuals/invalid/compare-object-items.md +9 -0
  172. package/src/__tests__/fixtures/fences/slides-visuals/invalid/flow-branching-no-source.md +5 -0
  173. package/src/__tests__/fixtures/fences/slides-visuals/invalid/flow-converging-no-target.md +6 -0
  174. package/src/__tests__/fixtures/fences/slides-visuals/invalid/indented-fence.md +4 -0
  175. package/src/__tests__/fixtures/fences/slides-visuals/invalid/staircase-empty-steps.md +3 -0
  176. package/src/__tests__/fixtures/fences/slides-visuals/invalid/stat-grid-missing-fields.md +5 -0
  177. package/src/__tests__/fixtures/fences/slides-visuals/invalid/timeline-horizontal-no-events.md +2 -0
  178. package/src/__tests__/fixtures/fences/slides-visuals/invalid/unknown-type.md +3 -0
  179. package/src/__tests__/fixtures/fences/slides-visuals/valid/compare.md +10 -0
  180. package/src/__tests__/fixtures/fences/slides-visuals/valid/comparison-table.md +14 -0
  181. package/src/__tests__/fixtures/fences/slides-visuals/valid/flow-branching-no-split.md +7 -0
  182. package/src/__tests__/fixtures/fences/slides-visuals/valid/flow-branching.md +8 -0
  183. package/src/__tests__/fixtures/fences/slides-visuals/valid/flow-converging-no-merge.md +7 -0
  184. package/src/__tests__/fixtures/fences/slides-visuals/valid/flow-converging.md +8 -0
  185. package/src/__tests__/fixtures/fences/slides-visuals/valid/funnel.md +7 -0
  186. package/src/__tests__/fixtures/fences/slides-visuals/valid/kpi.md +5 -0
  187. package/src/__tests__/fixtures/fences/slides-visuals/valid/layer-cake.md +6 -0
  188. package/src/__tests__/fixtures/fences/slides-visuals/valid/pyramid.md +6 -0
  189. package/src/__tests__/fixtures/fences/slides-visuals/valid/quadrant-grid.md +8 -0
  190. package/src/__tests__/fixtures/fences/slides-visuals/valid/scorecard.md +13 -0
  191. package/src/__tests__/fixtures/fences/slides-visuals/valid/staircase-down.md +7 -0
  192. package/src/__tests__/fixtures/fences/slides-visuals/valid/staircase.md +8 -0
  193. package/src/__tests__/fixtures/fences/slides-visuals/valid/stat-grid.md +8 -0
  194. package/src/__tests__/fixtures/fences/slides-visuals/valid/timeline-horizontal.md +9 -0
  195. package/src/__tests__/fixtures/fences/slides-visuals/valid/timeline-vertical.md +10 -0
  196. package/src/__tests__/init.test.ts +35 -0
  197. package/src/__tests__/plugin-loader.test.ts +221 -0
  198. package/src/__tests__/shared.test.ts +451 -0
  199. package/src/__tests__/slides-visuals-fence-contract.test.ts +28 -0
  200. package/src/__tests__/slides-visuals-runtime-regressions.bun.test.ts +147 -0
  201. package/src/__tests__/styles.test.ts +35 -0
  202. package/src/cli.ts +9 -4
  203. package/src/plugin-loader.ts +245 -0
  204. package/src/shared.ts +650 -7
  205. package/src/site/styles.css +331 -0
  206. package/src/site/template.html +66 -5
  207. package/src/templates/deck.ts +186 -0
  208. package/src/templates/driver.ts +11 -1
  209. package/src/templates/minimal.ts +1 -0
@@ -173,6 +173,26 @@ body {
173
173
  }
174
174
  }
175
175
 
176
+ .logo-icon.logo-fallback,
177
+ .mobile-logo.logo-fallback {
178
+ width: 2rem;
179
+ height: 2rem;
180
+ max-width: none;
181
+ border-radius: 999px;
182
+ align-items: center;
183
+ justify-content: center;
184
+ background: var(--color-accent);
185
+ }
186
+
187
+ .logo-icon.logo-fallback::before,
188
+ .mobile-logo.logo-fallback::before {
189
+ content: attr(data-initial);
190
+ color: var(--color-bg);
191
+ font-size: 1rem;
192
+ font-weight: 700;
193
+ line-height: 1;
194
+ }
195
+
176
196
  .logo-text {
177
197
  display: flex;
178
198
  flex-direction: column;
@@ -412,6 +432,287 @@ body {
412
432
  max-width: 1100px;
413
433
  }
414
434
 
435
+ /* Slides mode */
436
+ .mode-slides .content {
437
+ max-width: none;
438
+ padding: 1.5rem 2rem;
439
+ padding-right: 2rem;
440
+ padding-bottom: calc(var(--footer-height) + 1rem);
441
+ }
442
+
443
+ .mode-slides .toc,
444
+ .mode-slides .breadcrumbs,
445
+ .mode-slides .page-meta {
446
+ display: none !important;
447
+ }
448
+
449
+ .slides-shell {
450
+ display: flex;
451
+ flex-direction: column;
452
+ gap: 0.75rem;
453
+ }
454
+
455
+ .slide-viewport {
456
+ display: flex;
457
+ align-items: center;
458
+ justify-content: center;
459
+ min-height: calc(100vh - var(--footer-height) - 11rem);
460
+ }
461
+
462
+ .slide-frame {
463
+ aspect-ratio: var(--slide-aspect, 16/9);
464
+ width: min(100%, 1100px);
465
+ max-height: calc(100vh - var(--footer-height) - 12rem);
466
+ overflow: auto;
467
+ border: 1px solid var(--color-border);
468
+ border-radius: 0.5rem;
469
+ background: var(--color-bg);
470
+ padding: 2rem 2.5rem;
471
+ }
472
+
473
+ .slide {
474
+ display: none;
475
+ }
476
+
477
+ .slide.active {
478
+ display: block;
479
+ }
480
+
481
+ .slide-nav {
482
+ display: flex;
483
+ align-items: center;
484
+ justify-content: center;
485
+ gap: 0.75rem;
486
+ color: var(--color-text-muted);
487
+ font-size: 0.8125rem;
488
+ }
489
+
490
+ .slide-prev,
491
+ .slide-next {
492
+ border: 1px solid var(--color-border);
493
+ background: var(--color-bg);
494
+ color: var(--color-text);
495
+ border-radius: 0.375rem;
496
+ padding: 0.25rem 0.625rem;
497
+ cursor: pointer;
498
+ }
499
+
500
+ .slide-prev:disabled,
501
+ .slide-next:disabled {
502
+ opacity: 0.5;
503
+ cursor: not-allowed;
504
+ }
505
+
506
+ .slide-progress {
507
+ width: 10rem;
508
+ height: 0.35rem;
509
+ border-radius: 999px;
510
+ background: var(--color-code-bg);
511
+ overflow: hidden;
512
+ }
513
+
514
+ .slide-progress-bar {
515
+ display: block;
516
+ height: 100%;
517
+ background: var(--color-link);
518
+ transition: width 150ms ease;
519
+ }
520
+
521
+ .slide.centered {
522
+ min-height: 100%;
523
+ flex-direction: column;
524
+ justify-content: center;
525
+ }
526
+
527
+ .slide.two-column {
528
+ column-count: 2;
529
+ column-gap: 1.5rem;
530
+ }
531
+
532
+ .slide.active.centered {
533
+ display: flex;
534
+ }
535
+
536
+ .slide.active.two-column {
537
+ display: block;
538
+ }
539
+
540
+ .slide.active.two-column > h1,
541
+ .slide.active.two-column > h2,
542
+ .slide.active.two-column > h3 {
543
+ column-span: all;
544
+ }
545
+
546
+ .slide.active.two-column > * {
547
+ break-inside: avoid;
548
+ }
549
+
550
+ .slide.active.title-slide {
551
+ display: flex;
552
+ min-height: 100%;
553
+ flex-direction: column;
554
+ align-items: center;
555
+ justify-content: center;
556
+ text-align: center;
557
+ background: color-mix(in srgb, var(--color-link) 12%, var(--color-bg));
558
+ border: 1px solid color-mix(in srgb, var(--color-link) 40%, var(--color-border));
559
+ border-radius: 0.5rem;
560
+ padding: 2rem;
561
+ }
562
+
563
+ .slide.active.section-header {
564
+ display: flex;
565
+ min-height: 100%;
566
+ flex-direction: column;
567
+ align-items: center;
568
+ justify-content: center;
569
+ text-align: center;
570
+ background: color-mix(in srgb, var(--color-link) 6%, var(--color-bg));
571
+ border: 1px solid var(--color-border);
572
+ border-radius: 0.5rem;
573
+ padding: 2rem;
574
+ }
575
+
576
+ .slide.title-slide h1,
577
+ .slide.section-header h1 {
578
+ font-size: 2.25rem;
579
+ }
580
+
581
+ .slide.diagram .mermaid {
582
+ margin: 0.75rem 0;
583
+ }
584
+
585
+ /* Slide layout primitives (core structural patterns) */
586
+ .block {
587
+ border: 1px solid var(--color-border);
588
+ background: var(--color-bg-sidebar);
589
+ color: var(--color-text);
590
+ border-radius: 0.5rem;
591
+ padding: 0.75rem 1rem;
592
+ text-align: center;
593
+ transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
594
+ }
595
+
596
+ @media (prefers-reduced-motion: reduce) {
597
+ .block {
598
+ transition: none;
599
+ }
600
+ }
601
+
602
+ .block.accent {
603
+ background: color-mix(in srgb, var(--color-link) 12%, var(--color-bg));
604
+ border-color: color-mix(in srgb, var(--color-link) 50%, var(--color-border));
605
+ }
606
+
607
+ .block.muted {
608
+ opacity: 0.8;
609
+ }
610
+
611
+ .block.outline {
612
+ background: transparent;
613
+ }
614
+
615
+ .block.circle {
616
+ border-radius: 50%;
617
+ aspect-ratio: 1 / 1;
618
+ inline-size: min(7rem, 100%);
619
+ margin-inline: auto;
620
+ display: flex;
621
+ align-items: center;
622
+ justify-content: center;
623
+ padding: 0.75rem;
624
+ }
625
+
626
+ .block.pill {
627
+ border-radius: 9999px;
628
+ }
629
+
630
+ .block.diamond {
631
+ clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
632
+ }
633
+
634
+ .block.chevron {
635
+ clip-path: polygon(0 0, 75% 0, 100% 50%, 75% 100%, 0 100%, 25% 50%);
636
+ }
637
+
638
+ .block.hexagon {
639
+ clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
640
+ }
641
+
642
+ .block.triangle {
643
+ clip-path: polygon(50% 0, 100% 100%, 0 100%);
644
+ }
645
+
646
+ .block.block-arrow {
647
+ clip-path: polygon(0 25%, 65% 25%, 65% 0, 100% 50%, 65% 100%, 65% 75%, 0 75%);
648
+ }
649
+
650
+ .block-label {
651
+ display: block;
652
+ font-size: 0.6875rem;
653
+ text-transform: uppercase;
654
+ letter-spacing: 0.03em;
655
+ color: var(--color-text-muted);
656
+ margin-bottom: 0.25rem;
657
+ }
658
+
659
+ .block-flow {
660
+ display: flex;
661
+ flex-wrap: wrap;
662
+ justify-content: center;
663
+ gap: 0.75rem 1.5rem;
664
+ align-items: stretch;
665
+ }
666
+
667
+ .block-flow .block {
668
+ position: relative;
669
+ min-width: 8rem;
670
+ }
671
+
672
+ .block-flow:not(.vertical) .block:not(:last-child)::after {
673
+ content: "→";
674
+ position: absolute;
675
+ right: -1.05rem;
676
+ top: 50%;
677
+ transform: translateY(-50%);
678
+ color: var(--color-text-muted);
679
+ }
680
+
681
+ .block-flow.vertical {
682
+ flex-direction: column;
683
+ align-items: stretch;
684
+ max-width: 30rem;
685
+ margin-inline: auto;
686
+ }
687
+
688
+ .block-flow.vertical .block:not(:last-child)::after {
689
+ content: "↓";
690
+ position: static;
691
+ display: block;
692
+ margin-top: 0.5rem;
693
+ color: var(--color-text-muted);
694
+ }
695
+
696
+ .block-grid {
697
+ display: grid;
698
+ grid-template-columns: repeat(2, minmax(0, 1fr));
699
+ gap: 0.75rem;
700
+ }
701
+
702
+ .block-grid.cols-3 {
703
+ grid-template-columns: repeat(3, minmax(0, 1fr));
704
+ }
705
+
706
+ .block-grid.cols-4 {
707
+ grid-template-columns: repeat(4, minmax(0, 1fr));
708
+ }
709
+
710
+ .block-stack {
711
+ display: flex;
712
+ flex-direction: column;
713
+ gap: 0.5rem;
714
+ }
715
+
415
716
  /* Breadcrumbs */
416
717
  .breadcrumbs {
417
718
  font-size: 0.875rem;
@@ -816,6 +1117,11 @@ body {
816
1117
  padding-right: 4rem;
817
1118
  max-width: 900px;
818
1119
  }
1120
+
1121
+ .mode-slides .content {
1122
+ max-width: none;
1123
+ padding-right: 2rem;
1124
+ }
819
1125
  }
820
1126
 
821
1127
  @media (max-width: 1024px) {
@@ -838,6 +1144,11 @@ body {
838
1144
  margin-left: 240px;
839
1145
  padding: 2rem;
840
1146
  }
1147
+
1148
+ .mode-slides .content {
1149
+ margin-left: 240px;
1150
+ padding: 1.25rem;
1151
+ }
841
1152
  }
842
1153
 
843
1154
  @media (max-width: 768px) {
@@ -877,6 +1188,26 @@ body {
877
1188
  padding-top: 4rem;
878
1189
  padding-bottom: calc(var(--footer-height) + 1rem);
879
1190
  }
1191
+
1192
+ .mode-slides .content {
1193
+ margin-left: 0;
1194
+ padding: 1rem;
1195
+ padding-top: 4rem;
1196
+ }
1197
+
1198
+ .slide-frame {
1199
+ width: 100%;
1200
+ padding: 1.25rem;
1201
+ max-height: calc(100vh - var(--footer-height) - 9rem);
1202
+ }
1203
+
1204
+ .slide.two-column {
1205
+ column-count: 1;
1206
+ }
1207
+
1208
+ .slide-progress {
1209
+ width: 7rem;
1210
+ }
880
1211
  }
881
1212
 
882
1213
  /* Print styles */
@@ -11,6 +11,7 @@
11
11
  <!-- Syntax highlighting - Prism.js -->
12
12
  <link rel="stylesheet" href="{{PRISM_LIGHT_URL}}" id="prism-light">
13
13
  <link rel="stylesheet" href="{{PRISM_DARK_URL}}" id="prism-dark" disabled>
14
+ {{PLUGIN_HEAD}}
14
15
  <script>
15
16
  // Apply saved theme immediately to prevent flash
16
17
  (function() {
@@ -28,15 +29,15 @@
28
29
  })();
29
30
  </script>
30
31
  </head>
31
- <body>
32
+ <body class="{{BODY_CLASS}}">
32
33
  <div class="mobile-header">
33
34
  <button class="nav-toggle" onclick="toggleNav()" aria-label="Toggle navigation">
34
35
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
35
36
  <path d="M3 12h18M3 6h18M3 18h18"/>
36
37
  </svg>
37
38
  </button>
38
- <a href="{{PATH_PREFIX}}" class="mobile-logo" title="Home">
39
- <img src="{{PATH_PREFIX}}{{BRAND_LOGO}}" alt="{{BRAND_NAME}}" class="logo-img {{BRAND_LOGO_CLASS}}"/>
39
+ <a href="{{PATH_PREFIX}}" class="mobile-logo" title="Home" data-initial="{{BRAND_INITIAL}}">
40
+ <img src="{{PATH_PREFIX}}{{BRAND_LOGO}}" alt="{{BRAND_NAME}}" class="logo-img {{BRAND_LOGO_CLASS}}" onerror="this.onerror=null;this.style.display='none';this.parentElement.classList.add('logo-fallback')"/>
40
41
  </a>
41
42
  <button class="mobile-theme-toggle" onclick="toggleTheme()" title="Toggle theme" aria-label="Toggle theme">
42
43
  <svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@@ -52,8 +53,8 @@
52
53
  <nav class="sidebar">
53
54
  <div class="sidebar-header">
54
55
  <div class="logo {{BRAND_LOGO_CLASS}}">
55
- <a href="{{BRAND_URL}}" class="logo-icon"{{BRAND_TARGET}}>
56
- <img src="{{PATH_PREFIX}}{{BRAND_LOGO}}" alt="{{BRAND_NAME}}" class="logo-img"/>
56
+ <a href="{{BRAND_URL}}" class="logo-icon" data-initial="{{BRAND_INITIAL}}"{{BRAND_TARGET}}>
57
+ <img src="{{PATH_PREFIX}}{{BRAND_LOGO}}" alt="{{BRAND_NAME}}" class="logo-img" onerror="this.onerror=null;this.style.display='none';this.parentElement.classList.add('logo-fallback')"/>
57
58
  </a>
58
59
  <span class="logo-text">
59
60
  <a href="{{BRAND_URL}}" class="brand"{{BRAND_TARGET}}>{{BRAND_NAME}}</a>
@@ -123,6 +124,7 @@
123
124
  await mermaid.run({ nodes: diagrams });
124
125
  };
125
126
  </script>
127
+ {{PLUGIN_BODY_END}}
126
128
  <script>
127
129
  function toggleTheme() {
128
130
  const html = document.documentElement;
@@ -159,6 +161,65 @@
159
161
  }
160
162
  }
161
163
 
164
+ // Slides mode hash routing
165
+ (function initSlidesMode() {
166
+ const shell = document.querySelector('.slides-shell');
167
+ if (!shell) return;
168
+
169
+ const slides = Array.from(document.querySelectorAll('.slide'));
170
+ if (!slides.length) return;
171
+
172
+ const prevBtn = document.querySelector('.slide-prev');
173
+ const nextBtn = document.querySelector('.slide-next');
174
+ const counter = document.querySelector('.slide-counter');
175
+ const progressBar = document.querySelector('.slide-progress-bar');
176
+ const navLinks = Array.from(document.querySelectorAll('.sidebar-nav a[href^="#slide-"]'));
177
+ let current = 0;
178
+
179
+ function setActive(n) {
180
+ current = Math.max(0, Math.min(n, slides.length - 1));
181
+ slides.forEach((slide, idx) => slide.classList.toggle('active', idx === current));
182
+ navLinks.forEach((link) => {
183
+ const active = link.getAttribute('href') === '#' + slides[current].id;
184
+ link.classList.toggle('active', active);
185
+ });
186
+ if (counter) counter.textContent = (current + 1) + ' / ' + slides.length;
187
+ if (progressBar) progressBar.style.width = (((current + 1) / slides.length) * 100) + '%';
188
+ if (prevBtn) prevBtn.disabled = current === 0;
189
+ if (nextBtn) nextBtn.disabled = current === slides.length - 1;
190
+ history.replaceState(null, '', '#' + slides[current].id);
191
+ }
192
+
193
+ function setFromHash() {
194
+ const hash = window.location.hash || '';
195
+ const idx = slides.findIndex((s) => '#' + s.id === hash);
196
+ if (idx >= 0) setActive(idx);
197
+ else setActive(0);
198
+ }
199
+
200
+ prevBtn?.addEventListener('click', () => setActive(current - 1));
201
+ nextBtn?.addEventListener('click', () => setActive(current + 1));
202
+
203
+ document.addEventListener('keydown', (e) => {
204
+ if (e.key === 'ArrowRight' || e.key === ' ') {
205
+ e.preventDefault();
206
+ setActive(current + 1);
207
+ } else if (e.key === 'ArrowLeft') {
208
+ e.preventDefault();
209
+ setActive(current - 1);
210
+ } else if (e.key === 'Home') {
211
+ e.preventDefault();
212
+ setActive(0);
213
+ } else if (e.key === 'End') {
214
+ e.preventDefault();
215
+ setActive(slides.length - 1);
216
+ }
217
+ });
218
+
219
+ window.addEventListener('hashchange', setFromHash);
220
+ setFromHash();
221
+ })();
222
+
162
223
  // Copy code button
163
224
  document.querySelectorAll('.prose pre code').forEach(block => {
164
225
  const button = document.createElement('button');
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Deck Template
3
+ *
4
+ * Slides-first template for briefings and presentations.
5
+ * Uses mode: slides with a starter multi-slide markdown file.
6
+ */
7
+
8
+ import type { TemplateContext, TemplateDef } from "./schema.ts";
9
+
10
+ export const deck: TemplateDef = {
11
+ id: "deck",
12
+ name: "Presentation Deck",
13
+ description: "Fixed-aspect slides for briefings and presentations",
14
+ version: 1,
15
+ extends: "minimal",
16
+ sections: [
17
+ {
18
+ name: "Slides",
19
+ path: "content/slides",
20
+ description: "Slide content (one file per slide or --- slide --- delimiters)",
21
+ },
22
+ ],
23
+ files: [
24
+ {
25
+ path: "site.yaml",
26
+ content: (ctx: TemplateContext) => `# ${ctx.branding.siteName} - Slides Configuration
27
+ # Documentation: https://github.com/3leaps/kitfly
28
+
29
+ title: "${ctx.branding.siteName}"
30
+ mode: slides
31
+ aspect: "16/9"
32
+ # Sections are resolved from repo root by default (docroot: ".")
33
+
34
+ brand:
35
+ name: "${ctx.branding.brandName}"
36
+ url: "${ctx.branding.brandUrl}"
37
+ # external: false # Set true if brand URL is external
38
+
39
+ sections:
40
+ - name: "Slides"
41
+ path: "content/slides"
42
+ `,
43
+ },
44
+ {
45
+ path: "index.md",
46
+ content: (ctx: TemplateContext) => `---
47
+ title: ${ctx.branding.siteName}
48
+ description: ${ctx.branding.siteName} slide deck
49
+ ---
50
+
51
+ # ${ctx.branding.siteName}
52
+
53
+ This site is configured for slides mode.
54
+
55
+ Run \`kitfly dev\` and use the slide controls to navigate.
56
+ `,
57
+ },
58
+ {
59
+ path: "content/slides/briefing.md",
60
+ content: (ctx: TemplateContext) => `---
61
+ title: Title
62
+ class: title-slide
63
+ ---
64
+
65
+ # ${ctx.branding.siteName}
66
+
67
+ **${ctx.branding.brandName}**
68
+
69
+ ${new Date().toISOString().split("T")[0]}
70
+
71
+ --- slide ---
72
+ ---
73
+ title: Agenda
74
+ ---
75
+
76
+ ## Agenda
77
+
78
+ 1. Context
79
+ 2. Current State
80
+ 3. Options
81
+ 4. Recommendation
82
+
83
+ --- slide ---
84
+ ---
85
+ title: Options
86
+ class: two-column
87
+ ---
88
+
89
+ ## Build vs Buy
90
+
91
+ **Build In-House**
92
+
93
+ - Full control
94
+ - More setup effort
95
+ - Longer implementation timeline
96
+
97
+ **Buy SaaS**
98
+
99
+ - Faster launch
100
+ - Ongoing subscription cost
101
+ - Vendor dependency
102
+
103
+ --- slide ---
104
+ ---
105
+ title: Architecture
106
+ class: diagram
107
+ ---
108
+
109
+ ## Architecture Snapshot
110
+
111
+ \`\`\`mermaid
112
+ flowchart LR
113
+ A["Users"] --> B["Web App"]
114
+ B --> C["API"]
115
+ C --> D["Data Store"]
116
+ \`\`\`
117
+
118
+ --- slide ---
119
+ ---
120
+ title: Section Break
121
+ class: section-header
122
+ ---
123
+
124
+ # Recommendation
125
+
126
+ Preferred path and next actions
127
+
128
+ --- slide ---
129
+ ---
130
+ title: Summary
131
+ ---
132
+
133
+ ## Summary
134
+
135
+ - Current state and trade-offs reviewed
136
+ - Recommended path identified
137
+ - Next milestone scheduled this quarter
138
+ `,
139
+ },
140
+ {
141
+ path: "CUSTOMIZING.md",
142
+ content: (ctx: TemplateContext) => `---
143
+ template: deck
144
+ template_version: 1
145
+ created: ${new Date().toISOString().split("T")[0]}
146
+ ---
147
+
148
+ # Customizing ${ctx.branding.siteName}
149
+
150
+ This template is optimized for \`mode: slides\`.
151
+
152
+ ## Slide Authoring Patterns
153
+
154
+ You can author slides in either style:
155
+
156
+ 1. One file per slide in \`content/slides/\`
157
+ 2. One file with explicit delimiters:
158
+
159
+ \`\`\`markdown
160
+ --- slide ---
161
+ \`\`\`
162
+
163
+ ## Slide Frontmatter
164
+
165
+ \`\`\`yaml
166
+ ---
167
+ title: My Slide
168
+ class: title-slide
169
+ ---
170
+ \`\`\`
171
+
172
+ Built-in classes:
173
+ - \`title-slide\`
174
+ - \`section-header\`
175
+ - \`centered\`
176
+ - \`two-column\`
177
+ - \`diagram\`
178
+
179
+ ## Two-Column Notes
180
+
181
+ For markdown-only content, \`two-column\` will flow content into columns.
182
+ For strict side-by-side control, use explicit HTML wrappers inside the slide body.
183
+ `,
184
+ },
185
+ ],
186
+ };
@@ -12,6 +12,7 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
12
12
  import { dirname, join } from "node:path";
13
13
  import { fileURLToPath } from "node:url";
14
14
  import { crucible } from "./crucible.ts";
15
+ import { deck } from "./deck.ts";
15
16
  import { handbook } from "./handbook.ts";
16
17
  import { minimal } from "./minimal.ts";
17
18
  import { pipeline } from "./pipeline.ts";
@@ -53,6 +54,7 @@ export function listTemplates(): TemplateDef[] {
53
54
 
54
55
  // Register built-in templates
55
56
  registerTemplate(minimal);
57
+ registerTemplate(deck);
56
58
  registerTemplate(handbook);
57
59
  registerTemplate(pipeline);
58
60
  registerTemplate(productbook);
@@ -148,19 +150,27 @@ const STANDALONE_FILES = [
148
150
  "src/shared.ts",
149
151
  "src/engine.ts",
150
152
  "src/theme.ts",
153
+ "src/plugin-loader.ts",
151
154
  // Schemas (editor validation + migrations)
152
155
  "schemas/README.md",
153
156
  "schemas/site.schema.json",
154
157
  "schemas/theme.schema.json",
158
+ "schemas/plugin.schema.json",
159
+ "schemas/plugin-registry.schema.json",
160
+ "schemas/plugins.schema.json",
155
161
  "schemas/v0/site.schema.json",
156
162
  "schemas/v0/theme.schema.json",
163
+ "schemas/v0/common.schema.json",
164
+ "schemas/v0/plugin.schema.json",
165
+ "schemas/v0/plugin-registry.schema.json",
166
+ "schemas/v0/plugins.schema.json",
157
167
  // Site templates and assets
158
168
  "src/site/template.html",
159
169
  "src/site/styles.css",
160
170
  ];
161
171
 
162
172
  // Directories to copy entirely
163
- const STANDALONE_DIRS = ["assets"];
173
+ const STANDALONE_DIRS = ["assets", "registry", "plugins-dist"];
164
174
 
165
175
  function toArrayBuffer(data: Uint8Array): ArrayBuffer {
166
176
  // Normalize to a standalone ArrayBuffer to satisfy SubtleCrypto typing.
@@ -70,6 +70,7 @@ This is your documentation site, powered by [Kitfly](https://github.com/3leaps/k
70
70
  path: ".gitignore",
71
71
  content: () => `# Build output
72
72
  dist/
73
+ bundles/
73
74
 
74
75
  # Dependencies (if using kitfly as dependency)
75
76
  node_modules/