| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- import data from "../../assets/data/2.0/data.json"; // Adjust path if needed
- import ModuleSlots from "./ModuleSlots";
- import type { Beacon } from "../../../scripts/factorio-dump/process-data.models";
- import { qualityShortcut, useQualityScroller } from "../../hooks/useQualityScroller";
- import Icon from "../icon";
- import NumberInput from "../components/NumberInput";
- import styles from "./BeaconConfigurator.module.css";
- import type { BeaconGroup } from "../../engine";
- const beaconsData = data.beacons as Beacon[];
- export type BeaconGroupConf = BeaconGroup & {
- id: string;
- };
- type BeaconConfiguratorProps = {
- groups: BeaconGroupConf[];
- onChange: (g: BeaconGroupConf[]) => void;
- direction?: "horizontal" | "vertical";
- };
- function BeaconIconWrapper({
- beacon,
- qualityLevel,
- onChangeQuality,
- }: {
- beacon: Beacon;
- qualityLevel: number;
- onChangeQuality: (qualityLevel: number) => void;
- }) {
- // Use the hook in controlled mode by passing qualityLevel
- const { scrollRef, activeQuality } = useQualityScroller("normal", qualityLevel, (q) => onChangeQuality(q.level));
- return (
- <div ref={scrollRef} className={styles.iconWrapper} title={qualityShortcut + " to change beacon quality"}>
- <label>Beacon</label>
- <Icon iconName={beacon.icon ?? ""} size={44} qualityLevel={activeQuality.level} />
- </div>
- );
- }
- export default function BeaconConfigurator({ groups, onChange, direction = "vertical" }: BeaconConfiguratorProps) {
- const handleAddGroup = () => {
- const defaultBeacon = beaconsData[0];
- onChange([
- ...groups,
- {
- id: crypto.randomUUID(), // Use modern UUID instead of Date.now()
- beacon: defaultBeacon,
- beaconQualityLevel: 0,
- count: 1,
- modules: [],
- },
- ]);
- };
- const updateGroup = (id: string, patch: Partial<BeaconGroup>) => {
- onChange(groups.map((g) => (g.id === id ? { ...g, ...patch } : g)));
- };
- return (
- <div className={`${styles.container} ${direction === "horizontal" ? styles.horizontal : styles.vertical}`}>
- {groups.map((g) => (
- <div key={g.id} className={styles.groupCard}>
- {/* Beacon Count */}
- <div className="field" style={{ minWidth: "60px" }}>
- <label style={{ fontSize: "11px", color: "#999", marginBottom: "4px" }}>Count</label>
- <NumberInput min={1} max={50} value={g.count} onChange={(val) => updateGroup(g.id, { count: val || 1 })} />
- </div>
- {/* Beacon Type & Quality */}
- <BeaconIconWrapper
- beacon={g.beacon}
- qualityLevel={g.beaconQualityLevel ?? 0} // Pass the controlled state down!
- onChangeQuality={(q) => updateGroup(g.id, { beaconQualityLevel: q })}
- />
- {/* Beacon Modules */}
- <div className="field">
- <label style={{ fontSize: "11px", color: "#999", marginBottom: "4px" }}>
- Modules ({g.beacon.module_slots})
- </label>
- <ModuleSlots
- value={g.modules} // Pass the controlled state down!
- maxSlots={g.beacon.module_slots}
- allowedEffects={g.beacon.allowed_effects as string[]}
- onChange={(mods) => updateGroup(g.id, { modules: mods })}
- />
- </div>
- <button
- className={styles.removeBtn}
- onClick={() => onChange(groups.filter((x) => x.id !== g.id))}
- title="Remove Beacon Group"
- >
- ✕
- </button>
- </div>
- ))}
- <button onClick={handleAddGroup} className={styles.addBtn}>
- + Add Beacons
- </button>
- </div>
- );
- }
|