diff --git a/src/frontend/apps/web/app/(main)/[stockSlug]/page.tsx b/src/frontend/apps/web/app/(main)/[stockSlug]/page.tsx index d5c88713..6595a5fe 100644 --- a/src/frontend/apps/web/app/(main)/[stockSlug]/page.tsx +++ b/src/frontend/apps/web/app/(main)/[stockSlug]/page.tsx @@ -17,7 +17,7 @@ export async function generateMetadata({ params }) { export default function StockDetailsPage({ params }) { const { stockSlug } = params; - // console.log(1, params); + // console.log(1, stockSlug); return (
@@ -32,7 +32,7 @@ export default function StockDetailsPage({ params }) {
- +
); diff --git a/src/frontend/apps/web/src/features/chat/index.tsx b/src/frontend/apps/web/src/features/chat/index.tsx index 1d699593..ff5ff4a1 100644 --- a/src/frontend/apps/web/src/features/chat/index.tsx +++ b/src/frontend/apps/web/src/features/chat/index.tsx @@ -1 +1,2 @@ export { default as ChatContainer } from './ui/chat-container'; +export { default as ThreadContainer } from './ui/thread-panel'; diff --git a/src/frontend/apps/web/src/features/chat/ui/avatarlist.tsx b/src/frontend/apps/web/src/features/chat/ui/avatarlist.tsx index 7e411795..9a197c01 100644 --- a/src/frontend/apps/web/src/features/chat/ui/avatarlist.tsx +++ b/src/frontend/apps/web/src/features/chat/ui/avatarlist.tsx @@ -1,8 +1,14 @@ +'use client'; + +import { useState } from 'react'; import { Avatar, AvatarImage, AvatarFallback } from '@workspace/ui/components'; import type { ChatContentWithAvatarsProps } from './chat-content'; -const AvatarList = ({ avatarUrls }: ChatContentWithAvatarsProps) => { +const AvatarList = ({ + avatarUrls, + setIsThreadOpen, +}: ChatContentWithAvatarsProps) => { if (!avatarUrls) { avatarUrls = [ 'https://github.com/shadcn.png', @@ -19,24 +25,43 @@ const AvatarList = ({ avatarUrls }: ChatContentWithAvatarsProps) => { const displayedAvatars = avatarUrls.slice(0, 5); const remainingCount = avatarUrls.length - displayedAvatars.length; - return ( -
- {displayedAvatars.map((url, index) => ( - 0 ? 'relative' : ''} - > - - profile + const [isHovered, setIsHovered] = useState(false); - {index === 4 && remainingCount > 0 && ( -
+{remainingCount}
- )} -
- ))} - {avatarUrls.length > 0 &&
{avatarUrls.length}개의 댓글
} + return ( +
setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + onClick={() => setIsThreadOpen(true)} + > +
+ {displayedAvatars.map((url, index) => ( + 0 ? 'relative' : ''} + > + + profile + {index === 4 && remainingCount > 0 && ( +
+ +{remainingCount} +
+ )} +
+ ))} + {avatarUrls.length > 0 && ( +
+ {avatarUrls.length}개의 댓글 +
+ )} +
+
+ 스레드 보기 +
); }; diff --git a/src/frontend/apps/web/src/features/chat/ui/chat-container.tsx b/src/frontend/apps/web/src/features/chat/ui/chat-container.tsx index afae9a61..d2592860 100644 --- a/src/frontend/apps/web/src/features/chat/ui/chat-container.tsx +++ b/src/frontend/apps/web/src/features/chat/ui/chat-container.tsx @@ -1,14 +1,15 @@ import { SidebarInset, SidebarProvider } from '@workspace/ui/components'; +import { SidebarContainer } from '@/src/shared/components/sidebar'; + import ChatHeader from './chat-header'; import ChatSection from './chat-section'; -import { SidebarContainer } from '@/src/shared/components/sidebar'; -const ChatContainer = () => { +const ChatContainer = ({ stockSlug }: { stockSlug: string }) => { return ( - + diff --git a/src/frontend/apps/web/src/features/chat/ui/chat-content.tsx b/src/frontend/apps/web/src/features/chat/ui/chat-content.tsx index 8035e0c6..a4609bd1 100644 --- a/src/frontend/apps/web/src/features/chat/ui/chat-content.tsx +++ b/src/frontend/apps/web/src/features/chat/ui/chat-content.tsx @@ -1,26 +1,44 @@ import ContentText from './content-text'; import ContentAvatar from './content-avatar'; +import { MessageSquareText } from 'lucide-react'; + export type ChatContentProps = { type?: 'default' | 'live'; }; export type ChatContentWithAvatarsProps = ChatContentProps & { avatarUrls?: string[]; + setIsThreadOpen: (value: boolean) => void; }; -const ChatContent = ({ type = 'default', avatarUrls }: ChatContentWithAvatarsProps) => { +const ChatContent = ({ + type = 'live', + avatarUrls, + setIsThreadOpen, +}: ChatContentWithAvatarsProps) => { const backgroundColor = type === 'live' ? 'bg-live' : 'bg-white'; - const hoverColor = type === 'default' ? 'hover:bg-chatboxHover' : ''; return ( -
+
- +
+ +
+ setIsThreadOpen(true)} + /> +
+
); }; diff --git a/src/frontend/apps/web/src/features/chat/ui/chat-header.tsx b/src/frontend/apps/web/src/features/chat/ui/chat-header.tsx index a6f02f27..b9471680 100644 --- a/src/frontend/apps/web/src/features/chat/ui/chat-header.tsx +++ b/src/frontend/apps/web/src/features/chat/ui/chat-header.tsx @@ -1,11 +1,23 @@ -import { SidebarTrigger } from '@workspace/ui/components'; +import { Button, SidebarTrigger } from '@workspace/ui/components'; +import { Headset } from 'lucide-react'; +import Header from './header'; -const ChatHeader = () => { +const ChatHeader = ({ stockSlug }: { stockSlug: string }) => { return ( -
- - 123 -
+
+
+ + {stockSlug} +
+
+ +
+
); }; diff --git a/src/frontend/apps/web/src/features/chat/ui/chat-section.tsx b/src/frontend/apps/web/src/features/chat/ui/chat-section.tsx index b4c6a9ac..ac74e840 100644 --- a/src/frontend/apps/web/src/features/chat/ui/chat-section.tsx +++ b/src/frontend/apps/web/src/features/chat/ui/chat-section.tsx @@ -1,14 +1,33 @@ +'use client'; + +import { useState } from 'react'; + import ChatContent from './chat-content'; import ChatTextarea from './chat-textarea'; +import ThreadPanel from './thread-panel'; const ChatSection = () => { + const [isThreadOpen, setIsThreadOpen] = useState(false); + return ( -
-
- +
+ {/* Main Chat Area */} +
+
+ +
+
+ +
-
- + + {/* Thread Panel Overlay */} +
+ {isThreadOpen && setIsThreadOpen(false)} />}
); diff --git a/src/frontend/apps/web/src/features/chat/ui/content-text.tsx b/src/frontend/apps/web/src/features/chat/ui/content-text.tsx index 0410ee51..c65cf230 100644 --- a/src/frontend/apps/web/src/features/chat/ui/content-text.tsx +++ b/src/frontend/apps/web/src/features/chat/ui/content-text.tsx @@ -3,7 +3,11 @@ import { Badge } from '@workspace/ui/components'; import type { ChatContentWithAvatarsProps } from './chat-content'; import AvatarList from './avatarlist'; -const ContentText = ({ type, avatarUrls }: ChatContentWithAvatarsProps) => { +const ContentText = ({ + type, + avatarUrls, + setIsThreadOpen, +}: ChatContentWithAvatarsProps) => { return (
@@ -21,7 +25,12 @@ const ContentText = ({ type, avatarUrls }: ChatContentWithAvatarsProps) => {
안녕하세요
- +
setIsThreadOpen(true)}> + +
); }; diff --git a/src/frontend/apps/web/src/features/chat/ui/header.tsx b/src/frontend/apps/web/src/features/chat/ui/header.tsx new file mode 100644 index 00000000..b404446a --- /dev/null +++ b/src/frontend/apps/web/src/features/chat/ui/header.tsx @@ -0,0 +1,9 @@ +const Header = ({ children }: { children: React.ReactNode }) => { + return ( +
+ {children} +
+ ); +}; + +export default Header; diff --git a/src/frontend/apps/web/src/features/chat/ui/thread-header.tsx b/src/frontend/apps/web/src/features/chat/ui/thread-header.tsx new file mode 100644 index 00000000..9bce8ab9 --- /dev/null +++ b/src/frontend/apps/web/src/features/chat/ui/thread-header.tsx @@ -0,0 +1,16 @@ +import Header from './header'; + +import { X } from 'lucide-react'; + +const ThreadHeader = ({ onClose }: { onClose: (value: boolean) => void }) => { + return ( +
+ 스레드 + +
+ ); +}; + +export default ThreadHeader; diff --git a/src/frontend/apps/web/src/features/chat/ui/thread-panel.tsx b/src/frontend/apps/web/src/features/chat/ui/thread-panel.tsx new file mode 100644 index 00000000..71485a44 --- /dev/null +++ b/src/frontend/apps/web/src/features/chat/ui/thread-panel.tsx @@ -0,0 +1,12 @@ +import ThreadHeader from './thread-header'; +import ThreadSection from './thread-section'; + +const ThreadPanel = ({ onClose }: { onClose: (value: boolean) => void }) => { + return ( +
+ +
+ ); +}; + +export default ThreadPanel; diff --git a/src/frontend/apps/web/src/features/chat/ui/thread-section.tsx b/src/frontend/apps/web/src/features/chat/ui/thread-section.tsx new file mode 100644 index 00000000..63d255fa --- /dev/null +++ b/src/frontend/apps/web/src/features/chat/ui/thread-section.tsx @@ -0,0 +1,14 @@ +import ChatTextArea from './chat-textarea'; + +const ThreadSection = () => { + return ( +
+
+
+ +
+
+ ); +}; + +export default ThreadSection;