- Extract LandingNav, LiveTicker, StatsRow, VerdictCard, and HeroSearch into reusable landing components - Implement responsive two-layout strategy: mobile stacked (hero search + verdict card + CTA) vs desktop inline pill input with verdict card sidebar - Add serif/mono font tokens and live-dot pulse animation to CSS - Move verdict card above search input on mobile, to right sidebar on desktop - Replace hero "fill up now" mockup with dynamic VerdictCard showing top stations, pricing, and recommendation - Simplify navigation with uppercase tracking, add Fleet anchor, and gate CTA by auth state - Lazy-load LeafletMap with defineAsyncComponent to reduce initial bundle - Relocate SearchBar below hero on search attempt for persistent filter UI - Add meta description for SEO
46 lines
1.5 KiB
Vue
46 lines
1.5 KiB
Vue
<template>
|
|
<div class="inline-flex items-center gap-2 font-mono text-[11px] uppercase tracking-[0.15em] text-zinc-600">
|
|
<span class="size-1.5 rounded-full bg-status-good live-dot"></span>
|
|
<span class="font-medium">Live</span>
|
|
<span v-if="stationCount" aria-hidden="true">·</span>
|
|
<span v-if="stationCount">{{ formattedStationCount }} UK stations</span>
|
|
<span aria-hidden="true">·</span>
|
|
<span>updated {{ updatedAgo || '…' }}</span>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
|
|
|
const props = defineProps({
|
|
stationCount: { type: Number, default: null },
|
|
latestPriceAt: { type: String, default: null },
|
|
})
|
|
|
|
const now = ref(Date.now())
|
|
let ticker = null
|
|
|
|
const formattedStationCount = computed(() => {
|
|
return props.stationCount == null ? '' : props.stationCount.toLocaleString('en-GB')
|
|
})
|
|
|
|
const updatedAgo = computed(() => {
|
|
if (!props.latestPriceAt) return ''
|
|
const diffMin = Math.floor((now.value - new Date(props.latestPriceAt).getTime()) / 60000)
|
|
if (diffMin < 1) return 'just now'
|
|
if (diffMin < 60) return `${diffMin} min ago`
|
|
const hours = Math.floor(diffMin / 60)
|
|
if (hours < 24) return `${hours} hr ago`
|
|
const days = Math.floor(hours / 24)
|
|
return `${days} day${days === 1 ? '' : 's'} ago`
|
|
})
|
|
|
|
onMounted(() => {
|
|
ticker = setInterval(() => { now.value = Date.now() }, 60000)
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
if (ticker) clearInterval(ticker)
|
|
})
|
|
</script>
|