diff --git a/frontend/src/landing/app/docs/[[...slug]]/page.tsx b/frontend/src/landing/app/docs/[[...slug]]/page.tsx index b00e971cd..cc0ab48a8 100644 --- a/frontend/src/landing/app/docs/[[...slug]]/page.tsx +++ b/frontend/src/landing/app/docs/[[...slug]]/page.tsx @@ -20,8 +20,8 @@ export default async function DocsSlugPage({ params }: PageProps) { toc={page.data.toc} full={page.data.full} tableOfContent={{ - style: "clerk", - single: false, + style: "normal", + single: true, }} editOnGithub={{ owner: "ComposioHQ", diff --git a/frontend/src/landing/app/docs/docs.css b/frontend/src/landing/app/docs/docs.css index 88aebd9c4..67442594f 100644 --- a/frontend/src/landing/app/docs/docs.css +++ b/frontend/src/landing/app/docs/docs.css @@ -140,6 +140,11 @@ color: var(--docs-accent) !important; } +#nd-toc [class*="bg-fd-primary"] { + background-color: var(--docs-accent) !important; + box-shadow: 0 0 18px rgba(130, 170, 255, 0.35); +} + /* Breadcrumb: neutral gray */ #nd-page nav a, #nd-page [aria-label="breadcrumb"] a { @@ -180,7 +185,7 @@ } /* ═══════════════════════════════════════════════════════════════════════════ - 2. TYPOGRAPHY — Geist 13px body, JetBrains Mono code (dashboard match) + 2. TYPOGRAPHY — readable technical docs, compact chrome ═══════════════════════════════════════════════════════════════════════════ */ #nd-docs-layout { @@ -190,27 +195,42 @@ system-ui, -apple-system, sans-serif; - font-size: 13px; - letter-spacing: -0.011em; + font-size: 16px; + line-height: 1.7; + letter-spacing: 0; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } +#nd-page { + font-size: 16px; + line-height: 1.7; +} + +#nd-page .prose { + color: var(--color-text-secondary); + font-size: 16px; + line-height: 1.7; + letter-spacing: 0; +} + #nd-docs-layout code, #nd-docs-layout kbd, #nd-docs-layout pre { font-family: var(--font-jetbrains-mono), ui-monospace, "SFMono-Regular", monospace; } -/* Sidebar — smaller text like dashboard */ +/* Sidebar — compact app chrome, not body typography */ #nd-sidebar { font-size: 12.5px; + letter-spacing: 0; } /* TOC — compact */ #nd-toc, #nd-tocnav { font-size: 11.5px; + line-height: 1.55; } /* ═══════════════════════════════════════════════════════════════════════════ @@ -220,26 +240,44 @@ #nd-docs-layout .prose h1 { color: var(--color-text-primary); font-weight: 700; - font-size: 1.65em; + font-size: clamp(2rem, 3vw, 2.75rem); + line-height: 1.08; letter-spacing: -0.02em; } #nd-docs-layout .prose h2 { color: var(--color-text-primary); - font-weight: 680; - font-size: 1.3em; - letter-spacing: -0.015em; + font-weight: 660; + font-size: clamp(1.35rem, 2vw, 1.65rem); + line-height: 1.22; + letter-spacing: -0.01em; } #nd-docs-layout .prose h3 { color: var(--color-text-primary); font-weight: 640; - font-size: 1.1em; + font-size: 1.125rem; + line-height: 1.32; + letter-spacing: 0; } #nd-docs-layout .prose h4 { color: var(--color-text-primary); font-weight: 620; + letter-spacing: 0; +} + +#nd-docs-layout .prose p, +#nd-docs-layout .prose li { + color: var(--color-text-secondary); + font-size: 1rem; + line-height: 1.74; + letter-spacing: 0; +} + +#nd-docs-layout .prose strong { + color: var(--color-text-primary); + font-weight: 650; } /* Heading anchors — strip card border/bg */ @@ -266,7 +304,8 @@ /* Tables — dashboard style: uppercase headers, dense */ #nd-docs-layout .prose table { - font-size: 12.5px; + font-size: 14px; + line-height: 1.6; } #nd-docs-layout .prose th { @@ -285,13 +324,13 @@ /* Inline code */ #nd-docs-layout :not(pre) > code { - font-size: 0.85em; - padding: 0.12em 0.4em; - border-radius: 4px; + font-size: 0.84em; + padding: 0.16em 0.42em; + border-radius: 5px; background-color: var(--color-bg-subtle); border: 1px solid var(--color-border-subtle); color: var(--docs-accent); - font-weight: 450; + font-weight: 520; } /* No underlines in sidebar (desktop + mobile), TOC, or nav */ diff --git a/frontend/src/landing/app/docs/layout.tsx b/frontend/src/landing/app/docs/layout.tsx index f4aeb1001..363dade29 100644 --- a/frontend/src/landing/app/docs/layout.tsx +++ b/frontend/src/landing/app/docs/layout.tsx @@ -4,6 +4,7 @@ import { DocsLayout } from "fumadocs-ui/layouts/docs"; import { RootProvider } from "fumadocs-ui/provider"; import type { LinkItemType } from "fumadocs-ui/layouts/shared"; import { source } from "@/lib/source"; +import { DocsClipboardFix } from "@/components/docs/DocsClipboardFix"; import "./docs.css"; function GithubIcon({ size = 16 }: { size?: number } = {}) { @@ -76,10 +77,11 @@ async function GitHubStars() { export default function Layout({ children }: { children: ReactNode }) { return ( - + @@ -91,7 +93,7 @@ export default function Layout({ children }: { children: ReactNode }) { height={22} className="h-[22px] w-[22px] rounded-[5px] object-cover" /> - AO + Agent Orchestrator ), }} @@ -112,6 +114,7 @@ export default function Layout({ children }: { children: ReactNode }) { ), }} > + {children} diff --git a/frontend/src/landing/components/docs/DocsClipboardFix.tsx b/frontend/src/landing/components/docs/DocsClipboardFix.tsx new file mode 100644 index 000000000..5ab90d9c7 --- /dev/null +++ b/frontend/src/landing/components/docs/DocsClipboardFix.tsx @@ -0,0 +1,103 @@ +"use client"; + +import { useEffect } from "react"; + +async function writeClipboard(text: string) { + if (!text) return false; + + if (navigator.clipboard?.writeText) { + try { + await navigator.clipboard.writeText(text); + return true; + } catch { + // Fall through to execCommand for browsers that block async clipboard. + } + } + + const textarea = document.createElement("textarea"); + textarea.value = text; + textarea.setAttribute("readonly", ""); + textarea.style.position = "fixed"; + textarea.style.left = "-9999px"; + textarea.style.top = "0"; + document.body.appendChild(textarea); + + const selection = document.getSelection(); + const selectedRange = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null; + + textarea.focus(); + textarea.select(); + + let copied = false; + try { + copied = document.execCommand("copy"); + } catch { + copied = false; + } + + document.body.removeChild(textarea); + + if (selectedRange && selection) { + selection.removeAllRanges(); + selection.addRange(selectedRange); + } + + return copied; +} + +function getCodeText(button: HTMLButtonElement) { + const figure = button.closest("figure"); + const pre = figure?.querySelector("pre"); + if (!pre) return ""; + + const clone = pre.cloneNode(true) as HTMLElement; + clone.querySelectorAll(".nd-copy-ignore").forEach((node) => { + node.replaceWith("\n"); + }); + return clone.textContent ?? ""; +} + +function getLinkText(button: HTMLButtonElement) { + const header = button.closest("h1,h2,h3,h4,h5,h6"); + const id = header?.id; + if (!id) return ""; + + const url = new URL(window.location.href); + url.hash = id; + return url.toString(); +} + +export function DocsClipboardFix() { + useEffect(() => { + const onClick = (event: MouseEvent) => { + const button = (event.target as Element | null)?.closest("button"); + if (!(button instanceof HTMLButtonElement)) return; + + const label = button.getAttribute("aria-label") ?? ""; + const isCodeCopy = label === "Copy Text" || label === "Copied Text"; + const isLinkCopy = label === "Copy Link"; + if (!isCodeCopy && !isLinkCopy) return; + + const text = isCodeCopy ? getCodeText(button) : getLinkText(button); + if (!text) return; + + event.preventDefault(); + event.stopPropagation(); + + void writeClipboard(text).then((copied) => { + if (!copied) return; + button.dataset.checked = "true"; + button.setAttribute("aria-label", isCodeCopy ? "Copied Text" : "Copied Link"); + window.setTimeout(() => { + delete button.dataset.checked; + button.setAttribute("aria-label", isCodeCopy ? "Copy Text" : "Copy Link"); + }, 1500); + }); + }; + + document.addEventListener("click", onClick, true); + return () => document.removeEventListener("click", onClick, true); + }, []); + + return null; +}