docs(09-md3-components): create phase plan

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-01 09:14:15 +02:00
co-authored by Claude Opus 4.6
parent 80a26e395d
commit a6c2ec7292
4 changed files with 640 additions and 3 deletions
@@ -0,0 +1,272 @@
---
phase: 09-md3-components
plan: 03
type: execute
wave: 2
depends_on: ["09-01"]
files_modified:
- src/components/ui/FieldRenderer.tsx
- src/components/ui/PasswordField.tsx
- src/components/ui/BackendCard.tsx
- src/components/wizard/OutputBlock.tsx
- src/components/wizard/BackendSelectionStep.tsx
- src/components/wizard/RemoteConfigStep.tsx
- src/components/wizard/DeploymentStep.tsx
- src/components/wizard/ReviewStep.tsx
- src/index.css
autonomous: false
requirements: [COMP-01, COMP-02, COMP-03]
must_haves:
truths:
- "All text inputs in the wizard render with floating labels that animate on focus and when the field has content"
- "Next and Download All buttons use MD3 filled style (rounded-full, bg-primary)"
- "Back, Copy, and Download buttons use MD3 outlined style (rounded-full, border)"
- "BackendCard uses rounded-xl shape and shadow elevation"
- "OutputBlock pre blocks use rounded-xl and subtle shadow"
- "All existing tests pass with no regressions"
artifacts:
- path: "src/components/ui/FieldRenderer.tsx"
provides: "Text-branch using TextFieldMD3 component"
contains: "TextFieldMD3"
- path: "src/components/ui/PasswordField.tsx"
provides: "Password field using TextFieldMD3 layout"
contains: "TextFieldMD3"
- path: "src/components/ui/BackendCard.tsx"
provides: "MD3 elevation and shape"
contains: "rounded-xl"
- path: "src/components/wizard/BackendSelectionStep.tsx"
provides: "MD3 filled button for Next"
contains: "MD3_BTN_FILLED"
key_links:
- from: "src/components/ui/FieldRenderer.tsx"
to: "src/components/ui/TextFieldMD3.tsx"
via: "import and render TextFieldMD3"
pattern: "import.*TextFieldMD3"
- from: "src/components/wizard/BackendSelectionStep.tsx"
to: "src/styles/md3-buttons.ts"
via: "import button constants"
pattern: "import.*MD3_BTN"
- from: "src/components/wizard/ReviewStep.tsx"
to: "src/styles/md3-buttons.ts"
via: "import button constants"
pattern: "import.*MD3_BTN"
---
<objective>
Wire TextFieldMD3 into FieldRenderer and PasswordField, apply MD3 button styles across all wizard steps, and add MD3 elevation to BackendCard and OutputBlock.
Purpose: This is the integration plan that connects the primitives from Plan 01 into the actual wizard UI, completing COMP-01 (floating labels everywhere), COMP-02 (button hierarchy everywhere), and COMP-03 (elevation on cards and code blocks).
Output: All wizard components updated with MD3 styling.
</objective>
<execution_context>
@C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md
@C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/09-md3-components/09-RESEARCH.md
@.planning/phases/09-md3-components/09-01-SUMMARY.md
@src/components/ui/FieldRenderer.tsx
@src/components/ui/PasswordField.tsx
@src/components/ui/BackendCard.tsx
@src/components/wizard/OutputBlock.tsx
@src/components/wizard/BackendSelectionStep.tsx
@src/components/wizard/RemoteConfigStep.tsx
@src/components/wizard/DeploymentStep.tsx
@src/components/wizard/ReviewStep.tsx
<interfaces>
<!-- TextFieldMD3 and button constants created in Plan 01 -->
From src/components/ui/TextFieldMD3.tsx (created in 09-01):
```typescript
interface TextFieldMD3Props {
id: string;
label: string;
error?: FieldError;
registration: UseFormRegisterReturn;
type?: 'text' | 'password';
helpText?: string;
required?: boolean;
suffix?: React.ReactNode;
}
export function TextFieldMD3(props: TextFieldMD3Props): JSX.Element;
```
From src/styles/md3-buttons.ts (created in 09-01):
```typescript
export const MD3_BTN_FILLED: string; // filled primary action
export const MD3_BTN_OUTLINED: string; // outlined secondary action
export const MD3_BTN_TEXT: string; // text tertiary action
```
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: Integrate TextFieldMD3 into FieldRenderer and PasswordField</name>
<files>src/components/ui/FieldRenderer.tsx, src/components/ui/PasswordField.tsx</files>
<action>
**FieldRenderer.tsx — text branch (default, lines 82-119):**
Replace the entire text-branch return block with a `<TextFieldMD3>` render. Import TextFieldMD3 at top. The text branch currently renders label + input + helpText + error manually. Replace with:
```tsx
return (
<div className="flex flex-col gap-1">
{field.tooltipText && /* keep tooltip button + tooltip display exactly as-is */}
<TextFieldMD3
id={field.key}
label={field.label}
error={error}
registration={register(field.key)}
helpText={field.helpText}
required={field.required}
/>
</div>
);
```
CRITICAL: The tooltip button (lines 88-99) must remain OUTSIDE TextFieldMD3, rendered above it. TextFieldMD3 handles the label, input, helpText, and error display. The tooltip is a separate concern that stays in FieldRenderer.
Actually, re-examining the layout: the current text branch has tooltip button inline with label. Since TextFieldMD3 includes its own label (floating), the tooltip must be rendered separately. Place the tooltip button + tooltip content ABOVE the TextFieldMD3 component in the flex column. This preserves existing tooltip behavior.
Keep the select branch (lines 40-79) UNCHANGED — select fields do NOT get floating labels.
**PasswordField.tsx:**
Replace the manual label + input layout with TextFieldMD3, passing the show/hide toggle as `suffix`:
```tsx
import { TextFieldMD3 } from './TextFieldMD3';
export function PasswordField({ id, label, error, registration, helpText, tooltipText }: PasswordFieldProps) {
const [show, setShow] = useState(false);
const [showTooltip, setShowTooltip] = useState(false);
const toggleButton = (
<button type="button" onClick={() => setShow(v => !v)}
aria-label={show ? 'Hide' : 'Show'}
className="text-on-surface-container/50 hover:text-on-surface-container text-sm">
{show ? 'Hide' : 'Show'}
</button>
);
return (
<div className="flex flex-col gap-1">
{tooltipText && (
<button type="button" onClick={() => setShowTooltip(v => !v)}
aria-label={`More info about ${label}`}
className="text-primary hover:text-primary text-xs leading-none self-start">
</button>
)}
{tooltipText && showTooltip && (
<p className="text-xs text-primary bg-primary/10 border border-primary/30 rounded px-2 py-1.5">
{tooltipText}
</p>
)}
<TextFieldMD3
id={id}
label={label}
error={error}
registration={registration}
type={show ? 'text' : 'password'}
helpText={helpText}
suffix={toggleButton}
/>
</div>
);
}
```
Remove the `placeholder` prop from PasswordFieldProps interface since TextFieldMD3 uses `placeholder=" "` internally.
Run full test suite after — ALL `getByLabelText` queries must still work because TextFieldMD3 preserves htmlFor/id pairing.
</action>
<verify>
<automated>npx vitest run --reporter=dot</automated>
</verify>
<done>FieldRenderer text-branch renders TextFieldMD3 with floating label. PasswordField uses TextFieldMD3 with suffix for show/hide toggle. All existing tests pass (getByLabelText queries work). No regressions.</done>
</task>
<task type="auto">
<name>Task 2: Apply MD3 button styles and elevation across all wizard steps</name>
<files>src/components/wizard/BackendSelectionStep.tsx, src/components/wizard/RemoteConfigStep.tsx, src/components/wizard/DeploymentStep.tsx, src/components/wizard/ReviewStep.tsx, src/components/wizard/OutputBlock.tsx, src/components/ui/BackendCard.tsx, src/index.css</files>
<action>
**Button styling (COMP-02):** Import `{ MD3_BTN_FILLED, MD3_BTN_OUTLINED }` from `../../styles/md3-buttons` in each wizard step file. Apply className replacements:
BackendSelectionStep.tsx: "Next" button gets `className={MD3_BTN_FILLED}`. No Back button here.
RemoteConfigStep.tsx: "Back" button gets `className={MD3_BTN_OUTLINED}`, "Next" (submit) button gets `className={MD3_BTN_FILLED}`.
DeploymentStep.tsx: "Back" button gets `className={MD3_BTN_OUTLINED}`, "Next" button gets `className={MD3_BTN_FILLED}`.
ReviewStep.tsx: "Back" button gets `className={MD3_BTN_OUTLINED}`, "Download All (ZIP)" button gets `className={MD3_BTN_FILLED}`.
OutputBlock.tsx: "Copy" button gets `className={MD3_BTN_OUTLINED + ' text-xs !px-3 !py-1'}` (keep smaller size). "Download" button gets same. Import from `../../styles/md3-buttons`. Note: OutputBlock buttons are small utility buttons — keep `text-xs` and reduce padding with overrides. Alternatively, create a size-reduced variant inline: `className={\`\${MD3_BTN_OUTLINED} !text-xs !px-3 !py-1.5\`}`.
CRITICAL: Do NOT change button text content — only className. Tests use `getByRole('button', { name: /next/i })` etc.
**BackendCard elevation (COMP-03):**
Update BackendCard.tsx className:
- Change `rounded-lg` to `rounded-xl` (MD3 medium shape, 12px)
- Add `shadow hover:shadow-md` to unselected state
- Selected state: add `shadow-md`
- Add `transition-all` (already present — keep)
**OutputBlock elevation (COMP-03):**
Update OutputBlock.tsx `<pre>` className:
- Change `rounded` to `rounded-xl`
- Add `shadow-sm`
**Optional: Add elevation shadow token to index.css:**
If standard Tailwind `shadow` is insufficient, add to `@theme` block:
```css
--shadow-elevation-1: 0 1px 4px 0 rgb(0 0 0 / 0.37);
```
Only add this if the default `shadow` utility doesn't provide enough visual lift. Use your judgment.
Run full test suite after all changes.
</action>
<verify>
<automated>npx vitest run --reporter=dot</automated>
</verify>
<done>All Next/Download buttons use MD3 filled (rounded-full, bg-primary). All Back/Copy buttons use MD3 outlined (rounded-full, border). BackendCard has rounded-xl and shadow. OutputBlock pre has rounded-xl and shadow-sm. All tests pass.</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<name>Task 3: Visual verification of complete MD3 component set</name>
<what-built>Complete MD3 component migration: floating label text fields, MD3 button hierarchy (filled/outlined), card elevation, and rebuilt step indicator</what-built>
<how-to-verify>
1. Run `npm run dev` and open http://localhost:5173
2. **Step Indicator:** Verify numbered circles with connector lines at top. Step 1 should be highlighted, future steps muted.
3. **Backend Selection:** Click a backend card — verify rounded corners (rounded-xl) and shadow elevation. Verify "Next" button is pill-shaped (rounded-full) with primary fill color.
4. **Remote Config:** Verify text inputs have floating labels that animate up on focus and stay floated when field has value. Verify "Back" button is pill-shaped outlined, "Next" is pill-shaped filled.
5. **Password fields:** Verify floating label works with show/hide toggle button visible on right side.
6. **Deployment Step:** Verify Back/Next button styles match MD3 hierarchy.
7. **Review Step:** Verify "Back" is outlined, "Download All" is filled. Verify OutputBlock code areas have rounded corners and subtle shadow. Verify Copy/Download buttons are outlined style.
8. **Navigate back** to step 1 — verify step indicator shows checkmark on completed step, and the step is clickable.
9. **Toggle dark mode** — verify all new components look correct in dark theme (no hardcoded colors, shadows work).
</how-to-verify>
<resume-signal>Type "approved" or describe issues</resume-signal>
</task>
</tasks>
<verification>
- `npx vitest run` — full suite passes (166+ tests, zero regressions)
- All text inputs render floating labels
- Buttons follow MD3 filled/outlined/text hierarchy
- Cards and code blocks have MD3 elevation
- Dark mode renders correctly
</verification>
<success_criteria>
- COMP-01: All text inputs (FieldRenderer text-branch + PasswordField) render as MD3 outlined fields with floating labels
- COMP-02: Buttons across all wizard steps follow filled/outlined/text hierarchy
- COMP-03: BackendCard has rounded-xl + shadow, OutputBlock pre has rounded-xl + shadow-sm
- Zero test regressions
- User visually approves the complete MD3 component set
</success_criteria>
<output>
After completion, create `.planning/phases/09-md3-components/09-03-SUMMARY.md`
</output>