fix(nav): only the most-specific sidebar item is active
On /career/builder/{id} both "Career Workspace" (/career) and "CV Builder"
(/career/builder) highlighted, because AppShell tested each item with
`pathname === to || pathname.startsWith(to + "/")` — so /career matched
every /career/... child. No "most specific wins" rule.
Add AppShell.activeNavTo(pathname, tos): the longest `to` that the path is
at or under wins, across both nav lists; every other item is inactive. A
child route never lights up a parent nav item. `selected` now compares
against that single computed activeTo. Exported as a pure function so the
ownership rule is unit-tested directly (sidebar-active-nav.test.ts):
exactly one active item for /career, /career/builder and
/career/builder/{id}, and no double-highlight.
Also give the breadcrumb/title in App.tsx explicit /career/builder ->
"CV Builder" ownership (it previously showed "Career Workspace"), and
reframe the Career Workspace header to the "Career Profile" product
framing: "This information powers your CVs, applications, cover letters
and AI assistance."
Frontend only — no change to CareerProfiles, CvVariants, CV generation,
extraction APIs, AI, permissions or tenant isolation. Plan for the deeper
information-architecture work is in docs/career-workspace-ux-refactor.md,
staged so the 1376-line CareerProfilePage and the live CV/extraction
pipeline are refactored incrementally with verification, not in one risky
rewrite.
Verified: tsc clean, frontend build clean, 135 frontend tests pass
(128 + 7 new nav tests). Backend untouched.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -15,15 +15,15 @@ export default function CareerWorkspacePage() {
|
||||
<Box sx={{ display: "grid", gap: 2 }}>
|
||||
<Paper sx={{ p: 2.5, borderRadius: 4, boxShadow: "0px 8px 24px -12px rgba(15,23,42,0.12)", display: "flex", alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 1 }}>
|
||||
<Box>
|
||||
<Typography variant="h5" sx={{ fontWeight: 900, mb: 0.5 }}>Career Workspace</Typography>
|
||||
<Typography variant="h5" sx={{ fontWeight: 900, mb: 0.5 }}>Career Profile</Typography>
|
||||
<Typography sx={{ color: "text.secondary" }}>
|
||||
Maintain the master career profile that powers your CVs, tailored application material, and future portfolio outputs.
|
||||
This information powers your CVs, applications, cover letters and AI assistance.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Button variant="contained" startIcon={<DescriptionOutlinedIcon />} onClick={() => navigate("/career/builder")}>Open CV Builder</Button>
|
||||
</Paper>
|
||||
<Alert severity="info" sx={{ borderRadius: 3 }}>
|
||||
Your master profile is the source of truth. Job-specific CV drafts remain separate and never overwrite it.
|
||||
Your career profile holds your information. The CV Builder creates documents from it — job-specific CVs stay separate and never overwrite your profile.
|
||||
</Alert>
|
||||
<Paper sx={{ borderRadius: 4, p: { xs: 1.5, md: 2.5 }, boxShadow: "0px 8px 24px -12px rgba(15,23,42,0.12)" }}>
|
||||
<CareerProfilePage />
|
||||
|
||||
Reference in New Issue
Block a user