Commit Graph
55 Commits
Author SHA1 Message Date
nmemmertandClaude Sonnet 4.6 3197d29a28 Add course import/export: JSON bundle and direct Word docx upload
- Export any course as a .json bundle (GET /api/admin/courses/:id/export)
- Import a .json bundle as a new course (POST /api/admin/import-course)
- Import one or more unit .docx files directly in the browser — server
  parses each file with mammoth, extracts Week N: headings as lesson
  items and the Unit Quiz section as a graded quiz with answer key
  (POST /api/admin/import-course-docx, multer memory storage)
- Admin UI: Export button on course detail; Import card with JSON and
  Word docs tabs; multi-file picker for docx uploads
- scripts/import-kitchen-course.js: one-time converter that produced
  the Kitchen, Tools & Electrical Skills course JSON bundle (already
  imported as course id 3: 8 units, 44 items)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-03 10:02:10 -04:00
Nate EmmertandClaude Sonnet 4.6 a44cf659b5 Make crossword view full-width to avoid grid scrolling
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-01 20:34:45 -04:00
Nate EmmertandClaude Sonnet 4.6 2a21045e70 Fix crossword clue scrollIntoView jumping the page
Replace scrollIntoView (which escapes to the window when the list isn't
tall enough to scroll) with manual scrollTop logic that stays strictly
within the clue list container.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-01 20:28:10 -04:00
Nate EmmertandClaude Sonnet 4.6 747cc76be6 Remove preventScroll from crossword cell focus
preventScroll was blocking the viewport from scrolling to the grid cell
when a clue was clicked from the sidebar. The clue list overflow fix is
sufficient to contain scrollIntoView without needing preventScroll.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-01 20:20:35 -04:00
Nate EmmertandClaude Sonnet 4.6 d88d5d22c7 Fix narrow views and crossword scroll-jump issues
Widen quiz, flashcards, practice, test, and crossword views to match the
960px max-width already used by course/lesson/assignment. Fix crossword
jumping to top on cell focus by using preventScroll and containing clue
list scrollIntoView within a max-height overflow container.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-01 20:14:07 -04:00
Nate EmmertandClaude Sonnet 4.6 10b4e3ae09 Rename crossword WORD placeholder to ANSWER for clarity
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-01 18:17:56 -04:00
Nate EmmertandClaude Sonnet 4.6 682534a061 Add crossword puzzle item type
Admin enters Across/Down words and clues; server auto-generates the grid
using a backtracking placement algorithm (longest-first, intersection-based).
Students fill in the interactive grid with click-to-select, direction toggle,
arrow-key navigation, and Tab-to-next-word. Auto-graded per word on submit,
with correct/wrong color highlighting on the results view. Includes a print
worksheet option for blank paper practice.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-01 17:56:46 -04:00
Nate EmmertandClaude Sonnet 4.6 60bfe3ca4a Add instructions field to quiz and matching item types
Instructions are optional free text shown to the student above the questions/word bank.
Admin enters them in the item editor; stored in items.body for quiz and matching types.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-01 16:57:52 -04:00
Nate EmmertandClaude Sonnet 4.6 f9cc515cec Fix matching type showing undefined in admin unit view; add print worksheet
- Add matching to TYPE_ICON/TYPE_LABEL in admin.js (was missing, caused undefined)
- Add 🖨 Print worksheet button on matching exercise (prints word bank + clue blanks)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-01 16:55:15 -04:00
Nate EmmertandClaude Sonnet 4.6 05cfdf7b09 Add matching quiz type, more theme colors, animal icon picker, and fix color persistence
- Fix theme not saving across sessions: /api/state was missing `theme` in SELECT
- Add 4 new color themes: red, teal, yellow, indigo (student + admin)
- Add animal icon picker (32 animals) with PATCH /api/students/:id/emoji endpoint
- Add Matching item type: word bank (A, B, C… alphabetical) + clue blanks, auto-graded
- Matching submit button stays disabled until all blanks are filled

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-01 16:27:22 -04:00
nmemmertandClaude Sonnet 4.6 183bcf0ef2 Import .docx content directly into RTE editor as editable HTML
Instead of embedding an iframe, mammoth HTML is inserted straight into
the contenteditable body so the admin can edit it like any other content.
A download link to the original .docx sits above the content.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-30 12:26:55 -04:00
nmemmertandClaude Sonnet 4.6 35ae40819b Add rich text editor to assignment body field
Replaces the plain textarea with a contenteditable div + full toolbar
(bold, italic, underline, H2/H3, paragraph, bullet/numbered lists, link,
YouTube embed) — same as the lesson editor.

Toolbar buttons use mousedown+preventDefault so selection is preserved
when clicking format buttons. Both editors share the same button wiring
via closest('.rte-group') rather than hardcoded element IDs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-30 12:16:39 -04:00
nmemmertandClaude Sonnet 4.6 c7dd48d0c3 Widen course, lesson, and assignment views to 960px
Home, quiz, and spelling screens stay at 640px. Course units,
lesson content, and assignment bodies now use more of the screen.
Text-align set to left for content-heavy views.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-30 11:49:24 -04:00
nmemmertandClaude Sonnet 4.6 fe29d25ddb Restore iframe embed with full-width, auto-height CSS
- Removed narrow max-width/margin from generated HTML page
- iframe now spans full card width (100%)
- onload JS auto-sizes iframe height to content so nothing is cut off
- Falls back to 500px if cross-origin restriction ever applies

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-30 11:37:58 -04:00
nmemmertandClaude Sonnet 4.6 2384fc9f7d Render document content inline instead of in iframe
Replace the <iframe> with an inline <div> containing the mammoth HTML.
Content now flows full-width with the page instead of being cramped in
a fixed-height scrolling box. Download link still available below.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-30 10:31:50 -04:00
nmemmertandClaude Sonnet 4.6 be9d58e972 Render assignment body as HTML instead of escaped text
Assignment body was being run through esc() which turned <details>/<iframe>
tags into visible raw text. Set innerHTML directly to render the HTML.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-30 09:34:57 -04:00
nmemmertandClaude Sonnet 4.6 c57f1ed827 Wrap document iframe in collapsible <details> element
Each imported doc now shows as a collapsed summary line (📄 filename.docx)
that expands to reveal the iframe and download link when clicked.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-30 09:03:42 -04:00
nmemmertandClaude Sonnet 4.6 68ec9af806 Append imported docs to body instead of replacing
Each imported .docx now adds its iframe below any existing body content
so multiple documents can be attached to a single item.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-30 08:59:46 -04:00
nmemmertandClaude Sonnet 4.6 eff8cf5e60 Embed .docx as HTML iframe with download fallback
On upload, mammoth converts the doc to a styled HTML page saved alongside
the .docx. The item body gets an <iframe> pointing to the HTML so students
see the document inline. A download link below gives access to the original.
Falls back to a plain download link if HTML conversion fails.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-30 08:58:02 -04:00
nmemmertandClaude Sonnet 4.6 5de4cfa6cf Replace docx text extraction with file attachment upload
Instead of parsing .docx content via mammoth and inserting raw text/HTML,
the import flow now saves the file to data/attachments/ (UUID filename) and
inserts an <a> link into the item body so students can open/download the doc.

- Added GET /api/attachments/:filename (no PIN — students access directly)
- Added POST /api/admin/upload-attachment (PIN required)
- Removed mammoth dependency from server
- Updated admin.js import handler to POST to new endpoint and set link HTML

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-30 08:56:12 -04:00
nmemmertandClaude Sonnet 4.6 6b72031672 Fix import content not appearing in editor fields
Lesson body is a contenteditable div — must use innerHTML, not .value.
Assignment body is a plain textarea — strip HTML tags before setting .value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-30 08:38:17 -04:00
nmemmertandClaude Sonnet 4.6 19f922c4ba Replace Ollama docx import with mammoth HTML conversion
Remove all AI processing from the import-docx endpoint. Instead:
- Convert the .docx to HTML with mammoth.convertToHtml (preserves
  bold, headings, lists, etc.) — the result goes straight into the
  item body and renders in the lesson viewer
- Extract raw text in parallel to pick the document title from the
  first non-empty line
- No external services, no AI, works on the deployed server

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-30 08:21:52 -04:00
nmemmertandClaude Sonnet 4.6 dcfb49585d Fix docx import crash on large files by chunking base64 encoding
btoa(String.fromCharCode(...new Uint8Array(buf))) exceeds V8's function
argument stack limit for files larger than ~65k bytes. Process in 8k
chunks instead to handle any file size.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-29 17:23:03 -04:00
nmemmertandClaude Sonnet 4.6 b048f51d46 Replace server-folder docx import with direct file picker
The old import scanned a hardcoded Seafile CloudStorage path that only
worked on one specific machine. Replaced with a standard <input type=file>
browser picker that reads the .docx as base64 and uploads it directly, so
the feature works everywhere. Server endpoint now accepts either a base64
payload or the legacy path. Also fixed a crash where resetImportSection()
still referenced the removed select element, which was breaking the item
editor for all item types.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-29 17:15:23 -04:00
nmemmertandClaude Sonnet 4.6 de598496bc Gradebook unit cards, scroll/state preservation on course edit
- Gradebook now groups items by unit with collapsible cards (same card
  style as course detail) and a Course overall summary table at the bottom
- server.js: add unit_id/unit_name to gradebook API so items can be grouped
- Course detail: preserve which units are open and scroll position across
  any in-place re-render (add unit, delete unit, save meta, return from
  item editor) — no more jumping to the top with everything reset

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-29 16:43:15 -04:00
nmemmertandClaude Sonnet 4.6 723bbb93c8 Redesign course unit list into collapsible cards on student and admin views
Student view auto-opens the unit whose item due-dates span today (falls back
to most-recent past unit, earliest future unit, then first with incomplete
work). Admin view starts all units expanded. Both share the same card design:
unit-number badge, name, progress/count indicator, animated chevron toggle.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-29 16:24:44 -04:00
nmemmertandClaude Sonnet 4.6 ac7b86b470 Allow planner cells to grow vertically instead of fixed height
Cells now expand to show all tasks rather than clipping with overflow:hidden.
Column widths stay equal (CSS grid 1fr) — only height is flexible.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 16:58:25 -04:00
nmemmertandClaude Sonnet 4.6 5bca261bf1 Fix planner calendar to use fixed-height columns instead of dynamic sizing
Week view days locked to 240px, month view cells to 100px — tasks scroll
within each card so one busy day no longer stretches the whole row.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 16:23:17 -04:00
nmemmertandClaude Sonnet 4.6 50a76e69cc Clear stale PIN from sessionStorage on load
Wipes any previously cached PIN so old browser sessions can't
auto-unlock the dashboard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 15:29:33 -04:00
nmemmertandClaude Sonnet 4.6 8f3f7634ff Require PIN on every visit to the parent dashboard
Remove sessionStorage caching of the PIN so the gate always shows on
page load instead of auto-unlocking from a previous session.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 15:27:11 -04:00
nmemmertandClaude Sonnet 4.6 2accefd122 Add toast notifications for all saves and batch planner task add
Toast: replace buried #admin-msg hint with a floating green/red toast
(bottom-right, auto-dismisses after 3s) covering every save action —
lists, decks, items, grades, kids, units, courses, bulk imports, and
planner saves.

Planner batch add: clicking '+ Add' now queues items locally (shown
as dashed pending badges) without saving. A '💾 Save N items' button
appears in the toolbar; clicking it commits everything at once and
refreshes the planner. Queue clears on student change.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 15:10:14 -04:00
nmemmertandClaude Sonnet 4.6 b048ebbd85 Add spelling test polish: date filter, CSV export, student history, planner badges
- Gradebook: period dropdown (all time / 30 / 90 days) and CSV export for
  Spelling Test History section
- Student portal spelling tab: shows last 10 tests as a Recent Tests list
- Planner: completed standalone spelling tests appear as read-only ⭐ badges
  on the day they were taken (week and month views)
- Removed dead s.tests query from /api/overview (now served by dedicated endpoints)
- New endpoints: GET /api/spelling-tests/csv, GET /api/students/:id/tests,
  GET /api/admin/students/:id/tests-range

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 14:26:47 -04:00
nmemmertandClaude Sonnet 4.6 183b43b452 Move spelling test results from Spelling panel into Gradebook
Adds a GET /api/spelling-tests endpoint that returns all standalone test
results grouped by student. The Gradebook panel now shows a "Spelling Test
History" section below the course gradebook table. Removed the "Test results"
section from the Spelling panel left column.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 13:55:23 -04:00
nmemmertandClaude Sonnet 4.6 774979f2e4 Add 4 UX improvements to spelling/flashcards panel
- Assign → button on each list row opens a popup to pick a kid directly
  without scrolling up to the assignment dropdowns
- Hide/Unhide button on built-in lists (stored in localStorage) keeps
  UNGROUPED clean; Show hidden toggle reveals them dimmed when needed
- Mastery progress bar on each kid showing X/Y words mastered for their
  current assigned list (server now returns listProgress in /api/overview)
- Filter-lists / filter-decks search input for fast lookup by name

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 13:47:27 -04:00
nmemmertandClaude Sonnet 4.6 5c2b5baec2 Fix toggle button styling and collapse groups by default
Toggle buttons now match the rest of the admin UI (same font, padding,
border-radius). Both start secondary/gray; the active one turns blue.
List and deck group sections are collapsed by default instead of open.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 13:19:10 -04:00
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
nmemmertandClaude Sonnet 4.6 4613946cea Use full browser width with 2-column layout at 1100px+
Widened admin-main to 1400px max-width and added panel-cols/panel-col
wrappers so Kids, Courses, Spelling, and Flashcards all display content
on the left and forms/editors on the right on wider screens. Falls back
to single-column on smaller viewports.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 13:07:38 -04:00
nmemmertandClaude Sonnet 4.6 adf4bf4cae Add bulk import for spelling lists and flashcard decks
Paste multiple lists/decks in one shot using # Name headers:
  # Week 1
  word1
  word2 | example sentence

  # Week 2
  ...

An optional group field applies to all imported items at once.
Progress shown inline; list/deck panel refreshes on completion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 13:02:45 -04:00
nmemmertandClaude Sonnet 4.6 24e709e038 Make list/deck group sections collapsible with prominent headers
Group headers now use a solid tan background, bold uppercase text, and a
▼/▶ arrow indicator so collapsible sections are visually obvious.
Uses native <details>/<summary> elements; ungrouped items show inline
when no named groups exist.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 12:48:51 -04:00
nmemmertandClaude Sonnet 4.6 9acd0a792f Add group/course labels to spelling lists and flashcard decks
- group_name column added to lists and decks tables
- GET/POST/PUT endpoints for both include group_name
- Admin Spelling and Flashcards panels render items grouped under
  labeled section headers (e.g. Bible 6, Bible 8) with ungrouped
  items shown last
- Group input in each form has datalist autocomplete from existing groups
- Edit/copy populates the group field; Clear resets it

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 12:22:27 -04:00
nmemmertandClaude Sonnet 4.6 0ae0db76bc Add course duplicate and compact list/roster layout
- POST /api/courses/:id/duplicate deep-copies a course with all units,
  items, and quiz questions; opens the copy immediately for renaming
- Roster changed from broken vertical stack to horizontal chip-pills
  (fixes admin-card label override that was collapsing inline-flex)
- item-row padding reduced for tighter lists throughout admin
- Courses and Kids admin panels now use a 2-column auto-fill grid

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 10:48:38 -04:00
Nate EmmertandClaude Sonnet 4.6 3dc4ddea4b Add rich text editor for lesson content input
Replaces the plain textarea with a WYSIWYG contenteditable editor so
the formatting the parent sees while writing matches what the student
sees when reading. Toolbar supports bold, italic, underline, H2/H3,
bullet/numbered lists, links, and YouTube embeds. Selection is saved
on editor blur and restored before each execCommand so toolbar clicks
don't lose the user's selection.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 20:00:03 -04:00
nmemmertandClaude Sonnet 4.6 84b8f77a37 Fix back button from course view returning to My Courses tab
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 17:06:51 -04:00
nmemmertandClaude Sonnet 4.6 5adefce486 Allow deleting built-in spelling lists and flashcard decks
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 17:03:14 -04:00
nmemmertandClaude Sonnet 4.6 9889da3462 Show course name and assignment content in planner print
Week print: tasks grouped by day, each showing course name, type,
and full assignment body text. Month print: course name in calendar
cells + an Assignment Detail section below the calendar with body text.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 16:53:46 -04:00
nmemmertandClaude Sonnet 4.6 934919e392 Include assignment body and quiz questions in print course output
Course detail API now returns item body text and quiz questions.
Print course renders body paragraphs and numbered quiz questions
with lettered choices (correct answers marked with ✓).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 16:50:01 -04:00
nmemmertandClaude Sonnet 4.6 19fe0cb053 Add month planner view and print for courses and planner
- Month view toggle in planner (Mon-Fri calendar grid, 4-5 weeks)
- Prev/Next navigate by month when in month mode
- Print month report (landscape calendar layout)
- Print course button on course detail (all units + items)
- New GET /api/schedule-range endpoint for arbitrary date spans

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 16:47:28 -04:00
nmemmertandClaude Sonnet 4.6 3c22fe05f8 Add kid engagement features and planner drag-and-drop
- Streak tracker: server-side streak counting per kid, celebration overlay
  when all today's tasks are done for the first time that day
- Kid themes: 5 colour palettes (blue/green/purple/orange/pink), picked via
  colour dots on the kid home screen; parents can set it from the Kids panel
- Grading badge: Grading nav pill turns red and shows a pending count
- Print worksheets: 🖨 Worksheet button per word list in admin Spelling panel;
  kids also get "Print my words" on the Spelling tab
- Parent feedback: gold 💬 badge on Today rows with unread comments; more
  prominent callout styling inside the assignment view
- Planner drag-and-drop: tasks can be dragged between days; PATCH
  /api/schedule/:id moves the task, drop zones highlight on hover

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 16:40:07 -04:00
Nate EmmertandClaude Sonnet 4.6 8fa906b559 Fix speechSynthesis cancel before speak to unblock audio
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 09:38:20 -04:00
Nate EmmertandClaude Sonnet 4.6 6f2281e2a7 Add spelling improvements and local Piper TTS
Practice: fire streak badge, first-letter hint on wrong answers, missed-words drill session after practice completes.
Test: audio-only mode with listening state before input appears, larger re-read button.
Words: definition field (DB migration + admin editor + TTS playback).
TTS: replace speechSynthesis with local Piper via /api/tts, WAV cached in data/tts-cache, falls back to browser voice when Piper is not installed.
Dockerfile: switched to node:26-slim, installs Piper binary + en_US-lessac-medium voice.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 08:47:10 -04:00