كتلة شيفرة
شيفرة في صندوق خاص بها، تُقرأ من اليسار إلى اليمين في أي صفحة. تُعرض على الخادم، وزر النسخ هو الشيفرة الوحيدة في المتصفح.
split - الحجم لم يُقَس بعد
كتلة شيفرة
split - الحجم لم يُقَس بعدشيفرة في صندوق خاص بها، تُقرأ من اليسار إلى اليمين في أي صفحة. تُعرض على الخادم، وزر النسخ هو الشيفرة الوحيدة في المتصفح.
app/invoices/page.tsx
export default async function Page() {
const invoices = await getInvoices({ status: 'overdue', sortBy: 'dueDate', order: 'descending' })
return <InvoiceTable items={invoices} />
}جرّبه
showCopy
wrap
الشيفرة
code-block.tsx
import type { CodeBlockDesignProps } from 'topclassui/code-block'
import { CodeBlock } from 'topclassui/code-block'
/** The docs stage: the Try it controls hand their values in as props. One line is long, so wrap shows. */
export default function Demo(props: CodeBlockDesignProps) {
return (
<CodeBlock lang="tsx" title="app/invoices/page.tsx" {...props}>
{`export default async function Page() {
const invoices = await getInvoices({ status: 'overdue', sortBy: 'dueDate', order: 'descending' })
return <InvoiceTable items={invoices} />
}`}
</CodeBlock>
)
}
مرّر الشيفرة ابنًا بصيغة template literal. لا يوجد ملوّن مدمج: مرّر العقد الملوّنة عبر highlighted.
كل الحالات، بدون تمرير الفأرة
3 حالاتapp/page.tsx
export default async function Page() {
const invoices = await getInvoices()
return <InvoiceTable items={invoices} />
}columns.ts
export const columns = ['number', 'customer', 'issued', 'due', 'amount', 'status', 'actions'] as constapp/reports/page.tsx
export default async function Page() {
const invoices = await getInvoices()
return <InvoiceTable items={invoices} />
}أو استورده من الحزمة
topclassui/code-block
import { CodeBlock } from 'topclassui/code-block'ثبّت مرة واحدة:npm i topclassui@beta zod
أمثلة
- الشيفرة هي
children، نص واحد: تُحفظ كل مسافة وكل سطر جديد، وهذا النص هو ما ينسخه الزر. titleيسمّي الكتلة: تصبح الشيفرة منطقة باسمه، ويُقرأ الزر "Copy page.tsx".langيُكتب فيdata-langولا شيء غير ذلك. لتلوين الشيفرة أنشئ العقد بنفسك، وقت البناء أو في مكوّن خادم خاص بك، ومرّرها عبرhighlighted؛ ويبقى الزر ينسخchildren.- السطر الطويل يُمرَّر أفقيًا داخل الكتلة؛ و
wrapيكسره بدلًا من ذلك. showCopy={false}يزيل الزر، فلا ترسل الكتلة عندها أي JavaScript.- في مكوّن الخادم مرّر
{...getLabels(locale)}: كلمات الزر تأتي منlabels.common.
basic
page.tsx
export default async function Page() {
const invoices = await getInvoices()
return <InvoiceTable items={invoices} />
}basic.tsx
import { CodeBlock } from 'topclassui/code-block'
/** The drawn block: a file name, the copy button, and the code passed as a template literal. */
export default function Demo() {
return (
<CodeBlock lang="tsx" title="page.tsx">
{`export default async function Page() {
const invoices = await getInvoices()
return <InvoiceTable items={invoices} />
}`}
</CodeBlock>
)
}
highlighted
sample.tsx
import { CodeBlock } from 'topclassui/code-block'
// Coloured by the caller, copied as plain text
export const sample = <CodeBlock title="page.tsx">{code}</CodeBlock>highlighted.tsx
import { CodeBlock } from 'topclassui/code-block'
const CODE = `import { CodeBlock } from 'topclassui/code-block'
// Coloured by the caller, copied as plain text
export const sample = <CodeBlock title="page.tsx">{code}</CodeBlock>`
const KEYWORD = 'font-semibold'
const STRING = 'italic'
const COMMENT = 'text-neutral-on-solid/70'
/** highlighted: nodes the caller made, here by hand, rendered in place of the text. The button
* still copies children. A highlighter at build time would hand the same kind of nodes. */
export default function Demo() {
return (
<CodeBlock
lang="tsx"
title="sample.tsx"
highlighted={(
<>
<span className={KEYWORD}>import</span>{' { CodeBlock } '}<span className={KEYWORD}>from</span>{' '}
<span className={STRING}>{`'topclassui/code-block'`}</span>
{'\n\n'}
<span className={COMMENT}>{'// Coloured by the caller, copied as plain text'}</span>
{'\n'}
<span className={KEYWORD}>export const</span>{' sample = <CodeBlock title='}<span className={STRING}>{'"page.tsx"'}</span>
{'>{code}</CodeBlock>'}
</>
)}
>
{CODE}
</CodeBlock>
)
}
long-line
token.ts
const token = 'a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5a1b2c3d4e5abcd'long-line.tsx
import { CodeBlock } from 'topclassui/code-block'
const LINE = ["const token = '", 'a1b2c3d4e5'.repeat(28), "abcd'"].join('')
/** One line of 300 characters: it scrolls inside the block, and the page never scrolls sideways. */
export default function Demo() {
return (
<CodeBlock lang="ts" title="token.ts">
{LINE}
</CodeBlock>
)
}
wrap
invoice-row.tsx
export const columns = ['number', 'customer', 'issued', 'due', 'amount', 'status', 'actions'] as const satisfies readonly InvoiceColumn[]wrap.tsx
import { CodeBlock } from 'topclassui/code-block'
/** wrap: a long line breaks inside the block instead of scrolling it, and the code is no tab stop. */
export default function Demo() {
return (
<CodeBlock lang="tsx" title="invoice-row.tsx" wrap>
{`export const columns = ['number', 'customer', 'issued', 'due', 'amount', 'status', 'actions'] as const satisfies readonly InvoiceColumn[]`}
</CodeBlock>
)
}
no-copy
globals.css
:root {
--tc-radius: 0.75rem;
}no-copy.tsx
import { CodeBlock } from 'topclassui/code-block'
/** A title and no button: the block ships no script at all. */
export default function Demo() {
return (
<CodeBlock lang="css" title="globals.css" showCopy={false}>
{`:root {
--tc-radius: 0.75rem;
}`}
</CodeBlock>
)
}
no-header
pnpm add topclassui zodno-header.tsx
import { CodeBlock } from 'topclassui/code-block'
/** No title and no copy button: no header either, so the code takes the top padding back. */
export default function Demo() {
return (
<CodeBlock lang="sh" showCopy={false}>
{'pnpm add topclassui zod'}
</CodeBlock>
)
}
بالعربية، من اليمين إلى اليسار
الفواتير.tsx
export default async function Page() {
const invoices = await getInvoices()
return <InvoiceTable items={invoices} />
}rtl.tsx
import { getLabels } from 'topclassui/labels/get-labels'
import { TopClassProvider } from 'topclassui/provider'
import { CodeBlock } from 'topclassui/code-block'
/** Arabic: the header keeps the page's direction, so the button sits at the inline end, on the
* left, and the button reads its Arabic name. The code still reads left to right. */
export default function Demo() {
return (
<TopClassProvider direction="rtl" locale="ar">
<div dir="rtl" lang="ar">
<CodeBlock {...getLabels('ar')} lang="tsx" title="الفواتير.tsx">
{`export default async function Page() {
const invoices = await getInvoices()
return <InvoiceTable items={invoices} />
}`}
</CodeBlock>
</div>
</TopClassProvider>
)
}
الخصائص
لوحة المفاتيح وإمكانية الوصول
- اسم الزر لا يتغير أبدًا: علامة الصح إشارة للعين، وحالة مهذبة تقول "تم النسخ" أو "تعذّر النسخ" مرة لكل ضغطة.
- النسخ يحتاج سياقًا آمنًا (https أو localhost)؛ وفي غيره يقول الزر "تعذّر النسخ" ويبقي أيقونته.
- الألوان التي تمرّرها في
highlightedمسؤوليتك، فتحقق من تباينها مع سطح الكتلة.
من اليمين إلى اليسار
الشيفرة دائمًا dir="ltr" وtranslate="no". أما الترويسة فتتبع اتجاه الصفحة، فيقع زر النسخ في العربية على اليسار، عند نهاية السطر.
الخادم والمتصفح
يُعرض على الخادم، والجزء التفاعلي مكوّن متصفح لا يُرسل إلا عند استخدامه.
الملفات: index.tsx, client.tsx.
على الشارة: split - الحجم لم يُقَس بعد.