refactor: divides logic in components

This commit is contained in:
HerozDotExe 2025-08-16 10:52:50 +02:00
parent d878ee5737
commit 2af92f8e16
5 changed files with 206 additions and 181 deletions

View file

@ -1,186 +1,11 @@
<script lang="ts">
import { _Audio } from '$lib/audio'
import { Button } from '$lib/components/ui/button'
import { Input } from '$lib/components/ui/input/'
import * as Table from '$lib/components/ui/table/'
import * as Dialog from '$lib/components/ui/dialog/'
import { onMount } from 'svelte'
import * as Select from '$lib/components/ui/select'
import * as RadioGroup from '$lib/components/ui/radio-group/'
import { Label } from '$lib/components/ui/label/'
type Sound = {
name: string
// author: string
// favorited: number
// viewed: number
link: string
src: string
}
let sounds: Sound[] = $state([])
let searchValue = $state('')
function debounce(func, delay) {
let timeout
return function (...args) {
clearTimeout(timeout)
timeout = setTimeout(() => {
func.apply(this, args)
}, delay)
}
}
async function search(): Promise<void> {
sounds = await window.api.search(searchValue)
console.log(sounds)
}
const dSearch = debounce(search, 500)
let sound: _Audio
function play(src: string): void {
if (!localStorage.getItem('output_device_id')) {
return alert('Please select an audio device to ouput sounds.')
}
if (sound) {
sound.stop()
}
sound = new _Audio(src)
sound.setOuputDevice(localStorage.getItem('output_device_id'))
sound.play()
}
let showSelectDeviceDialog = $state(false)
let devices: MediaDeviceInfo[] = $state([])
let device = $state(localStorage.getItem('output_device_id'))
const triggerContent: string = $derived(
devices.find((d) => d.deviceId === device)?.label ?? 'Select a device'
)
let kinds = $state([])
let kind = $state('audiooutput')
async function updateDevices(): Promise<void> {
devices = await navigator.mediaDevices.enumerateDevices()
kinds = []
devices.forEach((d) => {
if (!kinds.includes(d.kind)) {
kinds.push(d.kind)
}
})
devices = devices.filter((d) => d.kind === kind)
}
onMount(async () => {
sounds = await window.api.search()
updateDevices()
console.log(devices)
if (!localStorage.getItem('output_device_id')) {
showSelectDeviceDialog = true
}
})
import Header from '$lib/components/Header.svelte'
import Footer from '$lib/components/Footer.svelte'
import Results from '$lib/components/Results.svelte'
</script>
<header class="absolute top-0 left-0 h-16 w-full">
<Input
placeholder="Search a sound"
class="absolute top-[50%] left-[50%] w-[calc(100%-64px)] translate-[-50%]"
bind:value={searchValue}
onkeyup={dSearch} />
</header>
<Header></Header>
<main
class="absolute top-16 left-[50%] h-[calc(100%-128px)] w-[calc(100%-64px)] translate-x-[-50%] overflow-y-scroll">
<Table.Root>
<!-- <Table.Header>
<Table.Row>
<Table.Head class="w-[100px]">Sound</Table.Head>
<Table.Head>Author</Table.Head>
<Table.Head>Favorited</Table.Head>
<Table.Head>Viewed</Table.Head>
<Table.Head class="text-right"></Table.Head>
<Table.Head class="text-right"></Table.Head>
</Table.Row>
</Table.Header> -->
<Table.Body>
{#each sounds as sound (sound)}
<Table.Row>
<Table.Cell class="font-medium"
><Button variant="link" href={sound.link} target="_blank">{sound.name}</Button
></Table.Cell>
<!-- <Table.Cell>{sound.author}</Table.Cell>
<Table.Cell>{sound.favorited}</Table.Cell>
<Table.Cell>{sound.viewed}</Table.Cell> -->
<Table.Cell class="text-right">
<Button variant="link">Add to favorites</Button></Table.Cell>
<Table.Cell class="text-right">
<Button
class="mr-4"
onclick={() => {
play(sound.src)
}}>Play</Button>
</Table.Cell>
</Table.Row>
{/each}
</Table.Body>
</Table.Root>
</main>
<Results></Results>
<footer class="absolute bottom-0 left-0 h-16 w-full">
<Dialog.Root open={showSelectDeviceDialog}>
<Dialog.Trigger
><Button
class="absolute top-[50%] right-8 w-fit translate-y-[-50%]"
onclick={() => {
showSelectDeviceDialog = true
}}>Select audio device</Button
></Dialog.Trigger>
<Dialog.Content class="max-w-[425px]">
<Dialog.Header>
<Dialog.Title>Select audio device</Dialog.Title>
<Dialog.Description>Usually you should select "CABLE Input"</Dialog.Description>
</Dialog.Header>
<RadioGroup.Root bind:value={kind} onValueChange={updateDevices}>
{#each kinds as kind (kind)}
<div class="flex items-center space-x-2">
<RadioGroup.Item value={kind} />
<Label for="r1">{kind}</Label>
</div>
{/each}
</RadioGroup.Root>
<Select.Root type="single" name="device" bind:value={device}>
<Select.Trigger class="w-full">
{triggerContent}
</Select.Trigger>
<Select.Content>
<Select.Group>
<Select.Label>Devices</Select.Label>
{#each devices as device (`${device.deviceId}`)}
<Select.Item value={device.deviceId} label={device.label}>
{device.label}
</Select.Item>
{/each}
</Select.Group>
</Select.Content>
</Select.Root>
<Dialog.Footer>
<Button
type="button"
class="w-full"
onclick={() => {
console.log('save')
if (device !== '') {
localStorage.setItem('output_device_id', device)
} else localStorage.removeItem('output_device_id')
showSelectDeviceDialog = false
}}>Save</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>
</footer>
<Footer></Footer>

View file

@ -0,0 +1,95 @@
<script lang="ts">
import * as Dialog from '$lib/components/ui/dialog/'
import { Button } from '$lib/components/ui/button'
import * as Select from '$lib/components/ui/select'
import * as RadioGroup from '$lib/components/ui/radio-group/'
import { Label } from '$lib/components/ui/label/'
import { onMount } from 'svelte'
let showSelectDeviceDialog = $state(false)
let devices: MediaDeviceInfo[] = $state([])
let device = $state(localStorage.getItem('output_device_id'))
const triggerContent: string = $derived(
devices.find((d) => d.deviceId === device)?.label ?? 'Select a device'
)
let kinds = $state([])
let kind = $state('audiooutput')
async function updateDevices(): Promise<void> {
devices = await navigator.mediaDevices.enumerateDevices()
kinds = []
devices.forEach((d) => {
if (!kinds.includes(d.kind)) {
kinds.push(d.kind)
}
})
devices = devices.filter((d) => d.kind === kind)
}
onMount(() => {
updateDevices()
console.log(devices)
if (!localStorage.getItem('output_device_id')) {
showSelectDeviceDialog = true
}
})
</script>
<footer class="absolute bottom-0 left-0 h-16 w-full">
<Dialog.Root open={showSelectDeviceDialog}>
<Dialog.Trigger
><Button
class="absolute top-[50%] right-8 w-fit translate-y-[-50%]"
onclick={() => {
showSelectDeviceDialog = true
}}>Select audio device</Button
></Dialog.Trigger>
<Dialog.Content class="max-w-[425px]">
<Dialog.Header>
<Dialog.Title>Select audio device</Dialog.Title>
<Dialog.Description>Usually you should select "CABLE Input"</Dialog.Description>
</Dialog.Header>
<RadioGroup.Root bind:value={kind} onValueChange={updateDevices}>
{#each kinds as kind (kind)}
<div class="flex items-center space-x-2">
<RadioGroup.Item value={kind} />
<Label for="r1">{kind}</Label>
</div>
{/each}
</RadioGroup.Root>
<Select.Root type="single" name="device" bind:value={device}>
<Select.Trigger class="w-full">
{triggerContent}
</Select.Trigger>
<Select.Content>
<Select.Group>
<Select.Label>Devices</Select.Label>
{#each devices as device (`${device.deviceId}`)}
<Select.Item value={device.deviceId} label={device.label}>
{device.label}
</Select.Item>
{/each}
</Select.Group>
</Select.Content>
</Select.Root>
<Dialog.Footer>
<Button
type="button"
class="w-full"
onclick={() => {
console.log('save')
if (device !== '') {
localStorage.setItem('output_device_id', device)
} else localStorage.removeItem('output_device_id')
showSelectDeviceDialog = false
}}>Save</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>
</footer>

View file

@ -0,0 +1,30 @@
<script lang="ts">
import { Input } from '$lib/components/ui/input/'
import { states } from '$lib/states.svelte'
let searchValue = $state('')
function debounce(func, delay) {
let timeout
return function (...args) {
clearTimeout(timeout)
timeout = setTimeout(() => {
func.apply(this, args)
}, delay)
}
}
async function search(): Promise<void> {
states.sounds = await window.api.search(searchValue)
}
const dSearch = debounce(search, 500)
</script>
<header class="absolute top-0 left-0 h-16 w-full">
<Input
placeholder="Search a sound"
class="absolute top-[50%] left-[50%] w-[calc(100%-64px)] translate-[-50%]"
bind:value={searchValue}
onkeyup={dSearch} />
</header>

View file

@ -0,0 +1,61 @@
<script lang="ts">
import { Button } from '$lib/components/ui/button'
import * as Table from '$lib/components/ui/table/'
import { _Audio } from '$lib/audio'
import { onMount } from 'svelte'
import { states } from '$lib/states.svelte'
let sound: _Audio
function play(src: string): void {
if (!localStorage.getItem('output_device_id')) {
return alert('Please select an audio device to ouput sounds.')
}
if (sound) {
sound.stop()
}
sound = new _Audio(src)
sound.setOuputDevice(localStorage.getItem('output_device_id'))
sound.play()
}
onMount(async () => {
states.sounds = await window.api.search()
})
</script>
<main
class="absolute top-16 left-[50%] h-[calc(100%-128px)] w-[calc(100%-64px)] translate-x-[-50%] overflow-y-scroll">
<Table.Root>
<!-- <Table.Header>
<Table.Row>
<Table.Head class="w-[100px]">Sound</Table.Head>
<Table.Head>Author</Table.Head>
<Table.Head>Favorited</Table.Head>
<Table.Head>Viewed</Table.Head>
<Table.Head class="text-right"></Table.Head>
<Table.Head class="text-right"></Table.Head>
</Table.Row>
</Table.Header> -->
<Table.Body>
{#each states.sounds as sound (sound)}
<Table.Row>
<Table.Cell class="font-medium"
><Button variant="link" href={sound.link} target="_blank">{sound.name}</Button
></Table.Cell>
<!-- <Table.Cell>{sound.author}</Table.Cell>
<Table.Cell>{sound.favorited}</Table.Cell>
<Table.Cell>{sound.viewed}</Table.Cell> -->
<Table.Cell class="text-right">
<Button variant="link">Add to favorites</Button></Table.Cell>
<Table.Cell class="text-right">
<Button
class="mr-4"
onclick={() => {
play(sound.src)
}}>Play</Button>
</Table.Cell>
</Table.Row>
{/each}
</Table.Body>
</Table.Root>
</main>

View file

@ -0,0 +1,14 @@
type Sound = {
name: string
// author: string
// favorited: number
// viewed: number
link: string
src: string
}
type States = { sounds: Sound[] }
export const states: States = $state({
sounds: []
})