Simplify custom world result editing controls
This commit is contained in:
@@ -23,12 +23,19 @@ import {
|
||||
type MedievalRace,
|
||||
sanitizeCustomWorldNpcVisual,
|
||||
} from '../data/medievalNpcVisuals';
|
||||
import { type CustomWorldNpc, type CustomWorldNpcVisual } from '../types';
|
||||
import {
|
||||
type CustomWorldNpc,
|
||||
type CustomWorldNpcVisual,
|
||||
type CustomWorldProfile,
|
||||
} from '../types';
|
||||
import { buildDefaultCustomWorldNpcVisual } from './customWorldNpcVisualDefaults';
|
||||
import { HostileNpcAnimator } from './HostileNpcAnimator';
|
||||
import { MedievalNpcAnimator } from './MedievalNpcAnimator';
|
||||
|
||||
type EditableNpcSource = Pick<CustomWorldNpc, 'id' | 'name' | 'role' | 'description'>
|
||||
type EditableNpcSource = Pick<
|
||||
CustomWorldNpc,
|
||||
'id' | 'name' | 'role' | 'description' | 'imageSrc'
|
||||
>
|
||||
& Partial<
|
||||
Pick<
|
||||
CustomWorldNpc,
|
||||
@@ -291,25 +298,37 @@ function ActionButton({
|
||||
|
||||
export function CustomWorldNpcPortrait({
|
||||
npc,
|
||||
profile,
|
||||
visual,
|
||||
className = '',
|
||||
scale = 2.05,
|
||||
preferImageSrc = false,
|
||||
}: {
|
||||
npc: EditableNpcSource;
|
||||
profile?: CustomWorldProfile | null;
|
||||
visual?: CustomWorldNpcVisual;
|
||||
className?: string;
|
||||
scale?: number;
|
||||
preferImageSrc?: boolean;
|
||||
}) {
|
||||
const previewSpec = buildPreviewSpec(npc, visual ? sanitizeCustomWorldNpcVisual(visual) : undefined);
|
||||
const monsterPreset = visual
|
||||
? null
|
||||
: resolveCustomWorldNpcMonsterPreset(npc);
|
||||
: resolveCustomWorldNpcMonsterPreset(npc, undefined, profile ?? null);
|
||||
const preferredImageSrc =
|
||||
preferImageSrc && npc.imageSrc?.trim() ? npc.imageSrc.trim() : '';
|
||||
|
||||
return (
|
||||
<div className={`relative overflow-hidden rounded-2xl border border-white/10 bg-[radial-gradient(circle_at_top,rgba(56,189,248,0.16),transparent_48%),linear-gradient(180deg,rgba(19,24,39,0.96),rgba(8,10,17,0.92))] ${className}`}>
|
||||
<div className="absolute inset-0 opacity-10 [background-image:linear-gradient(rgba(255,255,255,0.16)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.16)_1px,transparent_1px)] [background-size:16px_16px]" />
|
||||
<div className="relative flex h-full min-h-[7rem] items-center justify-center p-3">
|
||||
{monsterPreset ? (
|
||||
{preferredImageSrc ? (
|
||||
<img
|
||||
src={preferredImageSrc}
|
||||
alt={npc.name}
|
||||
className="h-full w-full object-contain drop-shadow-[0_12px_18px_rgba(0,0,0,0.38)]"
|
||||
/>
|
||||
) : monsterPreset ? (
|
||||
<div
|
||||
className="origin-center drop-shadow-[0_12px_18px_rgba(0,0,0,0.38)]"
|
||||
style={{
|
||||
@@ -333,11 +352,13 @@ export function CustomWorldNpcPortrait({
|
||||
|
||||
export function CustomWorldNpcVisualEditor({
|
||||
npc,
|
||||
profile,
|
||||
value,
|
||||
onChange,
|
||||
onAiGenerate,
|
||||
}: {
|
||||
npc: EditableNpcSource;
|
||||
profile?: CustomWorldProfile | null;
|
||||
value?: CustomWorldNpcVisual;
|
||||
onChange: (value: CustomWorldNpcVisual) => void;
|
||||
onAiGenerate: () => void;
|
||||
@@ -411,6 +432,7 @@ export function CustomWorldNpcVisualEditor({
|
||||
<div className="mx-auto w-full max-w-[9.5rem] space-y-3">
|
||||
<CustomWorldNpcPortrait
|
||||
npc={npc}
|
||||
profile={profile}
|
||||
visual={effectiveVisual}
|
||||
className="aspect-square"
|
||||
scale={2.05}
|
||||
|
||||
Reference in New Issue
Block a user