Add AI chat to dashboard, refactor stream module, snapshot --urls, batch argument mode (#1160)
* chat * refactor * fixes * fixes * fixes * fixes * improvements * download chat * batch * fixes * fixes * fixes * fmt * fixes * fixes * fixes * fmt
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -186,3 +186,22 @@ button {
|
||||
:is(.dark *).json-punct {
|
||||
color: #a1a1a1;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% { background-position: 200% 0; }
|
||||
100% { background-position: -200% 0; }
|
||||
}
|
||||
|
||||
.shimmer-text {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
currentColor 25%,
|
||||
color-mix(in srgb, currentColor 40%, transparent) 50%,
|
||||
currentColor 75%
|
||||
);
|
||||
background-size: 200% 100%;
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
animation: shimmer 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Geist } from "next/font/google";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { JotaiProvider } from "@/store/provider";
|
||||
import { ThemeProvider } from "@/components/theme-provider";
|
||||
|
||||
const geist = Geist({ subsets: ["latin"], variable: "--font-sans" });
|
||||
|
||||
@@ -18,11 +19,13 @@ export default function RootLayout({
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="en" className={cn("dark font-sans antialiased", geist.variable)}>
|
||||
<html lang="en" className={cn("font-sans antialiased", geist.variable)} suppressHydrationWarning>
|
||||
<body>
|
||||
<JotaiProvider>
|
||||
<TooltipProvider>{children}</TooltipProvider>
|
||||
</JotaiProvider>
|
||||
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem disableTransitionOnChange>
|
||||
<JotaiProvider>
|
||||
<TooltipProvider>{children}</TooltipProvider>
|
||||
</JotaiProvider>
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import { useAtomValue } from "jotai/react";
|
||||
import { activePortAtom } from "@/store/sessions";
|
||||
import { useAtomValue, useSetAtom } from "jotai/react";
|
||||
import { activePortAtom, sessionsAtom, newSessionDialogAtom } from "@/store/sessions";
|
||||
import { useSessionsSync } from "@/store/sessions";
|
||||
import { useStreamSync, hasConsoleErrorsAtom, consoleLogsAtom } from "@/store/stream";
|
||||
import { useActivitySync } from "@/store/activity";
|
||||
import { activeExtensionsAtom } from "@/store/sessions";
|
||||
import { useChatStatusSync } from "@/store/chat";
|
||||
import { useMediaQuery } from "@/hooks/use-media-query";
|
||||
import { Viewport } from "@/components/viewport";
|
||||
import { ActivityFeed } from "@/components/activity-feed";
|
||||
import { ChatPanel } from "@/components/chat-panel";
|
||||
import { ConsolePanel } from "@/components/console-panel";
|
||||
import { StoragePanel } from "@/components/storage-panel";
|
||||
import { ExtensionsPanel } from "@/components/extensions-panel";
|
||||
@@ -20,21 +22,28 @@ import {
|
||||
ResizableHandle,
|
||||
} from "@/components/ui/resizable";
|
||||
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
export default function DashboardPage() {
|
||||
const activePort = useAtomValue(activePortAtom);
|
||||
useStreamSync(activePort);
|
||||
useSessionsSync();
|
||||
useActivitySync();
|
||||
useChatStatusSync();
|
||||
|
||||
const sessions = useAtomValue(sessionsAtom);
|
||||
const hasSessions = sessions.length > 0;
|
||||
const setNewSessionDialog = useSetAtom(newSessionDialogAtom);
|
||||
const isDesktop = useMediaQuery("(min-width: 768px)");
|
||||
const hasConsoleErrors = useAtomValue(hasConsoleErrorsAtom);
|
||||
const activeExtensions = useAtomValue(activeExtensionsAtom);
|
||||
|
||||
const sidePanel = (
|
||||
<Tabs defaultValue="activity" className="flex h-full flex-col">
|
||||
<Tabs defaultValue="chat" className="flex h-full flex-col">
|
||||
<div className="shrink-0 px-2 pt-1">
|
||||
<TabsList variant="line" className="h-7 w-full">
|
||||
<TabsTrigger value="chat" className="text-[11px]">Chat</TabsTrigger>
|
||||
<TabsTrigger value="activity" className="text-[11px]">Activity</TabsTrigger>
|
||||
<TabsTrigger value="console" className="text-[11px]">
|
||||
Console
|
||||
@@ -67,10 +76,46 @@ export default function DashboardPage() {
|
||||
<TabsContent value="extensions" className="min-h-0 flex-1 overflow-hidden">
|
||||
<ExtensionsPanel />
|
||||
</TabsContent>
|
||||
<TabsContent value="chat" className="min-h-0 flex-1 overflow-hidden">
|
||||
<ChatPanel />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
);
|
||||
|
||||
if (isDesktop) {
|
||||
if (!hasSessions) {
|
||||
return (
|
||||
<div className="flex h-screen flex-col bg-background">
|
||||
<ResizablePanelGroup
|
||||
orientation="horizontal"
|
||||
className="min-h-0 flex-1"
|
||||
>
|
||||
<ResizablePanel id="sessions" defaultSize="15%" minSize="10%" maxSize="30%">
|
||||
<SessionTree />
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel id="empty" defaultSize="85%">
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<div className="text-center space-y-4">
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm text-muted-foreground">No active sessions</p>
|
||||
<p className="text-xs text-muted-foreground/60">Create a session to get started</p>
|
||||
</div>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => setNewSessionDialog(true)}
|
||||
>
|
||||
<Plus className="size-3.5" />
|
||||
New session
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-screen flex-col bg-background">
|
||||
<ResizablePanelGroup
|
||||
|
||||
Reference in New Issue
Block a user