Slides System Architecture Refactor — Layout Composition, Adaptive Typography, and Control Bar UX
OneSlideDeck stops duplicating boilerplate and builds on BoilerPlateHTML instead, which is what finally made mode-switching inherit correctly. Type scales with clamp() rather than fixed sizes.
Changelog - 2025-12-14 (#2)
Hypernova Site: Slides System Architecture Refactor — Layout Composition, Adaptive Typography, and Control Bar UX
Overview
This sprint addressed critical architectural and UX issues in the slides system:
Layout Composition Pattern — OneSlideDeck now uses BoilerPlateHTML as its foundation, ensuring proper mode-switching inheritance.
Adaptive Typography — Font sizes now scale responsively using CSS
clamp()functions.Control Bar UX — Centered control bar with proper content offset to prevent overlap.
Light Mode Fixes — Solid button backgrounds instead of transparent for better visibility.
Key Achievement: A clean component composition model where slides properly inherit mode-switching from the single source of truth (BoilerPlateHTML).
Architecture Changes
Before: Duplicated Boilerplate
BaseThemeLayout.astro (has header/footer)
└── Used by normal pages
OneSlideDeck.astro (created its own HTML document!)
└── Standalone, duplicated mode-switching logicProblem: OneSlideDeck duplicated BoilerPlateHTML's functionality, creating maintenance burden and bypassing the single source of truth for mode switching.
After: Proper Composition
BoilerPlateHTML.astro (base HTML boilerplate + mode switching)
├── bodyClass prop (NEW)
├── <slot name="head" /> (NEW)
│
└── OneSlideDeck.astro (RevealJS wrapper)
├── passes bodyClass="slide-deck-active"
├── uses head slot for RevealJS CSS
└── SlidesControlButtons.astroSolution: OneSlideDeck now composes from BoilerPlateHTML, inheriting all mode-switching logic while adding slide-specific styling via bodyClass and head slot.
Changes by Area
1. BoilerPlateHTML Enhancement
Modified: src/layouts/BoilerPlateHTML.astro
Added two new capabilities for composability:
<!-- New Props -->
export interface Props {
title: string;
description: string;
themeClass: string;
bodyClass?: string; // NEW: Allow layouts to add body classes
// ...
}
<!-- New Named Slot -->
<head>
<slot name="head" /> <!-- NEW: Allow layouts to inject head content -->
</head>
<body class={bodyClass}>2. OneSlideDeck Refactor
Modified: src/layouts/OneSlideDeck.astro
Complete rewrite to use BoilerPlateHTML:
<!-- Before: Created its own HTML document -->
<html lang="en" class="theme-hypernova dark">
<head>...</head>
<body>
<div class="reveal">...</div>
</body>
</html>
<!-- After: Composes from BoilerPlateHTML -->
<BoilerPlateHTML
title={title}
description={description}
themeClass="theme-hypernova"
bodyClass="slide-deck-active"
>
<link slot="head" rel="stylesheet" href="reveal.min.css" />
<SlidesControlButtons />
<div class="reveal-container">
<div class="reveal">
<div class="slides">
<slot />
</div>
</div>
</div>
</BoilerPlateHTML>3. RevealJS Configuration Updates
Sizing changes for better scaling:
// Before
width: 1600,
height: 900,
margin: 0.15,
minScale: 0.2,
maxScale: 0.85,
// After - smaller base for better scaling on all screens
width: 1280,
height: 720,
margin: 0.08,
minScale: 0.5,
maxScale: 2.5,4. Adaptive Typography
New CSS using clamp() for responsive font sizes:
.reveal h1 {
font-size: clamp(1.75rem, 5vw + 1rem, 4rem);
line-height: 1.1;
}
.reveal h2 {
font-size: clamp(1.5rem, 3.5vw + 0.75rem, 3rem);
line-height: 1.2;
}
.reveal h3 {
font-size: clamp(1.25rem, 2.5vw + 0.5rem, 2.25rem);
line-height: 1.3;
}
.reveal p {
font-size: clamp(1rem, 1.5vw + 0.5rem, 1.5rem);
line-height: 1.6;
}
.reveal li {
font-size: clamp(0.95rem, 1.4vw + 0.45rem, 1.4rem);
line-height: 1.5;
}5. Control Bar Positioning
Modified: src/components/slides/SlidesControlButtons.astro
Centered control bar with content offset:
/* Control bar positioning */
.control-buttons {
position: fixed;
top: 1rem;
left: 50%;
transform: translateX(-50%);
z-index: 9999;
}
/* Content offset to clear control bar */
.reveal-container {
position: fixed;
top: 4rem; /* Clear the control bar */
left: 0;
width: 100%;
height: calc(100% - 4rem);
}6. Solid Button Backgrounds
Fixed: Light mode button visibility
/* Before: Transparent backgrounds washed out in light mode */
.control-button {
background: rgba(var(--color-primary-800), 0.3);
}
/* After: Solid backgrounds for visibility */
.control-button {
background: rgb(var(--color-primary-800));
color: rgb(var(--color-primary-50));
border: 1px solid rgba(var(--color-primary-600), 0.5);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
/* Light mode overrides */
html[data-mode="light"]:not(.dark) .control-button {
background: white;
color: rgb(var(--color-primary-900));
border: 1px solid rgb(var(--color-primary-200));
}7. Standalone Page Fix
Modified: src/pages/slides/Global-CVC-for-Multinationals.astro
Modified: src/pages/slides/The-Future-of-CPG.astro
Removed Layout wrapper that was causing header/footer collision:
<!-- Before: Wrapped in BaseThemeLayout (WRONG) -->
<Layout title={title} description={description}>
<OneSlideDeck>
<!-- Header/footer appeared on slides! -->
</OneSlideDeck>
</Layout>
<!-- After: Use OneSlideDeck directly -->
<OneSlideDeck title={title} description={description}>
<section>...</section>
</OneSlideDeck>8. Mode-Responsive RevealJS Controls
New: Styling for RevealJS built-in controls
/* Dark mode navigation arrows */
html[data-mode="dark"] .reveal .controls button,
html.dark .reveal .controls button {
color: rgba(255, 255, 255, 0.7);
}
/* Light mode navigation arrows */
html[data-mode="light"]:not(.dark) .reveal .controls button {
color: rgba(0, 0, 0, 0.6);
}
/* Dark mode slide number */
html[data-mode="dark"] .reveal .slide-number {
background-color: rgba(0, 0, 0, 0.5);
color: rgba(255, 255, 255, 0.8);
}
/* Light mode slide number */
html[data-mode="light"]:not(.dark) .reveal .slide-number {
background-color: rgba(255, 255, 255, 0.8);
color: rgba(0, 0, 0, 0.7);
}Files Changed Summary
Modified
src/layouts/BoilerPlateHTML.astro— AddedbodyClassprop and<slot name="head" />named slotsrc/layouts/OneSlideDeck.astro— Refactored to compose from BoilerPlateHTML; added adaptive typography and mode-responsive stylessrc/components/slides/SlidesControlButtons.astro— Centered positioning, solid backgrounds, light mode fixessrc/pages/slides/Global-CVC-for-Multinationals.astro— Removed Layout wrappersrc/pages/slides/The-Future-of-CPG.astro— Removed Layout wrappercontext-v/Slides-System-for-Astro-and-Markdown.md— Updated architecture documentation
Key Lessons
Component Composition > Duplication — When a layout needs specialized behavior, extend the base rather than duplicating it.
Named Slots for Composability — Using
<slot name="head" />allows child layouts to inject content into specific areas without breaking encapsulation.Solid vs Transparent — For UI elements that need to work in both light and dark modes, solid backgrounds with mode-specific overrides are more reliable than transparent backgrounds.
Content Offset Pattern — Fixed position elements (like control bars) should use a container offset pattern (
top: 4rem; height: calc(100% - 4rem)) rather than padding on content.CSS clamp() for Typography — The
clamp(min, preferred, max)function provides responsive typography without media queries.
Context Document Updated
The specification at context-v/Slides-System-for-Astro-and-Markdown.md was updated with:
Section 1.4: Key Architecture Decisions explaining the layout hierarchy
Section 3.3: Updated OneSlideDeck code example using BoilerPlateHTML
Section 3.4: Updated SlidesControlButtons with centered positioning and solid backgrounds
Section 8.1: Updated RevealJS configuration with new dimensions (1280x720)
Section 9.5: New section on standalone presentation pages (use OneSlideDeck directly, not wrapped in Layout)
