|
@@ -14,69 +14,127 @@ export type BeaconGroup = {
|
|
|
modules: { module: Module; qualityLevel: number }[];
|
|
modules: { module: Module; qualityLevel: number }[];
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-export default function BeaconConfigurator({ groups, onChange }: { groups: BeaconGroup[], onChange: (g: BeaconGroup[]) => void }) {
|
|
|
|
|
|
|
+function BeaconIconWrapper({
|
|
|
|
|
+ beacon,
|
|
|
|
|
+ onChangeQuality,
|
|
|
|
|
+}: {
|
|
|
|
|
+ beacon: Beacon;
|
|
|
|
|
+ onChangeQuality: (qualityLevel: number) => void;
|
|
|
|
|
+}) {
|
|
|
|
|
+ const { scrollRef, activeQuality } = useQualityScroller("normal", (q) => onChangeQuality(q.level));
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div
|
|
|
|
|
+ ref={scrollRef}
|
|
|
|
|
+ style={{ display: "flex", flexDirection: "column", alignItems: "center", cursor: "ns-resize", gap: "4px" }}
|
|
|
|
|
+ title="Shift+Scroll to change beacon quality"
|
|
|
|
|
+ >
|
|
|
|
|
+ <label style={{ fontSize: "11px", color: "#999" }}>Beacon</label>
|
|
|
|
|
+ <Icon iconName={beacon.icon ?? ""} size={44} qualityLevel={activeQuality.level} />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+}
|
|
|
|
|
+export default function BeaconConfigurator({
|
|
|
|
|
+ groups,
|
|
|
|
|
+ onChange,
|
|
|
|
|
+}: {
|
|
|
|
|
+ groups: BeaconGroup[];
|
|
|
|
|
+ onChange: (g: BeaconGroup[]) => void;
|
|
|
|
|
+}) {
|
|
|
const handleAddGroup = () => {
|
|
const handleAddGroup = () => {
|
|
|
const defaultBeacon = beaconsData[0];
|
|
const defaultBeacon = beaconsData[0];
|
|
|
- onChange([...groups, {
|
|
|
|
|
- id: Date.now().toString(),
|
|
|
|
|
- beacon: defaultBeacon,
|
|
|
|
|
- qualityLevel: 0,
|
|
|
|
|
- count: 1,
|
|
|
|
|
- modules: []
|
|
|
|
|
- }]);
|
|
|
|
|
|
|
+ onChange([
|
|
|
|
|
+ ...groups,
|
|
|
|
|
+ {
|
|
|
|
|
+ id: Date.now().toString(),
|
|
|
|
|
+ beacon: defaultBeacon,
|
|
|
|
|
+ qualityLevel: 0,
|
|
|
|
|
+ count: 1,
|
|
|
|
|
+ modules: [],
|
|
|
|
|
+ },
|
|
|
|
|
+ ]);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const updateGroup = (id: string, patch: Partial<BeaconGroup>) => {
|
|
const updateGroup = (id: string, patch: Partial<BeaconGroup>) => {
|
|
|
- onChange(groups.map(g => g.id === id ? { ...g, ...patch } : g));
|
|
|
|
|
|
|
+ onChange(groups.map((g) => (g.id === id ? { ...g, ...patch } : g)));
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
<div style={{ display: "flex", flexDirection: "column", gap: "10px" }}>
|
|
<div style={{ display: "flex", flexDirection: "column", gap: "10px" }}>
|
|
|
{groups.map((g) => (
|
|
{groups.map((g) => (
|
|
|
- <div key={g.id} style={{ display: "flex", gap: "16px", alignItems: "center", background: "#242324", padding: "8px", borderRadius: "4px", border: "1px solid #3a3a3a" }}>
|
|
|
|
|
-
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ key={g.id}
|
|
|
|
|
+ style={{
|
|
|
|
|
+ display: "flex",
|
|
|
|
|
+ gap: "16px",
|
|
|
|
|
+ alignItems: "center",
|
|
|
|
|
+ background: "#242324",
|
|
|
|
|
+ padding: "8px",
|
|
|
|
|
+ borderRadius: "4px",
|
|
|
|
|
+ border: "1px solid #3a3a3a",
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
{/* Beacon Count */}
|
|
{/* Beacon Count */}
|
|
|
<div style={{ display: "flex", flexDirection: "column", gap: "4px" }}>
|
|
<div style={{ display: "flex", flexDirection: "column", gap: "4px" }}>
|
|
|
<label style={{ fontSize: "11px", color: "#999" }}>Count</label>
|
|
<label style={{ fontSize: "11px", color: "#999" }}>Count</label>
|
|
|
- <input
|
|
|
|
|
- type="number" min="1" max="50"
|
|
|
|
|
- value={g.count}
|
|
|
|
|
- onChange={e => updateGroup(g.id, { count: Number(e.target.value) || 1 })}
|
|
|
|
|
- style={{ width: "50px", background: "#1a1a1a", color: "#ffe6c0", border: "1px solid #646464", padding: "4px", borderRadius: "4px" }}
|
|
|
|
|
|
|
+ <input
|
|
|
|
|
+ type="number"
|
|
|
|
|
+ min="1"
|
|
|
|
|
+ max="50"
|
|
|
|
|
+ value={g.count}
|
|
|
|
|
+ onChange={(e) => updateGroup(g.id, { count: Number(e.target.value) || 1 })}
|
|
|
|
|
+ style={{
|
|
|
|
|
+ width: "50px",
|
|
|
|
|
+ background: "#1a1a1a",
|
|
|
|
|
+ color: "#ffe6c0",
|
|
|
|
|
+ border: "1px solid #646464",
|
|
|
|
|
+ padding: "4px",
|
|
|
|
|
+ borderRadius: "4px",
|
|
|
|
|
+ }}
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
{/* Beacon Type & Quality */}
|
|
{/* Beacon Type & Quality */}
|
|
|
- <BeaconIconWrapper
|
|
|
|
|
- beacon={g.beacon}
|
|
|
|
|
- qualityLevel={g.qualityLevel}
|
|
|
|
|
- onChangeQuality={(q) => updateGroup(g.id, { qualityLevel: q })}
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <BeaconIconWrapper beacon={g.beacon} onChangeQuality={(q) => updateGroup(g.id, { qualityLevel: q })} />
|
|
|
|
|
|
|
|
{/* Beacon Modules */}
|
|
{/* Beacon Modules */}
|
|
|
<div style={{ display: "flex", flexDirection: "column", gap: "4px" }}>
|
|
<div style={{ display: "flex", flexDirection: "column", gap: "4px" }}>
|
|
|
- <label style={{ fontSize: "11px", color: "#999" }}>Modules ({g.beacon.module_slots})</label>
|
|
|
|
|
- <ModuleSlots
|
|
|
|
|
- maxSlots={g.beacon.module_slots}
|
|
|
|
|
- allowedEffects={g.beacon.allowed_effects as string[]}
|
|
|
|
|
- onChange={mods => updateGroup(g.id, { modules: mods })}
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <label style={{ fontSize: "11px", color: "#999" }}>Modules ({g.beacon.module_slots})</label>
|
|
|
|
|
+ <ModuleSlots
|
|
|
|
|
+ maxSlots={g.beacon.module_slots}
|
|
|
|
|
+ allowedEffects={g.beacon.allowed_effects as string[]}
|
|
|
|
|
+ onChange={(mods) => updateGroup(g.id, { modules: mods })}
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <button onClick={() => onChange(groups.filter(x => x.id !== g.id))} style={{ marginLeft: "auto", background: "none", border: "none", color: "#d9614f", cursor: "pointer", fontSize: "16px" }}>✕</button>
|
|
|
|
|
|
|
+ <button
|
|
|
|
|
+ onClick={() => onChange(groups.filter((x) => x.id !== g.id))}
|
|
|
|
|
+ style={{
|
|
|
|
|
+ marginLeft: "auto",
|
|
|
|
|
+ background: "none",
|
|
|
|
|
+ border: "none",
|
|
|
|
|
+ color: "#d9614f",
|
|
|
|
|
+ cursor: "pointer",
|
|
|
|
|
+ fontSize: "16px",
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ ✕
|
|
|
|
|
+ </button>
|
|
|
</div>
|
|
</div>
|
|
|
))}
|
|
))}
|
|
|
- <button onClick={handleAddGroup} style={{ alignSelf: "flex-start", background: "none", border: "1px dashed #646464", color: "#999", padding: "6px 12px", borderRadius: "4px", cursor: "pointer" }}>+ Add Beacons</button>
|
|
|
|
|
|
|
+ <button
|
|
|
|
|
+ onClick={handleAddGroup}
|
|
|
|
|
+ style={{
|
|
|
|
|
+ alignSelf: "flex-start",
|
|
|
|
|
+ background: "none",
|
|
|
|
|
+ border: "1px dashed #646464",
|
|
|
|
|
+ color: "#999",
|
|
|
|
|
+ padding: "6px 12px",
|
|
|
|
|
+ borderRadius: "4px",
|
|
|
|
|
+ cursor: "pointer",
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ + Add Beacons
|
|
|
|
|
+ </button>
|
|
|
</div>
|
|
</div>
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-function BeaconIconWrapper({ beacon, qualityLevel, onChangeQuality }: any) {
|
|
|
|
|
- const { scrollRef, activeQuality } = useQualityScroller("normal", (q) => onChangeQuality(q.level));
|
|
|
|
|
- return (
|
|
|
|
|
- <div ref={scrollRef} style={{ display: "flex", flexDirection: "column", alignItems: "center", cursor: "ns-resize", gap: "4px" }} title="Shift+Scroll to change beacon quality">
|
|
|
|
|
- <label style={{ fontSize: "11px", color: "#999" }}>Beacon</label>
|
|
|
|
|
- <Icon iconName={beacon.icon ?? ""} size={44} qualityLevel={activeQuality.level} />
|
|
|
|
|
- </div>
|
|
|
|
|
- );
|
|
|
|
|
-}
|
|
|