Initial commit

This commit is contained in:
Rohan Verma 2024-07-30 16:00:11 -07:00 committed by GitHub
commit 55332d1ddb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
168 changed files with 18456 additions and 0 deletions

View file

@ -0,0 +1,82 @@
"use client";
import Link from "next/link";
import { AnimatePresence, motion } from "framer-motion";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
export default function LinkComponent(...props: any) {
const activeLink = props[0].activeLink;
const collapsed = props[0].collapsed;
const animationDuration = props[0].animationDuration;
return (
<Link href={props[0].href}>
{collapsed ? (
<TooltipProvider delayDuration={150}>
<Tooltip>
<TooltipTrigger asChild>
<div
className={`flex flex-row gap-6 rounded-md py-3 font-normal ${
collapsed ? "justify-center" : "items-center"
} ${activeLink ? "bg-border text-foreground" : ""}`}
>
<div className={collapsed ? "p-0" : "pl-4"}>
{props[0].icon}
</div>
<AnimatePresence>
<motion.div
layout
animate={{
x: collapsed ? -20 : 0,
y: collapsed ? 0 : 0,
opacity: collapsed ? 0 : 1,
width: collapsed ? 0 : "auto",
display: collapsed ? "none" : "block",
}}
transition={{ duration: animationDuration }}
className="text-sm"
>
{props[0].label}
</motion.div>
</AnimatePresence>
</div>
</TooltipTrigger>
<TooltipContent side="right">
<p>{props[0].label}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
) : (
<div
className={`flex flex-row gap-6 rounded-md py-3 font-normal ${
collapsed ? "justify-center" : "items-center"
} ${activeLink ? "bg-border text-foreground" : ""}`}
>
<div className={collapsed ? "p-0" : "pl-4"}>{props[0].icon}</div>
<AnimatePresence>
<motion.div
layout
animate={{
x: collapsed ? -20 : 0,
y: collapsed ? 0 : 0,
opacity: collapsed ? 0 : 1,
width: collapsed ? 0 : "auto",
display: collapsed ? "none" : "block",
}}
transition={{ duration: animationDuration }}
className="text-sm"
>
{props[0].label}
</motion.div>
</AnimatePresence>
</div>
)}
</Link>
);
}

View file

@ -0,0 +1,67 @@
import { FC } from "react";
import { usePathname } from "next/navigation";
import LinkComponent from "./NavLink";
import { navConfig } from "@/lib/config/";
type NavLinksProps = {
collapsed: boolean;
animationDuration: number;
};
const NavLinks: FC<NavLinksProps> = ({ collapsed, animationDuration }) => {
const pathName = usePathname();
return (
<div className="flex h-full flex-col justify-between">
<div id="topNavLinks">
{navConfig.navLinks.map((link, index) => {
if (link.navLocation === "top") {
const activeLink = pathName === link.href;
return (
<div
key={index}
className="px-5 text-muted-foreground transition-all duration-300 hover:text-foreground"
>
<LinkComponent
activeLink={activeLink}
href={link.href}
label={link.label}
icon={link.icon}
animationDuration={animationDuration}
collapsed={collapsed}
/>
</div>
);
}
})}
</div>
<div id="btmNavLinks">
{navConfig.navLinks.map((link, index) => {
if (link.navLocation === "bottom") {
const activeLink = pathName === link.href;
return (
<div
key={index}
className="px-5 text-muted-foreground transition-all duration-300 hover:text-foreground"
>
<LinkComponent
activeLink={activeLink}
href={link.href}
label={link.label}
icon={link.icon}
animationDuration={animationDuration}
collapsed={collapsed}
/>
</div>
);
}
})}
</div>
</div>
);
};
export default NavLinks;

View file

@ -0,0 +1,84 @@
"use client";
import { useEffect } from "react";
import { useState } from "react";
import Link from "next/link";
import { Icons } from "@/components/icons";
import { motion } from "framer-motion";
import NavLinks from "./NavLinks";
const Sidebar = () => {
const [collapsed, setCollapsed] = useState(false);
const animationDuration = 0.4;
const sideBarWidth = "250px";
// Load collapsed state from localStorage on component mount
useEffect(() => {
const collapsedState = localStorage.getItem("sidebarCollapsed");
if (collapsedState !== null) {
setCollapsed(collapsedState === "true" ? true : false);
}
}, []);
const handleClose = () => {
localStorage.setItem("sidebarCollapsed", (!collapsed).toString());
setCollapsed(!collapsed);
};
return (
<motion.div
layout
initial={{ width: collapsed ? "88px" : sideBarWidth }}
animate={{
minWidth: collapsed ? "88px" : sideBarWidth,
width: collapsed ? "88px" : sideBarWidth,
}}
transition={{ duration: animationDuration }}
id="sidebar"
className={`flex h-full flex-col justify-between gap-8 border-r border-border`}
>
<div
className={`flex h-20 items-center justify-between border-b border-border ${
collapsed ? "px-8" : "px-4"
} `}
>
<Link href="/">
<motion.div
layout
animate={{
x: collapsed ? -100 : 0,
y: collapsed ? 0 : 0,
opacity: collapsed ? 0 : 1,
width: collapsed ? 0 : "auto",
display: collapsed ? "none" : "block",
}}
transition={{ duration: animationDuration }}
>
<div className="flex flex-row items-center gap-1 font-semibold text-sm text-foreground">
<span>
<Icons.logo className="h-5" />
</span>
Next-Fast-Turbo
</div>
</motion.div>
</Link>
{collapsed ? (
<Icons.panelLeftOpen
className="h-6 w-6 cursor-pointer text-muted-foreground transition-all hover:text-foreground hover:duration-300"
onClick={handleClose}
/>
) : (
<Icons.panelLeftClose
className="h-6 w-6 cursor-pointer text-muted-foreground transition-all hover:text-foreground hover:duration-300"
onClick={handleClose}
/>
)}
</div>
<div className="flex-1 border-border pb-8">
<NavLinks collapsed={collapsed} animationDuration={animationDuration} />
</div>
</motion.div>
);
};
export default Sidebar;

View file

@ -0,0 +1,58 @@
"use client";
import { useRef } from "react";
import { useState } from "react";
import { Squash as Hamburger } from "hamburger-react";
import { useClickAway } from "react-use";
import { navConfig } from "@/lib/config/";
import { AnimatePresence, motion } from "framer-motion";
import Link from "next/link";
import { Separator } from "@/components/ui/separator";
const SidebarMobile = () => {
const [isOpen, setOpen] = useState(false);
const ref = useRef(null);
useClickAway(ref, () => setOpen(false));
return (
<div ref={ref}>
<Hamburger toggled={isOpen} size={20} toggle={setOpen} />
<AnimatePresence>
{isOpen && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2 }}
className="fixed left-0 w-[85%] py-12 h-screen px-8 bg-background"
>
<ul className="grid min-h-72 content-evenly">
{navConfig.navLinks.map((link, index) => {
return (
<motion.li
initial={{ scale: 0, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{
type: "spring",
stiffness: 260,
damping: 20,
delay: 0.1 + index / 10,
}}
key={link.pageTitle}
className="w-full"
>
<Link href={link.href}>{link.pageTitle}</Link>
<Separator className="my-2" />
</motion.li>
);
})}
</ul>
</motion.div>
)}
</AnimatePresence>
</div>
);
};
export default SidebarMobile;

View file

@ -0,0 +1,2 @@
export { default as Sidebar } from "./Sidebar";
export { default as SidebarMobile } from "./SidebarMobile";