← back to Letsbegin
components/ui/SidebarDemo.tsx
222 lines
"use client";
import React, { useState } from "react";
import { Sidebar, SidebarBody, SidebarLink } from "@/components/ui/sidebar";
import {
FileText,
RefreshCw,
Play,
FolderOpen,
Settings,
LogOut,
Rocket,
Zap
} from "lucide-react";
import Link from "next/link";
import { motion } from "framer-motion";
import { cn } from "@/lib/utils";
interface SidebarDemoProps {
currentStep: number;
onStepChange: (step: number) => void;
onLogout: () => void;
username?: string;
children: React.ReactNode;
}
export function SidebarDemo({
currentStep,
onStepChange,
onLogout,
username = "Admin",
children
}: SidebarDemoProps) {
const links = [
{
label: "Quick Mode",
href: "#",
icon: (
<Zap className={cn(
"h-5 w-5 flex-shrink-0",
currentStep === 0 ? "text-[var(--primary)]" : "text-neutral-700 dark:text-neutral-200"
)} />
),
step: 0,
},
{
label: "PRD Generator",
href: "#",
icon: (
<FileText className={cn(
"h-5 w-5 flex-shrink-0",
currentStep === 1 ? "text-[var(--primary)]" : "text-neutral-700 dark:text-neutral-200"
)} />
),
step: 1,
},
{
label: "Ralph Converter",
href: "#",
icon: (
<RefreshCw className={cn(
"h-5 w-5 flex-shrink-0",
currentStep === 2 ? "text-[var(--primary)]" : "text-neutral-700 dark:text-neutral-200"
)} />
),
step: 2,
},
{
label: "Ralphy Boy Runner",
href: "#",
icon: (
<Play className={cn(
"h-5 w-5 flex-shrink-0",
currentStep === 3 ? "text-[var(--primary)]" : "text-neutral-700 dark:text-neutral-200"
)} />
),
step: 3,
},
];
const bottomLinks = [
{
label: "Projects",
href: "#",
icon: (
<FolderOpen className="text-neutral-700 dark:text-neutral-200 h-5 w-5 flex-shrink-0" />
),
},
{
label: "Settings",
href: "#",
icon: (
<Settings className="text-neutral-700 dark:text-neutral-200 h-5 w-5 flex-shrink-0" />
),
},
];
const [open, setOpen] = useState(false);
return (
<div
className={cn(
"flex flex-col md:flex-row bg-[var(--background)] w-full flex-1 border border-[var(--border)] overflow-hidden",
"h-screen"
)}
>
<Sidebar open={open} setOpen={setOpen}>
<SidebarBody className="justify-between gap-10 bg-[var(--surface)] border-r border-[var(--border)]">
<div className="flex flex-col flex-1 overflow-y-auto overflow-x-hidden">
{open ? <Logo /> : <LogoIcon />}
{/* Step Navigation */}
<div className="mt-8 flex flex-col gap-2">
<div className="text-xs text-[var(--foreground-tertiary)] px-2 mb-2">
{open && "WORKFLOW"}
</div>
{links.map((link, idx) => (
<button
key={idx}
onClick={() => onStepChange(link.step)}
className={cn(
"flex items-center justify-start gap-2 group/sidebar py-2 px-2 rounded-lg transition-colors",
currentStep === link.step
? "bg-[var(--primary)]/20 text-[var(--primary)]"
: "hover:bg-[var(--surface-alt)]"
)}
>
{link.icon}
<motion.span
animate={{
display: open ? "inline-block" : "none",
opacity: open ? 1 : 0,
}}
className={cn(
"text-sm group-hover/sidebar:translate-x-1 transition duration-150 whitespace-pre inline-block !p-0 !m-0",
currentStep === link.step
? "text-[var(--primary)] font-medium"
: "text-[var(--foreground)]"
)}
>
{link.label}
</motion.span>
</button>
))}
</div>
{/* Bottom Links */}
<div className="mt-auto flex flex-col gap-2">
<div className="text-xs text-[var(--foreground-tertiary)] px-2 mb-2">
{open && "TOOLS"}
</div>
{bottomLinks.map((link, idx) => (
<SidebarLink key={idx} link={link} />
))}
</div>
</div>
{/* User Section */}
<div className="border-t border-[var(--border)] pt-4">
<button
onClick={onLogout}
className="flex items-center justify-start gap-2 group/sidebar py-2 px-2 rounded-lg hover:bg-red-500/10 transition-colors w-full"
>
<LogOut className="text-red-400 h-5 w-5 flex-shrink-0" />
<motion.span
animate={{
display: open ? "inline-block" : "none",
opacity: open ? 1 : 0,
}}
className="text-red-400 text-sm whitespace-pre inline-block !p-0 !m-0"
>
Logout ({username})
</motion.span>
</button>
</div>
</SidebarBody>
</Sidebar>
{/* Main Content */}
<div className="flex flex-1 overflow-hidden">
<div className="flex-1 overflow-auto">
{children}
</div>
</div>
</div>
);
}
export const Logo = () => {
return (
<Link
href="#"
className="font-normal flex space-x-2 items-center text-sm py-1 relative z-20"
>
<div className="h-6 w-6 bg-gradient-to-br from-[var(--primary)] to-[var(--secondary)] rounded-lg flex items-center justify-center flex-shrink-0">
<Rocket className="h-4 w-4 text-white" />
</div>
<motion.span
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="font-bold text-[var(--foreground)] whitespace-pre"
>
GoodQuestionRalph
</motion.span>
</Link>
);
};
export const LogoIcon = () => {
return (
<Link
href="#"
className="font-normal flex space-x-2 items-center text-sm py-1 relative z-20"
>
<div className="h-6 w-6 bg-gradient-to-br from-[var(--primary)] to-[var(--secondary)] rounded-lg flex items-center justify-center flex-shrink-0">
<Rocket className="h-4 w-4 text-white" />
</div>
</Link>
);
};
export default SidebarDemo;