feat(layout): login, uygulama kabuğu, alt menü, hızlı ekle ve dashboard

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-05 01:35:10 +03:00
parent 4dbd2eb441
commit 1cf9fd9d8c
31 changed files with 1061 additions and 14 deletions
+80
View File
@@ -0,0 +1,80 @@
"use client";
import { Menu, Plus } from "lucide-react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useSidebar } from "@/components/ui/sidebar";
import { tr } from "@/i18n/tr";
import { cn } from "@/lib/utils";
import { BOTTOM_NAV, isActivePath, isAvailable, type NavItem } from "./nav-config";
import { useQuickAdd } from "./quick-add";
const itemClass =
"flex min-h-14 flex-1 flex-col items-center justify-center gap-0.5 text-[0.7rem] font-medium outline-none focus-visible:bg-muted";
function BottomNavLink({ item, pathname }: { item: NavItem; pathname: string }) {
const Icon = item.icon;
if (!isAvailable(item)) {
return (
<span
aria-disabled
className={cn(itemClass, "text-muted-foreground/50")}
title={tr.common.comingSoon}
>
<Icon className="size-5" />
{item.label}
</span>
);
}
const active = isActivePath(pathname, item.href);
return (
<Link
href={item.href}
aria-current={active ? "page" : undefined}
className={cn(itemClass, active ? "text-primary" : "text-muted-foreground")}
>
<Icon className="size-5" />
{item.label}
</Link>
);
}
/** Mobil alt gezinme çubuğu (md altı). */
export function BottomNav() {
const pathname = usePathname();
const { openQuickAdd } = useQuickAdd();
const { setOpenMobile } = useSidebar();
return (
<nav
aria-label={tr.nav.main}
className="fixed inset-x-0 bottom-0 z-40 border-t bg-background/95 pb-safe backdrop-blur supports-backdrop-filter:bg-background/80 md:hidden"
>
<div className="flex items-stretch">
{BOTTOM_NAV.left.map((item) => (
<BottomNavLink key={item.href} item={item} pathname={pathname} />
))}
<div className="flex flex-1 items-center justify-center">
<button
type="button"
onClick={openQuickAdd}
aria-label={tr.quickAdd.button}
className="-mt-5 flex size-14 items-center justify-center rounded-full bg-primary text-primary-foreground shadow-lg outline-none focus-visible:ring-4 focus-visible:ring-ring/50"
>
<Plus className="size-6" />
</button>
</div>
{BOTTOM_NAV.right.map((item) => (
<BottomNavLink key={item.href} item={item} pathname={pathname} />
))}
<button
type="button"
onClick={() => setOpenMobile(true)}
className={cn(itemClass, "text-muted-foreground")}
>
<Menu className="size-5" />
{tr.nav.more}
</button>
</div>
</nav>
);
}