Follow-up to the #39 fix in d274275, which mara reports still doesn't
scroll in practice.
The bug: overflow-y: auto and justify-content: flex-end on the *same* flex
column is a known WebKit/Safari interop gap — the flex-end-justified
overflow gets clipped at the container bounds instead of becoming a
scrollable region, so nothing actually changed from the user's side despite
the CSS being 'correct' per spec. This app targets iOS Safari 12+
(vite.config.ts legacy targets), squarely in the affected range.
Fix: split the concerns onto two elements. .cart-items is now a plain
overflow-y: auto scroll container with no alignment property. The new
inner .cart-items-inner wrapper carries display:flex/flex-direction:column/
justify-content:flex-end, with min-height: 100% (a floor, not a fixed
height) so it still bottom-anchors a short list but grows past 100% and
scrolls normally in the outer container once content overflows it.
Build clean.
Closes#40.
New /stats route (client/stats.html + src/stats/), served by the same
catch-all pattern as /admin. Reuses the admin login (STATS_PUBLIC env var
on the server side decides whether it needs one at all).
Three uPlot charts (daily revenue, daily transaction count, top-5-drink
sold-qty trend) plus the same three tables Admin.tsx used to render inline
— those move here wholesale, Admin.tsx now just links to /stats instead of
fetching /admin/api/stats itself. The 'Statistik zurücksetzen' reset button
moves here too, gated on an actual admin session (checked separately from
whether /api/stats itself succeeded, since STATS_PUBLIC can make that true
for an anonymous viewer).
Chart lib is uPlot (~45kb) per mara's steer not to hand-roll this. Both
client and server build/typecheck clean; manually smoke-tested the auth
gate (401 unauthed, 200 after login) and the /stats route against a fresh
DB.
.cart-items clipped overflow instead of scrolling, so once the cart
had more line items than fit in the 38vh cart panel the extra rows
were just invisible. overflow-y: auto lets it scroll while still
anchoring to the bottom (justify-content: flex-end) when short.
Closes#39.
Per review: don't hardcode pixel values. grid-auto-rows: minmax(min-content, 1fr)
— the floor is each row's own natural content height (name + price + Pfand at
whatever font-size is active), not a manually guessed number. Same mechanism
naturally covers the <=480px breakpoint's smaller fonts too, so the separate
--tile-min-height custom property + its mobile override are gone — one rule,
no magic numbers on either side.
Per review: remove the assumption that exactly 5 rows fill the visible area.
grid-auto-rows: minmax(96px, 1fr) — rows are at least 96px (the touch-target
size used elsewhere in this file), equal height, and stretch evenly to fill
leftover space when there's room; when there isn't (more rows than fit), every
row stays at the 96px floor and the grid scrolls instead of shrinking rows to
squeeze them in. Smaller floor (80px) in the <=480px media query to match the
already-smaller mobile font sizes there.
Name/price/Pfand were packed tight (2px gap before Pfand, 1.15 line-height on
the name) — small bump to margins + line-height so tiles read less cramped
regardless of how many rows are on screen. Independent of the row-count
question raised on the issue (grid-auto-rows sizing for 5 rows vs however many
drinks are actually configured) — that's a separate, bigger call pending
confirmation of what device the screenshot was taken on.
- App.tsx: the error screen (shown when api.config(barId) fails, e.g.
an admin deleted/renamed the bar while this tablet was offline)
only offered 'Neu laden', which re-reads the same stale localStorage
bar_id and fails again — a permanent stuck loop with no in-app fix.
Added a 'Bar wechseln' button reusing the existing changeBar()
logic, which now also clears the error state.
- Admin.tsx BarDrinkEditor: the drag-and-drop reorder is a
mouse-oriented API that doesn't fire on touch-only input and has no
keyboard equivalent. Added ▲/▼ buttons alongside the drag handle so
reordering works regardless of input method.
Cart entries (drink lines and Pfand-zurück) now have +/- buttons next
to the quantity instead of only accumulating via repeated taps;
decrementing to 0 removes the line. Long-pressing a drink tile opens
a small overlay with buttons 1-5 to add that many at once — a plain
tap still adds one. The long-press timer is cancelled on pointerup/
leave/cancel, and the click that follows a fired long-press is
swallowed so it doesn't also add a plain 1x.
On narrow phone screens the tablet UI had two problems:
- Drink button text could overflow the tile (no overflow: hidden / word-break),
causing garbled text spill visible in the issue screenshot.
- All font sizes and the cart height were tablet-sized (22px drinks, 56px total,
38vh cart, 64px action buttons); no phone overrides existed beyond the 2-column
grid switch.
Fixes:
- .drink: add overflow: hidden so text never bleeds outside the tile.
- .drink .name: word-break + overflow-wrap so long names wrap rather than clip.
- .topbar .bar-name: nowrap + text-overflow: ellipsis so a long bar name
truncates cleanly rather than wrapping/overflowing.
- @media (max-width: 480px): scale down topbar (20px), drink tiles (17px),
pfand label (12px), cart height (34vh), cart total (38px), action buttons
(52px / 18px) to fit a portrait phone comfortably.
Closes#3.
User feedback (#1): drink buttons all the same size in a 3-column grid with
any number of rows; scroll when more than ~5 rows of drinks exist; entry
overview + sum stay visible. Device: iPad mini 2 (portrait).
The grid used `grid-auto-rows: 1fr` + `overflow: hidden`, which divided the
available height across however many drinks there were — tiles shrank as the
catalog grew and it never scrolled (the known UX/scaling item in TODO.md).
Now: `grid-auto-rows: calc((100% - 4 * var(--gap)) / 5)` — the row height is
DERIVED so exactly five equal rows fill the visible grid area (no hardcoded
tile pixel size), with `align-content: start` + `overflow-y: auto` (+ iOS
momentum scroll). Tiles are a consistent size regardless of count, ~5 rows
show, the rest scroll. The cart stays pinned below (unchanged) so the overview
+ sum remain permanently visible.
CSS-only.
- favicon.svg (beer mug), linked from both entry points and shown in
the tablet topbar next to the bar name
- inline data-theme in <head> kills the flash of dark on light-mode load
- hide the "Pfand zurück" tile when the bar has no Pfand
- show drink price and Pfand separately on tiles and in cart
- add light/dark toggle on the bar-picker page (persisted)
- theme via CSS variables, applied on load for tablet + admin
- larger, bolder text throughout; much bigger total sum