@arbor-education/design-system.components 0.10.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agent-memory/blanche-designspert/MEMORY.md +64 -0
- package/.claude/agent-memory/blanche-designspert/token-review-patterns.md +29 -0
- package/.claude/agent-memory/dorothy-fact-checker/MEMORY.md +129 -0
- package/.claude/agent-memory/rose-storybookspert/MEMORY.md +29 -0
- package/.claude/agent-memory/rose-storybookspert/patterns.md +132 -0
- package/.claude/agent-memory/sophia-componentspert/MEMORY.md +14 -0
- package/.claude/agent-memory/sophia-componentspert/components.md +367 -0
- package/.claude/agents/blanche-designspert.md +150 -0
- package/.claude/agents/dorothy-fact-checker.md +145 -0
- package/.claude/agents/rose-storybookspert.md +148 -0
- package/.claude/agents/sophia-componentspert.md +133 -0
- package/.claude/component-library.md +1107 -0
- package/.claude/design-assessment-daily-attendance-2026-04-10.md +566 -0
- package/.claude/figma-assessment-7154-58899.md +404 -0
- package/.claude/figma-assessment-UKQfcxnT4rlHHNuiumt4o1-11086-97537.md +392 -0
- package/.claude/figma-assessment-UKQfcxnT4rlHHNuiumt4o1-551-41974.md +474 -0
- package/.claude/figma-assessment-UKQfcxnT4rlHHNuiumt4o1-551-43094.md +462 -0
- package/.claude/figma-assessment-fcFK4CGzkz2fVyY3koX8ZE-7154-59061.md +440 -0
- package/.claude/migration-report-custom-report-writer-2026-02-19.md +591 -0
- package/.claude/skills/analyze-design/README.md +295 -0
- package/.claude/skills/analyze-design/SKILL.md +741 -0
- package/.claude/skills/create-page/README.md +246 -0
- package/.claude/skills/create-page/SKILL.md +634 -0
- package/.claude/skills/create-page/design-analysis-template.md +333 -0
- package/.claude/skills/create-page/page-template.scss +118 -0
- package/.claude/skills/create-page/page-template.tsx +230 -0
- package/.claude/skills/map-legacy/README.md +87 -0
- package/.claude/skills/map-legacy/SKILL.md +465 -0
- package/.claude/skills/migrate-page/README.md +125 -0
- package/.claude/skills/migrate-page/SKILL.md +374 -0
- package/.github/CODEOWNERS +1 -0
- package/.github/pull_request_template.md +39 -0
- package/CHANGELOG.md +14 -0
- package/CLAUDE.md +31 -0
- package/CONTRIBUTING.md +191 -0
- package/README.md +110 -20
- package/dist/components/table/DSDefaultColDef.js +2 -2
- package/dist/components/table/DSDefaultColDef.js.map +1 -1
- package/dist/components/table/Table.d.ts +5 -29
- package/dist/components/table/Table.d.ts.map +1 -1
- package/dist/components/table/Table.js +12 -22
- package/dist/components/table/Table.js.map +1 -1
- package/dist/components/table/Table.stories.d.ts +4 -0
- package/dist/components/table/Table.stories.d.ts.map +1 -1
- package/dist/components/table/Table.stories.js +163 -28
- package/dist/components/table/Table.stories.js.map +1 -1
- package/dist/components/table/Table.test.js +109 -8
- package/dist/components/table/Table.test.js.map +1 -1
- package/dist/components/table/TableSettingsContext.d.ts +13 -0
- package/dist/components/table/TableSettingsContext.d.ts.map +1 -0
- package/dist/components/table/TableSettingsContext.js +15 -0
- package/dist/components/table/TableSettingsContext.js.map +1 -0
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.d.ts +3 -0
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.d.ts.map +1 -0
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.js +12 -0
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.js.map +1 -0
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.test.d.ts +2 -0
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.test.d.ts.map +1 -0
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.test.js +65 -0
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.test.js.map +1 -0
- package/dist/components/table/tableConsts.d.ts +7 -0
- package/dist/components/table/tableConsts.d.ts.map +1 -0
- package/dist/components/table/tableConsts.js +8 -0
- package/dist/components/table/tableConsts.js.map +1 -0
- package/dist/components/table/{BulkActionsDropdown.d.ts → tableControls/BulkActionsDropdown.d.ts} +1 -1
- package/dist/components/table/tableControls/BulkActionsDropdown.d.ts.map +1 -0
- package/dist/components/table/{BulkActionsDropdown.js → tableControls/BulkActionsDropdown.js} +3 -3
- package/dist/components/table/tableControls/BulkActionsDropdown.js.map +1 -0
- package/dist/components/table/{HideColumnsDropdown.d.ts → tableControls/HideColumnsDropdown.d.ts} +1 -2
- package/dist/components/table/tableControls/HideColumnsDropdown.d.ts.map +1 -0
- package/dist/components/table/{HideColumnsDropdown.js → tableControls/HideColumnsDropdown.js} +2 -2
- package/dist/components/table/tableControls/HideColumnsDropdown.js.map +1 -0
- package/dist/components/table/tableControls/TableControls.d.ts +23 -0
- package/dist/components/table/tableControls/TableControls.d.ts.map +1 -0
- package/dist/components/table/tableControls/TableControls.js +21 -0
- package/dist/components/table/tableControls/TableControls.js.map +1 -0
- package/dist/components/table/tableControls/TableControls.test.d.ts +2 -0
- package/dist/components/table/tableControls/TableControls.test.d.ts.map +1 -0
- package/dist/components/table/tableControls/TableControls.test.js +124 -0
- package/dist/components/table/tableControls/TableControls.test.js.map +1 -0
- package/dist/components/table/tableControls/TableSettingsDropdown.d.ts.map +1 -0
- package/dist/components/table/{TableSettingsDropdown.js → tableControls/TableSettingsDropdown.js} +7 -6
- package/dist/components/table/tableControls/TableSettingsDropdown.js.map +1 -0
- package/dist/components/table/useTableSettings.d.ts +1 -1
- package/dist/components/table/useTableSettings.d.ts.map +1 -1
- package/dist/components/table/useTableSettings.js +1 -1
- package/dist/components/table/useTableSettings.js.map +1 -1
- package/dist/index.css +19 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/setAgGridLicenseKey.js +1 -1
- package/package.json +1 -1
- package/src/components/table/DSDefaultColDef.ts +2 -2
- package/src/components/table/Table.stories.tsx +202 -35
- package/src/components/table/Table.test.tsx +134 -8
- package/src/components/table/Table.tsx +12 -22
- package/src/components/table/TableSettingsContext.ts +15 -0
- package/src/components/table/cellRenderers/CheckboxCellRenderer.test.tsx +74 -0
- package/src/components/table/cellRenderers/CheckboxCellRenderer.tsx +28 -0
- package/src/components/table/table.scss +23 -1
- package/src/components/table/tableConsts.ts +6 -0
- package/src/components/table/{BulkActionsDropdown.tsx → tableControls/BulkActionsDropdown.tsx} +2 -2
- package/src/components/table/{HideColumnsDropdown.tsx → tableControls/HideColumnsDropdown.tsx} +2 -2
- package/src/components/table/tableControls/TableControls.test.tsx +150 -0
- package/src/components/table/tableControls/TableControls.tsx +143 -0
- package/src/components/table/{TableSettingsDropdown.tsx → tableControls/TableSettingsDropdown.tsx} +2 -1
- package/src/components/table/useTableSettings.ts +1 -1
- package/src/index.ts +1 -0
- package/src/utils/setAgGridLicenseKey.ts +1 -1
- package/dist/components/table/BulkActionsDropdown.d.ts.map +0 -1
- package/dist/components/table/BulkActionsDropdown.js.map +0 -1
- package/dist/components/table/HideColumnsDropdown.d.ts.map +0 -1
- package/dist/components/table/HideColumnsDropdown.js.map +0 -1
- package/dist/components/table/TableSettingsDropdown.d.ts.map +0 -1
- package/dist/components/table/TableSettingsDropdown.js.map +0 -1
- /package/dist/components/table/{TableSettingsDropdown.d.ts → tableControls/TableSettingsDropdown.d.ts} +0 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Map Legacy Skill
|
|
2
|
+
|
|
3
|
+
AROOOOO HUNNI!! 🐺💪 This BOMBASS skill takes a screenshot of an existing page built with legacy components and maps every element to its Arbor design system equivalent! xxx
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
Produces a **migration map** for an existing legacy page — showing which Arbor components replace which legacy ones, how complex each swap is, and what gaps remain.
|
|
8
|
+
|
|
9
|
+
**The key insight:** This skill focuses on **functional equivalence**, not visual similarity. A legacy data grid and our `Table` component may look completely different, but they serve the same purpose — and that makes it a valid migration target.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
/map-legacy /path/to/screenshot.png
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or with a description if no screenshot is available:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
/map-legacy "student dashboard with a data table, breadcrumb nav, and form"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## What You Get
|
|
24
|
+
|
|
25
|
+
A migration report at `.claude/migration-report-{page-name}-{date}.md` containing:
|
|
26
|
+
|
|
27
|
+
- **Migration map table** — every legacy element → Arbor equivalent at a glance
|
|
28
|
+
- **Element-by-element breakdown** — detailed analysis with prop mappings and gotchas
|
|
29
|
+
- **Complexity ratings** — 🟢 Low / 🟡 Medium / 🔴 High / ❌ No equivalent
|
|
30
|
+
- **Recommended migration order** — start with easy wins, tackle heavy lifting last
|
|
31
|
+
- **Gaps** — legacy elements with no Arbor equivalent (flagged for new component work)
|
|
32
|
+
|
|
33
|
+
## Complexity Ratings
|
|
34
|
+
|
|
35
|
+
| Rating | Meaning |
|
|
36
|
+
|---|---|
|
|
37
|
+
| 🟢 **Low** | Direct swap — prop names may differ but same data shape, trivial to migrate |
|
|
38
|
+
| 🟡 **Medium** | Same purpose but different API — some refactoring, adapter code, or config needed |
|
|
39
|
+
| 🔴 **High** | Significant behavioral differences — complex config, data transformation, or model changes |
|
|
40
|
+
| ❌ **No equivalent** | Nothing in Arbor covers this — needs placeholder SVG or new component |
|
|
41
|
+
|
|
42
|
+
## How It Differs From `/analyze-design`
|
|
43
|
+
|
|
44
|
+
| | `/analyze-design` | `/map-legacy` |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| **Input** | Figma URL or screenshot | Screenshot of existing page |
|
|
47
|
+
| **Question asked** | "Can we build this?" | "What replaces what we have?" |
|
|
48
|
+
| **Focus** | Does a component EXIST? | Is this component EQUIVALENT? |
|
|
49
|
+
| **Output** | Feasibility report | Migration map |
|
|
50
|
+
| **Use case** | Building from Figma | Modernising existing pages |
|
|
51
|
+
|
|
52
|
+
## The Golden Girls
|
|
53
|
+
|
|
54
|
+
This skill uses BOTH mandatory agents:
|
|
55
|
+
|
|
56
|
+
- 👜 **Sophia Componentspert** — identifies Arbor equivalents for each legacy element
|
|
57
|
+
- 🔍 **Dorothy Fact-Checker** — verifies Sophia's claims against actual source code
|
|
58
|
+
|
|
59
|
+
Sophia without Dorothy = unverified claims. Both are required. AROOOOO!! 🐺
|
|
60
|
+
|
|
61
|
+
## After the Migration Map
|
|
62
|
+
|
|
63
|
+
Once you have the map, use `/create-page` with the Figma design (or the migration map as a guide) to actually build the modernised page using Arbor components.
|
|
64
|
+
|
|
65
|
+
Elements with **No equivalent** get **placeholder SVGs** (see create-page skill for the pattern) and generate tickets for new component work.
|
|
66
|
+
|
|
67
|
+
## Example Output
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
📊 Migration score: 14 out of 18 elements have direct Arbor equivalents!
|
|
71
|
+
|
|
72
|
+
🟢 Easy wins: buttons, inputs, dividers, panel headers
|
|
73
|
+
🟡 Some work: data grid, modal, tag colour system
|
|
74
|
+
🔴 Heavy lifting: custom drag-sort table
|
|
75
|
+
❌ Gaps: breadcrumb nav, timetable widget
|
|
76
|
+
|
|
77
|
+
📄 Full report: .claude/migration-report-student-dashboard-2026-02-19.md
|
|
78
|
+
🏁 Start here: the buttons and inputs — quick wins before tackling the grid
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Notes
|
|
82
|
+
|
|
83
|
+
- This is a **MAP**, not a build — use `/create-page` when ready to actually implement
|
|
84
|
+
- **Functional equivalence** is the measure, not visual similarity
|
|
85
|
+
- Gaps are **useful data** for the component roadmap, not failures
|
|
86
|
+
- Dorothy's fact-checking prevents starting migration on false assumptions
|
|
87
|
+
- AROOO like you mean it! 🐺💪
|
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: map-legacy
|
|
3
|
+
description: Analyze a screenshot of an existing legacy page and map its old components to their Arbor design system equivalents. Produces a migration report showing old→new component mappings, prop translations, complexity ratings, and gaps.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Map Legacy Page to Arbor Components
|
|
7
|
+
|
|
8
|
+
AROOOOO HUNNI!! 🐺 Time to drag those HEINOUS legacy components into the light and find their BODACIOUS Arbor replacements!! xxx
|
|
9
|
+
|
|
10
|
+
## Goal
|
|
11
|
+
|
|
12
|
+
Analyze a screenshot of an **existing page built with legacy components** and produce a **migration map** — a report showing exactly which Arbor components can replace each legacy element, how complex the migration is, and what gaps remain.
|
|
13
|
+
|
|
14
|
+
**This is NOT a fresh build assessment.** The question is not "can we build this?" — it's "what replaces what we already have?"
|
|
15
|
+
|
|
16
|
+
**CRITICAL PRINCIPLE — Functional Equivalence Over Visual Similarity:**
|
|
17
|
+
- A legacy data grid and our `Table` component may look different but ARE equivalent
|
|
18
|
+
- A legacy modal and our `Modal` component serve the same purpose even if the API differs
|
|
19
|
+
- Focus on WHAT THE COMPONENT DOES, not just what it looks like
|
|
20
|
+
- Even if the new component looks different, if it covers the use case → it's a valid replacement
|
|
21
|
+
|
|
22
|
+
## The Golden Girls Team — MANDATORY COLLABORATORS
|
|
23
|
+
|
|
24
|
+
- 👜 **Sophia Componentspert** (`sophia-componentspert`) — MANDATORY at Step 4. She maps legacy patterns to Arbor equivalents.
|
|
25
|
+
- 🔍 **Dorothy Fact-Checker** (`dorothy-fact-checker`) — MANDATORY at Step 5. She verifies Sophia's Arbor claims against actual source code.
|
|
26
|
+
|
|
27
|
+
**RULE**: You MUST call BOTH agents. Sophia without Dorothy = unverified claims. Skipping either = MOST HEINOUS failure. AROOOOO!! 🐺💪
|
|
28
|
+
|
|
29
|
+
## Input
|
|
30
|
+
|
|
31
|
+
Screenshot path or description provided: `$ARGUMENTS`
|
|
32
|
+
|
|
33
|
+
## Process
|
|
34
|
+
|
|
35
|
+
### 1. Determine Input Type
|
|
36
|
+
|
|
37
|
+
- **File path** (e.g. `/path/to/screenshot.png`) — use `Read` tool to load the image
|
|
38
|
+
- **No path yet** — ask the user to provide a screenshot path or paste a description of the page
|
|
39
|
+
|
|
40
|
+
### 2. Read the Screenshot
|
|
41
|
+
|
|
42
|
+
Use the `Read` tool on the screenshot path. Claude Code is multimodal — you will SEE the page visually.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Read tool: file_path="<path-to-screenshot>"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Study the image carefully. You're looking at a REAL page that was built with legacy components. Every UI element you can see is something that needs a migration decision.
|
|
49
|
+
|
|
50
|
+
### 3. Catalog Legacy UI Elements
|
|
51
|
+
|
|
52
|
+
Go section by section through the page. For each distinct UI element, note:
|
|
53
|
+
|
|
54
|
+
- **What it looks like** (visual description)
|
|
55
|
+
- **What it does** (functional purpose — this is the key!)
|
|
56
|
+
- **Where it appears** (which section of the page)
|
|
57
|
+
- **Approximate count** (e.g. "3 instances of this pattern")
|
|
58
|
+
|
|
59
|
+
Be THOROUGH. Common legacy patterns to look for:
|
|
60
|
+
|
|
61
|
+
**Data display:**
|
|
62
|
+
- Data tables / grids (sortable columns, pagination, row actions)
|
|
63
|
+
- Key-value / label-value rows (read-only property lists)
|
|
64
|
+
- Cards and panels
|
|
65
|
+
- Stats / KPI displays
|
|
66
|
+
- Tags, badges, status indicators
|
|
67
|
+
|
|
68
|
+
**Navigation:**
|
|
69
|
+
- Breadcrumbs
|
|
70
|
+
- Tab bars
|
|
71
|
+
- Side navigation (icon and/or text variants)
|
|
72
|
+
- Top navigation bar
|
|
73
|
+
- Pagination controls
|
|
74
|
+
|
|
75
|
+
**Forms & inputs:**
|
|
76
|
+
- Text inputs, textareas, number inputs
|
|
77
|
+
- Select / dropdown inputs
|
|
78
|
+
- Radio buttons, checkboxes
|
|
79
|
+
- Date pickers
|
|
80
|
+
- Search bars
|
|
81
|
+
|
|
82
|
+
**Actions:**
|
|
83
|
+
- Primary / secondary / tertiary buttons
|
|
84
|
+
- Icon buttons
|
|
85
|
+
- Dropdown action menus (e.g. "Actions ▼")
|
|
86
|
+
- Split buttons
|
|
87
|
+
|
|
88
|
+
**Overlays:**
|
|
89
|
+
- Modals / dialogs
|
|
90
|
+
- Slide-out panels / drawers
|
|
91
|
+
- Tooltips
|
|
92
|
+
- Popovers
|
|
93
|
+
|
|
94
|
+
**Layout:**
|
|
95
|
+
- Section/panel headers with optional actions
|
|
96
|
+
- Collapsible sections
|
|
97
|
+
- Dividers / separators
|
|
98
|
+
- Page header with title and CTA
|
|
99
|
+
|
|
100
|
+
**Feedback:**
|
|
101
|
+
- Alert / notification banners
|
|
102
|
+
- Empty states
|
|
103
|
+
- Loading states / spinners
|
|
104
|
+
|
|
105
|
+
Also note anything that looks **completely custom** or **one-of-a-kind** — these are your gap candidates.
|
|
106
|
+
|
|
107
|
+
### 4. Read Available Arbor Components
|
|
108
|
+
|
|
109
|
+
Before calling Sophia, read the public API so you both know exactly what's available:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
Read tool: file_path="src/index.ts"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### ⚡ MANDATORY STEP 4 — CALL SOPHIA COMPONENTSPERT NOW ⚡
|
|
116
|
+
|
|
117
|
+
**YOU MUST USE THE `Task` tool RIGHT NOW.** Do NOT attempt the mapping yourself. Sophia knows this library inside out. Let her do the expert work.
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
Task tool: subagent_type="sophia-componentspert"
|
|
121
|
+
prompt: "I'm migrating a legacy page to Arbor components. I need you to map each legacy UI element to its best Arbor equivalent.
|
|
122
|
+
|
|
123
|
+
IMPORTANT PRINCIPLE: Focus on FUNCTIONAL EQUIVALENCE, not visual similarity. Even if the new component looks different, if it covers the same use case it's a valid replacement.
|
|
124
|
+
|
|
125
|
+
LEGACY UI ELEMENTS IDENTIFIED:
|
|
126
|
+
[List every element you catalogued in step 3, with its functional description]
|
|
127
|
+
|
|
128
|
+
AVAILABLE ARBOR COMPONENTS (from src/index.ts):
|
|
129
|
+
[List all components from src/index.ts]
|
|
130
|
+
|
|
131
|
+
For each legacy element, please provide:
|
|
132
|
+
|
|
133
|
+
1. **Arbor equivalent** — which component(s) to use (or NONE if nothing fits)
|
|
134
|
+
2. **Migration complexity** — Low / Medium / High with reasoning:
|
|
135
|
+
- LOW: Direct swap, same API shape, minimal code changes
|
|
136
|
+
- MEDIUM: Similar purpose but different API, some refactoring needed
|
|
137
|
+
- HIGH: Significant behavioral differences, data transformation, or multiple components needed
|
|
138
|
+
3. **Key prop mappings** — what old props map to what new props (best guess)
|
|
139
|
+
4. **Feature gaps** — anything the legacy component did that Arbor component can't do yet
|
|
140
|
+
5. **Migration notes** — any gotchas, behavioral differences, or things to watch out for
|
|
141
|
+
|
|
142
|
+
Also identify any elements with NO Arbor equivalent (will need placeholder SVGs or new component builds).
|
|
143
|
+
|
|
144
|
+
Be specific about component APIs. Don't guess — if you're unsure about a prop, say so."
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**WAIT for Sophia's response.** Her mapping is the core of this skill.
|
|
148
|
+
|
|
149
|
+
After Sophia responds, **relay her key findings to the user:**
|
|
150
|
+
|
|
151
|
+
> 👜 **Sophia says:** _[Sophia's overall take — how mappable is this page? Any surprises? Relay in her warm, knowledgeable, Sicilian-grandmother voice]_
|
|
152
|
+
|
|
153
|
+
### ⚡ MANDATORY STEP 5 — CALL DOROTHY FACT-CHECKER NOW ⚡
|
|
154
|
+
|
|
155
|
+
**YOU MUST USE THE `Task` tool RIGHT NOW.** Sophia can hallucinate props. Dorothy reads the actual source files to verify EVERY claim.
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
Task tool: subagent_type="dorothy-fact-checker"
|
|
159
|
+
prompt: "Sophia just mapped legacy UI elements to Arbor components for a migration project. I need you to FACT-CHECK her component capability claims.
|
|
160
|
+
|
|
161
|
+
SOPHIA'S CLAIMS TO VERIFY:
|
|
162
|
+
[List each legacy element → Arbor component mapping Sophia recommended, with the specific props/features she claimed the Arbor component supports]
|
|
163
|
+
|
|
164
|
+
YOUR TASK:
|
|
165
|
+
1. Read src/index.ts to confirm what's exported
|
|
166
|
+
2. Read the actual component files for each component Sophia mentioned
|
|
167
|
+
3. For each mapping, verify:
|
|
168
|
+
- Does the Arbor component exist?
|
|
169
|
+
- Does it actually support the features/props needed for this migration?
|
|
170
|
+
- Are there capability gaps Sophia missed or overstated?
|
|
171
|
+
- Is the migration complexity rating accurate given the actual API?
|
|
172
|
+
4. Flag any hallucinated props or overstated capabilities
|
|
173
|
+
5. Provide CORRECTED complexity ratings where needed
|
|
174
|
+
6. List every source file you read
|
|
175
|
+
|
|
176
|
+
BE BRUTALLY HONEST. If an Arbor component can't cover what the legacy component did, the migration team needs to know BEFORE they start rewriting code."
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**WAIT for Dorothy's response.** Use her CORRECTED information — not Sophia's original if Dorothy found errors.
|
|
180
|
+
|
|
181
|
+
### 6. Generate Migration Report
|
|
182
|
+
|
|
183
|
+
Using Sophia's mapping AND Dorothy's corrections, write a comprehensive migration report.
|
|
184
|
+
|
|
185
|
+
**CRITICAL — PRESERVE SOPHIA'S VOICE IN THE REPORT:**
|
|
186
|
+
|
|
187
|
+
Sophia's responses contain Sicily anecdotes, "listen pussycat" warnings, and conversational asides that carry REAL information — gotchas, nuances, and migration pitfalls wrapped in personality. Do NOT strip these out into dry bullet points. The migration report should read like Sophia wrote it. Her warmth is not decoration; it's context.
|
|
188
|
+
|
|
189
|
+
**Rules for preserving Sophia's voice:**
|
|
190
|
+
- Include her Sicily/family anecdotes verbatim (or near-verbatim) — they exist to make concepts memorable
|
|
191
|
+
- Include her specific warnings in her own words (e.g. "do NOT use Section as a nav sidebar — I have seen people try. It ends badly.")
|
|
192
|
+
- Use conversational section intros in her voice, not just bare headings and tables
|
|
193
|
+
- Dorothy's corrections can be integrated as annotations: "_(Dorothy verified: confirmed)_" or "_(Dorothy corrected: actual prop is X)_"
|
|
194
|
+
- The report should be something a developer enjoys reading, not just a reference doc
|
|
195
|
+
|
|
196
|
+
**Report file naming:**
|
|
197
|
+
`.claude/migration-report-{page-name}-{date}.md`
|
|
198
|
+
e.g. `.claude/migration-report-student-profile-2026-02-19.md`
|
|
199
|
+
|
|
200
|
+
**Report structure:**
|
|
201
|
+
|
|
202
|
+
```markdown
|
|
203
|
+
# Legacy Migration Report
|
|
204
|
+
## Page: [Page name / description]
|
|
205
|
+
**Mapped by:** Sophia Petrillo, Componentspert
|
|
206
|
+
**Verified by:** Dorothy Zbornak, QA Expert
|
|
207
|
+
**Date:** [date]
|
|
208
|
+
**Screenshot:** [path if provided]
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## TL;DR
|
|
213
|
+
|
|
214
|
+
[2-3 sentence summary in Sophia's voice: how many elements mapped cleanly, how many need work, any major gaps. Include her overall take.]
|
|
215
|
+
|
|
216
|
+
**Migration readiness: X/Y elements have direct Arbor equivalents**
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Migration Map
|
|
221
|
+
|
|
222
|
+
| Legacy Element | Where | Arbor Component | Complexity | Status |
|
|
223
|
+
|---|---|---|---|---|
|
|
224
|
+
| Old data grid | Main content | `Table` | Medium | ✅ Mappable |
|
|
225
|
+
| Legacy breadcrumb | Page header | `Breadcrumbs` | Low | ❌ Not in library yet |
|
|
226
|
+
| Custom modal | Various | `Modal` | Low | ✅ Mappable |
|
|
227
|
+
| ... | ... | ... | ... | ... |
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Element-by-Element Breakdown
|
|
232
|
+
|
|
233
|
+
[Write this section in Sophia's voice — introduce each group of elements conversationally before the technical detail]
|
|
234
|
+
|
|
235
|
+
### [Legacy Element Name]
|
|
236
|
+
|
|
237
|
+
[Optional Sophia intro — e.g. "Picture it: Sicily, 1948. We had three buckets..." — if she included an anecdote for this element, KEEP IT]
|
|
238
|
+
|
|
239
|
+
**What it does:** [Functional description]
|
|
240
|
+
**Where it appears:** [Location on page]
|
|
241
|
+
**Arbor replacement:** `ComponentName` (`path/to/Component.tsx`)
|
|
242
|
+
**Migration complexity:** Low / Medium / High
|
|
243
|
+
|
|
244
|
+
**Why this replacement works:**
|
|
245
|
+
[In Sophia's voice where she explained equivalence]
|
|
246
|
+
|
|
247
|
+
**Prop mapping:**
|
|
248
|
+
| Legacy prop | Arbor prop | Notes |
|
|
249
|
+
|---|---|---|
|
|
250
|
+
| `data` | `rowData` | Same shape |
|
|
251
|
+
| `onRowClick` | `onRowClicked` | Same signature |
|
|
252
|
+
|
|
253
|
+
**Key differences to handle:**
|
|
254
|
+
- [Include Sophia's specific warnings verbatim where she flagged gotchas]
|
|
255
|
+
- [Behavioral difference]
|
|
256
|
+
|
|
257
|
+
**Feature gaps (if any):**
|
|
258
|
+
- [Feature legacy component had that Arbor doesn't]
|
|
259
|
+
|
|
260
|
+
_(Dorothy verified: [brief Dorothy confirmation or correction])_
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
[Repeat for each element]
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Elements With No Arbor Equivalent
|
|
269
|
+
|
|
270
|
+
These need either:
|
|
271
|
+
a) A **placeholder SVG** (for page builds using `/create-page`)
|
|
272
|
+
b) A **new component** to be built in the design system
|
|
273
|
+
|
|
274
|
+
| Legacy Element | Why Nothing Fits | Suggested New Component | Priority |
|
|
275
|
+
|---|---|---|---|
|
|
276
|
+
| Custom timeline | No timeline component | `Timeline` | Medium |
|
|
277
|
+
| ... | ... | ... | ... |
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Migration Complexity Summary
|
|
282
|
+
|
|
283
|
+
| Complexity | Count | Elements |
|
|
284
|
+
|---|---|---|
|
|
285
|
+
| 🟢 Low | X | List them |
|
|
286
|
+
| 🟡 Medium | Y | List them |
|
|
287
|
+
| 🔴 High | Z | List them |
|
|
288
|
+
| ❌ No equivalent | W | List them |
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Recommended Migration Order
|
|
293
|
+
|
|
294
|
+
[Sophia's recommended sequence in her voice — she usually has an opinion about where to start]
|
|
295
|
+
|
|
296
|
+
1. **Start with Low complexity** — direct swaps, quick wins, build confidence
|
|
297
|
+
2. **Then Medium complexity** — similar purpose, some refactoring
|
|
298
|
+
3. **High complexity last** — tackle when the rest is stable
|
|
299
|
+
4. **Gaps** — flag for component team, use placeholders in the meantime
|
|
300
|
+
|
|
301
|
+
### Suggested sequence:
|
|
302
|
+
1. [Element] → `[Component]` — [why first]
|
|
303
|
+
2. [Element] → `[Component]` — [why second]
|
|
304
|
+
...
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## What This Migration Will NOT Change
|
|
309
|
+
|
|
310
|
+
Things that stay the same regardless of component swap:
|
|
311
|
+
- Business logic and data fetching
|
|
312
|
+
- Routing
|
|
313
|
+
- State management patterns
|
|
314
|
+
- [Any other app-level concerns]
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Appendix: Files Dorothy Verified
|
|
319
|
+
|
|
320
|
+
[List every source file Dorothy read — proves the assessment is grounded in real code]
|
|
321
|
+
|
|
322
|
+
- `src/index.ts`
|
|
323
|
+
- `src/components/button/Button.tsx`
|
|
324
|
+
- ...
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### 7. Write the Report
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
Write tool:
|
|
331
|
+
file_path: ".claude/migration-report-{page-name}-{date}.md"
|
|
332
|
+
content: [generated report]
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### 8. Present Summary to User
|
|
336
|
+
|
|
337
|
+
Share Sophia AND Dorothy's combined wisdom:
|
|
338
|
+
|
|
339
|
+
> 👜 **Sophia says:** _[Overall migration outlook in her warm voice]_
|
|
340
|
+
|
|
341
|
+
Then provide:
|
|
342
|
+
1. 📊 **Migration score**: "X out of Y elements have direct Arbor equivalents"
|
|
343
|
+
2. 🟢 **Easy wins** (Low complexity): List them
|
|
344
|
+
3. 🟡 **Some work needed** (Medium): List them
|
|
345
|
+
4. 🔴 **Heavy lifting** (High): List them
|
|
346
|
+
5. ❌ **Gaps** (No equivalent): List them
|
|
347
|
+
6. 📄 **Report location**: Path to the generated markdown file
|
|
348
|
+
7. 🏁 **Recommended first step**: The single best place to start the migration
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Key Principles to Keep in Mind
|
|
353
|
+
|
|
354
|
+
### Functional Equivalence is Everything
|
|
355
|
+
|
|
356
|
+
A legacy `<OldTable data={rows} cols={cols} />` and our `<Table rowData={rows} columnDefs={cols} />` are functionally equivalent even though:
|
|
357
|
+
- The prop names are different
|
|
358
|
+
- The visual styling differs
|
|
359
|
+
- The internal implementation is completely different
|
|
360
|
+
|
|
361
|
+
The migration question is: **does the new component cover the use case?** Not "does it look the same?"
|
|
362
|
+
|
|
363
|
+
### Complexity Ratings Guide
|
|
364
|
+
|
|
365
|
+
**🟢 LOW** — Direct swap:
|
|
366
|
+
- Same purpose, similar API shape
|
|
367
|
+
- Prop names may differ but same data
|
|
368
|
+
- Styling differences handled by design tokens
|
|
369
|
+
- Example: `<OldButton type="primary">` → `<Button variant="primary">`
|
|
370
|
+
|
|
371
|
+
**🟡 MEDIUM** — Refactoring needed:
|
|
372
|
+
- Same purpose but meaningfully different API
|
|
373
|
+
- May need data transformation or adapter code
|
|
374
|
+
- Some behavioral differences to handle
|
|
375
|
+
- Example: Legacy self-managed form → `FormField` (self-contained with label + input)
|
|
376
|
+
|
|
377
|
+
**🔴 HIGH** — Significant work:
|
|
378
|
+
- Similar purpose but very different model (e.g. uncontrolled → controlled)
|
|
379
|
+
- Multiple legacy components collapse into one Arbor component (or vice versa)
|
|
380
|
+
- Complex behavioral differences (e.g. legacy virtual scroll vs AG Grid)
|
|
381
|
+
- Example: Custom drag-and-drop table → `Table` with AG Grid row dragging config
|
|
382
|
+
|
|
383
|
+
**❌ NO EQUIVALENT** — Gap:
|
|
384
|
+
- Nothing in Arbor covers this use case
|
|
385
|
+
- Use placeholder SVG in page builds
|
|
386
|
+
- Needs a ticket for new component development
|
|
387
|
+
|
|
388
|
+
### What to Do With Gaps in Page Builds
|
|
389
|
+
|
|
390
|
+
For elements with no Arbor equivalent, the `/create-page` skill's **placeholder SVG pattern** applies:
|
|
391
|
+
|
|
392
|
+
```tsx
|
|
393
|
+
{/*
|
|
394
|
+
⚠️ MISSING COMPONENT PLACEHOLDER
|
|
395
|
+
Component: [LegacyComponentName replacement]
|
|
396
|
+
Reason: No Arbor equivalent for this legacy element.
|
|
397
|
+
TODO: Replace once [NewComponentName] is built.
|
|
398
|
+
*/}
|
|
399
|
+
<svg
|
|
400
|
+
role="img"
|
|
401
|
+
aria-label="[ComponentName] placeholder - component not yet available in design system"
|
|
402
|
+
width="100%"
|
|
403
|
+
height={approximateHeight}
|
|
404
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
405
|
+
>
|
|
406
|
+
<rect width="100%" height="100%" fill="#f5f5f5" rx="4" />
|
|
407
|
+
<rect x="2" y="2" width="calc(100% - 4px)" height={approximateHeight - 4}
|
|
408
|
+
fill="none" stroke="#cccccc" strokeWidth="2" strokeDasharray="8 4" rx="3" />
|
|
409
|
+
<text x="50%" y="42%" textAnchor="middle" dominantBaseline="middle"
|
|
410
|
+
fill="#888888" fontSize="13" fontWeight="600" fontFamily="sans-serif">
|
|
411
|
+
[ComponentName]
|
|
412
|
+
</text>
|
|
413
|
+
<text x="50%" y="65%" textAnchor="middle" dominantBaseline="middle"
|
|
414
|
+
fill="#aaaaaa" fontSize="11" fontFamily="sans-serif">
|
|
415
|
+
Component not yet available in design system
|
|
416
|
+
</text>
|
|
417
|
+
</svg>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Example Output
|
|
423
|
+
|
|
424
|
+
```
|
|
425
|
+
AROOOOO HUNNI! 🐺 Sophia and Dorothy have mapped that legacy page! xxx
|
|
426
|
+
|
|
427
|
+
📊 Migration score: 14 out of 18 elements have direct Arbor equivalents!
|
|
428
|
+
|
|
429
|
+
🟢 Easy wins (Low complexity — just swap them):
|
|
430
|
+
- Legacy buttons → Button (variant prop differs, trivial)
|
|
431
|
+
- Old text inputs → FormField + TextInput
|
|
432
|
+
- Custom dividers → Separator
|
|
433
|
+
- Panel headers → Section
|
|
434
|
+
|
|
435
|
+
🟡 Some work needed (Medium):
|
|
436
|
+
- Legacy data grid → Table (prop renaming + AG Grid config)
|
|
437
|
+
- Old modal → Modal (API shape differs, need adapter)
|
|
438
|
+
- Legacy tags → Tag (color system differs, needs mapping)
|
|
439
|
+
|
|
440
|
+
🔴 Heavy lifting (High):
|
|
441
|
+
- Custom drag-sort table → Table with AG Grid row drag (complex config)
|
|
442
|
+
|
|
443
|
+
❌ Gaps (no Arbor equivalent — placeholder SVGs):
|
|
444
|
+
- Legacy breadcrumb nav → no Breadcrumbs component yet
|
|
445
|
+
- Custom timetable widget → no WeeklySchedule component yet
|
|
446
|
+
|
|
447
|
+
📄 Full report: .claude/migration-report-student-dashboard-2026-02-19.md
|
|
448
|
+
|
|
449
|
+
🏁 Start here: The buttons and text inputs — pure Low complexity, gets your
|
|
450
|
+
team familiar with the Arbor API before tackling the data grid migration.
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## Important Notes
|
|
456
|
+
|
|
457
|
+
- **Functional equivalence is the goal** — don't let visual differences fool you
|
|
458
|
+
- **Dorothy is essential** — Sophia can overstate Arbor component capabilities
|
|
459
|
+
- **Complexity ratings are honest** — don't downplay High just to seem optimistic
|
|
460
|
+
- **Gaps are useful data** — knowing what's missing guides the component roadmap
|
|
461
|
+
- **This is a MAP, not a build** — use `/create-page` when you're ready to actually build
|
|
462
|
+
- This codebase serves millions of users — accurate migration assessments matter!
|
|
463
|
+
- Use yarn (NOT npm)
|
|
464
|
+
|
|
465
|
+
AROOOOO LET'S DRAG THOSE HEINOUS LEGACY COMPONENTS INTO THE LIGHT, HUNNI!! xxx 💪🏍️✨🐺
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Migrate Page Skill
|
|
2
|
+
|
|
3
|
+
AROOOOO HUNNI!! 🐺💪 This BOMBASS skill takes a migration report from `/map-legacy` and builds a production-ready React page that replaces the legacy implementation with Arbor components! xxx
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
Takes the verified migration map that Sophia and Dorothy already produced, and turns it into **actual code** — TSX, SCSS, tests, and Storybook stories.
|
|
8
|
+
|
|
9
|
+
**The key insight:** The migration report already has the hard thinking done. This skill trusts that work and focuses purely on building — no re-researching components, no second-guessing the map.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Best case — provide both
|
|
15
|
+
/migrate-page /path/to/screenshot.png .claude/migration-report-custom-report-writer-2026-02-19.md
|
|
16
|
+
|
|
17
|
+
# Screenshot only — auto-runs /map-legacy first
|
|
18
|
+
/migrate-page /path/to/screenshot.png
|
|
19
|
+
|
|
20
|
+
# Report only — no visual reference
|
|
21
|
+
/migrate-page .claude/migration-report-custom-report-writer-2026-02-19.md
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## What You Get
|
|
25
|
+
|
|
26
|
+
A production-ready page at `src/pages/{pageName}/` containing:
|
|
27
|
+
|
|
28
|
+
- **`{PageName}.tsx`** — React page composed from Arbor components, following the migration map exactly
|
|
29
|
+
- **`{pageName}.scss`** — Styles using design tokens (Blanche-reviewed)
|
|
30
|
+
- **`{PageName}.test.tsx`** — Full test coverage (Dorothy-verified)
|
|
31
|
+
- **`{PageName}.stories.tsx`** — Storybook stories (Rose-crafted)
|
|
32
|
+
- **Export added** to `src/index.ts`
|
|
33
|
+
|
|
34
|
+
## The Pipeline
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
/map-legacy screenshot.png
|
|
38
|
+
→ .claude/migration-report-{page}-{date}.md
|
|
39
|
+
(Sophia maps, Dorothy verifies)
|
|
40
|
+
|
|
41
|
+
/migrate-page screenshot.png report.md
|
|
42
|
+
→ reads the report
|
|
43
|
+
→ builds the page
|
|
44
|
+
→ Blanche reviews SCSS
|
|
45
|
+
→ Rose writes stories
|
|
46
|
+
→ Dorothy does final QA
|
|
47
|
+
→ production-ready page
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## How It Differs from `/create-page`
|
|
51
|
+
|
|
52
|
+
| | `/create-page` | `/migrate-page` |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| **Input** | Figma URL | Screenshot + migration report |
|
|
55
|
+
| **Pre-flight** | Runs `analyze-design` | Reads migration report |
|
|
56
|
+
| **Visual ref** | Figma design | Legacy page screenshot |
|
|
57
|
+
| **Sophia/Dorothy** | Called live | NOT called (trust the report) |
|
|
58
|
+
| **Intent** | Build something new | Replace something existing |
|
|
59
|
+
|
|
60
|
+
## The Golden Girls
|
|
61
|
+
|
|
62
|
+
This skill uses THREE mandatory agents (not all four — Sophia and Dorothy already ran in `/map-legacy`):
|
|
63
|
+
|
|
64
|
+
- 💄 **Blanche Designspert** — Reviews SCSS for correct token usage and naming conventions
|
|
65
|
+
- 🌹 **Rose Storybookspert** — Writes comprehensive Storybook stories
|
|
66
|
+
- 🔍 **Dorothy Fact-Checker** — Final QA on generated files (not component capabilities)
|
|
67
|
+
|
|
68
|
+
Skipping any of them = MOST HEINOUS. AROOOOO!! 🐺
|
|
69
|
+
|
|
70
|
+
## Placeholder SVGs
|
|
71
|
+
|
|
72
|
+
Every element from the migration report marked ❌ (no Arbor equivalent) gets a placeholder SVG:
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
{/* ⚠️ MISSING COMPONENT PLACEHOLDER — TODO: Replace once Breadcrumbs is built */}
|
|
76
|
+
<svg role="img" aria-label="Breadcrumbs placeholder - component not yet available in design system" ...>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Placeholders are:
|
|
80
|
+
- Accessible (`role="img"` + `aria-label`)
|
|
81
|
+
- Testable (`getByRole('img', { name: /Breadcrumbs placeholder/i })`)
|
|
82
|
+
- Visually obvious in Storybook (dashed border)
|
|
83
|
+
- Clearly documented with TODO comments
|
|
84
|
+
|
|
85
|
+
## Example Output
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
AROOOOO HUNNI! 🐺 That legacy page has been BODACIOUSLY MIGRATED! xxx
|
|
89
|
+
|
|
90
|
+
✅ Files created:
|
|
91
|
+
- src/pages/customReportWriterPage/CustomReportWriterPage.tsx
|
|
92
|
+
- src/pages/customReportWriterPage/customReportWriterPage.scss
|
|
93
|
+
- src/pages/customReportWriterPage/CustomReportWriterPage.test.tsx
|
|
94
|
+
- src/pages/customReportWriterPage/CustomReportWriterPage.stories.tsx
|
|
95
|
+
|
|
96
|
+
✅ Migration map followed:
|
|
97
|
+
- Heading → Heading level={1}
|
|
98
|
+
- Create New Report → Button variant="primary"
|
|
99
|
+
- Tabs → Tabs + Tabs.Item
|
|
100
|
+
- Data table → Table (AG Grid) with full columnDefs
|
|
101
|
+
- Bulk action → Table.BulkActionsDropdown
|
|
102
|
+
- Hide columns → Table.HideColumnsDropdown
|
|
103
|
+
- ... (14/21 elements)
|
|
104
|
+
|
|
105
|
+
⚠️ Placeholder SVGs:
|
|
106
|
+
- TopNav (app shell — ~48px)
|
|
107
|
+
- SideNavIcons (app shell — ~100% height)
|
|
108
|
+
- SideNavText (app shell — ~100% height)
|
|
109
|
+
- Breadcrumbs (~24px)
|
|
110
|
+
- Warning/Alert Banner (~64px)
|
|
111
|
+
|
|
112
|
+
✅ Tests: 24/24 passing
|
|
113
|
+
✅ Type check: PASS
|
|
114
|
+
✅ Style lint: PASS
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Notes
|
|
118
|
+
|
|
119
|
+
- **Trust the migration report** — Sophia and Dorothy already verified everything
|
|
120
|
+
- **Screenshot is layout reference only** — not the source of component decisions
|
|
121
|
+
- **Table must be mocked in tests** — AG Grid needs a license key
|
|
122
|
+
- **100% test pass rate** — always
|
|
123
|
+
- **No `any` types** — define proper TypeScript interfaces
|
|
124
|
+
- Use yarn (NOT npm)
|
|
125
|
+
- AROOOOO!! 🐺💪
|