diff --git a/web/src/components/canvas/canvas-camera-control-popover.tsx b/web/src/components/canvas/canvas-camera-control-popover.tsx new file mode 100644 index 000000000..466ea2fbd --- /dev/null +++ b/web/src/components/canvas/canvas-camera-control-popover.tsx @@ -0,0 +1,50 @@ +import { useState } from "react"; +import { Camera } from "lucide-react"; + +import { AppModal } from "@/components/ui/product/app-modal/app-modal"; +import type { CanvasTheme } from "@/lib/canvas-theme"; +import type { CameraControlOptions } from "@/lib/canvas/camera-prompt-library"; +import { CanvasNodeCameraPanel } from "./canvas-node-camera-dialog"; + +type CanvasCameraControlPopoverProps = { + cameraControl?: CameraControlOptions; + onCameraControlChange: (options: CameraControlOptions) => void; + theme: CanvasTheme; + compact?: boolean; +}; + +export function CanvasCameraControlPopover({ cameraControl, onCameraControlChange, theme, compact = false }: CanvasCameraControlPopoverProps) { + const [open, setOpen] = useState(false); + const cameraEnabled = cameraControl?.enabled === true; + return ( + <> + + {open ? ( + setOpen(false)}> + setOpen(false)} + onConfirm={(options) => { + onCameraControlChange(options); + setOpen(false); + }} + /> + + ) : null} + + ); +} diff --git a/web/src/components/canvas/canvas-node-prompt-panel.tsx b/web/src/components/canvas/canvas-node-prompt-panel.tsx index 8bd0501c4..095fe74f0 100644 --- a/web/src/components/canvas/canvas-node-prompt-panel.tsx +++ b/web/src/components/canvas/canvas-node-prompt-panel.tsx @@ -1,7 +1,7 @@ import { Button, Image as AntImage, InputNumber, Modal, Popover } from "antd"; import { Tooltip } from "@/components/ui/base/tooltip"; import { useEffect, useMemo, useRef, useState, type CSSProperties, type KeyboardEvent as ReactKeyboardEvent, type PointerEvent as ReactPointerEvent, type ReactNode } from "react"; -import { ArrowUp, AtSign, Boxes, Camera, ChevronDown, FileText, GripVertical, ImageIcon, ImagePlus, Link2, LoaderCircle, Maximize2, Music2, Pencil, SlidersHorizontal, UserRound, Video, WandSparkles, X } from "lucide-react"; +import { ArrowUp, AtSign, Boxes, ChevronDown, FileText, GripVertical, ImageIcon, ImagePlus, Link2, LoaderCircle, Maximize2, Music2, Pencil, SlidersHorizontal, UserRound, Video, WandSparkles, X } from "lucide-react"; import { ModelPicker } from "@/components/model-picker"; import { defaultConfig, modelOptionName, resolveModelChannel, useEffectiveConfig, type AiConfig } from "@/stores/use-config-store"; @@ -14,9 +14,8 @@ import { modelRequestOptions, resolveCompatibleModel, resolveModelGenerationDefa import { navigateToSettings } from "@/lib/settings-navigation"; import { useThemeStore } from "@/stores/use-theme-store"; import { useUserStore } from "@/stores/use-user-store"; -import type { CameraControlOptions } from "@/lib/canvas/camera-prompt-library"; +import { CanvasCameraControlPopover } from "./canvas-camera-control-popover"; import { CanvasImageSettingsPopover } from "./canvas-image-settings-popover"; -import { CanvasNodeCameraPanel } from "./canvas-node-camera-dialog"; import { CanvasAudioSettingsPopover, type CanvasAudioSettingKey } from "./canvas-audio-settings-popover"; import { CanvasResourceMentionTextarea } from "./canvas-resource-mention-textarea"; import { CanvasVideoSettingsPopover } from "./canvas-video-settings-popover"; @@ -83,7 +82,6 @@ export function CanvasNodePromptPanel({ projectId, node, isRunning, onPromptChan const [manualPromptHeight, setManualPromptHeight] = useState(null); const [manualExpandedPromptHeight, setManualExpandedPromptHeight] = useState(null); const [paramsExpanded, setParamsExpanded] = useState(false); // #98 决策2:B区参数区折叠状态(手风琴) - const [cameraPanelOpen, setCameraPanelOpen] = useState(false); const [promptOptimizerOpen, setPromptOptimizerOpen] = useState(false); const [autoLinkEnabled, setAutoLinkEnabled] = useState(true); const resolvedMentionReferences = useResolvedCanvasResourceReferences(mentionReferences, { projectId }); @@ -181,7 +179,6 @@ export function CanvasNodePromptPanel({ projectId, node, isRunning, onPromptChan setExpandedPromptContentHeight(estimatePromptContentHeight(normalizedSavedPrompt, true)); setManualPromptHeight(null); setManualExpandedPromptHeight(null); - setCameraPanelOpen(false); }, [node.id]); useEffect(() => { @@ -401,12 +398,11 @@ export function CanvasNodePromptPanel({ projectId, node, isRunning, onPromptChan ) : mode === "image" ? ( // 图片模式下,显示相机配置与镜头配置 <> - onConfigChange(node.id, { cameraControl: options })} theme={theme} compact={!expanded} - open={cameraPanelOpen} - onOpenChange={setCameraPanelOpen} /> ( -
- setCameraPanelOpen(false)} - onConfirm={(options) => { - onConfigChange(node.id, { cameraControl: options }); - setCameraPanelOpen(false); - }} - /> -
- ); - return ( updatePrompt(nextPrompt)} >
event.stopPropagation()} onPointerDown={(event) => event.stopPropagation()} @@ -511,7 +494,6 @@ export function CanvasNodePromptPanel({ projectId, node, isRunning, onPromptChan {renderComposerHeader(false)} {renderPromptEditor(false)} - {cameraPanelOpen ? renderCameraPanel() : null} {/* B区 参数区(对应 #98 决策2:默认折叠,手风琴展开)*/} {hasVideoPromptTools ? ( @@ -558,7 +540,6 @@ export function CanvasNodePromptPanel({ projectId, node, isRunning, onPromptChan
{renderComposerHeader(true)}
{renderPromptEditor(true)} - {cameraPanelOpen ? renderCameraPanel() : null} {hasVideoPromptTools ? (
onConfigChange(node.id, patch)} /> @@ -573,29 +554,6 @@ export function CanvasNodePromptPanel({ projectId, node, isRunning, onPromptChan ); } -function CameraToolsPopover({ cameraControl, theme, compact, open, onOpenChange }: { cameraControl?: CameraControlOptions; theme: CanvasTheme; compact: boolean; open: boolean; onOpenChange: (open: boolean) => void }) { - const cameraEnabled = cameraControl?.enabled === true; - const active = open || cameraEnabled; - return ( - - ); -} - function ReferenceToolsPopover({ canAutoMention, autoLinkEnabled, onAutoMention, onAutoLinkEnabledChange, accent, compact }: { canAutoMention: boolean; autoLinkEnabled: boolean; onAutoMention: () => void; onAutoLinkEnabledChange: (enabled: boolean) => void; accent: string; compact: boolean }) { return ( - + {!compact ? 引用 : null}