File size: 6,073 Bytes
b636e8f
780df80
 
 
 
 
b636e8f
 
780df80
fcd8ded
27a07a9
7d94a77
62283c0
b636e8f
 
780df80
 
 
 
 
 
 
 
7d94a77
b636e8f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
780df80
 
 
62283c0
 
 
 
 
 
 
 
 
79ae05b
62283c0
 
 
 
 
 
 
fcd8ded
62283c0
 
fcd8ded
7d94a77
 
 
 
 
 
 
 
 
 
 
780df80
 
27a07a9
 
 
780df80
 
27a07a9
 
 
 
62283c0
27a07a9
 
 
 
780df80
 
 
 
79ae05b
780df80
 
 
 
 
 
 
79ae05b
b636e8f
780df80
 
 
 
 
 
 
 
 
 
 
 
 
b636e8f
780df80
 
 
b636e8f
 
780df80
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
"use client";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { LayoutGrid, Menu, MessageCircle, Network, Settings } from "lucide-react";
import React, { useState } from "react";
import { ThemeToggle } from "./ThemeToggle";
import Link from "next/link";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Sheet, SheetContent, SheetTrigger, SheetTitle, SheetDescription } from "@/components/ui/sheet";
import ResearchGraph from "@/components/visualizations/ResearchGraph";
import { useChatContext } from "@/lib/store/ChatContext";

interface ChatLayoutProps {
  sidebar: React.ReactNode;
  mainContent: React.ReactNode;
  settingsPanel: React.ReactNode;
}

const ChatLayout: React.FC<ChatLayoutProps> = ({ sidebar, mainContent, settingsPanel }) => {
  const { chatState, connectionMode, setConnectionMode } = useChatContext();
  const [activeTab, setActiveTab] = useState<string>("chat");
  const [visualizationType, setVisualizationType] = useState<"d3" | "reactflow">("d3");

  // Get the latest research tree from messages
  const latestResearchTree = React.useMemo(() => {
    // First look for the most recent completed research message
    const completedResearch = [...chatState.messages].reverse().find((msg) => msg.role === "assistant" && !msg.isProgress && msg.research_tree);

    if (completedResearch?.research_tree) {
      return completedResearch.research_tree;
    }

    // If no completed research, look for progress messages
    const progressMessage = [...chatState.messages].reverse().find((msg) => msg.role === "assistant" && msg.isProgress && msg.research_tree);

    return progressMessage?.research_tree;
  }, [chatState.messages]);

  return (
    <div className="h-screen flex flex-col">
      <header className="border-b-2 h-14 flex items-center px-6">
        <Sheet>
          <SheetTrigger asChild>
            <Button variant="ghost" size="icon" className="md:hidden mr-2">
              <Menu size={20} />
              <span className="sr-only">Toggle sidebar</span>
            </Button>
          </SheetTrigger>
          <SheetContent side="left" className="w-[80%] sm:w-[350px] p-0">
            <SheetTitle className="sr-only">Mobile Navigation</SheetTitle>
            <SheetDescription className="sr-only">Sidebar navigation for mobile devices</SheetDescription>
            <div className="border-b p-4">
              <h2 className="text-lg font-semibold">Conversations</h2>
            </div>
            <ScrollArea className="h-[calc(100%-60px)] py-2">{sidebar}</ScrollArea>
          </SheetContent>
        </Sheet>

        <Link href={"/"}>
          <h1 className="text-xl font-semibold hidden sm:inline">KnowledgeNet: Deep Research</h1>
          <h1 className="text-lg font-semibold sm:hidden">KNet: Deep Research</h1>
        </Link>
        <div className="ml-4">
          <Select value={connectionMode} onValueChange={(value) => setConnectionMode(value as "agent" | "workflow")}>
            <SelectTrigger className="w-[120px]">
              <SelectValue placeholder="Mode" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="agent">Agent</SelectItem>
              <SelectItem value="workflow">Workflow</SelectItem>
            </SelectContent>
          </Select>
        </div>
        <div className="flex-1" />
        <ThemeToggle />
        <Dialog>
          <DialogTrigger asChild>
            <Button variant="ghost" size="icon" className="h-9 w-9" title="Settings">
              <Settings size={20} />
            </Button>
          </DialogTrigger>
          <DialogContent>
            <DialogHeader>
              <DialogTitle>Research Settings</DialogTitle>
              <DialogDescription>Configure your research parameters and preferences.</DialogDescription>
            </DialogHeader>
            {settingsPanel}
          </DialogContent>
        </Dialog>
      </header>

      <div className="flex-1 overflow-hidden">
        <ResizablePanelGroup direction="horizontal">
          <ResizablePanel defaultSize={15} className="hidden md:block min-w-[15rem] max-w-[35rem]">
            <Card className="h-full rounded-none border-r border-t-0 border-l-0 border-b-0">
              <ScrollArea className="h-full">{sidebar}</ScrollArea>
            </Card>
          </ResizablePanel>

          <ResizableHandle withHandle className="hidden md:flex" />

          <ResizablePanel defaultSize={85} className="w-full md:w-auto">
            <Tabs value={activeTab} onValueChange={setActiveTab} className="h-full flex flex-col">
              <div className="p-4">
                <TabsList className="">
                  <TabsTrigger value="chat" className="flex items-center gap-2">
                    <MessageCircle size={16} />
                    <span>Chat</span>
                  </TabsTrigger>
                  <TabsTrigger value="visualizations" className="flex items-center gap-2">
                    <LayoutGrid size={16} />
                    <span>Visualizations</span>
                  </TabsTrigger>
                </TabsList>
              </div>

              <TabsContent value="chat" className="overflow-auto flex-1 !mt-0" tabIndex={-1}>
                {mainContent}
              </TabsContent>

              <TabsContent value="visualizations" className="p-4 pt-0 overflow-auto flex-1 !mt-0" tabIndex={-1}>
                <ResearchGraph researchTree={latestResearchTree} />
              </TabsContent>
            </Tabs>
          </ResizablePanel>
        </ResizablePanelGroup>
      </div>
    </div>
  );
};

export default ChatLayout;