Initial import of 1407 block sources under blocks/
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,511 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import {
|
||||
Activity,
|
||||
Calendar,
|
||||
Clapperboard,
|
||||
FileText,
|
||||
Handshake,
|
||||
Home,
|
||||
Images,
|
||||
Inbox,
|
||||
Kanban,
|
||||
LayoutDashboard,
|
||||
ListTodo,
|
||||
Receipt,
|
||||
Settings,
|
||||
Wallet,
|
||||
} from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
import {
|
||||
Drawer,
|
||||
DrawerContent,
|
||||
DrawerHeader,
|
||||
DrawerTitle,
|
||||
} from "@/components/ui/drawer";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarHeader,
|
||||
SidebarInset,
|
||||
SidebarMenu,
|
||||
SidebarMenuBadge,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarProvider,
|
||||
SidebarTrigger,
|
||||
useSidebar,
|
||||
} from "@/components/ui/sidebar";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type ModuleId =
|
||||
| "overview"
|
||||
| "sales"
|
||||
| "production"
|
||||
| "deliverables"
|
||||
| "finance";
|
||||
|
||||
type NavItem = {
|
||||
label: string;
|
||||
icon: React.ComponentType<React.SVGProps<SVGSVGElement>>;
|
||||
href: string;
|
||||
badge?: string;
|
||||
active?: boolean;
|
||||
};
|
||||
|
||||
type NavSection = {
|
||||
title?: string;
|
||||
items: NavItem[];
|
||||
};
|
||||
|
||||
type NavModule = {
|
||||
id: ModuleId;
|
||||
label: string;
|
||||
icon: NavItem["icon"];
|
||||
sections: NavSection[];
|
||||
};
|
||||
|
||||
const navModules: NavModule[] = [
|
||||
{
|
||||
id: "overview",
|
||||
label: "نمای کلی",
|
||||
icon: LayoutDashboard,
|
||||
sections: [
|
||||
{
|
||||
title: "نمای کلی",
|
||||
items: [
|
||||
{ label: "خانه", icon: Home, href: "#", active: true },
|
||||
{ label: "داشبورد", icon: Activity, href: "#" },
|
||||
{ label: "صندوق ورودی", icon: Inbox, href: "#", badge: "۳" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "وظایف",
|
||||
items: [
|
||||
{ label: "وظایف من", icon: ListTodo, href: "#", badge: "۵" },
|
||||
{ label: "تقویم", icon: Calendar, href: "#" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "sales",
|
||||
label: "فروش",
|
||||
icon: Handshake,
|
||||
sections: [
|
||||
{
|
||||
title: "قیف فروش",
|
||||
items: [
|
||||
{ label: "سرنخهای جدید", icon: Inbox, href: "#", active: true },
|
||||
{ label: "پیشفاکتورها", icon: FileText, href: "#" },
|
||||
{ label: "رزروها", icon: Calendar, href: "#" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "گزارشها",
|
||||
items: [{ label: "داشبورد فروش", icon: Activity, href: "#" }],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "production",
|
||||
label: "تولید",
|
||||
icon: Clapperboard,
|
||||
sections: [
|
||||
{
|
||||
title: "مسیر تولید",
|
||||
items: [
|
||||
{ label: "تخته فیلمبرداری", icon: Kanban, href: "#", active: true },
|
||||
{ label: "لیست شاتها", icon: ListTodo, href: "#" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "تیم",
|
||||
items: [{ label: "تخصیصها", icon: Inbox, href: "#" }],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "deliverables",
|
||||
label: "تحویلها",
|
||||
icon: Images,
|
||||
sections: [
|
||||
{
|
||||
title: "گالریها",
|
||||
items: [
|
||||
{ label: "همه گالریها", icon: Images, href: "#", active: true },
|
||||
{ label: "تأییدها", icon: Inbox, href: "#", badge: "۲" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "خروجیها",
|
||||
items: [{ label: "مرکز دانلود", icon: FileText, href: "#" }],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "finance",
|
||||
label: "مالی",
|
||||
icon: Wallet,
|
||||
sections: [
|
||||
{
|
||||
title: "صورتحساب",
|
||||
items: [
|
||||
{ label: "فاکتورها", icon: Receipt, href: "#", active: true },
|
||||
{ label: "پرداختها", icon: Wallet, href: "#" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "گزارشها",
|
||||
items: [{ label: "سود و زیان", icon: Activity, href: "#" }],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const utilities: NavItem[] = [{ label: "تنظیمات", icon: Settings, href: "#" }];
|
||||
|
||||
interface ModulePanelProps {
|
||||
className?: string;
|
||||
module: NavModule;
|
||||
}
|
||||
|
||||
function ModulePanel({ className, module }: ModulePanelProps) {
|
||||
return (
|
||||
<div className={cn("space-y-4 px-4 py-3 text-start text-sm", className)}>
|
||||
{module.sections.map((section, index) => (
|
||||
<div className="space-y-2" key={section.title ?? index}>
|
||||
{section.title && (
|
||||
<SidebarGroupLabel className="mb-1 text-xs font-medium tracking-wide text-muted-foreground">
|
||||
{section.title}
|
||||
</SidebarGroupLabel>
|
||||
)}
|
||||
<SidebarMenu>
|
||||
{section.items.map((item) => {
|
||||
const Icon = item.icon;
|
||||
return (
|
||||
<SidebarMenuItem
|
||||
key={item.label}
|
||||
className="text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<SidebarMenuButton
|
||||
asChild
|
||||
isActive={item.active}
|
||||
className="px-2"
|
||||
>
|
||||
<a href={item.href}>
|
||||
<Icon className="size-4" />
|
||||
{item.badge && (
|
||||
<SidebarMenuBadge>{item.badge}</SidebarMenuBadge>
|
||||
)}
|
||||
<span>{item.label}</span>
|
||||
</a>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
);
|
||||
})}
|
||||
</SidebarMenu>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className="border-t pt-3">
|
||||
<SidebarGroupLabel className="mb-2 text-xs font-medium tracking-wide text-muted-foreground">
|
||||
استودیو
|
||||
</SidebarGroupLabel>
|
||||
<SidebarMenu className="text-sm">
|
||||
{utilities.map((item) => {
|
||||
const Icon = item.icon;
|
||||
return (
|
||||
<SidebarMenuItem key={item.label}>
|
||||
<SidebarMenuButton
|
||||
asChild
|
||||
className="gap-2.5 px-2 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<a href={item.href}>
|
||||
<Icon className="size-4" />
|
||||
<span>{item.label}</span>
|
||||
</a>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
);
|
||||
})}
|
||||
</SidebarMenu>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface AppSidebarProps extends Omit<
|
||||
React.ComponentProps<typeof Sidebar>,
|
||||
"className"
|
||||
> {
|
||||
className?: string;
|
||||
activeKey: ModuleId;
|
||||
onNavChange: (key: ModuleId) => void;
|
||||
}
|
||||
|
||||
export function AppSidebar({
|
||||
className,
|
||||
activeKey,
|
||||
onNavChange,
|
||||
...props
|
||||
}: AppSidebarProps) {
|
||||
const { state, setOpen, isMobile } = useSidebar();
|
||||
const isCollapsed = state === "collapsed";
|
||||
const showFooter = isCollapsed || isMobile;
|
||||
|
||||
const activeModule =
|
||||
navModules.find((module) => module.id === activeKey) ?? navModules[0];
|
||||
const activeNavLabel = activeModule.label;
|
||||
|
||||
return (
|
||||
<Sidebar
|
||||
side="right"
|
||||
collapsible="icon"
|
||||
className={cn(
|
||||
"overflow-hidden *:data-[sidebar=sidebar]:flex-row",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<Sidebar
|
||||
collapsible="none"
|
||||
className="w-[calc(var(--sidebar-width-icon)+1px)]! border-e"
|
||||
>
|
||||
<SidebarHeader className="h-14 border-b">
|
||||
<SidebarMenu className="my-auto">
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton size="lg" asChild className="md:h-8 md:p-0">
|
||||
<a href="#">
|
||||
<div className="flex aspect-square size-8 items-center justify-center rounded-sm bg-primary">
|
||||
<img
|
||||
src="/block-media/shadcnblocks/block/logos/ShadcnBlocks-logo.svg"
|
||||
alt="شادسیان بلاکس"
|
||||
className="size-6 text-primary-foreground invert dark:invert-0"
|
||||
/>
|
||||
</div>
|
||||
<span className="text-lg font-semibold tracking-tighter">
|
||||
ری یو آی
|
||||
</span>
|
||||
</a>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarHeader>
|
||||
|
||||
<SidebarContent>
|
||||
<SidebarGroup>
|
||||
<SidebarGroupContent className="px-1.5 md:px-0">
|
||||
<SidebarMenu>
|
||||
{" "}
|
||||
<SidebarMenuItem>
|
||||
<motion.div
|
||||
key={isCollapsed ? "h-collapsed" : "h-expanded"}
|
||||
className={cn(
|
||||
isCollapsed
|
||||
? "hidden items-center justify-center sm:flex"
|
||||
: "hidden",
|
||||
)}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
>
|
||||
<SidebarTrigger />
|
||||
</motion.div>
|
||||
</SidebarMenuItem>
|
||||
{navModules.map((module) => {
|
||||
const Icon = module.icon;
|
||||
return (
|
||||
<SidebarMenuItem key={module.id}>
|
||||
<SidebarMenuButton
|
||||
tooltip={{
|
||||
children: module.label,
|
||||
hidden: isMobile,
|
||||
}}
|
||||
onClick={() => {
|
||||
onNavChange(module.id);
|
||||
setOpen(true);
|
||||
}}
|
||||
isActive={activeKey === module.id}
|
||||
aria-label={module.label}
|
||||
className="px-2.5 md:px-2"
|
||||
>
|
||||
<Icon className="size-4" />
|
||||
<span>{module.label}</span>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
);
|
||||
})}
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
|
||||
<SidebarFooter className={cn(showFooter ? "flex" : "hidden")}>
|
||||
<SidebarGroup className="p-0">
|
||||
<SidebarGroupContent className="px-1.5 md:px-0">
|
||||
<SidebarMenu>
|
||||
{utilities.map((item) => {
|
||||
const Icon = item.icon;
|
||||
return (
|
||||
<SidebarMenuItem key={item.label}>
|
||||
<SidebarMenuButton
|
||||
asChild
|
||||
tooltip={{
|
||||
children: item.label,
|
||||
hidden: isMobile,
|
||||
}}
|
||||
className="px-2.5 md:px-2"
|
||||
aria-label={item.label}
|
||||
>
|
||||
<a href={item.href}>
|
||||
<Icon className="size-4" />
|
||||
<span>{item.label}</span>
|
||||
</a>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
);
|
||||
})}
|
||||
</SidebarMenu>{" "}
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
</SidebarFooter>
|
||||
</Sidebar>
|
||||
|
||||
<Sidebar collapsible="none" className="hidden flex-1 md:flex">
|
||||
<SidebarHeader className="h-14 gap-3.5 border-b px-4">
|
||||
<div className="my-auto flex w-full items-center justify-between">
|
||||
<div className="text-start text-base font-medium text-foreground">
|
||||
{activeNavLabel}
|
||||
</div>
|
||||
<div className="hidden sm:block">
|
||||
<SidebarTrigger />
|
||||
</div>
|
||||
</div>
|
||||
</SidebarHeader>
|
||||
|
||||
<SidebarContent className="overflow-hidden">
|
||||
<ScrollArea className="min-h-0 flex-1">
|
||||
<SidebarGroup className="px-0">
|
||||
<SidebarGroupContent>
|
||||
<ModulePanel module={activeModule} />
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
</ScrollArea>
|
||||
</SidebarContent>
|
||||
</Sidebar>
|
||||
</Sidebar>
|
||||
);
|
||||
}
|
||||
|
||||
interface ApplicationShell6Props {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function ApplicationShell6({ className }: ApplicationShell6Props) {
|
||||
const [activeKey, setActiveKey] = React.useState<ModuleId>(navModules[0].id);
|
||||
const [isMobilePanelOpen, setIsMobilePanelOpen] = React.useState(false);
|
||||
|
||||
const activeModule =
|
||||
navModules.find((module) => module.id === activeKey) ?? navModules[0];
|
||||
const activeNavLabel = activeModule.label;
|
||||
|
||||
return (
|
||||
<SidebarProvider
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
style={
|
||||
{
|
||||
"--sidebar-width": "350px",
|
||||
} as React.CSSProperties
|
||||
}
|
||||
className={cn(className)}
|
||||
>
|
||||
<div className="hidden md:block">
|
||||
<AppSidebar activeKey={activeKey} onNavChange={setActiveKey} />
|
||||
</div>
|
||||
|
||||
<SidebarInset className="pb-20 md:pb-0">
|
||||
<div className="flex flex-1 flex-col gap-4">
|
||||
<div className="sticky top-0 z-40 flex h-14 items-center gap-2 border-b bg-background px-4 md:hidden">
|
||||
<SidebarTrigger />
|
||||
<Separator
|
||||
orientation="vertical"
|
||||
className="ms-2 data-[orientation=vertical]:h-4"
|
||||
/>
|
||||
<a href="#">
|
||||
<div className="flex aspect-square size-8 items-center justify-center rounded-sm bg-primary">
|
||||
<img
|
||||
src="/block-media/shadcnblocks/block/logos/ShadcnBlocks-logo.svg"
|
||||
alt="شادسیان بلاکس"
|
||||
className="size-6 text-primary-foreground invert dark:invert-0"
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
<div className="ms-auto text-sm font-medium text-muted-foreground">
|
||||
{activeNavLabel}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-1 flex-col gap-4 p-4">
|
||||
<div className="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min" />
|
||||
</div>
|
||||
</div>
|
||||
</SidebarInset>
|
||||
|
||||
<Drawer
|
||||
open={isMobilePanelOpen}
|
||||
onOpenChange={setIsMobilePanelOpen}
|
||||
dismissible
|
||||
>
|
||||
<DrawerContent dir="rtl" className="text-start md:hidden">
|
||||
<DrawerHeader>
|
||||
<DrawerTitle className="text-start">{activeNavLabel}</DrawerTitle>
|
||||
</DrawerHeader>
|
||||
<div className="pb-6">
|
||||
<ModulePanel module={activeModule} />
|
||||
</div>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
<nav
|
||||
aria-label="ناوبری پایین موبایل"
|
||||
className="fixed inset-x-0 bottom-0 z-40 border-t bg-background/95 backdrop-blur md:hidden"
|
||||
>
|
||||
<div className="grid grid-cols-5">
|
||||
{navModules.map((module) => {
|
||||
const Icon = module.icon;
|
||||
const isActive = module.id === activeKey;
|
||||
return (
|
||||
<button
|
||||
key={module.id}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setActiveKey(module.id);
|
||||
setIsMobilePanelOpen(true);
|
||||
}}
|
||||
className={`flex flex-col items-center justify-center py-3 text-xs ${
|
||||
isActive
|
||||
? "text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground"
|
||||
}`}
|
||||
aria-label={module.label}
|
||||
>
|
||||
<Icon className="h-5 w-5" />
|
||||
<span className="sr-only">{module.label}</span>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</nav>
|
||||
</SidebarProvider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user