Files
homeschool/public/admin.html
T
nmemmertandClaude Sonnet 4.6 91fe38c00d
Build and Push Docker Image / build-and-push (push) Successful in 35s
Fix parent doc viewer: sign comment permissions server-side
Client-side permission overrides invalidated the JWT. Move the
comment-only config to a new PIN-protected endpoint that signs
the correct permissions before returning to the browser.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-10-19 16:38:34 -04:00

799 lines
42 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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">
<div class="pin-deco" aria-hidden="true">📚 ✏️ 🎓</div>
<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>
<aside class="admin-sidebar">
<a href="index.html" class="admin-logo">
<span class="admin-logo-icon">🏫</span>
<span id="admin-school-name">Homeschool</span>
</a>
<nav class="admin-nav">
<button class="nav-pill active" data-panel="dashboard">
<span class="nav-icon">⊞</span><span class="nav-label">Dashboard</span>
</button>
<div class="nav-section-label">People</div>
<button class="nav-pill" data-panel="kids">
<span class="nav-icon">🧒</span><span class="nav-label">Kids</span>
</button>
<button class="nav-pill" data-panel="messages">
<span class="nav-icon">💬</span><span class="nav-label">Messages</span>
</button>
<div class="nav-section-label">Academics</div>
<button class="nav-pill" data-panel="courses">
<span class="nav-icon">📚</span><span class="nav-label">Courses</span>
</button>
<button class="nav-pill" data-panel="planner">
<span class="nav-icon">🗓️</span><span class="nav-label">Planner</span>
</button>
<button class="nav-pill" data-panel="grading">
<span class="nav-icon">✅</span><span class="nav-label">Grading</span>
</button>
<button class="nav-pill" data-panel="gradebook">
<span class="nav-icon">📊</span><span class="nav-label">Gradebook</span>
</button>
<div class="nav-section-label">Tools</div>
<button class="nav-pill" data-panel="spelling">
<span class="nav-icon">✏️</span><span class="nav-label">Spelling</span>
</button>
<button class="nav-pill" data-panel="decks">
<span class="nav-icon">🗂️</span><span class="nav-label">Flashcards</span>
</button>
<button class="nav-pill" data-panel="docs">
<span class="nav-icon">📝</span><span class="nav-label">Docs</span>
</button>
</nav>
<div class="admin-sidebar-footer">
<button class="nav-pill" data-panel="settings">
<span class="nav-icon">⚙️</span><span class="nav-label">Settings</span>
</button>
</div>
</aside>
<div class="admin-body">
<header class="admin-topbar">
<button class="sidebar-toggle" id="sidebar-toggle" aria-label="Toggle menu">☰</button>
<h1 class="admin-page-title" id="admin-page-title">Dashboard</h1>
<div class="admin-topbar-right">
<a href="index.html" class="topbar-btn">← Student view</a>
<button class="topbar-btn topbar-lock" id="btn-lock">🔒 Lock</button>
</div>
</header>
<main class="admin-main">
<!-- Dashboard -->
<section id="panel-dashboard" class="panel">
<div id="dashboard-greeting" class="dash-greeting"></div>
<div id="dashboard-kid-cards" class="dash-kid-grid"></div>
<div class="dash-bottom-row">
<div class="dash-col">
<h3 class="dash-col-title">Today's Schedule</h3>
<div id="dashboard-schedule" class="dash-schedule-list"></div>
</div>
<div class="dash-col">
<h3 class="dash-col-title">Recent Scores</h3>
<div id="dashboard-scores" class="dash-score-list"></div>
</div>
</div>
</section>
<!-- Kids -->
<section id="panel-kids" class="panel" hidden>
<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>
<label style="font-size:.85rem;color:#666;margin-top:.25rem">🎂 Birthday (optional)
<input id="new-student-birthday" type="date" aria-label="Birthday" style="margin-top:.25rem">
</label>
<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 class="admin-card" style="margin-top:1rem">
<h2 style="margin:0 0 0.75rem">Import course</h2>
<!-- mode tabs -->
<div style="display:flex;gap:0.5rem;margin-bottom:1rem">
<button type="button" class="import-tab-btn secondary" data-tab="json" style="flex:1">📄 From JSON</button>
<button type="button" class="import-tab-btn secondary" data-tab="docx" style="flex:1">📝 From Word docs</button>
</div>
<!-- JSON import -->
<div id="import-tab-json">
<p class="hint" style="margin:0 0 0.75rem">Import a <code>.json</code> bundle previously exported from this app.</p>
<input type="file" id="import-course-file" accept=".json" hidden>
<div class="inline-form" style="align-items:center;gap:0.5rem">
<button type="button" id="import-course-browse" class="secondary">📂 Choose file…</button>
<span id="import-course-filename" class="hint" style="flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"></span>
<button type="button" id="import-course-go" class="secondary" disabled>📥 Import</button>
</div>
</div>
<!-- Word docx import -->
<div id="import-tab-docx" hidden>
<p class="hint" style="margin:0 0 0.75rem">Select all unit <code>.docx</code> files at once — one file per unit, sorted by filename.</p>
<div class="inline-form" style="flex-direction:column;gap:0.5rem">
<input id="import-docx-name" placeholder="Course name (required)" aria-label="Course name" style="width:100%">
<input id="import-docx-subject" placeholder="Subject (optional)" aria-label="Subject" style="width:100%">
<div style="display:flex;align-items:center;gap:0.5rem">
<label style="font-size:0.85rem">Color</label>
<input id="import-docx-color" type="color" value="#4f86f7" aria-label="Color">
</div>
</div>
<input type="file" id="import-docx-files" accept=".docx" multiple hidden>
<div class="inline-form" style="align-items:center;gap:0.5rem;margin-top:0.5rem">
<button type="button" id="import-docx-browse" class="secondary">📂 Choose .docx files…</button>
<span id="import-docx-filenames" class="hint" style="flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"></span>
<button type="button" id="import-docx-go" class="secondary" disabled>📥 Import</button>
</div>
</div>
<p id="import-course-status" class="hint" style="margin:0.5rem 0 0"></p>
</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-export" class="secondary">⬇ Export 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="matching">🔤 Matching</option>
<option value="crossword">⬛ Crossword</option>
<option value="flashcards">🗂️ Flashcards</option>
<option value="worksheet">📋 Worksheet</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>
<!-- Import from .docx file: visible for lesson, assignment, quiz types -->
<div id="ie-import-section" class="scan-card" hidden>
<strong>📂 Import from .docx</strong>
<input type="file" id="import-local-input" accept=".docx" hidden>
<div class="scan-controls">
<button type="button" id="import-browse-btn" class="secondary">📂 Choose file…</button>
<span id="import-local-name" class="hint" style="flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"></span>
<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 rte-group">
<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 rte-link-btn" title="Add link">🔗 Link</button>
<button type="button" class="rte-btn 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 rte-group">
<div class="rte-label">Instructions</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 rte-link-btn" title="Add link">🔗 Link</button>
<button type="button" class="rte-btn rte-youtube-btn" title="Embed YouTube">▶ YouTube</button>
</div>
<div id="ie-body-assignment" class="rte-editor lesson-body" contenteditable="true"
data-placeholder="Draw today's weather and write one sentence."></div>
<label style="margin-top:.75rem">Points possible <input id="ie-points" type="number" min="0" value="10"></label>
</div>
<div id="ie-field-quiz" class="ie-field">
<label>Instructions <small style="color:#888">(optional — shown to student before questions)</small>
<textarea id="ie-quiz-instructions" rows="2" placeholder="e.g. Choose the best answer for each question." style="width:100%;margin-top:.25rem;resize:vertical"></textarea>
</label>
<div class="inline-form" style="margin:.5rem 0">
<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-matching" class="ie-field">
<label>Instructions <small style="color:#888">(optional — shown to student before the word bank)</small>
<textarea id="ie-matching-instructions" rows="2" placeholder="e.g. Match each definition to the correct term." style="width:100%;margin-top:.25rem;resize:vertical"></textarea>
</label>
<p class="hint" style="margin:.5rem 0">Enter word-clue pairs. Words are shown as A, B, C… (alphabetical order) in the word bank.</p>
<div id="ie-pairs"></div>
<button type="button" id="ie-add-pair" class="secondary">+ Add pair</button>
</div>
<div id="ie-field-crossword" class="ie-field" hidden>
<div class="cw-entry-cols">
<div>
<h3 style="margin-bottom:.5rem">Across clues</h3>
<div id="ie-across-clues"></div>
<button type="button" id="ie-add-across" class="secondary small">+ Add across clue</button>
</div>
<div>
<h3 style="margin-bottom:.5rem">Down clues</h3>
<div id="ie-down-clues"></div>
<button type="button" id="ie-add-down" class="secondary small">+ Add down clue</button>
</div>
</div>
<div style="margin-top:1rem;display:flex;gap:.75rem;align-items:center;flex-wrap:wrap">
<button type="button" id="ie-crossword-generate" class="secondary">⚡ Generate crossword</button>
<span id="ie-crossword-status" class="hint"></span>
</div>
<div id="ie-crossword-preview" style="margin-top:.75rem;overflow-x:auto"></div>
</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 id="ie-field-worksheet" class="ie-field" hidden>
<label style="margin-bottom:.25rem">Paste your worksheet text
<textarea id="ie-ws-paste" rows="10" placeholder="Paste your printed worksheet here. The parser handles:&#10;• Name: ____ Date: ____ → header line&#10;• Part 1 — Title → section header&#10;• 1. Sentence with _____ blanks. → fill-in-the-blank&#10;• T F Statement text → true/false question&#10;• 4. Question with no blanks → short answer (parent grades)" style="width:100%;margin-top:.25rem;resize:vertical;font-family:monospace;font-size:.85rem"></textarea>
</label>
<button type="button" id="ie-ws-parse" class="secondary" style="margin:.5rem 0">⚡ Parse worksheet</button>
<p id="ie-ws-parse-status" class="hint" hidden></p>
<div id="ie-ws-editor"></div>
</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">
<div class="planner-toolbar">
<div class="planner-toolbar-left">
<div class="planner-view-toggle">
<button id="planner-view-week" class="view-toggle-btn active">Week</button>
<button id="planner-view-month" class="view-toggle-btn">Month</button>
</div>
<div class="planner-nav-group">
<button id="planner-prev" class="planner-nav-btn">‹</button>
<span id="planner-week-label" class="week-label"></span>
<button id="planner-next" class="planner-nav-btn">›</button>
</div>
<button id="planner-today" class="secondary small">Today</button>
</div>
<div class="planner-toolbar-right">
<select id="planner-student" class="planner-kid-select"></select>
<button id="planner-copy" class="secondary small" title="Copy last week's tasks to this week">📋 Copy week</button>
<button id="planner-print" class="secondary small">🖨 Print</button>
<button id="planner-add-btn">+ Add task</button>
</div>
</div>
<div class="planner-auto-bar">
<span class="planner-auto-label">⚡ Auto-schedule</span>
<select id="auto-course"></select>
from <input type="date" id="auto-start-date" style="width:8rem">
<input type="number" id="auto-items-per-day" value="1" min="1" max="10" style="width:3.5rem" title="Items per day">
<span style="color:var(--muted);font-size:.8rem">items/day</span>
<button id="auto-schedule-btn" class="secondary small">Schedule</button>
<span id="auto-schedule-msg" class="hint"></span>
</div>
<div id="planner-grid" class="planner-grid"></div>
</section>
<!-- Grading queue -->
<section id="panel-grading" class="panel">
<h1>Grading Queue</h1>
<div class="inline-form" style="margin-bottom:1rem">
<label>Student <select id="grading-student-filter"><option value="">All students</option></select></label>
</div>
<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>
<!-- Messages -->
<section id="panel-messages" class="panel">
<h1>Messages</h1>
<div class="msg-admin-cols">
<div id="msg-thread-list" class="msg-thread-list"></div>
<div id="msg-admin-thread" class="msg-admin-thread">
<p class="hint" style="padding:1rem">Select a student to view the conversation.</p>
</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>
<details class="admin-card" id="paper-score-details" style="margin:1.5rem 0">
<summary style="cursor:pointer;font-weight:600">📝 Record Paper Score</summary>
<p class="hint" style="margin:.5rem 0 .75rem">Use this to log a score from a paper quiz, assignment, or other item done off-screen.</p>
<div class="inline-form" style="flex-direction:column;gap:.6rem">
<div class="inline-form" style="gap:.5rem;flex-wrap:wrap">
<label>Student <select id="paper-score-student"></select></label>
<label>Course <select id="paper-score-course"></select></label>
</div>
<label>Item <select id="paper-score-item"><option value="">— select a course first —</option></select></label>
<div class="inline-form" style="gap:.5rem;align-items:center">
<label>Score <input type="number" id="paper-score-score" min="0" style="width:4.5rem" placeholder="0"></label>
<span style="padding-top:1.4rem">out of</span>
<label>Total <input type="number" id="paper-score-total" min="1" style="width:4.5rem"></label>
<label>Date <input type="date" id="paper-score-date"></label>
</div>
<div>
<button type="button" id="paper-score-save">Record score</button>
<span id="paper-score-status" class="hint" style="margin-left:.5rem"></span>
</div>
</div>
</details>
<h2>Spelling Test History</h2>
<div class="inline-form">
<label>Period <select id="spelling-tests-since">
<option value="">All time</option>
<option value="30">Last 30 days</option>
<option value="90">Last 90 days</option>
</select></label>
<button id="spelling-tests-csv-btn" class="secondary small">⬇ CSV</button>
</div>
<div id="spelling-tests-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>
<div id="correct-test-modal" class="modal" hidden>
<div class="modal-box">
<h3>Correct Spelling Test</h3>
<p id="correct-test-meta" class="hint"></p>
<table class="results" id="correct-test-table">
<tr><th>Word</th><th>Typed</th><th>Mark correct</th></tr>
</table>
<div class="inline-form" style="margin-top:1rem">
<button id="correct-test-save">Save corrections</button>
<button id="correct-test-cancel" class="secondary">Cancel</button>
</div>
</div>
</div>
</section>
<!-- Spelling (legacy word lists + weekly assignment) -->
<section id="panel-spelling" class="panel">
<h1>Spelling</h1>
<details class="admin-card" id="paper-test-details" style="margin-bottom:1.5rem">
<summary style="cursor:pointer;font-weight:600">📝 Record Paper Test</summary>
<div class="inline-form" style="flex-direction:column;gap:.6rem;margin-top:.75rem">
<div class="inline-form" style="gap:.5rem;flex-wrap:wrap">
<label>Student <select id="paper-test-student"></select></label>
<label>Word list <select id="paper-test-list"></select></label>
</div>
<div class="inline-form" style="gap:.5rem;align-items:center">
<label>Score <input type="number" id="paper-test-score" min="0" style="width:4.5rem" placeholder="0"></label>
<span style="padding-top:1.4rem">out of</span>
<label>Total <input type="number" id="paper-test-total" min="1" style="width:4.5rem"></label>
<label>Date <input type="date" id="paper-test-date"></label>
</div>
<div>
<button type="button" id="paper-test-save">Record test</button>
<span id="paper-test-status" class="hint" style="margin-left:.5rem"></span>
</div>
</div>
</details>
<h2>Practice Sessions</h2>
<div class="inline-form">
<label>Period <select id="sessions-since">
<option value="30">Last 30 days</option>
<option value="90">Last 90 days</option>
<option value="">All time</option>
</select></label>
</div>
<div id="practice-sessions-table"></div>
<h2>Practice Activity (word-by-word)</h2>
<div class="inline-form">
<label>Period <select id="practice-since">
<option value="30">Last 30 days</option>
<option value="90">Last 90 days</option>
<option value="">All time</option>
</select></label>
</div>
<div id="practice-activity-table"></div>
<div id="practice-modal" class="modal" hidden>
<div class="modal-box">
<h3 id="practice-modal-title">Practice Detail</h3>
<div id="practice-modal-body"></div>
<button id="practice-modal-close" class="secondary">Close</button>
</div>
</div>
<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 class="filter-bar">
<input id="list-filter" type="search" placeholder="Filter lists…" aria-label="Filter lists">
<button type="button" id="list-show-hidden" class="secondary small" hidden>Show hidden</button>
</div>
<div id="list-rows"></div>
</div>
<div class="panel-col">
<div class="toggle-btns">
<button type="button" id="list-new-btn" class="secondary">+ New list</button>
<button type="button" id="list-bulk-btn" class="secondary">⬆ Bulk import</button>
<button type="button" id="list-csv-btn" class="secondary">📄 CSV file</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 id="list-csv-section" hidden>
<h3 class="section-form-title">Import from CSV file</h3>
<div class="admin-card">
<p class="hint" style="margin:0 0 0.5rem">Upload a <code>.csv</code> or <code>.txt</code> file. Each row is one word. Columns: <code>word</code> (required), <code>sentence</code> (optional), <code>definition</code> (optional). A header row is ignored automatically.</p>
<div class="inline-form" style="flex-direction:column;gap:.5rem">
<input id="list-csv-name" placeholder="List name (required)" aria-label="List name for CSV import">
<input id="list-csv-group" placeholder="Group (optional)" aria-label="Group for CSV import" list="list-groups-datalist">
</div>
<input type="file" id="list-csv-file" accept=".csv,.txt" hidden>
<div class="inline-form" style="align-items:center;gap:.5rem;margin-top:.5rem">
<button type="button" id="list-csv-browse" class="secondary">📂 Choose file…</button>
<span id="list-csv-filename" class="hint" style="flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"></span>
<button type="button" id="list-csv-go" class="secondary" disabled>📥 Import</button>
</div>
<p id="list-csv-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 class="filter-bar">
<input id="deck-filter" type="search" placeholder="Filter decks…" aria-label="Filter decks">
</div>
<div id="deck-rows"></div>
</div>
<div class="panel-col">
<div class="toggle-btns">
<button type="button" id="deck-new-btn" class="secondary">+ 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>
<!-- Docs -->
<section id="panel-docs" class="panel" hidden>
<h1>Submitted Documents</h1>
<div id="admin-docs-list">
<p class="hint">Loading…</p>
</div>
<!-- Full-screen doc viewer -->
<div id="admin-doc-viewer" hidden>
<div class="docs-editor-toolbar">
<button id="btn-admin-doc-back" class="docs-back-btn">← Back to list</button>
<span id="admin-doc-viewer-title" class="docs-editor-title-text"></span>
<a id="admin-doc-download" class="docs-submit-btn" download>⬇ Download</a>
</div>
<div id="admin-doc-frame"></div>
</div>
</section>
<!-- Settings -->
<section id="panel-settings" class="panel">
<h1>Settings</h1>
<h2>Parent PIN</h2>
<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>School</h2>
<form id="app-settings-form">
<div class="field-group">
<label for="setting-school-name">School / family name <span class="hint">(appears on home screen and printed reports)</span></label>
<input id="setting-school-name" type="text" placeholder="e.g. Emmert Academy" style="max-width:22rem;display:block;margin-top:.35rem">
</div>
<div class="field-group" style="margin-top:1rem">
<label>School logo <span class="hint">(shown on the student home screen)</span></label>
<div id="logo-preview-wrap" style="margin:.4rem 0 .6rem">
<img id="logo-preview" src="" alt="School logo" hidden style="max-height:80px;max-width:240px;border-radius:6px;display:block;margin-bottom:.4rem">
<p id="logo-none-msg" class="hint" style="margin:0">No logo uploaded.</p>
</div>
<div class="inline-form" style="gap:.5rem;flex-wrap:wrap">
<label class="btn" style="cursor:pointer;display:inline-flex;align-items:center;gap:.3rem">
📁 Choose logo
<input id="logo-file-input" type="file" accept="image/png,image/jpeg,image/gif,image/webp,image/svg+xml" style="display:none">
</label>
<button type="button" id="logo-remove-btn" hidden>Remove logo</button>
</div>
<p class="hint" style="margin-top:.3rem">PNG, JPG, GIF, WebP, or SVG · max 2 MB</p>
</div>
<div class="field-group" style="margin-top:1rem">
<label for="setting-passing-pct">Passing grade threshold</label>
<div class="inline-form" style="margin-top:.35rem">
<input id="setting-passing-pct" type="number" min="0" max="100" style="width:5rem" aria-label="Passing percent"> <span>%</span>
</div>
<p class="hint">Scores at or above this show green in gradebooks and reports.</p>
</div>
<div class="field-group" style="margin-top:1rem">
<label>School week starts on</label>
<label class="radio-label" style="margin-top:.35rem">
<input type="radio" name="week_start_day" value="monday"> Monday (Mon–Fri)
</label>
<label class="radio-label">
<input type="radio" name="week_start_day" value="sunday"> Sunday (Sun–Thu)
</label>
</div>
<div class="field-group" style="margin-top:1rem">
<label>Student home screen</label>
<label class="toggle-label" style="margin-top:.5rem">
<input type="checkbox" id="setting-show-emoji" role="switch">
<span class="toggle-track"><span class="toggle-thumb"></span></span>
Show floating emoji on the kid picker screen
</label>
</div>
<button type="submit" style="margin-top:1.25rem">Save settings</button>
</form>
</section>
</main>
</div><!-- /.admin-body -->
</div><!-- /#console -->
<!-- Floating assign popup -->
<div id="assign-popup" hidden>
<p class="assign-popup-label">Assign to…</p>
<div id="assign-popup-students"></div>
</div>
<div id="toast" role="status" aria-live="polite" hidden></div>
<!-- Planner add-task modal -->
<div id="planner-add-modal" class="modal" hidden>
<div class="modal-box planner-add-box">
<div class="planner-modal-header">
<h3>Add to planner</h3>
<button id="planner-modal-close" class="secondary small">✕</button>
</div>
<div id="planner-day-tabs" class="day-tabs"></div>
<input id="planner-item-search" type="search" class="planner-item-search" placeholder="Search course items…" autocomplete="off">
<div id="planner-item-list" class="item-list"></div>
<div class="planner-offline-row">
<input id="planner-offline-input" placeholder="Or type an offline task…">
<button id="planner-offline-add">Add</button>
</div>
</div>
</div>
<script src="admin.js?v=5"></script>
</body>
</html>