diff options
| author | Adam Soltys <[email protected]> | 2026-02-27 11:44:26 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-02-27 11:44:26 -0800 |
| commit | cb1b9276c878017357a6ef5569e9a53fcbd8fae5 (patch) | |
| tree | b7cbea00f3e997404838196280ef1e14b2d36c74 /src | |
| parent | f24c32376a7d6085e095a58ded4122748ec5bd2f (diff) | |
| download | coinos-ui-cb1b9276c878017357a6ef5569e9a53fcbd8fae5.tar.gz coinos-ui-cb1b9276c878017357a6ef5569e9a53fcbd8fae5.zip | |
map fixes
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/LocationsMap.svelte | 113 |
1 files changed, 29 insertions, 84 deletions
diff --git a/src/components/LocationsMap.svelte b/src/components/LocationsMap.svelte index 2f942e85..279c477f 100644 --- a/src/components/LocationsMap.svelte +++ b/src/components/LocationsMap.svelte @@ -13,8 +13,6 @@ let search: string = $state(""); let clearSearch = (e: any) => (search = ""); - let currentIndex = -1; - let timeout: any = $state(); let full = () => { if (!document.fullscreenElement) { @@ -56,49 +54,38 @@ let selected = $state(); function select(m: any) { selected = m; - stopFlying(); - currentIndex = inview.indexOf(m); - flyToMarker(m, 500); - } - - async function flyToMarker(marker, duration = 1500) { - if (!marker) return; + if (m.category && !activeFilters.has(m.category)) { + activeFilters.add(m.category); + activeFilters = new Set(activeFilters); + } map.flyTo({ zoom: 12, - center: marker.getLngLat(), + center: m.getLngLat(), essential: true, - easing: function (t) { - return 1 - Math.pow(1 - t, 3); - }, - duration, + duration: 500, }); - - await new Promise((r) => setTimeout(r, duration)); - marker.getElement().style.display = ""; - marker.getElement().click(); - updateLabelVisibility(); - await new Promise((r) => setTimeout(r, 2500)); - - if (!timeout) return; + setTimeout(() => { + m.getElement().style.display = ""; + m.getElement().click(); + updateLabelVisibility(); + }, 500); } - let toggle = () => { - if (timeout) stopFlying(); - else startFlying(); - }; - let toggleList = () => { showList = !showList; showFilters = false; if (showList) scrollToFirstActive(); }; + function scrollToCategory(el: Element | null) { + if (el) el.scrollIntoView({ block: "start" }); + } + function scrollToFirstActive() { tick().then(() => { let target = lastToggledOn && activeFilters.has(lastToggledOn) ? lastToggledOn : activeFilters.values().next().value; if (!target) return; - let el = document.querySelector(`[data-category="${target}"]`); - if (el) el.scrollIntoView({ block: "start" }); + scrollToCategory(document.querySelector(`[data-category="${target}"]`)); }); } let showList = $state(true); @@ -146,7 +133,8 @@ if (turningOn) { tick().then(() => { let el = document.querySelector(`[data-category="${slug}"]`); - if (el) el.scrollIntoView({ block: "start" }); + if (!el) el = document.querySelector(`[data-category]`); + scrollToCategory(el); }); } } @@ -172,17 +160,6 @@ updateClusterSource(); }); - let currentPopup; - function startFlying() { - currentIndex++; - - for (let p in popups) popups[p].remove(); - if (currentIndex >= inview.length) currentIndex = 0; - flyToMarker(inview[currentIndex]); - - timeout = setTimeout(startFlying, 4000); - } - function debounce(func: any, delay: any) { let timeout: any; let immediate = true; @@ -203,20 +180,6 @@ }; } - function stopFlying() { - updateLabelVisibility(); - if (!timeout) return; - clearTimeout(timeout); - timeout = undefined; - - if (currentPopup) { - currentPopup.remove(); - } - - map.jumpTo({ center: map.getCenter(), zoom: map.getZoom() }); - map.off("moveend"); - } - let inview: any[] = $state([]); function syncMarkerVisibility() { @@ -250,7 +213,7 @@ marker.getElement().style.display = passesFilter ? "" : "none"; } - if (isInView && passesFilter) inview.push(marker); + if (isInView) inview.push(marker); } inview = inview.sort((a, b) => a.tags.name.localeCompare(b.tags.name)); @@ -338,7 +301,7 @@ let marker = new maplibre.Marker({ element: createCategoryMarker(tags) }) .setLngLat([lon, lat]) - .setPopup(new maplibre.Popup().setDOMContent(popupContainer)) + .setPopup(new maplibre.Popup({ offset: [0, -46] }).setDOMContent(popupContainer)) .addTo(map); marker.id = counter++; @@ -581,11 +544,6 @@ map.on("moveend", fetchOnMove); }); - map.on("mousedown", stopFlying); - map.on("touchstart", stopFlying); - map.on("wheel", stopFlying); - map.on("dragstart", stopFlying); - let resize = () => map && map.resize(); document.addEventListener("fullscreenchange", resize, false); @@ -609,7 +567,7 @@ let categoryLabelMap = Object.fromEntries(categoryLabels.map((c) => [c.slug, c.name])); let presentCategories = $derived( - categoryLabels.filter((c) => markers.some((m) => m.category === c.slug)), + categoryLabels.filter((c) => inview.some((m) => m.category === c.slug)), ); let allList = $derived( @@ -647,12 +605,10 @@ </div> <div class="relative"> {#if showList} - <div - class="space-y-1 text-sm w-[300px] max-w-[calc(100vw*0.5)] h-[300px] max-h-[calc(100vh*0.4)] overflow-y-scroll p-4 bg-base-100/90 absolute right-4 bottom-8 rounded-2xl shadow text-ellipsis overflow-x-hidden" - > - <div class="relative mb-4 sticky top-0 bg-base-100/90 z-10"> - <input bind:value={search} placeholder="Search locations..." class="w-full border border-base-300 rounded-lg pl-3 pr-8 py-2" /> - <div class="flex items-center absolute right-2 top-1/2 -translate-y-1/2"> + <div class="flex flex-col w-[300px] max-w-[calc(100vw*0.5)] absolute right-4 bottom-8 bg-base-100/90 rounded-2xl shadow overflow-hidden"> + <div class="relative p-3"> + <input bind:value={search} placeholder="Search locations..." class="w-full border border-base-300 rounded-lg pl-3 pr-8 py-2 text-sm" /> + <div class="flex items-center absolute right-5 top-1/2 -translate-y-1/2"> {#if search} <button type="button" onclick={clearSearch} aria-label="Clear"> <iconify-icon noobserver icon="ph:x-bold" width="20"></iconify-icon> @@ -662,7 +618,7 @@ {/if} </div> </div> - + <div class="space-y-1 text-sm h-[250px] max-h-[calc(100vh*0.35)] overflow-y-scroll px-4 pb-4 text-ellipsis overflow-x-hidden"> {#each groupedList as group} {@const active = activeFilters.has(group.slug)} <button @@ -686,12 +642,12 @@ class:selected={selected === marker} class="block whitespace-nowrap text-ellipsis text-left w-full overflow-hidden pl-5 transition-opacity" class:opacity-30={!active} - disabled={!active} > {marker.tags.name} </button> {/each} {/each} + </div> </div> {/if} {#if showFilters} @@ -731,30 +687,19 @@ {/if} <div class="absolute flex top-2 right-2 gap-2"> <button - class="rounded-full border-2 border-primary bg-base-100/80 w-16 h-16 flex items-center justify-center" + class="rounded-full border-2 border-primary w-16 h-16 flex items-center justify-center {showFilters ? 'bg-primary text-white' : 'bg-base-100/80'}" onclick={toggleFilters} aria-label="Filter categories" > <iconify-icon noobserver icon="ph:funnel-bold" width="24"></iconify-icon> </button> <button - class="rounded-full border-2 border-primary bg-base-100/80 w-16 h-16 flex items-center justify-center" + class="rounded-full border-2 border-primary w-16 h-16 flex items-center justify-center {showList ? 'bg-primary text-white' : 'bg-base-100/80'}" onclick={toggleList} aria-label="Toggle location list" > <iconify-icon noobserver icon="ph:list-bold" width="24"></iconify-icon> </button> - <button - class="rounded-full border-2 border-primary bg-base-100/80 w-16 h-16 flex items-center justify-center" - onclick={toggle} - aria-label={timeout ? "Resume map" : "Pause map"} - > - {#if timeout} - <iconify-icon noobserver icon="ph:pause-bold" width="24"></iconify-icon> - {:else} - <iconify-icon noobserver icon="ph:play-bold" width="24"></iconify-icon> - {/if} - </button> </div> </div> </div> |
