feat(ui): mobile-first redesign — compact hero, inline submit button, map-first with collapsible list
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

- Hero: remove full-width mobile submit, add inline "Go" button next to locate
- Prediction cards: tighter mobile padding (px-3 py-3)
- Search filters: right-aligned toolbar, remove "X stations found" count and map toggle
- Map: initialize view immediately to avoid tile wiggle, skip recenter on fresh init
- Station list: hidden by default, toggled via "Stations {count}" pill above map
- Typography: hide desktop h1 on mobile, scale down section headings and spacing
- Footer: remove uppercase styling from headings and copyright line
- Filter popover: auto-close on fuel/radius/sort/brand selection

fix(llm): retry submit_overlay when events_cited is missing, extend Fuel Finder timeout with retries

- LlmOverlayService: add `minItems: 1` to events_cited schema, detect missing citations
  in submit response, inject tool_result error and retry once with explicit prompt
- Log full raw_result context when no verified citations, capturing direction/confidence/reasoning
- FuelPriceService: add 3×1s retry with 60s timeout to batch price requests (was 30s no retry)
- Tests: cover successful retry recovery and rejection when retry also omits citations
This commit is contained in:
Ovidiu U
2026-05-14 13:23:52 +01:00
parent 11a3b433ff
commit 97e27fc057
10 changed files with 302 additions and 87 deletions

View File

@@ -204,6 +204,20 @@ function initMap() {
// map-polish:7 — replace default attribution control with custom ⓘ button
mapInstance = L.map(mapContainer.value, {zoomControl: false, attributionControl: false})
// Set the initial view immediately so tiles load at the correct spot from
// frame 1 — avoids the "wiggle" caused by setView running after the
// container is already laid out and tiles are mid-load.
const initialZoom = getZoomForRadius(props.radiusMiles)
const initialCenter = props.origin?.lat != null && props.origin?.lng != null
? [props.origin.lat, props.origin.lng]
: props.stations.length
? [props.stations[0].lat, props.stations[0].lng]
: null
if (initialCenter) {
mapInstance.setView(initialCenter, initialZoom)
hasInitialView = true
}
// map-polish:5 — Carto Positron tile (cleaner than raw OSM)
L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
subdomains: 'abcd',
@@ -230,7 +244,7 @@ function initMap() {
locateUser()
}
function renderMarkers() {
function renderMarkers({skipRecenter = false} = {}) {
if (!mapInstance || !markersLayer) return
markersLayer.clearLayers()
@@ -262,6 +276,8 @@ function renderMarkers() {
bounds.push([station.lat, station.lng])
})
if (skipRecenter) return
const zoom = getZoomForRadius(props.radiusMiles)
const center = props.origin?.lat != null && props.origin?.lng != null
? [props.origin.lat, props.origin.lng]
@@ -290,9 +306,10 @@ function destroyMap() {
async function openMap() {
await nextTick()
const wasFreshInit = !mapInstance
initMap()
mapInstance?.invalidateSize()
renderMarkers()
renderMarkers({skipRecenter: wasFreshInit})
}
onMounted(() => {