feat: Add showLineNumbers prop to Snippet component
This commit is contained in:
parent
3f6d324980
commit
8bf5c5de40
@ -6,8 +6,19 @@ import { Fragment, useMemo } from "react";
|
|||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import { Button } from "./Button";
|
import { Button } from "./Button";
|
||||||
import Prism from "prismjs";
|
import Prism from "prismjs";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
export default function CSRFence({ children, language }: { children: string; language: string }) {
|
export default function CSRSnippet({
|
||||||
|
children,
|
||||||
|
language,
|
||||||
|
label,
|
||||||
|
showLineNumbers = false,
|
||||||
|
}: {
|
||||||
|
children: string;
|
||||||
|
language: string;
|
||||||
|
label?: string;
|
||||||
|
showLineNumbers?: boolean;
|
||||||
|
}) {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
|
|
||||||
const prismTheme = useMemo(() => {
|
const prismTheme = useMemo(() => {
|
||||||
@ -23,10 +34,24 @@ export default function CSRFence({ children, language }: { children: string; lan
|
|||||||
<>
|
<>
|
||||||
<Highlight code={children.trimEnd()} language={language} theme={prismTheme} prism={Prism}>
|
<Highlight code={children.trimEnd()} language={language} theme={prismTheme} prism={Prism}>
|
||||||
{({ className, style, tokens, getTokenProps }) => (
|
{({ className, style, tokens, getTokenProps }) => (
|
||||||
<pre className={className} style={style}>
|
<div className="relative w-full">
|
||||||
|
{label && (
|
||||||
|
<div className="absolute px-4 py-1 left-0 text-sm text-gray-700 dark:text-gray-200 italic w-full bg-gray-200 dark:bg-gray-700 rounded-t-xl">
|
||||||
|
{label}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<pre className={clsx(className, { "pt-11": !!label })} style={style}>
|
||||||
<code>
|
<code>
|
||||||
{tokens.map((line, lineIndex) => (
|
{tokens.map((line, lineIndex) => (
|
||||||
<Fragment key={lineIndex}>
|
<Fragment key={lineIndex}>
|
||||||
|
{showLineNumbers && (
|
||||||
|
<span
|
||||||
|
className="text-gray-400 dark:text-gray-500 text-right font-mono w-8 inline-block pr-4"
|
||||||
|
style={{ userSelect: "none" }}
|
||||||
|
>
|
||||||
|
{lineIndex + 1}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
{line
|
{line
|
||||||
.filter((token) => !token.empty)
|
.filter((token) => !token.empty)
|
||||||
.map((token, tokenIndex) => (
|
.map((token, tokenIndex) => (
|
||||||
@ -37,11 +62,15 @@ export default function CSRFence({ children, language }: { children: string; lan
|
|||||||
))}
|
))}
|
||||||
</code>
|
</code>
|
||||||
</pre>
|
</pre>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</Highlight>
|
</Highlight>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className="absolute top-2 right-2 w-8 h-8 aspect-square opacity-0 group-hover:opacity-50 hover:opacity-100 transition-opacity"
|
className={clsx(
|
||||||
|
"absolute right-2 w-8 h-8 aspect-square opacity-0 group-hover:opacity-50 hover:opacity-100 transition-opacity",
|
||||||
|
!!label ? "top-10" : "top-2",
|
||||||
|
)}
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={copyToClipboard}
|
onClick={copyToClipboard}
|
||||||
|
|||||||
@ -10,13 +10,26 @@ import { Fragment, useMemo } from "react";
|
|||||||
|
|
||||||
const CSRSnippet = clientOnly(() => import("./CSRSnippet"));
|
const CSRSnippet = clientOnly(() => import("./CSRSnippet"));
|
||||||
|
|
||||||
function SSRSnippet({ language, children }: { language: string; children: string }) {
|
function SSRSnippet({
|
||||||
|
language,
|
||||||
|
children,
|
||||||
|
label,
|
||||||
|
showLineNumbers = false,
|
||||||
|
}: {
|
||||||
|
language: string;
|
||||||
|
children: string;
|
||||||
|
label?: string;
|
||||||
|
showLineNumbers?: boolean;
|
||||||
|
}) {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
|
|
||||||
const prismTheme = useMemo(() => {
|
const prismTheme = useMemo(() => {
|
||||||
return prismThemes[theme];
|
return prismThemes[theme];
|
||||||
}, [theme]);
|
}, [theme]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
{label && <div className="text-sm text-gray-500 dark:text-gray-400 mb-2">{label}</div>}
|
||||||
<Highlight code={children.trimEnd()} language={language} theme={prismTheme} prism={Prism}>
|
<Highlight code={children.trimEnd()} language={language} theme={prismTheme} prism={Prism}>
|
||||||
{({ className, style, tokens, getTokenProps }) => (
|
{({ className, style, tokens, getTokenProps }) => (
|
||||||
<pre className={className} style={style}>
|
<pre className={className} style={style}>
|
||||||
@ -35,10 +48,21 @@ function SSRSnippet({ language, children }: { language: string; children: string
|
|||||||
</pre>
|
</pre>
|
||||||
)}
|
)}
|
||||||
</Highlight>
|
</Highlight>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Snippet({ path, language, label }: { path: string; language: string; label?: string }) {
|
export function Snippet({
|
||||||
|
path,
|
||||||
|
language,
|
||||||
|
label,
|
||||||
|
showLineNumbers,
|
||||||
|
}: {
|
||||||
|
path: string;
|
||||||
|
language: string;
|
||||||
|
label?: string;
|
||||||
|
showLineNumbers: boolean;
|
||||||
|
}) {
|
||||||
const { snippets } = useData<Data>();
|
const { snippets } = useData<Data>();
|
||||||
|
|
||||||
const snippet = snippets.find((snippet) => snippet.path === path);
|
const snippet = snippets.find((snippet) => snippet.path === path);
|
||||||
@ -47,6 +71,7 @@ export function Snippet({ path, language, label }: { path: string; language: str
|
|||||||
const props = {
|
const props = {
|
||||||
language,
|
language,
|
||||||
label,
|
label,
|
||||||
|
showLineNumbers,
|
||||||
children: snippet.content,
|
children: snippet.content,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -50,7 +50,7 @@ Parlons dans un premier temps de la signature d'un reducer :
|
|||||||
|
|
||||||
{% tab value="jsx" label="JSX" %}
|
{% tab value="jsx" label="JSX" %}
|
||||||
|
|
||||||
{% snippet path="data/docs/react/usereducer/reducer-example.jsx" language="jsx" label="test" /%}
|
{% snippet path="data/docs/react/usereducer/reducer-example.jsx" language="jsx" label="test" showLineNumbers=true /%}
|
||||||
|
|
||||||
{% /tab %}
|
{% /tab %}
|
||||||
|
|
||||||
|
|||||||
@ -83,44 +83,12 @@ const tags = {
|
|||||||
},
|
},
|
||||||
label: { type: String },
|
label: { type: String },
|
||||||
path: { type: String },
|
path: { type: String },
|
||||||
|
showLineNumbers: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// snippet: {
|
|
||||||
// // render: Fence2,
|
|
||||||
// attributes: {
|
|
||||||
// language: {
|
|
||||||
// type: String,
|
|
||||||
// default: "auto",
|
|
||||||
// },
|
|
||||||
// label: { type: String },
|
|
||||||
// description: { type: String },
|
|
||||||
// path: { type: String },
|
|
||||||
// },
|
|
||||||
// async transform(node: any, config: any) {
|
|
||||||
// const attributes = node.transformAttributes(config);
|
|
||||||
|
|
||||||
// const pathValue = attributes.path;
|
|
||||||
|
|
||||||
// let language = attributes.language ?? "auto";
|
|
||||||
// let content = "";
|
|
||||||
|
|
||||||
// if (!pathValue) {
|
|
||||||
// console.warn("No path provided for snippet tag");
|
|
||||||
// } else {
|
|
||||||
// const absolutePath = path.resolve(__dirname, pathValue);
|
|
||||||
// // Read the file content
|
|
||||||
// try {
|
|
||||||
// content = await fs.readFile(absolutePath, "utf-8");
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error("Error reading file:", error);
|
|
||||||
// content = `Error reading file: ${absolutePath}`;
|
|
||||||
// language = "plain";
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // return new Tag("fence2", { ...attributes, language, content, label: "Temp" });
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default tags;
|
export default tags;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user