diff --git a/docs/app/global.css b/docs/app/global.css index 5f70726f78..2408ff7e87 100644 --- a/docs/app/global.css +++ b/docs/app/global.css @@ -132,8 +132,8 @@ article .prose { pre, code, pre code { - user-select: text !important; - -webkit-user-select: text !important; + user-select: text; + -webkit-user-select: text; } /* Rebrand: SEED Callout은 MDX children(코드블록/Tabs/문단)을 인라인 description(span)으로 받는데, @@ -159,31 +159,17 @@ pre code { align-items: flex-start; } -/* Rebrand: brand-tinted text selection — the same lime highlight everywhere so light - and dark modes read as one brand. Lime is a light color, so on light surfaces the - inherited dark text sits on it fine (background only). Unlayered so it wins over - fumadocs/Tailwind. The colors live on :root so the search-result highlight can - reuse the same lime — and, as :root vars, they resolve inside the portaled search dialog - (where the surface-scoped selection selectors below never match). */ +/* Rebrand: brand-tinted text selection — the same dark-on-lime treatment everywhere so + light and dark surfaces read as one brand. Setting both colors also keeps links and + inline code from carrying their resting text color into the selected state. Unlayered + so it wins over fumadocs/Tailwind. The colors live on :root so the search-result + highlight can reuse the same lime, including inside the portaled search dialog. */ :root { --selection-bg: #ccffa3; --selection-fg: #212124; } ::selection { background-color: var(--selection-bg); -} - -/* Dark surfaces — docs dark mode + the landing's dark sections (both carry light text). - Keep the lime highlight but flip the SELECTED text dark, mirroring light mode's - dark-on-lime, so the lime stays legible instead of light-on-light. Landing dark - sections are enumerated by the section ids the landing already uses for scroll/tone - logic; hero/bento and the orange footer (dark text) fall through to the base above. */ -.dark ::selection, -#intro ::selection, -#values ::selection, -#showcase ::selection, -#blog ::selection { - background-color: var(--selection-bg); color: var(--selection-fg); } diff --git a/docs/components/changelog-entry-item.tsx b/docs/components/changelog-entry-item.tsx index 6d665cd106..8918f18d46 100644 --- a/docs/components/changelog-entry-item.tsx +++ b/docs/components/changelog-entry-item.tsx @@ -1,8 +1,8 @@ import type { ChangelogEntry } from "@/lib/parse-changelog"; import { SeedClientCodeBlock } from "@/components/codeblock/client-code-block"; +import { INLINE_CODE_DESCENDANT_CLASS_NAME } from "./inline-code"; -const PROSE_CLASS = - "prose prose-sm dark:prose-invert max-w-none min-w-0 break-words prose-p:my-0 prose-li:my-0.5 prose-a:text-fd-primary prose-code:text-fd-primary prose-code:bg-fd-muted prose-code:px-1 prose-code:py-0.5 prose-code:rounded prose-code:text-xs [&>*:last-child]:mb-0 [&_a]:break-words [&_code]:break-words"; +const PROSE_CLASS = `prose prose-sm dark:prose-invert max-w-none min-w-0 break-words prose-p:my-0 prose-li:my-0.5 prose-a:text-fd-primary [&>*:last-child]:mb-0 [&_a]:break-words ${INLINE_CODE_DESCENDANT_CLASS_NAME}`; export function ChangelogEntryItem({ entry, diff --git a/docs/components/inline-code.tsx b/docs/components/inline-code.tsx new file mode 100644 index 0000000000..cd8ba051ef --- /dev/null +++ b/docs/components/inline-code.tsx @@ -0,0 +1,37 @@ +import clsx from "clsx"; +import { Children, cloneElement, isValidElement, type ComponentProps, type ReactNode } from "react"; + +export const INLINE_CODE_CLASS_NAME = + "rounded-r1 border-0 bg-bg-transparent-selected px-0 py-x0_5 font-mono text-[0.92em] font-medium leading-[inherit] wrap-anywhere [box-shadow:2px_0_0_var(--seed-color-bg-transparent-selected),-2px_0_0_var(--seed-color-bg-transparent-selected)] [box-decoration-break:clone] [-webkit-box-decoration-break:clone]"; + +// Changelog Markdown is sanitized HTML rather than React nodes, so it needs the same +// treatment expressed as descendant variants on its prose container. +export const INLINE_CODE_DESCENDANT_CLASS_NAME = + "[&_code]:rounded-r1 [&_code]:border-0 [&_code]:bg-bg-transparent-selected [&_code]:px-0 [&_code]:py-x0_5 [&_code]:font-mono [&_code]:text-[0.92em] [&_code]:font-medium [&_code]:leading-[inherit] [&_code]:wrap-anywhere [&_code]:[box-shadow:2px_0_0_var(--seed-color-bg-transparent-selected),-2px_0_0_var(--seed-color-bg-transparent-selected)] [&_code]:[box-decoration-break:clone] [&_code]:[-webkit-box-decoration-break:clone]"; + +export function InlineCode({ className, ...props }: ComponentProps<"code">) { + return ( + + ); +} + +export function renderInlineCode(node: ReactNode): ReactNode { + return Children.map(node, (child) => { + if (!isValidElement<{ children?: ReactNode }>(child)) return child; + + if (child.type === "code") { + return )} />; + } + + if (child.props.children === undefined) return child; + + return cloneElement(child, undefined, renderInlineCode(child.props.children)); + }); +} diff --git a/docs/components/mdx-components.tsx b/docs/components/mdx-components.tsx index fe3516da18..2055d9f5c6 100644 --- a/docs/components/mdx-components.tsx +++ b/docs/components/mdx-components.tsx @@ -41,6 +41,7 @@ import { DontImage } from "./guideline/dont-image"; import { Image } from "./guideline/image"; import { IconComponent, IconTerminal } from "./icons"; import { IconLibrary } from "./iconography/icon-library-lazy"; +import { InlineCode } from "./inline-code"; import { ColorMigrationIndex } from "./migration/color-migration-index"; import { IconographyMigrationIndex, V2Icon, V2IconColor, V3Icon } from "./migration/lazy"; import { TypographyMigrationIndex } from "./migration/typography-migration-index"; @@ -51,6 +52,8 @@ import { TableRoot } from "./table"; export const mdxComponents: MDXComponents = { ...defaultMdxComponents, + code: InlineCode, + // All fenced code blocks (```) render as the SEED "Codeblock" (Shiki colors preserved). // Inside a tabbed code card (`CodeBlockTabs`), SeedCodeBlockAuto renders the code bare. pre: ({ title, icon, children, ...props }: ComponentProps<"pre"> & { icon?: ReactNode }) => ( diff --git a/docs/components/table-of-contents.tsx b/docs/components/table-of-contents.tsx index 5d50a23cb1..79b098ce5c 100644 --- a/docs/components/table-of-contents.tsx +++ b/docs/components/table-of-contents.tsx @@ -13,6 +13,7 @@ import { type ReactNode, } from "react"; import { twMerge as cn } from "tailwind-merge"; +import { renderInlineCode } from "./inline-code"; import { buildTocTrackGeometry, getActiveTrackClip, @@ -196,7 +197,7 @@ function TocList({ list, onItemClick, variant }: TocListProps) { {item._step} ) : null} - {item.title} + {renderInlineCode(item.title)} ); })}