@gendive/chatllm 0.6.4 → 0.6.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/react/index.js +159 -10
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +160 -11
- package/dist/react/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react/index.js
CHANGED
|
@@ -1882,18 +1882,11 @@ var parseInlineElements = (text, key) => {
|
|
|
1882
1882
|
if (match) {
|
|
1883
1883
|
elements.push(
|
|
1884
1884
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1885
|
-
|
|
1885
|
+
ImageWithCopyButton,
|
|
1886
1886
|
{
|
|
1887
1887
|
src: match[2],
|
|
1888
1888
|
alt: match[1] || "",
|
|
1889
|
-
|
|
1890
|
-
style: {
|
|
1891
|
-
maxWidth: "100%",
|
|
1892
|
-
borderRadius: "8px",
|
|
1893
|
-
margin: "8px 0",
|
|
1894
|
-
display: "block"
|
|
1895
|
-
},
|
|
1896
|
-
loading: "lazy"
|
|
1889
|
+
imageKey: `${key}-image-${index}`
|
|
1897
1890
|
},
|
|
1898
1891
|
`${key}-image-${index}`
|
|
1899
1892
|
)
|
|
@@ -2066,6 +2059,162 @@ var CodeBlock = ({ language, code }) => {
|
|
|
2066
2059
|
}
|
|
2067
2060
|
);
|
|
2068
2061
|
};
|
|
2062
|
+
var ImageWithCopyButton = ({ src, alt, imageKey }) => {
|
|
2063
|
+
const [isHovered, setIsHovered] = import_react5.default.useState(false);
|
|
2064
|
+
const [copyState, setCopyState] = import_react5.default.useState("idle");
|
|
2065
|
+
const handleCopyImage = async () => {
|
|
2066
|
+
setCopyState("copying");
|
|
2067
|
+
try {
|
|
2068
|
+
const response = await fetch(src);
|
|
2069
|
+
if (!response.ok) throw new Error("Failed to fetch image");
|
|
2070
|
+
const blob = await response.blob();
|
|
2071
|
+
if (navigator.clipboard && navigator.clipboard.write) {
|
|
2072
|
+
let imageBlob = blob;
|
|
2073
|
+
if (blob.type !== "image/png") {
|
|
2074
|
+
const img = new Image();
|
|
2075
|
+
img.crossOrigin = "anonymous";
|
|
2076
|
+
await new Promise((resolve, reject) => {
|
|
2077
|
+
img.onload = () => {
|
|
2078
|
+
const canvas = document.createElement("canvas");
|
|
2079
|
+
canvas.width = img.naturalWidth;
|
|
2080
|
+
canvas.height = img.naturalHeight;
|
|
2081
|
+
const ctx = canvas.getContext("2d");
|
|
2082
|
+
if (!ctx) {
|
|
2083
|
+
reject(new Error("Failed to get canvas context"));
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
2086
|
+
ctx.drawImage(img, 0, 0);
|
|
2087
|
+
canvas.toBlob((pngBlob) => {
|
|
2088
|
+
if (pngBlob) {
|
|
2089
|
+
imageBlob = pngBlob;
|
|
2090
|
+
resolve();
|
|
2091
|
+
} else {
|
|
2092
|
+
reject(new Error("Failed to convert to PNG"));
|
|
2093
|
+
}
|
|
2094
|
+
}, "image/png");
|
|
2095
|
+
};
|
|
2096
|
+
img.onerror = () => reject(new Error("Failed to load image"));
|
|
2097
|
+
img.src = URL.createObjectURL(blob);
|
|
2098
|
+
});
|
|
2099
|
+
}
|
|
2100
|
+
await navigator.clipboard.write([
|
|
2101
|
+
new ClipboardItem({
|
|
2102
|
+
[imageBlob.type]: imageBlob
|
|
2103
|
+
})
|
|
2104
|
+
]);
|
|
2105
|
+
setCopyState("copied");
|
|
2106
|
+
setTimeout(() => setCopyState("idle"), 2e3);
|
|
2107
|
+
} else {
|
|
2108
|
+
await navigator.clipboard.writeText(src);
|
|
2109
|
+
setCopyState("copied");
|
|
2110
|
+
setTimeout(() => setCopyState("idle"), 2e3);
|
|
2111
|
+
}
|
|
2112
|
+
} catch (error) {
|
|
2113
|
+
console.error("Failed to copy image:", error);
|
|
2114
|
+
setCopyState("error");
|
|
2115
|
+
setTimeout(() => setCopyState("idle"), 2e3);
|
|
2116
|
+
}
|
|
2117
|
+
};
|
|
2118
|
+
const getCopyButtonText = () => {
|
|
2119
|
+
switch (copyState) {
|
|
2120
|
+
case "copying":
|
|
2121
|
+
return "\uBCF5\uC0AC \uC911...";
|
|
2122
|
+
case "copied":
|
|
2123
|
+
return "\uBCF5\uC0AC\uB428!";
|
|
2124
|
+
case "error":
|
|
2125
|
+
return "\uBCF5\uC0AC \uC2E4\uD328";
|
|
2126
|
+
default:
|
|
2127
|
+
return "\uC774\uBBF8\uC9C0 \uBCF5\uC0AC";
|
|
2128
|
+
}
|
|
2129
|
+
};
|
|
2130
|
+
const getCopyButtonColor = () => {
|
|
2131
|
+
switch (copyState) {
|
|
2132
|
+
case "copied":
|
|
2133
|
+
return "var(--chatllm-success, #22c55e)";
|
|
2134
|
+
case "error":
|
|
2135
|
+
return "var(--chatllm-error, #ef4444)";
|
|
2136
|
+
default:
|
|
2137
|
+
return "var(--chatllm-text, #ffffff)";
|
|
2138
|
+
}
|
|
2139
|
+
};
|
|
2140
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2141
|
+
"div",
|
|
2142
|
+
{
|
|
2143
|
+
style: {
|
|
2144
|
+
position: "relative",
|
|
2145
|
+
display: "inline-block",
|
|
2146
|
+
margin: "8px 0"
|
|
2147
|
+
},
|
|
2148
|
+
onMouseEnter: () => setIsHovered(true),
|
|
2149
|
+
onMouseLeave: () => setIsHovered(false),
|
|
2150
|
+
children: [
|
|
2151
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2152
|
+
"img",
|
|
2153
|
+
{
|
|
2154
|
+
src,
|
|
2155
|
+
alt,
|
|
2156
|
+
className: "chatllm-image",
|
|
2157
|
+
style: {
|
|
2158
|
+
maxWidth: "100%",
|
|
2159
|
+
borderRadius: "8px",
|
|
2160
|
+
display: "block"
|
|
2161
|
+
},
|
|
2162
|
+
loading: "lazy"
|
|
2163
|
+
}
|
|
2164
|
+
),
|
|
2165
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2166
|
+
"button",
|
|
2167
|
+
{
|
|
2168
|
+
onClick: handleCopyImage,
|
|
2169
|
+
disabled: copyState === "copying",
|
|
2170
|
+
style: {
|
|
2171
|
+
position: "absolute",
|
|
2172
|
+
top: "8px",
|
|
2173
|
+
right: "8px",
|
|
2174
|
+
display: "flex",
|
|
2175
|
+
alignItems: "center",
|
|
2176
|
+
gap: "6px",
|
|
2177
|
+
padding: "6px 12px",
|
|
2178
|
+
backgroundColor: "rgba(0, 0, 0, 0.7)",
|
|
2179
|
+
color: getCopyButtonColor(),
|
|
2180
|
+
border: "none",
|
|
2181
|
+
borderRadius: "6px",
|
|
2182
|
+
fontSize: "12px",
|
|
2183
|
+
fontWeight: 500,
|
|
2184
|
+
cursor: copyState === "copying" ? "wait" : "pointer",
|
|
2185
|
+
opacity: isHovered || copyState !== "idle" ? 1 : 0,
|
|
2186
|
+
transform: isHovered || copyState !== "idle" ? "translateY(0)" : "translateY(-4px)",
|
|
2187
|
+
transition: "opacity 0.2s ease, transform 0.2s ease",
|
|
2188
|
+
backdropFilter: "blur(4px)",
|
|
2189
|
+
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.2)"
|
|
2190
|
+
},
|
|
2191
|
+
children: [
|
|
2192
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2193
|
+
"svg",
|
|
2194
|
+
{
|
|
2195
|
+
width: "14",
|
|
2196
|
+
height: "14",
|
|
2197
|
+
viewBox: "0 0 24 24",
|
|
2198
|
+
fill: "none",
|
|
2199
|
+
stroke: "currentColor",
|
|
2200
|
+
strokeWidth: "2",
|
|
2201
|
+
strokeLinecap: "round",
|
|
2202
|
+
strokeLinejoin: "round",
|
|
2203
|
+
children: copyState === "copied" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("polyline", { points: "20 6 9 17 4 12" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2204
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
|
|
2205
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
2206
|
+
] })
|
|
2207
|
+
}
|
|
2208
|
+
),
|
|
2209
|
+
getCopyButtonText()
|
|
2210
|
+
]
|
|
2211
|
+
}
|
|
2212
|
+
)
|
|
2213
|
+
]
|
|
2214
|
+
},
|
|
2215
|
+
imageKey
|
|
2216
|
+
);
|
|
2217
|
+
};
|
|
2069
2218
|
var ChoiceButtons = ({ choices, onChoiceClick }) => {
|
|
2070
2219
|
const [hoveredIndex, setHoveredIndex] = import_react5.default.useState(null);
|
|
2071
2220
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
@@ -4422,7 +4571,7 @@ var ChatUI = ({
|
|
|
4422
4571
|
]
|
|
4423
4572
|
}
|
|
4424
4573
|
),
|
|
4425
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
4574
|
+
showSettings && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
4426
4575
|
MemoryPanel,
|
|
4427
4576
|
{
|
|
4428
4577
|
items: memoryItems,
|