LogoSkills

widgetbook-agent

Widgetbook component showcase specialist. Used for UseCase writing and component catalog configuration

ํ•ญ๋ชฉ๋‚ด์šฉ
Invoke/shared:widgetbook
Aliases/widgetbook:add, /catalog:create
ToolsRead, Edit, Write, Glob, Grep
Modelsonnet
Skillsflutter-ui

/shared:widgetbook โ€” ํ™”๋ฉด ๋ถ€ํ’ˆ ์ „์‹œ์žฅ ๋งŒ๋“ค๊ธฐ#

ํ•œ๋งˆ๋””๋กœ#

์•ฑ์— ๋“ค์–ด๊ฐ€๋Š” ๋ฒ„ํŠผยท์นด๋“œยท์ž…๋ ฅ์ฐฝ ๊ฐ™์€ UI ๋ถ€ํ’ˆ๋“ค์„ ํ•œ๊ณณ์— ๋ชจ์•„ ๋ณด์—ฌ์ฃผ๋Š” "์ „์‹œ์žฅ(์นดํƒˆ๋กœ๊ทธ)"์„ ๋งŒ๋“ค์–ด ์ฃผ๋Š” ๋„์šฐ๋ฏธ์ž…๋‹ˆ๋‹ค. ๊ฐ€๊ตฌ์ ์— ๊ฐ€๋ฉด ์†ŒํŒŒ ํ•˜๋‚˜๋ฅผ ์ƒ‰๊น”ยทํฌ๊ธฐ๋ณ„๋กœ ์ญ‰ ์ง„์—ดํ•ด ๋‘” ๊ฒƒ์ฒ˜๋Ÿผ, ์šฐ๋ฆฌ ์•ฑ ๋ถ€ํ’ˆ๋„ ์ƒํƒœ๋ณ„ยท๊ธฐ๊ธฐ๋ณ„๋กœ ํ•œ๋ˆˆ์— ๋ชจ์•„ ๋ณด๊ฒŒ ํ•ด ์ค๋‹ˆ๋‹ค.

๋ˆ„๊ฐ€ยท์–ธ์ œ ์“ฐ๋‚˜์š”#

  • ๋””์ž์ด๋„ˆยท๊ธฐํš์ž๊ฐ€ ์•ฑ์— ๋“ค์–ด๊ฐ„ UI ๋ถ€ํ’ˆ์ด ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ๋ณด์ด๋Š”์ง€ ์ง์ ‘ ๋ˆŒ๋Ÿฌ ๋ณด๋ฉฐ ํ™•์ธํ•˜๊ณ  ์‹ถ์„ ๋•Œ
  • ๊ฐœ๋ฐœ์ž๊ฐ€ ์ƒˆ ๋ถ€ํ’ˆ(๋ฒ„ํŠผ, ์นด๋“œ ๋“ฑ)์„ ๋งŒ๋“ค๊ณ  ๋‚˜์„œ ์ „์‹œ์žฅ์— ๋“ฑ๋กํ•˜๊ณ  ์‹ถ์„ ๋•Œ
  • /shared:widgetbook ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜, ๋ถ€ํ’ˆ ์นดํƒˆ๋กœ๊ทธยทUseCase ์ž‘์„ฑ ์ž‘์—…์ด ํ•„์š”ํ•  ๋•Œ ์ž๋™์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค

๋ฌด์—‡์„ ํ•ด์ฃผ๋‚˜์š”#

  • Widgetbook ์ด๋ผ๋Š” ์ „์‹œ์žฅ ์•ฑ(app/kobic_widgetbook/)์— UI ๋ถ€ํ’ˆ์„ ๋“ฑ๋กํ•ด ์ค๋‹ˆ๋‹ค
  • ๋ถ€ํ’ˆ์„ ์„ฑ๊ฒฉ๋ณ„๋กœ ์„ธ ์นธ์œผ๋กœ ๋‚˜๋ˆ  ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค โ€” ์ผ๋ฐ˜ ๋ถ€ํ’ˆ([Component]), ํ™”๋ฉด ๋‹จ์œ„([Feature]), ์ƒ‰์ƒยท๊ธ€๊ผด ๊ฐ™์€ ๊ธฐ์ดˆ ์š”์†Œ([Foundation])
  • ๊ฐ™์€ ๋ถ€ํ’ˆ์„ ์—ฌ๋Ÿฌ ๊ธฐ๊ธฐ ํฌ๊ธฐ(์•„์ดํฐยท์•„์ดํŒจ๋“œยท๋ฐ์Šคํฌํ†ฑ)์™€ ํ…Œ๋งˆ(๋ผ์ดํŠธ/๋‹คํฌ), ์–ธ์–ด(ํ•œ๊ตญ์–ดยท์˜์–ดยท์ผ๋ณธ์–ด ๋“ฑ)๋กœ ๋ฐ”๊ฟ” ๊ฐ€๋ฉฐ ๋ณผ ์ˆ˜ ์žˆ๊ฒŒ ์„ค์ •ํ•ด ์ค๋‹ˆ๋‹ค
  • ์‹ค์ œ ๋ฐ์ดํ„ฐ ์—†์ด๋„ ํ™”๋ฉด์ด ์ฑ„์›Œ์ ธ ๋ณด์ด๋„๋ก ๊ฐ€์งœ ๋ฐ์ดํ„ฐ(Mock)๋ฅผ ๋ผ์›Œ ์ค๋‹ˆ๋‹ค

์–ด๋–ป๊ฒŒ ์“ฐ๋‚˜์š”#

# ์ „์‹œ์žฅ ์•ฑ์„ ๋ธŒ๋ผ์šฐ์ €(Chrome)๋กœ ์‹คํ–‰ํ•ด์„œ ์ง์ ‘ ๋‘˜๋Ÿฌ๋ณด๊ธฐ
flutter run -t lib/main.dart -d chrome

# ๋ถ€ํ’ˆ์„ ์ƒˆ๋กœ ๋“ฑ๋กยท์ˆ˜์ •ํ•œ ๋’ค ์ „์‹œ์žฅ์— ๋ฐ˜์˜(์ฝ”๋“œ ์ž๋™ ์ƒ์„ฑ)
cd app/kobic_widgetbook  & &   dart run build_runner build --delete-conflicting-outputs

# ์›น์šฉ์œผ๋กœ ๋นŒ๋“œ(๊ณต์œ ยท๋ฐฐํฌ์šฉ)
flutter build web -t lib/main.dart

๋ช…๋ น ์ž์ฒด๋Š” /shared:widgetbook ๋กœ ์‹คํ–‰ํ•˜๋ฉฐ, ๋ถ€ํ’ˆ ์ด๋ฆ„(component_name)๋งŒ ์žˆ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋ถ„๋ฅ˜(category)์™€ ๊ฒฝ๋กœ(path)๋Š” ์„ ํƒ ์‚ฌํ•ญ์ด๋ผ ๋น„์›Œ ๋‘๋ฉด ์ผ๋ฐ˜ ๋ถ€ํ’ˆ์œผ๋กœ ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค.

์•ˆ์—์„œ ๋ฌด์Šจ ์ผ์ด ๋ฒŒ์–ด์ง€๋‚˜์š”#

  1. ์ „์‹œ์žฅ ์•ฑ์˜ ๊ธฐ๋ณธ ๊ณจ๊ฒฉ(์ง„์ž…์ , ๊ธฐ๊ธฐ ํฌ๊ธฐยทํ…Œ๋งˆยท์–ธ์–ด ์„ ํƒ ๋ฉ”๋‰ด)์„ ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ณด์—ฌ ์ค„ ๋ถ€ํ’ˆ์— "์ „์‹œ ํ‘œ์‹œ(@UseCase)"๋ฅผ ๋ถ™์—ฌ, ์–ด๋А ์นธ(์ผ๋ฐ˜/ํ™”๋ฉด/๊ธฐ์ดˆ)์— ์ง„์—ดํ• ์ง€ ์ •ํ•ฉ๋‹ˆ๋‹ค.
  3. ํ•œ ๋ถ€ํ’ˆ์˜ ์—ฌ๋Ÿฌ ์ƒํƒœ(๊ธฐ๋ณธยท๋น„ํ™œ์„ฑยท๋กœ๋”ฉ ๋“ฑ)๋ฅผ ๋‚˜๋ž€ํžˆ ๋Š˜์–ด๋†“์•„ ๋น„๊ตํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋ฌถ์Šต๋‹ˆ๋‹ค.
  4. ํ™”๋ฉด ๋‹จ์œ„ ๋ถ€ํ’ˆ์€ ์‹ค์ œ ๋ฐ์ดํ„ฐ ๋Œ€์‹  ๊ฐ€์งœ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด ๊นจ์ง€์ง€ ์•Š๊ฒŒ ์ฑ„์›๋‹ˆ๋‹ค.
  5. ์ฝ”๋“œ ์ž๋™ ์ƒ์„ฑ์„ ๋Œ๋ ค ์ „์‹œ์žฅ์— ์ƒˆ ๋ถ€ํ’ˆ์„ ๋ฐ˜์˜ํ•˜๊ณ , ์—ฌ๋Ÿฌ ๊ธฐ๊ธฐ ํฌ๊ธฐ์—์„œ ์ž˜ ๋ณด์ด๋Š”์ง€ ์ ๊ฒ€ํ•ฉ๋‹ˆ๋‹ค.

โš™๏ธ ์ƒ์„ธ ์˜ต์…˜ยท์‹คํ–‰ ๋ช…์„ธ (๊ฐœ๋ฐœ์ž / AI ์—์ด์ „ํŠธ์šฉ)

Role#

Manages component catalog using Widgetbook.

  • @UseCase annotation-based component showcase
  • Addon configuration (Viewport, Theme, Slang)
  • Component, Feature, Foundation structure
  • Mock object setup

Activation Conditions#

  • /shared:widgetbook Activated when command is invoked
  • Invoked during component catalog and UseCase writing

Parameters#

ParameterRequiredDescription
component_nameโœ…Component name (PascalCase)
categoryโŒcomponent, feature, foundation (default: component)
pathโŒPath within Widgetbook

Package Structure#

app/kobic_widgetbook/
โ”œโ”€โ”€ lib/
โ”‚   โ”œโ”€โ”€ main.dart                     # ์•ฑ ์ง„์ž…์ 
โ”‚   โ”œโ”€โ”€ main.directories.g.dart       # ์ž๋™ ์ƒ์„ฑ
โ”‚   โ”œโ”€โ”€ add_on/                       # ์ปค์Šคํ…€ Addon
โ”‚   โ”‚   โ”œโ”€โ”€ add_on.dart
โ”‚   โ”‚   โ”œโ”€โ”€ slang_addon.dart
โ”‚   โ”‚   โ”œโ”€โ”€ view_ports.dart
โ”‚   โ”‚   โ””โ”€โ”€ widgetbook_group.dart
โ”‚   โ”œโ”€โ”€ component/                    # UI ์ปดํฌ๋„ŒํŠธ
โ”‚   โ”‚   โ”œโ”€โ”€ component.dart
โ”‚   โ”‚   โ”œโ”€โ”€ widget_book_button.dart
โ”‚   โ”‚   โ”œโ”€โ”€ widget_book_input.dart
โ”‚   โ”‚   โ””โ”€โ”€ widget_book_card.dart
โ”‚   โ”œโ”€โ”€ feature/                      # Feature ์ปดํฌ๋„ŒํŠธ
โ”‚   โ”‚   โ”œโ”€โ”€ feature.dart
โ”‚   โ”‚   โ”œโ”€โ”€ widget_book_home.dart
โ”‚   โ”‚   โ””โ”€โ”€ widget_book_profile.dart
โ”‚   โ””โ”€โ”€ foundation/                   # ๊ธฐ์ดˆ ์š”์†Œ
โ”‚       โ”œโ”€โ”€ foundation.dart
โ”‚       โ”œโ”€โ”€ widget_book_colors.dart
โ”‚       โ””โ”€โ”€ widget_book_typography.dart
โ””โ”€โ”€ pubspec.yaml

Import Order (Required)#

// 1. Flutter standard
import 'package:flutter/material.dart' as material;

// 2. Widgetbook package
import 'package:widgetbook/widgetbook.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart';

// 3. UI Kit (CoUI)
import 'package:coui_flutter/coui_flutter.dart';

// 4. Internal modules
import 'add_on/add_on.dart';
import 'main.directories.g.dart';

Core Patterns#

1. Main App Setup#

import 'package:flutter/material.dart' as material;
import 'package:i10n/i10n.dart';
import 'package:resources/resources.dart';
import 'package:widgetbook/widgetbook.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart';

import 'add_on/add_on.dart';
import 'main.directories.g.dart';

/// Widgetbook ์•ฑ ์ง„์ž…์ 
@App()
class WidgetbookApp extends material.StatelessWidget {
  /// WidgetbookApp ์ƒ์„ฑ์ž
  const WidgetbookApp({super.key});

  @override
  material.Widget build(material.BuildContext context) {
    return Widgetbook.material(
      // ์ดˆ๊ธฐ ๋ผ์šฐํŠธ
      initialRoute: '/StorePage',

      // ์ž๋™ ์ƒ์„ฑ๋œ ๋””๋ ‰ํ† ๋ฆฌ
      directories: directories,

      // Addon ๊ตฌ์„ฑ
      addons: [
        // ๋ทฐํฌํŠธ ์„ ํƒ
        ViewportAddon(Viewports.all),

        // ์œ„์ ฏ ์ธ์ŠคํŽ™ํ„ฐ
        InspectorAddon(),

        // ๋‹ค๊ตญ์–ด ์ง€์›
        SlangAddon(
          locales: AppLocaleUtils.supportedLocales,
          localeNames: {
            const material.Locale('en'): 'English',
            const material.Locale('ko'): 'ํ•œ๊ตญ์–ด',
            const material.Locale('ja'): 'ๆ—ฅๆœฌ่ชž',
            // ... ์ถ”๊ฐ€ ๋กœ์ผ€์ผ
          },
        ),

        // ํ…Œ๋งˆ ์„ ํƒ
        MaterialThemeAddon(
          themes: [
            WidgetbookTheme(
              name: 'Light',
              data: AppTheme.light,
            ),
            WidgetbookTheme(
              name: 'Dark',
              data: AppTheme.dark,
            ),
          ],
        ),

        // ์ •๋ ฌ ์˜ต์…˜
        AlignmentAddon(initialAlignment: material.Alignment.topLeft),

        // ํ…์ŠคํŠธ ์Šค์ผ€์ผ
        TextScaleAddon(initialScale: 1),

        // SafeArea ๋ž˜ํผ
        BuilderAddon(
          name: 'SafeArea',
          builder: (context, child) => material.SafeArea(child: child),
        ),
      ],
    );
  }
}

/// ์•ฑ ๋ฉ”์ธ ํ•จ์ˆ˜
void main() {
  material.runApp(const WidgetbookApp());
}

2. UseCase Annotation Pattern#

import 'package:coui_flutter/coui_flutter.dart';
import 'package:flutter/material.dart' as material;
import 'package:widgetbook_annotation/widgetbook_annotation.dart';

import 'add_on/widgetbook_group.dart';

/// Button ์ปดํฌ๋„ŒํŠธ UseCase
@UseCase(
  name: 'Button',
  type: Button,
  path: '[Component]',
)
material.Widget buildWidgetbookButtonUseCase(material.BuildContext context) {
  return WidgetbookGroup(
    label: 'Unibook Button',
    children: [
      // Primary Button
      WidgetbookButton(
        label: 'Primary Button',
        button: CoButton(
          variant: CoreButtonVariant.primary,
          onPressed: () {},
          child: const Text('Primary'),
        ),
      ),

      // Secondary Button
      WidgetbookButton(
        label: 'Secondary Button',
        button: CoButton(
          variant: CoreButtonVariant.secondary,
          onPressed: () {},
          child: const Text('Secondary'),
        ),
      ),

      // Outlined Button
      WidgetbookButton(
        label: 'Outlined Button',
        button: CoButton(
          variant: CoreButtonVariant.outline,
          onPressed: () {},
          child: const Text('Outlined'),
        ),
      ),

      // Disabled Button
      WidgetbookButton(
        label: 'Disabled Button',
        button: CoButton(
          variant: CoreButtonVariant.primary,
          onPressed: null,
          child: const Text('Disabled'),
        ),
      ),

      // Loading Button
      WidgetbookButton(
        label: 'Loading Button',
        button: CoButton(
          variant: CoreButtonVariant.primary,
          onPressed: () {},
          child: const Text('Loading'),
        ),
      ),
    ],
  );
}

3. WidgetbookGroup Helper#

import 'package:flutter/material.dart' as material;

/// Widgetbook ๊ทธ๋ฃน ์ปจํ…Œ์ด๋„ˆ
class WidgetbookGroup extends material.StatelessWidget {
  /// WidgetbookGroup ์ƒ์„ฑ์ž
  const WidgetbookGroup({
    required this.label,
    required this.children,
    super.key,
  });

  /// ๊ทธ๋ฃน ๋ผ๋ฒจ
  final String label;

  /// ์ž์‹ ์œ„์ ฏ๋“ค
  final List<material.Widget> children;

  @override
  material.Widget build(material.BuildContext context) {
    return material.SingleChildScrollView(
      padding: const material.EdgeInsets.all(16),
      child: material.Column(
        crossAxisAlignment: material.CrossAxisAlignment.start,
        children: [
          material.Text(
            label,
            style: const material.TextStyle(
              fontSize: 24,
              fontWeight: material.FontWeight.bold,
            ),
          ),
          const material.SizedBox(height: 16),
          ...children.map((child) => material.Padding(
                padding: const material.EdgeInsets.only(bottom: 16),
                child: child,
              )),
        ],
      ),
    );
  }
}

/// Widgetbook ๋ฒ„ํŠผ ํ•ญ๋ชฉ
class WidgetbookButton extends material.StatelessWidget {
  /// WidgetbookButton ์ƒ์„ฑ์ž
  const WidgetbookButton({
    required this.label,
    required this.button,
    super.key,
  });

  /// ๋ฒ„ํŠผ ๋ผ๋ฒจ
  final String label;

  /// ๋ฒ„ํŠผ ์œ„์ ฏ
  final material.Widget button;

  @override
  material.Widget build(material.BuildContext context) {
    return material.Column(
      crossAxisAlignment: material.CrossAxisAlignment.start,
      children: [
        material.Text(
          label,
          style: const material.TextStyle(
            fontSize: 14,
            color: material.Colors.grey,
          ),
        ),
        const material.SizedBox(height: 8),
        button,
      ],
    );
  }
}

4. Slang Addon#

import 'package:flutter/material.dart' as material;
import 'package:i10n/i10n.dart';
import 'package:widgetbook/widgetbook.dart';

/// Slang ๋‹ค๊ตญ์–ด Addon
class SlangAddon extends WidgetbookAddon<material.Locale> {
  /// SlangAddon ์ƒ์„ฑ์ž
  SlangAddon({
    required this.locales,
    required this.localeNames,
    material.Locale? initialLocale,
  }) : super(
          name: 'Locale',
          initialSetting: initialLocale ?? locales.first,
        );

  /// ์ง€์› ๋กœ์ผ€์ผ ๋ชฉ๋ก
  final List<material.Locale> locales;

  /// ๋กœ์ผ€์ผ๋ณ„ ํ‘œ์‹œ ์ด๋ฆ„
  final Map<material.Locale, String> localeNames;

  @override
  List<Field> get fields => [
        ListField<material.Locale>(
          name: 'Locale',
          values: locales,
          initialValue: initialSetting,
          labelBuilder: (locale) =>
              localeNames[locale] ?? locale.languageCode,
        ),
      ];

  @override
  material.Locale valueFromQueryGroup(Map<String, String> group) {
    final localeCode = group['Locale'];
    return locales.firstWhere(
      (locale) => locale.languageCode == localeCode,
      orElse: () => locales.first,
    );
  }

  @override
  material.Widget buildUseCase(
    material.BuildContext context,
    material.Widget child,
    material.Locale setting,
  ) {
    return TranslationProvider(
      child: material.Builder(
        builder: (context) {
          // ๋กœ์ผ€์ผ ๋ณ€๊ฒฝ
          LocaleSettings.setLocale(
            AppLocale.values.firstWhere(
              (l) => l.languageCode == setting.languageCode,
              orElse: () => AppLocale.en,
            ),
          );
          return child;
        },
      ),
    );
  }
}

5. Viewports Definition#

import 'package:widgetbook/widgetbook.dart';

/// ๋ทฐํฌํŠธ ์ •์˜
abstract final class Viewports {
  /// ๋ชจ๋“  ๋ทฐํฌํŠธ
  static const List<Device> all = [
    // ๋ชจ๋ฐ”์ผ
    Device.phone(name: 'iPhone SE', resolution: Resolution(width: 375, height: 667)),
    Device.phone(name: 'iPhone 14', resolution: Resolution(width: 390, height: 844)),
    Device.phone(name: 'iPhone 14 Pro Max', resolution: Resolution(width: 430, height: 932)),
    Device.phone(name: 'Android Small', resolution: Resolution(width: 360, height: 640)),
    Device.phone(name: 'Android Large', resolution: Resolution(width: 412, height: 915)),

    // ํƒœ๋ธ”๋ฆฟ
    Device.tablet(name: 'iPad Mini', resolution: Resolution(width: 744, height: 1133)),
    Device.tablet(name: 'iPad Pro 11"', resolution: Resolution(width: 834, height: 1194)),
    Device.tablet(name: 'iPad Pro 12.9"', resolution: Resolution(width: 1024, height: 1366)),

    // ๋ฐ์Šคํฌํ†ฑ
    Device.desktop(name: 'Desktop HD', resolution: Resolution(width: 1280, height: 720)),
    Device.desktop(name: 'Desktop FHD', resolution: Resolution(width: 1920, height: 1080)),
    Device.desktop(name: 'Desktop 4K', resolution: Resolution(width: 3840, height: 2160)),
  ];

  /// ๋ชจ๋ฐ”์ผ ๋ทฐํฌํŠธ๋งŒ
  static const List<Device> mobile = [
    Device.phone(name: 'iPhone SE', resolution: Resolution(width: 375, height: 667)),
    Device.phone(name: 'iPhone 14', resolution: Resolution(width: 390, height: 844)),
    Device.phone(name: 'Android', resolution: Resolution(width: 412, height: 915)),
  ];

  /// ํƒœ๋ธ”๋ฆฟ ๋ทฐํฌํŠธ๋งŒ
  static const List<Device> tablet = [
    Device.tablet(name: 'iPad Mini', resolution: Resolution(width: 744, height: 1133)),
    Device.tablet(name: 'iPad Pro', resolution: Resolution(width: 1024, height: 1366)),
  ];
}

6. Feature UseCase Example#

import 'package:feature_home/feature_home.dart';
import 'package:flutter/material.dart' as material;
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart';

/// Home ํŽ˜์ด์ง€ UseCase
@UseCase(
  name: 'HomePage',
  type: HomePage,
  path: '[Feature]/Home',
)
material.Widget buildWidgetbookHomePageUseCase(material.BuildContext context) {
  return BlocProvider(
    create: (_) => MockHomeBloC(),
    child: const HomePage(),
  );
}

/// Mock Home BLoC
class MockHomeBloC extends Cubit<HomeState> {
  MockHomeBloC()
      : super(const HomeLoaded(
          items: [
            HomeItem(id: 1, title: 'Item 1'),
            HomeItem(id: 2, title: 'Item 2'),
            HomeItem(id: 3, title: 'Item 3'),
          ],
        ));
}

7. Foundation UseCase Example#

import 'package:flutter/material.dart' as material;
import 'package:resources/resources.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart';

/// Colors UseCase
@UseCase(
  name: 'Colors',
  type: material.ColorScheme,
  path: '[Foundation]',
)
material.Widget buildWidgetbookColorsUseCase(material.BuildContext context) {
  final colorScheme = material.Theme.of(context).colorScheme;

  return material.SingleChildScrollView(
    padding: const material.EdgeInsets.all(16),
    child: material.Column(
      crossAxisAlignment: material.CrossAxisAlignment.start,
      children: [
        _ColorTile(name: 'Primary', color: colorScheme.primary),
        _ColorTile(name: 'On Primary', color: colorScheme.onPrimary),
        _ColorTile(name: 'Secondary', color: colorScheme.secondary),
        _ColorTile(name: 'On Secondary', color: colorScheme.onSecondary),
        _ColorTile(name: 'Surface', color: colorScheme.surface),
        _ColorTile(name: 'On Surface', color: colorScheme.onSurface),
        _ColorTile(name: 'Error', color: colorScheme.error),
        _ColorTile(name: 'On Error', color: colorScheme.onError),
      ],
    ),
  );
}

class _ColorTile extends material.StatelessWidget {
  const _ColorTile({required this.name, required this.color});

  final String name;
  final material.Color color;

  @override
  material.Widget build(material.BuildContext context) {
    return material.Padding(
      padding: const material.EdgeInsets.only(bottom: 8),
      child: material.Row(
        children: [
          material.Container(
            width: 48,
            height: 48,
            decoration: material.BoxDecoration(
              color: color,
              borderRadius: material.BorderRadius.circular(8),
              border: material.Border.all(color: material.Colors.grey),
            ),
          ),
          const material.SizedBox(width: 16),
          material.Text(name),
        ],
      ),
    );
  }
}

Build Commands#

# Run Widgetbook
flutter run -t lib/main.dart -d chrome

# Code generation
cd app/kobic_widgetbook  & &   dart run build_runner build --delete-conflicting-outputs

# Web build
flutter build web -t lib/main.dart

Reference Files#

app/kobic_widgetbook/lib/main.dart
app/kobic_widgetbook/lib/add_on/slang_addon.dart
app/kobic_widgetbook/lib/add_on/view_ports.dart
app/kobic_widgetbook/lib/component/widget_book_button.dart

Checklist#

  • @App() Annotation Apply
  • @UseCase Annotation Writing
  • Maintain path consistency ([Component], [Feature], [Foundation])
  • Configure Addons (Viewport, Theme, Slang)
  • Set up Mock objects (BLoC, Repository)
  • Execute build_runner
  • Test across various viewports