-
Notifications
You must be signed in to change notification settings - Fork 162
Hoverable and expandend Sidebar UI #243
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@Harshit2569 is attempting to deploy a commit to the AJEET PRATAP SINGH's projects Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughSidebar now expands on hover while collapsed using a new Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User as User (mouse)
participant Sidebar as Sidebar component
participant Profile as ProfileMenu
User->>Sidebar: mouseenter
Sidebar->>Sidebar: set isHovered = true\ncompute isSidebarExpanded
Sidebar-->>User: expand UI (width/labels visible)
Sidebar->>Profile: render with isCollapsed = !isSidebarExpanded
User->>Sidebar: mouseleave
Sidebar->>Sidebar: delay 150ms, set isHovered = false\ncompute isSidebarExpanded
alt becomes collapsed
Sidebar-->>User: collapse UI (icons only)
Sidebar->>Profile: render with isCollapsed = true
else remains expanded
Sidebar-->>User: keep expanded
end
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/web/src/components/dashboard/Sidebar.tsx (1)
1-527: clean up commented-out legacy sidebar implementationthere’s a full copy of the previous
sidebarandprofilemenuimplementation left in comments at the top of the file. this adds a lot of noise and makes it harder to see the real implementation below.since git already tracks history, it’s better to delete this legacy block entirely and keep only the active implementation.
-// "use client"; -// -// import React, { useState, useEffect } from "react"; -// import Link from "next/link"; -// ... -// ); -// } - - "use client";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/src/components/dashboard/Sidebar.tsx(12 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Files:
apps/web/src/components/dashboard/Sidebar.tsx
apps/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
apps/web/src/**/*.{ts,tsx}: Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
NEVER use hardcoded hex values (e.g.,#5519f7) directly in components; ALWAYS reference colors from the design token system using Tailwind classes
Use semantic color names that describe purpose, not appearance
Usefont-sansfor standard UI text (Geist Sans) andfont-monofor code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale (0.25rem increments); for section padding use mobilep-4(1rem) and desktopp-[60px]
Use appropriate border radius: small elementsrounded-lg, mediumrounded-xl, largerounded-2xl, buttonsrounded-[16px]
Use animation durations: fastduration-100(0.1s), normalduration-300(0.3s), slowduration-600(0.6s)
Files:
apps/web/src/components/dashboard/Sidebar.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,ts}: Prefer functional components with TypeScript and use proper TypeScript types, avoidany
Extract reusable logic into custom hooks
Use descriptive prop names and define prop types using TypeScript interfaces or types
Prefer controlled components over uncontrolled
Use zustand for global state (located insrc/store/)
Use absolute imports from@/prefix when available
Include proper aria labels for accessibility
Ensure keyboard navigation works
Maintain proper heading hierarchy
Provide alt text for images
Avoid unnecessary re-renders
Files:
apps/web/src/components/dashboard/Sidebar.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Organize imports: react → third-party → local components → utils → types
Files:
apps/web/src/components/dashboard/Sidebar.tsx
**/*[A-Z]*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Use PascalCase for component file names (e.g.,
UserProfile.tsx)
Files:
apps/web/src/components/dashboard/Sidebar.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Memoize expensive computations
Files:
apps/web/src/components/dashboard/Sidebar.tsx
apps/web/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Optimize images using next/image
apps/web/src/**/*.{tsx,ts}: Use Zustand for global state, located insrc/store/
Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Optimize images using next/image
Memoize expensive computations
Define a type when defining const functions
Files:
apps/web/src/components/dashboard/Sidebar.tsx
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}
📄 CodeRabbit inference engine (.cursor/rules/general_rules.mdc)
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Files:
apps/web/src/components/dashboard/Sidebar.tsx
apps/web/src/components/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts,jsx,js}: Never use hardcoded hex values directly in components; always reference colors from the design token system using Tailwind classes
Use semantic color names from the design token system that describe purpose, not appearance (e.g., bg-brand-purple, bg-surface-primary, text-text-primary)
Use font-sans for standard UI text (Geist Sans) and font-mono for code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale for section padding: p-4 (1rem) on mobile, p-[60px] on desktop
Use rounded-lg (0.5rem) for small elements, rounded-xl (1rem) for medium elements, rounded-2xl (1.5rem) for large elements, and rounded-[16px] for buttons
Use duration-100 (0.1s) for fast transitions, duration-300 (0.3s) for normal transitions, and duration-600 (0.6s) for slow transitions
Use available custom animations: animate-accordion-down, animate-accordion-up, animate-scrollRight, animate-scrollLeft, animate-customspin, animate-spin-slow, animate-spin-slow-reverse, animate-marquee, animate-marquee-vertical, animate-shine
Prefer functional components with TypeScript
Extract reusable logic into custom hooks
Prefer controlled components over uncontrolled
Include proper aria labels for accessibility
Ensure keyboard navigation works in interactive components
Maintain proper heading hierarchy in page components
Provide alt text for images
Use 'class:' instead of the ternary operator in class tags whenever possible
Implement accessibility features on interactive elements (e.g., tabindex='0', aria-label, onClick, onKeyDown)
Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
Files:
apps/web/src/components/dashboard/Sidebar.tsx
apps/web/src/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts}: Use proper TypeScript types and avoid usinganytype
Use descriptive prop names and define prop types using TypeScript interfaces or types
Name components using PascalCase (e.g., UserProfile.tsx)
Files:
apps/web/src/components/dashboard/Sidebar.tsx
apps/web/src/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/**/*.{tsx,ts,jsx,js}: Organize imports in order: React → third-party → local components → utils → types
Use absolute imports from@/prefix when available
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags
Use descriptive variable and function names; name event functions with a 'handle' prefix (e.g., handleClick, handleKeyDown)
Use const with arrow functions instead of function declarations (e.g., 'const toggle = () =>')
Files:
apps/web/src/components/dashboard/Sidebar.tsx
🧬 Code graph analysis (1)
apps/web/src/components/dashboard/Sidebar.tsx (1)
apps/web/src/components/ui/IconWrapper.tsx (1)
IconWrapper(10-22)
🔇 Additional comments (4)
apps/web/src/components/dashboard/Sidebar.tsx (4)
559-587: route config and constants look consistent
routeconfigincluding the optionalbadgefield and bothfree_routes/premium_routesarrays are typed correctly and line up with howbadgeis used later in the jsx. no issues here.Also applies to: 589-602
538-551: derivedisSidebarExpandedwiring across layout/content looks solidtying the ui to
isSidebarExpanded = !isCollapsed || isHoveredreads clean and the usages look consistent:
- desktop header now hides the brand text when collapsed-but-not-hovered, and shows it when either fully expanded or temporarily expanded on hover.
- the collapse/expand chevron direction correctly reflects the current visual state (expanded ⇒ left chevron, collapsed ⇒ right chevron).
- route items keep icons always visible while labels/badges/dividers only render when
isSidebarExpandedis true, which matches a compact icon rail + expanded-panel pattern.- premium section, its sub-items, the locked preview, and the “request a feature” item all respect the expanded state, and the
profilemenureceivesisCollapsed={!isSidebarExpanded}so its own layout matches the sidebar width.this matches the hover-to-expand behavior described in the pr and doesn’t introduce obvious regressions.
Also applies to: 647-651, 685-747, 753-945, 948-960, 964-967
1013-1015: chevron rotation formatting change is finethe
chevronlefticonrotation still depends purely on theopenstate; the multi-line template string just improves readability. behavior is unchanged and looks good.
611-613: Clear hover timeout on mouse enter and unmount to prevent race conditions and state update warningsThe hover-based sidebar expansion has two edge cases:
- if the user quickly moves the mouse out and back in before the 150ms timeout fires, the pending timeout will still collapse the sidebar even though it's currently hovered.
- the timeout isn't cleared on unmount, which can cause a state update on an unmounted component if the sidebar unmounts while a timeout is pending.
Fix by tracking the timeout ID in a ref, clearing it when the user re-enters, and cleaning it up on unmount. This preserves the 150ms delay without the flicker:
-import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useRef } from "react"; const [isHovered, setIsHovered] = useState(false); + const hoverTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null); const handleMouseEnter = () => { + if (hoverTimeoutRef.current) { + clearTimeout(hoverTimeoutRef.current); + hoverTimeoutRef.current = null; + } if (isCollapsed) setIsHovered(true); }; const handleMouseLeave = () => { - if (isHovered) setTimeout(() => setIsHovered(false), 150); + if (!isCollapsed) return; + hoverTimeoutRef.current = setTimeout(() => { + setIsHovered(false); + hoverTimeoutRef.current = null; + }, 150); }; + + useEffect(() => { + return () => { + if (hoverTimeoutRef.current) { + clearTimeout(hoverTimeoutRef.current); + } + }; + }, []);Also update comments to lowercase and focus on the "why":
- // 🟣 New state for hover expand + // hover-based expand state when the persisted sidebar is collapsed - // 🟣 Hover handlers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/src/components/dashboard/Sidebar.tsx (1)
84-123: hover expand logic: avoid timeout race and consider overlay behaviorthe hover-expand behavior is nice, but
handleMouseLeaveusessetTimeoutwithout clearing it on re‑enter, so a quick re‑hover can still collapse the sidebar ~150ms later, causing a small flicker. you can store the timeout id in areact.useRefand clear it inhandleMouseEnterbefore settingisHoveredagain. also, since hover doesn’t exist on touch, ifoverlayis true and the globalisCollapsedis true, the overlay may stay at the collapsed width; if the design expects full-width overlays regardless of the collapsed state, consider bypassingisCollapsedwhenoverlayis true.
🧹 Nitpick comments (3)
apps/web/src/components/dashboard/Sidebar.tsx (3)
120-140: reduce duplication between animate width and inline style
desktopWidth/mobileWidthare passed both viaanimate={{ width: ... }}andstyle={{ width: ... }}, which is redundant and can make it harder to see which source of truth controls the width. you can keep the animation by relying onanimateonly (and dropstyle), or, if you don’t need animation for width, remove it fromanimateand keep onlystyle.
32-37: route config and badge rendering are consistent and type-safethe
RouteConfigextension with optionalbadgeand its usage for premium routes (including guarded rendering underisSidebarExpanded) is consistent and type-safe. if you plan to have a fixed set of badge labels (e.g."new" | "beta"), you could narrow the type later, but it’s fine asstringfor now.Also applies to: 62-75, 202-219
233-418: premium section expanded/collapsed behavior and a11y are solid with a minor enhancement possiblethe premium section logic keyed off
isSidebarExpandedandproSectionExpandedlooks correct for both paid and free users, and keyboard and aria attributes on the main trigger and locked previews are handled well. for even better accessibility, you could add anidto the premium content container and wirearia-controlson the trigger soaria-expandedpoints to the actual collapsible region.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/src/components/dashboard/Sidebar.tsx(12 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Files:
apps/web/src/components/dashboard/Sidebar.tsx
apps/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
apps/web/src/**/*.{ts,tsx}: Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
NEVER use hardcoded hex values (e.g.,#5519f7) directly in components; ALWAYS reference colors from the design token system using Tailwind classes
Use semantic color names that describe purpose, not appearance
Usefont-sansfor standard UI text (Geist Sans) andfont-monofor code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale (0.25rem increments); for section padding use mobilep-4(1rem) and desktopp-[60px]
Use appropriate border radius: small elementsrounded-lg, mediumrounded-xl, largerounded-2xl, buttonsrounded-[16px]
Use animation durations: fastduration-100(0.1s), normalduration-300(0.3s), slowduration-600(0.6s)
Files:
apps/web/src/components/dashboard/Sidebar.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,ts}: Prefer functional components with TypeScript and use proper TypeScript types, avoidany
Extract reusable logic into custom hooks
Use descriptive prop names and define prop types using TypeScript interfaces or types
Prefer controlled components over uncontrolled
Use zustand for global state (located insrc/store/)
Use absolute imports from@/prefix when available
Include proper aria labels for accessibility
Ensure keyboard navigation works
Maintain proper heading hierarchy
Provide alt text for images
Avoid unnecessary re-renders
Files:
apps/web/src/components/dashboard/Sidebar.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Organize imports: react → third-party → local components → utils → types
Files:
apps/web/src/components/dashboard/Sidebar.tsx
**/*[A-Z]*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Use PascalCase for component file names (e.g.,
UserProfile.tsx)
Files:
apps/web/src/components/dashboard/Sidebar.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Memoize expensive computations
Files:
apps/web/src/components/dashboard/Sidebar.tsx
apps/web/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Optimize images using next/image
apps/web/src/**/*.{tsx,ts}: Use Zustand for global state, located insrc/store/
Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Optimize images using next/image
Memoize expensive computations
Define a type when defining const functions
Files:
apps/web/src/components/dashboard/Sidebar.tsx
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}
📄 CodeRabbit inference engine (.cursor/rules/general_rules.mdc)
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Files:
apps/web/src/components/dashboard/Sidebar.tsx
apps/web/src/components/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts,jsx,js}: Never use hardcoded hex values directly in components; always reference colors from the design token system using Tailwind classes
Use semantic color names from the design token system that describe purpose, not appearance (e.g., bg-brand-purple, bg-surface-primary, text-text-primary)
Use font-sans for standard UI text (Geist Sans) and font-mono for code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale for section padding: p-4 (1rem) on mobile, p-[60px] on desktop
Use rounded-lg (0.5rem) for small elements, rounded-xl (1rem) for medium elements, rounded-2xl (1.5rem) for large elements, and rounded-[16px] for buttons
Use duration-100 (0.1s) for fast transitions, duration-300 (0.3s) for normal transitions, and duration-600 (0.6s) for slow transitions
Use available custom animations: animate-accordion-down, animate-accordion-up, animate-scrollRight, animate-scrollLeft, animate-customspin, animate-spin-slow, animate-spin-slow-reverse, animate-marquee, animate-marquee-vertical, animate-shine
Prefer functional components with TypeScript
Extract reusable logic into custom hooks
Prefer controlled components over uncontrolled
Include proper aria labels for accessibility
Ensure keyboard navigation works in interactive components
Maintain proper heading hierarchy in page components
Provide alt text for images
Use 'class:' instead of the ternary operator in class tags whenever possible
Implement accessibility features on interactive elements (e.g., tabindex='0', aria-label, onClick, onKeyDown)
Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
Files:
apps/web/src/components/dashboard/Sidebar.tsx
apps/web/src/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts}: Use proper TypeScript types and avoid usinganytype
Use descriptive prop names and define prop types using TypeScript interfaces or types
Name components using PascalCase (e.g., UserProfile.tsx)
Files:
apps/web/src/components/dashboard/Sidebar.tsx
apps/web/src/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/**/*.{tsx,ts,jsx,js}: Organize imports in order: React → third-party → local components → utils → types
Use absolute imports from@/prefix when available
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags
Use descriptive variable and function names; name event functions with a 'handle' prefix (e.g., handleClick, handleKeyDown)
Use const with arrow functions instead of function declarations (e.g., 'const toggle = () =>')
Files:
apps/web/src/components/dashboard/Sidebar.tsx
🧬 Code graph analysis (1)
apps/web/src/components/dashboard/Sidebar.tsx (1)
apps/web/src/components/ui/IconWrapper.tsx (1)
IconWrapper(10-22)
🔇 Additional comments (3)
apps/web/src/components/dashboard/Sidebar.tsx (3)
158-175: desktop header + collapse button behavior with hover expansion looks goodusing
isSidebarExpandedinstead ofisCollapsedensures the logo and chevron align correctly for both pinned and hover-expanded states, and centering the collapse button when collapsed improves the collapsed ux. no functional issues spotted here.
421-433: bottom utilities and profile menu now correctly follow hover-expanded statepassing
collapsed={!isSidebarExpanded}intoSidebarItemandProfileMenuensures those bottom areas respect both pinned and hover-expanded sidebar states, which keeps the layout and information density consistent. this change looks correct and aligned with the new hover behavior.Also applies to: 437-437
486-488: profile menu chevron rotation matches open/closed statetying the chevron rotation purely to
open(rotate-90vs-rotate-90) keeps the visual state of the dropdown indicator in sync with the menu state. the change is straightforward and doesn’t introduce any regressions.
https://drive.google.com/file/d/1kXKHzm4LtAHSXrq6i1xJc89JKVxC3GZp/view?usp=sharing
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.