Replace details/summary expanders with toggle buttons for list/deck forms

New list, Bulk import, New deck, and Bulk import decks are now proper
buttons. Clicking one toggles the form open (highlighted blue) and
clicking again or cancelling closes it. Only one form open at a time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 4.6 committed 2026-07-27 13:17:17 -04:00
1 parent 4613946cea
commit 2d663f6964
3 files changed
+64 -16

No files matched your search

+22 -14
View File
@@ -305,8 +305,12 @@
<div id="results-area"></div> <div id="results-area"></div>
</div> </div>
<div class="panel-col"> <div class="panel-col">
<details id="list-editor-details"> <div class="toggle-btns">
<summary id="list-editor-title">New list</summary> <button type="button" id="list-new-btn">+ New list</button>
<button type="button" id="list-bulk-btn" class="secondary">⬆ Bulk import</button>
</div>
<div id="list-editor-section" hidden>
<h3 id="list-editor-title" class="section-form-title">New list</h3>
<form id="list-form" class="admin-card"> <form id="list-form" class="admin-card">
<input type="hidden" id="list-id"> <input type="hidden" id="list-id">
<input id="list-name" placeholder="List name (e.g. Week of July 6)" aria-label="List name"> <input id="list-name" placeholder="List name (e.g. Week of July 6)" aria-label="List name">
@@ -316,12 +320,12 @@
placeholder="One word per line. Paste any list from your curriculum!&#10;&#10;Add an example sentence with |&#10;receive | Did you receive my letter?&#10;&#10;Or just a plain list:&#10;because&#10;enough&#10;friend"></textarea> placeholder="One word per line. Paste any list from your curriculum!&#10;&#10;Add an example sentence with |&#10;receive | Did you receive my letter?&#10;&#10;Or just a plain list:&#10;because&#10;enough&#10;friend"></textarea>
<div class="row-actions"> <div class="row-actions">
<button type="submit">Save list</button> <button type="submit">Save list</button>
<button type="button" id="list-cancel" class="secondary">Clear</button> <button type="button" id="list-cancel" class="secondary">Cancel</button>
</div> </div>
</form> </form>
</details> </div>
<details id="list-bulk-details"> <div id="list-bulk-section" hidden>
<summary>Bulk import lists</summary> <h3 class="section-form-title">Bulk import lists</h3>
<div class="admin-card"> <div class="admin-card">
<p class="hint" style="margin:0 0 0.5rem">Start each list with <strong># List name</strong> on its own line, then words below it. Optional group applies to all imported lists.</p> <p class="hint" style="margin:0 0 0.5rem">Start each list with <strong># List name</strong> on its own line, then words below it. Optional group applies to all imported lists.</p>
<input id="list-bulk-group" placeholder="Group (e.g. Bible 6) — optional" aria-label="Group for bulk import" list="list-groups-datalist"> <input id="list-bulk-group" placeholder="Group (e.g. Bible 6) — optional" aria-label="Group for bulk import" list="list-groups-datalist">
@@ -333,7 +337,7 @@
</div> </div>
<p id="list-bulk-status" class="hint" style="margin:0.4rem 0 0"></p> <p id="list-bulk-status" class="hint" style="margin:0.4rem 0 0"></p>
</div> </div>
</details> </div>
</div> </div>
</div> </div>
</section> </section>
@@ -346,8 +350,12 @@
<div id="deck-rows"></div> <div id="deck-rows"></div>
</div> </div>
<div class="panel-col"> <div class="panel-col">
<details id="deck-editor-details"> <div class="toggle-btns">
<summary id="deck-editor-title">New deck</summary> <button type="button" id="deck-new-btn">+ New deck</button>
<button type="button" id="deck-bulk-btn" class="secondary">⬆ Bulk import</button>
</div>
<div id="deck-editor-section" hidden>
<h3 id="deck-editor-title" class="section-form-title">New deck</h3>
<form id="deck-form" class="admin-card"> <form id="deck-form" class="admin-card">
<input type="hidden" id="deck-id"> <input type="hidden" id="deck-id">
<input id="deck-name" placeholder="Deck name (e.g. State Capitals)" aria-label="Deck name"> <input id="deck-name" placeholder="Deck name (e.g. State Capitals)" aria-label="Deck name">
@@ -357,12 +365,12 @@
placeholder="One card per line: front | back&#10;What is the capital of Ohio? | Columbus"></textarea> placeholder="One card per line: front | back&#10;What is the capital of Ohio? | Columbus"></textarea>
<div class="row-actions"> <div class="row-actions">
<button type="submit">Save deck</button> <button type="submit">Save deck</button>
<button type="button" id="deck-cancel" class="secondary">Clear</button> <button type="button" id="deck-cancel" class="secondary">Cancel</button>
</div> </div>
</form> </form>
</details> </div>
<details id="deck-bulk-details"> <div id="deck-bulk-section" hidden>
<summary>Bulk import decks</summary> <h3 class="section-form-title">Bulk import decks</h3>
<div class="admin-card"> <div class="admin-card">
<p class="hint" style="margin:0 0 0.5rem">Start each deck with <strong># Deck name</strong> on its own line, then cards below as <strong>front | back</strong>. Optional group applies to all imported decks.</p> <p class="hint" style="margin:0 0 0.5rem">Start each deck with <strong># Deck name</strong> on its own line, then cards below as <strong>front | back</strong>. Optional group applies to all imported decks.</p>
<input id="deck-bulk-group" placeholder="Group (e.g. Bible 6) — optional" aria-label="Group for bulk import" list="deck-groups-datalist"> <input id="deck-bulk-group" placeholder="Group (e.g. Bible 6) — optional" aria-label="Group for bulk import" list="deck-groups-datalist">
@@ -374,7 +382,7 @@
</div> </div>
<p id="deck-bulk-status" class="hint" style="margin:0.4rem 0 0"></p> <p id="deck-bulk-status" class="hint" style="margin:0.4rem 0 0"></p>
</div> </div>
</details> </div>
</div> </div>
</div> </div>
</section> </section>
+37 -2
View File
@@ -1368,7 +1368,7 @@ function renderLists(lists) {
return w.word; return w.word;
}).join('\n'); }).join('\n');
$('#list-editor-title').textContent = list.builtin ? 'New list (from copy)' : `Editing: ${list.name}`; $('#list-editor-title').textContent = list.builtin ? 'New list (from copy)' : `Editing: ${list.name}`;
$('#list-editor-details').open = true; showSection('list', 'editor');
$('#list-name').scrollIntoView({ behavior: 'smooth' }); $('#list-name').scrollIntoView({ behavior: 'smooth' });
}) })
); );
@@ -1398,6 +1398,7 @@ $('#list-form').addEventListener('submit', async (e) => {
if (id) await api(`/api/lists/${id}`, { method: 'PUT', body: { name, words, groupName } }); if (id) await api(`/api/lists/${id}`, { method: 'PUT', body: { name, words, groupName } });
else await api('/api/lists', { method: 'POST', body: { name, words, groupName } }); else await api('/api/lists', { method: 'POST', body: { name, words, groupName } });
clearListForm(); clearListForm();
hideSections('list');
msg('List saved.'); msg('List saved.');
loadSpelling(); loadSpelling();
}); });
@@ -1408,8 +1409,31 @@ function clearListForm() {
$('#list-group').value = ''; $('#list-group').value = '';
$('#list-words').value = ''; $('#list-words').value = '';
$('#list-editor-title').textContent = 'New list'; $('#list-editor-title').textContent = 'New list';
hideSections('list');
} }
function showSection(type, which) {
$(`#${type}-editor-section`).hidden = which !== 'editor';
$(`#${type}-bulk-section`).hidden = which !== 'bulk';
$(`#${type}-new-btn`).classList.toggle('active', which === 'editor');
$(`#${type}-bulk-btn`).classList.toggle('active', which === 'bulk');
}
function hideSections(type) {
$(`#${type}-editor-section`).hidden = true;
$(`#${type}-bulk-section`).hidden = true;
$(`#${type}-new-btn`).classList.remove('active');
$(`#${type}-bulk-btn`).classList.remove('active');
}
$('#list-new-btn').addEventListener('click', () => {
if ($('#list-editor-section').hidden) showSection('list', 'editor');
else hideSections('list');
});
$('#list-bulk-btn').addEventListener('click', () => {
if ($('#list-bulk-section').hidden) showSection('list', 'bulk');
else hideSections('list');
});
function parseBulkSections(text) { function parseBulkSections(text) {
const sections = []; const sections = [];
let current = null; let current = null;
@@ -1560,7 +1584,7 @@ async function loadDecks() {
$('#deck-group').value = deck.group_name || ''; $('#deck-group').value = deck.group_name || '';
$('#deck-cards').value = deck.cards.map((c) => `${c.front} | ${c.back}`).join('\n'); $('#deck-cards').value = deck.cards.map((c) => `${c.front} | ${c.back}`).join('\n');
$('#deck-editor-title').textContent = deck.builtin ? 'New deck (from copy)' : `Editing: ${deck.name}`; $('#deck-editor-title').textContent = deck.builtin ? 'New deck (from copy)' : `Editing: ${deck.name}`;
$('#deck-editor-details').open = true; showSection('deck', 'editor');
$('#deck-name').scrollIntoView({ behavior: 'smooth' }); $('#deck-name').scrollIntoView({ behavior: 'smooth' });
}) })
); );
@@ -1590,6 +1614,7 @@ $('#deck-form').addEventListener('submit', async (e) => {
if (id) await api(`/api/decks/${id}`, { method: 'PUT', body: { name, cards, groupName } }); if (id) await api(`/api/decks/${id}`, { method: 'PUT', body: { name, cards, groupName } });
else await api('/api/decks', { method: 'POST', body: { name, cards, groupName } }); else await api('/api/decks', { method: 'POST', body: { name, cards, groupName } });
clearDeckForm(); clearDeckForm();
hideSections('deck');
msg('Deck saved.'); msg('Deck saved.');
loadDecks(); loadDecks();
}); });
@@ -1600,8 +1625,18 @@ function clearDeckForm() {
$('#deck-group').value = ''; $('#deck-group').value = '';
$('#deck-cards').value = ''; $('#deck-cards').value = '';
$('#deck-editor-title').textContent = 'New deck'; $('#deck-editor-title').textContent = 'New deck';
hideSections('deck');
} }
$('#deck-new-btn').addEventListener('click', () => {
if ($('#deck-editor-section').hidden) showSection('deck', 'editor');
else hideSections('deck');
});
$('#deck-bulk-btn').addEventListener('click', () => {
if ($('#deck-bulk-section').hidden) showSection('deck', 'bulk');
else hideSections('deck');
});
$('#deck-bulk-save').addEventListener('click', async () => { $('#deck-bulk-save').addEventListener('click', async () => {
const groupName = $('#deck-bulk-group').value.trim(); const groupName = $('#deck-bulk-group').value.trim();
const sections = parseBulkSections($('#deck-bulk-text').value); const sections = parseBulkSections($('#deck-bulk-text').value);
+5
View File
@@ -338,6 +338,11 @@ table.results tr:nth-child(even) td { background: #faf7ee; }
.admin-main h2 { margin: 1.5rem 0 0.5rem; font-size: 1.15rem; } .admin-main h2 { margin: 1.5rem 0 0.5rem; font-size: 1.15rem; }
.panel { text-align: left; } .panel { text-align: left; }
/* ---------- toggle button rows (new/bulk import) ---------- */
.toggle-btns { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.75rem; }
.toggle-btns button.active { background: var(--accent); color: #fff; }
.section-form-title { font-size: 1rem; font-weight: 700; margin: 0 0 0; color: var(--ink); }
/* 2-column layout for wide screens */ /* 2-column layout for wide screens */
.panel-cols { display: flex; flex-direction: column; gap: 1.5rem; } .panel-cols { display: flex; flex-direction: column; gap: 1.5rem; }
.panel-col { min-width: 0; } .panel-col { min-width: 0; }