feat: all project setup
This commit is contained in:
160
components/layout/app-sidebar.tsx
Normal file
160
components/layout/app-sidebar.tsx
Normal file
@@ -0,0 +1,160 @@
|
||||
"use client";
|
||||
|
||||
// ============================================================================
|
||||
// Application Sidebar
|
||||
// ============================================================================
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
BarChart3,
|
||||
Folder,
|
||||
LayoutDashboard,
|
||||
Megaphone,
|
||||
ShoppingCart,
|
||||
Target,
|
||||
TrendingUp,
|
||||
Settings2,
|
||||
ExternalLink,
|
||||
} from "lucide-react";
|
||||
|
||||
import { NavMain } from "@/components/nav-main";
|
||||
import { NavUser } from "@/components/nav-user";
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
SidebarHeader,
|
||||
SidebarRail,
|
||||
} from "@/components/ui/sidebar";
|
||||
import { useAuth } from "@/components/auth/auth-provider";
|
||||
|
||||
const data = {
|
||||
navMain: [
|
||||
{
|
||||
title: "Главная",
|
||||
url: "/",
|
||||
icon: LayoutDashboard,
|
||||
isActive: true,
|
||||
},
|
||||
{
|
||||
title: "Целевые каналы",
|
||||
url: "/channels",
|
||||
icon: Target,
|
||||
items: [
|
||||
{
|
||||
title: "Все каналы",
|
||||
url: "/channels",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Внешние каналы",
|
||||
url: "/external-channels",
|
||||
icon: ExternalLink,
|
||||
items: [
|
||||
{
|
||||
title: "Каталог",
|
||||
url: "/external-channels",
|
||||
},
|
||||
{
|
||||
title: "Импорт",
|
||||
url: "/external-channels/import",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Креативы",
|
||||
url: "/creatives",
|
||||
icon: Folder,
|
||||
items: [
|
||||
{
|
||||
title: "Все креативы",
|
||||
url: "/creatives",
|
||||
},
|
||||
{
|
||||
title: "Создать",
|
||||
url: "/creatives/new",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Закупы",
|
||||
url: "/purchases",
|
||||
icon: ShoppingCart,
|
||||
items: [
|
||||
{
|
||||
title: "Все закупы",
|
||||
url: "/purchases",
|
||||
},
|
||||
{
|
||||
title: "Создать",
|
||||
url: "/purchases/new",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Аналитика",
|
||||
url: "/analytics",
|
||||
icon: BarChart3,
|
||||
items: [
|
||||
{
|
||||
title: "Обзор",
|
||||
url: "/analytics",
|
||||
},
|
||||
{
|
||||
title: "Затраты",
|
||||
url: "/analytics/costs",
|
||||
},
|
||||
{
|
||||
title: "По каналам",
|
||||
url: "/analytics/channels",
|
||||
},
|
||||
{
|
||||
title: "По креативам",
|
||||
url: "/analytics/creatives",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
const { user } = useAuth();
|
||||
|
||||
return (
|
||||
<Sidebar collapsible="icon" {...props}>
|
||||
<SidebarHeader>
|
||||
<div className="flex items-center gap-2 px-2 py-2">
|
||||
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-primary text-primary-foreground">
|
||||
<Megaphone className="h-4 w-4" />
|
||||
</div>
|
||||
<div className="grid flex-1 text-left text-sm leading-tight">
|
||||
<span className="truncate font-semibold">TGEX</span>
|
||||
<span className="truncate text-xs text-muted-foreground">
|
||||
Управление закупками
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SidebarHeader>
|
||||
<SidebarContent>
|
||||
<NavMain items={data.navMain} />
|
||||
</SidebarContent>
|
||||
<SidebarFooter>
|
||||
{user && (
|
||||
<NavUser
|
||||
user={{
|
||||
name: `${user.first_name}${
|
||||
user.last_name ? " " + user.last_name : ""
|
||||
}`,
|
||||
email: user.username
|
||||
? `@${user.username}`
|
||||
: `ID: ${user.telegram_id}`,
|
||||
avatar: `https://ui-avatars.com/api/?name=${user.first_name}`,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</SidebarFooter>
|
||||
<SidebarRail />
|
||||
</Sidebar>
|
||||
);
|
||||
}
|
||||
61
components/layout/dashboard-header.tsx
Normal file
61
components/layout/dashboard-header.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
"use client";
|
||||
|
||||
// ============================================================================
|
||||
// Dashboard Header
|
||||
// ============================================================================
|
||||
|
||||
import { SidebarTrigger } from "@/components/ui/sidebar";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from "@/components/ui/breadcrumb";
|
||||
import { ThemeToggle } from "@/components/theme-toggle";
|
||||
import React from "react";
|
||||
|
||||
interface BreadcrumbItem {
|
||||
label: string;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
interface DashboardHeaderProps {
|
||||
breadcrumbs?: BreadcrumbItem[];
|
||||
}
|
||||
|
||||
export const DashboardHeader: React.FC<DashboardHeaderProps> = ({
|
||||
breadcrumbs = [],
|
||||
}) => {
|
||||
return (
|
||||
<header className="flex h-16 shrink-0 items-center gap-2 border-b px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
<Separator orientation="vertical" className="mr-2 h-4" />
|
||||
{breadcrumbs.length > 0 && (
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
{breadcrumbs.map((item, index) => (
|
||||
<React.Fragment key={index}>
|
||||
{index > 0 && <BreadcrumbSeparator />}
|
||||
<BreadcrumbItem>
|
||||
{item.href ? (
|
||||
<BreadcrumbLink href={item.href}>
|
||||
{item.label}
|
||||
</BreadcrumbLink>
|
||||
) : (
|
||||
<BreadcrumbPage>{item.label}</BreadcrumbPage>
|
||||
)}
|
||||
</BreadcrumbItem>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
)}
|
||||
<div className="ml-auto">
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user