Lossless Changelog
product

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.

Michael StatonMusic Editor

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:

  1. Layout Composition Pattern — OneSlideDeck now uses BoilerPlateHTML as its foundation, ensuring proper mode-switching inheritance.

  2. Adaptive Typography — Font sizes now scale responsively using CSS clamp() functions.

  3. Control Bar UX — Centered control bar with proper content offset to prevent overlap.

  4. 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 logic

Problem: 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.astro

Solution: 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:

ASTRO
<!-- 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:

ASTRO
<!-- 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:

JAVASCRIPT
// 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:

CSS
.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:

CSS
/* 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

CSS
/* 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:

ASTRO
<!-- 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

CSS
/* 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 — Added bodyClass prop and <slot name="head" /> named slot

  • src/layouts/OneSlideDeck.astro — Refactored to compose from BoilerPlateHTML; added adaptive typography and mode-responsive styles

  • src/components/slides/SlidesControlButtons.astro — Centered positioning, solid backgrounds, light mode fixes

  • src/pages/slides/Global-CVC-for-Multinationals.astro — Removed Layout wrapper

  • src/pages/slides/The-Future-of-CPG.astro — Removed Layout wrapper

  • context-v/Slides-System-for-Astro-and-Markdown.md — Updated architecture documentation


Key Lessons

  1. Component Composition > Duplication — When a layout needs specialized behavior, extend the base rather than duplicating it.

  2. Named Slots for Composability — Using <slot name="head" /> allows child layouts to inject content into specific areas without breaking encapsulation.

  3. 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.

  4. 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.

  5. 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)