From 2d01298ed13b9c1dd59716a37ed772fe5ca4c0b3 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Tue, 4 Nov 2025 14:11:33 +0000 Subject: [PATCH] Improve layout Signed-off-by: Charles de Dreuille --- docs-ui/src/app/components/[slug]/page.tsx | 4 +- docs-ui/src/app/layout.module.css | 28 +++- docs-ui/src/app/layout.tsx | 10 +- docs-ui/src/components/CodeBlock/index.tsx | 19 ++- .../components/CodeBlock/styles.module.css | 20 ++- .../src/components/Snippet/styles.module.css | 4 +- .../TableOfContents.module.css | 93 ++++++++++++ .../TableOfContents/TableOfContents.tsx | 132 ++++++++++++++++++ .../src/components/TableOfContents/index.ts | 1 + .../src/content/{components => }/avatar.mdx | 0 .../content/{components => }/avatar.props.ts | 0 docs-ui/src/content/{components => }/box.mdx | 0 .../src/content/{components => }/box.props.ts | 0 .../content/{components => }/button-icon.mdx | 0 .../{components => }/button-icon.props.ts | 0 .../content/{components => }/button-link.mdx | 0 .../{components => }/button-link.props.ts | 4 +- .../src/content/{components => }/button.mdx | 0 .../content/{components => }/button.props.ts | 4 +- docs-ui/src/content/{components => }/card.mdx | 0 .../content/{components => }/card.props.ts | 0 .../src/content/{components => }/checkbox.mdx | 0 .../{components => }/checkbox.props.ts | 0 .../content/{components => }/collapsible.mdx | 0 .../{components => }/collapsible.props.ts | 0 .../content/{components => }/container.mdx | 0 .../{components => }/container.props.ts | 0 .../src/content/{components => }/dialog.mdx | 0 .../content/{components => }/dialog.props.ts | 0 docs-ui/src/content/{components => }/flex.mdx | 0 .../content/{components => }/flex.props.ts | 0 docs-ui/src/content/{components => }/grid.mdx | 0 .../content/{components => }/grid.props.ts | 0 .../content/{components => }/header-page.mdx | 0 .../{components => }/header-page.props.ts | 0 .../src/content/{components => }/header.mdx | 0 .../content/{components => }/header.props.ts | 0 docs-ui/src/content/{components => }/link.mdx | 0 .../content/{components => }/link.props.ts | 0 docs-ui/src/content/{components => }/menu.mdx | 0 .../content/{components => }/menu.props.ts | 0 .../{components => }/password-field.mdx | 0 .../{components => }/password-field.props.ts | 0 .../content/{components => }/radio-group.mdx | 0 .../{components => }/radio-group.props.ts | 0 .../content/{components => }/search-field.mdx | 0 .../{components => }/search-field.props.ts | 0 .../src/content/{components => }/select.mdx | 0 .../content/{components => }/select.props.ts | 0 .../src/content/{components => }/skeleton.mdx | 0 .../{components => }/skeleton.props.ts | 0 .../src/content/{components => }/switch.mdx | 0 .../content/{components => }/switch.props.ts | 0 .../src/content/{components => }/table.mdx | 0 .../content/{components => }/table.props.ts | 2 +- docs-ui/src/content/{components => }/tabs.mdx | 0 .../content/{components => }/tabs.props.ts | 0 .../content/{components => }/tag-group.mdx | 0 .../{components => }/tag-group.props.ts | 0 .../content/{components => }/text-field.mdx | 0 .../{components => }/text-field.props.ts | 0 docs-ui/src/content/{components => }/text.mdx | 0 .../content/{components => }/text.props.ts | 0 .../src/content/{components => }/tooltip.mdx | 0 .../content/{components => }/tooltip.props.ts | 0 .../{components => }/visually-hidden.mdx | 0 .../{components => }/visually-hidden.props.ts | 0 docs-ui/src/css/globals.css | 4 + docs-ui/src/css/mdx.module.css | 24 ++++ docs-ui/src/mdx-components.tsx | 55 +++++++- docs-ui/src/utils/data.ts | 13 -- 71 files changed, 372 insertions(+), 45 deletions(-) create mode 100644 docs-ui/src/components/TableOfContents/TableOfContents.module.css create mode 100644 docs-ui/src/components/TableOfContents/TableOfContents.tsx create mode 100644 docs-ui/src/components/TableOfContents/index.ts rename docs-ui/src/content/{components => }/avatar.mdx (100%) rename docs-ui/src/content/{components => }/avatar.props.ts (100%) rename docs-ui/src/content/{components => }/box.mdx (100%) rename docs-ui/src/content/{components => }/box.props.ts (100%) rename docs-ui/src/content/{components => }/button-icon.mdx (100%) rename docs-ui/src/content/{components => }/button-icon.props.ts (100%) rename docs-ui/src/content/{components => }/button-link.mdx (100%) rename docs-ui/src/content/{components => }/button-link.props.ts (94%) rename docs-ui/src/content/{components => }/button.mdx (100%) rename docs-ui/src/content/{components => }/button.props.ts (94%) rename docs-ui/src/content/{components => }/card.mdx (100%) rename docs-ui/src/content/{components => }/card.props.ts (100%) rename docs-ui/src/content/{components => }/checkbox.mdx (100%) rename docs-ui/src/content/{components => }/checkbox.props.ts (100%) rename docs-ui/src/content/{components => }/collapsible.mdx (100%) rename docs-ui/src/content/{components => }/collapsible.props.ts (100%) rename docs-ui/src/content/{components => }/container.mdx (100%) rename docs-ui/src/content/{components => }/container.props.ts (100%) rename docs-ui/src/content/{components => }/dialog.mdx (100%) rename docs-ui/src/content/{components => }/dialog.props.ts (100%) rename docs-ui/src/content/{components => }/flex.mdx (100%) rename docs-ui/src/content/{components => }/flex.props.ts (100%) rename docs-ui/src/content/{components => }/grid.mdx (100%) rename docs-ui/src/content/{components => }/grid.props.ts (100%) rename docs-ui/src/content/{components => }/header-page.mdx (100%) rename docs-ui/src/content/{components => }/header-page.props.ts (100%) rename docs-ui/src/content/{components => }/header.mdx (100%) rename docs-ui/src/content/{components => }/header.props.ts (100%) rename docs-ui/src/content/{components => }/link.mdx (100%) rename docs-ui/src/content/{components => }/link.props.ts (100%) rename docs-ui/src/content/{components => }/menu.mdx (100%) rename docs-ui/src/content/{components => }/menu.props.ts (100%) rename docs-ui/src/content/{components => }/password-field.mdx (100%) rename docs-ui/src/content/{components => }/password-field.props.ts (100%) rename docs-ui/src/content/{components => }/radio-group.mdx (100%) rename docs-ui/src/content/{components => }/radio-group.props.ts (100%) rename docs-ui/src/content/{components => }/search-field.mdx (100%) rename docs-ui/src/content/{components => }/search-field.props.ts (100%) rename docs-ui/src/content/{components => }/select.mdx (100%) rename docs-ui/src/content/{components => }/select.props.ts (100%) rename docs-ui/src/content/{components => }/skeleton.mdx (100%) rename docs-ui/src/content/{components => }/skeleton.props.ts (100%) rename docs-ui/src/content/{components => }/switch.mdx (100%) rename docs-ui/src/content/{components => }/switch.props.ts (100%) rename docs-ui/src/content/{components => }/table.mdx (100%) rename docs-ui/src/content/{components => }/table.props.ts (99%) rename docs-ui/src/content/{components => }/tabs.mdx (100%) rename docs-ui/src/content/{components => }/tabs.props.ts (100%) rename docs-ui/src/content/{components => }/tag-group.mdx (100%) rename docs-ui/src/content/{components => }/tag-group.props.ts (100%) rename docs-ui/src/content/{components => }/text-field.mdx (100%) rename docs-ui/src/content/{components => }/text-field.props.ts (100%) rename docs-ui/src/content/{components => }/text.mdx (100%) rename docs-ui/src/content/{components => }/text.props.ts (100%) rename docs-ui/src/content/{components => }/tooltip.mdx (100%) rename docs-ui/src/content/{components => }/tooltip.props.ts (100%) rename docs-ui/src/content/{components => }/visually-hidden.mdx (100%) rename docs-ui/src/content/{components => }/visually-hidden.props.ts (100%) diff --git a/docs-ui/src/app/components/[slug]/page.tsx b/docs-ui/src/app/components/[slug]/page.tsx index d6f98c8f93..1422334471 100644 --- a/docs-ui/src/app/components/[slug]/page.tsx +++ b/docs-ui/src/app/components/[slug]/page.tsx @@ -7,9 +7,7 @@ export default async function Page({ }) { const { slug } = await params; - const { default: Component } = await import( - `@/content/components/${slug}.mdx` - ); + const { default: Component } = await import(`@/content/${slug}.mdx`); return ; } diff --git a/docs-ui/src/app/layout.module.css b/docs-ui/src/app/layout.module.css index 5c1d113a98..df89f02283 100644 --- a/docs-ui/src/app/layout.module.css +++ b/docs-ui/src/app/layout.module.css @@ -5,10 +5,28 @@ padding-inline: 24px; } -.content { +.contentWrapper { + display: flex; width: 100%; max-width: 1200px; margin: 0 auto; + justify-content: center; + flex-direction: column; +} + +.content { + display: flex; + gap: 40px; +} + +.contentInner { + flex: 1; + min-width: 0; + overflow-x: hidden; +} + +.toc { + display: none; } @media (min-width: 768px) { @@ -18,3 +36,11 @@ margin-right: 40px; } } + +@media (min-width: 1280px) { + .toc { + display: block; + width: 240px; + flex-shrink: 0; + } +} diff --git a/docs-ui/src/app/layout.tsx b/docs-ui/src/app/layout.tsx index 2bafa97d32..738a995795 100644 --- a/docs-ui/src/app/layout.tsx +++ b/docs-ui/src/app/layout.tsx @@ -4,6 +4,7 @@ import { Toolbar } from '@/components/Toolbar'; import { StickyHeader } from '../components/StickyHeader/StickyHeader'; import { Providers } from './providers'; import { CustomTheme } from '@/components/CustomTheme'; +import { TableOfContents } from '@/components/TableOfContents'; import styles from './layout.module.css'; import '../css/globals.css'; @@ -53,9 +54,14 @@ export default async function RootLayout({ {/* */}
-
+
- {children} +
+
{children}
+ +
diff --git a/docs-ui/src/components/CodeBlock/index.tsx b/docs-ui/src/components/CodeBlock/index.tsx index 96fdb6bea5..1467bca465 100644 --- a/docs-ui/src/components/CodeBlock/index.tsx +++ b/docs-ui/src/components/CodeBlock/index.tsx @@ -9,15 +9,24 @@ export interface CodeBlockProps { code?: string; } -export async function CodeBlock({ lang = 'tsx', title, code }: CodeBlockProps) { - const out = await codeToHtml(code || '', { - lang: lang, +export async function CodeBlock(props: CodeBlockProps) { + const { lang = 'tsx', title, code } = props; + let out = await codeToHtml(code || '', { + lang, + transformers: [transformerNotationDiff({ matchAlgorithm: 'v3' })], themes: { - light: 'min-light', + light: 'github-dark', dark: 'min-dark', }, - transformers: [transformerNotationDiff({ matchAlgorithm: 'v3' })], }); + // Remove background-color from the pre tag to use our theme colors + out = out.replace( + /style="([^"]*?)background-color:[^;]+;?([^"]*?)"/g, + 'style="$1$2"', + ); + // Clean up empty style attributes + out = out.replace(/style=""\s?/g, ''); + return ; } diff --git a/docs-ui/src/components/CodeBlock/styles.module.css b/docs-ui/src/components/CodeBlock/styles.module.css index d786140482..30e1837f60 100644 --- a/docs-ui/src/components/CodeBlock/styles.module.css +++ b/docs-ui/src/components/CodeBlock/styles.module.css @@ -1,33 +1,29 @@ .codeBlock { - border-radius: 4px; - border: 1px solid var(--border); + border-radius: 8px; position: relative; background: transparent; overflow-x: auto; font-family: var(--font-mono); - background-color: #fff; + background-color: var(--code-bg); margin-bottom: 1rem; } -[data-theme-mode='dark'] .codeBlock { - background-color: #121212; -} - .title { - border-bottom: 1px solid var(--border); padding: 12px 20px; font-size: 0.8125rem; - color: var(--primary); + color: #fff; font-family: var(--font-regular); font-weight: var(--font-weight-bold); + background-color: var(--code-title); } .title code { - background-color: var(--surface-1); + background-color: rgba(255, 255, 255, 0.1); padding: 0.2rem 0.375rem; border-radius: 0.25rem; - color: var(--secondary); - font-size: 0.8125rem; + color: #fff; + font-size: 0.75rem; + font-weight: var(--font-weight-bold); } .code { diff --git a/docs-ui/src/components/Snippet/styles.module.css b/docs-ui/src/components/Snippet/styles.module.css index bb0d1cbc50..3141564293 100644 --- a/docs-ui/src/components/Snippet/styles.module.css +++ b/docs-ui/src/components/Snippet/styles.module.css @@ -5,9 +5,9 @@ } .preview { - border-radius: 4px; + border-radius: 8px; box-shadow: inset 0 0 0 1px var(--border); - background-color: var(--bg); + background-color: var(--bui-bg); padding: 1px; position: relative; } diff --git a/docs-ui/src/components/TableOfContents/TableOfContents.module.css b/docs-ui/src/components/TableOfContents/TableOfContents.module.css new file mode 100644 index 0000000000..7275c24520 --- /dev/null +++ b/docs-ui/src/components/TableOfContents/TableOfContents.module.css @@ -0,0 +1,93 @@ +.container { + position: sticky; + top: 24px; + max-height: calc(100vh - 48px); + overflow-y: auto; + padding: 16px 0; +} + +.list { + list-style: none; + padding: 0; + margin: 0; + position: relative; +} + +.list::before { + content: ''; + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 2px; + background-color: var(--border); +} + +.indicator { + position: absolute; + left: 0; + width: 2px; + background-color: var(--primary); + transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1), + height 0.3s cubic-bezier(0.4, 0, 0.2, 1); + pointer-events: none; + z-index: 1; +} + +.item { + position: relative; + margin: 0; +} + +.itemNested { + padding-left: 16px; +} + +.link { + display: block; + width: 100%; + text-align: left; + background: none; + border: none; + padding: 6px 16px; + font-size: 0.875rem; + color: var(--text-secondary); + cursor: pointer; + transition: color 0.2s ease; + line-height: 1.4; + position: relative; +} + +.link:hover { + color: var(--text); +} + +.itemActive .link { + color: var(--primary); + font-weight: 500; +} + +/* Hide scrollbar for webkit browsers */ +.container::-webkit-scrollbar { + width: 4px; +} + +.container::-webkit-scrollbar-track { + background: transparent; +} + +.container::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 2px; +} + +.container::-webkit-scrollbar-thumb:hover { + background: var(--text-secondary); +} + +/* Responsive: hide on smaller screens */ +@media (max-width: 1280px) { + .container { + display: none; + } +} diff --git a/docs-ui/src/components/TableOfContents/TableOfContents.tsx b/docs-ui/src/components/TableOfContents/TableOfContents.tsx new file mode 100644 index 0000000000..d18265415b --- /dev/null +++ b/docs-ui/src/components/TableOfContents/TableOfContents.tsx @@ -0,0 +1,132 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { usePathname } from 'next/navigation'; +import styles from './TableOfContents.module.css'; + +interface Heading { + id: string; + text: string; + level: number; +} + +export function TableOfContents() { + const [headings, setHeadings] = useState([]); + const [activeId, setActiveId] = useState(''); + const [indicatorTop, setIndicatorTop] = useState(0); + const [indicatorHeight, setIndicatorHeight] = useState(0); + const pathname = usePathname(); + + useEffect(() => { + // Extract all H2 and H3 headings from the document + const elements = Array.from( + document.querySelectorAll('h2[id], h3[id]'), + ) as HTMLHeadingElement[]; + + const headingData: Heading[] = elements.map(element => ({ + id: element.id, + text: (element.textContent || '').replace('#', '').trim(), + level: parseInt(element.tagName.substring(1)), + })); + + setHeadings(headingData); + + // Set initial active heading (first visible heading or first heading) + if (headingData.length > 0) { + const viewportTop = window.scrollY + 100; // offset for header + const visibleHeading = elements.find(element => { + const rect = element.getBoundingClientRect(); + return rect.top + window.scrollY >= viewportTop - 200; + }); + setActiveId(visibleHeading?.id || headingData[0].id); + } + + // Set up IntersectionObserver to track visible headings + const observerOptions = { + rootMargin: '-80px 0px -80% 0px', + threshold: 1, + }; + + const observerCallback = (entries: IntersectionObserverEntry[]) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + setActiveId(entry.target.id); + } + }); + }; + + const observer = new IntersectionObserver( + observerCallback, + observerOptions, + ); + + elements.forEach(element => observer.observe(element)); + + return () => { + elements.forEach(element => observer.unobserve(element)); + }; + }, [pathname]); + + // Update indicator position when activeId changes + useEffect(() => { + if (activeId) { + const activeElement = document.querySelector( + `[data-toc-id="${activeId}"]`, + ) as HTMLElement; + if (activeElement) { + const list = activeElement.closest('ul'); + if (list) { + const listRect = list.getBoundingClientRect(); + const elementRect = activeElement.getBoundingClientRect(); + setIndicatorTop(elementRect.top - listRect.top); + setIndicatorHeight(elementRect.height); + } + } + } + }, [activeId, headings]); + + const handleClick = (id: string) => { + const element = document.getElementById(id); + if (element) { + element.scrollIntoView({ behavior: 'smooth', block: 'start' }); + // Update URL without scrolling (already handled above) + window.history.pushState(null, '', `#${id}`); + } + }; + + if (headings.length === 0) { + return null; + } + + return ( + + ); +} diff --git a/docs-ui/src/components/TableOfContents/index.ts b/docs-ui/src/components/TableOfContents/index.ts new file mode 100644 index 0000000000..ffe4593ca7 --- /dev/null +++ b/docs-ui/src/components/TableOfContents/index.ts @@ -0,0 +1 @@ +export { TableOfContents } from './TableOfContents'; diff --git a/docs-ui/src/content/components/avatar.mdx b/docs-ui/src/content/avatar.mdx similarity index 100% rename from docs-ui/src/content/components/avatar.mdx rename to docs-ui/src/content/avatar.mdx diff --git a/docs-ui/src/content/components/avatar.props.ts b/docs-ui/src/content/avatar.props.ts similarity index 100% rename from docs-ui/src/content/components/avatar.props.ts rename to docs-ui/src/content/avatar.props.ts diff --git a/docs-ui/src/content/components/box.mdx b/docs-ui/src/content/box.mdx similarity index 100% rename from docs-ui/src/content/components/box.mdx rename to docs-ui/src/content/box.mdx diff --git a/docs-ui/src/content/components/box.props.ts b/docs-ui/src/content/box.props.ts similarity index 100% rename from docs-ui/src/content/components/box.props.ts rename to docs-ui/src/content/box.props.ts diff --git a/docs-ui/src/content/components/button-icon.mdx b/docs-ui/src/content/button-icon.mdx similarity index 100% rename from docs-ui/src/content/components/button-icon.mdx rename to docs-ui/src/content/button-icon.mdx diff --git a/docs-ui/src/content/components/button-icon.props.ts b/docs-ui/src/content/button-icon.props.ts similarity index 100% rename from docs-ui/src/content/components/button-icon.props.ts rename to docs-ui/src/content/button-icon.props.ts diff --git a/docs-ui/src/content/components/button-link.mdx b/docs-ui/src/content/button-link.mdx similarity index 100% rename from docs-ui/src/content/components/button-link.mdx rename to docs-ui/src/content/button-link.mdx diff --git a/docs-ui/src/content/components/button-link.props.ts b/docs-ui/src/content/button-link.props.ts similarity index 94% rename from docs-ui/src/content/components/button-link.props.ts rename to docs-ui/src/content/button-link.props.ts index 758d6fd811..2bd4e2196a 100644 --- a/docs-ui/src/content/components/button-link.props.ts +++ b/docs-ui/src/content/button-link.props.ts @@ -1,5 +1,5 @@ -import { classNamePropDefs, stylePropDefs } from '../../utils/propDefs'; -import type { PropDef } from '../../utils/propDefs'; +import { classNamePropDefs, stylePropDefs } from '@/utils/propDefs'; +import type { PropDef } from '@/utils/propDefs'; export const buttonLinkPropDefs: Record = { variant: { diff --git a/docs-ui/src/content/components/button.mdx b/docs-ui/src/content/button.mdx similarity index 100% rename from docs-ui/src/content/components/button.mdx rename to docs-ui/src/content/button.mdx diff --git a/docs-ui/src/content/components/button.props.ts b/docs-ui/src/content/button.props.ts similarity index 94% rename from docs-ui/src/content/components/button.props.ts rename to docs-ui/src/content/button.props.ts index 4647c20956..a3bb2659bf 100644 --- a/docs-ui/src/content/components/button.props.ts +++ b/docs-ui/src/content/button.props.ts @@ -1,5 +1,5 @@ -import { classNamePropDefs, stylePropDefs } from '../../utils/propDefs'; -import type { PropDef } from '../../utils/propDefs'; +import { classNamePropDefs, stylePropDefs } from '@/utils/propDefs'; +import type { PropDef } from '@/utils/propDefs'; export const buttonPropDefs: Record = { variant: { diff --git a/docs-ui/src/content/components/card.mdx b/docs-ui/src/content/card.mdx similarity index 100% rename from docs-ui/src/content/components/card.mdx rename to docs-ui/src/content/card.mdx diff --git a/docs-ui/src/content/components/card.props.ts b/docs-ui/src/content/card.props.ts similarity index 100% rename from docs-ui/src/content/components/card.props.ts rename to docs-ui/src/content/card.props.ts diff --git a/docs-ui/src/content/components/checkbox.mdx b/docs-ui/src/content/checkbox.mdx similarity index 100% rename from docs-ui/src/content/components/checkbox.mdx rename to docs-ui/src/content/checkbox.mdx diff --git a/docs-ui/src/content/components/checkbox.props.ts b/docs-ui/src/content/checkbox.props.ts similarity index 100% rename from docs-ui/src/content/components/checkbox.props.ts rename to docs-ui/src/content/checkbox.props.ts diff --git a/docs-ui/src/content/components/collapsible.mdx b/docs-ui/src/content/collapsible.mdx similarity index 100% rename from docs-ui/src/content/components/collapsible.mdx rename to docs-ui/src/content/collapsible.mdx diff --git a/docs-ui/src/content/components/collapsible.props.ts b/docs-ui/src/content/collapsible.props.ts similarity index 100% rename from docs-ui/src/content/components/collapsible.props.ts rename to docs-ui/src/content/collapsible.props.ts diff --git a/docs-ui/src/content/components/container.mdx b/docs-ui/src/content/container.mdx similarity index 100% rename from docs-ui/src/content/components/container.mdx rename to docs-ui/src/content/container.mdx diff --git a/docs-ui/src/content/components/container.props.ts b/docs-ui/src/content/container.props.ts similarity index 100% rename from docs-ui/src/content/components/container.props.ts rename to docs-ui/src/content/container.props.ts diff --git a/docs-ui/src/content/components/dialog.mdx b/docs-ui/src/content/dialog.mdx similarity index 100% rename from docs-ui/src/content/components/dialog.mdx rename to docs-ui/src/content/dialog.mdx diff --git a/docs-ui/src/content/components/dialog.props.ts b/docs-ui/src/content/dialog.props.ts similarity index 100% rename from docs-ui/src/content/components/dialog.props.ts rename to docs-ui/src/content/dialog.props.ts diff --git a/docs-ui/src/content/components/flex.mdx b/docs-ui/src/content/flex.mdx similarity index 100% rename from docs-ui/src/content/components/flex.mdx rename to docs-ui/src/content/flex.mdx diff --git a/docs-ui/src/content/components/flex.props.ts b/docs-ui/src/content/flex.props.ts similarity index 100% rename from docs-ui/src/content/components/flex.props.ts rename to docs-ui/src/content/flex.props.ts diff --git a/docs-ui/src/content/components/grid.mdx b/docs-ui/src/content/grid.mdx similarity index 100% rename from docs-ui/src/content/components/grid.mdx rename to docs-ui/src/content/grid.mdx diff --git a/docs-ui/src/content/components/grid.props.ts b/docs-ui/src/content/grid.props.ts similarity index 100% rename from docs-ui/src/content/components/grid.props.ts rename to docs-ui/src/content/grid.props.ts diff --git a/docs-ui/src/content/components/header-page.mdx b/docs-ui/src/content/header-page.mdx similarity index 100% rename from docs-ui/src/content/components/header-page.mdx rename to docs-ui/src/content/header-page.mdx diff --git a/docs-ui/src/content/components/header-page.props.ts b/docs-ui/src/content/header-page.props.ts similarity index 100% rename from docs-ui/src/content/components/header-page.props.ts rename to docs-ui/src/content/header-page.props.ts diff --git a/docs-ui/src/content/components/header.mdx b/docs-ui/src/content/header.mdx similarity index 100% rename from docs-ui/src/content/components/header.mdx rename to docs-ui/src/content/header.mdx diff --git a/docs-ui/src/content/components/header.props.ts b/docs-ui/src/content/header.props.ts similarity index 100% rename from docs-ui/src/content/components/header.props.ts rename to docs-ui/src/content/header.props.ts diff --git a/docs-ui/src/content/components/link.mdx b/docs-ui/src/content/link.mdx similarity index 100% rename from docs-ui/src/content/components/link.mdx rename to docs-ui/src/content/link.mdx diff --git a/docs-ui/src/content/components/link.props.ts b/docs-ui/src/content/link.props.ts similarity index 100% rename from docs-ui/src/content/components/link.props.ts rename to docs-ui/src/content/link.props.ts diff --git a/docs-ui/src/content/components/menu.mdx b/docs-ui/src/content/menu.mdx similarity index 100% rename from docs-ui/src/content/components/menu.mdx rename to docs-ui/src/content/menu.mdx diff --git a/docs-ui/src/content/components/menu.props.ts b/docs-ui/src/content/menu.props.ts similarity index 100% rename from docs-ui/src/content/components/menu.props.ts rename to docs-ui/src/content/menu.props.ts diff --git a/docs-ui/src/content/components/password-field.mdx b/docs-ui/src/content/password-field.mdx similarity index 100% rename from docs-ui/src/content/components/password-field.mdx rename to docs-ui/src/content/password-field.mdx diff --git a/docs-ui/src/content/components/password-field.props.ts b/docs-ui/src/content/password-field.props.ts similarity index 100% rename from docs-ui/src/content/components/password-field.props.ts rename to docs-ui/src/content/password-field.props.ts diff --git a/docs-ui/src/content/components/radio-group.mdx b/docs-ui/src/content/radio-group.mdx similarity index 100% rename from docs-ui/src/content/components/radio-group.mdx rename to docs-ui/src/content/radio-group.mdx diff --git a/docs-ui/src/content/components/radio-group.props.ts b/docs-ui/src/content/radio-group.props.ts similarity index 100% rename from docs-ui/src/content/components/radio-group.props.ts rename to docs-ui/src/content/radio-group.props.ts diff --git a/docs-ui/src/content/components/search-field.mdx b/docs-ui/src/content/search-field.mdx similarity index 100% rename from docs-ui/src/content/components/search-field.mdx rename to docs-ui/src/content/search-field.mdx diff --git a/docs-ui/src/content/components/search-field.props.ts b/docs-ui/src/content/search-field.props.ts similarity index 100% rename from docs-ui/src/content/components/search-field.props.ts rename to docs-ui/src/content/search-field.props.ts diff --git a/docs-ui/src/content/components/select.mdx b/docs-ui/src/content/select.mdx similarity index 100% rename from docs-ui/src/content/components/select.mdx rename to docs-ui/src/content/select.mdx diff --git a/docs-ui/src/content/components/select.props.ts b/docs-ui/src/content/select.props.ts similarity index 100% rename from docs-ui/src/content/components/select.props.ts rename to docs-ui/src/content/select.props.ts diff --git a/docs-ui/src/content/components/skeleton.mdx b/docs-ui/src/content/skeleton.mdx similarity index 100% rename from docs-ui/src/content/components/skeleton.mdx rename to docs-ui/src/content/skeleton.mdx diff --git a/docs-ui/src/content/components/skeleton.props.ts b/docs-ui/src/content/skeleton.props.ts similarity index 100% rename from docs-ui/src/content/components/skeleton.props.ts rename to docs-ui/src/content/skeleton.props.ts diff --git a/docs-ui/src/content/components/switch.mdx b/docs-ui/src/content/switch.mdx similarity index 100% rename from docs-ui/src/content/components/switch.mdx rename to docs-ui/src/content/switch.mdx diff --git a/docs-ui/src/content/components/switch.props.ts b/docs-ui/src/content/switch.props.ts similarity index 100% rename from docs-ui/src/content/components/switch.props.ts rename to docs-ui/src/content/switch.props.ts diff --git a/docs-ui/src/content/components/table.mdx b/docs-ui/src/content/table.mdx similarity index 100% rename from docs-ui/src/content/components/table.mdx rename to docs-ui/src/content/table.mdx diff --git a/docs-ui/src/content/components/table.props.ts b/docs-ui/src/content/table.props.ts similarity index 99% rename from docs-ui/src/content/components/table.props.ts rename to docs-ui/src/content/table.props.ts index d46c6b8ea7..443526182e 100644 --- a/docs-ui/src/content/components/table.props.ts +++ b/docs-ui/src/content/table.props.ts @@ -2,7 +2,7 @@ import { classNamePropDefs, stylePropDefs, type PropDef, -} from '../../utils/propDefs'; +} from '@/utils/propDefs'; export const tablePropDefs: Record = { selectionBehavior: { diff --git a/docs-ui/src/content/components/tabs.mdx b/docs-ui/src/content/tabs.mdx similarity index 100% rename from docs-ui/src/content/components/tabs.mdx rename to docs-ui/src/content/tabs.mdx diff --git a/docs-ui/src/content/components/tabs.props.ts b/docs-ui/src/content/tabs.props.ts similarity index 100% rename from docs-ui/src/content/components/tabs.props.ts rename to docs-ui/src/content/tabs.props.ts diff --git a/docs-ui/src/content/components/tag-group.mdx b/docs-ui/src/content/tag-group.mdx similarity index 100% rename from docs-ui/src/content/components/tag-group.mdx rename to docs-ui/src/content/tag-group.mdx diff --git a/docs-ui/src/content/components/tag-group.props.ts b/docs-ui/src/content/tag-group.props.ts similarity index 100% rename from docs-ui/src/content/components/tag-group.props.ts rename to docs-ui/src/content/tag-group.props.ts diff --git a/docs-ui/src/content/components/text-field.mdx b/docs-ui/src/content/text-field.mdx similarity index 100% rename from docs-ui/src/content/components/text-field.mdx rename to docs-ui/src/content/text-field.mdx diff --git a/docs-ui/src/content/components/text-field.props.ts b/docs-ui/src/content/text-field.props.ts similarity index 100% rename from docs-ui/src/content/components/text-field.props.ts rename to docs-ui/src/content/text-field.props.ts diff --git a/docs-ui/src/content/components/text.mdx b/docs-ui/src/content/text.mdx similarity index 100% rename from docs-ui/src/content/components/text.mdx rename to docs-ui/src/content/text.mdx diff --git a/docs-ui/src/content/components/text.props.ts b/docs-ui/src/content/text.props.ts similarity index 100% rename from docs-ui/src/content/components/text.props.ts rename to docs-ui/src/content/text.props.ts diff --git a/docs-ui/src/content/components/tooltip.mdx b/docs-ui/src/content/tooltip.mdx similarity index 100% rename from docs-ui/src/content/components/tooltip.mdx rename to docs-ui/src/content/tooltip.mdx diff --git a/docs-ui/src/content/components/tooltip.props.ts b/docs-ui/src/content/tooltip.props.ts similarity index 100% rename from docs-ui/src/content/components/tooltip.props.ts rename to docs-ui/src/content/tooltip.props.ts diff --git a/docs-ui/src/content/components/visually-hidden.mdx b/docs-ui/src/content/visually-hidden.mdx similarity index 100% rename from docs-ui/src/content/components/visually-hidden.mdx rename to docs-ui/src/content/visually-hidden.mdx diff --git a/docs-ui/src/content/components/visually-hidden.props.ts b/docs-ui/src/content/visually-hidden.props.ts similarity index 100% rename from docs-ui/src/content/components/visually-hidden.props.ts rename to docs-ui/src/content/visually-hidden.props.ts diff --git a/docs-ui/src/css/globals.css b/docs-ui/src/css/globals.css index be75bad36d..dcc348a9ee 100644 --- a/docs-ui/src/css/globals.css +++ b/docs-ui/src/css/globals.css @@ -15,11 +15,15 @@ --border: #e5e5e5; --border2: #cdcdcd; --surface-1: #f4f4f4; + --code-bg: #3e444f; + --code-title: #505865; } [data-theme-mode='dark'] { --bg: #000000; --bg-hover: #202020; + --code-bg: #202020; + --code-title: #292929; --primary: #fff; --secondary: #818181; --action: #202020; diff --git a/docs-ui/src/css/mdx.module.css b/docs-ui/src/css/mdx.module.css index 6a65995003..7cc2422ecd 100644 --- a/docs-ui/src/css/mdx.module.css +++ b/docs-ui/src/css/mdx.module.css @@ -49,3 +49,27 @@ .a:hover { text-decoration: underline; } + +.headingWithAnchor { + position: relative; + scroll-margin-top: 80px; +} + +.anchorLink { + color: inherit; + text-decoration: none; + display: inline-flex; + align-items: center; + gap: 0.5rem; +} + +.anchorHash { + opacity: 0; + transition: opacity 0.2s; + font-size: 0.8em; + color: var(--text-secondary); +} + +.anchorLink:hover .anchorHash { + opacity: 1; +} diff --git a/docs-ui/src/mdx-components.tsx b/docs-ui/src/mdx-components.tsx index 01a865ae3d..3e3efbe1ee 100644 --- a/docs-ui/src/mdx-components.tsx +++ b/docs-ui/src/mdx-components.tsx @@ -4,10 +4,61 @@ import Image, { ImageProps } from 'next/image'; import { CodeBlock } from '@/components/CodeBlock'; import styles from './css/mdx.module.css'; +// Utility function to generate slug from heading text +function slugify(text: string): string { + return text + .toString() + .toLowerCase() + .trim() + .replace(/\s+/g, '-') + .replace(/[^\w\-]+/g, '') + .replace(/\-\-+/g, '-') + .replace(/^-+/, '') + .replace(/-+$/, ''); +} + +// Component for heading with anchor link +function HeadingWithAnchor({ + level, + children, + className, +}: { + level: number; + children: ReactNode; + className: string; +}) { + const text = + typeof children === 'string' + ? children + : Array.isArray(children) + ? children.join('') + : ''; + const id = slugify(text); + + const Tag = `h${level}` as keyof JSX.IntrinsicElements; + + return ( + + + {children} + # + + + ); +} + export const formattedMDXComponents: MDXComponents = { h1: ({ children }) =>

{children as ReactNode}

, - h2: ({ children }) =>

{children as ReactNode}

, - h3: ({ children }) =>

{children as ReactNode}

, + h2: ({ children }) => ( + + {children as ReactNode} + + ), + h3: ({ children }) => ( + + {children as ReactNode} + + ), p: ({ children }) =>

{children as ReactNode}

, a: ({ children, href }) => ( diff --git a/docs-ui/src/utils/data.ts b/docs-ui/src/utils/data.ts index 98f042e6de..ae150b4c1e 100644 --- a/docs-ui/src/utils/data.ts +++ b/docs-ui/src/utils/data.ts @@ -125,16 +125,3 @@ export const components: Page[] = [ slug: 'visually-hidden', }, ]; - -export type ScreenSize = { - title: string; - slug: string; - width: number; -}; - -export const screenSizes: ScreenSize[] = [ - { title: 'Mobile', slug: 'mobile', width: 390 }, - { title: 'Tablet', slug: 'tablet', width: 768 }, - { title: 'Desktop', slug: 'desktop', width: 1280 }, - { title: 'Wide', slug: 'wide', width: 1600 }, -];