Commit graph

27 commits

Author SHA1 Message Date
spearzificial
deaa6d9b3d Result page: share box with copy-link button for the paper's public URL 2026-10-17 11:03:35 +05:30
spearzificial
22c6c24e87 Result page: score-banded encouragement card (ZenithPrep modal analogue) 2026-10-17 10:53:36 +05:30
spearzificial
adefc976fe Result page: sticky left nav with section anchors, negative-marks card, mistakes badge 2026-10-17 10:45:30 +05:30
spearzificial
b12f7dcac1 Bust Cloudflare cache for style.css and exam.js via ?v=4 2026-10-17 10:22:17 +05:30
spearzificial
aae54300be Replicate ZenithPrep active-exam UI: white question card with inline options, 5-state CBT palette, NTA action bar 2026-10-17 10:04:23 +05:30
dev
374e2e2056 Paper preview in ZenithPrep style: stat cards, subject sections
shared() now renders: stat cards (questions, duration, max marks,
+4/-1), per-subject sections with q-ranges and chapter lists, a
'take this paper' card with the save-and-next explainer and privacy
note, then the full question list. New .kv/.grid2/.subj-sec/.ch-list
CSS with mobile single-column fallback.
2026-10-16 14:56:27 +05:30
dev
600ff95315 Fix rich() eating raw < in math, title-case chapter titles
Sanitizer root cause: a '<' followed by space/digit (e.g. '\(a < 0\)')
was parsed as a tag, failed allowlist, and got DELETED along with its
content — unbalancing KaTeX delimiters and killing all math after it
on the page. Now only '<' followed by letter, /, ! or ? starts a tag;
everything else becomes &lt;. 4 regression tests added.

CSS: .zp-chk-wrap and .zp-subtopic-row labels no longer inherit the
generic uppercase rule, so chapter names render in DB title case
('Quadratic Equations', not 'QUADRATIC EQUATIONS').
2026-10-16 14:38:23 +05:30
dev
5b732080d6 Bump favicon and apple-touch-icon to v3 (darkened artwork) 2026-10-16 13:23:49 +05:30
dev
21dfdde92d Cache-bust logo and embed URLs (v3) for darkened artwork 2026-10-16 13:16:13 +05:30
dev
71b637c9fb Darken whale logo to match site theme, username placeholder
- Logo: modulate 78 brightness / 88 saturation on the v3 whale source.
  Verified clean (no line artifacts on black-flatten). Regenerated
  logo.png, favicon.png, apple-touch-icon.png, and embed.png from it.
- Username input placeholder: 'e.g. Aarav Sharma' -> 'e.g. Nikhil The Great'.
2026-10-16 13:08:16 +05:30
dev
28e4c09e06 Cache-bust favicon and apple-touch-icon URLs (v2)
Cloudflare edge cached the old placeholder bytes on the bare
/static/favicon.png and /static/apple-touch-icon.png URLs. The ?v=2
query string forces a fresh origin fetch with zero behavior change.
2026-10-16 12:17:14 +05:30
dev
84060de856 Replace placeholder logo with user's whale artwork
- logo.png: user's whale (1024px JPEG) with background flood-filled to
  transparent at fuzz 3 (preserves white belly details), alpha
  thresholded to kill JPEG-noise halos, trimmed and centered on
  720px canvas. v3 verified clean: no streaks, no box lines, no fringe.
- favicon.png (32px) and apple-touch-icon.png (180px) regenerated
  from the same source.
- embed.png (1200x630) rebuilt: whale at 440px left, no overlap with
  the WhalePrep title text.
- views.rs: nav brand now references logo.png instead of logo.svg.
2026-10-16 12:04:45 +05:30
dev
b1b6887a26 Add whale logo, favicon, apple-touch-icon, and social embeds
Logo: hand-crafted SVG whale silhouette in blue gradient (#3b82f6 to
#1d4ed8), DeepSeek-inspired minimalist style with water spout, eye,
and wave arc. Renders at 28px in the nav header.

Embeds: Open Graph and Twitter Card meta tags on every page. og:image
is a 1200x630 embed card with the whale logo, WhalePrep title, tagline,
and stats. Favicon.png (32x32) and apple-touch-icon.png (180x180)
generated from the same SVG. theme-color #0a0f1c for mobile browsers.
2026-10-16 00:53:46 +05:30
dev
7c4b1a4009 Fix stray dollars, remove dead UI, clear selection feedback, count input
Dollar fix: 5,634 questions had a lone $ before \( or $$ from the
source data. fix_single_dollar now strips any orphan single $ while
preserving $$..$$ display pairs; the live tablet DB was patched in
place and the importer inherits the fix.

UI: removed the non-functional 'previous year paper' mode card, the
complete-syllabus button, the tick glyph inside filter pills, and the
'2025 Syllabus' badge beside the header title. Question count pills
replaced by a plain number input (5-75). Checked chapters now show a
blue left-edge highlight so a second click visibly deselects; checked
subtopics tint blue the same way.
2026-10-14 16:30:17 +05:30
dev
ab7486bcc2 ZenithPrep-style build page with difficulty and year filters
Replicates zenithprepare.com/PYQ topic-selection UX:
- Subject switcher pills (Maths/Physics/Chemistry) with live selection
  counters; only the active subject's chapters are shown.
- Searchable chapter rows with independent subtopic expand arrows
  (checking a chapter no longer toggles the tray).
- Complete-syllabus one-click button (selects all 15 units, 75 Qs,
  JEE mode).
- Difficulty filter pills (Easy/Medium/Hard, default all) and year
  filter pills (2018-2025, default 2020-2025) wired through new
  difficulties/years form fields; build_paper filters both, including
  the FIFO recycle path. Verified end-to-end: Hard-only paper returns
  only Hard questions; Medium+Hard across 2022-2025 leaks zero Easy.
- Settings bar with count pills, JEE-mode toggle and live pool
  estimate.
Also fixes: brand header badge, raw-string delimiter clash with SVG
hex fill, Maths subject-key mismatch between pills and DB.
2026-10-14 10:14:46 +05:30
dev
54ba844f92 Revamp UI/UX, fix UTF-8 mojibake, normalize question typography, and reorganize JEE portions
1. UTF-8 Bugfix: Fixed byte-casting in views::rich() that turned multi-byte UTF-8
   sequences into Latin-1 mojibake (e.g. 2.06 × 10 -> 2.06 × 10).
2. Question Typography: Replaced nested <p class='stem'> with <div class='stem'>
   and strict CSS overrides ensuring consistent 1.0625rem font-size and weight
   across all 9,837 questions regardless of inner tags.
3. Modern Educational Theme: Removed harsh minimal 0-radius monospace styling;
   introduced comfortable slate dark theme (#090d16), rounded corners (8-12px),
   Inter typography, and refined option card states.
4. Topic Selection (/build) Revamp:
   - Added Quick Presets bar (Full Mock 75 Qs, Physics/Chemistry/Maths focus, Clear).
   - Added Subject Navigation Tabs (All, Physics, Chemistry, Mathematics).
   - Independent subtopic expand chevrons that don't force-check parent chapters.
   - Live question pool estimator and interactive count pills.
5. JEE Portion Reorganization (scripts/reorganize_jee_db.py): Re-categorized
   the database into the 15 official JEE Main units across Physics, Chemistry,
   and Mathematics.
2026-10-13 11:09:12 +05:30
dev
338aa2e8ef Print stylesheet: light surfaces for options/inputs, print buttons
Exam/solution pages print clean via browser print-to-PDF: interactive
chrome hidden, questions unhidden, ink-friendly colors. Options printed
as black bars without the surface override — .opt/.chk/inputs/palette
now forced white. Verified with print-media emulation screenshot.
2026-10-13 08:28:54 +05:30
dev
32f5e7a440 Remove dead SubtopicRow struct (zero-warning build)
Unused since the chapter-block refactor. Build is warning-free;
25 tests green (16 unit + 2 form + 7 grading).
2026-10-13 08:17:54 +05:30
dev
dc754fe996 Student sign-in UX, gzip, landing stats cache
Sign-in page rewritten for non-technical students: Google-first when
configured, plain-language email path with honest 30-day scope, recovery
note, placeholders, full-width CTA. deploy/termux-start.sh sources .env
for GOOGLE_* credentials; deploy/env.example documents the 5-minute
Cloud Console setup; .gitignore covers secrets, DBs, pid/log files.
bench scripts send a browser UA so Cloudflare bot checks stop 403ing
local load tests. Landing bank counts cached 60s (five aggregate
subselects no longer run per hit). gzip compression on all responses.
2026-10-12 23:33:33 +05:30
dev
f796c566b9 Owner paper route plus take-paper CTA on shared pages
GET /paper/:id redirects the owning user to their attempt screen (404
otherwise, login wall otherwise). Shared /s/:token pages now end in a
real action instead of a dead list: signed visitors get a take-this-paper
button, anonymous visitors get a sign-in link preserving the share URL
as next. Verified live: 1/302/1 across the three states.
2026-10-12 13:25:17 +05:30
dev
4427837e7a Mistake tagging: per-question why-lost form plus dashboard rollup
Result page shows a why-lost row (concept gap / calculation slip /
misread / out of time / blind guess) on every wrong or blank question.
POST /result/:attempt/tag/:qid toggles one tag; ownership checked,
vocabulary enforced server-side. Dashboard gains a 'why you lose marks'
section aggregating tags across all submitted attempts. Verified live:
tag persists, rollup renders.
2026-10-12 12:44:30 +05:30
dev
45d2f38b0c Import 9,813 real JEE Main PYQs, KaTeX math, DB indexes
scripts/import_examgoal.py pulls the MIT-licensed examgoal-derived
14,973-question pickle and keeps the 9,813 fully-text MCQs with single
correct answers (2002-2025, all subjects). chapterGroup becomes our
chapter, chapter slug becomes our subtopic. Idempotent: skips stems
already present.

views.rs gains rich() — a read-side sanitizer matching the importer's
allowlist — and all six stem/option/solution render sites use it.
KaTeX auto-render (trust:false) added to head() for $$..$$ math.

db.rs gains nine CREATE INDEX statements; the chapter loader query
drops from ~5s to 6ms on the 9.8k-question bank. DATA.md rewritten
around the real pipeline with attribution.
2026-10-12 10:55:20 +05:30
dev
5c4b8ab7f2 Rename zenith-pyq-clone to whaleprep
Package, binary, tracing filter, footer copy, run_server.sh and README
updated. Footer no longer attributes zenithprepare.com.
2026-10-12 08:17:40 +05:30
dev
1d8ee3b5ff Subtopic picker, JEE mode, per-subject timers
The builder previously exposed only chapters. Now each chapter expands to show
its subtopics as individual checkboxes: selecting a chapter checks all of its
subtopics, selecting the subject-level box checks everything, and selecting
individual subtopics sets the chapter to indeterminate. The exam query filters
by subtopic_id when any are given; the SQL path deduplicates so a question
matching two subtopics only appears once.

JEE mode sets duration to 60 × unique-subject-count (180 min for a full paper).
On the exam screen this renders per-subject countdown strips: Physics 60:00,
Maths 60:00, Chemistry 60:00. Each strip counts down independently; when one
hits zero the screen auto-jumps to the first unanswered question of the next
subject. The last strip exhausting time submits the form.

Single-subject papers keep the flat timer and show no strips.

Also: all audit targets now genuinely 44px (the .opt labels were 42px).
2026-10-12 05:13:09 +05:30
dev
14542f169a Make the exam screen work on a phone
The screen had no mobile state at all: the clock scrolled away mid-paper, the
only navigation was save-and-next so a candidate could not go back, the palette
sat below the question where it pushed submit off-screen, and the nav row lost
three of its four links under 700px.

Sticky header carries the clock and a progress bar; previous/next are real
buttons; the palette is a drawer below 1024px opened by a floating button that
sits above the tab bar. Primary destinations move to a bottom tab bar on
phones, data tables scroll inside their own card, and every control meets the
44px touch minimum.

Verified with a headless browser across five viewports rather than by reading
the stylesheet: scripts/audit_mobile.py fails on horizontal overflow, tap
targets under 44px, and content hidden behind a fixed bar; scripts/shots.py
captures each page at both widths. Both caught bugs I would otherwise have
shipped, including a palette toggle that lived inside the drawer it opened and
so could never be pressed on a phone.

fmt_dur drops a leading zero hour, so a 24 minute paper reads 24m 00s.
2026-10-11 21:54:17 +05:30
dev
3f88f6c388 Google sign-in with server-side token verification
Two paths, one session. The GSI popup posts an ID token to /student/google;
where a popup is refused a PKCE authorization-code flow redeems server side at
/student/google/callback, keeping the client secret out of the browser.

ID tokens are verified here rather than trusted from the browser: RS256
signature against Google's published JWKS (cached an hour), audience pinned to
this client, issuer restricted to Google, expiry enforced, email must be
verified. State is single use and expires in ten minutes. Without
GOOGLE_CLIENT_ID the button is hidden and the email form is offered instead.

13 tests cover the verification rules using locally generated RSA keys,
including rejection of a foreign signature, a wrong audience, a wrong issuer,
an expired token and a rewritten payload. An example signs a token from an
untrusted key so the rejection path can be checked without a Google account.
2026-10-11 20:37:56 +05:30
dev
d3001612b2 PYQ clone: builder, CBT exam screen, grading, analytics dashboard
Axum + SQLite full-stack copy of the ZenithPrep PYQ practice app.
Paper builder with unseen-question exclusion, timed CBT screen with
palette and autosave, +4/-1 grading with numerical tolerance, per-question
analysis, history, dashboard with weak-subtopic tracking and coach notes.
2026-10-11 20:06:26 +05:30