diff --git a/apps/docs/app/[lang]/[[...slug]]/page.tsx b/apps/docs/app/[lang]/[[...slug]]/page.tsx index 228bf6da1..025df8093 100644 --- a/apps/docs/app/[lang]/[[...slug]]/page.tsx +++ b/apps/docs/app/[lang]/[[...slug]]/page.tsx @@ -185,11 +185,6 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l tableOfContent={{ style: 'clerk', enabled: true, - header: ( -
- On this page -
- ), footer: , single: false, }} diff --git a/apps/docs/app/[lang]/layout.tsx b/apps/docs/app/[lang]/layout.tsx index 4dbd3d5a4..2563b9d4b 100644 --- a/apps/docs/app/[lang]/layout.tsx +++ b/apps/docs/app/[lang]/layout.tsx @@ -3,13 +3,13 @@ import { defineI18nUI } from 'fumadocs-ui/i18n' import { DocsLayout } from 'fumadocs-ui/layouts/docs' import { RootProvider } from 'fumadocs-ui/provider/next' import { Geist_Mono, Inter } from 'next/font/google' -import Image from 'next/image' import { SidebarFolder, SidebarItem, SidebarSeparator, } from '@/components/docs-layout/sidebar-components' import { Navbar } from '@/components/navbar/navbar' +import { SimLogoFull } from '@/components/ui/sim-logo' import { i18n } from '@/lib/i18n' import { source } from '@/lib/source' import '../global.css' @@ -102,16 +102,7 @@ export default async function Layout({ children, params }: LayoutProps) { - ), + title: , }} sidebar={{ defaultOpenLevel: 0, diff --git a/apps/docs/app/api/og/route.tsx b/apps/docs/app/api/og/route.tsx index 9fec7a4b5..7481224d6 100644 --- a/apps/docs/app/api/og/route.tsx +++ b/apps/docs/app/api/og/route.tsx @@ -33,15 +33,41 @@ async function loadGoogleFont(font: string, weights: string, text: string): Prom throw new Error('Failed to load font data') } +/** + * Sim logo with icon and "Sim" text for OG image. + */ +function SimLogoFull() { + return ( + + {/* Green icon - top left shape with cutout */} + + {/* Green icon - bottom right square */} + + {/* "Sim" text - white for dark background */} + + + ) +} + /** * Generates dynamic Open Graph images for documentation pages. + * Style matches Cursor docs: dark background, title at top, logo bottom-left, domain bottom-right. */ export async function GET(request: NextRequest) { const { searchParams } = new URL(request.url) const title = searchParams.get('title') || 'Documentation' - const baseUrl = new URL(request.url).origin - const allText = `${title}docs.sim.ai` const fontData = await loadGoogleFont('Geist', '400;500;600', allText) @@ -52,84 +78,39 @@ export async function GET(request: NextRequest) { width: '100%', display: 'flex', flexDirection: 'column', - background: '#0c0c0c', - position: 'relative', + justifyContent: 'space-between', + padding: '56px 64px', + background: '#121212', // Dark mode background matching docs (hsla 0, 0%, 7%) fontFamily: 'Geist', }} > - {/* Base gradient layer - subtle purple tint across the entire image */} -
- - {/* Secondary glow - adds depth without harsh edges */} -
- - {/* Top darkening - creates natural vignette */} -
- - {/* Content */} -
- {/* Logo */} - sim + {title} + - {/* Title */} - - {title} - - - {/* Footer */} + {/* Footer: icon left, domain right */} +
+ diff --git a/apps/docs/app/global.css b/apps/docs/app/global.css index 53bc8db7f..656b946cd 100644 --- a/apps/docs/app/global.css +++ b/apps/docs/app/global.css @@ -9,11 +9,20 @@ body { } @theme { - --color-fd-primary: #802fff; /* Purple from control-bar component */ + --color-fd-primary: #33c482; /* Green from Sim logo */ --font-geist-sans: var(--font-geist-sans); --font-geist-mono: var(--font-geist-mono); } +/* Ensure primary color is set in both light and dark modes */ +:root { + --color-fd-primary: #33c482; +} + +.dark { + --color-fd-primary: #33c482; +} + /* Font family utilities */ .font-sans { font-family: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, @@ -34,7 +43,7 @@ body { :root { --fd-border: transparent !important; --fd-border-sidebar: transparent !important; - --fd-nav-height: 64px; /* Custom navbar height (h-16 = 4rem = 64px) */ + --fd-nav-height: 65px; /* Custom navbar height (h-16 = 64px + 1px border) */ /* Content container width used to center main content */ --spacing-fd-container: 1400px; /* Edge gutter = leftover space on each side of centered container */ @@ -136,11 +145,11 @@ aside#nd-sidebar { /* On mobile, let fumadocs handle the layout natively */ @media (min-width: 1024px) { :root { - --fd-banner-height: 64px !important; + --fd-banner-height: 65px !important; /* 64px navbar + 1px border */ } #nd-docs-layout { - --fd-docs-height: calc(100dvh - 64px) !important; + --fd-docs-height: calc(100dvh - 65px) !important; /* 64px navbar + 1px border */ --fd-sidebar-width: 300px !important; margin-left: var(--sidebar-offset) !important; margin-right: var(--toc-offset) !important; @@ -227,19 +236,19 @@ html:not(.dark) #nd-sidebar button:not([aria-label*="ollapse"]):not([aria-label* letter-spacing: 0.05em !important; } -/* Override active state (NO PURPLE) */ +/* Override active state */ #nd-sidebar a[data-active="true"], #nd-sidebar button[data-active="true"], #nd-sidebar a.bg-fd-primary\/10, #nd-sidebar a.text-fd-primary, #nd-sidebar a[class*="bg-fd-primary"], #nd-sidebar a[class*="text-fd-primary"], -/* Override custom sidebar purple classes */ +/* Override custom sidebar green classes */ #nd-sidebar - a.bg-purple-50\/80, -#nd-sidebar a.text-purple-600, -#nd-sidebar a[class*="bg-purple"], -#nd-sidebar a[class*="text-purple"] { + a.bg-emerald-50\/80, +#nd-sidebar a.text-emerald-600, +#nd-sidebar a[class*="bg-emerald"], +#nd-sidebar a[class*="text-emerald"] { background-image: none !important; } @@ -250,10 +259,10 @@ html.dark #nd-sidebar a.bg-fd-primary\/10, html.dark #nd-sidebar a.text-fd-primary, html.dark #nd-sidebar a[class*="bg-fd-primary"], html.dark #nd-sidebar a[class*="text-fd-primary"], -html.dark #nd-sidebar a.bg-purple-50\/80, -html.dark #nd-sidebar a.text-purple-600, -html.dark #nd-sidebar a[class*="bg-purple"], -html.dark #nd-sidebar a[class*="text-purple"] { +html.dark #nd-sidebar a.bg-emerald-50\/80, +html.dark #nd-sidebar a.text-emerald-600, +html.dark #nd-sidebar a[class*="bg-emerald"], +html.dark #nd-sidebar a[class*="text-emerald"] { background-color: rgba(255, 255, 255, 0.15) !important; color: rgba(255, 255, 255, 1) !important; } @@ -265,10 +274,10 @@ html:not(.dark) #nd-sidebar a.bg-fd-primary\/10, html:not(.dark) #nd-sidebar a.text-fd-primary, html:not(.dark) #nd-sidebar a[class*="bg-fd-primary"], html:not(.dark) #nd-sidebar a[class*="text-fd-primary"], -html:not(.dark) #nd-sidebar a.bg-purple-50\/80, -html:not(.dark) #nd-sidebar a.text-purple-600, -html:not(.dark) #nd-sidebar a[class*="bg-purple"], -html:not(.dark) #nd-sidebar a[class*="text-purple"] { +html:not(.dark) #nd-sidebar a.bg-emerald-50\/80, +html:not(.dark) #nd-sidebar a.text-emerald-600, +html:not(.dark) #nd-sidebar a[class*="bg-emerald"], +html:not(.dark) #nd-sidebar a[class*="text-emerald"] { background-color: rgba(0, 0, 0, 0.07) !important; color: rgba(0, 0, 0, 0.9) !important; } @@ -286,8 +295,8 @@ html:not(.dark) #nd-sidebar button:hover:not([data-active="true"]) { } /* Dark mode - ensure active/selected items don't change on hover */ -html.dark #nd-sidebar a.bg-purple-50\/80:hover, -html.dark #nd-sidebar a[class*="bg-purple"]:hover, +html.dark #nd-sidebar a.bg-emerald-50\/80:hover, +html.dark #nd-sidebar a[class*="bg-emerald"]:hover, html.dark #nd-sidebar a[data-active="true"]:hover, html.dark #nd-sidebar button[data-active="true"]:hover { background-color: rgba(255, 255, 255, 0.15) !important; @@ -295,8 +304,8 @@ html.dark #nd-sidebar button[data-active="true"]:hover { } /* Light mode - ensure active/selected items don't change on hover */ -html:not(.dark) #nd-sidebar a.bg-purple-50\/80:hover, -html:not(.dark) #nd-sidebar a[class*="bg-purple"]:hover, +html:not(.dark) #nd-sidebar a.bg-emerald-50\/80:hover, +html:not(.dark) #nd-sidebar a[class*="bg-emerald"]:hover, html:not(.dark) #nd-sidebar a[data-active="true"]:hover, html:not(.dark) #nd-sidebar button[data-active="true"]:hover { background-color: rgba(0, 0, 0, 0.07) !important; @@ -368,16 +377,22 @@ aside[data-sidebar] > *:not([data-sidebar-viewport]) { button[aria-label="Toggle Sidebar"], button[aria-label="Collapse Sidebar"], /* Hide nav title/logo in sidebar on desktop - target all possible locations */ + #nd-sidebar + a[href="/"], + #nd-sidebar a[href="/"] img, + #nd-sidebar a[href="/"] svg, + #nd-sidebar > a:first-child, + #nd-sidebar > div:first-child > a:first-child, + #nd-sidebar img[alt="Sim"], + #nd-sidebar svg[aria-label="Sim"], aside[data-sidebar] a[href="/"], aside[data-sidebar] a[href="/"] img, aside[data-sidebar] > a:first-child, aside[data-sidebar] > div > a:first-child, aside[data-sidebar] img[alt="Sim"], + aside[data-sidebar] svg[aria-label="Sim"], [data-sidebar-header], [data-sidebar] [data-title], - #nd-sidebar > a:first-child, - #nd-sidebar > div:first-child > a:first-child, - #nd-sidebar img[alt="Sim"], /* Hide theme toggle at bottom of sidebar on desktop */ #nd-sidebar > footer, @@ -515,6 +530,15 @@ pre code .line { color: var(--color-fd-primary); } +/* ============================================ + TOC (Table of Contents) Styling + ============================================ */ + +/* Remove the thin border-left on nested TOC items (keeps main indicator only) */ +#nd-toc a[style*="padding-inline-start"] { + border-left: none !important; +} + /* Add bottom spacing to prevent abrupt page endings */ [data-content] { padding-top: 1.5rem !important; diff --git a/apps/docs/components/docs-layout/sidebar-components.tsx b/apps/docs/components/docs-layout/sidebar-components.tsx index e5fb882fb..e6fbe18cd 100644 --- a/apps/docs/components/docs-layout/sidebar-components.tsx +++ b/apps/docs/components/docs-layout/sidebar-components.tsx @@ -44,7 +44,7 @@ export function SidebarItem({ item }: { item: Item }) { 'lg:text-gray-600 lg:dark:text-gray-400', !active && 'lg:hover:bg-gray-100/60 lg:dark:hover:bg-gray-800/40', active && - 'lg:bg-purple-50/80 lg:font-normal lg:text-purple-600 lg:dark:bg-purple-900/15 lg:dark:text-purple-400' + 'lg:bg-emerald-50/80 lg:font-normal lg:text-emerald-600 lg:dark:bg-emerald-900/15 lg:dark:text-emerald-400' )} > {item.name} @@ -79,7 +79,7 @@ export function SidebarFolder({ item, children }: { item: Folder; children: Reac 'lg:text-gray-600 lg:dark:text-gray-400', !active && 'lg:hover:bg-gray-100/60 lg:dark:hover:bg-gray-800/40', active && - 'lg:bg-purple-50/80 lg:font-normal lg:text-purple-600 lg:dark:bg-purple-900/15 lg:dark:text-purple-400' + 'lg:bg-emerald-50/80 lg:font-normal lg:text-emerald-600 lg:dark:bg-emerald-900/15 lg:dark:text-emerald-400' )} > {item.name} @@ -104,7 +104,7 @@ export function SidebarFolder({ item, children }: { item: Folder; children: Reac 'lg:text-gray-800 lg:dark:text-gray-200', !active && 'lg:hover:bg-gray-100/60 lg:dark:hover:bg-gray-800/40', active && - 'lg:bg-purple-50/80 lg:text-purple-600 lg:dark:bg-purple-900/15 lg:dark:text-purple-400' + 'lg:bg-emerald-50/80 lg:text-emerald-600 lg:dark:bg-emerald-900/15 lg:dark:text-emerald-400' )} > {item.name} diff --git a/apps/docs/components/docs-layout/toc-footer.tsx b/apps/docs/components/docs-layout/toc-footer.tsx index cd62bd6c7..01eb5d81a 100644 --- a/apps/docs/components/docs-layout/toc-footer.tsx +++ b/apps/docs/components/docs-layout/toc-footer.tsx @@ -23,7 +23,7 @@ export function TOCFooter() { rel='noopener noreferrer' onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} - className='group mt-2 inline-flex h-8 w-fit items-center justify-center gap-1 whitespace-nowrap rounded-[10px] border border-[#6F3DFA] bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] px-3 pr-[10px] pl-[12px] font-medium text-sm text-white shadow-[inset_0_2px_4px_0_#9B77FF] outline-none transition-all hover:shadow-lg focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50' + className='group mt-2 inline-flex h-8 w-fit items-center justify-center gap-1 whitespace-nowrap rounded-[10px] border border-[#2AAD6C] bg-gradient-to-b from-[#3ED990] to-[#2AAD6C] px-3 pr-[10px] pl-[12px] font-medium text-sm text-white shadow-[inset_0_2px_4px_0_#5EE8A8] outline-none transition-all hover:shadow-lg focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50' aria-label='Get started with Sim - Sign up for free' > Get started diff --git a/apps/docs/components/navbar/navbar.tsx b/apps/docs/components/navbar/navbar.tsx index bbddf45e6..12bf9f7be 100644 --- a/apps/docs/components/navbar/navbar.tsx +++ b/apps/docs/components/navbar/navbar.tsx @@ -1,9 +1,9 @@ 'use client' -import Image from 'next/image' import Link from 'next/link' import { LanguageDropdown } from '@/components/ui/language-dropdown' import { SearchTrigger } from '@/components/ui/search-trigger' +import { SimLogoFull } from '@/components/ui/sim-logo' import { ThemeToggle } from '@/components/ui/theme-toggle' export function Navbar() { @@ -27,13 +27,7 @@ export function Navbar() { {/* Left cluster: logo */}
- Sim +
diff --git a/apps/docs/components/ui/action-media.tsx b/apps/docs/components/ui/action-media.tsx index 1f187fb90..629716b66 100644 --- a/apps/docs/components/ui/action-media.tsx +++ b/apps/docs/components/ui/action-media.tsx @@ -1,38 +1,87 @@ 'use client' -import { getAssetUrl } from '@/lib/utils' +import { useState } from 'react' +import { cn, getAssetUrl } from '@/lib/utils' +import { Lightbox } from './lightbox' interface ActionImageProps { src: string alt: string + enableLightbox?: boolean } interface ActionVideoProps { src: string alt: string + enableLightbox?: boolean } -export function ActionImage({ src, alt }: ActionImageProps) { +export function ActionImage({ src, alt, enableLightbox = true }: ActionImageProps) { + const [isLightboxOpen, setIsLightboxOpen] = useState(false) + + const handleClick = () => { + if (enableLightbox) { + setIsLightboxOpen(true) + } + } + return ( - {alt} + <> + {alt} + {enableLightbox && ( + setIsLightboxOpen(false)} + src={src} + alt={alt} + type='image' + /> + )} + ) } -export function ActionVideo({ src, alt }: ActionVideoProps) { +export function ActionVideo({ src, alt, enableLightbox = true }: ActionVideoProps) { + const [isLightboxOpen, setIsLightboxOpen] = useState(false) const resolvedSrc = getAssetUrl(src) + const handleClick = () => { + if (enableLightbox) { + setIsLightboxOpen(true) + } + } + return ( -