AgentSkillsCN

Frontend Design

在前端/ 目录中创建、修改或审查任何文件时使用。提供设计系统规范、组件模式、语义化标记、shadcn/ui 使用指南,以及 Next.js + React 前端的文件组织约定。

SKILL.md
--- frontmatter
name: Frontend Design
description: Use when creating, modifying, or reviewing any files in the frontend/ directory. Provides design system rules, component patterns, semantic tokens, shadcn/ui usage, and file organization conventions for the Next.js + React frontend.

Frontend Design Skill

Design system rules and patterns for Meal Genie. For token values, see globals.css. For component examples, reference existing implementations.

Critical Rules (Never Violate)

RuleWrongRight
Fake cards<div className="bg-card border rounded-xl"><Card>
Raw buttons<button className="px-4 py-2"><Button variant="...">
Raw badges<span className="px-2 py-1 rounded-full"><Badge>
Hardcoded colorstext-gray-500, bg-slate-800text-muted-foreground, bg-card
Arbitrary valuesh-[38px], gap-[15px]h-10, gap-4
Missing aria-label<Button size="icon"><X /></Button><Button size="icon" aria-label="Close">
Wrong iconsreact-icons, heroiconslucide-react with strokeWidth={1.5}

Imports Pattern

tsx
// UI components (shadcn/ui)
import { Button } from "@/components/ui/button";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";

// Icons (always lucide-react)
import { Plus, X, ChevronRight, Loader2 } from "lucide-react";

// Utilities
import { cn } from "@/lib/utils";

Semantic Tokens

Always use semantic tokens from globals.css. Never hardcode Tailwind colors.

Text:

  • text-foreground — primary text
  • text-muted-foreground — secondary, placeholders
  • text-primary — accent, links
  • text-destructive — errors

Backgrounds:

  • bg-background — page
  • bg-card or bg-elevated — cards, panels
  • bg-muted — subtle surfaces
  • bg-accent — hover states

Borders:

  • border-border — default
  • border-input — form inputs
  • border-destructive — error states

Recipe-specific:

  • bg-recipe-category-bg / text-recipe-category-text — category badges
  • bg-recipe-meal-type-bg / text-recipe-meal-type-text — meal type badges
  • bg-recipe-dietary-bg / text-recipe-dietary-text — dietary badges

Spacing & Sizing

Use Tailwind scale exclusively. No arbitrary pixel values.

Spacing:

  • gap-2 (8px) — icon + text, related elements
  • gap-4 (16px) — form fields, card sections
  • gap-6 (24px) — content sections
  • space-y-2 — label to input
  • space-y-4 — between form fields
  • space-y-6 — between sections

Heights:

  • h-8 (32px) — small buttons, dense UI
  • h-10 (40px) — default inputs, buttons
  • h-12 (48px) — large buttons, touch targets

Icons:

  • size-4 (16px) — inline with text
  • size-5 (20px) — standalone small
  • size-6 (24px) — standalone medium

Interactive States

Components have built-in states. Don't duplicate hover/focus classes on shadcn components.

For custom interactive elements:

tsx
// Interactive card
<Card className="interactive cursor-pointer">

// Subtle interaction (smaller elements)  
<Card className="interactive-subtle cursor-pointer">

Loading states:

tsx
<Button disabled>
  <Loader2 className="size-4 mr-2 animate-spin" />
  Saving...
</Button>

Component Patterns

Icon Buttons

tsx
// Always include aria-label
<Button size="icon" variant="ghost" aria-label="Close">
  <X className="size-4" strokeWidth={1.5} />
</Button>

Form Fields

tsx
<div className="space-y-2">
  <Label htmlFor="name">
    Recipe Name <span className="text-destructive">*</span>
  </Label>
  <Input id="name" placeholder="Enter recipe name" />
  <p className="text-sm text-muted-foreground">Helper text</p>
</div>

Icon + Text

tsx
<div className="flex items-center gap-2">
  <Clock className="size-4 text-muted-foreground" strokeWidth={1.5} />
  <span className="text-sm">30 minutes</span>
</div>

Empty States

tsx
<div className="flex flex-col items-center justify-center py-12 text-center">
  <div className="rounded-full bg-muted p-4 mb-4">
    <FileX className="size-8 text-muted-foreground" strokeWidth={1.5} />
  </div>
  <h3 className="text-lg font-semibold">No recipes found</h3>
  <p className="text-sm text-muted-foreground mt-1 mb-4">
    Try adjusting your filters
  </p>
  <Button>Add Recipe</Button>
</div>

File Organization

TypeLocation
Pagessrc/app/[page]/page.tsx
Page-specific componentssrc/app/[page]/_components/
Shared componentssrc/components/common/
Domain componentssrc/components/[domain]/ (recipe, meal-planner, etc.)
shadcn/ui primitivessrc/components/ui/ (don't modify)
Hookssrc/hooks/
Design tokenssrc/app/globals.css

Reference Files

For patterns, look at existing implementations:

PatternReference
Recipe cardcomponents/recipe/RecipeCard.tsx
Form layoutapp/recipes/add/page.tsx
Dialog usageapp/meal-planner/_components/
Filter UIcomponents/common/FilterBar.tsx
Loading statesAny component with React Query

Quick Audit Checklist

Before completing UI work:

  • Using shadcn components (Card, Button, Badge, Input)?
  • No hardcoded colors (gray-, slate-, etc.)?
  • No arbitrary values (h-[px], w-[px])?
  • Icon buttons have aria-label?
  • Form inputs have Label with htmlFor?
  • Loading states show spinner + disabled?
  • Using cn() for conditional classes?
  • Icons from lucide-react with strokeWidth={1.5}?

Adding shadcn Components

bash
npx shadcn@latest add button dialog card

Components install to components/ui/. Don't modify these — extend with wrapper components if needed.