import { type ReactNode, useDeferredValue, useEffect, useMemo, useState } from 'react'; import { PRESET_CHARACTERS } from '../data/characterPresets'; import { getInventoryItemValue } from '../data/economy'; import { validateItemOverrides } from '../data/editorValidation'; import { getEquipmentSlotFromItem, getEquipmentSlotLabel } from '../data/equipmentEffects'; import { isInventoryItemUsable, resolveInventoryItemUseEffect } from '../data/inventoryEffects'; import { applyItemCatalogOverride, buildItemCatalogFromAssetPaths, createInventoryItemFromCatalogEntry, ITEM_CATALOG_API_PATH, ITEM_CATEGORY_OPTIONS, ITEM_OVERRIDES_API_PATH, } from '../data/itemCatalog'; import { fetchJson, saveJsonObject } from '../editor/shared/jsonClient'; import { SectionCard as Section } from '../editor/shared/SectionCard'; import { type ItemCatalogOverride, type ItemRarity, type TimedBuildBuff,WorldType } from '../types'; import { PixelIcon } from './PixelIcon'; const ITEM_PREVIEW_CHARACTER = PRESET_CHARACTERS[0] ?? null; const LIST_PREVIEW_LIMIT = 240; type ItemCatalogAssetResponse = { assetPaths: string[]; }; const RARITY_OPTIONS: ItemRarity[] = ['common', 'uncommon', 'rare', 'epic', 'legendary']; const RARITY_LABELS: Record = { common: '普通', uncommon: '不普通', rare: '稀有', epic: '史诗', legendary: '传奇', }; function arraysEqual(left: string[], right: string[]) { if (left.length !== right.length) return false; return left.every((value, index) => value === right[index]); } function parseTagsInput(value: string) { return [...new Set( value .split(/[\n,]/u) .map(tag => tag.trim()) .filter(Boolean), )]; } function tagsInputValue(tags: string[]) { return tags.join(', '); } function parseBuildBuffLines( value: string, sourceType: TimedBuildBuff['sourceType'], sourceId: string, ) { return value .split('\n') .map(line => line.trim()) .filter(Boolean) .map((line, index) => { const [namePart, tagsPart, durationPart] = line.split('|').map(part => part.trim()); const tags = parseTagsInput(tagsPart ?? ''); const durationTurns = Math.max(1, Number(durationPart ?? '1') || 1); return { id: `${sourceId}-buff-${index + 1}`, sourceType, sourceId, name: namePart || `${sourceId}-buff-${index + 1}`, tags, durationTurns, } satisfies TimedBuildBuff; }) .filter(buff => buff.tags.length > 0); } function buildBuffLinesValue(buffs: TimedBuildBuff[] | null | undefined) { return (buffs ?? []) .map(buff => `${buff.name}|${buff.tags.join(',')}|${buff.durationTurns}`) .join('\n'); } function Label({ children }: { children: ReactNode }) { return
{children}
; } function TextInput({ value, onChange, placeholder, disabled = false, }: { value: string; onChange: (value: string) => void; placeholder?: string; disabled?: boolean; }) { return ( onChange(event.target.value)} placeholder={placeholder} disabled={disabled} className="w-full rounded-lg border border-white/10 bg-black/30 px-3 py-2 text-sm text-white outline-none transition focus:border-emerald-400/40 disabled:cursor-not-allowed disabled:opacity-60" /> ); } function TextArea({ value, onChange, rows = 4, }: { value: string; onChange: (value: string) => void; rows?: number; }) { return (