Include tableofcontents

--
This commit is contained in:
Andre Heinecke 2025-06-09 21:52:14 +02:00
parent 0091129557
commit 295a380933
No known key found for this signature in database
GPG Key ID: 2978E9D40CBABA5C
3 changed files with 358 additions and 170 deletions

View File

@ -29,6 +29,7 @@ $(STAGING_DIR)/%.html: $(SRC_DIR)/%.md $(TEMPLATE) | $(STAGING_DIR)
--template=$(TEMPLATE) \
--standalone \
--css=css/style.css \
--toc \
--output=$@ \
$<

View File

@ -13,7 +13,7 @@
<div class="container">
<div class="header-content">
<div class="logo">
<h1>ΞSUS</h1>
<a href="index.html"><h1>ΞSUS</h1></a>
</div>
<nav class="main-nav">
<a href="index.html#about">About</a>
@ -27,20 +27,20 @@
</div>
</div>
</header>
<div class="page_layout">
<div id="page-layout">
<aside id="toc-wrapper" class="toc hidden collapsed">
<button id="toc-toggle" aria-label="Toggle Table of Contents">☰Table of Contents</button>
<div class="toc-inner toc-toggle">
<h2>Contents</h2>
<button id="toc-toggle" aria-label="Toggle Table of Contents">☰ Table of Contents</button>
<div class="toc-inner">
$toc$
</div>
</aside>
</div>
<main class="main-content">
<div class="container">
$body$
</div>
</main>
</div>
<footer class="site-footer">
<div class="container">
<p>ΞSUS Project - Open Source Philosophy for Human and AI Consciousness</p>
@ -71,17 +71,88 @@
const tocWrapper = document.getElementById("toc-wrapper");
const tocListItems = tocWrapper?.querySelectorAll("li") ?? [];
const toggleBtn = document.getElementById("toc-toggle");
const toggleBtn2 = document.getElementById("toc-toggle-off");
// Show TOC if it has 5 or more items
if (tocListItems.length >= 5) {
tocWrapper.classList.remove("hidden");
// On mobile/tablet, start collapsed
if (window.innerWidth < 1200) {
tocWrapper.classList.add("collapsed");
} else {
// On desktop, start expanded
tocWrapper.classList.remove("collapsed");
}
}
// Toggle button functionality
toggleBtn?.addEventListener("click", () => {
tocWrapper.classList.toggle("collapsed");
// Update button text
if (tocWrapper.classList.contains("collapsed")) {
toggleBtn.textContent = "☰ Table of Contents";
} else {
toggleBtn.textContent = "✕ Table of Contents";
}
});
toggleBtn2.addEventListener("click", () => {
tocWrapper.classList.toggle("collapsed");
// Handle window resize
let resizeTimer;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
if (window.innerWidth < 1200 && !tocWrapper.classList.contains('collapsed')) {
tocWrapper.classList.add('collapsed');
toggleBtn.textContent = "☰ Table of Contents";
}
}, 250);
});
// Smooth scroll to anchors
tocWrapper?.addEventListener('click', (e) => {
if (e.target.tagName === 'A' && e.target.getAttribute('href')?.startsWith('#')) {
e.preventDefault();
const targetId = e.target.getAttribute('href').substring(1);
const targetElement = document.getElementById(targetId);
if (targetElement) {
targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
// On mobile, collapse TOC after clicking
if (window.innerWidth < 1200) {
tocWrapper.classList.add('collapsed');
toggleBtn.textContent = "☰ Table of Contents";
}
}
}
});
// Highlight current section in TOC
const observerOptions = {
rootMargin: '-10% 0px -70% 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const id = entry.target.getAttribute('id');
if (id) {
// Remove all active classes
tocWrapper?.querySelectorAll('a').forEach(a => {
a.classList.remove('active');
});
// Add active class to current section
const activeLink = tocWrapper?.querySelector(`a[href="#${id}"]`);
if (activeLink) {
activeLink.classList.add('active');
}
}
}
});
}, observerOptions);
// Observe all headings with IDs
document.querySelectorAll('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').forEach(heading => {
observer.observe(heading);
});
});
</script>

View File

@ -18,6 +18,8 @@
--max-width: 1200px;
--content-width: 800px;
--toc-min-width: 250px;
--toc-max-width: 400px;
}
* {
@ -26,6 +28,11 @@
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
scroll-padding-top: 80px; /* Account for sticky header */
}
body {
font-family: var(--font-family);
line-height: 1.6;
@ -46,7 +53,7 @@ body {
padding: 1rem 0;
position: sticky;
top: 0;
z-index: 100;
z-index: 1000;
}
.header-content {
@ -88,6 +95,10 @@ body {
color: var(--accent-color);
}
.translate-button {
margin-left: auto;
}
/* Hero Section */
.hero {
text-align: center;
@ -117,11 +128,245 @@ body {
margin: 0 auto;
}
/* Main Content */
.main-content {
/* Page Layout with TOC */
#page-layout {
position: relative;
padding: 0;
width: 100%;
}
/* Table of Contents */
.toc {
background: var(--background);
border: 1px solid var(--border-color);
border-radius: 8px;
transition: all 0.3s ease;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.toc:not(.collapsed) {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
}
.toc.hidden {
display: none !important;
}
#toc-toggle {
width: 100%;
padding: 0.75rem 1rem;
background: var(--background-light);
border: none;
border-bottom: 1px solid var(--border-color);
cursor: pointer;
text-align: left;
font-weight: 600;
color: var(--primary-color);
transition: background-color 0.2s ease;
border-radius: 8px 8px 0 0;
}
#toc-toggle:hover {
background: var(--border-color);
}
.toc.collapsed #toc-toggle {
border-bottom: none;
border-radius: 8px;
}
.toc-inner {
padding: 1rem;
max-height: calc(100vh - 200px);
overflow-y: auto;
}
/* Responsive TOC font sizing */
@media (min-width: 1200px) and (max-width: 1399px) {
.toc {
font-size: 0.95rem;
}
.toc-inner {
padding: 0.75rem;
}
}
@media (min-width: 1600px) {
.toc-inner {
padding: 1.5rem;
}
.toc a {
font-size: 1.05rem;
padding: 0.3rem 0;
}
}
@media (min-width: 2000px) {
.toc-inner {
padding: 2rem;
}
.toc a {
font-size: 1.1rem;
padding: 0.35rem 0;
}
}
.toc.collapsed .toc-inner {
display: none;
}
/* Custom scrollbar for TOC */
.toc-inner::-webkit-scrollbar {
width: 6px;
}
.toc-inner::-webkit-scrollbar-track {
background: var(--background-light);
border-radius: 3px;
}
.toc-inner::-webkit-scrollbar-thumb {
background: var(--border-color);
border-radius: 3px;
}
.toc-inner::-webkit-scrollbar-thumb:hover {
background: var(--text-light);
}
/* TOC List Styling */
.toc ul {
list-style: none;
margin: 0;
padding: 0;
}
.toc ul ul {
margin-left: 1.5rem;
}
.toc li {
margin-bottom: 0.5rem;
}
.toc a {
color: var(--text-color);
text-decoration: none;
display: block;
padding: 0.25rem 0;
transition: color 0.2s ease;
}
.toc a:hover {
color: var(--accent-color);
}
.toc a.active {
color: var(--accent-color);
font-weight: 600;
border-left: 3px solid var(--accent-color);
padding-left: 0.5rem;
margin-left: -0.5rem;
}
/* Desktop Layout - TOC to the left of centered content */
@media (min-width: 1200px) {
#page-layout {
display: grid;
grid-template-columns: 1fr var(--content-width) 1fr;
gap: 0;
padding: 3rem 0;
min-height: calc(100vh - 200px);
}
.toc {
grid-column: 1;
justify-self: end;
margin-right: 2rem;
position: sticky;
top: 100px;
align-self: start;
width: 100%;
max-width: var(--toc-max-width);
min-width: var(--toc-min-width);
height: fit-content;
max-height: calc(100vh - 150px);
}
.main-content {
grid-column: 2;
width: 100%;
max-width: var(--content-width);
padding: 0 2rem;
}
/* Calculate TOC width based on available space */
@media (min-width: 1400px) {
.toc {
width: calc(100% - 2rem);
}
}
}
/* Extra wide screens - allow TOC to grow even more */
@media (min-width: 1600px) {
#page-layout {
grid-template-columns: minmax(auto, 1fr) var(--content-width) minmax(auto, 1fr);
}
.toc {
max-width: min(500px, calc(100% - 2rem));
}
}
/* Ultra-wide screens */
@media (min-width: 2000px) {
.toc {
max-width: min(600px, calc(100% - 2rem));
}
}
/* Tablet/Mobile Layout - TOC above content */
@media (max-width: 1199px) {
#page-layout {
display: block;
padding: 2rem 0;
}
.toc {
margin: 0 auto 2rem;
max-width: var(--content-width);
width: calc(100% - 4rem);
position: static;
}
.toc.collapsed {
margin-bottom: 2rem;
}
.main-content {
max-width: var(--content-width);
margin: 0 auto;
padding: 3rem 2rem;
padding: 0 2rem;
}
}
/* Main Content */
.main-content {
width: 100%;
}
/* Ensure proper spacing on all screen sizes */
.main-content > *:first-child {
margin-top: 0;
}
.main-content > *:last-child {
margin-bottom: 0;
}
h1, h2, h3, h4, h5, h6 {
@ -290,7 +535,7 @@ code {
}
.main-content {
padding: 2rem 1rem;
padding: 0 1rem;
}
.resource-grid {
@ -301,6 +546,14 @@ code {
padding: 1.5rem;
font-size: 1.2rem;
}
.toc {
width: calc(100% - 2rem);
}
.toc a {
font-size: 0.95rem;
}
}
@media (max-width: 480px) {
@ -332,8 +585,14 @@ button:focus {
/* Print styles */
@media print {
.site-header,
.site-footer {
display: none;
.site-footer,
.toc {
display: none !important;
}
#page-layout {
display: block !important;
padding: 0 !important;
}
.main-content {
@ -429,7 +688,7 @@ button:focus {
.human-voice h4,
.ai-claude-voice h4,
.ai-chatgpt-voice h4 {
margin-top: 1rem;
margin-top: 1.5rem;
margin-bottom: 0.75rem;
}
@ -439,7 +698,7 @@ button:focus {
.ai-claude-voice,
.ai-chatgpt-voice {
padding: 1.5rem;
margin: 1rem 0;
margin: 1.5rem 0;
}
.human-voice::before,
@ -449,146 +708,3 @@ button:focus {
left: 15px;
}
}
/* Print styles */
@media print {
.site-header,
.site-footer {
display: none;
}
.main-content {
max-width: none;
margin: 0;
padding: 0;
}
a {
color: var(--text-color);
text-decoration: underline;
}
.resource-card {
border: 1px solid var(--border-color);
break-inside: avoid;
}
.human-voice,
.ai-claude-voice,
.ai-chatgpt-voice {
background: none !important;
border: 1px solid var(--border-color) !important;
break-inside: avoid;
}
.human-voice::before,
.ai-claude-voice::before,
.ai-chatgpt-voice::before {
color: black !important;
}
}
/* TOC layout container */
.page-layout {
display: flex;
gap: 2rem;
align-items: flex-start;
position: relative;
}
/* Sidebar TOC */
#toc-wrapper {
flex: 0 0 240px;
background: var(--background-light);
border-right: 2px solid var(--border-color);
padding: 1rem;
max-height: calc(100vh - 80px);
overflow-y: auto;
position: sticky;
top: 80px;
transition: transform 0.3s ease, width 0.3s ease;
z-index: 10;
}
/* Inner ToC content (for collapsing) */
.toc-inner {
display: block;
}
/* TOC toggle button */
#toc-toggle {
background: none;
border: none;
font-size: 1.2rem;
cursor: pointer;
margin-bottom: 1rem;
display: block;
}
/* Collapsed mode */
#toc-wrapper.collapsed .toc-inner {
display: none;
}
#toc-wrapper.collapsed {
width: auto;
padding: 0.5rem;
}
#toc-wrapper.collapsed #toc-toggle {
display: block;
}
#toc-wrapper h2 {
font-size: 1.1rem;
margin-bottom: 0.5rem;
}
#toc-wrapper ul {
list-style: none;
padding-left: 0;
font-size: 0.9rem;
}
#toc-wrapper li {
margin: 0.5rem 0;
}
#toc-wrapper a {
color: var(--text-color);
text-decoration: none;
}
#toc-wrapper a:hover {
text-decoration: underline;
}
/* Content */
.content-area {
flex: 1;
min-width: 0;
}
/* Hide on mobile */
@media (max-width: 768px) {
.page-layout {
flex-direction: column;
}
#toc-wrapper {
position: relative;
top: unset;
border-right: none;
border-bottom: 2px solid var(--border-color);
width: 100%;
max-height: none;
}
#toc-toggle {
display: block;
}
#toc-wrapper.collapsed {
padding: 0.5rem;
}
}