fix: proper dropdown option labelling

This commit is contained in:
Maya 2026-02-19 18:45:41 +03:00
parent 1c65d37963
commit e9db7a9568
No known key found for this signature in database
8 changed files with 108 additions and 44 deletions

View File

@ -128,8 +128,8 @@
}, },
"common": { "common": {
"metadata": "Metadata", "metadata": "Metadata",
"auto": "auto", "auto": "Auto",
"custom": "custom" "custom": "Custom"
} }
}, },
"tooltips": { "tooltips": {

View File

@ -5,7 +5,7 @@
import { quintOut } from "svelte/easing"; import { quintOut } from "svelte/easing";
type Props = { type Props = {
options: string[]; options: string[] | { value: string; label: string }[];
selected?: string; selected?: string;
onselect?: (option: string) => void; onselect?: (option: string) => void;
disabled?: boolean; disabled?: boolean;
@ -14,7 +14,9 @@
let { let {
options, options,
selected = $bindable(options[0]), selected = $bindable(
typeof options[0] === "string" ? options[0] : options[0].value,
),
onselect, onselect,
disabled, disabled,
settingsStyle, settingsStyle,
@ -29,12 +31,21 @@
open = !open; open = !open;
}; };
const select = (option: string) => { const getValue = (option: string | { value: string; label: string }) =>
const oldIndex = options.indexOf(selected || ""); typeof option === "string" ? option : option.value;
const newIndex = options.indexOf(option);
const getLabel = (option: string | { value: string; label: string }) =>
typeof option === "string" ? option : option.label;
const select = (option: string | { value: string; label: string }) => {
const selectedValue = getValue(option);
const oldIndex = options.findIndex((opt) => getValue(opt) === selected);
const newIndex = options.findIndex(
(opt) => getValue(opt) === selectedValue,
);
isUp = oldIndex > newIndex; isUp = oldIndex > newIndex;
selected = option; selected = selectedValue;
onselect?.(option); onselect?.(selectedValue);
toggle(); toggle();
}; };
@ -89,14 +100,17 @@
? 'font-normal' ? 'font-normal'
: 'font-medium'}" : 'font-medium'}"
> >
{selected} {getLabel(
options.find((opt) => getValue(opt) === selected) ||
selected,
)}
</p> </p>
{/key} {/key}
{#each options as option} {#each options as option}
<p <p
class="col-start-1 row-start-1 invisible pointer-events-none" class="col-start-1 row-start-1 invisible pointer-events-none"
> >
{option} {getLabel(option)}
</p> </p>
{/each} {/each}
</div> </div>
@ -121,7 +135,7 @@
class="w-full p-2 px-4 text-left hover:bg-panel" class="w-full p-2 px-4 text-left hover:bg-panel"
onclick={() => select(option)} onclick={() => select(option)}
> >
{option} {getLabel(option)}
</button> </button>
{/each} {/each}
</div> </div>

View File

@ -104,7 +104,13 @@
{#if setting.type === "select"} {#if setting.type === "select"}
<Dropdown <Dropdown
options={setting.options?.map( options={setting.options?.map(
(opt) => opt.value, (opt) =>
typeof opt === "string"
? {
value: opt,
label: opt,
}
: opt,
) || []} ) || []}
selected={settings[setting.key] ?? selected={settings[setting.key] ??
file.conversionSettings[ file.conversionSettings[

View File

@ -121,7 +121,10 @@ export class FFmpegConverter extends Converter {
default: global.ffmpegQuality, default: global.ffmpegQuality,
options: CONVERSION_BITRATES.map((b) => ({ options: CONVERSION_BITRATES.map((b) => ({
value: b, value: b,
label: b, label:
b === "auto" || b === "custom"
? m[`convert.settings.common.${b}`]()
: `${b} kbps`,
})), })),
hasCustomInput: true, hasCustomInput: true,
customInputKey: "customBitrate", customInputKey: "customBitrate",
@ -138,7 +141,10 @@ export class FFmpegConverter extends Converter {
: global.ffmpegSampleRate, : global.ffmpegSampleRate,
options: SAMPLE_RATES.map((r) => ({ options: SAMPLE_RATES.map((r) => ({
value: r, value: r,
label: r, label:
r === "auto" || r === "custom"
? m[`convert.settings.common.${r}`]()
: `${r} Hz`,
})), })),
hasCustomInput: true, hasCustomInput: true,
customInputKey: "customSampleRate", customInputKey: "customSampleRate",
@ -179,11 +185,9 @@ export class FFmpegConverter extends Converter {
return [bitrate, sampleRate, tracks, channels, metadata]; return [bitrate, sampleRate, tracks, channels, metadata];
} }
public async getDefaultSettings( public async getDefaultSettings(): Promise<ConversionSettings> {
input: VertFile,
): Promise<ConversionSettings> {
const defaults: ConversionSettings = {}; const defaults: ConversionSettings = {};
const settings = await this.getAvailableSettings(input); const settings = await this.getAvailableSettings();
settings.forEach((setting) => { settings.forEach((setting) => {
defaults[setting.key] = setting.default; defaults[setting.key] = setting.default;
}); });
@ -200,7 +204,7 @@ export class FFmpegConverter extends Converter {
const conversionSettings = const conversionSettings =
Object.keys(settings).length > 0 Object.keys(settings).length > 0
? settings ? settings
: await this.getDefaultSettings(input); // use defaults if not provided : await this.getDefaultSettings(); // use defaults if not provided
const isAlac = to === ".alac"; const isAlac = to === ".alac";
if (isAlac) to = ".m4a"; if (isAlac) to = ".m4a";

View File

@ -136,13 +136,12 @@ export class MagickConverter extends Converter {
label: m["convert.settings.image.depth"](), label: m["convert.settings.image.depth"](),
type: "select", type: "select",
default: "auto", default: "auto",
// somehow implement custom option
options: [ options: [
{ value: "auto", label: "Auto" }, { value: "auto", label: "Auto" },
{ value: "custom", label: "Custom" },
{ value: "8", label: "8-bit" }, { value: "8", label: "8-bit" },
{ value: "16", label: "16-bit" }, { value: "16", label: "16-bit" },
{ value: "32", label: "32-bit" }, { value: "32", label: "32-bit" },
{ value: "custom", label: "Custom" },
], ],
}; };
@ -166,8 +165,12 @@ export class MagickConverter extends Converter {
}; };
// TODO: check other formats for transparency support // TODO: check other formats for transparency support
const fromJpeg = input.from === ".jpg" || input.from === ".jpeg" || input.from === ".jfif"; const fromJpeg =
const toJpeg = input.to === ".jpg" || input.to === ".jpeg" || input.to === ".jfif"; input.from === ".jpg" ||
input.from === ".jpeg" ||
input.from === ".jfif";
const toJpeg =
input.to === ".jpg" || input.to === ".jpeg" || input.to === ".jfif";
const transparency: SettingDefinition = { const transparency: SettingDefinition = {
key: "transparency", key: "transparency",
label: m["convert.settings.image.transparency"](), label: m["convert.settings.image.transparency"](),
@ -188,9 +191,11 @@ export class MagickConverter extends Converter {
return [quality, depth, colorSpace, transparency, metadata]; return [quality, depth, colorSpace, transparency, metadata];
} }
public async getDefaultSettings(): Promise<ConversionSettings> { public async getDefaultSettings(
input: VertFile,
): Promise<ConversionSettings> {
const defaults: ConversionSettings = {}; const defaults: ConversionSettings = {};
const settings = await this.getAvailableSettings(); const settings = await this.getAvailableSettings(input);
settings.forEach((setting) => { settings.forEach((setting) => {
defaults[setting.key] = setting.default; defaults[setting.key] = setting.default;
}); });
@ -272,7 +277,7 @@ export class MagickConverter extends Converter {
const conversionSettings = JSON.stringify( const conversionSettings = JSON.stringify(
Object.keys(settings).length > 0 Object.keys(settings).length > 0
? settings // user-provided settings ? settings // user-provided settings
: await this.getDefaultSettings(), // use defaults if not provided : await this.getDefaultSettings(input), // use defaults if not provided
); );
const convertMsg: WorkerMessage = { const convertMsg: WorkerMessage = {
type: "convert", type: "convert",

View File

@ -61,8 +61,8 @@ export class PandocConverter extends Converter {
from: file.from, from: file.from,
to, to,
}, },
compression: null,
id: file.id, id: file.id,
conversionSettings: "", // no settings for pandoc yet
}; };
worker.postMessage(convertMsg); worker.postMessage(convertMsg);
const result = await waitForMessage(worker); const result = await waitForMessage(worker);

View File

@ -483,7 +483,12 @@ export class VertdConverter extends Converter {
default: "auto", default: "auto",
options: CONVERSION_BITRATES.map((b) => ({ options: CONVERSION_BITRATES.map((b) => ({
value: b, value: b,
label: b, label:
b === "auto"
? m["convert.settings.common.auto"]()
: b === "custom"
? m["convert.settings.common.custom"]()
: `${b} kbps`,
})), })),
hasCustomInput: true, hasCustomInput: true,
customInputKey: "customBitrate", customInputKey: "customBitrate",
@ -497,7 +502,12 @@ export class VertdConverter extends Converter {
default: "auto", default: "auto",
options: SAMPLE_RATES.map((r) => ({ options: SAMPLE_RATES.map((r) => ({
value: r, value: r,
label: r, label:
r === "auto"
? m["convert.settings.common.auto"]()
: r === "custom"
? m["convert.settings.common.custom"]()
: `${r} Hz`,
})), })),
hasCustomInput: true, hasCustomInput: true,
customInputKey: "customSampleRate", customInputKey: "customSampleRate",

View File

@ -43,7 +43,9 @@
{m["settings.conversion.filename_format"]()} {m["settings.conversion.filename_format"]()}
</p> </p>
<p class="text-sm text-muted font-normal"> <p class="text-sm text-muted font-normal">
{@html sanitize(m["settings.conversion.filename_description"]())} {@html sanitize(
m["settings.conversion.filename_description"](),
)}
</p> </p>
</div> </div>
<FancyTextInput <FancyTextInput
@ -71,8 +73,14 @@
<div <div
class={clsx( class={clsx(
"flex flex-col gap-8 transition-all duration-300 ease-in-out", "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}, "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-8">
@ -102,7 +110,9 @@
size="24" size="24"
class="inline-block mr-2" class="inline-block mr-2"
/> />
{m["settings.conversion.default_format_enable"]()} {m[
"settings.conversion.default_format_enable"
]()}
</button> </button>
<button <button
@ -118,7 +128,9 @@
size="24" size="24"
class="inline-block mr-2" class="inline-block mr-2"
/> />
{m["settings.conversion.default_format_disable"]()} {m[
"settings.conversion.default_format_disable"
]()}
</button> </button>
</div> </div>
</div> </div>
@ -193,9 +205,7 @@
<p class="text-base font-bold"> <p class="text-base font-bold">
{m["settings.conversion.metadata"]()} {m["settings.conversion.metadata"]()}
</p> </p>
<p <p class="text-sm text-muted font-normal">
class="text-sm text-muted font-normal"
>
{m[ {m[
"settings.conversion.metadata_description" "settings.conversion.metadata_description"
]()} ]()}
@ -273,8 +283,17 @@
]()} ]()}
</p> </p>
<Dropdown <Dropdown
options={CONVERSION_BITRATES.map((b) => options={CONVERSION_BITRATES.map(
b.toString(), (b) => ({
value: b.toString(),
label:
b === "auto" ||
b === "custom"
? m[
`convert.settings.common.${b}`
]()
: `${b} kbps`,
}),
)} )}
selected={settings.ffmpegQuality.toString()} selected={settings.ffmpegQuality.toString()}
onselect={(option: string) => onselect={(option: string) =>
@ -290,13 +309,19 @@
{m["settings.conversion.rate"]()} {m["settings.conversion.rate"]()}
</p> </p>
<Dropdown <Dropdown
options={SAMPLE_RATES.map((r) => options={SAMPLE_RATES.map((r) => ({
r.toString(), value: r.toString(),
)} label:
r === "auto" || r === "custom"
? m[
`convert.settings.common.${r}`
]()
: `${r} Hz`,
}))}
selected={settings.ffmpegSampleRate.toString()} selected={settings.ffmpegSampleRate.toString()}
onselect={(option: string) => { onselect={(option: string) => {
settings.ffmpegSampleRate = settings.ffmpegSampleRate =
option as SampleRate; option as SampleRate as string;
}} }}
settingsStyle settingsStyle
/> />