Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / frontend/src/components/AppShell.tsx |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 3be46ba89edb737182075a2b320509b42dc916f8 |
| Branch | workstream-d-missionmatch |
| Path or archive member | frontend/src/components/AppShell.tsx |
| Original SHA-256 | 0efacd3f603d498ba92d57d90aa6bb765f21955491421873d6dcd06759b5701f |
| Git blob SHA | 6e54a6123713796111acd6a50dbbbd5a04e35ad5 |
| Reading-copy SHA-256 | 0efacd3f603d498ba92d57d90aa6bb765f21955491421873d6dcd06759b5701f |
Every recorded occurrence
These 45 records contain identical original source bytes. Their paths and revisions remain part of the archive.
| Original record | Branch or archive | Revision / identifier | Original location |
|---|---|---|---|
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | workstream-d-missionmatch | 3be46ba89edb737182075a2b320509b42dc916f8 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | m5-price-to-win | 41000ad30fff4129fdaf5ec84e15ba14c27d4890 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | workstream-e-dataflow-deploy | 433815a042f9741411e60fa553fe72143e9b10db | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | w3-ai-staffing-recommendations | 43d56387270ef4da4cabd794d97ca6a49909bc7d | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ws3-clearance | 4b8e7ce594c068621867f9c9deed0ec64ae6c553 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | collision-deconfliction | 4ee5a09972608ed89f8377c6665542d5f450f0a6 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ai-intelligence-layer | 5d5ddff70393a197c5f54a45280bb5dd42b24755 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ws7-federal-signal | 6a9f6ce9cfb13345ffb47770d4960e7c2d9c17c2 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ws6-retrieval | 6c56e29231ec05735927fa265c97d517499dfeaf | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | per-tenant-routing | 9bde0f9a74b89d01980fa658e5253acda7528d0c | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ai-brain-live | aac32fc49c878cc5bca099459307611562d0bac1 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | graphrag-foundation | b0ddeb9f633fd138d09309d1a17b7d13bc3a67f7 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ws1-ontology-sync | b596f449a32a1016fbd403c36505cc00a1ac9ee6 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | time-to-fill-survival | b66e1e505863d4f17741a4b9ede73509e45bd6c6 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | mag-substrate | b82c7100a492dec67dfd1eda6b3f53def859be35 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | capture-readiness | bae6af7cb2997e819174a9e9cfff5e16067a1975 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | deploy-and-ops | bdacd9d0b4d5998d25fc74bf4007f4c3ec538c7a | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ws8-teaching-loop | c823f0fb6bb2aba0f39001eb6de96f4000d9321f | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | phase2-eval-fairness | d361af254701975fe239927656ababb56374655e | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | phase2-connectors | e038d4c687aec16f8bd9bc4d907eea14d91f8704 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ws2-alias-relationship | e4dada4601c6eb101830f9d223a9655dfa120616 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ws9-bench-ingestion | f585a9ef32fa554663ce1fba9a414a54b6e49cf0 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | vendor-intelligence | fe9796a19c261951d3f2565206c0c1b5ac294465 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | per-tenant-routing | 9bde0f9a74b89d01980fa658e5253acda7528d0c | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | collision-deconfliction | 4ee5a09972608ed89f8377c6665542d5f450f0a6 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ws6-retrieval | 6c56e29231ec05735927fa265c97d517499dfeaf | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | m5-price-to-win | 41000ad30fff4129fdaf5ec84e15ba14c27d4890 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ws1-ontology-sync | b596f449a32a1016fbd403c36505cc00a1ac9ee6 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ws8-teaching-loop | c823f0fb6bb2aba0f39001eb6de96f4000d9321f | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | w3-ai-staffing-recommendations | 43d56387270ef4da4cabd794d97ca6a49909bc7d | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | mag-substrate | b82c7100a492dec67dfd1eda6b3f53def859be35 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ws3-clearance | 4b8e7ce594c068621867f9c9deed0ec64ae6c553 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | phase2-eval-fairness | d361af254701975fe239927656ababb56374655e | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | workstream-e-dataflow-deploy | 433815a042f9741411e60fa553fe72143e9b10db | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | time-to-fill-survival | b66e1e505863d4f17741a4b9ede73509e45bd6c6 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ai-intelligence-layer | 5d5ddff70393a197c5f54a45280bb5dd42b24755 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | graphrag-foundation | b0ddeb9f633fd138d09309d1a17b7d13bc3a67f7 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | deploy-and-ops | bdacd9d0b4d5998d25fc74bf4007f4c3ec538c7a | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ws9-bench-ingestion | f585a9ef32fa554663ce1fba9a414a54b6e49cf0 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ws2-alias-relationship | e4dada4601c6eb101830f9d223a9655dfa120616 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ws7-federal-signal | 6a9f6ce9cfb13345ffb47770d4960e7c2d9c17c2 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | ai-brain-live | aac32fc49c878cc5bca099459307611562d0bac1 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | workstream-d-missionmatch | 3be46ba89edb737182075a2b320509b42dc916f8 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | phase2-connectors | e038d4c687aec16f8bd9bc4d907eea14d91f8704 | Open original |
| Janady13/missionmatch / frontend/src/components/AppShell.tsx | capture-readiness | bae6af7cb2997e819174a9e9cfff5e16067a1975 | Open original |
Recovered source transcript
Download complete source text ↓211 lines · 7.7 KB
import type { ComponentType, CSSProperties } from 'react'
import { NavLink, Outlet, useLocation } from 'react-router-dom'
import {
ClipboardList,
Crosshair,
Layers,
LogOut,
Radar,
Scale,
Settings as SettingsIcon,
ShieldCheck,
Users,
} from 'lucide-react'
import { useAuth } from '../lib/useAuth'
type Icon = ComponentType<{ size?: number; className?: string; style?: CSSProperties }>
type NavItem = { to: string; label: string; icon: Icon }
type Tool = {
key: string
name: string
tagline: string
accent: string
basePath: string
icon: Icon
match: (path: string) => boolean
nav: NavItem[]
}
// The three tools under the missionMATCH umbrella. The switcher routes between them; each owns its
// accent and its own nav. missionMATCH (gold) is the home tool and the default after login.
const TOOLS: Tool[] = [
{
key: 'mission',
name: 'missionMATCH',
tagline: 'Command Center',
accent: 'var(--color-gold)',
basePath: '/command',
icon: Radar,
match: (p) => p === '/' || p.startsWith('/command') || p.startsWith('/compliance'),
nav: [
{ to: '/command', label: 'Command Center', icon: Radar },
{ to: '/command/candidates', label: 'Candidates', icon: Users },
{ to: '/compliance', label: 'Compliance', icon: Scale },
],
},
{
key: 'screen',
name: 'screenMATCH',
tagline: 'Qualification',
accent: 'var(--color-screen)',
basePath: '/screen',
icon: Crosshair,
match: (p) => p.startsWith('/screen') || p.startsWith('/requirements') || p.startsWith('/evaluate'),
nav: [
{ to: '/screen', label: 'Screen Candidate', icon: Crosshair },
{ to: '/requirements', label: 'Opportunities', icon: ClipboardList },
],
},
{
key: 'slate',
name: 'slateMATCH',
tagline: 'Proposal Slates',
accent: 'var(--color-slate-accent)',
basePath: '/slate',
icon: Layers,
match: (p) => p.startsWith('/slate'),
nav: [{ to: '/slate', label: 'Candidate Slate', icon: Layers }],
},
]
function activeTool(path: string): Tool {
return TOOLS.find((t) => t.match(path)) ?? TOOLS[0]
}
// Shared and legacy routes belong to no tool; give them their own header title so it never reads the
// fallback tool's first nav label (for example the Settings page must not show "Command Center").
const SHARED_TITLES: Record<string, string> = {
'/settings': 'Settings',
'/pipeline': 'Talent Pipeline',
'/dashboard': 'Dashboard',
}
function isSharedPath(path: string): boolean {
return path in SHARED_TITLES
}
function headerTitle(tool: Tool, path: string): string {
if (SHARED_TITLES[path]) return SHARED_TITLES[path]
const item = tool.nav.find((n) => (path === n.to ? true : path.startsWith(n.to) && n.to !== tool.basePath))
return item?.label ?? tool.nav[0]?.label ?? tool.name
}
export function AppShell() {
const { pathname } = useLocation()
const { principal, logout } = useAuth()
const tool = activeTool(pathname)
// On a shared or legacy route no tool is truly active, so no tool chip lights and the header stays
// neutral rather than borrowing the fallback tool's identity.
const shared = isSharedPath(pathname)
return (
<div className="grid h-full grid-cols-[248px_1fr]">
<aside className="flex flex-col border-r border-line/70 bg-navy-950/70 backdrop-blur">
<div className="flex items-center gap-2.5 px-5 py-5">
<span className="grid size-9 place-items-center rounded-lg bg-gradient-to-br from-blue to-navy-700 text-gold">
<ShieldCheck size={20} />
</span>
<div className="leading-tight">
<div className="text-[15px] font-extrabold tracking-tight">
mission<span className="text-gold">MATCH</span>
<span className="align-super text-[9px]">™</span>
</div>
<div className="text-[10px] uppercase tracking-[0.16em] text-faint">Mission Workforce</div>
</div>
</div>
{/* Tool switcher: one chip per tool, the active tool wears its accent. */}
<div className="mx-3 mb-2 space-y-1 rounded-xl border border-line/60 bg-navy-900/50 p-1.5">
{TOOLS.map((t) => {
const isActive = t.key === tool.key && !shared
return (
<NavLink
key={t.key}
to={t.basePath}
className="flex items-center gap-2.5 rounded-lg px-2.5 py-2 text-sm font-semibold transition-colors"
style={{
background: isActive ? 'color-mix(in srgb, ' + t.accent + ' 16%, transparent)' : 'transparent',
color: isActive ? 'var(--color-ink)' : 'var(--color-muted)',
boxShadow: isActive ? 'inset 2px 0 0 0 ' + t.accent : 'none',
}}
>
<t.icon size={16} style={{ color: t.accent }} />
{t.name}
</NavLink>
)
})}
</div>
<nav className="mt-1 flex-1 space-y-0.5 px-3">
<div className="px-3 pb-1 pt-2 text-[10px] font-bold uppercase tracking-[0.16em] text-faint">
{tool.tagline}
</div>
{tool.nav.map(({ to, label, icon: ItemIcon }) => (
<NavLink
key={to}
to={to}
end={to === tool.basePath}
className={({ isActive }) =>
`flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors ${
isActive ? 'text-ink' : 'text-muted hover:bg-navy-800/60 hover:text-ink'
}`
}
style={({ isActive }) =>
isActive
? { background: 'color-mix(in srgb, ' + tool.accent + ' 15%, transparent)', boxShadow: 'inset 2px 0 0 0 ' + tool.accent }
: undefined
}
>
<ItemIcon size={17} />
{label}
</NavLink>
))}
</nav>
<NavLink
to="/settings"
className={({ isActive }) =>
`mx-3 mb-2 flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors ${
isActive ? 'bg-navy-800/60 text-ink' : 'text-muted hover:bg-navy-800/60 hover:text-ink'
}`
}
>
<SettingsIcon size={17} /> Settings
</NavLink>
</aside>
<div className="flex min-w-0 flex-col">
<header className="flex items-center justify-between border-b border-line/70 bg-navy-950/40 px-6 py-3.5 backdrop-blur">
<div className="flex items-center gap-3">
<span className="h-7 w-1.5 rounded-full" style={{ background: shared ? 'var(--color-line)' : tool.accent }} />
<div>
<h1 className="text-lg font-bold tracking-tight">{headerTitle(tool, pathname)}</h1>
<p className="text-xs text-faint">{shared ? 'missionMATCH' : `${tool.name} · ${tool.tagline}`}</p>
</div>
</div>
<div className="flex items-center gap-3">
<span className="rounded-full border border-line/70 px-3 py-1 text-[11px] font-semibold text-muted">
FIPS 140-3 • RLS isolated
</span>
{principal && (
<span className="rounded-full bg-blue/20 px-2.5 py-1 text-[11px] font-semibold uppercase tracking-wide text-blue-soft">
{principal.role}
</span>
)}
<button
onClick={() => void logout()}
title="Sign out"
className="grid size-8 place-items-center rounded-md border border-line/70 text-muted hover:border-risk/60 hover:text-risk"
>
<LogOut size={15} />
</button>
</div>
</header>
<main className="min-h-0 flex-1 overflow-y-auto p-6">
<Outlet />
</main>
</div>
</div>
)
}