aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/components')
-rw-r--r--app/src/components/navbar.tsx100
-rw-r--r--app/src/components/theme-provider.tsx9
-rw-r--r--app/src/components/ui/theme-toggle.tsx61
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