From 2b5237c94217aaa9f1d21876b0d71e55ca5b8588 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 23 Sep 2026 17:27:06 +0400 Subject: [PATCH 1/5] Unify documentation menu styling --- apps/web/src/components/ui/context-menu.tsx | 41 +++++------ apps/web/src/components/ui/dropdown-menu.tsx | 44 +++++------- apps/web/src/components/ui/menu-styles.ts | 16 +++++ apps/web/src/components/ui/menubar.tsx | 73 +++----------------- apps/web/src/components/web/brand-menu.tsx | 8 +-- 5 files changed, 65 insertions(+), 117 deletions(-) create mode 100644 apps/web/src/components/ui/menu-styles.ts diff --git a/apps/web/src/components/ui/context-menu.tsx b/apps/web/src/components/ui/context-menu.tsx index 2ce2d233..7c63bbf2 100644 --- a/apps/web/src/components/ui/context-menu.tsx +++ b/apps/web/src/components/ui/context-menu.tsx @@ -4,6 +4,14 @@ import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu import * as React from "react"; import { RiArrowRightSLine, RiCheckLine } from "react-icons/ri"; +import { + menuContentStyles, + menuDestructiveItemStyles, + menuItemStyles, + menuLabelStyles, + menuSeparatorStyles, + menuSubTriggerStyles, +} from "@/components/ui/menu-styles"; import { cn } from "@/lib/utils"; function ContextMenu({ ...props }: ContextMenuPrimitive.Root.Props) { @@ -52,11 +60,7 @@ function ContextMenuContent({ > @@ -79,10 +83,7 @@ function ContextMenuLabel({ ); @@ -103,8 +104,9 @@ function ContextMenuItem({ data-inset={inset} data-variant={variant} className={cn( - "group/context-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 focus:*:[svg]:text-accent-foreground data-[variant=destructive]:*:[svg]:text-destructive", - "rounded-sm", + "group/context-menu-item", + menuItemStyles, + menuDestructiveItemStyles, className, )} {...props} @@ -128,10 +130,7 @@ function ContextMenuSubTrigger({ {children} @@ -164,10 +163,7 @@ function ContextMenuCheckboxItem({ @@ -197,10 +193,7 @@ function ContextMenuRadioItem({ @@ -217,7 +210,7 @@ function ContextMenuSeparator({ className, ...props }: ContextMenuPrimitive.Sepa return ( ); diff --git a/apps/web/src/components/ui/dropdown-menu.tsx b/apps/web/src/components/ui/dropdown-menu.tsx index 72e75160..ac0f96a8 100644 --- a/apps/web/src/components/ui/dropdown-menu.tsx +++ b/apps/web/src/components/ui/dropdown-menu.tsx @@ -4,6 +4,14 @@ import { Menu as MenuPrimitive } from "@base-ui/react/menu"; import * as React from "react"; import { RiArrowRightSLine, RiCheckLine } from "react-icons/ri"; +import { + menuContentStyles, + menuDestructiveItemStyles, + menuItemStyles, + menuLabelStyles, + menuSeparatorStyles, + menuSubTriggerStyles, +} from "@/components/ui/menu-styles"; import { cn } from "@/lib/utils"; function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) { @@ -38,10 +46,7 @@ function DropdownMenuContent({ > @@ -64,10 +69,7 @@ function DropdownMenuLabel({ ); @@ -88,7 +90,9 @@ function DropdownMenuItem({ data-inset={inset} data-variant={variant} className={cn( - "group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive", + "group/dropdown-menu-item", + menuItemStyles, + menuDestructiveItemStyles, className, )} {...props} @@ -112,10 +116,7 @@ function DropdownMenuSubTrigger({ {children} @@ -135,10 +136,7 @@ function DropdownMenuSubContent({ return ( @@ -197,10 +192,7 @@ function DropdownMenuRadioItem({ ); diff --git a/apps/web/src/components/ui/menu-styles.ts b/apps/web/src/components/ui/menu-styles.ts new file mode 100644 index 00000000..44b2dbb8 --- /dev/null +++ b/apps/web/src/components/ui/menu-styles.ts @@ -0,0 +1,16 @@ +export const menuContentStyles = + "z-50 max-h-(--available-height) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-sm bg-popover p-0.5 text-foreground/75 shadow-md ring-1 ring-[color:color-mix(in_srgb,var(--foreground)_10%,var(--popover))] duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95"; + +export const menuItemStyles = + "relative flex cursor-default items-center gap-1.5 rounded-xs min-h-6.75 px-1.5 py-0.5 text-sm text-foreground/75 outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:text-muted-foreground [&_svg:not([class*='size-'])]:size-4"; + +export const menuLabelStyles = + "px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7"; + +export const menuSeparatorStyles = "-mx-0.5 my-0.5 h-px bg-border"; + +export const menuDestructiveItemStyles = + "data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:[&_svg]:text-destructive"; + +export const menuSubTriggerStyles = + "data-open:bg-accent data-open:text-accent-foreground data-popup-open:bg-accent data-popup-open:text-accent-foreground"; diff --git a/apps/web/src/components/ui/menubar.tsx b/apps/web/src/components/ui/menubar.tsx index a63ce43f..49a4262a 100644 --- a/apps/web/src/components/ui/menubar.tsx +++ b/apps/web/src/components/ui/menubar.tsx @@ -20,6 +20,7 @@ import { DropdownMenuSubTrigger, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; +import { menuItemStyles } from "@/components/ui/menu-styles"; import { cn } from "@/lib/utils"; function Menubar({ className, ...props }: MenubarPrimitive.Props) { @@ -58,7 +59,6 @@ function MenubarTrigger({ className, ...props }: React.ComponentProps ); @@ -90,10 +86,7 @@ function MenubarItem({ data-slot="menubar-item" data-inset={inset} data-variant={variant} - className={cn( - "group/menubar-item gap-1.5 rounded-md px-1.5 py-1 text-sm focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive!", - className, - )} + className={cn("group/menubar-item", className)} {...props} /> ); @@ -112,10 +105,7 @@ function MenubarCheckboxItem({ @@ -145,10 +135,7 @@ function MenubarRadioItem({ @@ -162,33 +149,16 @@ function MenubarRadioItem({ } function MenubarLabel({ - className, inset, ...props }: React.ComponentProps & { inset?: boolean; }) { - return ( - - ); + return ; } -function MenubarSeparator({ - className, - ...props -}: React.ComponentProps) { - return ( - - ); +function MenubarSeparator({ ...props }: React.ComponentProps) { + return ; } function MenubarShortcut({ @@ -212,39 +182,16 @@ function MenubarSub({ ...props }: React.ComponentProps) } function MenubarSubTrigger({ - className, inset, ...props }: React.ComponentProps & { inset?: boolean; }) { - return ( - - ); + return ; } -function MenubarSubContent({ - className, - ...props -}: React.ComponentProps) { - return ( - - ); +function MenubarSubContent({ ...props }: React.ComponentProps) { + return ; } export { diff --git a/apps/web/src/components/web/brand-menu.tsx b/apps/web/src/components/web/brand-menu.tsx index 5cd93965..0da8581a 100644 --- a/apps/web/src/components/web/brand-menu.tsx +++ b/apps/web/src/components/web/brand-menu.tsx @@ -85,11 +85,11 @@ export function BrandMenu({ sideOffset={4} positionerClassName="z-100" > - copyAsSvg("Logo")}> - Copy logo as SVG + copyAsSvg("Logo")}> + Copy logo as SVG - copyAsSvg("Wordmark")}> - Copy wordmark as SVG + copyAsSvg("Wordmark")}> + Copy wordmark as SVG From 5185541a65ae0686b529a0c16b69b8024cd24be5 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 23 Sep 2026 19:10:07 +0400 Subject: [PATCH 2/5] Unify subtle hover backgrounds --- apps/web/src/components/docs/docs-layout.tsx | 4 ++-- apps/web/src/components/layout/navigation-bar.tsx | 6 +++--- apps/web/src/components/ui/button.tsx | 2 +- apps/web/src/components/ui/menu-styles.ts | 4 ++-- apps/web/src/styles/globals.css | 3 +++ 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/web/src/components/docs/docs-layout.tsx b/apps/web/src/components/docs/docs-layout.tsx index e737d28a..49ea5508 100644 --- a/apps/web/src/components/docs/docs-layout.tsx +++ b/apps/web/src/components/docs/docs-layout.tsx @@ -60,7 +60,7 @@ function SearchButton({ className }: { className?: string }) {