mirror of https://github.com/VERT-sh/VERT.git
280 lines
7.6 KiB
Svelte
280 lines
7.6 KiB
Svelte
<script lang="ts">
|
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
import { SearchIcon } from "lucide-svelte";
|
|
import Dropdown from "../Dropdown.svelte";
|
|
import FancyInput from "../FancyInput.svelte";
|
|
import Modal from "./Modal.svelte";
|
|
import { m } from "$lib/paraglide/messages";
|
|
import type { VertFile } from "$lib/types";
|
|
import { sanitize } from "$lib/store/index.svelte";
|
|
import { log } from "$lib/util/logger";
|
|
import { type ConversionSettings } from "$lib/types/conversion-settings";
|
|
|
|
type Props = {
|
|
file: VertFile | null;
|
|
onclose?: () => void;
|
|
};
|
|
|
|
let { file, onclose }: Props = $props();
|
|
|
|
const getAvailableConverters = (vertFile: VertFile) => {
|
|
return vertFile.isZip()
|
|
? vertFile.converters
|
|
: vertFile.findConverters([vertFile.from, vertFile.to]);
|
|
};
|
|
|
|
const getValidConverter = (vertFile: VertFile, converterName?: string) => {
|
|
const available = getAvailableConverters(vertFile);
|
|
const name = converterName || vertFile.conversionSettings.converter;
|
|
return available.find((c) => c.name === name) || available[0];
|
|
};
|
|
|
|
let settings = $derived<ConversionSettings>({
|
|
converter: file ? getValidConverter(file)?.name : undefined,
|
|
});
|
|
|
|
const handleSettingChange = (key: string, value: any) => {
|
|
if (!file) return;
|
|
settings[key] = value;
|
|
};
|
|
|
|
const applySettings = async (converterName: string) => {
|
|
if (!file) return;
|
|
const converter = getValidConverter(file, converterName);
|
|
if (!converter) {
|
|
log(
|
|
["settings", "modal"],
|
|
`No converter found for ${file.name}, cannot apply settings`,
|
|
);
|
|
return;
|
|
}
|
|
// apply defaults, then existing settings, then new settings on top
|
|
file.conversionSettings = {
|
|
...(await converter.getDefaultSettings(file)),
|
|
...file.conversionSettings,
|
|
...settings,
|
|
};
|
|
log(
|
|
["settings", "modal"],
|
|
`Applied settings for ${file.name}: ${JSON.stringify(file.conversionSettings, null, 2)}`,
|
|
);
|
|
};
|
|
</script>
|
|
|
|
<Modal
|
|
icon={SearchIcon}
|
|
title={m["convert.settings.title"]()}
|
|
color="purple"
|
|
buttons={[
|
|
{
|
|
text: "Cancel",
|
|
action: () => onclose?.(),
|
|
},
|
|
{
|
|
text: "Apply",
|
|
action: () => {
|
|
applySettings(settings.converter!);
|
|
onclose?.();
|
|
},
|
|
primary: true,
|
|
},
|
|
]}
|
|
onclose={() => onclose?.()}
|
|
>
|
|
<div class="flex flex-col gap-8 max-h-[calc(100vh-225px)] overflow-y-auto">
|
|
{#if file}
|
|
{@const availableConverters = getAvailableConverters(file)}
|
|
{@const validConverter = getValidConverter(
|
|
file,
|
|
settings.converter,
|
|
)}
|
|
<p class="text-base">
|
|
{@html sanitize(
|
|
m["convert.settings.description"]({
|
|
converter: validConverter?.name || "unknown",
|
|
filename: file.name,
|
|
}),
|
|
)}
|
|
</p>
|
|
|
|
<div class="flex flex-col gap-2">
|
|
<p class="text-sm font-bold mb-1">
|
|
{m["convert.settings.converter"]()}
|
|
</p>
|
|
<Dropdown
|
|
options={availableConverters.map((converter) => ({
|
|
value: converter.name,
|
|
label: converter.name,
|
|
}))}
|
|
selected={validConverter?.name}
|
|
settingsStyle
|
|
onselect={(value) => {
|
|
settings = { converter: value }; // TODO: dont think i need to add the converter here
|
|
}}
|
|
/>
|
|
</div>
|
|
<!-- FIXME: modal loads before settings is finished for some reason -->
|
|
{#key settings}
|
|
{#await file.getAvailableSettings(file, settings.converter) then availableSettings}
|
|
<div class="flex flex-col gap-4">
|
|
{#if availableSettings.length === 0}
|
|
<p class="text-sm text-muted">
|
|
{m["convert.settings.none"]()}
|
|
</p>
|
|
{:else}
|
|
<div class="grid grid-cols-2 gap-4">
|
|
{#each availableSettings as setting (setting.key)}
|
|
<div
|
|
class={setting.forceFullWidth
|
|
? "col-span-2"
|
|
: "flex flex-col gap-2"}
|
|
>
|
|
<p class="text-sm font-bold">
|
|
{setting.label}
|
|
</p>
|
|
<!-- prob unneeded -->
|
|
{#if setting.description}
|
|
<p class="text-xs text-muted mt-1">
|
|
{setting.description}
|
|
</p>
|
|
{/if}
|
|
|
|
{#if setting.type === "select"}
|
|
<Dropdown
|
|
options={setting.options?.map(
|
|
(opt) =>
|
|
typeof opt === "string"
|
|
? {
|
|
value: opt,
|
|
label: opt,
|
|
}
|
|
: opt,
|
|
) || []}
|
|
selected={settings[
|
|
setting.key
|
|
] ??
|
|
file.conversionSettings[
|
|
setting.key
|
|
] ??
|
|
setting.default}
|
|
settingsStyle
|
|
onselect={(value) =>
|
|
handleSettingChange(
|
|
setting.key,
|
|
value,
|
|
)}
|
|
disabled={setting.disabled}
|
|
/>
|
|
{#if setting.hasCustomInput}
|
|
{@const disabled =
|
|
(settings[setting.key] ??
|
|
file.conversionSettings[
|
|
setting.key
|
|
]) !== "custom"}
|
|
<FancyInput
|
|
type="text"
|
|
value={settings[
|
|
setting.customInputKey!
|
|
] ??
|
|
file.conversionSettings[
|
|
setting
|
|
.customInputKey!
|
|
] ??
|
|
""}
|
|
placeholder={setting.placeholder}
|
|
disabled={disabled ||
|
|
setting.disabled}
|
|
oninput={(e) =>
|
|
handleSettingChange(
|
|
setting.customInputKey!,
|
|
e.currentTarget
|
|
.value,
|
|
)}
|
|
/>
|
|
{/if}
|
|
{:else if setting.type === "boolean"}
|
|
<FancyInput
|
|
type="checkbox"
|
|
checked={settings[
|
|
setting.key
|
|
] ??
|
|
file.conversionSettings[
|
|
setting.key
|
|
] ??
|
|
setting.default}
|
|
placeholder={setting.placeholder}
|
|
onchange={(e) =>
|
|
handleSettingChange(
|
|
setting.key,
|
|
e.currentTarget.checked,
|
|
)}
|
|
disabled={setting.disabled}
|
|
/>
|
|
{:else if setting.type === "range"}
|
|
{@const rangeValue = (settings[
|
|
setting.key
|
|
] ??
|
|
file.conversionSettings[
|
|
setting.key
|
|
] ??
|
|
setting.default ??
|
|
setting.min ??
|
|
0) as number}
|
|
{@const rangeLabel =
|
|
setting.options?.[rangeValue]
|
|
?.label ?? rangeValue}
|
|
<div
|
|
class="flex items-center mt-2 gap-2"
|
|
>
|
|
<input
|
|
type="range"
|
|
min={setting.min}
|
|
max={setting.max}
|
|
step={setting.step}
|
|
value={rangeValue}
|
|
class="range-slider w-full"
|
|
oninput={(e) => {
|
|
const nextValue =
|
|
e.currentTarget
|
|
.valueAsNumber;
|
|
handleSettingChange(
|
|
setting.key,
|
|
nextValue,
|
|
);
|
|
}}
|
|
disabled={setting.disabled}
|
|
/>
|
|
<span
|
|
class="text-sm max-w-28 w-full text-right"
|
|
>
|
|
{rangeLabel}
|
|
</span>
|
|
</div>
|
|
{:else}
|
|
<FancyInput
|
|
type={setting.type}
|
|
value={settings[setting.key] ??
|
|
file.conversionSettings[
|
|
setting.key
|
|
] ??
|
|
setting.default}
|
|
placeholder={setting.placeholder}
|
|
oninput={(e) =>
|
|
handleSettingChange(
|
|
setting.key,
|
|
e.currentTarget.value,
|
|
)}
|
|
disabled={setting.disabled}
|
|
/>
|
|
{/if}
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
{/await}
|
|
{/key}
|
|
{/if}
|
|
</div>
|
|
</Modal>
|