shadcn.io is not affiliated with official shadcn/ui
Restaurant Finder Map Block for React Aria
A dining map with cuisine, price and rating filters whose options show how many places each choice would leave, price-and-cuisine pills that hide in place, a best-rated list and opening hours worked out from a fixed time.
Installation
Overview
Let diners narrow a city by what they feel like eating with this restaurant finder map for React with React Aria. Supperly, a dining guide, draws the invented town of Dunscombe as an SVG street map with ten places as pills, each with a two-letter cuisine code and a price level. A cuisine Toggle Group (Italian, Thai, Lebanese, Vegetarian, Bakery; any of the ones pressed), a price toggle group and a minimum rating select narrow the list, and every option carries the count the other choices would leave, so the number on "Thai" is how many Thai places pass the price and rating you set. A place that stops matching stays on the map in its spot, unseen, so nothing reflows, and leaves the list at the side, best rated first, with its cuisine, price, rating and opening hours ("Open until 22:30", "Closed on Mondays") worked out from one fixed time. A combination with nothing in it shows an empty state in the same box with a button that clears the filters. The list is a scroll region of its own and the way in for the keyboard; the pins are a shortcut for the pointer. A polite status line speaks the count once the controls settle. On a phone the map comes first and the list sits under it. It's built from Toggle Group, Native Select, Empty, Button and Guides, with a CSS entrance only. For dining guides, delivery apps and city guides.
FAQ
How do I fill it with my restaurants?
Edit PLACES. Each place has an id, a name, a cuisine id from CUISINES, a price level from 1 to 3, a rating in tenths (46 is 4.6), opening and closing times in minutes after midnight, an optional closedDay, and an x and y in the drawing's 480 by 360 units. In your app project each restaurant's latitude and longitude onto the map you use and keep passes, the one function that decides whether a place matches.
How are the counts on the options worked out?
Each count is the number of places that would match if that option were the only one chosen in its group, with the other two facets held as they are. So pressing "Thai" never lowers the count on "Italian", because cuisines are an "any of" choice; the price and rating counts do move when you change a cuisine. All three come from the same matchesOf function that builds the list, so they can't disagree with it.
Where do the opening hours come from?
From AS_OF, a fixed Monday evening in the file, compared with each place's opening and closing times and its closed day. It is never read from the clock, so the demo looks the same at any hour. In your app pass the visitor's current time and the venue's time zone.
Can I use it without a mouse?
Yes. The cuisine and price groups are toggle buttons you can reach with Tab and press with Space or Enter, the rating is a native select, and every match is a button in the list that marks the place. The pins on the map are hidden from assistive technology and skipped by the Tab key because the list says the same things in text.
What stays local in the demo, and how do I wire it up?
All of it. The places are typed sample data, the map is a drawing and nothing is searched, saved or sent. Marking a place only highlights it. In your app load the places from your search service when a facet changes, keep the pins mounted so the map doesn't jump, and make a row open the place's page.