From 3ba4bed1c4cf8575381a8f18da719310a78eb2be Mon Sep 17 00:00:00 2001 From: marcoitaloesp-ai Date: Tue, 16 Dec 2025 08:35:10 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20v1.40.0=20-=20Sidebar=20Mobile?= =?UTF-8?q?=20Overlay:=20UX=20Reimaginada?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Substituída sidebar comprimida por overlay slide-in moderna: MOBILE (<768px): - Sidebar ESCONDIDA por padrão (left: -100%) - Conteúdo em tela cheia (app-main margin-left: 0, width: 100%) - Hamburger menu (☰) 44x44px no header - Click hamburger: sidebar slide-in de 280px sobre conteúdo - Backdrop escuro (rgba(0,0,0,0.5)) para fechar ao clicar fora - Animação: cubic-bezier(0.4, 0, 0.2, 1) 0.3s - Shadow: 4px 0 12px rgba(0,0,0,0.5) quando aberta - Classe .mobile-open para estado aberto - Auto-close ao redimensionar para desktop DESKTOP (>=769px): - Mantém comportamento atual (sidebar fixa colapsável) - Hamburger e backdrop escondidos - Toggle colapsa/expande (não esconde) COMPONENTE (Layout.jsx): - Estado sidebarOpen (mobile) separado de sidebarCollapsed (desktop) - isMobile() helper para detectar <768px - toggleSidebar() inteligente (mobile: open/close | desktop: collapse/expand) - handleBackdropClick() fecha sidebar mobile - useEffect cleanup ao resize CSS: - @media (max-width: 768px) com sidebar overlay - @media (min-width: 769px) esconde mobile-only elements - Removidas regras conflitantes de sidebar 56px/50px - Safe area: padding-left/right 0 em body para permitir overlay - Touch target hamburger: 44x44px com hover effect Deploy: frontend/dist --- CHANGELOG.md | 20 ++++ VERSION | 2 +- frontend/src/components/Layout.jsx | 44 ++++++-- frontend/src/index.css | 175 ++++++++++++++++------------- 4 files changed, 153 insertions(+), 88 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 094b584..d615734 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,26 @@ O formato segue [Keep a Changelog](https://keepachangelog.com/pt-BR/). Este projeto adota [Versionamento Semântico](https://semver.org/pt-BR/). +## [1.40.0] - 2025-12-16 + +### Changed +- **SIDEBAR MOBILE OVERLAY** - UX completamente reimaginada para mobile + - Sidebar escondida por padrão em mobile (<768px) - conteúdo em tela cheia + - Hamburger menu (☰) no header para abrir sidebar + - Sidebar slide-in overlay (280px) sobre o conteúdo + - Backdrop escuro (rgba(0,0,0,0.5)) para fechar ao clicar fora + - Animação suave: cubic-bezier(0.4, 0, 0.2, 1) 0.3s + - Shadow: 4px 0 12px quando aberta + - App-main: margin-left 0 em mobile (100% width) + - Fechamento automático ao redimensionar para desktop + - Mantém comportamento desktop: sidebar fixa colapsável + +### Fixed +- **Layout mobile** - Agora conteúdo usa 100% da largura da tela +- **Touch target** - Hamburger menu 44x44px (Apple HIG) +- **Safe areas** - Removido padding-left/right do body para permitir overlay +- **Backdrop** - Escondido em desktop, visível apenas em mobile + ## [1.39.2] - 2025-12-16 ### Fixed diff --git a/VERSION b/VERSION index ecbe9df..32b7211 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.39.2 +1.40.0 diff --git a/frontend/src/components/Layout.jsx b/frontend/src/components/Layout.jsx index 31ececf..a6ab2f9 100644 --- a/frontend/src/components/Layout.jsx +++ b/frontend/src/components/Layout.jsx @@ -13,20 +13,38 @@ const Layout = ({ children }) => { const { t, i18n } = useTranslation(); const { date } = useFormatters(); - // Sidebar colapsado por padrão em mobile, expandido em desktop - const getInitialSidebarState = () => window.innerWidth < 1024; - const [sidebarCollapsed, setSidebarCollapsed] = useState(getInitialSidebarState); + // Mobile: sidebar oculta por padrão | Desktop: expandida + const isMobile = () => window.innerWidth < 768; + const [sidebarOpen, setSidebarOpen] = useState(false); // Mobile: inicia fechada + const [sidebarCollapsed, setSidebarCollapsed] = useState(false); // Desktop: colapsado ou não // Atualizar estado do sidebar quando a tela for redimensionada useEffect(() => { const handleResize = () => { - const isMobile = window.innerWidth < 1024; - setSidebarCollapsed(isMobile); + if (!isMobile() && sidebarOpen) { + setSidebarOpen(false); // Fecha sidebar mobile ao mudar para desktop + } }; window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); - }, []); + }, [sidebarOpen]); + + // Fecha sidebar mobile ao clicar fora (backdrop) + const handleBackdropClick = () => { + if (isMobile()) { + setSidebarOpen(false); + } + }; + + // Toggle sidebar (mobile: abre/fecha | desktop: expande/colapsa) + const toggleSidebar = () => { + if (isMobile()) { + setSidebarOpen(!sidebarOpen); + } else { + setSidebarCollapsed(!sidebarCollapsed); + } + }; const [expandedGroups, setExpandedGroups] = useState({ movements: true, @@ -104,8 +122,13 @@ const Layout = ({ children }) => { return (
+ {/* Mobile Backdrop */} + {sidebarOpen && ( +
+ )} + {/* Sidebar */} -