SlotGrid.svelte 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. <script lang="ts" module>
  2. export type Cell = {
  3. slot: number;
  4. label: string; // "A01"
  5. name: string; // sample or sequence name; empty for an empty slot
  6. meta: string; // small line under the name
  7. aria: string;
  8. };
  9. </script>
  10. <script lang="ts">
  11. // A 4x4 grid of pads or sequence slots, used by both tabs.
  12. let {
  13. cells,
  14. selected,
  15. onpick,
  16. dropTarget = false,
  17. }: {
  18. cells: Cell[]; // 16 cells in grid order, top-left first
  19. selected: number;
  20. onpick: (slot: number) => void;
  21. dropTarget?: boolean; // accept WAV files dropped from the system
  22. } = $props();
  23. </script>
  24. <div class="grid">
  25. {#each cells as c (c.slot)}
  26. <button
  27. type="button"
  28. class:filled={c.name !== ""}
  29. class:on={c.slot === selected}
  30. aria-pressed={c.slot === selected}
  31. aria-label={c.aria}
  32. data-file-drop-target={dropTarget ? "" : undefined}
  33. data-slot={c.slot}
  34. onclick={() => onpick(c.slot)}
  35. >
  36. <span class="num">{c.label}</span>
  37. <span class="name">{c.name}</span>
  38. <span class="meta">{c.meta}</span>
  39. </button>
  40. {/each}
  41. </div>
  42. <style>
  43. /* Fills the height its panel gives it: four equal rows. */
  44. .grid {
  45. flex: 1;
  46. min-height: 0;
  47. display: grid;
  48. grid-template-columns: repeat(4, minmax(0, 1fr));
  49. grid-template-rows: repeat(4, minmax(0, 1fr));
  50. gap: 8px;
  51. }
  52. button {
  53. min-height: 0;
  54. padding: 6px 8px;
  55. display: flex;
  56. flex-direction: column;
  57. align-items: flex-start;
  58. justify-content: space-between;
  59. gap: 4px;
  60. text-align: left;
  61. background: var(--cell-empty);
  62. color: var(--text);
  63. border: 2px solid var(--line);
  64. border-radius: 8px;
  65. font: inherit;
  66. cursor: pointer;
  67. overflow: hidden;
  68. }
  69. button.filled {
  70. background: var(--cell-filled);
  71. border-color: var(--cell-filled-edge);
  72. }
  73. button.on {
  74. border-color: var(--accent);
  75. }
  76. /* Wails adds this class while a file is dragged over a drop target. */
  77. button:global(.file-drop-target-active) {
  78. border-color: var(--accent);
  79. background: rgba(245, 165, 36, 0.12);
  80. }
  81. .num {
  82. font-family: var(--mono);
  83. font-size: 11px;
  84. font-weight: 500;
  85. color: var(--muted);
  86. }
  87. button.on .num {
  88. color: var(--accent);
  89. }
  90. .name {
  91. font-size: 12px;
  92. font-weight: 600;
  93. line-height: 1.25;
  94. max-width: 100%;
  95. overflow: hidden;
  96. text-overflow: ellipsis;
  97. white-space: nowrap;
  98. }
  99. .meta {
  100. font-family: var(--mono);
  101. font-size: 11px;
  102. color: var(--soft);
  103. min-height: 15px;
  104. white-space: nowrap;
  105. }
  106. </style>