Native <input type='date'> and <input type='datetime-local'> render their display format (mm/dd/yyyy vs dd/mm/yyyy, 12h vs 24h) based on browser/OS locale, ignoring HTML lang attributes in Firefox and inconsistently in Chrome. The previous lang=en-GB fix was unreliable. Create DateInput.svelte and DateTimeInput.svelte components that show dd/mm/yyyy (and DD/MM/YYYY HH:MM for datetime) by formatting the ISO value in JS, while delegating the actual picker to a hidden native input triggered via showPicker(). Supported in Chrome 99+, Firefox 101+, Safari 16+ (covers all modern browsers). Updated 8 component files across CollectionModal, ChecklistModal, NoteModal, ImmichSelect, CollectionMap, TransportationDetails, LodgingDetails, and LocationVisits.
73 lines
2.2 KiB
Svelte
73 lines
2.2 KiB
Svelte
<script lang="ts">
|
|
import { createEventDispatcher } from 'svelte';
|
|
|
|
export let value: string | null = ''; // ISO yyyy-mm-ddTHH:MM
|
|
export let id: string = '';
|
|
export let name: string = '';
|
|
export let inputClass: string = 'input input-bordered w-full';
|
|
export let disabled: boolean = false;
|
|
export let min: string | null | undefined = undefined;
|
|
export let max: string | null | undefined = undefined;
|
|
export let required: boolean = false;
|
|
export let readonly: boolean = false;
|
|
|
|
const dispatch = createEventDispatcher<{ change: Event }>();
|
|
|
|
let nativeInput: HTMLInputElement;
|
|
|
|
$: normalizedValue = value ?? '';
|
|
$: normalizedMin = min ?? undefined;
|
|
$: normalizedMax = max ?? undefined;
|
|
|
|
$: displayDateTime = formatDateTime(normalizedValue);
|
|
|
|
function formatDateTime(iso: string): string {
|
|
if (!iso) return '';
|
|
const [datePart, timePart] = iso.split('T');
|
|
if (!datePart) return '';
|
|
const [y, m, d] = datePart.split('-');
|
|
if (!y || !m || !d) return '';
|
|
const timeStr = timePart ? timePart.slice(0, 5) : '';
|
|
return timeStr ? `${d}/${m}/${y} ${timeStr}` : `${d}/${m}/${y}`;
|
|
}
|
|
|
|
function openPicker() {
|
|
if (!disabled && !readonly) nativeInput?.showPicker?.();
|
|
}
|
|
|
|
function handleChange(e: Event) {
|
|
value = (e.currentTarget as HTMLInputElement).value;
|
|
dispatch('change', e);
|
|
}
|
|
</script>
|
|
|
|
<div class="relative w-full">
|
|
<button
|
|
type="button"
|
|
class="{inputClass} text-left flex items-center justify-between"
|
|
on:click={openPicker}
|
|
disabled={disabled || readonly}
|
|
>
|
|
<span class={displayDateTime ? '' : 'opacity-40'}>{displayDateTime || 'DD/MM/YYYY HH:MM'}</span>
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 opacity-60" viewBox="0 0 24 24" fill="currentColor">
|
|
<path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 18H5V8h14v13zM7 10h5v5H7z"/>
|
|
</svg>
|
|
</button>
|
|
<input
|
|
bind:this={nativeInput}
|
|
type="datetime-local"
|
|
{id}
|
|
{name}
|
|
value={normalizedValue}
|
|
min={normalizedMin}
|
|
max={normalizedMax}
|
|
{required}
|
|
{readonly}
|
|
on:change={handleChange}
|
|
{disabled}
|
|
tabindex="-1"
|
|
aria-hidden="true"
|
|
style="position:absolute;opacity:0;width:1px;height:1px;top:0;left:0;pointer-events:none;z-index:-1"
|
|
/>
|
|
</div>
|