diff --git a/docs-site/app/global.css b/docs-site/app/global.css index c86e84b2..e7e2c5b2 100644 --- a/docs-site/app/global.css +++ b/docs-site/app/global.css @@ -231,57 +231,10 @@ figure[data-rehype-pretty-code-figure]:has(.ktx-code) { margin: 0; } -/* ── Mode A: Terminal ─────────────────────── */ -.ktx-code-terminal { - background: #0c1417; - border: 1px solid rgba(255, 255, 255, 0.08); - color: #c8c3bc; - box-shadow: - 0 1px 2px rgba(0, 0, 0, 0.1), - 0 12px 32px -16px rgba(0, 0, 0, 0.3); -} - -.ktx-code-terminal:hover { - border-color: rgba(34, 211, 238, 0.2); - box-shadow: - 0 1px 2px rgba(0, 0, 0, 0.1), - 0 14px 32px -12px rgba(34, 211, 238, 0.18); -} - -.ktx-code-terminal-head { - display: flex; - align-items: center; - gap: 6px; - padding: 10px 12px; - border-bottom: 1px solid rgba(255, 255, 255, 0.06); - background: linear-gradient(180deg, rgba(255, 255, 255, 0.03), transparent); -} - -.ktx-tl-dot { - width: 11px; - height: 11px; - border-radius: 999px; - flex-shrink: 0; -} - -.ktx-code-terminal-label { - margin-left: 8px; - font-size: 11px; - font-weight: 500; - letter-spacing: 0.02em; - color: rgba(255, 255, 255, 0.4); -} - -.ktx-code-body-terminal { - background: transparent !important; - color: #c8c3bc !important; -} - /* ── Mode D: Output preview (wizard prompts, status output) ── */ .ktx-code-output { background: var(--color-fd-muted); border: 1px solid var(--color-fd-border); - border-left: 3px solid color-mix(in oklch, var(--color-fd-primary) 50%, var(--color-fd-border)); position: relative; box-shadow: 0 1px 2px rgba(27, 27, 24, 0.02); } @@ -289,17 +242,14 @@ figure[data-rehype-pretty-code-figure]:has(.ktx-code) { .dark .ktx-code-output { background: #111a1e; border-color: rgba(255, 255, 255, 0.05); - border-left-color: rgba(34, 211, 238, 0.25); } .ktx-code-output:hover { border-color: color-mix(in oklch, var(--color-fd-primary) 25%, var(--color-fd-border)); - border-left-color: var(--color-fd-primary); } .dark .ktx-code-output:hover { border-color: rgba(255, 255, 255, 0.08); - border-left-color: rgba(34, 211, 238, 0.45); } .ktx-code-output-label { @@ -460,26 +410,6 @@ figure[data-rehype-pretty-code-figure]:has(.ktx-code) { border-color: rgba(34, 211, 238, 0.2); } -.ktx-code-minimal-lang { - position: absolute; - top: 8px; - left: 14px; - font-size: 10px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.05em; - color: var(--color-fd-muted-foreground); - font-family: var(--font-display), var(--font-sans), sans-serif; - opacity: 0; - transition: opacity 0.2s var(--ktx-ease); - pointer-events: none; - z-index: 1; -} - -.ktx-code-minimal:hover .ktx-code-minimal-lang { - opacity: 0.5; -} - .ktx-code-minimal-copy { position: absolute !important; top: 7px !important; @@ -1073,8 +1003,7 @@ body::after { .pill-badge .pill-dot { animation: none; } .card-lift { transition: none; } .ktx-code, - .ktx-code-minimal-copy, - .ktx-code-minimal-lang { + .ktx-code-minimal-copy { transition: none; } #nd-sidebar div[data-state]:not([class]) > button[data-state] svg { diff --git a/docs-site/components/code-block.tsx b/docs-site/components/code-block.tsx index 7d6a22af..9c9d71ec 100644 --- a/docs-site/components/code-block.tsx +++ b/docs-site/components/code-block.tsx @@ -13,7 +13,7 @@ type Props = ComponentPropsWithoutRef<"pre"> & { "data-language"?: string; }; -const TERMINAL_LANGS = new Set(["bash", "sh", "shell", "zsh"]); +const OUTPUT_LANGS = new Set(["text", "plain", "plaintext", "console", "output"]); const WIZARD_GLYPHS = /^\s*[◆◇◯◐○●]/; function extractText(node: ReactNode): string { @@ -27,6 +27,33 @@ function extractText(node: ReactNode): string { return ""; } +function findLanguageInNode(node: ReactNode): string | null { + if (!isValidElement(node)) return null; + const props = (node as ReactElement<{ + className?: string; + "data-language"?: string; + children?: ReactNode; + }>).props; + + const dataLang = props["data-language"]; + if (typeof dataLang === "string" && dataLang) return dataLang; + + const className = typeof props.className === "string" ? props.className : ""; + const m = className.match(/language-([\w-]+)/); + if (m) return m[1]; + + const children = props.children; + if (Array.isArray(children)) { + for (const child of children) { + const found = findLanguageInNode(child); + if (found) return found; + } + } else if (children) { + return findLanguageInNode(children); + } + return null; +} + function detectLanguage(props: Props, children: ReactNode): string | null { const dataLang = props["data-language"]; if (typeof dataLang === "string" && dataLang) return dataLang; @@ -35,14 +62,7 @@ function detectLanguage(props: Props, children: ReactNode): string | null { const m = className.match(/language-([\w-]+)/); if (m) return m[1]; - if (isValidElement(children)) { - const childProps = (children as ReactElement<{ className?: string }>).props; - const childClass = typeof childProps.className === "string" ? childProps.className : ""; - const cm = childClass.match(/language-([\w-]+)/); - if (cm) return cm[1]; - } - - return null; + return findLanguageInNode(children); } export function CodeBlock(props: Props) { @@ -50,32 +70,11 @@ export function CodeBlock(props: Props) { const language = detectLanguage(props, children); const codeText = extractText(children); - const isTerminal = language !== null && TERMINAL_LANGS.has(language); - const isOutput = !isTerminal && WIZARD_GLYPHS.test(codeText); const hasTitle = typeof title === "string" && title.length > 0; - - // Mode A - Terminal (commands the user types) - if (isTerminal) { - return ( -
-
- - - - - {hasTitle ? title : "zsh"} - - -
-
-          {children}
-        
-
- ); - } + const isOutput = + !hasTitle && + (WIZARD_GLYPHS.test(codeText) || + (language !== null && OUTPUT_LANGS.has(language))); // Mode D - Output preview (wizard prompts, terminal output) if (isOutput) { @@ -110,7 +109,6 @@ export function CodeBlock(props: Props) { // Mode C - Minimal default return (
- {language && {language}}
         {children}
diff --git a/docs-site/components/copy-button.tsx b/docs-site/components/copy-button.tsx
index a3d01a1a..c0dd1f31 100644
--- a/docs-site/components/copy-button.tsx
+++ b/docs-site/components/copy-button.tsx
@@ -25,7 +25,7 @@ export function CopyButton({ text, className = "" }: Props) {
       type="button"
       onClick={onClick}
       aria-label={copied ? "Copied" : "Copy code"}
-      className={`inline-flex items-center justify-center w-9 h-9 rounded-md transition-all hover:bg-white/5 ${className}`}
+      className={`inline-flex items-center justify-center w-9 h-9 rounded-md transition-all hover:bg-fd-muted ${className}`}
     >
       {copied ? (