@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,110 @@
|
|
|
1
|
+
import type { TokenManifestEntry } from "virtual:honeydeck/token-manifest";
|
|
2
|
+
import * as tokenManifest from "virtual:honeydeck/token-manifest";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { Intro } from "./Intro.tsx";
|
|
5
|
+
|
|
6
|
+
const { tokens } = tokenManifest;
|
|
7
|
+
|
|
8
|
+
function colorLike(token: TokenManifestEntry): boolean {
|
|
9
|
+
const value = token.defaultValue.toLowerCase();
|
|
10
|
+
return (
|
|
11
|
+
value.startsWith("#") ||
|
|
12
|
+
value.startsWith("rgb(") ||
|
|
13
|
+
value.startsWith("hsl(") ||
|
|
14
|
+
value.startsWith("oklch(")
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function TokenValue({ value }: { value: string }) {
|
|
19
|
+
return (
|
|
20
|
+
<code
|
|
21
|
+
className="block max-w-full overflow-hidden text-ellipsis whitespace-nowrap rounded-xs bg-surface px-2 py-1 font-mono text-xs text-surface-foreground"
|
|
22
|
+
title={value}
|
|
23
|
+
>
|
|
24
|
+
{value}
|
|
25
|
+
</code>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function ComputedTokenValue({ name }: { name: string }) {
|
|
30
|
+
const [value, setValue] = useState("");
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
function read() {
|
|
34
|
+
setValue(
|
|
35
|
+
getComputedStyle(document.documentElement)
|
|
36
|
+
.getPropertyValue(name)
|
|
37
|
+
.trim(),
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
read();
|
|
42
|
+
const observer = new MutationObserver(read);
|
|
43
|
+
observer.observe(document.documentElement, {
|
|
44
|
+
attributes: true,
|
|
45
|
+
attributeFilter: ["data-honeydeck-color-mode"],
|
|
46
|
+
});
|
|
47
|
+
return () => observer.disconnect();
|
|
48
|
+
}, [name]);
|
|
49
|
+
|
|
50
|
+
return <TokenValue value={value || "—"} />;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function ThemeTab() {
|
|
54
|
+
return (
|
|
55
|
+
<>
|
|
56
|
+
<Intro title="Theme tokens">
|
|
57
|
+
All{" "}
|
|
58
|
+
<code className="rounded-xs bg-surface px-1 py-0.5 font-mono">
|
|
59
|
+
--honeydeck-*
|
|
60
|
+
</code>{" "}
|
|
61
|
+
tokens. Descriptions come from CSS comments; computed values come from{" "}
|
|
62
|
+
<code className="rounded-xs bg-surface px-1 py-0.5 font-mono">
|
|
63
|
+
getComputedStyle
|
|
64
|
+
</code>
|
|
65
|
+
.
|
|
66
|
+
</Intro>
|
|
67
|
+
|
|
68
|
+
<div className="overflow-x-auto rounded-md border border-border">
|
|
69
|
+
<table className="w-full min-w-240 table-fixed border-collapse text-left text-md">
|
|
70
|
+
<thead className="border-b border-border bg-surface text-xs uppercase tracking-wider text-surface-foreground/60">
|
|
71
|
+
<tr>
|
|
72
|
+
<th className="w-[28%] px-4 py-3 font-medium">Token</th>
|
|
73
|
+
<th className="w-[32%] px-4 py-3 font-medium">Description</th>
|
|
74
|
+
<th className="w-[20%] px-4 py-3 font-medium">Default</th>
|
|
75
|
+
<th className="w-[20%] px-4 py-3 font-medium">Computed</th>
|
|
76
|
+
</tr>
|
|
77
|
+
</thead>
|
|
78
|
+
<tbody className="divide-y divide-border">
|
|
79
|
+
{tokens.map((token) => (
|
|
80
|
+
<tr key={token.name}>
|
|
81
|
+
<td className="px-4 py-3 align-top">
|
|
82
|
+
<div className="flex items-center gap-2">
|
|
83
|
+
{colorLike(token) && (
|
|
84
|
+
<span
|
|
85
|
+
className="size-5 shrink-0 rounded-xs border border-border"
|
|
86
|
+
style={{ backgroundColor: `var(${token.name})` }}
|
|
87
|
+
/>
|
|
88
|
+
)}
|
|
89
|
+
<code className="font-mono text-sm font-medium text-foreground">
|
|
90
|
+
{token.name}
|
|
91
|
+
</code>
|
|
92
|
+
</div>
|
|
93
|
+
</td>
|
|
94
|
+
<td className="px-4 py-3 align-top leading-6 text-foreground/70">
|
|
95
|
+
{token.description || "—"}
|
|
96
|
+
</td>
|
|
97
|
+
<td className="px-4 py-3 align-top">
|
|
98
|
+
<TokenValue value={token.defaultValue} />
|
|
99
|
+
</td>
|
|
100
|
+
<td className="px-4 py-3 align-top">
|
|
101
|
+
<ComputedTokenValue name={token.name} />
|
|
102
|
+
</td>
|
|
103
|
+
</tr>
|
|
104
|
+
))}
|
|
105
|
+
</tbody>
|
|
106
|
+
</table>
|
|
107
|
+
</div>
|
|
108
|
+
</>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for overview-grid keyboard navigation.
|
|
3
|
+
*
|
|
4
|
+
* Arrow up/down must follow the grid the browser actually rendered. This keeps
|
|
5
|
+
* keyboard movement aligned with CSS after first layout and after resizes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export function countGridColumnsFromChildren(children: HTMLCollection): number {
|
|
9
|
+
const firstChild = children.item(0) as HTMLElement | null;
|
|
10
|
+
if (!firstChild) return 0;
|
|
11
|
+
|
|
12
|
+
const firstRowTop = firstChild.offsetTop;
|
|
13
|
+
let columns = 0;
|
|
14
|
+
|
|
15
|
+
for (const child of Array.from(children) as HTMLElement[]) {
|
|
16
|
+
if (Math.abs(child.offsetTop - firstRowTop) > 1) break;
|
|
17
|
+
columns += 1;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return columns;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function countGridTemplateColumns(templateColumns: string): number {
|
|
24
|
+
const trimmed = templateColumns.trim();
|
|
25
|
+
if (!trimmed || trimmed === "none") return 0;
|
|
26
|
+
|
|
27
|
+
let depth = 0;
|
|
28
|
+
let count = 0;
|
|
29
|
+
let inTrack = false;
|
|
30
|
+
|
|
31
|
+
for (const char of trimmed) {
|
|
32
|
+
if (char === "(" || char === "[") depth += 1;
|
|
33
|
+
if (char === ")" || char === "]") depth = Math.max(0, depth - 1);
|
|
34
|
+
|
|
35
|
+
if (/\s/.test(char) && depth === 0) {
|
|
36
|
+
if (inTrack) count += 1;
|
|
37
|
+
inTrack = false;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
inTrack = true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (inTrack) count += 1;
|
|
45
|
+
|
|
46
|
+
return count;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getOverviewGridColumnCount(grid: HTMLElement | null): number {
|
|
50
|
+
if (!grid) return 1;
|
|
51
|
+
|
|
52
|
+
const measuredColumns = countGridColumnsFromChildren(grid.children);
|
|
53
|
+
if (measuredColumns > 0) return measuredColumns;
|
|
54
|
+
|
|
55
|
+
const templateColumns = window.getComputedStyle(grid).gridTemplateColumns;
|
|
56
|
+
const computedColumns = countGridTemplateColumns(templateColumns);
|
|
57
|
+
|
|
58
|
+
return Math.max(1, computedColumns);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type OverviewGridSelectionDirection =
|
|
62
|
+
| "ArrowRight"
|
|
63
|
+
| "ArrowLeft"
|
|
64
|
+
| "ArrowDown"
|
|
65
|
+
| "ArrowUp";
|
|
66
|
+
|
|
67
|
+
export type OverviewGridSelectionMove = {
|
|
68
|
+
selected: number;
|
|
69
|
+
didMove: boolean;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export function getOverviewGridSelectionMove(
|
|
73
|
+
selected: number,
|
|
74
|
+
total: number,
|
|
75
|
+
columns: number,
|
|
76
|
+
direction: OverviewGridSelectionDirection,
|
|
77
|
+
): OverviewGridSelectionMove {
|
|
78
|
+
if (total <= 0) return { selected: 0, didMove: false };
|
|
79
|
+
|
|
80
|
+
const columnCount = Math.max(1, columns);
|
|
81
|
+
const current = Math.min(Math.max(selected, 0), total - 1);
|
|
82
|
+
|
|
83
|
+
let next = current;
|
|
84
|
+
|
|
85
|
+
switch (direction) {
|
|
86
|
+
case "ArrowRight":
|
|
87
|
+
next = Math.min(current + 1, total - 1);
|
|
88
|
+
break;
|
|
89
|
+
case "ArrowLeft":
|
|
90
|
+
next = Math.max(current - 1, 0);
|
|
91
|
+
break;
|
|
92
|
+
case "ArrowDown": {
|
|
93
|
+
const lastRowStart = Math.floor((total - 1) / columnCount) * columnCount;
|
|
94
|
+
next =
|
|
95
|
+
current >= lastRowStart
|
|
96
|
+
? current
|
|
97
|
+
: Math.min(current + columnCount, total - 1);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
case "ArrowUp":
|
|
101
|
+
next = current < columnCount ? current : current - columnCount;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return { selected: next, didMove: next !== current };
|
|
106
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type PresenterNextPreview = {
|
|
2
|
+
slideIndex: number;
|
|
3
|
+
stepIndex: number;
|
|
4
|
+
} | null;
|
|
5
|
+
|
|
6
|
+
export function getPresenterNextPreview({
|
|
7
|
+
currentIndex,
|
|
8
|
+
step,
|
|
9
|
+
stepCount,
|
|
10
|
+
totalSlides,
|
|
11
|
+
}: {
|
|
12
|
+
currentIndex: number;
|
|
13
|
+
step: number;
|
|
14
|
+
stepCount: number;
|
|
15
|
+
totalSlides: number;
|
|
16
|
+
}): PresenterNextPreview {
|
|
17
|
+
if (step < stepCount) {
|
|
18
|
+
return { slideIndex: currentIndex, stepIndex: step + 1 };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const nextSlideIndex = currentIndex + 1;
|
|
22
|
+
if (nextSlideIndex < totalSlides) {
|
|
23
|
+
return { slideIndex: nextSlideIndex, stepIndex: 0 };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript ambient declarations for Honeydeck virtual modules.
|
|
3
|
+
*
|
|
4
|
+
* These modules don't exist on disk — they're synthesised at build/dev time
|
|
5
|
+
* by `src/vite-plugin/virtual-modules.ts`. Without these declarations,
|
|
6
|
+
* TypeScript would reject any `import` statement targeting them.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** Barrel re-export of all slides in the deck. */
|
|
10
|
+
declare module "virtual:honeydeck/slides" {
|
|
11
|
+
/** Total number of slides in the deck. */
|
|
12
|
+
export const slideCount: number;
|
|
13
|
+
|
|
14
|
+
// Individual slide components are exported as Slide0, Slide1, Slide2, …
|
|
15
|
+
// Per-slide metadata is exported as stepCount0, slideTitle0, slideFrontmatter0, slideLayout0, …
|
|
16
|
+
// They cannot be statically typed here because the count is dynamic.
|
|
17
|
+
// Access them via a cast:
|
|
18
|
+
// import * as slideModules from 'virtual:honeydeck/slides';
|
|
19
|
+
// const C = (slideModules as Record<string, unknown>)[`Slide${i}`] as ComponentType;
|
|
20
|
+
// const title = (slideModules as Record<string, unknown>)[`slideTitle${i}`] as string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* CSS token manifest — all --honeydeck-* tokens with descriptions and default values.
|
|
25
|
+
* Generated at build time from src/theme/base.css.
|
|
26
|
+
*/
|
|
27
|
+
declare module "virtual:honeydeck/token-manifest" {
|
|
28
|
+
export type TokenManifestEntry = {
|
|
29
|
+
name: string;
|
|
30
|
+
description: string;
|
|
31
|
+
defaultValue: string;
|
|
32
|
+
};
|
|
33
|
+
export const tokens: TokenManifestEntry[];
|
|
34
|
+
export default tokens;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Active layout map and docs reference demo metadata. */
|
|
38
|
+
declare module "virtual:honeydeck/layouts" {
|
|
39
|
+
import type {
|
|
40
|
+
CompiledLayoutDemo,
|
|
41
|
+
LayoutMap,
|
|
42
|
+
LayoutPropDoc,
|
|
43
|
+
} from "./types.ts";
|
|
44
|
+
|
|
45
|
+
export const layoutMap: LayoutMap;
|
|
46
|
+
export const layoutNames: string[];
|
|
47
|
+
export const layoutDemos: Record<string, CompiledLayoutDemo>;
|
|
48
|
+
export const layoutPropDocs: Record<string, LayoutPropDoc[]>;
|
|
49
|
+
export const layoutDemoWarnings: string[];
|
|
50
|
+
export default layoutMap;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Built-in component reference documentation metadata. */
|
|
54
|
+
declare module "virtual:honeydeck/components" {
|
|
55
|
+
import type { ComponentType } from "react";
|
|
56
|
+
import type { ComponentDoc } from "./types.ts";
|
|
57
|
+
|
|
58
|
+
export const componentMap: Record<
|
|
59
|
+
string,
|
|
60
|
+
ComponentType<Record<string, unknown>>
|
|
61
|
+
>;
|
|
62
|
+
export const componentNames: string[];
|
|
63
|
+
export const componentDocs: Record<string, ComponentDoc>;
|
|
64
|
+
export const componentDocWarnings: string[];
|
|
65
|
+
export default componentMap;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Parsed deck-level frontmatter (the YAML block at the top of deck.mdx). */
|
|
69
|
+
declare module "virtual:honeydeck/config" {
|
|
70
|
+
const config: Record<string, unknown>;
|
|
71
|
+
|
|
72
|
+
export { config };
|
|
73
|
+
export default config;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Individual compiled slide modules.
|
|
78
|
+
* Each slide exports its component as default, plus metadata named exports.
|
|
79
|
+
*/
|
|
80
|
+
declare module "virtual:honeydeck/slide/*.mdx" {
|
|
81
|
+
import type { ComponentType } from "react";
|
|
82
|
+
|
|
83
|
+
/** Compiled slide React component */
|
|
84
|
+
const Component: ComponentType;
|
|
85
|
+
export default Component;
|
|
86
|
+
|
|
87
|
+
/** Number of timeline steps on this slide (from remarkStepNumbering) */
|
|
88
|
+
export const stepCount: number;
|
|
89
|
+
|
|
90
|
+
/** Plain-text content of the first h1 (from remarkH1Extract) */
|
|
91
|
+
export const slideTitle: string;
|
|
92
|
+
|
|
93
|
+
/** Parsed YAML frontmatter for this slide (from remarkH1Extract) */
|
|
94
|
+
export const slideFrontmatter: Record<string, unknown>;
|
|
95
|
+
|
|
96
|
+
/** Layout name from frontmatter.layout, or '' for default */
|
|
97
|
+
export const slideLayout: string;
|
|
98
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Honeydeck Theme Specification
|
|
2
|
+
|
|
3
|
+
> Observable behavior for design tokens, theme CSS, Tailwind mapping, and color modes.
|
|
4
|
+
|
|
5
|
+
## Design Token System
|
|
6
|
+
|
|
7
|
+
Honeydeck defines a CSS custom property contract. In the base theme, colors derive from a primary color using `oklch` relative color syntax. Light and dark modes each have their own primary. Theme layers may override any token directly.
|
|
8
|
+
|
|
9
|
+
### Color Tokens (per mode)
|
|
10
|
+
|
|
11
|
+
```css
|
|
12
|
+
/* Source color — brand identity for this mode */
|
|
13
|
+
--honeydeck-primary
|
|
14
|
+
|
|
15
|
+
/* Text color on primary backgrounds */
|
|
16
|
+
--honeydeck-primary-foreground
|
|
17
|
+
|
|
18
|
+
/* Main slide background (derived from primary) */
|
|
19
|
+
--honeydeck-background
|
|
20
|
+
|
|
21
|
+
/* Main text color (derived from primary) */
|
|
22
|
+
--honeydeck-foreground
|
|
23
|
+
|
|
24
|
+
/* Secondary surfaces — cards, code blocks, callouts */
|
|
25
|
+
--honeydeck-surface
|
|
26
|
+
|
|
27
|
+
/* Text color on surface backgrounds */
|
|
28
|
+
--honeydeck-surface-foreground
|
|
29
|
+
|
|
30
|
+
/* Border/divider color */
|
|
31
|
+
--honeydeck-border
|
|
32
|
+
|
|
33
|
+
/* Accent — computed as the complementary hue by default */
|
|
34
|
+
--honeydeck-accent
|
|
35
|
+
|
|
36
|
+
/* Text on accent backgrounds */
|
|
37
|
+
--honeydeck-accent-foreground
|
|
38
|
+
|
|
39
|
+
/* Link color */
|
|
40
|
+
--honeydeck-link-color /* default: inherit */
|
|
41
|
+
|
|
42
|
+
/* Border radius for cards, code blocks, buttons */
|
|
43
|
+
--honeydeck-border-radius
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Typography Tokens
|
|
47
|
+
|
|
48
|
+
Typography tokens are **shared across color modes** (not redefined per light/dark).
|
|
49
|
+
|
|
50
|
+
The base font size seeds `rem` for the entire slide canvas (`font-size` on `:root`). All other sizes are expressed in `rem` so they scale proportionally.
|
|
51
|
+
|
|
52
|
+
```css
|
|
53
|
+
/* Font families */
|
|
54
|
+
--honeydeck-font-heading
|
|
55
|
+
--honeydeck-font-body
|
|
56
|
+
--honeydeck-font-mono
|
|
57
|
+
|
|
58
|
+
/* Base font size — sets :root font-size, everything scales relative to this */
|
|
59
|
+
--honeydeck-font-size-base /* default: 36px */
|
|
60
|
+
|
|
61
|
+
/* Scale factor for heading progression (e.g. 1.25 = major third) */
|
|
62
|
+
--honeydeck-font-scale /* default: 1.25 */
|
|
63
|
+
|
|
64
|
+
/* Body / paragraph text */
|
|
65
|
+
--honeydeck-font-size-body /* 1rem (= base) */
|
|
66
|
+
|
|
67
|
+
/* Computed heading sizes (1rem × scale^n), individually overridable */
|
|
68
|
+
--honeydeck-font-size-display /* 1rem × scale⁵ */
|
|
69
|
+
--honeydeck-font-size-h1 /* 1rem × scale⁴ */
|
|
70
|
+
--honeydeck-font-size-h2 /* 1rem × scale³ */
|
|
71
|
+
--honeydeck-font-size-h3 /* 1rem × scale² */
|
|
72
|
+
--honeydeck-font-size-h4 /* 1rem × scale¹ */
|
|
73
|
+
--honeydeck-font-size-small /* 1rem ÷ scale */
|
|
74
|
+
|
|
75
|
+
/* Code blocks */
|
|
76
|
+
--honeydeck-font-size-code /* 0.83rem */
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Layout Token
|
|
80
|
+
|
|
81
|
+
```css
|
|
82
|
+
/* Internal padding between slide edge and layout content */
|
|
83
|
+
--honeydeck-slide-padding /* default: 2rem */
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Built-in layouts apply this via the shared `SlideFrame` wrapper. This is content padding inside the slide canvas, not a viewport inset.
|
|
87
|
+
|
|
88
|
+
### Code Token
|
|
89
|
+
|
|
90
|
+
```css
|
|
91
|
+
/* Opacity for non-highlighted lines during step-through (0–1) */
|
|
92
|
+
--honeydeck-code-line-dim-opacity /* default: 0.4 */
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
> **Note:** Code block syntax highlighting colors come from Honeydeck's built-in syntax themes, not from Honeydeck tokens. Honeydeck does not expose custom syntax theme configuration. Only the dim-opacity token is part of the Honeydeck token contract; plain fallback code blocks use Honeydeck CSS tokens.
|
|
96
|
+
|
|
97
|
+
### Light/Dark Mode
|
|
98
|
+
|
|
99
|
+
Each mode defines its own `--honeydeck-primary`. All other color tokens derive from it:
|
|
100
|
+
|
|
101
|
+
```css
|
|
102
|
+
[data-honeydeck-color-mode="light"] {
|
|
103
|
+
--honeydeck-primary: oklch(50% 0.2 250);
|
|
104
|
+
--honeydeck-primary-foreground: oklch(from var(--honeydeck-primary) 98% 0.01 h);
|
|
105
|
+
--honeydeck-background: oklch(from var(--honeydeck-primary) 98% 0.01 h);
|
|
106
|
+
--honeydeck-foreground: oklch(from var(--honeydeck-primary) 15% 0.02 h);
|
|
107
|
+
--honeydeck-surface: oklch(from var(--honeydeck-primary) 94% 0.02 h);
|
|
108
|
+
--honeydeck-surface-foreground: oklch(from var(--honeydeck-primary) 20% 0.02 h);
|
|
109
|
+
--honeydeck-border: oklch(from var(--honeydeck-primary) 85% 0.03 h);
|
|
110
|
+
--honeydeck-accent: oklch(from var(--honeydeck-primary) l c calc(h + 180));
|
|
111
|
+
--honeydeck-accent-foreground: oklch(from var(--honeydeck-accent) 15% 0.01 h);
|
|
112
|
+
--honeydeck-link-color: inherit;
|
|
113
|
+
--honeydeck-border-radius: 0.5rem;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
[data-honeydeck-color-mode="dark"] {
|
|
117
|
+
--honeydeck-primary: oklch(70% 0.2 250);
|
|
118
|
+
--honeydeck-primary-foreground: oklch(from var(--honeydeck-primary) 10% 0.01 h);
|
|
119
|
+
--honeydeck-background: oklch(from var(--honeydeck-primary) 12% 0.02 h);
|
|
120
|
+
--honeydeck-foreground: oklch(from var(--honeydeck-primary) 95% 0.01 h);
|
|
121
|
+
--honeydeck-surface: oklch(from var(--honeydeck-primary) 20% 0.03 h);
|
|
122
|
+
--honeydeck-surface-foreground: oklch(from var(--honeydeck-primary) 90% 0.02 h);
|
|
123
|
+
--honeydeck-border: oklch(from var(--honeydeck-primary) 30% 0.03 h);
|
|
124
|
+
--honeydeck-accent: oklch(from var(--honeydeck-primary) l c calc(h + 180));
|
|
125
|
+
--honeydeck-accent-foreground: oklch(from var(--honeydeck-accent) 95% 0.01 h);
|
|
126
|
+
--honeydeck-link-color: inherit;
|
|
127
|
+
--honeydeck-border-radius: 0.5rem;
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Any derived token can be explicitly overridden.
|
|
132
|
+
|
|
133
|
+
### Tailwind Mapping
|
|
134
|
+
|
|
135
|
+
Honeydeck uses Tailwind v4 `@theme` in `base.css` to map tokens to utilities:
|
|
136
|
+
|
|
137
|
+
```css
|
|
138
|
+
@theme {
|
|
139
|
+
--color-primary: var(--honeydeck-primary);
|
|
140
|
+
--color-primary-foreground: var(--honeydeck-primary-foreground);
|
|
141
|
+
--color-background: var(--honeydeck-background);
|
|
142
|
+
--color-foreground: var(--honeydeck-foreground);
|
|
143
|
+
--color-surface: var(--honeydeck-surface);
|
|
144
|
+
--color-surface-foreground: var(--honeydeck-surface-foreground);
|
|
145
|
+
--color-border: var(--honeydeck-border);
|
|
146
|
+
--color-accent: var(--honeydeck-accent);
|
|
147
|
+
--color-accent-foreground: var(--honeydeck-accent-foreground);
|
|
148
|
+
--color-link: var(--honeydeck-link-color);
|
|
149
|
+
|
|
150
|
+
--radius-honeydeck: var(--honeydeck-border-radius);
|
|
151
|
+
--font-heading: var(--honeydeck-font-heading);
|
|
152
|
+
--font-body: var(--honeydeck-font-body);
|
|
153
|
+
--font-mono: var(--honeydeck-font-mono);
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`base.css` also defines runtime fallback colors (`bg-error-surface`, `bg-void`, etc.) plus pixel-based spacing/text-size scales so runtime UI is not affected by the slide root font size.
|
|
158
|
+
|
|
159
|
+
Base theme CSS owns global and generated-content styling that cannot be attached at a React call site: slide Markdown typography, documentation Markdown typography, Shiki-generated code descendants, and generated plain-code fallback markup. Honeydeck-owned React component wrappers use Tailwind utilities for their own layout and visual styling while preserving stable `honeydeck-*` class hooks where runtime code, PDF export, tests, or generated descendant styling need to find them.
|
|
160
|
+
|
|
161
|
+
The base CSS also applies `--honeydeck-link-color` to slide anchors and underlines links. `cursor: pointer` is reserved for real links only: anchors with `href` (`a[href]`) in slide/doc content and runtime route links. Buttons and other non-link controls must not set `cursor: pointer`; they keep the default cursor. Theme CSS is exported as `@honeydeck/honeydeck/theme.css`, `@honeydeck/honeydeck/themes/base.css`, `@honeydeck/honeydeck/themes/clean.css`, and `@honeydeck/honeydeck/themes/bee.css`.
|
|
162
|
+
|
|
163
|
+
Usage in MDX:
|
|
164
|
+
|
|
165
|
+
```mdx
|
|
166
|
+
<div className="bg-surface text-surface-foreground border border-border rounded-honeydeck">
|
|
167
|
+
Card content
|
|
168
|
+
</div>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Color Mode Behavior
|
|
172
|
+
|
|
173
|
+
- Browser defaults to system preference
|
|
174
|
+
- User can toggle via navigation controls (system / light / dark)
|
|
175
|
+
- `colorMode:` frontmatter can pin the deck to one mode
|
|
176
|
+
- PDF ignores system preference; if no PDF override or pinned deck mode exists, it uses light
|
|
177
|
+
- PDF color mode resolves as CLI `--mode` > `pdfColorMode` > pinned `colorMode` (`light`/`dark`) > `light`
|
|
178
|
+
- Renderer applies: `data-honeydeck-color-mode="light"` or `data-honeydeck-color-mode="dark"`
|
|
179
|
+
- Base theme CSS sets browser `color-scheme` to match the effective Honeydeck color mode so built-in browser defaults and embedded rendered assets stay visually consistent in static builds and PDF export
|