mirror of
https://github.com/coleam00/Archon.git
synced 2025-12-24 02:39:17 -05:00
code rabbit updates
This commit is contained in:
@@ -197,18 +197,96 @@ grep -rn "type=\"checkbox\"\|type=\"radio\"" [path] --include="*.tsx"
|
||||
|
||||
---
|
||||
|
||||
## 5. PRIMITIVES LIBRARY
|
||||
## 5. CENTRALIZED STYLING (styles.ts)
|
||||
|
||||
### CRITICAL RULE: Use glassCard & glassmorphism from styles.ts
|
||||
|
||||
**Location**: `@/features/ui/primitives/styles.ts`
|
||||
|
||||
All styling definitions MUST come from the centralized `glassCard` and `glassmorphism` objects in styles.ts. Do NOT duplicate style objects in components.
|
||||
|
||||
### Anti-Patterns
|
||||
```tsx
|
||||
// ❌ WRONG - Duplicating style definitions
|
||||
const edgeColors = {
|
||||
cyan: { solid: "bg-cyan-500", gradient: "from-cyan-500/40", border: "border-cyan-500/30" },
|
||||
// ... more colors
|
||||
};
|
||||
|
||||
// ❌ WRONG - Local variant objects
|
||||
const colorVariants = {
|
||||
cyan: "shadow-cyan-500/20",
|
||||
blue: "shadow-blue-500/20",
|
||||
};
|
||||
```
|
||||
|
||||
### Good Examples
|
||||
```tsx
|
||||
// ✅ CORRECT - Use centralized definitions
|
||||
const edgeStyle = glassCard.edgeColors[edgeColor];
|
||||
<div className={edgeStyle.border}>
|
||||
<div className={edgeStyle.solid} />
|
||||
<div className={edgeStyle.gradient} />
|
||||
</div>
|
||||
|
||||
// ✅ CORRECT - Use glassCard variants
|
||||
const glowVariant = glassCard.variants[glowColor];
|
||||
<div className={cn(glowVariant.border, glowVariant.glow, glowVariant.hover)} />
|
||||
|
||||
// ✅ CORRECT - Use glassmorphism tokens
|
||||
<div className={cn(glassmorphism.background.card, glassmorphism.border.default)} />
|
||||
```
|
||||
|
||||
### What's in styles.ts
|
||||
|
||||
**glassCard object:**
|
||||
- `blur` - Blur intensity levels (sm, md, lg, xl, 2xl, 3xl)
|
||||
- `transparency` - Glass transparency (clear, light, medium, frosted, solid)
|
||||
- `variants` - Color variants with border, glow, hover (purple, blue, cyan, green, orange, pink, red)
|
||||
- `edgeColors` - Edge-lit styling with solid, gradient, border, bg
|
||||
- `tints` - Colored glass tints
|
||||
- `sizes` - Padding variants (none, sm, md, lg, xl)
|
||||
- `outerGlowSizes` - Glow size variants per color
|
||||
- `innerGlowSizes` - Inner glow size variants per color
|
||||
- `edgeLit` - Edge-lit effects (position, color with line/glow/gradient)
|
||||
|
||||
**glassmorphism object:**
|
||||
- `background` - Background variations
|
||||
- `border` - Border styles
|
||||
- `interactive` - Interactive states
|
||||
- `animation` - Animation presets
|
||||
- `shadow` - Shadow effects with neon glow
|
||||
|
||||
### Automated Scans
|
||||
```bash
|
||||
# Check for duplicate edge color definitions
|
||||
grep -rn "const edgeColors = {" [path]/primitives --include="*.tsx"
|
||||
|
||||
# Check for duplicate variant objects (should use glassCard.variants)
|
||||
grep -rn "const.*Variants = {" [path]/primitives --include="*.tsx" -A 3 | grep "cyan:\|blue:\|purple:"
|
||||
|
||||
# Check imports - all primitives should import from styles.ts
|
||||
grep -rn "from \"./styles\"" [path]/primitives --include="*.tsx" --files-without-match
|
||||
```
|
||||
|
||||
**Fix Pattern**: Import glassCard/glassmorphism from styles.ts, use object properties instead of duplicating
|
||||
|
||||
---
|
||||
|
||||
## 6. PRIMITIVES LIBRARY
|
||||
|
||||
### Archon Components
|
||||
- **Card** - For all glassmorphism effects
|
||||
- **DataCard** - Cards with header/content/footer slots
|
||||
- **PillNavigation** - Tab navigation (NEVER create custom)
|
||||
- **styles.ts** - Import `glassCard`, `glassmorphism` for styling
|
||||
- **styles.ts** - Central styling definitions (ALWAYS import)
|
||||
|
||||
### Rules
|
||||
- **Use Card props** - blur, transparency, edgePosition, glowColor (don't hardcode)
|
||||
- **Import from styles.ts** - Don't duplicate blur/glow classes
|
||||
- **All primitive props must affect rendering** - No unused props
|
||||
- **Use glassCard for card styling** - edgeColors, variants, tints, sizes
|
||||
- **Use glassmorphism for general styling** - background, border, shadow, animation
|
||||
|
||||
### Anti-Patterns
|
||||
```tsx
|
||||
@@ -269,11 +347,14 @@ grep -rn "const blurClasses\|backdrop-blur-md" [path]/primitives --include="*.ts
|
||||
|
||||
// ❌ role="button" without keyboard
|
||||
<div onClick={handler} role="button"> // Missing onKeyDown!
|
||||
|
||||
// ❌ Clickable icon without button wrapper
|
||||
<ChevronRight onClick={handler} className="cursor-pointer" />
|
||||
```
|
||||
|
||||
### Good Examples
|
||||
```tsx
|
||||
// ✅ Full keyboard support
|
||||
// ✅ Full keyboard support on div
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
@@ -286,6 +367,23 @@ grep -rn "const blurClasses\|backdrop-blur-md" [path]/primitives --include="*.ts
|
||||
}}
|
||||
aria-selected={isSelected}
|
||||
>
|
||||
|
||||
// ✅ Clickable icon wrapped in button
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Expand menu"
|
||||
aria-expanded={isExpanded}
|
||||
onClick={handler}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
handler();
|
||||
}
|
||||
}}
|
||||
className="focus:outline-none focus:ring-2"
|
||||
>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
</button>
|
||||
```
|
||||
|
||||
### Automated Scans
|
||||
@@ -293,9 +391,14 @@ grep -rn "const blurClasses\|backdrop-blur-md" [path]/primitives --include="*.ts
|
||||
# Interactive divs without keyboard
|
||||
grep -rn "onClick.*role=\"button\"" [path] --include="*.tsx"
|
||||
# Then manually verify onKeyDown exists
|
||||
|
||||
# Icons with onClick (should be wrapped in button)
|
||||
grep -rn "<[A-Z].*onClick={" [path] --include="*.tsx" | grep -v "<button\|<Button"
|
||||
```
|
||||
|
||||
**Fix Pattern**: Add onKeyDown handler with Enter/Space, add tabIndex={0}, add ARIA
|
||||
**Fix Pattern**:
|
||||
- Add onKeyDown handler with Enter/Space, add tabIndex={0}, add ARIA
|
||||
- Wrap clickable icons in `<button type="button">` with proper ARIA attributes
|
||||
|
||||
---
|
||||
|
||||
@@ -304,8 +407,10 @@ grep -rn "onClick.*role=\"button\"" [path] --include="*.tsx"
|
||||
### Rules
|
||||
- **Async functions return Promise<void>** - Not just `void` if awaited
|
||||
- **All props must be used** - If prop in interface, must affect rendering
|
||||
- **Color types consistent** - Use "green" not "emerald" across components
|
||||
- **Color types consistent** - Use "green" not "emerald" across components (avoid emerald entirely)
|
||||
- **Run `tsc --noEmit`** to catch type errors
|
||||
- **Use `satisfies` for lookup objects** - Enforce type coverage on color variants
|
||||
- **120 character line limit** - Split long class strings into arrays with `.join(" ")`
|
||||
|
||||
### Anti-Patterns
|
||||
```tsx
|
||||
@@ -319,6 +424,18 @@ return <div> {/* glowColor never used! */}
|
||||
// ❌ Color type mismatch
|
||||
// PillNavigation: colorVariant?: "emerald"
|
||||
// Select: color?: "green" // Should match!
|
||||
|
||||
// ❌ Long class strings (exceeds 120 chars)
|
||||
const activeClasses = {
|
||||
blue: "data-[state=active]:bg-blue-500/20 dark:data-[state=active]:bg-blue-400/20 data-[state=active]:text-blue-700 dark:data-[state=active]:text-blue-300 data-[state=active]:border data-[state=active]:border-blue-400/50",
|
||||
};
|
||||
|
||||
// ❌ Lookup objects without type safety
|
||||
const colorClasses = {
|
||||
cyan: "bg-cyan-500",
|
||||
blue: "bg-blue-500",
|
||||
// What if we forget purple? No compile error!
|
||||
};
|
||||
```
|
||||
|
||||
### Good Examples
|
||||
@@ -331,8 +448,28 @@ interface CardProps { glowColor?: string }
|
||||
const glow = glassCard.variants[glowColor];
|
||||
return <div className={glow.border} />
|
||||
|
||||
// ✅ Consistent color types
|
||||
// ✅ Consistent color types (always use "green", never "emerald")
|
||||
type Color = "purple" | "blue" | "cyan" | "green" | "orange" | "pink";
|
||||
|
||||
// ✅ Split long class strings (under 120 chars per line)
|
||||
const activeClasses = {
|
||||
blue: [
|
||||
"data-[state=active]:bg-blue-500/20 dark:data-[state=active]:bg-blue-400/20",
|
||||
"data-[state=active]:text-blue-700 dark:data-[state=active]:text-blue-300",
|
||||
"data-[state=active]:border data-[state=active]:border-blue-400/50",
|
||||
].join(" "),
|
||||
};
|
||||
|
||||
// ✅ Type-safe lookup objects with satisfies
|
||||
type Color = "purple" | "blue" | "cyan" | "green" | "orange" | "pink";
|
||||
const colorClasses = {
|
||||
purple: "bg-purple-500",
|
||||
blue: "bg-blue-500",
|
||||
cyan: "bg-cyan-500",
|
||||
green: "bg-green-500",
|
||||
orange: "bg-orange-500",
|
||||
pink: "bg-pink-500",
|
||||
} satisfies Record<Color, string>; // TypeScript enforces all colors present!
|
||||
```
|
||||
|
||||
### Automated Scans
|
||||
@@ -340,16 +477,25 @@ type Color = "purple" | "blue" | "cyan" | "green" | "orange" | "pink";
|
||||
# TypeScript errors
|
||||
npx tsc --noEmit [path] 2>&1 | grep "error TS"
|
||||
|
||||
# Color type inconsistencies
|
||||
grep -rn "emerald.*type.*Color" [path] --include="*.tsx"
|
||||
grep -rn "green.*type.*Color" [path] --include="*.tsx"
|
||||
# Color type inconsistencies (must use "green" not "emerald")
|
||||
grep -rn "emerald" [path] --include="*.tsx" --include="*.ts"
|
||||
|
||||
# Line length violations (over 120 chars)
|
||||
grep -rn ".\{121,\}" [path] --include="*.tsx" | grep className
|
||||
|
||||
# Lookup objects without satisfies
|
||||
grep -rn "const.*Classes = {" [path]/primitives --include="*.tsx" -A 5 | grep -v "satisfies"
|
||||
|
||||
# Unused props (manual)
|
||||
grep -rn "interface.*Props" [path]/primitives --include="*.tsx" -A 10
|
||||
# Then verify each prop name appears in return statement
|
||||
```
|
||||
|
||||
**Fix Pattern**: Update types to match implementation, wire props to rendering, use consistent names
|
||||
**Fix Pattern**:
|
||||
- Split long strings into arrays: `["class1", "class2"].join(" ")`
|
||||
- Add `satisfies Record<ColorType, string>` to lookup objects
|
||||
- Replace all "emerald" with "green" + update RGB to green-500 (34,197,94)
|
||||
- Wire all props to rendering
|
||||
|
||||
---
|
||||
|
||||
@@ -418,16 +564,20 @@ Run ALL these scans during review:
|
||||
- Non-responsive grids: `grep -rn "grid-cols-[2-9]" [path] | grep -v "md:\|lg:"`
|
||||
- Unconstrained scroll: `grep -rn "overflow-x-auto" [path]` (verify w-full parent)
|
||||
- Native HTML: `grep -rn "<select>\|type=\"checkbox\"" [path]`
|
||||
- Emerald usage: `grep -rn "emerald" [path] --include="*.tsx" --include="*.ts"` (must use "green")
|
||||
|
||||
### High Priority
|
||||
- Missing keyboard: `grep -rn "onClick.*role=\"button\"" [path]` (verify onKeyDown)
|
||||
- Clickable icons: `grep -rn "<[A-Z].*onClick={" [path] --include="*.tsx" | grep -v "<button\|<Button"`
|
||||
- Missing dark mode: `grep -rn "bg-.*-[0-9]" [path] | grep -v "dark:"`
|
||||
- Hardcoded glass: `grep -rn "backdrop-blur.*bg-white/.*border" [path]`
|
||||
- Missing min-w-0: `grep -rn "flex-1" [path] | grep -v "min-w-0"`
|
||||
- Duplicate styling: `grep -rn "const edgeColors = {\|const.*Variants = {" [path]/primitives`
|
||||
|
||||
### Medium Priority
|
||||
- TypeScript: `npx tsc --noEmit [path] 2>&1 | grep "error TS"`
|
||||
- Color mismatches: `grep -rn "emerald\|green" [path] | grep "type.*Color"`
|
||||
- Line length: `grep -rn ".\{121,\}" [path] --include="*.tsx" | grep className`
|
||||
- Missing satisfies: `grep -rn "const.*Classes = {" [path]/primitives -A 5 | grep -v "satisfies"`
|
||||
- Props unused: Manual check interfaces vs usage
|
||||
|
||||
---
|
||||
|
||||
@@ -357,7 +357,7 @@ const SidebarProjectCard = ({
|
||||
icon={<Activity className="w-3 h-3" />}
|
||||
/>
|
||||
<StatPill
|
||||
color="emerald"
|
||||
color="green"
|
||||
value={project.taskCounts.done}
|
||||
size="sm"
|
||||
icon={<CheckCircle2 className="w-3 h-3" />}
|
||||
|
||||
@@ -5,7 +5,7 @@ export const StaticColors = () => {
|
||||
const semanticColors = [
|
||||
{ name: "Primary", hex: "#3b82f6", tailwind: "blue-500", usage: "Primary actions, links, focus states" },
|
||||
{ name: "Secondary", hex: "#6b7280", tailwind: "gray-500", usage: "Secondary actions, neutral elements" },
|
||||
{ name: "Success", hex: "#10b981", tailwind: "emerald-500", usage: "Success states, confirmations" },
|
||||
{ name: "Success", hex: "#22c55e", tailwind: "green-500", usage: "Success states, confirmations" },
|
||||
{ name: "Warning", hex: "#f97316", tailwind: "orange-500", usage: "Warnings, cautions" },
|
||||
{ name: "Error", hex: "#ef4444", tailwind: "red-500", usage: "Errors, destructive actions" },
|
||||
];
|
||||
|
||||
@@ -68,29 +68,7 @@ export const Card = React.forwardRef<HTMLDivElement, CardProps>(
|
||||
return glassCard.outerGlowHover?.[glowColor]?.[glowSize] || glowVariant.hover;
|
||||
};
|
||||
|
||||
// Edge color mappings
|
||||
const edgeColors = {
|
||||
purple: { solid: "bg-purple-500", gradient: "from-purple-500/40", border: "border-purple-500/30" },
|
||||
blue: { solid: "bg-blue-500", gradient: "from-blue-500/40", border: "border-blue-500/30" },
|
||||
cyan: { solid: "bg-cyan-500", gradient: "from-cyan-500/40", border: "border-cyan-500/30" },
|
||||
green: { solid: "bg-green-500", gradient: "from-green-500/40", border: "border-green-500/30" },
|
||||
orange: { solid: "bg-orange-500", gradient: "from-orange-500/40", border: "border-orange-500/30" },
|
||||
pink: { solid: "bg-pink-500", gradient: "from-pink-500/40", border: "border-pink-500/30" },
|
||||
red: { solid: "bg-red-500", gradient: "from-red-500/40", border: "border-red-500/30" },
|
||||
};
|
||||
|
||||
const edgeStyle = edgeColors[edgeColor];
|
||||
|
||||
// Tint backgrounds for edge-lit cards
|
||||
const tintBackgrounds = {
|
||||
purple: "bg-gradient-to-br from-purple-500/15 to-purple-600/5",
|
||||
blue: "bg-gradient-to-br from-blue-500/15 to-blue-600/5",
|
||||
cyan: "bg-gradient-to-br from-cyan-500/15 to-cyan-600/5",
|
||||
green: "bg-gradient-to-br from-green-500/15 to-green-600/5",
|
||||
orange: "bg-gradient-to-br from-orange-500/15 to-orange-600/5",
|
||||
pink: "bg-gradient-to-br from-pink-500/15 to-pink-600/5",
|
||||
red: "bg-gradient-to-br from-red-500/15 to-red-600/5",
|
||||
};
|
||||
const edgeStyle = glassCard.edgeColors[edgeColor];
|
||||
|
||||
if (hasEdge) {
|
||||
// Edge-lit card with actual div elements (not pseudo-elements)
|
||||
@@ -129,9 +107,7 @@ export const Card = React.forwardRef<HTMLDivElement, CardProps>(
|
||||
{/* Glow bleeding into card */}
|
||||
<div className={cn(config.glow, "blur-lg pointer-events-none z-10", edgeStyle.gradient)} />
|
||||
{/* Content with tinted background - INHERIT flex classes */}
|
||||
<div className={cn("backdrop-blur-sm", tintBackgrounds[edgeColor], glassCard.sizes[size], flexClasses)}>
|
||||
{children}
|
||||
</div>
|
||||
<div className={cn("backdrop-blur-sm", edgeStyle.bg, glassCard.sizes[size], flexClasses)}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,10 +24,10 @@ const checkboxVariants = {
|
||||
focusRing: "focus-visible:ring-blue-500",
|
||||
},
|
||||
green: {
|
||||
checked: "data-[state=checked]:bg-emerald-500/20 data-[state=checked]:border-emerald-500",
|
||||
glow: "data-[state=checked]:shadow-[0_0_15px_rgba(16,185,129,0.5)]",
|
||||
indicator: "text-emerald-400 drop-shadow-[0_0_3px_rgba(16,185,129,0.7)]",
|
||||
focusRing: "focus-visible:ring-emerald-500",
|
||||
checked: "data-[state=checked]:bg-green-500/20 data-[state=checked]:border-green-500",
|
||||
glow: "data-[state=checked]:shadow-[0_0_15px_rgba(34,197,94,0.5)]",
|
||||
indicator: "text-green-400 drop-shadow-[0_0_3px_rgba(34,197,94,0.7)]",
|
||||
focusRing: "focus-visible:ring-green-500",
|
||||
},
|
||||
pink: {
|
||||
checked: "data-[state=checked]:bg-pink-500/20 data-[state=checked]:border-pink-500",
|
||||
|
||||
@@ -42,7 +42,7 @@ export const DataCard = React.forwardRef<HTMLDivElement, DataCardProps>(
|
||||
ref={ref}
|
||||
className={cn(
|
||||
glassCard.base,
|
||||
glassCard.edgeLit.color[edgeColor].border || "border-gray-300/20 dark:border-white/10",
|
||||
glassCard.edgeColors[edgeColor].border || "border-gray-300/20 dark:border-white/10",
|
||||
"min-h-[240px]",
|
||||
className,
|
||||
)}
|
||||
@@ -80,17 +80,18 @@ export const DataCard = React.forwardRef<HTMLDivElement, DataCardProps>(
|
||||
}
|
||||
|
||||
// Standard card (no edge-lit)
|
||||
const glowClasses = !hasEdge && hasGlow ? [glowVariant.border, glowVariant.glow, glowVariant.hover] : [];
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative rounded-xl overflow-hidden border min-h-[240px]",
|
||||
"relative rounded-xl overflow-hidden min-h-[240px]",
|
||||
glassCard.blur[blur],
|
||||
glassCard.transparency[transparency],
|
||||
"flex flex-col",
|
||||
hasGlow ? glowVariant.border : "border-gray-300/20 dark:border-white/10",
|
||||
hasGlow && glowVariant.glow,
|
||||
hasGlow && glowVariant.hover,
|
||||
hasGlow ? "" : "border border-gray-300/20 dark:border-white/10",
|
||||
...glowClasses,
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -112,13 +112,24 @@ export const PillNavigation = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ChevronRight
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
"w-4 h-4 transition-transform duration-300 ml-2 cursor-pointer",
|
||||
"ml-2 flex h-6 w-6 items-center justify-center rounded-full transition-transform duration-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-transparent focus:ring-current",
|
||||
isThisExpanded ? "-rotate-90" : "rotate-0",
|
||||
)}
|
||||
aria-label={isThisExpanded ? `Collapse ${item.label}` : `Expand ${item.label}`}
|
||||
aria-expanded={isThisExpanded}
|
||||
onClick={() => onSectionClick(item.id)}
|
||||
/>
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
onSectionClick(item.id);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
/* Regular pill for non-selected items */
|
||||
|
||||
@@ -22,8 +22,8 @@ const selectColorVariants = {
|
||||
},
|
||||
green: {
|
||||
trigger:
|
||||
"hover:border-emerald-400/50 hover:shadow-[0_0_15px_rgba(16,185,129,0.3)] focus:border-emerald-500 focus:shadow-[0_0_20px_rgba(16,185,129,0.4)]",
|
||||
item: "hover:bg-emerald-500/20 dark:hover:bg-emerald-400/20 data-[state=checked]:bg-emerald-500/30 dark:data-[state=checked]:bg-emerald-400/30 data-[state=checked]:text-emerald-700 dark:data-[state=checked]:text-emerald-300",
|
||||
"hover:border-green-400/50 hover:shadow-[0_0_15px_rgba(34,197,94,0.3)] focus:border-green-500 focus:shadow-[0_0_20px_rgba(34,197,94,0.4)]",
|
||||
item: "hover:bg-green-500/20 dark:hover:bg-green-400/20 data-[state=checked]:bg-green-500/30 dark:data-[state=checked]:bg-green-400/30 data-[state=checked]:text-green-700 dark:data-[state=checked]:text-green-300",
|
||||
},
|
||||
pink: {
|
||||
trigger:
|
||||
@@ -107,7 +107,7 @@ export const SelectContent = React.forwardRef<
|
||||
const glowColor = {
|
||||
purple: "shadow-purple-500/20 dark:shadow-purple-500/30",
|
||||
blue: "shadow-blue-500/20 dark:shadow-blue-500/30",
|
||||
green: "shadow-emerald-500/20 dark:shadow-emerald-500/30",
|
||||
green: "shadow-green-500/20 dark:shadow-green-500/30",
|
||||
pink: "shadow-pink-500/20 dark:shadow-pink-500/30",
|
||||
orange: "shadow-orange-500/20 dark:shadow-orange-500/30",
|
||||
cyan: "shadow-cyan-500/20 dark:shadow-cyan-500/30",
|
||||
|
||||
@@ -13,7 +13,8 @@ export const TabsList = React.forwardRef<
|
||||
<TabsPrimitive.List
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"backdrop-blur-sm bg-white/40 dark:bg-white/5 border border-white/30 dark:border-white/15 rounded-full p-1 shadow-lg inline-flex gap-1",
|
||||
"backdrop-blur-sm bg-white/40 dark:bg-white/5 border border-white/30 dark:border-white/15",
|
||||
"rounded-full p-1 shadow-lg inline-flex gap-1",
|
||||
className,
|
||||
)}
|
||||
role="tablist"
|
||||
@@ -23,23 +24,52 @@ export const TabsList = React.forwardRef<
|
||||
TabsList.displayName = TabsPrimitive.List.displayName;
|
||||
|
||||
// Trigger
|
||||
type TabColor = "blue" | "purple" | "pink" | "orange" | "cyan" | "green";
|
||||
|
||||
export const TabsTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger> & {
|
||||
color?: "blue" | "purple" | "pink" | "orange" | "cyan" | "green";
|
||||
color?: TabColor;
|
||||
}
|
||||
>(({ className, color = "blue", ...props }, ref) => {
|
||||
const activeClasses = {
|
||||
blue: "data-[state=active]:bg-blue-500/20 dark:data-[state=active]:bg-blue-400/20 data-[state=active]:text-blue-700 dark:data-[state=active]:text-blue-300 data-[state=active]:border data-[state=active]:border-blue-400/50 data-[state=active]:shadow-[0_0_10px_rgba(59,130,246,0.5)]",
|
||||
purple:
|
||||
"data-[state=active]:bg-purple-500/20 dark:data-[state=active]:bg-purple-400/20 data-[state=active]:text-purple-700 dark:data-[state=active]:text-purple-300 data-[state=active]:border data-[state=active]:border-purple-400/50 data-[state=active]:shadow-[0_0_10px_rgba(168,85,247,0.5)]",
|
||||
pink: "data-[state=active]:bg-pink-500/20 dark:data-[state=active]:bg-pink-400/20 data-[state=active]:text-pink-700 dark:data-[state=active]:text-pink-300 data-[state=active]:border data-[state=active]:border-pink-400/50 data-[state=active]:shadow-[0_0_10px_rgba(236,72,153,0.5)]",
|
||||
orange:
|
||||
"data-[state=active]:bg-orange-500/20 dark:data-[state=active]:bg-orange-400/20 data-[state=active]:text-orange-700 dark:data-[state=active]:text-orange-300 data-[state=active]:border data-[state=active]:border-orange-400/50 data-[state=active]:shadow-[0_0_10px_rgba(251,146,60,0.5)]",
|
||||
cyan: "data-[state=active]:bg-cyan-500/20 dark:data-[state=active]:bg-cyan-400/20 data-[state=active]:text-cyan-700 dark:data-[state=active]:text-cyan-300 data-[state=active]:border data-[state=active]:border-cyan-400/50 data-[state=active]:shadow-[0_0_10px_rgba(34,211,238,0.5)]",
|
||||
green:
|
||||
"data-[state=active]:bg-green-500/20 dark:data-[state=active]:bg-green-400/20 data-[state=active]:text-green-700 dark:data-[state=active]:text-green-300 data-[state=active]:border data-[state=active]:border-green-400/50 data-[state=active]:shadow-[0_0_10px_rgba(16,185,129,0.5)]",
|
||||
};
|
||||
blue: [
|
||||
"data-[state=active]:bg-blue-500/20 dark:data-[state=active]:bg-blue-400/20",
|
||||
"data-[state=active]:text-blue-700 dark:data-[state=active]:text-blue-300",
|
||||
"data-[state=active]:border data-[state=active]:border-blue-400/50",
|
||||
"data-[state=active]:shadow-[0_0_10px_rgba(59,130,246,0.5)]",
|
||||
].join(" "),
|
||||
purple: [
|
||||
"data-[state=active]:bg-purple-500/20 dark:data-[state=active]:bg-purple-400/20",
|
||||
"data-[state=active]:text-purple-700 dark:data-[state=active]:text-purple-300",
|
||||
"data-[state=active]:border data-[state=active]:border-purple-400/50",
|
||||
"data-[state=active]:shadow-[0_0_10px_rgba(168,85,247,0.5)]",
|
||||
].join(" "),
|
||||
pink: [
|
||||
"data-[state=active]:bg-pink-500/20 dark:data-[state=active]:bg-pink-400/20",
|
||||
"data-[state=active]:text-pink-700 dark:data-[state=active]:text-pink-300",
|
||||
"data-[state=active]:border data-[state=active]:border-pink-400/50",
|
||||
"data-[state=active]:shadow-[0_0_10px_rgba(236,72,153,0.5)]",
|
||||
].join(" "),
|
||||
orange: [
|
||||
"data-[state=active]:bg-orange-500/20 dark:data-[state=active]:bg-orange-400/20",
|
||||
"data-[state=active]:text-orange-700 dark:data-[state=active]:text-orange-300",
|
||||
"data-[state=active]:border data-[state=active]:border-orange-400/50",
|
||||
"data-[state=active]:shadow-[0_0_10px_rgba(251,146,60,0.5)]",
|
||||
].join(" "),
|
||||
cyan: [
|
||||
"data-[state=active]:bg-cyan-500/20 dark:data-[state=active]:bg-cyan-400/20",
|
||||
"data-[state=active]:text-cyan-700 dark:data-[state=active]:text-cyan-300",
|
||||
"data-[state=active]:border data-[state=active]:border-cyan-400/50",
|
||||
"data-[state=active]:shadow-[0_0_10px_rgba(34,211,238,0.5)]",
|
||||
].join(" "),
|
||||
green: [
|
||||
"data-[state=active]:bg-green-500/20 dark:data-[state=active]:bg-green-400/20",
|
||||
"data-[state=active]:text-green-700 dark:data-[state=active]:text-green-300",
|
||||
"data-[state=active]:border data-[state=active]:border-green-400/50",
|
||||
"data-[state=active]:shadow-[0_0_10px_rgba(34,197,94,0.5)]",
|
||||
].join(" "),
|
||||
} satisfies Record<TabColor, string>;
|
||||
|
||||
const focusRingClasses = {
|
||||
blue: "focus-visible:ring-blue-500",
|
||||
@@ -47,8 +77,8 @@ export const TabsTrigger = React.forwardRef<
|
||||
pink: "focus-visible:ring-pink-500",
|
||||
orange: "focus-visible:ring-orange-500",
|
||||
cyan: "focus-visible:ring-cyan-500",
|
||||
green: "focus-visible:ring-emerald-500",
|
||||
};
|
||||
green: "focus-visible:ring-green-500",
|
||||
} satisfies Record<TabColor, string>;
|
||||
|
||||
return (
|
||||
<TabsPrimitive.Trigger
|
||||
@@ -79,7 +109,8 @@ export const TabsContent = React.forwardRef<
|
||||
<TabsPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2",
|
||||
"focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -1,422 +0,0 @@
|
||||
# UI Consistency Review
|
||||
|
||||
**Date**: 2025-10-09
|
||||
**Scope**: `archon-ui-main/src/features/style-guide`
|
||||
**Components Analyzed**: 18
|
||||
|
||||
---
|
||||
|
||||
## Overall Scores
|
||||
|
||||
| Category | Score | Assessment |
|
||||
|----------|-------|------------|
|
||||
| Reusability | 9/10 | Excellent |
|
||||
| Radix Usage | 10/10 | Perfect |
|
||||
| Primitives Usage | 10/10 | Perfect |
|
||||
| Styling Consistency | 8/10 | Very Good |
|
||||
|
||||
**Overall Grade**: A- - Excellent adherence to design system with minor color type inconsistency
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
The style-guide feature demonstrates **exemplary** implementation of Archon's design system. This is one of the cleanest, most consistent feature implementations in the codebase. The code follows nearly all best practices:
|
||||
|
||||
### ✅ Strengths
|
||||
- **Zero dynamic class construction** - All color variants use proper static lookup objects
|
||||
- **100% Radix UI adoption** - All form elements use Radix primitives
|
||||
- **100% Card primitive usage** - Every card uses the Card primitive with proper props
|
||||
- **Responsive grids everywhere** - All layouts use proper breakpoints
|
||||
- **Perfect PillNavigation usage** - Uses the shared component, no duplication
|
||||
- **Working drag-and-drop** - DraggableCard implementation is functional
|
||||
- **Working filters** - Filter state correctly affects rendered data
|
||||
- **Excellent text truncation** - All dynamic content has proper truncation
|
||||
- **Full dark mode support** - Every color has dark: variant
|
||||
|
||||
### ⚠️ Areas for Improvement
|
||||
1. **Color type inconsistency** - Primitive uses "emerald", shared component uses "green" (not critical, but inconsistent)
|
||||
2. **Duplicate PillNavigation component** - Two implementations exist (shared/ vs ui/primitives/)
|
||||
|
||||
**Impact**: None of the issues are critical. This feature could ship as-is with zero functional problems.
|
||||
|
||||
---
|
||||
|
||||
## Component-by-Component Analysis
|
||||
|
||||
### StaticCards.tsx ✅
|
||||
|
||||
**Scores:**
|
||||
- Reusability: 10/10
|
||||
- Radix Usage: 10/10
|
||||
- Primitives Usage: 10/10
|
||||
- Styling Consistency: 10/10
|
||||
|
||||
**Perfect Implementation** - This file is a **textbook example** of how to use the Archon design system:
|
||||
|
||||
**Highlights:**
|
||||
- Lines 151-156: Static color lookup object (perfect Tailwind v4 compliance)
|
||||
- Lines 37-42: Card primitive with all props working (transparency, blur, size)
|
||||
- Lines 85-95: Proper glowColor, glowType, glowSize props
|
||||
- Lines 182-192: Edge-lit cards using edgePosition/edgeColor props
|
||||
- Lines 203-214: Fully functional drag-and-drop with state management
|
||||
- Lines 224: Responsive grid with `grid-cols-1 md:grid-cols-2`
|
||||
- Lines 253: Responsive grid with `grid-cols-1 sm:grid-cols-2 md:grid-cols-3`
|
||||
|
||||
**Why this is excellent:**
|
||||
```tsx
|
||||
// Lines 151-156 - Static color classes (NOT dynamic)
|
||||
const tabColorClasses = {
|
||||
cyan: "bg-cyan-500/20 text-cyan-700 dark:text-cyan-300 border border-cyan-500/50",
|
||||
purple: "bg-purple-500/20 text-purple-700 dark:text-purple-300 border border-purple-500/50",
|
||||
// ... all properties included statically
|
||||
};
|
||||
```
|
||||
|
||||
This ensures Tailwind generates all CSS at build time.
|
||||
|
||||
**Issues Found:** None
|
||||
|
||||
---
|
||||
|
||||
### StaticForms.tsx ✅
|
||||
|
||||
**Scores:**
|
||||
- Reusability: 10/10
|
||||
- Radix Usage: 10/10
|
||||
- Primitives Usage: 10/10
|
||||
- Styling Consistency: 10/10
|
||||
|
||||
**Perfect Radix Usage** - Shows every form element using Radix primitives:
|
||||
|
||||
**Highlights:**
|
||||
- Lines 4-8: Imports all from `@/features/ui/primitives/`
|
||||
- Lines 68-78: Checkbox with color variants (cyan, purple)
|
||||
- Lines 89-98: Switch component usage
|
||||
- Lines 109-133: Select dropdown with color variants
|
||||
- Lines 38, 42: Input component with proper Label association
|
||||
- Lines 53-59: Textarea with glassmorphism styling
|
||||
|
||||
**Issues Found:** None
|
||||
|
||||
---
|
||||
|
||||
### KnowledgeLayoutExample.tsx ✅
|
||||
|
||||
**Scores:**
|
||||
- Reusability: 10/10
|
||||
- Radix Usage: 10/10
|
||||
- Primitives Usage: 10/10
|
||||
- Styling Consistency: 10/10
|
||||
|
||||
**Perfect Layout Pattern** - Demonstrates switchable views with functional filtering:
|
||||
|
||||
**Highlights:**
|
||||
- Lines 72-75: `useMemo` for efficient filtering (state correctly affects data)
|
||||
- Lines 134: Responsive grid `grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4`
|
||||
- Lines 141-159: Proper horizontal scroll with `w-full` wrapper
|
||||
- Lines 202-266: DataCard primitive with all slots (Header, Content, Footer)
|
||||
- Lines 233: Text truncation `line-clamp-2` on dynamic titles
|
||||
- Lines 235: URL truncation with `truncate`
|
||||
- Lines 169-186: GroupedCard component usage
|
||||
|
||||
**Functional Logic:**
|
||||
```tsx
|
||||
// Lines 72-75 - Filter actually works!
|
||||
const filteredItems = useMemo(() => {
|
||||
if (typeFilter === "all") return MOCK_KNOWLEDGE_ITEMS;
|
||||
return MOCK_KNOWLEDGE_ITEMS.filter((item) => item.type === typeFilter);
|
||||
}, [typeFilter]);
|
||||
```
|
||||
|
||||
**Issues Found:** None
|
||||
|
||||
---
|
||||
|
||||
### StyleGuideView.tsx ✅
|
||||
|
||||
**Scores:**
|
||||
- Reusability: 10/10
|
||||
- Radix Usage: 10/10
|
||||
- Primitives Usage: 10/10
|
||||
- Styling Consistency: 10/10
|
||||
|
||||
**Perfect PillNavigation Usage:**
|
||||
- Lines 33-42: Uses shared PillNavigation component
|
||||
- All props properly configured (colorVariant, showIcons, hasSubmenus)
|
||||
|
||||
**Issues Found:** None
|
||||
|
||||
---
|
||||
|
||||
### StaticToggles.tsx ✅
|
||||
|
||||
**Scores:**
|
||||
- Reusability: 10/10
|
||||
- Radix Usage: 10/10
|
||||
- Primitives Usage: 10/10
|
||||
- Styling Consistency: 10/10
|
||||
|
||||
**Highlights:**
|
||||
- Lines 33-67: PowerButton with functional state management
|
||||
- Lines 79-86: Switch primitive usage
|
||||
- Proper Label associations with `useId()`
|
||||
|
||||
**Issues Found:** None
|
||||
|
||||
---
|
||||
|
||||
### PillNavigation (Duplication Issue) ⚠️
|
||||
|
||||
**Locations:**
|
||||
- `/features/style-guide/shared/PillNavigation.tsx`
|
||||
- `/features/ui/primitives/pill-navigation.tsx`
|
||||
|
||||
**Scores:**
|
||||
- Reusability: 7/10 (duplicate implementation)
|
||||
- Radix Usage: 10/10
|
||||
- Primitives Usage: 10/10
|
||||
- Styling Consistency: 7/10 (color type mismatch)
|
||||
|
||||
**Issue #1: Duplicate Component**
|
||||
- **Problem**: Two identical implementations of PillNavigation exist
|
||||
- **Impact**: Medium - Maintenance burden, potential for divergence
|
||||
- **Location**:
|
||||
- `archon-ui-main/src/features/style-guide/shared/PillNavigation.tsx` (154 lines)
|
||||
- `archon-ui-main/src/features/ui/primitives/pill-navigation.tsx` (154 lines)
|
||||
|
||||
**Issue #2: Color Type Inconsistency**
|
||||
- **Problem**: Primitive accepts `"green"` but renders using `emerald` classes
|
||||
- **Impact**: Low - Works functionally, but confusing for developers
|
||||
- **Location**:
|
||||
- Primitive (line 19): `colorVariant?: "blue" | "orange" | "cyan" | "purple" | "green"`
|
||||
- Primitive (line 54-56): `green: isSelected ? "bg-emerald-500/20 ... text-emerald-700"`
|
||||
- Style-guide version (line 19): Uses `"emerald"` in type definition
|
||||
|
||||
**Current Behavior:**
|
||||
```tsx
|
||||
// ui/primitives/pill-navigation.tsx:19
|
||||
colorVariant?: "blue" | "orange" | "cyan" | "purple" | "green"
|
||||
|
||||
// ui/primitives/pill-navigation.tsx:54-56
|
||||
green: isSelected
|
||||
? "bg-emerald-500/20 dark:bg-emerald-400/20 text-emerald-700 ..."
|
||||
```
|
||||
|
||||
**Why this matters:**
|
||||
- Developer passes `color="green"` but CSS uses `emerald` classes
|
||||
- Inconsistent naming convention (all others match: cyan→cyan, blue→blue)
|
||||
|
||||
**Recommendation:**
|
||||
1. **Remove** `archon-ui-main/src/features/style-guide/shared/PillNavigation.tsx`
|
||||
2. **Update imports** in style-guide components to use `@/features/ui/primitives/pill-navigation`
|
||||
3. **Decide on naming**: Either:
|
||||
- Change type to `"emerald"` and require `colorVariant="emerald"`, or
|
||||
- Change CSS classes from `emerald-*` to `green-*`
|
||||
- (Recommend the latter for consistency with "green" being more intuitive)
|
||||
|
||||
---
|
||||
|
||||
## Critical Issues (Must Fix)
|
||||
|
||||
**None** - No critical issues found. All anti-patterns were avoided.
|
||||
|
||||
---
|
||||
|
||||
## Medium Priority Issues
|
||||
|
||||
### 1. Duplicate PillNavigation Component
|
||||
- **Files**:
|
||||
- `/features/style-guide/shared/PillNavigation.tsx` (should be removed)
|
||||
- `/features/ui/primitives/pill-navigation.tsx` (canonical version)
|
||||
- **Problem**: Two identical 154-line implementations
|
||||
- **Why**: Maintenance burden, potential for divergence
|
||||
- **Fix**:
|
||||
```tsx
|
||||
// In all style-guide components, change:
|
||||
import { PillNavigation } from '../shared/PillNavigation';
|
||||
|
||||
// To:
|
||||
import { PillNavigation } from '@/features/ui/primitives/pill-navigation';
|
||||
|
||||
// Then delete: features/style-guide/shared/PillNavigation.tsx
|
||||
```
|
||||
|
||||
### 2. Color Type Inconsistency ("green" vs "emerald")
|
||||
- **File**: `archon-ui-main/src/features/ui/primitives/pill-navigation.tsx`
|
||||
- **Problem**: Type accepts `"green"` but CSS uses `emerald` classes
|
||||
- **Why**: Confusing for developers, inconsistent with other color names
|
||||
- **Fix Option 1** (Recommended - Use "green" everywhere):
|
||||
```tsx
|
||||
// Line 54-56: Change from:
|
||||
green: isSelected
|
||||
? "bg-emerald-500/20 dark:bg-emerald-400/20 text-emerald-700 dark:text-emerald-300 border border-emerald-400/50 shadow-[0_0_10px_rgba(16,185,129,0.5)]"
|
||||
|
||||
// To:
|
||||
green: isSelected
|
||||
? "bg-green-500/20 dark:bg-green-400/20 text-green-700 dark:text-green-300 border border-green-400/50 shadow-[0_0_10px_rgba(34,197,94,0.5)]"
|
||||
```
|
||||
|
||||
**Fix Option 2** (Alternative - Use "emerald" everywhere):
|
||||
```tsx
|
||||
// Line 19: Change type from:
|
||||
colorVariant?: "blue" | "orange" | "cyan" | "purple" | "green"
|
||||
|
||||
// To:
|
||||
colorVariant?: "blue" | "orange" | "cyan" | "purple" | "emerald"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Recommendations
|
||||
|
||||
### Immediate Actions
|
||||
|
||||
1. **Remove duplicate PillNavigation** - Delete `/features/style-guide/shared/PillNavigation.tsx` and update imports (5 minutes)
|
||||
2. **Resolve color naming** - Decide "green" vs "emerald" and make consistent (2 minutes)
|
||||
|
||||
### Pattern Improvements
|
||||
|
||||
**None needed** - This feature is already a best-practice reference implementation.
|
||||
|
||||
### Refactoring Priorities
|
||||
|
||||
1. **Low Priority**: Deduplicate PillNavigation (1 hour including testing all style-guide pages)
|
||||
2. **Low Priority**: Color naming consistency (10 minutes)
|
||||
|
||||
---
|
||||
|
||||
## Design System Compliance
|
||||
|
||||
### Primitives Used Correctly ✅
|
||||
|
||||
**All components perfectly use primitives:**
|
||||
- Card with transparency, blur, glowColor, glowType, glowSize, edgePosition, edgeColor
|
||||
- DataCard with Header, Content, Footer slots
|
||||
- SelectableCard with isSelected, showAuroraGlow, onSelect
|
||||
- DraggableCard with functional drag-and-drop
|
||||
- PillNavigation (though duplicated)
|
||||
- GroupedCard with progressive scaling
|
||||
- Button, Input, Label, Checkbox, Switch, Select (all Radix)
|
||||
|
||||
### Radix Compliance ✅
|
||||
|
||||
**Perfect Radix adoption:**
|
||||
- No native `<select>`, `<option>`, `<input type="checkbox">`, `<input type="radio">` anywhere
|
||||
- All form controls use Radix primitives from `/features/ui/primitives/`
|
||||
- Proper composition with asChild (where applicable)
|
||||
|
||||
### Styling Patterns ✅
|
||||
|
||||
**Excellent consistency:**
|
||||
- Edge-lit cards: 100% use Card primitive with edgePosition/edgeColor (no hardcoding)
|
||||
- Pill navigation: 100% use PillNavigation component (no custom implementations in showcases)
|
||||
- Glass effects: All use Card primitive blur prop, no manual backdrop-blur
|
||||
- Dark mode: Every color has dark: variant
|
||||
- Text truncation: All dynamic text has truncate or line-clamp
|
||||
- Responsive grids: All use breakpoints (md:, lg:, xl:)
|
||||
|
||||
### Anti-Pattern Avoidance ✅
|
||||
|
||||
**Zero violations found:**
|
||||
- ✅ No dynamic class construction (all use static lookup objects)
|
||||
- ✅ No non-responsive grids (all use breakpoints)
|
||||
- ✅ No native HTML form elements (100% Radix)
|
||||
- ✅ No unconstrained horizontal scroll
|
||||
- ✅ No missing dark mode variants
|
||||
- ✅ No hardcoded glassmorphism (all use Card primitive)
|
||||
- ✅ No missing text truncation
|
||||
- ✅ Functional UI logic (filters work, drag-drop works, state affects rendering)
|
||||
|
||||
---
|
||||
|
||||
## Automated Scan Results
|
||||
|
||||
### Critical Scans (Breaking Issues) ✅
|
||||
- ✅ **Dynamic classes**: None found
|
||||
- ✅ **Non-responsive grids**: None found
|
||||
- ✅ **Unconstrained scroll**: None found (all have w-full wrapper)
|
||||
- ✅ **Native HTML**: None found
|
||||
|
||||
### High Priority Scans ✅
|
||||
- ✅ **Missing keyboard**: No interactive divs without button
|
||||
- ✅ **Missing dark mode**: All colors have dark: variant
|
||||
- ✅ **Hardcoded glass**: None found (all use Card primitive)
|
||||
- ✅ **Missing min-w-0**: No flex-1 without min-w-0
|
||||
|
||||
### Medium Priority Scans ⚠️
|
||||
- ⚠️ **Color mismatch**: "green" type → emerald classes (non-critical)
|
||||
- ⚠️ **Duplicate component**: Two PillNavigation implementations
|
||||
|
||||
---
|
||||
|
||||
## Testing Notes
|
||||
|
||||
**Tested Scenarios:**
|
||||
1. ✅ All card variants render correctly (base, outer glow, inner glow, edge-lit)
|
||||
2. ✅ Card props (transparency, blur, glow, edge) all affect rendering
|
||||
3. ✅ Drag-and-drop reordering works (DraggableCard has state + onDrop)
|
||||
4. ✅ Selectable cards show selection state (SelectableCard has isSelected prop working)
|
||||
5. ✅ Type filter in KnowledgeLayoutExample filters data
|
||||
6. ✅ View mode toggle (grid/table) changes layout
|
||||
7. ✅ Form elements all use Radix primitives
|
||||
8. ✅ PillNavigation color variants all work
|
||||
9. ✅ Responsive grids collapse on mobile breakpoints
|
||||
10. ✅ Dark mode works across all components
|
||||
|
||||
**No broken functionality detected.**
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
### For Development Team
|
||||
|
||||
**Priority 1 (Optional):**
|
||||
1. Deduplicate PillNavigation component (~1 hour)
|
||||
- Delete `/features/style-guide/shared/PillNavigation.tsx`
|
||||
- Update 2-3 imports in style-guide components
|
||||
- Test all style-guide pages
|
||||
|
||||
**Priority 2 (Optional):**
|
||||
2. Resolve "green" vs "emerald" naming (~10 minutes)
|
||||
- Choose one naming convention
|
||||
- Update either type definition or CSS classes
|
||||
- Grep codebase for usage and update
|
||||
|
||||
**Priority 3:**
|
||||
3. Use style-guide as reference for other features
|
||||
- This implementation is **gold standard** for Archon UI
|
||||
- Copy patterns from here when building new features
|
||||
|
||||
### For Code Reviewers
|
||||
|
||||
**Accept this PR without changes** - The two issues found are:
|
||||
- Non-critical (don't affect functionality)
|
||||
- Low priority (maintenance/consistency concerns only)
|
||||
- Can be addressed in future cleanup PR
|
||||
|
||||
---
|
||||
|
||||
## Estimated Effort
|
||||
|
||||
- **Full refactor**: 1.5 hours (deduplicate + color naming)
|
||||
- **Current state**: **Production-ready as-is**
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
The style-guide feature is an **exemplary implementation** of the Archon design system. It demonstrates:
|
||||
- Perfect use of primitives
|
||||
- Zero anti-patterns
|
||||
- 100% Radix adoption
|
||||
- Functional UI logic throughout
|
||||
- Responsive design everywhere
|
||||
- Full dark mode support
|
||||
|
||||
**This should be used as a reference implementation for all other features.**
|
||||
|
||||
The only issues are minor maintenance concerns (duplication, naming) that don't affect functionality. This code could ship to production today with zero user-facing problems.
|
||||
|
||||
**Recommendation: Approve and use as design system reference.**
|
||||
Reference in New Issue
Block a user