SelectedBlockPanel.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import styles from "./SelectedBlockPanel.module.css";
  2. import { ACTION_PRESETS, getPreset } from "./ClockTimeline/model";
  3. import ExpressionInput from "./components/ExpressionInpux";
  4. import { useClockStore } from "../store/useClockStore";
  5. import { useMemo } from "react";
  6. import Preset from "./components/Preset";
  7. import Select from "./components/Select";
  8. export default function SelectedBlockPanel() {
  9. const { selectedBlockIds, removeBlocks, blocks, updateBlock } = useClockStore();
  10. const blockId = useMemo(() => selectedBlockIds.keys().next().value, [selectedBlockIds]);
  11. const block = useMemo(() => {
  12. if (blockId) return blocks[blockId];
  13. }, [blockId]);
  14. if (selectedBlockIds.size > 1) {
  15. return (
  16. <div className={styles.wrap}>
  17. <span className={styles.multiLabel}>{selectedBlockIds.size} blocks selected</span>
  18. <button className={styles.removeBtn} onClick={() => removeBlocks(Array.from(selectedBlockIds))}>
  19. Remove all
  20. </button>
  21. </div>
  22. );
  23. }
  24. if (!blockId || !block) {
  25. return <div className={styles.empty}>Select a block on the timeline to edit it.</div>;
  26. }
  27. const preset = getPreset(block.presetId);
  28. return (
  29. <div className={styles.wrap}>
  30. <div className={styles.preview}>
  31. <Preset preset={preset} size={40} />
  32. </div>
  33. <div className={styles.fields}>
  34. <div className="field">
  35. <label>Action</label>
  36. <Select
  37. style={{ minWidth: 120 }}
  38. value={block.presetId}
  39. onChange={(e) => {
  40. const p = getPreset(e);
  41. updateBlock(blockId, { presetId: p.id, duration: p.ticks + 1 });
  42. }}
  43. options={ACTION_PRESETS.filter((p) => p.id !== "custom").map((p) => ({ ...p }))}
  44. />
  45. </div>
  46. <div className="field">
  47. <label>Start (tick)</label>
  48. <ExpressionInput value={block.start} min={0} onCommit={(v) => updateBlock(blockId, { start: v })} />
  49. </div>
  50. <div className="field">
  51. <label>Duration (ticks)</label>
  52. <ExpressionInput value={block.duration} min={1} onCommit={(v) => updateBlock(blockId, { duration: v })} />
  53. </div>
  54. <div className="field">
  55. <label>Count</label>
  56. <ExpressionInput value={block.count} min={1} onCommit={(v) => updateBlock(blockId, { count: v })} />
  57. </div>
  58. <div className="field">
  59. <label>Repeat ×</label>
  60. <ExpressionInput value={block.repeat ?? 1} min={1} onCommit={(v) => updateBlock(blockId, { repeat: v })} />
  61. </div>
  62. </div>
  63. <button className={styles.removeBtn} onClick={() => removeBlocks([blockId])}>
  64. Remove block
  65. </button>
  66. </div>
  67. );
  68. }