Files
homeschool/public/admin.html
T
nmemmertandClaude Sonnet 4.6 2d663f6964 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>
2026-07-27 13:17:17 -04:00

443 lines
22 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Parent Dashboard</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<section id="pin-gate" class="view parent">
<h1>👩‍🏫 Parent Dashboard</h1>
<form id="pin-form">
<input id="pin-input" type="password" inputmode="numeric" placeholder="Enter PIN" aria-label="Parent PIN">
<button type="submit">Unlock</button>
</form>
<p id="pin-error" class="error" hidden>Wrong PIN, try again.</p>
<p class="hint">Default PIN is 1234 — change it in Settings after unlocking.</p>
<p><a class="link-btn" href="index.html">← Back to kid picker</a></p>
</section>
<div id="console" hidden>
<header class="admin-header">
<a href="index.html" class="admin-logo">🎓 Homeschool</a>
<nav class="admin-nav">
<button class="nav-pill active" data-panel="kids">🧒 Kids</button>
<button class="nav-pill" data-panel="courses">📚 Courses</button>
<button class="nav-pill" data-panel="planner">🗓️ Planner</button>
<button class="nav-pill" data-panel="grading">✅ Grading</button>
<button class="nav-pill" data-panel="gradebook">📊 Gradebook</button>
<button class="nav-pill" data-panel="spelling">✏️ Spelling</button>
<button class="nav-pill" data-panel="decks">🗂️ Flashcards</button>
<button class="nav-pill" data-panel="settings">⚙️ Settings</button>
</nav>
</header>
<main class="admin-main">
<!-- Kids -->
<section id="panel-kids" class="panel">
<h1>Kids</h1>
<div class="panel-cols">
<div class="panel-col">
<div id="student-rows"></div>
</div>
<div class="panel-col">
<div class="admin-card">
<h2 style="margin:0 0 0.75rem">Add a kid</h2>
<form id="add-student-form" class="inline-form" style="flex-direction:column">
<input id="new-student-name" placeholder="Name" aria-label="New kid name">
<select id="new-student-emoji" aria-label="Avatar">
<option>🦊</option><option>🐸</option><option>🦄</option><option>🐯</option>
<option>🐼</option><option>🦖</option><option>🐙</option><option>🦉</option>
<option>🐻</option><option>🐰</option><option>🦁</option><option>🐶</option>
</select>
<button type="submit">Add kid</button>
</form>
</div>
</div>
</div>
</section>
<!-- Courses list -->
<section id="panel-courses" class="panel">
<h1>Courses</h1>
<div class="panel-cols">
<div class="panel-col">
<div id="course-rows"></div>
</div>
<div class="panel-col">
<div class="admin-card">
<h2 style="margin:0 0 0.75rem">Add a course</h2>
<form id="add-course-form" class="inline-form" style="flex-direction:column">
<input id="new-course-name" placeholder="Course name (e.g. Science 3)" aria-label="Course name">
<input id="new-course-subject" placeholder="Subject" aria-label="Subject">
<input id="new-course-color" type="color" value="#4f86f7" aria-label="Color">
<button type="submit">Add course</button>
</form>
</div>
</div>
</div>
</section>
<!-- Course detail (units + items + roster) -->
<section id="panel-course-detail" class="panel" hidden>
<button class="back-btn" data-nav="courses">← All courses</button>
<h1 id="cd-name"></h1>
<div class="admin-card">
<h2>Course info</h2>
<form id="course-meta-form" class="inline-form">
<input id="cd-name-input" placeholder="Course name">
<input id="cd-subject-input" placeholder="Subject">
<input id="cd-color-input" type="color">
<label class="checkbox-label"><input type="checkbox" id="cd-archived"> Archived</label>
<button type="submit">Save</button>
<button type="button" id="cd-duplicate" class="secondary">Duplicate course</button>
<button type="button" id="cd-delete" class="danger">Delete course</button>
</form>
</div>
<div class="admin-card">
<h2>Roster</h2>
<div id="cd-roster"></div>
</div>
<div class="admin-card">
<h2>Units &amp; content <button type="button" id="cd-print" class="secondary small" style="float:right">🖨 Print course</button></h2>
<div id="cd-units"></div>
<form id="add-unit-form" class="inline-form">
<input id="new-unit-name" placeholder="Unit name (e.g. Week 1: Weather)" aria-label="Unit name">
<button type="submit">Add unit</button>
</form>
</div>
</section>
<!-- Item editor (lesson / assignment / quiz / spelling / flashcards) -->
<section id="panel-item-editor" class="panel" hidden>
<button class="back-btn" data-nav="course-detail">← Back to course</button>
<h1 id="ie-heading">New item</h1>
<form id="item-form" class="admin-card">
<input type="hidden" id="ie-id">
<input type="hidden" id="ie-unit-id">
<label>Type
<select id="ie-type">
<option value="lesson">📖 Lesson</option>
<option value="assignment">📝 Assignment</option>
<option value="quiz">❓ Quiz</option>
<option value="spelling_practice">✏️ Spelling Practice</option>
<option value="spelling_test">⭐ Spelling Test</option>
<option value="flashcards">🗂️ Flashcards</option>
</select>
</label>
<label>Title <input id="ie-title" placeholder="Item title"></label>
<div class="inline-form">
<label>Due date <input type="date" id="ie-due-date"></label>
<label class="checkbox-label"><input type="checkbox" id="ie-allow-retakes"> Allow retakes</label>
</div>
<label>Prerequisite item (must be done first)
<select id="ie-prereq"><option value="">None</option></select>
</label>
<div class="inline-form">
<label>Evidence from student
<select id="ie-evidence-mode">
<option value="none">None</option>
<option value="optional">Optional</option>
<option value="required">Required</option>
</select>
</label>
<label>Retake score policy
<select id="ie-retake-policy">
<option value="latest">Latest attempt</option>
<option value="highest">Highest score</option>
<option value="average">Average of all</option>
</select>
</label>
</div>
<!-- Scan a page: visible for lesson + quiz types -->
<div id="ie-scan-section" class="scan-card" hidden>
<strong>📷 Scan a book page</strong>
<input type="file" id="scan-file-input" accept="image/*" capture="environment" hidden>
<div class="scan-controls">
<button type="button" id="scan-pick-btn" class="secondary">Choose photo</button>
<button type="button" id="scan-go-btn" disabled>🔍 Scan this page</button>
</div>
<img id="scan-preview" alt="Selected page photo" hidden>
<p id="scan-status" class="hint"></p>
</div>
<!-- Import from Homeschool folder: visible for lesson, assignment, quiz types -->
<div id="ie-import-section" class="scan-card" hidden>
<strong>📂 Import from Homeschool folder</strong>
<div class="scan-controls">
<select id="import-file-select" style="flex:1"><option value="">— choose a file —</option></select>
<button type="button" id="import-load-btn" class="secondary">↓ Load files</button>
<button type="button" id="import-go-btn" class="secondary" disabled>📥 Import</button>
</div>
<p id="import-status" class="hint"></p>
</div>
<div id="ie-field-lesson" class="ie-field">
<div class="rte-label">Lesson content</div>
<div class="rte-toolbar">
<button type="button" class="rte-btn" data-cmd="bold" title="Bold"><b>B</b></button>
<button type="button" class="rte-btn" data-cmd="italic" title="Italic"><i>I</i></button>
<button type="button" class="rte-btn" data-cmd="underline" title="Underline"><u>U</u></button>
<span class="rte-sep"></span>
<button type="button" class="rte-btn" data-cmd="formatBlock" data-val="h2" title="Heading">H2</button>
<button type="button" class="rte-btn" data-cmd="formatBlock" data-val="h3" title="Sub-heading">H3</button>
<button type="button" class="rte-btn" data-cmd="formatBlock" data-val="p" title="Paragraph"></button>
<span class="rte-sep"></span>
<button type="button" class="rte-btn" data-cmd="insertUnorderedList" title="Bullet list">• List</button>
<button type="button" class="rte-btn" data-cmd="insertOrderedList" title="Numbered list">1. List</button>
<span class="rte-sep"></span>
<button type="button" class="rte-btn" id="rte-link-btn" title="Add link">🔗 Link</button>
<button type="button" class="rte-btn" id="rte-youtube-btn" title="Embed YouTube">▶ YouTube</button>
</div>
<div id="ie-body-lesson" class="rte-editor lesson-body" contenteditable="true"
data-placeholder="Weather is what the sky and air are doing right now.&#10;Add images, YouTube embeds, and more."></div>
</div>
<div id="ie-field-assignment" class="ie-field">
<label>Instructions <textarea id="ie-body-assignment" rows="5" placeholder="Draw today's weather and write one sentence."></textarea></label>
<label>Points possible <input id="ie-points" type="number" min="0" value="10"></label>
</div>
<div id="ie-field-quiz" class="ie-field">
<div class="inline-form" style="margin-bottom:.5rem">
<select id="ie-template-select"><option value="">— load from template —</option></select>
<button type="button" id="ie-load-template" class="secondary">Load</button>
<button type="button" id="ie-save-template" class="secondary">Save as template</button>
</div>
<div id="ie-questions"></div>
<button type="button" id="ie-add-question" class="secondary">+ Add question</button>
</div>
<div id="ie-field-spelling" class="ie-field">
<label>Word list <select id="ie-list"></select></label>
</div>
<div id="ie-field-flashcards" class="ie-field">
<label>Deck <select id="ie-deck"></select></label>
</div>
<div class="row-actions">
<button type="submit">Save item</button>
<button type="button" id="ie-delete" class="danger" hidden>Delete item</button>
</div>
<p id="ie-error" class="error" hidden></p>
</form>
</section>
<!-- Planner -->
<section id="panel-planner" class="panel">
<h1>Planner</h1>
<div class="inline-form">
<label>Kid <select id="planner-student"></select></label>
<button id="planner-view-week" class="secondary active-view">Week</button>
<button id="planner-view-month" class="secondary">Month</button>
<button id="planner-prev" class="secondary">← Prev</button>
<span id="planner-week-label" class="week-label"></span>
<button id="planner-next" class="secondary">Next →</button>
<button id="planner-copy" class="secondary">Copy last week</button>
<button id="planner-print">🖨 Print</button>
</div>
<details id="auto-schedule-details" class="admin-card" style="margin-bottom:1rem">
<summary style="cursor:pointer;font-weight:600">⚡ Auto-schedule a course</summary>
<div class="inline-form" style="margin-top:.75rem">
<label>Course <select id="auto-course"></select></label>
<label>Start date <input type="date" id="auto-start-date"></label>
<label>Items/day <input type="number" id="auto-items-per-day" value="1" min="1" max="10" style="width:5rem"></label>
<button id="auto-schedule-btn">Schedule</button>
</div>
<p id="auto-schedule-msg" class="hint" style="margin-top:.5rem"></p>
</details>
<div id="planner-grid" class="planner-grid"></div>
</section>
<!-- Grading queue -->
<section id="panel-grading" class="panel">
<h1>Grading Queue</h1>
<div id="grading-rows"></div>
<p id="grading-empty" class="hint" hidden>Nothing waiting to be graded 🎉</p>
<!-- Evidence lightbox -->
<div id="evidence-lightbox" class="modal" hidden>
<div class="modal-box">
<h3>Evidence</h3>
<div id="evidence-lightbox-body"></div>
<button id="evidence-lightbox-close" class="secondary">Close</button>
</div>
</div>
</section>
<!-- Gradebook -->
<section id="panel-gradebook" class="panel">
<h1>Gradebook</h1>
<div class="inline-form">
<label>Course <select id="gradebook-course"></select></label>
<button id="gradebook-csv-btn" class="secondary">⬇ Export CSV</button>
</div>
<div id="gradebook-table"></div>
<div id="history-modal" class="modal" hidden>
<div class="modal-box">
<h3 id="history-modal-title">Attempt History</h3>
<div id="history-modal-body"></div>
<button id="history-modal-close" class="secondary">Close</button>
</div>
</div>
</section>
<!-- Spelling (legacy word lists + weekly assignment) -->
<section id="panel-spelling" class="panel">
<h1>Spelling</h1>
<div class="panel-cols">
<div class="panel-col">
<h2>This week's list per kid</h2>
<div id="assign-rows"></div>
<h2>Word lists</h2>
<div id="list-rows"></div>
<h2>Test results</h2>
<div id="results-area"></div>
</div>
<div class="panel-col">
<div class="toggle-btns">
<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">
<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-group" placeholder="Group (e.g. Bible 6)" aria-label="Group" list="list-groups-datalist">
<datalist id="list-groups-datalist"></datalist>
<textarea id="list-words" rows="8"
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">
<button type="submit">Save list</button>
<button type="button" id="list-cancel" class="secondary">Cancel</button>
</div>
</form>
</div>
<div id="list-bulk-section" hidden>
<h3 class="section-form-title">Bulk import lists</h3>
<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>
<input id="list-bulk-group" placeholder="Group (e.g. Bible 6) — optional" aria-label="Group for bulk import" list="list-groups-datalist">
<textarea id="list-bulk-text" rows="12"
placeholder="# Week 1&#10;because&#10;enough&#10;friend&#10;&#10;# Week 2&#10;receive | Did you receive my letter?&#10;achieve&#10;believe"></textarea>
<div class="row-actions">
<button type="button" id="list-bulk-save">Import all lists</button>
<button type="button" id="list-bulk-clear" class="secondary">Clear</button>
</div>
<p id="list-bulk-status" class="hint" style="margin:0.4rem 0 0"></p>
</div>
</div>
</div>
</div>
</section>
<!-- Flashcard decks -->
<section id="panel-decks" class="panel">
<h1>Flashcard Decks</h1>
<div class="panel-cols">
<div class="panel-col">
<div id="deck-rows"></div>
</div>
<div class="panel-col">
<div class="toggle-btns">
<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">
<input type="hidden" id="deck-id">
<input id="deck-name" placeholder="Deck name (e.g. State Capitals)" aria-label="Deck name">
<input id="deck-group" placeholder="Group (e.g. Bible 6)" aria-label="Group" list="deck-groups-datalist">
<datalist id="deck-groups-datalist"></datalist>
<textarea id="deck-cards" rows="8"
placeholder="One card per line: front | back&#10;What is the capital of Ohio? | Columbus"></textarea>
<div class="row-actions">
<button type="submit">Save deck</button>
<button type="button" id="deck-cancel" class="secondary">Cancel</button>
</div>
</form>
</div>
<div id="deck-bulk-section" hidden>
<h3 class="section-form-title">Bulk import decks</h3>
<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>
<input id="deck-bulk-group" placeholder="Group (e.g. Bible 6) — optional" aria-label="Group for bulk import" list="deck-groups-datalist">
<textarea id="deck-bulk-text" rows="12"
placeholder="# Chapter 1 Vocab&#10;What is photosynthesis? | The process plants use to make food&#10;What does chlorophyll do? | Absorbs light&#10;&#10;# Chapter 2 Vocab&#10;What is mitosis? | Cell division producing identical cells"></textarea>
<div class="row-actions">
<button type="button" id="deck-bulk-save">Import all decks</button>
<button type="button" id="deck-bulk-clear" class="secondary">Clear</button>
</div>
<p id="deck-bulk-status" class="hint" style="margin:0.4rem 0 0"></p>
</div>
</div>
</div>
</div>
</section>
<!-- Settings -->
<section id="panel-settings" class="panel">
<h1>Settings</h1>
<form id="pin-change-form" class="inline-form">
<input id="new-pin" type="password" inputmode="numeric" placeholder="New PIN (4+ digits)" aria-label="New PIN">
<button type="submit">Change PIN</button>
</form>
<h2>Page scanning (AI vision)</h2>
<p class="hint">Used by "Scan a page" in the lesson/quiz editor. Configure one or both providers — the primary is tried first and the other is used as automatic fallback.</p>
<form id="scan-config-form">
<fieldset class="scan-provider-box">
<legend>Primary provider</legend>
<label class="radio-label">
<input type="radio" name="scan_primary" value="local"> Local (Ollama) — runs on your machine, completely free &amp; private
</label>
<label class="radio-label">
<input type="radio" name="scan_primary" value="ollama_cloud"> Ollama Cloud — free hosted tier, requires API key
</label>
</fieldset>
<fieldset class="scan-provider-box">
<legend>Local — Ollama</legend>
<div class="inline-form">
<input id="ollama-host" placeholder="http://localhost:11434" aria-label="Ollama host">
<input id="ollama-model" placeholder="llava" aria-label="Vision model">
<button type="button" id="ollama-test-btn" class="secondary">Test</button>
</div>
<p id="ollama-test-result" class="hint"></p>
<p class="hint">Install a vision model: <code>ollama pull llava</code> or <code>ollama pull llava-llama3</code></p>
</fieldset>
<fieldset class="scan-provider-box">
<legend>Ollama Cloud (free tier)</legend>
<div class="inline-form">
<input id="ollama-cloud-model" placeholder="gemma4" aria-label="Ollama Cloud model">
<input id="ollama-cloud-api-key" type="password" placeholder="Ollama Cloud API key" aria-label="Ollama Cloud API key">
<span id="ollama-cloud-key-status" class="hint"></span>
</div>
<p class="hint">Runs through your local Ollama but offloads compute to Ollama's cloud. Get a free API key at <strong>ollama.com</strong> → Account → API Keys, then pull the model: <code>ollama pull gemma4:cloud</code>. Enter the base name only (e.g. <code>gemma4</code>) — <code>:cloud</code> is added automatically.</p>
</fieldset>
<button type="submit">Save scan settings</button>
</form>
</section>
<p id="admin-msg" class="hint"></p>
</main>
</div>
<script src="admin.js"></script>
</body>
</html>