Compare commits
14 Commits
a5cb6fa7fa
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d70a6416b | |||
| 984fb97499 | |||
| ebb3a6ad08 | |||
| a149559a74 | |||
| 76b498ae14 | |||
| b17fc2d6e0 | |||
| c8c8f028fa | |||
| 03ee2b3645 | |||
| 8ded70b743 | |||
| fe07a23a2f | |||
| b455bae614 | |||
| ab9abdb53e | |||
| 17c8270742 | |||
| e7252c4a74 |
6919
2025-restaurants.json
Normal file
6919
2025-restaurants.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,6 @@
|
|||||||
[
|
{
|
||||||
|
"eventDates": "FEBRUARY 26 – MARCH 7, 2026",
|
||||||
|
"restaurants": [
|
||||||
{
|
{
|
||||||
"name": "315",
|
"name": "315",
|
||||||
"slug": "315cuisine",
|
"slug": "315cuisine",
|
||||||
@@ -2230,18 +2232,42 @@
|
|||||||
{
|
{
|
||||||
"name": "Albi Italian",
|
"name": "Albi Italian",
|
||||||
"desc": "Mixed greens, cucumber, red onion, croutons, pepperoncini, tomato, Italian vinaigrette GFA"
|
"desc": "Mixed greens, cucumber, red onion, croutons, pepperoncini, tomato, Italian vinaigrette GFA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "“A” Street Chips",
|
||||||
|
"desc": "deep fried thin sliced potatoes; choice of Flying Goat seasoning or salt & vinegar DF – add cup of creamy gorgonzola dressing $2.25"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "German Sausage Plate",
|
||||||
|
"desc": "German sausage, sauerkraut, potato wedges, house mustard GFA"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
|
{
|
||||||
|
"name": "Alberta",
|
||||||
|
"desc": "red sauce, fresh mozzarella, pepperoni, red onion, roasted basil (7” pizza) GFA – sub GF crust for additional charge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Short Rib Pizza",
|
||||||
|
"desc": "Extra virgin olive oil, short ribs, marinated portabella mushrooms, goat cheese, roasted garlic, green onion (7” pizza) GFA – sub GF crust for additional charge"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Driscoll",
|
"name": "Driscoll",
|
||||||
"desc": "Roasted red pepper sauce, goat cheese, roasted eggplant, red onions, roasted cremini mushrooms, with truffle oil tossed arugula \u0026 shredded pecorino (7” pizza) – sub GF crust for additional charge GFA"
|
"desc": "roasted red pepper sauce, goat cheese, roasted eggplant, red onions, roasted cremini mushrooms, with truffle oil tossed arugula & shredded pecorino (7” pizza) GFA V – sub GF crust for additional charge"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
{
|
{
|
||||||
"name": "Affogato",
|
"name": "Glazed Cinnamon Roll",
|
||||||
"desc": "Espresso, house-made biscotti \u0026 ice cream GFA"
|
"desc": "house-made cinnamon roll"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "“Affogato",
|
||||||
|
"desc": "espresso, house-made biscotti & ice cream GFA V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Root Beer Float",
|
||||||
|
"desc": "Pelican root beer, vanilla ice cream GF"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -5058,13 +5084,43 @@
|
|||||||
{
|
{
|
||||||
"name": "Repub Fries",
|
"name": "Repub Fries",
|
||||||
"desc": "Crispy Idaho fries tossed in togarashi, topped with aioli and chili sauce. Garnished with cilantro, pickled jalapeños, blue cheese, and garlic confit – add candied bacon $3 GF"
|
"desc": "Crispy Idaho fries tossed in togarashi, topped with aioli and chili sauce. Garnished with cilantro, pickled jalapeños, blue cheese, and garlic confit – add candied bacon $3 GF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Double Cooked Chicken Wings",
|
||||||
|
"desc": "Cured, slow-cooked, and then fried. Choose BBQ spice, salt and pepper, hot, buffalo, or honey butter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Deviled Eggs",
|
||||||
|
"desc": "Beer mustard whipped yolk, chile sauce, seed mix, candied bacon, green onion"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
|
{
|
||||||
|
"name": "Loco Moco",
|
||||||
|
"desc": "8 oz. grilled WA beef on a bed of jasmine rice, covered in house-made mushroom gravy, with a sunny-side-up egg, kimchi, avocado, and fresh cilantro"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Monte Cristo",
|
||||||
|
"desc": "Crispy bacon, melted cheddar cheese and stone-ground dijon served on French toast with a side of house-made raspberry jam and choice of side – add a fried egg $2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Macaroni and Cheese",
|
||||||
|
"desc": "Curly noodles tossed in a creamy garlic-cheese sauce then baked until golden brown – make it dirty $4"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
|
{
|
||||||
|
"name": "Brown Butter Old Fashioned Donut",
|
||||||
|
"desc": "Classic glazed donut, cooked in brown butter, served warm, then topped with vanilla bean ice cream and sea salt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "NY Style Cheesecake",
|
||||||
|
"desc": "Whipped cream, caramel and candied pecans"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Churro Waffle",
|
||||||
|
"desc": "Tossed in cinnamon and sugar with salted caramel ice cream and fudge sauce"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5090,12 +5146,24 @@
|
|||||||
{
|
{
|
||||||
"name": "Roasted Beet Salad",
|
"name": "Roasted Beet Salad",
|
||||||
"desc": "Balsamic roasted beets, goat cheese, arugula, candied pine nuts, sherry citrus vinaigrette GF"
|
"desc": "Balsamic roasted beets, goat cheese, arugula, candied pine nuts, sherry citrus vinaigrette GF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pi Bites",
|
||||||
|
"desc": "baked and crisp-fried pi dough, sea salt, Perry Street beer cheese sauce, green onion"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
|
{
|
||||||
|
"name": "Pork Carnitas Pizza",
|
||||||
|
"desc": "roasted tomatillo verde, cheese blend, jalapenos, red onion, chipotle crema (7” pizza) – sub GF crust for additional charge GFA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "30th Off Grand",
|
||||||
|
"desc": "rossa sauce, Italian sausage, pepperoni, house cured ham, cheese blend (7” pizza) – sub GF crust for additional charge GFA"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Wild Mushroom Pizza",
|
"name": "Wild Mushroom Pizza",
|
||||||
"desc": "Roasted pepper coulis, goat cheese, baby kale, caramelized shallots (7” pizza) – sub GF crust for additional charge GFA"
|
"desc": "roasted pepper coulis, goat cheese, baby kale, caramelized shallots (7” pizza) – sub GF crust for additional charge GFA V"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
@@ -5188,44 +5256,44 @@
|
|||||||
"courses": {
|
"courses": {
|
||||||
"First Course": [
|
"First Course": [
|
||||||
{
|
{
|
||||||
"name": "V Nut Free",
|
"name": "Cauliflower Wings",
|
||||||
"desc": "Cauliflower WingsBuffalo or Thai ginger style • carrot sticks • dipping sauce df – Make it full size: $7"
|
"desc": "Buffalo or Thai ginger style • carrot sticks • dipping sauce df V Nut Free – Make it full size: $7"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "GF V+ DF Nut Free",
|
"name": "Blistered Shishitos",
|
||||||
"desc": "Blistered Shishitosmiso-tahini sauce • lemon salt • togarashi – Make it full size: $7"
|
"desc": "miso-tahini sauce • lemon salt • togarashi GF V+ DF Nut Free – Make it full size: $7"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "GFA V+ DF Nut Free Soy Free",
|
"name": "Creamy Tomato Soup",
|
||||||
"desc": "Creamy Tomato Soupbreadcrumbs • parsley • parmesan – Make it a bowl $4"
|
"desc": "breadcrumbs • parsley • parmesan GFA V+ DF Nut Free Soy Free – Make it a bowl $4"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
{
|
{
|
||||||
"name": "GFA V+ DF Nut Free",
|
"name": "Bbq Jackfruit Sandwich",
|
||||||
"desc": "Bbq Jackfruit Sandwichrainbow slaw • crispy onion • Carolina style BBQ sauce • pretzel bun • choice of side"
|
"desc": "rainbow slaw • crispy onion • Carolina style BBQ sauce • pretzel bun • choice of side GFA V+ DF Nut Free"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "GFA V+ DF Nut Free",
|
"name": "Lemongrass Yellow Curry",
|
||||||
"desc": "Lemongrass Yellow Currytofu • jasmine rice • roasted radish • snap pea • red bell pepper • carrot slaw • crispy shallot"
|
"desc": "tofu • jasmine rice • roasted radish • snap pea • red bell pepper • carrot slaw • crispy shallot GFA V+ DF Nut Free"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Philly Sandwich",
|
"name": "Philly Sandwich",
|
||||||
"desc": "Braised mushroom medley • onion \u0026 peppers • smokey cashew provolone • long bread • choice of side V+"
|
"desc": "braised mushroom medley • onion & peppers • smokey cashew provolone • long bread • choice of side V+ DF"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
{
|
{
|
||||||
"name": "GF V+",
|
"name": "Tea Time",
|
||||||
"desc": "Tea Timeearl grey cheesecake • lemon coulis • lemon-ginger sugar cookie"
|
"desc": "earl grey cheesecake • lemon coulis • lemon-ginger sugar cookie GF V+ DF"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "GF V DF Nut Free",
|
"name": "Cookies & Cream",
|
||||||
"desc": "Cookies \u0026 Creamchocolate chunk cookie • vanilla ice cream • raspberry coulis"
|
"desc": "chocolate chunk cookie • vanilla ice cream • raspberry coulis GF V DF Nut Free"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "GF V+",
|
"name": "Turtle Torte",
|
||||||
"desc": "Turtle Torteflourless chocolate torte • miso caramel • candied walnuts"
|
"desc": "flourless chocolate torte • miso caramel • candied walnuts GF V+ DF"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -5246,24 +5314,44 @@
|
|||||||
"courses": {
|
"courses": {
|
||||||
"First Course": [
|
"First Course": [
|
||||||
{
|
{
|
||||||
"name": "Fried CalamariDeep-fried calamari with a lemon garlic aioli",
|
"name": "Fried Calamari",
|
||||||
"desc": "Zuppa ToscanaSpicy Italian sausage, kale and potatoes in a rich chicken broth Antipasto SaladSalami, pepperoni, Castelvetrano olives, mozzarella, roasted cherry tomatoes, romaine, red wine vinegar dressing"
|
"desc": "Deep-fried calamari with a lemon garlic aioli DF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Zuppa Toscana",
|
||||||
|
"desc": "Spicy Italian sausage, kale and potatoes in a rich chicken broth GF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Antipasto Salad",
|
||||||
|
"desc": "Salami, pepperoni, Castelvetrano olives, mozzarella, roasted cherry tomatoes, romaine, red wine vinegar dressing GF"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
{
|
{
|
||||||
"name": "Clam LinguineManila clams, linguine pasta, white wine clam sauce",
|
"name": "Clam Linguine",
|
||||||
"desc": "Spicy Sausage Penne PastaGarlic, shallots, vodka-tomato cream sauce, parmesan, toasted bread, basil Grilled Chicken Bruschetta Sandwich6 oz. chicken breast, tomato-olive tapenade, sliced mozzarella, arugula, basil, roasted garlic puree on a ciabatta with tomato-basil chips A"
|
"desc": "Manila clams, linguine pasta, white wine clam sauce DF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Spicy Sausage Penne Pasta",
|
||||||
|
"desc": "Garlic, shallots, vodka-tomato cream sauce, parmesan, toasted bread, basil"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ZGrilled Chicken Bruschetta Sandwich",
|
||||||
|
"desc": "6 oz. chicken breast, tomato-olive tapenade, sliced mozzarella, arugula, basil, roasted garlic puree on a ciabatta with tomato-basil chips GFA"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
{
|
{
|
||||||
"name": "Creme Brulée",
|
"name": "Lemon Ricotta Cheesecake",
|
||||||
"desc": "House-made custard, caramelized candy shell, fresh berries GF"
|
"desc": "Sweet ricotta, lemon, cookie crust, raspberry puree, candied lemon, whipped cream V"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "GF V V+",
|
"name": "Creme Brulée",
|
||||||
"desc": "SorbetChoice of seasonal offerings"
|
"desc": "House-made custard, caramelized candy shell, fresh berries GF V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sorbet",
|
||||||
|
"desc": "Choice of seasonal offerings GF V V+ DF"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -5286,18 +5374,42 @@
|
|||||||
{
|
{
|
||||||
"name": "Fried Polenta",
|
"name": "Fried Polenta",
|
||||||
"desc": "Fried polenta, topped with house-made marinara, mozzarella, balsmic glaze and fresh basil GF"
|
"desc": "Fried polenta, topped with house-made marinara, mozzarella, balsmic glaze and fresh basil GF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Salmon Cakes",
|
||||||
|
"desc": "House-made salmon cakes seasoned with peppers garlic, shallots, on a bed of arugula and shaved fennel topped with pineapple salsa DF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bacon Jam Crostini",
|
||||||
|
"desc": "Warmed brie cheese, topped with house-made onion bacon jam. Garnished with parsley and pickled jalapeños"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
|
{
|
||||||
|
"name": "Lemon Herbed Mahi",
|
||||||
|
"desc": "Seasoned mahi, on a bed of lemon herb rice, with roasted asparagus and blistered cherry tomatoes topped with caper lemon butter sauce GF"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Beef and Mushroom Pappardelle",
|
"name": "Beef and Mushroom Pappardelle",
|
||||||
"desc": "House-made braised short rib with mushrooms and pappardelle pasta in a cream sauce topped with parmesan and parsley – Vegetarian option available GF"
|
"desc": "House-made braised short rib with mushrooms and pappardelle pasta in a cream sauce topped with parmesan and parsley – Vegetarian option available GF V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pork Belly and Grits",
|
||||||
|
"desc": "Pork belly over cheesy cheddar grits and roasted asparagus, topped with a house-made maple bourbon glaze and pickled jalapenos GF"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
{
|
{
|
||||||
"name": "Blackberry CrispBlackberry crisp served with vanilla ice cream",
|
"name": "Blackberry Crisp",
|
||||||
"desc": "Sweet PretzelsCinnamon sugar pretzels served with a cream cheese frosting Chocolate Peanut Butter PiePeanut butter cups sandwiched between layers of chocolate and peanut butter mousse on an Oreo crumb crust"
|
"desc": "Blackberry crisp served with vanilla ice cream GF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sweet Pretzels",
|
||||||
|
"desc": "Cinnamon sugar pretzels served with a cream cheese frosting"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Chocolate Peanut Butter Pie",
|
||||||
|
"desc": "Peanut butter cups sandwiched between layers of chocolate and peanut butter mousse on an Oreo crumb crust"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -5433,9 +5545,13 @@
|
|||||||
"phone": "(208) 664-8008",
|
"phone": "(208) 664-8008",
|
||||||
"courses": {
|
"courses": {
|
||||||
"First Course": [
|
"First Course": [
|
||||||
|
{
|
||||||
|
"name": "House Caesar Salad",
|
||||||
|
"desc": "Crisp romaine lettuce tossed in house-made Caesar dressing. Topped with tomatoes, lemon and croutons GFA"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "House Bistro Salad",
|
"name": "House Bistro Salad",
|
||||||
"desc": "Mixed arcadian greens tossed in your choice of our house-made dressings. Topped with grape tomatoes, mixed dried fruit and croutons GFA"
|
"desc": "Mixed arcadian greens tossed in your choice of our house-made dressings. Topped with grape tomatoes, mixed dried fruit and croutons GFA V"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Butternut Squash Bisque",
|
"name": "Butternut Squash Bisque",
|
||||||
@@ -5443,12 +5559,31 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
|
{
|
||||||
|
"name": "Peppercorn Sirloin",
|
||||||
|
"desc": "Pendleton Oregon sirloin steak served with house-made creamy peppercorn sauce, roasted garlic mashed potatoes, and seasonal vegetables GF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Saffron Seafood Stew",
|
||||||
|
"desc": "Wild Norwegian salmon, Alaskan cod, shrimp, Andouille sausage, and red potatoes in a hearty house-made saffron tomato broth, with sourdough toast GFA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Cilantro Lime Chicken",
|
||||||
|
"desc": "Two chile con limon seasoned chicken breasts served over house-made chimichurri rice and seasonal vegetables GF"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
{
|
{
|
||||||
"name": "Huckleberry CheesecakeHuckleberry cheesecake served with huckleberry-gin compote",
|
"name": "Huckleberry Cheesecake",
|
||||||
"desc": "Death by Chocolate CakeDouble layered chocolate cake with a chocolate cream cheese frosting and finished with whipped cream Rotating Seasonal GelatoThree scoops of locally sourced gelato from Gelato by the Lake (Ask your server for the current selection)"
|
"desc": "Huckleberry cheesecake served with huckleberry-gin compote"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Death by Chocolate Cake",
|
||||||
|
"desc": "Double layered chocolate cake with a chocolate cream cheese frosting and finished with whipped cream"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rotating Seasonal Gelato",
|
||||||
|
"desc": "Three scoops of locally sourced gelato from Gelato by the Lake (Ask your server for the current selection) GF"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -5643,28 +5778,44 @@
|
|||||||
"courses": {
|
"courses": {
|
||||||
"First Course": [
|
"First Course": [
|
||||||
{
|
{
|
||||||
"name": "GF V+",
|
"name": "Fish Cakes",
|
||||||
"desc": "Fresh RollRice paper-wrapped lettuce, carrots, cabbage, cilantro, basil, cucumber and vermicelli rice noodles, served with peanut sauce and topped with special sauce"
|
"desc": "Deep-fried blended tilapia with sliced string beans, mixed with our special curry. Served with sweet chili sauce and garnished with cucumber DF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Fresh Roll",
|
||||||
|
"desc": "Rice paper-wrapped lettuce, carrots, cabbage, cilantro, basil, cucumber and vermicelli rice noodles, served with peanut sauce and topped with special sauce GF V+ DF "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Crab Rangoon",
|
||||||
|
"desc": "Deep fried wonton-wrapped crab meat, cream cheese, onion, celery, and carrots served with sweet chili sauce"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
{
|
{
|
||||||
"name": "GF V+",
|
"name": "Khao Man Gai",
|
||||||
"desc": "Panang Curry Braised Beef/Tofu“Braised beef, Panang curry, coconut milk, lime leaves and potatoes garnished with basil and bell pepper and kaffir lime leaves. Served with rice”"
|
"desc": "Slow-roasted chicken, Sirinya’s special sauce, garlic, ginger, cilantro, white radish, green onion with jasmine rice and soup. Garnished with cucumber DF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Panang Curry Braised Beef/Tofu",
|
||||||
|
"desc": "“Braised beef, Panang curry, coconut milk, lime leaves and potatoes garnished with basil and bell pepper and kaffir lime leaves. Served with rice” GF V+ DF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bahmi Haeng Hmudaeng",
|
||||||
|
"desc": "Lo mein noodles with roasted red pork and bok choy, topped with dried garlic, cilantro, green onion and special sauce"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
{
|
{
|
||||||
"name": "GFA V+",
|
"name": "Bua Loi",
|
||||||
"desc": "Bua LoiRice flour rolled sweet potato cooked in pandan and sweet coconut milk"
|
"desc": "Rice flour rolled sweet potato cooked in pandan and sweet coconut milk GFA V+ DF"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "GFA V+",
|
"name": "Sirinya’s Black Rice Pudding",
|
||||||
"desc": "Sirinya’s Black Rice PuddingSweet black rice with coconut cream and pandan, topped with peaches"
|
"desc": "Sweet black rice with coconut cream and pandan, topped with peaches GFA V+ DF"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Deep Fried Banana Ice Cream",
|
"name": "Deep Fried Banana Ice Cream",
|
||||||
"desc": "Deep fried sweet banana wrapped with wheat flour, coconut ice cream topped with honey garnished with a cherry V+"
|
"desc": "Deep fried sweet banana wrapped with wheat flour, coconut ice cream topped with honey garnished with a cherry V+ DF"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -5689,20 +5840,40 @@
|
|||||||
"desc": "Pick two of our dips to sample with pita or veggies: Hummus, mutabel (roasted eggplant), muhamara (roasted red pepper and walnut), lebneh (mint-yogurt) – Additional dips $4 GFA"
|
"desc": "Pick two of our dips to sample with pita or veggies: Hummus, mutabel (roasted eggplant), muhamara (roasted red pepper and walnut), lebneh (mint-yogurt) – Additional dips $4 GFA"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "GF V V+",
|
"name": "Falafel Bites",
|
||||||
"desc": "Falafel BitesSkewers’ scratch-made falafel served with our housemade taratour (sesame sauce) and pickled turnips – Add hummus \u0026 pita $4"
|
"desc": "Skewers’ scratch-made falafel served with our housemade taratour (sesame sauce) and pickled turnips GF V V+ DF – Add hummus & pita $4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Curry Cup",
|
||||||
|
"desc": "Our popular Armenian chicken curry, made with imported spices GFA –Add rice pilaf $4 pita bread $1"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
{
|
{
|
||||||
"name": "GFA V V+",
|
"name": "Ghoozoo Eechee",
|
||||||
"desc": "DolmaPepper stuffed with a rice and walnut based mixture. Served with fattoush salad (pomegranate dressing) topped with pita chips and a Skewers sauce of choice"
|
"desc": "Slow cooked Lamb shank served with lavash bread and a well-spiced rice, topped with an array of nuts. Comes with a Skewers sauce of choice GFA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Hamem Chicken",
|
||||||
|
"desc": "Seasoned chicken quarter: bone-in, skin on, roasted. Served with pita and flavorful rice with onions and peppers. Comes with a Skewers sauce of choice GFA "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dolma",
|
||||||
|
"desc": "Pepper stuffed with a rice and walnut based mixture. Served with fattoush salad (pomegranate dressing) topped with pita chips and a Skewers sauce of choice GFA V V+ DF"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
{
|
{
|
||||||
"name": "GF V V+",
|
"name": "Walnut Pakhlava",
|
||||||
"desc": "Cardamom Rice PuddingCoconut-based rice pudding made with cardamom and rose. Topped with pistachios and rose petals"
|
"desc": "Pastry made with alternating thin layers of phyllo dough and walnuts. Sweetened with a house made floral-honey syrup (2 pieces) GFA – Add 2 pieces $3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "GLayali Lubnan “Lebanese Nights”",
|
||||||
|
"desc": "Semolina pudding, topped with a layer of ashta (clotted cream), garnished with a heavy layer of pistachio, and sweetened with Skewers’ rose attar (syrup) GFA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Cardamom Rice Pudding",
|
||||||
|
"desc": "Coconut-based rice pudding made with cardamom and rose. Topped with pistachios and rose petals GF V V+ DF"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -5787,15 +5958,38 @@
|
|||||||
{
|
{
|
||||||
"name": "Caprese Canapes",
|
"name": "Caprese Canapes",
|
||||||
"desc": "Rich compound cheese topped with seasoned tomatoes, basil, and balsamic reduction. Served with crostinis GFA"
|
"desc": "Rich compound cheese topped with seasoned tomatoes, basil, and balsamic reduction. Served with crostinis GFA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Crab Cakes",
|
||||||
|
"desc": "House-made crab cakes served with house aioli"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
|
{
|
||||||
|
"name": "Bánh Mì Burger",
|
||||||
|
"desc": "A juicy Angus beef patty cooked in a tangy marinade and topped with BBQ pork pâté, cilantro, pickled carrots and cucumber, all on a ciabatta bun GFA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Birria Ramen",
|
||||||
|
"desc": "Rice noodles topped with birria consume, braised birria meat, pickled radish, shredded cabbage, onions, and cotija cheese GFA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Vodka Pasta with Meatballs",
|
||||||
|
"desc": "Fettuccini noodles tossed in tomato vodka sauce with mushrooms, and red peppers. Served with house-made meatballs"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
|
{
|
||||||
|
"name": "Lemon Tart",
|
||||||
|
"desc": "Bright lemon curd in a crisp crust V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Apple Cheesecake Eggroll",
|
||||||
|
"desc": "House-made spiced apples and cheesecake wrapped in an eggroll shell and fried to perfection. Served with house-made bourbon caramel sauce V"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Chocolate Torte",
|
"name": "Chocolate Torte",
|
||||||
"desc": "A rich slice of flourless paradise GF"
|
"desc": "A rich slice of flourless paradise GF V"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -5993,21 +6187,41 @@
|
|||||||
"name": "Oeuf Mayonnaise",
|
"name": "Oeuf Mayonnaise",
|
||||||
"desc": "Eight-minute egg, scallion oil, flaky salt, fresh greens – Add tobiko caviar $3; chili crisp $1.50 GF"
|
"desc": "Eight-minute egg, scallion oil, flaky salt, fresh greens – Add tobiko caviar $3; chili crisp $1.50 GF"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "César Revisité",
|
||||||
|
"desc": "Romaine, creamy lemon and garlic dressing, bacon, fresh and crispy Parmesan cheese GF – Add 8-minute Egg $2 Anchovies $2 Smoked Duck $8"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Bisque de Tomates",
|
"name": "Bisque de Tomates",
|
||||||
"desc": "Tomato bisque….Rich, thick, luxurious, creamy, tangy, addictive… and CdA famous GF"
|
"desc": "Tomato bisque….Rich, thick, luxurious, creamy, tangy, addictive… and CdA famous GF V"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
|
{
|
||||||
|
"name": "Chicken Fricassée",
|
||||||
|
"desc": "A French country classic: Chicken thigh and mushrooms braised with white wine, chicken stock, shallots, cream, and herbs. Served with baby potatoes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Croque Monsieur",
|
||||||
|
"desc": "Back Pocket Bakery baguette, Béchamel sauce, dijon, French ham and Swiss cheese baked until warm and melty. Served with mixed greens – Sub tomato bisque ($2) or potato chips"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Salade de Betteraves Rôties et Burrata",
|
"name": "Salade de Betteraves Rôties et Burrata",
|
||||||
"desc": "Roasted beets, burrata cheese, scallion oil, arugula and flaky salt, served with Back Pocket Bakery baguette GFA"
|
"desc": "Roasted beets, burrata cheese, scallion oil, arugula and flaky salt, served with Back Pocket Bakery baguette GFA V"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
{
|
{
|
||||||
"name": "Pots de Crème",
|
"name": "Pots de Crème",
|
||||||
"desc": "Rich chocolate custard finished with whipped cream – Add 3 oz. of 2018 Duorum LBV Port $12 GF"
|
"desc": "Rich chocolate custard finished with whipped cream – Add 3 oz. of 2018 Duorum LBV Port $12 GF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pouding de Croissants au Caramel et aux Pistaches",
|
||||||
|
"desc": "Croissants baked in vanilla custard and served warm with caramel sauce, crushed pistachios and whipped cream – Add 3 oz. Rare Wine Co. Boston Bual Madeira $12"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Fromage Comté",
|
||||||
|
"desc": "Comté is a French alpine cheese from the Jura, aged 18 months for nutty, savory depth and a smooth, firm texture. Served with pear jam & hazelnuts – Add 3oz Huet Vouvray Moelleux 1ere Trie LHL $15"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6028,16 +6242,46 @@
|
|||||||
"phone": "(208) 667-1170",
|
"phone": "(208) 667-1170",
|
||||||
"courses": {
|
"courses": {
|
||||||
"First Course": [
|
"First Course": [
|
||||||
|
{
|
||||||
|
"name": "Lumpia",
|
||||||
|
"desc": "Crispy Filipino spring rolls filled with savory pork, veggies, garlic, and spices, fried golden and served with a sweet chili dipping sauce"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Toasted Ravioli",
|
||||||
|
"desc": "Crispy, golden-breaded ravioli stuffed with portabella mushrooms and ricotta, fried to perfection and served with warm marinara for dipping V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Smoked Steelhead Spread",
|
||||||
|
"desc": "Creamy smoked steelhead dip blended with herbs, lemon, and spices, rich and savory with a delicate smoky finish. Served with fried pita GFA"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
|
{
|
||||||
|
"name": "Oxtail Stew",
|
||||||
|
"desc": "Slow-braised oxtail stew with fall-off-the-bone meat in a rich, savory broth of herbs, butter beans, and Jamaican spices served over rice GF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Elote Mac and Cheese",
|
||||||
|
"desc": "Creamy mac and cheese blended with spiced chicken, roasted corn, chili, and cotija, inspired by classic elotes for a smoky, zesty, crave-worthy twist GFA"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Spam Fried Rice",
|
"name": "Spam Fried Rice",
|
||||||
"desc": "Savory fried rice tossed with crispy Spam, scrambled eggs, green onions, and soy, finished with a hint of sesame for bold, comforting flavor GF"
|
"desc": "Savory fried rice tossed with crispy Spam, scrambled eggs, green onions, and soy, finished with a hint of sesame for bold, comforting flavor GF DF"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
|
{
|
||||||
|
"name": "Tiramisu",
|
||||||
|
"desc": "Classic Italian dessert with espresso-soaked ladyfingers layered with creamy mascarpone, lightly sweetened and finished with a dusting of cocoa GF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Funfetti Edible Cookie Dough",
|
||||||
|
"desc": "Sweet, creamy edible cookie dough loaded with colorful sprinkles, white chocolate chips, rich vanilla flavor, and a fun, nostalgic crunch every bite"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Spanish Flan",
|
||||||
|
"desc": "Silky Spanish custard with rich vanilla flavor, baked to perfection and topped with a smooth, golden caramel sauce GF"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6175,12 +6419,12 @@
|
|||||||
"courses": {
|
"courses": {
|
||||||
"First Course": [
|
"First Course": [
|
||||||
{
|
{
|
||||||
"name": "V DF",
|
"name": "Crispy Spring Rolls",
|
||||||
"desc": "Crispy Spring RollsTasty combination of vegetables and Thai spices hand-rolled in a thin wrapper, deep fried to a golden brown and served with plum sauce"
|
"desc": "Tasty combination of vegetables and Thai spices hand-rolled in a thin wrapper, deep fried to a golden brown and served with plum sauce V DF V+"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "V V+",
|
"name": "Golden Samosas",
|
||||||
"desc": "Golden SamosasA blend of sweet potatoes, carrots, peas, potatoes, cashews and Indian spices in a wonton wrapper, fried and served with a sweet chili dipping sauce"
|
"desc": "A blend of sweet potatoes, carrots, peas, potatoes, cashews and Indian spices in a wonton wrapper, fried and served with a sweet chili dipping sauce V V+ DF"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Chicken Satay",
|
"name": "Chicken Satay",
|
||||||
@@ -6207,8 +6451,8 @@
|
|||||||
"desc": "Your choice of two scoops: vanilla, coconut, huckleberry or Thai tea GF"
|
"desc": "Your choice of two scoops: vanilla, coconut, huckleberry or Thai tea GF"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "GF V V+",
|
"name": "Mango Sticky Rice",
|
||||||
"desc": "Mango Sticky RiceWarm, sweet white sticky rice topped with mango and sweetened coconut cream"
|
"desc": "Warm, sweet white sticky rice topped with mango and sweetened coconut cream GF V V+ DF"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Coconut Cheesecake",
|
"name": "Coconut Cheesecake",
|
||||||
@@ -6232,21 +6476,45 @@
|
|||||||
"phone": "(208) 292-5678",
|
"phone": "(208) 292-5678",
|
||||||
"courses": {
|
"courses": {
|
||||||
"First Course": [
|
"First Course": [
|
||||||
|
{
|
||||||
|
"name": "House-Made Focaccia",
|
||||||
|
"desc": "Honey Butter | Garlic Confit | Trapani Sea Salt V"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Crispy Prosciutto Wrapped Asparagus",
|
"name": "Crispy Prosciutto Wrapped Asparagus",
|
||||||
"desc": "Balsamic Reduction | Crushed Almonds GF"
|
"desc": "Balsamic Reduction | Crushed Almonds GF DF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Romaine Salad",
|
||||||
|
"desc": "Marinated Anchovy | Lemon Garlic Aioli | Parmesan GF"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
{
|
{
|
||||||
"name": "DFA",
|
"name": "Seafood Linguine",
|
||||||
"desc": "Duck ConfitRosemary Gnocchi | Broccolini | Butternut Squash | Fennel | Campari Glaze"
|
"desc": "Seafood Linguine | House-Made Pasta | Penn Cove Clams | Shrimp | Pacific Cod | Lemon Cream Sauce"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Duck Confit",
|
||||||
|
"desc": "Rosemary Gnocchi | Broccolini | Butternut Squash | Fennel | Campari Glaze DFA "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Royal Ranch Short Rib",
|
||||||
|
"desc": "Mushroom Risotto | Brussels Sprouts | Marsala Demi-Glace GF"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
{
|
{
|
||||||
"name": "Tiramisu DomeSoft Sponge Cake | Zabaglione | Cocoa | Coffee Cream",
|
"name": "Tiramisu Dome",
|
||||||
"desc": "Lemon Mascarpone CheesecakeStrawberries | Honey | Sweet Cream Pistachio CannoliCrisp Cannoli Shell | Sweet Ricotta | Toasted Pistachio | Dark Chocolate Curls"
|
"desc": "Soft Sponge Cake | Zabaglione | Cocoa | Coffee Cream V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lemon Mascarpone Cheesecake",
|
||||||
|
"desc": "Strawberries | Honey | Sweet Cream V "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pistachio Cannoli",
|
||||||
|
"desc": "Crisp Cannoli Shell | Sweet Ricotta | Toasted Pistachio | Dark Chocolate Curls V"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6268,12 +6536,31 @@
|
|||||||
"courses": {
|
"courses": {
|
||||||
"First Course": [
|
"First Course": [
|
||||||
{
|
{
|
||||||
"name": "Tomato Basil SoupA Tomato Street favorite! Served with fresh garlic bread",
|
"name": "Tomato Basil Soup",
|
||||||
"desc": "Minestrone SoupAn Italian classic, served with fresh garlic bread A House Garden or Caesar SaladHouse salad with your choice of dressing, or a Caesar salad. Served with fresh garlic bread A"
|
"desc": "A Tomato Street favorite! Served with fresh garlic bread V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Minestrone Soup",
|
||||||
|
"desc": "An Italian classic, served with fresh garlic bread GFA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "House Garden or Caesar Salad",
|
||||||
|
"desc": "House salad with your choice of dressing, or a Caesar salad. Served with fresh garlic bread GFA"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
|
{
|
||||||
|
"name": "Shrimp Aragosta",
|
||||||
|
"desc": "Fettuccini with a rich lobster cream sauce, sauteed prawns and bay shrimp, green onions and oven-dried tomatoes GFA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Carbonara",
|
||||||
|
"desc": "A classic carbonara with a roasted garlic and black pepper cream sauce, tossed with bacon and spaghetti noodles, topped with parmesan cheese GFA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Chicken Parmigiana",
|
||||||
|
"desc": "Breaded chicken breast topped with marinara sauce, melted mozzarella, provolone and parmesan cheeses, served with a side of fettuccine Alfredo"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
{
|
{
|
||||||
@@ -6657,24 +6944,44 @@
|
|||||||
"courses": {
|
"courses": {
|
||||||
"First Course": [
|
"First Course": [
|
||||||
{
|
{
|
||||||
"name": "PolpetteHouse Made Meatballs. Nonna Sauce. Parmigiano-Reggiano.",
|
"name": "Polpette",
|
||||||
"desc": "Caesar SaladCrispy Capers. Parmigiano-Reggiano. Croutons. E OO. A FocacciaHouse Made. Tomato Sauce. Green Onions. Sea Salt. E OO."
|
"desc": "House Made Meatballs. Nonna Sauce. Parmigiano-Reggiano."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Caesar Salad",
|
||||||
|
"desc": "Crispy Capers. Parmigiano-Reggiano. Croutons. EVOO. GFA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Focaccia",
|
||||||
|
"desc": "House Made. Tomato Sauce. Green Onions. Sea Salt. EVOO."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
|
{
|
||||||
|
"name": "Calabrese Pizza",
|
||||||
|
"desc": "House Italian Sausage. Burrata. Calabrian Chili Sauce. Fresh Scallions. Sea Salt. GFA – Sub house gluten-free crust $4"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Margherita Pizza",
|
"name": "Margherita Pizza",
|
||||||
"desc": "San Marzano Tomato Sauce. Fresh Mozzarella. Basil. Basil Oil. – Sub house gluten-free crust $4 GFA"
|
"desc": "San Marzano Tomato Sauce. Fresh Mozzarella. Basil. Basil Oil. GFA V – Sub house gluten-free crust $4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Spaghetti & Meatballs",
|
||||||
|
"desc": "House Meatballs. Marinara. Fresh Basil. Parmigiano-Reggiano."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
|
{
|
||||||
|
"name": "Zeppole",
|
||||||
|
"desc": "Italian Donut. Lemon. Mascarpone. V"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Chocolate Panna Cotta",
|
"name": "Chocolate Panna Cotta",
|
||||||
"desc": "Chantilly Cream. Shaved Chocolate. GF"
|
"desc": "Chantilly Cream. Shaved Chocolate. GF V"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Gelato",
|
"name": "Gelato",
|
||||||
"desc": "Whiskey Cream or Amarena Cherry. GF"
|
"desc": "Whiskey Cream or Amarena Cherry. GF V"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6695,20 +7002,44 @@
|
|||||||
"courses": {
|
"courses": {
|
||||||
"First Course": [
|
"First Course": [
|
||||||
{
|
{
|
||||||
"name": "Whipped Honey CornbreadOur Famous Cornbread With Whipped Honey Butter",
|
"name": "Whipped Honey Cornbread",
|
||||||
"desc": "Crawfish GougeresServed With House Creole Sauce Andouille Cheddar DipServed With Firecracker Crostini"
|
"desc": "Our Famous Cornbread With Whipped Honey Butter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Crawfish Gougeres",
|
||||||
|
"desc": "Served With House Creole Sauce"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Andouille Cheddar Dip",
|
||||||
|
"desc": "Served With Firecracker Crostini"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
{
|
{
|
||||||
"name": "Gator Red RedAlligator, Andouille Sausage, Red Beans, Holy Trinity",
|
"name": "Gator Red Red",
|
||||||
"desc": "Bacon-Wrapped Shrimp And GritsWith Stone-Ground Cheesy Grits And Red Eye Gravy Short Rib A La QueenCarrots, Peas, Corn, Potato"
|
"desc": "Alligator, Andouille Sausage, Red Beans, Holy Trinity GF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bacon-Wrapped Shrimp And Grits",
|
||||||
|
"desc": "With Stone-Ground Cheesy Grits And Red Eye Gravy GF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Short Rib A La Queen",
|
||||||
|
"desc": "Carrots, Peas, Corn, Potato"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
{
|
{
|
||||||
"name": "Praline BlondieThink Nutty, Caramel Goodness!",
|
"name": "Praline Blondie",
|
||||||
"desc": "BeignetOur Classic French Doughnut! Have As Is, Make It An Affogato, Or A 21+ Affogato! – Affogato $8, 21+ Affogato $9 Tarte Au CitronLemon Custard Tarte With Fresh Berries"
|
"desc": "Think Nutty, Caramel Goodness! V"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Beignet",
|
||||||
|
"desc": "Our Classic French Doughnut! Have As Is, Make It An Affogato, Or A 21+ Affogato! – Affogato $8, 21+ Affogato $9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tarte Au Citron",
|
||||||
|
"desc": "Lemon Custard Tarte With Fresh Berries V"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6728,29 +7059,45 @@
|
|||||||
"phone": "(208) 758-7770",
|
"phone": "(208) 758-7770",
|
||||||
"courses": {
|
"courses": {
|
||||||
"First Course": [
|
"First Course": [
|
||||||
|
{
|
||||||
|
"name": "Stuffed Onion",
|
||||||
|
"desc": "Italian Sausage. Herbs. Parmigiano-Reggiano. GF"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Grilled Asparagus",
|
"name": "Grilled Asparagus",
|
||||||
"desc": "Whipped Tarragon Chèvre. Fresh Peas. Lemon Jelly. GF"
|
"desc": "Whipped Tarragon Chèvre. Fresh Peas. Lemon Jelly. GF V"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Spanish Bomba",
|
"name": "Spanish Bomba",
|
||||||
"desc": "Sherry Braised Pork. Sauce Bravas. Garlic Aioli. GF"
|
"desc": "Sherry Braised Pork. Sauce Bravas. Garlic Aioli. GF DF"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
{
|
{
|
||||||
"name": "Goose RavioliBrown Butter. Parmigiano-Reggiano.",
|
"name": "Goose Ravioli",
|
||||||
"desc": "Grilled Lamb SkewerZa’atar. Charred Broccolini. Mint Yogurt. Migas al PastorPork Belly. Chorizo. Smoked Paprika. Red Peppers. Breadcrumbs. Grapes."
|
"desc": "Brown Butter. Parmigiano-Reggiano."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Grilled Lamb Skewer",
|
||||||
|
"desc": "Za’atar. Charred Broccolini. Mint Yogurt. GF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Migas al Pastor",
|
||||||
|
"desc": "Pork Belly. Chorizo. Smoked Paprika. Red Peppers. Breadcrumbs. Grapes."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
|
{
|
||||||
|
"name": "Galatopita",
|
||||||
|
"desc": "Lemon Custard Pie. Cinnamon. Honey. V"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Chocolate Crémeux",
|
"name": "Chocolate Crémeux",
|
||||||
"desc": "Chili Olive Oil. Flaky Sea Salt. GF"
|
"desc": "Chili Olive Oil. Flaky Sea Salt. GF V"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Cheese Plate",
|
"name": "Cheese Plate",
|
||||||
"desc": "Tomme de Saison. Cherry Jam. House Cracker. GF"
|
"desc": "Tomme de Saison. Cherry Jam. House Cracker. GF V"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6770,29 +7117,49 @@
|
|||||||
"phone": "(509) 838-4600",
|
"phone": "(509) 838-4600",
|
||||||
"courses": {
|
"courses": {
|
||||||
"First Course": [
|
"First Course": [
|
||||||
|
{
|
||||||
|
"name": "Jalapeño Cheddar Chicken Soup",
|
||||||
|
"desc": "Chicken stock base, jalapeños, sharp cheddar, shredded chicken, fresh herbs, and a touch of cream — a must-try! GF"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Mandarin Salad",
|
"name": "Mandarin Salad",
|
||||||
"desc": "Organic spring greens tossed in an Asian vinaigrette, topped with vegetable slaw, mandarins, toasted cashews and crispy wontons– Vegan Available by request GFA"
|
"desc": "Organic spring greens tossed in an Asian vinaigrette, topped with vegetable slaw, mandarins, toasted cashews and crispy wontons GFA V – Vegan Available by request"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Roasted Beet Salad",
|
"name": "Roasted Beet Salad",
|
||||||
"desc": "Organic spring greens tossed in a balsamic white truffle vinaigrette, topped with roasted beets, toasted hazelnuts and chèvre – Vegan Available by request GF"
|
"desc": "Organic spring greens tossed in a balsamic white truffle vinaigrette, topped with roasted beets, toasted hazelnuts and chèvre GF V – Vegan Available by request"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Second Course": [
|
"Second Course": [
|
||||||
|
{
|
||||||
|
"name": "Lamb Ragu",
|
||||||
|
"desc": "Tender braised leg of lamb in a rich, rustic tomato sauce, tossed with bucatini pasta and finished with fine herbs and parmesan GFA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Shrimp Risotto and Lobster Butter",
|
||||||
|
"desc": "Creamy risotto tossed with fresh asparagus, garlic-sauteed jumbo shrimp, and finished with a decadent lobster butter GF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Yellow Curry Chicken or Tofu",
|
||||||
|
"desc": "Housemade yellow curry, choice of tofu or chicken. Served with a coconut rice cake, sweet peas, heirloom carrots, roasted red peppers, and pea shoots GF – Vegan Available by request"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"Third Course": [
|
"Third Course": [
|
||||||
|
{
|
||||||
|
"name": "Mini Margarita Pie",
|
||||||
|
"desc": "Frozen key lime pie with graham cracker crust, silver tequila, whipped cream and red sea salt V"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Chocolate Pot de Crème",
|
"name": "Chocolate Pot de Crème",
|
||||||
"desc": "Rich mousse with coconut cream, chocolate and a hint of spice. Topped with raspberry purée and candied pecans – Vegan Available by request GF"
|
"desc": "Rich mousse with coconut cream, chocolate and a hint of spice. Topped with raspberry purée and candied pecans GF V – Vegan Available by request"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Wiley’s Bourbon Crème Brûlée",
|
"name": "Wiley’s Bourbon Crème Brûlée",
|
||||||
"desc": "Brûléed custard with vanilla bean and orange peel. Topped with bourbon-nutmeg caramel and whipped cream on the side GF"
|
"desc": "Brûléed custard with vanilla bean and orange peel. Topped with bourbon-nutmeg caramel and whipped cream on the side GF V"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
|||||||
38
README.md
38
README.md
@@ -16,6 +16,7 @@ Each couple gets their own set of interest checkboxes ("His Picks" / "Her Picks"
|
|||||||
- **Interest filter** — narrow the list to His Picks, Her Picks, Both Picked, or Either Picked
|
- **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
|
- **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
|
- **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
|
||||||
|
- **Year selector** — dropdown on the course browse bar switches between available event years (2025, 2026); restaurant data, filters, and interest picks are all scoped to the selected year
|
||||||
- **Clear Filters** — one-click button to reset all search and filter fields back to their defaults
|
- **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
|
- **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
|
- **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
|
||||||
@@ -23,7 +24,7 @@ Each couple gets their own set of interest checkboxes ("His Picks" / "Her Picks"
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
1. Serve the folder from a web server and open `restaurant-picker.html` in a browser. (The app fetches `2026-restaurants.json` at runtime, so it cannot be opened directly as a local `file://` URL — a server is required. A simple option is the VS Code Live Server extension, or `npx serve .` in the project folder.)
|
1. Serve the folder from a web server and open `restaurant-picker.html` in a browser. (The app fetches a `YYYY-restaurants.json` file at runtime, so it cannot be opened directly as a local `file://` URL — a server is required. A simple option is the VS Code Live Server extension, or `npx serve .` in the project folder.)
|
||||||
2. Browse the restaurant list or use the toolbar filters to narrow choices.
|
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.
|
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.
|
4. Check the **You** and **Wife** boxes on any restaurant you're each interested in.
|
||||||
@@ -45,12 +46,25 @@ Each couple gets their own set of interest checkboxes ("His Picks" / "Her Picks"
|
|||||||
|
|
||||||
```
|
```
|
||||||
restaurant-picker.html # App shell — HTML, CSS, and JS logic
|
restaurant-picker.html # App shell — HTML, CSS, and JS logic
|
||||||
2026-restaurants.json # Restaurant data for the 2026 event (loaded at runtime via fetch)
|
2026-restaurants.json # Restaurant + event date data for the 2026 event
|
||||||
|
2025-restaurants.json # Restaurant + event date data for the 2025 event
|
||||||
LICENSE
|
LICENSE
|
||||||
README.md
|
README.md
|
||||||
```
|
```
|
||||||
|
|
||||||
Each year, create a new `YYYY-restaurants.json` and update the filename in the `fetch()` call near the bottom of `restaurant-picker.html`.
|
### Adding a New Year
|
||||||
|
|
||||||
|
1. Create a new `YYYY-restaurants.json` file following the schema described below (see [Data Entry Guide](#data-entry-guide)).
|
||||||
|
2. In `restaurant-picker.html`, add a new `<option>` to the year selector dropdown:
|
||||||
|
```html
|
||||||
|
<select id="yearSelect" onchange="loadYear(this.value)">
|
||||||
|
<option value="2027">2027</option> <!-- add new year at top -->
|
||||||
|
<option value="2026">2026</option>
|
||||||
|
<option value="2025">2025</option>
|
||||||
|
</select>
|
||||||
|
```
|
||||||
|
3. Update the hardcoded default in the `loadYear('2026')` init call at the bottom of the `<script>` block to the new year.
|
||||||
|
4. Update the static fallback date in the `<span id="eventDates">` header element — it will be overwritten at runtime, but the static value is shown briefly on first load.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -58,6 +72,20 @@ Each year, create a new `YYYY-restaurants.json` and update the filename in the `
|
|||||||
|
|
||||||
Each year's restaurant data is stored as a JSON file (`YYYY-restaurants.json`) loaded by `restaurant-picker.html` at runtime. 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.
|
Each year's restaurant data is stored as a JSON file (`YYYY-restaurants.json`) loaded by `restaurant-picker.html` at runtime. 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.
|
||||||
|
|
||||||
|
### File-Level Schema
|
||||||
|
|
||||||
|
Each `YYYY-restaurants.json` is an **object** (not a bare array) with two top-level keys:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"eventDates": "FEBRUARY 26 – MARCH 7, 2026",
|
||||||
|
"restaurants": [ ... ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `eventDates` — the display string shown in the header when that year is selected; use an em dash (`–`) between the start and end dates
|
||||||
|
- `restaurants` — array of restaurant objects (see schema below)
|
||||||
|
|
||||||
### Restaurant Object Schema
|
### Restaurant Object Schema
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -179,7 +207,9 @@ Run the following Python script against the JSON file to identify any restaurant
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
with open('2026-restaurants.json', encoding='utf-8') as f:
|
with open('2026-restaurants.json', encoding='utf-8') as f:
|
||||||
restaurants = json.load(f)
|
data = json.load(f)
|
||||||
|
|
||||||
|
restaurants = data['restaurants']
|
||||||
|
|
||||||
for r in restaurants:
|
for r in restaurants:
|
||||||
name = r.get('name', 'Unknown')
|
name = r.get('name', 'Unknown')
|
||||||
|
|||||||
48
memory/MEMORY.md
Normal file
48
memory/MEMORY.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# Inlander Restaurant Week Picker - Project Memory
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
- See `scraping-guide.md` for full year-scraping instructions and script templates
|
||||||
|
- See `html-structures.md` for HTML parsing patterns per restaurant type
|
||||||
|
- Project dir: `\\WinServ-20-3.chns.local\Profiles\derekc\Documents\Coding Projects\Gitea-CooperandGoodman-Inlander-Restaurant-Week-Picker\Inlander-Restaurant-Week-Picker`
|
||||||
|
|
||||||
|
## Key Constraints (CRITICAL)
|
||||||
|
- **WebFetch cannot access web.archive.org** — use `curl` via Bash tool instead
|
||||||
|
- **PowerShell cannot run scripts from UNC paths** (\\server\...) — always `cp` scripts to local temp first
|
||||||
|
- **bash `/tmp`** = `C:\Users\DEREKC~1.CHN\AppData\Local\Temp` (8.3 short name)
|
||||||
|
- **PowerShell temp** = `C:\Users\derekc.CHNSLocal\AppData\Local\Temp` (long name) — same dir, different string
|
||||||
|
- **Wayback Machine rate limits** to ~20 requests before throttling with 429; use 3-5 sec delays, wait 30+ min after getting blocked
|
||||||
|
|
||||||
|
## JSON Schema
|
||||||
|
Each entry in `YEAR-restaurants.json`:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "Restaurant Name",
|
||||||
|
"slug": "restaurantslug",
|
||||||
|
"price": 45,
|
||||||
|
"areas": ["Downtown"],
|
||||||
|
"cuisine": "American",
|
||||||
|
"url": "https://inlanderrestaurantweek.com/project/SLUG/",
|
||||||
|
"menu": {
|
||||||
|
"hours": "Menu served 5pm-close",
|
||||||
|
"phone": "(509) 555-1234",
|
||||||
|
"courses": {
|
||||||
|
"First Course": [{"name": "Dish Name", "desc": "Description"}],
|
||||||
|
"Second Course": [...],
|
||||||
|
"Third Course": [...]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Price is always 25, 35, or 45. gardenparty genuinely has 4 Third Course options.
|
||||||
|
|
||||||
|
## 2025 Data Status — COMPLETE
|
||||||
|
- **File**: `2025-restaurants.json` (121 restaurants)
|
||||||
|
- **Wayback snapshot used**: `20250306132630`
|
||||||
|
- **Complete (3/3/3+)**: 112 restaurants
|
||||||
|
- **gardenparty**: 3/3/4 — correct, it genuinely offers 4 dessert choices
|
||||||
|
- **tavolata**: 3/3/3 — FIXED (recovered Third Course from snapshot `20250306132630`)
|
||||||
|
- **0/0/0 (JS-only, unrecoverable)**: heritage, kismet, littlenoodle, macdaddys, purgatory, redtail, republickitchen, republicpi, vicinopizza
|
||||||
|
|
||||||
|
## Scripts in Project Directory
|
||||||
|
- `fix-tavolata.ps1` — already run, tavolata is complete; kept for reference
|
||||||
|
- `check-2025.ps1` — validates all restaurant course counts
|
||||||
152
memory/html-structures.md
Normal file
152
memory/html-structures.md
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
# IRW Website HTML Structure Reference
|
||||||
|
|
||||||
|
## Restaurant Page URL
|
||||||
|
Live: `https://inlanderrestaurantweek.com/project/SLUG/`
|
||||||
|
Archived: `https://web.archive.org/web/TIMESTAMP/https://inlanderrestaurantweek.com/project/SLUG/`
|
||||||
|
|
||||||
|
## Page Framework
|
||||||
|
The site uses WordPress + Divi theme. Relevant container class: `et_pb_text_inner`.
|
||||||
|
Each course section typically occupies one or two `et_pb_text_inner` divs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Course Layout Types
|
||||||
|
|
||||||
|
### Layout A — Heading and items in SEPARATE divs (most restaurants)
|
||||||
|
```html
|
||||||
|
<div class="et_pb_text_inner"><h3>First Course</h3></div>
|
||||||
|
<div class="et_pb_text_inner">
|
||||||
|
<p><strong>Dish Name</strong><br/>Description</p>
|
||||||
|
<p><strong>Dish Name 2</strong><br/>Description 2</p>
|
||||||
|
</div>
|
||||||
|
<div class="et_pb_text_inner"><h3>Second Course</h3></div>
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Layout B — Heading and items in SAME div (tavolata, durkins, table13, others)
|
||||||
|
```html
|
||||||
|
<div class="et_pb_text_inner">
|
||||||
|
<h3>First Course</h3>
|
||||||
|
<p><strong>Dish Name</strong><br/>Description</p>
|
||||||
|
<p><strong>Dish Name 2</strong><br/>Description 2</p>
|
||||||
|
</div>
|
||||||
|
<div class="et_pb_text_inner">
|
||||||
|
<h3>Second Course</h3>
|
||||||
|
...
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dish Name Tag Styles
|
||||||
|
|
||||||
|
### Style 1 — `<strong>` tag (most restaurants)
|
||||||
|
Examples: 315cuisine, anthonys, bardenay, barkrescuepub, etc.
|
||||||
|
```html
|
||||||
|
<p><strong>Dish Name</strong><br/>Description text here</p>
|
||||||
|
<p><strong>Dish Name</strong> <br/>With space before br</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Style 2 — `<b>` tag with `<br/>` inside (India House, Lebanon, Karma, ponderosa)
|
||||||
|
```html
|
||||||
|
<p><b>Dish Name <br/></b><span>Description text</span></p>
|
||||||
|
<p><b>Dish Name<br/></b> Description without span</p>
|
||||||
|
```
|
||||||
|
Key: name is inside `<b>`, the `<br/>` is INSIDE the `<b>` tag.
|
||||||
|
|
||||||
|
### Style 3 — `<b>` + `<strong>` combo (1898 restaurant)
|
||||||
|
```html
|
||||||
|
<p><span><b>First Part</b></span><strong>Second Part</strong> Description</p>
|
||||||
|
```
|
||||||
|
Full dish name = "First Part" + " " + "Second Part"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Field Extraction Patterns
|
||||||
|
|
||||||
|
### Name (from page title)
|
||||||
|
```
|
||||||
|
<title>Restaurant Name | Inlander Restaurant Week</title>
|
||||||
|
```
|
||||||
|
Regex: `<title>(.+?) \| Inlander`
|
||||||
|
|
||||||
|
### Price (WARNING: unreliable — use price listing page instead)
|
||||||
|
```html
|
||||||
|
<h1 style="text-align: left;"><strong>$45</strong></h1>
|
||||||
|
```
|
||||||
|
Regex: `<strong>\$(\d+)</strong>`
|
||||||
|
PROBLEM: Some pages show drink prices like $22 that match before the real price.
|
||||||
|
SOLUTION: Always build an authoritative slug→price map from the price listing page.
|
||||||
|
|
||||||
|
### Price Listing Page — Authoritative Prices
|
||||||
|
URL: `https://inlanderrestaurantweek.com/price/` (or Wayback archived version)
|
||||||
|
```html
|
||||||
|
<article class="et_pb_portfolio_item ... project_category_45 ...">
|
||||||
|
...
|
||||||
|
<a href="https://inlanderrestaurantweek.com/project/SLUG/">
|
||||||
|
```
|
||||||
|
Extract price tier from `project_category_(25|35|45)` CSS class.
|
||||||
|
Extract slug from `href=".../project/SLUG/"`.
|
||||||
|
|
||||||
|
### Cuisine
|
||||||
|
```html
|
||||||
|
CUISINE: AMERICAN COMFORT FOOD
|
||||||
|
```
|
||||||
|
Often inside `<strong>` or `<em>` tags. Extract uppercase text after "CUISINE:".
|
||||||
|
Apply `.ToTitleCase()` for proper formatting.
|
||||||
|
|
||||||
|
### Phone
|
||||||
|
Area codes: 509 (Spokane area) or 208 (Idaho/CDA area)
|
||||||
|
Pattern: `(509) 555-1234` or `(208) 555-1234`
|
||||||
|
Regex: `\((?:208|509)\) \d{3}-\d{4}`
|
||||||
|
|
||||||
|
### Hours
|
||||||
|
```
|
||||||
|
Menu served 5pm-9pm nightly
|
||||||
|
Menu served Thursday-Sunday, 5-9pm
|
||||||
|
```
|
||||||
|
Regex: `Menu served [^<]+`
|
||||||
|
|
||||||
|
### Area
|
||||||
|
Look for area keywords (ALL CAPS in source) anywhere in the HTML:
|
||||||
|
- DOWNTOWN, NORTH SPOKANE, SOUTH SPOKANE, WEST SPOKANE, SPOKANE VALLEY
|
||||||
|
- AIRWAY HEIGHTS, LIBERTY LAKE, COEUR D'ALENE, POST FALLS, HAYDEN, ATHOL, WORLEY
|
||||||
|
Default to ["Downtown"] if nothing matched.
|
||||||
|
Some restaurants appear in multiple areas — collect all matches.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dietary Tag Filtering
|
||||||
|
Skip these as dish names — they appear in `<strong>` but are dietary labels, not dish names:
|
||||||
|
- GF (gluten free)
|
||||||
|
- GFA (gluten free available)
|
||||||
|
- V, V+ (vegetarian, vegan)
|
||||||
|
- DF, DFA (dairy free, dairy free available)
|
||||||
|
- V:, V+A (legend lines)
|
||||||
|
- 2025 (year marker some restaurants include)
|
||||||
|
- Drink (some restaurants label beverage course)
|
||||||
|
|
||||||
|
Full regex: `^(GF|GFA|V\+?|DF|DFA|V:|2025|Drink|V\+A)$`
|
||||||
|
Also skip names matching `^[A-Z]{1,3}:` (legend lines like "GF: Gluten Free")
|
||||||
|
Also skip names shorter than 3 chars or longer than 80 chars.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Restaurants by Known HTML Style (2025)
|
||||||
|
|
||||||
|
**Layout B (same-block)**: tavolata, durkins, table13, terraza, and others
|
||||||
|
**Style 2 (`<b>` tags)**: indiahouse, lebanon, karma, ponderosa, collectivekitchen, dryfly, masselowslounge, vieuxcarre, wileys, osprey, shawnodonnells, ganderryegrass
|
||||||
|
**Style 3 (`<b>`+`<strong>` combo)**: 1898
|
||||||
|
|
||||||
|
Note: These styles may change year to year as restaurants update their pages.
|
||||||
|
Always check a few representative pages before assuming the same structure applies.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## JS-Only Pages (no static HTML menu content)
|
||||||
|
These restaurants had no recoverable menu data from any Wayback snapshot in 2025:
|
||||||
|
heritage, kismet, littlenoodle, macdaddys, purgatory, redtail, republickitchen, republicpi, vicinopizza
|
||||||
|
|
||||||
|
Their pages are fully JS-rendered — the static HTML captured by Wayback Machine
|
||||||
|
shows the page shell but not the menu content. For future years, these may or may not
|
||||||
|
have static caches depending on server-side rendering changes.
|
||||||
237
memory/scraping-guide.md
Normal file
237
memory/scraping-guide.md
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
# IRW Scraping Guide — Full Process for Adding a New Year
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
The Inlander Restaurant Week website (inlanderrestaurantweek.com) is WordPress/Divi.
|
||||||
|
Menu pages are partially JS-rendered but WP-Super-Cache creates static HTML snapshots
|
||||||
|
that the Wayback Machine archives. We scrape those static snapshots.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1: Find Restaurant Slugs
|
||||||
|
|
||||||
|
Fetch the price listing page to get all slugs for that year:
|
||||||
|
```bash
|
||||||
|
curl -s "https://web.archive.org/web/TIMESTAMP/https://inlanderrestaurantweek.com/price/" \
|
||||||
|
-o /tmp/irw-price-YEAR.html
|
||||||
|
```
|
||||||
|
|
||||||
|
Pick a timestamp close to the event (Wayback Machine format: YYYYMMDDHHmmss).
|
||||||
|
The price listing page has portfolio items like:
|
||||||
|
```html
|
||||||
|
<article class="et_pb_portfolio_item ... project_category_45">
|
||||||
|
<a href="https://inlanderrestaurantweek.com/project/SLUG/">
|
||||||
|
```
|
||||||
|
Extract slug from the href. The class `project_category_(25|35|45)` gives authoritative price.
|
||||||
|
|
||||||
|
**Important**: Scrape the price listing page FIRST and save the slug→price map.
|
||||||
|
Some restaurant pages have drink prices ($22, $33) that confuse the price parser.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 2: Scrape Each Restaurant Page
|
||||||
|
|
||||||
|
Use a PowerShell script (written to project dir, copied to local temp to run):
|
||||||
|
|
||||||
|
**Wayback Machine URL format**:
|
||||||
|
```
|
||||||
|
https://web.archive.org/web/TIMESTAMP/https://inlanderrestaurantweek.com/project/SLUG/
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key fields to extract**:
|
||||||
|
```powershell
|
||||||
|
# Name
|
||||||
|
$nameM = [regex]::Match($html, '<title>(.+?) \| Inlander')
|
||||||
|
|
||||||
|
# Price (from page, but USE PRICE LISTING MAP - this can be wrong)
|
||||||
|
$priceM = [regex]::Match($html, '<strong>\$(\d+)</strong>')
|
||||||
|
|
||||||
|
# Cuisine
|
||||||
|
$cuisineM = [regex]::Match($html, 'CUISINE:\s*([A-Z][A-Za-z/ ]+?)(?:\s*</|\s*<)')
|
||||||
|
$cuisine = (Get-Culture).TextInfo.ToTitleCase($c.ToLower())
|
||||||
|
|
||||||
|
# Phone
|
||||||
|
$phoneM = [regex]::Match($html, '\((?:208|509)\) \d{3}-\d{4}')
|
||||||
|
|
||||||
|
# Hours
|
||||||
|
$hoursM = [regex]::Match($html, 'Menu served [^<]+')
|
||||||
|
|
||||||
|
# Area (match against known area keys, case-insensitive)
|
||||||
|
$areaMap keys: "AIRWAY HEIGHTS","ATHOL","COEUR D'ALENE","POST FALLS","HAYDEN",
|
||||||
|
"LIBERTY LAKE","NORTH SPOKANE","SOUTH SPOKANE","SPOKANE VALLEY",
|
||||||
|
"WEST SPOKANE","WORLEY","DOWNTOWN"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Rate limiting**: Add `Start-Sleep -Milliseconds 2000` between each request.
|
||||||
|
After a 429, stop and wait 30+ minutes before trying again.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 3: Parse Menu Courses
|
||||||
|
|
||||||
|
### Course Block Extraction (`Get-CourseBlock`)
|
||||||
|
Two HTML layouts exist:
|
||||||
|
|
||||||
|
**Layout A** (most common): heading and items in SEPARATE `et_pb_text_inner` blocks
|
||||||
|
```powershell
|
||||||
|
# Strategy 1: find content between this label and next label
|
||||||
|
$m = [regex]::Match($html, [regex]::Escape($label) + '(.+?)(?=' + [regex]::Escape($nextLabel) + ')', $opts)
|
||||||
|
|
||||||
|
# Strategy 3 (fallback): items in next et_pb_text_inner block
|
||||||
|
$im = [regex]::Match($sub, '(?s)et_pb_text_inner">(?!<h[123])(.+?)(?=et_pb_text_inner"><h|</div>\s*</div>\s*</div>\s*</div>\s*<div)', $opts)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Layout B** (some restaurants — tavolata, durkins, table13, etc.): heading + items in SAME block
|
||||||
|
```powershell
|
||||||
|
# Strategy 2: extract <p> tags after </h3> within same div
|
||||||
|
$sameDivM = [regex]::Match($sub, '(?s)</h[123]>\s*(<p.+?)(?=</div>)', $opts)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dish Parsing (`Parse-Dish`)
|
||||||
|
Three tag styles exist:
|
||||||
|
|
||||||
|
**Style 1** (most restaurants): `<strong>` for name
|
||||||
|
```html
|
||||||
|
<p><strong>Dish Name</strong><br/>Description text</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Style 2** (India House, Lebanon, Karma, others): `<b>` with `<br/>` before `</b>`
|
||||||
|
```html
|
||||||
|
<p><b>Dish Name <br/></b><span>Description text</span></p>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Style 3** (1898): `<b>` + `<strong>` combination
|
||||||
|
```html
|
||||||
|
<p><span><b>Part1</b></span><strong>Part2</strong> Description</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Multi-strategy parser** (handles all three):
|
||||||
|
```powershell
|
||||||
|
function Parse-Dish($pContent) {
|
||||||
|
$opts = [System.Text.RegularExpressions.RegexOptions]::Singleline
|
||||||
|
|
||||||
|
# Style 2: <b>Name <br/></b>
|
||||||
|
$bWithBrM = [regex]::Match($pContent, '(?s)<b>(.*?)<br\s*/?>', $opts)
|
||||||
|
if ($bWithBrM.Success) {
|
||||||
|
$name = Get-CleanText $bWithBrM.Groups[1].Value
|
||||||
|
if (Test-ValidDishName $name) {
|
||||||
|
$desc = Get-CleanText ($pContent.Substring($bWithBrM.Index + $bWithBrM.Length))
|
||||||
|
return [PSCustomObject]@{ name = $name; desc = $desc }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Style 3: <b>Part1</b>...<strong>Part2</strong>
|
||||||
|
$bM = [regex]::Match($pContent, '(?s)<b>(.*?)</b>', $opts)
|
||||||
|
if ($bM.Success) {
|
||||||
|
$namePart = Get-CleanText $bM.Groups[1].Value
|
||||||
|
if (Test-ValidDishName $namePart) {
|
||||||
|
$afterB = $pContent.Substring($bM.Index + $bM.Length)
|
||||||
|
$sM2 = [regex]::Match($afterB, '(?s)^[^<]*<strong>(.*?)</strong>(.*)', $opts)
|
||||||
|
if ($sM2.Success) {
|
||||||
|
$p2 = Get-CleanText $sM2.Groups[1].Value
|
||||||
|
if (-not (Test-DietaryTag $p2) -and $p2.Length -ge 2) {
|
||||||
|
return [PSCustomObject]@{ name = "$namePart $p2".Trim(); desc = Get-CleanText $sM2.Groups[2].Value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [PSCustomObject]@{ name = $namePart; desc = Get-CleanText $afterB }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Style 1: <strong>Name</strong>
|
||||||
|
$sM = [regex]::Match($pContent, '(?s)<strong>(.*?)</strong>', $opts)
|
||||||
|
if ($sM.Success) {
|
||||||
|
$name = Get-CleanText $sM.Groups[1].Value
|
||||||
|
if (-not (Test-ValidDishName $name)) { return $null }
|
||||||
|
$afterBr = ''
|
||||||
|
if ($pContent -match '(?s)<br\s*/?>(.*?)$') { $afterBr = $matches[1] }
|
||||||
|
else { $am = [regex]::Match($pContent, '(?s)</strong>(.*?)$', $opts); if ($am.Success) { $afterBr = $am.Groups[1].Value } }
|
||||||
|
return [PSCustomObject]@{ name = $name; desc = Get-CleanText $afterBr }
|
||||||
|
}
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-ValidDishName($name) {
|
||||||
|
$name.Length -ge 3 -and $name.Length -le 80 -and
|
||||||
|
$name -notmatch '^(GF|GFA|V\+?|DF|DFA|V:|2025|Drink|V\+A)$' -and
|
||||||
|
$name -notmatch '^[A-Z]{1,3}:'
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-DietaryTag($str) {
|
||||||
|
$str -match '^(GF|GFA|V\+?|DF|DFA|V:|2025|Drink|V\+A)$'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTML Cleanup
|
||||||
|
```powershell
|
||||||
|
function Get-CleanText($rawHtml) {
|
||||||
|
$t = $rawHtml -replace '<[^>]+>', ' '
|
||||||
|
$t = $t -replace '&', '&' -replace ''', "'" -replace '"', '"'
|
||||||
|
$t = $t -replace '<', '<' -replace '>', '>' -replace ' ', ' '
|
||||||
|
$t = $t -replace '–', '-' -replace '—', '-'
|
||||||
|
($t -replace '\s+', ' ').Trim()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 4: Fix Prices
|
||||||
|
|
||||||
|
After scraping, apply authoritative prices from the price listing page:
|
||||||
|
- Parse `project_category_(25|35|45)` CSS class from portfolio items
|
||||||
|
- Match slug from adjacent `href` attribute
|
||||||
|
- Build a hashtable and apply to all entries
|
||||||
|
|
||||||
|
Common gotcha: Restaurant pages may show $22 (wine), $33 (lunch) — these are NOT the event price.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 5: Recover Missing Restaurants
|
||||||
|
|
||||||
|
If a restaurant has 0/0/0 courses:
|
||||||
|
1. Try alternate Wayback timestamps: `20250401000000`, `20250415000000`, `20250501000000`, `20250601000000`
|
||||||
|
2. Check if page uses Layout B (same-block) — add Strategy 2 to course block extractor
|
||||||
|
3. Check if page uses `<b>` tags instead of `<strong>` for dish names
|
||||||
|
|
||||||
|
**Known JS-only restaurants** (no static cache recoverable for 2025):
|
||||||
|
heritage, kismet, littlenoodle, macdaddys, purgatory, redtail, republickitchen, republicpi, vicinopizza
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 6: Output and Validation
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Save as UTF-8 (important — special characters in restaurant names)
|
||||||
|
$json = $data | ConvertTo-Json -Depth 10
|
||||||
|
[System.IO.File]::WriteAllText($outPath, $json, [System.Text.Encoding]::UTF8)
|
||||||
|
|
||||||
|
# Validate: list any restaurant not at 3/3/3
|
||||||
|
$data | Where-Object {
|
||||||
|
$_.menu.courses.'First Course'.Count -ne 3 -or
|
||||||
|
$_.menu.courses.'Second Course'.Count -ne 3 -or
|
||||||
|
$_.menu.courses.'Third Course'.Count -ne 3
|
||||||
|
} | ForEach-Object {
|
||||||
|
"$($_.slug): $($_.menu.courses.'First Course'.Count)/$($_.menu.courses.'Second Course'.Count)/$($_.menu.courses.'Third Course'.Count)"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PowerShell Script Execution Pattern (REQUIRED)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Write script to project dir (via Write tool or Edit)
|
||||||
|
# Then in bash:
|
||||||
|
cp "//WinServ-20-3.chns.local/Profiles/derekc/Documents/Coding Projects/.../script.ps1" \
|
||||||
|
"/c/Users/derekc.CHNSLocal/AppData/Local/Temp/script.ps1"
|
||||||
|
powershell.exe -ExecutionPolicy Bypass -File "C:\Users\derekc.CHNSLocal\AppData\Local\Temp\script.ps1"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Never** use `powershell -Command "..."` for multi-line scripts — escaping is unreliable.
|
||||||
|
**Never** try to run `.ps1` directly from `\\WinServ-20-3...` UNC path — execution policy blocks it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PowerShell Gotchas
|
||||||
|
- `"$slug: text"` fails if `:` follows var — use `"${slug}: text"`
|
||||||
|
- Function names like `Is-X`, `Decode-X`, `Parse-X` get PSScriptAnalyzer warnings (unapproved verbs) but work fine
|
||||||
|
- `return ,$array` (comma prefix) forces PowerShell to return an array, not unroll it
|
||||||
|
- `[System.IO.File]::WriteAllText(path, json, UTF8)` — use this, not `Out-File`, to avoid BOM/encoding issues
|
||||||
@@ -74,7 +74,8 @@ header p{font-size:0.85rem;color:#f0cca0;margin-top:3px}
|
|||||||
@keyframes pop{from{transform:scale(0.85);opacity:0}to{transform:scale(1);opacity:1}}
|
@keyframes pop{from{transform:scale(0.85);opacity:0}to{transform:scale(1);opacity:1}}
|
||||||
.no-results{padding:30px;text-align:center;color:#5a3a20}
|
.no-results{padding:30px;text-align:center;color:#5a3a20}
|
||||||
::-webkit-scrollbar{width:5px}::-webkit-scrollbar-track{background:#1a0a00}::-webkit-scrollbar-thumb{background:#5a2a00;border-radius:3px}
|
::-webkit-scrollbar{width:5px}::-webkit-scrollbar-track{background:#1a0a00}::-webkit-scrollbar-thumb{background:#5a2a00;border-radius:3px}
|
||||||
.course-browse-bar{background:#241000;padding:8px 24px;display:flex;gap:10px;border-bottom:1px solid #5a2a00}
|
.course-browse-bar{background:#241000;padding:8px 24px;display:flex;gap:10px;align-items:center;border-bottom:1px solid #5a2a00}
|
||||||
|
.course-browse-bar select{background:#3a1a00;border:1px solid #7a4a00;color:#f0e6d3;padding:7px 10px;border-radius:6px;font-size:0.85rem;cursor:pointer;margin-left:auto;flex-shrink:0}
|
||||||
.btn-course{background:#3a1a00;border:1px solid #7a4a00;color:#f5c842;padding:7px 20px;border-radius:20px;cursor:pointer;font-size:0.85rem;font-weight:600;transition:all 0.2s}
|
.btn-course{background:#3a1a00;border:1px solid #7a4a00;color:#f5c842;padding:7px 20px;border-radius:20px;cursor:pointer;font-size:0.85rem;font-weight:600;transition:all 0.2s}
|
||||||
.btn-course:hover{background:#5a2a00;border-color:#f5c842}
|
.btn-course:hover{background:#5a2a00;border-color:#f5c842}
|
||||||
.course-modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.78);z-index:100;display:flex;align-items:center;justify-content:center}
|
.course-modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.78);z-index:100;display:flex;align-items:center;justify-content:center}
|
||||||
@@ -97,8 +98,9 @@ header p{font-size:0.85rem;color:#f0cca0;margin-top:3px}
|
|||||||
.toolbar select{flex:1;min-width:0}
|
.toolbar select{flex:1;min-width:0}
|
||||||
.spacer{display:none}
|
.spacer{display:none}
|
||||||
.tag-counts{width:100%;order:10;text-align:center}
|
.tag-counts{width:100%;order:10;text-align:center}
|
||||||
.course-browse-bar{padding:8px 12px}
|
.course-browse-bar{padding:8px 12px;flex-wrap:wrap}
|
||||||
.btn-course{flex:1;padding:7px 6px;text-align:center}
|
.btn-course{flex:1;padding:7px 6px;text-align:center}
|
||||||
|
.course-browse-bar select{margin-left:0;width:100%}
|
||||||
.main{height:auto;min-height:calc(100svh - 98px);flex-direction:column}
|
.main{height:auto;min-height:calc(100svh - 98px);flex-direction:column}
|
||||||
.list-panel{width:100%;min-width:0;border-right:none;min-height:calc(100svh - 98px)}
|
.list-panel{width:100%;min-width:0;border-right:none;min-height:calc(100svh - 98px)}
|
||||||
.detail-panel{display:none;width:100%;padding:16px 14px}
|
.detail-panel{display:none;width:100%;padding:16px 14px}
|
||||||
@@ -120,7 +122,7 @@ header p{font-size:0.85rem;color:#f0cca0;margin-top:3px}
|
|||||||
<h1>🍽️ Inlander Restaurant Week Picker</h1>
|
<h1>🍽️ Inlander Restaurant Week Picker</h1>
|
||||||
<p>Browse menus · Mark favorites · Let fate decide</p>
|
<p>Browse menus · Mark favorites · Let fate decide</p>
|
||||||
</div>
|
</div>
|
||||||
<span style="margin-left:auto;font-size:1.5rem;font-weight:700;color:#f5c842;white-space:nowrap">FEBRUARY 26 – MARCH 7, 2026</span>
|
<span id="eventDates" style="margin-left:auto;font-size:1.5rem;font-weight:700;color:#f5c842;white-space:nowrap">FEBRUARY 26 – MARCH 7, 2026</span>
|
||||||
</header>
|
</header>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<input type="text" id="search" placeholder="Search restaurants..." oninput="applyFilters()"/>
|
<input type="text" id="search" placeholder="Search restaurants..." oninput="applyFilters()"/>
|
||||||
@@ -147,6 +149,10 @@ header p{font-size:0.85rem;color:#f0cca0;margin-top:3px}
|
|||||||
<button class="btn btn-course" onclick="openCourseBrowse('First Course')">🥗 First Course</button>
|
<button class="btn btn-course" onclick="openCourseBrowse('First Course')">🥗 First Course</button>
|
||||||
<button class="btn btn-course" onclick="openCourseBrowse('Second Course')">🍖 Second Course</button>
|
<button class="btn btn-course" onclick="openCourseBrowse('Second Course')">🍖 Second Course</button>
|
||||||
<button class="btn btn-course" onclick="openCourseBrowse('Third Course')">🍮 Third Course</button>
|
<button class="btn btn-course" onclick="openCourseBrowse('Third Course')">🍮 Third Course</button>
|
||||||
|
<select id="yearSelect" onchange="loadYear(this.value)">
|
||||||
|
<option value="2026">2026</option>
|
||||||
|
<option value="2025">2025</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="list-panel" id="listPanel"></div>
|
<div class="list-panel" id="listPanel"></div>
|
||||||
@@ -172,8 +178,8 @@ header p{font-size:0.85rem;color:#f0cca0;margin-top:3px}
|
|||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
let RESTAURANTS = [];
|
let RESTAURANTS = [];
|
||||||
|
let currentYear = '2026';
|
||||||
let interests = JSON.parse(localStorage.getItem('irw_interests')||'{}');
|
let interests = JSON.parse(localStorage.getItem('irw_interests_2026')||'{}');
|
||||||
let filteredList = [];
|
let filteredList = [];
|
||||||
let activeSlug = null;
|
let activeSlug = null;
|
||||||
let currentWinner = null;
|
let currentWinner = null;
|
||||||
@@ -240,7 +246,7 @@ function toggleInterest(slug,who,checked){
|
|||||||
if(!interests[slug]) interests[slug]={};
|
if(!interests[slug]) interests[slug]={};
|
||||||
interests[slug][who]=checked;
|
interests[slug][who]=checked;
|
||||||
if(!interests[slug].you && !interests[slug].wife) delete interests[slug];
|
if(!interests[slug].you && !interests[slug].wife) delete interests[slug];
|
||||||
localStorage.setItem('irw_interests',JSON.stringify(interests));
|
localStorage.setItem('irw_interests_'+currentYear,JSON.stringify(interests));
|
||||||
renderList();
|
renderList();
|
||||||
updateCounts();
|
updateCounts();
|
||||||
if(activeSlug===slug) showDetail(slug);
|
if(activeSlug===slug) showDetail(slug);
|
||||||
@@ -249,7 +255,7 @@ function toggleInterest(slug,who,checked){
|
|||||||
function clearAll(){
|
function clearAll(){
|
||||||
if(!confirm('Clear all your selections?')) return;
|
if(!confirm('Clear all your selections?')) return;
|
||||||
interests={};
|
interests={};
|
||||||
localStorage.setItem('irw_interests',JSON.stringify(interests));
|
localStorage.setItem('irw_interests_'+currentYear,JSON.stringify(interests));
|
||||||
renderList(); updateCounts();
|
renderList(); updateCounts();
|
||||||
}
|
}
|
||||||
function resetFilters(){
|
function resetFilters(){
|
||||||
@@ -354,15 +360,37 @@ function openCourseBrowse(course){
|
|||||||
function closeCourseBrowse(){ document.getElementById('courseBrowseOverlay').style.display = 'none'; }
|
function closeCourseBrowse(){ document.getElementById('courseBrowseOverlay').style.display = 'none'; }
|
||||||
function selectCourseDish(slug){ closeCourseBrowse(); showDetail(slug); }
|
function selectCourseDish(slug){ closeCourseBrowse(); showDetail(slug); }
|
||||||
|
|
||||||
// Init
|
function loadYear(year){
|
||||||
fetch('2026-restaurants.json')
|
currentYear = year;
|
||||||
|
interests = JSON.parse(localStorage.getItem('irw_interests_'+year)||'{}');
|
||||||
|
activeSlug = null;
|
||||||
|
currentWinner = null;
|
||||||
|
document.querySelector('.main').classList.remove('show-detail');
|
||||||
|
document.getElementById('detailPanel').innerHTML = `
|
||||||
|
<div class="detail-empty">
|
||||||
|
<div class="icon">🍴</div>
|
||||||
|
<h3 style="color:#8b4a20">Select a restaurant to see its menu</h3>
|
||||||
|
<p>Check boxes to mark ones you're interested in, then hit "Pick for Us!"</p>
|
||||||
|
</div>`;
|
||||||
|
document.getElementById('filterArea').innerHTML = '<option value="">All Areas</option>';
|
||||||
|
document.getElementById('filterCuisine').innerHTML = '<option value="">All Cuisines</option>';
|
||||||
|
resetFilters();
|
||||||
|
fetch(year+'-restaurants.json', {cache:'no-store'})
|
||||||
.then(function(r){ return r.json(); })
|
.then(function(r){ return r.json(); })
|
||||||
.then(function(data){
|
.then(function(data){
|
||||||
RESTAURANTS = data;
|
RESTAURANTS = Array.isArray(data) ? data : data.restaurants;
|
||||||
|
if(data.eventDates) document.getElementById('eventDates').textContent = data.eventDates;
|
||||||
initDropdowns();
|
initDropdowns();
|
||||||
applyFilters();
|
applyFilters();
|
||||||
updateCounts();
|
updateCounts();
|
||||||
|
})
|
||||||
|
.catch(function(err){
|
||||||
|
document.getElementById('listPanel').innerHTML = '<div class="no-results">⚠️ Failed to load restaurant data.<br><small>'+err+'</small><br><small>Try serving this file from a local web server instead of opening it directly.</small></div>';
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init
|
||||||
|
loadYear('2026');
|
||||||
</script>
|
</script>
|
||||||
<div class="course-modal-overlay" id="courseBrowseOverlay" style="display:none" onclick="if(event.target===this)closeCourseBrowse()">
|
<div class="course-modal-overlay" id="courseBrowseOverlay" style="display:none" onclick="if(event.target===this)closeCourseBrowse()">
|
||||||
<div class="course-modal">
|
<div class="course-modal">
|
||||||
|
|||||||
Reference in New Issue
Block a user