Stats dashboard, template engine, and UI overhaul - #3
Merged
Conversation
…RS panels Add per-deck (with subdeck rollup) and time-range filtering to the stats screen, backed by a much richer StatsDto: true weekly retention, answer-button distribution, hourly breakdown, FSRS stability/difficulty/retrievability, a year heatmap with streaks, forecast + backlog, and a hierarchical deck breakdown table. Filters live in the URL so views are shareable/reloadable. Frontend charts follow a single-axis-only, fixed-categorical-color methodology, with count-up stat tiles, staggered entrance, skeleton loading, and CSV export per panel.
The stats-dashboard rebuild made get_stats the heaviest read command in the app, but it was still sync, so Tauri ran it on the main thread and blocked the UI event loop while it churned through the revlog aggregates. Made it async, matching every other heavy command (optimize_fsrs, create_backup, etc).
import_package blocked the UI thread and did per-note/per-card SELECT+INSERT/UPDATE round trips, dominating time on large decks. Async-ify the command (matches the get_stats fix), pre-load existing notes/cards into HashMaps before merging, and use prepare_cached for the remaining statements. Also surfaces live import progress to the UI via a new synapse://import-progress event.
Add a per-deck, per-day new-card limit override (day_limit_overrides table + Collection::increase_today_new_limit), wired through the scheduler so it actually raises today's new-card cap. Expose it via a new + control on each deck row and on the "all done" screen. Also removes the old "study at most N cards this session" box, which was unrelated to the daily new-card limit and looked/behaved poorly.
Decks and Study were separate pages over the same deck-list data, with Study duplicating its own picker and no rename UI despite the backend already supporting it. The deck list is now the study launcher: click a deck to enter /study/$deckId (route-param session, so refresh and back both work), manage decks (create, rename, delete, options, filtered rebuild/empty, increase-today's-limit) from the same row via hover actions and an overflow menu, and see today's workload at a glance in the header. Studying or counting a parent deck now rolls up its whole non-filtered subtree (Anki behavior) instead of only its own cards, since the merged UI makes parent rows far more clickable than before. Each subdeck still respects its own daily limits; cross-deck learning-queue merges sort by due time. Fixed a related bug this surfaced: answer_card computed remaining counts from the answered card's own (leaf) deck instead of the session's root deck, which would have shown wrong header counts and broken next-card fetch for any parent-deck session.
Header checkbox now renders a dash when some but not all visible rows are selected, instead of only checked/unchecked.
Tauri's setup() closure ran DB backup zip, full search-index rebuild, and plugin install synchronously before the window became responsive, causing "Not Responding" on every launch. Only the DB open/migration (cheap, required for command state) stays sync; the rest now runs on a background thread after collection state is managed.
…ounts Day boundary was a fixed 24h block anchored to collection creation instant, with no timezone or rollover-hour concept. Added an Anki-style rollover hour (default 4am, local time) in Settings, and made the day-number/day-cutoff math in Collection::today() honor it. Also fixes new-card counts going stale in the deck browser when the app is left open across a day boundary: the deck list query only invalidated on mutation events, never on the passage of time, so it now polls every 60s.
…itor Rewrites synapse-render as a proper tokenizer/AST parser (fixing nested conditionals) and adds every remaining Anki template feature: hint, cloze-only, type:cloze, tts/tts-voices, furigana/kana/kanji filters, and special fields (Tags/Deck/Subdeck/Type/Card/CardFlag). Renders cards inside a shadow DOM (CardFace) so per-notetype CSS from imported decks or user edits stays isolated from app chrome, with a new "modern editorial" default stylesheet and six auto-seeded stock note types (Basic, +reversed, optional-reversed, type-in, Cloze, Image Occlusion). Rebuilds the field editor with a full formatting toolbar (colors, sub/sup, lists, cloze shortcuts, image/audio insert, LaTeX helper), adds SpeechSynthesis-backed TTS unified into the sound playback queue, and a drag-to-draw image occlusion editor with mode-aware shape rendering. Also fixes a same-name notetype collision where importing a .apkg could silently keep an unused stock notetype's templates instead of the imported deck's own.
…zable home Collapse the stacked titlebar/header/screen-header chrome into two slim layers, apply a glassy translucent chrome/panel treatment with a cooler accent, add a manual focus mode for study (F/Esc, progress bar, vignette), and let the deck browser switch between list/grid/hero layouts. Flashcard rendering itself is untouched. Also fixes a latent bug where study shortcuts (s/b/r) could fire while typing into the type-answer field.
cargo fmt --all had accumulated formatting drift across several crates; renderCard.ts assigned walker.currentNode to a variable that was immediately overwritten by the loop condition, tripping eslint's no-useless-assignment rule.
prettier --write across the workspace (pre-existing formatting drift, mostly in files this branch never touched); satisfy two new clippy lints (manual_is_multiple_of, redundant_guards) surfaced by a newer clippy version.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Test plan
pnpm lint,pnpm test,pnpm buildpass (verified for the UI overhaul commit)