Files
Inlander-Restaurant-Week-Pi…/README.md

156 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Inlander Restaurant Week Picker
A single-file web app for browsing, marking favorites, and randomly selecting a restaurant during [Inlander Restaurant Week](https://inlanderrestaurantweek.com/).
## Overview
The app presents all participating IRW restaurants in a two-panel layout — a scrollable list on the left and a detail view on the right — making it easy to browse full multi-course menus before deciding where to eat.
Each couple gets their own set of interest checkboxes ("His Picks" / "Her Picks") that persist in `localStorage` across sessions. Once both people have marked their favorites, the built-in randomizer picks a winner from the mutually-agreed pool.
## Features
- **Browse & search** — filter restaurants by name, price tier ($25 / $35 / $45), neighborhood/area, and cuisine type
- **Full menu detail** — click any restaurant to view its complete multi-course IRW menu with descriptions
- **Dual interest tracking** — independently mark restaurants as interesting for two people; selections are saved automatically in the browser
- **Interest filter** — narrow the list to His Picks, Her Picks, Both Picked, or Either Picked
- **Random picker** — "Pick for Us!" draws a random winner from the currently filtered pool, with an option to re-roll
- **Course browse** — dedicated First Course, Second Course, and Third Course buttons open a modal listing every dish for that course across all restaurants; click any dish to jump straight to that restaurant's detail view
- **Clear Filters** — one-click button to reset all search and filter fields back to their defaults
- **Reset Selected** — clears all saved picks (with a confirmation prompt) so you can start fresh
- **Mobile-friendly** — responsive single-panel layout on small screens; the list and detail views swap in place, with a Back button to return to the list
- **No dependencies** — pure HTML, CSS, and vanilla JavaScript; open the file directly in any browser
## Usage
1. Open `restaurant-picker.html` in a web browser (no server required).
2. Browse the restaurant list or use the toolbar filters to narrow choices.
3. Use the **First Course**, **Second Course**, or **Third Course** buttons to browse all dishes for a given course and jump to any restaurant that interests you.
4. Check the **You** and **Wife** boxes on any restaurant you're each interested in.
5. Click **Pick for Us!** to randomly select from the restaurants you both want.
6. Re-roll as needed, or click **View Details** to jump to the winner's menu.
7. Use **Clear Filters** to reset the toolbar, or **Reset Selected** to clear all picks and start over.
## Tech Stack
| Layer | Details |
|-------|---------|
| Structure | HTML5 |
| Styling | Inline CSS (dark red/gold IRW theme) |
| Logic | Vanilla JavaScript |
| Persistence | Browser `localStorage` |
| Dependencies | None |
## File Structure
```
restaurant-picker.html # The entire app — HTML, CSS, and JS in one file
LICENSE
README.md
```
---
## Data Entry Guide
Each year's restaurant data is stored as a JavaScript array (`const RESTAURANTS = [...]`) inline in `restaurant-picker.html`. The source data comes from the [IRW restaurant listing pages](https://inlanderrestaurantweek.com/restaurants/). This section covers the data schema and common pitfalls to avoid when entering or updating restaurant records.
### Restaurant Object Schema
```json
{
"name": "Restaurant Name",
"slug": "restaurantname",
"price": 35,
"areas": ["Downtown"],
"cuisine": "Italian",
"url": "https://inlanderrestaurantweek.com/project/restaurantname/",
"menu": {
"hours": "Menu served Tue-Sat, 5 pm-close",
"phone": "(509) 555-1234",
"courses": {
"First Course": [
{ "name": "Dish Name", "desc": "Ingredients and description GF" }
],
"Second Course": [
{ "name": "Dish Name", "desc": "Ingredients and description" }
],
"Third Course": [
{ "name": "Dish Name", "desc": "Ingredients and description V+" }
]
}
}
}
```
**Field notes:**
- `slug` — lowercase, no spaces or special characters; used as an internal identifier
- `price` — must be `25`, `35`, or `45` (the three IRW price tiers)
- `areas` — array; a restaurant can belong to more than one area (e.g. `["Downtown", "Coeur d'Alene"]`)
- `phone` — use empty string `""` if not listed
- Each course is an **array** — restaurants sometimes offer a choice of two or more dishes per course; add one object per option
### Valid Area Values
```
Airway Heights Athol Coeur d'Alene Downtown
Hayden Liberty Lake North Spokane Post Falls
South Spokane Spokane Valley West Spokane Worley
ID (Coeur d'Alene-area catch-all)
```
### Valid Cuisine Values
```
American Asian Barbecue Bistro Eclectic European French
Fusion Gastropub German Indian Irish Italian Latin
Mediterranean Mexican Middle Eastern Northwest Pizza
Seafood Southern Steakhouse Thai
```
New cuisine types can be added, but check existing values first to keep filters consistent.
### Dietary Tags
Dietary tags go at the **end of the `desc` field**, separated by a space. Multiple tags are space-separated.
| Tag | Meaning |
|-----|---------|
| `GF` | Gluten Free |
| `GFA` | Gluten Free Available (on request or with substitution) |
| `V` | Vegetarian |
| `V+` | Vegan |
| `DF` | Dairy Free |
**Examples:**
```
"desc": "Mixed greens, candied walnuts, goat cheese, balsamic vinaigrette GF V"
"desc": "House pasta with roasted vegetables sub GF pasta available GFA V"
"desc": "Coconut curry with tofu and seasonal vegetables V+ GF DF"
```
Tags that are inline notes within a description (e.g. ` sub GF crust for additional charge`) are fine to leave mid-sentence; only the primary applicable tags belong at the end.
### Common Data Entry Pitfall: Dietary Tag as Dish Name
The IRW website displays a dietary icon **before** the dish name. When copying menu data, it is easy to accidentally paste the dietary tag as the `name` field and run the dish name directly into the start of `desc` with no separator.
**Wrong (broken):**
```json
{ "name": "GFA", "desc": "Margherita PizzaSan Marzano Tomato Sauce. Fresh Mozzarella." }
```
**Correct:**
```json
{ "name": "Margherita Pizza", "desc": "San Marzano Tomato Sauce. Fresh Mozzarella. GFA" }
```
Signs that an entry has this problem:
- The `name` field is just a dietary tag (`"GF"`, `"GFA"`, `"V+"`, etc.)
- The `desc` field starts with what looks like a dish name run together with the description (no space or punctuation between them, e.g. `"Chocolate TorteA rich slice of flourless paradise"`)
### Special Characters
The data lives inside a JavaScript string, so be careful with quotation marks inside descriptions. Use a **curly/smart right double-quote** (`"`, U+201D) for inch marks (e.g. `7" pizza`) rather than a straight ASCII `"`, which would break the JS string delimiters. Em dashes (``) and curly apostrophes (`'`) from the source website copy fine as-is.
**Critical: field delimiters must be straight ASCII double quotes.** Some editors and AI tools auto-correct straight `"` to curly `"` / `"` (U+201C / U+201D). If curly quotes end up wrapping property names or values (e.g. `"name"` instead of `"name"`), JavaScript will fail to parse the entire `RESTAURANTS` array and no restaurants will appear in the app. Always verify that the structural quotes in the data use the straight ASCII `"` character (U+0022).