feat(changelog): make release sections collapsible

Add toggle buttons for changelog sections with item counts and chevrons
Style expanded states and responsive layout for the new controls
This commit is contained in:
2026-03-23 14:48:46 +01:00
parent 6f291d050f
commit eed12be06d
+129
View File
@@ -837,6 +837,63 @@ import BaseLayout from '../layouts/BaseLayout.astro';
</main> </main>
</BaseLayout> </BaseLayout>
<script is:inline>
const changelogSections = document.querySelectorAll('.changes-section');
changelogSections.forEach((section, index) => {
const title = section.querySelector('.changes-title');
const list = section.querySelector('.changes-list');
if (!(title instanceof HTMLElement) || !(list instanceof HTMLElement)) {
return;
}
const itemCount = list.querySelectorAll(':scope > li').length;
const listId = `changes-list-${index + 1}`;
const toggle = document.createElement('button');
const titleContent = document.createElement('span');
const meta = document.createElement('span');
const count = document.createElement('span');
const chevron = document.createElement('span');
toggle.type = 'button';
toggle.className = 'changes-title changes-toggle';
toggle.setAttribute('aria-expanded', 'false');
toggle.setAttribute('aria-controls', listId);
titleContent.className = 'changes-toggle-main';
while (title.firstChild) {
titleContent.appendChild(title.firstChild);
}
meta.className = 'changes-toggle-meta';
count.className = 'changes-count';
count.textContent = `(${itemCount})`;
chevron.className = 'changes-chevron';
chevron.setAttribute('aria-hidden', 'true');
chevron.textContent = '+';
meta.append(count, chevron);
toggle.append(titleContent, meta);
list.id = listId;
list.hidden = true;
toggle.addEventListener('click', () => {
const isExpanded = toggle.getAttribute('aria-expanded') === 'true';
const nextExpanded = !isExpanded;
toggle.setAttribute('aria-expanded', String(nextExpanded));
list.hidden = !nextExpanded;
section.classList.toggle('changes-section-open', nextExpanded);
chevron.textContent = nextExpanded ? '' : '+';
});
title.replaceWith(toggle);
});
</script>
<style> <style>
/* Changelog Page Specific Styles */ /* Changelog Page Specific Styles */
@@ -1020,6 +1077,11 @@ import BaseLayout from '../layouts/BaseLayout.astro';
background: var(--color-bg); background: var(--color-bg);
border: 1px solid var(--color-border); border: 1px solid var(--color-border);
padding: var(--space-md); padding: var(--space-md);
transition: border-color 0.2s ease, background-color 0.2s ease;
}
.changes-section-open {
border-color: var(--color-accent);
} }
.version-latest .changes-section { .version-latest .changes-section {
@@ -1128,6 +1190,59 @@ import BaseLayout from '../layouts/BaseLayout.astro';
font-family: var(--font-mono); font-family: var(--font-mono);
letter-spacing: 0.05em; letter-spacing: 0.05em;
} }
.changes-toggle {
width: 100%;
justify-content: space-between;
margin-bottom: 0;
padding: 0;
border: none;
background: none;
cursor: pointer;
text-align: left;
color: var(--color-accent);
}
.changes-toggle:hover {
color: var(--color-text);
}
.changes-toggle:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 4px;
}
.changes-toggle-main {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
min-width: 0;
}
.changes-toggle-meta {
display: inline-flex;
align-items: center;
gap: var(--space-sm);
margin-left: var(--space-md);
flex-shrink: 0;
}
.changes-count {
color: var(--color-text-secondary);
font-size: 0.85rem;
}
.changes-chevron {
display: inline-flex;
align-items: center;
justify-content: center;
width: 1.25rem;
height: 1.25rem;
border: 1px solid currentColor;
border-radius: 999px;
font-size: 0.85rem;
line-height: 1;
}
.changes-icon { .changes-icon {
font-size: 1rem; font-size: 1rem;
@@ -1135,6 +1250,7 @@ import BaseLayout from '../layouts/BaseLayout.astro';
.changes-list { .changes-list {
list-style: none; list-style: none;
margin-top: var(--space-sm);
} }
.changes-list li { .changes-list li {
@@ -1212,6 +1328,19 @@ import BaseLayout from '../layouts/BaseLayout.astro';
.version-number { .version-number {
font-size: 1.75rem; font-size: 1.75rem;
} }
.changes-toggle {
align-items: flex-start;
gap: var(--space-sm);
}
.changes-toggle-main {
flex: 1;
}
.changes-toggle-meta {
margin-left: 0;
}
} }
/* Screenshot Showcase */ /* Screenshot Showcase */