93 lines
2.6 KiB
Svelte
93 lines
2.6 KiB
Svelte
<script>
|
|
import Setting from './Setting.svelte';
|
|
|
|
import { createEventDispatcher } from 'svelte';
|
|
const dispatch = createEventDispatcher();
|
|
|
|
|
|
export let title;
|
|
// seconds are required
|
|
export let seconds;
|
|
|
|
export let min = 0;
|
|
export let max = null;
|
|
|
|
// best unit is the unit that results in the smallest non-fractional number
|
|
let unit = null;
|
|
|
|
const UNITS = {
|
|
Seconds: 1,
|
|
Minutes: 60,
|
|
Hours: 3600,
|
|
Days: 86400,
|
|
};
|
|
|
|
if (unit === null) {
|
|
let min = Infinity;
|
|
let bestUnit = null;
|
|
for (const [u, multiplier] of Object.entries(UNITS)) {
|
|
const v = seconds / multiplier;
|
|
if (v < min && v >= 1) {
|
|
min = v;
|
|
bestUnit = u;
|
|
}
|
|
}
|
|
unit = bestUnit;
|
|
}
|
|
|
|
|
|
// local value is only one-way synced to value so that we can better handle changes
|
|
$: localValue = (seconds / UNITS[unit]).toString();
|
|
let error = null;
|
|
|
|
function updateValue() {
|
|
localValue = localValue.replace(/[^0-9.]/g, '');
|
|
// Don't update the value, but also don't error, if it's empty,
|
|
// or if it could be the start of a float
|
|
if (localValue === '' || localValue === '.') {
|
|
error = null;
|
|
return;
|
|
}
|
|
|
|
const num = parseFloat(localValue);
|
|
if (num < 0) {
|
|
error = `${num} is not a valid duration`
|
|
}
|
|
else if (min !== null && num < min) {
|
|
error = `Too low (minimum ${min * UNITS[unit]}`;
|
|
}
|
|
else if (max !== null & num > max) {
|
|
error = `Too high (maximum ${max * UNITS[unit]}`;
|
|
}
|
|
else {
|
|
error = null;
|
|
seconds = Math.round(num * UNITS[unit]);
|
|
dispatch('update', {seconds});
|
|
}
|
|
}
|
|
</script>
|
|
|
|
|
|
<Setting {title}>
|
|
<div slot="input">
|
|
<select class="select select-bordered select-sm mr-2" bind:value={unit}>
|
|
{#each Object.keys(UNITS) as u}
|
|
<option selected={u === unit || null}>{u}</option>
|
|
{/each}
|
|
</select>
|
|
|
|
<div class="tooltip tooltip-error" class:tooltip-open={error !== null} data-tip={error}>
|
|
<input
|
|
type="text"
|
|
class="input input-sm input-bordered text-right"
|
|
size={Math.max(5, localValue.length)}
|
|
class:input-error={error}
|
|
bind:value={localValue}
|
|
on:input={updateValue}
|
|
>
|
|
</div>
|
|
</div>
|
|
|
|
<slot name="description" slot="description"></slot>
|
|
</Setting>
|