Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
"@cloudflare/vite-plugin": "^1.42.0",
"@content-collections/core": "^0.14.3",
"@content-collections/vite": "^0.2.9",
"@figma/code-connect": "^1.4.8",
"@tanstack/devtools-vite": "^0.7.0",
"@tanstack/react-devtools": "^0.10.5",
"@tanstack/react-query-devtools": "^5.100.11",
Expand Down
686 changes: 686 additions & 0 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/components/FeatureGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react'
import { CheckCircleIcon } from '~/components/icons/CheckCircleIcon'
import { CheckCircle } from '@phosphor-icons/react'

type FeatureGridProps = {
title?: string
Expand All @@ -23,7 +23,7 @@ export function FeatureGrid({ title, items, gridClassName }: FeatureGridProps) {
>
{items.map((d, i) => (
<span key={i} className="flex gap-2">
<CheckCircleIcon className="text-green-500 h-lh w-4 shrink-0" /> {d}
<CheckCircle className="text-green-500 h-lh w-4 shrink-0" /> {d}
</span>
))}
</div>
Expand Down
120 changes: 120 additions & 0 deletions src/components/MegaMenuItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import * as React from 'react'
import { Link } from '@tanstack/react-router'
import { twMerge } from 'tailwind-merge'
import { ArrowSquareOut } from '@phosphor-icons/react'

type IconComponent = React.ComponentType<{ className?: string }>

export interface MegaMenuItemProps {
/** Leading icon, shown in a bordered rounded square. */
icon?: IconComponent
title: React.ReactNode
description?: React.ReactNode
/** Internal route or external (http/mailto) URL. */
to: string
hash?: string
badge?: string
onNavigate?: () => void
variant?: 'desktop' | 'mobile'
/** Elevated variant used for standalone / featured rows. */
compact?: boolean
className?: string
}

function isExternal(to: string) {
return to.startsWith('http') || to.startsWith('mailto:')
}

/**
* A single mega-menu row — icon + title + description with rest / hover /
* pressed states. Modeled on the Figma "Mega Menu Item" component: bordered
* icon square, Bricolage-bold title (heading-5), muted body-xs description, and
* a mode-adaptive overlay on hover/press. Used by the site Navbar and shown in
* the design system at /ds/navbar.
*/
export function MegaMenuItem({
icon: Icon,
title,
description,
to,
hash,
badge,
onNavigate,
variant = 'desktop',
compact,
className,
}: MegaMenuItemProps) {
const external = isExternal(to)

const rootClassName = twMerge(
// Figma "Mega Menu Item": gap 10px, pl 8 / pr 16 / py 8, radius 12px.
'group/mmi flex items-center gap-2.5 rounded-xl py-2 pl-2 pr-4 text-left transition-colors',
// States differ only by row background: hover white/4%, pressed white/12%
// (mode-adaptive via text-primary so it also works on light menu panels).
'hover:bg-text-primary/[0.04] focus:bg-text-primary/[0.04] focus:outline-none active:bg-text-primary/[0.12]',
compact && 'border border-border-subtle bg-background-surface',
variant === 'desktop' && !compact && 'w-[260px]',
variant === 'mobile' && 'py-2.5',
className,
)

const content = (
<>
{Icon ? (
<span className="inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-md border border-border-default text-text-secondary">
<Icon className="h-7 w-7" />
</span>
) : null}
<span className="flex min-w-0 flex-1 flex-col gap-1.5">
<span className="flex items-center gap-2">
<span className="font-ds-display text-ds-heading-5 text-text-primary">
{title}
</span>
{badge ? (
<span className="rounded-md border border-status-success/50 px-1.5 py-0.5 text-[0.6rem] font-black uppercase leading-none text-status-success">
{badge}
</span>
) : null}
{external && !to.startsWith('mailto:') ? (
<ArrowSquareOut className="h-3 w-3 text-text-muted transition-colors group-hover/mmi:text-text-secondary" />
) : null}
</span>
{description ? (
// Plain string (not twMerge) — the DS text-size and text-color
// utilities both start with `text-`, and twMerge would drop the color.
<span
className={`block text-text-secondary ${variant === 'desktop' ? 'text-ds-body-xs' : 'text-ds-body-sm'}`}
>
{description}
</span>
) : null}
</span>
</>
)

if (external) {
return (
<a
href={to}
target={to.startsWith('mailto:') ? undefined : '_blank'}
rel={to.startsWith('mailto:') ? undefined : 'noopener noreferrer'}
className={rootClassName}
onClick={onNavigate}
>
{content}
</a>
)
}

return (
<Link
to={to}
hash={hash}
className={rootClassName}
onClick={onNavigate}
preload="intent"
>
{content}
</Link>
)
}
96 changes: 21 additions & 75 deletions src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ const LazyNavbarAuthControls = React.lazy(() =>
})),
)
import { NavbarCartButton } from './NavbarCartButton'
import { MegaMenuItem } from './MegaMenuItem'
import { Link, useLocation, useMatches } from '@tanstack/react-router'
import {
BookOpen,
Code,
ArrowSquareOut,
GridFour,
Hammer,
Heart,
Expand Down Expand Up @@ -327,6 +327,12 @@ const NAV_GROUPS = [
description: 'Logos, colors, and brand usage.',
icon: PaintBrush,
},
{
label: 'Design System',
to: '/ds',
description: 'Design tokens and components for TanStack surfaces.',
icon: GridFour,
},
],
},
],
Expand All @@ -353,10 +359,6 @@ function getLibraryDisplayName(library: LibrarySlim) {
return library.name.replace(/^TanStack\s+/, '')
}

function isExternalLink(to: string) {
return to.startsWith('http') || to.startsWith('mailto:')
}

function getLibraryDocsTo(library: NavigationLibrary) {
return `${library.to}/latest/docs`
}
Expand Down Expand Up @@ -561,8 +563,8 @@ export function Navbar({ children }: { children: React.ReactNode }) {
const navbar = (
<div
className={twMerge(
'w-full h-[var(--navbar-height)] p-2 fixed top-0 z-[100] bg-white/90 dark:bg-black/90 backdrop-blur-lg',
'flex items-center justify-between gap-2 min-[1120px]:gap-3',
'w-full h-[var(--navbar-height)] px-3 py-2 min-[900px]:px-5 fixed top-0 z-[100] bg-white/90 dark:bg-black/90 backdrop-blur-lg',
'flex items-center justify-between gap-2 min-[1120px]:gap-4',
'border-b border-gray-500/20',
)}
ref={containerRef}
Expand All @@ -587,7 +589,7 @@ export function Navbar({ children }: { children: React.ReactNode }) {
aria-label="Primary navigation"
className={twMerge(
DESKTOP_NAV_CLASS,
'relative shrink-0 items-center justify-center gap-0',
'relative shrink-0 items-center justify-center gap-1',
)}
>
{NAV_GROUPS.map((group) => (
Expand All @@ -605,7 +607,7 @@ export function Navbar({ children }: { children: React.ReactNode }) {
))}
</nav>

<div className="flex flex-1 items-center justify-end gap-1.5 sm:gap-2">
<div className="flex flex-1 items-center justify-end gap-2 sm:gap-2.5">
<div className={DESKTOP_SOCIAL_CLASS}>{socialLinks}</div>
<ThemeToggle />
<NavbarCartButton />
Expand Down Expand Up @@ -902,7 +904,7 @@ function MegaMenuContent({
</div>
<div
className={twMerge(
'grid gap-1',
'grid gap-2',
variant === 'desktop' &&
group.key === 'learn' &&
'grid-cols-[repeat(2,260px)]',
Expand Down Expand Up @@ -1354,74 +1356,18 @@ function MenuItemLink({
variant: 'desktop' | 'mobile'
compact?: boolean
}) {
const Icon = item.icon
const isExternal = isExternalLink(item.to)
const className = twMerge(
'group flex items-start gap-3 rounded-lg px-2 py-2.5 text-left',
'hover:bg-gray-500/10 focus:bg-gray-500/10 focus:outline-none',
compact && 'bg-white dark:bg-black/40',
variant === 'desktop' && !compact && 'w-[260px]',
variant === 'mobile' && 'px-2 py-3',
)
const content = (
<>
{Icon ? (
<span className="mt-0.5 inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-gray-100 text-gray-700 dark:bg-gray-900 dark:text-gray-300">
<Icon className="h-4 w-4" />
</span>
) : null}
<span className="min-w-0 flex-1">
<span className="flex items-center gap-2">
<span className="font-bold text-gray-950 dark:text-white">
{item.label}
</span>
{item.badge ? (
<span className="rounded-md border border-green-500/50 px-1.5 py-0.5 text-[0.6rem] font-black uppercase leading-none text-green-600 dark:text-green-400">
{item.badge}
</span>
) : null}
{isExternal && !item.to.startsWith('mailto:') ? (
<ArrowSquareOut className="h-3 w-3 text-gray-400 group-hover:text-gray-600 dark:group-hover:text-gray-300" />
) : null}
</span>
{item.description ? (
<span
className={twMerge(
'mt-0.5 block text-gray-600 dark:text-gray-400',
variant === 'desktop' ? 'text-xs leading-4' : 'text-sm leading-5',
)}
>
{item.description}
</span>
) : null}
</span>
</>
)

if (isExternal) {
return (
<a
href={item.to}
target={item.to.startsWith('mailto:') ? undefined : '_blank'}
rel={item.to.startsWith('mailto:') ? undefined : 'noopener noreferrer'}
className={className}
onClick={onNavigate}
>
{content}
</a>
)
}

return (
<Link
<MegaMenuItem
icon={item.icon}
title={item.label}
description={item.description}
to={item.to}
hash={item.hash}
className={className}
onClick={onNavigate}
preload="intent"
>
{content}
</Link>
badge={item.badge}
onNavigate={onNavigate}
variant={variant}
compact={compact}
/>
)
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/ds/DsKit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function DsPage({
children: React.ReactNode
}) {
return (
<div className="mx-auto max-w-5xl px-6 py-10 lg:px-10">
<div className="mx-auto max-w-7xl px-6 py-10 lg:px-10">
<header className="mb-10">
<h1 className="font-ds-display text-ds-display-sm text-text-primary">
{title}
Expand Down
1 change: 1 addition & 0 deletions src/components/ds/ds-nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const dsNav: Array<DsNavSection> = [
{ label: 'Collapsible', to: '/ds/collapsible' },
{ label: 'Breadcrumbs', to: '/ds/breadcrumbs' },
{ label: 'Cards & Surfaces', to: '/ds/cards' },
{ label: 'Navbar', to: '/ds/navbar' },
],
},
]
28 changes: 0 additions & 28 deletions src/components/icons/CheckCircleIcon.tsx

This file was deleted.

25 changes: 0 additions & 25 deletions src/components/icons/CogsIcon.tsx

This file was deleted.

5 changes: 2 additions & 3 deletions src/libraries/ai.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Library } from '.'
import { Plug, Lightning } from '@phosphor-icons/react'
import { Plug, Lightning, Gear } from '@phosphor-icons/react'
import { twMerge } from 'tailwind-merge'
import { CogsIcon } from '~/components/icons/CogsIcon'
import { ai } from './libraries'

const textStyles = `text-pink-600 dark:text-pink-500`
Expand Down Expand Up @@ -37,7 +36,7 @@ export const aiProject = {
},
{
title: 'Typed Tools & Media',
icon: <CogsIcon className={twMerge(textStyles)} />,
icon: <Gear className={twMerge(textStyles)} />,
description: (
<div>
Type-safe client/server tools, provider-native tools, structured
Expand Down
Loading
Loading