@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.
- package/AGENTS.md +25 -0
- package/DEVELOPMENT.md +522 -0
- package/LICENSE +21 -0
- package/Readme.md +49 -0
- package/SPEC.md +88 -0
- package/docs/components.md +63 -0
- package/docs/configuration.md +91 -0
- package/docs/getting-started.md +116 -0
- package/docs/kit-authoring.md +207 -0
- package/docs/kits.md +387 -0
- package/docs/local-development.md +95 -0
- package/docs/mermaid.md +198 -0
- package/docs/mobile.md +108 -0
- package/docs/navigation.md +93 -0
- package/docs/next-steps.md +377 -0
- package/docs/pdf-export.md +91 -0
- package/docs/presenter-mode.md +104 -0
- package/docs/slides.md +130 -0
- package/docs/slidev-migration.md +42 -0
- package/docs/steps-and-reveals.md +171 -0
- package/package.json +134 -0
- package/skills/SPEC.md +21 -0
- package/skills/honeydeck/SKILL.md +65 -0
- package/skills/presentation-writing/SKILL.md +75 -0
- package/skills/slidev-migration/SKILL.md +153 -0
- package/src/SPEC.md +89 -0
- package/src/assets.d.ts +30 -0
- package/src/cli/SPEC.md +230 -0
- package/src/cli/args.ts +3 -0
- package/src/cli/banner.ts +9 -0
- package/src/cli/bin.js +5 -0
- package/src/cli/build.ts +229 -0
- package/src/cli/deck-path.ts +32 -0
- package/src/cli/dev.ts +263 -0
- package/src/cli/index.ts +126 -0
- package/src/cli/init.ts +369 -0
- package/src/cli/pdf.ts +923 -0
- package/src/cli/skill.ts +75 -0
- package/src/cli/templates/SPEC.md +70 -0
- package/src/cli/templates/deck-mdx.ts +15 -0
- package/src/cli/templates/package-json.ts +36 -0
- package/src/cli/templates/sparkle-button.ts +15 -0
- package/src/cli/templates/starter/components/SparkleButton.tsx +84 -0
- package/src/cli/templates/starter/deck.mdx +153 -0
- package/src/cli/templates/starter/styles.css +14 -0
- package/src/cli/templates/styles-css.ts +14 -0
- package/src/defaults.ts +1 -0
- package/src/layouts/ColorModeImage.tsx +55 -0
- package/src/layouts/SPEC.md +393 -0
- package/src/layouts/SlideFrame.tsx +48 -0
- package/src/layouts/bee/Blank.tsx +12 -0
- package/src/layouts/bee/Cover.tsx +70 -0
- package/src/layouts/bee/Default.tsx +42 -0
- package/src/layouts/bee/Image/Image.tsx +151 -0
- package/src/layouts/bee/Image/placeholder-dark.webp +0 -0
- package/src/layouts/bee/Image/placeholder-vertical-dark.webp +0 -0
- package/src/layouts/bee/Image/placeholder-vertical.webp +0 -0
- package/src/layouts/bee/Image/placeholder.webp +0 -0
- package/src/layouts/bee/ImageLeft.tsx +27 -0
- package/src/layouts/bee/ImageRight.tsx +27 -0
- package/src/layouts/bee/ImageSide.tsx +107 -0
- package/src/layouts/bee/Section.tsx +40 -0
- package/src/layouts/bee/TwoCol.tsx +108 -0
- package/src/layouts/bee/index.ts +40 -0
- package/src/layouts/clean/Blank.tsx +12 -0
- package/src/layouts/clean/Cover.tsx +58 -0
- package/src/layouts/clean/Default.tsx +33 -0
- package/src/layouts/clean/Image/Image.tsx +103 -0
- package/src/layouts/clean/ImageLeft.tsx +27 -0
- package/src/layouts/clean/ImageRight.tsx +27 -0
- package/src/layouts/clean/ImageSide.tsx +113 -0
- package/src/layouts/clean/Section.tsx +35 -0
- package/src/layouts/clean/TwoCol.tsx +63 -0
- package/src/layouts/clean/index.ts +40 -0
- package/src/layouts/index.ts +60 -0
- package/src/layouts/placeholders.ts +9 -0
- package/src/layouts/utils.ts +13 -0
- package/src/remark/SPEC.md +49 -0
- package/src/remark/h1-extract.ts +124 -0
- package/src/remark/index.ts +4 -0
- package/src/remark/shiki-code-blocks.ts +325 -0
- package/src/remark/step-numbering.ts +412 -0
- package/src/runtime/Deck.tsx +533 -0
- package/src/runtime/SPEC.md +256 -0
- package/src/runtime/SlideCanvas.tsx +95 -0
- package/src/runtime/TimelineContext.tsx +122 -0
- package/src/runtime/app-shell/index.html +31 -0
- package/src/runtime/app-shell/main.tsx +42 -0
- package/src/runtime/aspectRatio.ts +34 -0
- package/src/runtime/colorMode.ts +23 -0
- package/src/runtime/components/BrowserFrame.tsx +233 -0
- package/src/runtime/components/Button.tsx +57 -0
- package/src/runtime/components/CodeBlock.tsx +210 -0
- package/src/runtime/components/ColorModeCycleButton.tsx +59 -0
- package/src/runtime/components/ErrorBoundary.tsx +125 -0
- package/src/runtime/components/Keyboard.tsx +87 -0
- package/src/runtime/components/ListStyle.tsx +203 -0
- package/src/runtime/components/NavBar.tsx +223 -0
- package/src/runtime/components/NavBarButton.tsx +47 -0
- package/src/runtime/components/NavBarDivider.tsx +3 -0
- package/src/runtime/components/Notes.tsx +171 -0
- package/src/runtime/components/Reveal.tsx +82 -0
- package/src/runtime/components/RevealGroup.tsx +193 -0
- package/src/runtime/components/SPEC.md +263 -0
- package/src/runtime/components/SlideNumberBadge.tsx +11 -0
- package/src/runtime/components/TimelineSteps.tsx +115 -0
- package/src/runtime/components/index.ts +55 -0
- package/src/runtime/index.ts +42 -0
- package/src/runtime/inputOwnership.ts +68 -0
- package/src/runtime/keyboardTarget.ts +7 -0
- package/src/runtime/lastSlideRoute.ts +56 -0
- package/src/runtime/navigation.ts +211 -0
- package/src/runtime/router.ts +157 -0
- package/src/runtime/slideData.ts +137 -0
- package/src/runtime/sync.ts +267 -0
- package/src/runtime/types.ts +182 -0
- package/src/runtime/useKeyboardNav.ts +138 -0
- package/src/runtime/useSwipeNav.ts +257 -0
- package/src/runtime/views/DocsView.tsx +74 -0
- package/src/runtime/views/OverviewView.tsx +386 -0
- package/src/runtime/views/PresenterNotesPanel.tsx +76 -0
- package/src/runtime/views/PresenterView.tsx +340 -0
- package/src/runtime/views/SPEC.md +152 -0
- package/src/runtime/views/docs/ComponentsTab.tsx +178 -0
- package/src/runtime/views/docs/DocsHeader.tsx +101 -0
- package/src/runtime/views/docs/Intro.tsx +20 -0
- package/src/runtime/views/docs/LayoutsTab.tsx +324 -0
- package/src/runtime/views/docs/ThemeTab.tsx +110 -0
- package/src/runtime/views/index.ts +7 -0
- package/src/runtime/views/overviewGrid.ts +106 -0
- package/src/runtime/views/presenterPreview.ts +27 -0
- package/src/runtime/virtual-modules.d.ts +98 -0
- package/src/theme/SPEC.md +179 -0
- package/src/theme/base.css +623 -0
- package/src/theme/bee.css +35 -0
- package/src/theme/clean.css +38 -0
- package/src/vite-plugin/SPEC.md +114 -0
- package/src/vite-plugin/component-doc-crawler.ts +350 -0
- package/src/vite-plugin/deck-loader.ts +148 -0
- package/src/vite-plugin/index.ts +373 -0
- package/src/vite-plugin/layout-demo-crawler.ts +802 -0
- package/src/vite-plugin/splitter.ts +353 -0
- package/src/vite-plugin/token-manifest.ts +163 -0
- 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
|
+
};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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
|
+
};
|