Token导航 LogoToken导航TokenDH.com
开发执行命令github未标认证来源可访问许可证需确认审计通过

flutter-duskmoon-designFlutter duskmoon 设计

Agent Skill

用于辅助界面设计、视觉规范、排版、配色、布局和交互体验优化。它适合让 Agent 根据产品场景整理页面结构、生成 UI 方案、检查视觉一致性或改进组件层级。使用时需要结合现有品牌、设计系统和用户任务,不应只堆装饰元素;涉及真实页面改动时,应通过截图或浏览器预览检查文本溢出、对齐和响应式表现。

总安装

353

周安装

15

GitHub Stars

公开资料未说明

下载量

124
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:flutter-duskmoon-design(Flutter duskmoon 设计)
来源仓库:https://github.com/gsmlg-dev/code-agent
仓库路径:skills/flutter-duskmoon-design
安装命令:
npx skills add https://github.com/gsmlg-dev/code-agent --skill flutter-duskmoon-design
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/gsmlg-dev/code-agent --skill flutter-duskmoon-design

简介

flutter-duskmoon-design 用于辅助界面设计、视觉规范、排版、配色、布局和交互体验优化。

  • 适合让 Agent 根据产品场景整理页面结构、生成 UI 方案或检查视觉一致性。
  • 使用时需结合现有品牌、设计系统和用户任务,避免堆砌装饰元素。
  • 涉及真实页面改动时,应通过截图或浏览器预览检查文本溢出和对齐表现。
  • 适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

SKILL.md

Flutter DuskMoon UI — Design Principles & Usage Rules

Architecture Overview

Package Dependency Graph (import direction →)

duskmoon-dev/design (YAML → codegen)
  → duskmoon_theme
      ├ DmDesignTokens (generated const data)
      ├ DmTheme (InheritedWidget)
      ├ DmPlatformStyle { material, cupertino, fluent }
      └ toMaterial() / toCupertino() / toFluent()

duskmoon_theme
  → duskmoon_widgets
      ├ DuskmoonApp (root shell)
      ├ DmAdaptiveWidget (base class)
      └ Dm* widgets (Button, TextField, Switch, etc.)

duskmoon_widgets
  → duskmoon_settings
  → duskmoon_feedback
  → duskmoon_ui (umbrella re-export)

Rule: Never import downstream. duskmoon_theme must never import from duskmoon_widgets. duskmoon_widgets must never import from duskmoon_settings.

Widget Tree (Runtime)

DuskmoonApp(tokens: .sunshine, darkTokens: .moonlight, platformStyle: .cupertino)
  └→ DmTheme (InheritedWidget — .of(context) available everywhere below)
       └→ CupertinoApp(theme: tokens.toCupertino())
            └→ user's widget tree
                 └→ DmButton(label: "Save")  // dispatches to CupertinoButton

Rule 1: Theme Setup

Correct App Root

// ✅ ALWAYS — use DuskmoonApp as the root widget
void main() {
  runApp(
    DuskmoonApp(
      tokens: DmDesignTokens.sunshine,
      darkTokens: DmDesignTokens.moonlight,
      themeMode: ThemeMode.system,
      platformStyle: DmPlatformStyle.material,
      home: const MyHomePage(),
    ),
  );
}

❌ NEVER — bypass DuskmoonApp

// ❌ NEVER wrap MaterialApp/CupertinoApp directly
void main() {
  runApp(MaterialApp(
    theme: DmDesignTokens.sunshine.toMaterial(), // wrong — skips DmTheme
    home: MyHomePage(),
  ));
}

Why: DuskmoonApp injects DmTheme above the platform app. Without it, DmTheme.of(context) returns null and all Dm* widgets fail to resolve tokens.


Rule 2: Accessing Design Tokens

Always use DmTheme.of(context)

// ✅ Read tokens from the widget tree
Widget build(BuildContext context) {
  final tokens = DmTheme.of(context).tokens;
  return Container(
    color: tokens.primaryContainer,
    child: Text('Hello', style: TextStyle(color: tokens.onPrimaryContainer)),
  );
}

❌ NEVER reference generated constants directly in widget builds

// ❌ This ignores dark mode, theme overrides, and subtree overrides
Widget build(BuildContext context) {
  return Container(color: DmDesignTokens.sunshine.primaryContainer);
}

Why: The resolved tokens depend on ThemeMode, platform brightness, and possible DmThemeOverride ancestors. Only DmTheme.of(context) returns the correct resolved set.

Exception — static adapter methods

DuskmoonApp itself must convert tokens to platform ThemeData before DmTheme exists in the tree. For this case only, use the static adapters:

// Inside DuskmoonApp.build() — acceptable
MaterialApp(theme: DmTheme.staticToMaterial(resolvedTokens));

Rule 3: Color System

Token Structure (61 color tokens per theme)

GroupTokensUsage
Primaryprimary, onPrimary, primaryContainer, onPrimaryContainerMain brand actions, primary CTAs
Secondarysecondary, onSecondary, secondaryContainer, onSecondaryContainerSupporting actions, alternative CTAs
Tertiarytertiary, onTertiary, tertiaryContainer, onTertiaryContainerAccent highlights, badges, special UI
Errorerror, onError, errorContainer, onErrorContainerError states, destructive actions
Surfacesurface, onSurface, surfaceDim, surfaceBright, surfaceContainerLowestHighest, surfaceVariant, onSurfaceVariantBackgrounds, cards, elevation
Outlineoutline, outlineVariantBorders, dividers
InverseinverseSurface, inverseOnSurface, inversePrimarySnackbars, contrast overlays
Scrim/Shadowscrim (with alpha), shadowModal overlays, elevation shadows
Semanticinfo, success, warning (+ content variants)Status indicators

Color Format: OKLCH

All colors are defined in OKLCH in the source CSS. The Dart codegen converts to Color objects via inline OKLCH→sRGB math (zero external deps).

❌ NEVER hardcode color values

// ❌ Hardcoded hex
Container(color: Color(0xFF60A5FA))

// ❌ Hardcoded Material color
Container(color: Colors.blue)

// ✅ Use design tokens
Container(color: DmTheme.of(context).tokens.primary)

Semantic color pairing rule

Every background token has a corresponding foreground token. Always pair them:

// ✅ Correct pairing
Container(
  color: tokens.primaryContainer,
  child: Text('Label', style: TextStyle(color: tokens.onPrimaryContainer)),
)

// ❌ Mismatched — onSurface on primaryContainer may fail contrast
Container(
  color: tokens.primaryContainer,
  child: Text('Label', style: TextStyle(color: tokens.onSurface)),
)
BackgroundForeground
primaryonPrimary
primaryContaineronPrimaryContainer
secondaryonSecondary
secondaryContaineronSecondaryContainer
tertiaryonTertiary
tertiaryContaineronTertiaryContainer
surfaceonSurface
surfaceVariantonSurfaceVariant
erroronError
errorContaineronErrorContainer
inverseSurfaceinverseOnSurface

Surface elevation hierarchy

Use surface container tokens for visual depth, not opacity or shadows alone:

surfaceContainerLowest  →  bottom layer (behind everything)
surfaceContainerLow     →  low-elevation cards
surfaceContainer        →  standard cards/containers
surfaceContainerHigh    →  elevated cards, menus
surfaceContainerHighest →  dialogs, tooltips, top layer

Rule 4: Available Themes

5 themes defined in duskmoon-dev/design, codegen'd to Dart:

ThemeModePrimary Character
sunshinelightWarm amber/gold
moonlightdarkCool blue/lavender
oceandarkDeep blue/teal
forestlightNatural green/earth
sunsetlightWarm orange/rose

Access via DmDesignTokens.sunshine, DmDesignTokens.moonlight, etc.


Rule 5: Platform Adaptive Widgets

Resolution Stack (highest priority first)

L1: Per-widget `platformOverride` parameter
L2: Nearest DmPlatformOverride ancestor (subtree override)
L3: DmTheme.of(context).platformStyle (from DuskmoonApp)
L4: defaultTargetPlatform (auto-detect)

Writing an adaptive widget

All adaptive widgets extend DmAdaptiveWidget:

class DmButton extends DmAdaptiveWidget {
  const DmButton({super.key, required this.label, super.platformOverride});
  final String label;

  @override
  Widget buildMaterial(BuildContext context, DmDesignTokens tokens) {
    return FilledButton(onPressed: () {}, child: Text(label));
  }

  @override
  Widget buildCupertino(BuildContext context, DmDesignTokens tokens) {
    return CupertinoButton.filled(onPressed: () {}, child: Text(label));
  }

  // buildFluent defaults to buildMaterial unless overridden
}

❌ NEVER check platform manually

// ❌ Manual platform switching
if (Platform.isIOS) {
  return CupertinoButton(...);
} else {
  return ElevatedButton(...);
}

// ✅ Use DmAdaptiveWidget dispatch or DmPlatformStyle resolution
class MyWidget extends DmAdaptiveWidget { ... }

File structure for adaptive widgets

dm_button/
├── dm_button.dart            # Public API, extends DmAdaptiveWidget
├── dm_button_material.dart   # buildMaterial implementation
├── dm_button_cupertino.dart  # buildCupertino implementation
└── dm_button_fluent.dart     # buildFluent (optional, falls through to material)

Rule 6: Shared Design Enums

All Dm* widgets share these semantic enums. Use them consistently — never invent ad-hoc parameters.

enum DmColorRole { primary, secondary, tertiary, error, neutral }
enum DmSize { xs, sm, md, lg, xl }
enum DmButtonVariant { filled, outlined, ghost, tonal }
enum DmInputVariant { outlined, filled, underlined }

Color resolution from DmColorRole

Every widget that takes DmColorRole resolves tokens identically:

DmColorRoleBackgroundForegroundContainerOn Container
primarytokens.primarytokens.onPrimarytokens.primaryContainertokens.onPrimaryContainer
secondarytokens.secondarytokens.onSecondarytokens.secondaryContainertokens.onSecondaryContainer
tertiarytokens.tertiarytokens.onTertiarytokens.tertiaryContainertokens.onTertiaryContainer
errortokens.errortokens.onErrortokens.errorContainertokens.onErrorContainer
neutraltokens.surfacetokens.onSurfacetokens.surfaceContainerHightokens.onSurface

Size scale

DmSizeHorizontal paddingVertical paddingFont scale
xs840.75rem (12)
sm1260.875rem (14)
md1680.875rem (14)
lg24121rem (16)
xl32161.125rem (18)

Rule 7: Component Design — Actions

DmButton

Default: variant: filled, color: primary, size: md

VariantBackgroundForegroundBorderUse case
filledrole coloronRolenonePrimary CTAs, main actions
outlinedtransparentrole colorrole colorSecondary actions, cancel
ghosttransparentrole colornoneTertiary/inline actions, links
tonalroleContaineronRoleContainernoneSoft emphasis, toggles

Color role assignment convention:

Action typeColor roleExample
Main CTA, save, submit, confirmprimary"Save Changes"
Alternative action, secondary flowsecondary"Export", "Share"
Accent action, special highlighttertiary"Watch Demo", "Premium"
Destructive, delete, removeerror"Delete Account"
Neutral, dismiss, low emphasisneutral"Cancel", "Skip"
// ✅ Typical action group
Row(children: [
  DmButton(variant: .ghost, color: .neutral, child: Text('Cancel')),
  DmButton(variant: .outlined, color: .secondary, child: Text('Save Draft')),
  DmButton(variant: .filled, color: .primary, child: Text('Publish')),
])

DmIconButton

Same color/size system as DmButton. Must always have semanticLabel.

DmIconButton(
  icon: Icons.delete,
  color: DmColorRole.error,
  semanticLabel: 'Delete item',
  onPressed: () {},
)

DmFab (Floating Action Button)

  • Default color: primary — the single most important action on the screen
  • Surface: primaryContainer background, onPrimaryContainer icon
  • Rule: Maximum one FAB per screen. If you need multiple actions, use DmActionList.
DmFab(
  onPressed: () {},
  icon: Icons.add,
  // FAB always uses primaryContainer/onPrimaryContainer — no color param
)

DmActionList

Adapts rendering to available space:

BreakpointRendering
Small (< 600)Popup menu (overflow)
Medium (600–1200)Icon buttons in row
Large (> 1200)Text buttons with icons
DmActionList(
  actions: [
    DmAction(icon: Icons.edit, label: 'Edit', onPressed: ...),
    DmAction(icon: Icons.share, label: 'Share', onPressed: ...),
    DmAction(icon: Icons.delete, label: 'Delete', color: DmColorRole.error, onPressed: ...),
  ],
)

Rule 8: Component Design — Navigation

DmAppBar

Default token mapping:

ElementTokenRationale
BackgroundprimaryBrand presence, top-level identity
Title textonPrimaryContrast on primary
Icon buttonsonPrimaryConsistent with primary surface
Bottom bordernone (primary fills)Clean branded bar

Scrolled/elevated state: Background transitions to primaryContainer, text to onPrimaryContainer.

DmAppBar(
  title: Text('Settings'),
  leading: DmIconButton(icon: Icons.arrow_back, semanticLabel: 'Back'),
  actions: [
    DmIconButton(icon: Icons.search, semanticLabel: 'Search'),
    DmIconButton(icon: Icons.more_vert, semanticLabel: 'More options'),
  ],
)

Neutral variant: For screens where the app bar should not compete with content (e.g., content-heavy reading views), pass color: DmColorRole.neutral to fall back to surface/onSurface.

DmBottomNav

ElementToken
Backgroundprimary
Selected icon/labelonPrimary
Unselected icon/labelonPrimary at 70% opacity
Selected indicatorprimaryContainer (pill behind icon)
Top bordernone (primary fills)

Rule: 3–5 destinations maximum. Labels always visible (not icon-only).

DmTabBar

ElementToken
Backgroundsurface
Selected tabprimary (indicator + text)
Unselected tabonSurfaceVariant
Indicatorprimary (bottom line in Material, pill in Cupertino)

DmDrawer

ElementToken
Backgroundsecondary
Header areasecondaryContainer
Selected item bgonSecondary at 15% opacity
Selected item textonSecondary
Unselected textonSecondary at 70% opacity
DividersonSecondary at 20% opacity
Scrim (overlay behind drawer)scrim with alpha

Side menus and drawers use the secondary color family to visually distinguish navigation chrome from the primary-branded top bar.

DmBreadcrumbs

ElementToken
Active (current)onSurface (no link)
Ancestors (links)primary
SeparatoronSurfaceVariant

Rule 9: Component Design — Layout & Cards

DmCard

Elevation hierarchy via surface tokens:

Card styleBackground tokenUse case
FlatsurfaceInline content, no separation
Outlinedsurface + outlineVariant borderList items, settings rows
ElevatedsurfaceContainerLowStandard cards
FilledsurfaceContainerHighEmphasized/grouped content

Interior layout convention:

┌─────────────────────────────────┐
│ [optional media/image]          │
├─────────────────────────────────┤
│ Title         (onSurface)       │
│ Subtitle      (onSurfaceVariant)│
│                                 │
│ Body text     (onSurface)       │
│                                 │
│ ┌─────────────────────────────┐ │
│ │ Actions: ghost/outlined btns│ │
│ └─────────────────────────────┘ │
└─────────────────────────────────┘
DmCard(
  style: DmCardStyle.elevated,
  child: Column(children: [
    Image(...),
    Padding(
      padding: EdgeInsets.all(16),
      child: Column(children: [
        Text('Title', style: TextStyle(color: tokens.onSurface)),
        Text('Subtitle', style: TextStyle(color: tokens.onSurfaceVariant)),
        Row(children: [
          DmButton(variant: .ghost, child: Text('Cancel')),
          DmButton(variant: .filled, child: Text('Confirm')),
        ]),
      ]),
    ),
  ]),
)

❌ NEVER put a filled primary card background with onPrimary text for regular content cards. Primary/secondary/tertiary containers are for interactive highlights (selected state, feature callout), not default card backgrounds.

DmDivider

VariantTokenUse case
DefaultoutlineVariantSection separation
StrongoutlineMajor section breaks

DmScaffold

Responsive layout dispatch:

BreakpointNavigation style
Compact (< 600)DmBottomNav
Medium (600–1200)NavigationRail (collapsed)
Expanded (> 1200)NavigationRail (expanded with labels)

Page body background: surface. Rail/side nav background: secondary.


Rule 10: Component Design — Data Display (Bricks)

DmBadge

Small status/count indicator. Takes DmColorRole.

VariantBackgroundForegroundUse case
Filledrole coloronRoleNotification count, status dot
TonalroleContaineronRoleContainerSoft label, category tag

Default: color: error (notification convention), size: sm

DmBadge(count: 3)                                  // red notification dot
DmBadge(label: 'New', color: .tertiary, variant: .tonal)  // soft accent tag
DmBadge(label: 'Draft', color: .neutral, variant: .tonal) // muted status

DmChip

Selectable/filterable labels. Takes DmColorRole.

StateBackgroundForegroundBorder
UnselectedsurfaceonSurfaceVariantoutline
SelectedsecondaryContaineronSecondaryContainernone
Disabledsurface at 38% opacityonSurface at 38%outline at 12%

Default selection color: secondary — secondary containers are for selection states.

DmAvatar

VariantBackgroundForeground
With image
Initials (default)primaryContaineronPrimaryContainer
Initials (group variety)Cycle through primary/secondary/tertiary containersMatching onContainer

Sizes follow DmSize enum. Default: md (40dp diameter).

DmStat (Data Brick)

Statistics display block:

┌───────────────┐
│ 1,234         │  ← value: onSurface, large/bold
│ Active Users  │  ← label: onSurfaceVariant, small
│ ▲ 12.5%       │  ← trend: success or error token
└───────────────┘
ElementToken
ValueonSurface
LabelonSurfaceVariant
Positive trendsuccess (or tokens.success)
Negative trenderror
Card backgroundsurfaceContainerLow (when in card)

DmTable / Data Grid

ElementToken
Header row bgsurfaceContainerHigh
Header textonSurface (bold)
Body row bg (even)surface
Body row bg (odd)surfaceContainerLowest
Body textonSurface
Row hoversurfaceContainerLow
Selected rowsecondaryContainer
Border/grid linesoutlineVariant
Sort indicatorprimary

Rule 11: Component Design — Feedback

DmAlert

SemanticBackgroundForegroundIcon color
InfoinfoContainer (or surfaceContainerHigh + info icon)onSurfaceinfo
SuccesssuccessContaineronSurfacesuccess
WarningwarningContaineronSurfacewarning
ErrorerrorContaineronErrorContainererror

Convention: Alerts use semantic container tokens with full-width layout. For inline indicators, use DmBadge.

DmDialog

ElementToken
Scrim (backdrop)scrim with alpha
Dialog surfacesurfaceContainerHighest
TitleonSurface
BodyonSurfaceVariant
Confirm buttonDmButton(variant:.filled, color:.primary)
Cancel buttonDmButton(variant:.ghost, color:.neutral)
Destructive confirmDmButton(variant:.filled, color:.error)

DmSnackbar

Uses inverse tokens for contrast against current theme:

ElementToken
BackgroundinverseSurface
TextinverseOnSurface
Action buttoninversePrimary

DmProgress

Linear and circular variants. Default color: primary.

VariantTrackIndicator
DefaultsurfaceContainerHighestprimary
With color roleroleContainer (at low opacity)role color

DmSkeleton

Loading placeholder. Uses surfaceContainerHigh with shimmer animation toward surfaceContainerLow.


Rule 12: Component Design — Inputs

DmTextField

VariantIdleFocusedError
outlinedoutlineVariant borderprimary border (2px)error border
filledsurfaceContainerHighest bgprimary bottom indicatorerror indicator
underlinedoutlineVariant bottom lineprimary bottom line (2px)error line
ElementToken
Input textonSurface
Placeholder/hintonSurfaceVariant
Label (floating)onSurfaceVariantprimary when focused
Helper textonSurfaceVariant
Error texterror
Prefix/suffix icononSurfaceVariant

Default variant: outlined

DmCheckbox / DmSwitch / DmSlider

StateToken
Unchecked/offonSurfaceVariant (border), surface (fill)
Checked/onprimary (fill), onPrimary (checkmark)
Track (switch off)surfaceContainerHighest
Track (switch on)primary at 50% → primaryContainer
Thumboutline (off) → onPrimary (on, over primary track)
Slider active trackprimary
Slider inactive tracksurfaceContainerHighest
Slider thumbprimary
DisabledAll at 38% opacity

Rule 13: Visual Design Principles

Hierarchy through token roles, not through ad-hoc colors

Primary   → THE action (one per screen section)
Secondary → supporting actions, selection states
Tertiary  → accents, highlights, special callouts
Surface   → everything else (backgrounds, text, structure)

If you need emphasis, promote the token role — don't invent a color.

Density and spacing

DuskMoon follows MD3 density: default padding 16dp, compact 12dp, comfortable 24dp. Widget padding follows the DmSize scale.

Elevation = surface tokens, not shadows

Use surfaceContainerLowestsurfaceContainerHighest for visual hierarchy. Shadows (shadow token) are supplementary, not the primary depth cue.

// ✅ Surface-token elevation
Container(color: tokens.surfaceContainerHigh)  // elevated
Container(color: tokens.surface)                // base level

// ❌ Shadow-only elevation
Container(
  decoration: BoxDecoration(
    color: tokens.surface,
    boxShadow: [BoxShadow(blurRadius: 8)],  // shadow without surface distinction
  ),
)

Dark mode is not "invert everything"

Each theme has its own curated token set. The codegen produces distinct values per theme. Never compute dark colors by inverting or dimming light colors at runtime.

// ❌ Never compute dark variants
final darkBg = Color.lerp(tokens.surface, Colors.black, 0.3);

// ✅ Use the dark theme's own tokens
DuskmoonApp(tokens: .sunshine, darkTokens: .moonlight)  // moonlight has its own curated values

Rule 14: Package Boundaries

(Architecture rules — same as above, renumbered for continuity)

What goes where

PackageContainsDoes NOT contain
duskmoon_themeDmDesignTokens, DmTheme, DmPlatformStyle, toMaterial() / toCupertino() / toFluent() adaptersAny widgets, any BuildContext-dependent rendering
duskmoon_widgetsDuskmoonApp, DmAdaptiveWidget, all Dm* widgetsToken definitions, theme adapters
duskmoon_theme_blocDmThemeBloc, DmThemeCubit for runtime theme switchingWidget implementations
duskmoon_settingsSettings UI widgets built on adaptive dispatchTheme internals
duskmoon_feedbackFeedback/bug-report widgetsTheme internals
duskmoon_uiUmbrella — re-exports all aboveNo unique code

❌ NEVER add duskmoon_widgets as dependency of duskmoon_theme

This creates a circular dependency. If duskmoon_theme needs to reference a widget concept, use an abstract interface or callback, not a concrete widget import.


Rule 15: Code Engine Integration

duskmoon_code_engine has zero dependency on duskmoon_theme. The theme adapter lives as an extension method in duskmoon_theme:

// In duskmoon_theme — NOT in duskmoon_code_engine
extension DmCodeEngineTheme on DmDesignTokens {
  CodeEditorTheme toCodeEditorTheme() => CodeEditorTheme(
    background: surface,
    foreground: onSurface,
    // ...
  );
}

Rule 16: Codegen Pipeline

duskmoon-dev/design YAML
  → Bun/TypeScript emitter
    → CSS (duskmoonui consumption)
    → TypeScript (duskmoonui/duskmoon-elements)
    → Dart (flutter_duskmoon_ui — committed, CI never needs Bun)
    → JSON (documentation/tooling)

Generated Dart files are committed to git. CI must never require Bun or Node to build the Flutter packages.

❌ NEVER hand-edit generated files

Files in packages/duskmoon_theme/lib/src/generated/ are produced by codegen. Edit the YAML source in duskmoon-dev/design and re-run the pipeline.


Rule 17: Accessibility

  • All color pairings must meet WCAG 2.1 AA contrast (4.5:1 normal text, 3:1 large text)
  • Every interactive Dm* widget must support keyboard navigation
  • Semantic labels required on all icon-only buttons
  • Focus indicators must be visible on all themes

Rule 18: Testing Patterns

Widget tests must verify all three platforms

for (final style in DmPlatformStyle.values) {
  testWidgets('DmButton renders on $style', (tester) async {
    await tester.pumpWidget(
      DuskmoonApp(
        tokens: DmDesignTokens.sunshine,
        platformStyle: style,
        home: const DmButton(label: 'Test'),
      ),
    );
    expect(find.text('Test'), findsOneWidget);
  });
}

Theme tests must verify token resolution

testWidgets('DmTheme.of resolves correct tokens', (tester) async {
  late DmDesignTokens resolved;
  await tester.pumpWidget(
    DuskmoonApp(
      tokens: DmDesignTokens.sunshine,
      home: Builder(builder: (context) {
        resolved = DmTheme.of(context).tokens;
        return const SizedBox();
      }),
    ),
  );
  expect(resolved.primary, equals(DmDesignTokens.sunshine.primary));
});

Quick Reference: Anti-Patterns

❌ Don't✅ Do
MaterialApp(theme: tokens.toMaterial()) as rootDuskmoonApp(tokens:...) as root
DmDesignTokens.sunshine.primary in widget buildDmTheme.of(context).tokens.primary
Color(0xFF...) or Colors.bluetokens.primary / tokens.secondary
Platform.isIOS for widget dispatchExtend DmAdaptiveWidget
Hand-edit generated/ Dart filesEdit YAML source, re-run codegen
Import duskmoon_widgets from duskmoon_themeKeep dependency direction strict
Put theme adapter in duskmoon_code_engineExtension method in duskmoon_theme
primaryContainer bg + onSurface textPair primaryContainer + onPrimaryContainer
AppBar background = surfaceAppBar background = primary (DuskMoon convention)
Drawer/side menu bg = primaryDrawer/side menu bg = secondary (navigation chrome distinction)
Card default bg = primaryContainerCard bg = surfaceContainerLow / surface + outline
Shadows as primary depth cueSurface container tokens for elevation hierarchy
Color.lerp(x, Colors.black, 0.3) for dark modeUse the dark theme's own curated tokens
Multiple FABs on one screenOne FAB max; use DmActionList for multiple
Icon button without semanticLabelAlways provide semanticLabel on DmIconButton
Selection highlight with primarySelection states use secondaryContainer
Inventing colors outside the token systemPromote token role (primary→secondary→tertiary)

Checklist for Code Review

When reviewing Flutter code that uses DuskMoon UI, verify:

Architecture:

  • App root is DuskmoonApp, not MaterialApp/CupertinoApp directly
  • Package imports flow downstream only (theme → widgets → settings)
  • No generated files were hand-edited
  • No duskmoon_theme dependency in duskmoon_code_engine
  • Adaptive widgets extend DmAdaptiveWidget, not manual platform checks

Color & Tokens:

  • All color values come from DmTheme.of(context).tokens, not hardcoded
  • Background/foreground token pairs match (primary↔onPrimary, etc.)
  • No Colors.* or Color(0x...) literals
  • Dark mode uses separate theme tokens, no runtime color computation

Component Design:

  • Buttons use DmColorRole convention (primary=main CTA, error=destructive, etc.)
  • AppBar and BottomNav use primary/onPrimary defaults
  • Drawer and side menu use secondary/onSecondary defaults
  • Cards use surface container tokens, not primary/secondary containers for default bg
  • Selection states use secondaryContainer tokens
  • Surface elevation via container tokens, not shadow-only
  • Maximum one FAB per screen section
  • DmActionList for multiple actions, not ad-hoc button rows
  • Snackbar uses inverse tokens
  • Dialog scrim uses scrim token with alpha

Accessibility:

  • Semantic labels on all icon-only buttons
  • Focus indicators visible on all themes
  • Widget tests cover all three DmPlatformStyle values
  • WCAG AA contrast on all bg/fg pairings

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

36.39%
按下载量换算45

Claude

28.85%
按下载量换算36

Cursor

19.88%
按下载量换算25

Gemini CLI

8.62%
按下载量换算11

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

执行命令

安装流程涉及命令执行,可能通过 npx skills add https://github.com/gsmlg-dev/code-agent --skill flutter-duskmoon-design 联网下载 Skill 或依赖。用户安装前应确认命令来源、仓库内容和执行环境。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills