- 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
Change brew card from div to anchor element with hover border effect.
Brew Again button uses preventDefault to avoid navigating to the detail
page when clicked.
- Add --highlight-rgb CSS custom property for light and dark themes
- Add MutationObserver to world-map for theme change detection
- Read choropleth colors from CSS custom properties instead of hardcoded values
- Simplify stats_map partial to use text-highlight class
- Add format_weight() and format_relative_time() in domain/formatting.rs
- Replace ad-hoc weight format strings across views and timeline events
- Move relative_date() body to domain layer with explicit now param
- Remove hardcoded "g" suffix from bag templates (now in format_weight)
- Document formatting helpers in CLAUDE.md
- 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 small-caps + tracking-wide thead with plain text-text-secondary
across all 7 list tables
- Bag status: widen progress bar to fill cell, use thicker bar on desktop
- Bag status: replace pill with plain text for "Closed"
- Bag status: use text-xs instead of small-caps for amount labels
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
- Add @utility text-2xs (0.65rem) and small-caps (font-variant) to input.css
- Replace inline style="font-variant: small-caps" with .small-caps class
across all list partials and base.html footer
- Add gap support to .tab and .tab-mobile for icon+label layout
- Reduce mobile top padding (py-4 md:py-10) on main container
- Rename CSS section header from "Scrollbar hide" to "Utilities"
- Add small-caps to all table column headers
- Show Added date in normal font size with time as smaller subtext
- Show Finished date in normal font size in bag table
- Rename "Previous" to "Prev" in pagination controls
- Use orange text and subtle hover on Prev/Next buttons and Rows select
- 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
- Change btn-adjust to grey border with orange text and subtle hover
- Add font-family/font-size to .input-field for consistency
- Redesign desktop tabs: bordered, orange text, equal width, accent
border on active instead of filled background
- Redesign mobile tab selector: bordered dropdown with orange text,
rounded container, subtle active background
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
- 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
The same ~250-character inline onclick handler was copy-pasted across
all 7 list templates. Extract it into a toggleRow() function in
base.html and replace the inline copies with a single call.
Only persist theme to localStorage when the user's choice differs from
the OS preference. Clear it when they match so the prefers-color-scheme
listener remains active and automatically tracks system theme changes.
- Create light (orange-700) and dark (orange-600) coffee cup SVG favicons
- Add explicit routes for both SVG variants
- Set correct favicon on initial load before body renders
- Swap favicon href on manual theme toggle
- Listen for OS prefers-color-scheme changes when no manual override set
Add view-layer mapping that categorises tasting notes into 9 colour
families (floral, fruity, citrus, sweet, nutty, spice, roasted, sour,
vegetal) based on the SCA Coffee Tasting Wheel. Matching uses
case-insensitive exact lookup against ~90 known terms, then substring
fallback, with pill-muted as the default for unrecognised notes.
- Add tasting_notes module with NoteCategory enum and categorize()
- Add 9 pill CSS variants with light and dark mode support
- Update roast list and timeline templates to render coloured pills
- Add used_percent field to BagView computed from amount/remaining
- Display accent-colored progress bar on homepage bag cards
- Replace Open pill with progress bar in bag data table (desktop and mobile)
- Merge Weight column into Status column showing remaining/total
- Add full-width progress bar to mobile card view for open bags
- Sort Status column by remaining grams (closed bags treated as 10000g)
- Hide Finished field on mobile for open bags
- Use small-caps typography for remaining text labels
- Add spacious flat table CSS for desktop (transparent card wrapper,
lighter dividers, visible hover, larger cell padding)
- Split roaster/cafe columns into separate Country and City columns
with sortable headers
- Split cup Roast/Roaster into separate desktop columns with city
sort support (full-stack: domain, repo, view, template)
- Add sortable Status column to bags with colored pills (green Open,
amber Closed) and remaining weight subtext
- Style bag Finished column as date-only (NaiveDate) and Weight
column with smaller text
- Show status pill next to mobile bag card actions menu
- Add city to cups mobile card view
- Use middle dot separator for brew recipe weight/volume
- Add tasting notes pills to roast list, brew notes to brew list
- Fix build.rs to use rerun-if-changed for CSS and templates
- Remove bordered card wrapper from table sections on desktop
- Strip thead background, rely on typography for header distinction
- Increase cell vertical padding from 0.75rem to 1rem
- Add white row backgrounds with explicit horizontal borders
- Add accent-tinted hover with left bar indicator
- Float pagination below table as un-bordered footer
- Shrink pagination prev/next to compact card-style buttons
- Add page header, card-wrapped sections, and surface-alt item cards
to the account page for visual consistency with the rest of the app
- Style CLI callback page with centered icon + heading layout matching
the login page, with dark-mode-safe colors
- Add dark mode variants to all error/success alerts on account page
- Add check_circle icon for CLI callback success state
Replace the full-width inline menu with a compact right-aligned dropdown
that floats over page content. Adds click-outside-to-close via an
invisible backdrop, and uses z-50 to sit above timeline sticky headings.
- Replace database icon with squares (2x2 grid) for Data link
- Remove 5 unused icon macros: star, pen, login, sparkles, clipboard
- Add hover highlight (bg-surface-alt) to dropdown items
After AI extraction, check if the roaster and roast already exist by
slug. When matched, show compact summary cards instead of full edit
forms. Each card has a "Change" link to revert to the form if the
match is wrong.
- Add match_existing_entities() for slug-based roaster/roast lookup
- Return _matched-roaster-id and _matched-roast-id signals from extraction
- Add submit_existing_roast() path to skip creation when roast exists
- Dynamic submit buttons: Save Roaster & Roast / Save Roast / Open Bag
- Hidden inputs bound to signals handle all form submission cleanly
- Add initial-value attribute to searchable-select web component
- Update bag card Brew link to pass bag_id query parameter to add page
- Thread bag_id through route handler and template to pre-select the bag
- Add quick_notes_raw field to BrewView with comma-separated form values
- Include quick_notes hidden input in all three brew-again forms
(homepage, brew list desktop, brew list mobile)
Replace ~268 hardcoded text-stone-* classes with theme-aware token
utilities (text-text, text-text-secondary, text-text-muted) across all
templates and JS components. Adjust dark mode token values to meet
WCAG AA contrast ratios on dark surfaces.
Predefined toggleable tags for brews: Good, Too Fast, Too Slow,
Too Hot, Under Extracted, Over Extracted.
- Add quick_notes TEXT column storing JSON array
- Add QuickNote enum with label/form-value/positive helpers
- Update repository to encode/decode JSON, backup to export notes
- Add toggle pill UI on brew form with Datastar signals
- Show pills on home page cards (muted for Good, amber for others)
- Show comma-joined text in data table Notes column
- Add --quick-notes flag to CLI, update HTTP client
- Update bootstrap script with sample quick notes
- Split created_at into created_date + created_time across all view models
- Add inline card-detail pattern for mobile action buttons
- Add desktop detail-row with ellipsis toggle for table actions
- Add pill-warning and pill-success CSS variants with dark mode
- Center mobile card-detail buttons, fix card-date vertical spacing
- Rename action labels: "View on Map" → "View Map", "Visit website/homepage" → "Homepage"
Move 9 page templates to templates/pages/, nav to partials/,
7 list partials + table.html to partials/lists/. Extract duplicated
scan result form (~85 lines) from home.html and add.html into
partials/forms/scan_result_form.html. Update all Askama template
paths, include/import directives.
- Create shared tab_bar.html partial with desktop + mobile layouts
- Add CSS component classes (.tab, .tab-active, .tab-mobile variants)
- Replace divergent implementations in data.html and add.html
- Rename DataTab to Tab for shared use across templates
- Improve readability: darker inactive text, more spacing, hover states
Overhaul the web UI with CSS custom property-based theming and
dark mode support. Extract reusable template partials (location
search, scan input) and web components (photo-capture,
searchable-select). Add version and commit info to page footer.
- Replace hardcoded amber palette with semantic theme tokens
- Add dark mode with localStorage persistence and system preference detection
- Extract <brew-photo-capture> and <searchable-select> web components
- Extract location_search and scan_input Askama macros
- Add sun/moon, timeline, database, map icons
- Display version and git commit in footer
- Improve timeline coordinate rounding and map link formatting
- Add roast_name, roaster_name, remaining to BagOptionView