Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
- **Summary chip:** it sat on top of the zoom buttons in the top-left corner. While it shows, the corner's controls now sit below it.
- **Logo and attribution:** the legend covered the Mapbox logo, and an open results panel covered the attribution, both of which the Mapbox terms require to stay visible. The legend now sits above the logo and the panel stops above the attribution, and the map's fit leaves room for the legend's new spot.
- **Testing:** added tests for both buttons, the traffic layer and legend, restoring layers and base map config after a switch, `showTraffic` on, off and left out, and the controls moving below the summary. The test sandbox's fake map now tracks sources and layers like a style does (`setStyle` clears them), and mounts controls through `onAdd`. Checked a live San Francisco tile: the source layer is `traffic`, with `congestion`, `class` and `structure`. Checked in Claude Desktop on both styles.
- **`render_map_tool`: results carousel at the bottom of the map instead of the side list (#292).** Search results and id-bearing markers now show as a row of swipeable cards along the bottom, like the place results in ChatGPT, instead of the 280 px list on the right, which covered much of an inline map or started collapsed below 560 px wide. Each card has the place's name, category, price level (Places `attributes.price_level` as `$` to `$$$$`) and distance, its photo once loaded, and a second line with its hours. There's no star rating, since the Places API doesn't have one and `score.popularity` isn't one.
- **Place pins instead of orange numbers:** places are white pins with a [Maki](https://github.com/mapbox/maki) icon for their category (the Maki name Search Box gives each result, or one matched from the category, falling back to a plain marker), like ChatGPT's place results. About 20 common icons are inlined (about 12 KB). A caller's color tints the icon. Numbered badges stay for markers whose number means something: a caller's `style: "numbered"` with a `label` (a visit order), optimized trip stops, and route start/end.
- **Card and pin stay in sync:** the selected card gets a border, and its pin turns black (a numbered badge turns white), and comes to the front. Every carousel pin shows its name under it with a white halo, like a map label. The first card starts selected. Swiping selects whichever card ends up in the middle, clicking a card selects it, and clicking a pin scrolls to its card. Picking a card or a pin moves the map only when the pin or its name label is off screen or behind the cards, and then only far enough to show them.
- **No popups on carousel pins:** a pin with a card no longer opens a popup, and the phone number waits for a place detail card. Pins without an id (route ends, waypoints) keep their popups.
- **Hours:** parsed from the OSM-style `opening_hours` string for simple rules (`Mo-Fr 07:00-19:00; Sa,Su 08:00-17:00`, `Su off`, `24/7`, several ranges a day, ranges past midnight). Anything more complex (holidays, months) shows no hours rather than wrong ones. With the place's time zone (Places `telemetry.tags.timezone`) the card says "Open until 8:30 PM" in green or "Closed · opens 7:30 AM" in red. Without one it shows today's hours on the viewer's day ("Open 7:30–15:00"). Times use the viewer's locale.
- **Layout:** the cards sit 36 px up so the Mapbox logo and attribution stay visible, the legend moves up above them, and the map fits its data above both. The collapse toggle and the right-hand fit padding are gone. The zoom buttons move down below the summary chip ("6 results for …") while it shows, instead of sitting under it (same fix as #278).
- **OpenAI's [UI guidelines](https://developers.openai.com/plugins/concepts/ui-guidelines):** every card has a picture (the place's icon on a muted tile until a photo loads, or when there is none), labeled with the place's name for screen readers. Numbered badges pick dark or white numbers by contrast with the badge color (WCAG). The tool description asks the model not to list the places again after rendering, since the cards already show them.
- **Light and dark:** the cards, summary chip, legend and messages follow the host's theme (MCP Apps `hostContext.theme`, at start and on `host-context-changed`), or the system's `prefers-color-scheme` when the host sends none. Colors come from the host's style variables (`--color-background-primary`, `--color-text-primary` and so on) when it sends them, so the cards match the chat around them. The map, its pins and their name labels look the same in both.
- Tool and resource descriptions now say "carousel" instead of "panel". Dedupe across merged payloads, the batched Place Details lookup and photo loading are unchanged.
- **`static_map_image_tool` shows its map full size in an MCP App viewer (#315).** MCP Apps hosts showed the image result as a small thumbnail, and the model's reply couldn't show it. The tool now points `_meta.ui` at `ui://mapbox/static-map/index.html`, which draws the image from the tool result at full width as a `data:` URL (no token, no request), falling back to #312's public-token URL when the image went to a temporary resource. Clients that declare MCP Apps support get text saying the map is already shown, so the reply doesn't repeat it. The result itself is unchanged, so hosts without MCP Apps keep the image and the link.

### Bug Fixes
Expand Down
4 changes: 2 additions & 2 deletions src/resources/place-photo/PlacePhotoResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const lookupAll: LookupHost = async (hostname) =>

/**
* A POI's first Place Details photo, proxied through the server for the map
* app's results panel.
* app's results carousel.
*
* Place Details photos are hosted wherever the business's own site hosts
* them (Yext, Webflow and so on), so the map app's CSP can't list their
Expand All @@ -67,7 +67,7 @@ export class PlacePhotoResource extends MapboxApiBasedResource {
readonly uri = `${URI_PREFIX}{id}`;
readonly name = 'Mapbox Place Photo';
readonly description =
"The first photo of a POI from Place Details, as an image, for the map app's results panel. " +
"The first photo of a POI from Place Details, as an image, for the map app's results carousel. " +
'Read with mapbox://place-photo/{mapbox_id}.';
readonly mimeType = 'image/jpeg';

Expand Down
2 changes: 1 addition & 1 deletion src/resources/resourceRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const ALL_RESOURCES = [
new MapAppUIResource({ httpRequest }),
// Full-width viewer for static_map_image_tool's image.
new StaticMapViewerUIResource(),
// Photos for the map app's results panel, which its CSP can't load directly.
// Photos for the map app's results carousel, which its CSP can't load directly.
new PlacePhotoResource({ httpRequest }),
new VersionResource()
] as const;
Expand Down
Loading
Loading