refactor: divides logic in components
This commit is contained in:
parent
d878ee5737
commit
2af92f8e16
5 changed files with 206 additions and 181 deletions
|
|
@ -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>
|
||||
|
|
|
|||
95
src/renderer/src/lib/components/Footer.svelte
Normal file
95
src/renderer/src/lib/components/Footer.svelte
Normal 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>
|
||||
30
src/renderer/src/lib/components/Header.svelte
Normal file
30
src/renderer/src/lib/components/Header.svelte
Normal 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>
|
||||
61
src/renderer/src/lib/components/Results.svelte
Normal file
61
src/renderer/src/lib/components/Results.svelte
Normal 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>
|
||||
14
src/renderer/src/lib/states.svelte.ts
Normal file
14
src/renderer/src/lib/states.svelte.ts
Normal 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: []
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue