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
65 changes: 44 additions & 21 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -1368,7 +1368,7 @@ select {
.prose-docs pre {
overflow: auto;
margin: 20px 0;
padding: 19px 20px;
padding: 20px 5px;
border: 1px solid color-mix(in srgb, var(--border) 75%, black);
border-radius: 12px;
background: var(--code-bg);
Expand All @@ -1386,7 +1386,7 @@ select {

.prose-docs .code-block-shell pre {
margin: 0;
padding-top: 48px;
padding: 20px 5px;
}

.prose-docs .code-block-shell.is-inside-tabs {
Expand All @@ -1403,17 +1403,16 @@ select {
z-index: 1;
top: 10px;
right: 10px;
display: inline-flex;
display: inline-grid;
width: 30px;
height: 30px;
align-items: center;
gap: 6px;
min-height: 30px;
padding: 0 9px;
justify-content: center;
padding: 0;
border: 1px solid rgb(255 255 255 / 0.11);
border-radius: 7px;
background: rgb(255 255 255 / 0.06);
color: color-mix(in srgb, var(--code-text) 86%, white);
font-size: 11px;
font-weight: 700;
transition:
background 150ms ease,
border-color 150ms ease,
Expand All @@ -1427,8 +1426,13 @@ select {
}

.code-copy-button svg {
width: 15px;
height: 15px;
width: 14px;
height: 14px;
}

.code-copy-button:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}

.code-tabs {
Expand Down Expand Up @@ -2739,6 +2743,20 @@ select {
text-transform: uppercase;
}

.pagination a .pagination-label {
display: flex;
width: 100%;
align-items: center;
gap: 5px;
}

.pagination a .pagination-label svg {
width: 15px;
height: 15px;
flex: 0 0 auto;
color: var(--accent);
}

.pagination a strong {
min-width: 0;
overflow: hidden;
Expand All @@ -2752,13 +2770,8 @@ select {
text-align: right;
}

.pagination-next svg {
position: absolute;
right: 11px;
bottom: 10px;
width: 15px;
height: 15px;
color: var(--accent);
.pagination-next .pagination-label {
justify-content: flex-end;
}

.toc-nav > p {
Expand Down Expand Up @@ -2841,6 +2854,7 @@ select {
.search-dialog {
width: min(720px, calc(100vw - 28px));
max-height: min(680px, calc(100vh - 40px));
margin: 10vh auto auto;
padding: 0;
overflow: hidden;
border: 1px solid var(--border-strong);
Expand Down Expand Up @@ -3936,6 +3950,19 @@ html.dark .guide-markdown a {
line-height: 1.65;
}

.guide-markdown .code-block-shell {
position: relative;
margin: 20px 0;
}

.guide-markdown .code-block-shell pre {
max-height: none;
overflow-x: auto;
overflow-y: visible;
margin: 0;
padding: 20px 5px;
}

.guide-markdown blockquote {
margin: 0;
padding: 14px 16px;
Expand Down Expand Up @@ -4640,10 +4667,6 @@ html.dark .guide-markdown a {
grid-template-columns: 1fr;
}

.pagination-next {
text-align: left;
}

.feedback-card,
.site-footer {
align-items: flex-start;
Expand Down
11 changes: 10 additions & 1 deletion source.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,13 @@ export const docs = defineDocs({
},
});

export default defineConfig();
export default defineConfig({
mdxOptions: {
rehypeCodeOptions: {
themes: {
light: 'github-dark',
dark: 'github-dark',
},
},
},
});
43 changes: 32 additions & 11 deletions src/components/docs/code-block.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,42 @@
'use client';

import { useState } from 'react';
import { useRef, useState, type ComponentPropsWithoutRef, type ReactNode } from 'react';
import { CheckIcon, CopyIcon } from '@/src/components/ui/icons';
import { writeClipboardText } from '@/src/lib/clipboard';
import type { Locale } from '@/src/lib/i18n';

export type CodeTab = {
code: string;
highlightedHtml?: string;
language: string;
title: string;
};

export function CodeBlock({
code,
insideTabs = false,
highlightedHtml,
children,
language,
locale = 'en',
...preProps
}: {
code: string;
code?: string;
insideTabs?: boolean;
language: string;
highlightedHtml?: string;
language?: string;
locale?: Locale;
}) {
children?: ReactNode;
} & Omit<ComponentPropsWithoutRef<'pre'>, 'children'>) {
const codeBlockRef = useRef<HTMLDivElement>(null);
const [copied, setCopied] = useState(false);
const copyLabel = locale === 'zh' ? '复制代码' : 'Copy code';
const copiedLabel = locale === 'zh' ? '已复制' : 'Copied';

async function copyCode() {
try {
await writeClipboardText(code);
const renderedCode = codeBlockRef.current?.querySelector('pre')?.textContent;
await writeClipboardText(renderedCode ?? code ?? '');
setCopied(true);
window.setTimeout(() => setCopied(false), 1400);
} catch {
Expand All @@ -37,7 +45,7 @@ export function CodeBlock({
}

return (
<div className={`code-block-shell ${insideTabs ? 'is-inside-tabs' : ''}`}>
<div className={`code-block-shell ${insideTabs ? 'is-inside-tabs' : ''}`} ref={codeBlockRef}>
<button
aria-label={copied ? copiedLabel : copyLabel}
className="code-copy-button"
Expand All @@ -46,11 +54,18 @@ export function CodeBlock({
type="button"
>
{copied ? <CheckIcon /> : <CopyIcon />}
<span>{copied ? copiedLabel : copyLabel}</span>
</button>
<pre>
<code data-language={language}>{code}</code>
</pre>
{highlightedHtml ? (
<div className="code-highlight" dangerouslySetInnerHTML={{ __html: highlightedHtml }} />
) : children !== undefined ? (
<div className="code-highlight">
<pre {...preProps}>{children}</pre>
</div>
) : (
<pre>
<code data-language={language}>{code ?? ''}</code>
</pre>
)}
</div>
);
}
Expand All @@ -75,7 +90,13 @@ export function CodeTabs({ locale = 'en', tabs }: { locale?: Locale; tabs: CodeT
</button>
))}
</div>
<CodeBlock code={current.code} insideTabs language={current.language} locale={locale} />
<CodeBlock
code={current.code}
highlightedHtml={current.highlightedHtml}
insideTabs
language={current.language}
locale={locale}
/>
</div>
);
}
37 changes: 22 additions & 15 deletions src/components/docs/guides-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { resolve } from 'node:path';
import Link from 'next/link';
import { notFound, redirect } from 'next/navigation';
import { Fragment, type ReactNode } from 'react';
import { CodeBlock } from '@/src/components/docs/code-block';
import { ArticleHeader } from '@/src/components/docs/article-header';
import type { ContextOption } from '@/src/components/docs/context-picker';
import { DocsShell } from '@/src/components/docs/docs-shell';
import { ChevronRightIcon } from '@/src/components/ui/icons';
import guidesContentData from '@/src/generated/guides-content.json';
import { highlightCode } from '@/src/lib/code-highlighting';
import { extractMarkdownHeadings } from '@/src/lib/heading-ids';
import type { Locale } from '@/src/lib/i18n';
import { toLocalizedPath } from '@/src/lib/i18n';
Expand Down Expand Up @@ -884,7 +886,7 @@ function GuidesBody({
);
}

function GuideMarkdown({
async function GuideMarkdown({
body,
locale,
sourceMap,
Expand All @@ -897,16 +899,18 @@ function GuideMarkdown({
}) {
return (
<div className="guide-markdown">
{parseGuideMarkdown(body).map((block, index) => (
<GuideMarkdownBlock
block={block}
index={index}
key={`${block.type}-${index}`}
locale={locale}
sourceMap={sourceMap}
sourcePath={sourcePath}
/>
))}
{await Promise.all(
parseGuideMarkdown(body).map((block, index) => (
<GuideMarkdownBlock
block={block}
index={index}
key={`${block.type}-${index}`}
locale={locale}
sourceMap={sourceMap}
sourcePath={sourcePath}
/>
)),
)}
</div>
);
}
Expand All @@ -920,7 +924,7 @@ type GuideMarkdownBlock =
| { type: 'paragraph'; text: string }
| { type: 'table'; rows: string[][] };

function GuideMarkdownBlock({
async function GuideMarkdownBlock({
block,
index,
locale,
Expand Down Expand Up @@ -964,9 +968,12 @@ function GuideMarkdownBlock({

if (block.type === 'code') {
return (
<pre>
<code data-language={block.language}>{block.code}</code>
</pre>
<CodeBlock
code={block.code}
highlightedHtml={await highlightCode(block.code, block.language)}
language={block.language}
locale={locale}
/>
);
}

Expand Down
40 changes: 28 additions & 12 deletions src/components/docs/markdown-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Link from 'next/link';
import { Fragment, type ReactNode } from 'react';
import { CodeBlock, CodeTabs, type CodeTab } from '@/src/components/docs/code-block';
import { createHeadingIdGenerator } from '@/src/lib/heading-ids';
import { highlightCode } from '@/src/lib/code-highlighting';
import type { Locale } from '@/src/lib/i18n';
import { t, toLocalizedPath } from '@/src/lib/i18n';
import { matchCommercialSymbol } from '@/src/lib/client-sdk-commercial';
Expand All @@ -21,7 +22,7 @@ type InlineRenderOptions = {
locale: Locale;
};

export function MarkdownContent({
export async function MarkdownContent({
body,
locale,
commercialNames,
Expand All @@ -34,19 +35,21 @@ export function MarkdownContent({

return (
<>
{parseMarkdown(body).map((block, index) => (
<MarkdownBlockView
block={block}
index={index}
inlineOptions={inlineOptions}
key={`${block.type}-${index}`}
/>
))}
{await Promise.all(
parseMarkdown(body).map((block, index) => (
<MarkdownBlockView
block={block}
index={index}
inlineOptions={inlineOptions}
key={`${block.type}-${index}`}
/>
)),
)}
</>
);
}

function MarkdownBlockView({
async function MarkdownBlockView({
block,
index,
inlineOptions,
Expand Down Expand Up @@ -81,11 +84,24 @@ function MarkdownBlockView({
}

if (block.type === 'code') {
return <CodeBlock code={block.code} language={block.language} locale={inlineOptions.locale} />;
return (
<CodeBlock
code={block.code}
highlightedHtml={await highlightCode(block.code, block.language)}
language={block.language}
locale={inlineOptions.locale}
/>
);
}

if (block.type === 'codeTabs') {
return <CodeTabs locale={inlineOptions.locale} tabs={block.tabs} />;
const tabs = await Promise.all(
block.tabs.map(async (tab) => ({
...tab,
highlightedHtml: await highlightCode(tab.code, tab.language),
})),
);
return <CodeTabs locale={inlineOptions.locale} tabs={tabs} />;
}

if (block.type === 'list') {
Expand Down
Loading