d2
uibento-01source: ok · hit
Bento 01
Bento grid for an education program platform with admin overview, faculty view and a program form.
npx shadcn add "https://ui.d2studio.dev/r/bento-01.json"free
Where it goes
dashboard-shellbento-grid
Visual style
bento
Use cases
dashboard
Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.
Dependencies
Bundle weight · mediumiconslucide-react
chartsrecharts
Registry dependencies
badgebuttoncardinputhttps://ui.aceternity.com/registry/dotted-glow-background.json
Files1 · source cached 10/15/2026, 8:05:39 AM
registry/default/ui/bento-01.tsx
"use client";
import {
ArrowUp,
BarChart3,
Building2,
Clock,
Command,
LayoutGrid,
Plus,
Settings,
Upload,
Users,
Zap,
} from "lucide-react";
import * as React from "react";
import { Area, AreaChart, ResponsiveContainer } from "recharts";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { DottedGlowBackground } from "@/components/ui/dotted-glow-background";
// --- Data ---
const enrollmentData = [
{ value: 400 },
{ value: 300 },
{ value: 500 },
{ value: 280 },
{ value: 590 },
{ value: 320 },
{ value: 480 },
{ value: 850 }, // Peak
{ value: 400 },
{ value: 300 },
{ value: 200 },
{ value: 350 },
{ value: 250 },
{ value: 300 },
];
// --- Sub-Components ---
function StatRow({
label,
value,
trend,
subLabel,
}: {
label: string;
value: string;
trend: string;
subLabel?: string;
}) {
return (
<div className="flex items-center justify-between py-3 border-b border-gray-100 last:border-0">
<div>
<div className="text-2xl font-bold text-gray-900">{value}</div>
<div className="text-xs text-gray-500 font-medium mt-0.5">{label}</div>
</div>
<div className="flex items-center gap-1 text-xs font-bold text-green-600 bg-green-50 px-2 py-1 rounded-full">
<ArrowUp className="h-3 w-3" />
{trend}
</div>
</div>
);
}
function GlassIcon({
icon: Icon,
}: {
icon: React.ComponentType<{ className?: string }>;
}) {
return (
<div className="flex h-12 w-12 items-center justify-center rounded-xl bg-white shadow-[0_2px_8px_rgba(0,0,0,0.08)] border border-gray-100 hover:scale-105 transition-transform cursor-default">
<Icon className="h-5 w-5 text-gray-600" />
</div>
);
}
function BentoSkeleton() {
return (
<div className="max-w-7xl w-full grid grid-cols-1 sm:grid-cols-12 gap-6 animate-pulse">
{/* Card 1 Skeleton */}
<div className="sm:col-span-6 lg:col-span-4 bg-gray-100 rounded-3xl h-[300px] p-6 flex flex-col">
<div className="h-6 w-32 bg-gray-200 rounded mb-2" />
<div className="h-4 w-48 bg-gray-200 rounded mb-6" />
<div className="flex flex-col sm:flex-row gap-4 flex-1">
<div className="flex-1 bg-white/50 rounded-2xl" />
<div className="h-24 sm:h-auto sm:w-32 bg-white/50 rounded-2xl" />
</div>
</div>
{/* Card 2 Skeleton */}
<div className="sm:col-span-6 lg:col-span-4 bg-gray-100 rounded-3xl h-[300px] p-6 flex flex-col">
<div className="flex-1 grid grid-cols-4 gap-3 place-content-center">
{[...Array(8)].map((_, i) => (
<div key={i} className="h-12 w-12 bg-white/50 rounded-xl mx-auto" />
))}
</div>
<div className="h-6 w-48 bg-gray-200 rounded mt-4 mb-2" />
<div className="h-4 w-full bg-gray-200 rounded" />
</div>
{/* Card 3 Skeleton */}
<div className="sm:col-span-12 lg:col-span-4 bg-gray-100 rounded-3xl h-[300px] p-6 flex flex-col">
<div className="flex-1 flex items-center justify-center">
<div className="h-10 w-full max-w-[200px] bg-white/50 rounded-full" />
</div>
<div className="h-6 w-40 bg-gray-200 rounded mt-4 mb-2" />
<div className="h-4 w-full bg-gray-200 rounded" />
</div>
{/* Card 4 Skeleton */}
<div className="sm:col-span-12 lg:col-span-6 bg-gray-100 rounded-3xl h-[300px] p-6 flex flex-col">
<div className="h-6 w-32 bg-gray-200 rounded mb-2" />
<div className="h-4 w-48 bg-gray-200 rounded mb-6" />
<div className="flex flex-col sm:flex-row gap-4 flex-1">
<div className="flex-1 bg-white/50 rounded-xl" />
<div className="h-24 sm:h-auto sm:w-48 bg-white/50 rounded-xl" />
</div>
</div>
{/* Card 5 Skeleton */}
<div className="sm:col-span-12 lg:col-span-6 bg-gray-100 rounded-3xl h-[300px] p-6 flex flex-col">
<div className="h-6 w-32 bg-gray-200 rounded mb-2" />
<div className="h-4 w-48 bg-gray-200 rounded mb-6" />
<div className="flex flex-col sm:flex-row gap-4 flex-1">
<div className="h-24 sm:h-auto sm:w-48 bg-white/50 rounded-xl" />
<div className="flex-1 bg-white/50 rounded-xl" />
</div>
</div>
</div>
);
}
// --- Main Component ---
const Bento01 = () => {
const [isLoading, setIsLoading] = React.useState(true);
React.useEffect(() => {
const timer = setTimeout(() => {
setIsLoading(false);
}, 2000); // Simulate loading
return () => clearTimeout(timer);
}, []);
return (
<div className="min-h-screen bg-white text-gray-900 font-sans p-6 sm:p-8 md:p-16 flex flex-col items-center">
{/* Header */}
<div className="max-w-5xl w-full mb-8 sm:mb-12 animate-in fade-in slide-in-from-bottom-4 duration-700">
<h1 className="text-3xl sm:text-4xl md:text-5xl font-bold tracking-tight text-gray-900 mb-4">
Everything You Need for{" "}
<span className="block sm:inline">Professional Growth</span>
</h1>
<p className="text-gray-500 max-w-2xl text-base sm:text-lg leading-relaxed">
From interactive workshop to certification programs, our platforms
provides comprehensive tools for faculty development and institutional
growth.
</p>
</div>
{isLoading ? (
<BentoSkeleton />
) : (
/* Bento Grid */
<div className="max-w-7xl w-full grid grid-cols-1 sm:grid-cols-12 gap-4 sm:gap-6">
{/* Card 1: Admin Overview — sm:6 / lg:4 */}
<Card className="sm:col-span-6 lg:col-span-4 bg-gray-50/50 border-gray-100 shadow-none rounded-3xl overflow-hidden animate-in fade-in slide-in-from-bottom-8 duration-700 fill-mode-both">
<CardContent className="p-5 sm:p-6 h-full flex flex-col">
<div className="mb-4 sm:mb-6">
<h3 className="font-semibold text-gray-900">Admin Overview</h3>
<p className="text-sm text-gray-500">
Monitor platform health and revenue.
</p>
</div>
{/* Stack vertically on mobile, side-by-side on sm+ */}
<div className="flex flex-col sm:flex-row gap-4 flex-1">
{/* Stats Column */}
<div className="flex-1 bg-white rounded-2xl p-4 shadow-sm border border-gray-100 flex flex-col justify-center">
<StatRow label="Active Programs" value="42" trend="8%" />
<StatRow label="Enrollments" value="3,214" trend="12%" />
<StatRow label="Enrollments" value="₹8.6L" trend="5%" />
</div>
{/* Chart Column — full width on mobile, fixed on sm+ */}
<div className="sm:w-32 bg-white rounded-2xl p-4 shadow-sm border border-gray-100 flex flex-row sm:flex-col justify-between sm:justify-between gap-4 sm:gap-0">
<div>
<div className="text-[10px] font-semibold text-gray-900">
Enrollment Trend
</div>
<div className="text-[9px] text-gray-400">Last 14 days</div>
<div className="text-xl font-bold text-gray-900 mt-1 sm:mt-2">
1,521
</div>
</div>
<div className="h-16 flex-1 sm:flex-none sm:w-full mt-0 sm:mt-2">
<ResponsiveContainer width="100%" height="100%">
<AreaChart data={enrollmentData}>
<defs>
<linearGradient
id="colorGradient"
x1="0"
y1="0"
x2="0"
y2="1"
>
<stop
offset="0%"
stopColor="#4f46e5"
stopOpacity={0.4}
/>
<stop
offset="100%"
stopColor="#4f46e5"
stopOpacity={0}
/>
</linearGradient>
</defs>
<Area
type="monotone"
dataKey="value"
stroke="#6366f1"
strokeWidth={2}
fill="url(#colorGradient)"
/>
</AreaChart>
</ResponsiveContainer>
</div>
</div>
</div>
</CardContent>
</Card>
{/* Card 2: Dashboard & Multi-Role Access — sm:6 / lg:4 */}
<Card className="sm:col-span-6 lg:col-span-4 bg-gray-50/50 border-gray-100 shadow-none rounded-3xl overflow-hidden animate-in fade-in slide-in-from-bottom-8 duration-700 delay-100 fill-mode-both">
<CardContent className="p-5 sm:p-6 h-full flex flex-col">
{/* Icon Grid */}
<div className="flex-1 flex items-center justify-center py-6 sm:py-8">
<div className="grid grid-cols-4 gap-3">
<GlassIcon icon={BarChart3} />
<GlassIcon icon={Clock} />
<GlassIcon icon={LayoutGrid} />
<GlassIcon icon={Users} />
<GlassIcon icon={Plus} />
<GlassIcon icon={Settings} />
<GlassIcon icon={Zap} />
<GlassIcon icon={Command} />
</div>
</div>
<div className="mt-auto">
<h3 className="font-semibold text-gray-900">
Dashboard & Multi-Role Access
</h3>
<p className="text-sm text-gray-500 mt-1 leading-relaxed">
Get real-time insights with dashboards tailored for every
user, from admin to faculty, using granular permissions for
simplified, secure access.
</p>
</div>
</CardContent>
</Card>
{/* Card 3: A Complete Platform — sm:12 / lg:4 */}
<Card className="sm:col-span-12 lg:col-span-4 bg-gray-50/50 border-gray-100 shadow-none rounded-3xl overflow-hidden animate-in fade-in slide-in-from-bottom-8 duration-700 delay-200 fill-mode-both group">
<CardContent className="p-5 sm:p-6 h-full flex flex-col relative">
<style jsx global>{`
@keyframes office-glow {
0%,
100% {
transform: scale(1);
}
10% {
transform: scale(1.05);
}
20% {
transform: scale(1);
}
}
@keyframes beam-travel-1 {
0%,
15% {
width: 0;
opacity: 0;
left: 0;
}
20% {
opacity: 1;
}
40% {
width: 100%;
opacity: 1;
left: 0;
}
45% {
width: 0;
opacity: 0;
left: 100%;
}
100% {
width: 0;
opacity: 0;
left: 100%;
}
}
@keyframes lightning-pulse {
0%,
40% {
transform: scale(1);
}
45% {
transform: scale(1.1);
}
55% {
transform: scale(1);
}
100% {
transform: scale(1);
}
}
@keyframes beam-travel-2 {
0%,
50% {
width: 0;
opacity: 0;
left: 0;
}
55% {
opacity: 1;
}
75% {
width: 100%;
opacity: 1;
left: 0;
}
80% {
width: 0;
opacity: 0;
left: 100%;
}
100% {
width: 0;
opacity: 0;
left: 100%;
}
}
@keyframes user-ripple {
0%,
75% {
box-shadow: 0 0 0 0 rgba(99, 102, 241, 0);
}
80% {
box-shadow: 0 0 0 10px rgba(99, 102, 241, 0.1);
}
100% {
box-shadow: 0 0 0 20px rgba(99, 102, 241, 0);
}
}
@keyframes animate-spin-blur {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.loader-ring {
position: relative;
border-radius: 50%;
overflow: hidden;
box-shadow:
-2px -2px 5px rgba(255, 255, 255, 0.8),
3px 3px 5px rgba(0, 0, 0, 0.1);
}
.loader-ring::before {
content: "";
position: absolute;
top: 3px;
left: 3px;
right: 3px;
bottom: 3px;
z-index: 10;
background: white;
border-radius: 50%;
border: 1px solid #f3f4f6;
}
.loader-ring span {
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
filter: blur(8px);
z-index: -1;
animation: animate-spin-blur 2s linear infinite;
}
.loader-ring.indigo span {
background-image: linear-gradient(
-225deg,
#4f46e5 0%,
#6366f1 50%,
#818cf8 100%
);
}
.loader-ring.green span {
background-image: linear-gradient(
-225deg,
#16a34a 0%,
#22c55e 50%,
#4ade80 100%
);
}
.animate-office-glow {
animation: office-glow 4s infinite;
}
.animate-beam-1 {
animation: beam-travel-1 4s infinite ease-in-out;
}
.animate-lightning-pulse {
animation: lightning-pulse 4s infinite;
}
.animate-beam-2 {
animation: beam-travel-2 4s infinite ease-in-out;
}
.animate-user-ripple {
animation: user-ripple 4s infinite;
}
`}</style>
<DottedGlowBackground
className="pointer-events-none z-0 [mask-image:radial-gradient(ellipse_at_center,white_25%,transparent_60%)]"
opacity={0.5}
gap={10}
radius={1.2}
colorLightVar="--color-indigo-200"
glowColorLightVar="--color-indigo-400"
backgroundOpacity={0}
speedMin={0.3}
speedMax={1.6}
speedScale={1}
/>
{/* Timeline Visual */}
<div className="flex-1 flex items-center justify-center py-8 relative z-10">
<div className="flex items-center gap-0 w-full max-w-xs sm:max-w-[320px]">
{/* Office Icon */}
<div className="relative z-10 shrink-0">
<div className="h-11 w-11 sm:h-14 sm:w-14 flex items-center justify-center loader-ring indigo animate-office-glow">
<span></span>
<div className="relative z-20">
<Building2 className="h-5 w-5 sm:h-6 sm:w-6 text-indigo-600" />
</div>
</div>
</div>
{/* Path 1: Office -> Lightning */}
<div className="flex-1 h-[2px] bg-gray-100 relative overflow-hidden mx-1 sm:mx-2">
<div className="absolute top-0 left-0 h-full bg-indigo-400 shadow-[0_0_15px_2px_rgba(99,102,241,1),0_0_30px_5px_rgba(99,102,241,0.5)] animate-beam-1 rounded-full" />
</div>
{/* Center: Lightning Icon */}
<div className="relative z-10 shrink-0">
<div className="h-13 w-13 sm:h-16 sm:w-16 flex items-center justify-center loader-ring green animate-lightning-pulse">
<span></span>
<div className="relative z-20">
<Zap className="h-6 w-6 sm:h-7 sm:w-7 text-green-500 fill-green-500" />
</div>
</div>
</div>
{/* Path 2: Lightning -> User */}
<div className="flex-1 h-[2px] bg-gray-100 relative overflow-hidden mx-1 sm:mx-2 flex flex-col justify-center gap-[2px]">
<div className="absolute top-0 left-0 h-full bg-indigo-400 shadow-[0_0_15px_2px_rgba(99,102,241,1),0_0_30px_5px_rgba(99,102,241,0.5)] animate-beam-2 rounded-full" />
</div>
{/* User Icon */}
<div className="relative z-10 shrink-0">
<div className="h-11 w-11 sm:h-14 sm:w-14 flex items-center justify-center loader-ring indigo animate-user-ripple">
<span></span>
<div className="relative z-20">
<Users className="h-5 w-5 sm:h-6 sm:w-6 text-indigo-600" />
</div>
</div>
</div>
</div>
</div>
<div className="mt-auto text-center sm:text-left">
<h3 className="font-semibold text-gray-900">
A Complete Platform
</h3>
<p className="text-sm text-gray-500 mt-1 leading-relaxed">
Seamless flow from institution to faculty.
</p>
</div>
</CardContent>
</Card>
{/* Card 4: Host College — sm:12 / lg:6 */}
<Card className="sm:col-span-12 lg:col-span-6 bg-gray-50/50 border-gray-100 shadow-none rounded-3xl overflow-hidden animate-in fade-in slide-in-from-bottom-8 duration-700 delay-300 fill-mode-both">
<CardContent className="p-5 sm:p-6 h-full flex flex-col">
<div className="mb-4 sm:mb-6">
<h3 className="font-semibold text-gray-900">Host College</h3>
<p className="text-sm text-gray-500">
Create, schedule, and manage program.
</p>
</div>
{/* Stack on mobile, side-by-side on sm+ */}
<div className="flex flex-col sm:flex-row gap-4">
{/* Left Panel: Sessions List */}
<div className="flex-1 bg-white rounded-xl border border-gray-100 p-4 shadow-sm">
<div className="mb-3">
<div className="text-xs font-semibold text-gray-900">
Create Program
</div>
<div className="text-[10px] text-gray-400">
Title, dates, fee, capacity
</div>
</div>
<div className="space-y-2">
{[1, 2].map((i) => (
<div
key={i}
className="flex items-center justify-between p-2 rounded-lg border border-gray-50 bg-gray-50/50"
>
<div className="min-w-0 mr-2">
<div className="text-[10px] font-medium text-gray-900 truncate">
Sessions 02 - Evaluating AI Tools
</div>
<div className="text-[9px] text-gray-400">
10:00 AM - 11:30 AM IST • Room B-301
</div>
</div>
<Button
variant="outline"
size="sm"
className="h-6 text-[9px] px-2 bg-white border-gray-200 shrink-0"
>
Mark Attendance
</Button>
</div>
))}
</div>
</div>
{/* Right Panel: Create Form — full width on mobile, fixed on sm+ */}
<div className="sm:w-48 bg-white rounded-xl border border-gray-100 p-4 shadow-sm flex flex-col gap-2">
<div className="mb-1">
<div className="text-xs font-semibold text-gray-900">
Create Program
</div>
<div className="text-[10px] text-gray-400">
Title, dates, fee, capacity
</div>
</div>
<Input
className="h-7 text-[10px] px-2"
placeholder="Program title"
/>
<div className="flex gap-2">
<Input
className="h-7 text-[10px] px-2"
placeholder="Start"
/>
<Input className="h-7 text-[10px] px-2" placeholder="End" />
</div>
<div className="flex gap-2">
<Input className="h-7 text-[10px] px-2" placeholder="Fee" />
<Input
className="h-7 text-[10px] px-2"
placeholder="Capacity"
/>
</div>
<Button className="h-7 w-full bg-black hover:bg-gray-800 text-white text-[10px] mt-1">
Publish
</Button>
</div>
</div>
</CardContent>
</Card>
{/* Card 5: Faculty View — sm:12 / lg:6 */}
<Card className="sm:col-span-12 lg:col-span-6 bg-gray-50/50 border-gray-100 shadow-none rounded-3xl overflow-hidden animate-in fade-in slide-in-from-bottom-8 duration-700 delay-500 fill-mode-both">
<CardContent className="p-5 sm:p-6 h-full flex flex-col">
<div className="mb-4 sm:mb-6">
<h3 className="font-semibold text-gray-900">Faculty View</h3>
<p className="text-sm text-gray-500">
Enroll, complete assignment, download certificate.
</p>
</div>
{/* Stack on mobile, side-by-side on sm+ */}
<div className="flex flex-col sm:flex-row gap-4">
{/* Left Panel: Enrollment — full width on mobile, fixed on sm+ */}
<div className="sm:w-48 bg-white rounded-xl border border-gray-100 p-4 shadow-sm">
<div className="mb-3">
<div className="text-xs font-semibold text-gray-900">
Current Enrollment
</div>
<div className="text-[10px] text-green-600 font-medium">
2 active
</div>
</div>
<div className="space-y-3">
{[
{
name: "Modern Web",
time: "Tue 10:00",
progress: "70%",
},
{
name: "AI for Educators",
time: "Wed 14:00",
progress: "45%",
},
{
name: "Data Science Bootcamp",
time: "Thu 16:00",
progress: "60%",
},
].map((item) => (
<div
key={item.name}
className="flex items-center justify-between"
>
<div className="min-w-0 mr-2">
<div className="text-[10px] font-medium text-gray-900 truncate">
{item.name}
</div>
<div className="text-[9px] text-gray-400">
Next session: {item.time}
</div>
</div>
<div className="text-[10px] font-bold text-gray-700 shrink-0">
{item.progress}
</div>
</div>
))}
</div>
</div>
{/* Right Panel: Assignments */}
<div className="flex-1 bg-white rounded-xl border border-gray-100 p-4 shadow-sm flex flex-col">
<div className="mb-3">
<div className="text-xs font-semibold text-gray-900">
Assignments
</div>
<div className="text-[10px] text-gray-400">
Upload & track feedback
</div>
</div>
<div className="flex-1 min-h-[2rem]" /> {/* Spacer */}
<div className="flex items-center justify-between mb-2">
<div className="text-[10px] font-medium text-gray-900">
Rubric draft
</div>
<Badge
variant="secondary"
className="h-5 text-[9px] bg-red-50 text-red-600 hover:bg-red-50 border-none"
>
Due Fri
</Badge>
</div>
<div className="flex gap-2">
<div className="flex-1 h-7 rounded-md border border-gray-200 flex items-center px-2 text-[10px] text-gray-400">
Attach file...
</div>
<Button className="h-7 bg-black hover:bg-gray-800 text-white text-[10px] gap-1 px-3">
<Upload className="h-3 w-3" />
Upload
</Button>
</div>
</div>
</div>
</CardContent>
</Card>
</div>
)}
</div>
);
};
export default Bento01;