Skip to content

feat: sidebar#3003

Merged
ogzhanolguncu merged 11 commits intomainfrom
feat-sidebar
Mar 20, 2025
Merged

feat: sidebar#3003
ogzhanolguncu merged 11 commits intomainfrom
feat-sidebar

Conversation

@ogzhanolguncu
Copy link
Contributor

@ogzhanolguncu ogzhanolguncu commented Mar 20, 2025

What does this PR do?

Fixes # (issue)

  • Fixes border color issue of TeamSwitcher and UserButton
  • Adds new sidebar structure
  • Fixes sidebar icons
  • Prepares sidebar for future iterations

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (refactoring code, technical debt, workflow improvements)
  • Enhancement (small improvements)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How should this be tested?

  • Test A
  • Test B

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read Contributing Guide
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand areas
  • Ran pnpm build
  • Ran pnpm fmt
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues

Appreciated

  • If a UI change was made: Added a screen recording or screenshots to this PR
  • Updated the Unkey Docs if changes were necessary

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Introduced a modern, interactive sidebar navigation system for both desktop and mobile views.
    • Enhanced workspace switching and user interface controls for seamless navigation.
    • Added a new custom hook to detect mobile viewport sizes.
  • UI Enhancements

    • Updated iconography with a refreshed set of icons and expanded customization options.
    • Revamped background styling for a cleaner, more contemporary dashboard look.
  • Refactor

    • Streamlined legacy sidebar components to improve responsiveness and overall performance.
    • Consolidated user button rendering logic for improved clarity and responsiveness.
  • Bug Fixes

    • Removed deprecated components to reduce clutter and improve maintainability.

@changeset-bot
Copy link

changeset-bot bot commented Mar 20, 2025

⚠️ No Changeset found

Latest commit: 11e7b2b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Mar 20, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
dashboard ✅ Ready (Inspect) Visit Preview 💬 Add feedback Mar 20, 2025 2:36pm
engineering ✅ Ready (Inspect) Visit Preview 💬 Add feedback Mar 20, 2025 2:36pm
play ✅ Ready (Inspect) Visit Preview 💬 Add feedback Mar 20, 2025 2:36pm
www ✅ Ready (Inspect) Visit Preview 💬 Add feedback Mar 20, 2025 2:36pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 20, 2025

📝 Walkthrough

Walkthrough

This pull request removes legacy sidebar components (DesktopSidebar and MobileSideBar) and updates the dashboard layout to integrate new sidebar components. The layout now imports and uses AppSidebar, SidebarMobile, and SidebarProvider to better manage navigation state and responsiveness. Additionally, navigation icons have been updated with alternatives from @unkey/icons and the type definitions refined. Other changes include the addition of a mobile detection hook, enhancements to Tailwind CSS configuration and component aliases, a dependency upgrade, and several new icon components and sidebar UI subcomponents.

Changes

File(s) Change Summary
apps/dashboard/app/(app)/desktop-sidebar.tsx
apps/dashboard/app/(app)/mobile-sidebar.tsx
Removed legacy DesktopSidebar and MobileSideBar components, including subcomponents like NavLink.
apps/dashboard/app/(app)/layout.tsx Updated layout to use new AppSidebar, SidebarMobile, and SidebarProvider, and changed background styling from bg-background to bg-base-12.
apps/dashboard/components.json Added "tsx": true, set "prefix": "" in Tailwind section, and introduced new alias entries for "ui", "lib", and "hooks".
apps/dashboard/components/app-sidebar.tsx
apps/dashboard/components/navigation/sidebar/sidebar-mobile.tsx
Added new sidebar components for desktop (AppSidebar) and mobile (SidebarMobile) views with enhanced navigation.
apps/dashboard/components/ui/sidebar.tsx Introduced a comprehensive Sidebar component with multiple subcomponents (e.g., SidebarHeader, SidebarFooter) and the useSidebar hook for state management.
apps/dashboard/components/navigation/sidebar/team-switcher.tsx
apps/dashboard/components/navigation/sidebar/user-button.tsx
apps/dashboard/components/navigation/sidebar/workspace-navigations.tsx
Updated navigation UI components: refined styling, responsiveness (e.g., isCollapsed state), and replaced several icons with new ones from @unkey/icons.
apps/dashboard/hooks/use-mobile.tsx Added useIsMobile hook for detecting mobile view based on viewport width (<768px).
apps/dashboard/package.json Upgraded the tailwind-merge dependency from ^2.2.2 to ^2.5.4.
internal/icons/src/icons/circle-question.tsx
internal/icons/src/icons/sidebar-left-hide.tsx
internal/icons/src/icons/sidebar-left-show.tsx
Added new icon components: CircleQuestion, SidebarLeftHide, and SidebarLeftShow with default size and stroke configuration.
internal/icons/src/index.ts Exported the new icon components for broader usage.
internal/icons/src/props.ts Extended the Weight type by adding a "medium" option and updated the sizeMap accordingly for various sizes.
internal/ui/tailwind.config.js Added a new color name "base" to the color generation array in the Tailwind configuration.
apps/dashboard/components/array-input.tsx
apps/dashboard/components/multi-select.tsx
Completely removed ArrayInput and MultiSelect components.

Possibly related PRs

  • fix: Ratelimit identifier component changes #2712: The changes in the main PR involve the complete removal of the ArrayInput component, while the retrieved PR updates the same ArrayInput component to improve its functionality, indicating a direct relationship at the code level.
  • feat: remove old css stuff and use @unkey/ui #2737: The changes in the main PR, which involve the removal of the DesktopSidebar and MobileSideBar components, are related to the retrieved PR as both involve modifications to sidebar components and their integration with the new @unkey/ui library.
  • fix: use workspace name in team switcher #2719: The changes in the main PR involve the complete removal of the DesktopSidebar and MobileSideBar components, while the retrieved PR modifies these components by adding a workspace prop to the WorkspaceSwitcher within them, indicating a direct relationship at the code level.

Suggested labels

🕹️ oss.gg, :joystick: 300 points, :joystick: 150 points

Suggested reviewers

  • mcstepp
  • chronark
  • perkinsjr
  • MichaelUnkey

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 87ec122 and 11e7b2b.

📒 Files selected for processing (2)
  • apps/dashboard/components/array-input.tsx (0 hunks)
  • apps/dashboard/components/multi-select.tsx (0 hunks)
💤 Files with no reviewable changes (2)
  • apps/dashboard/components/multi-select.tsx
  • apps/dashboard/components/array-input.tsx
⏰ Context from checks skipped due to timeout of 90000ms (9)
  • GitHub Check: Test Packages / Test ./packages/cache
  • GitHub Check: Test Packages / Test ./internal/id
  • GitHub Check: Test Packages / Test ./internal/clickhouse
  • GitHub Check: Test Agent Local / test_agent_local
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Build / Build
  • GitHub Check: autofix
  • GitHub Check: Analyze (javascript-typescript)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 20, 2025

Thank you for following the naming conventions for pull request titles! 🙏

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (12)
apps/dashboard/hooks/use-mobile.tsx (3)

5-19: Consider refining the mobile detection implementation

The hook correctly detects mobile viewport width, but there's an inconsistency in how it's implemented. The event listener uses matchMedia but the actual check uses window.innerWidth.

For consistency, consider using the matches property from the MediaQueryList:

 export function useIsMobile() {
   const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
 
   React.useEffect(() => {
     const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
     const onChange = () => {
-      setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
+      setIsMobile(mql.matches);
     };
     mql.addEventListener("change", onChange);
-    setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
+    setIsMobile(mql.matches);
     return () => mql.removeEventListener("change", onChange);
   }, []);
 
   return !!isMobile;
 }

This approach is more consistent and reduces the chance of edge case bugs where the two methods might return different results.


3-3: Consider using Tailwind's breakpoint for consistency

The constant MOBILE_BREAKPOINT is set to 768px, which aligns with medium (md) breakpoint in many CSS frameworks. If you're using Tailwind CSS in this project, consider using their breakpoint values for consistency across the codebase:

-const MOBILE_BREAKPOINT = 768;
+// Match Tailwind's md breakpoint
+const MOBILE_BREAKPOINT = 768;

This ensures that your JavaScript breakpoints match your CSS breakpoints.


6-6: Initial state could be determined synchronously for SSR compatibility

Setting the initial state to undefined works but could cause a brief flash of UI during rendering. Since this hook is for client-side detection, you might want to consider improving SSR compatibility:

-const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
+const [isMobile, setIsMobile] = React.useState<boolean>(false);

Then in your useEffect, you could add a check to prevent the hook from running during SSR:

React.useEffect(() => {
  if (typeof window === 'undefined') return;
  
  // rest of the code
}, []);

This prevents hydration mismatches and improves the predictability of your UI during server-side rendering.

apps/dashboard/components/navigation/navbar.tsx (1)

80-99: Conditional button for icon or sidebar toggle.
Switching between a custom icon and the sidebar toggle button is clever. Consider adding labels or tooltips for improved accessibility.

+              <Button
+                aria-label="Toggle sidebar"
+                onClick={toggleSidebar}
+                variant="outline"
+                className="size-6 p-0 [&>svg]:size-[18px] bg-gray-4 hover:bg-gray-5"
+              >
+                {isCollapsed ? (
+                  <SidebarLeftShow size="md-medium" />
+                ) : (
+                  <SidebarLeftHide size="md-medium" />
+                )}
+              </Button>
apps/dashboard/components/app-sidebar.tsx (3)

42-50: Consider clarifying or removing the placeholder logic in createNestedNavigation.
Currently, this function just returns baseNav without processing. If the intention is to nest items in the future, it might be clearer to rename the function or add a comment indicating upcoming logic.


193-249: Validate screen-reader compatibility for AnimatedLoadingSpinner.
Since this spinner changes its opacity dynamically, ensure it won't cause confusion for screen-reader users. Consider adding role="status" and aria-live="polite" or visually hiding text that informs the user of loading.


266-291: Check SSR compatibility with runtime style injection.
Appending <style> to document.head works only in a browser environment (typeof document !== "undefined"). For server-rendered pages, consider adding the animation styling to a global CSS file or a server-safe approach to avoid hydration mismatch.

apps/dashboard/components/navigation/sidebar/workspace-navigations.tsx (2)

62-62: Confirm correctness of switching from a different icon to Nodes.
Previously, the summary mentioned removing the Nodes icon. However, the code now uses Nodes. Verify this aligns with your new design choice; otherwise, remove references.


126-126: Mark external links more clearly.
Using BookBookmark for docs is good, but consider an external-link icon or label. This helps emphasize navigation outside your app.

apps/dashboard/components/ui/sidebar.tsx (3)

19-34: Handle cookie fallback or server-side rendering.
Storing sidebar state in a cookie is convenient, but confirm SSR usage. If the server tries to read the cookie for an initial collapsed state, you may need to ensure synchronization between server and client for a smooth user experience.


47-149: Encapsulate or validate the defaultOpen read from cookies.
Right now, the state is inlined with a default open prop. If you plan to read from cookies initially, consider a function that checks for a valid Boolean to prevent possible parse errors from malformed cookies.


90-105: Review the keyboard shortcut event logic.
Currently, Ctrl/Cmd + b toggles the sidebar. Ensure no collisions with browser/OS shortcuts. Consider making this binding configurable to respect user preferences or possible conflicts.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a62550f and 8c4353f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • apps/dashboard/app/(app)/apis/navigation.tsx (1 hunks)
  • apps/dashboard/app/(app)/desktop-sidebar.tsx (0 hunks)
  • apps/dashboard/app/(app)/layout.tsx (2 hunks)
  • apps/dashboard/app/(app)/mobile-sidebar.tsx (0 hunks)
  • apps/dashboard/components.json (1 hunks)
  • apps/dashboard/components/app-sidebar.tsx (1 hunks)
  • apps/dashboard/components/navigation/navbar.tsx (3 hunks)
  • apps/dashboard/components/navigation/sidebar/sidebar-mobile.tsx (1 hunks)
  • apps/dashboard/components/navigation/sidebar/team-switcher.tsx (7 hunks)
  • apps/dashboard/components/navigation/sidebar/user-button.tsx (2 hunks)
  • apps/dashboard/components/navigation/sidebar/workspace-navigations.tsx (5 hunks)
  • apps/dashboard/components/ui/sidebar.tsx (1 hunks)
  • apps/dashboard/hooks/use-mobile.tsx (1 hunks)
  • apps/dashboard/package.json (1 hunks)
  • internal/icons/src/icons/circle-question.tsx (1 hunks)
  • internal/icons/src/icons/sidebar-left-hide.tsx (1 hunks)
  • internal/icons/src/icons/sidebar-left-show.tsx (1 hunks)
  • internal/icons/src/index.ts (1 hunks)
  • internal/icons/src/props.ts (1 hunks)
  • internal/ui/tailwind.config.js (1 hunks)
💤 Files with no reviewable changes (2)
  • apps/dashboard/app/(app)/desktop-sidebar.tsx
  • apps/dashboard/app/(app)/mobile-sidebar.tsx
🧰 Additional context used
🧬 Code Definitions (9)
apps/dashboard/app/(app)/apis/navigation.tsx (1)
apps/dashboard/components/navigation/navbar.tsx (1) (1)
  • Navbar (46-59)
internal/icons/src/icons/sidebar-left-hide.tsx (1)
internal/icons/src/props.ts (2) (2)
  • IconProps (26-30)
  • sizeMap (7-24)
internal/icons/src/icons/sidebar-left-show.tsx (1)
internal/icons/src/props.ts (2) (2)
  • IconProps (26-30)
  • sizeMap (7-24)
apps/dashboard/app/(app)/layout.tsx (4)
apps/dashboard/components/ui/sidebar.tsx (1) (1)
  • SidebarProvider (591-591)
apps/dashboard/components/app-sidebar.tsx (1) (1)
  • AppSidebar (153-191)
apps/dashboard/components/navigation/sidebar/sidebar-mobile.tsx (1) (1)
  • SidebarMobile (9-29)
internal/ui/src/components/empty.tsx (1) (1)
  • Empty (6-18)
apps/dashboard/components/ui/sidebar.tsx (1)
apps/dashboard/hooks/use-mobile.tsx (1) (1)
  • useIsMobile (5-19)
apps/dashboard/components/navigation/sidebar/sidebar-mobile.tsx (4)
apps/dashboard/components/ui/sidebar.tsx (1) (1)
  • useSidebar (593-593)
internal/icons/src/icons/sidebar-left-show.tsx (1) (1)
  • SidebarLeftShow (15-63)
apps/dashboard/components/navigation/sidebar/team-switcher.tsx (1) (1)
  • WorkspaceSwitcher (31-173)
apps/dashboard/components/navigation/sidebar/user-button.tsx (1) (1)
  • UserButton (20-111)
apps/dashboard/components/navigation/sidebar/team-switcher.tsx (1)
apps/dashboard/components/ui/sidebar.tsx (1) (1)
  • useSidebar (593-593)
apps/dashboard/components/navigation/navbar.tsx (2)
apps/dashboard/components/ui/sidebar.tsx (1) (1)
  • useSidebar (593-593)
internal/ui/src/components/button.tsx (1) (1)
  • Button (443-443)
internal/icons/src/icons/circle-question.tsx (1)
internal/icons/src/props.ts (2) (2)
  • IconProps (26-30)
  • sizeMap (7-24)
🔇 Additional comments (33)
internal/ui/tailwind.config.js (1)

79-79: Added "base" color to the generateRadixColors function

The addition of the "base" color to the color names array enhances the available color palette for the application. This new color will be available throughout the application via Tailwind classes.

apps/dashboard/package.json (1)

100-100: Updated tailwind-merge dependency to version 2.5.4

Good update to the tailwind-merge package. This ensures the application uses a more recent version which may include bug fixes, performance improvements, and potentially new features for handling Tailwind class merging.

apps/dashboard/app/(app)/apis/navigation.tsx (1)

13-13: Simplified Navbar.Breadcrumbs by removing the icon prop

The icon prop was removed from the Navbar.Breadcrumbs component, which aligns with the PR's objective of updating the navigation logic. This simplification makes the code cleaner while maintaining functionality.

internal/icons/src/index.ts (1)

53-55: Added new icon exports for sidebar functionality

The addition of three new icon exports (circle-question, sidebar-left-show, and sidebar-left-hide) supports the new sidebar component functionality being implemented in this PR. These icons will likely be used for toggling sidebar visibility and help functionality.

internal/icons/src/icons/sidebar-left-hide.tsx (1)

1-63: New icon component is well-structured

This component is well-implemented following the established pattern for icon components in the project. It properly:

  • Utilizes the IconProps interface
  • Leverages the sizeMap for consistent sizing
  • Has appropriate SVG attributes and viewBox
  • Uses proper SVG structure with clear semantic elements

The visual design with the vertical line, polyline, and rectangle effectively represents a "hide sidebar" action.

internal/icons/src/icons/sidebar-left-show.tsx (1)

1-63: New icon component properly implements show sidebar functionality

This component is correctly implemented, matching the pattern of other icon components. The key difference from the SidebarLeftHide icon is in the polyline points (line 40), which create an arrow pointing in the opposite direction to visually indicate "show sidebar" functionality.

The component is properly structured with appropriate SVG attributes and follows the project's icon implementation conventions.

internal/icons/src/icons/circle-question.tsx (1)

1-53: Question mark icon implementation follows project conventions

The CircleQuestion icon is well-implemented, following the same pattern as other icon components in the codebase. It correctly:

  • Uses the IconProps interface with appropriate defaults
  • Leverages the sizeMap for consistent sizing
  • Has appropriate SVG attributes
  • Creates a visually distinct question mark in a circle using proper SVG elements

The implementation is clean and follows the project's established conventions for icon components.

apps/dashboard/components.json (3)

5-5: Added TypeScript JSX support.

The addition of "tsx": true properly enables TypeScript JSX support for the dashboard components, which is a good practice for type safety.


10-11: Tailwind CSS configuration update.

The addition of CSS variables and empty prefix settings provides better flexibility for styling components and prevents potential class name conflicts.


15-18: New import aliases added.

These additional aliases (ui, lib, and hooks) provide convenient shortcuts for importing components, utilities, and hooks. This makes the codebase more maintainable by reducing import path complexity.

apps/dashboard/components/navigation/sidebar/sidebar-mobile.tsx (3)

9-14: Clean conditional rendering for mobile view.

The component correctly uses the isMobile state from the sidebar context to conditionally render, ensuring this component only appears on mobile devices.


17-26: Mobile sidebar implementation with appropriate UI elements.

The component provides essential navigation elements for mobile: a sidebar toggle button, workspace switcher, and user menu. The button for opening the sidebar uses appropriate styling and icon.


24-26: Future implementation comment.

There's a TODO comment indicating plans for additional functionality. Consider creating a task to track this for the next iteration.

Would you like me to help create a task for implementing the mentioned indicator in the next iteration?

apps/dashboard/app/(app)/layout.tsx (5)

1-3: New sidebar component imports.

Replacing legacy sidebar components with new implementations (AppSidebar, SidebarMobile, and SidebarProvider) aligns with the PR's goal of updating the navigation system.


32-32: Updated base layout styling.

Changed background from bg-background to bg-base-12 to maintain consistent styling with the new sidebar components.


34-38: Desktop sidebar implementation.

The layout now properly uses the SidebarProvider to manage sidebar state and renders the new AppSidebar component with appropriate styling through className.


39-47: Main content and mobile sidebar structure.

The content area is well-organized with clear comments and proper positioning of the mobile sidebar at the top of content when on mobile devices.


48-67: Preserved workspace status handling.

The conditional rendering based on workspace enabled status has been properly maintained, ensuring a consistent user experience when workspaces are disabled.

internal/icons/src/props.ts (2)

3-3: Added "medium" weight option.

The addition of a "medium" weight option to the Weight type enhances the flexibility of icon styling, allowing for more nuanced visual hierarchies.


9-9: New medium weight icon size configurations.

Consistently added medium weight entries with 1.5 stroke width across all size variants. This provides a balanced option between the thin (1.0) and regular (2.0) weights.

Also applies to: 13-13, 17-17, 21-21

apps/dashboard/components/navigation/sidebar/team-switcher.tsx (3)

3-3: Imports look consistent.
These imports are utilized seamlessly in the subsequent code. No duplication or conflicts observed.

Also applies to: 13-13, 14-14, 16-16, 17-17, 18-18, 20-20


41-41: Correct usage of the sidebar state.
Using isMobile and state from useSidebar to define isCollapsed is clear and maintains separate behaviors for desktop vs. mobile.

Also applies to: 43-44


74-86: Effective styling and tooltip condition logic.
Good job applying conditional classes for the DropdownMenuTrigger and rendering tooltips/icons based on the sidebar's collapsed state. This approach keeps the UI responsive and user-friendly.

Also applies to: 101-102, 115-115, 119-119

apps/dashboard/components/navigation/sidebar/user-button.tsx (5)

12-13: New imports for sidebar logic.
Bringing in useSidebar and cn aligns with the revised architecture and seems consistent.


32-33: Concise user display name logic.
Combining username, fullName, and primaryEmailAddress under a single variable is a clean design choice.


37-43: Conditional rendering for desktop vs. mobile.
Dynamically adjusting layout (avatar, username, chevron) based on isCollapsed and mobile state delivers a unified user experience. Good use of fallback avatar handling.

Also applies to: 45-65, 68-69


72-76: Dropdown alignment.
Declaring side="bottom" and setting responsive widths (max-w-xs, md:w-96) effectively handles both mobile and desktop needs.


23-23:

Details

✅ Verification successful

Sidebar collapsed state handling.
The condition (state === "collapsed" || isMobile) && !(isMobile && openMobile) appears correct for setting the collapsed UI on mobile vs. desktop.

Run the following script to confirm openMobile usage is consistent across other components:

Also applies to: 25-26


🏁 Script executed:

#!/bin/bash
# Searching references to openMobile in the codebase
rg -A 4 'openMobile'

Length of output: 2965


Verified openMobile usage consistency across components.

The usage of openMobile in the condition (state === "collapsed" || isMobile) && !(isMobile && openMobile) in apps/dashboard/components/navigation/sidebar/user-button.tsx aligns with its usage in apps/dashboard/components/ui/sidebar.tsx. No changes are needed here.

apps/dashboard/components/navigation/navbar.tsx (2)

3-3: Importing icons and useSidebar.
The new imports for SidebarLeftHide, SidebarLeftShow, and useSidebar align with the expanded/collapsed sidebar logic.

Also applies to: 8-8


33-33: Optional breadcrumb icon and sidebar toggling logic.
Allowing an optional icon is flexible, and using useSidebar for controlling the breadcrumb-based sidebar toggle is neatly integrated.

Also applies to: 69-70, 73-74

apps/dashboard/components/navigation/sidebar/workspace-navigations.tsx (2)

74-74: Review alignment of replaced icons with intended meanings.
Icons like ShieldKey, InputSearch, Grid, Layers3, Sparkle3, and Gear each symbolize different concepts. Make sure these new icons match the menu labels and user expectations.

Also applies to: 81-81, 87-87, 94-94, 101-101, 116-116


16-19:

Details

✅ Verification successful

Ensure icon type changes don’t break existing references.
icon: React.ElementType; is broader than the removed LucideIcon type. Confirm no existing code relies on strict Lucide types, and verify external references compile properly.


🏁 Script executed:

#!/bin/bash
# Search codebase for usage patterns of NavItem.icon to confirm that
# references match the updated type.
rg -A 3 'NavItem' 

Length of output: 4507


Icon type change verified—no refactoring required.

After searching the codebase, the updated icon: React.ElementType; in apps/dashboard/components/navigation/sidebar/workspace-navigations.tsx appears to be used consistently across the project (e.g., in app-sidebar.tsx and dashboard/navbar.tsx). There’s no evidence that any existing references rely on the stricter LucideIcon type, and nothing in the search output indicates compilation issues related to this change.

apps/dashboard/components/ui/sidebar.tsx (1)

575-595: Overall, the modular structure of the new Sidebar components is excellent.
It’s cohesive and follows best practices with a context-driven approach. Code is well-organized, ensuring good maintainability and consistent UI patterns across the app.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 (5)
apps/dashboard/components/app-sidebar.tsx (4)

33-41: Consider consolidating conditional class handling in getButtonStyles.
While this utility function effectively applies different Tailwind classes based on isActive or showLoader, you might streamline readability by extracting shared or repeated classes and grouping conditional logic. This can help new contributors quickly parse the style rules.


53-151: Split or modularize NavItems for clarity.
The NavItems component handles both single-level and nested items. While the logic is correct, consider extracting the collapsible logic (lines 91–151) into a dedicated sub-component for easier maintenance and testing.


223-295: Loading spinner logic is visually appealing but consider timing and performance.
Using setInterval at 125ms is acceptable for a short rotor, yet consider whether using pure CSS animations might simplify code. Alternatively, a more React-friendly approach (like useReducer or requestAnimationFrame) might further reduce re-renders.


297-321: Runtime CSS injection works but review potential duplication.
Handling custom animations via appended <style> ensures the spinner's motion preference respect. However, extracting these rules into a shared CSS or style module might reduce overhead if multiple components adopt a similar pattern.

apps/dashboard/components/ui/sidebar.tsx (1)

47-149: Persisting the 'open' state in cookies is helpful; consider reading cookie on mount.
This approach sets the cookie but does not initialize from an existing cookie. If you want to preserve the user’s previous session state, read this cookie on mount to sync the default. Otherwise, your defaults here may override user preferences.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c4353f and cb7369e.

📒 Files selected for processing (4)
  • apps/dashboard/components/app-sidebar.tsx (1 hunks)
  • apps/dashboard/components/navigation/sidebar/team-switcher.tsx (7 hunks)
  • apps/dashboard/components/navigation/sidebar/user-button.tsx (2 hunks)
  • apps/dashboard/components/ui/sidebar.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/dashboard/components/navigation/sidebar/team-switcher.tsx
  • apps/dashboard/components/navigation/sidebar/user-button.tsx
🧰 Additional context used
🧬 Code Definitions (2)
apps/dashboard/components/app-sidebar.tsx (4)
apps/dashboard/components/navigation/sidebar/workspace-navigations.tsx (3) (3)
  • NavItem (16-26)
  • createWorkspaceNavigation (56-122)
  • resourcesNavigation (124-137)
apps/dashboard/components/ui/sidebar.tsx (10) (10)
  • SidebarMenuButton (587-587)
  • SidebarMenuSub (589-589)
  • SidebarMenuSubItem (591-591)
  • SidebarMenuSubButton (590-590)
  • Sidebar (577-577)
  • SidebarHeader (584-584)
  • SidebarContent (578-578)
  • SidebarGroup (580-580)
  • SidebarMenu (585-585)
  • SidebarFooter (579-579)
internal/icons/src/icons/sidebar-left-show.tsx (1) (1)
  • SidebarLeftShow (15-63)
internal/icons/src/icons/sidebar-left-hide.tsx (1) (1)
  • SidebarLeftHide (15-63)
apps/dashboard/components/ui/sidebar.tsx (1)
apps/dashboard/hooks/use-mobile.tsx (1) (1)
  • useIsMobile (5-19)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (12)
apps/dashboard/components/app-sidebar.tsx (3)

1-32: Imports look consistent and purposeful.
All imports appear to be in use, and the structure is clean. This ensures a clear separation of responsibilities for each module and sets a solid foundation for the component logic that follows.


43-51: Placeholder function for nested navigation is acceptable.
createNestedNavigation simply returns baseNav here, suggesting future expansions might add sub-items. The straightforward approach is fine for maintainability.


153-221: AppSidebar is well-structured; verify defaults for different screen sizes.
This component nicely integrates core sidebar elements. The toggle button logic for collapsed vs. expanded states is clear. Just ensure that the default collapsed state, or any custom user preferences, is respected in all scenarios (mobile vs. desktop).

apps/dashboard/components/ui/sidebar.tsx (9)

1-18: Imports and initial setup are coherent.
The file correctly brings in Radix UI, class-variance-authority, and supporting hooks. This scaffolds the sidebar’s advanced behavior.


19-24: Cookie constants are clearly defined.
Retention of sidebar state in a cookie with a one-week max-age is straightforward. Ensure the lifetime aligns with broader product requirements (e.g. user preferences or compliance rules).


26-36: Context type is well-addressed.
SidebarContextProps succinctly captures needed fields (state, open, openMobile, etc.). No issues noted.


38-45: Custom hook usage constraint is appropriate.
Throwing an error if useSidebar is used outside SidebarProvider ensures no invalid usage. This is a best practice to prevent unexpected null context references.


151-253: Sidebar component transitions cleanly between desktop and mobile.
Excellent approach handling collapsed vs. mobile states. The usage of Sheet for mobile is consistent with Radix UI standards, ensuring a strong responsive pattern.


258-299: Header, Footer, and Separator sub-components are elegantly minimal.
These small wrappers neatly enforce spacing and style. Extended customization for each region remains flexible.


301-385: Structural components (Content, Group, Labels, Actions) are straightforward.
The separate sub-components (SidebarContent, SidebarGroup, etc.) effectively isolate responsibilities and avoid large monolithic code blocks.


388-432: Menu and menu-item structures, plus CVA usage, are well implemented.
The sidebarMenuButtonVariants clearly delineates styling across states and sizes. This cva approach is helpful for consistent design tokens throughout the app.


434-595: Menu actions, sub-menus, and exports are comprehensive.
Your tooltip logic in SidebarMenuButton is well-handled, particularly with conditional string vs. object usage. Sub-components (SidebarMenuAction, SidebarMenuSub, SidebarMenuSubItem, and SidebarMenuSubButton) are neatly separated, facilitating easy updates. The final exports confirm a clear public API for the sidebar module.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 (6)
apps/dashboard/components/navigation/sidebar/sidebar-mobile.tsx (1)

18-19: Add an accessible label to the sidebar toggle button.

Providing an aria-label on this button can help screen readers identify its purpose.

<Button 
  variant="ghost" 
  onClick={() => setOpenMobile(true)} 
+ aria-label="Open sidebar"
  className="[&_svg]:size-[20px]"
>
apps/dashboard/components/app-sidebar.tsx (2)

33-103: Segment the AppSidebar logic further to reduce complexity.

Even though the structure is modular, consider extracting some logic (e.g., header content or resource navigation) into sub-components. This improves maintainability and testability, especially as the sidebar grows.

-export function AppSidebar({...props}: ... & { workspace: Workspace }) {
-  // Entire logic
+export function AppSidebar({...props}: ... & { workspace: Workspace }) {
+  const headerContent = <AppSidebarHeader workspace={props.workspace} />;
+  // ...
+  return (
+    <Sidebar ...>
+      {headerContent}
+      // ...
+    </Sidebar>
+  );
+}

+function AppSidebarHeader({ workspace }: { workspace: Workspace }) {
+  // ...
+}

219-247: Optimize sub-route navigation if frequently accessed.

If the user navigates heavily between routes, consider prefetching links (e.g., Next.js Link prefetch) to speed up transitions. This is especially helpful if the sub-routes are used often.

apps/dashboard/components/ui/sidebar.tsx (3)

19-25: Consider using local or session storage instead of cookies for UI state
Storing UI preferences in cookies sends them on every request. If this data doesn’t need to be sent to the server, local or session storage may be simpler.


90-92: Watch for conflicts with common “Ctrl + B” shortcut
“Ctrl + B” is often used to toggle bold text in many editors and applications, which could surprise users. Consider making the keyboard shortcut configurable or using a different combination.


525-539: Naming clarification for “SidebarMenuSub”
While not strictly incorrect, “SidebarMenuSub” can be ambiguous. Consider something more specific if nested submenus become common.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb7369e and 87ec122.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • apps/dashboard/components/app-sidebar.tsx (1 hunks)
  • apps/dashboard/components/navigation/sidebar/sidebar-mobile.tsx (1 hunks)
  • apps/dashboard/components/navigation/sidebar/team-switcher.tsx (7 hunks)
  • apps/dashboard/components/navigation/sidebar/user-button.tsx (2 hunks)
  • apps/dashboard/components/ui/sidebar.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/dashboard/components/navigation/sidebar/team-switcher.tsx
🧰 Additional context used
🧬 Code Definitions (2)
apps/dashboard/components/navigation/sidebar/sidebar-mobile.tsx (4)
apps/dashboard/components/ui/sidebar.tsx (1) (1)
  • useSidebar (594-594)
internal/icons/src/icons/sidebar-left-show.tsx (1) (1)
  • SidebarLeftShow (15-63)
apps/dashboard/components/navigation/sidebar/team-switcher.tsx (1) (1)
  • WorkspaceSwitcher (31-176)
apps/dashboard/components/navigation/sidebar/user-button.tsx (1) (1)
  • UserButton (19-107)
apps/dashboard/components/ui/sidebar.tsx (1)
apps/dashboard/hooks/use-mobile.tsx (1) (1)
  • useIsMobile (5-19)
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: Test Agent Local / test_agent_local
  • GitHub Check: Test Packages / Test ./internal/hash
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Test Packages / Test ./internal/clickhouse
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Test Packages / Test ./internal/keys
  • GitHub Check: Test Packages / Test ./packages/hono
  • GitHub Check: Build / Build
  • GitHub Check: autofix
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (10)
apps/dashboard/components/navigation/sidebar/sidebar-mobile.tsx (1)

9-14: Ensure this component is tested thoroughly.

Currently, there's no explicit test coverage for the mobile-only behavior. Consider adding tests (e.g., using React Testing Library) to verify that this component returns null in non-mobile contexts and renders the UI in mobile contexts.

You can create a companion test file and confirm the rendering of this component under mobile vs. non-mobile breakpoints or configurations.

apps/dashboard/components/navigation/sidebar/user-button.tsx (2)

35-67: Consider adding a small test for the dropdown trigger in collapsed vs. open states.

Tests can cover:

  1. Ensuring the trigger is center-aligned in collapsed mode.
  2. Verifying the username and chevron appear correctly in expanded mode.

22-25:

Details

❓ Verification inconclusive

Validate isMobile state transitions.

The logic that combines isMobile with openMobile is clear, but ensure dynamic resizing scenarios are handled (e.g., if a user resizes from desktop to mobile mid-session). This might require an additional effect to synchronize.

Please verify if the useSidebar hook recalculates isMobile on viewport resize, and that user experience remains consistent.


🏁 Script executed:

#!/bin/bash
# Searching for the isMobile usage and checking if there's any event listener for viewport resizing
rg 'isMobile'

Length of output: 2634


Ensure dynamic resizing is handled for isMobile state

After reviewing the repository, we confirmed that the isMobile value is derived from the custom useMobile (and indirectly via useSidebar) hook. However, there is no clear indication—via an event listener or media query listener—that this hook actively recalculates its value on viewport resizing. This raises concerns about whether dynamic changes (e.g., switching from desktop to mobile mid-session) are properly handled.

  • in apps/dashboard/hooks/use-mobile.tsx: Verify that the hook incorporates logic (e.g., an event listener for the window resize event or a media query listener) to update isMobile when the viewport changes.
  • in apps/dashboard/components/navigation/sidebar/user-button.tsx: Confirm that the isCollapsed computation reflects these potential state transitions promptly.

Please double-check the implementation of useSidebar and its underlying hooks. If dynamic viewport changes aren’t currently managed, consider adding the necessary effect to update isMobile accordingly.

apps/dashboard/components/app-sidebar.tsx (2)

355-379: Kudos for supporting motion preferences.

This block respects the prefers-reduced-motion setting by halting animations—this is an excellent accessibility practice.


249-322:

Details

❓ Verification inconclusive

Verify nested item state resets on route changes.

The logic that sets subPending[subItem.label] = true and then resets it may not catch all route transition scenarios (e.g., if the user navigates away quickly or the route fails). Ensure this does not leave any pending load states.

Here's a script that can search for other references to subPending to see if there's a fallback or error handling:


🏁 Script executed:

#!/bin/bash
ast-grep --pattern $'$_ = $_.subPending[$_] = $_'

Length of output: 50


Action: Confirm Robust State Reset on Route Transition Failures

  • The current implementation resets the loading state for nested items using a fixed 300ms delay after invoking router.push within a startTransition callback.
  • There is no additional error handling or fallback mechanism if the route navigation fails or the user navigates away quickly, which may leave a pending state active.
  • Please verify manually that under all route transition scenarios (including failures and quick navigations), the loading state for nested items is reliably reset. Consider adding error handling or leveraging router events (e.g., cancellation or error callbacks) to ensure state consistency.
apps/dashboard/components/ui/sidebar.tsx (5)

70-88: Good job allowing external control and internal state
The approach of using both an internal _open state and optional external open & onOpenChange props is a flexible pattern that accommodates multiple use cases.


95-105: Clean keyboard event handling
Attaching and removing the keydown listener on mount/unmount is well implemented. It reduces the risk of memory leaks and ensures the shortcut is properly cleaned up.


187-208: Mobile sheet implementation looks good
Switching to a Sheet on mobile devices is a neat solution. The layout remains consistent, and responsiveness is well managed through isMobile and setOpenMobile.


211-253: Refactor suggestion reiterated
This multi-layered approach (group, peer, and data attributes) is powerful but can be complex for future maintainers. Consider simplifying or documenting the layering strategy if your team finds it hard to maintain.


576-595: Exports are cleanly organized
Exporting all sidebar-related components, types, and hooks in one place promotes discoverability and modular usage throughout the codebase.

Copy link
Contributor Author

@perkinsjr time to break 😄

Copy link
Member

Looks fine,

To be clear this is V1 of the sidebar without the nested options like the design?

Copy link
Collaborator

Yeah we do it in multiple passes to make it easier to review

Copy link
Member

Well then this is fine.

Copy link
Member

I think this is in the wrong thread LMAO

Copy link
Collaborator

opps

Copy link
Contributor Author

Nested routes are a bit problematic we have to do data fetching etc... PR would be too big. I plan to go route by route like, apis nested routes first, then ratelimits etc...

Copy link
Member

Sorry about that boys 🫡

Copy link
Contributor Author

@MichaelUnkey :pepeout:

Copy link
Collaborator

ignore me

Copy link
Contributor Author

😄

@ogzhanolguncu ogzhanolguncu added this pull request to the merge queue Mar 20, 2025
Merged via the queue into main with commit 1f12539 Mar 20, 2025
29 of 30 checks passed
@ogzhanolguncu ogzhanolguncu deleted the feat-sidebar branch March 20, 2025 19:41
revogabe pushed a commit to revogabe/unkey that referenced this pull request Mar 21, 2025
* feat: add new sidebar

* fix: icon

* fix: padding issues

* feat: add new sidebar

* fix: ui issues

* chore: clenaup

* chore: remove unused button

* fix: collapse issue

* fix: ui issues

* chore: remove unused files
chronark added a commit that referenced this pull request Apr 8, 2025
* feat: add usage-insight on the desktop-sidebar

* remove console.log

* refactor: improve code consistency and formatting across multiple files

* fix: keep only the progress circle, remove the particle effect, keep the card always open

* refactor: simplify layout and desktop sidebar components, remove unused billing logic

* feat(billing): add usage fetching hook and TRPC query for billing usage data

* fix: update workspace creation logic to set plan to 'free' and improve error handling

* fix: remove unnecessary console log for usage query fetching

* refactor: adjust padding and height in usage insights component for improved layout

* fix: update plan type in usage insights to handle workspace tier and default to 'Free'

* [autofix.ci] apply automated fixes

* refactor: improve code readability and formatting in usage insights component

* refactor: remove Particles component and relocate useMousePosition hook

* refactor: enhance code formatting and readability in desktop sidebar component

* fix: remove use-mouse hook

* pnpm fmt

* pnpm-lock fix

* refactor: update usage insights to use 'tier' instead of 'plan' and simplify loading state handling

* fix: remove outdated and wrong quota check (#3000)

we now have proper quotas, so this check is redundand.

If a workspace is disabled, there is already a warning in the root
layout to contact us.

* Update README.md (#3002)

Fix Invalid URL of "Read our blog post"

* feat: sidebar (#3003)

* feat: add new sidebar

* fix: icon

* fix: padding issues

* feat: add new sidebar

* fix: ui issues

* chore: clenaup

* chore: remove unused button

* fix: collapse issue

* fix: ui issues

* chore: remove unused files

* fix: layout shifts and missing props (#3006)

* fix: layout shift

* fix: missing active tags

* refactor: clean up imports and improve layout component structure

* pnpm fmt

* refactor: simplify usage query options in useFetchUsage hook

* pnpm fmt

* fix: broken lock

* fix: quotas rename to quota

This fixes the incorrect usage max issue

* fix: refetch usage

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Oğuzhan Olguncu <21091016+ogzhanolguncu@users.noreply.github.com>
Co-authored-by: James P <jamesperkins@hey.com>
Co-authored-by: Andreas Thomas <dev@chronark.com>
Co-authored-by: okuma <49895482+kumachan99@users.noreply.github.com>
Co-authored-by: ogzhanolguncu <ogzhan11@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants