Implement Embedded Slide Presentations in Markdown Render Pipeline
Summary
Implemented a comprehensive embedded slide presentation system that allows Reveal.js presentations to be embedded directly within markdown documents using custom code block syntax. The system supports configuration options, theme customization, and seamless integration with the existing markdown rendering pipeline.
Why Care
This feature transforms static documentation into interactive, engaging content by allowing slide presentations to be embedded anywhere in markdown files. It's particularly valuable for technical specifications, educational content, and documentation that benefits from visual presentation formats. The system maintains the simplicity of markdown while adding rich presentation capabilities without requiring separate slide authoring tools.
Implementation
Changes Made
Core Components Added
/src/components/SlidesEmbed.astro
- Main embed component that renders iframe containers for slide presentations/src/pages/slides/embed/[...slug].astro
- Dynamic route handler for embedded presentation rendering/src/generated-content/slides/css-animation-systems.md
- Comprehensive CSS animation systems presentation content
Markdown Processing Pipeline Integration
/src/components/markdown/AstroMarkdown.astro
(lines 980-1028) - Added 'slides' case to code block processing with configuration parsing and component rendering
Content Collection Configuration
/src/content.config.ts
(lines 58-66) - Enhanced slides collection with proper slug generation from filenames and frontmatter
Specification Documentation
/Maintain-Embeddable-Slides.md
- Complete technical specification for the embedded slides system/src/generated-content/specs/Maintain-a-CSS-Animation-System.md
(lines 32-39) - Integration example demonstrating the embed syntax
Slide Content Files Enhanced
/src/generated-content/slides/docker-intro.md
- Added slug: docker-intro/src/generated-content/slides/git-basics.md
- Added slug: git-basics/src/generated-content/slides/sample-presentation.md
- Added slug: sample-presentation/src/generated-content/slides/typescript-fundamentals.md
- Added slug: typescript-fundamentals
Technical Details
Custom Markdown Syntax
The system introduces a new code block type
slides
with YAML-style configuration: markdown
```slides
theme: black
transition: slide
controls: true
progress: true
- [[slides/css-animation-systems.md|CSS Animation Systems]]
text
### Architecture Flow
```mermaid
graph TD
A[Markdown Document] --> B[AstroMarkdown.astro Parser]
B --> C{Code Block Type?}
C -->|slides| D[Parse Configuration]
D --> E[Extract Slide Links]
E --> F[SlidesEmbed Component]
F --> G[Generate Embed URL]
G --> H[Render iframe]
H --> I[/slides/embed/slug Route]
I --> J[Load Slide Content]
J --> K[MarkdownSlideDeck Layout]
K --> L[Reveal.js Presentation]
Configuration Parser Implementation
javascript
// /src/components/markdown/AstroMarkdown.astro (lines 985-1020)
case 'slides':
const lines = value.trim().split('\n');
const config = {};
const slides = [];
let configSection = true;
for (const line of lines) {
const trimmedLine = line.trim();
if (!trimmedLine) continue;
if (trimmedLine.startsWith('- [[')) {
configSection = false;
const linkMatch = trimmedLine.match(/\[\[(.*?)\|(.*?)\]\]/);
if (linkMatch) {
slides.push({
path: linkMatch[1],
title: linkMatch[2]
});
}
} else if (configSection) {
// Parse both "key: value" and "key=value" syntax
const colonMatch = trimmedLine.match(/^(\w+):\s*(.+)$/);
const equalsMatch = trimmedLine.match(/^(\w+)=(.+)$/);
if (colonMatch) {
config[colonMatch[1]] = colonMatch[2].trim();
} else if (equalsMatch) {
config[equalsMatch[1]] = equalsMatch[2].trim();
}
}
}
return <SlidesEmbed slides={slides} config={config} />;
URL Structure and Routing
- Embed URLs:
/slides/embed/{slug}
with query parameters for configuration - Direct URLs:
/slides/markdown/{slug}
for standalone presentations - Path-based parameters: Uses Astro's
[...slug].astro
dynamic routing
Filesystem vs Collections Approach
Initially attempted to use Astro content collections but encountered slug generation issues. Resolved by switching to direct filesystem reading:
javascript
// /src/pages/slides/embed/[...slug].astro (lines 41-69)
try {
const slidesDir = path.join(process.cwd(), 'src', 'generated-content', 'slides');
const fullPath = path.join(slidesDir, `${slidePath}.md`);
const fileContent = await readFile(fullPath, 'utf-8');
// Parse frontmatter and content
const frontmatterMatch = fileContent.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
if (frontmatterMatch) {
const frontmatterText = frontmatterMatch[1];
combinedMarkdown = frontmatterMatch[2];
const titleMatch = frontmatterText.match(/title:\s*(.+)/);
if (titleMatch) {
title = titleMatch[1].trim().replace(/['"]/g, '');
}
}
} catch (error) {
combinedMarkdown = `# Slide Not Found\n\nThe requested slide "${slidePath}" could not be loaded.`;
}
Integration Points
Markdown Processing Chain
The slides processor integrates with the existing markdown rendering pipeline in
AstroMarkdown.astro
, sitting alongside other custom code block processors like mermaid diagrams and code galleries.Component Architecture
- SlidesEmbed.astro: Handles iframe generation and URL construction
- MarkdownSlideDeck.astro: Existing layout component reused for consistency
- Reveal.js Integration: Uses CDN-hosted Reveal.js for presentation functionality
Content Management
- Slides stored in
/src/generated-content/slides/
directory - Each slide file requires frontmatter with
title
andslug
fields - Uses standard markdown with
---
separators for slide breaks
Configuration System
Supports both inline and block configuration styles:
markdown
# Block style
```slides
theme: dark
transition: fade
- [[slides/example.md|Example]]
Inline style
text
## Documentation
### Usage Examples
**Basic Embed:**
```markdown
```slides
- [[slides/my-presentation.md|My Presentation]]
text
**With Configuration:**
```markdown
```slides
theme: black
transition: slide
controls: true
progress: true
- [[slides/advanced-topic.md|Advanced Topic]]
text
### API Integration
The embed system exposes configuration through URL parameters:
- `theme`: Reveal.js theme name
- `transition`: Slide transition style
- `controls`: Show/hide navigation controls
- `progress`: Show/hide progress bar
- `autoSlide`: Auto-advance timing (milliseconds)
- `loop`: Enable/disable presentation looping
### File Structure
src/
├── components/
│ ├── SlidesEmbed.astro
│ └── markdown/
│ └── AstroMarkdown.astro (modified)
├── pages/slides/
│ └── embed/
│ └── [...slug].astro
└── generated-content/slides/
├── css-animation-systems.md
├── docker-intro.md
├── git-basics.md
└── typescript-fundamentals.md
text
### Performance Considerations
- Iframe lazy loading implemented with `loading="lazy"`
- Static file serving for slide content
- Minimal JavaScript footprint using Reveal.js CDN
- Server-side rendering for embed containers
### Browser Compatibility
- Modern browsers supporting iframe and ES6 features
- Responsive design with mobile-specific height adjustments
- Keyboard navigation support through Reveal.js
- Print/PDF export capabilities maintained
This implementation provides a robust, extensible foundation for embedded presentations while maintaining the simplicity and flexibility that makes markdown-based authoring effective.