Skip to content

Commit 3deaf8d

Browse files
committed
prettify chat message
1 parent 186dbcd commit 3deaf8d

File tree

5 files changed

+351
-60
lines changed

5 files changed

+351
-60
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,6 @@ permissions:
1010
contents: read
1111
id-token: write #required for GCP Workload Identity federation which we use to login into Google Artifact Registry
1212

13-
permissions:
14-
contents: read
15-
id-token: write #required for GCP Workload Identity federation which we use to login into Google Artifact Registry
16-
issues: write
17-
pull-requests: write
18-
checks: write
19-
2013
jobs:
2114
lint:
2215
runs-on: ubuntu-latest

apps/nextra/components/chat-widget/chat-dialog.tsx

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import { ChatSidebar } from "./chat-sidebar";
1616
import type { ChatWidgetProps } from "@aptos-labs/ai-chatbot-client";
1717
import { useState, useRef, useEffect } from "react";
1818
import { cn } from "utils/cn";
19+
import Image from "next/image";
20+
import aptosLogo from "../../public/favicon/favicon.png";
1921

2022
export interface ChatDialogProps extends ChatWidgetProps {
2123
open?: boolean;
@@ -96,21 +98,8 @@ export function ChatDialog({
9698
{showTrigger && (
9799
<Dialog.Trigger asChild>
98100
<button className="flex items-center gap-2 text-sm font-medium text-text-primary hover:text-text-link">
99-
<svg
100-
xmlns="http://www.w3.org/2000/svg"
101-
fill="none"
102-
viewBox="0 0 24 24"
103-
strokeWidth={1.5}
104-
stroke="currentColor"
105-
className="w-5 h-5"
106-
>
107-
<path
108-
strokeLinecap="round"
109-
strokeLinejoin="round"
110-
d="M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 01.865-.501 48.172 48.172 0 003.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0012 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018z"
111-
/>
112-
</svg>
113-
Chat with AI
101+
<Image src={aptosLogo} alt="Aptos AI" className="h-4 w-4" />
102+
AskAptos
114103
</button>
115104
</Dialog.Trigger>
116105
)}
@@ -139,7 +128,8 @@ export function ChatDialog({
139128
>
140129
<div className="flex items-center gap-4">
141130
<div className="flex items-center gap-2">
142-
<Dialog.Title className="text-lg font-medium text-white">
131+
<Dialog.Title className="flex items-center gap-2 text-lg font-medium text-white">
132+
<Image src={aptosLogo} alt="Aptos AI" className="h-5 w-5" />
143133
Ask AI
144134
</Dialog.Title>
145135
{showSidebar && user && (
@@ -303,18 +293,41 @@ export function ChatDialog({
303293

304294
{/* Input Area */}
305295
{(!user && !isRateLimited) || user ? (
306-
<div
307-
className="shrink-0 border-t border-[#1F1F1F] bg-[#0F0F0F] px-4"
308-
style={{ height: "var(--footer-height)" }}
309-
>
310-
<ChatInput
311-
ref={chatInputRef}
312-
onSend={onSendMessage}
313-
onStop={onStopGenerating}
314-
isLoading={isGenerating}
315-
className="h-full py-3"
316-
/>
317-
</div>
296+
<>
297+
<div
298+
className="shrink-0 border-t border-[#1F1F1F] bg-[#0F0F0F] px-4"
299+
style={{ height: "var(--footer-height)" }}
300+
>
301+
<ChatInput
302+
ref={chatInputRef}
303+
onSend={onSendMessage}
304+
onStop={onStopGenerating}
305+
isLoading={isGenerating}
306+
className="h-full py-3"
307+
/>
308+
</div>
309+
{/* Disclaimer */}
310+
<div className="text-center px-4 pb-2 text-xs text-gray-400 bg-[#0F0F0F]">
311+
By messaging AskAptos, you agree to our{" "}
312+
<a
313+
href="https://aptoslabs.com/terms"
314+
target="_blank"
315+
rel="noopener noreferrer"
316+
className="text-blue-400 hover:text-blue-300"
317+
>
318+
Terms
319+
</a>{" "}
320+
and have read our{" "}
321+
<a
322+
href="https://aptoslabs.com/privacy"
323+
target="_blank"
324+
rel="noopener noreferrer"
325+
className="text-blue-400 hover:text-blue-300"
326+
>
327+
Privacy Policy
328+
</a>
329+
</div>
330+
</>
318331
) : null}
319332
</div>
320333
</div>

apps/nextra/components/chat-widget/chat-message.tsx

Lines changed: 141 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import remarkGfm from "remark-gfm";
66
import Image from "next/image";
77
import aptosLogo from "../../public/favicon/favicon.png";
88
import { cn } from "utils/cn";
9+
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
10+
import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
911

1012
export interface ChatMessageProps {
1113
message: Message;
@@ -25,39 +27,155 @@ export function ChatMessage({
2527
return (
2628
<div
2729
className={cn(
28-
"flex items-start gap-4 rounded-lg p-4",
29-
isUser ? "bg-gray-900" : "bg-black",
30+
"flex w-full items-start gap-4 p-6 font-['Satoshi']",
31+
isUser ? "bg-black" : "bg-gray-900",
3032
className,
3133
)}
3234
>
3335
{isUser ? (
34-
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-blue-600">
36+
<div className="flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-full bg-blue-600">
3537
<User className="h-4 w-4 text-white" />
3638
</div>
3739
) : (
38-
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-white">
40+
<div className="flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-full bg-white">
3941
<Image src={aptosLogo} alt="Aptos AI" className="h-5 w-5" />
4042
</div>
4143
)}
4244

43-
<div className="flex-1 space-y-2">
44-
<div className="prose prose-invert max-w-none text-white">
45+
<div className="flex min-w-0 flex-1 flex-col gap-2 overflow-hidden">
46+
<div className="prose prose-invert max-w-none break-words text-gray-100">
4547
<ReactMarkdown
4648
remarkPlugins={[remarkGfm]}
4749
components={{
48-
code({ className, children }) {
50+
code(props) {
51+
const { children, className } = props;
52+
// @ts-ignore - inline is actually available in the props
53+
const isInline = props.inline;
54+
55+
if (isInline) {
56+
return (
57+
<code className="rounded bg-gray-800 px-1.5 py-0.5 text-sm text-gray-100 font-mono">
58+
{children}
59+
</code>
60+
);
61+
}
62+
4963
const match = /language-(\w+)/.exec(className || "");
64+
const lang = match ? match[1] : "";
65+
5066
return (
51-
<pre
52-
className={cn(
53-
"rounded-lg bg-gray-800 p-4 text-white",
54-
match && `language-${match[1]}`,
55-
)}
56-
>
57-
<code className={cn("text-white", className)}>
67+
<div className="relative !mt-4 max-w-full">
68+
<div className="absolute right-2 top-2 z-10">
69+
<button
70+
onClick={() => {
71+
navigator.clipboard.writeText(children as string);
72+
}}
73+
className="rounded bg-gray-700/50 p-1.5 text-gray-400 transition-colors hover:bg-gray-700 hover:text-white"
74+
>
75+
<Copy className="h-4 w-4" />
76+
</button>
77+
</div>
78+
<div className="max-w-full overflow-x-auto">
79+
<SyntaxHighlighter
80+
language={lang}
81+
style={oneDark}
82+
customStyle={{
83+
margin: 0,
84+
borderRadius: "0.5rem",
85+
padding: "1rem",
86+
backgroundColor: "rgb(31 41 55)",
87+
}}
88+
codeTagProps={{
89+
className: "font-mono text-sm",
90+
}}
91+
wrapLongLines={true}
92+
>
93+
{String(children).replace(/\n$/, "")}
94+
</SyntaxHighlighter>
95+
</div>
96+
</div>
97+
);
98+
},
99+
p({ children }) {
100+
return (
101+
<p className="mb-4 text-gray-100 text-[0.9375rem] leading-[1.625] font-normal last:mb-0 break-words">
102+
{children}
103+
</p>
104+
);
105+
},
106+
ul({ children }) {
107+
return (
108+
<ul className="mb-4 list-disc pl-4 text-gray-100 text-[0.9375rem] leading-[1.625] last:mb-0">
109+
{children}
110+
</ul>
111+
);
112+
},
113+
ol({ children }) {
114+
return (
115+
<ol className="mb-4 list-decimal pl-4 text-gray-100 text-[0.9375rem] leading-[1.625] last:mb-0">
116+
{children}
117+
</ol>
118+
);
119+
},
120+
li({ children }) {
121+
return (
122+
<li className="mb-1 text-gray-100 text-[0.9375rem] leading-[1.625] last:mb-0">
123+
{children}
124+
</li>
125+
);
126+
},
127+
table({ children }) {
128+
return (
129+
<div className="my-4 w-full overflow-x-auto">
130+
<table className="w-full border-collapse text-left text-gray-100 text-[0.9375rem]">
58131
{children}
59-
</code>
60-
</pre>
132+
</table>
133+
</div>
134+
);
135+
},
136+
th({ children }) {
137+
return (
138+
<th className="border border-gray-600 bg-gray-800 px-4 py-2 text-left text-gray-100 font-semibold">
139+
{children}
140+
</th>
141+
);
142+
},
143+
td({ children }) {
144+
return (
145+
<td className="border border-gray-600 px-4 py-2 text-gray-100 whitespace-normal break-words">
146+
{children}
147+
</td>
148+
);
149+
},
150+
a({ children, href }) {
151+
return (
152+
<a
153+
href={href}
154+
className="text-blue-400 hover:text-blue-300 font-medium break-words"
155+
>
156+
{children}
157+
</a>
158+
);
159+
},
160+
h1({ children }) {
161+
return (
162+
<h1 className="mt-6 mb-4 text-2xl font-semibold text-gray-100 break-words">
163+
{children}
164+
</h1>
165+
);
166+
},
167+
h2({ children }) {
168+
return (
169+
<h2 className="mt-6 mb-4 text-xl font-semibold text-gray-100 break-words">
170+
{children}
171+
</h2>
172+
);
173+
},
174+
h3({ children }) {
175+
return (
176+
<h3 className="mt-6 mb-4 text-lg font-semibold text-gray-100 break-words">
177+
{children}
178+
</h3>
61179
);
62180
},
63181
}}
@@ -67,13 +185,13 @@ export function ChatMessage({
67185
</div>
68186

69187
{!isUser && (
70-
<div className="flex items-center gap-4">
188+
<div className="flex items-center gap-4 pt-2">
71189
<Tooltip.Provider>
72190
<Tooltip.Root>
73-
<Tooltip.Trigger>
191+
<Tooltip.Trigger asChild>
74192
<button
75193
onClick={() => onCopy?.()}
76-
className="text-gray-400 hover:text-white"
194+
className="rounded p-1 text-gray-400 transition-colors hover:bg-[#1F1F1F] hover:text-white"
77195
>
78196
<Copy className="h-4 w-4" />
79197
</button>
@@ -89,11 +207,11 @@ export function ChatMessage({
89207
</Tooltip.Root>
90208

91209
<Tooltip.Root>
92-
<Tooltip.Trigger>
210+
<Tooltip.Trigger asChild>
93211
<button
94212
onClick={() => onFeedback?.("positive")}
95213
className={cn(
96-
"text-gray-400 hover:text-green-500",
214+
"rounded p-1 text-gray-400 transition-colors hover:bg-[#1F1F1F] hover:text-green-500",
97215
message.feedback === "positive" && "text-green-500",
98216
)}
99217
>
@@ -111,11 +229,11 @@ export function ChatMessage({
111229
</Tooltip.Root>
112230

113231
<Tooltip.Root>
114-
<Tooltip.Trigger>
232+
<Tooltip.Trigger asChild>
115233
<button
116234
onClick={() => onFeedback?.("negative")}
117235
className={cn(
118-
"text-gray-400 hover:text-red-500",
236+
"rounded p-1 text-gray-400 transition-colors hover:bg-[#1F1F1F] hover:text-red-500",
119237
message.feedback === "negative" && "text-red-500",
120238
)}
121239
>

apps/nextra/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@
2020
},
2121
"dependencies": {
2222
"@aptos-internal/api-gateway-admin-api-client": "4.1.0",
23+
"@aptos-labs/ai-chatbot-client": "^0.1.0",
2324
"@aptos-labs/aptos-nextra-config": "workspace:*",
2425
"@aptos-labs/github-fetch": "workspace:*",
2526
"@aptos-labs/nextra-components": "workspace:*",
2627
"@graphiql/react": "^0.21.0",
2728
"@graphiql/toolkit": "^0.9.1",
28-
"@aptos-labs/ai-chatbot-client": "^0.1.0",
2929
"@next/third-parties": "^14.1.0",
3030
"@radix-ui/react-accordion": "^1.1.2",
3131
"@radix-ui/react-dialog": "^1.1.14",
@@ -35,6 +35,7 @@
3535
"@scalar/api-reference-react": "0.3.86",
3636
"@scalar/nextjs-api-reference": "0.4.85",
3737
"@tanstack/react-query": "^5.56.2",
38+
"@types/react-syntax-highlighter": "^15.5.13",
3839
"@vercel/og": "^0.5.0",
3940
"class-variance-authority": "^0.7.0",
4041
"clsx": "2.1.0",
@@ -44,8 +45,8 @@
4445
"graphiql": "^3.2.0",
4546
"graphql": "^16.8.1",
4647
"graphql-ws": "^5.16.0",
47-
"next": "^14.2.30",
4848
"lucide-react": "^0.514.0",
49+
"next": "^14.2.30",
4950
"next-sitemap": "^4.2.3",
5051
"nextra": "3.3.1",
5152
"nextra-theme-docs": "3.3.1",
@@ -55,6 +56,7 @@
5556
"react-intersection-observer": "^9.15.1",
5657
"react-markdown": "^10.1.0",
5758
"react-select": "^5.8.0",
59+
"react-syntax-highlighter": "^15.6.1",
5860
"remark-gfm": "^4.0.1",
5961
"sharp": "^0.33.5",
6062
"tailwind-merge": "^2.2.2",

0 commit comments

Comments
 (0)