Integrate role asset studio into custom world agent flow
This commit is contained in:
136
src/components/custom-world-agent/CustomWorldDraftEditPanel.tsx
Normal file
136
src/components/custom-world-agent/CustomWorldDraftEditPanel.tsx
Normal file
@@ -0,0 +1,136 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import type { CustomWorldDraftCardDetail } from '../../../packages/shared/src/contracts/customWorldAgent';
|
||||
|
||||
type CustomWorldDraftEditPanelProps = {
|
||||
detail: CustomWorldDraftCardDetail;
|
||||
disabled?: boolean;
|
||||
onSave: (
|
||||
sections: Array<{
|
||||
sectionId: string;
|
||||
value: string;
|
||||
}>,
|
||||
) => void;
|
||||
onCancel: () => void;
|
||||
};
|
||||
|
||||
function shouldUseTextarea(sectionId: string, value: string) {
|
||||
return (
|
||||
value.length > 28 ||
|
||||
value.includes('\n') ||
|
||||
sectionId === 'summary' ||
|
||||
sectionId === 'tone' ||
|
||||
sectionId === 'coreConflicts' ||
|
||||
sectionId === 'hiddenHook' ||
|
||||
sectionId === 'secret' ||
|
||||
sectionId === 'stakes' ||
|
||||
sectionId === 'openingEvent' ||
|
||||
sectionId === 'understandingShift' ||
|
||||
sectionId === 'description'
|
||||
);
|
||||
}
|
||||
|
||||
export function CustomWorldDraftEditPanel({
|
||||
detail,
|
||||
disabled = false,
|
||||
onSave,
|
||||
onCancel,
|
||||
}: CustomWorldDraftEditPanelProps) {
|
||||
const editableSections = useMemo(
|
||||
() =>
|
||||
detail.sections.filter((section) =>
|
||||
detail.editableSectionIds.includes(section.id),
|
||||
),
|
||||
[detail],
|
||||
);
|
||||
const [draftValues, setDraftValues] = useState<Record<string, string>>(() =>
|
||||
Object.fromEntries(
|
||||
editableSections.map((section) => [section.id, section.value]),
|
||||
),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setDraftValues(
|
||||
Object.fromEntries(editableSections.map((section) => [section.id, section.value])),
|
||||
);
|
||||
}, [editableSections]);
|
||||
|
||||
if (editableSections.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
{editableSections.map((section) => {
|
||||
const value = draftValues[section.id] ?? '';
|
||||
const multiline = shouldUseTextarea(section.id, value);
|
||||
|
||||
return (
|
||||
<label
|
||||
key={section.id}
|
||||
className="block rounded-[1.1rem] border border-white/8 bg-white/5 px-3 py-3"
|
||||
>
|
||||
<div className="text-[11px] tracking-[0.16em] text-zinc-400">
|
||||
{section.label}
|
||||
</div>
|
||||
{multiline ? (
|
||||
<textarea
|
||||
value={value}
|
||||
onChange={(event) => {
|
||||
const nextValue = event.target.value;
|
||||
setDraftValues((current) => ({
|
||||
...current,
|
||||
[section.id]: nextValue,
|
||||
}));
|
||||
}}
|
||||
rows={4}
|
||||
disabled={disabled}
|
||||
className="mt-2 w-full resize-none rounded-[0.9rem] border border-white/10 bg-black/26 px-3 py-3 text-sm leading-7 text-white outline-none transition focus:border-sky-400/40 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(event) => {
|
||||
const nextValue = event.target.value;
|
||||
setDraftValues((current) => ({
|
||||
...current,
|
||||
[section.id]: nextValue,
|
||||
}));
|
||||
}}
|
||||
disabled={disabled}
|
||||
className="mt-2 h-11 w-full rounded-[0.9rem] border border-white/10 bg-black/26 px-3 text-sm text-white outline-none transition focus:border-sky-400/40 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
/>
|
||||
)}
|
||||
</label>
|
||||
);
|
||||
})}
|
||||
|
||||
<div className="flex items-center justify-end gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onCancel}
|
||||
disabled={disabled}
|
||||
className="rounded-full border border-white/10 bg-black/20 px-4 py-2 text-sm text-zinc-200 transition hover:text-white disabled:cursor-not-allowed disabled:opacity-45"
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onSave(
|
||||
editableSections.map((section) => ({
|
||||
sectionId: section.id,
|
||||
value: draftValues[section.id] ?? '',
|
||||
})),
|
||||
);
|
||||
}}
|
||||
disabled={disabled}
|
||||
className="rounded-full border border-sky-300/20 bg-sky-500/10 px-4 py-2 text-sm font-medium text-sky-100 transition hover:text-white disabled:cursor-not-allowed disabled:opacity-45"
|
||||
>
|
||||
保存
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user