diff --git a/frontend/src/app/workspace/chats/[thread_id]/page.tsx b/frontend/src/app/workspace/chats/[thread_id]/page.tsx
index 4b44613f..3e24b019 100644
--- a/frontend/src/app/workspace/chats/[thread_id]/page.tsx
+++ b/frontend/src/app/workspace/chats/[thread_id]/page.tsx
@@ -24,6 +24,7 @@ import { MessageList } from "@/components/workspace/messages";
import { ThreadContext } from "@/components/workspace/messages/context";
import { ThreadTitle } from "@/components/workspace/thread-title";
import { Welcome } from "@/components/workspace/welcome";
+import { useArtifacts } from "@/components/workspace/artifacts";
import { useI18n } from "@/core/i18n/hooks";
import { useNotification } from "@/core/notification/hooks";
import { useLocalSettings } from "@/core/settings";
@@ -36,6 +37,7 @@ export default function ChatPage() {
const { t } = useI18n();
const [settings, setSettings] = useLocalSettings();
const [showExitDialog, setShowExitDialog] = useState(false);
+ const { fullscreen } = useArtifacts();
const { threadId, isNewThread, setIsNewThread, isMock } = useThreadChat();
useSpecificChatMode();
@@ -85,7 +87,7 @@ export default function ChatPage() {
- Todo
+ To-dos
}
/>
@@ -147,14 +149,19 @@ export default function ChatPage() {
-
+
;
export const Artifact = ({ className, ...props }: ArtifactProps) => (
{
return filepathFromProps.startsWith("write-file:");
}, [filepathFromProps]);
@@ -105,6 +107,33 @@ export function ArtifactFileDetail({
const [isInstalling, setIsInstalling] = useState(false);
const [zoom, setZoom] = useState(100);
const { isMock } = useThread();
+
+ // 全屏切换处理
+ const handleFullscreenToggle = useCallback(() => {
+ if (!document.fullscreenElement) {
+ document.documentElement.requestFullscreen().catch((err) => {
+ console.error("无法进入全屏模式:", err);
+ });
+ setFullscreen(true);
+ } else {
+ document.exitFullscreen().catch((err) => {
+ console.error("无法退出全屏模式:", err);
+ });
+ setFullscreen(false);
+ }
+ }, [setFullscreen]);
+
+ // 监听全屏变化
+ useEffect(() => {
+ const handleFullscreenChange = () => {
+ setFullscreen(!!document.fullscreenElement);
+ };
+ document.addEventListener("fullscreenchange", handleFullscreenChange);
+ return () => {
+ document.removeEventListener("fullscreenchange", handleFullscreenChange);
+ };
+ }, [setFullscreen]);
+
useEffect(() => {
if (isSupportPreview) {
setViewMode("preview");
@@ -172,11 +201,10 @@ export function ArtifactFileDetail({
)}
-
+
{/* 放大缩小选择器 */}
- {/* 新界面打开的按钮 */}
{/* {!isWriteFile && filepath.endsWith(".skill") && (
)} */}
- {!isWriteFile && (
+ {/* 新界面打开的按钮 */}
+ {/* {!isWriteFile && (
- )}
+ )} */}
+ {/* 复制按钮 */}
{isCodeFile && (
{
@@ -215,26 +244,143 @@ export function ArtifactFileDetail({
}
}}
tooltip={t.clipboard.copyToClipboard}
- />
+ >
+
+
)}
+ {/* 下载按钮 */}
{!isWriteFile && (
+ >
+
+
)}
+ {/* 全屏按钮 */}
+
+ {fullscreen ? (
+
+ ) : (
+
+ )}
+
+ {/* 关闭按钮 */}
setOpen(false)}
tooltip={t.common.close}
- />
+ >
+
+
diff --git a/frontend/src/components/workspace/artifacts/context.tsx b/frontend/src/components/workspace/artifacts/context.tsx
index af9b19ab..b2e67a76 100644
--- a/frontend/src/components/workspace/artifacts/context.tsx
+++ b/frontend/src/components/workspace/artifacts/context.tsx
@@ -21,6 +21,9 @@ export interface ArtifactsContextType {
open: boolean;
autoOpen: boolean;
setOpen: (open: boolean) => void;
+
+ fullscreen: boolean;
+ setFullscreen: (fullscreen: boolean) => void;
}
const ArtifactsContext = createContext
(
@@ -39,6 +42,7 @@ export function ArtifactsProvider({ children }: ArtifactsProviderProps) {
env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true",
);
const [autoOpen, setAutoOpen] = useState(true);
+ const [fullscreen, setFullscreen] = useState(false);
const { setOpen: setSidebarOpen } = useSidebar();
const select = useCallback(
@@ -78,6 +82,9 @@ export function ArtifactsProvider({ children }: ArtifactsProviderProps) {
selectedArtifact,
select,
deselect,
+
+ fullscreen,
+ setFullscreen,
};
return (
diff --git a/frontend/src/components/workspace/chats/chat-box.tsx b/frontend/src/components/workspace/chats/chat-box.tsx
index 59b12a35..f0d5c070 100644
--- a/frontend/src/components/workspace/chats/chat-box.tsx
+++ b/frontend/src/components/workspace/chats/chat-box.tsx
@@ -21,6 +21,7 @@ import {
} from "../artifacts";
import { useThread } from "../messages/context";
+const FULLSCREEN_MODE = { chat: 0, artifacts: 100 };
const CLOSE_MODE = { chat: 100, artifacts: 0 };
const OPEN_MODE = { chat: 50, artifacts: 50 };
@@ -40,6 +41,7 @@ const ChatBox: React.FC<{ children: React.ReactNode; threadId: string }> = ({
select: selectArtifact,
deselect,
selectedArtifact,
+ fullscreen,
} = useArtifacts();
const [autoSelectFirstArtifact, setAutoSelectFirstArtifact] = useState(true);
@@ -88,13 +90,15 @@ const ChatBox: React.FC<{ children: React.ReactNode; threadId: string }> = ({
useEffect(() => {
if (layoutRef.current) {
- if (artifactPanelOpen) {
+ if (fullscreen) {
+ layoutRef.current.setLayout(FULLSCREEN_MODE);
+ } else if (artifactPanelOpen) {
layoutRef.current.setLayout(OPEN_MODE);
} else {
layoutRef.current.setLayout(CLOSE_MODE);
}
}
- }, [artifactPanelOpen]);
+ }, [artifactPanelOpen, fullscreen]);
return (
= ({
groupRef={layoutRef}
>
@@ -111,8 +118,9 @@ const ChatBox: React.FC<{ children: React.ReactNode; threadId: string }> = ({