Skip to main content

Documentation Index

Fetch the complete documentation index at: https://grantmaster.dev/llms.txt

Use this file to discover all available pages before exploring further.

Component Library and Design System

GrantMaster uses a design system built on Tailwind CSS 4 with design tokens defined in the @theme block of src/index.css. Colors use OKLCH for perceptually uniform scales.

Tabs

  • Use PremiumTabs for section-level tab navigation inside feature pages and settings panels.
  • Use PremiumTabs variant="card" when the tab strip should sit inside a card container.
  • Use PageTabs for top-level page navigation shells only.
  • PageTabs must be route-driven for major workspace sections. The URL is the source of truth; do not keep the active tab in cross-route component state.
  • Always pass an explicit ariaLabel and a stable idBase when the tab content is rendered externally.
  • Render exactly one matching external tabpanel for the active route. The tab strip owns navigation; the page owns content.
  • TabNavigation and ModernTabs are retired and should not be used for new work.

🎨 Global Design Tokens

All tokens are defined in src/index.css under @theme. Always use these tokens rather than hardcoded hex values.

Brand Colors (OKLCH)

TokenScaleUsage
primary-50 .. primary-95011-step OKLCH scaleBrand blue. Anchor: #2e5af5. Never hardcode blue-*.
successSemanticemerald-* equivalent. Approvals, confirmations.
warningSemanticamber-* equivalent. Cautionary states.
errorSemanticrose-* equivalent. Destructive/reject.
infoSemanticInformational highlights.

Surface / Neutrals

TokenHex (light)Usage
surface-50#f8fafcLightest background
surface-100#f1f5f9Page background
surface-200#e2e8f0Card borders
surface-300#cbd5e1Dividers
surface-400#94a3b8Placeholder text
surface-500#64748bMuted text
surface-600#475569Secondary text
surface-700#334155Dark card backgrounds
surface-800#1e293bDark mode surfaces
surface-900#0f172aDark mode background
surface-950#020617OLED black
These map to slate-* Tailwind classes. Never use gray-*.

Spacing & Radius

TokenValueUsage
--radius-xs0.25remSmall chips
--radius-sm0.375remSmall inputs
--radius-md0.5remButtons
--radius-lg0.75remDefault
--radius-xl1remStandard card radius
--radius-2xl1.5remLarge modals/sections

Shadows

TokenUsage
--shadow-smSubtle elevation
--shadow-mdCard default
--shadow-lgElevated panels
--shadow-xlModals/overlays
--shadow-premiumPremium card appearance
--shadow-glassGlassmorphism

Motion Tokens (:root)

TokenValueUsage
--duration-micro150msHover, focus
--duration-small200msToggles, selections
--duration-medium300msModals, page transitions
--duration-large400msComplex reveals
--duration-slow500msStaggered sequences
--ease-defaultcubic-bezier(0.16, 1, 0.3, 1)Smooth deceleration
--ease-bouncecubic-bezier(0.34, 1.56, 0.64, 1)Playful overshoot
--ease-smoothcubic-bezier(0.4, 0, 0.2, 1)Material-style
Note: Decorative CSS animations are globally disabled. Only functional animations (spinners, skeleton shimmer) are whitelisted.

🧱 Core Components

1. Page Wrapper (PageLayout + PageHeader)

Every main page must be wrapped in <PageLayout> and use <PageHeader> for the title. Never write manual <h1> tags. For resolver-driven pages, prefer <PageShell> so breadcrumbs, actions, and tabs stay consistent across sections.
  • Breadcrumbs should show the ancestor path only. Do not repeat the current tab/page label in the breadcrumb line and the title line.
  • The title line should reflect the active route/tab title only once.
  • Reuse spacing tokens from the shared shell: gap-6 between header/content regions, mb-6 below page tabs, and card surfaces from shared primitives rather than local inline values.

2. Buttons (<Button>)

Always use <Button> from @/components/ui/button. Never raw <button> with inline classes.
  • default: Primary action (one per screen).
  • destructive: Delete/reject.
  • success: Approve/confirm.
  • warning: Cautionary.
  • outline / secondary / ghost / link: Lower emphasis.
  • Use isLoading + loadingText props for async states.

3. Modals & Side-Overs

  • Use Modal for focused, short interactions (e.g., “Confirm Delete”).
  • Use Sheet (right-side panel) for complex data entry or detailed views.

4. Status & Badges

  • <StatusBadge> with mapDomainStatus() for status indicators.
  • <Badge> for non-status labels.

5. Cards

  • Card from shadcn for composable layouts.
  • CardVariants / StatCard for presets and metric displays.
  • Never write card styling inline.

6. Secondary Sidebars

  • <SecondarySidebar> for left-side sub-navigation on tabbed pages.
  • Flat items via items prop; grouped items via groups prop.
  • Enable searchable for 10+ items.

Governance Matrix (Allowed vs Disallowed)

Use this quick matrix during implementation and review. The design system is the default; raw HTML is the exception.
ConcernAllowedDisallowed
Buttons<Button> variants from @/components/ui/buttonRaw <button> in feature files that import Button
Text inputs<Input> / <Textarea> / design-system SelectRaw text-like <input> when Input is available in file
Empty states<EmptyState> or <SurfaceEmptyState> with action copyPlain "No data" / "No results" text blocks
Loading statesSkeletonLoader presets (DashboardSkeleton, TablePageSkeleton, etc.)Hand-rolled animate-pulse scaffolds in feature screens
Page titles<PageHeader> or <SurfacePageHeader>Manual page-level <h1> blocks
Search/filter bars<SurfaceToolbar> or approved wrappers (SearchFilterBar)One-off control rows with custom spacing and state copy
KPI strips<SurfaceMetricGrid> / MetricCardAd-hoc stat tiles
Status labels<StatusBadge> + mapDomainStatus()Local status-to-color helpers
Primary color usageprimary-* token scaleblue-* utilities in tokenized files
Semantic status colorsemerald-* success, amber-* warning, rose-* dangergreen-*, yellow-*, red-* status mapping

✨ Animations

We use the motion library (npm package motion@^12, formerly Framer Motion) for intentional animations only. Decorative CSS animations are globally disabled in src/index.css.

🛠️ Implementation Rules

  1. Don’t build it twice: Check src/components/ui/ before creating a new UI element.
  2. Accessibility (a11y): Every button must have an aria-label if it only contains an icon. Use semantic HTML (<nav>, <main>, <aside>). Route-driven tab strips must expose role="tablist" / role="tab" / role="tabpanel" with linked IDs and keyboard navigation for ArrowLeft, ArrowRight, Home, and End. Inputs and selects need an associated label or aria-labelledby; placeholders are not labels.
  3. Dark Mode: Support both light and dark modes. Use shadcn CSS variables for theme-aware colors. Ensure all colors have high contrast ratios (minimum 4.5:1).
  4. Responsive: Use Tailwind breakpoints (sm:, md:, lg:). Test every component on a mobile view. Sidebar, page tabs, and page content must stack cleanly without overlap at narrower widths; horizontal overflow should be intentional and controlled.
  5. Icons: Use lucide-react exclusively. Size conventions: w-4 h-4 in buttons/badges, w-5 h-5 in section headers, w-8 h-8 in stat cards.