mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
improvement(docs): restructure sidebar, align chrome, rename Mothership to Chat (#6296)
Sidebar: 11 separator groups become 5, with each module a collapsible folder that auto-opens on the active page. 61 always-visible rows drop to 16. Groups mirror the app's own nav (Chats/Workspace/Workflows) rather than inventing a taxonomy; Enterprise and Self-Hosting are hoisted out of Platform. Chrome: register the `hover-hover` variant, without which every @sim/emcn hover state silently compiled to nothing; restore the sidebar's Geist font stack; add 11 emcn tokens that were falling back to currentColor; adopt the named type scale; align row geometry, hover tokens and group labels with the app. Rename: mothership/ -> chat/ with redirects for the old URLs. Asset paths, the @mothership.sim.ai domain and the `mothership` log-trigger enum value are deliberately left alone -- they are CDN objects, a real domain, and a live product value. Also removes the page-type badge, drops the "Next" heading from the ToC, and lets FAQ rows open independently so expanding one no longer shifts the page.
This commit is contained in:
@@ -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<string> = 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<string, string> = {
|
||||
en: 'en_US',
|
||||
es: 'es_ES',
|
||||
@@ -171,7 +185,7 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l
|
||||
breadcrumb={breadcrumbs}
|
||||
/>
|
||||
<DocsPage
|
||||
toc={data.toc}
|
||||
toc={data.toc.filter(isContentHeading)}
|
||||
breadcrumb={{
|
||||
enabled: false,
|
||||
}}
|
||||
@@ -218,7 +232,7 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l
|
||||
breadcrumb={breadcrumbs}
|
||||
/>
|
||||
<DocsPage
|
||||
toc={data.toc}
|
||||
toc={data.toc.filter(isContentHeading)}
|
||||
full={data.full || isAcademy}
|
||||
breadcrumb={{
|
||||
enabled: false,
|
||||
@@ -244,7 +258,6 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l
|
||||
</div>
|
||||
<PageNavigationArrows previous={neighbours?.previous} next={neighbours?.next} />
|
||||
</div>
|
||||
{data.pageType && <PageTypeBadge type={data.pageType} className='mb-3' />}
|
||||
<DocsTitle className='mb-2'>{data.title}</DocsTitle>
|
||||
</div>
|
||||
<DocsBody>
|
||||
|
||||
+73
-49
@@ -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 */
|
||||
@@ -358,10 +389,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 +417,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 +464,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 +741,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 +783,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 +945,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 +957,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 +1024,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 +1073,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 +1253,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 +1263,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 +1281,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 +1323,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 +1340,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 +1352,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 +1362,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 +1374,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 +1426,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 +1437,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 +1598,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 +1642,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 +1714,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 */
|
||||
|
||||
Reference in New Issue
Block a user