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 */}
+
+
+ {/* 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 (
+ <>
+ setOpen(true)}
+ onMouseLeave={() => setOpen(false)}
+ {...props}
+ >
+ {children}
+
+ >
+ );
+};
+
+export const MobileSidebar = ({
+ className,
+ children,
+ ...props
+}: React.ComponentProps<"div">) => {
+ const { open, setOpen } = useSidebar();
+ return (
+ <>
+
+
+ Finance Home
+
+
+
+
+ {open && (
+
+ setOpen(!open)}
+ >
+
+
+ {children}
+
+ )}
+
+
+ >
+ );
+};
+
+export const SidebarLink = ({
+ link,
+ className,
+ ...props
+}: {
+ link: Links;
+ className?: string;
+}) => {
+ const { open, animate } = useSidebar();
+ return (
+
+ {link.icon}
+
+
+ {link.label}
+
+
+ );
+};