all

视频

视频

视频

视频

视频

init
This commit is contained in:
LKH committed 2026-07-29 09:17:00 +08:00
commit 3b053c714c
128 files changed
+31559

No files matched your search

+102
View File
@@ -0,0 +1,102 @@
import "./styles/index.css";
import { useEffect } from "react";
import { X } from "lucide-react";
import { DirectorDeskShell } from "./app/layout/DirectorDeskShell";
import { DirectorCanvas } from "./editor/canvas/DirectorCanvas";
import { initDirectorDeskHostBridge } from "./editor/io/hostBridge";
import { useDirectorStore } from "./editor/store/directorStore";
function isEditableShortcutTarget(target: EventTarget | null) {
if (!(target instanceof HTMLElement)) return false;
return target.isContentEditable || ["INPUT", "TEXTAREA", "SELECT"].includes(target.tagName);
}
export default function App() {
const viewMode = useDirectorStore((state) => state.viewMode);
const setViewMode = useDirectorStore((state) => state.setViewMode);
useEffect(() => {
initDirectorDeskHostBridge();
window.parent?.postMessage({ type: "storyai:director-desk-ready" }, window.location.origin);
}, []);
function handleClose() {
window.parent?.postMessage({ type: "storyai:director-desk-close" }, window.location.origin);
}
useEffect(() => {
function handleKeyDown(event: KeyboardEvent) {
if (event.defaultPrevented || isEditableShortcutTarget(event.target)) return;
if (!event.metaKey && !event.ctrlKey) return;
const key = event.key.toLowerCase();
if (key === "c") {
event.preventDefault();
useDirectorStore.getState().copySelectedObjects();
return;
}
if (key === "v") {
event.preventDefault();
useDirectorStore.getState().pasteClipboardObjects();
return;
}
if (key === "z" && !event.shiftKey) {
event.preventDefault();
useDirectorStore.getState().undo();
}
}
window.addEventListener("keydown", handleKeyDown);
return () => {
window.removeEventListener("keydown", handleKeyDown);
};
}, []);
return (
<div className="app-shell">
<header className="top-bar">
<div className="top-bar-left">
<h1 className="top-bar-title">3D导演台</h1>
</div>
<div className="top-bar-center">
<div className="mode-toggle ui-segmented" role="group" aria-label="视角切换">
<button
className={`mode-toggle-button ui-segmented-item ${viewMode === "director" ? "ui-segmented-item-active" : ""}`}
aria-pressed={viewMode === "director"}
type="button"
onClick={() => setViewMode("director")}
>
导演视角
</button>
<button
className={`mode-toggle-button ui-segmented-item ${viewMode === "camera" ? "ui-segmented-item-active" : ""}`}
aria-pressed={viewMode === "camera"}
type="button"
onClick={() => setViewMode("camera")}
>
机位视角
</button>
</div>
</div>
<div className="top-bar-actions">
<button
className="top-bar-action-button"
type="button"
aria-label="关闭"
title="关闭"
onClick={handleClose}
>
<X aria-hidden="true" size={16} strokeWidth={1.8} />
</button>
</div>
</header>
<DirectorDeskShell>
<DirectorCanvas />
</DirectorDeskShell>
</div>
);
}