83 lines
1.4 KiB
Svelte
83 lines
1.4 KiB
Svelte
<script lang="ts">
|
|
import { onDestroy } from 'svelte';
|
|
|
|
let channelsEl: HTMLDivElement;
|
|
|
|
let cycling = false;
|
|
async function cycleChannels() {
|
|
cycling = true;
|
|
const buttons = channelsEl.querySelectorAll('button');
|
|
buttons.forEach((button) => (button.disabled = true));
|
|
const channels = channelsEl.querySelectorAll('audio');
|
|
while (cycling) {
|
|
for (const channel of channels) {
|
|
await channel.play();
|
|
await new Promise((resolve) => {
|
|
channel.onended = resolve;
|
|
});
|
|
if (!cycling) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
buttons.forEach((button) => (button.disabled = false));
|
|
}
|
|
|
|
function startCycle() {
|
|
cycling = !cycling;
|
|
if (cycling) {
|
|
cycleChannels();
|
|
}
|
|
}
|
|
|
|
onDestroy(() => {
|
|
cycling = false;
|
|
});
|
|
</script>
|
|
|
|
<div class="channels" bind:this={channelsEl}>
|
|
<slot />
|
|
</div>
|
|
<div class="controls">
|
|
<button on:click={startCycle}>Cycle all</button>
|
|
</div>
|
|
|
|
<style>
|
|
.channels {
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-evenly;
|
|
font-size: 2rem;
|
|
flex-grow: 1;
|
|
|
|
position: relative;
|
|
}
|
|
|
|
:global(.channels .row) {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.controls {
|
|
text-align: center;
|
|
margin: 2rem 0;
|
|
font-size: 1.5rem;
|
|
}
|
|
|
|
:global(.channels .center) {
|
|
font-size: 0.9em;
|
|
}
|
|
|
|
:global(.channels .label) {
|
|
opacity: 0.33;
|
|
font-size: 6rem;
|
|
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
|
|
pointer-events: none;
|
|
}
|
|
</style>
|