Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
6715189
feat: add MagicStarterTokens semantic alias layer
anilcancakir Jun 25, 2026
44055c4
refactor: migrate MagicStarterCard to WindRecipe atomic component
anilcancakir Jun 25, 2026
103a551
feat: add structure components (FormField, PageHeader, EmptyState, Er…
anilcancakir Jun 25, 2026
3d2b652
feat: build the generic design-system component library (atomic folders)
anilcancakir Jun 25, 2026
3c260df
refactor: rewrite views + layouts onto the design-system components
anilcancakir Jun 25, 2026
41d8baa
feat: add design.md.stub for consumer DESIGN.md scaffolding
anilcancakir Jun 25, 2026
782ea41
docs: complete post-change sync for the design-system work
anilcancakir Jun 25, 2026
992127a
fix(switch): position thumb via flex justify, drop no-op translate-x
anilcancakir Jun 26, 2026
b78a5b4
fix(button): default Button shrinks to content instead of full-width
anilcancakir Jun 26, 2026
3fe9902
feat(previews): dev-only previews.dart barrel for all 30 components
anilcancakir Jun 26, 2026
bc8b62f
fix(teams): switch to the new team on create (server-side current-team)
anilcancakir Jun 26, 2026
29f7b5f
fix(components): address PR #78 review (release boundary, semantic to…
anilcancakir Jun 26, 2026
7952e72
feat(settings): add SettingsSection/Row/NavRow atomic components
anilcancakir Jun 26, 2026
650149c
feat(page-header): add unified automatic back navigation
anilcancakir Jun 26, 2026
7c453a4
fix(layout): guest pages own their implicit scroll controller
anilcancakir Jun 26, 2026
7788cb6
feat(settings): add SettingsScaffold sub-page wrapper + barrel exports
anilcancakir Jun 26, 2026
d4905c1
feat(settings): add hub + Profile sub-page views, route getters
anilcancakir Jun 26, 2026
1b5f08c
feat(settings): add Security sub-pages (2FA, Password, Sessions)
anilcancakir Jun 26, 2026
80b4c62
feat(settings): add Preferences sub-pages (Appearance, Language, Time…
anilcancakir Jun 26, 2026
74b633a
feat(settings): wire iOS settings routes + registry, retarget nav to hub
anilcancakir Jun 26, 2026
be6557a
feat(settings): adopt unified back header on teams/notifications sub-…
anilcancakir Jun 26, 2026
73bacc5
feat(settings): register the 4 settings component previews (dev-only)
anilcancakir Jun 26, 2026
0e4d4bf
style: dart format settings components/views
anilcancakir Jun 26, 2026
d4d6dea
fix(settings): make hub/sub-pages resolve + back work at runtime
anilcancakir Jun 26, 2026
534fce7
style(settings): larger iOS rows + wider desktop column
anilcancakir Jun 26, 2026
4734bd0
feat(settings): ship settings i18n keys in the install lang stub
anilcancakir Jun 26, 2026
aac6a50
fix(settings): uniform page surface + de-duplicate timezone/language
anilcancakir Jun 26, 2026
51ebae8
fix(settings): fill desktop width + move Save below the card
anilcancakir Jun 26, 2026
b22a2a8
fix(layout): key guest page subtree by route to stop transition crash
anilcancakir Jun 26, 2026
c5a29b5
feat(settings): add Settings hub link to user dropdown; move Delete A…
anilcancakir Jun 26, 2026
245523d
fix(segmented-control): render segments horizontally
anilcancakir Jun 27, 2026
f58f2e5
fix(ui): PageHeader titleSuffix hugs the title (flex-initial title co…
anilcancakir Jun 30, 2026
f758a54
fix(ui): present BottomSheet on the root navigator so it anchors to t…
anilcancakir Jul 1, 2026
9aa7806
fix(cli): windTheme injection tolerates multi-arg MagicApplication
anilcancakir Jul 3, 2026
1905aba
fix(ui): caller className appends onto component recipe instead of re…
anilcancakir Jul 7, 2026
284387e
fix(ui): lift dropdown_menu + tooltip default classNames into recipes…
anilcancakir Jul 7, 2026
5bb7746
feat(ui): add first-class fullWidth prop to Button, Input, Textarea (…
anilcancakir Jul 7, 2026
b5064f0
feat(testing): defensive manager fallback + setUpMagicStarterForTests…
anilcancakir Jul 7, 2026
89fa5eb
feat(theme): one-call MagicStarter.useWindTheme(WindThemeData) adopti…
anilcancakir Jul 7, 2026
91001fd
refactor(ui)!: rename flat component exports to MS-prefixed names (MS…
anilcancakir Jul 7, 2026
35288cb
test(testing): make MS-6 fallback statics resettable for order-indepe…
anilcancakir Jul 7, 2026
0a9671b
fix(ui): settings scaffold uses min-h-full inside the app scroll (not…
anilcancakir Jul 7, 2026
fbbfda4
test(ui): scroll-wrap the SettingsNavRow preview test (tall preview o…
anilcancakir Jul 7, 2026
bbdbc3c
chore(deps): realign magic ^0.0.4 + magic_notifications ^0.0.1 (0.0.x…
anilcancakir Jul 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,24 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

### Added
- **`design.md.stub`**: a `DESIGN.md` template shipped at `assets/stubs/design.md.stub` covering all 17 semantic roles (`surface`, `fg`, `primary`, `border`, `destructive`, `success`, `warning`, and their variants), typography on the 4px logical scale, rounded/spacing scales, and key component entries with `{{ placeholder }}` tokens. Consumers copy it into their project root, fill in brand hex values and fonts, then run `design:lint` to validate and `design:sync` to generate the Wind theme. Pairs with `MagicStarterTokens.defaultAliases` as the stable key contract.
- **Wave 4 design-system component library**: 23 new generic UI components are now part of the public barrel (`package:magic_starter/magic_starter.dart`). Each component lives in the canonical atomic-component folder shape (`<name>.dart`, `<name>.recipe.dart`, `<name>.preview.dart`, `index.dart`) under `lib/src/ui/components/`.
- **Form controls**: `Button` (with `ButtonIntent`, `ButtonSize`, `buttonRecipe`), `Input` (with `InputState`, `inputRecipe`), `Textarea` (with `TextareaState`, `textareaRecipe`), `Checkbox`, `Switch`, `Radio`, `Select` (with `selectRecipe`), `Combobox` (with `comboboxRecipe`).
- **Feedback and display**: `Badge` (with `BadgeTone`), `Typography` (with `TypographyVariant`), `Skeleton` (with `SkeletonShape`), `Toast` (with `ToastVariant`), `Tooltip`, `EmptyState`, `ErrorState`.
- **Layout and navigation**: `Accordion` (with `AccordionItem`, `accordionRecipe`), `SegmentedControl` (with `SegmentedControlSize`, `segmentedControlRecipe`), `Tabs` (with `tabsRecipe`), `Navbar`, `Dropdown` menu (`DropdownMenu`, `DropdownMenuItem`).
- **Overlay**: `Dialog`, `BottomSheet`.
- **Composition**: `MagicFormField` (label, hint, error wrapper).
- Previously migrated components (`Card`, `PageHeader`, `SocialDivider`, `NotificationDropdown`, `UserProfileDropdown`, `TeamSelector`, `ConfirmDialog`) were already barrel-reachable through their existing alias exports and are unchanged.
- **Breaking collision note**: the barrel now exports `Switch`, `Dialog`, `Checkbox`, `Radio`, `Badge`, `Typography`, `BottomSheet`, `Tooltip`, `DropdownMenu`, and `DropdownMenuItem`. Tests and app code that import both `package:flutter/material.dart` and `package:magic_starter/magic_starter.dart` must add a `hide` clause on the material import (or the barrel import) to resolve the ambiguity.

### Changed
- **Wave 5 view rewrite**: the auth (login, register, forgot, reset, two-factor-challenge, otp-verify), profile, notifications (list + preferences matrix), and teams (create, settings, invitation-accept) views plus both layouts (`MagicStarterAppLayout`, `MagicStarterGuestLayout`) now compose the new design-system components (`Button`, `Card`, `Switch`, `PageHeader`, `SocialDivider`, etc.) instead of inline W-widgets. Views are now Wind-exclusive: bare `package:flutter/material.dart` imports were replaced with `widgets.dart` + `material show Icons` (and the few genuinely-needed Material shells via `show`), so the new component names no longer collide. Behavior, registry keys (`auth.*`, `profile.*`, `notifications.*`, `teams.*`, `layout.app`, `layout.guest`), controller contracts, gate abilities, `refreshNotifier`, and notification polling are all preserved; only the presentation layer changed.
- **Card migrated to the atomic-component folder + `WindRecipe`**: the card now lives at `lib/src/ui/components/card/` in the canonical 4-file shape (`card.dart` → `class Card`, `card.recipe.dart`, `card.preview.dart`, `index.dart`) and resolves its root className through a theme-driven `WindRecipe` instead of inline string interpolation. The recipe output is byte-identical to the previous `_defaultClassName` for every `CardVariant` x `noPadding` combination (gated by an explicit equivalence test). `MagicStarterCard` is retained as a thin re-export alias of `Card`, and `CardVariant` plus the barrel export path (`package:magic_starter/magic_starter.dart`) are unchanged, so existing callers and the widget-test suite are untouched. This establishes the verbatim template for the Wave 4 component migration.

### Added
- **`MagicStarterTokens.defaultAliases`**: semantic token alias map with 17 roles (`surface`, `surface-container`, `surface-container-high`, `fg`, `fg-muted`, `fg-disabled`, `primary`, `on-primary`, `primary-container`, `accent`, `border`, `border-subtle`, `destructive`, `on-destructive`, `destructive-container`, `success`, `warning`). Each role maps to a light+dark wind className pair (`'bg-... dark:bg-...'` / `'text-... dark:text-...'`). Pass as `WindThemeData(aliases: MagicStarterTokens.defaultAliases)` so components resolve against semantic roles rather than palette utilities directly. This map is the stable key contract that `design:sync` (Steps 20-21) will later regenerate from `DESIGN.md`.

### Fixed
- **Create team opens the new team's settings**: `MagicStarterTeamController.activeTeamName` now matches the local `currentTeamId` (when set) against the resolver's `allTeams()` by id, falling back to the resolver's `currentTeam()` when no match exists. Previously `activeTeamId` preferred the local `currentTeamId` notifier (set on create/switch) while `activeTeamName` read only the resolver's `currentTeam()`, so after creating a team the settings view pre-filled the OLD team's name and effectively opened the old team ([#14](https://github.com/fluttersdk/magic_starter/issues/14)).

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Flutter starter kit for the Magic Framework. Pre-built Auth, Profile, Teams & No

| Command | Description |
|---------|-------------|
| `flutter test --coverage` | Run all tests (~52 files, ~752 cases) with coverage |
| `flutter test --coverage` | Run all tests (~62 files, ~996 cases) with coverage |
| `flutter test test/http/controllers/` | Run controller tests only |
| `flutter test --name "pattern"` | Run tests matching pattern |
| `flutter analyze --no-fatal-infos` | Static analysis (flutter_lints ^6.0) |
Expand Down
48 changes: 46 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Stop rebuilding authentication, profile management, and team features from scrat
| :bell: | **Notifications** | Real-time polling, mark read/unread, preference matrix |
| :iphone: | **OTP Login** | Phone-based guest authentication with send/verify flow |
| :art: | **Wind UI** | Tailwind-like className system — no Material widgets, dark mode built-in |
| :package: | **Reusable Widgets** | PageHeader, Card (3 variants), ConfirmDialog (3 variants), PasswordConfirmDialog, TwoFactorModal — all standalone |
| :package: | **Design-System Components** | 29 atomic components (Button, Input, Badge, Dialog, Toast, Tabs, Accordion, and more) plus `MagicStarterTokens` semantic alias layer |
| :gear: | **13 Feature Toggles** | All opt-in, configure only what you need |
| :jigsaw: | **View Registry** | Override any screen or layout from the host app |
| :hammer_and_wrench: | **CLI Tools** | install, configure, doctor, publish, uninstall |
Expand Down Expand Up @@ -191,9 +191,53 @@ MagicStarter.useSidebarFooter((context) {

---

## Design-System Components

Magic Starter ships a full atomic design-system component library exported from `package:magic_starter/magic_starter.dart`. Every component lives in a canonical 4-file atomic folder (`<name>.dart`, `<name>.recipe.dart`, `<name>.preview.dart`, `index.dart`) under `lib/src/ui/components/` and is driven by a `WindRecipe` that reads from `MagicStarterTokens.defaultAliases`.

### MagicStarterTokens

`MagicStarterTokens.defaultAliases` is a map of 17 semantic roles to light+dark Wind className pairs:

| Role | Example className pair |
|------|----------------------|
| `surface` | `bg-white dark:bg-gray-950` |
| `fg` | `text-gray-900 dark:text-gray-50` |
| `primary` | `bg-primary-600 dark:bg-primary-500` |
| `destructive` | `bg-red-600 dark:bg-red-500` |
| `border` | `border-gray-200 dark:border-gray-800` |

Pass the map when configuring your Wind theme so all components resolve against semantic roles rather than raw palette utilities:

```dart
WindApp(
theme: WindThemeData(
aliases: MagicStarterTokens.defaultAliases,
),
child: const MyApp(),
)
```

> **Breaking import note**: the barrel now exports `Switch`, `Dialog`, `Checkbox`, `Radio`, `Badge`, `Typography`, `BottomSheet`, `Tooltip`, `DropdownMenu`, and `DropdownMenuItem`. If you import both `package:flutter/material.dart` and `package:magic_starter/magic_starter.dart`, add a `hide` clause on the conflicting names.

### Component families

| Family | Components |
|--------|-----------|
| Form controls | `Button`, `Input`, `Textarea`, `Checkbox`, `Switch`, `Radio`, `Select`, `Combobox` |
| Display | `Badge`, `Typography`, `Skeleton`, `Toast`, `Tooltip`, `EmptyState`, `ErrorState` |
| Selection / navigation | `SegmentedControl`, `Tabs`, `Accordion`, `Navbar`, `DropdownMenu` |
| Overlay | `Dialog`, `BottomSheet` |
| Composition | `MagicFormField`, `Card`, `PageHeader`, `SocialDivider` |
| App chrome | `NotificationDropdown`, `UserProfileDropdown`, `TeamSelector` |

All components accept Wind `className` strings and resolve colors through the semantic alias layer when configured.

---

## Reusable Widgets

Magic Starter exports a set of standalone UI widgets that consumer apps can use directly — no internal controller coupling required.
Magic Starter also exports a set of standalone UI widgets that consumer apps can use directly. No internal controller coupling required.

### MagicStarterPageHeader

Expand Down
176 changes: 176 additions & 0 deletions assets/stubs/design.md.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
---
name: {{ app_name }}
description: >
Design system for {{ app_name }}. Single-brand, Wind semantic tokens,
M3-role palette. Generate the Wind theme with:
dart run {{ app_package }}:artisan design:sync
colors:
surface:
light: "#FFFFFF"
dark: "#030712"
surface-container:
light: "#F9FAFB"
dark: "#111827"
surface-container-high:
light: "#F3F4F6"
dark: "#1F2937"
fg:
light: "#111827"
dark: "#F9FAFB"
fg-muted:
light: "#6B7280"
dark: "#9CA3AF"
fg-disabled:
light: "#D1D5DB"
dark: "#4B5563"
primary:
light: "#{{ primary_hex_light }}"
dark: "#{{ primary_hex_dark }}"
on-primary:
light: "#FFFFFF"
dark: "#FFFFFF"
primary-container:
light: "#{{ primary_container_light }}"
dark: "#{{ primary_container_dark }}"
accent:
light: "#{{ accent_hex_light }}"
dark: "#{{ accent_hex_dark }}"
border:
light: "#E5E7EB"
dark: "#374151"
border-subtle:
light: "#F3F4F6"
dark: "#1F2937"
destructive:
light: "#DC2626"
dark: "#EF4444"
on-destructive:
light: "#FFFFFF"
dark: "#FFFFFF"
destructive-container:
light: "#FEE2E2"
dark: "#7F1D1D"
success:
light: "#15803D"
dark: "#16A34A"
warning:
light: "#D97706"
dark: "#B45309"
typography:
display:
fontFamily: {{ font_family }}
fontSize: 36px
fontWeight: "700"
lineHeight: 44px
letterSpacing: -0.02em
headline-lg:
fontFamily: {{ font_family }}
fontSize: 28px
fontWeight: "700"
lineHeight: 36px
letterSpacing: -0.01em
headline-md:
fontFamily: {{ font_family }}
fontSize: 22px
fontWeight: "600"
lineHeight: 30px
title-lg:
fontFamily: {{ font_family }}
fontSize: 18px
fontWeight: "600"
lineHeight: 26px
body-lg:
fontFamily: {{ font_family }}
fontSize: 16px
fontWeight: "400"
lineHeight: 26px
body-md:
fontFamily: {{ font_family }}
fontSize: 14px
fontWeight: "400"
lineHeight: 22px
label-md:
fontFamily: {{ font_family }}
fontSize: 14px
fontWeight: "600"
lineHeight: 20px
letterSpacing: 0.01em
label-sm:
fontFamily: {{ font_family }}
fontSize: 12px
fontWeight: "500"
lineHeight: 16px
rounded:
sm: 4px
DEFAULT: 8px
md: 12px
lg: 16px
xl: 24px
full: 9999px
spacing:
xs: 4px
sm: 8px
md: 16px
lg: 24px
xl: 40px
gutter: 16px
section: 32px
components:
button-primary:
backgroundColor: "{colors.primary}"
textColor: "{colors.on-primary}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
button-destructive:
backgroundColor: "{colors.destructive}"
textColor: "{colors.on-destructive}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
card-surface:
backgroundColor: "{colors.surface-container}"
rounded: "{rounded.lg}"
padding: "{spacing.lg}"
input-field:
backgroundColor: "{colors.surface-container-high}"
rounded: "{rounded.DEFAULT}"
padding: "{spacing.md}"
---

## Overview

[Describe the brand personality, product purpose, and style direction for
{{ app_name }}. What does this design system represent?]

For responsive and accessible usage patterns, see
[docs/design-culture/](docs/design-culture/).

## Colors

[Explain the palette rationale: why these colors, what roles they serve, how
light and dark modes differ. Reference WCAG contrast requirements for
on-X / X pairs.]

## Typography

[Describe the chosen font and why it fits the brand. List the scale levels and
their intended usage contexts (display, body, label).]

## Layout

[Describe the responsive grid: breakpoints, column model, gutter and section
spacing. Reference the wind-responsive doc for breakpoint-specific guidance.]

## Elevation & Depth

[Describe the elevation model: tonal backgrounds, shadows (if any), and how
depth signals hierarchy to the user.]

## Shapes

[Map corner-radius values to use cases: inputs, buttons, cards, dialogs,
badges.]

## Components

[List the key components and their token bindings. Variant matrices are visible
at `/preview` in debug builds. Run `design:lint` to validate token usage.]
Loading
Loading