Function bodies 443 total
purgeDuplicates function · typescript · L152-L165 (14 LOC)src/stores/user-data-sync.ts
export function purgeDuplicates(params: PurgeParams): PurgeResult {
const { duplicates, userEquipment, userEnchantments, userModifiers, userGems } = params;
const equipIds = new Set(duplicates.equipment.map((d) => d.userItemId));
const enchIds = new Set(duplicates.enchantments.map((d) => d.userItemId));
const modIds = new Set(duplicates.modifiers.map((d) => d.userItemId));
const gemIds = new Set(duplicates.gems.map((d) => d.userItemId));
return {
userEquipment: userEquipment.filter((r) => !equipIds.has(r.id)),
userEnchantments: userEnchantments.filter((r) => !enchIds.has(r.id)),
userModifiers: userModifiers.filter((r) => !modIds.has(r.id)),
userGems: userGems.filter((r) => !gemIds.has(r.id)),
};
}ErrorBoundary.render method · typescript · L39-L45 (7 LOC)src/ui/error-boundary.tsx
override render(): React.ReactNode {
if (!this.state.hasError) {
return this.props.children;
}
return <ErrorFallback error={this.state.error} />;
}ErrorFallback function · typescript · L52-L77 (26 LOC)src/ui/error-boundary.tsx
function ErrorFallback({
error,
}: {
error: Error | null;
}): React.JSX.Element {
const message = error?.message ?? "An unexpected error occurred.";
return (
<div className="flex min-h-screen items-center justify-center bg-bg-primary p-6">
<div className="card-game max-w-md space-y-4 p-8 text-center">
<h1 className="text-xl font-bold text-accent-gold">
Something went wrong
</h1>
<p className="text-sm text-text-secondary">{message}</p>
<Button
variant="default"
onClick={() => {
window.location.reload();
}}
>
Reload
</Button>
</div>
</div>
);
}validatePreSearch function · typescript · L51-L66 (16 LOC)src/ui/hooks/use-search-worker.ts
function validatePreSearch(
equipmentCount: number,
enchantmentCount: number,
constraintCount: number,
): string | null {
if (equipmentCount === 0 && enchantmentCount === 0) {
return "No gear enabled. Configure the gear pool before searching.";
}
if (equipmentCount === 0) {
return "No equipment enabled. Enable at least one piece in the gear pool.";
}
if (constraintCount === 0) {
return "No fitness constraints defined. Add at least one constraint.";
}
return null;
}buildFilteredGearPool function · typescript · L77-L104 (28 LOC)src/ui/hooks/use-search-worker.ts
function buildFilteredGearPool(
getters: MergedGetters,
ids: EnabledIds,
enabledVariants: ReadonlySet<string>,
): GearPool {
// Build base gear pool from merged data
const basePool = buildMergedGearPool(getters, ids);
// Expand equipment with variants into multiple candidates
const expandedChestplates = expandEquipment(basePool.chestplates, enabledVariants);
const expandedLeggings = expandEquipment(basePool.leggings, enabledVariants);
const expandedAccessories = expandEquipment(basePool.accessories, enabledVariants);
// Filter by slot type (expansion preserves slot, so just reassign)
const isAccessory = (e: EquipmentPiece): boolean =>
e.slot === "accessory" ||
e.slot === "accessory-H" ||
e.slot === "accessory-A";
return {
chestplates: expandedChestplates.filter((e) => e.slot === "chestplate"),
leggings: expandedLeggings.filter((e) => e.slot === "leggings"),
accessories: expandedAccessories.filter(isAccessory),
enchantments: basePoocheckLargeSearchPrompt function · typescript · L122-L143 (22 LOC)src/ui/hooks/use-search-worker.ts
function checkLargeSearchPrompt(
algorithm: Algorithm,
combinations: number,
setAlgorithm: (a: Algorithm) => void,
): Algorithm {
if (algorithm !== "exhaustive" || combinations <= LARGE_SEARCH_THRESHOLD) {
return algorithm;
}
const formatted = combinations.toLocaleString();
const shouldSwitch = window.confirm(
`This search has ${formatted} combinations, which may take a while.\n\n` +
`Switch to Genetic algorithm for faster results?\n\n` +
`Click OK to switch to Genetic, or Cancel to continue with Exhaustive.`
);
if (shouldSwitch) {
setAlgorithm("genetic");
return "genetic";
}
return algorithm;
}createSearchWorker function · typescript · L155-L176 (22 LOC)src/ui/hooks/use-search-worker.ts
function createSearchWorker(cb: WorkerCallbacks): Worker {
const worker = new Worker(
new URL("../../workers/search-worker.ts", import.meta.url),
{ type: "module" },
);
worker.onmessage = (event: MessageEvent<WorkerResponse>) => {
const msg = event.data;
switch (msg.type) {
case "progress": cb.onProgress(msg.checked, msg.total, msg.bestScore, msg.topResults); break;
case "complete": cb.onComplete(msg.results, msg.exitMetadata); worker.terminate(); break;
case "error": cb.onError(msg.message); worker.terminate(); break;
}
};
worker.onerror = () => {
cb.onError("Search worker encountered an unexpected error");
worker.terminate();
};
return worker;
}Repobility — the code-quality scanner for AI-generated software · https://repobility.com
launchWorker function · typescript · L192-L209 (18 LOC)src/ui/hooks/use-search-worker.ts
function launchWorker(config: LaunchConfig, cb: WorkerCallbacks): Worker {
const worker = createSearchWorker(cb);
const request: WorkerRequest = {
type: "start",
gearPool: config.gearPool,
constraints: DEFAULT_HARD_CONSTRAINTS,
fitness: [...config.fitness],
options: {
maxResults: config.maxResults,
populationSize: config.gaParams.populationSize,
generations: config.gaParams.generations,
mutationRate: config.gaParams.mutationRate,
},
algorithm: config.algorithm,
};
worker.postMessage(request);
return worker;
}launchCoordinator function · typescript · L227-L243 (17 LOC)src/ui/hooks/use-search-worker.ts
function launchCoordinator(config: CoordinatorLaunchConfig, cb: CoordinatorCallbacks): ExhaustiveCoordinator {
const coordinator = new ExhaustiveCoordinator();
coordinator.start(
{
gearPool: config.gearPool,
constraints: DEFAULT_HARD_CONSTRAINTS,
fitness: config.fitness,
maxResults: config.maxResults,
},
{
onProgress: cb.onProgress,
onComplete: cb.onComplete,
onError: cb.onError,
},
);
return coordinator;
}launchIslandCoordinator function · typescript · L262-L282 (21 LOC)src/ui/hooks/use-search-worker.ts
function launchIslandCoordinator(config: IslandLaunchConfig, cb: IslandCallbacks): IslandCoordinator {
const coordinator = new IslandCoordinator();
coordinator.start(
{
gearPool: config.gearPool,
constraints: DEFAULT_HARD_CONSTRAINTS,
fitness: config.fitness,
maxResults: config.maxResults,
populationSize: config.gaParams.populationSize,
generations: config.gaParams.generations,
mutationRate: config.gaParams.mutationRate,
islandCount: config.gaParams.islandCount,
},
{
onProgress: cb.onProgress,
onComplete: cb.onComplete,
onError: cb.onError,
},
);
return coordinator;
}executeSearch function · typescript · L307-L354 (48 LOC)src/ui/hooks/use-search-worker.ts
function executeSearch(ctx: SearchContext): void {
const { startSearch, setResults, setPreviewResults, setError, setExpandedCards, setProgress, workerRef, coordinatorRef, islandCoordinatorRef, algorithm, gaParams, constraints, enabledVariants, ids, getters, maxResults } = ctx;
const basePool = buildFilteredGearPool(getters, ids, enabledVariants);
// For exhaustive search, filter pool to items contributing to goal stats (or with sockets)
let gearPool = basePool;
let filterMessage: string | null = null;
if (algorithm === "exhaustive") {
const { pool: filteredPool, stats } = filterPoolByGoals(basePool, constraints);
gearPool = filteredPool;
filterMessage = formatFilterStats(stats);
}
startSearch();
setProgress({ ...INITIAL_PROGRESS, startTime: Date.now(), filterMessage });
const onProg = (c: number, t: number, b: number, r: readonly SearchResult[]): void => {
setProgress((p) => ({ ...p, checked: c, total: t, bestScore: b, resultsCount: r.length }));
useSearchWorker function · typescript · L366-L426 (61 LOC)src/ui/hooks/use-search-worker.ts
export function useSearchWorker(maxResults: number): WorkerHookResult {
const startSearch = useSearchStore((s) => s.startSearch);
const setResults = useSearchStore((s) => s.setResults);
const setPreviewResults = useSearchStore((s) => s.setPreviewResults);
const setError = useSearchStore((s) => s.setError);
const reset = useSearchStore((s) => s.reset);
const algorithm = useSearchStore((s) => s.algorithm);
const setAlgorithm = useSearchStore((s) => s.setAlgorithm);
const gaParams = useSearchStore((s) => s.gaParams);
const constraints = useFitnessStore((s) => s.constraintsConfig.constraints);
const enabledVariants = useFitnessStore((s) => s.enabledVariants);
const eqIds = useGearPoolStore((s) => s.enabledEquipmentIds);
const enIds = useGearPoolStore((s) => s.enabledEnchantmentIds);
const modIds = useGearPoolStore((s) => s.enabledModifierIds);
const gemIds = useGearPoolStore((s) => s.enabledGemIds);
const setExpandedCards = useUIStore((s) => s.setExpandedCardsAppShell function · typescript · L29-L78 (50 LOC)src/ui/layout/app-shell.tsx
export function AppShell(): React.JSX.Element {
const activePanel = useUIStore((s) => s.activePanel);
const setActivePanel = useUIStore((s) => s.setActivePanel);
return (
<div className="flex min-h-screen flex-col bg-bg-primary">
{/* Header */}
<header className="border-b border-border-default bg-bg-secondary">
<div className="mx-auto max-w-5xl px-4 py-3">
<h1 className="text-lg font-bold text-accent-gold">
Arcane Odyssey Armor Optimizer
</h1>
</div>
</header>
{/* Tab bar */}
<nav className="border-b border-border-default bg-bg-secondary">
<div className="mx-auto max-w-5xl flex items-center gap-1 px-4">
{TABS.map((tab) => (
<TabButton
key={tab.id}
tab={tab}
isActive={activePanel === tab.id}
onSelect={setActivePanel}
/>
))}
<div className="flex-1" />
<DataControls />
PanelContent function · typescript · L120-L141 (22 LOC)src/ui/layout/app-shell.tsx
function PanelContent({
panel,
}: {
panel: UIState["activePanel"];
}): React.JSX.Element {
return (
<>
<div className={panel === "optimizer" ? "" : "hidden"}>
<OptimizerPage />
</div>
<div className={panel === "gear" ? "" : "hidden"}>
<GearInventoryPanel />
</div>
<div className={panel === "data" ? "" : "hidden"}>
<DataManagementPanel />
</div>
<div className={panel === "help" ? "" : "hidden"}>
<HelpPanel />
</div>
</>
);
}DataControls function · typescript · L62-L77 (16 LOC)src/ui/layout/data-controls.tsx
export function DataControls(): React.JSX.Element {
const { fileInputRef, handleExport, handleImport } = useDataImportExport();
const [confirmClear, setConfirmClear] = useState(false);
return (
<>
<div className="flex items-center gap-1.5">
<input ref={fileInputRef} type="file" accept=".json" className="hidden" onChange={handleImport} />
<Button variant="outline" size="xs" onClick={() => { fileInputRef.current?.click(); }}>Import</Button>
<Button variant="outline" size="xs" onClick={handleExport}>Export</Button>
<Button variant="outline" size="xs" className="text-stat-negative hover:text-stat-negative" onClick={() => { setConfirmClear(true); }}>Clear All</Button>
</div>
<ConfirmClearDialog open={confirmClear} onOpenChange={setConfirmClear} />
</>
);
}Repobility · code-quality intelligence platform · https://repobility.com
getAppliedVariant function · typescript · L78-L83 (6 LOC)src/ui/panels/build-card.tsx
function getAppliedVariant(piece: EquipmentPiece | ExpandedEquipment): string | undefined {
if ("appliedVariant" in piece) {
return piece.appliedVariant;
}
return undefined;
}formatPieceName function · typescript · L85-L92 (8 LOC)src/ui/panels/build-card.tsx
function formatPieceName(piece: EquipmentPiece | ExpandedEquipment): string {
const variant = getAppliedVariant(piece);
if (variant != null) {
const capitalizedVariant = variant.charAt(0).toUpperCase() + variant.slice(1);
return `${piece.name} (${capitalizedVariant})`;
}
return piece.name;
}formatBuildText function · typescript · L98-L118 (21 LOC)src/ui/panels/build-card.tsx
function formatBuildText(rank: number, result: SearchResult): string {
const lines = [`Build #${String(rank)} (Score: ${result.score.toFixed(1)})`];
for (const slot of result.loadout.slots) {
const label = SLOT_LABELS[slot.piece.slot];
const parts = [formatPieceName(slot.piece)];
if (slot.enchantment != null) parts.push(`[${slot.enchantment.name}]`);
if (slot.modifier != null) parts.push(`(${slot.modifier.name})`);
if (slot.gems.length > 0) {
parts.push(`{${slot.gems.map((g) => g.name).join(", ")}}`);
}
lines.push(`${label}: ${parts.join(" ")}`);
}
const statParts = STAT_NAMES.filter((s) => result.stats[s] !== 0).map(
(s) => `${s}=${String(result.stats[s])}`,
);
lines.push(`Stats: ${statParts.join(", ")}`);
return lines.join("\n");
}BuildCard function · typescript · L143-L179 (37 LOC)src/ui/panels/build-card.tsx
export function BuildCard(props: BuildCardProps): React.JSX.Element {
const { rank, result, constraints, disabled = false, expanded: controlledExpanded, onToggleExpanded } = props;
const [internalExpanded, setInternalExpanded] = useState(false);
const [copied, setCopied] = useState(false);
const isControlled = controlledExpanded !== undefined;
const expanded = isControlled ? controlledExpanded : internalExpanded;
const constraintMap = buildConstraintMap(constraints);
const handleCopy = useCallback(() => {
if (disabled) return;
void navigator.clipboard.writeText(formatBuildText(rank, result)).then(() => {
setCopied(true);
setTimeout(() => { setCopied(false); }, 1500);
});
}, [rank, result, disabled]);
const handleToggle = useCallback(() => {
if (disabled) return;
if (isControlled && onToggleExpanded != null) onToggleExpanded();
else setInternalExpanded((prev) => !prev);
}, [disabled, isControlled, onToggleExpanded]);
const caKeyStatsDisplay function · typescript · L224-L237 (14 LOC)src/ui/panels/build-card.tsx
function KeyStatsDisplay({ stats }: { readonly stats: SearchResult["stats"] }): React.JSX.Element {
// Show all non-zero stats in the collapsed header
const nonZeroStats = STAT_NAMES.filter((stat) => stats[stat] !== 0);
return (
<div className="hidden sm:flex items-center gap-2 ml-2 flex-wrap">
{nonZeroStats.map((stat) => (
<span key={stat} className="text-[10px] text-text-secondary">
<span className="text-text-muted">{STAT_LABELS[stat]}</span>{" "}
<span className="font-stat">{stats[stat]}</span>
</span>
))}
</div>
);
}CompactSlotList function · typescript · L267-L301 (35 LOC)src/ui/panels/build-card.tsx
function CompactSlotList({
result,
}: {
readonly result: SearchResult;
}): React.JSX.Element {
return (
<div className="px-3 pb-2 space-y-0.5">
{result.loadout.slots.map((slot, i) => {
const variant = getAppliedVariant(slot.piece);
return (
<div key={i} className="flex items-center gap-1.5 text-[11px]">
<Badge variant="outline" className="px-1.5 py-0 text-[9px] shrink-0 w-10 justify-center">
{SLOT_LABELS[slot.piece.slot]}
</Badge>
<span className="text-text-primary">{slot.piece.name}</span>
{variant != null && (
<span className="text-accent-teal capitalize">({variant})</span>
)}
{slot.enchantment != null && (
<span className="text-accent-amber">[{slot.enchantment.name}]</span>
)}
{slot.modifier != null && (
<span className="text-text-muted">({slot.modifier.name})</span>
)}
ExpandedContent function · typescript · L307-L355 (49 LOC)src/ui/panels/build-card.tsx
function ExpandedContent({
result,
constraintMap,
}: {
readonly result: SearchResult;
readonly constraintMap: ReadonlyMap<StatName, SoftConstraint>;
}): React.JSX.Element {
return (
<div className="px-3 py-3 space-y-4">
{/* Stat bars - grouped in 4 columns */}
<div>
<h4 className="text-xs font-semibold text-accent-gold mb-2">
Total Stats
</h4>
<div className="grid grid-cols-4 gap-x-3 gap-y-1">
{STAT_GROUP_ORDER.map((groupKey) => {
const group = STAT_GROUPS[groupKey];
return (
<div key={groupKey} className="space-y-1">
<span className="text-[10px] font-medium text-text-muted">{group.label}</span>
{group.stats.map((stat) => (
<StatBar
key={stat}
stat={stat}
value={result.stats[stat]}
max={STAT_MAX_VALUES[stat]}
constraint={constraintMToggleIcon function · typescript · L31-L40 (10 LOC)src/ui/panels/collapsible-section.tsx
function ToggleIcon({ disabled, open }: { disabled: boolean; open: boolean }): React.JSX.Element {
if (disabled) {
return <Lock className="h-4 w-4 text-text-muted" />;
}
return (
<ChevronRight
className={`h-4 w-4 text-text-muted transition-transform ${open ? "rotate-90" : ""}`}
/>
);
}Repobility · code-quality intelligence · https://repobility.com
TrailingContent function · typescript · L43-L59 (17 LOC)src/ui/panels/collapsible-section.tsx
function TrailingContent({
disabled,
summary,
disabledReason,
}: {
disabled: boolean;
summary: React.ReactNode | undefined;
disabledReason: string | undefined;
}): React.JSX.Element | null {
if (disabled && disabledReason != null) {
return <span className="ml-auto text-xs text-text-muted italic">{disabledReason}</span>;
}
if (summary != null) {
return <span className="ml-auto text-xs text-text-secondary truncate max-w-[60%]">{summary}</span>;
}
return null;
}CollapsibleSection function · typescript · L61-L106 (46 LOC)src/ui/panels/collapsible-section.tsx
export function CollapsibleSection({
title,
summary,
children,
defaultOpen = false,
open: controlledOpen,
onOpenChange,
disabled = false,
disabledReason,
}: CollapsibleSectionProps): React.JSX.Element {
const [internalOpen, setInternalOpen] = useState(defaultOpen);
const isControlled = controlledOpen !== undefined;
const open = isControlled ? controlledOpen : internalOpen;
const handleOpenChange = (newOpen: boolean): void => {
if (isControlled) {
onOpenChange?.(newOpen);
} else {
setInternalOpen(newOpen);
}
};
const effectiveOpen = disabled ? false : open;
const roundedClass = effectiveOpen ? "rounded-t-md" : "rounded-md";
const buttonClass = disabled
? `flex w-full items-center gap-2 ${roundedClass} border border-border-default bg-bg-surface px-4 py-3 text-left transition-colors opacity-60 cursor-not-allowed`
: `flex w-full items-center gap-2 ${roundedClass} border border-border-default bg-bg-surface px-4 py-3 text-left ConstraintPips function · typescript · L18-L43 (26 LOC)src/ui/panels/constraint-pips.tsx
export function ConstraintPips({
stats,
constraints,
}: ConstraintPipsProps): React.JSX.Element {
if (constraints.length === 0) {
return <span className="text-xs text-text-muted">No constraints</span>;
}
return (
<div className="flex items-center gap-1">
{constraints.map((c, i) => {
const value = stats[c.stat];
const level = getSatisfaction(value, c);
const bgClass = SATISFACTION_BG_CLASSES[level];
return (
<span
key={`${c.stat}-${String(i)}`}
className={`inline-block h-2 w-2 rounded-full ${bgClass}`}
title={`${c.stat}: ${String(value)} (${c.type}${c.value != null ? ` ${String(c.value)}` : ""})`}
/>
);
})}
</div>
);
}useValueHandler function · typescript · L80-L92 (13 LOC)src/ui/panels/constraint-row.tsx
function useValueHandler(
constraint: SoftConstraint,
index: number,
onUpdate: (i: number, c: SoftConstraint) => void,
statMax: number | undefined,
): (v: number) => void {
return useCallback((v: number) => {
const clamped = statMax != null ? Math.min(v, statMax) : v;
let newHardCap = constraint.hardCap;
if (newHardCap != null && newHardCap < clamped) newHardCap = clamped;
onUpdate(index, { ...constraint, value: clamped, hardCap: newHardCap });
}, [constraint, index, onUpdate, statMax]);
}useHardCapHandler function · typescript · L94-L106 (13 LOC)src/ui/panels/constraint-row.tsx
function useHardCapHandler(
constraint: SoftConstraint,
index: number,
onUpdate: (i: number, c: SoftConstraint) => void,
statMax: number | undefined,
): (hc: number | undefined) => void {
return useCallback((hc: number | undefined) => {
const clamped = hc != null && statMax != null ? Math.min(hc, statMax) : hc;
let newValue = constraint.value ?? 0;
if (clamped != null && newValue > clamped) newValue = clamped;
onUpdate(index, { ...constraint, value: newValue, hardCap: clamped });
}, [constraint, index, onUpdate, statMax]);
}ConstraintRow function · typescript · L112-L141 (30 LOC)src/ui/panels/constraint-row.tsx
export function ConstraintRow({ constraint, index, onUpdate, onRemove }: ConstraintRowProps): React.JSX.Element {
const scoringMode = useFitnessStore((s) => s.scoringMode);
const showValue = VALUE_TYPES.has(constraint.type);
const showHardCap = HARDCAP_TYPES.has(constraint.type);
const isBetween = constraint.type === "between";
const statMax = STAT_MAX_VALUES[constraint.stat];
const handleValue = useValueHandler(constraint, index, onUpdate, statMax);
const handleHardCap = useHardCapHandler(constraint, index, onUpdate, statMax);
// In efficiency/multiplier modes, only hard filter types are available
const availableTypes = scoringMode === "linear" ? CONSTRAINT_TYPES : HARD_FILTER_TYPES;
return (
<div className="flex flex-wrap items-center gap-2 rounded-md border border-border-subtle bg-bg-surface px-2 py-1.5 transition-colors hover:border-border-default">
{/* Row 1: stat + operator (always together) */}
<div className="flex items-center gap-2 shrink-handleTypeChange function · typescript · L147-L159 (13 LOC)src/ui/panels/constraint-row.tsx
function handleTypeChange(
constraint: SoftConstraint,
index: number,
type: ConstraintType,
onUpdate: (i: number, c: SoftConstraint) => void,
): void {
onUpdate(index, {
...constraint,
type,
value: VALUE_TYPES.has(type) ? (constraint.value ?? 0) : undefined,
hardCap: HARDCAP_TYPES.has(type) ? constraint.hardCap : undefined,
});
}ApplicableToCheckboxes function · typescript · L21-L62 (42 LOC)src/ui/panels/data-management/applicable-to-checkboxes.tsx
export function ApplicableToCheckboxes({
applicableTo,
onChange,
}: ApplicableToCheckboxesProps): React.JSX.Element {
const hasArmor = applicableTo.includes("armor");
const hasAccessory = applicableTo.includes("accessory");
const toggle = (type: "armor" | "accessory"): void => {
const current = new Set(applicableTo);
if (current.has(type)) {
current.delete(type);
} else {
current.add(type);
}
onChange([...current] as ("armor" | "accessory")[]);
};
return (
<div className="flex gap-4">
<div className="flex items-center gap-1.5">
<Checkbox
id="armor"
checked={hasArmor}
onCheckedChange={() => { toggle("armor"); }}
/>
<Label htmlFor="armor" className="text-xs text-text-secondary cursor-pointer">
Armor
</Label>
</div>
<div className="flex items-center gap-1.5">
<Checkbox
id="accessory"
checked={hasAccessory}
onCheAbout: code-quality intelligence by Repobility · https://repobility.com
AtlanteanBehaviorEditor function · typescript · L22-L71 (50 LOC)src/ui/panels/data-management/atlantean-behavior-editor.tsx
export function AtlanteanBehaviorEditor({
modifier,
onChange,
}: AtlanteanBehaviorEditorProps): React.JSX.Element {
const hasAtlantean = modifier.atlanteanBehavior !== undefined;
const [expanded, setExpanded] = useState(hasAtlantean);
const toggleAtlantean = (): void => {
if (hasAtlantean) {
const { atlanteanBehavior: _, ...rest } = modifier;
onChange(rest as Modifier);
setExpanded(false);
} else {
const config: AtlanteanConfig = { insanity: 0, possibleBonusStats: [] };
onChange({ ...modifier, atlanteanBehavior: config });
setExpanded(true);
}
};
const handleClick = (): void => {
if (hasAtlantean) {
setExpanded((p) => !p);
} else {
toggleAtlantean();
}
};
return (
<div className="border border-border-subtle rounded-md overflow-hidden">
<button
type="button"
onClick={handleClick}
className="flex w-full items-center gap-2 px-2 py-1.5 text-left text-sm text-text-mAtlanteanFields function · typescript · L32-L60 (29 LOC)src/ui/panels/data-management/atlantean-fields.tsx
export function AtlanteanFields({
config,
onChange,
onRemove,
}: AtlanteanFieldsProps): React.JSX.Element {
const toggleStat = (stat: StatName): void => {
const current = new Set(config.possibleBonusStats);
if (current.has(stat)) {
current.delete(stat);
} else {
current.add(stat);
}
onChange({ ...config, possibleBonusStats: [...current] });
};
return (
<div className="p-2 space-y-3 border-t border-border-subtle">
<InsanityField config={config} onChange={onChange} />
<BonusStatsField config={config} toggleStat={toggleStat} />
<button
type="button"
onClick={onRemove}
className="text-xs text-stat-negative hover:underline"
>
Remove Atlantean Behavior
</button>
</div>
);
}AutocompleteInput function · typescript · L23-L47 (25 LOC)src/ui/panels/data-management/autocomplete-input.tsx
export function AutocompleteInput({
value,
placeholder,
options,
onChange,
}: AutocompleteInputProps): React.JSX.Element {
const listId = useId();
return (
<>
<Input
value={value}
placeholder={placeholder}
list={listId}
className="h-8 text-sm"
onChange={(e) => { onChange(e.target.value); }}
/>
<datalist id={listId}>
{options.map((opt) => (
<option key={opt} value={opt} />
))}
</datalist>
</>
);
}ConfirmClearDialog function · typescript · L29-L67 (39 LOC)src/ui/panels/data-management/confirm-clear-dialog.tsx
export function ConfirmClearDialog({
open,
onOpenChange,
}: ConfirmClearDialogProps): React.JSX.Element {
const clearAllUserData = useUserDataStore((s) => s.clearAllUserData);
const handleConfirm = (): void => {
clearAllUserData();
onOpenChange(false);
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="bg-bg-surface border-border-default">
<DialogHeader>
<DialogTitle className="text-text-primary">
Clear All User Data?
</DialogTitle>
<DialogDescription className="text-text-secondary">
This will permanently delete all custom items and modifications.
Bundled data will be restored to defaults.
</DialogDescription>
</DialogHeader>
<DialogFooter className="gap-2">
<Button
variant="outline"
size="sm"
onClick={() => { onOpenChange(false); }}
>
Cancel
<useDataCounts function · typescript · L32-L39 (8 LOC)src/ui/panels/data-management/data-management-panel.tsx
function useDataCounts(): Record<GameDataTab, number> {
return useUserDataStore(useShallow((s) => ({
enchantments: s.getMergedEnchantments().length,
modifiers: s.getMergedModifiers().length,
gems: s.getMergedGems().length,
variants: s.getMergedVariantTypes().length,
})));
}DataManagementPanel function · typescript · L45-L106 (62 LOC)src/ui/panels/data-management/data-management-panel.tsx
export function DataManagementPanel(): React.JSX.Element {
const [filter, setFilter] = useState("");
const [sortBy, setSortBy] = useState<SortOption>("name-asc");
const [activeTab, setActiveTab] = useState<GameDataTab>("enchantments");
const [addRequest, setAddRequest] = useState(0);
const counts = useDataCounts();
const handleAdd = useCallback((): void => {
setAddRequest((prev) => prev + 1);
}, []);
return (
<div className="space-y-4 p-4">
<PanelHeader onAdd={handleAdd} />
<div className="flex items-center gap-2">
<SearchInput value={filter} onChange={setFilter} />
<SortSelect value={sortBy} onChange={setSortBy} />
</div>
<Tabs value={activeTab} onValueChange={(v) => { if (isGameDataTab(v)) setActiveTab(v); }}>
<TabsList variant="line">
<TabsTrigger value="enchantments">Enchantments ({counts.enchantments})</TabsTrigger>
<TabsTrigger value="modifiers">Modifiers ({counts.modifiers})</TabsTriggEnchantmentEditDialog function · typescript · L27-L91 (65 LOC)src/ui/panels/data-management/enchantment-edit-dialog.tsx
export function EnchantmentEditDialog({
enchantment,
isNew,
onClose,
}: EnchantmentEditDialogProps): React.JSX.Element {
const addEnchantment = useUserDataStore((s) => s.addEnchantment);
const updateEnchantment = useUserDataStore((s) => s.updateEnchantment);
const [draft, setDraft] = useState<Enchantment | null>(null);
const [purpose, setPurpose] = useState<ItemPurpose>("contribution");
useEffect(() => {
setDraft(enchantment);
}, [enchantment]);
useEffect(() => {
if (enchantment !== null) {
setPurpose("contribution");
}
}, [enchantment]);
const handleSave = (): void => {
if (draft === null) return;
if (isNew) {
addEnchantment(draft, purpose);
} else {
updateEnchantment(draft.id, draft);
}
onClose();
};
const isValid =
draft !== null &&
draft.name.trim() !== "" &&
draft.id.trim() !== "" &&
draft.applicableTo.length > 0;
return (
<ItemEditorDialog
open={enchantment !== null}
EnchantmentEditor function · typescript · L16-L79 (64 LOC)src/ui/panels/data-management/enchantment-editor.tsx
export function EnchantmentEditor({
filter,
sortBy,
addRequest,
}: {
readonly filter: string;
readonly sortBy: SortOption;
readonly addRequest: number;
}): React.JSX.Element {
// Subscribe to userEnchantments to trigger re-render on changes
const userEnchantments = useUserDataStore((s) => s.userEnchantments);
const getMergedEnchantments = useUserDataStore((s) => s.getMergedEnchantments);
const getDeletedEnchantments = useUserDataStore((s) => s.getDeletedEnchantments);
const [editingItem, setEditingItem] = useState<Enchantment | null>(null);
const [isNew, setIsNew] = useState(false);
// Recompute merged items when userEnchantments changes
const items = useMemo(() => getMergedEnchantments(), [getMergedEnchantments, userEnchantments]);
const deletedItems = useMemo(() => getDeletedEnchantments(), [getDeletedEnchantments, userEnchantments]);
const filtered = useMemo(() => {
let result = items;
if (filter !== "") {
const lower = filter.toLowerRepobility — the code-quality scanner for AI-generated software · https://repobility.com
createNewEnchantment function · typescript · L85-L93 (9 LOC)src/ui/panels/data-management/enchantment-editor.tsx
function createNewEnchantment(): Enchantment {
return {
id: `custom-${String(Date.now())}`,
name: "",
tier: 1,
applicableTo: ["armor", "accessory"],
stats: {},
};
}EnchantmentForm function · typescript · L26-L83 (58 LOC)src/ui/panels/data-management/enchantment-form.tsx
export function EnchantmentForm({
enchantment,
onChange,
isNew,
}: EnchantmentFormProps): React.JSX.Element {
return (
<div className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div>
<Label className="text-xs text-text-muted mb-1 block">ID</Label>
<Input
value={enchantment.id}
onChange={(e) => { onChange({ ...enchantment, id: e.target.value }); }}
disabled={!isNew}
className="h-8 text-sm"
placeholder="unique-enchantment-id"
/>
</div>
<div>
<Label className="text-xs text-text-muted mb-1 block">Name</Label>
<Input
value={enchantment.name}
onChange={(e) => { onChange({ ...enchantment, name: e.target.value }); }}
className="h-8 text-sm"
placeholder="Enchantment Name"
/>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<LabEnchantmentList function · typescript · L25-L65 (41 LOC)src/ui/panels/data-management/enchantment-list.tsx
export function EnchantmentList({
items,
deletedItems,
onEdit,
}: EnchantmentListProps): React.JSX.Element {
const deleteEnchantment = useUserDataStore((s) => s.deleteEnchantment);
const restoreEnchantment = useUserDataStore((s) => s.restoreEnchantment);
return (
<>
<div className="border border-border-subtle rounded-md divide-y divide-border-subtle">
{items.length === 0 ? (
<p className="text-text-muted text-xs p-2">No matching enchantments.</p>
) : (
items.map((m) => (
<EnchantmentRow
key={m.item.id}
item={m}
onEdit={() => { onEdit(m.item); }}
onDelete={() => { deleteEnchantment(m.item.id); }}
onReset={m.isModified ? () => { restoreEnchantment(m.item.id); } : undefined}
/>
))
)}
</div>
{deletedItems.length > 0 && (
<HiddenItemsSection
items={deletedItems}
onRestore={(id) => {EnchantmentRow function · typescript · L28-L65 (38 LOC)src/ui/panels/data-management/enchantment-row.tsx
export function EnchantmentRow({
item,
onEdit,
onDelete,
onReset,
}: EnchantmentRowProps): React.JSX.Element {
const enchantment = item.item;
return (
<div className="flex items-center gap-2 px-2 py-1.5 bg-bg-surface hover:bg-bg-elevated transition-colors">
<span className="text-sm text-text-primary truncate flex-1">
{enchantment.name}
</span>
<SourceBadge item={item} />
<TierBadge tier={enchantment.tier} />
<ApplicableToBadge applicableTo={enchantment.applicableTo} />
<StatSummary stats={enchantment.stats} />
<div className="flex gap-1 ml-2">
<Button variant="ghost" size="xs" onClick={onEdit}>
Edit
</Button>
{item.isModified && onReset && (
<Button variant="ghost" size="xs" onClick={onReset}>
Reset
</Button>
)}
<Button
variant="ghost"
size="xs"
className="text-stat-negative hover:text-stat-negative"
EquipmentBasicFields function · typescript · L48-L107 (60 LOC)src/ui/panels/data-management/equipment-basic-fields.tsx
export function EquipmentBasicFields({
equipment,
onChange,
isNew,
}: EquipmentBasicFieldsProps): React.JSX.Element {
const update = <K extends keyof EquipmentPiece>(
key: K,
value: EquipmentPiece[K],
): void => {
onChange({ ...equipment, [key]: value });
};
return (
<>
<FormField label="ID">
<Input
value={equipment.id}
disabled={!isNew}
className="h-8 text-sm"
onChange={(e) => { update("id", e.target.value); }}
/>
</FormField>
<FormField label="Name">
<Input
value={equipment.name}
className="h-8 text-sm"
onChange={(e) => { update("name", e.target.value); }}
/>
</FormField>
<FormField label="Slot">
<Select
value={equipment.slot}
onValueChange={(v) => { if (isSlotType(v)) update("slot", v); }}
>
<SelectTrigger size="sm" className="h-8">
<SelectValue />
</SelEquipmentEditDialog function · typescript · L27-L84 (58 LOC)src/ui/panels/data-management/equipment-edit-dialog.tsx
export function EquipmentEditDialog({
equipment,
isNew,
onClose,
}: EquipmentEditDialogProps): React.JSX.Element {
const addEquipment = useUserDataStore((s) => s.addEquipment);
const updateEquipment = useUserDataStore((s) => s.updateEquipment);
const [draft, setDraft] = useState<EquipmentPiece | null>(null);
const [purpose, setPurpose] = useState<ItemPurpose>("contribution");
useEffect(() => {
setDraft(equipment);
}, [equipment]);
useEffect(() => {
if (equipment !== null) {
setPurpose("contribution");
}
}, [equipment]);
const handleSave = (): void => {
if (draft === null) return;
if (isNew) {
addEquipment(draft, purpose);
} else {
updateEquipment(draft.id, draft);
}
onClose();
};
const isValid =
draft !== null && draft.name.trim() !== "" && draft.id.trim() !== "";
return (
<ItemEditorDialog
open={equipment !== null}
onOpenChange={(open) => {
if (!open) onClose();
}}
EquipmentEditorHeader function · typescript · L20-L37 (18 LOC)src/ui/panels/data-management/equipment-editor-header.tsx
export function EquipmentEditorHeader({
count,
onAddNew,
}: EquipmentEditorHeaderProps): React.JSX.Element {
return (
<div className="flex items-center justify-between">
<h3 className="text-sm font-semibold text-accent-gold">
Equipment
<span className="ml-2 text-xs text-text-muted font-normal">
({String(count)} items)
</span>
</h3>
<Button variant="outline" size="xs" onClick={onAddNew}>
+ Add New
</Button>
</div>
);
}EquipmentEditor function · typescript · L17-L74 (58 LOC)src/ui/panels/data-management/equipment-editor.tsx
export function EquipmentEditor({
filter,
sortBy,
}: {
readonly filter: string;
readonly sortBy: SortOption;
}): React.JSX.Element {
// Subscribe to userEquipment to trigger re-render on changes
const userEquipment = useUserDataStore((s) => s.userEquipment);
const getMergedEquipment = useUserDataStore((s) => s.getMergedEquipment);
const getDeletedEquipment = useUserDataStore((s) => s.getDeletedEquipment);
const [editingItem, setEditingItem] = useState<EquipmentPiece | null>(null);
const [isNew, setIsNew] = useState(false);
// Recompute merged items when userEquipment changes
const items = useMemo(() => getMergedEquipment(), [getMergedEquipment, userEquipment]);
const deletedItems = useMemo(() => getDeletedEquipment(), [getDeletedEquipment, userEquipment]);
const filtered = useMemo(() => {
let result = items;
if (filter !== "") {
const lower = filter.toLowerCase();
result = result.filter(
(m) =>
m.item.name.toLowerCaseRepobility · code-quality intelligence platform · https://repobility.com
createNewEquipment function · typescript · L80-L90 (11 LOC)src/ui/panels/data-management/equipment-editor.tsx
function createNewEquipment(): EquipmentPiece {
return {
id: `custom-${String(Date.now())}`,
name: "",
slot: "accessory",
baseStats: {},
socketCount: 0,
maxLevel: 1,
tags: [],
};
}EquipmentExtraFields function · typescript · L25-L83 (59 LOC)src/ui/panels/data-management/equipment-extra-fields.tsx
export function EquipmentExtraFields({
equipment,
onChange,
}: EquipmentExtraFieldsProps): React.JSX.Element {
const getMergedEquipment = useUserDataStore((s) => s.getMergedEquipment);
// Extract known values from existing equipment for autocomplete
const { knownTags, knownSources } = useMemo(() => {
const tags = new Set<string>();
const sources = new Set<string>();
for (const { item } of getMergedEquipment()) {
for (const tag of item.tags) tags.add(tag);
if (item.source !== undefined) sources.add(item.source);
}
return { knownTags: [...tags].sort(), knownSources: [...sources].sort() };
}, [getMergedEquipment]);
return (
<>
<EquipmentNumericFields equipment={equipment} onChange={onChange} />
<FormField label="Tags (comma-separated, optional)">
<AutocompleteInput
value={equipment.tags.join(", ")}
placeholder="e.g., sunken, boss-drop"
options={knownTags}
onChange={(value) => {EquipmentForm function · typescript · L26-L55 (30 LOC)src/ui/panels/data-management/equipment-form.tsx
export function EquipmentForm({
equipment,
onChange,
isNew,
}: EquipmentFormProps): React.JSX.Element {
return (
<div className="space-y-4">
<EquipmentBasicFields
equipment={equipment}
onChange={onChange}
isNew={isNew}
/>
<EquipmentExtraFields equipment={equipment} onChange={onChange} />
<div>
<Label className="text-xs text-text-muted mb-2 block">Base Stats</Label>
<StatsEditor
stats={equipment.baseStats}
onChange={(s) => { onChange({ ...equipment, baseStats: s }); }}
/>
</div>
<VariantsEditor
variants={equipment.variants}
onChange={(v) => { onChange({ ...equipment, variants: v }); }}
/>
</div>
);
}