trips/mock/index.html
Greg Pomerantz 1ba39f7333 Fix arrival/return transfer legs + plan restore + router guards
Transfers (airport<->hotel) were the app's weakest surface; this fixes the
long-standing cluster of bugs in one pass:

- saneRoute(): reject OSRM results implausible for the straight-line distance
  (extract coverage holes once produced a 9h 'route' for a 5km taxi hop);
  applied at every routePts call site
- healTransfers() on load: re-sync transfer endpoints against current hotel +
  AIRPORTS table, re-sync stays[] against the day-base hotel objects (the
  saved stays[] carried pre-coord-fix locations, and dayBase() resolves the
  hotel FROM stays — every return leg was routed to the stale hotel), drop
  implausible or endpoint-drifted stored routes so they re-route cleanly,
  default a missing mode to car, and recover arrLandingMin from the booked
  flight time
- the last-stop->hotel ride is now a first-class editable leg (retLeg): the
  rail row opens the route card with drag + walk/taxi toggle, exactly like
  stop-to-stop legs; previously auto-routed returns seed it
- startMin now actually tracks landing + drop-off (syncArrivalStart had a
  null arrLandingMin guard that silently froze the day's start)
- applySavedPlan re-points day: days becomes a new object tree on restore,
  and the current-day reference stayed on the stale base-plan day — the rail
  rendered the base plan instead of the saved one until a day-tab click
- setDay enriches the opened day (idempotent), so a day opened from a saved
  plan gets its legs (incl. the return leg) routed instead of sitting on
  straight-line estimates

Also in this change set: correct LLM model name, keyword-router removal (chat
goes to the LLM), screenshot_map + relocate_stop tools for the UI LLM,
server-side plan store with localStorage migration, thinking toggle +
keep-alive warm-up, three-state LLM guard with proactive model load,
spatial /near /nearest /corridor SQL fixes, and the full data.js
coordinate correction for the Colombia demo.
2026-09-10 22:46:07 -04:00

145 lines
6.2 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Trip</title>
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='.9em' font-size='90'%3E%F0%9F%97%BA%3C/text%3E%3C/svg%3E">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="map"></div>
<!-- ======================= LANDING ======================= -->
<section id="landing">
<div class="land-card">
<h1>Where would you like to go?</h1>
<div class="land-row">
<input id="dest" type="text" placeholder="A city, a region, a country… e.g. Florence" />
<button id="dest-go" class="btn primary">Plan it</button>
</div>
<div class="land-div"><span>or</span></div>
<div id="dropzone">
<div class="dz-icon">🎫</div>
<div class="dz-text"><b>Drop a travel booking to start</b><br>ticket, flight or hotel confirmation</div>
<button id="dz-sample" class="btn ghost small">or start from an example booking</button>
</div>
<div class="land-demo">
<span>or pick a trip</span>
<button class="chip" data-city="colombia">Colombia · Cartagena → Santa Marta <i>· live walking routing</i></button>
<button class="chip" data-city="boston">Boston <i>· live road routing</i></button>
<button class="chip" data-city="florence">Florence</button>
</div>
</div>
</section>
<!-- booking parse modal -->
<div id="parse-modal" class="modal hidden">
<div class="modal-card">
<h2>Parsed booking</h2>
<table id="parse-table"></table>
<div class="modal-actions">
<button class="btn ghost" id="parse-cancel">Cancel</button>
<button class="btn primary" id="parse-confirm">Build plan around it</button>
</div>
</div>
</div>
<!-- ======================= APP ======================= -->
<header id="topbar" class="hidden">
<div class="tb-left">
<div class="trip-picker" id="trip-picker">
<button class="crumb" id="crumb" title="Switch trip — each keeps its own plan">…</button>
<div id="trip-menu" class="tripmenu hidden"></div>
</div>
<div class="scope-toggle" title="Day = working view · Trip = macro overview of all days">
<button id="scope-day" class="sct on" data-sc="day">Day</button>
<button id="scope-trip" class="sct" data-sc="trip">Trip</button>
</div>
<div class="daytabs" id="daytabs"></div>
</div>
<div class="tb-right">
<div class="verpill" id="verpill">
<button id="ver-undo" class="vp-btn off" title="Undo (Ctrl+Z)">↩</button>
<span id="verlabel" class="vp-label" title="Version history — recent edits, click to compare/revert">v0</span>
<button id="ver-redo" class="vp-btn off" title="Redo (Ctrl+Shift+Z)">↪</button>
</div>
<div id="verlist" class="verlist hidden"></div>
<span class="badge" id="offline-badge" title="On-trip offline bundle">📶 online</span>
<span class="badge" id="nudge-badge" title="Plan nudges">✓ looking good</span>
</div>
</header>
<div id="app" class="hidden">
<aside id="rail">
<div id="daystrip"></div>
<div class="rail-block" id="sugg-block"></div>
<div id="rail-body"></div>
<div class="rail-foot" id="rail-foot">
<div class="budget">
<div class="budget-label"><span id="budget-text">…</span></div>
<div class="budget-bar"><div id="budget-fill"></div></div>
</div>
<div id="nudges"></div>
<div class="legend">
<span class="tc t-user">·</span> you
<span class="tc t-sched">·</span> booked
<span class="tc t-computed">·</span> computed
<span class="tc t-search">~</span> web
<span class="tc t-llm">·</span> est.
</div>
</div>
</aside>
<div id="mapwrap">
<!-- discovery: a drawer over the map, the plan stays visible behind it -->
<div id="discover" class="hidden">
<div class="disc-head">
<div class="disc-chips" id="disc-chips"></div>
<div id="disc-title"></div>
<button id="disc-x" class="disc-x" title="Close (Esc)">✕</button>
</div>
<div class="disc-list" id="disc-list"></div>
</div>
<div id="l3-editor" class="hidden">
<div class="l3-title" id="l3-title">Route</div>
<div class="l3-hint">Drag the ● waypoint (or the endpoints) — the duration updates live; the local router re-routes on the road network when the area is covered.</div>
<div class="l3-mode hidden" id="l3-mode">
<span class="mode-label">getting around</span>
<div class="mode-toggle">
<button class="mode-btn" id="l3-foot" title="On foot between stops">🚶 Walk</button>
<button class="mode-btn" id="l3-car" title="By taxi between stops">🚗 Taxi</button>
</div>
</div>
<div class="l3-time">leg time: <span id="l3-time" class="tc t-computed">…</span></div>
<button class="btn ghost small" id="l3-close">Done</button>
</div>
</div>
<aside id="chat">
<div id="chat-body"></div>
<div id="doc-chips" class="hidden"></div>
<div id="chat-input-row">
<input id="doc-file" type="file" accept=".pdf,.txt,.ics,.html,.htm,.eml,.csv,.json" hidden />
<button class="btn small" id="doc-attach" title="Attach a booking or confirmation (PDF, HTML email, .eml, text) — flight bookings reconfigure the trip, and everything stays attached for reference">📎</button>
<input id="chat-input" type="text" placeholder="Ask, direct — or drop a booking…" />
<button class="btn small think-toggle on" id="think-toggle" title="LLM thinking: on = deliberate (slower, better planning) · off = quick answers (faster)">💭 on</button>
<button class="btn primary small" id="chat-send">→</button>
</div>
</aside>
</div>
<!-- comparison dock: side-by-side alternatives at any scale -->
<div id="dock" class="hidden"></div>
<nav id="mobiletabs" aria-label="Views">
<button data-t="plan" class="on">🗓️ Plan</button>
<button data-t="map">🗺️ Map</button>
<button data-t="chat">💬 Chat</button>
</nav>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="data.js"></script>
<script src="app.js"></script>
</body>
</html>