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}