|
|
@@ -6,6 +6,7 @@ import ExpressionInput from "../components/ExpressionInpux";
|
|
|
import Icon from "../icon";
|
|
|
import styles from "./ClockTimeline.module.css";
|
|
|
import { ACTION_PRESETS, expandBlockInstances, getPreset, type ClockBlock, type Signal } from "../types";
|
|
|
+import SignalEditorList from "./SignalEditorList";
|
|
|
|
|
|
type PackedInstance = {
|
|
|
id: string;
|
|
|
@@ -42,6 +43,7 @@ export default function TimelineRow({ rowId }: { rowId: string }) {
|
|
|
const { onPointerDownBlock, onPointerMove, onPointerUp, pxToTick } = useTimelineDrag();
|
|
|
|
|
|
const laneRef = useRef<HTMLDivElement>(null);
|
|
|
+
|
|
|
const row = rows[rowId];
|
|
|
if (!row) return null;
|
|
|
|
|
|
@@ -76,17 +78,26 @@ export default function TimelineRow({ rowId }: { rowId: string }) {
|
|
|
if (!signal) return;
|
|
|
updateRow(rowId, { signals: [...row.signals, signal] });
|
|
|
};
|
|
|
+
|
|
|
const updateRowSignal = (index: number, signal: Signal | null) => {
|
|
|
if (!signal) return;
|
|
|
const next = [...row.signals];
|
|
|
next[index] = signal;
|
|
|
updateRow(rowId, { signals: next });
|
|
|
};
|
|
|
+
|
|
|
const removeRowSignal = (index: number) => {
|
|
|
if (!row || row.signals.length <= 1) return;
|
|
|
updateRow(rowId, { signals: row.signals.filter((_, i) => i !== index) });
|
|
|
};
|
|
|
|
|
|
+ const reorderRowSignals = (sourceIdx: number, targetIdx: number) => {
|
|
|
+ const nextSignals = [...row.signals];
|
|
|
+ const [movedSignal] = nextSignals.splice(sourceIdx, 1);
|
|
|
+ nextSignals.splice(targetIdx, 0, movedSignal);
|
|
|
+ updateRow(rowId, { signals: nextSignals });
|
|
|
+ };
|
|
|
+
|
|
|
const autoFillRow = (presetId: string) => {
|
|
|
if (!row) return;
|
|
|
const preset = getPreset(presetId);
|
|
|
@@ -111,23 +122,13 @@ export default function TimelineRow({ rowId }: { rowId: string }) {
|
|
|
value={row.name}
|
|
|
onChange={(e) => updateRow(row.id, { name: e.target.value })}
|
|
|
/>
|
|
|
- <div className={styles.signalList}>
|
|
|
- {row.signals.map((s, i) => (
|
|
|
- <div key={`${s.name}-${i}`} className={styles.signalChip}>
|
|
|
- <SelectSignal value={s.name} onSelectSignal={(_, sig) => updateRowSignal(i, sig)} />
|
|
|
- {row.signals.length > 1 && (
|
|
|
- <button className={styles.signalRemove} onClick={() => removeRowSignal(i)}>
|
|
|
- ✕
|
|
|
- </button>
|
|
|
- )}
|
|
|
- </div>
|
|
|
- ))}
|
|
|
- <SelectSignal
|
|
|
- className={styles.signalEmpty}
|
|
|
- key={row.signals.length}
|
|
|
- onSelectSignal={(_, sig) => addRowSignal(sig)}
|
|
|
- />
|
|
|
- </div>
|
|
|
+ <SignalEditorList
|
|
|
+ signals={row.signals}
|
|
|
+ onAdd={addRowSignal}
|
|
|
+ onUpdate={updateRowSignal}
|
|
|
+ onRemove={removeRowSignal}
|
|
|
+ onReorder={reorderRowSignals}
|
|
|
+ />
|
|
|
<div className={styles.rowStats}>
|
|
|
<label>Stack</label>
|
|
|
<ExpressionInput value={row.stackSize} min={1} onCommit={(v) => updateRow(rowId, { stackSize: v })} />
|
|
|
@@ -150,7 +151,7 @@ export default function TimelineRow({ rowId }: { rowId: string }) {
|
|
|
>
|
|
|
Auto-fill ({row.inserterCount})
|
|
|
</button>
|
|
|
- <button className={styles.removeBtn} onClick={() => removeRow(row.id)}>
|
|
|
+ <button className={"button " + styles.removeBtn} onClick={() => removeRow(row.id)}>
|
|
|
✕
|
|
|
</button>
|
|
|
</div>
|