Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions assets/slides-runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,17 @@ const slides = document.querySelectorAll('.slide');
const progress = document.getElementById('progress');
const counter = document.getElementById('counter');
const slideNav = document.getElementById('slideNav');
let current = 0;
const total = slides.length;

// Parse a one-based "#N" hash into a zero-based index, clamped to range.
function slideFromHash() {
const n = parseInt((location.hash || '').replace('#', ''), 10);
if (isNaN(n)) return 0;
return Math.min(Math.max(n, 1), total) - 1;
}

let current = slideFromHash();

slides.forEach((_, i) => {
const dot = document.createElement('div');
dot.className = 'slide-nav-dot' + (i===0?' active':'');
Expand All @@ -44,6 +52,7 @@ function goTo(index) {
const prev = current;
current = index;
slides.forEach((s,i) => s.classList.toggle('active', i===current));
history.replaceState(null, '', '#' + (current + 1));
updateUI();
showSpeakerNotes(current);

Expand Down Expand Up @@ -81,6 +90,11 @@ document.addEventListener('wheel', (e) => {
}, {passive:true});

updateUI();
// Reconcile the active class with a deep-linked "current" so the right slide shows on load.
slides.forEach((s,i) => s.classList.toggle('active', i===current));

// The "index === current" guard in goTo prevents this from looping back on its own replaceState.
window.addEventListener('hashchange', () => goTo(slideFromHash()));

// =========================================
// Chart.js Integration
Expand Down Expand Up @@ -202,10 +216,10 @@ function destroyChart(canvasId) {
}
}

// Initialize charts on first slide
// Initialize charts on the slide that loads first, which may be a deep-linked one.
if (typeof Chart !== 'undefined') {
setTimeout(() => {
slides[0].querySelectorAll('.chart-container canvas').forEach(c => createChart(c.id));
slides[current].querySelectorAll('.chart-container canvas').forEach(c => createChart(c.id));
}, 400);
}

Expand Down Expand Up @@ -247,5 +261,5 @@ function showSpeakerNotes(index) {
}
}

// Show notes for first slide on load
setTimeout(function() { showSpeakerNotes(0); }, 500);
// Show notes for the slide that loads first, which may be a deep-linked one.
setTimeout(function() { showSpeakerNotes(current); }, 500);
19 changes: 17 additions & 2 deletions references/html-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,24 @@ Every generated HTML file **must** comply with these rules:
NAVIGATION (REQUIRED — global functions)
=========================================== */
var slides = document.querySelectorAll('.slide');
var current = 0;
var total = slides.length;

// Parse a one-based "#N" hash into a zero-based index, clamped to range.
function slideFromHash() {
var n = parseInt((location.hash || '').replace('#', ''), 10);
if (isNaN(n)) return 0;
return Math.min(Math.max(n, 1), total) - 1;
}

var current = slideFromHash();

function goTo(index) {
if (index < 0 || index >= total || index === current) return;
current = index;
slides.forEach(function(s, i) {
s.classList.toggle('active', i === current);
});
history.replaceState(null, '', '#' + (current + 1));
slides[current].scrollIntoView({ behavior: 'smooth' });
updateUI();
showSpeakerNotes(current);
Expand Down Expand Up @@ -191,6 +200,11 @@ Every generated HTML file **must** comply with these rules:
}

updateUI();
// Reconcile the active class with a deep-linked "current" so the right slide shows on load.
slides.forEach(function(s, i) { s.classList.toggle('active', i === current); });

// The "index === current" guard in goTo prevents this from looping back on its own replaceState.
window.addEventListener('hashchange', function() { goTo(slideFromHash()); });

/* ===========================================
SPEAKER NOTES (Console)
Expand Down Expand Up @@ -223,7 +237,8 @@ Every generated HTML file **must** comply with these rules:
console.log('%c\u270f\ufe0f Want to update the notes? See htmlslides.com/blog/update-inline-notes.html',
'font-size:10px;color:#8b949e;');
}
setTimeout(function() { showSpeakerNotes(0); }, 500);
// Show notes for the slide that loads first, which may be a deep-linked one.
setTimeout(function() { showSpeakerNotes(current); }, 500);

/* ===========================================
OPTIONAL ENHANCEMENTS
Expand Down
4 changes: 4 additions & 0 deletions references/presentation-layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ The presentation must support:

Build navigation inline following the pattern in [html-template.md](html-template.md). Generate `goTo()`, `next()`, `prev()` as global functions, plus speaker notes console logging on each slide change.

## Deep-Linking

Slides are addressable by a one-based `#N` URL hash. Loading `#5` opens the fifth slide directly, with its charts and speaker notes rendered for that slide rather than the first. Each navigation writes the current slide back to the hash, so a reload returns to the same slide and the browser Back button steps through the slides already visited. An out-of-range or malformed hash clamps to a valid slide, and a deck opened with no hash starts on slide one.

## Generator Meta Tag

Every presentation must include in `<head>`:
Expand Down