Adds a two-level browse tree (domain → category → subcategory) to the
recipe browser, plus an "All" unfiltered option at the top of every
domain.
browser_domains.py:
- Category values now support list[str] (flat) or dict with "keywords"
and "subcategories" keys — backward compatible with all existing flat
categories
- Added subcategories to: Italian (Sicilian, Neapolitan, Tuscan, Roman,
Venetian, Ligurian), Mexican (Oaxacan, Yucatecan, Veracruz, Street
Food, Mole), Asian (Korean, Japanese, Chinese, Thai, Vietnamese,
Filipino, Indonesian), Indian (North, South, Bengali, Gujarati),
Mediterranean (Greek, Turkish, Moroccan, Lebanese, Israeli), American
(Southern, Cajun/Creole, BBQ, Tex-Mex, New England), European
(French, Spanish, German, British/Irish, Scandinavian), Latin American
(Peruvian, Brazilian, Colombian, Cuban, Caribbean), Dinner, Lunch,
Breakfast, Snack, Dessert, Chicken, Beef, Pork, Fish, Vegetables
- New helpers: category_has_subcategories, get_subcategory_names,
get_keywords_for_subcategory
store.py:
- get_browser_categories now accepts has_subcategories_by_category and
includes has_subcategories: bool in each result row
- New get_browser_subcategories method for subcategory count queries
recipes.py endpoints:
- GET /browse/{domain}/{category}/subcategories — returns subcategory
list with recipe counts (registered before /{subcategory} to avoid
path collision)
- GET /browse/{domain}/{category} gains optional ?subcategory=X param
to narrow results within a category
- GET /browse/{domain}/{category}/_all — unfiltered paginated browse
(landed in previous commit)
api.ts: BrowserCategory adds has_subcategories; new BrowserSubcategory
type; listSubcategories() call; browse() gains subcategory param
RecipeBrowserPanel.vue:
- Category pills show a › indicator when subcategories exist
- Selecting such a category fetches subcategories in the background
(non-blocking — recipes load immediately at the category level)
- Subcategory row appears below the category list with an
"All [Category]" pill + one pill per subcategory with count
- Active subcategory highlighted; clicking "All [Category]" resets
to the full category view