- server.js: proxy /route, /table, /router-status to the local OSRM on :5000
- app.js: routeClient (polyline-5 decode, ordered route fetch); legs start as
straight-line estimates (conf 1) and are upgraded in the background to real
road geometry + duration (conf 3); out-of-coverage trips (Florence) fall
back gracefully with a 'estimate — outside router coverage' source
- L3 leg editor: dragging a waypoint now genuinely re-routes through the
router (was silently no-op — #app covered the map with pointer-events:auto,
so no map drag ever landed; #app is now pointer-events:none, children opt in)
- data.js: second demo city (Boston 14–16 Sep, inside the router's NE-US
extract) via ?city=boston; nudges + multimodal legs are now dataset-driven
- L0: Day/Trip scope toggle — per-day summary cards (pacing bar, stops,
end time, price, base) with click-to-jump; map fits the whole trip
- version history: commit() snapshots days+stays on every mutation; topbar
vN pill with undo/redo + dropdown timeline showing a diff label per version;
Ctrl+Z / Ctrl+Shift+Z / Ctrl+Y; restore() re-enriches legs (snapshots may
predate route enrichment)
- offline: staged 'prepare for offline' card in the trip rail (itinerary →
POI details → vector tiles) that flips the topbar badge to '📦 offline ready'
- chat/scripts/nudges: Florence-specific strings generalized (stay name/dates,
vibes, pacing summary) so both demo cities read naturally
130 lines
5.0 KiB
HTML
130 lines
5.0 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="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 explore a demo trip</span>
|
|
<button class="chip" data-city="florence">Florence</button>
|
|
<button class="chip" data-city="boston">Boston <i>· live road routing</i></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">
|
|
<span class="crumb" id="crumb">…</span>
|
|
<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="transit-block"></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-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="chat-input-row">
|
|
<input id="chat-input" type="text" placeholder="Ask, direct — or “find a lunch spot”…" />
|
|
<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>
|