diff --git a/apps/web/src/app/(main)/(landing)/pricing/page.tsx b/apps/web/src/app/(main)/(landing)/pricing/page.tsx index 11dfdde9..cc21dd66 100644 --- a/apps/web/src/app/(main)/(landing)/pricing/page.tsx +++ b/apps/web/src/app/(main)/(landing)/pricing/page.tsx @@ -112,7 +112,7 @@ const Pricing = () => { return ( <>
-
+
diff --git a/apps/web/src/components/dashboard/Sidebar.tsx b/apps/web/src/components/dashboard/Sidebar.tsx index d27c636e..12093196 100644 --- a/apps/web/src/components/dashboard/Sidebar.tsx +++ b/apps/web/src/components/dashboard/Sidebar.tsx @@ -1,3 +1,4 @@ + "use client"; import React, { useState, useEffect } from "react"; @@ -19,7 +20,7 @@ import { Squares2X2Icon, ChevronDownIcon, LockClosedIcon, - AcademicCapIcon + AcademicCapIcon, } from "@heroicons/react/24/outline"; import { useShowSidebar } from "@/store/useShowSidebar"; import { signOut, useSession } from "next-auth/react"; @@ -32,10 +33,9 @@ type RouteConfig = { path: string; label: string; icon: React.ReactNode; - badge?: string; // optional badge text (e.g., "New", "Beta") + badge?: string; }; -// free features only const FREE_ROUTES: RouteConfig[] = [ { path: "/dashboard/home", @@ -59,7 +59,6 @@ const FREE_ROUTES: RouteConfig[] = [ }, ]; -// premium features under Opensox Pro const PREMIUM_ROUTES: RouteConfig[] = [ { path: "/dashboard/pro/dashboard", @@ -82,6 +81,9 @@ export default function Sidebar({ overlay = false }: { overlay?: boolean }) { const { isPaidUser } = useSubscription(); const [proSectionExpanded, setProSectionExpanded] = useState(true); + // 🟣 New state for hover expand + const [isHovered, setIsHovered] = useState(false); + // auto-expand pro section if user is on a premium route useEffect(() => { if (isPaidUser) { @@ -106,7 +108,18 @@ export default function Sidebar({ overlay = false }: { overlay?: boolean }) { } }; - const desktopWidth = isCollapsed ? 80 : 288; + // 🟣 Hover handlers + const handleMouseEnter = () => { + if (isCollapsed) setIsHovered(true); + }; + + const handleMouseLeave = () => { + if (isHovered) setTimeout(() => setIsHovered(false), 150); + }; + + // compute dynamic width + const isSidebarExpanded = !isCollapsed || isHovered; + const desktopWidth = isSidebarExpanded ? 288 : 80; const mobileWidth = desktopWidth; return ( @@ -114,11 +127,14 @@ export default function Sidebar({ overlay = false }: { overlay?: boolean }) { className={`h-screen flex flex-col bg-dash-surface border-r border-dash-border z-50 ${ overlay ? "fixed left-0 top-0 bottom-0 xl:hidden" : "" }`} - initial={ - overlay ? { x: -400, width: mobileWidth } : { width: desktopWidth } - } - animate={overlay ? { x: 0, width: mobileWidth } : { width: desktopWidth }} - exit={overlay ? { x: -400, width: mobileWidth } : undefined} + onMouseEnter={handleMouseEnter} + onMouseLeave={handleMouseLeave} + initial={{ + width: overlay ? mobileWidth : desktopWidth, + }} + animate={{ + width: overlay ? mobileWidth : desktopWidth, + }} transition={{ type: "spring", stiffness: 260, damping: 30 }} style={{ width: overlay ? mobileWidth : desktopWidth }} > @@ -139,7 +155,7 @@ export default function Sidebar({ overlay = false }: { overlay?: boolean }) { {/* Desktop header with collapse */}
- {!isCollapsed && ( + {!isSidebarExpanded ? null : ( - {isCollapsed ? ( - - ) : ( + {isSidebarExpanded ? ( + ) : ( + )}
-
+ {/* Sidebar content */} +
{/* free features section */} {FREE_ROUTES.map((route) => { const isActive = @@ -182,7 +199,7 @@ export default function Sidebar({ overlay = false }: { overlay?: boolean }) { > {route.icon} - {!isCollapsed && ( + {isSidebarExpanded && (

)} {/* premium section */} - {!isCollapsed ? ( + {isSidebarExpanded ? (
{(() => { const isPremiumRouteActive = PREMIUM_ROUTES.some( @@ -401,7 +418,7 @@ export default function Sidebar({ overlay = false }: { overlay?: boolean }) { )} {/* divider */} - {!isCollapsed && ( + {isSidebarExpanded && (
@@ -412,12 +429,12 @@ export default function Sidebar({ overlay = false }: { overlay?: boolean }) { itemName="Request a feature" onclick={reqFeatureHandler} icon={} - collapsed={isCollapsed} + collapsed={!isSidebarExpanded} />
{/* Bottom profile */} - + ); } @@ -466,7 +483,9 @@ function ProfileMenu({ isCollapsed }: { isCollapsed: boolean }) { {userEmail}

)} diff --git a/apps/web/src/components/ui/header.tsx b/apps/web/src/components/ui/header.tsx index 7e5ddd95..5bc41572 100644 --- a/apps/web/src/components/ui/header.tsx +++ b/apps/web/src/components/ui/header.tsx @@ -1,27 +1,43 @@ 'use client' + import { motion } from 'framer-motion' import React from 'react' import { FlickeringGrid } from './flickering-grid' import { colors } from '@/lib/design-tokens' +import Link from 'next/link' +import { Home } from 'lucide-react' -const Header = ({title}: {title: string}) => { +const Header = ({ title, homeLink }: { title: string; homeLink?: string }) => { return ( -
+
+ + {homeLink && ( + + + + )} + {title} +
-
+ +
{ ) } -export default Header \ No newline at end of file +export default Header