@honeydeck/honeydeck 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.
Files changed (144) hide show
  1. package/AGENTS.md +25 -0
  2. package/DEVELOPMENT.md +522 -0
  3. package/LICENSE +21 -0
  4. package/Readme.md +49 -0
  5. package/SPEC.md +88 -0
  6. package/docs/components.md +63 -0
  7. package/docs/configuration.md +91 -0
  8. package/docs/getting-started.md +116 -0
  9. package/docs/kit-authoring.md +207 -0
  10. package/docs/kits.md +387 -0
  11. package/docs/local-development.md +95 -0
  12. package/docs/mermaid.md +198 -0
  13. package/docs/mobile.md +108 -0
  14. package/docs/navigation.md +93 -0
  15. package/docs/next-steps.md +377 -0
  16. package/docs/pdf-export.md +91 -0
  17. package/docs/presenter-mode.md +104 -0
  18. package/docs/slides.md +130 -0
  19. package/docs/slidev-migration.md +42 -0
  20. package/docs/steps-and-reveals.md +171 -0
  21. package/package.json +134 -0
  22. package/skills/SPEC.md +21 -0
  23. package/skills/honeydeck/SKILL.md +65 -0
  24. package/skills/presentation-writing/SKILL.md +75 -0
  25. package/skills/slidev-migration/SKILL.md +153 -0
  26. package/src/SPEC.md +89 -0
  27. package/src/assets.d.ts +30 -0
  28. package/src/cli/SPEC.md +230 -0
  29. package/src/cli/args.ts +3 -0
  30. package/src/cli/banner.ts +9 -0
  31. package/src/cli/bin.js +5 -0
  32. package/src/cli/build.ts +229 -0
  33. package/src/cli/deck-path.ts +32 -0
  34. package/src/cli/dev.ts +263 -0
  35. package/src/cli/index.ts +126 -0
  36. package/src/cli/init.ts +369 -0
  37. package/src/cli/pdf.ts +923 -0
  38. package/src/cli/skill.ts +75 -0
  39. package/src/cli/templates/SPEC.md +70 -0
  40. package/src/cli/templates/deck-mdx.ts +15 -0
  41. package/src/cli/templates/package-json.ts +36 -0
  42. package/src/cli/templates/sparkle-button.ts +15 -0
  43. package/src/cli/templates/starter/components/SparkleButton.tsx +84 -0
  44. package/src/cli/templates/starter/deck.mdx +153 -0
  45. package/src/cli/templates/starter/styles.css +14 -0
  46. package/src/cli/templates/styles-css.ts +14 -0
  47. package/src/defaults.ts +1 -0
  48. package/src/layouts/ColorModeImage.tsx +55 -0
  49. package/src/layouts/SPEC.md +393 -0
  50. package/src/layouts/SlideFrame.tsx +48 -0
  51. package/src/layouts/bee/Blank.tsx +12 -0
  52. package/src/layouts/bee/Cover.tsx +70 -0
  53. package/src/layouts/bee/Default.tsx +42 -0
  54. package/src/layouts/bee/Image/Image.tsx +151 -0
  55. package/src/layouts/bee/Image/placeholder-dark.webp +0 -0
  56. package/src/layouts/bee/Image/placeholder-vertical-dark.webp +0 -0
  57. package/src/layouts/bee/Image/placeholder-vertical.webp +0 -0
  58. package/src/layouts/bee/Image/placeholder.webp +0 -0
  59. package/src/layouts/bee/ImageLeft.tsx +27 -0
  60. package/src/layouts/bee/ImageRight.tsx +27 -0
  61. package/src/layouts/bee/ImageSide.tsx +107 -0
  62. package/src/layouts/bee/Section.tsx +40 -0
  63. package/src/layouts/bee/TwoCol.tsx +108 -0
  64. package/src/layouts/bee/index.ts +40 -0
  65. package/src/layouts/clean/Blank.tsx +12 -0
  66. package/src/layouts/clean/Cover.tsx +58 -0
  67. package/src/layouts/clean/Default.tsx +33 -0
  68. package/src/layouts/clean/Image/Image.tsx +103 -0
  69. package/src/layouts/clean/ImageLeft.tsx +27 -0
  70. package/src/layouts/clean/ImageRight.tsx +27 -0
  71. package/src/layouts/clean/ImageSide.tsx +113 -0
  72. package/src/layouts/clean/Section.tsx +35 -0
  73. package/src/layouts/clean/TwoCol.tsx +63 -0
  74. package/src/layouts/clean/index.ts +40 -0
  75. package/src/layouts/index.ts +60 -0
  76. package/src/layouts/placeholders.ts +9 -0
  77. package/src/layouts/utils.ts +13 -0
  78. package/src/remark/SPEC.md +49 -0
  79. package/src/remark/h1-extract.ts +124 -0
  80. package/src/remark/index.ts +4 -0
  81. package/src/remark/shiki-code-blocks.ts +325 -0
  82. package/src/remark/step-numbering.ts +412 -0
  83. package/src/runtime/Deck.tsx +533 -0
  84. package/src/runtime/SPEC.md +256 -0
  85. package/src/runtime/SlideCanvas.tsx +95 -0
  86. package/src/runtime/TimelineContext.tsx +122 -0
  87. package/src/runtime/app-shell/index.html +31 -0
  88. package/src/runtime/app-shell/main.tsx +42 -0
  89. package/src/runtime/aspectRatio.ts +34 -0
  90. package/src/runtime/colorMode.ts +23 -0
  91. package/src/runtime/components/BrowserFrame.tsx +233 -0
  92. package/src/runtime/components/Button.tsx +57 -0
  93. package/src/runtime/components/CodeBlock.tsx +210 -0
  94. package/src/runtime/components/ColorModeCycleButton.tsx +59 -0
  95. package/src/runtime/components/ErrorBoundary.tsx +125 -0
  96. package/src/runtime/components/Keyboard.tsx +87 -0
  97. package/src/runtime/components/ListStyle.tsx +203 -0
  98. package/src/runtime/components/NavBar.tsx +223 -0
  99. package/src/runtime/components/NavBarButton.tsx +47 -0
  100. package/src/runtime/components/NavBarDivider.tsx +3 -0
  101. package/src/runtime/components/Notes.tsx +171 -0
  102. package/src/runtime/components/Reveal.tsx +82 -0
  103. package/src/runtime/components/RevealGroup.tsx +193 -0
  104. package/src/runtime/components/SPEC.md +263 -0
  105. package/src/runtime/components/SlideNumberBadge.tsx +11 -0
  106. package/src/runtime/components/TimelineSteps.tsx +115 -0
  107. package/src/runtime/components/index.ts +55 -0
  108. package/src/runtime/index.ts +42 -0
  109. package/src/runtime/inputOwnership.ts +68 -0
  110. package/src/runtime/keyboardTarget.ts +7 -0
  111. package/src/runtime/lastSlideRoute.ts +56 -0
  112. package/src/runtime/navigation.ts +211 -0
  113. package/src/runtime/router.ts +157 -0
  114. package/src/runtime/slideData.ts +137 -0
  115. package/src/runtime/sync.ts +267 -0
  116. package/src/runtime/types.ts +182 -0
  117. package/src/runtime/useKeyboardNav.ts +138 -0
  118. package/src/runtime/useSwipeNav.ts +257 -0
  119. package/src/runtime/views/DocsView.tsx +74 -0
  120. package/src/runtime/views/OverviewView.tsx +386 -0
  121. package/src/runtime/views/PresenterNotesPanel.tsx +76 -0
  122. package/src/runtime/views/PresenterView.tsx +340 -0
  123. package/src/runtime/views/SPEC.md +152 -0
  124. package/src/runtime/views/docs/ComponentsTab.tsx +178 -0
  125. package/src/runtime/views/docs/DocsHeader.tsx +101 -0
  126. package/src/runtime/views/docs/Intro.tsx +20 -0
  127. package/src/runtime/views/docs/LayoutsTab.tsx +324 -0
  128. package/src/runtime/views/docs/ThemeTab.tsx +110 -0
  129. package/src/runtime/views/index.ts +7 -0
  130. package/src/runtime/views/overviewGrid.ts +106 -0
  131. package/src/runtime/views/presenterPreview.ts +27 -0
  132. package/src/runtime/virtual-modules.d.ts +98 -0
  133. package/src/theme/SPEC.md +179 -0
  134. package/src/theme/base.css +623 -0
  135. package/src/theme/bee.css +35 -0
  136. package/src/theme/clean.css +38 -0
  137. package/src/vite-plugin/SPEC.md +114 -0
  138. package/src/vite-plugin/component-doc-crawler.ts +350 -0
  139. package/src/vite-plugin/deck-loader.ts +148 -0
  140. package/src/vite-plugin/index.ts +373 -0
  141. package/src/vite-plugin/layout-demo-crawler.ts +802 -0
  142. package/src/vite-plugin/splitter.ts +353 -0
  143. package/src/vite-plugin/token-manifest.ts +163 -0
  144. package/src/vite-plugin/virtual-modules.ts +587 -0
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Image layout — prominent framed image with optional title and caption.
3
+ *
4
+ * The image is presented as a gallery-quality piece: a surface-coloured mat
5
+ * behind it, a deep shadow for lift, and a subtle ring border. A thin primary
6
+ * accent border at the caption ties the slide to the deck theme.
7
+ *
8
+ * - Use `image` frontmatter to supply the URL / path.
9
+ * - Use `darkImage` frontmatter to override the URL / path in dark mode.
10
+ * - The `alt` frontmatter field is forwarded to the <img> for accessibility.
11
+ * - Any MDX body text (after the h1) becomes the figure caption, separated
12
+ * by a primary left-border accent — italic, subordinate to the image.
13
+ *
14
+ * @example
15
+ * ```mdx
16
+ * ---
17
+ * layout: Image
18
+ * image: /diagrams/architecture.png
19
+ * darkImage: /diagrams/architecture-dark.png
20
+ * alt: High-level architecture diagram showing three service tiers
21
+ * ---
22
+ *
23
+ * # System Architecture
24
+ *
25
+ * Our distributed system in production.
26
+ * ```
27
+ */
28
+
29
+ import type { ReactNode } from "react";
30
+ import type { LayoutDemo, LayoutProps } from "../../../runtime/types.ts";
31
+ import {
32
+ ColorModeImage,
33
+ type DarkModeImageFrontmatter,
34
+ } from "../../ColorModeImage.tsx";
35
+ import { imagePlaceholder, imagePlaceholderDark } from "../../placeholders.ts";
36
+ import DefaultLayout from "../Default.tsx";
37
+
38
+ type ImageFrontmatter = DarkModeImageFrontmatter & {
39
+ /** URL or path to the image (supports /public/, relative, or external URLs) */
40
+ image?: string;
41
+ /** URL or path used when Honeydeck's effective color mode is dark */
42
+ darkImage?: string;
43
+ /** Alt text for the image */
44
+ alt?: string;
45
+ };
46
+
47
+ // ---------------------------------------------------------------------------
48
+ // ImageFrame — shared framed container for the image stage
49
+ // ---------------------------------------------------------------------------
50
+
51
+ function ImageFrame({ children }: { children: ReactNode }) {
52
+ return (
53
+ <div className="max-h-full rounded-honeydeck overflow-hidden bg-surface shadow-2xl ring-1 ring-border">
54
+ {children}
55
+ </div>
56
+ );
57
+ }
58
+
59
+ // ---------------------------------------------------------------------------
60
+ // Placeholder — shown when no `image` frontmatter key is set
61
+ // ---------------------------------------------------------------------------
62
+
63
+ function PlaceholderBox() {
64
+ return (
65
+ <div className="flex flex-col items-center gap-11 max-h-full min-h-0">
66
+ <ImageFrame>
67
+ <ColorModeImage
68
+ src={imagePlaceholder}
69
+ darkSrc={imagePlaceholderDark}
70
+ alt=""
71
+ className="max-h-full max-w-full object-contain"
72
+ aria-hidden="true"
73
+ />
74
+ </ImageFrame>
75
+ {/* Hint text below the frame */}
76
+ <p className="text-[length:var(--honeydeck-font-size-small)] text-surface-foreground text-center opacity-50 leading-snug">
77
+ Add{" "}
78
+ <code className="font-mono bg-background px-5 py-1 rounded-honeydeck">
79
+ image: /path/to/image.png
80
+ </code>{" "}
81
+ to frontmatter
82
+ </p>
83
+ </div>
84
+ );
85
+ }
86
+
87
+ // ---------------------------------------------------------------------------
88
+ // Layout
89
+ // ---------------------------------------------------------------------------
90
+
91
+ export default function ImageLayout({
92
+ title,
93
+ children,
94
+ frontmatter,
95
+ rawChildren,
96
+ }: LayoutProps<ImageFrontmatter>) {
97
+ const { image, darkImage, alt = "" } = frontmatter;
98
+ const hasImage = Boolean(image || darkImage);
99
+ const hasCaption = Boolean(children);
100
+
101
+ return (
102
+ <DefaultLayout
103
+ title={title}
104
+ frontmatter={frontmatter}
105
+ rawChildren={rawChildren}
106
+ >
107
+ {/*
108
+ Semantic <figure> groups the image and its optional caption.
109
+ h-full makes it consume all remaining vertical space so the
110
+ image stage is as large as possible.
111
+ */}
112
+ <figure className="h-full flex flex-col gap-11 m-0 p-0">
113
+ {/* ── Image stage ─────────────────────────────────────────────── */}
114
+ <div className="flex-1 min-h-0 flex flex-col items-center justify-center">
115
+ {hasImage ? (
116
+ <ImageFrame>
117
+ <ColorModeImage
118
+ src={image || imagePlaceholder}
119
+ darkSrc={darkImage}
120
+ alt={alt}
121
+ className="max-h-full max-w-full object-contain"
122
+ />
123
+ </ImageFrame>
124
+ ) : (
125
+ <PlaceholderBox />
126
+ )}
127
+ </div>
128
+
129
+ {/* ── Caption ─────────────────────────────────────────────────── */}
130
+ {hasCaption && (
131
+ <figcaption className="flex-shrink-0 border-l-4 border-accent pl-11 text-[length:var(--honeydeck-font-size-small)] text-surface-foreground italic leading-snug">
132
+ {children}
133
+ </figcaption>
134
+ )}
135
+ </figure>
136
+ </DefaultLayout>
137
+ );
138
+ }
139
+
140
+ export const demo: LayoutDemo<ImageFrontmatter> = {
141
+ mdx: `---
142
+ layout: Image
143
+ image: ""
144
+ darkImage: ""
145
+ alt: Architecture diagram
146
+ ---
147
+
148
+ # System Architecture
149
+
150
+ Our distributed system in production.`,
151
+ };
@@ -0,0 +1,27 @@
1
+ import type { LayoutDemo, LayoutProps } from "../../runtime/types.ts";
2
+ import type { DarkModeImageFrontmatter } from "../ColorModeImage.tsx";
3
+ import { DefaultImageSideLayout } from "./ImageSide.tsx";
4
+
5
+ type ImageLeftFrontmatter = DarkModeImageFrontmatter & {
6
+ /** Accessible text for the image. */
7
+ alt?: string;
8
+ };
9
+
10
+ export default function ImageLeftLayout(
11
+ props: LayoutProps<ImageLeftFrontmatter>,
12
+ ) {
13
+ return <DefaultImageSideLayout {...props} side="left" />;
14
+ }
15
+
16
+ export const demo: LayoutDemo<ImageLeftFrontmatter> = {
17
+ mdx: `---
18
+ layout: ImageLeft
19
+ image: ""
20
+ darkImage: ""
21
+ alt: Product detail
22
+ ---
23
+
24
+ # Product Detail
25
+
26
+ Use the body area for supporting context, bullets, or a short narrative beside the image.`,
27
+ };
@@ -0,0 +1,27 @@
1
+ import type { LayoutDemo, LayoutProps } from "../../runtime/types.ts";
2
+ import type { DarkModeImageFrontmatter } from "../ColorModeImage.tsx";
3
+ import { DefaultImageSideLayout } from "./ImageSide.tsx";
4
+
5
+ type ImageRightFrontmatter = DarkModeImageFrontmatter & {
6
+ /** Accessible text for the image. */
7
+ alt?: string;
8
+ };
9
+
10
+ export default function ImageRightLayout(
11
+ props: LayoutProps<ImageRightFrontmatter>,
12
+ ) {
13
+ return <DefaultImageSideLayout {...props} side="right" />;
14
+ }
15
+
16
+ export const demo: LayoutDemo<ImageRightFrontmatter> = {
17
+ mdx: `---
18
+ layout: ImageRight
19
+ image: ""
20
+ darkImage: ""
21
+ alt: Launch moment
22
+ ---
23
+
24
+ # Launch Moment
25
+
26
+ Pair a prominent image with the same heading treatment used by the default content slides.`,
27
+ };
@@ -0,0 +1,107 @@
1
+ import type { ReactNode } from "react";
2
+ import type { LayoutProps } from "../../runtime/types.ts";
3
+ import {
4
+ ColorModeImage,
5
+ type DarkModeImageFrontmatter,
6
+ } from "../ColorModeImage.tsx";
7
+ import {
8
+ verticalImagePlaceholder,
9
+ verticalImagePlaceholderDark,
10
+ } from "../placeholders.ts";
11
+ import { SlideFrame } from "../SlideFrame.tsx";
12
+ import { hasTitle } from "../utils.ts";
13
+
14
+ type ImageSideFrontmatter = DarkModeImageFrontmatter & {
15
+ alt?: string;
16
+ };
17
+
18
+ type ImageSide = "left" | "right";
19
+
20
+ type ImageSideLayoutProps = LayoutProps<ImageSideFrontmatter> & {
21
+ side: ImageSide;
22
+ };
23
+
24
+ function DefaultSideImageFrame({
25
+ image,
26
+ darkImage,
27
+ alt,
28
+ }: {
29
+ image?: string;
30
+ darkImage?: string;
31
+ alt: string;
32
+ }) {
33
+ const hasImage = Boolean(image || darkImage);
34
+
35
+ return (
36
+ <div className="h-full min-h-0 rounded-honeydeck bg-surface p-3 shadow-2xl ring-1 ring-border">
37
+ <ColorModeImage
38
+ src={image || verticalImagePlaceholder}
39
+ darkSrc={
40
+ darkImage || (hasImage ? undefined : verticalImagePlaceholderDark)
41
+ }
42
+ alt={hasImage ? alt : ""}
43
+ className="size-full rounded-honeydeck object-cover"
44
+ aria-hidden={hasImage ? undefined : "true"}
45
+ />
46
+ </div>
47
+ );
48
+ }
49
+
50
+ function DefaultSideContent({
51
+ title,
52
+ children,
53
+ }: {
54
+ title: ReactNode | null;
55
+ children: ReactNode;
56
+ }) {
57
+ return (
58
+ <div className="flex min-h-0 flex-col overflow-hidden">
59
+ {hasTitle(title) && (
60
+ <header className="mb-8 flex-shrink-0">
61
+ <h1 className="font-heading font-bold text-[length:var(--honeydeck-font-size-h2)] leading-tight text-primary">
62
+ {title}
63
+ </h1>
64
+ <div
65
+ className="mt-4 h-2 w-28 rounded-full bg-accent"
66
+ aria-hidden="true"
67
+ />
68
+ </header>
69
+ )}
70
+
71
+ <div className="min-h-0 flex-1 overflow-hidden">{children}</div>
72
+ </div>
73
+ );
74
+ }
75
+
76
+ export function DefaultImageSideLayout({
77
+ title,
78
+ children,
79
+ frontmatter,
80
+ side,
81
+ }: ImageSideLayoutProps) {
82
+ const { image, darkImage, alt = "" } = frontmatter;
83
+ const imagePane = (
84
+ <DefaultSideImageFrame image={image} darkImage={darkImage} alt={alt} />
85
+ );
86
+ const contentPane = (
87
+ <DefaultSideContent title={title}>{children}</DefaultSideContent>
88
+ );
89
+
90
+ return (
91
+ <SlideFrame>
92
+ <div className="grid h-full min-h-0 grid-cols-2 gap-12">
93
+ {side === "left" ? (
94
+ <>
95
+ {imagePane}
96
+ {contentPane}
97
+ </>
98
+ ) : (
99
+ <>
100
+ {contentPane}
101
+ {imagePane}
102
+ </>
103
+ )}
104
+ </div>
105
+ </SlideFrame>
106
+ );
107
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Section layout — big centered heading with primary background.
3
+ *
4
+ * Used as a visual divider between chapters/sections. The title is the
5
+ * only required content; body children appear as a subtitle below.
6
+ */
7
+
8
+ import type { LayoutDemo, LayoutProps } from "../../runtime/types.ts";
9
+ import { SlideFrame } from "../SlideFrame.tsx";
10
+ import { hasTitle } from "../utils.ts";
11
+
12
+ export default function SectionLayout({ title, children }: LayoutProps) {
13
+ return (
14
+ <SlideFrame className="items-center justify-center bg-primary dark:bg-primary/75 text-primary-foreground text-center">
15
+ {/* Big centered section title */}
16
+ {hasTitle(title) && (
17
+ <h1 className="font-heading font-black text-[length:var(--honeydeck-font-size-display)] leading-none mb-6 tracking-tight">
18
+ {title}
19
+ </h1>
20
+ )}
21
+
22
+ {/* Optional subtitle / body */}
23
+ {children && (
24
+ <div className="text-[length:var(--honeydeck-font-size-body)] text-primary-foreground/70 max-w-3xl font-light">
25
+ {children}
26
+ </div>
27
+ )}
28
+ </SlideFrame>
29
+ );
30
+ }
31
+
32
+ export const demo: LayoutDemo = {
33
+ mdx: `---
34
+ layout: Section
35
+ ---
36
+
37
+ # Section Title
38
+
39
+ An optional section subtitle or brief description.`,
40
+ };
@@ -0,0 +1,108 @@
1
+ /**
2
+ * TwoCol layout — two equal columns side by side.
3
+ *
4
+ * Exports `Left` and `Right` slot components that users place in their
5
+ * MDX to control which content appears in which column.
6
+ *
7
+ * @example
8
+ * ```mdx
9
+ * ---
10
+ * layout: TwoCol
11
+ * ---
12
+ *
13
+ * import { Left, Right } from '@honeydeck/honeydeck/layouts/bee/TwoCol'
14
+ *
15
+ * # My Two-Column Slide
16
+ *
17
+ * <Left>
18
+ * ## Pros
19
+ * - Fast
20
+ * - Simple
21
+ * </Left>
22
+ *
23
+ * <Right>
24
+ * ## Cons
25
+ * - Limited
26
+ * </Right>
27
+ * ```
28
+ */
29
+
30
+ import type { ReactNode } from "react";
31
+ import type { LayoutDemo, LayoutProps } from "../../runtime/types.ts";
32
+ import DefaultLayout from "./Default.tsx";
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Slot components — thin wrappers that emit data-honeydeck-slot attributes.
36
+ // Tailwind utility classes position them into the correct grid column.
37
+ // ---------------------------------------------------------------------------
38
+
39
+ /** Slot for the left column */
40
+ export function Left({ children }: { children?: ReactNode }) {
41
+ return (
42
+ <div data-honeydeck-slot="left" className="col-start-1 overflow-hidden">
43
+ {children}
44
+ </div>
45
+ );
46
+ }
47
+
48
+ /** Slot for the right column */
49
+ export function Right({ children }: { children?: ReactNode }) {
50
+ return (
51
+ <div data-honeydeck-slot="right" className="col-start-2 overflow-hidden">
52
+ {children}
53
+ </div>
54
+ );
55
+ }
56
+
57
+ // ---------------------------------------------------------------------------
58
+ // Layout component
59
+ // ---------------------------------------------------------------------------
60
+
61
+ /**
62
+ * TwoCol layout — renders children in a two-column CSS grid.
63
+ *
64
+ * The `<Left>` and `<Right>` slot components render divs with
65
+ * `data-honeydeck-slot="left|right"` attributes and Tailwind column utilities.
66
+ * This works because MDX components return fragments — the slot divs become
67
+ * direct DOM children of the grid container without any intermediate wrapper.
68
+ */
69
+ export default function TwoColLayout({
70
+ title,
71
+ children,
72
+ frontmatter,
73
+ rawChildren,
74
+ }: LayoutProps) {
75
+ return (
76
+ <DefaultLayout
77
+ title={title}
78
+ frontmatter={frontmatter}
79
+ rawChildren={rawChildren}
80
+ >
81
+ {/* Two columns — slot positioning handled by Tailwind utilities */}
82
+ <div className="grid h-full grid-cols-2 gap-12">{children}</div>
83
+ </DefaultLayout>
84
+ );
85
+ }
86
+
87
+ export const demo: LayoutDemo = {
88
+ mdx: `---
89
+ layout: TwoCol
90
+ ---
91
+
92
+ import { Left, Right } from '@honeydeck/honeydeck/layouts/bee/TwoCol'
93
+
94
+ # Pros vs Cons
95
+
96
+ <Left>
97
+ ## Pros
98
+
99
+ - Fast
100
+ - Simple
101
+ </Left>
102
+
103
+ <Right>
104
+ ## Cons
105
+
106
+ - Limited
107
+ </Right>`,
108
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Bee Honeydeck layout map.
3
+ *
4
+ * This keeps the original playful Honeydeck layouts available after the default
5
+ * `@honeydeck/honeydeck/layouts` export moved to the clean layout set.
6
+ */
7
+
8
+ import type { LayoutMap } from "../../runtime/types.ts";
9
+ import BlankLayout from "./Blank.tsx";
10
+ import CoverLayout from "./Cover.tsx";
11
+ import DefaultLayout from "./Default.tsx";
12
+ import ImageLayout from "./Image/Image.tsx";
13
+ import ImageLeftLayout from "./ImageLeft.tsx";
14
+ import ImageRightLayout from "./ImageRight.tsx";
15
+ import SectionLayout from "./Section.tsx";
16
+ import TwoColLayout from "./TwoCol.tsx";
17
+
18
+ const beeLayouts: LayoutMap = {
19
+ Default: DefaultLayout,
20
+ Blank: BlankLayout,
21
+ Cover: CoverLayout,
22
+ Section: SectionLayout,
23
+ TwoCol: TwoColLayout,
24
+ Image: ImageLayout,
25
+ ImageLeft: ImageLeftLayout,
26
+ ImageRight: ImageRightLayout,
27
+ };
28
+
29
+ export default beeLayouts;
30
+
31
+ export {
32
+ BlankLayout,
33
+ CoverLayout,
34
+ DefaultLayout,
35
+ ImageLayout,
36
+ ImageLeftLayout,
37
+ ImageRightLayout,
38
+ SectionLayout,
39
+ TwoColLayout,
40
+ };
@@ -0,0 +1,12 @@
1
+ import type { LayoutDemo, LayoutProps } from "../../runtime/types.ts";
2
+ import { SlideFrame } from "../SlideFrame.tsx";
3
+
4
+ export default function CleanBlankLayout(props: LayoutProps) {
5
+ return <SlideFrame>{props.children}</SlideFrame>;
6
+ }
7
+
8
+ export const demo: LayoutDemo = {
9
+ mdx: `---
10
+ layout: Blank
11
+ ---`,
12
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Clean Cover layout — centered title, body copy, and simple metadata.
3
+ */
4
+
5
+ import type { LayoutDemo, LayoutProps } from "../../runtime/types.ts";
6
+ import { SlideFrame } from "../SlideFrame.tsx";
7
+ import { hasTitle } from "../utils.ts";
8
+
9
+ type CoverFrontmatter = {
10
+ /** Speaker or organization shown below the cover body. */
11
+ author?: string;
12
+ /** Date or event label shown below the cover body. */
13
+ date?: string;
14
+ };
15
+
16
+ export default function CleanCoverLayout({
17
+ title,
18
+ children,
19
+ frontmatter,
20
+ }: LayoutProps<CoverFrontmatter>) {
21
+ const { author, date } = frontmatter;
22
+
23
+ return (
24
+ <SlideFrame className="items-center justify-center text-center">
25
+ {hasTitle(title) && (
26
+ <h1 className="mb-10 font-heading text-[length:var(--honeydeck-font-size-h1)] font-semibold leading-tight text-foreground">
27
+ {title}
28
+ </h1>
29
+ )}
30
+
31
+ {children && (
32
+ <div className="mb-12 max-w-4xl text-[length:var(--honeydeck-font-size-body)] leading-snug text-surface-foreground">
33
+ {children}
34
+ </div>
35
+ )}
36
+
37
+ {(author || date) && (
38
+ <div className="flex items-center gap-10 border-t border-border pt-5 text-[length:var(--honeydeck-font-size-small)] text-surface-foreground">
39
+ {author && <span>{author}</span>}
40
+ {author && date && <span aria-hidden="true">/</span>}
41
+ {date && <span>{date}</span>}
42
+ </div>
43
+ )}
44
+ </SlideFrame>
45
+ );
46
+ }
47
+
48
+ export const demo: LayoutDemo<CoverFrontmatter> = {
49
+ mdx: `---
50
+ layout: Cover
51
+ author: The honeydeck team
52
+ date: 2026
53
+ ---
54
+
55
+ # Welcome to My Talk
56
+
57
+ A modern slide framework.`,
58
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Clean Default layout — plain title and body.
3
+ */
4
+
5
+ import type { LayoutDemo, LayoutProps } from "../../runtime/types.ts";
6
+ import { SlideFrame } from "../SlideFrame.tsx";
7
+ import { hasTitle } from "../utils.ts";
8
+
9
+ export default function CleanDefaultLayout({ title, children }: LayoutProps) {
10
+ return (
11
+ <SlideFrame>
12
+ {hasTitle(title) && (
13
+ <header className="mb-8 flex-shrink-0">
14
+ <h1 className="font-heading text-[length:var(--honeydeck-font-size-h2)] font-semibold leading-tight text-foreground">
15
+ {title}
16
+ </h1>
17
+ </header>
18
+ )}
19
+
20
+ <div className="min-h-0 flex-1 overflow-hidden">{children}</div>
21
+ </SlideFrame>
22
+ );
23
+ }
24
+
25
+ export const demo: LayoutDemo = {
26
+ mdx: `---
27
+ layout: Default
28
+ ---
29
+
30
+ # Default Layout
31
+
32
+ Body content flows naturally below the title.`,
33
+ };