feat!: calm design system, rebuilt tools, shareable links#54
Merged
Conversation
Deploying swiss-grades with
|
| Latest commit: |
508c393
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://40a5f0cf.swiss-grades.pages.dev |
| Branch Preview URL: | https://next.swiss-grades.pages.dev |
Load Inter alongside JetBrains Mono and register both as Tailwind --font-sans / --font-mono. The body now defaults to Inter for UI text, while numeric values stay monospace via the font-mono utility (applied here to the grade and weight inputs in GradeRow). Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
The large grade result numbers used a fixed text-8xl and overflowed on phones; they now scale text-6xl -> sm:text-7xl -> lg:text-8xl and keep the mono font. Page headings step down from text-4xl to text-3xl on small screens, and numeric inputs/results use the mono font. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
…blet - Final grade scales text-6xl -> sm:text-8xl -> lg:text-9xl (was a fixed text-9xl that overflowed on mobile). - The status badge no longer clips: dropped the fixed sm:w-28 width in favour of a full-width, centered, wrapping badge so "Keine Fallnote" and the longer FR/IT strings fit. - The 5-column component grid now activates at lg instead of sm, so tablets keep the comfortable stacked-card layout. - Heading is responsive and grade/weight values use the mono font. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Convert all tracked text files from CRLF (and mixed CRLF/LF) to LF, the standard on Linux, and add a .gitattributes (`* text=auto eol=lf`) so git checks out and normalizes text files to LF going forward. This prevents the phantom whitespace churn that mixed endings caused on edits. No content changes — line endings only. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
The Inter pairing felt too different from the original monospace look; revert the body font to JetBrains Mono and drop the Inter web-font load. The --font-mono token and font-mono utilities stay (everything is mono again, so they're harmless no-ops on already-mono numeric elements). Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
daisyUI's .badge has a fixed height and overflow clipping, so the longer "Fall grade < 4.0" status (and its FR/IT equivalents) was cut off when it wrapped. Add h-auto + min-h-8 so the badge grows to fit wrapped text. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
The btn-ghost clear/reset buttons set no text colour, so they fell back to
daisyUI's default and were nearly invisible against the dark (Mocha) base.
Add class:text-ctp-subtext1={!confirmClear} so the resting state follows
the Catppuccin theme; the red confirm state keeps text-ctp-base. Applies
to the QV reset button and the clear buttons on average/calculator/needed.
Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
The icon variable was lowercase (activePresetIcon), so Svelte rendered <activePresetIcon> as a literal unknown HTML element instead of the component, leaving the selector button's icon slot empty. The selection modal worked because it used a capitalised const (ItemIcon). Rename to ActivePresetIcon so the chosen preset's logo renders on the button too. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Part of the UI rework. Retune the global daisyUI tweaks in app.css to a calm, consistent baseline (hairline borders, one radius scale, restrained font weights, soft shadows, a .section-label helper) and add small shared components to DRY up the pages and keep them consistent: - Page: standard heading + spacing shell - ToolbarRow: rounding + actions header - ClearButton: two-step confirm reset (was duplicated on all 4 pages) - ResultDisplay: understated inline result + optional pass/fail chip - StatusChip: one tonal pill for all statuses - EmptyState: calm placeholder - NavLink: single nav item (icon + active state), replaces 8x duplication Calm RoundingSelect/ShareButton to match. No page wiring yet; no logic changes. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Replace the 8x-duplicated nav active-state markup (desktop bar + mobile drawer) with a single NavLink component driven by a tools array, each with an icon (Average=scale, Points=convert, Required=flag, QV=cap) and one consistent active treatment + focus ring. Labels collapse to icon-only below md via short i18n labels (navShort) to keep the bar tidy. Also: align the footer width to the main container (max-w-5xl, was 3xl), calm the locale dropdown and brand mark, and add shared i18n strings (navShort, common.pass/fail/emptyState, calculator/average subtitles) to all four locales. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Wrap in <Page>, use ToolbarRow/ClearButton/ResultDisplay/EmptyState. Replace the giant glowing result card with an understated inline result + pass/fail chip, add an empty state, and render the formula as calm borderless text. No calculation changes. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Wrap in <Page>, move the rounding/CSV/share into ToolbarRow, replace the inline clear logic with <ClearButton>, and swap the giant glowing result card for an understated inline ResultDisplay + pass/fail chip (empty state when there is no average yet). Delta pills use calm tonal colors. Calm GradeRow weights/borders to match. Drag-reorder and keyboard shortcuts unchanged. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
…esult Wrap in <Page>, use ToolbarRow/ClearButton/ResultDisplay/StatusChip/ EmptyState. Future-exam rows now stack cleanly on mobile (name on top, weight + remove below) instead of a cramped fixed-width flex. Replace the results table that repeated the same required grade for every exam with a single clear result (or an impossible/achieved chip), with the assumption and best-attainable as calm footnotes. Calculation unchanged. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Wrap in <Page>, flatten the cards (hairline borders, soft shadows, one radius), drop font-black/glow, and replace every fall-grade/status pill with the shared <StatusChip> (tonal success/error/neutral). The final grade is now understated (no giant glow) with a calm pass/fail chip, and the reset uses the shared <ClearButton>. Sticky column header aligned to the 80px navbar. No QV logic changes. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Rename the nav tabs to concise, clearer words (Average / Calculator / Target / QV) in all four locales, and add common.clearAll/clearConfirm so every page can share one consistent clear/reset label. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Remove the per-tool icons from the top bar and drawer (NavLink icon is now optional) and show the concise renamed labels at all widths. Cleaner, less "vibecoded" navigation. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Polish round from review feedback: - New ShortcutHint component with a theme-safe .kbd-key style — the old keyboard hint was unreadable in dark mode and too small. - One consistent clear/reset label everywhere (was "Reset QV" vs "Clear all"); unify the Add grade / Add exam button styles. - Replace the bespoke QV track "join" buttons with a clean segmented control matching the rest of the app. - Remove the per-page subtitles and flatten the QV overview icon chips to a single lavender accent (drop the multi-colour rainbow). Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
The greenfield UI uses a hand-built Catppuccin token layer instead of daisyUI's theme/component system, and inline SVGs instead of the flowbite icon set. Removing both deps also drops the vite optimizeDeps workaround. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Hand-built two-theme token system (Latte light leaning white, Mocha dark) mapped onto Tailwind v4 utilities via @theme inline so colours switch at runtime with [data-theme]. One blue accent; --ctp-green/-yellow/-red stay reserved for pass/warning/fail (read by gradeColor). Latte warning yellow darkened for contrast on white. Neutral system sans, tabular-nums helper, visible focus ring. app.html bootstrap bg now white/Mocha; dropped the JetBrains Mono web font. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Sticky top nav with the four tool tabs (full labels, short labels on mobile, horizontal scroll if tight), a sun/moon theme toggle and a compact language select. Layout applies the active theme + lang to <html> and wraps each tool in a centered main; footer shows version/commit/build date. BREAKING CHANGE: The previous mobile off-canvas navigation drawer, the keyboard-navigable language dropdown, and the page fade-in / transition animations are removed in favour of a simpler top bar and a native language select. (The mobile drawer is reinstated in a later commit.) Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Page wrapper (title/subtitle, narrow/wide), Button (primary/secondary/ ghost/danger), NumberField (numericInput + clampInput actions), RoundingSelect, ShareButton (copy with feedback + prompt fallback), ClearButton (two-step confirm), ResultBar + StatusChip for understated inline results, EmptyState and ShortcutHint. Button/input/label base styles live in an app.css component layer driven by the design tokens. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Live result from (points × 5 / max) + 1 with the shared rounding select, share and two-step clear. Subtle formula display, understated inline result coloured green/yellow/red with a pass/fail chip, and the invalid / out-of-range states. Inputs and rounding persist via the settings store; share payloads round-trip on mount. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Recursive grade rows with nested sub-grades (parent grade derived from its children), drag-to-reorder within each sibling list, and Ctrl+Enter / Ctrl+Delete to add and remove the focused row. Live weighted average with the shared rounding select, understated pass/fail result, CSV export (disabled until there is exportable data), share and two-step clear. State persists via the grades store; share payloads hydrate on mount. BREAKING CHANGE: The rebuilt Average drops the per-row delta chips (each grade's difference from the running average) and the grade-input border colour coding that the previous UI provided. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Pulls the weighted sums from the Average grades and solves for the grade needed in every future exam to reach a target average, under the stated assumption of the same grade in all of them. Handles already-achieved (g<=1), impossible (g>6, with best-attainable at 6.0) and the no-grades / invalid-target states. Future exams add/remove with Ctrl+Enter / Ctrl+Delete, new stores/needed.ts persists target + exams, and share payloads carry the grade snapshot so links reproduce. BREAKING CHANGE: The Required Grade tool's saved state (swiss-grades-needed) adopts a new shape; state written by the previous version is not read back and falls back to defaults. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Apprenticeship preset + path selectors (path shown only when the preset has more than one), localized component cards with direct grade entry or expandable part-grades, and the Variant select for ABU/eGK modes (including dispensed). Live final grade via evaluateQV with fall-grade status per component, pass/fail/pending result, failed-fall-grade and required-grade guidance, plus the localized overview and sources. State persists via the qv store and share payloads round-trip on mount. BREAKING CHANGE: The rebuilt QV drops the completion progress bar, the visual preset-picker modal (now a plain select), the sticky desktop column header, and the per-variant mode descriptions from the previous UI. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Ghost buttons (add/details/clear idle) get a hairline border so they read as buttons; the QV Details toggle gains a chevron. QV clear now uses the shared 'Clear all' label for consistency with the other tools. QV component rows stack the label full-width on mobile so the grade input no longer overlaps it. Average grade/weight inputs use the short placeholders (no truncation), and the nav switches to short labels below md so 768 no longer clips. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Full labels overflowed at 768; switch the nav to short labels below lg so the wordmark, tabs and settings fit comfortably from 360 up to ~1024, with full labels on wide screens. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Re-add three niceties from the old UI: ShareButton now tries the native navigator.share() sheet first (clipboard, then prompt as fallbacks); QV component descriptions return as a hover tooltip on the label; and QV weights are shown as each component's share of the active weight, so BM / dispensed tracks read correctly (e.g. IPA 57.1% / IK 42.9% over 70%) while the regular track is unchanged. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
- Re-add the mobile hamburger off-canvas nav drawer (slide-in panel, backdrop, Escape/backdrop/link close); inline tabs now show from sm up. - Gate tool + nav-label content on hydration so non-German users no longer see a flash of the prerendered default locale. - Clamp grade weights to 1-100 (Average rows and Target future exams). - Fix the delete shortcut on macOS: accept Cmd+Backspace (without breaking Ctrl+Backspace word-delete on Windows) and show the platform hint as Cmd/erase. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
The sun/moon icon was rendered from the theme store, which is 'latte' during the prerender, so dark-mode users saw the light-mode icon until hydration. Render both icons and let CSS pick via html[data-theme] (set before first paint in app.html), so the correct icon shows immediately with no flash. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
- Align header, content and footer to one centered max-w-3xl column so the
whole page reads as centered; top nav uses short labels (full names stay in
the drawer), and the wordmarks are brand-accent.
- Make toolbar buttons consistent: ghost buttons now use the same text colour
as secondary ones (they were muted, which read as a different/lighter font).
- Rebuild the footer as a proper multi-column layout (brand + version badge /
commit / date, Tools and Project link columns) modelled on osc-skins-ui,
centered on mobile; add the footer i18n strings for all four locales.
- Fix a cascade bug: the global a{color:accent} was unlayered and overrode
text-muted/text-accent on links (nav tabs and footer links were all blue);
move it into @layer base so utilities win.
Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
- StatusChip: drop the filled pill; a small coloured dot + coloured text reads cleaner and less generic. - Footer build metadata: remove the dot-bullet separator and the version pill; make the whole 'version commit date' line one link to the GitHub release. - ShortcutHint: larger, filled keycaps with a darker label so ⌘/⌫ are legible on macOS, and hide the whole hint on mobile (no keyboard there). Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
…e labels - Center the nav tabs between the wordmark and the language/theme controls. - StatusChip: drop the coloured dot; show just green/red/yellow (or muted) text so a status reads as a word, not a badge. - Reword the fall-grade status: 'met' / 'not met' (DE 'Fallnote erfüllt' / 'nicht erfüllt', FR 'suffisante' / 'insuffisante', IT 'sufficiente' / 'insufficiente') instead of 'ok' / '< 4.0'. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
- Let the QV fall-grade status size to its content and never wrap, so 'Fallnote nicht erfüllt' stays on one line (verified no overflow at 360 in de/fr/it). - Footer version line now links to the repository root instead of the release tag. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Split the advisory sentence onto its own line and lay the sources out as a wrapped, generously-spaced list of underlined links instead of a single comma-jammed run, so each source is easy to tell apart. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
… rows - Weight inputs now use a language-independent '%' suffix (NumberField gains a suffix adornment) instead of the long '(%)' word that overflowed in de/fr/it on the Average and Target pages. - Restore the informative grade placeholder 'Note (1.00 - 6.00)' and widen the grade field so it fits, and add a 'Note' placeholder to the QV part-grade inputs. - Average rows never wrap on mobile: hide the subject name and drag handle on small screens so grade + weight + actions stay on one line (no overflow, verified de/fr/it at 360). - Default to 5 grade rows instead of 10 (store default, clear-all, and share hydration fallback). BREAKING CHANGE: The default number of blank grade rows changes from 10 to 5, and on small screens the subject-name field and drag handle are hidden. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
- Grade inputs now normalise on blur: clamp to 1-6 and format to 2 decimals (5 -> 5.00, 7 -> 6.00, 0 -> 1.00, 4.1 -> 4.10). Applies to Average grades and sub-grades, the Target average, and QV component + part-grade inputs, via a new decimals option on NumberField / clampInput. - Fix deep sub-grade nesting: a parent grade now resolves recursively from the bottom up, so a layer-4 leaf propagates all the way to layer 1 (previously it only read one level down and stalled). - Target: drop the exam name field on mobile so the row stays on one line. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
At the deepest layer the add-subgrade + button is hidden; render an equal-size spacer in its place so the button column keeps its width and the weight field no longer shifts toward the delete button. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Add a commitOnBlur mode to NumberField and enable it for the Average grade and weight inputs, so a typed value only propagates to the parent grades and the result once you leave the field (matching the old behaviour). Calculator and Target inputs stay live. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
The future-exam list (per-exam names and weights) was confusing: the result
was the same required grade for every exam, so names never mattered and the
weights were an advanced concept. Replace it with a single 'remaining exams'
stepper (each exam counts as one grade) and show one result line. Keeps the
already-achieved / not-reachable states, rounding, share and clear. The store
is now { target, count } (migrates the old shape); share still round-trips via
the futureExams array.
BREAKING CHANGE: The Required Grade tool no longer supports naming future exams
or giving them individual weights; it now takes a single count of remaining
exams, each weighted as one normal grade. Saved state and old share links are
migrated, but any per-exam weights they carried are dropped.
Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
Delete the CSV export feature: the Export CSV button, the utils/export.ts module, and the CSV i18n labels. Also remove code left unused after recent refactors — the EmptyState component, utils/focus.ts, the gradeColor() helper, and 37 orphaned message keys per locale (needed-tool leftovers, QV overview/track/header strings, short placeholders, calculate buttons, and the moved QV clear labels). BREAKING CHANGE: The Grade Average CSV export is removed. Claude-Session: https://claude.ai/code/session_013Tk2vvh35kVV1JSkMfQSzu
…rload roundToHalf had no callers. computeNeededGrade's componentModes|number union and targetGrade param served a calling convention nothing used; target is always the passing grade. Collapse to a plain modes map.
Remove unused exports (getQVTrack, resetQV, KNOWN_STORAGE_KEYS, QVTranslationField) and the dead index/isSub bits in GradeRow. Hoist the duplicated parent-grade normalization into grading.normalizeGrades and reuse it in the average/needed pages and GradeRow. Trim restatement/section-marker comments. Claude-Session: https://claude.ai/code/session_01EJFCCxeKiB5XMyddwG4S2j
Verified findings from a next-vs-main review: - share: guard oversized URLs on send, clear ?share= after load so a refresh no longer clobbers edits, reject out-of-range shared grades, announce copy status via aria-live - qv: restore the per-preset description dropped in the rebuild - grades: guard missing subgrades in normalizeGrades - needed: resync the remaining-exams field on blur - centralize grade tone/pass logic in gradeTone/isPassing/toneColor; drop dead .btn-primary variant and stale comments Claude-Session: https://claude.ai/code/session_01EJFCCxeKiB5XMyddwG4S2j
Contributor
|
🎉 This PR is included in version 2.0.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
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.
Reworks the app end to end: a calm, consistent design system, rebuilt tools, and shareable links — same Swiss grading logic, tests, and Catppuccin theming.
Design system & shared components
app.css(Latte/Mocha): hairline borders, one radius/weight scale, no neon glow.Page,Button,ClearButton,ResultBar,StatusChip,NumberField,GradeRow,RoundingSelect,ShareButton,ThemeToggle,LocaleSelect,ShortcutHint,NavBar,Footer.daisyUIandflowbite-svelte-iconsdependencies.Tools
Chrome
Sharing
Housekeeping
export.ts,focus.ts, unused helpers); LF normalization +.gitattributes.Verification
bun run check— 0 errors, 0 warnings.bun test— 56 pass.bun run build— clean (Cloudflare adapter).