@@ -4,6 +4,7 @@ import { useState, useRef, useEffect, FormEvent } from "react";
44import { Button } from "./ui/button" ;
55import { Input } from "./ui/input" ;
66import { Card } from "./ui/card" ;
7+ import { cn } from "@/lib/utils" ;
78import {
89 Send ,
910 X ,
@@ -19,6 +20,7 @@ import {
1920 Trash2 ,
2021 RotateCcw ,
2122 MessageSquare ,
23+ ExternalLink ,
2224} from "lucide-react" ;
2325import {
2426 DropdownMenu ,
@@ -30,10 +32,12 @@ import { useChat } from "./ChatContext";
3032import type { ChatSession } from "./ChatContext" ;
3133import { WebLLMProvider , useWebLLM } from "./WebLLMProvider" ;
3234import * as webllm from "@mlc-ai/web-llm" ;
35+ import Link from "next/link" ;
3336
3437interface ChatComponentProps {
3538 isOpen ?: boolean ;
3639 onClose ?: ( ) => void ;
40+ isFullPage ?: boolean ;
3741}
3842
3943export default function ChatComponent ( props : ChatComponentProps ) {
@@ -47,8 +51,9 @@ export default function ChatComponent(props: ChatComponentProps) {
4751function ChatComponentInner ( {
4852 isOpen : controlledIsOpen ,
4953 onClose,
54+ isFullPage = false ,
5055} : ChatComponentProps ) {
51- const [ isOpen , setIsOpen ] = useState < boolean > ( ! ! controlledIsOpen ) ;
56+ const [ isOpen , setIsOpen ] = useState < boolean > ( isFullPage || ! ! controlledIsOpen ) ;
5257 const [ model , setModel ] = useState ( "gpt-4o" ) ;
5358 const [ availableModels , setAvailableModels ] = useState < { id : string ; name : string ; isLocal ?: boolean } [ ] > ( [ ] ) ;
5459 const [ input , setInput ] = useState ( "" ) ;
@@ -331,15 +336,28 @@ function ChatComponentInner({
331336
332337 return (
333338 < Card
334- className = "fixed bottom-0 right-0 z-[60] w-full max-w-sm sm:max-w-md md:max-w-md h-[70vh] sm:h-[80vh] flex flex-col bg-zinc-900 border border-zinc-800 shadow-2xl rounded-tl-xl p-1 gap-0"
335- style = { { boxShadow : "0 8px 32px 0 rgba(0,0,0,0.45)" } }
339+ className = { cn (
340+ "z-[60] flex flex-col bg-zinc-900 border-zinc-800 shadow-2xl p-1 gap-0" ,
341+ isFullPage
342+ ? "w-full h-full rounded-xl border-zinc-700/50"
343+ : "fixed bottom-0 right-0 w-full max-w-sm sm:max-w-md md:max-w-md h-[70vh] sm:h-[80vh] rounded-tl-xl"
344+ ) }
345+ style = { ! isFullPage ? { boxShadow : "0 8px 32px 0 rgba(0,0,0,0.45)" } : { } }
336346 >
337347 { /* Header */ }
338- < div className = "flex items-center justify-between px-4 py-3 border-b border-zinc-800 bg-zinc-950 rounded-tl-xl" >
348+ < div className = { cn (
349+ "flex items-center justify-between px-4 py-3 border-b border-zinc-800 bg-zinc-950" ,
350+ isFullPage ? "rounded-t-xl" : "rounded-tl-xl"
351+ ) } >
339352 < div className = "flex flex-col" >
340353 < div className = "flex items-center gap-2" >
341354 < MessageCircle className = "w-5 h-5 text-blue-400" />
342355 < span className = "font-semibold text-white text-lg" > ST-K8s Chat</ span >
356+ { ! isFullPage && (
357+ < Link href = "/chat" target = "_blank" className = "ml-1 text-zinc-500 hover:text-blue-400 transition-colors" >
358+ < ExternalLink className = "w-3.5 h-3.5" />
359+ </ Link >
360+ ) }
343361 </ div >
344362 < div className = "flex items-center gap-2 mt-0.5" >
345363 < button
@@ -444,15 +462,17 @@ function ChatComponentInner({
444462 ) }
445463 </ DropdownMenuContent >
446464 </ DropdownMenu >
447- < Button
448- variant = "ghost"
449- size = "icon"
450- className = "text-zinc-400 hover:text-white w-8 h-8"
451- onClick = { handleToggle }
452- aria-label = "Close chat"
453- >
454- < X className = "w-5 h-5" />
455- </ Button >
465+ { ! isFullPage && (
466+ < Button
467+ variant = "ghost"
468+ size = "icon"
469+ className = "text-zinc-400 hover:text-white w-8 h-8"
470+ onClick = { handleToggle }
471+ aria-label = "Close chat"
472+ >
473+ < X className = "w-5 h-5" />
474+ </ Button >
475+ ) }
456476 </ div >
457477 </ div >
458478
@@ -556,10 +576,13 @@ function ChatComponentInner({
556576 className = { `flex \${msg.role === "user" ? "justify-end" : "justify-start"}` }
557577 >
558578 < div
559- className = { `max-w-[80%] px-4 py-2 rounded-lg text-sm whitespace-pre-line \${msg.role === "user"
560- ? "bg-blue-600 text-white rounded-br-none"
561- : "bg-zinc-800 text-zinc-100 rounded-bl-none border border-zinc-700"
562- }` }
579+ className = { cn (
580+ "px-4 py-2 rounded-lg text-sm whitespace-pre-line" ,
581+ isFullPage ? "max-w-[90%]" : "max-w-[80%]" ,
582+ msg . role === "user"
583+ ? "bg-blue-600 text-white rounded-br-none"
584+ : "bg-zinc-800 text-zinc-100 rounded-bl-none border border-zinc-700"
585+ ) }
563586 >
564587 { msg . content }
565588 </ div >
@@ -575,7 +598,10 @@ function ChatComponentInner({
575598 ) }
576599 { webllmLoading && webllmProgress && (
577600 < div className = "flex justify-start" >
578- < div className = "flex flex-col gap-1 bg-zinc-800 text-zinc-300 px-4 py-2 rounded-lg border border-zinc-700 w-full max-w-[80%]" >
601+ < div className = { cn (
602+ "flex flex-col gap-1 bg-zinc-800 text-zinc-300 px-4 py-2 rounded-lg border border-zinc-700 w-full" ,
603+ isFullPage ? "max-w-[90%]" : "max-w-[80%]"
604+ ) } >
579605 < div className = "flex justify-between text-xs mb-1" >
580606 < span > Downloading Model Array into Browser</ span >
581607 </ div >
0 commit comments