feat: reading-mode toggle for long research papers

Three density modes: Overview (~3 min), Standard (~12 min), Deep (~25 min).
Applied to researcher.html — 7 sections tagged with data-reading-level.
Persists user preference in localStorage. Auto-injects toggle UI.
Reusable component for architectural-alignment papers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
TheFlow 2026-04-17 07:15:44 +12:00
parent 2909ab98fe
commit 240cc7d3a9
3 changed files with 179 additions and 7 deletions

View file

@ -0,0 +1,54 @@
.reading-mode-toggle {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1.5rem;
margin: 1rem auto 2rem;
max-width: 900px;
background: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 0.5rem;
font-size: 0.875rem;
}
.reading-mode-label {
color: #64748b;
font-weight: 500;
margin-right: 0.25rem;
}
.reading-mode-btn {
padding: 0.375rem 0.75rem;
border: 1px solid #cbd5e1;
border-radius: 0.375rem;
background: white;
color: #475569;
cursor: pointer;
font-size: 0.8rem;
font-weight: 500;
transition: all 0.2s;
}
.reading-mode-btn:hover {
background: #f1f5f9;
border-color: #94a3b8;
}
.reading-mode-btn.active {
background: #1e40af;
color: white;
border-color: #1e40af;
}
.reading-mode-estimate {
margin-left: auto;
color: #94a3b8;
font-size: 0.8rem;
}
@media (max-width: 640px) {
.reading-mode-toggle {
flex-wrap: wrap;
padding: 0.5rem 1rem;
}
}

114
public/js/reading-mode.js Normal file
View file

@ -0,0 +1,114 @@
/**
* Reading Mode Toggle
* Provides overview/standard/deep density modes for long research papers.
*
* Usage: Add data-reading-level="overview|standard|deep" to content sections.
* Sections without the attribute are always visible.
*
* The toggle is auto-injected at the top of any page that includes this script
* and has elements with data-reading-level attributes.
*/
(function() {
'use strict';
var STORAGE_KEY = 'tractatus-reading-mode';
var MODES = ['overview', 'standard', 'deep'];
var MODE_LABELS = {
overview: { label: 'Overview', desc: 'Key points only' },
standard: { label: 'Standard', desc: 'Main content' },
deep: { label: 'Deep', desc: 'Full detail' }
};
function init() {
// Only activate if page has reading-level content
var leveledContent = document.querySelectorAll('[data-reading-level]');
if (leveledContent.length === 0) return;
var savedMode = localStorage.getItem(STORAGE_KEY) || 'standard';
// Inject toggle UI after the first h1 or at the top of main content
var heroOrH1 = document.querySelector('.hero-section, .page-hero, h1');
var insertPoint = (heroOrH1 && heroOrH1.parentElement)
|| document.querySelector('main')
|| document.body;
var toggle = document.createElement('div');
toggle.className = 'reading-mode-toggle';
toggle.setAttribute('role', 'radiogroup');
toggle.setAttribute('aria-label', 'Reading depth');
toggle.innerHTML = '<span class="reading-mode-label">Reading depth:</span>' +
MODES.map(function(mode) {
return '<button class="reading-mode-btn ' + (mode === savedMode ? 'active' : '') + '" ' +
'data-mode="' + mode + '" ' +
'role="radio" ' +
'aria-checked="' + (mode === savedMode) + '" ' +
'title="' + MODE_LABELS[mode].desc + '">' +
MODE_LABELS[mode].label +
'</button>';
}).join('') +
'<span class="reading-mode-estimate"></span>';
// Insert after the hero/h1 section
if (insertPoint.nextSibling) {
insertPoint.parentNode.insertBefore(toggle, insertPoint.nextSibling);
} else {
insertPoint.parentNode.appendChild(toggle);
}
// Apply initial mode
applyMode(savedMode);
// Handle clicks
toggle.addEventListener('click', function(e) {
var btn = e.target.closest('.reading-mode-btn');
if (!btn) return;
var mode = btn.dataset.mode;
localStorage.setItem(STORAGE_KEY, mode);
// Update button states
var buttons = toggle.querySelectorAll('.reading-mode-btn');
for (var i = 0; i < buttons.length; i++) {
var b = buttons[i];
if (b.dataset.mode === mode) {
b.classList.add('active');
b.setAttribute('aria-checked', 'true');
} else {
b.classList.remove('active');
b.setAttribute('aria-checked', 'false');
}
}
applyMode(mode);
});
}
function applyMode(mode) {
var elements = document.querySelectorAll('[data-reading-level]');
var modeIndex = MODES.indexOf(mode);
for (var i = 0; i < elements.length; i++) {
var el = elements[i];
var level = el.dataset.readingLevel;
var levelIndex = MODES.indexOf(level);
// overview shows only overview; standard shows overview+standard; deep shows all
var visible = levelIndex <= modeIndex;
el.style.display = visible ? '' : 'none';
el.setAttribute('aria-hidden', !visible);
}
// Update reading time estimate if present
var counter = document.querySelector('.reading-mode-estimate');
if (counter) {
var labels = { overview: '~3 min read', standard: '~12 min read', deep: '~25 min read' };
counter.textContent = labels[mode] || '';
}
}
// Init on DOM ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();

View file

@ -38,6 +38,7 @@
<link rel="stylesheet" href="/css/fonts.css?v=0.1.2.1776331424881">
<link rel="stylesheet" href="/css/tailwind.css?v=0.1.2.1776331424881">
<link rel="stylesheet" href="/css/tractatus-theme.min.css?v=0.1.2.1776331424881">
<link rel="stylesheet" href="/css/reading-mode.css?v=0.1.2">
<style>
.skip-link { position: absolute; left: -9999px; }
.skip-link:focus { left: 0; z-index: 100; background: white; padding: 1rem; }
@ -148,7 +149,7 @@
</section>
<!-- Current Research: Distributive Equity Through Structure (April 2026) -->
<section class="mb-16 bg-gradient-to-br from-indigo-50 to-purple-50 border-2 border-indigo-200 rounded-xl p-8 animate-on-scroll" data-animation="fade-in">
<section class="mb-16 bg-gradient-to-br from-indigo-50 to-purple-50 border-2 border-indigo-200 rounded-xl p-8 animate-on-scroll" data-animation="fade-in" data-reading-level="overview">
<div class="flex items-start gap-4 mb-4">
<div class="flex-shrink-0">
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-indigo-600 to-purple-600 text-white flex items-center justify-center">
@ -181,7 +182,7 @@
</section>
<!-- Alexander Integration (October 2025) -->
<section class="mb-16 bg-blue-50 border-2 border-blue-200 rounded-xl p-8 animate-on-scroll" data-animation="fade-in">
<section class="mb-16 bg-blue-50 border-2 border-blue-200 rounded-xl p-8 animate-on-scroll" data-animation="fade-in" data-reading-level="standard">
<div class="flex items-start gap-4 mb-4">
<div class="flex-shrink-0">
<div class="w-12 h-12 rounded-full bg-blue-600 text-white flex items-center justify-center">
@ -255,7 +256,7 @@
</section>
<!-- Steering Vectors & Mechanical Bias Research (STO-RES-0009) -->
<section class="mb-16 bg-gradient-to-br from-emerald-50 to-teal-50 border-2 border-emerald-200 rounded-xl p-8 animate-on-scroll" data-animation="fade-in">
<section class="mb-16 bg-gradient-to-br from-emerald-50 to-teal-50 border-2 border-emerald-200 rounded-xl p-8 animate-on-scroll" data-animation="fade-in" data-reading-level="deep">
<div class="flex items-start gap-4 mb-4">
<div class="flex-shrink-0">
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-emerald-600 to-teal-600 text-white flex items-center justify-center">
@ -302,7 +303,7 @@
</section>
<!-- Taonga-Centred Steering Governance (STO-RES-0010) -->
<section class="mb-16 bg-gradient-to-br from-amber-50 to-orange-50 border-2 border-amber-200 rounded-xl p-8 animate-on-scroll" data-animation="fade-in">
<section class="mb-16 bg-gradient-to-br from-amber-50 to-orange-50 border-2 border-amber-200 rounded-xl p-8 animate-on-scroll" data-animation="fade-in" data-reading-level="deep">
<div class="flex items-start gap-4 mb-4">
<div class="flex-shrink-0">
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-amber-600 to-orange-600 text-white flex items-center justify-center">
@ -353,7 +354,7 @@
</section>
<!-- Village AI: Sovereign Governance Research Platform -->
<section class="mb-16 bg-gradient-to-br from-sky-50 to-blue-50 border-2 border-sky-200 rounded-xl p-8 animate-on-scroll" data-animation="fade-in">
<section class="mb-16 bg-gradient-to-br from-sky-50 to-blue-50 border-2 border-sky-200 rounded-xl p-8 animate-on-scroll" data-animation="fade-in" data-reading-level="standard">
<div class="flex items-start gap-4 mb-4">
<div class="flex-shrink-0">
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-sky-600 to-blue-600 text-white flex items-center justify-center">
@ -908,7 +909,7 @@
</section>
<!-- Agent Lightning Integration: Research Perspective -->
<section class="mb-16 bg-gradient-to-br from-purple-50 to-blue-50 border-2 border-purple-200 rounded-xl p-8">
<section class="mb-16 bg-gradient-to-br from-purple-50 to-blue-50 border-2 border-purple-200 rounded-xl p-8" data-reading-level="deep">
<div class="flex items-start gap-4 mb-6">
<div class="flex-shrink-0">
<div class="w-14 h-14 rounded-full bg-gradient-to-br from-purple-600 to-indigo-600 text-white flex items-center justify-center">
@ -1271,7 +1272,7 @@
</section>
<!-- Research Collaboration Opportunities -->
<section class="mb-16">
<section class="mb-16" data-reading-level="standard">
<h2 class="text-2xl font-bold text-gray-900 mb-6" data-i18n="sections.research_collaboration.heading">Research Collaboration Opportunities</h2>
<div class="bg-blue-50 border-l-4 border-blue-600 p-6 rounded-r-lg mb-8">
@ -1794,5 +1795,8 @@
<!-- Newsletter Subscription Modal -->
<script src="/js/components/newsletter.js?v=0.1.2.1776331424881"></script>
<!-- Reading Mode Toggle -->
<script src="/js/reading-mode.js?v=0.1.2" defer></script>
</body>
</html>