mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-07-23 14:59:36 +02:00
feat: Add TimezoneSelector component and integrate Luxon for date handling
This commit is contained in:
parent
7499722867
commit
6942f5e1bb
4 changed files with 221 additions and 48 deletions
|
@ -43,6 +43,7 @@
|
||||||
"dompurify": "^3.2.4",
|
"dompurify": "^3.2.4",
|
||||||
"emoji-picker-element": "^1.26.0",
|
"emoji-picker-element": "^1.26.0",
|
||||||
"gsap": "^3.12.7",
|
"gsap": "^3.12.7",
|
||||||
|
"luxon": "^3.6.1",
|
||||||
"marked": "^15.0.4",
|
"marked": "^15.0.4",
|
||||||
"psl": "^1.15.0",
|
"psl": "^1.15.0",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
|
|
9
frontend/pnpm-lock.yaml
generated
9
frontend/pnpm-lock.yaml
generated
|
@ -23,6 +23,9 @@ importers:
|
||||||
gsap:
|
gsap:
|
||||||
specifier: ^3.12.7
|
specifier: ^3.12.7
|
||||||
version: 3.12.7
|
version: 3.12.7
|
||||||
|
luxon:
|
||||||
|
specifier: ^3.6.1
|
||||||
|
version: 3.6.1
|
||||||
marked:
|
marked:
|
||||||
specifier: ^15.0.4
|
specifier: ^15.0.4
|
||||||
version: 15.0.4
|
version: 15.0.4
|
||||||
|
@ -1469,6 +1472,10 @@ packages:
|
||||||
lru-queue@0.1.0:
|
lru-queue@0.1.0:
|
||||||
resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==}
|
resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==}
|
||||||
|
|
||||||
|
luxon@3.6.1:
|
||||||
|
resolution: {integrity: sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
magic-string@0.30.10:
|
magic-string@0.30.10:
|
||||||
resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
|
resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
|
||||||
|
|
||||||
|
@ -3514,6 +3521,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
es5-ext: 0.10.64
|
es5-ext: 0.10.64
|
||||||
|
|
||||||
|
luxon@3.6.1: {}
|
||||||
|
|
||||||
magic-string@0.30.10:
|
magic-string@0.30.10:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.4.15
|
'@jridgewell/sourcemap-codec': 1.4.15
|
||||||
|
|
92
frontend/src/lib/components/TimezoneSelector.svelte
Normal file
92
frontend/src/lib/components/TimezoneSelector.svelte
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { t } from 'svelte-i18n';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
export let selectedTimezone: string = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||||
|
|
||||||
|
let dropdownOpen = false;
|
||||||
|
let searchQuery = '';
|
||||||
|
const timezones = Intl.supportedValuesOf('timeZone');
|
||||||
|
|
||||||
|
// Filter timezones based on search query
|
||||||
|
$: filteredTimezones = searchQuery
|
||||||
|
? timezones.filter((tz) => tz.toLowerCase().includes(searchQuery.toLowerCase()))
|
||||||
|
: timezones;
|
||||||
|
|
||||||
|
function selectTimezone(tz: string) {
|
||||||
|
selectedTimezone = tz;
|
||||||
|
dropdownOpen = false;
|
||||||
|
searchQuery = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close dropdown if clicked outside
|
||||||
|
onMount(() => {
|
||||||
|
const handleClickOutside = (e: MouseEvent) => {
|
||||||
|
const dropdown = document.getElementById('tz-selector');
|
||||||
|
if (dropdown && !dropdown.contains(e.target as Node)) dropdownOpen = false;
|
||||||
|
};
|
||||||
|
document.addEventListener('click', handleClickOutside);
|
||||||
|
return () => document.removeEventListener('click', handleClickOutside);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="form-control w-full max-w-xs relative" id="tz-selector">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text">Timezone</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<!-- Trigger -->
|
||||||
|
<div
|
||||||
|
tabindex="0"
|
||||||
|
role="button"
|
||||||
|
class="input input-bordered flex justify-between items-center cursor-pointer"
|
||||||
|
on:click={() => (dropdownOpen = !dropdownOpen)}
|
||||||
|
>
|
||||||
|
<span class="truncate">{selectedTimezone}</span>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="w-4 h-4"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
>
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Dropdown -->
|
||||||
|
{#if dropdownOpen}
|
||||||
|
<div
|
||||||
|
class="absolute mt-1 z-10 bg-base-100 shadow-lg rounded-box w-full max-h-60 overflow-y-auto"
|
||||||
|
>
|
||||||
|
<!-- Search -->
|
||||||
|
<div class="sticky top-0 bg-base-100 p-2 border-b">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Search timezone"
|
||||||
|
class="input input-sm input-bordered w-full"
|
||||||
|
bind:value={searchQuery}
|
||||||
|
autofocus
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Timezone list -->
|
||||||
|
{#if filteredTimezones.length > 0}
|
||||||
|
<ul class="menu p-2 space-y-1">
|
||||||
|
{#each filteredTimezones as tz}
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
class={`truncate ${tz === selectedTimezone ? 'active font-bold' : ''}`}
|
||||||
|
on:click|preventDefault={() => selectTimezone(tz)}
|
||||||
|
>
|
||||||
|
{tz}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
{:else}
|
||||||
|
<div class="p-2 text-sm text-center opacity-60">No timezones found</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
|
@ -6,36 +6,53 @@
|
||||||
import { addToast } from '$lib/toasts';
|
import { addToast } from '$lib/toasts';
|
||||||
let modal: HTMLDialogElement;
|
let modal: HTMLDialogElement;
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
// @ts-ignore
|
||||||
|
import { DateTime } from 'luxon';
|
||||||
|
|
||||||
|
// Initialize with browser's timezone
|
||||||
|
let selectedTimezone: string = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||||
|
|
||||||
|
// Store the UTC dates as source of truth
|
||||||
|
let utcStartDate: string | null = null;
|
||||||
|
let utcEndDate: string | null = null;
|
||||||
|
|
||||||
|
// Local display values
|
||||||
|
let localStartDate: string = '';
|
||||||
|
let localEndDate: string = '';
|
||||||
|
|
||||||
import MarkdownEditor from './MarkdownEditor.svelte';
|
import MarkdownEditor from './MarkdownEditor.svelte';
|
||||||
import { appVersion } from '$lib/config';
|
import { appVersion } from '$lib/config';
|
||||||
import { DefaultMarker, MapLibre } from 'svelte-maplibre';
|
import { DefaultMarker, MapLibre } from 'svelte-maplibre';
|
||||||
|
import TimezoneSelector from './TimezoneSelector.svelte';
|
||||||
|
|
||||||
export let collection: Collection;
|
export let collection: Collection;
|
||||||
export let transportationToEdit: Transportation | null = null;
|
export let transportationToEdit: Transportation | null = null;
|
||||||
|
|
||||||
let constrainDates: boolean = false;
|
let constrainDates: boolean = false;
|
||||||
|
|
||||||
// Format date as local datetime
|
// Convert a UTC ISO date to a datetime-local value in the specified timezone
|
||||||
// Convert an ISO date to a datetime-local value in local time.
|
function toLocalDatetime(utcDate: string | null, timezone: string = selectedTimezone): string {
|
||||||
function toLocalDatetime(value: string | null): string {
|
if (!utcDate) return '';
|
||||||
if (!value) return '';
|
return DateTime.fromISO(utcDate, { zone: 'UTC' })
|
||||||
const date = new Date(value);
|
.setZone(timezone)
|
||||||
// Adjust the time by subtracting the timezone offset.
|
.toISO({ suppressSeconds: true, includeOffset: false })
|
||||||
date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
|
.slice(0, 16);
|
||||||
// Return format YYYY-MM-DDTHH:mm
|
|
||||||
return date.toISOString().slice(0, 16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert a local datetime to UTC
|
||||||
|
function toUTCDatetime(localDate: string, timezone: string = selectedTimezone): string | null {
|
||||||
|
if (!localDate) return null;
|
||||||
|
return DateTime.fromISO(localDate, { zone: timezone }).toUTC().toISO();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize transportation object
|
||||||
let transportation: Transportation = {
|
let transportation: Transportation = {
|
||||||
id: transportationToEdit?.id || '',
|
id: transportationToEdit?.id || '',
|
||||||
type: transportationToEdit?.type || '',
|
type: transportationToEdit?.type || '',
|
||||||
name: transportationToEdit?.name || '',
|
name: transportationToEdit?.name || '',
|
||||||
description: transportationToEdit?.description || '',
|
description: transportationToEdit?.description || '',
|
||||||
date: transportationToEdit?.date ? toLocalDatetime(transportationToEdit.date) : null,
|
date: null,
|
||||||
end_date: transportationToEdit?.end_date
|
end_date: null,
|
||||||
? toLocalDatetime(transportationToEdit.end_date)
|
|
||||||
: null,
|
|
||||||
rating: transportationToEdit?.rating || 0,
|
rating: transportationToEdit?.rating || 0,
|
||||||
link: transportationToEdit?.link || '',
|
link: transportationToEdit?.link || '',
|
||||||
flight_number: transportationToEdit?.flight_number || '',
|
flight_number: transportationToEdit?.flight_number || '',
|
||||||
|
@ -69,13 +86,44 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(transportation);
|
// Update local display dates whenever timezone or UTC dates change
|
||||||
|
$: {
|
||||||
|
if (utcStartDate) {
|
||||||
|
localStartDate = toLocalDatetime(utcStartDate, selectedTimezone);
|
||||||
|
}
|
||||||
|
if (utcEndDate) {
|
||||||
|
localEndDate = toLocalDatetime(utcEndDate, selectedTimezone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicitly watch for timezone changes to update displayed dates
|
||||||
|
$: {
|
||||||
|
// This will trigger whenever selectedTimezone changes
|
||||||
|
selectedTimezone;
|
||||||
|
if (utcStartDate) {
|
||||||
|
localStartDate = toLocalDatetime(utcStartDate);
|
||||||
|
}
|
||||||
|
if (utcEndDate) {
|
||||||
|
localEndDate = toLocalDatetime(utcEndDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
modal = document.getElementById('my_modal_1') as HTMLDialogElement;
|
modal = document.getElementById('my_modal_1') as HTMLDialogElement;
|
||||||
if (modal) {
|
if (modal) {
|
||||||
modal.showModal();
|
modal.showModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize UTC dates from transportationToEdit if available
|
||||||
|
if (transportationToEdit?.date) {
|
||||||
|
utcStartDate = transportationToEdit.date;
|
||||||
|
localStartDate = toLocalDatetime(utcStartDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transportationToEdit?.end_date) {
|
||||||
|
utcEndDate = transportationToEdit.end_date;
|
||||||
|
localEndDate = toLocalDatetime(utcEndDate);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
|
@ -88,6 +136,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update UTC dates when local dates change
|
||||||
|
function updateUTCDates() {
|
||||||
|
utcStartDate = localStartDate ? toUTCDatetime(localStartDate) : null;
|
||||||
|
utcEndDate = localEndDate ? toUTCDatetime(localEndDate) : null;
|
||||||
|
}
|
||||||
|
|
||||||
async function geocode(e: Event | null) {
|
async function geocode(e: Event | null) {
|
||||||
if (e) {
|
if (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -172,47 +226,56 @@
|
||||||
Math.round(transportation.destination_longitude * 1e6) / 1e6;
|
Math.round(transportation.destination_longitude * 1e6) / 1e6;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transportation.end_date && !transportation.date) {
|
// Validate dates
|
||||||
transportation.date = null;
|
if (localEndDate && !localStartDate) {
|
||||||
transportation.end_date = null;
|
addToast('error', $t('adventures.start_date_required'));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transportation.date && !transportation.end_date) {
|
if (localStartDate && !localEndDate) {
|
||||||
transportation.end_date = transportation.date;
|
// If only start date is provided, set end date to the same value
|
||||||
|
localEndDate = localStartDate;
|
||||||
|
utcEndDate = utcStartDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
transportation.date &&
|
localStartDate &&
|
||||||
transportation.end_date &&
|
localEndDate &&
|
||||||
transportation.date > transportation.end_date
|
DateTime.fromISO(localStartDate).toMillis() > DateTime.fromISO(localEndDate).toMillis()
|
||||||
) {
|
) {
|
||||||
addToast('error', $t('adventures.start_before_end_error'));
|
addToast('error', $t('adventures.start_before_end_error'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert local dates to UTC
|
// Use the stored UTC dates for submission
|
||||||
if (transportation.date && !transportation.date.includes('Z')) {
|
const submissionData = {
|
||||||
transportation.date = new Date(transportation.date).toISOString();
|
...transportation,
|
||||||
}
|
date: utcStartDate,
|
||||||
if (transportation.end_date && !transportation.end_date.includes('Z')) {
|
end_date: utcEndDate
|
||||||
transportation.end_date = new Date(transportation.end_date).toISOString();
|
};
|
||||||
}
|
|
||||||
|
|
||||||
if (transportation.type != 'plane') {
|
if (transportation.type != 'plane') {
|
||||||
transportation.flight_number = '';
|
submissionData.flight_number = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transportation.id === '') {
|
if (submissionData.id === '') {
|
||||||
let res = await fetch('/api/transportations', {
|
let res = await fetch('/api/transportations', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify(transportation)
|
body: JSON.stringify(submissionData)
|
||||||
});
|
});
|
||||||
let data = await res.json();
|
let data = await res.json();
|
||||||
if (data.id) {
|
if (data.id) {
|
||||||
transportation = data as Transportation;
|
transportation = data as Transportation;
|
||||||
|
// Update the UTC dates with the values from the server
|
||||||
|
utcStartDate = data.date;
|
||||||
|
utcEndDate = data.end_date;
|
||||||
|
// Update displayed dates
|
||||||
|
localStartDate = toLocalDatetime(utcStartDate);
|
||||||
|
localEndDate = toLocalDatetime(utcEndDate);
|
||||||
|
|
||||||
addToast('success', $t('adventures.adventure_created'));
|
addToast('success', $t('adventures.adventure_created'));
|
||||||
dispatch('save', transportation);
|
dispatch('save', transportation);
|
||||||
} else {
|
} else {
|
||||||
|
@ -225,11 +288,18 @@
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify(transportation)
|
body: JSON.stringify(submissionData)
|
||||||
});
|
});
|
||||||
let data = await res.json();
|
let data = await res.json();
|
||||||
if (data.id) {
|
if (data.id) {
|
||||||
transportation = data as Transportation;
|
transportation = data as Transportation;
|
||||||
|
// Update the UTC dates with the values from the server
|
||||||
|
utcStartDate = data.date;
|
||||||
|
utcEndDate = data.end_date;
|
||||||
|
// Update displayed dates
|
||||||
|
localStartDate = toLocalDatetime(utcStartDate);
|
||||||
|
localEndDate = toLocalDatetime(utcEndDate);
|
||||||
|
|
||||||
addToast('success', $t('adventures.adventure_updated'));
|
addToast('success', $t('adventures.adventure_updated'));
|
||||||
dispatch('save', transportation);
|
dispatch('save', transportation);
|
||||||
} else {
|
} else {
|
||||||
|
@ -385,6 +455,7 @@
|
||||||
{$t('adventures.date_information')}
|
{$t('adventures.date_information')}
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
|
<TimezoneSelector bind:selectedTimezone />
|
||||||
<!-- Start Date -->
|
<!-- Start Date -->
|
||||||
<div>
|
<div>
|
||||||
<label for="date">
|
<label for="date">
|
||||||
|
@ -409,7 +480,8 @@
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
id="date"
|
id="date"
|
||||||
name="date"
|
name="date"
|
||||||
bind:value={transportation.date}
|
bind:value={localStartDate}
|
||||||
|
on:change={updateUTCDates}
|
||||||
min={constrainDates ? fullStartDate : ''}
|
min={constrainDates ? fullStartDate : ''}
|
||||||
max={constrainDates ? fullEndDate : ''}
|
max={constrainDates ? fullEndDate : ''}
|
||||||
class="input input-bordered w-full max-w-xs mt-1"
|
class="input input-bordered w-full max-w-xs mt-1"
|
||||||
|
@ -417,7 +489,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- End Date -->
|
<!-- End Date -->
|
||||||
{#if transportation.date}
|
{#if localStartDate}
|
||||||
<div>
|
<div>
|
||||||
<label for="end_date">
|
<label for="end_date">
|
||||||
{$t('adventures.end_date')}
|
{$t('adventures.end_date')}
|
||||||
|
@ -427,9 +499,10 @@
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
id="end_date"
|
id="end_date"
|
||||||
name="end_date"
|
name="end_date"
|
||||||
min={constrainDates ? transportation.date : ''}
|
min={constrainDates ? localStartDate : ''}
|
||||||
max={constrainDates ? fullEndDate : ''}
|
max={constrainDates ? fullEndDate : ''}
|
||||||
bind:value={transportation.end_date}
|
bind:value={localEndDate}
|
||||||
|
on:change={updateUTCDates}
|
||||||
class="input input-bordered w-full max-w-xs mt-1"
|
class="input input-bordered w-full max-w-xs mt-1"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -451,13 +524,17 @@
|
||||||
</svg>
|
</svg>
|
||||||
<span>
|
<span>
|
||||||
{$t('lodging.current_timezone')}:
|
{$t('lodging.current_timezone')}:
|
||||||
{(() => {
|
{selectedTimezone}
|
||||||
const tz = new Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
||||||
const [continent, city] = tz.split('/');
|
|
||||||
return `${continent} (${city.replace('_', ' ')})`;
|
|
||||||
})()}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
{#if utcStartDate}
|
||||||
|
<div class="text-sm mt-2">
|
||||||
|
UTC Time: {DateTime.fromISO(utcStartDate).toISO().slice(0, 16).replace('T', ' ')}
|
||||||
|
{#if utcEndDate && utcEndDate !== utcStartDate}
|
||||||
|
to {DateTime.fromISO(utcEndDate).toISO().slice(0, 16).replace('T', ' ')}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -585,11 +662,6 @@
|
||||||
class="relative aspect-[9/16] max-h-[70vh] w-full sm:aspect-video sm:max-h-full rounded-lg"
|
class="relative aspect-[9/16] max-h-[70vh] w-full sm:aspect-video sm:max-h-full rounded-lg"
|
||||||
standardControls
|
standardControls
|
||||||
>
|
>
|
||||||
<!-- MapEvents gives you access to map events even from other components inside the map,
|
|
||||||
where you might not have access to the top-level `MapLibre` component. In this case
|
|
||||||
it would also work to just use on:click on the MapLibre component itself. -->
|
|
||||||
<!-- @ts-ignore -->
|
|
||||||
|
|
||||||
{#if transportation.origin_latitude && transportation.origin_longitude}
|
{#if transportation.origin_latitude && transportation.origin_longitude}
|
||||||
<DefaultMarker
|
<DefaultMarker
|
||||||
lngLat={[transportation.origin_longitude, transportation.origin_latitude]}
|
lngLat={[transportation.origin_longitude, transportation.origin_latitude]}
|
||||||
|
@ -604,7 +676,6 @@ it would also work to just use on:click on the MapLibre component itself. -->
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</MapLibre>
|
</MapLibre>
|
||||||
<!-- button to clear to and from location -->
|
|
||||||
</div>
|
</div>
|
||||||
{#if transportation.from_location || transportation.to_location}
|
{#if transportation.from_location || transportation.to_location}
|
||||||
<button
|
<button
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue