feat: add geolocation support with Near Me button and user location marker on map
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.3) (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled

- Add "Near Me" button to SearchBar with loading state and geolocation via postcodes.io API
- Display user location on map with pulsing blue marker using geolocation API with IP fallback
- Adjust map zoom level based on search radius for better context
- Pass radiusMiles prop from
This commit is contained in:
Ovidiu U
2026-04-11 21:27:11 +01:00
parent a969c1b347
commit d25883ead4
3 changed files with 254 additions and 117 deletions

View File

@@ -4,17 +4,24 @@
<div class="flex flex-col sm:flex-row gap-3">
<div class="relative flex-1">
<label for="postcode-input" class="sr-only">Postcode or city</label>
<span aria-hidden="true"
class="absolute right-4 top-1/2 -translate-y-1/2 text-zinc-500 p-4"
>
<iconify-icon icon="lucide:map-pin" style="font-size:1.25rem"></iconify-icon>
</span>
<button
:disabled="locating"
aria-label="Use my location"
class="absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-1.5 px-3 py-1.5
bg-primary/85
text-white rounded-sm text-sm font-semibold transition-opacity hover:opacity-80"
type="button"
@click="useMyLocation"
>
<iconify-icon :class="{ 'animate-spin': locating }" :icon="locating ? 'lucide:loader-circle' : 'lucide:map-pin'" style="font-size:1rem"></iconify-icon>
<span class="hidden md:inline-flex">Near me</span>
</button>
<input
id="postcode-input"
v-model="postcode"
type="text"
placeholder="Enter postcode, e.g. SW1A 1AA"
class="w-full h-14 pr-12 pl-4 bg-white border border-zinc-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-accent shadow-inner text-base"
class="w-full h-14 pr-28 pl-4 bg-white border border-zinc-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-accent shadow-inner text-base"
@keyup.enter="onSearch"
/>
</div>
@@ -75,6 +82,28 @@ const postcode = ref('')
const fuelType = ref('e10')
const radius = ref(10)
const sort = ref('price')
const locating = ref(false)
function useMyLocation() {
if (!navigator.geolocation) return
locating.value = true
navigator.geolocation.getCurrentPosition(
async ({ coords }) => {
try {
const res = await fetch(`https://api.postcodes.io/postcodes?lon=${coords.longitude}&lat=${coords.latitude}&limit=1`)
const json = await res.json()
if (json.result?.[0]?.postcode) {
postcode.value = json.result[0].postcode
onSearch()
}
} finally {
locating.value = false
}
},
() => { locating.value = false },
{ timeout: 8000, enableHighAccuracy: false, maximumAge: 30000 },
)
}
function onSearch() {
if (!postcode.value.trim()) return