The flag emoji and country name were separate flex items inside mobile
card td cells, causing the flag to float away from the country text.
Wrapping them in a single span keeps them together as one flex item.
Replace verbose subtitles with a consistent pattern across all 7 detail
pages: a linked entity type pointing to the data list page, followed by
the creation date.
Replace viewport-relative w-[45vw] with fixed w-[200px] so brew and
bag cards maintain consistent width across breakpoints instead of
shrinking on narrow screens.
Add roaster and roast slug parameters to coffee_card and roaster_card
macros, rendering entity names as links to their detail pages. Add cafe
link in the cup detail page. Pass slug fields through template structs
and route handlers.
Add aria-required to required inputs, role=alert to error messages,
aria-label to icon-only list nav buttons, and progressbar ARIA to bag
status bars. Replace hardcoded red/green colors with error/success
design tokens across all templates. Add toast notifications for entity
creation and tab-switch links for empty add-form states. Increase scan
upload body limit to 10MB.
The stats recomputation task populates the cache with zero values on
startup, causing build_stat_cards() to return 6 cards even with an
empty database. Gate the stats section on stats.is_empty() in addition
to stat_cards.is_empty() so placeholders display correctly.
- Add roast detail page at /roasters/{slug}/roasts/{slug}
- Remove expand/collapse detail rows from all 7 list views
- List rows now navigate directly to entity detail pages
- Replace three-dots action button with chevron-right link
- Add delete buttons to brew and cup detail pages
- Restyle all delete buttons: outlined with red text
- Remove share buttons from all detail pages
- Update timeline card links to point at detail pages
- Make homepage activity cards clickable with hover effect
- Replace all vanilla JS delete/close with Datastar actions
- Extract render_redirect_script helper for Datastar redirects
- Update delete macro with referer-based routing for detail pages
- Add detail page routes, templates, and view models for roasters, cafes,
and gear, following the existing pattern from bags/brews/cups
- Add map_with_legend_1 macro for single-country detail maps
- Redirect to detail page after entity creation instead of list page
- Check referer in create handlers to return list fragment only from data page
- Update bag delete button to use red background style
- Update datastar tests to include referer header for create assertions
- Add bg-surface background to roast stats, consumption, and country pill cards
- Update tab CSS: bg-surface background, hover:border-accent/40 instead of bg-surface-alt
- Add hover:border-accent/40 to clickable country pill buttons
- Make Roasts the first and default tab on the stats page
- Create /bags/:id detail page with coffee, roaster, map, and bag info cards
- Extract shared template macros into detail_cards.html (coffee_card, roaster_card, map_with_legend, share_button)
- Extract build_coffee_info() and build_roaster_info() view model helpers
- Refactor brew.html and cup.html to use shared macros
- Make bag cards on homepage clickable, linking to detail page
- Add Close Bag and Delete actions on bag detail page
- Unify homepage card styling (bg-surface, hover:border-accent/40)
- Update CLAUDE.md with detail page patterns
- Add og:title, og:description, og:image, og:type, og:site_name and
twitter:card meta tags to base template with Askama block overrides
- Create static 1200x630 OG image served at /og-image.png
- Override OG blocks with entity-specific content on brew, cup, and
stats detail pages
- Reuse BREWLOG_RP_ORIGIN as base URL for absolute og:image URLs via
OnceLock initialized at server startup
Add /brews/:id and /cups/:id routes with full coffee, roaster, gear,
and recipe information. Each page includes a world map highlighting
relevant countries, tasting note pills, and a share button that copies
the URL to the clipboard.
- Add build_stat_cards() with shuffled order from stats cache
- Remove gear from homepage data cards and StatsView
- Add StatCard view struct for icon/value/label display
- Convert data cards from grid to horizontal scroll with chip-scroll
- Add stats section with 6 randomized stat cards
Extract <chip-scroll> custom element into its own file and wrap
Recent Brews and Open Bags horizontal scrollers with desktop-only
chevron navigation that half-overlaps the card edges.
- New /stats page with Roasters, Roasts, Cups, and Cafes tabs
- Interactive choropleth world map (SVG) colored by country counts
- Clickable country chips that highlight individual countries on the map
- Horizontal chip scroller with chevron navigation on desktop
- Datastar-powered tab switching without page reload
- Domain layer: country name → ISO code mapping, flag emoji generation
- StatsRepository trait with four aggregate SQL queries
- <world-map> and <chip-scroll> custom elements for Datastar compatibility
Replace "you/your" with impersonal alternatives across all
user-facing strings in templates, CLI output, error messages,
and documentation. Add copy style rule to CLAUDE.md.
- Add chevron_right icon macro
- Add icon to checkin "Next" and register "Go to Brewlog" buttons
- Align Back (checkin) and Cancel (scan_result_form) to Outlined
style: inline-flex, font-medium
- Rename "Log Brew" → "Save Brew" for consistency with other forms
- Replace icon-only delete/revoke buttons with outlined text buttons
- Rename: Add Passkey → New Passkey, Create Token → New Token,
Download Backup → New Backup, Restore from Backup → Restore,
Reset Database → Reset
- Add w-full sm:w-auto sm:min-w-44 to all action buttons for
consistent sizing on mobile and desktop
- Align Cancel buttons to font-medium text-text (Outlined style)
- Show blurred skeleton cards with overlay text for empty brews,
bags, and activity sections instead of plain dashed borders
- Use 6 skeleton cards for brew/bag sections to fill desktop width
- Skeleton structure mirrors real card layout (title, details, buttons)
- Wrap tab bar, search, and table in gap-4 container for tighter spacing
- Change search placeholder from "Search..." to "Filter..."
- Remove border/padding wrapper around tab bar and search
- Remove check-in and add links from scan input partial
- Add "or" separator between camera and text input
- Remove redundant text-sm from input fields (now in .input-field CSS)
- Fix label text size and color in check-in form
- Remove top-level scan section and scan_input import
- Add per-form extraction bars with camera + describe input
- Rename form signals from _add-* prefix to match extraction endpoints
- Add per-form extracting/error signals to guard datastar-fetch events
- Make Log Brew button full width
Instead of immediately creating a duplicate brew via inline POST,
the Brew Again button now links to the add-brew page with query
params that pre-fill all fields (bag, grinder, grind setting,
brewer, filter paper, water volume/temp, brew time, quick notes).
This lets users review and adjust parameters before brewing.
- Split equipment into separate Grinder and Brewer collapsible sections
with summary bars showing current selection
- Make all summary bars, matched-entity cards, and searchable-select
selected values clickable anywhere to change (not just the X/Change button)
- Fix stepper buttons broken after manual input by switching from
data-attr:value to data-bind with Number() coercion
- Merge Water + Brew Time into single Recipe section
- Make all add/confirm buttons full-width
- Add sticky submit button on mobile
- Fix missing closing > on cafe indicator div
- Fix broken Askama syntax on checkin page from formatter
- Hide native number input spin buttons across browsers
- Fix brew time field width to match sibling fields
- Restyle .btn-adjust with accent-subtle fill instead of border
- Remove (M:SS) hint from brew time label
- Replace token dismiss button with close icon in top-right corner
- Add terminal icon to token rows matching passkey layout
- Remove token row from DOM immediately on revoke
- Focus token name input when opening the create form
- Clear token name input after successful creation
- Add brew_time INTEGER column to brews table (nullable, stored as seconds)
- Display as M:SS format with stepper control (+/-5s) in add form
- Replace ratio with brew time in brew list Recipe column
- Show brew time in brew cards and timeline events
- Add --brew-time CLI flag and update bootstrap script (1:45-2:45 range)
- Add "Expand all" / "Collapse all" link under each month heading
- Individual cards remain toggleable even when month is expanded
- Three signals coordinate state: _expandedMonths (month-level),
_expandedCard (single card), _collapsedCards (individual overrides)
Cards start collapsed showing category, relative date, title, and
subtitle. Clicking expands to reveal full timestamp, detail rows,
tasting notes, and external links. Uses a single Datastar signal
for expand state.
- Replace pill badge with small-caps category label
- Remove brew-again button from timeline cards
- Replace @ separators with · in brew detail values
- Load last 10 brews instead of 3, display in horizontal scroll
- Extract brew card into reusable partial with portrait layout
- Add grinder_model field to BrewView for compact card display
- Move brew-again button to top-right icon, truncate long names
- Load all open bags instead of limiting to 3
- Replace grid layout with horizontal scroll container using snap
- Redesign bag cards as portrait layout with icon actions
- Add scrollbar-hide CSS utility and x_mark icon
- Add reset() method to BackupService that deletes all 8 coffee tables
in a transaction, respecting FK constraint order
- Add POST /api/v1/backup/reset endpoint (requires auth)
- Add "Reset Database" button with double-confirmation to account page
- Stack data buttons vertically on mobile for better layout