Preview
Preparing...
Installation
shadcn/ui
shadcn/ui Command
pnpm dlx shadcn@latest add https://code-blocks.pheralb.dev/r/block-select-package-manager.jsonManual
- Create
packageManager.tsstore:
reactPersist Package Manager
Custom store to persist the selected package manager using Zustand.
- Create the basic Code Block structure:
reactCode Block
The main structure of the Code Block component with header and content areas.
- Create the following client components:
reactCopy Button
A button component to copy content to the clipboard.
reactCode Block Client with Shiki
Create a client-side Code Block component using Shiki for syntax highlighting.
shadcn/ui Dropdown Menu
pnpm dlx shadcn@latest add dropdown-menu- Install the following dependencies (optional):
Optional Dependencies
pnpm i @react-symbols/icons lucide-react -E- Finally, create the Select Package Manager Block component:
.tsx
"use client";
import { useState, type FC, type SVGProps } from "react";
import {
usePackageManager,
type PackageManager,
} from "@/stores/packageManager";
import {
CodeBlock,
CodeBlockContent,
CodeBlockHeader,
CodeBlockIcon,
} from "@/components/code-block/code-block";
import { CopyButton } from "@/components/code-block/copy-button";
import { CodeblockShiki } from "@/components/code-block/client/shiki";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { cn } from "@/utils/cn";
import { Bun, NPM, PNPM, Yarn } from "@react-symbols/icons";
import { CheckIcon, ChevronDownIcon } from "lucide-react";
interface CodeBlockSelectPkgProps {
command: string;
title: string;
type: "install" | "dlx";
}
interface Command {
name: PackageManager;
install: string;
icon: FC<SVGProps<SVGSVGElement>>;
dlx: string;
}
const Commands: Command[] = [
{
name: "npm",
install: "npm i",
icon: NPM,
dlx: "npx",
},
{
name: "pnpm",
install: "pnpm i",
icon: PNPM,
dlx: "pnpm dlx",
},
{
name: "yarn",
install: "yarn add",
icon: Yarn,
dlx: "yarn dlx",
},
{
name: "bun",
install: "bun add",
icon: Bun,
dlx: "bunx --bun",
},
];
const SelectPackageManager = () => {
const [isOpen, setIsOpen] = useState(false);
const { packageManager, setPackageManager } = usePackageManager();
const selectedPkg =
Commands.find((pkg) => pkg.name === packageManager) ?? Commands[0];
const Icon = selectedPkg.icon;
return (
<DropdownMenu open={isOpen} onOpenChange={setIsOpen}>
<DropdownMenuTrigger
title="Select Package Manager"
className="group flex cursor-pointer items-center space-x-1 px-2"
>
<Icon className="size-4" />
<ChevronDownIcon
size={13}
className={cn(
"transform transition-transform duration-200 ease-in-out",
"group-hover:text-black dark:group-hover:text-white",
isOpen && "rotate-180 text-black dark:text-white",
)}
/>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" alignOffset={2}>
{Commands.map((pkg) => {
const PkgIcon = pkg.icon;
return (
<DropdownMenuItem
key={pkg.name}
title={`Using ${pkg.name}`}
onClick={() => setPackageManager(pkg.name)}
className="flex w-full items-center justify-between"
>
<div className="flex items-center space-x-2">
<PkgIcon className="size-4" />
<span>{pkg.name}</span>
</div>
{selectedPkg.name === pkg.name && <CheckIcon width={14} />}
</DropdownMenuItem>
);
})}
</DropdownMenuContent>
</DropdownMenu>
);
};
const CodeBlockSelectPkg = ({
title,
type,
command,
}: CodeBlockSelectPkgProps) => {
const { packageManager } = usePackageManager();
const selectedPkg =
Commands.find((pkg) => pkg.name === packageManager) ?? Commands[0];
const fullCommand = `${selectedPkg[type]} ${command}`;
return (
<CodeBlock>
<CodeBlockHeader>
<div className="flex items-center space-x-2">
<CodeBlockIcon language="bash" />
<span className="font-medium">{title}</span>
</div>
<div className="flex items-center space-x-2 divide-x divide-neutral-300 dark:divide-neutral-700">
<SelectPackageManager />
<CopyButton className="pl-1" content={fullCommand} />
</div>
</CodeBlockHeader>
<CodeBlockContent>
<CodeblockShiki language="bash" code={fullCommand} />
</CodeBlockContent>
</CodeBlock>
);
};
export { CodeBlockSelectPkg, SelectPackageManager };