Add speech button to sticky breadcrumb actions

- Click 🔊 to read page content aloud
- Button changes to ⏹ while speaking
- Click again to stop
- Strips out navigation, buttons, and other non-content elements

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-03 14:38:31 -05:00
parent 8ffd60db2a
commit 953ceb4ff4
2 changed files with 61 additions and 0 deletions
+51
View File
@@ -37,6 +37,57 @@ function changeFontSize(direction) {
}
}
// Page speech toggle (for breadcrumb button)
function togglePageSpeech() {
var btn = document.getElementById('speech-toggle-btn');
if (!btn || !('speechSynthesis' in window)) return;
// If speaking, stop
if (speechSynthesis.speaking || speechSynthesis.pending) {
speechSynthesis.cancel();
btn.classList.remove('speaking');
return;
}
// Get page content to read
var article = document.querySelector('article');
if (!article) return;
var clone = article.cloneNode(true);
// Remove elements we don't want to read
clone.querySelectorAll('.breadcrumb, .sidenote, .marginnote, .toc, script, style, nav, .chapter-nav, .verse-nav, button, .breadcrumb-actions').forEach(function(el) {
el.remove();
});
var text = (clone.textContent || clone.innerText || '').trim();
if (!text) return;
var utterance = new SpeechSynthesisUtterance(text);
utterance.rate = 0.9;
// Try to use a good English voice
var voices = speechSynthesis.getVoices();
var englishVoice = voices.find(function(v) {
return v.lang && v.lang.startsWith('en') && v.name.includes('Daniel');
}) || voices.find(function(v) {
return v.lang && v.lang.startsWith('en-GB');
}) || voices.find(function(v) {
return v.lang && v.lang.startsWith('en');
});
if (englishVoice) utterance.voice = englishVoice;
btn.classList.add('speaking');
utterance.onend = function() {
btn.classList.remove('speaking');
};
utterance.onerror = function() {
btn.classList.remove('speaking');
};
speechSynthesis.speak(utterance);
}
// Red letter toggle functionality
(function() {
// Check for saved red letter preference or default to enabled
+10
View File
@@ -420,6 +420,15 @@
content: '☾';
}
.breadcrumb-action-btn.speech-toggle::before {
content: '🔊';
font-size: 0.75rem;
}
.breadcrumb-action-btn.speech-toggle.speaking::before {
content: '⏹';
}
/* Font size scale classes */
[data-font-size="small"] article {
font-size: 0.9rem;
@@ -1446,6 +1455,7 @@
<span class="breadcrumb-actions">
<button class="breadcrumb-action-btn font-decrease" title="Decrease font size" onclick="changeFontSize(-1)" aria-label="Decrease font size">A</button>
<button class="breadcrumb-action-btn font-increase" title="Increase font size" onclick="changeFontSize(1)" aria-label="Increase font size">A</button>
<button class="breadcrumb-action-btn speech-toggle" id="speech-toggle-btn" title="Read aloud" onclick="togglePageSpeech()" aria-label="Read page aloud"></button>
<button class="breadcrumb-action-btn dark-toggle" title="Toggle dark mode" onclick="toggleDarkMode()" aria-label="Toggle dark mode"></button>
</span>
{% for crumb in breadcrumbs %}