Each time a student completes a pass through a spelling_practice course item — initial round, missed-words drill, or a retry — a row is now written to submission_history so the parent sees individual attempts instead of a single day-grouped entry. - app.js: send sessionAttempted/sessionCorrect with /complete calls - server.js: write to submission_history on each spelling_practice completion; add GET /api/spelling-sessions endpoint - admin.html/js: new "Practice Sessions" table shows one row per pass Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
631 lines
33 KiB
HTML
631 lines
33 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">
|
||
<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>
|
||
<header class="admin-header">
|
||
<a href="index.html" class="admin-logo" id="admin-school-name">🎓 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>
|
||
<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 & 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. 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: • Name: ____ Date: ____ → header line • Part 1 — Title → section header • 1. Sentence with _____ blanks. → fill-in-the-blank • T F Statement text → true/false question • 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">
|
||
<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-today" class="secondary">Today</button>
|
||
<button id="planner-copy" class="secondary">Copy last week</button>
|
||
<button id="planner-print">🖨 Print</button>
|
||
<button id="planner-add-btn">+ Add task</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 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>
|
||
|
||
<!-- 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>
|
||
<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>
|
||
</section>
|
||
|
||
<!-- Spelling (legacy word lists + weekly assignment) -->
|
||
<section id="panel-spelling" class="panel">
|
||
<h1>Spelling</h1>
|
||
|
||
<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>
|
||
</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! Add an example sentence with | receive | Did you receive my letter? Or just a plain list: because enough 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 because enough friend # Week 2 receive | Did you receive my letter? achieve 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 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 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 What is photosynthesis? | The process plants use to make food What does chlorophyll do? | Absorbs light # Chapter 2 Vocab 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>
|
||
|
||
<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>
|
||
|
||
<!-- 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"></script>
|
||
</body>
|
||
</html>
|