@malette/agent-sdk 0.1.3-beta.11 → 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.mjs CHANGED
@@ -4,7 +4,7 @@ import { create } from 'zustand';
4
4
  import { devtools } from 'zustand/middleware';
5
5
  import * as React16 from 'react';
6
6
  import React16__default, { createContext, memo, useState, useEffect, useCallback, useMemo, useRef, useImperativeHandle, useContext } from 'react';
7
- import { Image, X, Check, Copy, FileText, Code2, FileJson, FileCode, CheckCheck, Eye, ExternalLink, Download, ChevronUp, ChevronDown, Maximize2, Loader2, Clock, Sparkles, Bot, AlertTriangle, Play, Pencil, AlertCircle, Square, RotateCcw, SkipForward, Zap, ChevronRight, CheckCircle2, XCircle, Ban, Users, Volume2, Pause, VolumeX, Lightbulb, RefreshCw, BookmarkPlus, Trash2, PenLine, ImageIcon, GripVertical, Minimize2, Smartphone, Tablet, Monitor, Globe, FileImage, Minus, Plus, Maximize, Video, ChevronLeft, LayoutGrid, Undo2, Redo2, Save, PanelLeft, ArrowLeft, Settings, UserCheck, ShieldCheck, Shield, User, Lock, Share2, PanelLeftClose, Search, MessageSquare, Unlink, ImagePlus, BookOpen, Send, HelpCircle, Calendar, Link, Tag, EyeOff, Folder, Wand2, Mic, CheckCircle, ListOrdered, FileEdit, Edit, ArrowRight } from 'lucide-react';
7
+ import { Image, X, Check, Copy, FileText, Code2, FileJson, FileCode, CheckCheck, Eye, ExternalLink, Download, ChevronUp, ChevronDown, Maximize2, Loader2, Clock, Sparkles, Bot, AlertTriangle, Play, Pencil, AlertCircle, Square, RotateCcw, SkipForward, Zap, ChevronRight, CheckCircle2, XCircle, Ban, Users, Volume2, Pause, VolumeX, Lightbulb, RefreshCw, BookmarkPlus, Trash2, PenLine, ImageIcon, GripVertical, Minimize2, Smartphone, Tablet, Monitor, Globe, FileImage, Minus, Plus, Maximize, Video, ChevronLeft, LayoutGrid, Undo2, Redo2, Save, PanelLeft, ArrowLeft, Settings, UserCheck, ShieldCheck, Shield, User, Lock, Share2, PanelLeftClose, Search, MessageSquare, Unlink, ImagePlus, BookOpen, Send, HelpCircle, Calendar, Link, Tag, EyeOff, Folder, Wand2, Mic, CheckCircle, ListOrdered, FileEdit, Edit, MonitorPlay, ArrowRight } from 'lucide-react';
8
8
  import ReactMarkdown from 'react-markdown';
9
9
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
10
10
  import ReactDOM, { createPortal } from 'react-dom';
@@ -470,10 +470,16 @@ var artifactService = {
470
470
  /**
471
471
  * 更新产物内容(用户编辑后保存)
472
472
  */
473
- updateContent: async (artifactId, content) => {
473
+ updateContent: async (artifactId, content, options) => {
474
474
  return fetcher(`${API_BASE}/artifacts/${artifactId}/content`, {
475
475
  method: "PUT",
476
- body: JSON.stringify({ artifactId, content })
476
+ body: JSON.stringify({
477
+ artifactId,
478
+ content,
479
+ ...options?.type && { type: options.type },
480
+ ...options?.language !== void 0 && { language: options.language },
481
+ ...options?.title !== void 0 && { title: options.title }
482
+ })
477
483
  });
478
484
  },
479
485
  /**
@@ -1678,6 +1684,25 @@ var useAgentStore = create()(
1678
1684
  false,
1679
1685
  "updateArtifactVisibility"
1680
1686
  ),
1687
+ updateArtifactType: (artifactId, type, language) => set(
1688
+ (state) => {
1689
+ const existing = state.artifacts[artifactId];
1690
+ if (!existing) return state;
1691
+ return {
1692
+ artifacts: {
1693
+ ...state.artifacts,
1694
+ [artifactId]: {
1695
+ ...existing,
1696
+ type,
1697
+ language: language ?? existing.language,
1698
+ gmtModified: (/* @__PURE__ */ new Date()).toISOString()
1699
+ }
1700
+ }
1701
+ };
1702
+ },
1703
+ false,
1704
+ "updateArtifactType"
1705
+ ),
1681
1706
  // ============ 复合操作 ============
1682
1707
  startNewChat: (sessionId) => {
1683
1708
  set(
@@ -7780,6 +7805,104 @@ var resolveAssetForDisplay = async (asset, config) => {
7780
7805
  }
7781
7806
  return null;
7782
7807
  };
7808
+ var resolveHtmlAssetUrls = (html2) => {
7809
+ const origin = typeof window !== "undefined" ? window.location.origin : "";
7810
+ const resolveSrc = (src, isVideo) => {
7811
+ if (!src.trim()) return src;
7812
+ if (/^(data:|blob:|javascript:|#)/i.test(src)) return src;
7813
+ if (src.includes("${")) return src;
7814
+ if (/^https?:/i.test(src)) {
7815
+ if (src.includes("industryai")) {
7816
+ return src.split("?")[0];
7817
+ }
7818
+ return src;
7819
+ }
7820
+ const resolved = isVideo ? getHDImageUrl(src) : getImageUrl(src);
7821
+ return resolved.startsWith("http") ? resolved : `${origin}${resolved}`;
7822
+ };
7823
+ const processHtmlPart = (part) => {
7824
+ let result = part.replace(
7825
+ /(<(?:img|video|source)\s[^>]*?\bsrc\s*=\s*["'])([^"']*)(["'])/gi,
7826
+ (match, prefix, src, suffix) => {
7827
+ const tagMatch = match.match(/^<(\w+)/i);
7828
+ const tag = tagMatch?.[1]?.toLowerCase() ?? "";
7829
+ const isVideo = tag === "video" || tag === "source";
7830
+ return `${prefix}${resolveSrc(src, isVideo)}${suffix}`;
7831
+ }
7832
+ );
7833
+ result = result.replace(
7834
+ /(<video\s[^>]*?\bposter\s*=\s*["'])([^"']*)(["'])/gi,
7835
+ (match, prefix, src, suffix) => `${prefix}${resolveSrc(src, false)}${suffix}`
7836
+ );
7837
+ return result;
7838
+ };
7839
+ const parts = html2.split(/(<script\b[\s\S]*?<\/script>)/gi);
7840
+ return parts.map((part, i) => i % 2 === 1 ? part : processHtmlPart(part)).join("");
7841
+ };
7842
+ var resolveHtmlAssetUrlsAsync = async (html2, config) => {
7843
+ if (!config?.asset) return resolveHtmlAssetUrls(html2);
7844
+ const srcPattern = /(<(?:img|video|source)\s[^>]*?\bsrc\s*=\s*["'])([^"']*)(["'])/gi;
7845
+ const posterPattern = /(<video\s[^>]*?\bposter\s*=\s*["'])([^"']*)(["'])/gi;
7846
+ const scriptSplitPattern = /(<script\b[\s\S]*?<\/script>)/gi;
7847
+ const parts = html2.split(scriptSplitPattern);
7848
+ const nonScriptHtml = parts.filter((_, i) => i % 2 === 0).join("");
7849
+ const urlsToResolve = /* @__PURE__ */ new Map();
7850
+ const collectUrl = (src) => {
7851
+ if (!src.trim()) return;
7852
+ if (/^(data:|blob:|javascript:|#)/i.test(src)) return;
7853
+ if (src.includes("${")) return;
7854
+ urlsToResolve.set(src, src);
7855
+ };
7856
+ let match;
7857
+ const srcRe = new RegExp(srcPattern.source, srcPattern.flags);
7858
+ while ((match = srcRe.exec(nonScriptHtml)) !== null) {
7859
+ collectUrl(match[2]);
7860
+ }
7861
+ const posterRe = new RegExp(posterPattern.source, posterPattern.flags);
7862
+ while ((match = posterRe.exec(nonScriptHtml)) !== null) {
7863
+ collectUrl(match[2]);
7864
+ }
7865
+ await Promise.all(
7866
+ Array.from(urlsToResolve.keys()).map(async (src) => {
7867
+ const tagMatch = nonScriptHtml.match(
7868
+ new RegExp(`<(img|video|source)[^>]*(?:src|poster)=["']${src.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']`, "i")
7869
+ );
7870
+ const tag = tagMatch?.[1]?.toLowerCase() ?? "";
7871
+ const isVideo = tag === "video" || tag === "source";
7872
+ const type = isVideo ? "video" : "image";
7873
+ const isHttp = /^https?:/i.test(src);
7874
+ const asset = createAssetFromSource({
7875
+ fileId: !isHttp ? src : void 0,
7876
+ fileUrl: isHttp ? src : void 0,
7877
+ type
7878
+ });
7879
+ if (!asset) return;
7880
+ const resolved = await resolveAssetForDisplay(asset, config);
7881
+ if (resolved) {
7882
+ urlsToResolve.set(src, resolved.url);
7883
+ }
7884
+ })
7885
+ );
7886
+ const processedParts = parts.map((part, i) => {
7887
+ if (i % 2 === 1) return part;
7888
+ let result = part.replace(
7889
+ /(<(?:img|video|source)\s[^>]*?\bsrc\s*=\s*["'])([^"']*)(["'])/gi,
7890
+ (m, prefix, src, suffix) => {
7891
+ const resolved = urlsToResolve.get(src);
7892
+ return resolved && resolved !== src ? `${prefix}${resolved}${suffix}` : m;
7893
+ }
7894
+ );
7895
+ result = result.replace(
7896
+ /(<video\s[^>]*?\bposter\s*=\s*["'])([^"']*)(["'])/gi,
7897
+ (m, prefix, src, suffix) => {
7898
+ const resolved = urlsToResolve.get(src);
7899
+ return resolved && resolved !== src ? `${prefix}${resolved}${suffix}` : m;
7900
+ }
7901
+ );
7902
+ return result;
7903
+ });
7904
+ return processedParts.join("");
7905
+ };
7783
7906
  var ComponentContext = createContext(void 0);
7784
7907
  var ComponentProvider = ({
7785
7908
  components = {},
@@ -16231,10 +16354,10 @@ var Observer = class {
16231
16354
  });
16232
16355
  }
16233
16356
  };
16234
- this.custom = (jsx66, data) => {
16357
+ this.custom = (jsx68, data) => {
16235
16358
  const id = (data == null ? void 0 : data.id) || toastsCounter++;
16236
16359
  this.create({
16237
- jsx: jsx66(id),
16360
+ jsx: jsx68(id),
16238
16361
  id,
16239
16362
  ...data
16240
16363
  });
@@ -21743,15 +21866,24 @@ var CodeBlock3 = memo(function CodeBlock4({
21743
21866
  ] }, i)) }) }) })
21744
21867
  ] });
21745
21868
  });
21746
- var HtmlPreview3 = memo(function HtmlPreview4({ content }) {
21869
+ var HtmlPreview3 = memo(function HtmlPreview4({
21870
+ content,
21871
+ config
21872
+ }) {
21747
21873
  const [scale, setScale] = useState(1);
21748
21874
  const [deviceMode, setDeviceMode] = useState("responsive");
21749
21875
  const [isLoading, setIsLoading] = useState(true);
21750
21876
  const [iframeHeight, setIframeHeight] = useState(600);
21751
21877
  const iframeRef = useRef(null);
21752
21878
  const containerRef = useRef(null);
21753
- const blobUrl = useMemo(() => {
21754
- const styleInjection = `
21879
+ const [blobUrl, setBlobUrl] = useState("");
21880
+ useEffect(() => {
21881
+ let active = true;
21882
+ let currentUrl = "";
21883
+ const buildBlobUrl = async () => {
21884
+ const processed = config?.asset ? await resolveHtmlAssetUrlsAsync(content, config) : resolveHtmlAssetUrls(content);
21885
+ if (!active) return;
21886
+ const styleInjection = `
21755
21887
  <style>
21756
21888
  html, body {
21757
21889
  margin: 0;
@@ -21765,24 +21897,26 @@ var HtmlPreview3 = memo(function HtmlPreview4({ content }) {
21765
21897
  }
21766
21898
  </style>
21767
21899
  `;
21768
- let modifiedContent = content;
21769
- if (content.includes("<head>")) {
21770
- modifiedContent = content.replace("<head>", "<head>" + styleInjection);
21771
- } else if (content.includes("<html>")) {
21772
- modifiedContent = content.replace("<html>", "<html><head>" + styleInjection + "</head>");
21773
- } else if (content.includes("<!DOCTYPE") || content.includes("<!doctype")) {
21774
- modifiedContent = content.replace(/(<!DOCTYPE[^>]*>|<!doctype[^>]*>)/i, "$1<html><head>" + styleInjection + "</head><body>") + "</body></html>";
21775
- } else {
21776
- modifiedContent = `<!DOCTYPE html><html><head>${styleInjection}</head><body>${content}</body></html>`;
21777
- }
21778
- const blob = new Blob([modifiedContent], { type: "text/html" });
21779
- return URL.createObjectURL(blob);
21780
- }, [content]);
21781
- useEffect(() => {
21900
+ let modifiedContent = processed;
21901
+ if (processed.includes("<head>")) {
21902
+ modifiedContent = processed.replace("<head>", "<head>" + styleInjection);
21903
+ } else if (processed.includes("<html>")) {
21904
+ modifiedContent = processed.replace("<html>", "<html><head>" + styleInjection + "</head>");
21905
+ } else if (processed.includes("<!DOCTYPE") || processed.includes("<!doctype")) {
21906
+ modifiedContent = processed.replace(/(<!DOCTYPE[^>]*>|<!doctype[^>]*>)/i, "$1<html><head>" + styleInjection + "</head><body>") + "</body></html>";
21907
+ } else {
21908
+ modifiedContent = `<!DOCTYPE html><html><head>${styleInjection}</head><body>${processed}</body></html>`;
21909
+ }
21910
+ const blob = new Blob([modifiedContent], { type: "text/html" });
21911
+ currentUrl = URL.createObjectURL(blob);
21912
+ setBlobUrl(currentUrl);
21913
+ };
21914
+ buildBlobUrl();
21782
21915
  return () => {
21783
- URL.revokeObjectURL(blobUrl);
21916
+ active = false;
21917
+ if (currentUrl) URL.revokeObjectURL(currentUrl);
21784
21918
  };
21785
- }, [blobUrl]);
21919
+ }, [content, config]);
21786
21920
  const deviceConfig = {
21787
21921
  desktop: { width: "100%", maxWidth: "1400px", height: 800, icon: Monitor, label: "Desktop" },
21788
21922
  tablet: { width: "768px", height: 1024, icon: Tablet, label: "Tablet" },
@@ -21937,7 +22071,7 @@ var HtmlPreview3 = memo(function HtmlPreview4({ content }) {
21937
22071
  },
21938
22072
  children: [
21939
22073
  deviceMode === "mobile" && /* @__PURE__ */ jsx("div", { className: "h-6 bg-zinc-900 agent-sdk-light:bg-zinc-200 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "w-16 h-4 bg-zinc-800 agent-sdk-light:bg-zinc-300 rounded-full" }) }),
21940
- /* @__PURE__ */ jsx(
22074
+ blobUrl && /* @__PURE__ */ jsx(
21941
22075
  "iframe",
21942
22076
  {
21943
22077
  ref: iframeRef,
@@ -23834,6 +23968,237 @@ function ArtifactDeleteButton({
23834
23968
  modal
23835
23969
  ] });
23836
23970
  }
23971
+ var CHANGEABLE_TYPES = ["code", "html", "svg", "markdown", "json", "text"];
23972
+ function ArtifactTypeSelector({
23973
+ currentType,
23974
+ currentLanguage,
23975
+ onTypeChange,
23976
+ disabled = false
23977
+ }) {
23978
+ const [isOpen, setIsOpen] = useState(false);
23979
+ const [isChanging, setIsChanging] = useState(false);
23980
+ const dropdownRef = useRef(null);
23981
+ const typeConfig2 = artifactTypeConfig[currentType] || artifactTypeConfig.text;
23982
+ const isChangeable = CHANGEABLE_TYPES.includes(currentType);
23983
+ useEffect(() => {
23984
+ if (!isOpen) return;
23985
+ const handleClickOutside = (e) => {
23986
+ if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
23987
+ setIsOpen(false);
23988
+ }
23989
+ };
23990
+ document.addEventListener("mousedown", handleClickOutside);
23991
+ return () => document.removeEventListener("mousedown", handleClickOutside);
23992
+ }, [isOpen]);
23993
+ const handleSelectType = useCallback(async (newType) => {
23994
+ if (newType === currentType || isChanging) return;
23995
+ setIsChanging(true);
23996
+ try {
23997
+ await onTypeChange(newType);
23998
+ setIsOpen(false);
23999
+ } finally {
24000
+ setIsChanging(false);
24001
+ }
24002
+ }, [currentType, isChanging, onTypeChange]);
24003
+ if (!isChangeable) {
24004
+ return /* @__PURE__ */ jsx("div", { className: `w-7 h-7 rounded-lg ${typeConfig2.bgColor} flex items-center justify-center flex-shrink-0`, children: /* @__PURE__ */ jsx(typeConfig2.icon, { size: 14, className: typeConfig2.color }) });
24005
+ }
24006
+ const availableTypes = CHANGEABLE_TYPES.filter((t) => t !== currentType);
24007
+ return /* @__PURE__ */ jsxs("div", { className: "relative", ref: dropdownRef, children: [
24008
+ /* @__PURE__ */ jsxs(
24009
+ "button",
24010
+ {
24011
+ onClick: () => !disabled && !isChanging && setIsOpen(!isOpen),
24012
+ disabled: disabled || isChanging,
24013
+ className: cn3(
24014
+ "flex items-center gap-1 p-1 rounded-lg transition-colors",
24015
+ "hover:bg-zinc-800 agent-sdk-light:hover:bg-zinc-200",
24016
+ (disabled || isChanging) && "opacity-50 cursor-not-allowed"
24017
+ ),
24018
+ title: "\u5207\u6362\u4EA7\u7269\u7C7B\u578B",
24019
+ children: [
24020
+ /* @__PURE__ */ jsx("div", { className: `w-7 h-7 rounded-lg ${typeConfig2.bgColor} flex items-center justify-center flex-shrink-0`, children: isChanging ? /* @__PURE__ */ jsx(Loader2, { size: 14, className: `${typeConfig2.color} animate-spin` }) : /* @__PURE__ */ jsx(typeConfig2.icon, { size: 14, className: typeConfig2.color }) }),
24021
+ /* @__PURE__ */ jsx(ChevronDown, { size: 10, className: "text-zinc-500" })
24022
+ ]
24023
+ }
24024
+ ),
24025
+ isOpen && /* @__PURE__ */ 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: [
24026
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-2 border-b border-zinc-800/50 agent-sdk-light:border-zinc-100", children: /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-zinc-500 agent-sdk-light:text-zinc-400", children: "\u5207\u6362\u7C7B\u578B" }) }),
24027
+ /* @__PURE__ */ jsx("div", { className: "p-1", children: availableTypes.map((type) => {
24028
+ const config = artifactTypeConfig[type];
24029
+ const TypeIcon = config.icon;
24030
+ return /* @__PURE__ */ jsxs(
24031
+ "button",
24032
+ {
24033
+ onClick: () => handleSelectType(type),
24034
+ disabled: isChanging,
24035
+ className: cn3(
24036
+ "flex items-center gap-2.5 px-2 py-1.5 text-xs rounded-md transition-all w-full text-left",
24037
+ "text-zinc-300 agent-sdk-light:text-zinc-700",
24038
+ "hover:bg-zinc-800/70 agent-sdk-light:hover:bg-zinc-100",
24039
+ isChanging && "opacity-50 cursor-not-allowed"
24040
+ ),
24041
+ children: [
24042
+ /* @__PURE__ */ jsx("div", { className: cn3("w-5 h-5 rounded flex items-center justify-center flex-shrink-0", config.bgColor), children: /* @__PURE__ */ jsx(TypeIcon, { size: 11, className: config.color }) }),
24043
+ /* @__PURE__ */ jsx("span", { children: config.label })
24044
+ ]
24045
+ },
24046
+ type
24047
+ );
24048
+ }) })
24049
+ ] })
24050
+ ] });
24051
+ }
24052
+ var COMMON_LANGUAGES = [
24053
+ "javascript",
24054
+ "typescript",
24055
+ "python",
24056
+ "java",
24057
+ "go",
24058
+ "rust",
24059
+ "c",
24060
+ "cpp",
24061
+ "csharp",
24062
+ "ruby",
24063
+ "php",
24064
+ "swift",
24065
+ "kotlin",
24066
+ "sql",
24067
+ "shell",
24068
+ "html",
24069
+ "css",
24070
+ "json",
24071
+ "yaml",
24072
+ "xml",
24073
+ "markdown"
24074
+ ];
24075
+ function ArtifactLanguageSelector({
24076
+ currentLanguage,
24077
+ onLanguageChange,
24078
+ disabled = false
24079
+ }) {
24080
+ const [isOpen, setIsOpen] = useState(false);
24081
+ const [isChanging, setIsChanging] = useState(false);
24082
+ const [search, setSearch] = useState("");
24083
+ const dropdownRef = useRef(null);
24084
+ const inputRef = useRef(null);
24085
+ useEffect(() => {
24086
+ if (!isOpen) return;
24087
+ const handleClickOutside = (e) => {
24088
+ if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
24089
+ setIsOpen(false);
24090
+ setSearch("");
24091
+ }
24092
+ };
24093
+ document.addEventListener("mousedown", handleClickOutside);
24094
+ return () => document.removeEventListener("mousedown", handleClickOutside);
24095
+ }, [isOpen]);
24096
+ useEffect(() => {
24097
+ if (isOpen && inputRef.current) {
24098
+ inputRef.current.focus();
24099
+ }
24100
+ }, [isOpen]);
24101
+ const handleSelect = useCallback(async (language) => {
24102
+ if (language === currentLanguage || isChanging) return;
24103
+ setIsChanging(true);
24104
+ try {
24105
+ await onLanguageChange(language);
24106
+ setIsOpen(false);
24107
+ setSearch("");
24108
+ } finally {
24109
+ setIsChanging(false);
24110
+ }
24111
+ }, [currentLanguage, isChanging, onLanguageChange]);
24112
+ const handleKeyDown = useCallback((e) => {
24113
+ if (e.key === "Enter" && search.trim()) {
24114
+ e.preventDefault();
24115
+ handleSelect(search.trim().toLowerCase());
24116
+ } else if (e.key === "Escape") {
24117
+ setIsOpen(false);
24118
+ setSearch("");
24119
+ }
24120
+ }, [search, handleSelect]);
24121
+ const filteredLanguages = search.trim() ? COMMON_LANGUAGES.filter((lang) => lang.includes(search.trim().toLowerCase())) : COMMON_LANGUAGES;
24122
+ const showCustomOption = search.trim() && !COMMON_LANGUAGES.includes(search.trim().toLowerCase()) && search.trim().toLowerCase() !== currentLanguage;
24123
+ if (!currentLanguage) return null;
24124
+ return /* @__PURE__ */ jsxs("div", { className: "relative", ref: dropdownRef, children: [
24125
+ /* @__PURE__ */ jsx(
24126
+ "button",
24127
+ {
24128
+ onClick: () => !disabled && !isChanging && setIsOpen(!isOpen),
24129
+ disabled: disabled || isChanging,
24130
+ className: cn3(
24131
+ "text-zinc-500 agent-sdk-light:text-zinc-500 ml-1 text-xs transition-colors",
24132
+ "hover:text-zinc-300 agent-sdk-light:hover:text-zinc-700",
24133
+ (disabled || isChanging) && "opacity-50 cursor-not-allowed",
24134
+ !disabled && !isChanging && "cursor-pointer"
24135
+ ),
24136
+ children: isChanging ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
24137
+ /* @__PURE__ */ jsx(Loader2, { size: 10, className: "animate-spin" }),
24138
+ currentLanguage
24139
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
24140
+ "\u2022 ",
24141
+ currentLanguage
24142
+ ] })
24143
+ }
24144
+ ),
24145
+ isOpen && /* @__PURE__ */ 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: [
24146
+ /* @__PURE__ */ jsx("div", { className: "p-2 border-b border-zinc-800/50 agent-sdk-light:border-zinc-100", children: /* @__PURE__ */ jsx(
24147
+ "input",
24148
+ {
24149
+ ref: inputRef,
24150
+ type: "text",
24151
+ value: search,
24152
+ onChange: (e) => setSearch(e.target.value),
24153
+ onKeyDown: handleKeyDown,
24154
+ placeholder: "\u641C\u7D22\u8BED\u8A00...",
24155
+ 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"
24156
+ }
24157
+ ) }),
24158
+ /* @__PURE__ */ jsxs("div", { className: "max-h-48 overflow-y-auto p-1", children: [
24159
+ showCustomOption && /* @__PURE__ */ jsxs(
24160
+ "button",
24161
+ {
24162
+ onClick: () => handleSelect(search.trim().toLowerCase()),
24163
+ disabled: isChanging,
24164
+ className: cn3(
24165
+ "flex items-center justify-between px-2 py-1.5 text-xs rounded-md transition-all w-full text-left",
24166
+ "text-zinc-300 agent-sdk-light:text-zinc-700",
24167
+ "hover:bg-zinc-800/70 agent-sdk-light:hover:bg-zinc-100",
24168
+ isChanging && "opacity-50 cursor-not-allowed"
24169
+ ),
24170
+ children: [
24171
+ /* @__PURE__ */ jsxs("span", { children: [
24172
+ '"',
24173
+ search.trim().toLowerCase(),
24174
+ '"'
24175
+ ] }),
24176
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-zinc-600 agent-sdk-light:text-zinc-400", children: "\u56DE\u8F66\u786E\u8BA4" })
24177
+ ]
24178
+ }
24179
+ ),
24180
+ filteredLanguages.map((lang) => /* @__PURE__ */ jsxs(
24181
+ "button",
24182
+ {
24183
+ onClick: () => handleSelect(lang),
24184
+ disabled: isChanging,
24185
+ className: cn3(
24186
+ "flex items-center justify-between px-2 py-1.5 text-xs rounded-md transition-all w-full text-left",
24187
+ 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",
24188
+ isChanging && "opacity-50 cursor-not-allowed"
24189
+ ),
24190
+ children: [
24191
+ /* @__PURE__ */ jsx("span", { children: lang }),
24192
+ lang === currentLanguage && /* @__PURE__ */ jsx(Check, { size: 12, className: "text-green-400 agent-sdk-light:text-green-600 flex-shrink-0" })
24193
+ ]
24194
+ },
24195
+ lang
24196
+ )),
24197
+ filteredLanguages.length === 0 && !showCustomOption && /* @__PURE__ */ 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" })
24198
+ ] })
24199
+ ] })
24200
+ ] });
24201
+ }
23837
24202
  var ArtifactViewer = memo(function ArtifactViewer2({
23838
24203
  artifact,
23839
24204
  isOpen,
@@ -23851,13 +24216,20 @@ var ArtifactViewer = memo(function ArtifactViewer2({
23851
24216
  onContentChange,
23852
24217
  onSave,
23853
24218
  onVisibilityChange,
23854
- onDelete
24219
+ onDelete,
24220
+ onTypeChange,
24221
+ onLanguageChange,
24222
+ onTitleChange
23855
24223
  }) {
23856
24224
  const [viewMode, setViewMode] = useState(defaultView);
23857
24225
  const [isEditing, setIsEditing] = useState(false);
23858
24226
  const [editContent, setEditContent] = useState("");
23859
24227
  const [undoStack, setUndoStack] = useState([]);
23860
24228
  const [redoStack, setRedoStack] = useState([]);
24229
+ const [isEditingTitle, setIsEditingTitle] = useState(false);
24230
+ const [editingTitle, setEditingTitle] = useState("");
24231
+ const [isSavingTitle, setIsSavingTitle] = useState(false);
24232
+ const titleInputRef = useRef(null);
23861
24233
  useEffect(() => {
23862
24234
  if (artifact) {
23863
24235
  if (artifact.type === "html" || artifact.type === "markdown" || artifact.type === "svg") {
@@ -23869,8 +24241,9 @@ var ArtifactViewer = memo(function ArtifactViewer2({
23869
24241
  setEditContent(artifact.content);
23870
24242
  setUndoStack([]);
23871
24243
  setRedoStack([]);
24244
+ setIsEditingTitle(false);
23872
24245
  }
23873
- }, [artifact?.id]);
24246
+ }, [artifact?.id, artifact?.type]);
23874
24247
  useEffect(() => {
23875
24248
  if (artifact && !isEditing) {
23876
24249
  setEditContent(artifact.content);
@@ -23883,6 +24256,7 @@ var ArtifactViewer = memo(function ArtifactViewer2({
23883
24256
  const handleStartEdit = () => {
23884
24257
  setEditContent(artifact.content);
23885
24258
  setUndoStack([artifact.content]);
24259
+ handleStartEditTitle();
23886
24260
  setRedoStack([]);
23887
24261
  setIsEditing(true);
23888
24262
  setViewMode("code");
@@ -23917,6 +24291,43 @@ var ArtifactViewer = memo(function ArtifactViewer2({
23917
24291
  setEditContent(artifact.content);
23918
24292
  setIsEditing(false);
23919
24293
  };
24294
+ const handleStartEditTitle = useCallback(() => {
24295
+ if (!onTitleChange || isEditing || isSavingTitle) return;
24296
+ setEditingTitle(artifact.title);
24297
+ setIsEditingTitle(true);
24298
+ }, [onTitleChange, isEditing, isSavingTitle, artifact.title]);
24299
+ const handleSaveTitle = useCallback(async () => {
24300
+ const trimmed = editingTitle.trim();
24301
+ if (!trimmed || trimmed === artifact.title) {
24302
+ setIsEditingTitle(false);
24303
+ return;
24304
+ }
24305
+ setIsSavingTitle(true);
24306
+ try {
24307
+ await onTitleChange?.(artifact.id, trimmed);
24308
+ } finally {
24309
+ setIsSavingTitle(false);
24310
+ setIsEditingTitle(false);
24311
+ }
24312
+ }, [editingTitle, artifact.title, artifact.id, onTitleChange]);
24313
+ const handleCancelEditTitle = useCallback(() => {
24314
+ setIsEditingTitle(false);
24315
+ }, []);
24316
+ const handleTitleKeyDown = useCallback((e) => {
24317
+ if (e.key === "Enter") {
24318
+ e.preventDefault();
24319
+ handleSaveTitle();
24320
+ } else if (e.key === "Escape") {
24321
+ e.preventDefault();
24322
+ handleCancelEditTitle();
24323
+ }
24324
+ }, [handleSaveTitle, handleCancelEditTitle]);
24325
+ useEffect(() => {
24326
+ if (isEditingTitle && titleInputRef.current) {
24327
+ titleInputRef.current.focus();
24328
+ titleInputRef.current.select();
24329
+ }
24330
+ }, [isEditingTitle]);
23920
24331
  const displayContent = isEditing ? editContent : artifact.content;
23921
24332
  const renderContent = () => {
23922
24333
  if (isEditing) {
@@ -23957,7 +24368,7 @@ var ArtifactViewer = memo(function ArtifactViewer2({
23957
24368
  switch (artifact.type) {
23958
24369
  case "html":
23959
24370
  case "svg":
23960
- return /* @__PURE__ */ jsx(HtmlPreview3, { content: displayContent });
24371
+ return /* @__PURE__ */ jsx(HtmlPreview3, { content: displayContent, config });
23961
24372
  case "markdown":
23962
24373
  return /* @__PURE__ */ jsx(MarkdownPreview, { content: displayContent, config });
23963
24374
  default:
@@ -23974,15 +24385,56 @@ var ArtifactViewer = memo(function ArtifactViewer2({
23974
24385
  return /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col bg-zinc-900 agent-sdk-light:bg-white relative", children: [
23975
24386
  /* @__PURE__ */ 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: [
23976
24387
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
23977
- /* @__PURE__ */ jsx("div", { className: `w-7 h-7 rounded-lg ${typeConfig2.bgColor} flex items-center justify-center flex-shrink-0`, children: /* @__PURE__ */ jsx(typeConfig2.icon, { size: 14, className: typeConfig2.color }) }),
24388
+ onTypeChange ? /* @__PURE__ */ jsx(
24389
+ ArtifactTypeSelector,
24390
+ {
24391
+ currentType: artifact.type,
24392
+ currentLanguage: artifact.language,
24393
+ onTypeChange: (newType, language) => onTypeChange(artifact.id, newType, language),
24394
+ disabled: isEditing
24395
+ }
24396
+ ) : /* @__PURE__ */ jsx("div", { className: `w-7 h-7 rounded-lg ${typeConfig2.bgColor} flex items-center justify-center flex-shrink-0`, children: /* @__PURE__ */ jsx(typeConfig2.icon, { size: 14, className: typeConfig2.color }) }),
23978
24397
  /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
23979
- /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium text-zinc-100 agent-sdk-light:text-zinc-900 truncate", children: artifact.title }),
24398
+ isEditingTitle ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
24399
+ /* @__PURE__ */ jsx(
24400
+ "input",
24401
+ {
24402
+ ref: titleInputRef,
24403
+ type: "text",
24404
+ value: editingTitle,
24405
+ onChange: (e) => setEditingTitle(e.target.value),
24406
+ onKeyDown: handleTitleKeyDown,
24407
+ onBlur: handleSaveTitle,
24408
+ disabled: isSavingTitle,
24409
+ 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"
24410
+ }
24411
+ ),
24412
+ isSavingTitle && /* @__PURE__ */ jsx(Loader2, { size: 12, className: "text-zinc-500 animate-spin flex-shrink-0" })
24413
+ ] }) : /* @__PURE__ */ jsx(
24414
+ "h3",
24415
+ {
24416
+ className: cn3(
24417
+ "text-sm font-medium text-zinc-100 agent-sdk-light:text-zinc-900 truncate",
24418
+ onTitleChange && !isEditing && "cursor-pointer hover:text-zinc-300 agent-sdk-light:hover:text-zinc-600"
24419
+ ),
24420
+ onDoubleClick: handleStartEditTitle,
24421
+ title: onTitleChange && !isEditing ? "\u53CC\u51FB\u7F16\u8F91\u6807\u9898" : void 0,
24422
+ children: artifact.title
24423
+ }
24424
+ ),
23980
24425
  /* @__PURE__ */ jsxs("p", { className: `text-xs ${typeConfig2.color}`, children: [
23981
24426
  typeConfig2.label,
23982
- artifact.language && artifact.language !== artifact.type && /* @__PURE__ */ jsxs("span", { className: "text-zinc-500 agent-sdk-light:text-zinc-500 ml-1", children: [
24427
+ artifact.language && artifact.language !== artifact.type && (onLanguageChange ? /* @__PURE__ */ jsx(
24428
+ ArtifactLanguageSelector,
24429
+ {
24430
+ currentLanguage: artifact.language,
24431
+ onLanguageChange: (lang) => onLanguageChange(artifact.id, lang),
24432
+ disabled: isEditing
24433
+ }
24434
+ ) : /* @__PURE__ */ jsxs("span", { className: "text-zinc-500 agent-sdk-light:text-zinc-500 ml-1", children: [
23983
24435
  "\u2022 ",
23984
24436
  artifact.language
23985
- ] })
24437
+ ] }))
23986
24438
  ] })
23987
24439
  ] })
23988
24440
  ] }),
@@ -24107,15 +24559,54 @@ var ArtifactViewer = memo(function ArtifactViewer2({
24107
24559
  isOpen,
24108
24560
  onClose,
24109
24561
  title: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
24110
- /* @__PURE__ */ jsx("div", { className: `w-6 h-6 rounded-md ${typeConfig2.bgColor} flex items-center justify-center`, children: /* @__PURE__ */ jsx(typeConfig2.icon, { size: 14, className: typeConfig2.color }) }),
24111
- /* @__PURE__ */ jsx("span", { className: "truncate", children: artifact.title })
24562
+ onTypeChange ? /* @__PURE__ */ jsx(
24563
+ ArtifactTypeSelector,
24564
+ {
24565
+ currentType: artifact.type,
24566
+ currentLanguage: artifact.language,
24567
+ onTypeChange: (newType, language) => onTypeChange(artifact.id, newType, language),
24568
+ disabled: isEditing
24569
+ }
24570
+ ) : /* @__PURE__ */ jsx("div", { className: `w-6 h-6 rounded-md ${typeConfig2.bgColor} flex items-center justify-center`, children: /* @__PURE__ */ jsx(typeConfig2.icon, { size: 14, className: typeConfig2.color }) }),
24571
+ isEditingTitle ? /* @__PURE__ */ jsx(
24572
+ "input",
24573
+ {
24574
+ ref: titleInputRef,
24575
+ type: "text",
24576
+ value: editingTitle,
24577
+ onChange: (e) => setEditingTitle(e.target.value),
24578
+ onKeyDown: handleTitleKeyDown,
24579
+ onBlur: handleSaveTitle,
24580
+ disabled: isSavingTitle,
24581
+ 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"
24582
+ }
24583
+ ) : /* @__PURE__ */ jsx(
24584
+ "span",
24585
+ {
24586
+ className: cn3(
24587
+ "truncate",
24588
+ onTitleChange && !isEditing && "cursor-pointer hover:text-zinc-300 agent-sdk-light:hover:text-zinc-600"
24589
+ ),
24590
+ onDoubleClick: handleStartEditTitle,
24591
+ title: onTitleChange && !isEditing ? "\u53CC\u51FB\u7F16\u8F91\u6807\u9898" : void 0,
24592
+ children: artifact.title
24593
+ }
24594
+ ),
24595
+ isSavingTitle && /* @__PURE__ */ jsx(Loader2, { size: 12, className: "text-zinc-500 animate-spin flex-shrink-0" })
24112
24596
  ] }),
24113
24597
  subtitle: /* @__PURE__ */ jsxs("span", { className: typeConfig2.color, children: [
24114
24598
  typeConfig2.label,
24115
- artifact.language && artifact.language !== artifact.type && /* @__PURE__ */ jsxs("span", { className: "text-zinc-500 agent-sdk-light:text-zinc-500 ml-1", children: [
24599
+ artifact.language && artifact.language !== artifact.type && (onLanguageChange ? /* @__PURE__ */ jsx(
24600
+ ArtifactLanguageSelector,
24601
+ {
24602
+ currentLanguage: artifact.language,
24603
+ onLanguageChange: (lang) => onLanguageChange(artifact.id, lang),
24604
+ disabled: isEditing
24605
+ }
24606
+ ) : /* @__PURE__ */ jsxs("span", { className: "text-zinc-500 agent-sdk-light:text-zinc-500 ml-1", children: [
24116
24607
  "\u2022 ",
24117
24608
  artifact.language
24118
- ] })
24609
+ ] }))
24119
24610
  ] }),
24120
24611
  isFullscreen,
24121
24612
  onFullscreenToggle,
@@ -25028,7 +25519,7 @@ function useArtifactPanel({ currentSessionId }) {
25028
25519
  const existingArtifact = Object.values(artifacts).find(
25029
25520
  (a) => {
25030
25521
  const sameContent = a.currentContent === data.content && a.type === data.type;
25031
- const sameId = a?.metadata?.workId === data.metadata?.workId;
25522
+ const sameId = !!data.metadata?.workId && a?.metadata?.workId === data.metadata?.workId;
25032
25523
  return sameContent || sameId;
25033
25524
  }
25034
25525
  );
@@ -25090,7 +25581,8 @@ function useArtifactPanel({ currentSessionId }) {
25090
25581
  setActiveArtifact,
25091
25582
  removeArtifact,
25092
25583
  reorderArtifacts,
25093
- updateArtifactContent
25584
+ updateArtifactContent,
25585
+ upsertArtifact
25094
25586
  };
25095
25587
  }
25096
25588
 
@@ -25906,7 +26398,8 @@ var AgentChat = React16__default.forwardRef(({
25906
26398
  setActiveArtifact,
25907
26399
  removeArtifact,
25908
26400
  reorderArtifacts,
25909
- updateArtifactContent
26401
+ updateArtifactContent,
26402
+ upsertArtifact
25910
26403
  } = useArtifactPanel({ currentSessionId: useAgentStore((state) => state.currentSession?.sessionId) });
25911
26404
  const reconnectRef = useRef(null);
25912
26405
  const reconnectWrapper = useCallback(async (messageId) => {
@@ -26380,6 +26873,52 @@ var AgentChat = React16__default.forwardRef(({
26380
26873
  toast.error("\u5220\u9664\u4EA7\u7269\u5931\u8D25");
26381
26874
  }
26382
26875
  },
26876
+ onTypeChange: async (artifactId, newType, language) => {
26877
+ try {
26878
+ const content = activeArtifact?.currentContent || "";
26879
+ const res = await artifactService.updateContent(artifactId, content, {
26880
+ type: newType,
26881
+ language
26882
+ });
26883
+ if (res.success && res.data) {
26884
+ upsertArtifact(artifactService.normalizeEntry(res.data));
26885
+ toast.success("\u7C7B\u578B\u5DF2\u66F4\u65B0");
26886
+ } else {
26887
+ toast.error("\u7C7B\u578B\u66F4\u65B0\u5931\u8D25");
26888
+ }
26889
+ } catch (err) {
26890
+ console.error("[AgentChat] Change artifact type failed:", err);
26891
+ toast.error("\u7C7B\u578B\u66F4\u65B0\u5931\u8D25");
26892
+ }
26893
+ },
26894
+ onLanguageChange: async (artifactId, language) => {
26895
+ try {
26896
+ const content = activeArtifact?.currentContent || "";
26897
+ const res = await artifactService.updateContent(artifactId, content, { language });
26898
+ if (res.success && res.data) {
26899
+ upsertArtifact(artifactService.normalizeEntry(res.data));
26900
+ } else {
26901
+ toast.error("\u8BED\u8A00\u66F4\u65B0\u5931\u8D25");
26902
+ }
26903
+ } catch (err) {
26904
+ console.error("[AgentChat] Change artifact language failed:", err);
26905
+ toast.error("\u8BED\u8A00\u66F4\u65B0\u5931\u8D25");
26906
+ }
26907
+ },
26908
+ onTitleChange: async (artifactId, title) => {
26909
+ try {
26910
+ const content = activeArtifact?.currentContent || "";
26911
+ const res = await artifactService.updateContent(artifactId, content, { title });
26912
+ if (res.success && res.data) {
26913
+ upsertArtifact(artifactService.normalizeEntry(res.data));
26914
+ } else {
26915
+ toast.error("\u6807\u9898\u66F4\u65B0\u5931\u8D25");
26916
+ }
26917
+ } catch (err) {
26918
+ console.error("[AgentChat] Change artifact title failed:", err);
26919
+ toast.error("\u6807\u9898\u66F4\u65B0\u5931\u8D25");
26920
+ }
26921
+ },
26383
26922
  onVisibilityChange: async (artifactId, isPublic) => {
26384
26923
  try {
26385
26924
  const res = await artifactService.updateVisibility(artifactId, isPublic);
@@ -26915,19 +27454,58 @@ function ShareReplayPage({ shareId, onNavigateBack }) {
26915
27454
  ] });
26916
27455
  }
26917
27456
  var typeConfig = {
26918
- html: { icon: Globe, label: "HTML", color: "text-orange-400", bgColor: "bg-orange-500/10" },
26919
- svg: { icon: Globe, label: "SVG", color: "text-orange-400", bgColor: "bg-orange-500/10" },
26920
- markdown: { icon: FileText, label: "Markdown", color: "text-blue-400", bgColor: "bg-blue-500/10" },
26921
- json: { icon: FileJson, label: "JSON", color: "text-yellow-400", bgColor: "bg-yellow-500/10" },
26922
- code: { icon: FileCode, label: "Code", color: "text-purple-400", bgColor: "bg-purple-500/10" },
26923
- text: { icon: FileText, label: "Text", color: "text-zinc-400", bgColor: "bg-zinc-500/10" },
26924
- image: { icon: FileImage, label: "Image", color: "text-green-400", bgColor: "bg-green-500/10" },
26925
- video: { icon: Video, label: "Video", color: "text-pink-400", bgColor: "bg-pink-500/10" }
27457
+ html: { icon: Globe, label: "HTML", color: "#fb923c" },
27458
+ svg: { icon: Globe, label: "SVG", color: "#fb923c" },
27459
+ markdown: { icon: FileText, label: "Markdown", color: "#60a5fa" },
27460
+ json: { icon: FileJson, label: "JSON", color: "#facc15" },
27461
+ code: { icon: FileCode, label: "Code", color: "#c084fc" },
27462
+ text: { icon: FileText, label: "Text", color: "#a1a1aa" },
27463
+ image: { icon: FileImage, label: "Image", color: "#4ade80" },
27464
+ video: { icon: Video, label: "Video", color: "#f472b6" }
26926
27465
  };
27466
+ function FullscreenHtmlPreview({ content }) {
27467
+ const blobUrl = useMemo(() => {
27468
+ const processed = resolveHtmlAssetUrls(content);
27469
+ const styleInjection = `
27470
+ <style>
27471
+ html, body { margin: 0; padding: 0; width: 100%; min-height: 100%; box-sizing: border-box; }
27472
+ * { box-sizing: border-box; }
27473
+ </style>`;
27474
+ let modified = processed;
27475
+ if (processed.includes("<head>")) {
27476
+ modified = processed.replace("<head>", "<head>" + styleInjection);
27477
+ } else if (processed.includes("<html>")) {
27478
+ modified = processed.replace("<html>", "<html><head>" + styleInjection + "</head>");
27479
+ } else if (/<!(DOCTYPE|doctype)/i.test(processed)) {
27480
+ modified = processed.replace(/(<!DOCTYPE[^>]*>|<!doctype[^>]*>)/i, "$1<html><head>" + styleInjection + "</head><body>") + "</body></html>";
27481
+ } else {
27482
+ modified = `<!DOCTYPE html><html><head>${styleInjection}</head><body>${processed}</body></html>`;
27483
+ }
27484
+ const blob = new Blob([modified], { type: "text/html" });
27485
+ return URL.createObjectURL(blob);
27486
+ }, [content]);
27487
+ useEffect(() => {
27488
+ return () => URL.revokeObjectURL(blobUrl);
27489
+ }, [blobUrl]);
27490
+ return /* @__PURE__ */ jsx(
27491
+ "iframe",
27492
+ {
27493
+ src: blobUrl,
27494
+ style: { display: "block", width: "100%", height: "100%", border: "none", background: "white" },
27495
+ sandbox: "allow-scripts allow-same-origin allow-popups allow-forms allow-modals",
27496
+ title: "HTML Preview"
27497
+ }
27498
+ );
27499
+ }
26927
27500
  function PublicArtifactPage({ shareToken, onNavigateBack }) {
26928
27501
  const [pageState, setPageState] = useState("loading");
26929
27502
  const [error, setError] = useState(null);
26930
27503
  const [artifact, setArtifact] = useState(null);
27504
+ const [isTheaterMode, setIsTheaterMode] = useState(false);
27505
+ const [isBrowserFullscreen, setIsBrowserFullscreen] = useState(false);
27506
+ const [showTheaterControls, setShowTheaterControls] = useState(true);
27507
+ const theaterTimerRef = useRef(null);
27508
+ const isFullscreenSupported = typeof document !== "undefined" && typeof document.documentElement?.requestFullscreen === "function";
26931
27509
  useEffect(() => {
26932
27510
  if (!shareToken) {
26933
27511
  setPageState("not-found");
@@ -26951,31 +27529,13 @@ function PublicArtifactPage({ shareToken, onNavigateBack }) {
26951
27529
  }
26952
27530
  load();
26953
27531
  }, [shareToken]);
26954
- const handleShare = useCallback(() => {
26955
- const url = window.location.href;
26956
- navigator.clipboard.writeText(url);
26957
- toast.success("\u94FE\u63A5\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F");
26958
- }, []);
26959
27532
  const handleDownload = useCallback(() => {
26960
27533
  if (!artifact) return;
26961
- const extMap = {
26962
- html: "html",
26963
- svg: "svg",
26964
- markdown: "md",
26965
- json: "json",
26966
- code: artifact.language || "txt",
26967
- text: "txt"
26968
- };
26969
- const ext = extMap[artifact.type] || "txt";
26970
- const mimeMap = {
26971
- html: "text/html",
26972
- svg: "image/svg+xml",
26973
- markdown: "text/markdown",
26974
- json: "application/json",
26975
- code: "text/plain",
26976
- text: "text/plain"
26977
- };
26978
- const mime = mimeMap[artifact.type] || "text/plain";
27534
+ const type = artifact.type?.toLowerCase() ?? "text";
27535
+ const extMap = { html: "html", svg: "svg", markdown: "md", json: "json", code: artifact.language || "txt", text: "txt" };
27536
+ const ext = extMap[type] || "txt";
27537
+ const mimeMap = { html: "text/html", svg: "image/svg+xml", markdown: "text/markdown", json: "application/json", code: "text/plain", text: "text/plain" };
27538
+ const mime = mimeMap[type] || "text/plain";
26979
27539
  const blob = new Blob([artifact.content], { type: mime });
26980
27540
  const url = URL.createObjectURL(blob);
26981
27541
  const link2 = document.createElement("a");
@@ -26986,15 +27546,85 @@ function PublicArtifactPage({ shareToken, onNavigateBack }) {
26986
27546
  document.body.removeChild(link2);
26987
27547
  URL.revokeObjectURL(url);
26988
27548
  }, [artifact]);
27549
+ const toggleTheaterMode = useCallback(() => {
27550
+ setIsTheaterMode((prev) => !prev);
27551
+ setShowTheaterControls(true);
27552
+ }, []);
27553
+ const exitTheaterMode = useCallback(() => {
27554
+ setIsTheaterMode(false);
27555
+ setShowTheaterControls(true);
27556
+ }, []);
27557
+ const toggleBrowserFullscreen = useCallback(() => {
27558
+ if (!document.fullscreenElement) {
27559
+ document.documentElement.requestFullscreen().catch(() => {
27560
+ });
27561
+ } else {
27562
+ document.exitFullscreen().catch(() => {
27563
+ });
27564
+ }
27565
+ }, []);
27566
+ useEffect(() => {
27567
+ const handleFullscreenChange = () => {
27568
+ const isFs = !!document.fullscreenElement;
27569
+ setIsBrowserFullscreen(isFs);
27570
+ if (isFs) {
27571
+ setIsTheaterMode(true);
27572
+ setShowTheaterControls(true);
27573
+ } else {
27574
+ setIsTheaterMode(false);
27575
+ }
27576
+ };
27577
+ document.addEventListener("fullscreenchange", handleFullscreenChange);
27578
+ return () => document.removeEventListener("fullscreenchange", handleFullscreenChange);
27579
+ }, []);
27580
+ useEffect(() => {
27581
+ if (!isTheaterMode) return;
27582
+ const handleInteraction = () => {
27583
+ setShowTheaterControls(true);
27584
+ if (theaterTimerRef.current) clearTimeout(theaterTimerRef.current);
27585
+ theaterTimerRef.current = setTimeout(() => setShowTheaterControls(false), 3e3);
27586
+ };
27587
+ theaterTimerRef.current = setTimeout(() => setShowTheaterControls(false), 3e3);
27588
+ window.addEventListener("mousemove", handleInteraction);
27589
+ window.addEventListener("touchstart", handleInteraction);
27590
+ return () => {
27591
+ window.removeEventListener("mousemove", handleInteraction);
27592
+ window.removeEventListener("touchstart", handleInteraction);
27593
+ if (theaterTimerRef.current) clearTimeout(theaterTimerRef.current);
27594
+ };
27595
+ }, [isTheaterMode]);
27596
+ useEffect(() => {
27597
+ const handleKeyDown = (e) => {
27598
+ const tag = e.target?.tagName;
27599
+ if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return;
27600
+ if (e.key === "Escape") {
27601
+ if (document.fullscreenElement) return;
27602
+ if (isTheaterMode) exitTheaterMode();
27603
+ return;
27604
+ }
27605
+ if ((e.key === "f" || e.key === "F") && !e.ctrlKey && !e.metaKey && !e.altKey) {
27606
+ e.preventDefault();
27607
+ if (isFullscreenSupported) toggleBrowserFullscreen();
27608
+ return;
27609
+ }
27610
+ if ((e.key === "t" || e.key === "T") && !e.ctrlKey && !e.metaKey && !e.altKey) {
27611
+ e.preventDefault();
27612
+ toggleTheaterMode();
27613
+ }
27614
+ };
27615
+ document.addEventListener("keydown", handleKeyDown);
27616
+ return () => document.removeEventListener("keydown", handleKeyDown);
27617
+ }, [isTheaterMode, isFullscreenSupported, exitTheaterMode, toggleBrowserFullscreen, toggleTheaterMode]);
26989
27618
  const renderContent = () => {
26990
27619
  if (!artifact) return null;
26991
27620
  const content = artifact.content;
26992
- switch (artifact.type) {
27621
+ const type = artifact.type?.toLowerCase() ?? "text";
27622
+ switch (type) {
26993
27623
  case "html":
26994
27624
  case "svg":
26995
- return /* @__PURE__ */ jsx(HtmlPreview3, { content });
27625
+ return /* @__PURE__ */ jsx(FullscreenHtmlPreview, { content });
26996
27626
  case "markdown":
26997
- return /* @__PURE__ */ jsx("div", { className: "p-6 max-w-4xl mx-auto", children: /* @__PURE__ */ jsx(MarkdownPreview, { content }) });
27627
+ return /* @__PURE__ */ jsx("div", { className: "agent-sdk-theme", style: { background: "transparent", height: "100%", overflow: "auto" }, children: /* @__PURE__ */ jsx("div", { className: "p-6 max-w-4xl mx-auto", children: /* @__PURE__ */ jsx(MarkdownPreview, { content }) }) });
26998
27628
  case "image":
26999
27629
  return /* @__PURE__ */ jsx(ImageArtifactPreview, { content });
27000
27630
  case "video":
@@ -27003,73 +27633,90 @@ function PublicArtifactPage({ shareToken, onNavigateBack }) {
27003
27633
  case "code":
27004
27634
  case "text":
27005
27635
  default:
27006
- return /* @__PURE__ */ jsx(
27007
- CodeBlock3,
27008
- {
27009
- code: content,
27010
- language: artifact.language || artifact.type
27011
- }
27012
- );
27636
+ return /* @__PURE__ */ jsx("div", { className: "agent-sdk-theme", style: { background: "transparent", height: "100%", overflow: "auto" }, children: /* @__PURE__ */ jsx(CodeBlock3, { code: content, language: artifact.language || type }) });
27013
27637
  }
27014
27638
  };
27015
27639
  if (pageState === "loading") {
27016
- return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-screen bg-zinc-950", children: /* @__PURE__ */ jsx(Loader2, { className: "w-8 h-8 animate-spin text-[#d8ff00]" }) });
27640
+ return /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", height: "100vh", background: "#09090b" }, children: /* @__PURE__ */ jsx(Loader2, { size: 32, style: { color: "#d8ff00" }, className: "animate-spin" }) });
27017
27641
  }
27018
27642
  if (pageState === "not-found") {
27019
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center h-screen bg-zinc-950 gap-4", children: [
27020
- /* @__PURE__ */ jsx(AlertCircle, { size: 48, className: "text-zinc-600" }),
27021
- /* @__PURE__ */ jsx("p", { className: "text-zinc-400 text-lg", children: "\u4EA7\u7269\u4E0D\u5B58\u5728\u6216\u5DF2\u8BBE\u4E3A\u79C1\u6709" }),
27022
- /* @__PURE__ */ jsx("p", { className: "text-zinc-600 text-sm", children: "\u8BF7\u68C0\u67E5\u94FE\u63A5\u662F\u5426\u6B63\u786E\uFF0C\u6216\u8054\u7CFB\u4F5C\u8005\u91CD\u65B0\u5206\u4EAB" }),
27643
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", height: "100vh", background: "#09090b", gap: 16 }, children: [
27644
+ /* @__PURE__ */ jsx(AlertCircle, { size: 48, style: { color: "#52525b" } }),
27645
+ /* @__PURE__ */ jsx("p", { style: { color: "#a1a1aa", fontSize: 18, margin: 0 }, children: "\u4EA7\u7269\u4E0D\u5B58\u5728\u6216\u5DF2\u8BBE\u4E3A\u79C1\u6709" }),
27646
+ /* @__PURE__ */ jsx("p", { style: { color: "#52525b", fontSize: 14, margin: 0 }, children: "\u8BF7\u68C0\u67E5\u94FE\u63A5\u662F\u5426\u6B63\u786E\uFF0C\u6216\u8054\u7CFB\u4F5C\u8005\u91CD\u65B0\u5206\u4EAB" }),
27023
27647
  onNavigateBack && /* @__PURE__ */ jsx(
27024
27648
  "button",
27025
27649
  {
27026
27650
  onClick: onNavigateBack,
27027
- className: "mt-4 px-4 py-2 text-sm bg-zinc-800 text-white rounded-lg hover:bg-zinc-700 transition-colors",
27651
+ style: { marginTop: 16, padding: "8px 16px", fontSize: 14, background: "#27272a", color: "white", border: "none", borderRadius: 8, cursor: "pointer" },
27028
27652
  children: "\u8FD4\u56DE"
27029
27653
  }
27030
27654
  )
27031
27655
  ] });
27032
27656
  }
27033
27657
  if (pageState === "error") {
27034
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center h-screen bg-zinc-950 gap-4", children: [
27035
- /* @__PURE__ */ jsx(AlertCircle, { size: 48, className: "text-red-400" }),
27036
- /* @__PURE__ */ jsx("p", { className: "text-red-400 text-lg", children: error || "\u52A0\u8F7D\u5931\u8D25" }),
27658
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", height: "100vh", background: "#09090b", gap: 16 }, children: [
27659
+ /* @__PURE__ */ jsx(AlertCircle, { size: 48, style: { color: "#f87171" } }),
27660
+ /* @__PURE__ */ jsx("p", { style: { color: "#f87171", fontSize: 18, margin: 0 }, children: error || "\u52A0\u8F7D\u5931\u8D25" }),
27037
27661
  onNavigateBack && /* @__PURE__ */ jsx(
27038
27662
  "button",
27039
27663
  {
27040
27664
  onClick: onNavigateBack,
27041
- className: "mt-4 px-4 py-2 text-sm bg-zinc-800 text-white rounded-lg hover:bg-zinc-700 transition-colors",
27665
+ style: { marginTop: 16, padding: "8px 16px", fontSize: 14, background: "#27272a", color: "white", border: "none", borderRadius: 8, cursor: "pointer" },
27042
27666
  children: "\u8FD4\u56DE"
27043
27667
  }
27044
27668
  )
27045
27669
  ] });
27046
27670
  }
27047
27671
  if (!artifact) return null;
27048
- const config = typeConfig[artifact.type] || typeConfig.text;
27672
+ const normalizedType = artifact.type?.toLowerCase() ?? "text";
27673
+ const config = typeConfig[normalizedType] || typeConfig.text;
27049
27674
  const TypeIcon = config.icon;
27050
- const canDownload = ["html", "svg", "markdown", "json", "code", "text"].includes(artifact.type);
27051
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-screen bg-zinc-950", children: [
27052
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-2.5 border-b border-zinc-800/50 bg-zinc-950/80 backdrop-blur-sm flex-shrink-0", children: [
27053
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
27675
+ const canDownload = ["html", "svg", "markdown", "json", "code", "text"].includes(normalizedType);
27676
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100vh", background: "#09090b" }, children: [
27677
+ /* @__PURE__ */ jsxs("div", { style: {
27678
+ display: "flex",
27679
+ alignItems: "center",
27680
+ justifyContent: "space-between",
27681
+ padding: isTheaterMode ? "0 16px" : "10px 16px",
27682
+ maxHeight: isTheaterMode ? 0 : 200,
27683
+ overflow: "hidden",
27684
+ opacity: isTheaterMode ? 0 : 1,
27685
+ borderBottom: isTheaterMode ? "none" : "1px solid rgba(39, 39, 42, 0.5)",
27686
+ background: "rgba(9, 9, 11, 0.8)",
27687
+ backdropFilter: "blur(8px)",
27688
+ flexShrink: 0,
27689
+ transition: "max-height 0.3s ease, opacity 0.3s ease, padding 0.3s ease"
27690
+ }, children: [
27691
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12, minWidth: 0 }, children: [
27054
27692
  onNavigateBack && /* @__PURE__ */ jsx(
27055
27693
  "button",
27056
27694
  {
27057
27695
  onClick: onNavigateBack,
27058
- className: "p-1.5 text-zinc-400 hover:text-white hover:bg-zinc-800 rounded-lg transition-colors flex-shrink-0",
27696
+ style: { padding: 6, color: "#a1a1aa", background: "none", border: "none", borderRadius: 8, cursor: "pointer", flexShrink: 0 },
27059
27697
  children: /* @__PURE__ */ jsx(ArrowLeft, { size: 18 })
27060
27698
  }
27061
27699
  ),
27062
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 min-w-0", children: [
27063
- /* @__PURE__ */ jsx("div", { className: `w-7 h-7 rounded-lg ${config.bgColor} flex items-center justify-center flex-shrink-0`, children: /* @__PURE__ */ jsx(TypeIcon, { size: 14, className: config.color }) }),
27064
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
27065
- /* @__PURE__ */ jsx("h1", { className: "text-sm font-medium text-white truncate", children: artifact.title }),
27066
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 text-[11px] text-zinc-500 mt-0.5", children: [
27067
- /* @__PURE__ */ jsx("span", { className: config.color, children: config.label }),
27068
- artifact.sharedAt && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
27700
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 10, minWidth: 0 }, children: [
27701
+ /* @__PURE__ */ jsx("div", { style: {
27702
+ width: 28,
27703
+ height: 28,
27704
+ borderRadius: 8,
27705
+ display: "flex",
27706
+ alignItems: "center",
27707
+ justifyContent: "center",
27708
+ flexShrink: 0,
27709
+ background: `color-mix(in srgb, ${config.color} 15%, transparent)`
27710
+ }, children: /* @__PURE__ */ jsx(TypeIcon, { size: 14, style: { color: config.color } }) }),
27711
+ /* @__PURE__ */ jsxs("div", { style: { minWidth: 0 }, children: [
27712
+ /* @__PURE__ */ jsx("h1", { style: { fontSize: 14, fontWeight: 500, color: "white", margin: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: artifact.title }),
27713
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 10, fontSize: 11, color: "#71717a", marginTop: 2 }, children: [
27714
+ /* @__PURE__ */ jsx("span", { style: { color: config.color }, children: config.label }),
27715
+ artifact.sharedAt && /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
27069
27716
  /* @__PURE__ */ jsx(Calendar, { size: 10 }),
27070
27717
  new Date(artifact.sharedAt).toLocaleDateString()
27071
27718
  ] }),
27072
- artifact.viewCount !== void 0 && artifact.viewCount > 0 && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
27719
+ artifact.viewCount !== void 0 && artifact.viewCount > 0 && /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
27073
27720
  /* @__PURE__ */ jsx(Eye, { size: 10 }),
27074
27721
  artifact.viewCount
27075
27722
  ] })
@@ -27077,29 +27724,120 @@ function PublicArtifactPage({ shareToken, onNavigateBack }) {
27077
27724
  ] })
27078
27725
  ] })
27079
27726
  ] }),
27080
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 flex-shrink-0", children: [
27081
- canDownload && /* @__PURE__ */ jsx(
27727
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
27728
+ /* @__PURE__ */ jsx(
27082
27729
  "button",
27083
27730
  {
27084
- onClick: handleDownload,
27085
- className: "p-2 text-zinc-400 hover:text-white hover:bg-zinc-800 rounded-lg transition-colors",
27086
- title: "\u4E0B\u8F7D",
27087
- children: /* @__PURE__ */ jsx(Download, { size: 16 })
27731
+ onClick: toggleTheaterMode,
27732
+ style: { padding: 8, color: "#a1a1aa", background: "none", border: "none", borderRadius: 8, cursor: "pointer" },
27733
+ title: "\u6C89\u6D78\u6A21\u5F0F (T)",
27734
+ children: /* @__PURE__ */ jsx(MonitorPlay, { size: 16 })
27088
27735
  }
27089
27736
  ),
27090
- /* @__PURE__ */ jsx(
27737
+ isFullscreenSupported && /* @__PURE__ */ jsx(
27091
27738
  "button",
27092
27739
  {
27093
- onClick: handleShare,
27094
- className: "p-2 text-zinc-400 hover:text-[#d8ff00] hover:bg-zinc-800 rounded-lg transition-colors",
27095
- title: "\u590D\u5236\u5206\u4EAB\u94FE\u63A5",
27096
- children: /* @__PURE__ */ jsx(Share2, { size: 16 })
27740
+ onClick: toggleBrowserFullscreen,
27741
+ style: { padding: 8, color: "#a1a1aa", background: "none", border: "none", borderRadius: 8, cursor: "pointer" },
27742
+ title: isBrowserFullscreen ? "\u9000\u51FA\u5168\u5C4F (F)" : "\u5168\u5C4F (F)",
27743
+ children: isBrowserFullscreen ? /* @__PURE__ */ jsx(Minimize2, { size: 16 }) : /* @__PURE__ */ jsx(Maximize2, { size: 16 })
27744
+ }
27745
+ ),
27746
+ canDownload && /* @__PURE__ */ jsx(
27747
+ "button",
27748
+ {
27749
+ onClick: handleDownload,
27750
+ style: { padding: 8, color: "#a1a1aa", background: "none", border: "none", borderRadius: 8, cursor: "pointer" },
27751
+ title: "\u4E0B\u8F7D",
27752
+ children: /* @__PURE__ */ jsx(Download, { size: 16 })
27097
27753
  }
27098
27754
  )
27099
27755
  ] })
27100
27756
  ] }),
27101
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden", children: renderContent() }),
27102
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-2 border-t border-zinc-800/30 bg-zinc-950/50", children: /* @__PURE__ */ jsx("span", { className: "text-[10px] text-zinc-600", children: "Powered by BISHAN Agent" }) })
27757
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, overflow: "hidden" }, children: renderContent() }),
27758
+ /* @__PURE__ */ jsx("div", { style: {
27759
+ display: "flex",
27760
+ alignItems: "center",
27761
+ justifyContent: "center",
27762
+ padding: isTheaterMode ? "0" : "8px 0",
27763
+ maxHeight: isTheaterMode ? 0 : 50,
27764
+ overflow: "hidden",
27765
+ opacity: isTheaterMode ? 0 : 1,
27766
+ borderTop: isTheaterMode ? "none" : "1px solid rgba(39, 39, 42, 0.3)",
27767
+ background: "rgba(9, 9, 11, 0.5)",
27768
+ flexShrink: 0,
27769
+ transition: "max-height 0.3s ease, opacity 0.3s ease, padding 0.3s ease"
27770
+ }, children: /* @__PURE__ */ jsx("span", { style: { fontSize: 10, color: "#52525b" }, children: "Powered by BISHAN Agent" }) }),
27771
+ isTheaterMode && /* @__PURE__ */ jsx(
27772
+ "div",
27773
+ {
27774
+ onMouseEnter: () => setShowTheaterControls(true),
27775
+ style: {
27776
+ position: "fixed",
27777
+ top: 0,
27778
+ left: 0,
27779
+ right: 0,
27780
+ height: 40,
27781
+ zIndex: 99
27782
+ }
27783
+ }
27784
+ ),
27785
+ isTheaterMode && /* @__PURE__ */ jsxs("div", { style: {
27786
+ position: "fixed",
27787
+ top: 16,
27788
+ right: 16,
27789
+ zIndex: 100,
27790
+ display: "flex",
27791
+ alignItems: "center",
27792
+ gap: 8,
27793
+ opacity: showTheaterControls ? 1 : 0,
27794
+ transform: showTheaterControls ? "translateY(0)" : "translateY(-8px)",
27795
+ transition: "opacity 0.3s ease, transform 0.3s ease",
27796
+ pointerEvents: showTheaterControls ? "auto" : "none"
27797
+ }, children: [
27798
+ /* @__PURE__ */ jsxs(
27799
+ "button",
27800
+ {
27801
+ onClick: exitTheaterMode,
27802
+ style: {
27803
+ display: "flex",
27804
+ alignItems: "center",
27805
+ gap: 6,
27806
+ padding: "8px 12px",
27807
+ background: "rgba(39, 39, 42, 0.9)",
27808
+ backdropFilter: "blur(8px)",
27809
+ border: "1px solid rgba(63, 63, 70, 0.5)",
27810
+ borderRadius: 8,
27811
+ color: "#a1a1aa",
27812
+ fontSize: 12,
27813
+ cursor: "pointer",
27814
+ whiteSpace: "nowrap"
27815
+ },
27816
+ title: "\u9000\u51FA\u6C89\u6D78\u6A21\u5F0F (ESC)",
27817
+ children: [
27818
+ /* @__PURE__ */ jsx(X, { size: 14 }),
27819
+ "\u9000\u51FA\u6C89\u6D78"
27820
+ ]
27821
+ }
27822
+ ),
27823
+ isFullscreenSupported && /* @__PURE__ */ jsx(
27824
+ "button",
27825
+ {
27826
+ onClick: toggleBrowserFullscreen,
27827
+ style: {
27828
+ padding: 8,
27829
+ background: "rgba(39, 39, 42, 0.9)",
27830
+ backdropFilter: "blur(8px)",
27831
+ border: "1px solid rgba(63, 63, 70, 0.5)",
27832
+ borderRadius: 8,
27833
+ color: "#a1a1aa",
27834
+ cursor: "pointer"
27835
+ },
27836
+ title: isBrowserFullscreen ? "\u9000\u51FA\u5168\u5C4F (F)" : "\u5168\u5C4F (F)",
27837
+ children: isBrowserFullscreen ? /* @__PURE__ */ jsx(Minimize2, { size: 14 }) : /* @__PURE__ */ jsx(Maximize2, { size: 14 })
27838
+ }
27839
+ )
27840
+ ] })
27103
27841
  ] });
27104
27842
  }
27105
27843
  var AgentSDKProvider = ({