mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 05:06:55 +04:00
108 lines
4.7 KiB
Plaintext
108 lines
4.7 KiB
Plaintext
---
|
|
// A list of stores next to a map: picking a store moves the map and opens its popup.
|
|
import Map from '../demo/Map.astro'
|
|
import CaptureScript from '../CaptureScript.astro'
|
|
import Badge from '@ui/Badge.astro'
|
|
import Card from '@ui/Card.astro'
|
|
import CardHeader from '@ui/CardHeader.astro'
|
|
import CardTitle from '@ui/CardTitle.astro'
|
|
import Icon from '@ui/Icon.astro'
|
|
|
|
const stores = [
|
|
{ name: 'Tabler Store Mitte', address: 'Friedrichstraße 112, 10117 Berlin', distance: '0.4 km', open: true, lng: 13.3889, lat: 52.5246 },
|
|
{ name: 'Tabler Store Alexanderplatz', address: 'Karl-Liebknecht-Straße 9, 10178 Berlin', distance: '1.2 km', open: true, lng: 13.4094, lat: 52.5219 },
|
|
{ name: 'Tabler Store Kreuzberg', address: 'Oranienstraße 34, 10999 Berlin', distance: '2.6 km', open: true, lng: 13.4197, lat: 52.5009 },
|
|
{ name: 'Tabler Store Charlottenburg', address: 'Kantstraße 54, 10627 Berlin', distance: '4.8 km', open: false, lng: 13.3087, lat: 52.5063 },
|
|
{ name: 'Tabler Store Prenzlauer Berg', address: 'Kastanienallee 21, 10435 Berlin', distance: '2.1 km', open: true, lng: 13.4098, lat: 52.5385 },
|
|
{ name: 'Tabler Store Friedrichshain', address: 'Warschauer Straße 58, 10243 Berlin', distance: '3.9 km', open: false, lng: 13.4492, lat: 52.5083 },
|
|
]
|
|
---
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Store locator</CardTitle>
|
|
</CardHeader>
|
|
<div class="row g-0">
|
|
<div class="col-lg-4 border-end">
|
|
<div class="p-3 border-bottom">
|
|
<div class="input-icon">
|
|
<span class="input-icon-addon"><Icon name="search" /></span>
|
|
<input type="search" class="form-control" id="stores-search" placeholder="Search stores…" aria-label="Search stores" />
|
|
</div>
|
|
</div>
|
|
<div class="list-group list-group-flush overflow-auto" id="stores-list" style="height: 24rem">
|
|
{
|
|
stores.map((store, index) => (
|
|
<button type="button" class:list={['list-group-item list-group-item-action', index === 0 && 'active']}>
|
|
<div class="d-flex align-items-center gap-2">
|
|
<span class="fw-medium">{store.name}</span>
|
|
<Badge color={store.open ? 'green' : 'secondary'} light class="ms-auto" text={store.open ? 'Open' : 'Closed'} />
|
|
</div>
|
|
<div class="text-secondary">{store.address}</div>
|
|
<div class="text-secondary small mt-1">
|
|
<Icon name="map-pin" class="icon-inline" /> {store.distance}
|
|
</div>
|
|
</button>
|
|
))
|
|
}
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-8">
|
|
<Map mapId="stores" title="Store locator" center={[52.519, 13.39]} zoom={11.3} height="28.5rem" rounded={false} controls>
|
|
{
|
|
stores.map((store) => (
|
|
<span class="map-marker map-marker-pin" data-bs-lng={store.lng} data-bs-lat={store.lat} data-bs-anchor="bottom">
|
|
<Icon name="map-pin" />
|
|
<template>
|
|
<div class="fw-medium">{store.name}</div>
|
|
<div class="text-secondary">{store.address}</div>
|
|
</template>
|
|
</span>
|
|
))
|
|
}
|
|
</Map>
|
|
</div>
|
|
</div>
|
|
<CaptureScript>
|
|
<script is:inline>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
// The markers are in the same order as the stores in the list
|
|
const { map, markers } = tabler.MapView.getInstance('#map-stores')
|
|
const items = [...document.querySelectorAll('#stores-list .list-group-item')]
|
|
|
|
const select = (index, move) => {
|
|
items.forEach((item, position) => item.classList.toggle('active', position === index))
|
|
markers.forEach((marker, position) => marker.getPopup().isOpen() !== (position === index) && marker.togglePopup())
|
|
|
|
if (move) {
|
|
map.flyTo({ center: markers[index].getLngLat(), zoom: 13 })
|
|
}
|
|
}
|
|
|
|
items.forEach((item, index) => item.addEventListener('click', () => select(index, true)))
|
|
markers.forEach((marker, index) =>
|
|
marker.getElement().addEventListener('click', (event) => {
|
|
event.stopPropagation()
|
|
select(index, false)
|
|
items[index].scrollIntoView({ block: 'nearest' })
|
|
}),
|
|
)
|
|
|
|
// Search hides the stores, and their markers, that do not match
|
|
document.getElementById('stores-search').addEventListener('input', (event) => {
|
|
const query = event.target.value.trim().toLowerCase()
|
|
|
|
items.forEach((item, index) => {
|
|
const hidden = !item.textContent.toLowerCase().includes(query)
|
|
|
|
item.hidden = hidden
|
|
markers[index].getElement().hidden = hidden
|
|
})
|
|
})
|
|
|
|
select(0, false)
|
|
})
|
|
</script>
|
|
</CaptureScript>
|
|
</Card>
|