From 576b6e5307b21ae4464fdd9c53d637e9536baca0 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 00:40:45 +0000 Subject: [PATCH] feat: Integrate auto-collapsing sidebar component Integrate the provided sidebar component, ensuring it functions correctly on both desktop and mobile devices with automatic collapsing and expanding functionality. --- package-lock.json | 27 ++++ package.json | 1 + src/components/layout/Layout.tsx | 10 +- src/components/layout/ModernLayout.tsx | 199 +++++++++++++++++++++++++ src/components/ui/modern-sidebar.tsx | 192 ++++++++++++++++++++++++ 5 files changed, 428 insertions(+), 1 deletion(-) create mode 100644 src/components/layout/ModernLayout.tsx create mode 100644 src/components/ui/modern-sidebar.tsx diff --git a/package-lock.json b/package-lock.json index 555423e..825e46a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,7 @@ "@radix-ui/react-toggle-group": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.4", "@supabase/supabase-js": "^2.49.4", + "@tabler/icons-react": "^3.34.0", "@tanstack/react-query": "^5.56.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -2855,6 +2856,32 @@ "@swc/counter": "^0.1.3" } }, + "node_modules/@tabler/icons": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.34.0.tgz", + "integrity": "sha512-jtVqv0JC1WU2TTEBN32D9+R6mc1iEBuPwLnBsWaR02SIEciu9aq5806AWkCHuObhQ4ERhhXErLEK7Fs+tEZxiA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + } + }, + "node_modules/@tabler/icons-react": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.34.0.tgz", + "integrity": "sha512-OpEIR2iZsIXECtAIMbn1zfKfQ3zKJjXyIZlkgOGUL9UkMCFycEiF2Y8AVfEQsyre/3FnBdlWJvGr0NU47n2TbQ==", + "license": "MIT", + "dependencies": { + "@tabler/icons": "3.34.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + }, + "peerDependencies": { + "react": ">= 16" + } + }, "node_modules/@tailwindcss/typography": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.15.tgz", diff --git a/package.json b/package.json index d4db682..31b6072 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@radix-ui/react-toggle-group": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.4", "@supabase/supabase-js": "^2.49.4", + "@tabler/icons-react": "^3.34.0", "@tanstack/react-query": "^5.56.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/src/components/layout/Layout.tsx b/src/components/layout/Layout.tsx index 1d9bb74..0fd4e05 100644 --- a/src/components/layout/Layout.tsx +++ b/src/components/layout/Layout.tsx @@ -3,15 +3,17 @@ import { useState } from 'react'; import { useIsMobile } from '@/hooks/use-mobile'; import Header from './Header'; import Sidebar from './Sidebar'; +import ModernLayout from './ModernLayout'; import OnboardingTour from '@/components/onboarding/OnboardingTour'; import HelpIcon from '@/components/help/HelpIcon'; import { useOnboardingTour } from '@/hooks/useOnboardingTour'; interface LayoutProps { children: React.ReactNode; + useModernSidebar?: boolean; } -export default function Layout({ children }: LayoutProps) { +export default function Layout({ children, useModernSidebar = true }: LayoutProps) { const [sidebarOpen, setSidebarOpen] = useState(false); const isMobile = useIsMobile(); @@ -23,6 +25,12 @@ export default function Layout({ children }: LayoutProps) { closeTour } = useOnboardingTour(); + // Se useModernSidebar for true, usa o novo layout moderno + if (useModernSidebar) { + return {children}; + } + + // Layout antigo para compatibilidade const handleSidebarClose = () => { setSidebarOpen(false); }; diff --git a/src/components/layout/ModernLayout.tsx b/src/components/layout/ModernLayout.tsx new file mode 100644 index 0000000..2e61f93 --- /dev/null +++ b/src/components/layout/ModernLayout.tsx @@ -0,0 +1,199 @@ + +import React, { useState } from 'react'; +import { Link } from 'react-router-dom'; +import { useIsMobile } from '@/hooks/use-mobile'; +import { ModernSidebar, SidebarBody, SidebarLink } from '@/components/ui/modern-sidebar'; +import OnboardingTour from '@/components/onboarding/OnboardingTour'; +import HelpIcon from '@/components/help/HelpIcon'; +import { useOnboardingTour } from '@/hooks/useOnboardingTour'; +import { + Home, + Receipt, + CreditCard, + ListFilter, + Target, + Calendar, + Crown, + MessageSquareText, + Users, + Settings +} from 'lucide-react'; +import { motion } from 'framer-motion'; + +interface ModernLayoutProps { + children: React.ReactNode; +} + +const Logo = () => { + return ( + +
+ + Finance Home + + + ); +}; + +const LogoIcon = () => { + return ( + +
+ + ); +}; + +export default function ModernLayout({ children }: ModernLayoutProps) { + const [open, setOpen] = useState(false); + const isMobile = useIsMobile(); + + const { + isOpen: tourOpen, + currentStep, + nextStep, + skipTour, + closeTour + } = useOnboardingTour(); + + const links = [ + { + label: "Dashboard", + href: "/", + icon: , + }, + { + label: "Transações", + href: "/transacoes", + icon: , + }, + { + label: "Cartões de Crédito", + href: "/cartoes", + icon: , + }, + { + label: "Categorias", + href: "/categorias", + icon: , + }, + { + label: "Metas", + href: "/metas", + icon: , + }, + { + label: "Calendário", + href: "/calendario", + icon: , + }, + { + label: "Assinatura", + href: "/assinatura", + icon: , + } + ]; + + const whatsappLinks = [ + { + label: "Conectar WhatsApp", + href: "/whatsapp", + icon: , + }, + { + label: "Grupos", + href: "/grupos-whatsapp", + icon: , + } + ]; + + const configLinks = [ + { + label: "Configurações", + href: "/configuracoes", + icon: , + } + ]; + + return ( +
+ + +
+ {open ? : } + +
+ {links.map((link, idx) => ( + + ))} +
+ +
+ {open && ( + + WhatsApp + + )} +
+ {whatsappLinks.map((link, idx) => ( + + ))} +
+
+ +
+ {open && ( + + Configurações + + )} +
+ {configLinks.map((link, idx) => ( + + ))} +
+
+
+
+
+ + {/* Main content */} +
+
+
+ {children} +
+
+
+ + {/* Help Icon */} + + + {/* Tour de Onboarding */} + +
+ ); +} diff --git a/src/components/ui/modern-sidebar.tsx b/src/components/ui/modern-sidebar.tsx new file mode 100644 index 0000000..3283782 --- /dev/null +++ b/src/components/ui/modern-sidebar.tsx @@ -0,0 +1,192 @@ + +"use client"; +import { cn } from "@/lib/utils"; +import React, { useState, createContext, useContext } from "react"; +import { AnimatePresence, motion } from "framer-motion"; +import { Menu, X } from "lucide-react"; + +interface Links { + label: string; + href: string; + icon: React.JSX.Element | React.ReactNode; +} + +interface SidebarContextProps { + open: boolean; + setOpen: React.Dispatch>; + animate: boolean; +} + +const SidebarContext = createContext( + undefined +); + +export const useSidebar = () => { + const context = useContext(SidebarContext); + if (!context) { + throw new Error("useSidebar must be used within a SidebarProvider"); + } + return context; +}; + +export const SidebarProvider = ({ + children, + open: openProp, + setOpen: setOpenProp, + animate = true, +}: { + children: React.ReactNode; + open?: boolean; + setOpen?: React.Dispatch>; + animate?: boolean; +}) => { + const [openState, setOpenState] = useState(false); + + const open = openProp !== undefined ? openProp : openState; + const setOpen = setOpenProp !== undefined ? setOpenProp : setOpenState; + + return ( + + {children} + + ); +}; + +export const ModernSidebar = ({ + children, + open, + setOpen, + animate, +}: { + children: React.ReactNode; + open?: boolean; + setOpen?: React.Dispatch>; + animate?: boolean; +}) => { + return ( + + {children} + + ); +}; + +export const SidebarBody = (props: React.ComponentProps) => { + return ( + <> + + )} /> + + ); +}; + +export const DesktopSidebar = ({ + className, + children, + ...props +}: React.ComponentProps) => { + const { open, setOpen, animate } = useSidebar(); + return ( + <> + + + ); +}; + +export const MobileSidebar = ({ + className, + children, + ...props +}: React.ComponentProps<"div">) => { + const { open, setOpen } = useSidebar(); + return ( + <> +
+
+ Finance Home +
+
+ setOpen(!open)} + /> +
+ + {open && ( + +
setOpen(!open)} + > + +
+ {children} +
+ )} +
+
+ + ); +}; + +export const SidebarLink = ({ + link, + className, + ...props +}: { + link: Links; + className?: string; +}) => { + const { open, animate } = useSidebar(); + return ( + + {link.icon} + + + {link.label} + + + ); +};