diff --git a/src/assets/profile.png b/src/assets/profile.png new file mode 100644 index 0000000..b577a04 Binary files /dev/null and b/src/assets/profile.png differ diff --git a/src/lib/timeline/detail/EditForm.svelte b/src/lib/timeline/detail/EditForm.svelte index 6b68705..65591dd 100644 --- a/src/lib/timeline/detail/EditForm.svelte +++ b/src/lib/timeline/detail/EditForm.svelte @@ -5,6 +5,12 @@ import { getCitiesForCountry, ALL_CITIES } from '../../shared/cities.js'; import SearchInput from '../../shared/SearchInput.svelte'; import PhotoEditor from './PhotoEditor.svelte'; + import airplaneImg from '../../../assets/airplane.png'; + import trainImg from '../../../assets/train.png'; + import busImg from '../../../assets/bus.png'; + import carImg from '../../../assets/car.png'; + import shipImg from '../../../assets/ship.png'; + import walkImg from '../../../assets/walk.png'; /** * entry = null โ†’ "new entry" mode @@ -25,6 +31,8 @@ let memo = $state(entry?.memo ?? ''); let transport = $state(entry?.transport ?? ''); + let step = $state(1); // 1 | 2 | 3 + let errors = $state({ country: '', cities: '', date: '', days: '', tripType: '', transport: '' }); @@ -34,12 +42,12 @@ } const transportOptions = [ - { value: 'flight', label: 'โœˆ Flight' }, - { value: 'train', label: '๐Ÿš‚ Train' }, - { value: 'bus', label: '๐ŸšŒ Bus' }, - { value: 'car', label: '๐Ÿš— Car' }, - { value: 'ship', label: '๐Ÿšข Ship' }, - { value: 'walk', label: '๐Ÿšถ Walk' }, + { value: 'flight', label: 'Flight', img: airplaneImg }, + { value: 'train', label: 'Train', img: trainImg }, + { value: 'bus', label: 'Bus', img: busImg }, + { value: 'car', label: 'Car', img: carImg }, + { value: 'ship', label: 'Ship', img: shipImg }, + { value: 'walk', label: 'Walk', img: walkImg }, ]; const MEMO_MAX = 100; @@ -50,7 +58,6 @@ const raw = e.currentTarget.value; const words = raw.trim() === '' ? [] : raw.trim().split(/\s+/); if (words.length > MEMO_MAX) { - // keep first 100 words, preserve trailing space if user is mid-word memo = words.slice(0, MEMO_MAX).join(' '); e.currentTarget.value = memo; } else { @@ -58,7 +65,6 @@ } } - // Suggest cities โ€” when a country is selected show only cities from that country. let allEntries = $derived(getEntries()); let cityOptions = $derived( country.trim() @@ -78,17 +84,27 @@ cities = cities.filter(x => x !== c); } - async function save() { - clearErrors(); - let hasError = false; - if (!country.trim()) { errors.country = 'Country is required.'; hasError = true; } - if (cities.length === 0) { errors.cities = 'Add at least one city.'; hasError = true; } - if (!date) { errors.date = 'Date is required.'; hasError = true; } - if (!days || Number(days) < 1) { errors.days = 'Enter a valid number of days.'; hasError = true; } - if (!tripType) { errors.tripType = 'Select a trip type.'; hasError = true; } - if (!transport) { errors.transport = 'Select how you got there.'; hasError = true; } - if (hasError) return; + function nextStep() { + if (step === 1) { + clearErrors(); + let hasError = false; + if (!country.trim()) { errors.country = 'Country is required.'; hasError = true; } + if (cities.length === 0) { errors.cities = 'Add at least one city.'; hasError = true; } + if (!date) { errors.date = 'Date is required.'; hasError = true; } + if (!days || Number(days) < 1) { errors.days = 'Enter a valid number of days.'; hasError = true; } + if (!tripType) { errors.tripType = 'Select a trip type.'; hasError = true; } + if (!transport) { errors.transport = 'Select how you got there.'; hasError = true; } + if (hasError) return; + } + step++; + } + function prevStep() { + if (step === 1) onBack(); + else step--; + } + + async function save() { try { if (isNew) { await addEntry({ @@ -119,149 +135,162 @@ } -
+
-
+
-
- {isNew ? 'New trip' : 'Edit'} + +
+ {#each [1,2,3] as s} +
s}>
+ {/each} +
+
- + {#if step < 3} + + {:else} + + {/if}
-
-
{ e.preventDefault(); save(); }}> +
+
-
-
- - - {#if errors.country}{errors.country}{/if} -
-
- -
- + {#if step === 1} +

+ {isNew ? 'Journal your trip!' : 'Edit your trip'} +

+ +
+
+ + + {#if errors.country}{errors.country}{/if} +
+
+ + + {#if errors.cities}{errors.cities}{/if} + {#if cities.length > 0} +
+ {#each cities as c} + {c} + {/each} +
+ {/if} +
+
+ +
+
+ + + {#if errors.date}{errors.date}{/if} +
+
+ + + {#if errors.days}{errors.days}{/if}
- {#if errors.cities}{errors.cities}{/if} - {#if cities.length > 0} -
- {#each cities as c} - - {c} - - - {/each} -
- {/if}
-
-
- - - {#if errors.date}{errors.date}{/if} + +
+ {#each ['solo','friends','family'] as t} + + {/each} +
+ {#if errors.tripType}{errors.tripType}{/if}
+
- - - {#if errors.days}{errors.days}{/if} + +
+ {#each transportOptions as opt} + + {/each} +
+ {#if errors.transport}{errors.transport}{/if}
-
-
- -
- - - + {:else if step === 2} +

Photos

+

Optional โ€” add or update photos from your trip

+ (photos = p)} /> + + {:else} +

How was it?

+

Optional โ€” write a note about your trip

+
+
+ + {wordCount} / {MEMO_MAX} words +
+
- {#if errors.tripType}{errors.tripType}{/if} -
+ {/if} -
- -
- {#each transportOptions as opt} - - {/each} -
- {#if errors.transport}{errors.transport}{/if} -
- - (photos = p)} /> - -
-
- - {wordCount} / {MEMO_MAX} words -
- -
- - - +
diff --git a/src/lib/timeline/view/ShareCard.svelte b/src/lib/timeline/view/ShareCard.svelte index 985c2ce..958566a 100644 --- a/src/lib/timeline/view/ShareCard.svelte +++ b/src/lib/timeline/view/ShareCard.svelte @@ -1,5 +1,7 @@