Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(www): code blocks package manager #6075

Merged
merged 2 commits into from
Dec 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions apps/www/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 apps/www/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 apps/www/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 apps/www/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 apps/www/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 apps/www/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 apps/www/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
Loading