feat: advanced settings dropdown

hide most conversion settings under a "advanced settings" dropdown
This commit is contained in:
Maya 2025-09-22 15:35:15 +03:00
parent 424ed6e5d6
commit d5205666ff
No known key found for this signature in database
2 changed files with 273 additions and 192 deletions

View File

@ -101,6 +101,7 @@
},
"conversion": {
"title": "Conversion",
"advanced_settings": "Advanced settings",
"filename_format": "File name format",
"filename_description": "This will determine the name of the file on download, <b>not including the file extension.</b> You can put these following templates in the format, which will be replaced with the relevant information: <b>%name%</b> for the original file name, <b>%extension%</b> for the original file extension, and <b>%date%</b> for a date string of when the file was converted.",
"placeholder": "VERT_%name%",

View File

@ -1,7 +1,12 @@
<script lang="ts">
import FancyTextInput from "$lib/components/functional/FancyInput.svelte";
import Panel from "$lib/components/visual/Panel.svelte";
import { PauseIcon, PlayIcon, RefreshCwIcon } from "lucide-svelte";
import {
PauseIcon,
PlayIcon,
RefreshCwIcon,
ChevronDownIcon,
} from "lucide-svelte";
import type { ISettings } from "./index.svelte";
import {
CONVERSION_BITRATES,
@ -15,8 +20,10 @@
import { effects } from "$lib/store/index.svelte";
import FormatDropdown from "$lib/components/functional/FormatDropdown.svelte";
import { categories } from "$lib/converters";
import clsx from "clsx";
const { settings = $bindable() }: { settings: ISettings } = $props();
let showAdvanced = $state(false);
</script>
<Panel class="flex flex-col gap-8 p-6">
@ -29,7 +36,7 @@
/>
{m["settings.conversion.title"]()}
</h2>
<div class="flex flex-col gap-8">
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-2">
<p class="text-base font-bold">
@ -47,198 +54,271 @@
/>
</div>
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-2">
<p class="text-base font-bold">
{m["settings.conversion.default_format"]()}
</p>
<p class="text-sm text-muted font-normal">
{m["settings.conversion.default_format_description"]()}
</p>
</div>
<div class="flex flex-col gap-3 w-full">
<div class="flex gap-3 w-full">
<button
onclick={() => (settings.useDefaultFormat = true)}
class="btn {$effects
? ''
: '!scale-100'} {settings.useDefaultFormat
? 'selected'
: ''} flex-1 p-4 rounded-lg text-black dynadark:text-white flex items-center justify-center"
>
<PlayIcon size="24" class="inline-block mr-2" />
Enable
</button>
<button
onclick={() => (settings.useDefaultFormat = false)}
class="btn {$effects
? ''
: '!scale-100'} {settings.useDefaultFormat
? ''
: 'selected'} flex-1 p-4 rounded-lg text-black dynadark:text-white flex items-center justify-center"
>
<PauseIcon size="24" class="inline-block mr-2" />
Disable
</button>
</div>
</div>
<div
class="grid gap-3 grid-cols-2 md:grid-cols-4"
class:opacity-50={!settings.useDefaultFormat}
<button
onclick={() => (showAdvanced = !showAdvanced)}
class="bg-button flex items-center justify-between p-4 rounded-lg text-black dynadark:text-white w-full"
>
<div class="flex flex-col gap-2">
<p class="text-sm font-bold">
{m["settings.conversion.default_format_image"]()}
</p>
<FormatDropdown
categories={{ image: categories.image }}
from={".png"}
bind:selected={settings.defaultFormat.image}
disabled={!settings.useDefaultFormat}
/>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm font-bold">
{m["settings.conversion.default_format_audio"]()}
</p>
<FormatDropdown
categories={{ audio: categories.audio }}
from={".mp3"}
bind:selected={settings.defaultFormat.audio}
disabled={!settings.useDefaultFormat}
/>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm font-bold">
{m["settings.conversion.default_format_video"]()}
</p>
<FormatDropdown
categories={{ video: categories.video }}
from={".mp4"}
bind:selected={settings.defaultFormat.video}
disabled={!settings.useDefaultFormat}
/>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm font-bold">
{m["settings.conversion.default_format_document"]()}
</p>
<FormatDropdown
categories={{ doc: categories.doc }}
from={".docx"}
bind:selected={settings.defaultFormat.document}
disabled={!settings.useDefaultFormat}
/>
</div>
</div>
</div>
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-2">
<p class="text-base font-bold">
{m["settings.conversion.metadata"]()}
</p>
<p class="text-sm text-muted font-normal italic">
{m["settings.conversion.metadata_description"]()}
</p>
</div>
<div class="flex flex-col gap-3 w-full">
<div class="flex gap-3 w-full">
<button
onclick={() => (settings.metadata = true)}
class="btn {$effects
? ''
: '!scale-100'} {settings.metadata
? 'selected'
: ''} flex-1 p-4 rounded-lg text-black dynadark:text-white flex items-center justify-center"
>
<PlayIcon size="24" class="inline-block mr-2" />
{m["settings.conversion.keep"]()}
</button>
<span class="text-base font-bold"
>{m["settings.conversion.advanced_settings"]()}</span
>
<ChevronDownIcon
size="20"
class={clsx("transition-transform duration-300", {
"rotate-180": showAdvanced,
})}
/>
</button>
<div
class={clsx(
"flex flex-col gap-8 transition-all duration-300 ease-in-out",
{"max-h-[2000px] opacity-100 overflow-visible": showAdvanced},
{"max-h-0 opacity-0 overflow-hidden -mb-4": !showAdvanced},
)}
>
<div class="flex flex-col gap-8">
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-2">
<p class="text-base font-bold">
{m["settings.conversion.default_format"]()}
</p>
<p class="text-sm text-muted font-normal">
{m[
"settings.conversion.default_format_description"
]()}
</p>
</div>
<div class="flex flex-col gap-3 w-full">
<div class="flex gap-3 w-full">
<button
onclick={() =>
(settings.useDefaultFormat = true)}
class="btn {$effects
? ''
: '!scale-100'} {settings.useDefaultFormat
? 'selected'
: ''} flex-1 p-4 rounded-lg text-black dynadark:text-white flex items-center justify-center"
>
<PlayIcon
size="24"
class="inline-block mr-2"
/>
Enable
</button>
<button
onclick={() => (settings.metadata = false)}
class="btn {$effects
? ''
: '!scale-100'} {settings.metadata
? ''
: 'selected'} flex-1 p-4 rounded-lg text-black dynadark:text-white flex items-center justify-center"
>
<PauseIcon size="24" class="inline-block mr-2" />
{m["settings.conversion.remove"]()}
</button>
</div>
</div>
</div>
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-2">
<p class="text-base font-bold">
{m["settings.conversion.quality"]()}
</p>
<p class="text-sm text-muted font-normal">
{m["settings.conversion.quality_description"]()}
</p>
</div>
<div class="grid grid-cols-2 gap-3">
<div class="flex flex-col gap-2">
<p class="text-sm font-bold">
{m["settings.conversion.quality_images"]()}
</p>
<FancyInput
bind:value={
settings.magickQuality as unknown as string
}
type="number"
min={1}
max={100}
placeholder={"100"}
extension={"%"}
/>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm font-bold">
{m["settings.conversion.quality_audio"]()}
</p>
<Dropdown
options={CONVERSION_BITRATES.map((b) =>
b.toString(),
)}
selected={settings.ffmpegQuality.toString()}
onselect={(option: string) =>
(settings.ffmpegQuality =
option as ConversionBitrate)}
settingsStyle
/>
</div>
</div>
<div class="grid grid-cols-2 gap-3">
<div class="flex flex-col gap-2">
<p class="text-sm font-bold">
{m["settings.conversion.rate"]()}
</p>
<Dropdown
options={SAMPLE_RATES.map((r) => r.toString())}
selected={settings.ffmpegSampleRate.toString()}
onselect={(option: string) => {
settings.ffmpegSampleRate =
option as SampleRate;
}}
settingsStyle
/>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm font-bold select-none">
&nbsp;&nbsp;
</p>
<FancyInput
bind:value={
settings.ffmpegCustomSampleRate as unknown as string
}
type="number"
min={1}
placeholder={"44100"}
extension={"Hz"}
disabled={settings.ffmpegSampleRate !== "custom"}
/>
<button
onclick={() =>
(settings.useDefaultFormat = false)}
class="btn {$effects
? ''
: '!scale-100'} {settings.useDefaultFormat
? ''
: 'selected'} flex-1 p-4 rounded-lg text-black dynadark:text-white flex items-center justify-center"
>
<PauseIcon
size="24"
class="inline-block mr-2"
/>
Disable
</button>
</div>
</div>
<div
class="grid gap-3 grid-cols-2 md:grid-cols-4"
class:opacity-50={!settings.useDefaultFormat}
>
<div class="flex flex-col gap-2">
<p class="text-sm font-bold">
{m[
"settings.conversion.default_format_image"
]()}
</p>
<FormatDropdown
categories={{ image: categories.image }}
from={".png"}
bind:selected={
settings.defaultFormat.image
}
disabled={!settings.useDefaultFormat}
/>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm font-bold">
{m[
"settings.conversion.default_format_audio"
]()}
</p>
<FormatDropdown
categories={{ audio: categories.audio }}
from={".mp3"}
bind:selected={
settings.defaultFormat.audio
}
disabled={!settings.useDefaultFormat}
/>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm font-bold">
{m[
"settings.conversion.default_format_video"
]()}
</p>
<FormatDropdown
categories={{ video: categories.video }}
from={".mp4"}
bind:selected={
settings.defaultFormat.video
}
disabled={!settings.useDefaultFormat}
/>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm font-bold">
{m[
"settings.conversion.default_format_document"
]()}
</p>
<FormatDropdown
categories={{ doc: categories.doc }}
from={".docx"}
bind:selected={
settings.defaultFormat.document
}
disabled={!settings.useDefaultFormat}
/>
</div>
</div>
</div>
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-2">
<p class="text-base font-bold">
{m["settings.conversion.metadata"]()}
</p>
<p
class="text-sm text-muted font-normal italic"
>
{m[
"settings.conversion.metadata_description"
]()}
</p>
</div>
<div class="flex flex-col gap-3 w-full">
<div class="flex gap-3 w-full">
<button
onclick={() =>
(settings.metadata = true)}
class="btn {$effects
? ''
: '!scale-100'} {settings.metadata
? 'selected'
: ''} flex-1 p-4 rounded-lg text-black dynadark:text-white flex items-center justify-center"
>
<PlayIcon
size="24"
class="inline-block mr-2"
/>
{m["settings.conversion.keep"]()}
</button>
<button
onclick={() =>
(settings.metadata = false)}
class="btn {$effects
? ''
: '!scale-100'} {settings.metadata
? ''
: 'selected'} flex-1 p-4 rounded-lg text-black dynadark:text-white flex items-center justify-center"
>
<PauseIcon
size="24"
class="inline-block mr-2"
/>
{m["settings.conversion.remove"]()}
</button>
</div>
</div>
</div>
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-2">
<p class="text-base font-bold">
{m["settings.conversion.quality"]()}
</p>
<p class="text-sm text-muted font-normal">
{m[
"settings.conversion.quality_description"
]()}
</p>
</div>
<div class="grid grid-cols-2 gap-3">
<div class="flex flex-col gap-2">
<p class="text-sm font-bold">
{m[
"settings.conversion.quality_images"
]()}
</p>
<FancyInput
bind:value={
settings.magickQuality as unknown as string
}
type="number"
min={1}
max={100}
placeholder={"100"}
extension={"%"}
/>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm font-bold">
{m[
"settings.conversion.quality_audio"
]()}
</p>
<Dropdown
options={CONVERSION_BITRATES.map((b) =>
b.toString(),
)}
selected={settings.ffmpegQuality.toString()}
onselect={(option: string) =>
(settings.ffmpegQuality =
option as ConversionBitrate)}
settingsStyle
/>
</div>
</div>
<div class="grid grid-cols-2 gap-3">
<div class="flex flex-col gap-2">
<p class="text-sm font-bold">
{m["settings.conversion.rate"]()}
</p>
<Dropdown
options={SAMPLE_RATES.map((r) =>
r.toString(),
)}
selected={settings.ffmpegSampleRate.toString()}
onselect={(option: string) => {
settings.ffmpegSampleRate =
option as SampleRate;
}}
settingsStyle
/>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm font-bold select-none">
&nbsp;&nbsp;
</p>
<FancyInput
bind:value={
settings.ffmpegCustomSampleRate as unknown as string
}
type="number"
min={1}
placeholder={"44100"}
extension={"Hz"}
disabled={settings.ffmpegSampleRate !==
"custom"}
/>
</div>
</div>
</div>
</div>
</div>
</div>