@malette/agent-sdk 0.1.3-beta.12 → 0.1.3-beta.13
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.js +586 -46
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +586 -46
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +11 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -499,10 +499,16 @@ var artifactService = {
|
|
|
499
499
|
/**
|
|
500
500
|
* 更新产物内容(用户编辑后保存)
|
|
501
501
|
*/
|
|
502
|
-
updateContent: async (artifactId, content) => {
|
|
502
|
+
updateContent: async (artifactId, content, options) => {
|
|
503
503
|
return fetcher(`${API_BASE}/artifacts/${artifactId}/content`, {
|
|
504
504
|
method: "PUT",
|
|
505
|
-
body: JSON.stringify({
|
|
505
|
+
body: JSON.stringify({
|
|
506
|
+
artifactId,
|
|
507
|
+
content,
|
|
508
|
+
...options?.type && { type: options.type },
|
|
509
|
+
...options?.language !== void 0 && { language: options.language },
|
|
510
|
+
...options?.title !== void 0 && { title: options.title }
|
|
511
|
+
})
|
|
506
512
|
});
|
|
507
513
|
},
|
|
508
514
|
/**
|
|
@@ -1707,6 +1713,25 @@ var useAgentStore = zustand.create()(
|
|
|
1707
1713
|
false,
|
|
1708
1714
|
"updateArtifactVisibility"
|
|
1709
1715
|
),
|
|
1716
|
+
updateArtifactType: (artifactId, type, language) => set(
|
|
1717
|
+
(state) => {
|
|
1718
|
+
const existing = state.artifacts[artifactId];
|
|
1719
|
+
if (!existing) return state;
|
|
1720
|
+
return {
|
|
1721
|
+
artifacts: {
|
|
1722
|
+
...state.artifacts,
|
|
1723
|
+
[artifactId]: {
|
|
1724
|
+
...existing,
|
|
1725
|
+
type,
|
|
1726
|
+
language: language ?? existing.language,
|
|
1727
|
+
gmtModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
};
|
|
1731
|
+
},
|
|
1732
|
+
false,
|
|
1733
|
+
"updateArtifactType"
|
|
1734
|
+
),
|
|
1710
1735
|
// ============ 复合操作 ============
|
|
1711
1736
|
startNewChat: (sessionId) => {
|
|
1712
1737
|
set(
|
|
@@ -7809,6 +7834,104 @@ var resolveAssetForDisplay = async (asset, config) => {
|
|
|
7809
7834
|
}
|
|
7810
7835
|
return null;
|
|
7811
7836
|
};
|
|
7837
|
+
var resolveHtmlAssetUrls = (html2) => {
|
|
7838
|
+
const origin = typeof window !== "undefined" ? window.location.origin : "";
|
|
7839
|
+
const resolveSrc = (src, isVideo) => {
|
|
7840
|
+
if (!src.trim()) return src;
|
|
7841
|
+
if (/^(data:|blob:|javascript:|#)/i.test(src)) return src;
|
|
7842
|
+
if (src.includes("${")) return src;
|
|
7843
|
+
if (/^https?:/i.test(src)) {
|
|
7844
|
+
if (src.includes("industryai")) {
|
|
7845
|
+
return src.split("?")[0];
|
|
7846
|
+
}
|
|
7847
|
+
return src;
|
|
7848
|
+
}
|
|
7849
|
+
const resolved = isVideo ? getHDImageUrl(src) : getImageUrl(src);
|
|
7850
|
+
return resolved.startsWith("http") ? resolved : `${origin}${resolved}`;
|
|
7851
|
+
};
|
|
7852
|
+
const processHtmlPart = (part) => {
|
|
7853
|
+
let result = part.replace(
|
|
7854
|
+
/(<(?:img|video|source)\s[^>]*?\bsrc\s*=\s*["'])([^"']*)(["'])/gi,
|
|
7855
|
+
(match, prefix, src, suffix) => {
|
|
7856
|
+
const tagMatch = match.match(/^<(\w+)/i);
|
|
7857
|
+
const tag = tagMatch?.[1]?.toLowerCase() ?? "";
|
|
7858
|
+
const isVideo = tag === "video" || tag === "source";
|
|
7859
|
+
return `${prefix}${resolveSrc(src, isVideo)}${suffix}`;
|
|
7860
|
+
}
|
|
7861
|
+
);
|
|
7862
|
+
result = result.replace(
|
|
7863
|
+
/(<video\s[^>]*?\bposter\s*=\s*["'])([^"']*)(["'])/gi,
|
|
7864
|
+
(match, prefix, src, suffix) => `${prefix}${resolveSrc(src, false)}${suffix}`
|
|
7865
|
+
);
|
|
7866
|
+
return result;
|
|
7867
|
+
};
|
|
7868
|
+
const parts = html2.split(/(<script\b[\s\S]*?<\/script>)/gi);
|
|
7869
|
+
return parts.map((part, i) => i % 2 === 1 ? part : processHtmlPart(part)).join("");
|
|
7870
|
+
};
|
|
7871
|
+
var resolveHtmlAssetUrlsAsync = async (html2, config) => {
|
|
7872
|
+
if (!config?.asset) return resolveHtmlAssetUrls(html2);
|
|
7873
|
+
const srcPattern = /(<(?:img|video|source)\s[^>]*?\bsrc\s*=\s*["'])([^"']*)(["'])/gi;
|
|
7874
|
+
const posterPattern = /(<video\s[^>]*?\bposter\s*=\s*["'])([^"']*)(["'])/gi;
|
|
7875
|
+
const scriptSplitPattern = /(<script\b[\s\S]*?<\/script>)/gi;
|
|
7876
|
+
const parts = html2.split(scriptSplitPattern);
|
|
7877
|
+
const nonScriptHtml = parts.filter((_, i) => i % 2 === 0).join("");
|
|
7878
|
+
const urlsToResolve = /* @__PURE__ */ new Map();
|
|
7879
|
+
const collectUrl = (src) => {
|
|
7880
|
+
if (!src.trim()) return;
|
|
7881
|
+
if (/^(data:|blob:|javascript:|#)/i.test(src)) return;
|
|
7882
|
+
if (src.includes("${")) return;
|
|
7883
|
+
urlsToResolve.set(src, src);
|
|
7884
|
+
};
|
|
7885
|
+
let match;
|
|
7886
|
+
const srcRe = new RegExp(srcPattern.source, srcPattern.flags);
|
|
7887
|
+
while ((match = srcRe.exec(nonScriptHtml)) !== null) {
|
|
7888
|
+
collectUrl(match[2]);
|
|
7889
|
+
}
|
|
7890
|
+
const posterRe = new RegExp(posterPattern.source, posterPattern.flags);
|
|
7891
|
+
while ((match = posterRe.exec(nonScriptHtml)) !== null) {
|
|
7892
|
+
collectUrl(match[2]);
|
|
7893
|
+
}
|
|
7894
|
+
await Promise.all(
|
|
7895
|
+
Array.from(urlsToResolve.keys()).map(async (src) => {
|
|
7896
|
+
const tagMatch = nonScriptHtml.match(
|
|
7897
|
+
new RegExp(`<(img|video|source)[^>]*(?:src|poster)=["']${src.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']`, "i")
|
|
7898
|
+
);
|
|
7899
|
+
const tag = tagMatch?.[1]?.toLowerCase() ?? "";
|
|
7900
|
+
const isVideo = tag === "video" || tag === "source";
|
|
7901
|
+
const type = isVideo ? "video" : "image";
|
|
7902
|
+
const isHttp = /^https?:/i.test(src);
|
|
7903
|
+
const asset = createAssetFromSource({
|
|
7904
|
+
fileId: !isHttp ? src : void 0,
|
|
7905
|
+
fileUrl: isHttp ? src : void 0,
|
|
7906
|
+
type
|
|
7907
|
+
});
|
|
7908
|
+
if (!asset) return;
|
|
7909
|
+
const resolved = await resolveAssetForDisplay(asset, config);
|
|
7910
|
+
if (resolved) {
|
|
7911
|
+
urlsToResolve.set(src, resolved.url);
|
|
7912
|
+
}
|
|
7913
|
+
})
|
|
7914
|
+
);
|
|
7915
|
+
const processedParts = parts.map((part, i) => {
|
|
7916
|
+
if (i % 2 === 1) return part;
|
|
7917
|
+
let result = part.replace(
|
|
7918
|
+
/(<(?:img|video|source)\s[^>]*?\bsrc\s*=\s*["'])([^"']*)(["'])/gi,
|
|
7919
|
+
(m, prefix, src, suffix) => {
|
|
7920
|
+
const resolved = urlsToResolve.get(src);
|
|
7921
|
+
return resolved && resolved !== src ? `${prefix}${resolved}${suffix}` : m;
|
|
7922
|
+
}
|
|
7923
|
+
);
|
|
7924
|
+
result = result.replace(
|
|
7925
|
+
/(<video\s[^>]*?\bposter\s*=\s*["'])([^"']*)(["'])/gi,
|
|
7926
|
+
(m, prefix, src, suffix) => {
|
|
7927
|
+
const resolved = urlsToResolve.get(src);
|
|
7928
|
+
return resolved && resolved !== src ? `${prefix}${resolved}${suffix}` : m;
|
|
7929
|
+
}
|
|
7930
|
+
);
|
|
7931
|
+
return result;
|
|
7932
|
+
});
|
|
7933
|
+
return processedParts.join("");
|
|
7934
|
+
};
|
|
7812
7935
|
var ComponentContext = React16.createContext(void 0);
|
|
7813
7936
|
var ComponentProvider = ({
|
|
7814
7937
|
components = {},
|
|
@@ -16260,10 +16383,10 @@ var Observer = class {
|
|
|
16260
16383
|
});
|
|
16261
16384
|
}
|
|
16262
16385
|
};
|
|
16263
|
-
this.custom = (
|
|
16386
|
+
this.custom = (jsx68, data) => {
|
|
16264
16387
|
const id = (data == null ? void 0 : data.id) || toastsCounter++;
|
|
16265
16388
|
this.create({
|
|
16266
|
-
jsx:
|
|
16389
|
+
jsx: jsx68(id),
|
|
16267
16390
|
id,
|
|
16268
16391
|
...data
|
|
16269
16392
|
});
|
|
@@ -21772,15 +21895,24 @@ var CodeBlock3 = React16.memo(function CodeBlock4({
|
|
|
21772
21895
|
] }, i)) }) }) })
|
|
21773
21896
|
] });
|
|
21774
21897
|
});
|
|
21775
|
-
var HtmlPreview3 = React16.memo(function HtmlPreview4({
|
|
21898
|
+
var HtmlPreview3 = React16.memo(function HtmlPreview4({
|
|
21899
|
+
content,
|
|
21900
|
+
config
|
|
21901
|
+
}) {
|
|
21776
21902
|
const [scale, setScale] = React16.useState(1);
|
|
21777
21903
|
const [deviceMode, setDeviceMode] = React16.useState("responsive");
|
|
21778
21904
|
const [isLoading, setIsLoading] = React16.useState(true);
|
|
21779
21905
|
const [iframeHeight, setIframeHeight] = React16.useState(600);
|
|
21780
21906
|
const iframeRef = React16.useRef(null);
|
|
21781
21907
|
const containerRef = React16.useRef(null);
|
|
21782
|
-
const blobUrl = React16.
|
|
21783
|
-
|
|
21908
|
+
const [blobUrl, setBlobUrl] = React16.useState("");
|
|
21909
|
+
React16.useEffect(() => {
|
|
21910
|
+
let active = true;
|
|
21911
|
+
let currentUrl = "";
|
|
21912
|
+
const buildBlobUrl = async () => {
|
|
21913
|
+
const processed = config?.asset ? await resolveHtmlAssetUrlsAsync(content, config) : resolveHtmlAssetUrls(content);
|
|
21914
|
+
if (!active) return;
|
|
21915
|
+
const styleInjection = `
|
|
21784
21916
|
<style>
|
|
21785
21917
|
html, body {
|
|
21786
21918
|
margin: 0;
|
|
@@ -21794,24 +21926,26 @@ var HtmlPreview3 = React16.memo(function HtmlPreview4({ content }) {
|
|
|
21794
21926
|
}
|
|
21795
21927
|
</style>
|
|
21796
21928
|
`;
|
|
21797
|
-
|
|
21798
|
-
|
|
21799
|
-
|
|
21800
|
-
|
|
21801
|
-
|
|
21802
|
-
|
|
21803
|
-
|
|
21804
|
-
|
|
21805
|
-
|
|
21806
|
-
|
|
21807
|
-
|
|
21808
|
-
|
|
21809
|
-
|
|
21810
|
-
|
|
21929
|
+
let modifiedContent = processed;
|
|
21930
|
+
if (processed.includes("<head>")) {
|
|
21931
|
+
modifiedContent = processed.replace("<head>", "<head>" + styleInjection);
|
|
21932
|
+
} else if (processed.includes("<html>")) {
|
|
21933
|
+
modifiedContent = processed.replace("<html>", "<html><head>" + styleInjection + "</head>");
|
|
21934
|
+
} else if (processed.includes("<!DOCTYPE") || processed.includes("<!doctype")) {
|
|
21935
|
+
modifiedContent = processed.replace(/(<!DOCTYPE[^>]*>|<!doctype[^>]*>)/i, "$1<html><head>" + styleInjection + "</head><body>") + "</body></html>";
|
|
21936
|
+
} else {
|
|
21937
|
+
modifiedContent = `<!DOCTYPE html><html><head>${styleInjection}</head><body>${processed}</body></html>`;
|
|
21938
|
+
}
|
|
21939
|
+
const blob = new Blob([modifiedContent], { type: "text/html" });
|
|
21940
|
+
currentUrl = URL.createObjectURL(blob);
|
|
21941
|
+
setBlobUrl(currentUrl);
|
|
21942
|
+
};
|
|
21943
|
+
buildBlobUrl();
|
|
21811
21944
|
return () => {
|
|
21812
|
-
|
|
21945
|
+
active = false;
|
|
21946
|
+
if (currentUrl) URL.revokeObjectURL(currentUrl);
|
|
21813
21947
|
};
|
|
21814
|
-
}, [
|
|
21948
|
+
}, [content, config]);
|
|
21815
21949
|
const deviceConfig = {
|
|
21816
21950
|
desktop: { width: "100%", maxWidth: "1400px", height: 800, icon: lucideReact.Monitor, label: "Desktop" },
|
|
21817
21951
|
tablet: { width: "768px", height: 1024, icon: lucideReact.Tablet, label: "Tablet" },
|
|
@@ -21966,7 +22100,7 @@ var HtmlPreview3 = React16.memo(function HtmlPreview4({ content }) {
|
|
|
21966
22100
|
},
|
|
21967
22101
|
children: [
|
|
21968
22102
|
deviceMode === "mobile" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6 bg-zinc-900 agent-sdk-light:bg-zinc-200 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-4 bg-zinc-800 agent-sdk-light:bg-zinc-300 rounded-full" }) }),
|
|
21969
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
22103
|
+
blobUrl && /* @__PURE__ */ jsxRuntime.jsx(
|
|
21970
22104
|
"iframe",
|
|
21971
22105
|
{
|
|
21972
22106
|
ref: iframeRef,
|
|
@@ -23863,6 +23997,237 @@ function ArtifactDeleteButton({
|
|
|
23863
23997
|
modal
|
|
23864
23998
|
] });
|
|
23865
23999
|
}
|
|
24000
|
+
var CHANGEABLE_TYPES = ["code", "html", "svg", "markdown", "json", "text"];
|
|
24001
|
+
function ArtifactTypeSelector({
|
|
24002
|
+
currentType,
|
|
24003
|
+
currentLanguage,
|
|
24004
|
+
onTypeChange,
|
|
24005
|
+
disabled = false
|
|
24006
|
+
}) {
|
|
24007
|
+
const [isOpen, setIsOpen] = React16.useState(false);
|
|
24008
|
+
const [isChanging, setIsChanging] = React16.useState(false);
|
|
24009
|
+
const dropdownRef = React16.useRef(null);
|
|
24010
|
+
const typeConfig2 = artifactTypeConfig[currentType] || artifactTypeConfig.text;
|
|
24011
|
+
const isChangeable = CHANGEABLE_TYPES.includes(currentType);
|
|
24012
|
+
React16.useEffect(() => {
|
|
24013
|
+
if (!isOpen) return;
|
|
24014
|
+
const handleClickOutside = (e) => {
|
|
24015
|
+
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
24016
|
+
setIsOpen(false);
|
|
24017
|
+
}
|
|
24018
|
+
};
|
|
24019
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
24020
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
24021
|
+
}, [isOpen]);
|
|
24022
|
+
const handleSelectType = React16.useCallback(async (newType) => {
|
|
24023
|
+
if (newType === currentType || isChanging) return;
|
|
24024
|
+
setIsChanging(true);
|
|
24025
|
+
try {
|
|
24026
|
+
await onTypeChange(newType);
|
|
24027
|
+
setIsOpen(false);
|
|
24028
|
+
} finally {
|
|
24029
|
+
setIsChanging(false);
|
|
24030
|
+
}
|
|
24031
|
+
}, [currentType, isChanging, onTypeChange]);
|
|
24032
|
+
if (!isChangeable) {
|
|
24033
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-7 h-7 rounded-lg ${typeConfig2.bgColor} flex items-center justify-center flex-shrink-0`, children: /* @__PURE__ */ jsxRuntime.jsx(typeConfig2.icon, { size: 14, className: typeConfig2.color }) });
|
|
24034
|
+
}
|
|
24035
|
+
const availableTypes = CHANGEABLE_TYPES.filter((t) => t !== currentType);
|
|
24036
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref: dropdownRef, children: [
|
|
24037
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
24038
|
+
"button",
|
|
24039
|
+
{
|
|
24040
|
+
onClick: () => !disabled && !isChanging && setIsOpen(!isOpen),
|
|
24041
|
+
disabled: disabled || isChanging,
|
|
24042
|
+
className: cn3(
|
|
24043
|
+
"flex items-center gap-1 p-1 rounded-lg transition-colors",
|
|
24044
|
+
"hover:bg-zinc-800 agent-sdk-light:hover:bg-zinc-200",
|
|
24045
|
+
(disabled || isChanging) && "opacity-50 cursor-not-allowed"
|
|
24046
|
+
),
|
|
24047
|
+
title: "\u5207\u6362\u4EA7\u7269\u7C7B\u578B",
|
|
24048
|
+
children: [
|
|
24049
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-7 h-7 rounded-lg ${typeConfig2.bgColor} flex items-center justify-center flex-shrink-0`, children: isChanging ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 14, className: `${typeConfig2.color} animate-spin` }) : /* @__PURE__ */ jsxRuntime.jsx(typeConfig2.icon, { size: 14, className: typeConfig2.color }) }),
|
|
24050
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { size: 10, className: "text-zinc-500" })
|
|
24051
|
+
]
|
|
24052
|
+
}
|
|
24053
|
+
),
|
|
24054
|
+
isOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-0 top-full mt-1 z-50 w-44 bg-zinc-900 agent-sdk-light:bg-white border border-zinc-700/50 agent-sdk-light:border-zinc-200 rounded-lg shadow-xl overflow-hidden", children: [
|
|
24055
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 border-b border-zinc-800/50 agent-sdk-light:border-zinc-100", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-medium text-zinc-500 agent-sdk-light:text-zinc-400", children: "\u5207\u6362\u7C7B\u578B" }) }),
|
|
24056
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-1", children: availableTypes.map((type) => {
|
|
24057
|
+
const config = artifactTypeConfig[type];
|
|
24058
|
+
const TypeIcon = config.icon;
|
|
24059
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
24060
|
+
"button",
|
|
24061
|
+
{
|
|
24062
|
+
onClick: () => handleSelectType(type),
|
|
24063
|
+
disabled: isChanging,
|
|
24064
|
+
className: cn3(
|
|
24065
|
+
"flex items-center gap-2.5 px-2 py-1.5 text-xs rounded-md transition-all w-full text-left",
|
|
24066
|
+
"text-zinc-300 agent-sdk-light:text-zinc-700",
|
|
24067
|
+
"hover:bg-zinc-800/70 agent-sdk-light:hover:bg-zinc-100",
|
|
24068
|
+
isChanging && "opacity-50 cursor-not-allowed"
|
|
24069
|
+
),
|
|
24070
|
+
children: [
|
|
24071
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn3("w-5 h-5 rounded flex items-center justify-center flex-shrink-0", config.bgColor), children: /* @__PURE__ */ jsxRuntime.jsx(TypeIcon, { size: 11, className: config.color }) }),
|
|
24072
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: config.label })
|
|
24073
|
+
]
|
|
24074
|
+
},
|
|
24075
|
+
type
|
|
24076
|
+
);
|
|
24077
|
+
}) })
|
|
24078
|
+
] })
|
|
24079
|
+
] });
|
|
24080
|
+
}
|
|
24081
|
+
var COMMON_LANGUAGES = [
|
|
24082
|
+
"javascript",
|
|
24083
|
+
"typescript",
|
|
24084
|
+
"python",
|
|
24085
|
+
"java",
|
|
24086
|
+
"go",
|
|
24087
|
+
"rust",
|
|
24088
|
+
"c",
|
|
24089
|
+
"cpp",
|
|
24090
|
+
"csharp",
|
|
24091
|
+
"ruby",
|
|
24092
|
+
"php",
|
|
24093
|
+
"swift",
|
|
24094
|
+
"kotlin",
|
|
24095
|
+
"sql",
|
|
24096
|
+
"shell",
|
|
24097
|
+
"html",
|
|
24098
|
+
"css",
|
|
24099
|
+
"json",
|
|
24100
|
+
"yaml",
|
|
24101
|
+
"xml",
|
|
24102
|
+
"markdown"
|
|
24103
|
+
];
|
|
24104
|
+
function ArtifactLanguageSelector({
|
|
24105
|
+
currentLanguage,
|
|
24106
|
+
onLanguageChange,
|
|
24107
|
+
disabled = false
|
|
24108
|
+
}) {
|
|
24109
|
+
const [isOpen, setIsOpen] = React16.useState(false);
|
|
24110
|
+
const [isChanging, setIsChanging] = React16.useState(false);
|
|
24111
|
+
const [search, setSearch] = React16.useState("");
|
|
24112
|
+
const dropdownRef = React16.useRef(null);
|
|
24113
|
+
const inputRef = React16.useRef(null);
|
|
24114
|
+
React16.useEffect(() => {
|
|
24115
|
+
if (!isOpen) return;
|
|
24116
|
+
const handleClickOutside = (e) => {
|
|
24117
|
+
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
24118
|
+
setIsOpen(false);
|
|
24119
|
+
setSearch("");
|
|
24120
|
+
}
|
|
24121
|
+
};
|
|
24122
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
24123
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
24124
|
+
}, [isOpen]);
|
|
24125
|
+
React16.useEffect(() => {
|
|
24126
|
+
if (isOpen && inputRef.current) {
|
|
24127
|
+
inputRef.current.focus();
|
|
24128
|
+
}
|
|
24129
|
+
}, [isOpen]);
|
|
24130
|
+
const handleSelect = React16.useCallback(async (language) => {
|
|
24131
|
+
if (language === currentLanguage || isChanging) return;
|
|
24132
|
+
setIsChanging(true);
|
|
24133
|
+
try {
|
|
24134
|
+
await onLanguageChange(language);
|
|
24135
|
+
setIsOpen(false);
|
|
24136
|
+
setSearch("");
|
|
24137
|
+
} finally {
|
|
24138
|
+
setIsChanging(false);
|
|
24139
|
+
}
|
|
24140
|
+
}, [currentLanguage, isChanging, onLanguageChange]);
|
|
24141
|
+
const handleKeyDown = React16.useCallback((e) => {
|
|
24142
|
+
if (e.key === "Enter" && search.trim()) {
|
|
24143
|
+
e.preventDefault();
|
|
24144
|
+
handleSelect(search.trim().toLowerCase());
|
|
24145
|
+
} else if (e.key === "Escape") {
|
|
24146
|
+
setIsOpen(false);
|
|
24147
|
+
setSearch("");
|
|
24148
|
+
}
|
|
24149
|
+
}, [search, handleSelect]);
|
|
24150
|
+
const filteredLanguages = search.trim() ? COMMON_LANGUAGES.filter((lang) => lang.includes(search.trim().toLowerCase())) : COMMON_LANGUAGES;
|
|
24151
|
+
const showCustomOption = search.trim() && !COMMON_LANGUAGES.includes(search.trim().toLowerCase()) && search.trim().toLowerCase() !== currentLanguage;
|
|
24152
|
+
if (!currentLanguage) return null;
|
|
24153
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref: dropdownRef, children: [
|
|
24154
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
24155
|
+
"button",
|
|
24156
|
+
{
|
|
24157
|
+
onClick: () => !disabled && !isChanging && setIsOpen(!isOpen),
|
|
24158
|
+
disabled: disabled || isChanging,
|
|
24159
|
+
className: cn3(
|
|
24160
|
+
"text-zinc-500 agent-sdk-light:text-zinc-500 ml-1 text-xs transition-colors",
|
|
24161
|
+
"hover:text-zinc-300 agent-sdk-light:hover:text-zinc-700",
|
|
24162
|
+
(disabled || isChanging) && "opacity-50 cursor-not-allowed",
|
|
24163
|
+
!disabled && !isChanging && "cursor-pointer"
|
|
24164
|
+
),
|
|
24165
|
+
children: isChanging ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
|
|
24166
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 10, className: "animate-spin" }),
|
|
24167
|
+
currentLanguage
|
|
24168
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
24169
|
+
"\u2022 ",
|
|
24170
|
+
currentLanguage
|
|
24171
|
+
] })
|
|
24172
|
+
}
|
|
24173
|
+
),
|
|
24174
|
+
isOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-0 top-full mt-1 z-50 w-48 bg-zinc-900 agent-sdk-light:bg-white border border-zinc-700/50 agent-sdk-light:border-zinc-200 rounded-lg shadow-xl overflow-hidden", children: [
|
|
24175
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 border-b border-zinc-800/50 agent-sdk-light:border-zinc-100", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
24176
|
+
"input",
|
|
24177
|
+
{
|
|
24178
|
+
ref: inputRef,
|
|
24179
|
+
type: "text",
|
|
24180
|
+
value: search,
|
|
24181
|
+
onChange: (e) => setSearch(e.target.value),
|
|
24182
|
+
onKeyDown: handleKeyDown,
|
|
24183
|
+
placeholder: "\u641C\u7D22\u8BED\u8A00...",
|
|
24184
|
+
className: "w-full px-2 py-1.5 text-xs bg-zinc-800 agent-sdk-light:bg-zinc-100 text-zinc-200 agent-sdk-light:text-zinc-800 rounded-md border border-zinc-700/50 agent-sdk-light:border-zinc-200 outline-none focus:border-zinc-500 agent-sdk-light:focus:border-zinc-400 placeholder-zinc-600 agent-sdk-light:placeholder-zinc-400"
|
|
24185
|
+
}
|
|
24186
|
+
) }),
|
|
24187
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-h-48 overflow-y-auto p-1", children: [
|
|
24188
|
+
showCustomOption && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
24189
|
+
"button",
|
|
24190
|
+
{
|
|
24191
|
+
onClick: () => handleSelect(search.trim().toLowerCase()),
|
|
24192
|
+
disabled: isChanging,
|
|
24193
|
+
className: cn3(
|
|
24194
|
+
"flex items-center justify-between px-2 py-1.5 text-xs rounded-md transition-all w-full text-left",
|
|
24195
|
+
"text-zinc-300 agent-sdk-light:text-zinc-700",
|
|
24196
|
+
"hover:bg-zinc-800/70 agent-sdk-light:hover:bg-zinc-100",
|
|
24197
|
+
isChanging && "opacity-50 cursor-not-allowed"
|
|
24198
|
+
),
|
|
24199
|
+
children: [
|
|
24200
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
24201
|
+
'"',
|
|
24202
|
+
search.trim().toLowerCase(),
|
|
24203
|
+
'"'
|
|
24204
|
+
] }),
|
|
24205
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-zinc-600 agent-sdk-light:text-zinc-400", children: "\u56DE\u8F66\u786E\u8BA4" })
|
|
24206
|
+
]
|
|
24207
|
+
}
|
|
24208
|
+
),
|
|
24209
|
+
filteredLanguages.map((lang) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
24210
|
+
"button",
|
|
24211
|
+
{
|
|
24212
|
+
onClick: () => handleSelect(lang),
|
|
24213
|
+
disabled: isChanging,
|
|
24214
|
+
className: cn3(
|
|
24215
|
+
"flex items-center justify-between px-2 py-1.5 text-xs rounded-md transition-all w-full text-left",
|
|
24216
|
+
lang === currentLanguage ? "text-zinc-100 agent-sdk-light:text-zinc-900 bg-zinc-800/50 agent-sdk-light:bg-zinc-100" : "text-zinc-300 agent-sdk-light:text-zinc-700 hover:bg-zinc-800/70 agent-sdk-light:hover:bg-zinc-100",
|
|
24217
|
+
isChanging && "opacity-50 cursor-not-allowed"
|
|
24218
|
+
),
|
|
24219
|
+
children: [
|
|
24220
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: lang }),
|
|
24221
|
+
lang === currentLanguage && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { size: 12, className: "text-green-400 agent-sdk-light:text-green-600 flex-shrink-0" })
|
|
24222
|
+
]
|
|
24223
|
+
},
|
|
24224
|
+
lang
|
|
24225
|
+
)),
|
|
24226
|
+
filteredLanguages.length === 0 && !showCustomOption && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 py-3 text-xs text-zinc-600 agent-sdk-light:text-zinc-400 text-center", children: "\u65E0\u5339\u914D\u7ED3\u679C" })
|
|
24227
|
+
] })
|
|
24228
|
+
] })
|
|
24229
|
+
] });
|
|
24230
|
+
}
|
|
23866
24231
|
var ArtifactViewer = React16.memo(function ArtifactViewer2({
|
|
23867
24232
|
artifact,
|
|
23868
24233
|
isOpen,
|
|
@@ -23880,13 +24245,20 @@ var ArtifactViewer = React16.memo(function ArtifactViewer2({
|
|
|
23880
24245
|
onContentChange,
|
|
23881
24246
|
onSave,
|
|
23882
24247
|
onVisibilityChange,
|
|
23883
|
-
onDelete
|
|
24248
|
+
onDelete,
|
|
24249
|
+
onTypeChange,
|
|
24250
|
+
onLanguageChange,
|
|
24251
|
+
onTitleChange
|
|
23884
24252
|
}) {
|
|
23885
24253
|
const [viewMode, setViewMode] = React16.useState(defaultView);
|
|
23886
24254
|
const [isEditing, setIsEditing] = React16.useState(false);
|
|
23887
24255
|
const [editContent, setEditContent] = React16.useState("");
|
|
23888
24256
|
const [undoStack, setUndoStack] = React16.useState([]);
|
|
23889
24257
|
const [redoStack, setRedoStack] = React16.useState([]);
|
|
24258
|
+
const [isEditingTitle, setIsEditingTitle] = React16.useState(false);
|
|
24259
|
+
const [editingTitle, setEditingTitle] = React16.useState("");
|
|
24260
|
+
const [isSavingTitle, setIsSavingTitle] = React16.useState(false);
|
|
24261
|
+
const titleInputRef = React16.useRef(null);
|
|
23890
24262
|
React16.useEffect(() => {
|
|
23891
24263
|
if (artifact) {
|
|
23892
24264
|
if (artifact.type === "html" || artifact.type === "markdown" || artifact.type === "svg") {
|
|
@@ -23898,8 +24270,9 @@ var ArtifactViewer = React16.memo(function ArtifactViewer2({
|
|
|
23898
24270
|
setEditContent(artifact.content);
|
|
23899
24271
|
setUndoStack([]);
|
|
23900
24272
|
setRedoStack([]);
|
|
24273
|
+
setIsEditingTitle(false);
|
|
23901
24274
|
}
|
|
23902
|
-
}, [artifact?.id]);
|
|
24275
|
+
}, [artifact?.id, artifact?.type]);
|
|
23903
24276
|
React16.useEffect(() => {
|
|
23904
24277
|
if (artifact && !isEditing) {
|
|
23905
24278
|
setEditContent(artifact.content);
|
|
@@ -23912,6 +24285,7 @@ var ArtifactViewer = React16.memo(function ArtifactViewer2({
|
|
|
23912
24285
|
const handleStartEdit = () => {
|
|
23913
24286
|
setEditContent(artifact.content);
|
|
23914
24287
|
setUndoStack([artifact.content]);
|
|
24288
|
+
handleStartEditTitle();
|
|
23915
24289
|
setRedoStack([]);
|
|
23916
24290
|
setIsEditing(true);
|
|
23917
24291
|
setViewMode("code");
|
|
@@ -23946,6 +24320,43 @@ var ArtifactViewer = React16.memo(function ArtifactViewer2({
|
|
|
23946
24320
|
setEditContent(artifact.content);
|
|
23947
24321
|
setIsEditing(false);
|
|
23948
24322
|
};
|
|
24323
|
+
const handleStartEditTitle = React16.useCallback(() => {
|
|
24324
|
+
if (!onTitleChange || isEditing || isSavingTitle) return;
|
|
24325
|
+
setEditingTitle(artifact.title);
|
|
24326
|
+
setIsEditingTitle(true);
|
|
24327
|
+
}, [onTitleChange, isEditing, isSavingTitle, artifact.title]);
|
|
24328
|
+
const handleSaveTitle = React16.useCallback(async () => {
|
|
24329
|
+
const trimmed = editingTitle.trim();
|
|
24330
|
+
if (!trimmed || trimmed === artifact.title) {
|
|
24331
|
+
setIsEditingTitle(false);
|
|
24332
|
+
return;
|
|
24333
|
+
}
|
|
24334
|
+
setIsSavingTitle(true);
|
|
24335
|
+
try {
|
|
24336
|
+
await onTitleChange?.(artifact.id, trimmed);
|
|
24337
|
+
} finally {
|
|
24338
|
+
setIsSavingTitle(false);
|
|
24339
|
+
setIsEditingTitle(false);
|
|
24340
|
+
}
|
|
24341
|
+
}, [editingTitle, artifact.title, artifact.id, onTitleChange]);
|
|
24342
|
+
const handleCancelEditTitle = React16.useCallback(() => {
|
|
24343
|
+
setIsEditingTitle(false);
|
|
24344
|
+
}, []);
|
|
24345
|
+
const handleTitleKeyDown = React16.useCallback((e) => {
|
|
24346
|
+
if (e.key === "Enter") {
|
|
24347
|
+
e.preventDefault();
|
|
24348
|
+
handleSaveTitle();
|
|
24349
|
+
} else if (e.key === "Escape") {
|
|
24350
|
+
e.preventDefault();
|
|
24351
|
+
handleCancelEditTitle();
|
|
24352
|
+
}
|
|
24353
|
+
}, [handleSaveTitle, handleCancelEditTitle]);
|
|
24354
|
+
React16.useEffect(() => {
|
|
24355
|
+
if (isEditingTitle && titleInputRef.current) {
|
|
24356
|
+
titleInputRef.current.focus();
|
|
24357
|
+
titleInputRef.current.select();
|
|
24358
|
+
}
|
|
24359
|
+
}, [isEditingTitle]);
|
|
23949
24360
|
const displayContent = isEditing ? editContent : artifact.content;
|
|
23950
24361
|
const renderContent = () => {
|
|
23951
24362
|
if (isEditing) {
|
|
@@ -23986,7 +24397,7 @@ var ArtifactViewer = React16.memo(function ArtifactViewer2({
|
|
|
23986
24397
|
switch (artifact.type) {
|
|
23987
24398
|
case "html":
|
|
23988
24399
|
case "svg":
|
|
23989
|
-
return /* @__PURE__ */ jsxRuntime.jsx(HtmlPreview3, { content: displayContent });
|
|
24400
|
+
return /* @__PURE__ */ jsxRuntime.jsx(HtmlPreview3, { content: displayContent, config });
|
|
23990
24401
|
case "markdown":
|
|
23991
24402
|
return /* @__PURE__ */ jsxRuntime.jsx(MarkdownPreview, { content: displayContent, config });
|
|
23992
24403
|
default:
|
|
@@ -24003,15 +24414,56 @@ var ArtifactViewer = React16.memo(function ArtifactViewer2({
|
|
|
24003
24414
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col bg-zinc-900 agent-sdk-light:bg-white relative", children: [
|
|
24004
24415
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-zinc-800/50 agent-sdk-light:border-zinc-200 bg-zinc-900/95 agent-sdk-light:bg-zinc-50 backdrop-blur-sm flex-shrink-0", children: [
|
|
24005
24416
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
|
|
24006
|
-
|
|
24417
|
+
onTypeChange ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
24418
|
+
ArtifactTypeSelector,
|
|
24419
|
+
{
|
|
24420
|
+
currentType: artifact.type,
|
|
24421
|
+
currentLanguage: artifact.language,
|
|
24422
|
+
onTypeChange: (newType, language) => onTypeChange(artifact.id, newType, language),
|
|
24423
|
+
disabled: isEditing
|
|
24424
|
+
}
|
|
24425
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-7 h-7 rounded-lg ${typeConfig2.bgColor} flex items-center justify-center flex-shrink-0`, children: /* @__PURE__ */ jsxRuntime.jsx(typeConfig2.icon, { size: 14, className: typeConfig2.color }) }),
|
|
24007
24426
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
24008
|
-
/* @__PURE__ */ jsxRuntime.
|
|
24427
|
+
isEditingTitle ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
24428
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
24429
|
+
"input",
|
|
24430
|
+
{
|
|
24431
|
+
ref: titleInputRef,
|
|
24432
|
+
type: "text",
|
|
24433
|
+
value: editingTitle,
|
|
24434
|
+
onChange: (e) => setEditingTitle(e.target.value),
|
|
24435
|
+
onKeyDown: handleTitleKeyDown,
|
|
24436
|
+
onBlur: handleSaveTitle,
|
|
24437
|
+
disabled: isSavingTitle,
|
|
24438
|
+
className: "text-sm font-medium text-zinc-100 agent-sdk-light:text-zinc-900 bg-zinc-800 agent-sdk-light:bg-zinc-100 border border-zinc-600 agent-sdk-light:border-zinc-300 rounded px-1.5 py-0.5 outline-none focus:border-zinc-400 agent-sdk-light:focus:border-zinc-500 w-full min-w-0"
|
|
24439
|
+
}
|
|
24440
|
+
),
|
|
24441
|
+
isSavingTitle && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 12, className: "text-zinc-500 animate-spin flex-shrink-0" })
|
|
24442
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
24443
|
+
"h3",
|
|
24444
|
+
{
|
|
24445
|
+
className: cn3(
|
|
24446
|
+
"text-sm font-medium text-zinc-100 agent-sdk-light:text-zinc-900 truncate",
|
|
24447
|
+
onTitleChange && !isEditing && "cursor-pointer hover:text-zinc-300 agent-sdk-light:hover:text-zinc-600"
|
|
24448
|
+
),
|
|
24449
|
+
onDoubleClick: handleStartEditTitle,
|
|
24450
|
+
title: onTitleChange && !isEditing ? "\u53CC\u51FB\u7F16\u8F91\u6807\u9898" : void 0,
|
|
24451
|
+
children: artifact.title
|
|
24452
|
+
}
|
|
24453
|
+
),
|
|
24009
24454
|
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: `text-xs ${typeConfig2.color}`, children: [
|
|
24010
24455
|
typeConfig2.label,
|
|
24011
|
-
artifact.language && artifact.language !== artifact.type && /* @__PURE__ */ jsxRuntime.
|
|
24456
|
+
artifact.language && artifact.language !== artifact.type && (onLanguageChange ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
24457
|
+
ArtifactLanguageSelector,
|
|
24458
|
+
{
|
|
24459
|
+
currentLanguage: artifact.language,
|
|
24460
|
+
onLanguageChange: (lang) => onLanguageChange(artifact.id, lang),
|
|
24461
|
+
disabled: isEditing
|
|
24462
|
+
}
|
|
24463
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-zinc-500 agent-sdk-light:text-zinc-500 ml-1", children: [
|
|
24012
24464
|
"\u2022 ",
|
|
24013
24465
|
artifact.language
|
|
24014
|
-
] })
|
|
24466
|
+
] }))
|
|
24015
24467
|
] })
|
|
24016
24468
|
] })
|
|
24017
24469
|
] }),
|
|
@@ -24136,15 +24588,54 @@ var ArtifactViewer = React16.memo(function ArtifactViewer2({
|
|
|
24136
24588
|
isOpen,
|
|
24137
24589
|
onClose,
|
|
24138
24590
|
title: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
24139
|
-
|
|
24140
|
-
|
|
24591
|
+
onTypeChange ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
24592
|
+
ArtifactTypeSelector,
|
|
24593
|
+
{
|
|
24594
|
+
currentType: artifact.type,
|
|
24595
|
+
currentLanguage: artifact.language,
|
|
24596
|
+
onTypeChange: (newType, language) => onTypeChange(artifact.id, newType, language),
|
|
24597
|
+
disabled: isEditing
|
|
24598
|
+
}
|
|
24599
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-6 h-6 rounded-md ${typeConfig2.bgColor} flex items-center justify-center`, children: /* @__PURE__ */ jsxRuntime.jsx(typeConfig2.icon, { size: 14, className: typeConfig2.color }) }),
|
|
24600
|
+
isEditingTitle ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
24601
|
+
"input",
|
|
24602
|
+
{
|
|
24603
|
+
ref: titleInputRef,
|
|
24604
|
+
type: "text",
|
|
24605
|
+
value: editingTitle,
|
|
24606
|
+
onChange: (e) => setEditingTitle(e.target.value),
|
|
24607
|
+
onKeyDown: handleTitleKeyDown,
|
|
24608
|
+
onBlur: handleSaveTitle,
|
|
24609
|
+
disabled: isSavingTitle,
|
|
24610
|
+
className: "text-sm font-medium text-zinc-100 agent-sdk-light:text-zinc-900 bg-zinc-800 agent-sdk-light:bg-zinc-100 border border-zinc-600 agent-sdk-light:border-zinc-300 rounded px-1.5 py-0.5 outline-none focus:border-zinc-400 agent-sdk-light:focus:border-zinc-500 min-w-0 flex-1"
|
|
24611
|
+
}
|
|
24612
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
24613
|
+
"span",
|
|
24614
|
+
{
|
|
24615
|
+
className: cn3(
|
|
24616
|
+
"truncate",
|
|
24617
|
+
onTitleChange && !isEditing && "cursor-pointer hover:text-zinc-300 agent-sdk-light:hover:text-zinc-600"
|
|
24618
|
+
),
|
|
24619
|
+
onDoubleClick: handleStartEditTitle,
|
|
24620
|
+
title: onTitleChange && !isEditing ? "\u53CC\u51FB\u7F16\u8F91\u6807\u9898" : void 0,
|
|
24621
|
+
children: artifact.title
|
|
24622
|
+
}
|
|
24623
|
+
),
|
|
24624
|
+
isSavingTitle && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 12, className: "text-zinc-500 animate-spin flex-shrink-0" })
|
|
24141
24625
|
] }),
|
|
24142
24626
|
subtitle: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: typeConfig2.color, children: [
|
|
24143
24627
|
typeConfig2.label,
|
|
24144
|
-
artifact.language && artifact.language !== artifact.type && /* @__PURE__ */ jsxRuntime.
|
|
24628
|
+
artifact.language && artifact.language !== artifact.type && (onLanguageChange ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
24629
|
+
ArtifactLanguageSelector,
|
|
24630
|
+
{
|
|
24631
|
+
currentLanguage: artifact.language,
|
|
24632
|
+
onLanguageChange: (lang) => onLanguageChange(artifact.id, lang),
|
|
24633
|
+
disabled: isEditing
|
|
24634
|
+
}
|
|
24635
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-zinc-500 agent-sdk-light:text-zinc-500 ml-1", children: [
|
|
24145
24636
|
"\u2022 ",
|
|
24146
24637
|
artifact.language
|
|
24147
|
-
] })
|
|
24638
|
+
] }))
|
|
24148
24639
|
] }),
|
|
24149
24640
|
isFullscreen,
|
|
24150
24641
|
onFullscreenToggle,
|
|
@@ -25057,7 +25548,7 @@ function useArtifactPanel({ currentSessionId }) {
|
|
|
25057
25548
|
const existingArtifact = Object.values(artifacts).find(
|
|
25058
25549
|
(a) => {
|
|
25059
25550
|
const sameContent = a.currentContent === data.content && a.type === data.type;
|
|
25060
|
-
const sameId = a?.metadata?.workId === data.metadata?.workId;
|
|
25551
|
+
const sameId = !!data.metadata?.workId && a?.metadata?.workId === data.metadata?.workId;
|
|
25061
25552
|
return sameContent || sameId;
|
|
25062
25553
|
}
|
|
25063
25554
|
);
|
|
@@ -25119,7 +25610,8 @@ function useArtifactPanel({ currentSessionId }) {
|
|
|
25119
25610
|
setActiveArtifact,
|
|
25120
25611
|
removeArtifact,
|
|
25121
25612
|
reorderArtifacts,
|
|
25122
|
-
updateArtifactContent
|
|
25613
|
+
updateArtifactContent,
|
|
25614
|
+
upsertArtifact
|
|
25123
25615
|
};
|
|
25124
25616
|
}
|
|
25125
25617
|
|
|
@@ -25935,7 +26427,8 @@ var AgentChat = React16__namespace.default.forwardRef(({
|
|
|
25935
26427
|
setActiveArtifact,
|
|
25936
26428
|
removeArtifact,
|
|
25937
26429
|
reorderArtifacts,
|
|
25938
|
-
updateArtifactContent
|
|
26430
|
+
updateArtifactContent,
|
|
26431
|
+
upsertArtifact
|
|
25939
26432
|
} = useArtifactPanel({ currentSessionId: useAgentStore((state) => state.currentSession?.sessionId) });
|
|
25940
26433
|
const reconnectRef = React16.useRef(null);
|
|
25941
26434
|
const reconnectWrapper = React16.useCallback(async (messageId) => {
|
|
@@ -26409,6 +26902,52 @@ var AgentChat = React16__namespace.default.forwardRef(({
|
|
|
26409
26902
|
toast.error("\u5220\u9664\u4EA7\u7269\u5931\u8D25");
|
|
26410
26903
|
}
|
|
26411
26904
|
},
|
|
26905
|
+
onTypeChange: async (artifactId, newType, language) => {
|
|
26906
|
+
try {
|
|
26907
|
+
const content = activeArtifact?.currentContent || "";
|
|
26908
|
+
const res = await artifactService.updateContent(artifactId, content, {
|
|
26909
|
+
type: newType,
|
|
26910
|
+
language
|
|
26911
|
+
});
|
|
26912
|
+
if (res.success && res.data) {
|
|
26913
|
+
upsertArtifact(artifactService.normalizeEntry(res.data));
|
|
26914
|
+
toast.success("\u7C7B\u578B\u5DF2\u66F4\u65B0");
|
|
26915
|
+
} else {
|
|
26916
|
+
toast.error("\u7C7B\u578B\u66F4\u65B0\u5931\u8D25");
|
|
26917
|
+
}
|
|
26918
|
+
} catch (err) {
|
|
26919
|
+
console.error("[AgentChat] Change artifact type failed:", err);
|
|
26920
|
+
toast.error("\u7C7B\u578B\u66F4\u65B0\u5931\u8D25");
|
|
26921
|
+
}
|
|
26922
|
+
},
|
|
26923
|
+
onLanguageChange: async (artifactId, language) => {
|
|
26924
|
+
try {
|
|
26925
|
+
const content = activeArtifact?.currentContent || "";
|
|
26926
|
+
const res = await artifactService.updateContent(artifactId, content, { language });
|
|
26927
|
+
if (res.success && res.data) {
|
|
26928
|
+
upsertArtifact(artifactService.normalizeEntry(res.data));
|
|
26929
|
+
} else {
|
|
26930
|
+
toast.error("\u8BED\u8A00\u66F4\u65B0\u5931\u8D25");
|
|
26931
|
+
}
|
|
26932
|
+
} catch (err) {
|
|
26933
|
+
console.error("[AgentChat] Change artifact language failed:", err);
|
|
26934
|
+
toast.error("\u8BED\u8A00\u66F4\u65B0\u5931\u8D25");
|
|
26935
|
+
}
|
|
26936
|
+
},
|
|
26937
|
+
onTitleChange: async (artifactId, title) => {
|
|
26938
|
+
try {
|
|
26939
|
+
const content = activeArtifact?.currentContent || "";
|
|
26940
|
+
const res = await artifactService.updateContent(artifactId, content, { title });
|
|
26941
|
+
if (res.success && res.data) {
|
|
26942
|
+
upsertArtifact(artifactService.normalizeEntry(res.data));
|
|
26943
|
+
} else {
|
|
26944
|
+
toast.error("\u6807\u9898\u66F4\u65B0\u5931\u8D25");
|
|
26945
|
+
}
|
|
26946
|
+
} catch (err) {
|
|
26947
|
+
console.error("[AgentChat] Change artifact title failed:", err);
|
|
26948
|
+
toast.error("\u6807\u9898\u66F4\u65B0\u5931\u8D25");
|
|
26949
|
+
}
|
|
26950
|
+
},
|
|
26412
26951
|
onVisibilityChange: async (artifactId, isPublic) => {
|
|
26413
26952
|
try {
|
|
26414
26953
|
const res = await artifactService.updateVisibility(artifactId, isPublic);
|
|
@@ -26955,20 +27494,21 @@ var typeConfig = {
|
|
|
26955
27494
|
};
|
|
26956
27495
|
function FullscreenHtmlPreview({ content }) {
|
|
26957
27496
|
const blobUrl = React16.useMemo(() => {
|
|
27497
|
+
const processed = resolveHtmlAssetUrls(content);
|
|
26958
27498
|
const styleInjection = `
|
|
26959
27499
|
<style>
|
|
26960
27500
|
html, body { margin: 0; padding: 0; width: 100%; min-height: 100%; box-sizing: border-box; }
|
|
26961
27501
|
* { box-sizing: border-box; }
|
|
26962
27502
|
</style>`;
|
|
26963
|
-
let modified =
|
|
26964
|
-
if (
|
|
26965
|
-
modified =
|
|
26966
|
-
} else if (
|
|
26967
|
-
modified =
|
|
26968
|
-
} else if (/<!(DOCTYPE|doctype)/i.test(
|
|
26969
|
-
modified =
|
|
27503
|
+
let modified = processed;
|
|
27504
|
+
if (processed.includes("<head>")) {
|
|
27505
|
+
modified = processed.replace("<head>", "<head>" + styleInjection);
|
|
27506
|
+
} else if (processed.includes("<html>")) {
|
|
27507
|
+
modified = processed.replace("<html>", "<html><head>" + styleInjection + "</head>");
|
|
27508
|
+
} else if (/<!(DOCTYPE|doctype)/i.test(processed)) {
|
|
27509
|
+
modified = processed.replace(/(<!DOCTYPE[^>]*>|<!doctype[^>]*>)/i, "$1<html><head>" + styleInjection + "</head><body>") + "</body></html>";
|
|
26970
27510
|
} else {
|
|
26971
|
-
modified = `<!DOCTYPE html><html><head>${styleInjection}</head><body>${
|
|
27511
|
+
modified = `<!DOCTYPE html><html><head>${styleInjection}</head><body>${processed}</body></html>`;
|
|
26972
27512
|
}
|
|
26973
27513
|
const blob = new Blob([modified], { type: "text/html" });
|
|
26974
27514
|
return URL.createObjectURL(blob);
|