Files
supabase/apps/docs/components/Navigation/NavigationMenu/TopNavDropdown.tsx
T
Gildas Garcia c41e2835e3 chore: UI theme cleanup (#47519)
## Problem

- We still use/maintain the legacy theming even though we moved to
Shadcn
- We have two themes list with similar code

## Solution

- Migrate some components to `cva` and `cn` instead of `styleHandler`
- Remove redundant `themes` in favor of `singleThemes`

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

* **Bug Fixes**
* Standardized theme selection across the app so theme menus
consistently offer the same light/dark/system options, including
dropdowns, navigation menus, and command menus.
* **Refactor**
* Refreshed styling for multiple shared UI components (menus, tabs, side
panels, loading indicators, icons, and modal dialogs) to improve
consistency while preserving visual behavior.
* **Chores**
* Improved the UI patterns CI “validate exports” check for clearer
failure output when exports change unexpectedly.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-02 17:03:08 +02:00

123 lines
3.5 KiB
TypeScript

'use client'
import { isFeatureEnabled } from 'common'
import { Menu } from 'lucide-react'
import { useTheme } from 'next-themes'
import Link from 'next/link'
import React, { Fragment } from 'react'
import {
buttonVariants,
cn,
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
singleThemes,
} from 'ui'
import MenuIconPicker from './MenuIconPicker'
const menu = [
[
isFeatureEnabled('docs:navigation_dropdown_links_home')
? {
label: 'Supabase.com',
icon: 'home',
href: 'https://supabase.com',
otherProps: {
target: '_blank',
rel: 'noreferrer noopener',
},
}
: {
label: 'Dashboard',
icon: 'home',
href: '../dashboard',
},
{
label: 'GitHub',
icon: 'github',
href: 'https://github.com/supabase/supabase',
otherProps: {
target: '_blank',
rel: 'noreferrer noopener',
},
},
{
label: 'Support',
icon: 'support',
href: 'https://supabase.com/support',
otherProps: {
target: '_blank',
rel: 'noreferrer noopener',
},
},
],
]
const TopNavDropdown = () => {
const { theme, setTheme } = useTheme()
return (
<DropdownMenu modal={false}>
<DropdownMenuTrigger asChild className="flex">
<button
title="Menu dropdown button"
className={cn(
buttonVariants({ variant: 'default' }),
'text-foreground-light border-default w-[30px] min-w-[30px] h-[30px] data-open:bg-overlay-hover/30 hover:border-strong data-open:border-stronger hover:bg-overlay-hover/50! bg-transparent'
)}
>
<Menu size={18} strokeWidth={1} />
</button>
</DropdownMenuTrigger>
<DropdownMenuContent side="bottom" align="end" className="w-52">
{menu.map((menuSection, sectionIdx) => (
<Fragment key={`topnav--${sectionIdx}`}>
{sectionIdx !== 0 && <DropdownMenuSeparator key={`topnav--${sectionIdx}`} />}
{menuSection.map((sectionItem, itemIdx) => (
<Link
key={`topnav-${sectionItem.label}-${sectionIdx}-${itemIdx}`}
href={sectionItem.href}
{...sectionItem.otherProps}
>
<DropdownMenuItem className="space-x-2" onClick={() => {}}>
{sectionItem.icon && (
<MenuIconPicker icon={sectionItem.icon} className="text-foreground-lighter" />
)}
<p>{sectionItem.label}</p>
</DropdownMenuItem>
</Link>
))}
</Fragment>
))}
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuLabel>Theme</DropdownMenuLabel>
<DropdownMenuRadioGroup
value={theme}
onValueChange={(value) => {
setTheme(value)
}}
>
{singleThemes
.filter((x) => x.value === 'light' || x.value === 'dark' || x.value === 'system')
.map((theme) => (
<DropdownMenuRadioItem key={`topnav-theme-${theme.value}`} value={theme.value}>
{theme.name}
</DropdownMenuRadioItem>
))}
</DropdownMenuRadioGroup>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
)
}
export default TopNavDropdown