Overview
Notentool is a single-page web app for keeping a personal grade book, built for Module 294 (JavaScript). It tracks four things, semesters, subjects, exams and homework, and computes what a student actually cares about: the weighted average per subject and per semester, the plus/minus points, and whether you are on track to pass.
The brief shaped the build: pure HTML, CSS and vanilla JavaScript, no framework, no build step, no server. Everything is stored in the browser's localStorage, so the data never leaves the device, there is no account to create, and a reload keeps everything exactly where it was.
What It Does
Four entities, one consistent flow: a floating "+" opens a form, the list shows what you have, and every derived number is recomputed on read, never stored stale.
Four entities, full CRUD
Create, list, search, edit and delete for semesters, subjects, exams and homework, each behind its own validated form with the right input type for every field.
Weighted averages
Per subject and per semester, weighting each exam by its weight. An empty set returns "no grade yet" instead of a misleading zero.
Plus/minus points
pp = grade − 4.0, rounded to half steps (Swiss model): 3.4 becomes −0.5, a clean 6.0 becomes +2.0.
Promotion check
Tells you whether you are on track, using the Swiss rule (double minus points against plus points) plus any per-subject minimum average you set.
Exam countdown
A live countdown to the next exam, with its priority derived automatically from the current subject average.
Dashboard
An at-a-glance view of the active semester: overall average, plus/minus, upcoming exams and open homework in one place.
Calendar
Upcoming exams (no grade yet) and homework in one list, sorted by date, with Eisenhower-style priority for what to do first.
Switchable grade scales
Multiple scales selectable at runtime (default Swiss 1.0–6.0, 4.0 = pass), each with its own pass threshold.
Under the Hood
No framework, no server
Pure HTML, CSS and JavaScript. Nothing to install, no build, no packages, it is just files running in the browser.
Robust localStorage
Reads go through try/catch and check the shape of the data, so a single corrupt entry can't take down the app, it falls back to an empty list.
Layered by concern
Storage, calculations and validation are pure functions in separate files; a single view layer builds the UI from them. Each file has one job.
Native dialog + FAB
Forms live in native <dialog> modals opened from a floating "+" button, so the modal behaviour is the browser's, not hand-rolled.
Cascading delete + undo
Deleting a semester removes its subjects and exams too; a toast offers a one-click undo, so an accidental delete is reversible.
Local-time dates
Custom date helpers compute in local time instead of UTC, fixing the off-by-one-day shift that toISOString quietly caused.
Double validation
Every field is checked in JavaScript and backed by native HTML constraints (required, min/max, maxlength), so bad input is caught twice.
Tech Stack
| Type | Single-page app (vanilla JS) |
|---|---|
| Languages | HTML5, CSS3, JavaScript (ES2020+) |
| Persistence | Browser localStorage (JSON) |
| UI | Native <dialog> modals, inline SVG icons |
| Architecture | Layered pure functions (storage / calc / validation) + view layer |
| Fonts | Bebas Neue (display) + Inter (body) |
| Testing | Custom in-browser test runner (113 tests) |
| Standards | W3C-valid HTML & CSS |
| Backend | None, runs entirely client-side |
| Module | M294 — JavaScript (school project) |
Testing & Validation
Because the brief allowed no frameworks, the project ships its own tiny test runner: it compares each pure function against expected values and shows a pass/fail list, 113 tests, all green. Several of them caught real bugs first, the timezone date shift and a divide-by-zero in the average among them. HTML and CSS both pass the W3C validators.
Status
Notentool was built for Module 294 and is complete (version 1.0). It runs fully in your browser, so go ahead and open the live demo above: create a semester, add subjects and grades, then reload and watch the data persist. Everything stays in your browser's local storage and nothing is sent anywhere.