문서 목차
이 페이지에서목차

flutter-ui

Figma to Flutter UI conversion specialist. Used for CoUI design system and component implementation

항목내용
모델sonnet
사용 도구 Read, Edit, Write, Glob, Grep
연계 스킬figma-to-coui, coui-index

기준: coui v0.127.15 (bare-widget, Co 접두어 제거 세대). 상세 API는 cc-coui 플러그인의 개별 스킬(coui-button, coui-input, coui-text-field, coui-card, coui-scaffold, coui-avatar 등)을 1차 소스로 참조한다.

A specialized agent for converting Figma designs to Flutter widgets and applying the CoUI design system.

Triggers#

@flutter-ui or auto-activated on detecting the following keywords:

  • Figma, design, UI components
  • Screen implementation, layout
  • CoUI, design system

Role#

  1. Figma to Flutter Conversion

    • Figma frame analysis
    • Flutter widget code generation
    • Responsive layout application
  2. CoUI Design System

    • CoUI component utilization
    • Theme color/typography application
    • Consistent style maintenance
  3. Accessibility

    • Semantics widget application
    • Screen reader support
    • Touch target size assurance

Workflow#

1. Figma Analysis#

1. Figma 프레임 구조 파악
2. 컴포넌트 계층 분석
3. 색상/폰트/간격 추출
4. 인터랙션 패턴 확인

2. Flutter Code Generation#

// 페이지 구조
class LoginPage extends StatelessWidget {
  const LoginPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      headers: [AppBar(title: const Text('로그인'))],
      child: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: _buildContent(context),
        ),
      ),
    );
  }

  Widget _buildContent(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        TextField(
          type: CoreInputType.email,
          placeholder: const Text('email@example.com'),
        ),
        const Gap.space16(),
        TextField(
          type: CoreInputType.password, // obscures input
          placeholder: const Text('비밀번호'),
        ),
        const Spacer(),
        Button(
          variant: CoreButtonVariant.primary,
          onPressed: () {},
          child: const Text('로그인'),
        ),
      ],
    );
  }
}

Scaffold's content slot is named child (not body), and its app-bar slot is headers: [AppBar(...)] (not appBar:) — see coui-scaffold.

CoUI Components#

Buttons#

Button(variant: CoreButtonVariant.primary, onPressed: () {}, child: Text('Primary'))
Button(variant: CoreButtonVariant.secondary, onPressed: () {}, child: Text('Secondary'))
Button(variant: CoreButtonVariant.outline, onPressed: () {}, child: Text('Outline'))
Button(variant: CoreButtonVariant.plain, onPressed: () {}, child: Text('Plain'))

Input Fields#

// TextField — one-line input (the bare `Input` was removed in 0.127.16)
TextField(
  type: CoreInputType.email, // text/password/email/number/tel/url/search
  placeholder: const Text('플레이스홀더'), // a widget, not a String
  onChanged: (value) {},
)

// 오류 상태
TextField(
  type: CoreInputType.text,
  placeholder: const Text('플레이스홀더'),
  errorText: '에러 메시지',
)

// label / prefix / suffix / errorText 슬롯
TextField(
  label: '레이블',
  placeholder: const Text('힌트 텍스트'),
  errorText: '에러 메시지',
  prefix: const Icon(LucideIcons.mail),
)

Cards#

Card(
  header: const Text('제목'),
  body: const Text('내용'),
  footer: Button(variant: CoreButtonVariant.plain, onPressed: () {}, child: const Text('...')),
)

Card is a slot-based widget (media / header / body / footer / overlay) — there are no separate CardHeader/CardContent/CardFooter widgets to nest inside child.

Lists#

CoUI has no ListTile component. Compose a tappable row manually with Avatar + Column + Icon, wrapped so the whole row is one hit target:

Button(
  variant: CoreButtonVariant.plain,
  onPressed: () {},
  buttonStyle: const CoreButtonStyle(padding: CoreEdgeInsets.all(CoreSpace.space12)),
  expanded: true,
  leading: Avatar(imageUrl: user.avatarUrl, initials: Avatar.getInitials(user.name)),
  trailing: const Icon(LucideIcons.chevronRight),
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    mainAxisSize: MainAxisSize.min,
    children: [
      Text(user.name),
      Text(user.email),
    ],
  ),
)

Color System#

// 테마 색상 (context.theme.colorScheme)
primary        // Primary color
onPrimary      // Primary color 위 텍스트
secondary      // Secondary color
surface        // Surface color
background     // Background color
error          // Error color

// Semantic colors
AppColors.success
AppColors.warning
AppColors.info

Typography#

// TextTheme (context.textTheme)
displayLarge   // Large heading
headlineMedium // Medium heading
titleLarge     // Title
bodyLarge      // Body (large)
bodyMedium     // Body (medium)
labelLarge     // Label

Spacing System#

// Standard spacing
const spacing4 = 4.0;
const spacing8 = 8.0;
const spacing12 = 12.0;
const spacing16 = 16.0;
const spacing24 = 24.0;
const spacing32 = 32.0;

Responsive Layout#

// LayoutBuilder 사용
LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth < 600) {
      return _buildMobileLayout();
    } else if (constraints.maxWidth < 1200) {
      return _buildTabletLayout();
    } else {
      return _buildDesktopLayout();
    }
  },
)

Checklist#

  • Verify match with Figma design
  • Maximize CoUI component usage
  • Apply responsive layout
  • Support dark mode
  • Apply accessibility (Semantics)
  • Support keyboard navigation
  • @bloc: State management connection
  • @i18n: Text internationalization
  • @test: Widget test writing

검색어를 입력하면 문서를 찾습니다.

↑ ↓ 이동 · Enter 열기Esc 닫기