feat: 添加目标尺寸组件,支持动态保存和反馈机制
This commit is contained in:
@@ -4,3 +4,11 @@
|
|||||||
html, body {
|
html, body {
|
||||||
@apply size-full;
|
@apply size-full;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
&[type='number']::-webkit-outer-spin-button,
|
||||||
|
&[type='number']::-webkit-inner-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,10 +2,12 @@
|
|||||||
import DatasetName from './meta-form/DatasetName.svelte';
|
import DatasetName from './meta-form/DatasetName.svelte';
|
||||||
import SelectLoraType from './meta-form/SelectLoraType.svelte';
|
import SelectLoraType from './meta-form/SelectLoraType.svelte';
|
||||||
import SelectModel from './meta-form/SelectModel.svelte';
|
import SelectModel from './meta-form/SelectModel.svelte';
|
||||||
|
import TargetSize from './meta-form/TargetSize.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-col gap-2 px-4 py-4">
|
<div class="flex flex-col gap-2 px-4 py-4">
|
||||||
<DatasetName />
|
<DatasetName />
|
||||||
<SelectModel />
|
<SelectModel />
|
||||||
<SelectLoraType />
|
<SelectLoraType />
|
||||||
|
<TargetSize />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { activeDatasetMeta, updateActiveDatasetMeta } from '$lib/stores/dataset';
|
||||||
|
import {
|
||||||
|
createDebouncedTrigger,
|
||||||
|
createSaveFeedbackController,
|
||||||
|
type SaveFeedbackState,
|
||||||
|
} from '$lib/utils/form-save';
|
||||||
|
import { onDestroy, onMount } from 'svelte';
|
||||||
|
import { get } from 'svelte/store';
|
||||||
|
|
||||||
|
let width = $state<number>(512);
|
||||||
|
let height = $state<number>(512);
|
||||||
|
let saveFeedback = $state<SaveFeedbackState>('idle');
|
||||||
|
|
||||||
|
const feedback = createSaveFeedbackController((state) => {
|
||||||
|
saveFeedback = state;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
const meta = get(activeDatasetMeta);
|
||||||
|
if (meta?.imageSize) {
|
||||||
|
width = meta.imageSize?.[0] ?? 512;
|
||||||
|
height = meta.imageSize?.[1] ?? 512;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
saveLater.cancel();
|
||||||
|
feedback.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function saveTargetSize(nextWidth: number, nextHeight: number) {
|
||||||
|
const normalizedWidth = Number.isFinite(nextWidth) ? Math.floor(nextWidth) : 0;
|
||||||
|
const normalizedHeight = Number.isFinite(nextHeight) ? Math.floor(nextHeight) : 0;
|
||||||
|
|
||||||
|
if (normalizedWidth <= 0 || normalizedHeight <= 0) {
|
||||||
|
feedback.markNotUpdated();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await updateActiveDatasetMeta({ imageSize: [normalizedWidth, normalizedHeight] });
|
||||||
|
feedback.markUpdated();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to save target size:', error);
|
||||||
|
feedback.markNotUpdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveLater = createDebouncedTrigger(() => {
|
||||||
|
void saveTargetSize(width, height);
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
function saveTargetSizeDelayed() {
|
||||||
|
saveLater.trigger();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<label
|
||||||
|
class={[
|
||||||
|
'input w-fit focus-within:outline-none transition-colors duration-300 ease-out',
|
||||||
|
saveFeedback === 'updated' && 'border-green-500',
|
||||||
|
saveFeedback === 'not-updated' && 'border-red-500',
|
||||||
|
]}>
|
||||||
|
<span class="label min-w-[10em]">Scale To</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="text-right max-w-[5em]"
|
||||||
|
bind:value={width}
|
||||||
|
oninput={saveTargetSizeDelayed} />
|
||||||
|
<span>×</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="text-right max-w-[5em]"
|
||||||
|
bind:value={height}
|
||||||
|
oninput={saveTargetSizeDelayed} />
|
||||||
|
<span>px</span>
|
||||||
|
</label>
|
||||||
Reference in New Issue
Block a user