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:
parent
2909ab98fe
commit
240cc7d3a9
3 changed files with 179 additions and 7 deletions
54
public/css/reading-mode.css
Normal file
54
public/css/reading-mode.css
Normal 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
114
public/js/reading-mode.js
Normal 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();
|
||||
}
|
||||
})();
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue