diff --git a/apps/www/mdsvex.config.js b/apps/www/mdsvex.config.js index 375da47dd..6bf5bee1c 100644 --- a/apps/www/mdsvex.config.js +++ b/apps/www/mdsvex.config.js @@ -24,10 +24,18 @@ export const mdsvexOptions = { backticks: false, dashes: false }, - remarkPlugins: [remarkGfm, codeImport], + remarkPlugins: [ + // Github Flavored Markdown style + remarkGfm, + // Import code from other files and render them into code blocks + codeImport + ], rehypePlugins: [ + // Add IDs to headings rehypeSlug, + // Get component's source code from the 'name' attribute and render it rehypeComponentExample, + // Parse code blocks and add metadata to them () => (tree) => { visit(tree, (node) => { if (node?.type === "element" && node?.tagName === "pre") { @@ -52,8 +60,10 @@ export const mdsvexOptions = { } }); }, + // Replace `Component.pre` tags with `pre` tags. rehypeComponentPreToPre, [ + // Prettify code blocks rehypePrettyCode, { theme: JSON.parse( @@ -72,8 +82,11 @@ export const mdsvexOptions = { } } ], + // Add metadata tags to code blocks rehypeHandleMetadata, + // Render code into Components.pre or pre tags rehypeRenderCode, + // Replace back `pre` tags with `Component.pre` tags rehypePreToComponentPre ] }; @@ -144,6 +157,7 @@ export function rehypeComponentExample() { }); }; } + function rehypeHandleMetadata() { return async (tree) => { visit(tree, (node) => { @@ -181,13 +195,10 @@ function rehypeComponentPreToPre() { if (node?.type === "element" && node?.tagName === "Components.pre") { node.tagName = "pre"; } - - if (node?.type === "element" && node?.tagName === "pre") { - // - } }); }; } + function rehypePreToComponentPre() { return async (tree) => { visit(tree, (node) => { diff --git a/apps/www/src/lib/components/docs/copy-button.svelte b/apps/www/src/lib/components/docs/copy-button.svelte index f0f4d45a8..200d9afb9 100644 --- a/apps/www/src/lib/components/docs/copy-button.svelte +++ b/apps/www/src/lib/components/docs/copy-button.svelte @@ -2,12 +2,52 @@ import { clickToCopyAction } from "svelte-legos"; import { cn } from "$lib/utils"; import { Check, Copy } from "radix-icons-svelte"; + import { Button } from "@/registry/default/ui/button"; + import * as DropdownMenu from "@/registry/default/ui/dropdown-menu"; let copied = false; + let commands: Record<"npm" | "yarn" | "pnpm" | "bun", string> = { + npm: "", + yarn: "", + pnpm: "", + bun: "" + }; let className: string | undefined | null = undefined; export let value = ""; export { className as class }; + $: if (value) { + // npm install + if (value.startsWith("npm install")) { + commands = { + npm: value, + yarn: value.replace("npm install", "yarn add"), + pnpm: value.replace(/^npm/, "pnpm"), + bun: value.replace(/^npm/, "bun") + }; + } + + // npm create + else if (value.startsWith("npm create")) { + commands = { + npm: value, + yarn: value.replace(/^npm/, "yarn"), + pnpm: value.replace(/^npm/, "pnpm"), + bun: value.replace(/^npm/, "bun --bun") + }; + } + + // npx + else if (value.startsWith("npx")) { + commands = { + npm: value, + yarn: value.replace(/^npx/, "yarn dlx"), + pnpm: value.replace(/^npx/, "pnpx"), + bun: value.replace(/^npx/, "bunx --bun") + }; + } + } + function handleCopyDone() { copied = true; setTimeout(() => { @@ -20,20 +60,59 @@ } - +{#if Object.values(commands).filter(Boolean).length > 1} + + + + + + {#each Object.entries(commands) as [key, command]} + {#if command} + + navigator.clipboard + .writeText(command) + .then(handleCopyDone) + .catch(handleCopyError)} + > + {key} + + {/if} + {/each} + + +{:else} + +{/if}