@@ -197,7 +179,7 @@ export function SiteHeader() {
asChild
variant="text"
size="tiny"
- className="hidden px-2 sm:inline-flex"
+ className="hidden h-8 w-8 p-0 sm:inline-flex"
aria-label="View source on GitHub"
>
@@ -208,7 +190,7 @@ export function SiteHeader() {
asChild
variant="text"
size="small"
- className="hidden px-3 text-sm sm:inline-flex"
+ className="hidden h-8 px-3 text-sm sm:inline-flex"
iconRight={}
>
Docs
diff --git a/apps/ui-library/components/terminal-code.tsx b/apps/ui-library/components/terminal-code.tsx
new file mode 100644
index 00000000000..92f83490131
--- /dev/null
+++ b/apps/ui-library/components/terminal-code.tsx
@@ -0,0 +1,21 @@
+'use client'
+
+import dynamic from 'next/dynamic'
+
+const CodeBlock = dynamic(() => import('ui-patterns/CodeBlock').then((module) => module.CodeBlock))
+
+export function TerminalCode({ command }: { command: string }) {
+ return (
+
+ {command}
+
+ )
+}
diff --git a/apps/ui-library/components/theme-switcher-dropdown.tsx b/apps/ui-library/components/theme-switcher-dropdown.tsx
index c53583afbd1..882b4e5e765 100644
--- a/apps/ui-library/components/theme-switcher-dropdown.tsx
+++ b/apps/ui-library/components/theme-switcher-dropdown.tsx
@@ -58,7 +58,7 @@ const ThemeSwitcherDropdown = () => {
variant="text"
size="tiny"
aria-label="Choose a theme"
- className="px-1 group"
+ className="group h-8 w-8 p-0"
icon={
resolvedTheme?.includes('light') ? (
diff --git a/apps/ui-library/hooks/use-menu-aim.ts b/apps/ui-library/hooks/use-menu-aim.ts
new file mode 100644
index 00000000000..49259b6e26e
--- /dev/null
+++ b/apps/ui-library/hooks/use-menu-aim.ts
@@ -0,0 +1,59 @@
+'use client'
+
+import { useEffect, useRef, type PointerEvent } from 'react'
+
+// Keep the selected category while the pointer travels toward its content panel.
+export function useMenuAim(activeCategory: string, onCategoryChange: (category: string) => void) {
+ const previousPoint = useRef<{ x: number; y: number } | null>(null)
+ const timeout = useRef
| null>(null)
+
+ function cancelPending() {
+ if (timeout.current !== null) clearTimeout(timeout.current)
+ timeout.current = null
+ }
+
+ function reset() {
+ cancelPending()
+ previousPoint.current = null
+ }
+
+ useEffect(() => {
+ return () => {
+ if (timeout.current !== null) clearTimeout(timeout.current)
+ }
+ }, [])
+
+ function onPointerMove(event: PointerEvent) {
+ if (event.pointerType !== 'mouse') return
+
+ const previous = previousPoint.current
+ const point = { x: event.clientX, y: event.clientY }
+ previousPoint.current = point
+ const target = event.target instanceof Element ? event.target : null
+ const tab = target?.closest('[data-menu-category]')
+ const category = tab?.dataset.menuCategory
+ cancelPending()
+ if (!category || category === activeCategory) return
+
+ const list = tab?.closest('[role="tablist"]')?.getBoundingClientRect()
+ const panel = event.currentTarget.getBoundingClientRect()
+ if (previous && list && previous.x < point.x && point.x < list.right) {
+ const progress = (point.x - previous.x) / (list.right - previous.x)
+ const top = previous.y + (panel.top - previous.y) * progress
+ const bottom = previous.y + (panel.bottom - previous.y) * progress
+ if (point.y >= top && point.y <= bottom) {
+ timeout.current = setTimeout(() => onCategoryChange(category), 300)
+ return
+ }
+ }
+
+ onCategoryChange(category)
+ }
+
+ function selectCategory(category: string) {
+ reset()
+ onCategoryChange(category)
+ }
+
+ return { onPointerMove, onPointerLeave: reset, selectCategory }
+}