Files
supabase/apps/studio/components/layouts/AccountLayout/WithSidebar.tsx
Danny White daa3119b2f chore(studio): align sidebar hover states (#45569)
## What kind of change does this PR introduce?

UI polish. Updates sidebar and submenu navigation hover and active
styling.

## What is the current behavior?

Product submenu navigation items either lack a hover fill or use a hover
fill that visually matches the active state. Adjacent hovered and
selected rows can appear to touch.

## What is the new behavior?

Primary sidebar buttons, sidebar sub-buttons, and product submenu pills
now share a muted hover fill while preserving the full accent fill for
active/selected states. Product submenu rows also get a small visual gap
with slightly reduced vertical padding to keep the overall spacing
compact.

| After |
| --- |
| <img width="988" height="408" alt="CleanShot 2026-05-05 at 11 53
05@2x"
src="https://github.com/user-attachments/assets/560ac8a5-1262-41af-a196-618c86580150"
/> |



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Style**
* Refined sidebar hover/active states with subtle accent alpha colors
for a more polished visual experience.
* Updated sidebar menu spacing and rounded corners for improved touch
and visual clarity.

* **UI Improvements**
* Sidebar now only displays when sections exist and uses a streamlined
submenu flow for more consistent, predictable navigation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-05-05 07:52:11 -06:00

88 lines
2.5 KiB
TypeScript

import { ArrowLeft } from 'lucide-react'
import Link from 'next/link'
import { PropsWithChildren, ReactNode } from 'react'
import { cn } from 'ui'
import type { SidebarSection } from './AccountLayout.types'
import { getActiveKey, toSubMenuSections } from './AccountLayout.utils'
import { SubMenu } from '@/components/ui/ProductMenu/SubMenu'
interface WithSidebarProps {
title?: string
sections: SidebarSection[]
header?: ReactNode
backToDashboardURL?: string
}
export const WithSidebar = ({
title,
header,
children,
sections,
backToDashboardURL,
}: PropsWithChildren<WithSidebarProps>) => {
const noContent = !sections
return (
<div className="flex flex-col md:flex-row h-full">
{!noContent && (
<SidebarContent
title={title}
header={header}
sections={sections}
backToDashboardURL={backToDashboardURL}
className="hidden md:flex"
/>
)}
<div className="flex flex-1 flex-col">
<div className="flex-1 grow overflow-y-auto">{children}</div>
</div>
</div>
)
}
export const SidebarContent = ({
header,
sections,
backToDashboardURL,
className,
}: PropsWithChildren<Omit<WithSidebarProps, 'breadcrumbs'>> & { className?: string }) => {
const page = getActiveKey(sections)
const subMenuSections = toSubMenuSections(sections)
return (
<>
<div
id="with-sidebar"
className={cn(
'h-full bg-dash-sidebar flex flex-col justify-between',
'hide-scrollbar w-full md:w-64 md:border-r border-default',
className
)}
>
<div className="flex-1 flex flex-col">
{backToDashboardURL && (
<div className="shrink-0 hidden md:block">
<div className="flex h-12 max-h-12 items-center border-b px-6 border-default">
<Link
href={backToDashboardURL}
className="flex text-sm flex-row gap-2 items-center text-foreground-lighter focus-visible:text-foreground hover:text-foreground"
>
<ArrowLeft strokeWidth={1.5} size={16} />
Back to dashboard
</Link>
</div>
</div>
)}
{header && header}
<div className="flex-1 overflow-auto">
<div className="flex flex-col">
<SubMenu sections={subMenuSections} page={page} />
</div>
</div>
</div>
</div>
</>
)
}