feat: replace all native date inputs with custom DatePicker component
Add theme-aware DatePicker with pill display, calendar dropdown, prev/next day arrows, bilingual month/weekday names, and min/max support. Replace all 15 native <input type="date"> elements across fitness, tasks, and cospend.
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
import ImageUpload from '$lib/components/ImageUpload.svelte';
|
||||
import SaveFab from '$lib/components/SaveFab.svelte';
|
||||
import Toggle from '$lib/components/Toggle.svelte';
|
||||
import DatePicker from '$lib/components/DatePicker.svelte';
|
||||
|
||||
let { data, form } = $props();
|
||||
|
||||
@@ -454,13 +455,8 @@
|
||||
|
||||
<div class="form-group">
|
||||
<label for="date">{t('payment_date', lang)}</label>
|
||||
<input
|
||||
type="date"
|
||||
id="date"
|
||||
name="date"
|
||||
bind:value={formData.date}
|
||||
required
|
||||
/>
|
||||
<DatePicker bind:value={formData.date} {lang} />
|
||||
<input type="hidden" name="date" value={formData.date} />
|
||||
{#if formData.currency !== 'CHF'}
|
||||
<small class="help-text">{t('exchange_rate_date', lang)}</small>
|
||||
{/if}
|
||||
@@ -505,13 +501,8 @@
|
||||
|
||||
<div class="form-group">
|
||||
<label for="recurringStartDate">{t('start_date', lang)}</label>
|
||||
<input
|
||||
type="date"
|
||||
id="recurringStartDate"
|
||||
name="recurringStartDate"
|
||||
bind:value={recurringData.startDate}
|
||||
required
|
||||
/>
|
||||
<DatePicker bind:value={recurringData.startDate} {lang} />
|
||||
<input type="hidden" name="recurringStartDate" value={recurringData.startDate} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -545,13 +536,8 @@
|
||||
|
||||
<div class="form-group">
|
||||
<label for="recurringEndDate">{t('end_date_optional', lang)}</label>
|
||||
<input
|
||||
type="date"
|
||||
id="recurringEndDate"
|
||||
name="recurringEndDate"
|
||||
bind:value={recurringData.endDate}
|
||||
min={recurringData.startDate}
|
||||
/>
|
||||
<DatePicker bind:value={recurringData.endDate} min={recurringData.startDate} {lang} />
|
||||
<input type="hidden" name="recurringEndDate" value={recurringData.endDate} />
|
||||
<small class="help-text">{t('end_date_hint', lang)}</small>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import FormSection from '$lib/components/FormSection.svelte';
|
||||
import ImageUpload from '$lib/components/ImageUpload.svelte';
|
||||
import SaveFab from '$lib/components/SaveFab.svelte';
|
||||
import DatePicker from '$lib/components/DatePicker.svelte';
|
||||
|
||||
/**
|
||||
* @typedef {import('$models/Payment').IPayment & {splits?: import('$models/PaymentSplit').IPaymentSplit[]}} PaymentWithSplits
|
||||
@@ -42,6 +43,7 @@
|
||||
let jsEnhanced = $state(false);
|
||||
/** @type {number | null} */
|
||||
let originalAmount = $state(null);
|
||||
let paymentDateStr = $state('');
|
||||
|
||||
let categoryOptions = $derived(getCategoryOptionsI18n(lang));
|
||||
|
||||
@@ -169,6 +171,7 @@
|
||||
}));
|
||||
}
|
||||
|
||||
paymentDateStr = formatDateForInput(loaded.date);
|
||||
// Store original amount for comparison to prevent infinite recalculation
|
||||
originalAmount = loaded.amount;
|
||||
// Set initial lastCalculatedAmount to prevent immediate recalculation on load
|
||||
@@ -343,6 +346,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Sync date picker string back to payment object
|
||||
$effect(() => {
|
||||
if (payment && paymentDateStr) {
|
||||
payment.date = /** @type {Date} */ (new Date(paymentDateStr + 'T12:00:00'));
|
||||
}
|
||||
});
|
||||
|
||||
// Reactive statement for exchange rate fetching
|
||||
$effect(() => {
|
||||
if (jsEnhanced && payment && payment.currency && payment.currency !== 'CHF' && payment.date && payment.originalAmount) {
|
||||
@@ -469,13 +479,7 @@
|
||||
|
||||
<div class="form-group">
|
||||
<label for="date">{t('date', lang)}</label>
|
||||
<input
|
||||
type="date"
|
||||
id="date"
|
||||
value={formatDateForInput(payment.date)}
|
||||
onchange={(e) => { if (payment) payment.date = /** @type {Date} */ (new Date(/** @type {HTMLInputElement} */ (e.target).value)); }}
|
||||
required
|
||||
/>
|
||||
<DatePicker bind:value={paymentDateStr} {lang} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import SplitMethodSelector from '$lib/components/cospend/SplitMethodSelector.svelte';
|
||||
import UsersList from '$lib/components/cospend/UsersList.svelte';
|
||||
import SaveFab from '$lib/components/SaveFab.svelte';
|
||||
import DatePicker from '$lib/components/DatePicker.svelte';
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
@@ -416,12 +417,7 @@
|
||||
|
||||
<div class="form-group">
|
||||
<label for="startDate">{t('start_date', lang)}</label>
|
||||
<input
|
||||
type="date"
|
||||
id="startDate"
|
||||
bind:value={formData.startDate}
|
||||
required
|
||||
/>
|
||||
<DatePicker bind:value={formData.startDate} {lang} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -454,11 +450,7 @@
|
||||
|
||||
<div class="form-group">
|
||||
<label for="endDate">{t('end_date_optional', lang)}</label>
|
||||
<input
|
||||
type="date"
|
||||
id="endDate"
|
||||
bind:value={formData.endDate}
|
||||
/>
|
||||
<DatePicker bind:value={formData.endDate} {lang} />
|
||||
<div class="help-text">{t('end_date_hint', lang)}</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
import ExerciseName from '$lib/components/fitness/ExerciseName.svelte';
|
||||
import SetTable from '$lib/components/fitness/SetTable.svelte';
|
||||
import ExercisePicker from '$lib/components/fitness/ExercisePicker.svelte';
|
||||
import DatePicker from '$lib/components/DatePicker.svelte';
|
||||
import FitnessChart from '$lib/components/fitness/FitnessChart.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
@@ -503,7 +504,7 @@
|
||||
<div class="edit-meta">
|
||||
<div class="meta-row">
|
||||
<label for="edit-date">{t('date', lang)}</label>
|
||||
<input id="edit-date" type="date" bind:value={editData.date} />
|
||||
<DatePicker bind:value={editData.date} {lang} />
|
||||
</div>
|
||||
<div class="meta-row">
|
||||
<label for="edit-time">{t('time', lang)}</label>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import { toast } from '$lib/js/toast.svelte';
|
||||
import { confirm } from '$lib/js/confirmDialog.svelte';
|
||||
import SaveFab from '$lib/components/SaveFab.svelte';
|
||||
import DatePicker from '$lib/components/DatePicker.svelte';
|
||||
|
||||
const lang = $derived(detectFitnessLang($page.url.pathname));
|
||||
const measureSlug = $derived(lang === 'en' ? 'measure' : 'messen');
|
||||
@@ -289,7 +290,7 @@
|
||||
<!-- New measurement form -->
|
||||
<form class="add-form" onsubmit={(e) => { e.preventDefault(); saveMeasurement(); }}>
|
||||
<div class="date-row">
|
||||
<input type="date" bind:value={formDate} class="date-pill" />
|
||||
<DatePicker bind:value={formDate} {lang} />
|
||||
</div>
|
||||
|
||||
<div class="weight-card">
|
||||
@@ -588,20 +589,6 @@
|
||||
justify-content: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.date-pill {
|
||||
background: var(--color-bg-tertiary);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-pill);
|
||||
padding: 0.35rem 1rem;
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
}
|
||||
.date-pill:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.weight-card {
|
||||
background: var(--color-surface);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { confirm } from '$lib/js/confirmDialog.svelte';
|
||||
import { Trash2 } from '@lucide/svelte';
|
||||
import SaveFab from '$lib/components/SaveFab.svelte';
|
||||
import DatePicker from '$lib/components/DatePicker.svelte';
|
||||
|
||||
const lang = $derived(detectFitnessLang($page.url.pathname));
|
||||
const measureSlug = $derived(lang === 'en' ? 'measure' : 'messen');
|
||||
@@ -112,7 +113,7 @@
|
||||
<form onsubmit={(e) => { e.preventDefault(); saveMeasurement(); }}>
|
||||
<div class="form-group">
|
||||
<label for="m-date">{t('date', lang)}</label>
|
||||
<input id="m-date" type="date" bind:value={formDate} />
|
||||
<DatePicker bind:value={formDate} {lang} />
|
||||
</div>
|
||||
|
||||
<h3>{t('general', lang)}</h3>
|
||||
|
||||
Reference in New Issue
Block a user