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 +25 -22
- package/dist/index.d.mts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +88 -1
- package/dist/index.mjs +91 -1
- package/package.json +5 -2
- package/src/ChatPanel.css +26 -20
- package/src/ChatPanel.tsx +77 -4
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
|
-
.
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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.
|
|
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
|
-
.
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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
|
-
.
|
|
335
|
-
|
|
336
|
-
|
|
347
|
+
.side-panel-dark th {
|
|
348
|
+
border: 1px solid #ddd;
|
|
349
|
+
padding: 8px;
|
|
337
350
|
}
|
|
338
351
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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">
|