diff --git a/src/app/(dashboard)/suggestions/page.tsx b/src/app/(dashboard)/suggestions/page.tsx index a8522fa..81f5f66 100644 --- a/src/app/(dashboard)/suggestions/page.tsx +++ b/src/app/(dashboard)/suggestions/page.tsx @@ -9,5 +9,11 @@ export const dynamic = "force-dynamic"; export default async function SuggestionsPage() { const session = await getSession(); if (!session) redirect("/login"); - return ; + // The panel uses light-gray (neutral-*) text that assumes a white backdrop, so + // render it on a white card for readable contrast in light or dark theme. + return ( +
+ +
+ ); } diff --git a/src/components/layout/mobile-nav.tsx b/src/components/layout/mobile-nav.tsx new file mode 100644 index 0000000..9b5618f --- /dev/null +++ b/src/components/layout/mobile-nav.tsx @@ -0,0 +1,76 @@ +"use client"; + +import { useState, useEffect } from "react"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { Menu, X, Leaf } from "lucide-react"; +import { cn } from "@/lib/utils"; +import { navItems, settingsItems, isNavActive } from "./nav-items"; + +export function MobileNav() { + const [open, setOpen] = useState(false); + const path = usePathname(); + + useEffect(() => { setOpen(false); }, [path]); // close on navigation + useEffect(() => { + document.body.style.overflow = open ? "hidden" : ""; + return () => { document.body.style.overflow = ""; }; + }, [open]); + + const linkClass = (active: boolean, inactive: string) => + cn( + "flex items-center gap-2.5 px-3 py-2.5 rounded-md text-sm transition-colors", + active + ? "bg-[hsl(var(--canopy-accent))] text-[hsl(var(--canopy-accent-foreground))]" + : inactive, + ); + const MAIN_INACTIVE = "hover:bg-[hsl(var(--canopy-accent))] text-[hsl(var(--canopy-foreground))]/80"; + const SETTINGS_INACTIVE = "hover:bg-[hsl(var(--canopy-accent))] text-[hsl(var(--canopy-foreground))]/60"; + + return ( + <> + + + {open && ( +
+
setOpen(false)} /> + +
+ )} + + ); +} diff --git a/src/components/layout/nav-items.ts b/src/components/layout/nav-items.ts new file mode 100644 index 0000000..685bb46 --- /dev/null +++ b/src/components/layout/nav-items.ts @@ -0,0 +1,34 @@ +import { + LayoutDashboard, Leaf, BookOpen, Package, PawPrint, MapPin, Bell, + Lightbulb, KeyRound, HardDrive, RefreshCw, type LucideIcon, +} from "lucide-react"; + +export type NavItem = { label: string; href: string; icon: LucideIcon }; + +export const navItems: NavItem[] = [ + { label: "Dashboard", href: "/dashboard", icon: LayoutDashboard }, + { label: "Garden", href: "/garden", icon: Leaf }, + { label: "Plant types", href: "/garden/types", icon: BookOpen }, + { label: "Inventory", href: "/inventory", icon: Package }, + { label: "Animals", href: "/animals", icon: PawPrint }, + { label: "Locations", href: "/locations", icon: MapPin }, + { label: "Reminders", href: "/tasks", icon: Bell }, +]; + +export const settingsItems: NavItem[] = [ + { label: "Suggestions", href: "/suggestions", icon: Lightbulb }, + { label: "API tokens", href: "/settings/tokens", icon: KeyRound }, + { label: "Backup & Restore", href: "/settings/backup", icon: HardDrive }, + { label: "Updates", href: "/settings/updates", icon: RefreshCw }, +]; + +// Active on exact match or a sub-path, unless a more specific item (e.g. +// /garden/types) already claims the current path. +export function isNavActive(path: string, href: string, all: NavItem[]): boolean { + if (path === href) return true; + if (href === "/dashboard") return false; + if (!path.startsWith(href + "/")) return false; + return !all.some( + (o) => o.href.length > href.length && (path === o.href || path.startsWith(o.href + "/")), + ); +} diff --git a/src/components/layout/sidebar.tsx b/src/components/layout/sidebar.tsx index 737ce4e..0ae4704 100644 --- a/src/components/layout/sidebar.tsx +++ b/src/components/layout/sidebar.tsx @@ -2,28 +2,9 @@ import Link from "next/link"; import { usePathname } from "next/navigation"; -import { Leaf, Home, Wrench, LayoutDashboard, Bell, HardDrive, Lightbulb, RefreshCw, BookOpen, KeyRound, Package, PawPrint, MapPin } from "lucide-react"; +import { Leaf } from "lucide-react"; import { cn } from "@/lib/utils"; - -const navItems = [ - { label: "Dashboard", href: "/dashboard", icon: LayoutDashboard }, - { label: "Garden", href: "/garden", icon: Leaf }, - { label: "Plant types", href: "/garden/types", icon: BookOpen }, - { label: "Inventory", href: "/inventory", icon: Package }, - { label: "Animals", href: "/animals", icon: PawPrint }, - { label: "Locations", href: "/locations", icon: MapPin }, - { label: "Reminders", href: "/tasks", icon: Bell }, - // Home maintenance and Equipment come in future releases - // { label: "Home", href: "/home", icon: Home }, - // { label: "Equipment", href: "/equipment", icon: Wrench }, -]; - -const settingsItems = [ - { label: "Suggestions", href: "/suggestions", icon: Lightbulb }, - { label: "API tokens", href: "/settings/tokens", icon: KeyRound }, - { label: "Backup & Restore", href: "/settings/backup", icon: HardDrive }, - { label: "Updates", href: "/settings/updates", icon: RefreshCw }, -]; +import { navItems, settingsItems, isNavActive } from "./nav-items"; export function Sidebar() { const path = usePathname(); @@ -39,14 +20,7 @@ export function Sidebar() {