[Dashboard] Adds app store Descriptions and images#1041
Conversation
|
Skipped: No reviewable files found. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a thumbnail gallery with fullscreen preview and keyboard navigation; changes screenshot data to accept StaticImageData or string and enriches descriptions; converts a dialog container to a vertical flex layout; makes app tiles clickable; and refactors/memoizes prefetch components and UrlPrefetcher. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Thumbs as Thumbnails/Scroller
participant AppStore as AppStoreEntry
participant Modal as Preview Modal
participant Keyboard as Keyboard Events
User->>Thumbs: click thumbnail (index)
Thumbs->>AppStore: onClick(index)
AppStore->>AppStore: set previewIndex, open Dialog
AppStore->>Modal: render image at previewIndex
User->>Keyboard: press ArrowRight / ArrowLeft / Escape
Keyboard->>AppStore: navigatePreview(+1/-1) or close
AppStore->>Modal: update image or close Dialog
User->>AppStore: click next/prev buttons
AppStore->>AppStore: update previewIndex
AppStore->>Modal: re-render image
User->>AppStore: click thumbnail scroll controls
AppStore->>Thumbs: programmatic scroll
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
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: 1
🧹 Nitpick comments (1)
apps/dashboard/src/components/app-store-entry.tsx (1)
45-62: Consider removing redundant Escape key handling.The Dialog component already handles Escape key via
onOpenChange(line 162), so the manual Escape handling at line 55-57 is redundant. The Dialog's built-in behavior is sufficient.Apply this diff to simplify the keyboard handler:
useEffect(() => { if (previewIndex === null) return; const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'ArrowLeft') { e.preventDefault(); navigatePreview('prev'); } else if (e.key === 'ArrowRight') { e.preventDefault(); navigatePreview('next'); - } else if (e.key === 'Escape') { - setPreviewIndex(null); } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, [previewIndex, navigatePreview]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (38)
apps/dashboard/public/storeDesc-api-keys-1.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-auth-1.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-auth-2.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-auth-3.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-auth-4.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-auth-5.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-auth-6.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-data-vault-1.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-data-vault-2.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-data-vault-3.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-data-vault-4.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-emails-1.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-emails-2.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-emails-3.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-emails-4.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-emails-5.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-emails-6.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-emails-7.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-emails-8.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-payments-1.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-payments-2.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-payments-3.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-payments-4.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-payments-5.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-payments-6.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-payments-7.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-rbac-1.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-rbac-2.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-rbac-3.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-rbac-4.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-teams-1.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-teams-2.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-teams-3.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-teams-4.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-vercel-1.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-vercel-2.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-webhooks-1.pngis excluded by!**/*.pngapps/dashboard/public/storeDesc-webhooks-2.pngis excluded by!**/*.png
📒 Files selected for processing (3)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]/page-client.tsx(1 hunks)apps/dashboard/src/components/app-store-entry.tsx(4 hunks)apps/dashboard/src/lib/apps-frontend.tsx(10 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: For blocking alerts and errors, never usetoast, as they are easily missed by the user. Instead, use alerts
Keep hover/click transitions snappy and fast. Don't delay the action with a pre-transition; apply transitions after the action instead
NEVER try-catch-all, NEVER void a promise, and NEVER .catch(console.error). UserunAsynchronouslyorrunAsynchronouslyWithAlertinstead for asynchronous error handling
When creating hover transitions, avoid hover-enter transitions and just use hover-exit transitions (e.g.,transition-colors hover:transition-none)
Use ES6 maps instead of records wherever possible
Files:
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]/page-client.tsxapps/dashboard/src/components/app-store-entry.tsxapps/dashboard/src/lib/apps-frontend.tsx
apps/{backend,dashboard}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
NEVER use Next.js dynamic functions if you can avoid them. Instead, prefer using a client component and prefer
usePathnameinstead ofawait params
Files:
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]/page-client.tsxapps/dashboard/src/components/app-store-entry.tsxapps/dashboard/src/lib/apps-frontend.tsx
🧠 Learnings (1)
📚 Learning: 2025-11-28T21:21:39.123Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T21:21:39.123Z
Learning: Applies to apps-{frontend,config}.ts{,x} : To update the list of apps available, edit `apps-frontend.tsx` and `apps-config.ts`
Applied to files:
apps/dashboard/src/components/app-store-entry.tsxapps/dashboard/src/lib/apps-frontend.tsx
🧬 Code graph analysis (2)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]/page-client.tsx (1)
packages/stack-ui/src/components/ui/dialog.tsx (1)
DialogContent(126-126)
apps/dashboard/src/components/app-store-entry.tsx (2)
docs/src/components/icons.tsx (2)
ChevronLeft(313-315)ChevronRight(309-311)packages/stack-ui/src/components/ui/dialog.tsx (3)
Dialog(123-123)DialogContent(126-126)DialogTitle(132-132)
🔇 Additional comments (7)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]/page-client.tsx (1)
28-28: LGTM!The flex layout classes enable proper vertical stacking of the AppStoreEntry content within the modal.
apps/dashboard/src/lib/apps-frontend.tsx (3)
37-37: LGTM!Extending the type to support both string paths and StaticImageData provides flexibility for different image loading strategies.
77-284: LGTM!The store descriptions are well-written, consistent, and provide clear value propositions for each app. The use of
'for apostrophes in JSX is correct.
11-14: All referenced screenshot files exist in the public directory—no action required.Verification confirms that all 38 screenshot files referenced by the
getScreenshotshelper are present inapps/dashboard/public/and match the expected naming pattern and counts for each app (auth: 6, teams: 4, rbac: 4, api-keys: 1, payments: 7, emails: 8, data-vault: 4, webhooks: 2, vercel: 2).apps/dashboard/src/components/app-store-entry.tsx (3)
22-42: LGTM!The state management and navigation logic are well-structured. The use of
useCallbackprevents unnecessary re-renders of the navigation handler.
123-141: LGTM!The scroll controls use opacity transitions appropriately, appearing on group hover. The
transition-opacityfollows the pattern of transitioning on exit (when hover ends).
161-222: LGTM!The modal implementation is well-structured with proper accessibility labels, keyboard navigation, and responsive image handling. The use of
DialogTitlewithsr-onlyprovides screen reader context while keeping the UI clean.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/dashboard/src/components/app-store-entry.tsx (1)
199-212: Critical: Screenshots are not clickable — the preview modal can never be opened.The modal implementation exists (lines 231-292) with keyboard navigation and controls, but there's no way to open it. The screenshot elements lack an
onClickhandler to setpreviewIndex, so it remainsnullforever.Add click handlers to make screenshots open the preview modal:
{appFrontend.screenshots.map((screenshot: string, index: number) => ( - <div + <button key={index} - className="relative h-64 w-96 rounded-xl shadow-lg flex-shrink-0 overflow-hidden border border-gray-200 dark:border-gray-800" + onClick={() => setPreviewIndex(index)} + className="relative h-64 w-96 rounded-xl shadow-lg flex-shrink-0 overflow-hidden border border-gray-200 dark:border-gray-800 cursor-pointer hover:ring-2 hover:ring-blue-500 transition-shadow hover:transition-none focus:outline-none focus:ring-2 focus:ring-blue-500" + aria-label={`View ${app.displayName} screenshot ${index + 1}`} > <Image src={screenshot} alt={`${app.displayName} screenshot ${index + 1}`} fill className="object-cover select-none" draggable={false} /> - </div> + </button> ))}
♻️ Duplicate comments (1)
apps/dashboard/src/components/app-store-entry.tsx (1)
243-276: Adjust hover transitions on modal buttons to follow coding guidelines.The close, previous, and next buttons use
transition-colorswithouthover:transition-none. Per coding guidelines, hover transitions should snap instantly on hover and animate on exit.<button onClick={() => setPreviewIndex(null)} - className="absolute top-4 right-4 z-50 bg-white/10 hover:bg-white/20 p-2 rounded-full transition-colors" + className="absolute top-4 right-4 z-50 bg-white/10 hover:bg-white/20 p-2 rounded-full transition-colors hover:transition-none" aria-label="Close preview" ><button onClick={() => navigatePreview('prev')} - className="absolute left-4 top-1/2 -translate-y-1/2 z-50 bg-white/10 hover:bg-white/20 p-3 rounded-full transition-colors" + className="absolute left-4 top-1/2 -translate-y-1/2 z-50 bg-white/10 hover:bg-white/20 p-3 rounded-full transition-colors hover:transition-none" aria-label="Previous screenshot" ><button onClick={() => navigatePreview('next')} - className="absolute right-4 top-1/2 -translate-y-1/2 z-50 bg-white/10 hover:bg-white/20 p-3 rounded-full transition-colors" + className="absolute right-4 top-1/2 -translate-y-1/2 z-50 bg-white/10 hover:bg-white/20 p-3 rounded-full transition-colors hover:transition-none" aria-label="Next screenshot" >Based on learnings, hover transitions should snap on hover-enter and animate on hover-exit.
🧹 Nitpick comments (2)
apps/dashboard/src/lib/apps-frontend.tsx (2)
39-39: TheStaticImageDatatype is currently unused.While the type signature now allows
(string | StaticImageData)[], all current calls togetScreenshots()return onlystring[]. If you plan to support imported image objects in the future, this is fine; otherwise, you could keep the simplerstring[]type for now.
222-222: Empty descriptions for alpha-stage apps.The apps
tv-mode,catalyst,neon, andconvexstill have emptystoreDescriptionfields. If these apps are not yet ready for public promotion (all are marked as "alpha" in the config), this is acceptable. Otherwise, consider adding descriptions to maintain consistency.Also applies to: 246-246, 260-260, 274-274
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/dashboard/src/components/app-store-entry.tsx(3 hunks)apps/dashboard/src/lib/apps-frontend.tsx(10 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: For blocking alerts and errors, never usetoast, as they are easily missed by the user. Instead, use alerts
Keep hover/click transitions snappy and fast. Don't delay the action with a pre-transition; apply transitions after the action instead
NEVER try-catch-all, NEVER void a promise, and NEVER .catch(console.error). UserunAsynchronouslyorrunAsynchronouslyWithAlertinstead for asynchronous error handling
When creating hover transitions, avoid hover-enter transitions and just use hover-exit transitions (e.g.,transition-colors hover:transition-none)
Use ES6 maps instead of records wherever possible
Files:
apps/dashboard/src/lib/apps-frontend.tsxapps/dashboard/src/components/app-store-entry.tsx
apps/{backend,dashboard}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
NEVER use Next.js dynamic functions if you can avoid them. Instead, prefer using a client component and prefer
usePathnameinstead ofawait params
Files:
apps/dashboard/src/lib/apps-frontend.tsxapps/dashboard/src/components/app-store-entry.tsx
🧠 Learnings (3)
📚 Learning: 2025-11-28T21:21:39.123Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T21:21:39.123Z
Learning: Applies to apps-{frontend,config}.ts{,x} : To update the list of apps available, edit `apps-frontend.tsx` and `apps-config.ts`
Applied to files:
apps/dashboard/src/lib/apps-frontend.tsxapps/dashboard/src/components/app-store-entry.tsx
📚 Learning: 2025-11-28T21:21:39.123Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T21:21:39.123Z
Learning: Applies to **/*.{ts,tsx} : When creating hover transitions, avoid hover-enter transitions and just use hover-exit transitions (e.g., `transition-colors hover:transition-none`)
Applied to files:
apps/dashboard/src/components/app-store-entry.tsx
📚 Learning: 2025-11-28T21:21:39.123Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T21:21:39.123Z
Learning: Applies to **/*.{ts,tsx} : Keep hover/click transitions snappy and fast. Don't delay the action with a pre-transition; apply transitions after the action instead
Applied to files:
apps/dashboard/src/components/app-store-entry.tsx
🧬 Code graph analysis (1)
apps/dashboard/src/lib/apps-frontend.tsx (1)
packages/stack-shared/src/apps/apps-config.ts (2)
AppId(48-48)ALL_APPS(50-141)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: Vercel Agent Review
- GitHub Check: docker
- GitHub Check: all-good
- GitHub Check: lint_and_build (latest)
- GitHub Check: build (22.x)
- GitHub Check: build (22.x)
- GitHub Check: build (22.x)
- GitHub Check: restart-dev-and-test-with-custom-base-port
- GitHub Check: restart-dev-and-test
- GitHub Check: check_prisma_migrations (22.x)
- GitHub Check: setup-tests
🔇 Additional comments (5)
apps/dashboard/src/components/app-store-entry.tsx (2)
36-62: LGTM!The
navigatePreviewcallback and keyboard event handler are well-implemented with proper boundary checks and cleanup.
231-292: LGTM!The modal implementation is well-structured with proper accessibility (sr-only title, aria-labels), correct open/close state management, and appropriate conditional rendering of navigation buttons at boundary conditions.
apps/dashboard/src/lib/apps-frontend.tsx (3)
80-86: LGTM! Well-crafted descriptions.The store descriptions for Authentication, Teams, and RBAC are clear, informative, and user-focused. They effectively communicate the purpose and value of each app.
Also applies to: 96-102, 112-118
127-133: LGTM! Excellent descriptions across all major apps.The store descriptions for API Keys, Payments, Emails, Email API, Data Vault, Webhooks, and Launch Checklist are comprehensive and user-friendly. They consistently explain features and benefits while maintaining a professional tone.
Also applies to: 144-150, 162-168, 177-183, 192-198, 207-213, 231-237
13-16: All screenshot files are present and accounted for.The helper function correctly generates dynamic screenshot paths, and all referenced files exist in
apps/dashboard/public/. Each app's screenshot count matches itsgetScreenshots()call:
- auth (6), teams (4), rbac (4), api-keys (1), payments (7), emails (8), data-vault (4), webhooks (2), vercel (2)
The implementation is correct with no missing assets.
There was a problem hiding this comment.
Additional Suggestion:
Screenshot thumbnails are missing click handlers to open the preview modal, breaking the "clickable thumbnails" feature mentioned in the PR description.
View Details
📝 Patch Details
diff --git a/apps/dashboard/src/components/app-store-entry.tsx b/apps/dashboard/src/components/app-store-entry.tsx
index 0235f10e..c2f14228 100644
--- a/apps/dashboard/src/components/app-store-entry.tsx
+++ b/apps/dashboard/src/components/app-store-entry.tsx
@@ -199,7 +199,8 @@ export function AppStoreEntry({
{appFrontend.screenshots.map((screenshot: string, index: number) => (
<div
key={index}
- className="relative h-64 w-96 rounded-xl shadow-lg flex-shrink-0 overflow-hidden border border-gray-200 dark:border-gray-800"
+ onClick={() => setPreviewIndex(index)}
+ className="relative h-64 w-96 rounded-xl shadow-lg flex-shrink-0 overflow-hidden border border-gray-200 dark:border-gray-800 cursor-pointer hover:shadow-xl transition-shadow"
>
<Image
src={screenshot}
Analysis
Screenshot thumbnails missing click handlers to open preview modal
What fails: AppStoreEntry component screenshot thumbnails cannot be clicked to open the full-screen preview modal. The thumbnails are rendered but have no click event handlers, making the preview modal inaccessible to users. Users can only navigate screenshots with arrow keys if they find another way to trigger the modal (which is currently impossible from the UI).
How to reproduce:
- Navigate to the app store entry page for any app with screenshots
- Attempt to click on any thumbnail in the "Preview" section
- Observe that nothing happens - the modal does not open
Result: Clicking thumbnails has no effect. The modal remains closed.
Expected: Clicking a thumbnail should set previewIndex to that thumbnail's index, opening the full-screen preview modal displaying that screenshot. Users should then be able to navigate between screenshots using arrow keys or the on-screen navigation buttons.
Root cause: During the dashboard redesign (commit c2992f3), the screenshot thumbnail elements were refactored from <button> elements with onClick={() => setPreviewIndex(index)} handlers to plain <div> elements without click handlers. This regression removed the only user-accessible way to open the screenshot preview modal, which was introduced in commit 9c4a8a4 ("Support image slideshow, and open image in modals").
Fix: Restored the onClick={() => setPreviewIndex(index)} handler to the thumbnail container and added cursor-pointer and hover effects for better UX.
There was a problem hiding this comment.
Additional Suggestion:
Screenshot thumbnails are not clickable - the preview modal cannot be opened because the screenshot divs are missing onClick handlers to set the preview index.
View Details
📝 Patch Details
diff --git a/apps/dashboard/src/components/app-store-entry.tsx b/apps/dashboard/src/components/app-store-entry.tsx
index 0235f10e..c2f14228 100644
--- a/apps/dashboard/src/components/app-store-entry.tsx
+++ b/apps/dashboard/src/components/app-store-entry.tsx
@@ -199,7 +199,8 @@ export function AppStoreEntry({
{appFrontend.screenshots.map((screenshot: string, index: number) => (
<div
key={index}
- className="relative h-64 w-96 rounded-xl shadow-lg flex-shrink-0 overflow-hidden border border-gray-200 dark:border-gray-800"
+ onClick={() => setPreviewIndex(index)}
+ className="relative h-64 w-96 rounded-xl shadow-lg flex-shrink-0 overflow-hidden border border-gray-200 dark:border-gray-800 cursor-pointer hover:shadow-xl transition-shadow"
>
<Image
src={screenshot}
Analysis
Screenshot thumbnails missing onClick handlers in AppStoreEntry component
What fails: The screenshot preview gallery in apps/dashboard/src/components/app-store-entry.tsx (lines 200-212) renders thumbnail divs without onClick handlers, making it impossible to open the full-screen preview modal. The previewIndex state remains null, and the Dialog component (line 232) never opens because it's conditioned on previewIndex !== null.
How to reproduce:
- Navigate to a page that uses the
AppStoreEntrycomponent with screenshots - Attempt to click on any screenshot thumbnail
- The full-screen preview modal does not open
Result: Clicking thumbnails has no effect. The preview modal never opens. Users cannot view full-size screenshots.
Expected: Clicking any thumbnail should open a full-screen preview modal displaying that screenshot, with navigation controls to browse through other screenshots, as evidenced by the modal implementation (lines 232-292) that includes navigation buttons, keyboard handlers, and image display functionality.
Root cause: The setPreviewIndex(index) function is never called from user interaction. Code review shows setPreviewIndex is only called in:
- Initial state declaration (line 23, set to
null) - Navigation within modal (line 41, requires
previewIndex !== nullas precondition) - Close handlers (lines 56, 244)
The thumbnail divs lack the critical onClick={() => setPreviewIndex(index)} handler needed to open the modal initially.
Fix: Added onClick={() => setPreviewIndex(index)} to each thumbnail div and improved UX with cursor-pointer hover:shadow-xl transition-shadow CSS classes to indicate interactivity.
…ent in Link to navigate to the app details page, Triggers existing intercept route to open modal, enable/disable button still works
… to open lightbox preview, add left/right scroll buttons that appear on hover. Attach ref to scrollable container for button nav
…chMany outside HookPrefetcher for stable component ref. Wrap with memo() to skip re-renders when props unchanged, extract PrefetchCallback to isolate renders per callback
…ith memo() to prevent re-renders on context changes. Use useMemo() for callbacks array to maintain stable ref
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/dashboard/src/components/app-store-entry.tsx (1)
221-234: Type annotation may conflict with updatedscreenshotstype.The AI summary indicates
screenshotstype was changed to(string | StaticImageData)[], but line 221 explicitly types the parameter asstring. This will cause a TypeScript error if screenshots containStaticImageDataobjects.Apply this diff to fix the type:
- {appFrontend.screenshots.map((screenshot: string, index: number) => ( + {appFrontend.screenshots.map((screenshot, index) => (Letting TypeScript infer the type from the array is cleaner and avoids potential mismatches.
♻️ Duplicate comments (2)
apps/dashboard/src/components/app-store-entry.tsx (2)
199-214: Adjust hover transition on scroll buttons per coding guidelines.The
transition-opacitycauses the buttons to fade in smoothly on hover enter. Per coding guidelines, hover-enter transitions should snap instantly while hover-exit transitions should animate.Apply this diff:
<button onClick={() => scrollScreenshots('left')} - className="absolute left-0 top-1/2 -translate-y-1/2 z-10 bg-white/90 dark:bg-gray-900/90 hover:bg-white dark:hover:bg-gray-800 p-2 rounded-full shadow-lg border border-gray-200 dark:border-gray-700 opacity-0 group-hover/screenshots:opacity-100 transition-opacity focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-blue-500" + className="absolute left-0 top-1/2 -translate-y-1/2 z-10 bg-white/90 dark:bg-gray-900/90 hover:bg-white dark:hover:bg-gray-800 p-2 rounded-full shadow-lg border border-gray-200 dark:border-gray-700 opacity-0 group-hover/screenshots:opacity-100 transition-opacity group-hover/screenshots:transition-none focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-blue-500" aria-label="Scroll left" >Same change needed for the right scroll button on line 210.
222-226: Addhover:transition-noneto thumbnail buttons.Per coding guidelines, hover transitions should snap instantly on enter and only animate on exit.
- className="relative h-64 w-96 rounded-xl shadow-lg flex-shrink-0 overflow-hidden border border-gray-200 dark:border-gray-800 cursor-pointer hover:ring-2 hover:ring-blue-500/50 transition-shadow focus:outline-none focus:ring-2 focus:ring-blue-500" + className="relative h-64 w-96 rounded-xl shadow-lg flex-shrink-0 overflow-hidden border border-gray-200 dark:border-gray-800 cursor-pointer hover:ring-2 hover:ring-blue-500/50 transition-shadow hover:transition-none focus:outline-none focus:ring-2 focus:ring-blue-500"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/dashboard/src/components/app-square.tsx(4 hunks)apps/dashboard/src/components/app-store-entry.tsx(5 hunks)apps/dashboard/src/lib/prefetch/hook-prefetcher.tsx(1 hunks)apps/dashboard/src/lib/prefetch/url-prefetcher.tsx(2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: For blocking alerts and errors, never usetoast, as they are easily missed by the user. Instead, use alerts
Keep hover/click transitions snappy and fast. Don't delay the action with a pre-transition; apply transitions after the action instead
NEVER try-catch-all, NEVER void a promise, and NEVER .catch(console.error). UserunAsynchronouslyorrunAsynchronouslyWithAlertinstead for asynchronous error handling
When creating hover transitions, avoid hover-enter transitions and just use hover-exit transitions (e.g.,transition-colors hover:transition-none)
Use ES6 maps instead of records wherever possible
Files:
apps/dashboard/src/lib/prefetch/url-prefetcher.tsxapps/dashboard/src/lib/prefetch/hook-prefetcher.tsxapps/dashboard/src/components/app-square.tsxapps/dashboard/src/components/app-store-entry.tsx
apps/{backend,dashboard}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
NEVER use Next.js dynamic functions if you can avoid them. Instead, prefer using a client component and prefer
usePathnameinstead ofawait params
Files:
apps/dashboard/src/lib/prefetch/url-prefetcher.tsxapps/dashboard/src/lib/prefetch/hook-prefetcher.tsxapps/dashboard/src/components/app-square.tsxapps/dashboard/src/components/app-store-entry.tsx
🧠 Learnings (4)
📚 Learning: 2025-10-11T04:13:19.308Z
Learnt from: N2D4
Repo: stack-auth/stack-auth PR: 943
File: examples/convex/app/action/page.tsx:23-28
Timestamp: 2025-10-11T04:13:19.308Z
Learning: In the stack-auth codebase, use `runAsynchronouslyWithAlert` from `stackframe/stack-shared/dist/utils/promises` for async button click handlers and form submissions instead of manual try/catch blocks. This utility automatically handles errors and shows alerts to users.
Applied to files:
apps/dashboard/src/lib/prefetch/url-prefetcher.tsx
📚 Learning: 2025-11-28T21:21:39.142Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T21:21:39.142Z
Learning: Applies to apps-{frontend,config}.ts{,x} : To update the list of apps available, edit `apps-frontend.tsx` and `apps-config.ts`
Applied to files:
apps/dashboard/src/components/app-square.tsxapps/dashboard/src/components/app-store-entry.tsx
📚 Learning: 2025-11-28T21:21:39.142Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T21:21:39.142Z
Learning: Applies to **/*.{ts,tsx} : When creating hover transitions, avoid hover-enter transitions and just use hover-exit transitions (e.g., `transition-colors hover:transition-none`)
Applied to files:
apps/dashboard/src/components/app-store-entry.tsx
📚 Learning: 2025-11-28T21:21:39.142Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T21:21:39.142Z
Learning: Applies to **/*.{ts,tsx} : Keep hover/click transitions snappy and fast. Don't delay the action with a pre-transition; apply transitions after the action instead
Applied to files:
apps/dashboard/src/components/app-store-entry.tsx
🧬 Code graph analysis (3)
apps/dashboard/src/lib/prefetch/url-prefetcher.tsx (2)
packages/stack-shared/src/utils/urls.tsx (1)
url(278-280)apps/dashboard/src/lib/prefetch/hook-prefetcher.tsx (1)
HookPrefetcher(48-77)
apps/dashboard/src/components/app-square.tsx (2)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/use-admin-app.tsx (2)
useProjectId(46-53)useAdminApp(29-44)apps/dashboard/src/components/link.tsx (1)
Link(22-45)
apps/dashboard/src/components/app-store-entry.tsx (2)
docs/src/components/icons.tsx (2)
ChevronLeft(313-315)ChevronRight(309-311)packages/stack-ui/src/components/ui/dialog.tsx (3)
Dialog(123-123)DialogContent(126-126)DialogTitle(132-132)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: build (22.x)
- GitHub Check: build (22.x)
- GitHub Check: build (22.x)
- GitHub Check: restart-dev-and-test
- GitHub Check: restart-dev-and-test-with-custom-base-port
- GitHub Check: docker
- GitHub Check: setup-tests
- GitHub Check: check_prisma_migrations (22.x)
- GitHub Check: lint_and_build (latest)
- GitHub Check: all-good
- GitHub Check: Vercel Agent Review
🔇 Additional comments (10)
apps/dashboard/src/lib/prefetch/hook-prefetcher.tsx (1)
15-46: LGTM on the memoization refactor.Extracting
PrefetchMany,PrefetchCallback, andPrefetchCallbackInneras stable component references is a good approach for preventing unnecessary reconciliation. The try/finally pattern inPrefetchCallbackInnercorrectly maintains the counter state even when callbacks suspend or throw.Minor note: using array index as key (line 19) is acceptable here since the callbacks array is typically static per URL pattern.
apps/dashboard/src/lib/prefetch/url-prefetcher.tsx (1)
264-278: LGTM on the memoization improvements.Wrapping
UrlPrefetcherwithmemoand usinguseMemofor callbacks is a sensible optimization. The dependency array[url]is correct, and combining this with thekey={url.toString()}onHookPrefetcherensures proper remounting when URLs change while avoiding unnecessary recomputation when the parent re-renders with the samehref.apps/dashboard/src/components/app-store-entry.tsx (5)
6-9: LGTM!Imports are well-organized and appropriate for the component's functionality. The state setup with
screenshotContainerRefandpreviewIndexis correctly initialized.
36-42: LGTM!The
navigatePreviewfunction is properly memoized with correct dependencies and handles boundary conditions safely.
44-62: LGTM!Keyboard navigation is well-implemented with proper event listener cleanup and correct dependency tracking.
243-252: LGTM!The description section is cleanly implemented with proper prose styling for rich content rendering.
254-315: Well-structured preview modal with good accessibility.The modal implementation is comprehensive:
- Proper ARIA labeling with
sr-onlyDialogTitle- Keyboard navigation support (handled by the useEffect above)
- Conditional prev/next buttons based on bounds
- Image counter for orientation
One minor note: The modal control buttons (close, prev, next) at lines 268, 283, and 294 also have
transition-colorswithouthover:transition-none, following the same pattern flagged elsewhere.apps/dashboard/src/components/app-square.tsx (3)
1-1: LGTM! Correct use ofuseProjectIdfor client component.The use of
useProjectId()(which internally usesusePathname) aligns with the coding guideline to preferusePathnameoverawait paramsin client components. The path construction is clean and correct.Also applies to: 57-57, 63-63
103-135: LGTM! Clean navigation structure.Wrapping the card content in a
Linkwithabsolute inset-0makes the entire tile clickable and provides a clear navigation target. The structure works well with the absolutely-positioned button overlay that follows.
137-158: LGTM! Hover actions properly layered above the Link.The restructured hover actions with
z-10positioning ensure the Enable/Disable button remains clickable above the Link wrapper. The sibling relationship (rather than nesting inside the Link) is the correct approach, making thee.preventDefault()/e.stopPropagation()inhandleToggleEnabledtechnically redundant but harmless as defensive code.
| href={appDetailsPath} | ||
| className={cn( | ||
| "absolute inset-0 flex flex-col items-center p-3 sm:p-4 rounded-xl sm:rounded-2xl transition-all duration-200 cursor-default overflow-hidden", | ||
| "absolute inset-0 flex flex-col items-center p-3 sm:p-4 rounded-xl sm:rounded-2xl transition-all duration-200 cursor-pointer overflow-hidden", |
There was a problem hiding this comment.
Fix hover transitions to follow coding guidelines.
The hover transitions should use the hover-exit only pattern for snappier interactions. Currently, transition-all duration-200 applies on both hover-enter and hover-exit.
As per coding guidelines: When creating hover transitions, avoid hover-enter transitions and just use hover-exit transitions (e.g., transition-colors hover:transition-none).
Apply this diff to fix the hover transitions:
className={cn(
- "absolute inset-0 flex flex-col items-center p-3 sm:p-4 rounded-xl sm:rounded-2xl transition-all duration-200 cursor-pointer overflow-hidden",
+ "absolute inset-0 flex flex-col items-center p-3 sm:p-4 rounded-xl sm:rounded-2xl transition-all duration-200 hover:transition-none cursor-pointer overflow-hidden",
"bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800",
"hover:border-gray-300 dark:hover:border-gray-700 hover:shadow-lg", <div className={cn(
- "absolute inset-x-0 bottom-3 sm:bottom-4 flex justify-center gap-2 transition-all duration-200 z-10",
+ "absolute inset-x-0 bottom-3 sm:bottom-4 flex justify-center gap-2 transition-all duration-200 hover:transition-none z-10",
(isHovered || isProcessing) ? "opacity-100 translate-y-0" : "opacity-0 translate-y-2 pointer-events-none"
)}>Also applies to: 140-140
🤖 Prompt for AI Agents
In apps/dashboard/src/components/app-square.tsx around lines 106 and 140, the
element currently uses "transition-all duration-200" which applies on both
hover-enter and hover-exit; replace that with the hover-exit pattern by using
"transition-colors duration-200 hover:transition-none" (or equivalent: use a
specific transition property like transition-colors plus hover:transition-none)
so the transition only runs on hover-exit for snappier interactions.
Summary by CodeRabbit
New Features
Content
Style
✏️ Tip: You can customize this high-level summary in your review settings.
Note
Adds rich app store descriptions and screenshots across apps, plus a full-screen screenshot preview with keyboard navigation and minor dialog layout tweaks.
components/app-store-entry.tsx.DialogContentin.../@modal/(.)apps/[appId]/page-client.tsxa flex column container.storeDescriptionfor multiple apps inlib/apps-frontend.tsx.getScreenshotshelper to generate image paths.screenshotsfor numerous apps (e.g.,authentication,teams,rbac,payments,emails,data-vault,webhooks,vercel).AppFrontend.screenshotstype to(string | StaticImageData)[].storeDescriptioninAppStoreEntry.Written by Cursor Bugbot for commit b5e3b8a. This will update automatically on new commits. Configure here.