merge main
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
"@assistant-ui/react": "^0.8.0",
|
"@assistant-ui/react": "^0.8.0",
|
||||||
"@assistant-ui/react-markdown": "^0.8.0",
|
"@assistant-ui/react-markdown": "^0.8.0",
|
||||||
"@faker-js/faker": "^9.5.1",
|
"@faker-js/faker": "^9.5.1",
|
||||||
|
"@assistant-ui/react-syntax-highlighter": "^0.7.2",
|
||||||
"@langchain/core": "^0.3.41",
|
"@langchain/core": "^0.3.41",
|
||||||
"@langchain/google-genai": "^0.1.10",
|
"@langchain/google-genai": "^0.1.10",
|
||||||
"@langchain/langgraph": "^0.2.49",
|
"@langchain/langgraph": "^0.2.49",
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
"esbuild-plugin-tailwindcss": "^2.0.1",
|
"esbuild-plugin-tailwindcss": "^2.0.1",
|
||||||
"framer-motion": "^12.4.9",
|
"framer-motion": "^12.4.9",
|
||||||
|
"katex": "^0.16.21",
|
||||||
"lucide-react": "^0.476.0",
|
"lucide-react": "^0.476.0",
|
||||||
"next-themes": "^0.4.4",
|
"next-themes": "^0.4.4",
|
||||||
"prettier": "^3.5.2",
|
"prettier": "^3.5.2",
|
||||||
@@ -42,7 +44,10 @@
|
|||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-markdown": "^10.0.1",
|
"react-markdown": "^10.0.1",
|
||||||
"react-router-dom": "^6.17.0",
|
"react-router-dom": "^6.17.0",
|
||||||
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
|
"rehype-katex": "^7.0.1",
|
||||||
"remark-gfm": "^4.0.1",
|
"remark-gfm": "^4.0.1",
|
||||||
|
"remark-math": "^6.0.0",
|
||||||
"sonner": "^2.0.1",
|
"sonner": "^2.0.1",
|
||||||
"tailwind-merge": "^3.0.2",
|
"tailwind-merge": "^3.0.2",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
@@ -61,6 +66,7 @@
|
|||||||
"@types/node": "^22.13.5",
|
"@types/node": "^22.13.5",
|
||||||
"@types/react": "^19.0.8",
|
"@types/react": "^19.0.8",
|
||||||
"@types/react-dom": "^19.0.3",
|
"@types/react-dom": "^19.0.3",
|
||||||
|
"@types/react-syntax-highlighter": "^15.5.13",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"eslint": "^9.19.0",
|
"eslint": "^9.19.0",
|
||||||
|
|||||||
6489
pnpm-lock.yaml
generated
6489
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,7 @@ import {
|
|||||||
SheetHeader,
|
SheetHeader,
|
||||||
SheetTitle,
|
SheetTitle,
|
||||||
} from "@/components/ui/sheet";
|
} from "@/components/ui/sheet";
|
||||||
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
|
|
||||||
function ThreadList({
|
function ThreadList({
|
||||||
threads,
|
threads,
|
||||||
@@ -55,8 +56,19 @@ function ThreadList({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ThreadHistoryLoading() {
|
||||||
|
return (
|
||||||
|
<div className="h-full flex flex-col gap-2 items-start justify-start overflow-y-scroll [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-gray-300 [&::-webkit-scrollbar-track]:bg-transparent">
|
||||||
|
{Array.from({ length: 30 }).map((_, i) => (
|
||||||
|
<Skeleton key={`skeleton-${i}`} className="w-[264px] h-10" />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function ThreadHistory() {
|
export default function ThreadHistory() {
|
||||||
const [threads, setThreads] = useState<Thread[]>([]);
|
const [threads, setThreads] = useState<Thread[]>([]);
|
||||||
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
const [chatHistoryOpen, setChatHistoryOpen] = useQueryParam(
|
const [chatHistoryOpen, setChatHistoryOpen] = useQueryParam(
|
||||||
"chatHistoryOpen",
|
"chatHistoryOpen",
|
||||||
BooleanParam,
|
BooleanParam,
|
||||||
@@ -65,14 +77,19 @@ export default function ThreadHistory() {
|
|||||||
const { getThreads } = useThreads();
|
const { getThreads } = useThreads();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getThreads().then(setThreads).catch(console.error);
|
if (typeof window === "undefined") return;
|
||||||
|
setLoading(true);
|
||||||
|
getThreads()
|
||||||
|
.then(setThreads)
|
||||||
|
.catch(console.error)
|
||||||
|
.finally(() => setLoading(false));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="hidden lg:flex flex-col border-r-[1px] border-slate-300 items-start justify-start gap-6 h-screen w-[300px] shrink-0 px-2 py-4 shadow-inner-right">
|
<div className="hidden lg:flex flex-col border-r-[1px] border-slate-300 items-start justify-start gap-6 h-screen w-[300px] shrink-0 px-2 py-4 shadow-inner-right">
|
||||||
<h1 className="text-2xl font-medium pl-4">Thread History</h1>
|
<h1 className="text-2xl font-medium pl-4">Thread History</h1>
|
||||||
<ThreadList threads={threads} />
|
{loading ? <ThreadHistoryLoading /> : <ThreadList threads={threads} />}
|
||||||
</div>
|
</div>
|
||||||
<Sheet open={!!chatHistoryOpen} onOpenChange={setChatHistoryOpen}>
|
<Sheet open={!!chatHistoryOpen} onOpenChange={setChatHistoryOpen}>
|
||||||
<SheetContent side="left" className="lg:hidden flex">
|
<SheetContent side="left" className="lg:hidden flex">
|
||||||
|
|||||||
@@ -9,15 +9,24 @@ import {
|
|||||||
} from "@assistant-ui/react-markdown";
|
} from "@assistant-ui/react-markdown";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
import remarkGfm from "remark-gfm";
|
import remarkGfm from "remark-gfm";
|
||||||
|
import rehypeKatex from "rehype-katex";
|
||||||
|
import remarkMath from "remark-math";
|
||||||
import { FC, memo, useState } from "react";
|
import { FC, memo, useState } from "react";
|
||||||
import { CheckIcon, CopyIcon } from "lucide-react";
|
import { CheckIcon, CopyIcon } from "lucide-react";
|
||||||
|
import { SyntaxHighlighter } from "@/components/thread/syntax-highlighter";
|
||||||
|
|
||||||
import { TooltipIconButton } from "@/components/thread/tooltip-icon-button";
|
import { TooltipIconButton } from "@/components/thread/tooltip-icon-button";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
import "katex/dist/katex.min.css";
|
||||||
|
|
||||||
const MarkdownTextImpl = ({ children }: { children: string }) => {
|
const MarkdownTextImpl = ({ children }: { children: string }) => {
|
||||||
return (
|
return (
|
||||||
<ReactMarkdown remarkPlugins={[remarkGfm]} components={defaultComponents}>
|
<ReactMarkdown
|
||||||
|
remarkPlugins={[remarkGfm, remarkMath]}
|
||||||
|
rehypePlugins={[rehypeKatex]}
|
||||||
|
components={defaultComponents}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
);
|
);
|
||||||
@@ -195,7 +204,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|||||||
pre: ({ className, ...props }) => (
|
pre: ({ className, ...props }) => (
|
||||||
<pre
|
<pre
|
||||||
className={cn(
|
className={cn(
|
||||||
"overflow-x-auto rounded-b-lg bg-black p-4 text-white",
|
"overflow-x-auto rounded-b-lg bg-black p-4 text-white max-w-4xl",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -211,4 +220,5 @@ const defaultComponents = memoizeMarkdownComponents({
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
CodeHeader,
|
CodeHeader,
|
||||||
|
SyntaxHighlighter,
|
||||||
});
|
});
|
||||||
|
|||||||
24
src/components/thread/syntax-highlighter.tsx
Normal file
24
src/components/thread/syntax-highlighter.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { PrismAsyncLight } from "react-syntax-highlighter";
|
||||||
|
import { makePrismAsyncLightSyntaxHighlighter } from "@assistant-ui/react-syntax-highlighter";
|
||||||
|
|
||||||
|
import tsx from "react-syntax-highlighter/dist/esm/languages/prism/tsx";
|
||||||
|
import python from "react-syntax-highlighter/dist/esm/languages/prism/python";
|
||||||
|
|
||||||
|
import { coldarkDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
|
||||||
|
|
||||||
|
// register languages you want to support
|
||||||
|
PrismAsyncLight.registerLanguage("js", tsx);
|
||||||
|
PrismAsyncLight.registerLanguage("jsx", tsx);
|
||||||
|
PrismAsyncLight.registerLanguage("ts", tsx);
|
||||||
|
PrismAsyncLight.registerLanguage("tsx", tsx);
|
||||||
|
PrismAsyncLight.registerLanguage("python", python);
|
||||||
|
|
||||||
|
export const SyntaxHighlighter = makePrismAsyncLightSyntaxHighlighter({
|
||||||
|
style: coldarkDark,
|
||||||
|
customStyle: {
|
||||||
|
margin: 0,
|
||||||
|
width: "100%",
|
||||||
|
background: "transparent",
|
||||||
|
padding: "1.5rem 1rem",
|
||||||
|
},
|
||||||
|
});
|
||||||
13
src/components/ui/skeleton.tsx
Normal file
13
src/components/ui/skeleton.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="skeleton"
|
||||||
|
className={cn("bg-primary/10 animate-pulse rounded-md", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Skeleton };
|
||||||
Reference in New Issue
Block a user