Skip to content

Commit

Permalink
feat(www): code blocks package manager (shadcn-ui#6075)
Browse files Browse the repository at this point in the history
* feat(www): code blocks

* fix: code style
  • Loading branch information
shadcn authored Dec 14, 2024
1 parent 2d5bf20 commit d3b6eff
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 26 deletions.
108 changes: 108 additions & 0 deletions components/code-block-command.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="relative mt-6 max-h-[650px] overflow-x-auto rounded-xl bg-zinc-950 dark:bg-zinc-900">
<Tabs
defaultValue={packageManager}
onValueChange={(value) => {
setConfig({
...config,
packageManager: value as "pnpm" | "npm" | "yarn" | "bun",
})
}}
>
<div className="flex items-center justify-between border-b border-zinc-800 bg-zinc-900 px-3 pt-2.5">
<TabsList className="h-7 translate-y-[2px] gap-3 bg-transparent p-0 pl-1">
{Object.entries(tabs).map(([key, value]) => {
return (
<TabsTrigger
key={key}
value={key}
className="rounded-none border-b border-transparent bg-transparent p-0 pb-1.5 font-mono text-zinc-400 data-[state=active]:border-b-zinc-50 data-[state=active]:bg-transparent data-[state=active]:text-zinc-50"
>
{key}
</TabsTrigger>
)
})}
</TabsList>
</div>
{Object.entries(tabs).map(([key, value]) => {
return (
<TabsContent key={key} value={key} className="mt-0">
<pre className="px-4 py-5">
<code
className="relative font-mono text-sm leading-none"
data-language="bash"
>
{value}
</code>
</pre>
</TabsContent>
)
})}
</Tabs>
<Button
size="icon"
variant="ghost"
className="absolute right-2.5 top-2 z-10 h-6 w-6 text-zinc-50 hover:bg-zinc-700 hover:text-zinc-50 [&_svg]:h-3 [&_svg]:w-3"
onClick={copyCommand}
>
<span className="sr-only">Copy</span>
{hasCopied ? <CheckIcon /> : <ClipboardIcon />}
</Button>
</div>
)
}
33 changes: 17 additions & 16 deletions components/mdx-components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -192,37 +193,37 @@ const components = {
__src__?: string
__event__?: Event["name"]
} & NpmCommands) => {
const isNpmCommand =
__npmCommand__ && __yarnCommand__ && __pnpmCommand__ && __bunCommand__

if (isNpmCommand) {
return (
<CodeBlockCommand
__npmCommand__={__npmCommand__}
__yarnCommand__={__yarnCommand__}
__pnpmCommand__={__pnpmCommand__}
__bunCommand__={__bunCommand__}
/>
)
}

return (
<StyleWrapper styleName={__style__}>
<pre
className={cn(
"mb-4 mt-6 max-h-[650px] overflow-x-auto rounded-lg border bg-zinc-950 py-4 dark:bg-zinc-900",
"mb-4 mt-6 max-h-[650px] overflow-x-auto rounded-xl bg-zinc-950 py-4 dark:bg-zinc-900",
className
)}
{...props}
/>
{__rawString__ && !__npmCommand__ && (
{__rawString__ && (
<CopyButton
value={__rawString__}
src={__src__}
event={__event__}
className={cn("absolute right-4 top-4", __withMeta__ && "top-16")}
/>
)}
{__npmCommand__ &&
__yarnCommand__ &&
__pnpmCommand__ &&
__bunCommand__ && (
<CopyNpmCommandButton
commands={{
__npmCommand__,
__yarnCommand__,
__pnpmCommand__,
__bunCommand__,
}}
className={cn("absolute right-4 top-4", __withMeta__ && "top-16")}
/>
)}
</StyleWrapper>
)
},
Expand Down
2 changes: 1 addition & 1 deletion content/docs/installation/remix.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
7 changes: 4 additions & 3 deletions content/docs/installation/vite.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions hooks/use-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ type Config = {
style: Style["name"]
theme: BaseColor["name"]
radius: number
packageManager: "npm" | "yarn" | "pnpm" | "bun"
}

const configAtom = atomWithStorage<Config>("config", {
style: "new-york",
theme: "zinc",
radius: 0.5,
packageManager: "pnpm",
})

export function useConfig() {
Expand Down
13 changes: 8 additions & 5 deletions lib/rehype-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
20 changes: 19 additions & 1 deletion lib/rehype-npm-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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") &&
Expand Down

0 comments on commit d3b6eff

Please sign in to comment.