mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-11 09:51:40 +00:00
* feat: chart color * fix * fix * fix: chart color * chore: changeset * chore: restore directory registry formatting * feat: add fontHeading * feat: rebuild registry * fix: v0 * refactor * fix * fix * fix * fix * fix * fix: refactor preset handling * fix * fix * fix
298 lines
8.3 KiB
TypeScript
298 lines
8.3 KiB
TypeScript
import dedent from "dedent"
|
|
|
|
import { UI_COMPONENTS } from "@/lib/components"
|
|
import {
|
|
buildRegistryBase,
|
|
getBodyFont,
|
|
getHeadingFont,
|
|
getInheritedHeadingFontValue,
|
|
type DesignSystemConfig,
|
|
} from "@/registry/config"
|
|
|
|
// Builds step-by-step markdown instructions for manually setting up a project.
|
|
export function buildInstructions(config: DesignSystemConfig) {
|
|
const registryBase = buildRegistryBase(config)
|
|
const normalizedFontHeading =
|
|
config.fontHeading === config.font ? "inherit" : config.fontHeading
|
|
|
|
const dependencies = [
|
|
...(registryBase.dependencies ?? []),
|
|
"clsx",
|
|
"tailwind-merge",
|
|
]
|
|
|
|
const lightVars = Object.entries(registryBase.cssVars?.light ?? {})
|
|
.map(([key, value]) => ` --${key}: ${value};`)
|
|
.join("\n")
|
|
|
|
const darkVars = Object.entries(registryBase.cssVars?.dark ?? {})
|
|
.map(([key, value]) => ` --${key}: ${value};`)
|
|
.join("\n")
|
|
|
|
const font = getBodyFont(config.font)
|
|
const headingFont =
|
|
normalizedFontHeading === "inherit"
|
|
? undefined
|
|
: getHeadingFont(normalizedFontHeading)
|
|
|
|
const sections = [
|
|
buildDependenciesSection(dependencies),
|
|
buildUtilsSection(),
|
|
buildCssSection(
|
|
lightVars,
|
|
darkVars,
|
|
normalizedFontHeading === "inherit"
|
|
? getInheritedHeadingFontValue(config.font)
|
|
: "var(--font-heading)"
|
|
),
|
|
buildFontSection(font, headingFont),
|
|
buildComponentsJsonSection(config),
|
|
buildAvailableComponentsSection(config),
|
|
config.rtl ? buildRtlSection(config) : null,
|
|
]
|
|
|
|
return sections.filter(Boolean).join("\n\n---\n\n")
|
|
}
|
|
|
|
function buildDependenciesSection(dependencies: string[]) {
|
|
const list = dependencies.map((dep) => `- ${dep}`).join("\n")
|
|
|
|
return dedent`
|
|
## Step 1: Dependencies
|
|
|
|
The following dependencies are required:
|
|
|
|
${list}
|
|
`
|
|
}
|
|
|
|
function buildUtilsSection() {
|
|
return dedent`
|
|
## Step 2: Create \`lib/utils.ts\`
|
|
|
|
\`\`\`ts
|
|
import { clsx, type ClassValue } from "clsx"
|
|
import { twMerge } from "tailwind-merge"
|
|
|
|
export function cn(...inputs: ClassValue[]) {
|
|
return twMerge(clsx(inputs))
|
|
}
|
|
\`\`\`
|
|
`
|
|
}
|
|
|
|
function buildCssSection(
|
|
lightVars: string,
|
|
darkVars: string,
|
|
fontHeadingValue: string
|
|
) {
|
|
return dedent`
|
|
## Step 3: Set up CSS
|
|
|
|
Add the following to your global CSS file (e.g. \`app/globals.css\`):
|
|
|
|
\`\`\`css
|
|
@import "tailwindcss";
|
|
@import "tw-animate-css";
|
|
@import "shadcn/tailwind.css";
|
|
|
|
@theme inline {
|
|
--font-sans: var(--font-sans);
|
|
--font-heading: ${fontHeadingValue};
|
|
--font-mono: var(--font-mono);
|
|
--color-background: var(--background);
|
|
--color-foreground: var(--foreground);
|
|
--color-card: var(--card);
|
|
--color-card-foreground: var(--card-foreground);
|
|
--color-popover: var(--popover);
|
|
--color-popover-foreground: var(--popover-foreground);
|
|
--color-primary: var(--primary);
|
|
--color-primary-foreground: var(--primary-foreground);
|
|
--color-secondary: var(--secondary);
|
|
--color-secondary-foreground: var(--secondary-foreground);
|
|
--color-muted: var(--muted);
|
|
--color-muted-foreground: var(--muted-foreground);
|
|
--color-accent: var(--accent);
|
|
--color-accent-foreground: var(--accent-foreground);
|
|
--color-destructive: var(--destructive);
|
|
--color-destructive-foreground: var(--destructive-foreground);
|
|
--color-border: var(--border);
|
|
--color-input: var(--input);
|
|
--color-ring: var(--ring);
|
|
--color-chart-1: var(--chart-1);
|
|
--color-chart-2: var(--chart-2);
|
|
--color-chart-3: var(--chart-3);
|
|
--color-chart-4: var(--chart-4);
|
|
--color-chart-5: var(--chart-5);
|
|
--color-sidebar: var(--sidebar);
|
|
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
--color-sidebar-primary: var(--sidebar-primary);
|
|
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
--color-sidebar-accent: var(--sidebar-accent);
|
|
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
--color-sidebar-border: var(--sidebar-border);
|
|
--color-sidebar-ring: var(--sidebar-ring);
|
|
--radius-sm: calc(var(--radius) * 0.6);
|
|
--radius-md: calc(var(--radius) * 0.8);
|
|
--radius-lg: var(--radius);
|
|
--radius-xl: calc(var(--radius) * 1.4);
|
|
--radius-2xl: calc(var(--radius) * 1.8);
|
|
--radius-3xl: calc(var(--radius) * 2.2);
|
|
--radius-4xl: calc(var(--radius) * 2.6);
|
|
}
|
|
|
|
:root {
|
|
${lightVars}
|
|
}
|
|
|
|
.dark {
|
|
${darkVars}
|
|
}
|
|
|
|
@layer base {
|
|
* {
|
|
@apply border-border outline-ring/50;
|
|
}
|
|
body {
|
|
@apply bg-background text-foreground;
|
|
}
|
|
}
|
|
\`\`\`
|
|
`
|
|
}
|
|
|
|
function buildFontSection(
|
|
font: ReturnType<typeof getBodyFont>,
|
|
headingFont: ReturnType<typeof getHeadingFont>
|
|
) {
|
|
if (!font) {
|
|
return null
|
|
}
|
|
|
|
const googleFontsUrl = `https://fonts.google.com/specimen/${font.font.import.replace(/_/g, "+")}`
|
|
const headingGoogleFontsUrl = headingFont
|
|
? `https://fonts.google.com/specimen/${headingFont.font.import.replace(/_/g, "+")}`
|
|
: null
|
|
const nextImports = headingFont
|
|
? `${font.font.import}, ${headingFont.font.import}`
|
|
: font.font.import
|
|
const nextDeclarations = [
|
|
`const fontSans = ${font.font.import}({`,
|
|
` subsets: ["latin"],`,
|
|
` variable: "${font.font.variable}",`,
|
|
`})`,
|
|
headingFont ? `const fontHeading = ${headingFont.font.import}({` : null,
|
|
headingFont ? ` subsets: ["latin"],` : null,
|
|
headingFont ? ` variable: "${headingFont.font.variable}",` : null,
|
|
headingFont ? `})` : null,
|
|
]
|
|
.filter(Boolean)
|
|
.join("\n")
|
|
const nextHtmlClassName = headingFont
|
|
? 'className={fontSans.variable + " " + fontHeading.variable}'
|
|
: `className={fontSans.variable}`
|
|
const otherFrameworkCss = [
|
|
":root {",
|
|
` ${font.font.variable}: ${font.font.family};`,
|
|
...(headingFont
|
|
? [` ${headingFont.font.variable}: ${headingFont.font.family};`]
|
|
: []),
|
|
"}",
|
|
].join("\n")
|
|
const headingSection = headingFont
|
|
? dedent`
|
|
|
|
This config also uses **${headingFont.title.replace(" (Heading)", "")}** for headings (\`${headingFont.font.variable}\`).
|
|
`
|
|
: ""
|
|
|
|
return dedent`
|
|
## Step 4: Set up the font
|
|
|
|
This config uses **${font.title}** (\`${font.font.variable}\`).
|
|
${headingSection}
|
|
|
|
### Next.js
|
|
|
|
\`\`\`tsx
|
|
import { ${nextImports} } from "next/font/google"
|
|
|
|
${nextDeclarations}
|
|
|
|
// Add the font variable classes to your <html> className.
|
|
// <html ${nextHtmlClassName}>
|
|
\`\`\`
|
|
|
|
### Other frameworks
|
|
|
|
Add the font${headingFont ? "s" : ""} from [Google Fonts](${googleFontsUrl})${headingGoogleFontsUrl ? ` and [Google Fonts](${headingGoogleFontsUrl})` : ""} and set the CSS variable${headingFont ? "s" : ""} to the font famil${headingFont ? "ies" : "y"}:
|
|
|
|
\`\`\`css
|
|
${otherFrameworkCss}
|
|
\`\`\`
|
|
`
|
|
}
|
|
|
|
function buildComponentsJsonSection(config: DesignSystemConfig) {
|
|
const componentsJson = {
|
|
$schema: "https://ui.shadcn.com/schema.json",
|
|
style: `${config.base}-${config.style}`,
|
|
tailwind: {
|
|
css: "app/globals.css",
|
|
baseColor: config.baseColor,
|
|
},
|
|
iconLibrary: config.iconLibrary,
|
|
aliases: {
|
|
components: "@/components",
|
|
utils: "@/lib/utils",
|
|
ui: "@/components/ui",
|
|
lib: "@/lib",
|
|
hooks: "@/hooks",
|
|
},
|
|
}
|
|
|
|
return dedent`
|
|
## Step 5: Create \`components.json\`
|
|
|
|
Add a \`components.json\` file to the root of your project:
|
|
|
|
\`\`\`json
|
|
${JSON.stringify(componentsJson, null, 2)}
|
|
\`\`\`
|
|
`
|
|
}
|
|
|
|
function buildAvailableComponentsSection(config: DesignSystemConfig) {
|
|
const list = UI_COMPONENTS.join(", ")
|
|
const style = `${config.base}-${config.style}`
|
|
|
|
return dedent`
|
|
## Available Components
|
|
|
|
${list}
|
|
|
|
To fetch the source for a component, use:
|
|
\`https://ui.shadcn.com/r/styles/${style}/<component>.json\`
|
|
|
|
For documentation and examples, visit:
|
|
\`https://ui.shadcn.com/docs/components/${config.base}/<component>\`
|
|
`
|
|
}
|
|
|
|
function buildRtlSection(config: DesignSystemConfig) {
|
|
const template =
|
|
config.template === "next-monorepo" ? "next" : (config.template ?? "next")
|
|
|
|
return dedent`
|
|
## RTL Support
|
|
|
|
Add \`dir="rtl"\` to your root \`<html>\` element:
|
|
|
|
\`\`\`html
|
|
<html dir="rtl">
|
|
\`\`\`
|
|
|
|
For full RTL setup including the \`DirectionProvider\`, see the [RTL documentation](https://ui.shadcn.com/docs/rtl/${template}).
|
|
`
|
|
}
|