Skip to content

Commit e7aa5d1

Browse files
committed
Add slide layout system with title and default layouts
Parse <!-- layout: title --> directives in slide content to switch between centered title layout and left-aligned default layout. Title slides use larger headings and centered text, matching the common "title slide" pattern from PowerPoint/Keynote.
1 parent 0c30c6c commit e7aa5d1

52 files changed

Lines changed: 482 additions & 4739 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,26 @@ graph TD
112112
```
113113
````
114114

115+
### Slide layouts
116+
117+
Use `<!-- layout: title -->` to switch a slide to the title layout (centered, larger heading). Without the directive, slides use the default layout (left-aligned content).
118+
119+
```md
120+
<!-- layout: title -->
121+
122+
# My Presentation
123+
124+
A subtitle or tagline
125+
126+
---
127+
128+
# Regular Slide
129+
130+
This uses the default left-aligned layout.
131+
```
132+
133+
Available layouts: `title`, `default` (implicit).
134+
115135
### Fragment lists
116136

117137
Add `<!-- fragment -->` before a list to reveal items one at a time with arrow keys.
@@ -140,6 +160,7 @@ Press P to open it.
140160

141161
### Feature summary
142162

163+
- Slide layouts -- `<!-- layout: title -->` for centered title slides, default for content slides
143164
- Syntax highlighting -- Fenced code blocks highlighted via Shiki (vitesse-dark theme)
144165
- Math -- Inline (`$...$`) and block (`$$...$$`) math rendered with KaTeX
145166
- Mermaid diagrams -- Fenced code blocks with `mermaid` language render as SVG

scripts/generate-templates.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ title: ${title}
188188
theme: ${dirName}
189189
---
190190
191+
<!-- layout: title -->
192+
191193
# ${title}
192194
193195
Theme: ${dirName}

src/cli.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,11 @@ const exampleMarkdown = `---
124124
title: Example Slides
125125
---
126126
127-
# Example Slides
127+
<!-- layout: title -->
128128
129-
Created with **create-slides-app**
129+
# Example Slides
130130
131-
Slides are separated by \`---\` in Markdown
131+
Created with create-slides-app
132132
133133
---
134134

templates/reveal.js-beige/example.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ title: Reveal.js Beige
33
theme: reveal.js-beige
44
---
55

6+
<!-- layout: title -->
7+
68
# Reveal.js Beige
79

810
Theme: reveal.js-beige

templates/reveal.js-beige/src/engine/parser.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ export interface PresentationConfig {
66
[key: string]: unknown;
77
}
88

9+
export type SlideLayout = "default" | "title";
10+
911
export interface SlideData {
1012
index: number;
1113
content: string;
14+
layout: SlideLayout;
1215
frontmatter: Record<string, unknown>;
1316
notes: string;
1417
fragmentCount: number;
@@ -69,6 +72,18 @@ function parseNotes(raw: string): { content: string; notes: string } {
6972
return { content, notes };
7073
}
7174

75+
const validLayouts = new Set<SlideLayout>(["default", "title"]);
76+
77+
function extractLayout(raw: string): { content: string; layout: SlideLayout } {
78+
const pattern = /^<!--\s*layout:\s*(\S+)\s*-->\s*\n?/m;
79+
const match = raw.match(pattern);
80+
if (!match) return { content: raw, layout: "default" };
81+
const name = match[1] as SlideLayout;
82+
const layout = validLayouts.has(name) ? name : "default";
83+
const content = raw.slice(0, match.index) + raw.slice(match.index! + match[0].length);
84+
return { content, layout };
85+
}
86+
7287
function countFragments(content: string): number {
7388
const lines = content.split("\n");
7489
let count = 0;
@@ -107,11 +122,13 @@ export function parseSlides(markdown: string): ParsedPresentation {
107122

108123
const slides: SlideData[] = rawSlides.map((raw, index) => {
109124
const parsed = extractFrontmatter(raw);
110-
const { content: slideContent, notes } = parseNotes(parsed.content.trim());
125+
const { content: withoutNotes, notes } = parseNotes(parsed.content.trim());
126+
const { content: slideContent, layout } = extractLayout(withoutNotes);
111127
const fragmentCount = countFragments(slideContent);
112128
return {
113129
index,
114130
content: slideContent,
131+
layout,
115132
frontmatter: parsed.data as Record<string, unknown>,
116133
notes,
117134
fragmentCount,

templates/reveal.js-beige/src/engine/slide.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,5 +184,6 @@ export function Slide({ data, currentFragment }: SlideProps): React.ReactElement
184184
};
185185
}, [data.content, data.fragmentCount, currentFragment]);
186186

187-
return <div className="slide">{content}</div>;
187+
const layoutClass = data.layout === "title" ? "slide slide-layout-title" : "slide";
188+
return <div className={layoutClass}>{content}</div>;
188189
}

templates/reveal.js-beige/src/styles/base.css

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,22 @@ body {
8484
transform-origin: center center;
8585
}
8686

87+
.slide-layout-title {
88+
align-items: center;
89+
text-align: center;
90+
justify-content: center;
91+
}
92+
93+
.slide-layout-title h1 {
94+
font-size: 4rem;
95+
margin-bottom: 1.5rem;
96+
}
97+
98+
.slide-layout-title p {
99+
font-size: 1.5rem;
100+
color: #888;
101+
}
102+
87103
.slide-empty,
88104
.slide-fallback {
89105
align-items: center;

templates/reveal.js-black/example.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ title: Reveal.js Black
33
theme: reveal.js-black
44
---
55

6+
<!-- layout: title -->
7+
68
# Reveal.js Black
79

810
Theme: reveal.js-black

0 commit comments

Comments
 (0)