v0.2.0 — Plant autocomplete + annual/perennial flower categories

This commit is contained in:
Bonna Moon
2026-06-15 17:07:26 -05:00
parent 78728963f4
commit 5938c6346e
7 changed files with 421 additions and 38 deletions

View File

@@ -1,6 +1,6 @@
"use client";
import { useState } from "react";
import { useState, useRef, useEffect } from "react";
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
@@ -17,8 +17,10 @@ import {
Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
} from "@/components/ui/select";
import { useToast } from "@/hooks/use-toast";
import { Plus } from "lucide-react";
import { Plus, Leaf } from "lucide-react";
import { CATEGORY_LABELS, CATEGORY_ORDER } from "@/lib/garden/categories";
import { searchPlants, type PlantSuggestion } from "@/lib/garden/plant-db";
import { cn } from "@/lib/utils";
const schema = z.object({
commonName: z.string().min(1, "Name is required"),
@@ -34,6 +36,10 @@ type FormValues = z.infer<typeof schema>;
export function AddPlantButton() {
const [open, setOpen] = useState(false);
const [suggestions, setSuggestions] = useState<PlantSuggestion[]>([]);
const [showSuggestions, setShowSuggestions] = useState(false);
const [category, setCategory] = useState<PlantCategory>("CANOPY_TREE");
const nameRef = useRef<HTMLInputElement>(null);
const router = useRouter();
const { toast } = useToast();
@@ -42,6 +48,23 @@ export function AddPlantButton() {
defaultValues: { category: "CANOPY_TREE" },
});
function onNameChange(value: string) {
form.setValue("commonName", value);
const results = searchPlants(value);
setSuggestions(results);
setShowSuggestions(results.length > 0);
}
function applySuggestion(suggestion: PlantSuggestion) {
form.setValue("commonName", suggestion.commonName);
if (suggestion.species) form.setValue("species", suggestion.species);
if (suggestion.notes && !form.getValues("notes")) form.setValue("notes", suggestion.notes);
form.setValue("category", suggestion.category);
setCategory(suggestion.category);
setSuggestions([]);
setShowSuggestions(false);
}
async function onSubmit(values: FormValues) {
const res = await fetch("/api/plants", {
method: "POST",
@@ -57,13 +80,21 @@ export function AddPlantButton() {
toast({ title: "Plant added!", description: `${values.commonName} is now in your food forest.` });
setOpen(false);
form.reset();
setCategory("CANOPY_TREE");
setSuggestions([]);
router.push(`/garden/${plant.id}`);
router.refresh();
}
function handleOpen() {
setOpen(true);
setSuggestions([]);
setShowSuggestions(false);
}
return (
<>
<Button onClick={() => setOpen(true)} size="sm">
<Button onClick={handleOpen} size="sm">
<Plus className="h-4 w-4 mr-1" />
Add plant
</Button>
@@ -76,12 +107,48 @@ export function AddPlantButton() {
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<div className="grid grid-cols-2 gap-3">
<div className="col-span-2 space-y-1.5">
<Label htmlFor="commonName">Common name *</Label>
<Input id="commonName" placeholder="Apple, Comfrey, Raspberry…" {...form.register("commonName")} />
{/* Name with autocomplete */}
<div className="col-span-2 space-y-1.5 relative">
<Label htmlFor="commonName">What plant is it? *</Label>
<Input
id="commonName"
ref={nameRef}
placeholder="Start typing — apple, comfrey, zinnia…"
value={form.watch("commonName") ?? ""}
onChange={(e) => onNameChange(e.target.value)}
onBlur={() => setTimeout(() => setShowSuggestions(false), 150)}
onFocus={() => suggestions.length > 0 && setShowSuggestions(true)}
autoComplete="off"
/>
{form.formState.errors.commonName && (
<p className="text-xs text-destructive">{form.formState.errors.commonName.message}</p>
)}
{/* Suggestion dropdown */}
{showSuggestions && (
<div className="absolute top-full left-0 right-0 z-50 mt-1 bg-popover border rounded-md shadow-lg overflow-hidden">
{suggestions.map((s) => (
<button
key={`${s.commonName}-${s.category}`}
type="button"
className="w-full flex items-center gap-3 px-3 py-2.5 text-left hover:bg-accent hover:text-accent-foreground transition-colors"
onMouseDown={() => applySuggestion(s)}
>
<Leaf className="h-3.5 w-3.5 shrink-0 text-[hsl(var(--leaf))] opacity-70" />
<div className="min-w-0">
<p className="text-sm font-medium">{s.commonName}</p>
{s.species && (
<p className="text-xs text-muted-foreground italic truncate">{s.species} · {CATEGORY_LABELS[s.category]}</p>
)}
</div>
</button>
))}
<div className="px-3 py-2 border-t text-xs text-muted-foreground">
Don&apos;t see it? Just type the name and fill in the rest yourself.
</div>
</div>
)}
</div>
<div className="space-y-1.5">
@@ -92,8 +159,12 @@ export function AddPlantButton() {
<div className="space-y-1.5">
<Label>Category *</Label>
<Select
defaultValue="CANOPY_TREE"
onValueChange={(v) => form.setValue("category", v as PlantCategory)}
value={category}
onValueChange={(v) => {
const c = v as PlantCategory;
form.setValue("category", c);
setCategory(c);
}}
>
<SelectTrigger>
<SelectValue />
@@ -107,7 +178,7 @@ export function AddPlantButton() {
</div>
<div className="col-span-2 space-y-1.5">
<Label htmlFor="species">Scientific name (optional)</Label>
<Label htmlFor="species">Scientific name <span className="text-muted-foreground font-normal">(filled in automatically if known)</span></Label>
<Input id="species" placeholder="Malus domestica" className="italic" {...form.register("species")} />
</div>
@@ -128,7 +199,7 @@ export function AddPlantButton() {
<div className="col-span-2 space-y-1.5">
<Label htmlFor="notes">Notes</Label>
<Textarea id="notes" placeholder="Any notes about this plant…" rows={3} {...form.register("notes")} />
<Textarea id="notes" placeholder="Anything worth remembering about this plant…" rows={3} {...form.register("notes")} />
</div>
</div>

View File

@@ -8,6 +8,14 @@ export type ChangelogEntry = {
};
export const CHANGELOG: ChangelogEntry[] = [
{
version: "0.2.0",
date: "2026-06-15",
changes: [
"Add plant: type a name and the app suggests the scientific name and category automatically from a built-in database of 150+ plants. You can accept, ignore, or change anything it fills in.",
"New plant categories: Annual flower (zinnias, marigolds, nasturtiums…), Perennial flower (coneflower, bee balm, black-eyed Susan…), and Annual vegetable (tomatoes, squash, beans…).",
],
},
{
version: "0.1.1",
date: "2026-06-15",

View File

@@ -1,18 +1,21 @@
import { PlantCategory, PlantLogType } from "@prisma/client";
export const CATEGORY_LABELS: Record<PlantCategory, string> = {
CANOPY_TREE: "Canopy tree",
UNDERSTORY_TREE: "Understory tree",
LARGE_SHRUB: "Large shrub",
SHRUB: "Shrub",
HERB: "Herb",
GROUNDCOVER: "Groundcover",
VINE: "Vine",
ANNUAL: "Annual",
PERENNIAL: "Perennial",
BULB: "Bulb",
MUSHROOM: "Mushroom",
OTHER: "Other",
CANOPY_TREE: "Canopy tree",
UNDERSTORY_TREE: "Understory tree",
LARGE_SHRUB: "Large shrub",
SHRUB: "Shrub",
HERB: "Herb",
GROUNDCOVER: "Groundcover",
VINE: "Vine",
ANNUAL_VEGETABLE: "Annual vegetable",
ANNUAL: "Annual vegetable",
ANNUAL_FLOWER: "Annual flower",
PERENNIAL: "Perennial",
PERENNIAL_FLOWER: "Perennial flower",
BULB: "Bulb",
MUSHROOM: "Mushroom",
OTHER: "Other",
};
export const CATEGORY_ORDER: PlantCategory[] = [
@@ -24,7 +27,9 @@ export const CATEGORY_ORDER: PlantCategory[] = [
"GROUNDCOVER",
"VINE",
"PERENNIAL",
"ANNUAL",
"PERENNIAL_FLOWER",
"ANNUAL_VEGETABLE",
"ANNUAL_FLOWER",
"BULB",
"MUSHROOM",
"OTHER",
@@ -32,18 +37,18 @@ export const CATEGORY_ORDER: PlantCategory[] = [
export const LOG_TYPE_LABELS: Record<PlantLogType, string> = {
OBSERVATION: "Observation",
CARE: "Care",
HARVEST: "Harvest",
TREATMENT: "Treatment",
TRANSPLANT: "Transplanted",
DIED: "Died / removed",
CARE: "Care",
HARVEST: "Harvest",
TREATMENT: "Treatment",
TRANSPLANT: "Transplanted",
DIED: "Died / removed",
};
export const LOG_TYPE_COLORS: Record<PlantLogType, string> = {
OBSERVATION: "text-blue-600 dark:text-blue-400",
CARE: "text-[hsl(var(--leaf))]",
HARVEST: "text-amber-600 dark:text-amber-400",
TREATMENT: "text-orange-600 dark:text-orange-400",
TRANSPLANT: "text-purple-600 dark:text-purple-400",
DIED: "text-destructive",
CARE: "text-[hsl(var(--leaf))]",
HARVEST: "text-amber-600 dark:text-amber-400",
TREATMENT: "text-orange-600 dark:text-orange-400",
TRANSPLANT: "text-purple-600 dark:text-purple-400",
DIED: "text-destructive",
};

292
src/lib/garden/plant-db.ts Normal file
View File

@@ -0,0 +1,292 @@
import { PlantCategory } from "@prisma/client";
export type PlantSuggestion = {
commonName: string;
species?: string;
category: PlantCategory;
notes?: string;
};
// Built-in plant database — searched when you type a plant name.
// Scientific names are the species-level name where possible.
// Variety is always left blank — the user fills that in themselves.
export const PLANT_DB: PlantSuggestion[] = [
// ---------------------------------------------------------------------------
// Canopy trees
// ---------------------------------------------------------------------------
{ commonName: "Apple", species: "Malus domestica", category: "CANOPY_TREE" },
{ commonName: "Pear", species: "Pyrus communis", category: "CANOPY_TREE" },
{ commonName: "Plum", species: "Prunus domestica", category: "CANOPY_TREE" },
{ commonName: "Sweet cherry", species: "Prunus avium", category: "CANOPY_TREE" },
{ commonName: "Walnut, black", species: "Juglans nigra", category: "CANOPY_TREE" },
{ commonName: "Walnut, English", species: "Juglans regia", category: "CANOPY_TREE" },
{ commonName: "Chestnut", species: "Castanea spp.", category: "CANOPY_TREE" },
{ commonName: "Hickory", species: "Carya spp.", category: "CANOPY_TREE" },
{ commonName: "Mulberry", species: "Morus spp.", category: "CANOPY_TREE" },
{ commonName: "Persimmon", species: "Diospyros virginiana", category: "CANOPY_TREE" },
{ commonName: "Pecan", species: "Carya illinoinensis", category: "CANOPY_TREE" },
{ commonName: "Quince", species: "Cydonia oblonga", category: "CANOPY_TREE" },
// ---------------------------------------------------------------------------
// Understory trees
// ---------------------------------------------------------------------------
{ commonName: "Sour cherry", species: "Prunus cerasus", category: "UNDERSTORY_TREE" },
{ commonName: "Peach", species: "Prunus persica", category: "UNDERSTORY_TREE" },
{ commonName: "Nectarine", species: "Prunus persica", category: "UNDERSTORY_TREE" },
{ commonName: "Apricot", species: "Prunus armeniaca", category: "UNDERSTORY_TREE" },
{ commonName: "Pawpaw", species: "Asimina triloba", category: "UNDERSTORY_TREE" },
{ commonName: "Serviceberry", species: "Amelanchier spp.", category: "UNDERSTORY_TREE" },
{ commonName: "Elderberry", species: "Sambucus nigra", category: "UNDERSTORY_TREE" },
{ commonName: "Crabapple", species: "Malus spp.", category: "UNDERSTORY_TREE" },
{ commonName: "Nanking cherry", species: "Prunus tomentosa", category: "UNDERSTORY_TREE" },
{ commonName: "Redbud", species: "Cercis canadensis", category: "UNDERSTORY_TREE" },
{ commonName: "Dogwood", species: "Cornus spp.", category: "UNDERSTORY_TREE" },
// ---------------------------------------------------------------------------
// Large shrubs
// ---------------------------------------------------------------------------
{ commonName: "Hazelnut", species: "Corylus americana", category: "LARGE_SHRUB" },
{ commonName: "Hazelnut, European", species: "Corylus avellana", category: "LARGE_SHRUB" },
{ commonName: "Arrowwood viburnum", species: "Viburnum dentatum", category: "LARGE_SHRUB" },
{ commonName: "Nannyberry", species: "Viburnum lentago", category: "LARGE_SHRUB" },
{ commonName: "Highbush cranberry", species: "Viburnum trilobum", category: "LARGE_SHRUB" },
{ commonName: "Lilac", species: "Syringa vulgaris", category: "LARGE_SHRUB" },
{ commonName: "Buttonbush", species: "Cephalanthus occidentalis", category: "LARGE_SHRUB" },
{ commonName: "Mock orange", species: "Philadelphus coronarius", category: "LARGE_SHRUB" },
// ---------------------------------------------------------------------------
// Shrubs / berries
// ---------------------------------------------------------------------------
{ commonName: "Raspberry", species: "Rubus idaeus", category: "SHRUB" },
{ commonName: "Blackberry", species: "Rubus allegheniensis", category: "SHRUB" },
{ commonName: "Blueberry", species: "Vaccinium corymbosum", category: "SHRUB" },
{ commonName: "Currant, black", species: "Ribes nigrum", category: "SHRUB" },
{ commonName: "Currant, red", species: "Ribes rubrum", category: "SHRUB" },
{ commonName: "Currant, white", species: "Ribes rubrum", category: "SHRUB" },
{ commonName: "Gooseberry", species: "Ribes uva-crispa", category: "SHRUB" },
{ commonName: "Aronia / Chokeberry", species: "Aronia melanocarpa", category: "SHRUB" },
{ commonName: "Rose", species: "Rosa spp.", category: "SHRUB" },
{ commonName: "Rugosa rose", species: "Rosa rugosa", category: "SHRUB" },
{ commonName: "Jostaberry", species: "Ribes × nidigrolaria", category: "SHRUB" },
{ commonName: "Goji berry", species: "Lycium barbarum", category: "SHRUB" },
// ---------------------------------------------------------------------------
// Herbs
// ---------------------------------------------------------------------------
{ commonName: "Comfrey", species: "Symphytum officinale", category: "HERB", notes: "Dynamic accumulator. Chop-and-drop around fruit trees." },
{ commonName: "Yarrow", species: "Achillea millefolium", category: "HERB" },
{ commonName: "Mint", species: "Mentha spp.", category: "HERB", notes: "Spreads aggressively — consider planting in containers." },
{ commonName: "Spearmint", species: "Mentha spicata", category: "HERB" },
{ commonName: "Peppermint", species: "Mentha × piperita", category: "HERB" },
{ commonName: "Chives", species: "Allium schoenoprasum", category: "HERB" },
{ commonName: "Garlic chives", species: "Allium tuberosum", category: "HERB" },
{ commonName: "Oregano", species: "Origanum vulgare", category: "HERB" },
{ commonName: "Thyme", species: "Thymus vulgaris", category: "HERB" },
{ commonName: "Sage", species: "Salvia officinalis", category: "HERB" },
{ commonName: "Rosemary", species: "Salvia rosmarinus", category: "HERB" },
{ commonName: "Lavender", species: "Lavandula angustifolia", category: "HERB" },
{ commonName: "Lemon balm", species: "Melissa officinalis", category: "HERB" },
{ commonName: "Fennel", species: "Foeniculum vulgare", category: "HERB" },
{ commonName: "Parsley", species: "Petroselinum crispum", category: "HERB" },
{ commonName: "Tarragon", species: "Artemisia dracunculus", category: "HERB" },
{ commonName: "Lovage", species: "Levisticum officinale", category: "HERB" },
{ commonName: "Hyssop", species: "Hyssopus officinalis", category: "HERB" },
{ commonName: "Catnip", species: "Nepeta cataria", category: "HERB" },
{ commonName: "Valerian", species: "Valeriana officinalis", category: "HERB" },
{ commonName: "St. John's wort", species: "Hypericum perforatum", category: "HERB" },
{ commonName: "Echinacea / Coneflower", species: "Echinacea purpurea", category: "HERB" },
// ---------------------------------------------------------------------------
// Groundcovers
// ---------------------------------------------------------------------------
{ commonName: "Strawberry", species: "Fragaria × ananassa", category: "GROUNDCOVER" },
{ commonName: "Wild strawberry", species: "Fragaria vesca", category: "GROUNDCOVER" },
{ commonName: "Creeping thyme", species: "Thymus serpyllum", category: "GROUNDCOVER" },
{ commonName: "White clover", species: "Trifolium repens", category: "GROUNDCOVER" },
{ commonName: "Sweet woodruff", species: "Galium odoratum", category: "GROUNDCOVER" },
{ commonName: "Ajuga / Bugleweed", species: "Ajuga reptans", category: "GROUNDCOVER" },
{ commonName: "Creeping Jenny", species: "Lysimachia nummularia", category: "GROUNDCOVER" },
{ commonName: "Mint (groundcover)", species: "Mentha spp.", category: "GROUNDCOVER" },
// ---------------------------------------------------------------------------
// Vines
// ---------------------------------------------------------------------------
{ commonName: "Grape", species: "Vitis spp.", category: "VINE" },
{ commonName: "Hops", species: "Humulus lupulus", category: "VINE" },
{ commonName: "Hardy kiwi", species: "Actinidia arguta", category: "VINE" },
{ commonName: "Kiwi, fuzzy", species: "Actinidia deliciosa", category: "VINE" },
{ commonName: "Climbing rose", species: "Rosa spp.", category: "VINE" },
{ commonName: "Clematis", species: "Clematis spp.", category: "VINE" },
{ commonName: "Wisteria", species: "Wisteria spp.", category: "VINE" },
{ commonName: "Trumpet vine", species: "Campsis radicans", category: "VINE" },
{ commonName: "Passionflower", species: "Passiflora incarnata", category: "VINE" },
{ commonName: "Honeysuckle", species: "Lonicera spp.", category: "VINE" },
// ---------------------------------------------------------------------------
// Perennial vegetables
// ---------------------------------------------------------------------------
{ commonName: "Asparagus", species: "Asparagus officinalis", category: "PERENNIAL" },
{ commonName: "Rhubarb", species: "Rheum rhabarbarum", category: "PERENNIAL" },
{ commonName: "Artichoke", species: "Cynara cardunculus", category: "PERENNIAL" },
{ commonName: "Horseradish", species: "Armoracia rusticana", category: "PERENNIAL" },
{ commonName: "Good King Henry", species: "Blitum bonus-henricus", category: "PERENNIAL" },
{ commonName: "Sorrel", species: "Rumex acetosa", category: "PERENNIAL" },
{ commonName: "Turkish rocket", species: "Bunias orientalis", category: "PERENNIAL" },
{ commonName: "Nine star broccoli", species: "Brassica oleracea", category: "PERENNIAL" },
// ---------------------------------------------------------------------------
// Perennial flowers
// ---------------------------------------------------------------------------
{ commonName: "Coneflower", species: "Echinacea purpurea", category: "PERENNIAL_FLOWER" },
{ commonName: "Black-eyed Susan", species: "Rudbeckia hirta", category: "PERENNIAL_FLOWER" },
{ commonName: "Bee balm", species: "Monarda didyma", category: "PERENNIAL_FLOWER" },
{ commonName: "Wild bergamot", species: "Monarda fistulosa", category: "PERENNIAL_FLOWER" },
{ commonName: "Peony", species: "Paeonia lactiflora", category: "PERENNIAL_FLOWER" },
{ commonName: "Hosta", species: "Hosta spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Daylily", species: "Hemerocallis spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Iris", species: "Iris spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Salvia, perennial", species: "Salvia nemorosa", category: "PERENNIAL_FLOWER" },
{ commonName: "Catmint", species: "Nepeta × faassenii", category: "PERENNIAL_FLOWER" },
{ commonName: "Astilbe", species: "Astilbe spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Coreopsis", species: "Coreopsis spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Lupine", species: "Lupinus spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Delphinium", species: "Delphinium spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Hollyhock", species: "Alcea rosea", category: "PERENNIAL_FLOWER" },
{ commonName: "Foxglove", species: "Digitalis purpurea", category: "PERENNIAL_FLOWER" },
{ commonName: "Phlox", species: "Phlox paniculata", category: "PERENNIAL_FLOWER" },
{ commonName: "Sedum / Stonecrop", species: "Sedum spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Russian sage", species: "Perovskia atriplicifolia", category: "PERENNIAL_FLOWER" },
{ commonName: "Goldenrod", species: "Solidago spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Joe Pye weed", species: "Eutrochium purpureum", category: "PERENNIAL_FLOWER" },
{ commonName: "Bleeding heart", species: "Lamprocapnos spectabilis", category: "PERENNIAL_FLOWER" },
{ commonName: "Columbine", species: "Aquilegia spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Coral bells", species: "Heuchera spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Liatris / Blazing star", species: "Liatris spicata", category: "PERENNIAL_FLOWER" },
{ commonName: "Milkweed", species: "Asclepias spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Butterfly weed", species: "Asclepias tuberosa", category: "PERENNIAL_FLOWER" },
{ commonName: "Monkshood", species: "Aconitum spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Prairie dropseed", species: "Sporobolus heterolepis", category: "PERENNIAL_FLOWER" },
{ commonName: "Coneflower, yellow", species: "Ratibida pinnata", category: "PERENNIAL_FLOWER" },
{ commonName: "False indigo", species: "Baptisia australis", category: "PERENNIAL_FLOWER" },
{ commonName: "Shasta daisy", species: "Leucanthemum × superbum", category: "PERENNIAL_FLOWER" },
{ commonName: "Spiderwort", species: "Tradescantia ohiensis", category: "PERENNIAL_FLOWER" },
{ commonName: "Tickseed", species: "Coreopsis tinctoria", category: "PERENNIAL_FLOWER" },
{ commonName: "Rose mallow", species: "Hibiscus moscheutos", category: "PERENNIAL_FLOWER" },
{ commonName: "Obedient plant", species: "Physostegia virginiana", category: "PERENNIAL_FLOWER" },
{ commonName: "Globe thistle", species: "Echinops spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Agastache", species: "Agastache spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Gaillardia / Blanket flower", species: "Gaillardia spp.", category: "PERENNIAL_FLOWER" },
{ commonName: "Veronicastrum", species: "Veronicastrum virginicum", category: "PERENNIAL_FLOWER" },
{ commonName: "Turtlehead", species: "Chelone glabra", category: "PERENNIAL_FLOWER" },
{ commonName: "Wild ginger", species: "Asarum canadense", category: "PERENNIAL_FLOWER" },
// ---------------------------------------------------------------------------
// Annual vegetables
// ---------------------------------------------------------------------------
{ commonName: "Tomato", species: "Solanum lycopersicum", category: "ANNUAL_VEGETABLE" },
{ commonName: "Pepper, sweet", species: "Capsicum annuum", category: "ANNUAL_VEGETABLE" },
{ commonName: "Pepper, hot", species: "Capsicum annuum", category: "ANNUAL_VEGETABLE" },
{ commonName: "Eggplant", species: "Solanum melongena", category: "ANNUAL_VEGETABLE" },
{ commonName: "Zucchini", species: "Cucurbita pepo", category: "ANNUAL_VEGETABLE" },
{ commonName: "Summer squash", species: "Cucurbita pepo", category: "ANNUAL_VEGETABLE" },
{ commonName: "Winter squash", species: "Cucurbita maxima", category: "ANNUAL_VEGETABLE" },
{ commonName: "Pumpkin", species: "Cucurbita pepo", category: "ANNUAL_VEGETABLE" },
{ commonName: "Cucumber", species: "Cucumis sativus", category: "ANNUAL_VEGETABLE" },
{ commonName: "Watermelon", species: "Citrullus lanatus", category: "ANNUAL_VEGETABLE" },
{ commonName: "Cantaloupe / Melon", species: "Cucumis melo", category: "ANNUAL_VEGETABLE" },
{ commonName: "Bean, green / snap", species: "Phaseolus vulgaris", category: "ANNUAL_VEGETABLE" },
{ commonName: "Bean, pole", species: "Phaseolus vulgaris", category: "ANNUAL_VEGETABLE" },
{ commonName: "Bean, dried", species: "Phaseolus vulgaris", category: "ANNUAL_VEGETABLE" },
{ commonName: "Pea", species: "Pisum sativum", category: "ANNUAL_VEGETABLE" },
{ commonName: "Pea, snow", species: "Pisum sativum", category: "ANNUAL_VEGETABLE" },
{ commonName: "Lettuce", species: "Lactuca sativa", category: "ANNUAL_VEGETABLE" },
{ commonName: "Spinach", species: "Spinacia oleracea", category: "ANNUAL_VEGETABLE" },
{ commonName: "Kale", species: "Brassica oleracea", category: "ANNUAL_VEGETABLE" },
{ commonName: "Swiss chard", species: "Beta vulgaris", category: "ANNUAL_VEGETABLE" },
{ commonName: "Beet", species: "Beta vulgaris", category: "ANNUAL_VEGETABLE" },
{ commonName: "Carrot", species: "Daucus carota", category: "ANNUAL_VEGETABLE" },
{ commonName: "Radish", species: "Raphanus sativus", category: "ANNUAL_VEGETABLE" },
{ commonName: "Turnip", species: "Brassica rapa", category: "ANNUAL_VEGETABLE" },
{ commonName: "Sweet corn", species: "Zea mays", category: "ANNUAL_VEGETABLE" },
{ commonName: "Sweet potato", species: "Ipomoea batatas", category: "ANNUAL_VEGETABLE" },
{ commonName: "Potato", species: "Solanum tuberosum", category: "ANNUAL_VEGETABLE" },
{ commonName: "Onion", species: "Allium cepa", category: "ANNUAL_VEGETABLE" },
{ commonName: "Leek", species: "Allium ampeloprasum", category: "ANNUAL_VEGETABLE" },
{ commonName: "Cabbage", species: "Brassica oleracea", category: "ANNUAL_VEGETABLE" },
{ commonName: "Broccoli", species: "Brassica oleracea", category: "ANNUAL_VEGETABLE" },
{ commonName: "Cauliflower", species: "Brassica oleracea", category: "ANNUAL_VEGETABLE" },
{ commonName: "Brussels sprouts", species: "Brassica oleracea", category: "ANNUAL_VEGETABLE" },
{ commonName: "Kohlrabi", species: "Brassica oleracea", category: "ANNUAL_VEGETABLE" },
{ commonName: "Arugula", species: "Eruca vesicaria", category: "ANNUAL_VEGETABLE" },
{ commonName: "Cilantro / Coriander", species: "Coriandrum sativum", category: "ANNUAL_VEGETABLE" },
{ commonName: "Dill", species: "Anethum graveolens", category: "ANNUAL_VEGETABLE" },
{ commonName: "Basil", species: "Ocimum basilicum", category: "ANNUAL_VEGETABLE" },
{ commonName: "Sunflower", species: "Helianthus annuus", category: "ANNUAL_VEGETABLE" },
{ commonName: "Okra", species: "Abelmoschus esculentus", category: "ANNUAL_VEGETABLE" },
// ---------------------------------------------------------------------------
// Annual flowers
// ---------------------------------------------------------------------------
{ commonName: "Zinnia", species: "Zinnia elegans", category: "ANNUAL_FLOWER" },
{ commonName: "Marigold", species: "Tagetes spp.", category: "ANNUAL_FLOWER" },
{ commonName: "Nasturtium", species: "Tropaeolum majus", category: "ANNUAL_FLOWER" },
{ commonName: "Calendula", species: "Calendula officinalis", category: "ANNUAL_FLOWER" },
{ commonName: "Cosmos", species: "Cosmos bipinnatus", category: "ANNUAL_FLOWER" },
{ commonName: "Bachelor's button", species: "Centaurea cyanus", category: "ANNUAL_FLOWER" },
{ commonName: "Sweet pea", species: "Lathyrus odoratus", category: "ANNUAL_FLOWER" },
{ commonName: "Larkspur", species: "Consolida ajacis", category: "ANNUAL_FLOWER" },
{ commonName: "Snapdragon", species: "Antirrhinum majus", category: "ANNUAL_FLOWER" },
{ commonName: "Cleome / Spider flower", species: "Cleome hassleriana", category: "ANNUAL_FLOWER" },
{ commonName: "Borage", species: "Borago officinalis", category: "ANNUAL_FLOWER" },
{ commonName: "Morning glory", species: "Ipomoea purpurea", category: "ANNUAL_FLOWER" },
{ commonName: "Petunia", species: "Petunia × atkinsiana", category: "ANNUAL_FLOWER" },
{ commonName: "Pansy", species: "Viola × wittrockiana", category: "ANNUAL_FLOWER" },
{ commonName: "Statice", species: "Limonium sinuatum", category: "ANNUAL_FLOWER" },
{ commonName: "Ammi / False Queen Anne's lace", species: "Ammi majus", category: "ANNUAL_FLOWER" },
{ commonName: "Celosia", species: "Celosia argentea", category: "ANNUAL_FLOWER" },
{ commonName: "Nigella / Love-in-a-mist", species: "Nigella damascena", category: "ANNUAL_FLOWER" },
{ commonName: "Chamomile, German", species: "Matricaria chamomilla", category: "ANNUAL_FLOWER" },
{ commonName: "Phacelia", species: "Phacelia tanacetifolia", category: "ANNUAL_FLOWER" },
{ commonName: "Scabiosa", species: "Scabiosa atropurpurea", category: "ANNUAL_FLOWER" },
{ commonName: "Lisianthus", species: "Eustoma grandiflorum", category: "ANNUAL_FLOWER" },
// ---------------------------------------------------------------------------
// Bulbs
// ---------------------------------------------------------------------------
{ commonName: "Garlic", species: "Allium sativum", category: "BULB" },
{ commonName: "Tulip", species: "Tulipa spp.", category: "BULB" },
{ commonName: "Daffodil", species: "Narcissus spp.", category: "BULB" },
{ commonName: "Crocus", species: "Crocus spp.", category: "BULB" },
{ commonName: "Allium, ornamental", species: "Allium spp.", category: "BULB" },
{ commonName: "Hyacinth", species: "Hyacinthus orientalis", category: "BULB" },
{ commonName: "Lily", species: "Lilium spp.", category: "BULB" },
{ commonName: "Dahlia", species: "Dahlia spp.", category: "BULB" },
{ commonName: "Gladiolus", species: "Gladiolus spp.", category: "BULB" },
{ commonName: "Camassia", species: "Camassia spp.", category: "BULB" },
{ commonName: "Fritillaria", species: "Fritillaria spp.", category: "BULB" },
{ commonName: "Scilla", species: "Scilla siberica", category: "BULB" },
// ---------------------------------------------------------------------------
// Mushrooms
// ---------------------------------------------------------------------------
{ commonName: "Shiitake", species: "Lentinula edodes", category: "MUSHROOM", notes: "Inoculated log. Likes oak, hornbeam, or ironwood logs." },
{ commonName: "Oyster mushroom", species: "Pleurotus ostreatus", category: "MUSHROOM" },
{ commonName: "Wine cap", species: "Stropharia rugosoannulata", category: "MUSHROOM", notes: "Wood chip bed. Great for the garden paths." },
{ commonName: "Lion's mane", species: "Hericium erinaceus", category: "MUSHROOM" },
];
// Search the database by common name (case-insensitive, partial match).
// Returns up to 8 results, sorted so exact starts-with matches come first.
export function searchPlants(query: string): PlantSuggestion[] {
if (!query || query.trim().length < 2) return [];
const q = query.toLowerCase().trim();
const results = PLANT_DB.filter((p) =>
p.commonName.toLowerCase().includes(q)
);
results.sort((a, b) => {
const aStarts = a.commonName.toLowerCase().startsWith(q) ? 0 : 1;
const bStarts = b.commonName.toLowerCase().startsWith(q) ? 0 : 1;
return aStarts - bStarts || a.commonName.localeCompare(b.commonName);
});
return results.slice(0, 8);
}

View File

@@ -1,2 +1,2 @@
// Bump on every user-visible release. Changelog entries live in `src/lib/changelog.ts`.
export const APP_VERSION = "0.1.1";
export const APP_VERSION = "0.2.0";