Frontend-only React + TypeScript app for exploring Performance+ analytics. UI follows the OmniHR Design System (Liberty palette, Lato type scale, OmniHR spacing/shadow tokens).
- React 18 + TypeScript
- Vite
- React Router v6
- Tailwind CSS (configured with OmniHR tokens)
- No backend, no auth, no API layer — all data is mocked in
src/data/
npm install
npm run dev # start dev server (http://localhost:5173)
npm run build # type-check + production build
npm run preview # preview the built bundle| Path | Page |
|---|---|
/ |
Home |
/analytics |
Analytics landing (links to sub-sections) |
/analytics/people |
People analytics (placeholder) |
/analytics/compensation |
Compensation analytics (placeholder) |
/analytics/performance |
Performance — redirects to first tab |
/analytics/performance/cycle-health |
Cycle Health & Executive Overview |
/analytics/performance/phase-progress |
Phase Progress & Completion |
/analytics/performance/score-calibration |
Score & Calibration Insights |
/analytics/performance/goal-health |
Goal Health & Quality |
/analytics/performance/reviewer-coverage |
Reviewer & Coverage Diagnostics |
/analytics/performance/trends |
Trends Over Time |
/analytics/performance/calibration-readiness |
Calibration Readiness |
/analytics/performance/audit-compliance |
Audit & Compliance |
/analytics/leave |
Leave analytics (placeholder) |
Routes are derived from src/app/navigationConfig.tsx and the Performance tab list in src/modules/analytics/performance/performanceTabsConfig.ts — there are no hardcoded paths duplicated across files.
src/
app/
navigationConfig.tsx # single source of truth for sidebar + routes
routes.tsx # builds <Routes> from navigationConfig
layouts/
AppLayout.tsx # sidebar + main content shell
Sidebar.tsx # config-driven vertical nav
SectionTabs.tsx # presentational horizontal tab strip
PageHeader.tsx # title + subtitle + right slot
pages/
HomePage.tsx
AnalyticsMainPage.tsx
AnalyticsSectionPage.tsx # generic placeholder for People/Comp/Leave
PerformanceAnalyticsPage.tsx # hosts cycle selector, phase tabs, filters
modules/
analytics/
performance/
performanceTabsConfig.ts # tab list (label, slug, Component)
tabs/ # one file per Performance tab
blocks/ # reusable analytics blocks (cards/charts/tables)
components/
ui/ # generic UI primitives
layout/ # layout helpers
charts/ # chart primitives (recharts/visx/etc. when added)
filters/ # filter widgets
cards/ # card primitives
tables/ # table primitives
data/
mockData.ts # cycles, departments, locations (frontend-only)
types/
navigation.ts # NavItem, NavChild, PerformanceTab
analytics.ts # ReviewCycle, GlobalFilters, PerformancePhase
utils/
formatting.ts # formatPercent, formatNumber, formatDate, clamp
styles/
index.css # Tailwind directives + design-system CSS vars
Edit src/app/navigationConfig.tsx. The same config drives the sidebar and the route tree — no other file needs to change.
{
id: "settings",
label: "Settings",
path: "/settings",
icon: "⚙️",
Component: SettingsPage,
children: [
{ slug: "profile", label: "Profile", Component: ProfilePage },
],
}Edit src/modules/analytics/performance/performanceTabsConfig.ts. Add a new { id, slug, label, Component } entry; the tab strip and the nested route both pick it up automatically.
- Create
src/modules/analytics/<area>/withtabs/andblocks/subfolders. - Build reusable blocks (cards, charts, tables) under
blocks/— pass data via props so they can be moved between tabs/pages. - Wire the area into
navigationConfig.tsx(and a tab config file if it has horizontal tabs).
Keep page files focused on layout/composition. Heavy logic belongs in blocks or utils/.
All data lives in src/data/mockData.ts. Add new datasets as named exports — never inline mock data in components.
src/utils/formatting.ts for shared formatters. Add sibling files (e.g. utils/calibration.ts) for domain calculations so tab/page files stay layout-only.
The Tailwind config (tailwind.config.js) and CSS variables (src/styles/index.css) implement the OmniHR Design System tokens:
- Colours — Liberty (primary), Slate (neutral), Tangerine (warning), Info, Danger, Success
- Spacing —
omni-1…omni-16(4px base grid) - Shadows —
shadow-main,shadow-main-hover,shadow-box - Radius —
rounded-chip,rounded-tooltip,rounded-dropdown,rounded-card,rounded-pill - Typography — Lato, loaded in
index.html
Always reference tokens by name. Never write raw hex colours or off-grid spacing values.
Reference docs: ../skills/omnihr-design-system/
- Frontend only — no backend, database, API layer, auth, or Redux
- Mock data stays on the frontend
- Avoid hardcoded duplicated labels or paths — drive them from config
- Keep files small and modular