File size: 1,550 Bytes
c126239
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<script lang="ts">
  /** Playback control over generated decoding steps. */
  let {
    total,
    index = $bindable(),
    intervalMs = 420,
  }: { total: number; index: number; intervalMs?: number } = $props();

  let playing = $state(false);
  let timer: ReturnType<typeof setInterval> | null = null;

  function stop() {
    if (timer) clearInterval(timer);
    timer = null;
    playing = false;
  }

  function toggle() {
    if (playing) {
      stop();
      return;
    }
    if (index >= total - 1) index = 0;
    playing = true;
    timer = setInterval(() => {
      if (index >= total - 1) {
        stop();
        return;
      }
      index = index + 1;
    }, intervalMs);
  }

  $effect(() => () => stop());
</script>

<div class="player">
  <button onclick={toggle} disabled={total === 0}>{playing ? 'pause' : 'play'}</button>
  <button onclick={() => { stop(); index = Math.max(0, index - 1); }} disabled={index <= 0}>
    prev
  </button>
  <button
    onclick={() => { stop(); index = Math.min(total - 1, index + 1); }}
    disabled={index >= total - 1}>next</button
  >
  <input
    type="range"
    min="0"
    max={Math.max(0, total - 1)}
    bind:value={index}
    oninput={stop}
    disabled={total === 0}
  />
  <span class="mono small dim">step {total === 0 ? 0 : index + 1} / {total}</span>
</div>

<style>
  .player {
    display: flex;
    align-items: center;
    gap: 6px;
  }
  .player button {
    padding: 3px 9px;
    font-size: 12.5px;
  }
  input[type='range'] {
    flex: 1;
    min-width: 100px;
  }
</style>