Repository navigation
feat: Dashboard UI, login redesign, and landing page - #68
Conversation
- Sidebar with navigation, app branding, and user dropdown (sign-out, profile, settings) - Dashboard page fetches repos via DAL + DB singleton, renders repo cards grid - Repo cards show status badge, branch, file/chunk counts, last indexed time - Empty state with GitHub App install CTA when no repos - Status badges: pending (yellow), indexing (blue), ready (green), error (red) - Added shadcn components: sidebar, dropdown-menu, tooltip, dialog, progress, chart, tabs, sheet, input, scroll-area - TooltipProvider added to root providers - Theme toggle moved from fixed position to dashboard header
- Split layout: terminal demo panel (left) + sign-in form (right) - Terminal panel shows fake search results to showcase the product - Feature badges: Semantic Search, AST Chunking, Hybrid Search - Responsive: single column on mobile, split on desktop - Consistent with design system (monospace, neutral, dark mode)
- Hero section: "Search your codebase by meaning" with CTA buttons - Terminal preview showing fake search results with blinking cursor - 4-card features grid: Semantic Search, AST Chunking, Hybrid Search, Incremental Sync - Consistent nav bar with CodeIndexer branding, Sign in + Get Started - Footer with GitHub link - All Phosphor icons, shadcn components, design system tokens
- Made app-sidebar a client component to fix Link + asChild hydration mismatch - Added metadata export to landing page for SEO
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a dashboard layout and page that fetches user session and repositories, new dashboard UI components (sidebar, repo cards, empty state), numerous UI primitives (sidebar, chart, dialog, dropdown, sheet, tabs, tooltip, input, progress, scroll-area), landing/login redesigns, and package dependency additions for motion and recharts. Changes
Sequence DiagramsequenceDiagram
actor User
participant Browser
participant Server as Next.js Server
participant Auth as getSession()
participant DB as Database
participant ClientUI as Client Components
User->>Browser: Request /dashboard
Browser->>Server: Server-side render DashboardLayout
Server->>Auth: getSession()
Auth-->>Server: session (user)
Server->>ClientUI: Render AppSidebar with user
Server->>Server: Render DashboardPage (server)
Server->>DB: query repos where userId = session.user.id
DB-->>Server: repos[]
Server->>ClientUI: Render RepoCard grid or EmptyState
User->>ClientUI: Click "Add Repository" or Sign Out
alt Add Repository
ClientUI->>Browser: Open GitHub App install URL
else Sign Out
ClientUI->>Auth: authClient.signOut()
ClientUI->>Browser: BroadcastChannel message + navigate to /login
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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: 8
🧹 Nitpick comments (7)
apps/web/src/app/login/page.tsx (1)
18-20: Consider surfacing sign-in failure feedback to the user.Right now failure only resets loading; adding a toast/message would avoid a silent no-op experience.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/app/login/page.tsx` around lines 18 - 20, The catch block that currently only calls setLoading(false) should surface sign-in failure to the user: modify the catch to accept the error (catch (error)), keep setLoading(false), and then show a user-facing message (e.g., call your toast/error UI or set an error state) with a friendly message and optional error details; locate the async sign-in handler where setLoading is used (the function containing the shown catch) and add a toast/error display (e.g., toast.error or setError) so failures are not silent.apps/web/src/components/ui/chart.tsx (1)
80-107: Note:dangerouslySetInnerHTMLusage for CSS injection.The static analysis tool flagged this as a potential XSS risk. While this is a common pattern for injecting dynamic CSS variables, ensure that
configvalues (particularly color strings) are never derived from untrusted user input. Malicious color values like</style><script>alert(1)</script>could escape the style block.The current implementation is acceptable since
ChartConfigis typically defined by developers, but consider adding a simple sanitization function if config values might come from external sources in the future:🛡️ Optional: Add color value sanitization
+const sanitizeColor = (color: string) => color.replace(/[<>"'&]/g, ''); + const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { const colorConfig = Object.entries(config).filter(([, config]) => config.theme ?? config.color); if (!colorConfig.length) { return null; } return ( <style dangerouslySetInnerHTML={{ __html: Object.entries(THEMES) .map( ([theme, prefix]) => ` ${prefix} [data-chart=${id}] { ${colorConfig .map(([key, itemConfig]) => { const color = itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ?? itemConfig.color; - return color ? ` --color-${key}: ${color};` : null; + return color ? ` --color-${key}: ${sanitizeColor(color)};` : null; }) .join('\n')} } `, ) .join('\n'), }} /> ); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/components/ui/chart.tsx` around lines 80 - 107, The ChartStyle component uses dangerouslySetInnerHTML to inject CSS from config values (ChartConfig and THEMES) which can be an XSS risk; implement a sanitizer (e.g., sanitizeColor or validateColor) and use it when deriving color in the map inside ChartStyle (replace usages of itemConfig.theme?.[...] ?? itemConfig.color) so only safe color tokens are emitted (allow only hex, rgba(), hsla(), CSS variable names, or a whitelist) and fall back to null/empty if validation fails before building the innerHTML.apps/web/src/components/dashboard/repo-card.tsx (1)
38-38: Implicit assumption onfullNameformat.The destructuring assumes
fullNamefollows theowner/repoformat. This is correct for GitHub repositories, but iffullNameever contains additional slashes (e.g., nested paths) or no slash, the parsing would produce unexpected results.This is acceptable for the current GitHub-specific use case, but consider documenting this expectation in the type definition or adding a comment.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/components/dashboard/repo-card.tsx` at line 38, The code in repo-card.tsx assumes fullName is "owner/repo" via the line const [owner, name] = fullName.split('/'); — make this explicit: either validate/safely parse fullName (e.g., check for a single slash and fallback or throw a clear error) or document the invariant on the prop/type that fullName must be "owner/repo" (add a comment and update the related prop/type definition). Reference the fullName variable and the destructuring expression so the change is applied where const [owner, name] = fullName.split('/') is defined.apps/web/src/app/dashboard/page.tsx (1)
10-10: Duplicate constant withempty-state.tsx.As noted earlier, this URL is duplicated. Consider a shared constants file.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/app/dashboard/page.tsx` at line 10, The constant GITHUB_APP_INSTALL_URL is duplicated; extract it into a shared constant and update usages to import that single source of truth. Create a new exported constant (e.g., GITHUB_APP_INSTALL_URL) in a shared module (constants or urls) and replace the inline declaration in the dashboard's GITHUB_APP_INSTALL_URL and the one in empty-state (or any other duplicates) with imports from that module so both consume the same value.apps/web/src/components/dashboard/nav-user.tsx (1)
75-82: Profile and Settings menu items are non-functional.These
DropdownMenuItemcomponents have noonClickhandlers or navigation. Consider adding navigation to the respective pages or removing them until implemented.♻️ Option: Add navigation or disable until ready
- <DropdownMenuItem> + <DropdownMenuItem asChild> + <Link href="/profile"> <User className="mr-2 size-4" /> Profile + </Link> </DropdownMenuItem> - <DropdownMenuItem> + <DropdownMenuItem asChild> + <Link href="/settings"> <Gear className="mr-2 size-4" /> Settings + </Link> </DropdownMenuItem>Note: This requires importing
Linkfromnext/link.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/components/dashboard/nav-user.tsx` around lines 75 - 82, The Profile and Settings menu items in nav-user.tsx are non-functional because the DropdownMenuItem elements (containing User and Gear icons) have no navigation or click handlers; fix by wiring them to the proper routes or disabling them: either import Link from next/link and wrap each DropdownMenuItem (or use the menu component's asChild pattern) to point to the intended routes (e.g., "/profile" and "/settings"), or use Next's useRouter and add onClick handlers that call router.push("/profile") and router.push("/settings"); alternatively, if those pages aren’t ready, add a disabled prop to the DropdownMenuItem to prevent interaction until implemented.apps/web/src/components/ui/sidebar.tsx (1)
80-81: Cookie missingSameSiteattribute.The sidebar state cookie is set without a
SameSiteattribute. While browsers default toLax, explicitly setting it improves clarity and cross-browser consistency.♻️ Proposed fix to add SameSite
- document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`; + document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}; SameSite=Lax`;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/components/ui/sidebar.tsx` around lines 80 - 81, The cookie write for the sidebar state (where document.cookie is set using SIDEBAR_COOKIE_NAME, openState and SIDEBAR_COOKIE_MAX_AGE in sidebar.tsx) should include an explicit SameSite attribute for clarity and cross-browser consistency; update the document.cookie assignment that uses SIDEBAR_COOKIE_NAME, openState and SIDEBAR_COOKIE_MAX_AGE to append an explicit `SameSite=Lax` (or `SameSite=Strict` if you want stricter behavior) along with the existing path and max-age attributes.apps/web/src/components/dashboard/empty-state.tsx (1)
5-5: Duplicated GitHub App install URL constant.This URL is also defined in
apps/web/src/app/dashboard/page.tsx(line 10). Consider extracting it to a shared constants file (e.g.,@/lib/constants.ts) to avoid duplication and ensure consistency if the URL changes.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/components/dashboard/empty-state.tsx` at line 5, The GITHUB_APP_INSTALL_URL constant is duplicated; extract it into a shared constants module (e.g., create and export from "@/lib/constants.ts" as GITHUB_APP_INSTALL_URL) and update both usages to import that exported constant (replace the local GITHUB_APP_INSTALL_URL in empty-state.tsx and the other file to import from the shared module); ensure the constant is exported (export const GITHUB_APP_INSTALL_URL = 'https://github.com/apps/codeindexer-dev/installations/new') and update any references to use the imported symbol so there is a single source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/web/src/components/dashboard/app-sidebar.tsx`:
- Around line 19-23: The navItems array contains entries for non-existent routes
('/search' and '/settings') which will produce 404s; either remove or comment
out the offending entries in navItems (the objects with title 'Search' and
'Settings' referencing MagnifyingGlass and Gear) or implement corresponding
route files under app/ to match those hrefs; if you remove them, ensure any
references to those icons (MagnifyingGlass, Gear) are also removed to avoid
unused-import warnings, otherwise add pages at /search and /settings that export
the expected React components so the links resolve.
In `@apps/web/src/components/dashboard/nav-user.tsx`:
- Around line 34-36: In nav-user.tsx the BroadcastChannel sends { type:
'signed-out' } which doesn't match the listener expecting { type: 'n' }; update
the bc.postMessage call in the nav user sign-out flow to send { type: 'n' }
(keep bc initialization and bc.close() as-is) so it matches the message format
used by use-session-sync and sign-out-button and other tabs will recognize the
logout.
- Around line 43-48: The initials computation using user.name can break when
user.name is empty; update the logic that defines initials to first trim and
guard the name (e.g., const name = (user.name || '').trim()), split on
whitespace, filter out empty segments, then map to first characters, join,
toUpperCase and slice(0,2); if that results in an empty string, fall back to a
safe default such as the first two chars of user.email (or a constant like '?')
so the initials variable always yields a valid 1–2 character string.
In `@apps/web/src/components/ui/progress.tsx`:
- Line 25: Clamp the progress value before using it in the inline transform to
avoid out-of-range translations: compute a clampedValue (e.g. const clampedValue
= Math.max(0, Math.min(100, value || 0))) inside the Progress component and
replace the style usage style={{ transform: `translateX(-${100 - (value ||
0)}%)` }} with style={{ transform: `translateX(-${100 - clampedValue}%)` }} so
the indicator never moves beyond 0–100%.
In `@apps/web/src/components/ui/scroll-area.tsx`:
- Line 42: The Tailwind variants in the scroll-area component's class string
currently use boolean-style variants like "data-horizontal:..." and
"data-vertical:..." which don't match the component's
data-orientation="horizontal|vertical"; update those to attribute-value variants
"data-[orientation=horizontal]:..." and "data-[orientation=vertical]:..." in the
same class entry so the rules (e.g., h-2.5, flex-col, border-t, border-l, etc.)
apply correctly when the element's data-orientation equals "horizontal" or
"vertical".
In `@apps/web/src/components/ui/sidebar.tsx`:
- Around line 567-570: The random width initializer for the width state (const
[width] = React.useState(() => ...)) causes server/client hydration mismatches;
change to a deterministic SSR-safe initial value (e.g., null or a fixed
percentage) and set the random width only on the client inside a useEffect (use
React.useState for width and React.useEffect to call Math.random and update
width on mount), ensuring you reference and update the same width state variable
and remove direct Math.random usage from the initial React.useState initializer.
In `@apps/web/src/components/ui/tabs.tsx`:
- Around line 9-22: The Tabs component destructures orientation but doesn't
forward it to TabsPrimitive.Root, breaking ARIA/keyboard behavior; update the
Tabs function to pass orientation={orientation} into TabsPrimitive.Root (in
addition to data-orientation) so Radix receives the prop and keyboard
navigation/ARIA are correct; keep the existing spread {...props} and other
attributes (className, data-slot) unchanged and ensure the prop type remains
React.ComponentProps<typeof TabsPrimitive.Root>.
- Around line 54-68: The Tailwind selectors in TabsTrigger's className are using
non-existent Radix attributes; update the selectors in the TabsTrigger component
(where TabsPrimitive.Trigger is rendered) to use Radix's emitted attributes:
replace all occurrences of `data-active:` with `data-[state=active]:`,
`data-horizontal:` with `data-[orientation=horizontal]:`, and `data-vertical:`
with `data-[orientation=vertical]:` (also update any grouped selectors like
`group-data-horizontal/tabs:` and `group-data-vertical/tabs:` accordingly) so
state- and orientation-based styles match Radix Tabs' `data-state` and
`data-orientation` attributes.
---
Nitpick comments:
In `@apps/web/src/app/dashboard/page.tsx`:
- Line 10: The constant GITHUB_APP_INSTALL_URL is duplicated; extract it into a
shared constant and update usages to import that single source of truth. Create
a new exported constant (e.g., GITHUB_APP_INSTALL_URL) in a shared module
(constants or urls) and replace the inline declaration in the dashboard's
GITHUB_APP_INSTALL_URL and the one in empty-state (or any other duplicates) with
imports from that module so both consume the same value.
In `@apps/web/src/app/login/page.tsx`:
- Around line 18-20: The catch block that currently only calls setLoading(false)
should surface sign-in failure to the user: modify the catch to accept the error
(catch (error)), keep setLoading(false), and then show a user-facing message
(e.g., call your toast/error UI or set an error state) with a friendly message
and optional error details; locate the async sign-in handler where setLoading is
used (the function containing the shown catch) and add a toast/error display
(e.g., toast.error or setError) so failures are not silent.
In `@apps/web/src/components/dashboard/empty-state.tsx`:
- Line 5: The GITHUB_APP_INSTALL_URL constant is duplicated; extract it into a
shared constants module (e.g., create and export from "@/lib/constants.ts" as
GITHUB_APP_INSTALL_URL) and update both usages to import that exported constant
(replace the local GITHUB_APP_INSTALL_URL in empty-state.tsx and the other file
to import from the shared module); ensure the constant is exported (export const
GITHUB_APP_INSTALL_URL =
'https://github.com/apps/codeindexer-dev/installations/new') and update any
references to use the imported symbol so there is a single source of truth.
In `@apps/web/src/components/dashboard/nav-user.tsx`:
- Around line 75-82: The Profile and Settings menu items in nav-user.tsx are
non-functional because the DropdownMenuItem elements (containing User and Gear
icons) have no navigation or click handlers; fix by wiring them to the proper
routes or disabling them: either import Link from next/link and wrap each
DropdownMenuItem (or use the menu component's asChild pattern) to point to the
intended routes (e.g., "/profile" and "/settings"), or use Next's useRouter and
add onClick handlers that call router.push("/profile") and
router.push("/settings"); alternatively, if those pages aren’t ready, add a
disabled prop to the DropdownMenuItem to prevent interaction until implemented.
In `@apps/web/src/components/dashboard/repo-card.tsx`:
- Line 38: The code in repo-card.tsx assumes fullName is "owner/repo" via the
line const [owner, name] = fullName.split('/'); — make this explicit: either
validate/safely parse fullName (e.g., check for a single slash and fallback or
throw a clear error) or document the invariant on the prop/type that fullName
must be "owner/repo" (add a comment and update the related prop/type
definition). Reference the fullName variable and the destructuring expression so
the change is applied where const [owner, name] = fullName.split('/') is
defined.
In `@apps/web/src/components/ui/chart.tsx`:
- Around line 80-107: The ChartStyle component uses dangerouslySetInnerHTML to
inject CSS from config values (ChartConfig and THEMES) which can be an XSS risk;
implement a sanitizer (e.g., sanitizeColor or validateColor) and use it when
deriving color in the map inside ChartStyle (replace usages of
itemConfig.theme?.[...] ?? itemConfig.color) so only safe color tokens are
emitted (allow only hex, rgba(), hsla(), CSS variable names, or a whitelist) and
fall back to null/empty if validation fails before building the innerHTML.
In `@apps/web/src/components/ui/sidebar.tsx`:
- Around line 80-81: The cookie write for the sidebar state (where
document.cookie is set using SIDEBAR_COOKIE_NAME, openState and
SIDEBAR_COOKIE_MAX_AGE in sidebar.tsx) should include an explicit SameSite
attribute for clarity and cross-browser consistency; update the document.cookie
assignment that uses SIDEBAR_COOKIE_NAME, openState and SIDEBAR_COOKIE_MAX_AGE
to append an explicit `SameSite=Lax` (or `SameSite=Strict` if you want stricter
behavior) along with the existing path and max-age attributes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: cd6dad84-3c40-4922-9ea0-7d01f6898281
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (25)
apps/web/package.jsonapps/web/src/app/dashboard/layout.tsxapps/web/src/app/dashboard/page.tsxapps/web/src/app/layout.tsxapps/web/src/app/login/page.tsxapps/web/src/app/page.tsxapps/web/src/components/dashboard/app-sidebar.tsxapps/web/src/components/dashboard/empty-state.tsxapps/web/src/components/dashboard/nav-user.tsxapps/web/src/components/dashboard/repo-card.tsxapps/web/src/components/dashboard/repo-status-badge.tsxapps/web/src/components/providers.tsxapps/web/src/components/theme-toggle.tsxapps/web/src/components/ui/chart.tsxapps/web/src/components/ui/dialog.tsxapps/web/src/components/ui/dropdown-menu.tsxapps/web/src/components/ui/input.tsxapps/web/src/components/ui/progress.tsxapps/web/src/components/ui/scroll-area.tsxapps/web/src/components/ui/sheet.tsxapps/web/src/components/ui/sidebar.tsxapps/web/src/components/ui/skeleton.tsxapps/web/src/components/ui/tabs.tsxapps/web/src/components/ui/tooltip.tsxapps/web/src/hooks/use-mobile.ts
💤 Files with no reviewable changes (1)
- apps/web/src/components/ui/skeleton.tsx
| const navItems = [ | ||
| { title: 'Dashboard', href: '/dashboard', icon: House }, | ||
| { title: 'Search', href: '/search', icon: MagnifyingGlass }, | ||
| { title: 'Settings', href: '/settings', icon: Gear }, | ||
| ]; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if search and settings routes exist
fd -t d "search|settings" apps/web/src/app/
# Also check for any page files
fd "page.tsx" apps/web/src/app/ --exec grep -l "search\|settings" {} \; 2>/dev/null || echo "Checking app directory structure..."
tree apps/web/src/app/ -I node_modules 2>/dev/null || ls -la apps/web/src/app/Repository: HrushiBorhade/code-indexer
Length of output: 503
Routes /search and /settings do not exist and will cause 404 errors.
The sidebar navigation links to /search and /settings (lines 20-21), but these routes are not implemented in apps/web/src/app/. Either implement these routes or remove/disable the navigation items until they are ready.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/components/dashboard/app-sidebar.tsx` around lines 19 - 23, The
navItems array contains entries for non-existent routes ('/search' and
'/settings') which will produce 404s; either remove or comment out the offending
entries in navItems (the objects with title 'Search' and 'Settings' referencing
MagnifyingGlass and Gear) or implement corresponding route files under app/ to
match those hrefs; if you remove them, ensure any references to those icons
(MagnifyingGlass, Gear) are also removed to avoid unused-import warnings,
otherwise add pages at /search and /settings that export the expected React
components so the links resolve.
| const bc = new BroadcastChannel('codeindexer-session'); | ||
| bc.postMessage({ type: 'signed-out' }); | ||
| bc.close(); |
There was a problem hiding this comment.
BroadcastChannel message type mismatch — other tabs won't recognize this logout.
The message { type: 'signed-out' } doesn't match the expected format. From apps/web/src/hooks/use-session-sync.ts, the listener expects { type: 'n' }, and apps/web/src/components/sign-out-button.tsx sends { type: 'n' }. This inconsistency means sign-out from the sidebar won't trigger logout in other tabs.
🐛 Proposed fix to use consistent message type
await authClient.signOut();
const bc = new BroadcastChannel('codeindexer-session');
- bc.postMessage({ type: 'signed-out' });
+ bc.postMessage({ type: 'n' });
bc.close();📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const bc = new BroadcastChannel('codeindexer-session'); | |
| bc.postMessage({ type: 'signed-out' }); | |
| bc.close(); | |
| const bc = new BroadcastChannel('codeindexer-session'); | |
| bc.postMessage({ type: 'n' }); | |
| bc.close(); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/components/dashboard/nav-user.tsx` around lines 34 - 36, In
nav-user.tsx the BroadcastChannel sends { type: 'signed-out' } which doesn't
match the listener expecting { type: 'n' }; update the bc.postMessage call in
the nav user sign-out flow to send { type: 'n' } (keep bc initialization and
bc.close() as-is) so it matches the message format used by use-session-sync and
sign-out-button and other tabs will recognize the logout.
| const initials = user.name | ||
| .split(' ') | ||
| .map((n) => n[0]) | ||
| .join('') | ||
| .toUpperCase() | ||
| .slice(0, 2); |
There was a problem hiding this comment.
Handle edge case where user.name is empty.
If user.name is an empty string, split(' ') returns [''], and n[0] would be undefined, causing initials to be empty or potentially throwing on .toUpperCase().
🛡️ Proposed fix with fallback
const initials = user.name
.split(' ')
- .map((n) => n[0])
+ .map((n) => n[0] ?? '')
+ .filter(Boolean)
.join('')
.toUpperCase()
- .slice(0, 2);
+ .slice(0, 2) || '?';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/components/dashboard/nav-user.tsx` around lines 43 - 48, The
initials computation using user.name can break when user.name is empty; update
the logic that defines initials to first trim and guard the name (e.g., const
name = (user.name || '').trim()), split on whitespace, filter out empty
segments, then map to first characters, join, toUpperCase and slice(0,2); if
that results in an empty string, fall back to a safe default such as the first
two chars of user.email (or a constant like '?') so the initials variable always
yields a valid 1–2 character string.
| <ProgressPrimitive.Indicator | ||
| data-slot="progress-indicator" | ||
| className="size-full flex-1 bg-primary transition-all" | ||
| style={{ transform: `translateX(-${100 - (value || 0)}%)` }} |
There was a problem hiding this comment.
Clamp progress value to prevent invalid indicator transforms.
Line 25 uses value directly; out-of-range values can push the indicator beyond expected bounds.
💡 Proposed fix
function Progress({
className,
value,
...props
}: React.ComponentProps<typeof ProgressPrimitive.Root>) {
+ const safeValue = Math.min(100, Math.max(0, value ?? 0));
+
return (
@@
<ProgressPrimitive.Indicator
data-slot="progress-indicator"
className="size-full flex-1 bg-primary transition-all"
- style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
+ style={{ transform: `translateX(-${100 - safeValue}%)` }}
/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| style={{ transform: `translateX(-${100 - (value || 0)}%)` }} | |
| function Progress({ | |
| className, | |
| value, | |
| ...props | |
| }: React.ComponentProps<typeof ProgressPrimitive.Root>) { | |
| const safeValue = Math.min(100, Math.max(0, value ?? 0)); | |
| return ( | |
| <ProgressPrimitive.Root | |
| className={cn('relative h-4 w-full overflow-hidden rounded-full bg-secondary', className)} | |
| {...props} | |
| > | |
| <ProgressPrimitive.Indicator | |
| data-slot="progress-indicator" | |
| className="size-full flex-1 bg-primary transition-all" | |
| style={{ transform: `translateX(-${100 - safeValue}%)` }} | |
| /> | |
| </ProgressPrimitive.Root> | |
| ); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/components/ui/progress.tsx` at line 25, Clamp the progress value
before using it in the inline transform to avoid out-of-range translations:
compute a clampedValue (e.g. const clampedValue = Math.max(0, Math.min(100,
value || 0))) inside the Progress component and replace the style usage style={{
transform: `translateX(-${100 - (value || 0)}%)` }} with style={{ transform:
`translateX(-${100 - clampedValue}%)` }} so the indicator never moves beyond
0–100%.
| data-orientation={orientation} | ||
| orientation={orientation} | ||
| className={cn( | ||
| 'flex touch-none p-px transition-colors select-none data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-l data-vertical:border-l-transparent', |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Tailwind CSS v4, for an element with data-orientation="horizontal" or "vertical", what is the correct variant syntax? Is data-horizontal:h-2.5valid, or should it bedata-[orientation=horizontal]:h-2.5?
💡 Result:
In Tailwind CSS v4, the correct variant syntax for an element with data-orientation="horizontal" or data-orientation="vertical" is data-[orientation=horizontal]:h-2.5 or data-[orientation=vertical]:h-2.5. The syntax data-horizontal:h-2.5 is not valid for matching a specific value of a data attribute; it would only match the presence of a data-horizontal attribute (boolean-like, e.g., data-horizontal without a value). This is confirmed by multiple sources: - Official Tailwind CSS v4 announcement shows boolean data attributes use bare syntax like data-current:opacity-100 for data-current (no value), but for valued attributes, the bracketed arbitrary syntax is required. - shadcn/ui Separator component explicitly uses data-[orientation=horizontal]: and data-[orientation=vertical]: in Tailwind v4 to fix rendering issues, replacing custom data-horizontal: variants. - GitHub issues and discussions consistently use data-[attr=value]: for data attributes with specific values in v3 and v4. - Stack Overflow and Tailwind GitHub confirm data-[size=large]:p-8 syntax. data-horizontal: requires defining a @custom-variant or relies on shadcn-specific imports, which fail without them in plain Tailwind v4, treating it as boolean check that doesn't match data-orientation="horizontal". Use data-[orientation=horizontal]:h-2.5 on the child element when the parent has data-orientation="horizontal". If targeting ancestors, use in-data-[orientation=horizontal]:h-2.5.
Citations:
- 1: https://tailwindcss.com/blog/tailwindcss-v4
- 2: Fix(separator): use data-[orientation] selectors to fix invisible separator in Tailwind v4 shadcn-ui/ui#9572
- 3: TW4 Data Attribute Issue: Losing Global data-theme Inheritance in Next.js tailwindlabs/tailwindcss#17115
- 4: Arbitrary variant nesting selector doesn't work with data attribute selector tailwindlabs/tailwindcss#13523
- 5: https://stackoverflow.com/questions/71394904/how-to-target-elements-with-a-specific-data-attribute-with-tailwind-css
- 6: Normalize attribute selectors for
data-*andaria-*modifiers tailwindlabs/tailwindcss#14040
🏁 Script executed:
#!/bin/bash
# Check if the file exists and view the relevant lines around line 42
if [ -f "apps/web/src/components/ui/scroll-area.tsx" ]; then
echo "=== File exists ==="
wc -l apps/web/src/components/ui/scroll-area.tsx
echo -e "\n=== Content around line 42 (lines 38-50) ==="
sed -n '38,50p' apps/web/src/components/ui/scroll-area.tsx
else
echo "File not found"
find . -name "scroll-area.tsx" -type f 2>/dev/null | head -20
fiRepository: HrushiBorhade/code-indexer
Length of output: 781
Fix Tailwind variant syntax for data-orientation attribute.
Line 42 uses data-horizontal:* and data-vertical:*, but the component provides data-orientation="horizontal|vertical". These variants are invalid in Tailwind CSS v4 for matching specific attribute values—they only match a boolean data-horizontal attribute. The correct syntax is data-[orientation=horizontal]:* and data-[orientation=vertical]:*.
💡 Proposed fix
className={cn(
- 'flex touch-none p-px transition-colors select-none data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-l data-vertical:border-l-transparent',
+ 'flex touch-none select-none p-px transition-colors data-[orientation=horizontal]:h-2.5 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:border-t data-[orientation=horizontal]:border-t-transparent data-[orientation=vertical]:h-full data-[orientation=vertical]:w-2.5 data-[orientation=vertical]:border-l data-[orientation=vertical]:border-l-transparent',
className,
)}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 'flex touch-none p-px transition-colors select-none data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-l data-vertical:border-l-transparent', | |
| 'flex touch-none select-none p-px transition-colors data-[orientation=horizontal]:h-2.5 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:border-t data-[orientation=horizontal]:border-t-transparent data-[orientation=vertical]:h-full data-[orientation=vertical]:w-2.5 data-[orientation=vertical]:border-l data-[orientation=vertical]:border-l-transparent', |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/components/ui/scroll-area.tsx` at line 42, The Tailwind variants
in the scroll-area component's class string currently use boolean-style variants
like "data-horizontal:..." and "data-vertical:..." which don't match the
component's data-orientation="horizontal|vertical"; update those to
attribute-value variants "data-[orientation=horizontal]:..." and
"data-[orientation=vertical]:..." in the same class entry so the rules (e.g.,
h-2.5, flex-col, border-t, border-l, etc.) apply correctly when the element's
data-orientation equals "horizontal" or "vertical".
| // Random width between 50 to 90%. | ||
| const [width] = React.useState(() => { | ||
| return `${Math.floor(Math.random() * 40) + 50}%`; | ||
| }); |
There was a problem hiding this comment.
Potential hydration mismatch with random width.
useState with a random initializer (Math.random()) will produce different values on server vs client, causing a hydration mismatch. Consider using a deterministic value or generating the random width only on the client.
🛡️ Proposed fix using useEffect for client-only randomization
function SidebarMenuSkeleton({
className,
showIcon = false,
...props
}: React.ComponentProps<'div'> & {
showIcon?: boolean;
}) {
- // Random width between 50 to 90%.
- const [width] = React.useState(() => {
- return `${Math.floor(Math.random() * 40) + 50}%`;
- });
+ // Random width between 50 to 90%, set after hydration to avoid mismatch
+ const [width, setWidth] = React.useState('70%');
+
+ React.useEffect(() => {
+ setWidth(`${Math.floor(Math.random() * 40) + 50}%`);
+ }, []);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/components/ui/sidebar.tsx` around lines 567 - 570, The random
width initializer for the width state (const [width] = React.useState(() =>
...)) causes server/client hydration mismatches; change to a deterministic
SSR-safe initial value (e.g., null or a fixed percentage) and set the random
width only on the client inside a useEffect (use React.useState for width and
React.useEffect to call Math.random and update width on mount), ensuring you
reference and update the same width state variable and remove direct Math.random
usage from the initial React.useState initializer.
| function Tabs({ | ||
| className, | ||
| orientation = 'horizontal', | ||
| ...props | ||
| }: React.ComponentProps<typeof TabsPrimitive.Root>) { | ||
| return ( | ||
| <TabsPrimitive.Root | ||
| data-slot="tabs" | ||
| data-orientation={orientation} | ||
| className={cn('group/tabs flex gap-2 data-horizontal:flex-col', className)} | ||
| {...props} | ||
| /> | ||
| ); | ||
| } |
There was a problem hiding this comment.
orientation prop is not passed to TabsPrimitive.Root, breaking accessibility.
The orientation is destructured and used only for the data-orientation attribute (styling), but it's excluded from ...props. Radix's TabsPrimitive.Root requires the orientation prop directly to set proper ARIA attributes and enable correct keyboard navigation (horizontal uses left/right arrows, vertical uses up/down arrows).
🛠️ Proposed fix
function Tabs({
className,
orientation = 'horizontal',
...props
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
return (
<TabsPrimitive.Root
data-slot="tabs"
+ orientation={orientation}
data-orientation={orientation}
className={cn('group/tabs flex gap-2 data-horizontal:flex-col', className)}
{...props}
/>
);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function Tabs({ | |
| className, | |
| orientation = 'horizontal', | |
| ...props | |
| }: React.ComponentProps<typeof TabsPrimitive.Root>) { | |
| return ( | |
| <TabsPrimitive.Root | |
| data-slot="tabs" | |
| data-orientation={orientation} | |
| className={cn('group/tabs flex gap-2 data-horizontal:flex-col', className)} | |
| {...props} | |
| /> | |
| ); | |
| } | |
| function Tabs({ | |
| className, | |
| orientation = 'horizontal', | |
| ...props | |
| }: React.ComponentProps<typeof TabsPrimitive.Root>) { | |
| return ( | |
| <TabsPrimitive.Root | |
| data-slot="tabs" | |
| orientation={orientation} | |
| data-orientation={orientation} | |
| className={cn('group/tabs flex gap-2 data-horizontal:flex-col', className)} | |
| {...props} | |
| /> | |
| ); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/components/ui/tabs.tsx` around lines 9 - 22, The Tabs component
destructures orientation but doesn't forward it to TabsPrimitive.Root, breaking
ARIA/keyboard behavior; update the Tabs function to pass
orientation={orientation} into TabsPrimitive.Root (in addition to
data-orientation) so Radix receives the prop and keyboard navigation/ARIA are
correct; keep the existing spread {...props} and other attributes (className,
data-slot) unchanged and ensure the prop type remains
React.ComponentProps<typeof TabsPrimitive.Root>.
| function TabsTrigger({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Trigger>) { | ||
| return ( | ||
| <TabsPrimitive.Trigger | ||
| data-slot="tabs-trigger" | ||
| className={cn( | ||
| "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-none border border-transparent px-1.5 py-0.5 text-xs font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start group-data-vertical/tabs:py-[calc(--spacing(1.25))] hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", | ||
| 'group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent', | ||
| 'data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground', | ||
| 'after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100', | ||
| className, | ||
| )} | ||
| {...props} | ||
| /> | ||
| ); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check Tailwind config for custom data attribute shortcuts
fd -e ts -e js -e mjs "tailwind.config" --exec cat {}
# Check if similar data attribute patterns are used elsewhere
rg -n "data-active:" --type ts --type tsx -g '*.tsx' | head -20Repository: HrushiBorhade/code-indexer
Length of output: 97
🏁 Script executed:
#!/bin/bash
# Search for tailwind config at root and common locations
find . -maxdepth 2 -name "tailwind*" -o -name "*.config.*" | grep -E "(tailwind|config)" | head -20
# Check package.json for Tailwind version and config location
cat package.json 2>/dev/null | grep -A 5 -B 5 "tailwind" || echo "Not found in root package.json"
# Search for data-active in tsx files with correct rg syntax
rg "data-active:" apps/web --type ts --type js | head -20
# Check the actual tabs.tsx file
cat apps/web/src/components/ui/tabs.tsx | head -100Repository: HrushiBorhade/code-indexer
Length of output: 6005
🏁 Script executed:
#!/bin/bash
# Search for tailwind config in apps/web and root
find . -maxdepth 3 -type f \( -name "tailwind.config.*" -o -name "tailwind.json" \)
# Check apps/web for any config files
ls -la apps/web/ 2>/dev/null | grep -E "(tailwind|config)"
# Search for where data-orientation is being used and what's actually emitted
rg "data-orientation\|data-state\|data-active" apps/web --type ts --type js -B 2 -A 2 | head -40
# Check if there are any custom Tailwind plugins or config in the codebase
rg "theme:|extend:" . --type js --type ts | grep -i tailwind | head -10Repository: HrushiBorhade/code-indexer
Length of output: 331
🏁 Script executed:
#!/bin/bash
# Check postcss.config for Tailwind configuration
cat apps/web/postcss.config.mjs 2>/dev/null || cat postcss.config.mjs
# Check if there's a globals or tailwind CSS file with custom config
find apps/web -name "*.css" -o -name "globals.*" | head -10
# Search for any code that might be adding custom data attributes
rg "setAttribute.*data-\|dataset\[" apps/web --type ts --type tsx -B 2 -A 2 | head -40
# Check Radix UI version in package.json or lock file
rg "radix-ui.*version|@radix-ui" . --type json | head -5Repository: HrushiBorhade/code-indexer
Length of output: 237
🏁 Script executed:
#!/bin/bash
# Read globals.css to see Tailwind configuration
cat apps/web/src/app/globals.css | head -100
# Search for any custom attribute mappings or data-active assignments
rg "data-active|data-horizontal|data-vertical" apps/web --type ts --type js -B 3 -A 1 | head -50
# Check if Radix UI is being wrapped or customized anywhere
rg "TabsPrimitive\|from 'radix-ui'" apps/web --type ts --type js -B 2 -A 5 | head -40Repository: HrushiBorhade/code-indexer
Length of output: 10003
🏁 Script executed:
#!/bin/bash
# Search for shadcn/tailwind.css
find . -name "tailwind.css" -path "*shadcn*" 2>/dev/null
# Check if shadcn is imported from node_modules or local
rg "shadcn/tailwind.css" . --type css
# Look for any custom data attribute definitions in CSS
rg "@supports.*data-\|@theme.*data-" . --type css
# Search for where tabs' data-state might be used (Radix UI's actual attribute)
rg "data-state" apps/web --type ts --type js | head -10Repository: HrushiBorhade/code-indexer
Length of output: 479
🌐 Web query:
Radix UI Tabs component data attributes emitted
💡 Result:
The Radix UI Tabs component emits the following data attributes on its sub-components, as documented in the official API reference: Root: - [data-orientation] = "vertical" | "horizontal" List: - [data-orientation] = "vertical" | "horizontal" Trigger: - [data-state] = "active" | "inactive" - [data-disabled] = present when disabled - [data-orientation] = "vertical" | "horizontal" Content: - [data-state] = "active" | "inactive" - [data-orientation] = "vertical" | "horizontal" These attributes allow for state-based styling via CSS selectors like [data-state="active"]. No other data attributes are listed in the official docs.
Citations:
- 1: https://www.radix-ui.com/primitives/docs/components/tabs
- 2: https://www.radix-ui.com/docs/primitives/components/tabs
Fix Tailwind selectors to match Radix UI Tabs attribute emissions.
The component uses selectors like data-active:, data-horizontal:, and data-vertical: that don't correspond to any attributes Radix UI Tabs actually emits. According to Radix UI's official API, Tabs emits data-state="active"|"inactive" and data-orientation="vertical"|"horizontal", not data-active, data-horizontal, or data-vertical.
Update the selectors:
- Replace
data-active:withdata-[state=active]: - Replace
data-horizontal:withdata-[orientation=horizontal]: - Replace
data-vertical:withdata-[orientation=vertical]:
Without these changes, state and orientation-based styling won't apply to the tabs.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/components/ui/tabs.tsx` around lines 54 - 68, The Tailwind
selectors in TabsTrigger's className are using non-existent Radix attributes;
update the selectors in the TabsTrigger component (where TabsPrimitive.Trigger
is rendered) to use Radix's emitted attributes: replace all occurrences of
`data-active:` with `data-[state=active]:`, `data-horizontal:` with
`data-[orientation=horizontal]:`, and `data-vertical:` with
`data-[orientation=vertical]:` (also update any grouped selectors like
`group-data-horizontal/tabs:` and `group-data-vertical/tabs:` accordingly) so
state- and orientation-based styles match Radix Tabs' `data-state` and
`data-orientation` attributes.
- Staggered hero entrance: badge → title → description → CTA → terminal - Feature cards fade in on scroll with staggered delay - Feature cards lift on hover (y: -2) - Emil Kowalski easing: cubic-bezier(0.16, 1, 0.3, 1) for all entrances - Reusable FadeIn component for future use - motion library (formerly framer-motion) added
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/web/src/components/landing/hero-animations.tsx (1)
72-84: Consider reduced motion accessibility.The scroll-triggered and hover animations work well. For users who prefer reduced motion, you could wrap the app with
<MotionConfig reducedMotion="user">at a higher level (e.g., in a layout or provider), which respectsprefers-reduced-motionsystem settings automatically.This is optional since motion v12 provides this capability at the provider level rather than per-component.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/components/landing/hero-animations.tsx` around lines 72 - 84, Wrap application-level layout or provider with Framer Motion's MotionConfig and set reducedMotion="user" so components like FeatureCard (which uses motion.div and transition props) automatically respect prefers-reduced-motion; update the top-level layout/provider (not FeatureCard itself) to import MotionConfig and add reducedMotion="user" so scroll-triggered and hover animations in FeatureCard and other motion components honor user system settings.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/web/src/components/motion/fade-in.tsx`:
- Line 44: The FadeIn component is always setting whileInView={{ opacity: 1, y:
0, x: 0 }}, which forces an inline transform even when direction === "none";
update the logic that builds the motion props (the initial and whileInView
objects used on the motion.div in FadeIn) to only include x and y when the
direction prop is not "none" (e.g., conditionally add x:0/y:0 and the matching
initial offsets), otherwise omit x/y entirely so no transform is injected and
existing wrapper transform classes are preserved.
---
Nitpick comments:
In `@apps/web/src/components/landing/hero-animations.tsx`:
- Around line 72-84: Wrap application-level layout or provider with Framer
Motion's MotionConfig and set reducedMotion="user" so components like
FeatureCard (which uses motion.div and transition props) automatically respect
prefers-reduced-motion; update the top-level layout/provider (not FeatureCard
itself) to import MotionConfig and add reducedMotion="user" so scroll-triggered
and hover animations in FeatureCard and other motion components honor user
system settings.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b599e1ea-7235-46f4-b72d-41b97c5679ea
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (4)
apps/web/package.jsonapps/web/src/app/page.tsxapps/web/src/components/landing/hero-animations.tsxapps/web/src/components/motion/fade-in.tsx
✅ Files skipped from review due to trivial changes (1)
- apps/web/package.json
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/src/app/page.tsx
| <motion.div | ||
| className={className} | ||
| initial={initial} | ||
| whileInView={{ opacity: 1, y: 0, x: 0 }} |
There was a problem hiding this comment.
Avoid forcing transform when direction is none.
Line 44 always sets x and y, which adds inline transform even when no directional motion is requested. This can unintentionally override transform classes on the wrapper.
Proposed fix
export function FadeIn({
@@
}: FadeInProps) {
const dir = directionMap[direction];
const initial = {
opacity: 0,
...('y' in dir ? { y: dir.y * distance } : {}),
...('x' in dir ? { x: dir.x * distance } : {}),
};
+ const whileInView =
+ direction === 'none' ? { opacity: 1 } : { opacity: 1, y: 0, x: 0 };
return (
<motion.div
className={className}
initial={initial}
- whileInView={{ opacity: 1, y: 0, x: 0 }}
+ whileInView={whileInView}
viewport={{ once }}
transition={{🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/components/motion/fade-in.tsx` at line 44, The FadeIn component
is always setting whileInView={{ opacity: 1, y: 0, x: 0 }}, which forces an
inline transform even when direction === "none"; update the logic that builds
the motion props (the initial and whileInView objects used on the motion.div in
FadeIn) to only include x and y when the direction prop is not "none" (e.g.,
conditionally add x:0/y:0 and the matching initial offsets), otherwise omit x/y
entirely so no transform is injected and existing wrapper transform classes are
preserved.
Sequential inserts caused 46s timeouts on accounts with many repos. Promise.all sends all upserts in parallel over Neon HTTP.
Summary
Complete Phase 1 frontend — dashboard with sidebar navigation, login page redesign, and landing page.
Dashboard (Commit 1)
Login Redesign (Commit 2)
Landing Page (Commit 3)
Fixes (Commit 4)
Test plan
pnpm format:checkpassespnpm typecheckpasses (web + db)pnpm lintpassesCloses #60
Summary by CodeRabbit
New Features
UI/UX Improvements
Chores