diff --git a/apps/docs/app/[lang]/[[...slug]]/page.tsx b/apps/docs/app/[lang]/[[...slug]]/page.tsx index 438968103cf..a5702cc93c9 100644 --- a/apps/docs/app/[lang]/[[...slug]]/page.tsx +++ b/apps/docs/app/[lang]/[[...slug]]/page.tsx @@ -10,7 +10,6 @@ import { notFound } from 'next/navigation' import { PageFooter } from '@/components/docs-layout/page-footer' import { PageNavigationArrows } from '@/components/docs-layout/page-navigation-arrows' import { LLMCopyButton } from '@/components/page-actions' -import { PageTypeBadge } from '@/components/page-type-badge' import { StructuredData } from '@/components/structured-data' import { CodeBlock } from '@/components/ui/code-block' import { Heading } from '@/components/ui/heading' @@ -23,6 +22,21 @@ import { DOCS_BASE_URL } from '@/lib/urls' const SUPPORTED_LANGUAGES: Set = new Set(i18n.languages) const BASE_URL = DOCS_BASE_URL +/** + * Most pages close with a `## Next` / `## Next steps` grid of onward links. + * That heading is navigation, not content, so it is kept out of the table of + * contents — the ToC should say what the page covers, not where to go after it. + * The heading itself still renders above the cards. + * + * Matched on the slug rather than the rendered title because a ToC title is a + * `ReactNode`; the trailing group tolerates the slugger's dedupe suffix. + */ +const ONWARD_NAV_SLUG = /^#next(-steps)?(-\d+)?$/i + +function isContentHeading(item: { url: string }): boolean { + return !ONWARD_NAV_SLUG.test(item.url) +} + const OG_LOCALE_MAP: Record = { en: 'en_US', es: 'es_ES', @@ -171,7 +185,7 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l breadcrumb={breadcrumbs} /> - {data.pageType && } {data.title} diff --git a/apps/docs/app/global.css b/apps/docs/app/global.css index 1047524cc3d..5f6ea80f42d 100644 --- a/apps/docs/app/global.css +++ b/apps/docs/app/global.css @@ -5,6 +5,19 @@ @source "../../../packages/emcn/src"; @source "../../../packages/workflow-renderer/src"; +/* Every @sim/emcn component expresses hover through `hover-hover:` so touch + devices never latch a sticky hover state. The app registers it as a plugin + variant in apps/sim/tailwind.config.ts; docs is CSS-first Tailwind v4 with no + config, so without this declaration the variant compiles to nothing and every + emcn hover state silently no-ops here. */ +@custom-variant hover-hover { + @media (hover: hover) and (pointer: fine) { + &:hover { + @slot; + } + } +} + /* Prevent overscroll bounce effect on the page */ html, body { @@ -114,11 +127,24 @@ body { --badge-error-text: #dc2626; --badge-gray-bg: #e7e5e4; --badge-gray-text: #57534e; + --code-bg: #f5f5f5; + --code-foreground: #1a1a1a; + --code-line-number: #737373; + --selection-bg: #add6ff; + --selection-dark: #264f78; + --highlight-search-active: #f6ad55; --scrollbar-thumb-color: #c0c0c0; --scrollbar-thumb-hover-color: #a8a8a8; --shadow-subtle: 0 2px 4px 0 rgba(0, 0, 0, 0.08); --shadow-medium: 0 4px 12px rgba(0, 0, 0, 0.1); + --shadow-overlay: 0 10px 30px rgba(0, 0, 0, 0.11); --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.04); + /* z-index scale — poppers sit above the modal so menus stay clickable over + the modal overlay. Mirrors apps/sim/app/_styles/globals.css. */ + --z-toast: 150; + --z-modal: 200; + --z-popover: 300; + --z-tooltip: 400; } .dark { @@ -185,8 +211,13 @@ body { --badge-error-text: #fca5a5; --badge-gray-bg: #3a3a3a; --badge-gray-text: #a8a8a8; + --code-bg: #1f1f1f; + --code-foreground: #eeeeee; + --code-line-number: #a8a8a8; + --selection-bg: #264f78; --scrollbar-thumb-color: #5a5a5a; --scrollbar-thumb-hover-color: #6a6a6a; + --shadow-overlay: 0 10px 30px rgba(0, 0, 0, 0.3); } /* Scrollbars — platform thumb tokens, transparent track */ @@ -331,18 +362,32 @@ aside#nd-sidebar [data-radix-scroll-area-viewport] { min-height: var(--fd-docs-height) !important; } - /* Sidebar divider line — sticky within the docs layout box, so it ends where - the layout does instead of bleeding into (or past) the footer below it. - #nd-docs-layout is a CSS grid (see fumadocs' Container slot); a sticky - pseudo-element stays in normal flow, so without an explicit grid-area it - gets auto-placed into a real content cell and skews that cell's sizing. - Spanning the full grid keeps it purely decorative/overlaid instead. */ + /* Pin the sidebar to the viewport instead of letting fumadocs' `sticky` do it. + A sticky box is bottom-limited by its containing block, and #nd-docs-layout + ends ~660px above the document bottom because the site footer is a sibling + of the layout, not a grid child. So across the whole footer the sidebar gets + pushed upward — and any content-height change while the reader is in that + zone (expanding an FAQ row, say) makes it visibly jump. A fixed box ignores + both the container's end and the document's height, so neither happens. + + Safe because the grid columns are explicit (`0px 300px 1fr 268px 0px`), so + removing the placeholder from flow leaves its track intact. `left`/`width` + are restated because a fixed box no longer derives them from its grid cell, + and `top`/`height` already come from fumadocs' own utility classes. */ + [data-sidebar-placeholder] { + position: fixed !important; + left: var(--sidebar-offset); + width: var(--fd-sidebar-width); + } + + /* Sidebar divider line — pinned for the same reason, and so it stays glued to + the sidebar's right edge. Being fixed takes it out of #nd-docs-layout's grid + entirely, so it needs no grid placement and cannot skew a content cell; its + position comes from `left`/`top` alone. */ #nd-docs-layout::before { content: ""; display: block; - position: sticky; - grid-row: 1 / -1; - grid-column: 1 / -1; + position: fixed; top: 92px; /* below navbar */ height: calc(100dvh - 92px); left: calc(var(--sidebar-offset) + var(--fd-sidebar-width)); @@ -358,10 +403,10 @@ aside#nd-sidebar [data-radix-scroll-area-viewport] { } } -/* Sidebar spacing — left padding aligns item text with navbar content (item has 14px internal padding) */ +/* Sidebar spacing — left padding aligns item text with navbar content (item has 8px internal padding) */ [data-sidebar-viewport], #nd-sidebar > div { - padding: 0 14px 0 calc(var(--nav-inset) - 14px) !important; + padding: 0 14px 0 calc(var(--nav-inset) - 8px) !important; background: transparent !important; } @@ -386,15 +431,20 @@ html #nd-sidebar [data-radix-scroll-area-viewport] > div { /* Target Link and button elements in sidebar - override Fumadocs itemVariants */ /* Exclude the small chevron-only toggle buttons */ /* Using html prefix for higher specificity over Tailwind v4 utilities */ +/* NEVER set `display` here. This selector scores (1,2,2) and carries + `!important`, so it out-specifies every rule below that hides the language + selector, theme toggle, and search button — a `display` declaration here + forces all of them back into the sidebar. The 30px chip height therefore + comes from line-height + padding (20 + 5 + 5), not from flex centering. */ html #nd-sidebar a:not(:has(span.font-mono)), html #nd-sidebar button:not([aria-label*="ollapse"]):not([aria-label*="xpand"]) { font-size: 0.875rem !important; /* 14px to match navbar items */ - line-height: 1.4 !important; - padding: 0.375rem 0.875rem !important; - font-weight: 450 !important; + line-height: 20px !important; + padding: 5px 0.5rem !important; /* 30px tall overall — the app's chip pill, at its px-2 */ + font-weight: 400 !important; border-radius: 0.5rem !important; /* platform rounded-lg */ - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, - sans-serif !important; + font-family: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important; } /* Sidebar text — platform --text-body */ @@ -428,28 +478,24 @@ html #nd-sidebar button:not([aria-label*="ollapse"]):not([aria-label*="xpand"]) margin-bottom: 0 !important; } -/* Section separator headers — styling handled by component, override fumadocs defaults */ +/* Section separator headers — match the app sidebar's group label: 12px, + sentence case, normal weight. Only the fumadocs defaults are overridden here; + size and color stay on the component. */ [data-sidebar-viewport] [data-separator] p, #nd-sidebar [data-separator] p { - font-size: 0.625rem !important; /* 10px */ - font-weight: 600 !important; - text-transform: uppercase !important; - letter-spacing: 0.06em !important; + font-weight: 400 !important; + text-transform: none !important; + letter-spacing: normal !important; margin: 0 !important; padding: 0 !important; } -/* First separator has no top margin or divider; subsequent ones show the divider on desktop */ +/* The first group sits flush against the top padding — it has nothing to be + separated from. */ [data-separator]:not([data-separator] ~ [data-separator]) { margin-top: 0; } -@media (min-width: 1024px) { - [data-separator] ~ [data-separator] > .separator-divider { - display: block; - } -} - /* Active state — aligned with platform --surface-active */ #nd-sidebar a[data-active="true"]:not(:has(span.font-mono)), #nd-sidebar button[data-active="true"] { @@ -709,7 +755,7 @@ main article h4, [data-content] h4, #nd-page h3, #nd-page h4 { - font-size: 1rem !important; + font-size: var(--text-md) !important; font-weight: 470 !important; letter-spacing: -0.01em; color: var(--text-body); @@ -751,18 +797,26 @@ main article li, border-left: none !important; } +/* The clerk TOC draws its active range twice: a track segment, plus a dot that + animates along the track to the current heading. The dot is redundant with the + segment and reads as a stray artifact, so hide it and keep the segment. It is + the only node fumadocs gives an inline offset-path, which is what anchors it. */ +#nd-toc [style*="offset-path"] { + display: none !important; +} + /* TOC heading — align weight with landing */ #nd-toc h3, #nd-toc [class*="title"] { font-weight: 480 !important; - font-size: 0.8125rem !important; + font-size: var(--text-small) !important; color: var(--text-muted); } /* TOC links — softer colors aligned with landing muted text */ #nd-toc a { font-weight: 430 !important; - font-size: 0.8125rem !important; + font-size: var(--text-small) !important; color: var(--text-muted); transition: color 0.2s; } @@ -905,7 +959,7 @@ html #nd-sidebar a:has(span.font-mono.font-medium) { align-items: center; justify-content: center; width: 2.625rem; - font-size: 0.625rem !important; + font-size: var(--text-micro) !important; line-height: 1 !important; padding: 0.15625rem 0.25rem; border-radius: 0.375rem; @@ -917,7 +971,7 @@ html #nd-sidebar a:has(span.font-mono.font-medium) { display: inline-flex; align-items: center; justify-content: center; - font-size: 0.625rem !important; + font-size: var(--text-micro) !important; line-height: 1 !important; padding: 0.15625rem 0.375rem; border-radius: 0.375rem; @@ -984,7 +1038,7 @@ div.flex.flex-row.items-start.bg-fd-secondary.border.rounded-lg.text-xs { span.font-mono.font-medium { font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif !important; font-weight: 600 !important; - font-size: 0.6875rem !important; + font-size: var(--text-xs) !important; letter-spacing: 0.025em; text-transform: uppercase; padding: 0.125rem 0.5rem !important; @@ -1033,7 +1087,7 @@ div.flex.flex-row.items-start.bg-fd-secondary.border.rounded-lg.text-xs { background: none !important; border: none !important; padding: 0 !important; - font-size: 0.8125rem !important; + font-size: var(--text-small) !important; } /* Inline code in API pages — neutral color aligned with sim design. Exclude code inside the method+path bar (handled above). */ @@ -1213,7 +1267,7 @@ div.flex.flex-row.items-start.bg-fd-secondary.border.rounded-lg.text-xs { color: var(--text-secondary); padding: 0.1875rem 0.5rem; border-radius: 0.375rem; - font-size: 0.6875rem; + font-size: var(--text-xs); line-height: 1.125rem; font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; @@ -1223,7 +1277,6 @@ html.dark .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground { background-color: var(--surface-4); - color: var(--text-secondary); } /* Hide the "*" inside the name span — we'll add "required" as a ::after on the flex row */ @@ -1242,7 +1295,7 @@ html.dark color: var(--badge-error-text); padding: 0.1875rem 0.5rem; border-radius: 0.375rem; - font-size: 0.6875rem; + font-size: var(--text-xs); line-height: 1.125rem; font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; @@ -1284,7 +1337,7 @@ html.dark > .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground::after { content: "string"; - font-size: 0.6875rem; + font-size: var(--text-xs); line-height: 1.125rem; font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; @@ -1301,7 +1354,6 @@ html.dark > .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground::after { background-color: var(--surface-4); - color: var(--text-secondary); } /* "header" badge via ::before on the auth flex row */ @@ -1314,7 +1366,7 @@ html.dark color: var(--text-secondary); padding: 0.1875rem 0.5rem; border-radius: 0.375rem; - font-size: 0.6875rem; + font-size: var(--text-xs); line-height: 1.125rem; font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; @@ -1324,7 +1376,6 @@ html.dark div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before { background-color: var(--surface-4); - color: var(--text-secondary); } /* "required" badge via ::after on the auth flex row — red pill */ @@ -1337,7 +1388,7 @@ html.dark color: var(--badge-error-text); padding: 0.1875rem 0.5rem; border-radius: 0.375rem; - font-size: 0.6875rem; + font-size: var(--text-xs); line-height: 1.125rem; font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; @@ -1389,7 +1440,7 @@ html.dark color: var(--text-secondary); padding: 0.1875rem 0.5rem; border-radius: 0.375rem; - font-size: 0.6875rem; + font-size: var(--text-xs); line-height: 1.125rem; font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; @@ -1400,7 +1451,6 @@ html.dark .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button) { background-color: var(--surface-4); - color: var(--text-secondary); } /* Section headings (Authorization, Path Parameters, etc.) — consistent top spacing */ @@ -1562,10 +1612,6 @@ div > figure.shiki { box-shadow: none !important; } -html.dark div > figure.shiki { - background-color: transparent !important; -} - /* Tabbed code block container (cURL/JS/Go tabs) */ div:has(> [role="tablist"]):has(> div > figure.shiki) { border-radius: 0.5rem !important; @@ -1610,19 +1656,11 @@ figure.shiki pre { background-color: transparent !important; } -html.dark figure.shiki pre { - background-color: transparent !important; -} - /* Code viewport scroll area — transparent bg */ figure.shiki > div[role="region"] { background-color: transparent !important; } -html.dark figure.shiki > div[role="region"] { - background-color: transparent !important; -} - /* Copy button — minimal ghost style */ figure.shiki button[aria-label="Copy Text"], figure.shiki button[aria-label="Copied Text"] { @@ -1690,7 +1728,7 @@ figure.shiki > div:has(> button[aria-label]) { .grid > a[data-card] p, .grid > a[data-card] div { color: var(--text-muted) !important; - font-size: 0.8125rem !important; + font-size: var(--text-small) !important; } /* Steps — lighter styling aligned with platform */ diff --git a/apps/docs/components/docs-layout/page-footer.tsx b/apps/docs/components/docs-layout/page-footer.tsx index 7031211fe84..2b4f289e811 100644 --- a/apps/docs/components/docs-layout/page-footer.tsx +++ b/apps/docs/components/docs-layout/page-footer.tsx @@ -12,81 +12,40 @@ interface PageFooterProps { next?: PageNeighbour } -const SOCIAL_LINKS = [ - { - href: 'https://x.com/simdotai', - label: 'X (Twitter)', - icon: 'M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z', - }, - { - href: 'https://github.com/simstudioai/sim', - label: 'GitHub', - icon: 'M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z', - }, - { - href: 'https://join.slack.com/t/sim-ott9864/shared_invite/zt-43lp8tc5v-0qrrqHGBKUsvQlpoouH~TA', - label: 'Slack', - icon: 'M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z', - }, -] as const - +/** + * Sequential page navigation. The destination name carries the meaning, so each + * card shows it alone with a direction chevron — the chevron already says which + * way you are going, and a "Previous"/"Next" label above the name only repeated + * that. Social links live in the site footer directly below this. + */ export function PageFooter({ previous, next }: PageFooterProps) { - return ( -
-
- - {(previous || next) && ( -
- {previous ? ( - - Previous - - - {previous.name} - - - ) : ( -
- )} + if (!previous && !next) return null - {next ? ( - - Next - - {next.name} - - - - ) : ( -
- )} -
+ return ( +
+ {previous ? ( + + + {previous.name} + + ) : ( +
)} -
- {SOCIAL_LINKS.map((link) => ( - - - - - - ))} -
+ {next ? ( + + {next.name} + + + ) : ( +
+ )}
) } diff --git a/apps/docs/components/docs-layout/sidebar-components.tsx b/apps/docs/components/docs-layout/sidebar-components.tsx index e646b071895..6a603fc856e 100644 --- a/apps/docs/components/docs-layout/sidebar-components.tsx +++ b/apps/docs/components/docs-layout/sidebar-components.tsx @@ -40,18 +40,29 @@ function isActive(url: string, pathname: string, nested = true): boolean { ) } +/** + * Rows mirror the app sidebar's chip pill: 30px tall, `rounded-lg`, `px-2`, 14px + * at normal weight, `--text-body` at rest AND when active — only the background + * moves, to `--surface-active`, then `--surface-6` when an active row is hovered. + * + * Height, horizontal padding, weight and color are additionally pinned in + * `global.css` (`html #nd-sidebar a…`), which needs `!important` to beat + * fumadocs' own sidebar rules and therefore also beats these utilities. Keep the + * two in step: the classes here describe the intent and drive the mobile layout, + * the stylesheet is what actually lands on desktop. + */ const ITEM_BASE = - 'flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-[var(--text-muted)] text-sm transition-colors hover:bg-[var(--surface-active)] hover:text-[var(--text-body)]' -const ITEM_ACTIVE_MOBILE = 'bg-[var(--surface-active)] font-medium text-[var(--text-primary)]' + 'flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-[var(--text-body)] text-sm transition-colors hover:bg-[var(--surface-active)]' +const ITEM_ACTIVE_MOBILE = 'bg-[var(--surface-active)]' const ITEM_DESKTOP = - 'lg:mb-[0.0625rem] lg:block lg:rounded-lg lg:px-2 lg:py-1.5 lg:font-normal lg:text-sm lg:leading-tight' + 'lg:mb-[0.0625rem] lg:block lg:rounded-lg lg:px-2 lg:font-normal lg:text-sm lg:leading-tight' const ITEM_TEXT = 'lg:text-[var(--text-body)]' const ITEM_HOVER = 'lg:hover:bg-[var(--surface-active)]' const ITEM_ACTIVE = 'lg:bg-[var(--surface-active)] lg:font-normal lg:text-[var(--text-body)] lg:hover:bg-[var(--surface-6)]' -const FOLDER_TEXT = 'lg:text-[var(--text-body)] lg:font-medium' +const FOLDER_TEXT = 'lg:text-[var(--text-body)] lg:font-normal' const FOLDER_HOVER = 'lg:hover:bg-[var(--surface-active)]' const FOLDER_ACTIVE = 'lg:bg-[var(--surface-active)] lg:text-[var(--text-body)] lg:hover:bg-[var(--surface-6)]' @@ -133,9 +144,9 @@ export function SidebarFolder({ item, children }: { item: Folder; children: Reac data-active={active} className={cn( 'flex flex-1 items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors', - 'text-[var(--text-muted)] hover:bg-[var(--surface-active)] hover:text-[var(--text-body)]', + 'text-[var(--text-body)] hover:bg-[var(--surface-active)]', active && ITEM_ACTIVE_MOBILE, - 'lg:block lg:flex-1 lg:rounded-lg lg:px-2 lg:py-1.5 lg:text-sm lg:leading-tight', + 'lg:block lg:flex-1 lg:rounded-lg lg:px-2 lg:text-sm lg:leading-tight', FOLDER_TEXT, !active && FOLDER_HOVER, active && FOLDER_ACTIVE @@ -161,8 +172,8 @@ export function SidebarFolder({ item, children }: { item: Folder; children: Reac onClick={toggleOpen} className={cn( 'flex flex-1 items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors', - 'text-[var(--text-muted)] hover:bg-[var(--surface-active)]', - 'lg:flex lg:w-full lg:cursor-pointer lg:items-center lg:justify-between lg:rounded-lg lg:px-2 lg:py-1.5 lg:text-left lg:text-sm lg:leading-tight', + 'text-[var(--text-body)] hover:bg-[var(--surface-active)]', + 'lg:flex lg:w-full lg:cursor-pointer lg:items-center lg:justify-between lg:rounded-lg lg:px-2 lg:text-left lg:text-sm lg:leading-tight', FOLDER_TEXT, FOLDER_HOVER )} @@ -181,9 +192,7 @@ export function SidebarFolder({ item, children }: { item: Folder; children: Reac >
{children}
-
    - {children} -
+
    {children}
)} @@ -191,25 +200,16 @@ export function SidebarFolder({ item, children }: { item: Folder; children: Reac ) } +/** + * Group label. Mirrors the app sidebar's section header: a 12px `--text-muted` + * row at normal weight in sentence case, with the group's 16px top gap carried + * by the label itself (the app's `SIDEBAR_SECTION_GAP_CLASS`). Groups are told + * apart by that gap alone — the app draws no rule between them. + */ export function SidebarSeparator({ item }: { item: Separator }) { return ( -
-
-
-
-
-
-

- {item.name} -

+
+

{item.name}

) } diff --git a/apps/docs/components/footer/footer.tsx b/apps/docs/components/footer/footer.tsx index 1c20bb53d1b..75896de0aed 100644 --- a/apps/docs/components/footer/footer.tsx +++ b/apps/docs/components/footer/footer.tsx @@ -21,7 +21,7 @@ interface FooterItem { const PRODUCT_LINKS: FooterItem[] = [ { label: 'Enterprise', href: `${SIM_SITE_URL}/enterprise`, external: true }, - { label: 'Mothership', href: '/mothership' }, + { label: 'Chat', href: '/chat' }, { label: 'Workflows', href: '/introduction' }, { label: 'Knowledge Base', href: '/knowledgebase' }, { label: 'Tables', href: '/tables' }, @@ -130,9 +130,16 @@ function FooterColumn({ title, items }: { title: string; items: FooterItem[] }) ) } +/** + * Site footer. + * + * `relative z-[22]` stacks it above the docs sidebar (z-20) and that sidebar's + * divider (z-21), both of which are pinned to the viewport, so the footer slides + * over them at the end of the page instead of being drawn through. + */ export function Footer() { return ( -