Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 32 additions & 25 deletions apps/docs/app/components/components-page-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,39 @@ function CommandBlock({ children }: { children: string }) {
)
}

function HighlightedTsxBlock({ code, filename, variant = "source" }: { code: string; filename: string; variant?: "source" | "usage" }) {
const lines = code.split("\n")

return (
<pre aria-label={`${filename} code`} className="vekui-source-card__body" data-variant={variant}>
<code>
{lines.map((line, index) => (
<span className="vekui-source-line" key={`${index}-${line}`}>
<span aria-hidden="true">{index + 1}</span>
<span>
{tokenizeTsxLine(line).map((token, tokenIndex) =>
token.kind ? (
<span
className={`vekui-source-token vekui-source-token--${token.kind}`}
key={`${tokenIndex}-${token.text}`}
>
{token.text}
</span>
) : (
<span key={`${tokenIndex}-${token.text}`}>{token.text}</span>
)
)}
</span>
</span>
))}
</code>
</pre>
)
}

function SourceCodeBlock({ code, filename }: { code: string; filename: string }) {
const [copyLabel, setCopyLabel] = useState("Copy")
const [collapsed, setCollapsed] = useState(false)
const lines = code.split("\n")

function copyCode() {
setCopyLabel("Copied")
Expand Down Expand Up @@ -273,29 +302,7 @@ function SourceCodeBlock({ code, filename }: { code: string; filename: string })
</button>
</div>
</div>
<pre className="vekui-source-card__body">
<code>
{lines.map((line, index) => (
<span className="vekui-source-line" key={`${index}-${line}`}>
<span aria-hidden="true">{index + 1}</span>
<span>
{tokenizeTsxLine(line).map((token, tokenIndex) =>
token.kind ? (
<span
className={`vekui-source-token vekui-source-token--${token.kind}`}
key={`${tokenIndex}-${token.text}`}
>
{token.text}
</span>
) : (
<span key={`${tokenIndex}-${token.text}`}>{token.text}</span>
)
)}
</span>
</span>
))}
</code>
</pre>
<HighlightedTsxBlock code={code} filename={filename} />
</div>
)
}
Expand Down Expand Up @@ -766,7 +773,7 @@ function ComponentPanel({
{available ? (
<section className="vekui-component-detail-section" aria-labelledby={`${component.slug}-usage`}>
<h2 id={`${component.slug}-usage`}>Usage</h2>
<CommandBlock>{usageSnippet(component)}</CommandBlock>
<HighlightedTsxBlock code={usageSnippet(component)} filename={`${component.slug}.usage.tsx`} variant="usage" />
</section>
) : null}

Expand Down
18 changes: 17 additions & 1 deletion apps/docs/app/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -1429,6 +1429,11 @@
line-height: 1.85;
}

.vekui-source-card__body[data-variant="usage"] {
border: 1px solid var(--vk-code-border);
margin-top: 18px;
}

.vekui-source-card[data-collapsed="true"] .vekui-source-card__body {
max-height: 220px;
}
Expand Down Expand Up @@ -2713,7 +2718,8 @@
border: 0;
border-radius: 0;
max-height: calc(100svh - 100px);
padding: 0;
overflow-y: auto;
padding: 0 4px 0 0;
}

.vekui-components-nav-group + .vekui-components-nav-group {
Expand All @@ -2726,6 +2732,16 @@
background: var(--vk-surface);
}

.vekui-components-nav-group[aria-label="Components"] {
overflow: visible;
padding-right: 0;
}

.vekui-components-nav-group[aria-label="Components"] p {
position: static;
z-index: auto;
}

.vekui-components-nav-item {
border-radius: 0;
min-height: 31px;
Expand Down
44 changes: 44 additions & 0 deletions apps/docs/scripts/check-code-blocks.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ function assertIncludes(source, expected, message) {
}
}

function assertRuleIncludes(source, selector, expected, message) {
const escapedSelector = selector.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
const blocks = [...source.matchAll(new RegExp(`${escapedSelector}\\s*\\{([\\s\\S]*?)\\n\\}`, "g"))].map(
(match) => match[1]
)

if (!blocks.some((block) => block.includes(expected))) {
throw new Error(message)
}
}

assertIncludes(
componentPage,
"tokenizeTsxLine",
Expand All @@ -26,6 +37,21 @@ assertIncludes(
'className={`vekui-source-token vekui-source-token--${token.kind}`}',
"Component source blocks should render semantic syntax token classes."
)
assertIncludes(
componentPage,
'function HighlightedTsxBlock({ code, filename, variant = "source" }',
"Component docs should share one highlighted TSX block for source and usage snippets."
)
assertIncludes(
componentPage,
'<HighlightedTsxBlock code={usageSnippet(component)} filename={`${component.slug}.usage.tsx`} variant="usage" />',
"Component usage snippets should render through syntax-highlighted TSX blocks."
)
assertIncludes(
siteCss,
'.vekui-source-card__body[data-variant="usage"]',
"Usage code blocks should have a dedicated visual treatment when rendered outside source cards."
)
assertIncludes(
siteCss,
"--vk-code-surface",
Expand All @@ -36,6 +62,24 @@ assertIncludes(
".vekui-source-token--keyword",
"Code block syntax token classes should be styled."
)
assertRuleIncludes(
siteCss,
".vekui-components-sidebar",
"overflow-y: auto;",
"Components sidebar should own scrolling instead of clipping an inner floating section."
)
assertRuleIncludes(
siteCss,
'.vekui-components-nav-group[aria-label="Components"]',
"overflow: visible;",
"Components nav group should not create a nested scroll area that masks list items."
)
assertRuleIncludes(
siteCss,
'.vekui-components-nav-group[aria-label="Components"] p',
"position: static;",
"Components nav heading should not float over the component list."
)
assertIncludes(
siteCss,
".vekui-components-command {\n background: var(--vk-code-surface);",
Expand Down