diff --git a/apps/www/components/code-block-command.tsx b/apps/www/components/code-block-command.tsx
new file mode 100644
index 000000000..f74e21f16
--- /dev/null
+++ b/apps/www/components/code-block-command.tsx
@@ -0,0 +1,108 @@
+"use client"
+
+import * as React from "react"
+import { CheckIcon, ClipboardIcon } from "lucide-react"
+
+import { NpmCommands } from "@/types/unist"
+import { useConfig } from "@/hooks/use-config"
+import { copyToClipboardWithMeta } from "@/components/copy-button"
+import { Tabs } from "@/registry/default/ui/tabs"
+import { Button } from "@/registry/new-york/ui/button"
+import { TabsContent, TabsList, TabsTrigger } from "@/registry/new-york/ui/tabs"
+
+export function CodeBlockCommand({
+ __npmCommand__,
+ __yarnCommand__,
+ __pnpmCommand__,
+ __bunCommand__,
+}: React.ComponentProps<"pre"> & NpmCommands) {
+ const [config, setConfig] = useConfig()
+ const [hasCopied, setHasCopied] = React.useState(false)
+
+ React.useEffect(() => {
+ if (hasCopied) {
+ const timer = setTimeout(() => setHasCopied(false), 2000)
+ return () => clearTimeout(timer)
+ }
+ }, [hasCopied])
+
+ const packageManager = config.packageManager || "pnpm"
+ const tabs = React.useMemo(() => {
+ return {
+ pnpm: __pnpmCommand__,
+ npm: __npmCommand__,
+ yarn: __yarnCommand__,
+ bun: __bunCommand__,
+ }
+ }, [__npmCommand__, __pnpmCommand__, __yarnCommand__, __bunCommand__])
+
+ const copyCommand = React.useCallback(() => {
+ const command = tabs[packageManager]
+
+ if (!command) {
+ return
+ }
+
+ copyToClipboardWithMeta(command, {
+ name: "copy_npm_command",
+ properties: {
+ command,
+ pm: packageManager,
+ },
+ })
+ setHasCopied(true)
+ }, [packageManager, tabs])
+
+ return (
+
+
{
+ setConfig({
+ ...config,
+ packageManager: value as "pnpm" | "npm" | "yarn" | "bun",
+ })
+ }}
+ >
+
+
+ {Object.entries(tabs).map(([key, value]) => {
+ return (
+
+ {key}
+
+ )
+ })}
+
+
+ {Object.entries(tabs).map(([key, value]) => {
+ return (
+
+
+
+ {value}
+
+
+
+ )
+ })}
+
+
+
+ )
+}
diff --git a/apps/www/components/mdx-components.tsx b/apps/www/components/mdx-components.tsx
index 73fc1b392..680ae3ce7 100644
--- a/apps/www/components/mdx-components.tsx
+++ b/apps/www/components/mdx-components.tsx
@@ -11,6 +11,7 @@ import { Event } from "@/lib/events"
import { cn } from "@/lib/utils"
import { useConfig } from "@/hooks/use-config"
import { Callout } from "@/components/callout"
+import { CodeBlockCommand } from "@/components/code-block-command"
import { CodeBlockWrapper } from "@/components/code-block-wrapper"
import { ComponentExample } from "@/components/component-example"
import { ComponentPreview } from "@/components/component-preview"
@@ -192,16 +193,30 @@ const components = {
__src__?: string
__event__?: Event["name"]
} & NpmCommands) => {
+ const isNpmCommand =
+ __npmCommand__ && __yarnCommand__ && __pnpmCommand__ && __bunCommand__
+
+ if (isNpmCommand) {
+ return (
+
+ )
+ }
+
return (
- {__rawString__ && !__npmCommand__ && (
+ {__rawString__ && (
)}
- {__npmCommand__ &&
- __yarnCommand__ &&
- __pnpmCommand__ &&
- __bunCommand__ && (
-
- )}
)
},
diff --git a/apps/www/content/docs/installation/remix.mdx b/apps/www/content/docs/installation/remix.mdx
index 170d20a8a..a579e8213 100644
--- a/apps/www/content/docs/installation/remix.mdx
+++ b/apps/www/content/docs/installation/remix.mdx
@@ -47,7 +47,7 @@ Do you want to use CSS variables for colors? › no / yes
### Install Tailwind CSS
```bash
-npm add -D tailwindcss@latest autoprefixer@latest
+npm install -D tailwindcss@latest autoprefixer@latest
```
Then we create a `postcss.config.js` file:
diff --git a/apps/www/content/docs/installation/vite.mdx b/apps/www/content/docs/installation/vite.mdx
index 2b74834a8..a286dbf46 100644
--- a/apps/www/content/docs/installation/vite.mdx
+++ b/apps/www/content/docs/installation/vite.mdx
@@ -19,7 +19,9 @@ Install `tailwindcss` and its peer dependencies, then generate your `tailwind.co
```bash
npm install -D tailwindcss postcss autoprefixer
+```
+```bash
npx tailwindcss init -p
```
@@ -93,11 +95,10 @@ Add the following code to the `tsconfig.app.json` file to resolve paths, for you
### Update vite.config.ts
-Add the following code to the vite.config.ts so your app can resolve paths without error
+Add the following code to the vite.config.ts so your app can resolve paths without error:
```bash
-# (so you can import "path" without error)
-npm i -D @types/node
+npm install -D @types/node
```
```typescript
diff --git a/apps/www/hooks/use-config.ts b/apps/www/hooks/use-config.ts
index 8f0b26b2f..982e9ba0e 100644
--- a/apps/www/hooks/use-config.ts
+++ b/apps/www/hooks/use-config.ts
@@ -8,12 +8,14 @@ type Config = {
style: Style["name"]
theme: BaseColor["name"]
radius: number
+ packageManager: "npm" | "yarn" | "pnpm" | "bun"
}
const configAtom = atomWithStorage("config", {
style: "new-york",
theme: "zinc",
radius: 0.5,
+ packageManager: "pnpm",
})
export function useConfig() {
diff --git a/apps/www/lib/rehype-component.ts b/apps/www/lib/rehype-component.ts
index eb1e863a8..c43aa8d87 100644
--- a/apps/www/lib/rehype-component.ts
+++ b/apps/www/lib/rehype-component.ts
@@ -37,11 +37,14 @@ export function rehypeComponent() {
} else {
const component = Index[style.name][name]
src = fileName
- ? component.files.find((file: string) => {
- return (
- file.endsWith(`${fileName}.tsx`) ||
- file.endsWith(`${fileName}.ts`)
- )
+ ? component.files.find((file: unknown) => {
+ if (typeof file === "string") {
+ return (
+ file.endsWith(`${fileName}.tsx`) ||
+ file.endsWith(`${fileName}.ts`)
+ )
+ }
+ return false
}) || component.files[0]?.path
: component.files[0]?.path
}
diff --git a/apps/www/lib/rehype-npm-command.ts b/apps/www/lib/rehype-npm-command.ts
index 68157b66e..e0dd764da 100644
--- a/apps/www/lib/rehype-npm-command.ts
+++ b/apps/www/lib/rehype-npm-command.ts
@@ -26,7 +26,7 @@ export function rehypeNpmCommand() {
)
}
- // npx create.
+ // npx create-.
if (node.properties?.["__rawString__"]?.startsWith("npx create-")) {
const npmCommand = node.properties?.["__rawString__"]
node.properties["__npmCommand__"] = npmCommand
@@ -44,6 +44,24 @@ export function rehypeNpmCommand() {
)
}
+ // npm create.
+ if (node.properties?.["__rawString__"]?.startsWith("npm create")) {
+ const npmCommand = node.properties?.["__rawString__"]
+ node.properties["__npmCommand__"] = npmCommand
+ node.properties["__yarnCommand__"] = npmCommand.replace(
+ "npm create",
+ "yarn create"
+ )
+ node.properties["__pnpmCommand__"] = npmCommand.replace(
+ "npm create",
+ "pnpm create"
+ )
+ node.properties["__bunCommand__"] = npmCommand.replace(
+ "npm create",
+ "bun create"
+ )
+ }
+
// npx.
if (
node.properties?.["__rawString__"]?.startsWith("npx") &&