@@ -8,15 +8,18 @@ import ChatSubmit from '@/components/ChatSubmit';
88import ChatArea from '@/components/ChatArea' ;
99import { useChat } from '@/hooks/useChat' ;
1010import { useChatRooms } from '@/hooks/useChatRoom' ;
11- import ImageDetailPanel from '@/components/ImageDetailPanel ' ;
11+ import ImagePanel from '@/components/ImagePanel ' ;
1212
1313export default function Chat ( ) {
1414 const [ inputValue , setInputValue ] = useState < string > ( '' ) ;
1515 const [ inputImage , setInputImage ] = useState < MessageImage | undefined > ( undefined ) ;
1616 const [ currentChatId , setCurrentChatId ] = useState < number | null > ( null ) ;
1717 const [ isAIResponding , setIsAIResponding ] = useState < boolean > ( false ) ;
1818 const [ hasUserSentMessage , setHasUserSentMessage ] = useState < boolean > ( false ) ;
19- const [ selectedImage , setSelectedImage ] = useState < MessageImage | null > ( null ) ;
19+ const [ openTabs , setOpenTabs ] = useState < MessageImage [ ] > ( [ ] ) ;
20+ const [ activeTabId , setActiveTabId ] = useState < string | null > ( null ) ;
21+ const [ isPanelOpen , setIsPanelOpen ] = useState ( false ) ;
22+ const [ isSidebarOpen , setIsSidebarOpen ] = useState ( false ) ;
2023
2124 /** chat state 관리하는 hook */
2225 const { messages, examples, isLoading : isChatLoading , sendMessage, addMessageToCache } = useChat ( currentChatId ) ;
@@ -30,6 +33,12 @@ export default function Chat() {
3033 }
3134 } , [ messages , hasUserSentMessage ] ) ;
3235
36+ useEffect ( ( ) => {
37+ if ( isSidebarOpen ) {
38+ setIsPanelOpen ( false ) ;
39+ }
40+ } , [ isSidebarOpen ] ) ;
41+
3342 const sendMsg = useCallback (
3443 ( inputValue : string , inputImage ?: MessageImage ) => {
3544 const userMessage : Message = {
@@ -89,6 +98,32 @@ export default function Chat() {
8998 setInputImage ( undefined ) ;
9099 } ;
91100
101+ const handleOpenTab = ( newImageData : MessageImage ) => {
102+ const isAlreadyOpen = openTabs . some ( ( tab ) => tab . src === newImageData . src ) ;
103+ if ( ! isAlreadyOpen ) {
104+ setOpenTabs ( ( prevTabs ) => [ ...prevTabs , newImageData ] ) ;
105+ }
106+ setActiveTabId ( newImageData . src ) ;
107+ setIsPanelOpen ( true ) ; // 이미지 클릭 시 패널 열기
108+ } ;
109+
110+ // 3. 탭을 닫는 함수
111+ const handleCloseTab = ( tabSrcToClose : string ) => {
112+ const remainingTabs = openTabs . filter ( ( tab ) => tab . src !== tabSrcToClose ) ;
113+ setOpenTabs ( remainingTabs ) ;
114+ if ( activeTabId === tabSrcToClose ) {
115+ if ( remainingTabs . length > 0 ) {
116+ setActiveTabId ( remainingTabs [ remainingTabs . length - 1 ] . src ) ;
117+ } else {
118+ setActiveTabId ( null ) ;
119+ }
120+ }
121+ } ;
122+
123+ const handleTogglePanel = ( ) => {
124+ setIsPanelOpen ( ! isPanelOpen ) ;
125+ } ;
126+
92127 return (
93128 < div className = "flex min-h-screen w-full relative" >
94129 < div className = "hidden lg:block" >
@@ -106,6 +141,9 @@ export default function Chat() {
106141 onChatSelect = { handleChatSelect }
107142 onNewChat = { handleNewChat }
108143 chatRooms = { chatRooms }
144+ isSidebarOpen = { isSidebarOpen }
145+ setIsSidebarOpen = { setIsSidebarOpen }
146+ setIsPanelOpen = { setIsPanelOpen }
109147 />
110148 < div className = "flex-1 min-h-0" >
111149 < ChatArea
@@ -115,7 +153,7 @@ export default function Chat() {
115153 isAIResponding = { isAIResponding && hasUserSentMessage }
116154 examples = { examples }
117155 onExampleSelect = { handleExampleSelect }
118- setSelectedImage = { setSelectedImage }
156+ setSelectedImage = { handleOpenTab }
119157 />
120158 </ div >
121159 < ChatSubmit
@@ -127,18 +165,14 @@ export default function Chat() {
127165 />
128166 </ div >
129167 </ SidebarInset >
130- < div className = "flex h-[100vh] overflow-hidden" >
131- < div className = "hidden lg:block h-full" >
132- < div
133- className = { `h-full ${ selectedImage ? 'w-96' : 'w-0' } bg-beige border-l border-gray-200 transition-all duration-500 ease-in-out
134- ${ selectedImage ? 'translate-x-0 opacity-100' : 'translate-x-full opacity-0 pointer-events-none' }
135- ` }
136- style = { { minWidth : 0 } }
137- >
138- { selectedImage && < ImageDetailPanel imageData = { selectedImage } onClose = { ( ) => setSelectedImage ( null ) } /> }
139- </ div >
140- </ div >
141- </ div >
168+ < ImagePanel
169+ isOpen = { isPanelOpen }
170+ onToggle = { handleTogglePanel }
171+ openTabs = { openTabs }
172+ activeTabId = { activeTabId }
173+ onTabSelect = { setActiveTabId }
174+ onTabClose = { handleCloseTab }
175+ />
142176 </ div >
143177 ) ;
144178}
0 commit comments