From 82864f0c7a917bf9179764788b956d979a3a420a Mon Sep 17 00:00:00 2001 From: changui <122252160+changuii@users.noreply.github.com> Date: Wed, 10 Dec 2025 20:34:16 +0900 Subject: [PATCH 1/5] =?UTF-8?q?[FEAT]=20=EB=AA=A8=EB=B0=94=EC=9D=BC=20?= =?UTF-8?q?=ED=99=98=EA=B2=BD=EC=97=90=EC=84=9C=EB=8A=94=20=EC=9A=B0?= =?UTF-8?q?=EC=B8=A1=20=ED=95=98=EB=8B=A8=20=EB=A9=94=EB=89=B4=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=EC=9D=84=20=ED=86=B5=ED=95=B4=20=EC=82=AC=EC=9D=B4?= =?UTF-8?q?=EB=93=9C=EB=B0=94=EB=A5=BC=20=EC=82=AC=EC=9A=A9=20(#12)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 19 ++++++++- src/components/layout/Sidebar.jsx | 57 ++++++++++++++++----------- src/components/layout/UseIsMobile.jsx | 16 ++++++++ 3 files changed, 67 insertions(+), 25 deletions(-) create mode 100644 src/components/layout/UseIsMobile.jsx diff --git a/src/App.jsx b/src/App.jsx index d17b390..f4cc40f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,4 +1,4 @@ -import React, { useState, useCallback } from 'react'; +import React, { useState, useCallback, useEffect } from 'react'; // Contexts & Providers import { DataProvider } from './contexts/DataProvider'; @@ -41,6 +41,7 @@ import PasswordChangeModal from './components/modals/PasswordChangeModal'; import LostItemGuideModal from './components/modals/LostItemGuideModal'; import TimeTagAddModal from './components/modals/TimeTagAddModal'; import TimeTagEditModal from './components/modals/TimeTagEditModal'; +import { useIsMobile } from './components/layout/UseIsMobile'; // Common Components import Toast from './components/common/Toast'; @@ -50,6 +51,11 @@ function App() { const [modalState, setModalState] = useState({ type: null, props: {} }); const [toasts, setToasts] = useState([]); const [sidebarOpen, setSidebarOpen] = useState(true); // 사이드바 열림/닫힘 상태 추가 + const isMobile = useIsMobile(); + + useEffect(() => { + setSidebarOpen(!isMobile); // 모바일에서는 기본 닫힘 + }, [isMobile]); const showToast = useCallback((message) => { const id = Date.now() + Math.random(); @@ -111,7 +117,16 @@ function App() { -
+
+ {isMobile && !sidebarOpen && ( + + )}
diff --git a/src/components/layout/Sidebar.jsx b/src/components/layout/Sidebar.jsx index 77d344a..847e1c5 100644 --- a/src/components/layout/Sidebar.jsx +++ b/src/components/layout/Sidebar.jsx @@ -1,10 +1,15 @@ import React, { useState, useRef } from 'react'; import { usePage } from '../../hooks/usePage'; +import { useIsMobile } from './UseIsMobile'; const Sidebar = ({ open, setOpen }) => { const { page, setPage } = usePage(); const [textVisible, setTextVisible] = useState(open); - const handleNav = (targetPage) => setPage(targetPage); + const isMobile = useIsMobile(); + const handleNav = (targetPage) => { + setPage(targetPage); + if (isMobile) setOpen(false); + }; // 텍스트 표시 지연 처리 React.useEffect(() => { @@ -18,27 +23,31 @@ const Sidebar = ({ open, setOpen }) => { } }, [open]); // NavLink 컴포넌트도 open prop을 받도록 수정 - const NavLink = ({ target, icon, children, open }) => ( - { e.preventDefault(); handleNav(target); }} - className={`sidebar-link flex items-center py-3 rounded-lg transition duration-200 hover:bg-gray-700 hover:text-white ${page === target ? 'active' : 'text-gray-600'} px-4`} - style={{ justifyContent: 'flex-start' }} - > - - {open && ( - - {children} - - )} - - ); + const NavLink = ({ target, icon, children, open }) => { + const isExpanded = open || isMobile; + return ( + { e.preventDefault(); handleNav(target); }} + className={`sidebar-link flex items-center py-3 rounded-lg transition duration-200 hover:bg-gray-700 hover:text-white ${page === target ? 'active' : 'text-gray-600'} px-4`} + style={{ justifyContent: 'flex-start' }} + > + + {isExpanded && ( + + {children} + + )} + + ); + }; // SubMenu는 사이드바가 닫혀있으면 아이콘만, 열려있으면 텍스트와 하위 메뉴까지 보이도록 수정 const SubMenu = ({ icon, title, links, sidebarOpen }) => { const isActive = links.some(l => l.target === page); const contentRef = useRef(null); + const isExpanded = sidebarOpen || isMobile; return (
{ >
- {sidebarOpen && ( + {isExpanded && ( @@ -70,7 +79,7 @@ const Sidebar = ({ open, setOpen }) => {
{/* 사이드바가 열려있을 때만 하위 메뉴 렌더링 */} - {sidebarOpen && ( + {isExpanded && (
{
); }; + const sidebarClasses = isMobile + ? `${open ? 'translate-x-0' : '-translate-x-full'} fixed inset-0 z-50 w-72 max-w-full p-6 bg-white flex flex-col h-full overflow-y-auto transform transition-transform duration-300 ease-in-out shadow-lg` + : `${open ? 'w-64 p-4' : 'w-16 p-2'} bg-gray-50 shrink-0 flex flex-col border-r border-gray-200 h-full transition-all duration-300 ease-in-out relative overflow-hidden`; + return (