Systemy projektowe
Zbuduj kompletny system projektowy
Twój zespół projektowy stworzył kompleksowy system projektowy Figma dla dashboardu fintech. Zawiera złożone wizualizacje danych, responsywne układy, motywy ciemne/jasne i mikro-interakcje. Musisz zaimplementować pixel-perfect komponenty React, które dokładnie odpowiadają projektom, jednocześnie utrzymując standardy wydajności i dostępności.
Po ukończeniu tej lekcji opanujesz:
Przekształć makiety projektowe na kod produkcyjny, który:
Zacznij od zrzutów ekranu lub dostępu do Figma:
@figma-screenshot.png"Przeanalizuj ten system projektowy i zidentyfikuj:- Hierarchię komponentów- Tokeny projektowe (kolory, odstępy, typografia)- Responsywne breakpointy- Wzorce animacji- Wymagania dostępnościStwórz plan architektury komponentów"
"Na podstawie analizy projektu, stwórz system tokenów projektowych:- Paletę kolorów z semantycznym nazewnictwem- Skalę typograficzną- System odstępów (siatka 4px/8px)- Wartości border radius- Definicje cieni- Timing animacjiSformatuj jako zmienne CSS i typy TypeScript"
Przykładowe tokeny:
export const tokens = { colors: { // Prymitywy blue: { 50: '#eff6ff', 500: '#3b82f6', 900: '#1e3a8a', }, // Semantyczne primary: 'var(--blue-500)', background: { primary: 'var(--gray-50)', secondary: 'var(--white)', elevated: 'var(--white)', }, text: { primary: 'var(--gray-900)', secondary: 'var(--gray-600)', inverse: 'var(--white)', }, }, spacing: { xs: '0.25rem', // 4px sm: '0.5rem', // 8px md: '1rem', // 16px lg: '1.5rem', // 24px xl: '2rem', // 32px '2xl': '3rem', // 48px }, typography: { fontFamily: { sans: 'Inter, system-ui, sans-serif', mono: 'JetBrains Mono, monospace', }, fontSize: { xs: ['0.75rem', { lineHeight: '1rem' }], sm: ['0.875rem', { lineHeight: '1.25rem' }], base: ['1rem', { lineHeight: '1.5rem' }], lg: ['1.125rem', { lineHeight: '1.75rem' }], xl: ['1.25rem', { lineHeight: '1.75rem' }], '2xl': ['1.5rem', { lineHeight: '2rem' }], }, },} as const;
Przełącz na tryb Agent:
"Stwórz skalowalną strukturę komponentów:- Metodologia atomic design- Kategorie komponentów (atomy, molekuły, organizmy)- Konfiguracja Storybook dla dokumentacji- Implementacja dostawcy motywów- Konfiguracja CSS-in-JS lub modułów CSS"
Najpierw upewnij się, że serwer MCP Figma działa:
# W aplikacji Figma DesktopPreferences → Włącz Dev Mode MCP Server
Jeśli nie jest już skonfigurowane:
{ "mcpServers": { "figma": { "url": "http://127.0.0.1:3845/sse" } }}
Z zaznaczonym frame’em Figma:
"Używając Figma MCP, przeanalizuj zaznaczony komponent i:- Wyciągnij wszystkie tokeny projektowe (kolory, odstępy, typografia)- Uzyskaj dokładną strukturę komponentu- Wylistuj wszystkie warianty i stany- Generuj komponent React z odpowiednim stylingiem"
MCP zapewnia:
get_code
: Generuje kod React/Tailwind z zaznaczeniaget_variable_defs
: Wyciąga tokeny projektoweget_code_connect_map
: Mapuje na istniejące komponenty"Używając Figma MCP get_variable_defs:- Wylistuj wszystkie zmienne kolorów z dokładnymi wartościami- Wyciągnij skalę odstępów- Uzyskaj definicje typografii- Stwórz plik tokens.ts idealnie pasujący do Figma"
Przykład integracji odpowiedzi MCP:
// AI użyje danych MCP do wygenerowania:export const figmaTokens = { colors: { 'primary-500': '#3b82f6', // Dokładnie z Figma 'surface-elevated': '#ffffff', 'text-primary': '#111827', }, spacing: { 'component-padding': '14px', // Precyzyjne wartości Figma 'section-gap': '32px', }};
Z zaznaczonym komponentem Figma:
"Generuj komponent Button używając Figma MCP:- Użyj get_code dla dokładnej struktury- Zastosuj wszystkie warianty z projektu- Zawrzyj odpowiednią obsługę stanów- Dopasuj auto-layout Figma za pomocą flexbox"
MCP zapewnia:
// Bezpośrednio z zaznaczenia Figma"Generuj ten komponent karty"
// MCP zapewnia dokładne wartości:// - padding: 24px// - border-radius: 12px// - shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1)// - Używa tokenu koloru: surface.elevated
// Wygenerowany kod idealnie pasuje
// Manualna interpretacja ze zrzutu ekranu"Stwórz kartę podobną do tego obrazu"
// AI zgaduje wartości:// - padding: ~20px (faktycznie 24px)// - border-radius: ~10px (faktycznie 12px)// - shadow: generyczny (brakuje dokładnych wartości)// - color: white (brakuje odniesienia do tokenu)
@design-system/button.png"Stwórz komponent Button, który pasuje do tego projektu:- Wszystkie warianty (primary, secondary, ghost, danger)- Wszystkie rozmiary (sm, md, lg)- Stany (hover, active, disabled, loading)- Wsparcie ikon (lewo/prawo)- Pełna nawigacja klawiaturąUżyj wzorca compound component"
Przykład implementacji:
import { forwardRef, ButtonHTMLAttributes } from 'react';import { cva, type VariantProps } from 'class-variance-authority';import { Loader2 } from 'lucide-react';
const buttonVariants = cva( // Style bazowe 'inline-flex items-center justify-center font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', { variants: { variant: { primary: 'bg-primary text-white hover:bg-primary-dark active:bg-primary-darker', secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200 active:bg-gray-300', ghost: 'hover:bg-gray-100 active:bg-gray-200', danger: 'bg-red-500 text-white hover:bg-red-600 active:bg-red-700', }, size: { sm: 'h-8 px-3 text-sm rounded-md gap-1.5', md: 'h-10 px-4 text-base rounded-lg gap-2', lg: 'h-12 px-6 text-lg rounded-lg gap-2.5', }, }, defaultVariants: { variant: 'primary', size: 'md', }, });
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> { isLoading?: boolean; leftIcon?: React.ReactNode; rightIcon?: React.ReactNode;}
export const Button = forwardRef<HTMLButtonElement, ButtonProps>( ({ className, variant, size, isLoading, leftIcon, rightIcon, children, disabled, ...props }, ref) => { return ( <button ref={ref} className={buttonVariants({ variant, size, className })} disabled={disabled || isLoading} {...props} > {isLoading ? ( <Loader2 className="animate-spin" size={size === 'sm' ? 14 : 16} /> ) : leftIcon ? ( <span className="inline-flex shrink-0">{leftIcon}</span> ) : null} {children} {rightIcon && !isLoading && ( <span className="inline-flex shrink-0">{rightIcon}</span> )} </button> ); });
Button.displayName = 'Button';
@design-system/forms.png"Stwórz kompletny system komponentów formularzy:- Input ze wszystkimi stanami i wariantami- Select z niestandardowym stylem- Komponenty Checkbox i Radio- Pole formularza z etykietą i stanami błędów- Kompozycje grup inputówZapewnij zgodność ARIA"
@design-system/data-table.png"Stwórz komponent DataTable z:- Sortowalnymi kolumnami- Paginacją- Selekcją wierszy- Responsywnym zachowaniem- Stanami ładowania- Stanami pustymiUżyj wirtualizacji dla wydajności"
@dashboard-layout.png"Implementuj układ dashboardu:- Responsywną nawigację boczną- Nagłówek z menu użytkownika- Główny obszar treści z breadcrumbs- Podejście mobile-first- Płynne przejściaZawrzyj nawigację klawiaturą"
Przykład układu:
export const DashboardLayout: React.FC<{ children: ReactNode }> = ({ children }) => { const [sidebarOpen, setSidebarOpen] = useState(false); const { pathname } = useRouter();
return ( <div className="min-h-screen bg-background"> {/* Backdrop bocznego paska mobilnego */} <Transition show={sidebarOpen} as={Fragment}> <Dialog onClose={setSidebarOpen} className="relative z-50 lg:hidden"> <TransitionChild enter="transition-opacity ease-linear duration-300" enterFrom="opacity-0" enterTo="opacity-100" leave="transition-opacity ease-linear duration-300" leaveFrom="opacity-100" leaveTo="opacity-0" > <div className="fixed inset-0 bg-gray-900/80" /> </TransitionChild>
<div className="fixed inset-0 flex"> <TransitionChild enter="transition ease-in-out duration-300 transform" enterFrom="-translate-x-full" enterTo="translate-x-0" leave="transition ease-in-out duration-300 transform" leaveFrom="translate-x-0" leaveTo="-translate-x-full" > <DialogPanel className="relative mr-16 flex w-full max-w-xs flex-1"> <Sidebar onClose={() => setSidebarOpen(false)} /> </DialogPanel> </TransitionChild> </div> </Dialog> </Transition>
{/* Boczny pasek desktopowy */} <div className="hidden lg:fixed lg:inset-y-0 lg:flex lg:w-64 lg:flex-col"> <Sidebar /> </div>
<div className="lg:pl-64"> <Header onMenuClick={() => setSidebarOpen(true)} />
<main className="py-6"> <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8"> <Breadcrumbs /> {children} </div> </main> </div> </div> );};
@charts-design.png"Zbuduj komponenty wykresów pasujące do projektu:- Wykres liniowy z tooltipami- Wykres słupkowy z animacjami- Wykres pączka z legendami- Sparklines dla metryk- Aktualizacje danych w czasie rzeczywistymUżyj D3.js lub Recharts"
@interaction-flow.png"Stwórz interaktywne komponenty:- Tablicę kanban z przeciągnij i upuść- Wieloetapowy kreator formularza- Paletę poleceń (⌘K)- Powiadomienia toast- System modalny z pułapką focusu"
@micro-interactions.mp4"Implementuj te mikro-interakcje:- Efekty naciśnięcia przycisku- Przejścia stanów hover- Animacje szkieletu ładowania- Przejścia stron- Animacje wyzwalane scrollemUżyj Framer Motion"
Przykład animacji:
import { motion } from 'framer-motion';
export const AnimatedCard = ({ children, delay = 0 }) => { return ( <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.4, delay, ease: [0.25, 0.46, 0.45, 0.94], }} whileHover={{ scale: 1.02, boxShadow: '0 10px 30px rgba(0, 0, 0, 0.1)', }} className="bg-white rounded-xl p-6 cursor-pointer" > {children} </motion.div> );};
"Stwórz kompletny system motywów:- Przełącznik motywu jasny/ciemny- Wykrywanie preferencji systemowych- Płynne przejścia między motywami- Trwały wybór motywu- Komponenty świadome motywu"
"Optymalizuj UI dla produkcji:- Lazy load ciężkich komponentów- Implementuj wirtualne scrollowanie- Dodaj granice błędów- Optymalizuj rozmiar bundle- Preloaduj krytyczne czcionki"
"Skonfiguruj testowanie regresji wizualnej:- Historie Storybook dla wszystkich komponentów- Integracja Chromatic lub Percy- Testy zrzutów ekranu responsywnych- Testowanie cross-browser- Testowanie dostępności"
"Generuj kompleksową dokumentację:- Dokumentacja props- Przykłady użycia- Wytyczne projektowe- Notatki dostępności- Względy wydajnościowe"
"Zbuduj interaktywny playground:- Podgląd komponentów na żywo- Edytor props- Eksport kodu- Przełącznik motywów- Podgląd responsywny"
Systematyczny proces konwersji:
// 1. Z Figma MCP (Zalecane)// Zaznacz komponent w Figma, następnie:"Używając Figma MCP, generuj ten komponent z:- Dokładnymi tokenami projektowymi z get_variable_defs- Strukturą komponentu z get_code- Zastosuj mapowania Code Connect jeśli dostępne"
// 2. Bez MCP (Fallback)@component-design.png"Rozłóż ten komponent na:- Strukturę układu- Wartości odstępów- Użycie kolorów- Typografię- Stany interaktywne"
// 3. Udoskonal i wykończ"Dodaj animacje i mikro-interakcje pasujące do prototypów Figma"
Kluczowe zalety MCP:
Buduj złożone UI z prostych części:
// Komponuj złożone komponenty<Card> <Card.Header> <Card.Title>Przychody</Card.Title> <Card.Action> <Button size="sm" variant="ghost">Zobacz wszystkie</Button> </Card.Action> </Card.Header> <Card.Body> <MetricChart data={revenueData} /> </Card.Body></Card>
Optymalizuj dla 60fps:
// Użyj transformacji CSS dla animacjiconst slideIn = { initial: { transform: 'translateX(-100%)' }, animate: { transform: 'translateX(0)' }, exit: { transform: 'translateX(-100%)' },};
// Wirtualizuj długie listy<VirtualList height={600} itemCount={items.length} itemSize={80} renderItem={({ index, style }) => ( <div style={style}> <ListItem item={items[index]} /> </div> )}/>
Problem: Małe różnice względem projektu
Rozwiązanie:
// Użyj dokładnych wartości z projektuconst spacing = { // Nie: padding: '1rem' // Ale: padding: '14px' // Dokładnie z Figma}
// Lub użyj tokenów projektowychpadding: tokens.spacing.md // Spójnie
Problem: Rwące animacje i wolne renderowanie
Rozwiązanie:
// Użyj transform zamiast position// Źle: left: ${x}px// Dobrze: transform: translateX(${x}px)
// Memoizuj kosztowne komponentyconst ExpensiveChart = memo(({ data }) => { return <Chart data={data} />;}, (prev, next) => prev.data === next.data);
Problem: Komponenty nie przechodzą audytu dostępności
Rozwiązanie:
// Zawsze zawieraj etykiety ARIA<IconButton aria-label="Zamknij dialog" onClick={onClose}> <XIcon /></IconButton>
// Zarządzaj fokusem prawidłowouseEffect(() => { if (isOpen) { firstFocusableElement?.focus(); }}, [isOpen]);
Podnieś swoje umiejętności UI:
Zaawansowane interakcje
Skalowanie systemu projektowego
Doskonałość wydajności
Twoja implementacja odnosi sukces gdy:
Zespoły używające tych technik raportują:
Przed wysłaniem:
Opanowałeś implementację UI. Gotowy na więcej?
Systemy projektowe
Zbuduj kompletny system projektowy
Biblioteka animacji
Stwórz wzorce animacji wielokrotnego użytku
Biblioteka komponentów
Publikuj komponenty jako pakiet npm
Kontynuuj do Test-Driven Development →