Files
Genarrative/src/components/image-editor/ImageCanvasSpecGenerationPanelView.tsx
T
kdletters d8b935317d 拆分编辑器前端画布视图
抽出素材栏、生成器、舞台工具栏和画布世界视图

补充各拆分视图的聚焦测试

更新 TRACKING.md 记录第三十四阶段验证
2026-06-17 17:48:12 +08:00

224 lines
8.0 KiB
TypeScript

import { type CSSProperties } from 'react';
import { ImagePlus } from 'lucide-react';
import { PlatformActionButton } from '../common/PlatformActionButton';
import { PlatformFieldLabel } from '../common/PlatformFieldLabel';
import { PlatformStatusMessage } from '../common/PlatformStatusMessage';
import {
PlatformSelectField,
PlatformTextField,
} from '../common/PlatformTextField';
import {
CHARACTER_SPEC_VIEW_OPTIONS,
SPEC_GENERATION_COST,
} from './ImageCanvasGenerationModel';
import type {
GenerateDialogState,
SpecFormValues,
UploadTarget,
} from './ImageCanvasEditorTypes';
type ImageCanvasSpecGenerationPanelViewProps = {
dialog: GenerateDialogState;
style: CSSProperties;
onUpdateSpecFormValue: (key: keyof SpecFormValues, value: string) => void;
onRequestUpload: (target: UploadTarget) => void;
onSubmit: (dialog: GenerateDialogState) => void;
};
export function ImageCanvasSpecGenerationPanelView({
dialog,
style,
onUpdateSpecFormValue,
onRequestUpload,
onSubmit,
}: ImageCanvasSpecGenerationPanelViewProps) {
return (
<form
className="image-canvas-editor__generation-composer image-canvas-editor__spec-composer"
style={style}
role="dialog"
aria-label="生成规范"
onPointerDown={(event) => event.stopPropagation()}
onSubmit={(event) => {
event.preventDefault();
if (dialog.status !== 'generating') {
onSubmit(dialog);
}
}}
>
<div className="image-canvas-editor__spec-fields">
{dialog.specType === 'custom' ? (
<label className="image-canvas-editor__field-block">
<PlatformFieldLabel
variant="form"
className="image-canvas-editor__field-title"
>
自定义规范提示词
</PlatformFieldLabel>
<PlatformTextField
variant="textarea"
aria-label="自定义规范提示词"
value={dialog.specValues?.customPrompt ?? ''}
disabled={dialog.status === 'generating'}
size="sm"
density="compact"
className="image-canvas-editor__spec-textarea"
onChange={(event) =>
onUpdateSpecFormValue('customPrompt', event.target.value)
}
/>
</label>
) : (
<>
<label className="image-canvas-editor__field-block">
<PlatformFieldLabel
variant="form"
className="image-canvas-editor__field-title"
>
玩法设定
</PlatformFieldLabel>
<PlatformTextField
aria-label="玩法设定"
value={dialog.specValues?.playSetting ?? ''}
disabled={dialog.status === 'generating'}
size="sm"
density="compact"
className="image-canvas-editor__spec-input"
onChange={(event) =>
onUpdateSpecFormValue('playSetting', event.target.value)
}
/>
</label>
<label className="image-canvas-editor__field-block">
<PlatformFieldLabel
variant="form"
className="image-canvas-editor__field-title"
>
美术风格
</PlatformFieldLabel>
<PlatformTextField
aria-label="美术风格"
value={dialog.specValues?.artStyle ?? ''}
disabled={dialog.status === 'generating'}
size="sm"
density="compact"
className="image-canvas-editor__spec-input"
onChange={(event) =>
onUpdateSpecFormValue('artStyle', event.target.value)
}
/>
</label>
{dialog.specType === 'character' ? (
<>
<label className="image-canvas-editor__field-block">
<PlatformFieldLabel
variant="form"
className="image-canvas-editor__field-title"
>
头身比
</PlatformFieldLabel>
<PlatformSelectField
aria-label="头身比"
value={dialog.specValues?.bodyRatio ?? '3'}
disabled={dialog.status === 'generating'}
size="sm"
density="compact"
className="image-canvas-editor__spec-input"
onChange={(event) =>
onUpdateSpecFormValue('bodyRatio', event.target.value)
}
>
{['2', '3', '4', '5', '6'].map((value) => (
<option key={value} value={value}>
{value}
</option>
))}
</PlatformSelectField>
</label>
<label className="image-canvas-editor__field-block">
<PlatformFieldLabel
variant="form"
className="image-canvas-editor__field-title"
>
角色视角
</PlatformFieldLabel>
<PlatformSelectField
aria-label="角色视角"
value={dialog.specValues?.characterView ?? ''}
disabled={dialog.status === 'generating'}
size="sm"
density="compact"
className="image-canvas-editor__spec-input"
onChange={(event) =>
onUpdateSpecFormValue('characterView', event.target.value)
}
>
{CHARACTER_SPEC_VIEW_OPTIONS.map((value) => (
<option key={value} value={value}>
{value}
</option>
))}
</PlatformSelectField>
</label>
</>
) : null}
</>
)}
{dialog.specType !== 'icon' ? (
<div className="image-canvas-editor__field-block">
<PlatformFieldLabel
variant="form"
className="image-canvas-editor__field-title"
>
参考图
</PlatformFieldLabel>
<button
type="button"
className="image-canvas-editor__character-spec-ref image-canvas-editor__reference-tile image-canvas-editor__reference-tile--spec"
disabled={dialog.status === 'generating'}
onClick={() => onRequestUpload('spec-reference')}
>
<span className="image-canvas-editor__reference-tile-visual">
{dialog.specReference ? (
<img src={dialog.specReference.src} alt="" aria-hidden="true" />
) : (
<ImagePlus className="h-4 w-4" aria-hidden="true" />
)}
</span>
<span className="image-canvas-editor__reference-tile-copy">
{dialog.specReference?.label ?? '添加参考图'}
</span>
</button>
</div>
) : null}
</div>
{dialog.status === 'failed' ? (
<PlatformStatusMessage
tone="error"
surface="platform"
size="xs"
className="image-canvas-editor__generate-status"
role="alert"
>
{dialog.errorMessage}
</PlatformStatusMessage>
) : null}
<div className="image-canvas-editor__spec-footer">
<PlatformActionButton
type="submit"
tone="secondary"
size="sm"
className="image-canvas-editor__spec-submit"
disabled={dialog.status === 'generating'}
aria-label="提交生成规范"
>
{dialog.status === 'generating'
? '生成中'
: `消耗${SPEC_GENERATION_COST}泥点 · 生成`}
</PlatformActionButton>
</div>
</form>
);
}