Add square hover-flip CollectionCardSquare - #59
Conversation
New CollectionCardSquare shows preview image as a proportional square with title overlaid, flipping on hover to reveal the description on its back (skipped when there's no description). Wired into / and /published-collections; existing CollectionCard is untouched and still used on /collections and /collections/[id]. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Squares were too big at 3-per-row; now 4-per-row on / and /published-collections, homepage picks 4 random collections instead of 6 to fill exactly one row. Flip no longer swaps to a solid description panel - it's a true 3D flip so the same preview image shows mirrored, with the description fading in on top as a non-rotating overlay. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ove hover effects
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 35 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughChangesPublished collection card experience
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Homepage
participant PublishedCollectionsModel
participant CollectionCardSquare
Homepage->>PublishedCollectionsModel: request published collections
PublishedCollectionsModel->>PublishedCollectionsModel: select up to four random collections
PublishedCollectionsModel-->>Homepage: return selected collections
Homepage->>CollectionCardSquare: render each collection with square card props
CollectionCardSquare->>CollectionCardSquare: render image, placeholder, description, and overlays
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/shared/ui/__tests__/collection-card-square.test.ts`:
- Around line 15-30: Update mountCard to use the shared testing utilities to
stub Vuetify’s VImg and VIcon components instead of creating and registering a
real createVuetify() plugin. Remove the local Vuetify instance and configure the
shared boundary stubs in the mount options, preserving the existing route,
slots, and prop behavior while asserting CollectionCardSquare’s contract through
those stubs.
In `@app/shared/ui/collection-card-square.vue`:
- Line 14: The description is rendered with opacity 0 when canFlip is false,
causing it to disappear in noFlip mode. Update the description layout and
associated selectors in the collection card template/styles so noFlip displays
the description visibly on the front face, while preserving the existing flip
behavior when canFlip is true.
- Around line 19-23: Move the hover and focus-within flip-state styling from the
outer card to the collection-card-square__flipper component so overlay controls
remain operable. When to is absent, make the flippable div keyboard-focusable
and ensure keyboard focus reveals the description without immediately hiding
controls. Add coverage for overlay pointer activation, overlay keyboard
interaction, and keyboard access to unlinked cards.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 8a9beaea-1ae5-4a6f-906f-421d6af59112
📒 Files selected for processing (10)
app/features/published-collections/model/__tests__/use-random-published-collections.test.tsapp/features/published-collections/model/use-homepage-published-collections.tsapp/features/published-collections/model/use-random-published-collections.tsapp/pages/index.vueapp/pages/published-collections.vueapp/shared/ui/__tests__/collection-card-square.test.tsapp/shared/ui/collection-card-square.stories.tsapp/shared/ui/collection-card-square.vueapp/shared/ui/index.tsvitest.config.ts
| // Vuetify's components need a real Vuetify instance to render (they inject | ||
| // their defaults/theme via provide/inject) - mountSuspended gives Nuxt | ||
| // context but doesn't run the app's vuetify-nuxt-module plugin, so it's | ||
| // supplied explicitly here, same as Vuetify's own unit-testing docs. | ||
| const vuetify = createVuetify(); | ||
|
|
||
| function mountCard( | ||
| props: CollectionCardSquareProps, | ||
| extra: { route?: string; slots?: Record<string, () => string> } = {} | ||
| ) { | ||
| return mountSuspended(CollectionCardSquare, { | ||
| props, | ||
| route: extra.route, | ||
| slots: extra.slots, | ||
| global: { plugins: [vuetify] } | ||
| }); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate files =="
git ls-files | rg '(^|/)collection-card-square\.(test\.ts|vue)$|testing|vuetify|ui' | head -200 || true
echo
echo "== target test =="
if [ -f app/shared/ui/__tests__/collection-card-square.test.ts ]; then
wc -l app/shared/ui/__tests__/collection-card-square.test.ts
cat -n app/shared/ui/__tests__/collection-card-square.test.ts
fi
echo
echo "== candidate shared test utilities =="
python3 - <<'PY'
import os
base='app/shared/testing'
for root, dirs, files in os.walk(base):
dirs[:] = sorted(d for d in dirs if not d.startswith('.'))
for f in sorted(files):
if f.endswith(('.ts','.vue')):
p=os.path.join(root,f)
print(f)
lines=open(p,encoding='utf-8',errors='replace').readlines()
hits=[i+1 for i,l in enumerate(lines) if 'Vuetify' in l or 'VImg' in l or 'VIcon' in l or 'Mock' in l or 'Stub' in l or 'mountSuspended' in l]
print(' hits:', hits[:20] if hits else [])
PY
echo
echo "== search for vuetify mocking/stubbing in tests =="
rg -n "createVuetify|VImg|VIcon|useVuetify|localVue|vuetify|setupVuetify|global:|plugins:|resolve\(\"|Mock|Stub|component" app/shared app -g '*.test.ts' -g '*.ts' -g '*.vue' | head -250 || trueRepository: ebulgakov/linkfolio
Length of output: 32779
Mock the Vuetify boundary in this unit test.
The test uses createVuetify() instead of shared boundary mocking. Replace the real Vuetify plugin with stubs for VImg and VIcon through the shared testing utilities, then check the component contract against those stubs.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/shared/ui/__tests__/collection-card-square.test.ts` around lines 15 - 30,
Update mountCard to use the shared testing utilities to stub Vuetify’s VImg and
VIcon components instead of creating and registering a real createVuetify()
plugin. Remove the local Vuetify instance and configure the shared boundary
stubs in the mount options, preserving the existing route, slots, and prop
behavior while asserting CollectionCardSquare’s contract through those stubs.
Source: Coding guidelines
…s in CollectionCardSquare Addresses CodeRabbit review on PR #59: - noFlip cards never showed the description: the hover/focus rule that fades scrim->description was scoped to the --flip class, which noFlip disables. Split into a --reveal class (crossfade, gated on description presence alone) separate from --flip (rotation, still gated on !noFlip). The description's counter-rotation transform is now scoped to --flip only, since --reveal-only cards never rotate the parent and would otherwise render the text mirrored. - Hover/focus-within on the outer card made overlay slot controls (e.g. an "Add link" button) unclickable/unfocusable the instant the pointer or focus entered the card, and unlinked-but-flippable cards had no focusable element at all. Triggers now bind to the flipper itself (:hover/:focus), and the overlay uses a sibling-hover selector so it stays interactive once the pointer/focus actually reaches it; unlinked revealable cards get tabindex=0. Left the Vuetify-mocking suggestion (createVuetify() vs. a shared VImg/VIcon stub) unaddressed: no such shared stub utility exists in app/shared/testing, and the real-instance pattern here is the one documented in Vuetify's own testing docs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Addressed in 40bba04:
Added test coverage for the tabindex/reveal-class contract ( |
Summary
CollectionCardSquareshows a square preview with title overlaid, flipping on hover/focus to reveal the description mirrored on the same face (true 3D flip, no separate back panel)./and/published-collections(4-per-row grid); existingCollectionCarduntouched on/collections.will-change: transform,:focus-withinsupport for keyboard/touch, plus a blurred-background fill behind the preview image.Test plan
pnpm test— colocatedcollection-card-square.test.tspassespnpm lint/and/published-collections, confirm smooth flip with no mid-animation pop🤖 Generated with Claude Code
Summary by CodeRabbit