diff options
Diffstat (limited to 'app/src/components')
-rw-r--r-- | app/src/components/navbar.tsx | 100 | ||||
-rw-r--r-- | app/src/components/theme-provider.tsx | 9 | ||||
-rw-r--r-- | app/src/components/ui/theme-toggle.tsx | 61 |
3 files changed, 170 insertions, 0 deletions
diff --git a/app/src/components/navbar.tsx b/app/src/components/navbar.tsx new file mode 100644 index 0000000..37f1a5b --- /dev/null +++ b/app/src/components/navbar.tsx @@ -0,0 +1,100 @@ +"use client"; + +import Link from "next/link"; +import { useState } from "react"; +import { MapPin, Menu, X } from "lucide-react"; +import { SimpleThemeToggle } from "@/components/ui/theme-toggle"; +import { Button } from "@/components/ui/button"; + +export default function Navbar() { + const [isMenuOpen, setIsMenuOpen] = useState(false); + + const toggleMenu = () => { + setIsMenuOpen(!isMenuOpen); + }; + + return ( + <nav className="border-b bg-background"> + <div className="container mx-auto px-4 py-3"> + <div className="flex items-center justify-between"> + {/* Logo and Title */} + <Link href="/" className="flex items-center space-x-2"> + <MapPin className="h-6 w-6 text-primary" /> + <span className="text-lg font-bold">Location Tracker</span> + </Link> + + {/* Desktop Navigation */} + <div className="hidden md:flex items-center space-x-6"> + <Link + href="/map" + className="text-foreground/70 hover:text-foreground transition-colors" + > + Map + </Link> + <Link + href="/track" + className="text-foreground/70 hover:text-foreground transition-colors" + > + Track + </Link> + <Link + href="/share" + className="text-foreground/70 hover:text-foreground transition-colors" + > + Share + </Link> + <SimpleThemeToggle /> + </div> + + {/* Mobile Navigation Toggle */} + <div className="flex items-center md:hidden"> + <div className="mr-2"> + <SimpleThemeToggle /> + </div> + <Button + variant="ghost" + size="icon" + onClick={toggleMenu} + > + {isMenuOpen ? ( + <X className="h-5 w-5" /> + ) : ( + <Menu className="h-5 w-5" /> + )} + <span className="sr-only">Toggle menu</span> + </Button> + </div> + </div> + + {/* Mobile Navigation Menu */} + {isMenuOpen && ( + <div className="mt-2 py-2 border-t md:hidden"> + <div className="flex flex-col space-y-2"> + <Link + href="/map" + className="px-2 py-2 rounded-md hover:bg-accent transition-colors" + onClick={() => setIsMenuOpen(false)} + > + Map + </Link> + <Link + href="/track" + className="px-2 py-2 rounded-md hover:bg-accent transition-colors" + onClick={() => setIsMenuOpen(false)} + > + Track + </Link> + <Link + href="/share" + className="px-2 py-2 rounded-md hover:bg-accent transition-colors" + onClick={() => setIsMenuOpen(false)} + > + Share + </Link> + </div> + </div> + )} + </div> + </nav> + ); +}
\ No newline at end of file diff --git a/app/src/components/theme-provider.tsx b/app/src/components/theme-provider.tsx new file mode 100644 index 0000000..9fced93 --- /dev/null +++ b/app/src/components/theme-provider.tsx @@ -0,0 +1,9 @@ +"use client"; + +import * as React from "react"; +import { ThemeProvider as NextThemesProvider } from "next-themes"; +import { type ThemeProviderProps } from "next-themes/dist/types"; + +export function ThemeProvider({ children, ...props }: ThemeProviderProps) { + return <NextThemesProvider {...props}>{children}</NextThemesProvider>; +}
\ No newline at end of file diff --git a/app/src/components/ui/theme-toggle.tsx b/app/src/components/ui/theme-toggle.tsx new file mode 100644 index 0000000..fbf7448 --- /dev/null +++ b/app/src/components/ui/theme-toggle.tsx @@ -0,0 +1,61 @@ +"use client"; + +import * as React from "react"; +import { useTheme } from "next-themes"; +import { Moon, Sun } from "lucide-react"; + +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; + +export function ThemeToggle() { + const { setTheme, theme } = useTheme(); + + return ( + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button variant="outline" size="icon" className="rounded-full"> + <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" /> + <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" /> + <span className="sr-only">Toggle theme</span> + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent align="end"> + <DropdownMenuItem onClick={() => setTheme("light")}> + Light + </DropdownMenuItem> + <DropdownMenuItem onClick={() => setTheme("dark")}> + Dark + </DropdownMenuItem> + <DropdownMenuItem onClick={() => setTheme("system")}> + System + </DropdownMenuItem> + </DropdownMenuContent> + </DropdownMenu> + ); +} + +export function SimpleThemeToggle() { + const { setTheme, theme } = useTheme(); + + const toggleTheme = () => { + setTheme(theme === "dark" ? "light" : "dark"); + }; + + return ( + <Button + variant="ghost" + size="icon" + onClick={toggleTheme} + className="rounded-full h-9 w-9 relative" + aria-label="Toggle theme" + > + <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" /> + <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" /> + </Button> + ); +}
\ No newline at end of file |