llmasaservice-ui 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.css CHANGED
@@ -151,6 +151,19 @@
151
151
  .side-panel .scroll-button:hover {
152
152
  background-color: #0056b3;
153
153
  }
154
+ .side-panel table {
155
+ border-collapse: collapse;
156
+ margin-bottom: 1em;
157
+ border: 1px solid #777;
158
+ }
159
+ .side-panel th {
160
+ border: 1px solid #777;
161
+ padding: 8px;
162
+ }
163
+ .side-panel td {
164
+ border: 1px solid #777;
165
+ padding: 8px;
166
+ }
154
167
  .side-panel-dark {
155
168
  font-family:
156
169
  "Roboto",
@@ -306,26 +319,16 @@
306
319
  .side-panel-dark .scroll-button:hover {
307
320
  background-color: #0056b3;
308
321
  }
309
- .chat-status {
310
- display: flex;
311
- align-items: center;
312
- justify-content: center;
313
- padding: 10px;
314
- border-radius: 20px;
315
- background-color: #f0f0f0;
316
- }
317
- .loading-dots {
318
- font-size: 20px;
319
- animation: blink 1s linear infinite;
320
- }
321
- @keyframes blink {
322
- 0% {
323
- opacity: 1;
324
- }
325
- 50% {
326
- opacity: 0;
327
- }
328
- 100% {
329
- opacity: 1;
330
- }
322
+ .side-panel-dark table {
323
+ border-collapse: collapse;
324
+ margin-bottom: 1em;
325
+ border: 1px solid #ddd;
326
+ }
327
+ .side-panel-dark th {
328
+ border: 1px solid #ddd;
329
+ padding: 8px;
330
+ }
331
+ .side-panel-dark td {
332
+ border: 1px solid #ddd;
333
+ padding: 8px;
331
334
  }
package/dist/index.d.mts CHANGED
@@ -22,6 +22,9 @@ interface ChatPanelProps {
22
22
  url?: string | null;
23
23
  scrollToEnd?: boolean;
24
24
  }
25
- declare const ChatPanel: React.FC<ChatPanelProps>;
25
+ interface ExtraProps extends React.HTMLAttributes<HTMLElement> {
26
+ inline?: boolean;
27
+ }
28
+ declare const ChatPanel: React.FC<ChatPanelProps & ExtraProps>;
26
29
 
27
30
  export { ChatPanel, type ChatPanelProps };
package/dist/index.d.ts CHANGED
@@ -22,6 +22,9 @@ interface ChatPanelProps {
22
22
  url?: string | null;
23
23
  scrollToEnd?: boolean;
24
24
  }
25
- declare const ChatPanel: React.FC<ChatPanelProps>;
25
+ interface ExtraProps extends React.HTMLAttributes<HTMLElement> {
26
+ inline?: boolean;
27
+ }
28
+ declare const ChatPanel: React.FC<ChatPanelProps & ExtraProps>;
26
29
 
27
30
  export { ChatPanel, type ChatPanelProps };
package/dist/index.js CHANGED
@@ -22,6 +22,18 @@ var __spreadValues = (a, b) => {
22
22
  return a;
23
23
  };
24
24
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
25
+ var __objRest = (source, exclude) => {
26
+ var target = {};
27
+ for (var prop in source)
28
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
29
+ target[prop] = source[prop];
30
+ if (source != null && __getOwnPropSymbols)
31
+ for (var prop of __getOwnPropSymbols(source)) {
32
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
33
+ target[prop] = source[prop];
34
+ }
35
+ return target;
36
+ };
25
37
  var __export = (target, all) => {
26
38
  for (var name in all)
27
39
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -55,6 +67,9 @@ module.exports = __toCommonJS(llmasaservice_ui_exports);
55
67
  var import_llmasaservice_client = require("llmasaservice-client");
56
68
  var import_react = __toESM(require("react"));
57
69
  var import_react_markdown = __toESM(require("react-markdown"));
70
+ var import_remark_gfm = __toESM(require("remark-gfm"));
71
+ var import_react_syntax_highlighter = require("react-syntax-highlighter");
72
+ var import_prism = require("react-syntax-highlighter/dist/cjs/styles/prism");
58
73
  var ChatPanel = ({
59
74
  project_id,
60
75
  initialPrompt = "",
@@ -167,6 +182,63 @@ var ChatPanel = ({
167
182
  var _a;
168
183
  (_a = bottomRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
169
184
  };
185
+ const CodeBlock = (_a) => {
186
+ var _b = _a, { node, className, children, style } = _b, props = __objRest(_b, ["node", "className", "children", "style"]);
187
+ console.log("CodeBlock", className, children, style, props);
188
+ const match = /language-(\w+)/.exec(className || "");
189
+ return match ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
190
+ "div",
191
+ {
192
+ style: {
193
+ border: 0,
194
+ padding: 0,
195
+ height: "16px",
196
+ display: "flex",
197
+ justifyContent: "space-between",
198
+ alignItems: "center"
199
+ }
200
+ },
201
+ /* @__PURE__ */ import_react.default.createElement("span", null, match ? match[1] : "Unknown"),
202
+ /* @__PURE__ */ import_react.default.createElement(
203
+ "button",
204
+ {
205
+ onClick: () => copyToClipboard(children),
206
+ className: "copy-button"
207
+ },
208
+ /* @__PURE__ */ import_react.default.createElement(
209
+ "svg",
210
+ {
211
+ xmlns: "http://www.w3.org/2000/svg",
212
+ viewBox: "0 0 320 320",
213
+ fill: "currentColor",
214
+ className: "icon-svg"
215
+ },
216
+ /* @__PURE__ */ import_react.default.createElement(
217
+ "path",
218
+ {
219
+ d: "M35,270h45v45c0,8.284,6.716,15,15,15h200c8.284,0,15-6.716,15-15V75c0-8.284-6.716-15-15-15h-45V15\r\n c0-8.284-6.716-15-15-15H35c-8.284,0-15,6.716-15,15v240C20,263.284,26.716,270,35,270z M280,300H110V90h170V300z M50,30h170v30H95\r\n c-8.284,0-15,6.716-15,15v165H50V30z"
220
+ }
221
+ ),
222
+ /* @__PURE__ */ import_react.default.createElement("path", { d: "M155,120c-8.284,0-15,6.716-15,15s6.716,15,15,15h80c8.284,0,15-6.716,15-15s-6.716-15-15-15H155z" }),
223
+ /* @__PURE__ */ import_react.default.createElement("path", { d: "M235,180h-80c-8.284,0-15,6.716-15,15s6.716,15,15,15h80c8.284,0,15-6.716,15-15S243.284,180,235,180z" }),
224
+ /* @__PURE__ */ import_react.default.createElement(
225
+ "path",
226
+ {
227
+ d: "M235,240h-80c-8.284,0-15,6.716-15,15c0,8.284,6.716,15,15,15h80c8.284,0,15-6.716,15-15C250,246.716,243.284,240,235,240z\r\n "
228
+ }
229
+ )
230
+ )
231
+ )
232
+ ), /* @__PURE__ */ import_react.default.createElement(
233
+ import_react_syntax_highlighter.Prism,
234
+ __spreadValues({
235
+ style: theme === "light" ? import_prism.materialLight : import_prism.materialDark,
236
+ PreTag: "div",
237
+ language: match[1]
238
+ }, props),
239
+ String(children).replace(/\n$/, "")
240
+ )) : /* @__PURE__ */ import_react.default.createElement("code", __spreadValues({ className: className ? className : "" }, props), children);
241
+ };
170
242
  return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
171
243
  "div",
172
244
  {
@@ -174,7 +246,22 @@ var ChatPanel = ({
174
246
  className: "side-panel" + (theme === "light" ? "" : "-dark")
175
247
  },
176
248
  /* @__PURE__ */ import_react.default.createElement("div", { className: "title" }, title),
177
- /* @__PURE__ */ import_react.default.createElement("div", { className: "responseArea", ref: responseAreaRef }, initialMessage && initialMessage !== "" ? /* @__PURE__ */ import_react.default.createElement("div", { className: "history-entry" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "response" }, /* @__PURE__ */ import_react.default.createElement(import_react_markdown.default, { className: markdownClass }, initialMessage))) : null, Object.entries(history).map(([prompt, response2], index) => /* @__PURE__ */ import_react.default.createElement("div", { className: "history-entry", key: index }, hideInitialPrompt && index === 0 ? null : /* @__PURE__ */ import_react.default.createElement("div", { className: "prompt" }, prompt), /* @__PURE__ */ import_react.default.createElement("div", { className: "response" }, index === Object.keys(history).length - 1 && isLoading ? /* @__PURE__ */ import_react.default.createElement("div", { className: "loading-text" }, "loading...") : null, /* @__PURE__ */ import_react.default.createElement(import_react_markdown.default, { className: markdownClass }, response2), /* @__PURE__ */ import_react.default.createElement("div", { className: "button-container" }, /* @__PURE__ */ import_react.default.createElement(
249
+ /* @__PURE__ */ import_react.default.createElement("div", { className: "responseArea", ref: responseAreaRef }, initialMessage && initialMessage !== "" ? /* @__PURE__ */ import_react.default.createElement("div", { className: "history-entry" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "response" }, /* @__PURE__ */ import_react.default.createElement(
250
+ import_react_markdown.default,
251
+ {
252
+ className: markdownClass,
253
+ remarkPlugins: [import_remark_gfm.default]
254
+ },
255
+ initialMessage
256
+ ))) : null, Object.entries(history).map(([prompt, response2], index) => /* @__PURE__ */ import_react.default.createElement("div", { className: "history-entry", key: index }, hideInitialPrompt && index === 0 ? null : /* @__PURE__ */ import_react.default.createElement("div", { className: "prompt" }, prompt), /* @__PURE__ */ import_react.default.createElement("div", { className: "response" }, index === Object.keys(history).length - 1 && isLoading ? /* @__PURE__ */ import_react.default.createElement("div", { className: "loading-text" }, "loading...") : null, /* @__PURE__ */ import_react.default.createElement(
257
+ import_react_markdown.default,
258
+ {
259
+ className: markdownClass,
260
+ remarkPlugins: [import_remark_gfm.default],
261
+ components: { code: CodeBlock }
262
+ },
263
+ response2
264
+ ), /* @__PURE__ */ import_react.default.createElement("div", { className: "button-container" }, /* @__PURE__ */ import_react.default.createElement(
178
265
  "button",
179
266
  {
180
267
  className: "copy-button",
package/dist/index.mjs CHANGED
@@ -17,11 +17,29 @@ var __spreadValues = (a, b) => {
17
17
  return a;
18
18
  };
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __objRest = (source, exclude) => {
21
+ var target = {};
22
+ for (var prop in source)
23
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
+ target[prop] = source[prop];
25
+ if (source != null && __getOwnPropSymbols)
26
+ for (var prop of __getOwnPropSymbols(source)) {
27
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
+ target[prop] = source[prop];
29
+ }
30
+ return target;
31
+ };
20
32
 
21
33
  // src/ChatPanel.tsx
22
34
  import { useLLM } from "llmasaservice-client";
23
35
  import React, { useEffect, useRef, useState } from "react";
24
36
  import ReactMarkdown from "react-markdown";
37
+ import remarkGfm from "remark-gfm";
38
+ import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
39
+ import {
40
+ materialLight,
41
+ materialDark
42
+ } from "react-syntax-highlighter/dist/cjs/styles/prism";
25
43
  var ChatPanel = ({
26
44
  project_id,
27
45
  initialPrompt = "",
@@ -134,6 +152,63 @@ var ChatPanel = ({
134
152
  var _a;
135
153
  (_a = bottomRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
136
154
  };
155
+ const CodeBlock = (_a) => {
156
+ var _b = _a, { node, className, children, style } = _b, props = __objRest(_b, ["node", "className", "children", "style"]);
157
+ console.log("CodeBlock", className, children, style, props);
158
+ const match = /language-(\w+)/.exec(className || "");
159
+ return match ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
160
+ "div",
161
+ {
162
+ style: {
163
+ border: 0,
164
+ padding: 0,
165
+ height: "16px",
166
+ display: "flex",
167
+ justifyContent: "space-between",
168
+ alignItems: "center"
169
+ }
170
+ },
171
+ /* @__PURE__ */ React.createElement("span", null, match ? match[1] : "Unknown"),
172
+ /* @__PURE__ */ React.createElement(
173
+ "button",
174
+ {
175
+ onClick: () => copyToClipboard(children),
176
+ className: "copy-button"
177
+ },
178
+ /* @__PURE__ */ React.createElement(
179
+ "svg",
180
+ {
181
+ xmlns: "http://www.w3.org/2000/svg",
182
+ viewBox: "0 0 320 320",
183
+ fill: "currentColor",
184
+ className: "icon-svg"
185
+ },
186
+ /* @__PURE__ */ React.createElement(
187
+ "path",
188
+ {
189
+ d: "M35,270h45v45c0,8.284,6.716,15,15,15h200c8.284,0,15-6.716,15-15V75c0-8.284-6.716-15-15-15h-45V15\r\n c0-8.284-6.716-15-15-15H35c-8.284,0-15,6.716-15,15v240C20,263.284,26.716,270,35,270z M280,300H110V90h170V300z M50,30h170v30H95\r\n c-8.284,0-15,6.716-15,15v165H50V30z"
190
+ }
191
+ ),
192
+ /* @__PURE__ */ React.createElement("path", { d: "M155,120c-8.284,0-15,6.716-15,15s6.716,15,15,15h80c8.284,0,15-6.716,15-15s-6.716-15-15-15H155z" }),
193
+ /* @__PURE__ */ React.createElement("path", { d: "M235,180h-80c-8.284,0-15,6.716-15,15s6.716,15,15,15h80c8.284,0,15-6.716,15-15S243.284,180,235,180z" }),
194
+ /* @__PURE__ */ React.createElement(
195
+ "path",
196
+ {
197
+ d: "M235,240h-80c-8.284,0-15,6.716-15,15c0,8.284,6.716,15,15,15h80c8.284,0,15-6.716,15-15C250,246.716,243.284,240,235,240z\r\n "
198
+ }
199
+ )
200
+ )
201
+ )
202
+ ), /* @__PURE__ */ React.createElement(
203
+ SyntaxHighlighter,
204
+ __spreadValues({
205
+ style: theme === "light" ? materialLight : materialDark,
206
+ PreTag: "div",
207
+ language: match[1]
208
+ }, props),
209
+ String(children).replace(/\n$/, "")
210
+ )) : /* @__PURE__ */ React.createElement("code", __spreadValues({ className: className ? className : "" }, props), children);
211
+ };
137
212
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
138
213
  "div",
139
214
  {
@@ -141,7 +216,22 @@ var ChatPanel = ({
141
216
  className: "side-panel" + (theme === "light" ? "" : "-dark")
142
217
  },
143
218
  /* @__PURE__ */ React.createElement("div", { className: "title" }, title),
144
- /* @__PURE__ */ React.createElement("div", { className: "responseArea", ref: responseAreaRef }, initialMessage && initialMessage !== "" ? /* @__PURE__ */ React.createElement("div", { className: "history-entry" }, /* @__PURE__ */ React.createElement("div", { className: "response" }, /* @__PURE__ */ React.createElement(ReactMarkdown, { className: markdownClass }, initialMessage))) : null, Object.entries(history).map(([prompt, response2], index) => /* @__PURE__ */ React.createElement("div", { className: "history-entry", key: index }, hideInitialPrompt && index === 0 ? null : /* @__PURE__ */ React.createElement("div", { className: "prompt" }, prompt), /* @__PURE__ */ React.createElement("div", { className: "response" }, index === Object.keys(history).length - 1 && isLoading ? /* @__PURE__ */ React.createElement("div", { className: "loading-text" }, "loading...") : null, /* @__PURE__ */ React.createElement(ReactMarkdown, { className: markdownClass }, response2), /* @__PURE__ */ React.createElement("div", { className: "button-container" }, /* @__PURE__ */ React.createElement(
219
+ /* @__PURE__ */ React.createElement("div", { className: "responseArea", ref: responseAreaRef }, initialMessage && initialMessage !== "" ? /* @__PURE__ */ React.createElement("div", { className: "history-entry" }, /* @__PURE__ */ React.createElement("div", { className: "response" }, /* @__PURE__ */ React.createElement(
220
+ ReactMarkdown,
221
+ {
222
+ className: markdownClass,
223
+ remarkPlugins: [remarkGfm]
224
+ },
225
+ initialMessage
226
+ ))) : null, Object.entries(history).map(([prompt, response2], index) => /* @__PURE__ */ React.createElement("div", { className: "history-entry", key: index }, hideInitialPrompt && index === 0 ? null : /* @__PURE__ */ React.createElement("div", { className: "prompt" }, prompt), /* @__PURE__ */ React.createElement("div", { className: "response" }, index === Object.keys(history).length - 1 && isLoading ? /* @__PURE__ */ React.createElement("div", { className: "loading-text" }, "loading...") : null, /* @__PURE__ */ React.createElement(
227
+ ReactMarkdown,
228
+ {
229
+ className: markdownClass,
230
+ remarkPlugins: [remarkGfm],
231
+ components: { code: CodeBlock }
232
+ },
233
+ response2
234
+ ), /* @__PURE__ */ React.createElement("div", { className: "button-container" }, /* @__PURE__ */ React.createElement(
145
235
  "button",
146
236
  {
147
237
  className: "copy-button",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llmasaservice-ui",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "Prebuilt UI components for LLMAsAService.io",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -30,6 +30,7 @@
30
30
  "@storybook/react-webpack5": "^8.2.7",
31
31
  "@storybook/test": "^8.2.7",
32
32
  "@types/react": "^18.3.3",
33
+ "@types/react-syntax-highlighter": "^15.5.13",
33
34
  "react": "^18.3.1",
34
35
  "storybook": "^8.2.7",
35
36
  "tsup": "^8.2.4",
@@ -44,7 +45,9 @@
44
45
  ],
45
46
  "dependencies": {
46
47
  "llmasaservice-client": "^0.4.0",
47
- "react-markdown": "^9.0.1"
48
+ "react-markdown": "^9.0.1",
49
+ "react-syntax-highlighter": "^15.5.0",
50
+ "remark-gfm": "^4.0.0"
48
51
  },
49
52
  "peerDependencies": {
50
53
  "react": "^18.3.0",
package/src/ChatPanel.css CHANGED
@@ -165,6 +165,22 @@
165
165
  background-color: #0056b3;
166
166
  }
167
167
 
168
+ .side-panel table {
169
+ border-collapse: collapse;
170
+ margin-bottom: 1em;
171
+ border: 1px solid #777;
172
+ }
173
+
174
+ .side-panel th {
175
+ border: 1px solid #777;
176
+ padding: 8px;
177
+ }
178
+
179
+ .side-panel td {
180
+ border: 1px solid #777;
181
+ padding: 8px;
182
+ }
183
+
168
184
  .side-panel-dark {
169
185
  font-family: "Roboto", Arial, Helvetica, sans-serif;
170
186
  font-size: small;
@@ -322,28 +338,18 @@
322
338
  background-color: #0056b3;
323
339
  }
324
340
 
325
- .chat-status {
326
- display: flex;
327
- align-items: center;
328
- justify-content: center;
329
- padding: 10px;
330
- border-radius: 20px;
331
- background-color: #f0f0f0;
341
+ .side-panel-dark table {
342
+ border-collapse: collapse;
343
+ margin-bottom: 1em;
344
+ border: 1px solid #ddd;
332
345
  }
333
346
 
334
- .loading-dots {
335
- font-size: 20px;
336
- animation: blink 1s linear infinite;
347
+ .side-panel-dark th {
348
+ border: 1px solid #ddd;
349
+ padding: 8px;
337
350
  }
338
351
 
339
- @keyframes blink {
340
- 0% {
341
- opacity: 1;
342
- }
343
- 50% {
344
- opacity: 0;
345
- }
346
- 100% {
347
- opacity: 1;
348
- }
352
+ .side-panel-dark td {
353
+ border: 1px solid #ddd;
354
+ padding: 8px;
349
355
  }
package/src/ChatPanel.tsx CHANGED
@@ -2,7 +2,12 @@ import { LLMAsAServiceCustomer, useLLM } from "llmasaservice-client";
2
2
  import React, { useEffect, useRef, useState } from "react";
3
3
  import ReactMarkdown from "react-markdown";
4
4
  import "./ChatPanel.css";
5
- import ChatStatus from "./ChatStatus";
5
+ import remarkGfm from "remark-gfm";
6
+ import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
7
+ import {
8
+ materialLight,
9
+ materialDark,
10
+ } from "react-syntax-highlighter/dist/cjs/styles/prism";
6
11
 
7
12
  export interface ChatPanelProps {
8
13
  project_id: string;
@@ -23,7 +28,11 @@ export interface ChatPanelProps {
23
28
  scrollToEnd?: boolean;
24
29
  }
25
30
 
26
- const ChatPanel: React.FC<ChatPanelProps> = ({
31
+ interface ExtraProps extends React.HTMLAttributes<HTMLElement> {
32
+ inline?: boolean;
33
+ }
34
+
35
+ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
27
36
  project_id,
28
37
  initialPrompt = "",
29
38
  title = "Chat",
@@ -162,6 +171,63 @@ const ChatPanel: React.FC<ChatPanelProps> = ({
162
171
  bottomRef.current?.scrollIntoView({ behavior: "smooth" });
163
172
  };
164
173
 
174
+ const CodeBlock = ({ node, className, children, style, ...props }: any) => {
175
+ console.log("CodeBlock", className, children, style, props);
176
+ const match = /language-(\w+)/.exec(className || "");
177
+
178
+ return match ? (
179
+ <>
180
+ <div
181
+ style={{
182
+ border: 0,
183
+ padding: 0,
184
+ height: "16px",
185
+ display: "flex",
186
+ justifyContent: "space-between",
187
+ alignItems: "center",
188
+ }}
189
+ >
190
+ <span>{match ? match[1] : "Unknown"}</span>
191
+ <button
192
+ onClick={() => copyToClipboard(children)}
193
+ className="copy-button"
194
+ >
195
+ <svg
196
+ xmlns="http://www.w3.org/2000/svg"
197
+ viewBox="0 0 320 320"
198
+ fill="currentColor"
199
+ className="icon-svg"
200
+ >
201
+ <path
202
+ d="M35,270h45v45c0,8.284,6.716,15,15,15h200c8.284,0,15-6.716,15-15V75c0-8.284-6.716-15-15-15h-45V15
203
+ c0-8.284-6.716-15-15-15H35c-8.284,0-15,6.716-15,15v240C20,263.284,26.716,270,35,270z M280,300H110V90h170V300z M50,30h170v30H95
204
+ c-8.284,0-15,6.716-15,15v165H50V30z"
205
+ />
206
+ <path d="M155,120c-8.284,0-15,6.716-15,15s6.716,15,15,15h80c8.284,0,15-6.716,15-15s-6.716-15-15-15H155z" />
207
+ <path d="M235,180h-80c-8.284,0-15,6.716-15,15s6.716,15,15,15h80c8.284,0,15-6.716,15-15S243.284,180,235,180z" />
208
+ <path
209
+ d="M235,240h-80c-8.284,0-15,6.716-15,15c0,8.284,6.716,15,15,15h80c8.284,0,15-6.716,15-15C250,246.716,243.284,240,235,240z
210
+ "
211
+ />
212
+ </svg>
213
+ </button>
214
+ </div>
215
+ <SyntaxHighlighter
216
+ style={theme === "light" ? materialLight : materialDark}
217
+ PreTag="div"
218
+ language={match[1]}
219
+ {...props}
220
+ >
221
+ {String(children).replace(/\n$/, "")}
222
+ </SyntaxHighlighter>
223
+ </>
224
+ ) : (
225
+ <code className={className ? className : ""} {...props}>
226
+ {children}
227
+ </code>
228
+ );
229
+ };
230
+
165
231
  return (
166
232
  <>
167
233
  <div
@@ -173,7 +239,10 @@ const ChatPanel: React.FC<ChatPanelProps> = ({
173
239
  {initialMessage && initialMessage !== "" ? (
174
240
  <div className="history-entry">
175
241
  <div className="response">
176
- <ReactMarkdown className={markdownClass}>
242
+ <ReactMarkdown
243
+ className={markdownClass}
244
+ remarkPlugins={[remarkGfm]}
245
+ >
177
246
  {initialMessage}
178
247
  </ReactMarkdown>
179
248
  </div>
@@ -189,7 +258,11 @@ const ChatPanel: React.FC<ChatPanelProps> = ({
189
258
  {index === Object.keys(history).length - 1 && isLoading ? (
190
259
  <div className="loading-text">loading...</div>
191
260
  ) : null}
192
- <ReactMarkdown className={markdownClass}>
261
+ <ReactMarkdown
262
+ className={markdownClass}
263
+ remarkPlugins={[remarkGfm]}
264
+ components={{ code: CodeBlock }}
265
+ >
193
266
  {response}
194
267
  </ReactMarkdown>
195
268
  <div className="button-container">