Two deliverables: the /plants catalog page (browse built-ins, manage custom plants) and the reusable PlantPicker component the plop editor (#15) opens when placing plants. The picker is the part that must be great on mobile — it's in the critical path of the core planting flow.
Scope
/plants page: list/grid showing icon, color swatch, name, category, spacing (unit-aware). Search by name + filter chips by category. Built-ins badged; "duplicate to customize" copies one into a pre-filled create form.
Create/edit form for custom plants: name, category select, spacing (unit-aware input), color picker, icon (plain text input accepting an emoji is fine for v1), days to maturity, notes. Delete with confirm; surface the backend's "in use" refusal nicely.
web/src/editor/PlantPicker.tsx (reusable): search-first list with icons/colors, recently-used section (localStorage), category filter; renders as popover (desktop) / bottom sheet (mobile); onSelect(plant) callback. Demo it on a hidden route or within /plants until #15 consumes it.
React-query hooks + zod schemas for the plants endpoints; cache shared with the editor's /full referenced-plants data (keep query keys sane).
Browse + search the seeded catalog; create a custom plant; duplicate a built-in and tweak spacing; delete an unused custom plant.
PlantPicker: type "gar" → garlic surfaces; select fires the callback; recent list updates; usable one-handed on a phone.
npx tsc --noEmit clean.
Part of epic #20 · Design: [DESIGN.md](https://gitea.stevedudenhoeffer.com/steve/pansy/src/branch/main/DESIGN.md)
## Context
Two deliverables: the `/plants` catalog page (browse built-ins, manage custom plants) and the reusable `PlantPicker` component the plop editor (#15) opens when placing plants. The picker is the part that must be great on mobile — it's in the critical path of the core planting flow.
## Scope
- [ ] `/plants` page: list/grid showing icon, color swatch, name, category, spacing (unit-aware). Search by name + filter chips by category. Built-ins badged; "duplicate to customize" copies one into a pre-filled create form.
- [ ] Create/edit form for custom plants: name, category select, spacing (unit-aware input), color picker, icon (plain text input accepting an emoji is fine for v1), days to maturity, notes. Delete with confirm; surface the backend's "in use" refusal nicely.
- [ ] `web/src/editor/PlantPicker.tsx` (reusable): search-first list with icons/colors, recently-used section (localStorage), category filter; renders as popover (desktop) / bottom sheet (mobile); `onSelect(plant)` callback. Demo it on a hidden route or within `/plants` until #15 consumes it.
- [ ] React-query hooks + zod schemas for the plants endpoints; cache shared with the editor's `/full` referenced-plants data (keep query keys sane).
## Out of scope
- Plop placement itself (#15). Custom emoji/SVG icon sets (post-v1).
## Key files & patterns
- API from #12. Form/list conventions established in #8.
## Dependencies
Blocked by #6 and #12.
## Acceptance criteria
- Browse + search the seeded catalog; create a custom plant; duplicate a built-in and tweak spacing; delete an unused custom plant.
- PlantPicker: type "gar" → garlic surfaces; select fires the callback; recent list updates; usable one-handed on a phone.
- `npx tsc --noEmit` clean.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Part of epic #20 · Design: DESIGN.md
Context
Two deliverables: the
/plantscatalog page (browse built-ins, manage custom plants) and the reusablePlantPickercomponent the plop editor (#15) opens when placing plants. The picker is the part that must be great on mobile — it's in the critical path of the core planting flow.Scope
/plantspage: list/grid showing icon, color swatch, name, category, spacing (unit-aware). Search by name + filter chips by category. Built-ins badged; "duplicate to customize" copies one into a pre-filled create form.web/src/editor/PlantPicker.tsx(reusable): search-first list with icons/colors, recently-used section (localStorage), category filter; renders as popover (desktop) / bottom sheet (mobile);onSelect(plant)callback. Demo it on a hidden route or within/plantsuntil #15 consumes it./fullreferenced-plants data (keep query keys sane).Out of scope
Key files & patterns
Dependencies
Blocked by #6 and #12.
Acceptance criteria
npx tsc --noEmitclean.