shadimage
Shadcnspace Builder
blockdashboard-shell-01source: ok · refreshed

Dashboard Shell 01

A modern dashboard shell with a sidebar and header, ideal for admin dashboards to organize and navigate through different sections.

npx shadcn add "https://builder.shadcnspace.com/r/dashboard-shell-01.json"
free

Where it goes

navbarsidebardashboard-shellkanban

Use cases

dashboard

Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.

Dependencies

Bundle weight · medium
iconslucide-react
chartsrecharts
animationmotion

Registry dependencies

sidebarscroll-areacardbuttonbadgechartcollapsibledropdown-menuseparatorcheckboxprogresstable

Files9 · source cached 10/2/2026, 1:27:05 AM

src/components/shadcn-space/blocks/dashboard-shell-01/page.tsx
import AppSidebar from "@/components/shadcn-space/blocks/dashboard-shell-01/app-sidebar"
import StatisticsBlock from "@/components/shadcn-space/blocks/dashboard-shell-01/statistics"
import SalesOverviewChart from "@/components/shadcn-space/blocks/dashboard-shell-01/sales-overview-chart"
import EarningReportChart from "@/components/shadcn-space/blocks/dashboard-shell-01/earning-report-chart"
import TopProductTable from "@/components/shadcn-space/blocks/dashboard-shell-01/top-product-table"
import SalesByCountryWidget from "@/components/shadcn-space/blocks/dashboard-shell-01/salesbycountrywidget"
export default function Page() {
    return (
        <AppSidebar>
            <div className="grid grid-cols-12 gap-6 p-6">
                <div className="col-span-12">
                    <StatisticsBlock />
                </div>
                <div className="xl:col-span-8 col-span-12">
                    <SalesOverviewChart />
                </div>
                <div className="xl:col-span-4 col-span-12">
                    <EarningReportChart />
                </div>
                <div className="xl:col-span-8 col-span-12">
                    <TopProductTable />
                </div>
                <div className="xl:col-span-4 col-span-12">
                    <SalesByCountryWidget />
                </div>
            </div>
        </AppSidebar>
    )
}
src/components/shadcn-space/blocks/dashboard-shell-01/salesbycountrywidget.tsx
'use client'

import React, { useRef } from 'react'
import { Separator } from '@/components/ui/separator'
import {
    DropdownMenu,
    DropdownMenuContent,
    DropdownMenuItem,
    DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { Icon } from '@iconify/react'
import { Card, CardTitle, CardHeader, CardContent, CardAction } from '@/components/ui/card'
import { motion, useInView } from 'motion/react'
import { cn } from '@/lib/utils'
import { Badge } from '@/components/ui/badge'

const DEFAULT_DROPDOWN_ITEMS = [
    { title: 'Action', link: '#' },
    { title: 'Another action', link: '#' },
    { title: 'Something else', link: '#' },
]

const DEFAULT_TRANS_DATA = [
    {
        img: 'https://images.shadcnspace.com/assets/flags/flag-us.svg',
        title: 'PayPal Transfer',
        country: 'United states',
        rank: '$8,567k',
        badgeData: "+4.7%",
        badgeBG: "bg-teal-400/10"
    },
    {
        img: 'https://images.shadcnspace.com/assets/flags/flag-brazil.svg',
        title: 'Wallet',
        country: 'Brazil',
        rank: '$2,415k',
        badgeData: "-1.7%",
        badgeBG: "bg-orange-400/10"
    },
    {
        img: 'https://images.shadcnspace.com/assets/flags/flag-india.svg',
        title: 'Credit Card',
        country: 'India',
        rank: '$865k',
        badgeData: "+4.7%",
        badgeBG: "bg-teal-400/10"
    },
    {
        img: 'https://images.shadcnspace.com/assets/flags/flag-australia.svg',
        title: 'Bank Transfer',
        country: 'Australia',
        rank: '$745k',
        badgeData: "-1.7%",
        badgeBG: "bg-orange-400/10"
    },
    {
        img: 'https://images.shadcnspace.com/assets/flags/flag-france.svg',
        title: 'Refund',
        country: 'France',
        rank: '$45',
        badgeData: "+4.7%",
        badgeBG: "bg-teal-400/10"
    },
    {
        img: 'https://images.shadcnspace.com/assets/flags/flag-china.svg',
        title: 'Refund',
        country: 'China',
        rank: '$12k',
        badgeData: "+4.7%",
        badgeBG: "bg-teal-400/10"
    },
]

interface TransactionProps {
    img: string
    title: string
    country: string
    rank: string
    badgeData: string
    badgeBG: string
}

interface DropdownItemProps {
    title: string
    link?: string
}

interface WidgetProps {
    recentTransData?: TransactionProps[]
    dropdownItems?: DropdownItemProps[]
}

const SalesByCountryWidget = ({
    recentTransData = DEFAULT_TRANS_DATA,
    dropdownItems = DEFAULT_DROPDOWN_ITEMS,
}: WidgetProps) => {
    const ref = useRef(null)
    const isInView = useInView(ref, { once: true, amount: 0.2 })

    return (
        <Card>
            <CardHeader className='flex items-center justify-between'>
                <CardTitle className='text-lg font-medium text-foreground'>
                    Sales by Countries
                </CardTitle>
                <CardAction>
                    <DropdownMenu>
                        <DropdownMenuTrigger className='outline-none'>
                            <span className='h-9 w-9 flex justify-center items-center rounded-full hover:bg-accent hover:text-accent-foreground cursor-pointer'>
                                <Icon icon="solar:menu-dots-bold" width={22} height={22} className='rotate-90' />
                            </span>
                        </DropdownMenuTrigger>
                        <DropdownMenuContent>
                            {dropdownItems.map((item, index) => (
                                <DropdownMenuItem key={index} className='font-normal cursor-pointer'>
                                    {item.link ? (
                                        <a href={item.link} className="w-full">
                                            {item.title}
                                        </a>
                                    ) : (
                                        <span className='w-full justify-start'>
                                            {item.title}
                                        </span>
                                    )}
                                </DropdownMenuItem>
                            ))}
                        </DropdownMenuContent>
                    </DropdownMenu>
                </CardAction>
            </CardHeader>
            <CardContent className='px-0'>
                <motion.div
                    ref={ref}
                    className='flex flex-col gap-3'
                    initial='hidden'
                    animate={isInView ? 'visible' : 'hidden'}
                    variants={{
                        visible: {
                            transition: {
                                staggerChildren: 0.1,
                                delayChildren: 0.2,
                            },
                        },
                    }}>
                    {recentTransData.map((item, index) => (
                        <React.Fragment key={index}>
                            <motion.div
                                className='flex gap-3 items-center px-6'
                                variants={{
                                    hidden: { opacity: 0, y: 20 },
                                    visible: { opacity: 1, y: 0 },
                                }}
                                transition={{
                                    type: 'spring',
                                    stiffness: 300,
                                    damping: 24,
                                }}
                                whileHover={{ scale: 1.02, x: 4 }}
                                whileTap={{ scale: 0.98 }}>
                                <motion.div
                                    className={cn(`w-8 h-8 rounded-full flex justify-center items-center overflow-hidden`)}
                                    whileHover={{ rotate: 5, scale: 1.1 }}
                                    transition={{ type: 'spring', stiffness: 400 }}>
                                    <img src={item.img} alt='icon' width={32} height={32} />
                                </motion.div>
                                <div className="flex items-center justify-between flex-1">
                                    <div>
                                        <h5 className='text-base font-medium text-foreground'>{item.rank}</h5>
                                        <p className='text-sm font-normal tracking-wide text-muted-foreground'>
                                            {item.country}
                                        </p>
                                    </div>
                                    <Badge className={cn(`${item.badgeBG}`, "text-muted-foreground")}>
                                        {item.badgeData}
                                    </Badge>
                                </div>
                            </motion.div>
                            {index < recentTransData.length - 1 && <Separator />}
                        </React.Fragment>
                    ))}
                </motion.div>
            </CardContent>
        </Card>
    )
}

export default SalesByCountryWidget
src/components/shadcn-space/blocks/dashboard-shell-01/site-header.tsx
import { SidebarTrigger } from "@/components/ui/sidebar"
import UserDropdown from "@/components/shadcn-space/blocks/dashboard-shell-01/user-dropdown";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import NotificationDropdown from "@/components/shadcn-space/blocks/dashboard-shell-01/notification-dropdown";
import { BellRing, SearchIcon } from "lucide-react";
import { InputGroup, InputGroupAddon, InputGroupInput } from "@/components/ui/input-group";

export function SiteHeader() {
  return (
    <div className="flex w-full items-center justify-between">
      <div className="flex items-center gap-2">
        <SidebarTrigger className="-ml-1" />
        <InputGroup>
          <InputGroupInput placeholder="Search" />
          <InputGroupAddon>
            <SearchIcon />
          </InputGroupAddon>
        </InputGroup>
      </div>
      <div className="flex items-center gap-3">
        <NotificationDropdown
          defaultOpen={false}
          align="center"
          trigger={
            <div className="rounded-full p-2 hover:bg-accent relative before:absolute before:bottom-0 before:left-1/2 before:z-10 before:w-2 before:h-2 before:rounded-full before:bg-red-500 before:top-1">
              <BellRing className="size-4" />
            </div>
          }
        />
        <UserDropdown
          defaultOpen={false}
          align="center"
          trigger={
            <div className="rounded-full">
              <Avatar className="size-8 cursor-pointer">
                <AvatarImage
                  src="https://images.shadcnspace.com/assets/profiles/user-11.jpg"
                  alt="David McMichael"
                />
                <AvatarFallback>DM</AvatarFallback>
              </Avatar>
            </div>
          }
        />
      </div>
    </div>
  )
}
src/components/shadcn-space/blocks/dashboard-shell-01/top-product-table.tsx
"use client";

import { LucideIcon, AppWindowMac, HandMetal, Megaphone, Contrast, Brush } from 'lucide-react';
import { FolderPlus, FolderPen, FolderMinus } from 'lucide-react';
import { EllipsisVertical } from "lucide-react";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Checkbox } from "@/components/ui/checkbox";
import { Progress } from "@/components/ui/progress";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { Card, CardHeader, CardTitle, CardContent, CardDescription } from "@/components/ui/card";
import { cn } from "@/lib/utils";

interface TableAction {
    icon: LucideIcon;
    listtitle: string;
}

interface ProjectData {
    project: string;
    date: string;
    budget: string;
    icon: LucideIcon;
    iconcolor: string;
    iconbg: string;
    avatar: string;
    name: string;
    handle: string;
    progress: number;
    progressColor: string;
}

const TopProductTable = () => {
    const tableActionData: TableAction[] = [
        { icon: FolderPlus, listtitle: "Add" },
        { icon: FolderPen, listtitle: "Edit" },
        { icon: FolderMinus, listtitle: "Delete" },
    ];

    const checkboxTableData: ProjectData[] = [
        {
            project: 'Web App Project',
            date: "04 June 2026",
            budget: '12,000',
            icon: AppWindowMac,
            iconcolor: 'text-orange-400',
            iconbg: 'bg-orange-400/20',
            avatar: "https://images.shadcnspace.com/assets/profiles/user-11.jpg",
            name: 'Olivia Rhye',
            handle: 'olivia@ui.com',
            progress: 60,
            progressColor: '**:data-[slot=progress-indicator]:bg-orange-400'
        },
        {
            project: 'MaterialM Admin',
            date: "09 January 2026",
            budget: '8000',
            icon: HandMetal,
            iconcolor: 'text-sky-400',
            iconbg: 'bg-sky-400/20',
            avatar: "https://images.shadcnspace.com/assets/profiles/user-8.jpg",
            name: 'Barbara Steele',
            handle: 'steele@ui.com',
            progress: 30,
            progressColor: '**:data-[slot=progress-indicator]:bg-blue-500'
        },
        {
            project: 'Digital Marketing',
            date: "15 April 2026",
            budget: '15,000',
            icon: Megaphone,
            iconcolor: 'text-teal-400',
            iconbg: 'bg-teal-400/20',
            avatar: "https://images.shadcnspace.com/assets/profiles/user-3.jpg",
            name: 'Leonard Gordon',
            handle: 'olivia@ui.com',
            progress: 45,
            progressColor: '**:data-[slot=progress-indicator]:bg-amber-300'
        },
        {
            project: 'Shadcn Space Design',
            date: "30 March 2026",
            budget: '1000',
            icon: Contrast,
            iconcolor: 'text-red-500',
            iconbg: 'bg-red-500/20',
            avatar: "https://images.shadcnspace.com/assets/profiles/user-4.jpg",
            name: 'Evelyn Pope',
            handle: 'steele@ui.com',
            progress: 37,
            progressColor: '**:data-[slot=progress-indicator]:bg-red-500'
        },
        {
            project: 'Graphic Design',
            date: "23 October 2026",
            budget: '7000',
            icon: Brush,
            iconcolor: 'text-blue-500',
            iconbg: 'bg-blue-500/20',
            avatar: "https://images.shadcnspace.com/assets/profiles/user-5.jpg",
            name: 'Tommy Garza',
            handle: 'olivia@ui.com',
            progress: 87,
            progressColor: '**:data-[slot=progress-indicator]:bg-teal-400'
        },
        {
            project: 'Digital Marketing',
            date: "15 April 2026",
            budget: '15,000',
            icon: Megaphone,
            iconcolor: 'text-teal-400',
            iconbg: 'bg-teal-400/20',
            avatar: "https://images.shadcnspace.com/assets/profiles/user-3.jpg",
            name: 'Leonard Gordon',
            handle: 'olivia@ui.com',
            progress: 45,
            progressColor: '**:data-[slot=progress-indicator]:bg-amber-300'
        },
    ];

    return (
        <Card className="w-full border-0 overflow-hidden pb-0 h-full">
            <CardHeader>
                <CardTitle>Top Projects</CardTitle>
                <CardDescription>Checkout the statistics of top projects</CardDescription>
            </CardHeader>
            <CardContent className="px-0">
                <div className="overflow-x-auto">
                    <Table className="min-w-2xl">
                        <TableHeader>
                            <TableRow className="hover:bg-transparent!">
                                <TableHead className="p-3 ps-6">#</TableHead>
                                <TableHead className="p-2">Project Name</TableHead>
                                <TableHead className="p-2">Budget</TableHead>
                                <TableHead className="p-2">Manager</TableHead>
                                <TableHead className="p-2">Progress</TableHead>
                                <TableHead className="p-3 pe-6 flex justify-end">Action</TableHead>
                            </TableRow>
                        </TableHeader>

                        <TableBody className="divide-y divide-border dark:divide-darkborder">
                            {checkboxTableData.map((item, index) => (
                                <TableRow key={index}>
                                    {/* Checkbox */}
                                    <TableCell className="whitespace-nowrap p-3 ps-6">
                                        <Checkbox className="data-[state=checked]:bg-blue-500 dark:data-[state=checked]:bg-blue-500 data-[state=checked]:border-blue-500 dark:data-[state=checked]:border-blue-500 cursor-pointer" />
                                    </TableCell>

                                    {/* project */}
                                    <TableCell className="whitespace-nowrap">
                                        <div className="flex items-center gap-2">
                                            <div className={cn("h-9 w-9 rounded-full flex items-center justify-center", item.iconbg)}>
                                                <item.icon width={18} height={18} className={cn(item.iconcolor)} />
                                            </div>
                                            <div className="">
                                                <h6 className="text-sm font-medium">{item.project}</h6>
                                                <p className="text-xs text-muted-foreground">{item.date}</p>
                                            </div>
                                        </div>
                                    </TableCell>

                                    {/* Status Badge */}
                                    <TableCell className="whitespace-nowrap">
                                        <p className="text-sm text-foreground">
                                            ${item.budget}
                                        </p>
                                    </TableCell>

                                    {/* Customer */}
                                    <TableCell className="whitespace-nowrap">
                                        <div className="flex gap-3 items-center">
                                            <img
                                                src={item.avatar}
                                                alt="icon"
                                                className="h-9 w-9 rounded-full"
                                                width={36}
                                                height={36}
                                            />
                                            <div className="truncate line-clamp-2 max-w-56">
                                                <h6 className="text-base! font-normal!">{item.name}</h6>
                                                <p className="text-sm text-muted-foreground">{item.handle}</p>
                                            </div>
                                        </div>
                                    </TableCell>

                                    {/* Progress */}
                                    <TableCell className="whitespace-nowrap">
                                        <Progress
                                            value={item.progress}
                                            className={cn("w-full h-1", `${item.progressColor}`)}
                                        />
                                    </TableCell>

                                    {/* Dropdown Menu */}
                                    <TableCell className="whitespace-nowrap p-3 pe-6">
                                        <div className="flex items-center justify-end">
                                            <DropdownMenu>
                                                <DropdownMenuTrigger>
                                                    <span className="flex justify-center items-center rounded-full p-2 hover:bg-muted cursor-pointer">
                                                        <EllipsisVertical width={16} height={16} />
                                                    </span>
                                                </DropdownMenuTrigger>

                                                <DropdownMenuContent align="end">
                                                    {tableActionData.map((action, idx) => (
                                                        <DropdownMenuItem key={idx} className="group flex gap-3 hover:bg-accent! cursor-pointer">
                                                            <action.icon />
                                                            <span>{action.listtitle}</span>
                                                        </DropdownMenuItem>
                                                    ))}
                                                </DropdownMenuContent>
                                            </DropdownMenu>
                                        </div>
                                    </TableCell>
                                </TableRow>
                            ))}
                        </TableBody>
                    </Table>
                </div>
            </CardContent>
        </Card>
    );
};

export default TopProductTable;
src/components/shadcn-space/blocks/dashboard-shell-01/statistics.tsx
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Separator } from "@/components/ui/separator";
import { ArrowRight, CalendarDays, Handbag, LucideIcon } from "lucide-react";
import { cn } from "@/lib/utils";

type DashboardMetric = {
  label: string;
  value: string;
  percentage: string;
  isPositive?: boolean;
};

type MainDashboardData = {
  title: string;
  description: string;
  metrics: DashboardMetric[];
};

type StatItem = {
  title: string;
  value: string;
  percentage: string;
  icon: LucideIcon;
  isPositive?: boolean;
};

type StatisticsBlockProps = {
  mainDashboard?: MainDashboardData;
  secondaryStats?: StatItem[];
};

const mainDashboardData: MainDashboardData = {
  title: "Analytics Dashboard",
  description: "Check all the statistics",
  metrics: [
    {
      label: "Earnings",
      value: "$27,850",
      percentage: "+18%",
      isPositive: true,
    },
    {
      label: "Expense",
      value: "$18,453",
      percentage: "-5%",
      isPositive: false,
    },
  ],
};

const secondaryStatsData: StatItem[] = [
  {
    title: "Weekly Sales",
    value: "$4,587",
    percentage: "+18%",
    icon: CalendarDays,
    isPositive: true,
  },
  {
    title: "Purchase Orders",
    value: "230",
    percentage: "+18%",
    icon: Handbag,
    isPositive: true,
  },
];

const StatisticsBlock = ({
  mainDashboard = mainDashboardData,
  secondaryStats = secondaryStatsData,
}: StatisticsBlockProps) => {
  return (
    <div className="grid grid-cols-12 gap-6 h-full">
      <div className="col-span-12 xl:col-span-6 h-full">
        <Card className="p-0 ring-0 border rounded-2xl relative h-full">
          <CardContent className="p-0">
            <div className="ps-6 py-4 flex flex-col gap-9 justify-between">
              <div>
                <p className="text-lg font-medium text-card-foreground">
                  {mainDashboard.title}
                </p>
                <p className="text-xs font-normal text-muted-foreground">
                  {mainDashboard.description}
                </p>
              </div>
              <div className="flex items-center gap-6">
                {mainDashboard.metrics.map((metric, index) => (
                  <div key={index} className="flex items-center gap-6">
                    <div>
                      <p className="text-xs font-normal text-muted-foreground">
                        {metric.label}
                      </p>
                      <div className="flex items-center gap-1">
                        <p className="text-2xl font-medium text-card-foreground">
                          {metric.value}
                        </p>
                        <Badge
                          className={cn(
                            "font-normal text-muted-foreground",
                            metric.isPositive
                              ? "bg-teal-400/10 "
                              : "bg-red-500/10"
                          )}
                        >
                          {metric.percentage}
                        </Badge>
                      </div>
                    </div>
                    {index < mainDashboard.metrics.length - 1 && (
                      <Separator
                        orientation="vertical"
                        className={"h-12"}
                      />
                    )}
                  </div>
                ))}
              </div>
            </div>
            {/* image */}
            <img
              src="https://images.shadcnspace.com/assets/backgrounds/stats-01.webp"
              alt="user-img"
              width={211}
              height={168}
              className="absolute bottom-0 right-0 hidden sm:block"
            />
          </CardContent>
        </Card>
      </div>
      {secondaryStats.map((stat, index) => (
        <div
          key={index}
          className="col-span-12 sm:col-span-6 xl:col-span-3"
        >
          <Card className="p-6 ring-0 border rounded-2xl">
            <CardContent className="p-0 flex items-start justify-between">
              <div className="flex flex-col gap-5 justify-between">
                <div className="flex flex-col gap-1">
                  <p className="text-lg font-medium text-card-foreground">
                    {stat.title}
                  </p>
                  <div className="flex items-center gap-2">
                    <p className="text-2xl font-medium text-card-foreground">
                      {stat.value}
                    </p>
                    <Badge
                      className={cn(
                        "font-normal text-muted-foreground",
                        stat.isPositive !== false
                          ? "bg-teal-400/10"
                          : "bg-red-500/10"
                      )}
                    >
                      {stat.percentage}
                    </Badge>
                  </div>
                </div>
                {/* button */}
                <Button
                  variant={"outline"}
                  className={"flex items-center gap-1.5 w-fit rounded-xl"}
                >
                  <span>See Report</span>
                  <ArrowRight size={16} />
                </Button>
              </div>
              <div className="p-3 rounded-full outline">
                <stat.icon size={16} />
              </div>
            </CardContent>
          </Card>
        </div>
      ))}
    </div>
  );
};

export default StatisticsBlock;
src/components/shadcn-space/blocks/dashboard-shell-01/sales-overview-chart.tsx
"use client";
import {
    Card,
    CardHeader,
    CardTitle,
    CardContent,
} from "@/components/ui/card";
import {
    ChartContainer,
    ChartTooltip,
    ChartTooltipContent,
    type ChartConfig,
} from "@/components/ui/chart"
import { Badge } from "@/components/ui/badge";
import { cn } from "@/lib/utils";
import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts"

const chartData = [
    { month: "Jan", expense: 31, profit: 31, earning: 31 },
    { month: "Feb", expense: 83, profit: 83, earning: 83 },
    { month: "Mar", expense: 53, profit: 53, earning: 53 },
    { month: "Apr", expense: 36, profit: 36, earning: 36 },
    { month: "May", expense: 64, profit: 64, earning: 64 },
    { month: "Jun", expense: 47, profit: 47, earning: 47 },
    { month: "Jul", expense: 95, profit: 95, earning: 95 },
    { month: "Aug", expense: 69, profit: 69, earning: 69 },
    { month: "Sep", expense: 29, profit: 29, earning: 29 },
    { month: "Oct", expense: 73, profit: 73, earning: 73 },
    { month: "Nov", expense: 27, profit: 27, earning: 27 },
    { month: "Dec", expense: 53, profit: 53, earning: 53 },
]

const chartConfig = {
    expense: {
        label: "Expense",
        color: "var(--color-blue-500)",
    },
    profit: {
        label: "Profit",
        color: "var(--color-sky-400)",
    },
    earning: {
        label: "Earning",
        color: "rgba(56, 189, 248, 0.5)",
    },
} satisfies ChartConfig

export default function SalesOverviewChart() {
    const Countries = [
        {
            id: 1,
            title: "Earning",
            color: "bg-sky-400/50",
        },
        {
            id: 2,
            title: "Profit",
            color: "bg-sky-400",
        },
        {
            id: 3,
            title: "Expense",
            color: "bg-blue-500",
        }
    ];

    return (
        <Card className="w-full">
            <CardHeader className="flex sm:flex-row flex-col justify-between sm:items-center items-start gap-3">
                <div className="flex flex-col gap-1">
                    <CardTitle className="text-lg font-medium">Sales Overview</CardTitle>
                    <div className="flex items-center gap-2">
                        <h3 className="text-3xl font-medium text-card-foreground">$386.53K</h3>
                        <Badge
                            className={cn(
                                "bg-teal-400/10 text-muted-foreground shadow-none"
                            )}
                        >
                            +18%
                        </Badge>
                        <span className="text-xs text-muted-foreground">
                            than last year
                        </span>
                    </div>
                </div>
                <div className="flex items-center gap-3">
                    {Countries.map((item) => (
                        <div key={item.id} className="flex items-center gap-2">
                            <span className={cn("w-2.5 h-2.5 rounded-full", item.color)} />
                            <p className="text-sm text-muted-foreground">{item.title}</p>
                        </div>
                    ))}
                </div>
            </CardHeader>
            <CardContent>
                <ChartContainer config={chartConfig} className="h-[300px] w-full">
                    <BarChart accessibilityLayer data={chartData}>
                        <CartesianGrid vertical={false} strokeDasharray="3 3" stroke="rgba(144, 164, 174, 0.3)" />
                        <XAxis
                            dataKey="month"
                            tickLine={false}
                            tickMargin={10}
                            axisLine={false}
                            tickFormatter={(value) => value.slice(0, 3)}
                            fontSize={12}
                        />
                        <YAxis
                            tickLine={false}
                            axisLine={false}
                            tickMargin={10}
                            fontSize={12}
                            tickFormatter={(value) => `${value / 10}k`}
                            domain={[0, 100]}
                            ticks={[0, 50, 100, 150, 200, 250, 300]}
                        />
                        <ChartTooltip content={<ChartTooltipContent />} />
                        <Bar
                            dataKey="expense"
                            stackId="a"
                            fill="var(--color-expense)"
                            radius={[0, 0, 4, 4]}
                            barSize={20}
                        />
                        <Bar
                            dataKey="profit"
                            stackId="a"
                            fill="var(--color-profit)"
                            radius={[0, 0, 0, 0]}
                            barSize={20}
                        />
                        <Bar
                            dataKey="earning"
                            stackId="a"
                            fill="var(--color-earning)"
                            radius={[4, 4, 0, 0]}
                            barSize={20}
                        />
                    </BarChart>
                </ChartContainer>
            </CardContent>
        </Card>
    );
}
src/components/shadcn-space/blocks/dashboard-shell-01/nav-main.tsx
"use client"

import { ChevronRight } from "lucide-react";
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "@/components/ui/collapsible";
import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubItem, SidebarMenuSubButton } from "@/components/ui/sidebar";
import { NavItem } from "@/components/shadcn-space/blocks/dashboard-shell-01/app-sidebar";
import { cn } from "@/lib/utils";
import { usePathname } from "next/navigation";

export function NavMain({ items }: { items: NavItem[] }) {
  const pathname = usePathname();
  // Recursive render function
  const renderItem = (item: NavItem) => {
    //  Section label
    if (item.isSection && item.label) {
      return (
        <SidebarGroup key={item.label} className="p-0 pt-5 first:pt-0">
          <SidebarGroupLabel className="p-0 text-xs font-medium uppercase text-sidebar-foreground">
            {item.label}
          </SidebarGroupLabel>
        </SidebarGroup>
      );
    }
    const hasChildren = !!item.children?.length;
    // Item with children → collapsible
    if (hasChildren && item.title) {
      return (
        <SidebarGroup key={item.title} className="p-0">
          <SidebarMenu>
            <Collapsible>
              <SidebarMenuItem>
                <CollapsibleTrigger
                  render={
                    <SidebarMenuButton
                      tooltip={item.title}
                      className="rounded-xl text-sm px-3 py-2 h-9"
                    >
                      {item.icon && <item.icon size={16} />}
                      <span>{item.title}</span>
                      <ChevronRight className="ml-auto transition-transform duration-200 collapsible/button-[aria-expanded='true']:rotate-90" />
                    </SidebarMenuButton>} className="w-full collapsible/button"
                />
                <CollapsibleContent>
                  <SidebarMenuSub className="me-0 pe-0">
                    {item.children!.map(renderItemSub)}
                  </SidebarMenuSub>
                </CollapsibleContent>
              </SidebarMenuItem>
            </Collapsible>
          </SidebarMenu>
        </SidebarGroup>
      );
    }
    // Item without children
    if (item.title) {
      return (
        <SidebarGroup key={item.title} className="p-0">
          <SidebarMenu>
            <SidebarMenuItem>
              <SidebarMenuButton
                tooltip={item.title}
                className={cn("rounded-lg text-sm px-3 py-2 h-9 ", pathname === item.href ? "bg-primary hover:bg-primary dark:bg-blue-500 text-white dark:hover:bg-blue-500 hover:text-white" : "")}
              >
                {item.icon && <item.icon />}
                <a href={item.href} className="w-full">
                  {item.title}
                </a>
              </SidebarMenuButton>
            </SidebarMenuItem>
          </SidebarMenu>
        </SidebarGroup>
      );
    }
    return null;
  };
  // Recursive render function for sub-items
  const renderItemSub = (item: NavItem) => {
    const hasChildren = !!item.children?.length;
    if (hasChildren && item.title) {
      return (
        <SidebarMenuSubItem key={item.title}>
          <Collapsible>
            <CollapsibleTrigger className="w-full">
              <SidebarMenuSubButton className="rounded-xl text-sm px-3 py-2 h-9">
                {item.icon && <item.icon />}
                <span>{item.title}</span>
                <ChevronRight className="ml-auto transition-transform duration-200 data-[state=open]:rotate-90" />
              </SidebarMenuSubButton>
            </CollapsibleTrigger>
            <CollapsibleContent>
              <SidebarMenuSub className="me-0 pe-0">
                {item.children!.map(renderItemSub)}
              </SidebarMenuSub>
            </CollapsibleContent>
          </Collapsible>
        </SidebarMenuSubItem>
      );
    }
    if (item.title) {
      return (
        <SidebarMenuSubItem key={item.title} className="w-full">
          <SidebarMenuSubButton
            className="w-full"
            render={<a href={item.href}>{item.title}</a>}
          />
        </SidebarMenuSubItem>
      );
    }
    return null;
  };

  return <>{items.map(renderItem)}</>;
}
src/components/shadcn-space/blocks/dashboard-shell-01/earning-report-chart.tsx
"use client";

import * as React from "react"
import { Label, Pie, PieChart } from "recharts"
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import {
    ChartConfig,
    ChartContainer,
    ChartTooltip,
    ChartTooltipContent,
} from "@/components/ui/chart"
import { cn } from "@/lib/utils";

const chartData = [
    { browser: "Website", visitors: 60, fill: "var(--color-blue-500)" },
    { browser: "Marketplace", visitors: 20, fill: "var(--color-sky-400)" },
    { browser: "Affiliate", visitors: 20, fill: "rgba(56, 189, 248, 0.5)" },
]

const chartConfig = {
    visitors: {
        label: "Visitors",
    },
    Website: {
        label: "Website",
        color: "var(--color-blue-500)",
    },
    Marketplace: {
        label: "Marketplace",
        color: "var(--color-sky-400)",
    },
    Affiliate: {
        label: "Affiliate",
        color: "var(--color-blue-500)",
    },
} satisfies ChartConfig

export default function EarningReportChart() {
    const totalVisitors = React.useMemo(() => {
        return chartData.reduce((acc, curr) => acc + curr.visitors, 0)
    }, [])

    const CustomerSegmentation = [
        {
            id: 1,
            customer: "Website ",
            tagColor: "muted-foreground",
            borderColor: "bg-blue-500",
            badgeColor: "bg-teal-400/10",
            earning: 18356,
            growthPercentage: "+4.7%",
        },
        {
            id: 2,
            customer: "Marketplace",
            tagColor: "muted-foreground",
            borderColor: "bg-sky-400",
            badgeColor: "bg-teal-400/10",
            earning: 4590,
            growthPercentage: "+2.1%",
        },
        {
            id: 3,
            customer: "Affiliate",
            tagColor: "muted-foreground",
            borderColor: "bg-sky-400/50",
            badgeColor: "bg-teal-400/10",
            earning: 4385,
            growthPercentage: "-1.7%",
        },
    ];

    return (
        <Card className="h-full w-full">
            <CardHeader>
                <CardTitle>
                    <h4 className="text-lg font-semibold">Earning Reports</h4>
                </CardTitle>
            </CardHeader>
            <CardContent className="flex flex-col justify-between gap-2 flex-1">
                <ChartContainer
                    config={chartConfig}
                    className="aspect-square max-h-[250px]"
                >
                    <PieChart>
                        <ChartTooltip
                            cursor={false}
                            content={<ChartTooltipContent hideLabel />}
                        />
                        <Pie
                            data={chartData}
                            dataKey="visitors"
                            nameKey="browser"
                            innerRadius={65}
                            strokeWidth={50}
                        >
                            <Label
                                content={({ viewBox }) => {
                                    if (viewBox && "cx" in viewBox && "cy" in viewBox) {
                                        return (
                                            <text
                                                x={viewBox.cx}
                                                y={viewBox.cy}
                                                textAnchor="middle"
                                                dominantBaseline="middle"
                                            >
                                                <tspan
                                                    x={viewBox.cx}
                                                    y={(viewBox.cy || 0) - 10}
                                                    className="fill-muted-foreground text-sm"
                                                >
                                                    Total
                                                </tspan>
                                                <tspan
                                                    x={viewBox.cx}
                                                    y={(viewBox.cy || 0) + 15}
                                                    className="fill-foreground text-xl font-medium"
                                                >
                                                    $27,850
                                                </tspan>
                                            </text>
                                        )
                                    }
                                }}
                            />
                        </Pie>
                    </PieChart>
                </ChartContainer>
                <div className="flex flex-col gap-3">
                    {CustomerSegmentation.map((item) => (
                        <div key={item.id} className="flex items-center justify-between">
                            <div className="flex items-center gap-2">
                                <div className={cn(item.borderColor, "w-1 h-4 rounded-full")}></div>
                                <h6 className={cn("text-sm font-medium leading-tight")}>
                                    {item.customer}
                                </h6>
                            </div>
                            <div className="flex items-center gap-1">
                                <h6 className="text-sm font-medium">${item.earning}</h6>
                                <Badge
                                    className={cn(
                                        item.badgeColor,
                                        `text-${item.tagColor}`,
                                        "shadow-none"
                                    )}
                                >
                                    {item.growthPercentage}
                                </Badge>
                            </div>
                        </div>
                    ))}
                </div>
            </CardContent>
        </Card>
    );
}

src/components/shadcn-space/blocks/dashboard-shell-01/app-sidebar.tsx
"use client";
import React from "react";
import { Sidebar, SidebarContent, SidebarHeader, SidebarMenu, SidebarMenuItem, SidebarProvider, SidebarTrigger, } from "@/components/ui/sidebar";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import Logo from "@/assets/logo/logo";
import { NavMain } from "@/components/shadcn-space/blocks/dashboard-shell-01/nav-main";
import { AlignStartVertical, ChartPie, CircleUserRound, ClipboardList, LucideIcon, Notebook, NotepadText, Table, TextInitial, Ticket, } from "lucide-react";
import { SiteHeader } from "@/components/shadcn-space/blocks/dashboard-shell-01/site-header";
import SimpleBar from "simplebar-react";
import 'simplebar-react/dist/simplebar.min.css'

export type NavItem = {
    label?: string;
    isSection?: boolean;
    title?: string;
    icon?: LucideIcon;
    href?: string;
    children?: NavItem[];
};

export const navData: NavItem[] = [
    // Dashboards Section
    { label: "Dashboards", isSection: true },
    { title: "Analytics", icon: ChartPie, href: "/block/dashboard-shell-01/preview" },
    { title: "CRM Dashboard", icon: ClipboardList, href: "#" },

    // Pages Section
    { label: "Pages", isSection: true },
    { title: "Tables", icon: Table, href: "#" },
    { title: "Forms", icon: ClipboardList, href: "#" },
    { title: "User Profile", icon: CircleUserRound, href: "#" },

    // Apps Section
    { label: "Apps", isSection: true },
    { title: "Notes", icon: Notebook, href: "#" },
    { title: "Tickets", icon: Ticket, href: "#" },
    {
        title: "Blogs",
        icon: TextInitial,
        children: [
            { title: "Blog Post", href: "#" },
            { title: "Blog Detail", href: "#" },
            { title: "Blog Edit", href: "#" },
            { title: "Blog Create", href: "#" },
            { title: "Manage Blogs", href: "#" },
        ],
    },

    // Form Elements Section
    { label: "Form Elements", isSection: true },
    {
        title: "Shadcn Forms",
        icon: NotepadText,
        children: [
            { title: "Button", href: "#" },
            { title: "Input", href: "#" },
            { title: "Select", href: "#" },
            { title: "Checkbox", href: "#" },
            { title: "Radio", href: "#" },
        ],
    },
    {
        title: "Form layouts",
        icon: AlignStartVertical,
        children: [
            { title: "Forms Horizontal", href: "#" },
            { title: "Forms Vertical", href: "#" },
            { title: "Forms Validation", href: "#" },
            { title: "Forms Examples", href: "#" },
            { title: "Forms Wizard", href: "#" },
        ],
    },
];

/* -------------------------------------------------------------------------- */
/*                                   Page                                     */
/* -------------------------------------------------------------------------- */

const AppSidebar = ({ children }: { children: React.ReactNode }) => {
    return (
        <SidebarProvider>
            <Sidebar className="py-4 px-0 bg-background">
                <div className="flex flex-col gap-6 bg-background">
                    {/* ---------------- Header ---------------- */}
                    <SidebarHeader className="py-0 px-4">
                        <SidebarMenu>
                            <SidebarMenuItem>
                                <a href="#" className="w-full h-full">
                                    <Logo />
                                </a>
                            </SidebarMenuItem>
                        </SidebarMenu>
                    </SidebarHeader>

                    {/* ---------------- Content ---------------- */}
                    <SidebarContent className="overflow-hidden gap-0">
                        <SimpleBar autoHide={true} className="h-[calc(100vh-348px)] border-b border-border">
                            <div className="px-4">
                                <NavMain items={navData} />
                            </div>
                        </SimpleBar>
                        {/* card */}
                        <div className="pt-4 px-4">
                            <Card className="shadow-none ring-0 bg-blue-500/10 px-4 py-6">
                                <CardContent className="p-0 flex flex-col gap-3 items-center">
                                    <img
                                        src="https://images.shadcnspace.com/assets/backgrounds/download-img.png"
                                        alt="sidebar-img"
                                        width={74}
                                        height={74}
                                        className="h-20 w-20"
                                    />
                                    <div className="flex flex-col gap-4 items-center">
                                        <div>
                                            <p className="text-base font-semibold text-card-foreground text-center">
                                                Grab Pro Now
                                            </p>
                                            <p className="text-sm font-regular text-muted-foreground text-center">
                                                Customize your admin
                                            </p>
                                        </div>
                                        <Button className="w-fit px-4 py-2 shadow-none cursor-pointer rounded-xl bg-blue-500 font-medium hover:bg-blue-500/80">
                                            Get Premium
                                        </Button>
                                    </div>
                                </CardContent>
                            </Card>
                        </div>
                    </SidebarContent>
                </div>
            </Sidebar>

            {/* ---------------- Main ---------------- */}
            <div className="flex flex-1 flex-col">
                <header className="sticky top-0 z-50 flex items-center border-b px-6 py-3 bg-background">
                    <SiteHeader />
                </header>
                <main className="flex-1">
                    {children}
                </main>
            </div>
        </SidebarProvider>
    );
};

export default AppSidebar;

More from Shadcnspace Builder

Browse all components in this library →