Skip to content

Fix friend place-count bug + Recently Deleted relocation + chunked My Places rendering - #9

Merged
Osyna merged 7 commits into
mainfrom
feature/cartoon-ui-skin
Aug 10, 2026
Merged

Osyna merged 7 commits into
mainfrom
feature/cartoon-ui-skin

Conversation

@Osyna

@Osyna Osyna commented Aug 10, 2026

Copy link
Copy Markdown
Owner

1 · Real bug fixed: inflated friend place counts

friends.js used Prisma's bare _count.places for the 'N places' badge on friend cards and incoming/sent requests — that count had no deletedAt filter, unlike every other places query in the app, so it silently included soft-deleted places. Fixed with a filtered relation count. Verified end-to-end: badge correctly drops 3 → 2 immediately after a soft-delete (stayed at 3 with the bug).

2 · Recently Deleted → icon button next to Select

Was a section at the very bottom of a (now) 541-card list — unreachable without scrolling past everything. Moved to a dedicated trash-icon button in the header, right beside Select, with a pending-count badge. Opens a floating panel near the top (same pattern as the map's Pin-types legend) instead of pushing the list down.

3 · My Places: dynamic (chunked) rendering — the actual lag source

Confirmed 541 .pv-card elements were mounting in the DOM at once, and sortedPlaces re-filters/re-sorts on every GPS update (continuous watchPosition since the locate work). That's what caused visible lag, not the data size itself (541 places is ~250 KB, no network problem).

Now only a 60-card window renders, grown by 60 via an IntersectionObserver sentinel as the user scrolls — verified: 60 initial → 420 after scrolling, silent and instant (pure client-side slicing, no network wait).

Search stays instant and full-dataset, exactly as requested: Fuse indexes the complete in-memory store.places regardless of the render window. Verified by searching for a place confirmed not among the initial 60 rendered cards ('Grizzly') — found instantly. Header count ('541 saved') and category chip counts ('All (541)', 'Restaurant (327)'...) are also untouched — they read the full array, never the DOM window.

Osyna added 2 commits August 10, 2026 10:46
…y Places

Real bug found & fixed: friends.js used Prisma's bare _count.places to
show 'N places' on friend cards / requests — that count had NO
deletedAt filter, unlike every other places query, so it silently
included soft-deleted places and over-reported a friend's real place
count. Fixed by filtering the relation count (_count.places.where);
verified end-to-end: badge correctly drops 3 -> 2 after a soft-delete
(would have stayed 3 with the bug).

Recently Deleted UX: moved from a section at the very bottom of a
541-card list (had to scroll past everything to reach it) to a
dedicated icon button in the header, right next to Select, with a
badge for pending count. Opens a floating panel (same pattern as the
map's legend card) instead of pushing the list down.

Dynamic (chunked) rendering for My Places: mounting all 541 cards at
once (icons, stars, tag lists, thumbnails, and a sortedPlaces computed
that re-filters/sorts on every GPS update) was the actual render-lag
source. Now only a window of 60 cards is in the DOM, grown by 60 via
an IntersectionObserver sentinel as the user scrolls — verified 60
initial -> 420 after scrolling. Search, header count and category
chips are untouched (always computed over the FULL in-memory array,
never the render window): verified 'All (541)' stays correct and a
search for a place NOT among the initial 60 rendered cards is found
instantly ('Grizzly' -> found, full-dataset Fuse search unaffected).
.pv-count ('541 saved') had no padding/line-height at all — a bare
text pill hugging its own glyphs — stacked 3px below a bold 26px
title. Gave it proper padding (matching .fv-count's convention) and
widened the view-hero-text gap 3px -> 7px so the badge has visible
breathing room under the title.
@Osyna

Osyna commented Aug 10, 2026

Copy link
Copy Markdown
Owner Author

Fixed: cramped header spacing on My Places — the 541 saved badge had no padding at all and only a 3px gap under the title. Now has proper padding (matching the Friends count badge) and 7px breathing room. Verified: 7px gap between title baseline and badge top.

Address row is now a button with a subtle copy-icon affordance;
tapping copies the exact address text + haptic tap + 'Address
copied!' toast (same pattern as copyHandle elsewhere in the app).
Verified end-to-end: clipboard contents match the displayed address.
@Osyna

Osyna commented Aug 10, 2026

Copy link
Copy Markdown
Owner Author

Added: tap the address to copy it — the ADDRESS row in the place detail sheet is now tappable (subtle copy icon on the right), copies the exact address text to the clipboard with a haptic tap + 'Address copied!' toast. Verified end-to-end: clipboard content matches the displayed address exactly.

Converting the address row from <div> to <button class="info-row
info-row--copy"> added a scoped 'background: none' reset (meant to
kill the browser's default button-face gray). That selector
(.info-row.info-row--copy[data-v-hash], 2 classes + 1 attr) had
slightly higher specificity than cartoon.scss's 'html[data-skin]
.info-row' (1 class + 1 attr + 1 element), so it won and made the
Address card fall through to transparent -> the page's cream
backdrop instead of staying white like Coordinates/Notes/Added.

- Removed the scoped background reset (not needed / was the bug)
- cartoon.scss now explicitly owns .info-row--copy's background too,
  so future scoped tweaks in the component can't out-specify it again

Verified: all four info rows report identical
backgroundColor: rgb(255,255,255) via computed styles.
@Osyna

Osyna commented Aug 10, 2026

Copy link
Copy Markdown
Owner Author

Fixed: Address card background regression — the copy-to-clipboard change turned the address row into a <button> with a scoped CSS reset that accidentally out-specified cartoon.scss's white card background, making it fall through to the page backdrop (the cream tint you spotted). Fixed at the root (removed the offending reset) and reinforced cartoon.scss to own that background explicitly so it can't happen again. Verified: all four info rows now report identical rgb(255,255,255) backgrounds.

…ader/body

Navigation (App.vue)
- Switching tabs (click OR swipe) now does a smooth directional
  slide+fade (18px translateX + opacity, 320ms cubic-bezier) instead
  of an instant cut. Map (v-show, permanently mounted for MapLibre)
  and the other 4 views (v-if chain) share the same transition name/
  direction so the motion reads as one continuous animation across
  the mount-vs-show boundary. prefers-reduced-motion gets a fast
  plain crossfade instead.
- Swipe left/right ON the bottom tab bar moves to the next/previous
  view (in tab order: Map -> Search -> Places -> Friends -> Profile),
  clamped at the ends; a plain tap still switches tabs normally (the
  swipe handler only engages past a 12px/horizontal-dominant
  threshold and swallows the trailing synthetic click so it doesn't
  also fire a random button's onClick).
- Verified with real TouchEvent dispatch: swipe left -> next tab,
  swipe right -> previous tab, plain tap unaffected; verified the
  transition is a real animation by sampling computed opacity/
  transform mid-flight (0 -> 1, -18px -> 0px), not an instant swap.

Place detail redesign (PlaceDetail.vue)
- New header hierarchy: name -> 'Added <date>' (small meta line,
  moved out of the info list) -> rating/cuisine -> tags (moved up
  from the bottom of the sheet) -> friend-matches. One cohesive
  header instead of scattered metadata.
- Address + Coordinates merged into a single rounded pill: address
  row (tap to copy, unchanged) on top, a collapsed 'Coordinates'
  toggle below that expands to reveal the lat/lng plus its own copy
  button.
- Notes redone as a bigger, distinct card (soft yellow tint, bigger
  icon badge, 15.5px/1.55 line-height text) instead of a cramped
  generic info-row.
- Fixed two real bugs found before shipping: the new address/coords
  buttons had no background set, so the browser's default button-face
  gray (rgb(239,239,239)) covered the white card underneath; and no
  font-family reset, risking a system-font fallback instead of the
  app's webfont. Both fixed with explicit background:transparent +
  font:inherit on the button elements (verified via computed styles,
  not just a screenshot, after the earlier background-specificity
  incident).
@Osyna

Osyna commented Aug 10, 2026

Copy link
Copy Markdown
Owner Author

Added: smooth tab transitions + navbar swipe, and a full place-detail header/body redesign

Navigation

  • Switching views (tap or swipe) now does a smooth 320ms directional slide+fade instead of an instant cut — verified as a real animation by sampling live computed opacity/transform mid-transition (0→1, -18px→0px), not just a class swap.
  • Swipe left/right directly on the bottom tab bar moves to the next/previous view in tab order. Verified with real TouchEvent simulation: swipe left → next tab, swipe right → previous, and a plain tap still works normally (swipe only engages past a real horizontal drag).

Place detail redesign

  • New header: name → Added <date> right below it → rating/cuisine → tags (moved up from the bottom) — one cohesive 'cool header' instead of scattered metadata.
  • Address + Coordinates merged into one rounded pill: address (tap to copy) on top, Coordinates collapsed below — tap to expand and reveal lat/lng with its own copy button.
  • Notes redone: bigger dedicated card, soft yellow tint, bigger icon, much more readable 15.5px text — no longer a cramped generic row.
  • Found and fixed 2 real bugs before shipping (verified via computed styles, learned from last time): the new address/coordinates buttons had no background (browser default gray was covering the white card) and no font-family reset.

…nline toggle

Spacing bug: removing the old .info-sections wrapper in the earlier
header redesign dropped its 22px side padding, leaving .addr-card and
.notes-card bleeding edge-to-edge while quick-actions/tags kept their
own self-padding — the two cards visibly touched the sheet border.
Fixed by giving both their own margin: 0 22px 12px (verified via
bounding boxes: both now x=22 width=346, matching quick-actions'
content inset exactly). Notes card also got more generous padding
(16px 18px -> 18px 20px).

Coordinates: replaced the accordion (tap -> chevron rotates -> a new
row expands below with the value+copy button, changing the card's
height) with a single-line inline toggle — tapping the row REPLACES
the 'Coordinates' label in place with the value + a Copy button, same
row, same height (verified: 58px before and after). Tapping again
(anywhere but Copy) reverts to the label. The outer toggle is now a
div[role=button] (keyboard accessible: Enter/Space) instead of a
<button>, since a real Copy <button> now lives inside it and a button
cannot legally nest inside another button. Removed the now-dead
.coords-panel/.coords-expand-* CSS. Verified end-to-end: clipboard
content matches the displayed value.
@Osyna

Osyna commented Aug 10, 2026

Copy link
Copy Markdown
Owner Author

Fixed: card margins + coordinates redesigned as a single-line inline toggle

Spacing

The earlier header redesign accidentally dropped the wrapper that gave the address/coordinates card and the notes card their side margins — both were bleeding edge-to-edge while the buttons/tags above kept theirs. Fixed: both now sit at the same 22px inset as everything else (verified via bounding boxes). Notes card also got more generous internal padding.

Coordinates — much better UX now

Replaced the old accordion (tap → chevron rotates → a new row expands below, card grows taller) with a single-line inline toggle: tapping the row now replaces the 'Coordinates' label in place with the value + a Copy button — same row, same height (verified: 58px before and after, no layout jump). Tap again to revert to the label.

Verified end-to-end: margins match exactly, row height constant through the toggle, clipboard content matches the displayed value.

Content:
- New hook/tagline, badges, a 'Why Pinna' section that leads with
  benefits (delightful, organized, shareable, accessible, open,
  fast) instead of a dry feature dump
- Fixed the Live Demo link: maps.osyna.com doesn't even resolve
  anymore (DNS dead) — the real live app is maps.osyna.sh
- Fixed the demo login: test@test.com was wiped in the Feb incident
  and never recreated, so the README was advertising a broken
  credential to every first-time visitor. Recreated it as a public
  shared demo account with a curated dataset (24 real-world places
  across 15+ cities, 2 demo friends, a custom list, favorites) —
  same account doubles as the source for every screenshot below
- New hero: a 10s, 2.5MB optimized GIF (ffmpeg two-pass palette,
  recorded via Playwright) showing the swipe-driven tab transitions
  across all 5 identity colors and the inline coordinates-copy
  interaction — sells the motion work that static PNGs can't
- All 7 static screenshots re-captured against the CURRENT UI (per-
  tab hero colors, icon+color markers/legend, redesigned place detail
  header/notes/coordinates) — the previous images were from before
  most of this session's work and no longer represented the app
- Reorganized screenshot gallery, tech stack (Frontend/Backend/Infra
  columns), streamlined Docker one-liner framing, Contributing +
  star-the-repo close
@Osyna

Osyna commented Aug 10, 2026

Copy link
Copy Markdown
Owner Author

README rewrite + all-new screenshots — ready to actually sell the app

Found and fixed two things that were quietly sabotaging every first impression:

  • maps.osyna.com doesn't resolve anymore (DNS dead) — the README was linking people to a domain that no longer exists. Fixed to maps.osyna.sh, verified live (200).
  • The demo login (test@test.com) was broken — wiped in the Feb DB incident, never recreated, so anyone who did find the live link would've hit a wall trying to log in. Recreated it as a real public demo account.

What's new

  • A 'Why Pinna' section that leads with benefits instead of a dry feature list
  • A 10s hero GIF (2.5MB, ffmpeg two-pass palette from a Playwright recording) showing swipe-driven tab transitions across all 5 identity colors + the inline coordinates-copy interaction — the motion work genuinely doesn't sell as static PNGs
  • All 7 screenshots re-captured against a curated demo dataset (24 real-world places across 15+ cities, 2 demo friends, a custom list) — the old screenshots predated most of this session (no per-tab colors, old header, old coordinates UI, etc.)
  • Reorganized tech stack, streamlined setup, Contributing + star callout at the close

Verified: every local image path exists, every shields.io badge resolves, live login + domain both return 200.

@Osyna
Osyna merged commit a38b063 into main Aug 10, 2026
1 check passed
@Osyna
Osyna deleted the feature/cartoon-ui-skin branch August 10, 2026 15:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant