Auth pages, dialogs, the command palette, the user menu, Applications, the rich-text toolbar, the stylesheet editor and the error screens use the Material Symbols set instead of Phosphor; the icon subset gains the 35 glyphs they need. Phosphor stays for brand logos, the landing page and the icons printed on resumes. Also removes the form field and test mock that only wrapped the old rich input.
Six settings pages become Account, Preferences and AI & developer, with an
in-page nav beside a 680px column (tabs on tablets, a three-row root on
phones, which the Account tab opens).
- Account: photo upload, name, username with the instance host, and email,
each saving on blur; password, a two-step verification switch, passkeys and
connected sign-in; Export everything as one zip of documents and
applications; Delete account with the counts of what goes and typing
"delete"; Sign out.
- Preferences: Light, Dark and System tiles, the interface language and the
motion note.
- AI & developer: provider rows with Test ("Connected · 420 ms" or the exact
error) and an Edit dialog holding the switch and delete; Add provider with
all sixteen; API keys in a table with a New key dialog (30 days, 90 days,
Never), the key shown once, and Revoke with Undo; the MCP address with Copy.
The old settings addresses redirect, and links across the app, the command
palette and the user menu point at the new pages.
The dashboard becomes Documents: resumes and saved letters in one
library, in a new app shell (a 240px sidebar, an icon rail on tablets and
bottom tabs on phones) with Documents, Applications, Trash (when it has
items), New (N) and the account row.
- Documents: All / Resumes / Letters with counts, search (/) across
titles, tags and linked applications, sort, grid or list (remembered on
the device), tag chips once tags exist, cards with the real first page,
"Resume · Edited 2h ago", the linked application, lock and "New" badges,
and the first-run screen. A file dropped anywhere on the page imports.
- One menu on cards, rows and right-click/long-press: Open, Rename
(inline), Duplicate, Copy for a job… (resumes) or Link to application…
(letters), Tags…, Lock editing, and Move to Trash with Undo.
- Trash lists days left, with Restore and Delete now (asks once).
- New: import a file in three labelled steps with the result and flagged
fields (resumes, and saved letters' JSON), copy a resume for a job,
start blank (named after its headline until renamed), a new letter, or
a sample resume.
Also:
- /dashboard/resumes and /dashboard/cover-letters redirect to Documents.
- Settings pages sit behind a tab strip until they're regrouped, and the
account menu gains Settings.
- A letter written inside a resume can be copied to Documents from its
entry menu (Q3k), replacing the library's copy action.
- The builder's document menu and the letter editor move documents to
Trash instead of deleting them.
- Dialogs reopened right after closing start fresh.
- Removed: the resume and letter libraries and the old create and import
dialogs.
Replace the achromatic shadcn palette with the Desk & Paper tokens (warm
neutrals, one moss accent, danger, warn and info), exposed to Tailwind
under their spec names; the previous names resolve to the new tokens
until every screen is rebuilt. Hard-coded palette classes become semantic
tokens and stage colors follow the spec.
Fonts move to Newsreader, Hanken Grotesk and JetBrains Mono. The theme
gains a System option that follows the operating system live, applied
before first paint, and Base UI now receives the locale's direction.
Primitives follow the component spec: button variants primary,
secondary, ghost, danger and link with a loading state, accent focus
rings on inputs, SwitchRow, semantic badges, segmented and underline
tabs, restyled menus, dialogs, sheets, tooltips and command bar, and a
single bottom-center toast with an Undo action. New: IconButton,
SegmentedControl, RadioGroup and NativeSelect.
Audit every animation in the app and shared UI primitives against a
frequency-first motion bar: keyboard and high-frequency actions no longer
animate, remaining motion uses interruptible CSS transitions with shared
easing tokens, and redundant animation code is removed.
UI primitives (@reactive-resume/ui)
- Dialog, alert dialog, popover and tooltip move from tw-animate keyframes
to Base UI data-starting/ending-style transitions; menus, popovers and
tooltips skip motion when opened from the keyboard (data-instant).
- Dialog gains an `instant` prop; the command palette uses it.
- Accordion animates its real panel height; caret rotates instead of
swapping icons.
- Menu backdrop blur moves onto the popup so it no longer snaps in after
the fade; context menus and comboboxes fade only.
- Sidebar collapse uses the strong ease-out curve and snaps on Cmd+B.
- Toast, sheet, checkbox, tabs, toggle, inputs and message scroller get
tokenised easing, correct transition properties and press feedback.
- Tabs no longer squeeze a trigger narrower than its label.
- Spinners keep spinning under prefers-reduced-motion.
Web app
- Remove the default route view transition and page-entrance slides.
- Add EASE_OUT_STRONG for Motion; replace built-in "easeOut" everywhere.
- Switch LazyMotion to domMax so layout and Reorder animations run.
- Builder: consolidate 12 section list files into one ItemsSection,
opacity-only list rows with popLayout, instant Cmd+0, faster dock zoom,
crossfade that no longer dips, transform-based progress bars.
- Dashboard: keep previous results while sorting/filtering, no empty-state
flash, uncontrolled sidebar (no network round trip on collapse), calmer
resume card tilt, no stacked hover wrappers.
- Settings: drop entrance/stagger wrappers and ActionButton.
- Agent: CSS marquee paused on hover; thread switches keep the layout.
- Homepage: fix invalid transition declarations, CSS spotlight drift,
scroll-hiding header without a JS spring, tokenised curves.
- Theme switches change every color at once.
- Remove SSR-only useIsClient guards from the SPA.
Docs: rewrite the DESIGN.md animation section around the new tokens.
Rewrites the landing page, in-app microcopy, and public docs, then fixes what the rewrite exposed: stale template counts, a broken quickstart anchor, out-of-sync FAQ structured data, dead error-hint branches in the MCP tools, and wrong-sense translations across all 53 locales. Adds GLOSSARY.md so translators get the right sense of the ambiguous UI terms.
Swaps sonner's toast.success/error/loading/dismiss for the new toast.add({ type,
description }) and toast.close across dialogs, auth pages, the builder, the
dashboard and the applications views. Behaviour is unchanged.
* feat(applications): job application tracker with AI copilot
Add an Applications module at /dashboard/applications: pipeline board
(dnd-kit), table view with bulk actions, Insights (fit tiles, funnel,
sources, shareable funnel-flow SVG), campaigns, tags, CSV import, and
Add/Edit/Detail slide-overs. Each application links a live Reactive
Resume.
AI "Application Copilot" (applications.ai.*): job-posting autofill,
resume↔job match score (fit ring), resume tailoring, and cover-letter /
follow-up drafting — via the user's configured provider.
Board cards + table rows get context menus (edit / move / archive /
delete). Charts are CSS/SVG (no new chart dep); adds a UI Checkbox.
Also includes local TanStack devtools setup and toolchain bumps.
Claude-Session: https://claude.ai/code/session_01TEeRHnEayw2MFCShFRyL5f
* feat(applications): close follow-up gaps + squash migrations
Finish the deferred/open items on the applications tracker:
- Cover-letter upload re-enabled. Fix the storage blocker by deriving the
key extension from content type (buildFileKey/EXTENSION_BY_CONTENT_TYPE)
instead of hardcoding .jpeg, so PDFs serve correctly and non-JPEG image
avatars keep working under FLAG_DISABLE_IMAGE_PROCESSING. Add
coverLetterUrl/coverLetterName columns + Documents-section upload/remove.
- Contacts editor in the detail sheet (add/edit/remove, keyed per app).
- Board caps rendered cards per column (COLUMN_PAGE_SIZE=50 + "Show more").
- Extract new Lingui messages across locales.
- Guard coverLetterUrl to http(s)/relative at the API boundary.
Squash the five branch-only application-table migrations (create -> +tags
-> +cover-letter -> drop -> re-add) into a single clean CREATE TABLE via
drizzle-kit generate.
Claude-Session: https://claude.ai/code/session_01TEeRHnEayw2MFCShFRyL5f
* chore: update dependencies
* fix(web): address React Doctor findings — compiler, purity, query, component structure
prefer-module-scope-pure-function: hoist buildSubtitle, getDecimalPlaces,
handleLocaleChange, onLocaleChange, stop, listContent/groupedListContent to
module scope so they aren't rebuilt on every render.
react-compiler-todo (??=): rewrite draft.metadata.styleRules ??= [] to the
non-assignment form to unblock auto-memoization.
set-state-in-effect: derive updatedAtLabel at render time instead of syncing
it through useState + useEffect.
query-destructure-result: destructure useQuery results at call site in
resume-analysis and resume-thumbnail to follow TanStack Query v5 convention.
only-export-components: extract non-component exports to sibling .ts files so
Fast Refresh can preserve component state:
- getNextWeights → typography/get-next-weights.ts
- detectJsonImportType + ImportType → dialogs/resume/import.utils.ts
- getLocaleOptions → features/locale/locale-options.tsx
- preview helpers + DEFAULT_PDF_PAGE_SIZE → preview.shared.utils.ts
- resolveHighlightToolbarState + defaultHighlightColor → rich-input.utils.ts
- computeDelta + getSparklinePoints → statistics.utils.ts
no-multi-comp: split multi-component files into focused companions:
- ResumePane + ToolbarButton → routes/agent/-components/resume-pane.tsx
- DesktopBuilderShell → builder/$resumeId/-components/desktop-builder-shell.tsx
- MobileBuilderShell + helpers → builder/$resumeId/-components/mobile-builder-shell.tsx
- setBuilderLayout/getBuilderLayout moved to -store/sidebar.ts
fix(tests): add Resume type import to section-builder mocks and cast partial
mock data as unknown as Resume to satisfy stricter type checking; fix
noExplicitAny Biome errors in the same mocks.
* feat(applications): improve performance
* chore: fix knip issues
* perf(builder): halve per-keystroke render cost
Section-form fields called `form.handleSubmit()` on every keystroke, which
re-validated the whole form and toggled submit state — firing the render
cascade twice per character (~6809 renders/keystroke, FPS dropping to 9).
Persist via a form-level `listeners.onChange` instead and drop the per-field
`handleSubmit()` (basics, custom-fields, design). Narrow header/dock resume
subscriptions to metadata slices so they no longer re-render on content edits.
Cuts renders 6809 -> 3403 per keystroke (50%), 0 frame drops. Save, preview,
and design controls verified working; 449/449 web tests pass.
* perf(home): eliminate hero CLS from unreserved video box
The hero <section> is `flex items-center` (shrink-to-fit), so the video
wrapper's width depended on the video's intrinsic size, which only resolves
after the media loads. aspect-ratio couldn't reserve height without a definite
width, so the video grew from ~190px to ~563px after first paint and shoved the
centered hero text down ~373px (CLS ~0.095).
Give the wrapper a definite width (w-full + mx-auto on the CometCard) and set an
explicit aspect ratio + width/height on the video so its box is reserved before
load. CLS 0.095 -> 0; hero stays visually centered at max-w-4xl.
* docs: add application tracker guides
* chore(db): squash application migrations
* fix(email): import React in auth template for server-side rendering compatibility
* chore(release): v5.2.1
* Refactor resume rendering and builder workflows
* fix: address application tracker review findings