diff --git a/src/components/thread/history/index.tsx b/src/components/thread/history/index.tsx index 79f123d..7d0fbec 100644 --- a/src/components/thread/history/index.tsx +++ b/src/components/thread/history/index.tsx @@ -2,6 +2,7 @@ import { Button } from "@/components/ui/button"; import { useThreads } from "@/providers/Thread"; import { Thread } from "@langchain/langgraph-sdk"; import { useEffect } from "react"; + import { getContentString } from "../utils"; import { useQueryParam, StringParam, BooleanParam } from "use-query-params"; import { @@ -11,6 +12,9 @@ import { SheetTitle, } from "@/components/ui/sheet"; import { Skeleton } from "@/components/ui/skeleton"; +import { cn } from "@/lib/utils"; +import { PanelRightOpen } from "lucide-react"; +import { useMediaQuery } from "@/hooks/useMediaQuery"; function ThreadList({ threads, @@ -22,7 +26,7 @@ function ThreadList({ const [threadId, setThreadId] = useQueryParam("threadId", StringParam); return ( -
+
{threads.map((t) => { let itemText = t.thread_id; if ( @@ -36,10 +40,10 @@ function ThreadList({ itemText = getContentString(firstMessage.content); } return ( -
+
); @@ -58,15 +62,16 @@ function ThreadList({ function ThreadHistoryLoading() { return ( -
+
{Array.from({ length: 30 }).map((_, i) => ( - + ))}
); } export default function ThreadHistory() { + const isLargeScreen = useMediaQuery("(min-width: 1024px)"); const [chatHistoryOpen, setChatHistoryOpen] = useQueryParam( "chatHistoryOpen", BooleanParam, @@ -86,25 +91,44 @@ export default function ThreadHistory() { return ( <> -
-

Thread History

+
+
+ +

+ Thread History +

+
{threadsLoading ? ( ) : ( )}
- - - - Thread History - - setChatHistoryOpen((o) => !o)} - /> - - +
+ { + if (isLargeScreen) return; + setChatHistoryOpen(open); + }} + > + + + Thread History + + setChatHistoryOpen((o) => !o)} + /> + + +
); } diff --git a/src/components/thread/index.tsx b/src/components/thread/index.tsx index 3ffb8af..cadecf5 100644 --- a/src/components/thread/index.tsx +++ b/src/components/thread/index.tsx @@ -1,5 +1,6 @@ import { v4 as uuidv4 } from "uuid"; import { ReactNode, useEffect, useRef } from "react"; +import { motion } from "framer-motion"; import { cn } from "@/lib/utils"; import { useStreamContext } from "@/providers/Stream"; import { useState, FormEvent } from "react"; @@ -24,6 +25,7 @@ import { BooleanParam, StringParam, useQueryParam } from "use-query-params"; import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom"; import ThreadHistory from "./history"; import { toast } from "sonner"; +import { useMediaQuery } from "@/hooks/useMediaQuery"; function StickyToBottomContent(props: { content: ReactNode; @@ -65,12 +67,13 @@ function ScrollToBottom(props: { className?: string }) { export function Thread() { const [threadId, setThreadId] = useQueryParam("threadId", StringParam); - const [_, setChatHistoryOpen] = useQueryParam( + const [chatHistoryOpen, setChatHistoryOpen] = useQueryParam( "chatHistoryOpen", BooleanParam, ); const [input, setInput] = useState(""); const [firstTokenReceived, setFirstTokenReceived] = useState(false); + const isLargeScreen = useMediaQuery("(min-width: 1024px)"); const stream = useStreamContext(); const messages = stream.messages; @@ -166,16 +169,72 @@ export function Thread() { return (
- -
+ +
+ +
+
+
+ + {!chatStarted && ( +
+ {(!chatHistoryOpen || !isLargeScreen) && ( + + )} +
+ )} {chatStarted && (
-
+
+ {(!chatHistoryOpen || !isLargeScreen) && ( + + )} -
-
+
-
+
); } diff --git a/src/hooks/useMediaQuery.tsx b/src/hooks/useMediaQuery.tsx new file mode 100644 index 0000000..7e1468c --- /dev/null +++ b/src/hooks/useMediaQuery.tsx @@ -0,0 +1,16 @@ +import { useEffect, useState } from "react"; + +export function useMediaQuery(query: string) { + const [matches, setMatches] = useState(false); + + useEffect(() => { + const media = window.matchMedia(query); + setMatches(media.matches); + + const listener = (e: MediaQueryListEvent) => setMatches(e.matches); + media.addEventListener("change", listener); + return () => media.removeEventListener("change", listener); + }, [query]); + + return matches; +} diff --git a/src/index.css b/src/index.css index 2d4d0d8..3882f6f 100644 --- a/src/index.css +++ b/src/index.css @@ -118,9 +118,11 @@ * { @apply border-border outline-ring/50; } + body { @apply bg-background text-foreground; } + :root { --chart-1: 12 76% 61%; --chart-2: 173 58% 39%; diff --git a/tailwind.config.js b/tailwind.config.js index f49a279..2a0e74d 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,7 +1,11 @@ /** @type {import('tailwindcss').Config} */ module.exports = { darkMode: ["class"], - content: ["./index.html", "./src/**/*.{ts,tsx,js,jsx}"], + content: [ + "./index.html", + "./src/**/*.{ts,tsx,js,jsx}", + "./agent/**/*.{ts,tsx,js,jsx}", + ], theme: { extend: { borderRadius: {