Skip to content

Commit 78e6272

Browse files
PHKennyclaude
andcommitted
docs(claude-plugin): add themed-button, themed-alert and themed-snackbar skills
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 388af86 commit 78e6272

6 files changed

Lines changed: 932 additions & 0 deletions

File tree

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
name: themed-alert
3+
description: Use ThemedAlert in a layrz Flutter widget. Apply when rendering an inline status callout — info/success/warning/danger/context/custom severities with five visual styles (.layrz, .filledTonal, .filled, .outlined, .filledIcon).
4+
---
5+
6+
> **Dart syntax:** This library requires Dart ≥ 3.10. Use dot shorthand for all enum values (e.g. `.info`, `.danger`, `.filledTonal`, `.filledIcon`) — never write the fully-qualified form (`ThemedAlertType.info`).
7+
8+
> **Full constructor and property reference:** read `references/api.md` in this skill's directory.
9+
10+
---
11+
12+
## When to use
13+
14+
- Inline status messaging: form-level validation summaries, page-level banners, dialog body callouts, empty-state hints.
15+
- Choose `type` by **semantic severity:**
16+
- `.info` — neutral informational hint (default).
17+
- `.success` — confirmation that an action completed successfully.
18+
- `.warning` — reversible caution; user can still proceed.
19+
- `.danger` — blocking or destructive condition; user must act before continuing.
20+
- `.context` — muted/grey note; low-emphasis metadata.
21+
- `.custom` — only when you must override both icon and color. Requires `icon` and `color`.
22+
- Choose `style` by **surface context:**
23+
- `.layrz` — subtle tonal chip + plain text on transparent background; good default.
24+
- `.filledTonal` — soft 20% alpha background; use for moderate emphasis inside forms.
25+
- `.filled` — solid type-color background; use for strong emphasis, error banners.
26+
- `.outlined` — transparent background with type-color border; use inside cards.
27+
- `.filledIcon` — two-column layout (filled icon column + white body); use on dashboards.
28+
- **`ThemedAlert` is a pure `StatelessWidget` — there is no `ThemedAlert.show()` or dialog helper.** Place it directly inside a `Column`, `AlertDialog.content`, `SnackBar.content`, or any other layout widget.
29+
- Use `ThemedAlertIcon` when you need just the colored icon badge without a title or description.
30+
31+
---
32+
33+
## Minimal usage
34+
35+
```dart
36+
ThemedAlert(
37+
type: .warning,
38+
title: context.i18n.t('entity.warning.title'),
39+
description: context.i18n.t('entity.warning.description'),
40+
)
41+
```
42+
43+
---
44+
45+
## Key behaviors
46+
47+
- `title` and `description` are **required** — no factory variant exists without them.
48+
- `maxLines` (default 3) clips `description` with an ellipsis; bump it if the message is expected to be longer.
49+
- `.custom` type **requires** both `color` and `icon` — the widget has no fallback values for custom type.
50+
- `style` changes only the surface chrome (background, border); the semantic color always comes from `type`.
51+
- `iconSize` defaults to **25** when `style` is `.filledIcon`, **22** otherwise. Override explicitly only when layout demands it.
52+
- In `.filled` style, text color is auto-contrasted via `validateColor(typeColor)` — do not manually set text colors.
53+
54+
---
55+
56+
## Common patterns
57+
58+
```dart
59+
// 1. Info banner — default subtle style
60+
ThemedAlert(
61+
title: context.i18n.t('onboarding.tip.title'),
62+
description: context.i18n.t('onboarding.tip.description'),
63+
)
64+
65+
// 2. Filled danger alert inside an AlertDialog
66+
AlertDialog(
67+
content: ThemedAlert(
68+
type: .danger,
69+
style: .filled,
70+
title: context.i18n.t('errors.deleteTitle'),
71+
description: context.i18n.t('errors.deleteDescription'),
72+
),
73+
actions: [...],
74+
)
75+
76+
// 3. Outlined success summary inside a Card
77+
Card(
78+
child: Padding(
79+
padding: const EdgeInsets.all(16),
80+
child: ThemedAlert(
81+
type: .success,
82+
style: .outlined,
83+
title: context.i18n.t('export.done.title'),
84+
description: context.i18n.t('export.done.description'),
85+
),
86+
),
87+
)
88+
89+
// 4. Custom type with project-specific icon and color
90+
ThemedAlert(
91+
type: .custom,
92+
color: const Color(0xFF6A0DAD),
93+
icon: LayrzIcons.solarOutlineShieldCheck,
94+
title: context.i18n.t('security.verified.title'),
95+
description: context.i18n.t('security.verified.description'),
96+
)
97+
```
98+
99+
---
100+
101+
## Usage conventions
102+
103+
- Localize `title` and `description` via `context.i18n.t('...')` — never hardcode strings.
104+
- Don't stack multiple alerts of the same severity; collapse them into one with a combined description.
105+
- Keep descriptions short enough to fit in 3 lines. If content is inherently longer, set `maxLines` explicitly rather than leaving the default clip.
106+
- For action-triggered feedback (e.g. after a form submit), prefer wrapping `ThemedAlert` inside `SnackBar.content` so it auto-dismisses rather than cluttering the page layout.
107+
- Separate `ThemedAlert` from surrounding inputs or cards with `SizedBox(height: 10)`.
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# ThemedAlert — API Reference
2+
3+
Source: `lib/src/alerts/`
4+
5+
- `ThemedAlert` class — `src/alert.dart` line 37
6+
- `ThemedAlertType` enum — `src/type.dart`
7+
- `ThemedAlertStyle` enum — `src/style.dart`
8+
- `ThemedAlertIcon` class — `src/icon.dart` line 24
9+
10+
---
11+
12+
## Examples
13+
14+
```dart
15+
// Default — info type, layrz style
16+
ThemedAlert(
17+
title: 'Heads up',
18+
description: 'This action cannot be undone after 30 days.',
19+
)
20+
21+
// Warning with filledTonal background
22+
ThemedAlert(
23+
type: .warning,
24+
style: .filledTonal,
25+
title: 'Low disk space',
26+
description: 'You have less than 500 MB remaining.',
27+
)
28+
29+
// Danger with filled (solid) background
30+
ThemedAlert(
31+
type: .danger,
32+
style: .filled,
33+
title: 'Account suspended',
34+
description: 'Your account has been suspended due to policy violations.',
35+
)
36+
37+
// Success outlined (inside a Card)
38+
ThemedAlert(
39+
type: .success,
40+
style: .outlined,
41+
title: 'Export complete',
42+
description: 'Your file has been exported and is ready to download.',
43+
)
44+
45+
// FilledIcon style — two-column layout
46+
ThemedAlert(
47+
type: .info,
48+
style: .filledIcon,
49+
title: 'New version available',
50+
description: 'Version 3.2 introduces improved performance and bug fixes.',
51+
)
52+
53+
// Custom type — override icon and color
54+
ThemedAlert(
55+
type: .custom,
56+
color: const Color(0xFF6A0DAD),
57+
icon: LayrzIcons.solarOutlineShieldCheck,
58+
title: 'Identity verified',
59+
description: 'Your identity has been verified successfully.',
60+
)
61+
62+
// Extended description with bumped maxLines
63+
ThemedAlert(
64+
type: .context,
65+
title: 'About this feature',
66+
description: 'This feature is in beta. Some behaviors may change without '
67+
'notice. Please report any issues to the support team.',
68+
maxLines: 5,
69+
)
70+
```
71+
72+
---
73+
74+
## Constructor
75+
76+
```dart
77+
const ThemedAlert({
78+
super.key,
79+
this.type = .info,
80+
required this.title,
81+
required this.description,
82+
this.maxLines = 3,
83+
this.style = .layrz,
84+
this.color,
85+
this.icon,
86+
this.iconSize,
87+
});
88+
```
89+
90+
---
91+
92+
## Properties
93+
94+
| Property | Type | Default | Notes |
95+
|---|---|---|---|
96+
| `type` | `ThemedAlertType` | `.info` | Semantic severity. Drives the default icon and color. See enum table below. |
97+
| `title` | `String` || **Required.** Bold heading text of the alert. |
98+
| `description` | `String` || **Required.** Body text. Clipped at `maxLines` with an ellipsis. |
99+
| `maxLines` | `int` | `3` | Maximum lines for `description`. Increase when the message is known to be longer. |
100+
| `style` | `ThemedAlertStyle` | `.layrz` | Visual surface treatment. See enum table below. |
101+
| `color` | `Color?` | `null` | Used **only** when `type == .custom`. Has no effect for other types. |
102+
| `icon` | `IconData?` | `null` | Used **only** when `type == .custom`. Has no effect for other types. |
103+
| `iconSize` | `double?` | `null` | Icon size. Defaults to `25` when `style == .filledIcon`, `22` otherwise. |
104+
105+
---
106+
107+
## `ThemedAlertType` enum
108+
109+
| Value | Default icon | Default color | Notes |
110+
|---|---|---|---|
111+
| `.info` | `solarOutlineInfoSquare` | `Colors.blue` | Neutral informational hint. Default type. |
112+
| `.success` | `solarOutlineCheckSquare` | `Colors.green` | Confirmation that an action completed. |
113+
| `.warning` | `solarOutlineDangerSquare` | `Colors.orange` | Reversible caution; user can still proceed. |
114+
| `.danger` | `solarOutlineCloseSquare` | `Colors.red` | Blocking or destructive condition. |
115+
| `.context` | `solarOutlineMenuDotsSquare` | `Colors.grey` | Muted, low-emphasis metadata note. |
116+
| `.custom` | `null` (must set `icon`) | `null` (must set `color`) | Both `icon` and `color` are **required** when using this type. |
117+
118+
---
119+
120+
## `ThemedAlertStyle` enum
121+
122+
| Value | Description |
123+
|---|---|
124+
| `.layrz` | Soft tonal icon chip + plain text on a transparent background. Default. |
125+
| `.filledTonal` | Background filled at ~20% alpha of the type color; text and icon in type color. |
126+
| `.filled` | Solid type-color background. Text color is auto-contrasted via `validateColor(typeColor)`. |
127+
| `.outlined` | Transparent background with a 1 px type-color border. |
128+
| `.filledIcon` | Two-column layout: icon column filled with type color; body column uses `scaffoldBackgroundColor`. |
129+
130+
---
131+
132+
## Companion — `ThemedAlertIcon`
133+
134+
Standalone colored icon badge matching the alert's type palette. Use when you need just the badge without a title or description — for example, as a status indicator in a table row.
135+
136+
```dart
137+
const ThemedAlertIcon({
138+
super.key,
139+
this.type = .info,
140+
this.size = 30,
141+
this.iconSize = 20,
142+
this.padding = const EdgeInsets.all(5),
143+
this.color,
144+
this.icon,
145+
});
146+
```
147+
148+
| Property | Type | Default | Notes |
149+
|---|---|---|---|
150+
| `type` | `ThemedAlertType` | `.info` | Drives the icon and background color. |
151+
| `size` | `double` | `30` | Diameter of the circular badge. |
152+
| `iconSize` | `double` | `20` | Icon size inside the badge. |
153+
| `padding` | `EdgeInsetsGeometry` | `EdgeInsets.all(5)` | Internal padding around the icon. |
154+
| `color` | `Color?` | `null` | Used only when `type == .custom`. |
155+
| `icon` | `IconData?` | `null` | Used only when `type == .custom`. |
156+
157+
---
158+
159+
## Behavior notes
160+
161+
- **`.filledIcon` layout:** renders a `Row` with two columns — the left column is a `Container` filled with the type color and the right column uses the scaffold's background color. The icon column width is determined by `iconSize + padding`.
162+
- **`.filled` text contrast:** body text color is computed via `validateColor(typeColor)`, which selects black or white for maximum legibility — do not manually set text color inside a `.filled` alert.
163+
- **`.filledTonal` alpha:** background is `typeColor.withAlpha(51)` (≈ 20% opacity on any surface).
164+
- **`.outlined` border:** 1 px `BoxDecoration` border using the type color; no background fill.
165+
- **No dialog helper:** `ThemedAlert` is intentionally a pure layout widget with no `show()` or imperative API. Wrap it in `showDialog`, `ScaffoldMessenger.showSnackBar`, or any other mechanism the caller controls.
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
---
2+
name: themed-button
3+
description: Use ThemedButton in a layrz Flutter widget. Apply when rendering any tappable action — primary/secondary CTAs, icon-only FABs, destructive actions, cooldown buttons, or the six semantic factories (.save, .cancel, .info, .show, .edit, .delete).
4+
---
5+
6+
> **Dart syntax:** This library requires Dart ≥ 3.10. Use dot shorthand for all enum values (e.g. `.filledTonal`, `.fab`, `.outlined`) — never write the fully-qualified form (`ThemedButtonStyle.filledTonal`).
7+
8+
> **Full constructor and property reference:** read `references/api.md` in this skill's directory.
9+
10+
---
11+
12+
## When to use
13+
14+
- Any tappable action: CTA buttons, form submit/cancel, confirmation dialogs, detail pages.
15+
- **Prefer the six semantic factories** (`.save`, `.cancel`, `.info`, `.show`, `.edit`, `.delete`) for CRUD screens — they wire up the correct icon, color, and style automatically.
16+
- Use FAB-variant styles (`.fab`, `.filledTonalFab`, `.elevatedFab`, etc.) when the button is icon-only; `labelText` becomes the tooltip.
17+
- Use `isCooldown` for rate-limited actions (e.g. OTP resend, export trigger) where the user must wait before retrying.
18+
- Use `onLongPress` for destructive or confirm-before-act patterns — note it is **mutually exclusive with `onTap`**.
19+
- **Do not use** for static icons with no interaction — use a plain `Icon` instead.
20+
- **Do not use** for on/off toggles — use `ThemedAnimatedCheckbox` instead.
21+
- **Do not use** for a row of actions on a list item — use `ThemedActionsButtons` instead (collapses to FAB overlay on mobile automatically).
22+
23+
---
24+
25+
## Minimal usage
26+
27+
```dart
28+
// Semantic factory — recommended for CRUD save
29+
ThemedButton.save(
30+
labelText: context.i18n.t('actions.save'),
31+
isLoading: isSaving,
32+
onTap: () async {
33+
await save();
34+
if (context.mounted) onSaved.call();
35+
},
36+
)
37+
```
38+
39+
---
40+
41+
## Key behaviors
42+
43+
- **`label` XOR `labelText`** — exactly one must be provided (compile-time assert). Use `labelText` (String) for text; use `label` (Widget) for custom content.
44+
- **`onTap` XOR `onLongPress`** — providing both throws an assert.
45+
- `isLoading: true` replaces the button content with a circular spinner; `loadingBackgroundColor` / `loadingForegroundColor` override the spinner colors.
46+
- `isCooldown: true` locks the button for `cooldownDuration` (default 5 s) after a tap, then fires `onCooldownFinish`. Set `showCooldownRemainingDuration: false` to hide the countdown overlay.
47+
- `isDisabled: true` applies a grey tint via `ThemedButton.getDisabledColor(isDark, style)` and suppresses `onTap`.
48+
- **FAB variants** (`.fab`, `.filledTonalFab`, etc.) are icon-only — they use `labelText` as the tooltip. Set `tooltipEnabled: false` to suppress it.
49+
- `height` defaults to `ThemedButton.defaultHeight` (40). Minimum is 30; `iconSize` must be ≤ `height` and `fontSize` must be ≤ `height`.
50+
51+
---
52+
53+
## Common patterns
54+
55+
```dart
56+
// 1. Primary filledTonal with icon (default style)
57+
ThemedButton(
58+
labelText: context.i18n.t('actions.export'),
59+
icon: LayrzIcons.solarOutlineExport,
60+
onTap: () async {
61+
await export();
62+
if (context.mounted) onExported.call();
63+
},
64+
)
65+
66+
// 2. Icon-only FAB (label becomes tooltip)
67+
ThemedButton(
68+
labelText: context.i18n.t('actions.add'),
69+
icon: LayrzIcons.solarOutlineAddSquare,
70+
style: .fab,
71+
onTap: onAdd,
72+
)
73+
74+
// 3. Cooldown button (e.g. resend OTP)
75+
ThemedButton(
76+
labelText: context.i18n.t('auth.resendCode'),
77+
icon: LayrzIcons.solarOutlineRestart,
78+
isCooldown: true,
79+
cooldownDuration: const Duration(seconds: 30),
80+
onCooldownFinish: onCooldownEnd,
81+
onTap: onResend,
82+
)
83+
84+
// 4. Async loading state
85+
ThemedButton(
86+
labelText: context.i18n.t('actions.submit'),
87+
isLoading: isSubmitting,
88+
onTap: onSubmit,
89+
)
90+
91+
// 5. Semantic factory row — save + cancel
92+
Row(
93+
children: [
94+
ThemedButton.cancel(
95+
labelText: context.i18n.t('actions.cancel'),
96+
isMobile: isMobile,
97+
onTap: onCancel,
98+
),
99+
const SizedBox(width: 10),
100+
ThemedButton.save(
101+
labelText: context.i18n.t('actions.save'),
102+
isMobile: isMobile,
103+
isLoading: isSaving,
104+
onTap: onSave,
105+
),
106+
],
107+
)
108+
```
109+
110+
---
111+
112+
## Form conventions
113+
114+
- Localize every label with `context.i18n.t('...')` — never hardcode strings.
115+
- Always guard async callbacks: `if (context.mounted) callback.call();`
116+
- Use the six semantic factories on CRUD detail pages — they encode the project's icon/color conventions.
117+
- Separate stacked buttons with `SizedBox(height: 10)`; separate buttons in a `Row` with `SizedBox(width: 10)`.
118+
- Pass `isMobile: isMobile` (or `isMobile: context.isMobile`) to semantic factories so they switch to FAB style on small screens automatically.

0 commit comments

Comments
 (0)