Skip to content

feat(cards): glass floating action bar on feed cards (experiment)#6165

Open
tsahimatsliah wants to merge 18 commits into
mainfrom
claude/dazzling-herschel-d50db8
Open

feat(cards): glass floating action bar on feed cards (experiment)#6165
tsahimatsliah wants to merge 18 commits into
mainfrom
claude/dazzling-herschel-d50db8

Conversation

@tsahimatsliah

@tsahimatsliah tsahimatsliah commented Jun 9, 2026

Copy link
Copy Markdown
Member

What

Reclaims vertical space on feed grid cards by lifting the engagement/action bar off its own row and floating it over the bottom of the card with an iOS/macOS-style dark glass treatment (translucent tint + backdrop blur).

How it looks

A dark, blurred glass pill floats in the bottom-left of the card, in both light and dark themes (the tint is a consistent dark neutral, bg-overlay-primary-pepper).

It's one component that expands:

  • Collapsed (default): just the upvote + comment counts — a compact peek that barely covers the artwork.
  • Hover: the same pill grows rightward, revealing downvote / award / bookmark / copy-link via an animated grid column (grid-template-columns 0→1fr + opacity). No cross-fade — upvote + comment stay anchored on the left and the rest slide in.

On touch devices (no hover) the bar stays expanded.

When there's a cover image it floats over it (and the image goes full-bleed: edge-to-edge, flush to the bottom, rounded to the card). For text/markdown posts it floats over the content, which blurs through the glass.

Mock-up: Storybook → Components / Cards / Glass Actions Grid.

Card coverage (all grid post types)

Card Behavior
Article Glass bar over full-bleed cover image
Shared-to-squad Glass over the shared cover image (default); inline for the shared-post-preview / tweet / deleted / private footers
Collection Glass over cover image, or over content when image-less
Freeform (incl. text/markdown) Glass over cover image, or over the content (blurs through)
Poll Glass bar with reserved bottom space so it never covers the vote options

Implementation

  • Flag feed_card_glass_actionsfeatureFeedCardGlassActions, read via useFeedCardGlassActions.
  • FeedCardGlassActions is a self-contained expanding bar that reuses useCardActions (no mutation logic duplicated) and the standard button building blocks + tooltips.
  • Full-bleed cover via shared glassCoverImageClassName + an imageClassName override on WelcomePostCardFooter.
  • Each card switches its floor to min-h-cardGlass (21.5rem) when glass is active.

Flag default ⚠️

Defaults to true so the design renders by default for review. Flip to false before running the real GrowthBook experiment.

Testing

  • 45 card specs pass (Article / Share / Collection / Poll) with the flag on; action clicks work through the floating bar.
  • Strict typecheck + lint pass on changed files.

🤖 Generated with Claude Code

Preview domain

https://claude-dazzling-herschel-d50db8.preview.app.daily.dev

Float the engagement bar over the bottom of the cover image with an
iOS/macOS-style dark glass (translucent + blur) treatment and shrink the
grid card height since the bar no longer takes its own row.

Gated by the new `feed_card_glass_actions` GrowthBook flag. The flag
defaults to `true` for now so the design can be reviewed by default —
flip to `false` before running the real experiment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
daily-webapp Ready Ready Preview Jun 10, 2026 1:34pm
storybook Building Building Preview Jun 10, 2026 1:34pm

Request Review

Apply the floating glass action bar to the other image-based grid cards
(shared-to-squad, collection, image freeform), gated by the same
feed_card_glass_actions flag. The bar floats only when the card has a
cover image to float over; poll, text-only freeform, and the shared-post
preview/tweet/empty footers keep the inline bar so it never covers text
or vote options.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
By default the floating glass bar shows only a small left-aligned summary
(upvote + comment counts) so it barely covers the cover image. On card
hover (mouse/laptop) it expands into the full action bar; touch devices
keep the full bar always visible.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
In the glass variant the cover image now goes edge-to-edge (drop the side
padding), sits flush to the card bottom (drop the bottom margin), is taller
so it dominates the card, and its bottom corners are rounded to match the
card. Threaded via a shared `glassCoverImageClassName` and a new
`imageClassName` override on WelcomePostCardFooter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rebuild the floating bar as one component that expands: upvote + comment
stay anchored on the left and the rest of the actions (downvote, award,
bookmark, copy) reveal to the right on hover via an animated grid column,
so the same pill grows rightward instead of cross-fading two elements.
Reuses useCardActions so no mutation logic is duplicated; keeps the action
tooltips for accessibility.

Also extend the floating bar to every grid post type: text/markdown
freeform and image-less collections float it over the content (which
blurs through the glass), and polls reserve a little bottom space so the
bar never covers the vote options.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address review feedback on the glass action bar:
- Expanded state now spans the full card width and spreads the icons
  (justify-between) again by reusing the original ActionButtons.
- Restores the original action order (downvote left of comment) instead
  of the reordered custom layout.
- Bigger bar height (h-10) and more horizontal padding in both the
  collapsed peek and the expanded bar.
- Expand is now a smooth left-to-right clip-path reveal so the peek
  appears to grow into the full-width bar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address review feedback:
- Reduce left/right padding on both the peek and the full bar.
- Replace the clip-path reveal (which glitched/shifted) with a plain
  opacity cross-fade between two elements anchored at the same
  bottom-left, so there's no layout shift.
- Keep action icons white at rest AND on hover (pin both
  --button-default-color and --button-hover-color); only the pressed/
  active state shows a brand tint.
- Remove the drop shadow from the floating bar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the two stacked elements (peek pill + full bar cross-fading) with
a single glass pill whose max-width animates from a compact cap to 100%
on card hover. The border, tint and blur belong to one element, so
nothing swaps or shifts — the pill itself grows, and the full-width
action row redistributes its icons continuously while the width animates.
Peek counts and the action row are layered inside the pill with
choreographed fades (peek out fast, actions in slightly delayed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rebuild the glass bar on iOS-26 Liquid Glass principles: one pill holds
the real action buttons at all times, so the anchored actions are the
same DOM nodes in both states and physically cannot flash or shift.

- Peek shows only actions with engagement: upvote always (even at zero,
  as the affordance), comments only when there's a count — so the pill
  hugs its content and there's no dead space on the right.
- Every other action sits in its own grid track animating 0fr <-> 1fr;
  an outer fr-split grid stretches the pill from content-hug to full
  card width (fit-content -> 100% isn't animatable, fr tracks are).
- Contents materialize inside the growing surface (fade + visibility,
  slightly delayed) instead of cross-fading over it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tsahimatsliah and others added 2 commits June 10, 2026 13:40
The QuaternaryButton counter label has no right padding, so the last
count ended flush against the pill's right edge (~4px inset) while the
left edge got the pill padding plus the button's internal icon padding
(~10px). Add a matching pr-1.5 to the counter labels so both edges
inset equally (measured 11px / 11px in every collapsed variant).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The pill hard-coded a dark pepper tint and white icons, which looked
wrong in light mode. Switch to the design system's theme-aware glass
token `bg-blur-bg` (pepper @64% in dark, white @64% in light) with
`text-text-primary`, and pin the button rest/hover colors to
text-primary instead of white so icons adapt per theme while brand
tints remain for the pressed/active state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Theme tokens are plain `var(--theme-*)` strings, so Tailwind opacity
modifiers like `bg-background-default/70` or `bg-surface-float/40`
silently produced no CSS at all — ~45 call sites across the repo were
rendering fully transparent (verified via getComputedStyle).

Fix at the root: wrap the var-based color families in a `withAlpha`
helper that converts each leaf into a Tailwind function color emitting
`color-mix(in srgb, var(...) calc(a * 100%), transparent)` — the same
color-mix pattern base.css already uses — so every existing modifier
now works as authored, theme-aware, with no per-file changes.
Unmodified utilities are unaffected (verified plain tokens compute
identically in both themes).

Also switch EngagementRail's glass surfaces to the semantic blur tokens
(bg-blur-bg ~64%, bg-blur-baseline ~88%) instead of ad-hoc percentages.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Move downvote after comment so the anchored upvote + comment never
  shift when the pill expands (comment outranks downvote in value).
- Pin icon AND counter colors to text-primary via [&_.btn] /
  [&_.btn-quaternary] descendant overrides — the btn-tertiary-* classes
  re-declare the color vars per element, which was shadowing the
  pill-level pins and rendering icons/counters in text-secondary.
  Pressed/active brand tints are untouched.
- Drop the full-bleed cover treatment: the image returns to the
  production presentation (padded, h-40, rounded) so the glass cards
  actually get shorter — each card saves the old action-row height
  (~40px, min-h 24rem -> 21.5rem) instead of giving it back to a
  taller image. Removes glassCoverImageClassName and the
  WelcomePostCardFooter imageClassName prop added for it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Team feedback: scrolling fired a cascade of expand animations as cards
passed under the cursor, making the feed feel busy and interrupting
reading. Fix without dropping the hover-expand:

- New shared useIsScrolling hook: one capture-phase scroll listener (ref
  -counted via useSyncExternalStore) flips a flag true on scroll and
  back ~200ms after the last scroll event.
- The glass pill only attaches its group-hover expand utilities when the
  feed isn't scrolling, so a card under the cursor mid-scroll simply
  stays collapsed — no animation can fire. When scrolling stops, a
  genuinely hovered card expands.
- Add a ~180ms hover-intent delay so a quick pass doesn't trigger it
  either, and motion-reduce:transition-none for reduced-motion users.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tsahimatsliah and others added 2 commits June 10, 2026 15:14
Drop the cover image's left/right padding and bottom margin in the glass
variant so it meets the card's edges, and round its bottom corners to the
card radius (rounded-b-16, square top). Height and object-cover are
untouched — identical crop and aspect, just edge-to-edge instead of inset
by px-1/mb-1. Threaded via glassCoverImageClassName + the
WelcomePostCardFooter imageClassName prop, gated on useGlass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The hover-color pin (added earlier) forced icons/counters to stay white
on hover, so only the button's hover background changed. Drop the
--button-hover-color pin and keep only the rest-state --button-default-
color pin, so the btn-tertiary-* classes drive the hover tint again: the
icon AND its number turn the action's brand color on hover (avocado for
upvote, blueCheese for comment, etc.), matching standard ActionButtons.
Rest stays text-primary for contrast; pressed/active unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Making the theme tokens alpha-capable (withAlpha) means the Tailwind
ESLint plugin now recognizes alpha modifiers like bg-accent-onion-default
/[0.08] and bg-surface-float/40 as real utilities and sorts them into
canonical order — surfacing classnames-order warnings (which fail CI's
--max-warnings 0 lint, and webapp's pretest). Apply eslint --fix to the
affected files. Pure class reordering, no behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The ~180ms intent delay made the expand feel laggy. Drop it so a resting
hover expands immediately. The scroll-suppression rule is kept intact —
the group-hover expand utilities are still only attached when the feed
isn't scrolling, so cards expand on a resting hover but never as they
pass under the cursor mid-scroll.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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