Skip to content

Commit 4e7e540

Browse files
committed
add assistant-ui components
1 parent 0c132c1 commit 4e7e540

File tree

9 files changed

+612
-1
lines changed

9 files changed

+612
-1
lines changed

client/packages/lowcoder/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"antd": "^5.25.2",
5151
"axios": "^1.7.7",
5252
"buffer": "^6.0.3",
53+
"class-variance-authority": "^0.7.1",
5354
"clsx": "^2.0.0",
5455
"cnchar": "^3.2.4",
5556
"coolshapes-react": "lowcoder-org/coolshapes-react",
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import "@assistant-ui/react-markdown/styles/dot.css";
2+
3+
import {
4+
CodeHeaderProps,
5+
MarkdownTextPrimitive,
6+
unstable_memoizeMarkdownComponents as memoizeMarkdownComponents,
7+
useIsMarkdownCodeBlock,
8+
} from "@assistant-ui/react-markdown";
9+
import remarkGfm from "remark-gfm";
10+
import { FC, memo, useState } from "react";
11+
import { CheckIcon, CopyIcon } from "lucide-react";
12+
13+
import { TooltipIconButton } from "./tooltip-icon-button";
14+
import { cn } from "../../utils/cn";
15+
16+
const MarkdownTextImpl = () => {
17+
return (
18+
<MarkdownTextPrimitive
19+
remarkPlugins={[remarkGfm]}
20+
className="aui-md"
21+
components={defaultComponents}
22+
/>
23+
);
24+
};
25+
26+
export const MarkdownText = memo(MarkdownTextImpl);
27+
28+
const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
29+
const { isCopied, copyToClipboard } = useCopyToClipboard();
30+
const onCopy = () => {
31+
if (!code || isCopied) return;
32+
copyToClipboard(code);
33+
};
34+
35+
return (
36+
<div className="aui-code-header-root">
37+
<span className="aui-code-header-language">{language}</span>
38+
<TooltipIconButton tooltip="Copy" onClick={onCopy}>
39+
{!isCopied && <CopyIcon />}
40+
{isCopied && <CheckIcon />}
41+
</TooltipIconButton>
42+
</div>
43+
);
44+
};
45+
46+
const useCopyToClipboard = ({
47+
copiedDuration = 3000,
48+
}: {
49+
copiedDuration?: number;
50+
} = {}) => {
51+
const [isCopied, setIsCopied] = useState<boolean>(false);
52+
53+
const copyToClipboard = (value: string) => {
54+
if (!value) return;
55+
56+
navigator.clipboard.writeText(value).then(() => {
57+
setIsCopied(true);
58+
setTimeout(() => setIsCopied(false), copiedDuration);
59+
});
60+
};
61+
62+
return { isCopied, copyToClipboard };
63+
};
64+
65+
const defaultComponents = memoizeMarkdownComponents({
66+
h1: ({ className, ...props }) => (
67+
<h1 className={cn("aui-md-h1", className)} {...props} />
68+
),
69+
h2: ({ className, ...props }) => (
70+
<h2 className={cn("aui-md-h2", className)} {...props} />
71+
),
72+
h3: ({ className, ...props }) => (
73+
<h3 className={cn("aui-md-h3", className)} {...props} />
74+
),
75+
h4: ({ className, ...props }) => (
76+
<h4 className={cn("aui-md-h4", className)} {...props} />
77+
),
78+
h5: ({ className, ...props }) => (
79+
<h5 className={cn("aui-md-h5", className)} {...props} />
80+
),
81+
h6: ({ className, ...props }) => (
82+
<h6 className={cn("aui-md-h6", className)} {...props} />
83+
),
84+
p: ({ className, ...props }) => (
85+
<p className={cn("aui-md-p", className)} {...props} />
86+
),
87+
a: ({ className, ...props }) => (
88+
<a className={cn("aui-md-a", className)} {...props} />
89+
),
90+
blockquote: ({ className, ...props }) => (
91+
<blockquote className={cn("aui-md-blockquote", className)} {...props} />
92+
),
93+
ul: ({ className, ...props }) => (
94+
<ul className={cn("aui-md-ul", className)} {...props} />
95+
),
96+
ol: ({ className, ...props }) => (
97+
<ol className={cn("aui-md-ol", className)} {...props} />
98+
),
99+
hr: ({ className, ...props }) => (
100+
<hr className={cn("aui-md-hr", className)} {...props} />
101+
),
102+
table: ({ className, ...props }) => (
103+
<table className={cn("aui-md-table", className)} {...props} />
104+
),
105+
th: ({ className, ...props }) => (
106+
<th className={cn("aui-md-th", className)} {...props} />
107+
),
108+
td: ({ className, ...props }) => (
109+
<td className={cn("aui-md-td", className)} {...props} />
110+
),
111+
tr: ({ className, ...props }) => (
112+
<tr className={cn("aui-md-tr", className)} {...props} />
113+
),
114+
sup: ({ className, ...props }) => (
115+
<sup className={cn("aui-md-sup", className)} {...props} />
116+
),
117+
pre: ({ className, ...props }) => (
118+
<pre className={cn("aui-md-pre", className)} {...props} />
119+
),
120+
code: function Code({ className, ...props }) {
121+
const isCodeBlock = useIsMarkdownCodeBlock();
122+
return (
123+
<code
124+
className={cn(!isCodeBlock && "aui-md-inline-code", className)}
125+
{...props}
126+
/>
127+
);
128+
},
129+
CodeHeader,
130+
});
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import type { FC } from "react";
2+
import {
3+
ThreadListItemPrimitive,
4+
ThreadListPrimitive,
5+
} from "@assistant-ui/react";
6+
import { ArchiveIcon, PlusIcon } from "lucide-react";
7+
8+
import { Button } from "../ui/button";
9+
import { TooltipIconButton } from "./tooltip-icon-button";
10+
11+
export const ThreadList: FC = () => {
12+
return (
13+
<ThreadListPrimitive.Root className="aui-root aui-thread-list-root">
14+
<ThreadListNew />
15+
<ThreadListItems />
16+
</ThreadListPrimitive.Root>
17+
);
18+
};
19+
20+
const ThreadListNew: FC = () => {
21+
return (
22+
<ThreadListPrimitive.New asChild>
23+
<Button className="aui-thread-list-new" variant="ghost">
24+
<PlusIcon />
25+
New Thread
26+
</Button>
27+
</ThreadListPrimitive.New>
28+
);
29+
};
30+
31+
const ThreadListItems: FC = () => {
32+
return <ThreadListPrimitive.Items components={{ ThreadListItem }} />;
33+
};
34+
35+
const ThreadListItem: FC = () => {
36+
return (
37+
<ThreadListItemPrimitive.Root className="aui-thread-list-item">
38+
<ThreadListItemPrimitive.Trigger className="aui-thread-list-item-trigger">
39+
<ThreadListItemTitle />
40+
</ThreadListItemPrimitive.Trigger>
41+
<ThreadListItemArchive />
42+
</ThreadListItemPrimitive.Root>
43+
);
44+
};
45+
46+
const ThreadListItemTitle: FC = () => {
47+
return (
48+
<p className="aui-thread-list-item-title">
49+
<ThreadListItemPrimitive.Title fallback="New Chat" />
50+
</p>
51+
);
52+
};
53+
54+
const ThreadListItemArchive: FC = () => {
55+
return (
56+
<ThreadListItemPrimitive.Archive asChild>
57+
<TooltipIconButton
58+
className="aui-thread-list-item-archive"
59+
variant="ghost"
60+
tooltip="Archive thread"
61+
>
62+
<ArchiveIcon />
63+
</TooltipIconButton>
64+
</ThreadListItemPrimitive.Archive>
65+
);
66+
};

0 commit comments

Comments
 (0)