# 76 — Shadcn component implementation (Tiers 1–3) ## Goal Implement the three shadcn component adoption tiers that replace ad-hoc UI patterns across the app with shadcn/ui primitives. This is the **execution** phase — components are already installed (see `2026-06-13-shadcn-component-install.md`). | Tier | Name | Tasks | Files touched | | ---- | ------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------ | | 1 | Garden badges → Badge, topbar avatar → Avatar, + fallback, semantic token | 5 sub-tasks | topbar.tsx, sidebar.tsx, plant-detail.tsx, push-opt-in.tsx, care-schedule-editor.tsx, plant-widget.tsx | | 2 | Skeleton loading, Tabs nav, Sonner toasts, FieldGroup audit, Separator | 5 sub-tasks | d/[slug]/page.tsx, plant-detail.tsx, container-detail.tsx, layout.tsx, notify-channel-toggles.tsx | | 3 | Garden empty-state, Switch for notify channels | 2 sub-tasks | plant-list.tsx, container-list.tsx, notify-channel-toggles.tsx | ## Depends on - `2026-06-13-shadcn-component-install.md` — components are already in `src/components/ui/` - The shadcn migration map at `2026-06-13-shadcn-migration.md` ## Scope by tier ### Tier 1 (detailed brief: `docs/tasks/1a-badges-avatars.md`) **Task 1a — Garden health badges → ``** - File: `src/modules/garden/components/plant-detail.tsx` lines 44-48, 119-123 - Replace hand-crafted `badge-success/danger/warning` classes with shadcn `` - Delete the `healthBadgeClass()` helper function **Task 1b — Topbar avatar → ``** - File: `src/components/topbar.tsx` lines 60-75 - Replace manual `` with `` **Task 1c — HouseholdPill avatars → ``** - File: `src/components/sidebar.tsx` lines 106-120 - Replace inner span elements with Avatar components (keep avatarColor hash for fallback background) **Task 1d — Generic AvatarFallbackWithName component** - New file: `src/components/avatar-fallback.tsx` - Thin wrapper that handles the Image/Fallback pattern with name/initial logic - Imported by both topbar.tsx and sidebar.tsx to remove duplication **Task 1e — share-green → semantic token** - Files: push-opt-in.tsx (line ~104), care-schedule-editor.tsx (line ~185), plant-widget.tsx urgencyLabel, plus any other green-600/green-500 in garden components - Add `--c-success` CSS variable to the global theme - Replace all hardcoded green-600 references with `var(--c-success)` ### Tier 2 (detailed brief: `docs/tasks/1b-skeleton-tabs-toasts.md`) **Task 2a — Skeleton loading states** - d/[slug]/page.tsx inline animate-pulse → `` components - plant-detail.tsx & container-detail.tsx uploadingImage → skeleton overlay - Any other animate-pulse patterns outside skeleton.tsx itself **Task 2b — Settings/garden Tabs navigation → ``** - File: `src/modules/garden/components/plant-detail.tsx` lines 162-180 - File: `src/modules/garden/components/container-detail.tsx` lines 138-155 - Replace manual button-based tabs with shadcn Tabs/TabsList/TabsTrigger/TabsContent **Task 2c — Toast notifications via sonner** - Add `` to app layout (`src/app/layout.tsx`) - Convert delete confirmations, calendar schedule success/error, and share-link actions to `toast.success()`/`toast.error()` calls **Task 2d — Form FieldGroup audit** - Audit: container-form.tsx, plant-form.tsx, household edit forms - Check consistency of Label + Input + error pattern - Fix any non-shadcn form fields found **Task 2e — Manual separators → ``** - Remove border-bottom on garden detail tab bars, replace with shadcn Separator (usually alongside the Tabs component) ### Tier 3 (detailed brief: `docs/tasks/1c-emptystate-switch.md`) **Task 3a — Garden empty-state component** - File: `src/modules/garden/components/plant-list.tsx` line 22 → use EmptyState from ui/empty.tsx - File: `src/modules/garden/components/container-list.tsx` line 39 → use EmptyState - Use appropriate icons (Sprout for plants, Container for containers) **Task 3b — Notify channel toggles → ``** - File: `src/components/notify-channel-toggles.tsx` - Replace native `` with shadcn `` component - Keep server action integration (setNotifChannel) - Disabled state for ntfy when unconfigured ## Acceptance criteria (all tiers) 1. Zero `badge-success`, `badge-danger`, `badge-warning` class names remain in garden code 2. All avatars rendered via shadcn Avatar components (verified by DOM/JSX inspection) 3. All loading states use `` — no animate-pulse patterns outside skeleton.tsx 4. Garden detail pages use shadcn Tabs component (not manual buttons) 5. Toaster rendered in app layout, delete/cancel actions show toasts 6. EmptyState used in all garden list pages (no ad-hoc empty text paragraphs) 7. Notification channels use shadcn Switch components 8. `pnpm lint` passes with zero errors/warnings 9. `pnpm typecheck` passes with zero errors ## Execution order Execute tiers sequentially: 1 → 2 → 3. Each tier builds on the previous one's patterns and fixes foundational issues before adding polish. Detailed task briefs are in: - Tier 1: `docs/tasks/1a-badges-avatars.md` - Tier 2: `docs/tasks/1b-skeleton-tabs-toasts.md` - Tier 3: `docs/tasks/1c-emptystate-switch.md`