Conversational trip planning with a live MapLibre preview.
npm install
npm run devThen visit http://localhost:3000 and start describing your travel goals.
- Next.js 14 (App Router) — modern routing primitives and server actions.
- TypeScript — type-safety across UI and API boundaries.
- TailwindCSS — rapid design iteration while keeping the UI consistent.
- MapLibre GL JS — open-source mapping with an OSM demo style (no keys).
app/
api/plan/route.ts # Deterministic planner stub
layout.tsx # Global HTML shell
page.tsx # Chat + map layout
globals.css # Tailwind entrypoint
components/
ChatPanel.tsx # ChatGPT-inspired UI
MapView.tsx # MapLibre wrapper
lib/
types.ts # Shared data contracts
next.config.ts # Next.js configuration
postcss.config.mjs # Tailwind/PostCSS config
public/ # Static assets
README.md
- Install dependencies with
npm install. - Start the dev server via
npm run dev. - The planner stub is deterministic; refresh the page or tweak your prompt to see different destinations.
Note: The Codespaces-provided proxy occasionally blocks
npm install. If you see403 Forbiddenerrors, try re-running the command or using a personal network.
- The project is Next.js ready for Vercel, Netlify, or any Node 18+ platform.
- Set the
NEXT_PUBLIC_MAP_STYLEenv var (not yet used) once you migrate to a custom map provider. - Tailwind is already configured; run
npm run buildbefore deploying to catch type issues.
Replace the stub in app/api/plan/route.ts with a call to your planner model. Example pseudo-flow using OpenAI:
import OpenAI from "openai";
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
export async function POST(request: Request) {
const { messages } = await request.json();
const completion = await client.responses.create({
model: "gpt-4o-mini",
input: messages.map((message) => ({
role: message.role,
content: message.content
}))
});
// Parse completion, map to pins, and return JSON.
}- Update the
styleURL incomponents/MapView.tsxto point to MapTiler, Mapbox, or self-hosted tiles. - Add extra controls (geolocate, scale bar) via MapLibre's control APIs inside the first
useEffecthook.
- Map not rendering: Ensure
maplibre-glCSS is imported (already done inMapView.tsx). - CORS issues: When switching providers, confirm the tile server allows requests from your domain.
- Tailwind classes missing: Tailwind purges unused styles based on
contentglobs intailwind.config.ts. - Streaming needs: Replace the
fetchcall inChatPanel.tsxwith an SSE or websockets client; state updates are already centralized.