name: component-patterns description: Guidelines for organizing React components in Shadow Master. Use when creating new components, deciding between single-file vs subfolder structure, or understanding the component architecture. allowed-tools: Read, Grep, Glob
Component Organization Patterns
Guidelines for structuring React components in the Shadow Master codebase.
Component Directory Overview
/components/ # 130+ components total
├── index.ts # Root exports (DiceRoller only)
├── *.tsx # 6 standalone utility components
├── action-resolution/ # 3 components - dice pool building
├── auth/ # 1 component - email verification
├── character/ # 12 components - character sheet display
├── combat/ # 4 components - combat tracking UI
├── creation/ # 83 components - character creation
│ ├── *.tsx # 14 top-level cards
│ ├── shared/ # 14 reusable utilities
│ └── {feature}/ # 17 feature subfolders
├── cyberlimbs/ # 6 components - augmentation UI
├── sync/ # 2 components - ruleset sync status
└── ui/ # 2 components - BaseModal, Tooltip
Decision Flowchart
Does the component have modals?
├─ Yes → Create subfolder, extract modals
└─ No → Does it have reusable Row/ListItem components?
├─ Yes, used elsewhere → Create subfolder
└─ No → Keep as single file with internal helpers
When to Use a Subfolder
Create a subfolder with index.ts when:
- Component has one or more modals (selection dialogs, forms, etc.)
- Component has reusable row/list item components used in multiple places
- Component exceeds ~600 lines with clear separable concerns
- Component has distinct UI pieces that could be tested independently
Subfolder structure:
/components/{area}/{feature}/
├── FeatureCard.tsx # Main component
├── FeatureModal.tsx # Selection/edit modal
├── FeatureRow.tsx # Optional: if row is complex/reusable
├── constants.ts # Optional: magic values, options arrays
├── types.ts # Optional: feature-specific types
├── utils.ts # Optional: feature-specific helpers
├── index.ts # Re-exports public API
Index file pattern:
// index.ts - export only public API
export { FeatureCard } from "./FeatureCard";
export { FeatureModal } from "./FeatureModal"; // Only if used externally
When to Keep as Single File
Keep as a single file when:
- Component is self-contained with only internal helper components
- Internal components are tightly coupled and only make sense within the parent
- Component is under ~400 lines with straightforward structure
- No modals or independently reusable pieces
Component Areas
Root-Level Components (6 files)
Standalone utility components that don't fit a specific feature area:
| Component | Purpose |
|---|---|
DiceRoller.tsx | Dice rolling UI with edge rerolls |
AugmentationCard.tsx | Generic augmentation display |
EssenceDisplay.tsx | Essence tracking visualization |
ThemeProvider.tsx | Dark/light mode context |
EnvironmentBadge.tsx | Environment indicator (dev/staging) |
NotificationBell.tsx | Notification center UI |
/components/ui/ - Shared UI Primitives
Low-level accessible components used across the app. Built on React Aria.
| Component | Exports |
|---|---|
BaseModal.tsx | BaseModal, ModalHeader, ModalBody, ModalFooter |
Tooltip.tsx | Tooltip, TooltipTrigger, TooltipContent, InfoTooltip |
When to add here: Generic UI primitives with no business logic.
/components/auth/ - Authentication Components
| Component | Purpose |
|---|---|
EmailVerificationBanner.tsx | Prompts user to verify email |
/components/action-resolution/ - Dice Pool Building
Components for building and displaying action resolution dice pools.
| Component | Purpose |
|---|---|
ActionHistory.tsx | List of past action rolls |
ActionPoolBuilder.tsx | Construct dice pools for actions |
EdgeTracker.tsx | Edge point tracking and spending |
Note: No index.ts - import directly from files.
/components/character/ - Character Sheet Display
Components for viewing active characters (not creation). No index file - import directly.
| Component | Purpose |
|---|---|
AdeptPowerList.tsx | Display adept powers and PP |
AutosoftManager.tsx | Manage vehicle/drone autosofts |
CyberdeckConfig.tsx | Cyberdeck attribute configuration |
DroneNetworkManager.tsx | RCC drone network management |
JumpInControl.tsx | Vehicle/drone jump-in interface |
MagicSummary.tsx | Magic rating, tradition, drain |
MatrixActions.tsx | Matrix action buttons and state |
MatrixSummary.tsx | Matrix attributes and programs |
ProgramManager.tsx | Running programs management |
RiggingSummary.tsx | Rigging stats and VCR mode |
Spellbook.tsx | Spell list with casting interface |
VehicleActions.tsx | Vehicle action buttons |
/components/combat/ - Combat Tracking
Components for running combat encounters. Has index.ts and co-located tests.
| Component | Purpose |
|---|---|
CombatTracker.tsx | Initiative order and turn management |
ActionSelector.tsx | Action selection with categories |
ConditionMonitor.tsx | Health/damage tracking |
OpposedTestResolver.tsx | Opposed test dice rolling |
/components/cyberlimbs/ - Cyberlimb Management
Components for cyberlimb augmentation display and modification.
| Component | Purpose |
|---|---|
CyberlimbCard.tsx | Individual cyberlimb display |
CyberlimbList.tsx | List all installed cyberlimbs |
CyberlimbDetailPanel.tsx | Detailed cyberlimb info panel |
CyberlimbInstallModal.tsx | Install new cyberlimb |
CyberlimbEnhancementModal.tsx | Add attribute enhancements |
CyberlimbAccessoryModal.tsx | Add accessories to limb |
/components/sync/ - Ruleset Synchronization
Components for displaying ruleset sync status and migration.
| Component | Purpose |
|---|---|
StabilityShield.tsx | Visual sync status indicator |
MigrationWizard.tsx | Guide user through ruleset migration |
/components/creation/ - Character Creation
The largest component area (83 components). Organized by feature with shared utilities.
Top-Level Cards (14 files)
Single-file cards without complex modals:
| Card | Purpose |
|---|---|
PrioritySelectionCard | Priority table selection |
AttributesCard | Attribute allocation |
SkillsCard | Active skills management |
SpellsCard | Spell selection for mages |
AdeptPowersCard | Adept power selection |
ComplexFormsCard | Technomancer complex forms |
AugmentationsCard | Cyberware/bioware selection |
VehiclesCard | Vehicle/drone acquisition |
WeaponsPanel | Weapon purchases |
GearTabsCard | Tabbed gear interface |
DerivedStatsCard | Calculated stats display |
CharacterInfoCard | Name, background, description |
EditionSelector | Edition selection dropdown |
CreationErrorBoundary | Error boundary for creation |
Feature Subfolders (17 directories)
| Folder | Components | Pattern |
|---|---|---|
/armor | 4 | Panel + Row + PurchaseModal + ModModal |
/augmentations | 4 | 4 specialized modals |
/contacts | 3 | Card + Modal + KarmaConfirm |
/foci | 2 | Card + Modal |
/gear | 4 | Panel + Row + 2 Modals |
/identities | 6 | Card + Identity + 3 modal types |
/knowledge-languages | 5 | Card + 2 Row types + 2 Modals |
/magic-path | 2 | Card + Modal + utilities |
/matrix-gear | 2 | Card + Modal |
/metatype | 2 | Card + Modal |
/qualities | 3 | Card + SelectionModal + DetailCard |
/shared | 14 | Reusable utilities and hooks |
/skills | 10 | Panel + ListItem + 8 specialized modals |
/spells | 2 | ListItem + Modal |
/vehicles | 4 | 4 specialized modals |
/weapons | 4 | Row + 3 Modals |
Shared Utilities (/creation/shared/)
| Component | Purpose |
|---|---|
CreationCard.tsx | Standard card wrapper |
BudgetIndicator.tsx | Resource budget display |
CardSkeleton.tsx | Loading skeleton |
EmptyState.tsx | Empty list state |
KarmaConversionModal.tsx | Nuyen ↔ Karma conversion |
RatingSelector.tsx | 1-6 rating picker |
Stepper.tsx | +/- increment control |
SummaryFooter.tsx | Card summary footer |
ValidationBadge.tsx | Validation status indicator |
BulkQuantitySelector.tsx | Quantity picker for bulk items |
LifestyleModificationSelector | Lifestyle mod picker |
LifestyleSubscriptionSelector | Lifestyle subscription picker |
useKarmaConversionPrompt.ts | Hook for karma conversion modal |
Adding Components by Area
Adding a Creation Card
- Determine structure using the decision flowchart
- Create in
/components/creation/or/components/creation/{feature}/ - Use
CreationCardwrapper from/components/creation/shared/ - Add to
SheetCreationLayout.tsxin appropriate column - Update
CreationStatetype in/lib/types/creation.tsif needed - Export from
/components/creation/index.ts
Adding a Combat Component
- Create in
/components/combat/ - Export from
/components/combat/index.ts - Add co-located test in
/components/combat/__tests__/
Adding a Character Sheet Component
- Create in
/components/character/ - Import directly from file (no index.ts)
- Add to relevant page in
/app/characters/[id]/
Adding a Cyberlimb Component
- Create in
/components/cyberlimbs/ - Export from
/components/cyberlimbs/index.ts - Export types if needed for external use
Adding a UI Primitive
- Create in
/components/ui/ - Build on React Aria for accessibility
- Export from
/components/ui/index.ts - No business logic - pure presentation
Adding a New API Endpoint
- Create
/app/api/{path}/route.ts - Export HTTP method handlers (GET, POST, PUT, DELETE)
- Follow authentication pattern (getSession → validate user)
- Call storage layer functions
- Return JSON responses
Adding a New Ruleset Module
- Define module type in
/lib/types/edition.ts - Add module to book payload in
/data/editions/{editionCode}/ - Update merge logic in
/lib/rules/merge.tsif special handling needed - Create hook in
RulesetContext.tsxfor easy access
Key Reference Files
components/ui/BaseModal.tsx- Accessible modal foundationcomponents/creation/shared/CreationCard.tsx- Card wrapper patterncomponents/creation/SkillsCard.tsx- Modal-based editing examplecomponents/combat/CombatTracker.tsx- Combat component with testscomponents/cyberlimbs/index.ts- Feature folder export patternapp/characters/create/sheet/components/SheetCreationLayout.tsx- Three-column layout
Component Diagram Generation
Mermaid diagrams are auto-generated from the component structure.
Commands
# Preview all areas to stdout
pnpm generate-diagrams
# Generate specific area
pnpm generate-diagrams --area=combat
pnpm generate-diagrams --area=creation
# Update documentation files
pnpm generate-diagrams --output=files
# Verbose mode with component counts
pnpm generate-diagrams --verbose
Output Locations
| Mode | Location |
|---|---|
--output=stdout | Prints to terminal (default) |
--output=files | Writes to /docs/architecture/components/ |
Diagram Color Key
| Color | Hex | Component Type | Naming Pattern |
|---|---|---|---|
| Blue | #3b82f6 | Container | *Card.tsx, *Panel.tsx, *Tracker.tsx |
| Purple | #8b5cf6 | Modal | *Modal.tsx |
| Green | #22c55e | Row | *Row.tsx, *ListItem.tsx |
| Orange | #f59e0b | Hook | use*.ts, *Context.tsx |
| Gray | #6b7280 | Shared | Everything else |
When to Regenerate
Run pnpm generate-diagrams --output=files after:
- Adding a new component folder
- Adding/removing modals or cards
- Reorganizing component structure
- Before major documentation updates
Validation
# Validate creation docs structure (doesn't regenerate)
pnpm validate-creation-docs --verbose
Documentation Structure
Hand-Written (detailed)
/docs/architecture/creation-components/ - Detailed creation component docs with:
- Component descriptions
- Props documentation
- Usage patterns
- Context dependencies
Auto-Generated (overview)
/docs/architecture/components/ - Generated hierarchy diagrams:
- Mermaid component trees
- Summary tables
- Color-coded by type
Index File Conventions
| Area | Has index.ts? | Reason |
|---|---|---|
/ui | Yes | Stable public API |
/combat | Yes | Cohesive feature set |
/cyberlimbs | Yes | Cohesive feature set |
/sync | Yes | Cohesive feature set |
/creation | Yes | Organized by phases |
/character | No | Loosely coupled, import directly |
/action-resolution | No | Loosely coupled, import directly |
/auth | No | Single component |