mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-11 09:51:40 +00:00
fix
This commit is contained in:
244
apps/v4/app/(create)/init/md/build-instructions.ts
Normal file
244
apps/v4/app/(create)/init/md/build-instructions.ts
Normal file
@@ -0,0 +1,244 @@
|
||||
import dedent from "dedent"
|
||||
|
||||
import { UI_COMPONENTS } from "@/lib/components"
|
||||
import {
|
||||
buildRegistryBase,
|
||||
fonts,
|
||||
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 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 = fonts.find((f) => f.name === `font-${config.font}`)
|
||||
|
||||
const sections = [
|
||||
buildDependenciesSection(dependencies),
|
||||
buildUtilsSection(),
|
||||
buildCssSection(lightVars, darkVars),
|
||||
buildFontSection(font),
|
||||
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) {
|
||||
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-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: (typeof fonts)[number] | undefined) {
|
||||
if (!font) {
|
||||
return null
|
||||
}
|
||||
|
||||
const googleFontsUrl = `https://fonts.google.com/specimen/${font.font.import.replace(/_/g, "+")}`
|
||||
|
||||
return dedent`
|
||||
## Step 4: Set up the font
|
||||
|
||||
This config uses **${font.title}** (\`${font.font.variable}\`).
|
||||
|
||||
### Next.js
|
||||
|
||||
\`\`\`tsx
|
||||
import { ${font.font.import} } from "next/font/google"
|
||||
|
||||
const fontSans = ${font.font.import}({
|
||||
subsets: ["latin"],
|
||||
variable: "${font.font.variable}",
|
||||
})
|
||||
|
||||
// Add fontSans.variable to your <html> className.
|
||||
// <html className={fontSans.variable}>
|
||||
\`\`\`
|
||||
|
||||
### Other frameworks
|
||||
|
||||
Add the font from [Google Fonts](${googleFontsUrl}) and set the \`${font.font.variable}\` CSS variable to the font family:
|
||||
|
||||
\`\`\`css
|
||||
:root {
|
||||
${font.font.variable}: ${font.font.family};
|
||||
}
|
||||
\`\`\`
|
||||
`
|
||||
}
|
||||
|
||||
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}).
|
||||
`
|
||||
}
|
||||
30
apps/v4/app/(create)/init/md/route.ts
Normal file
30
apps/v4/app/(create)/init/md/route.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { type NextRequest } from "next/server"
|
||||
import { track } from "@vercel/analytics/server"
|
||||
|
||||
import { parseDesignSystemConfig } from "@/app/(create)/init/parse-config"
|
||||
|
||||
import { buildInstructions } from "./build-instructions"
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const searchParams = request.nextUrl.searchParams
|
||||
const result = parseDesignSystemConfig(searchParams)
|
||||
|
||||
if (!result.success) {
|
||||
return new Response(result.error, { status: 400 })
|
||||
}
|
||||
|
||||
track("create_app_manual", result.data)
|
||||
|
||||
const markdown = buildInstructions(result.data)
|
||||
|
||||
return new Response(markdown, {
|
||||
headers: { "Content-Type": "text/markdown; charset=utf-8" },
|
||||
})
|
||||
} catch (error) {
|
||||
return new Response(
|
||||
error instanceof Error ? error.message : "An unknown error occurred",
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
47
apps/v4/app/(create)/init/parse-config.ts
Normal file
47
apps/v4/app/(create)/init/parse-config.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { decodePreset, isPresetCode } from "shadcn/preset"
|
||||
|
||||
import {
|
||||
designSystemConfigSchema,
|
||||
type DesignSystemConfig,
|
||||
} from "@/registry/config"
|
||||
|
||||
// Parses design system config from URL search params.
|
||||
export function parseDesignSystemConfig(searchParams: URLSearchParams) {
|
||||
let configInput: Record<string, unknown>
|
||||
const presetParam = searchParams.get("preset")
|
||||
|
||||
if (presetParam && isPresetCode(presetParam)) {
|
||||
const decoded = decodePreset(presetParam)
|
||||
if (!decoded) {
|
||||
return { success: false as const, error: "Invalid preset code" }
|
||||
}
|
||||
configInput = {
|
||||
...decoded,
|
||||
base: searchParams.get("base") ?? "radix",
|
||||
template: searchParams.get("template") ?? undefined,
|
||||
rtl: searchParams.get("rtl") === "true",
|
||||
}
|
||||
} else {
|
||||
configInput = {
|
||||
base: searchParams.get("base"),
|
||||
style: searchParams.get("style"),
|
||||
iconLibrary: searchParams.get("iconLibrary"),
|
||||
baseColor: searchParams.get("baseColor"),
|
||||
theme: searchParams.get("theme"),
|
||||
font: searchParams.get("font"),
|
||||
menuAccent: searchParams.get("menuAccent"),
|
||||
menuColor: searchParams.get("menuColor"),
|
||||
radius: searchParams.get("radius"),
|
||||
template: searchParams.get("template") ?? undefined,
|
||||
rtl: searchParams.get("rtl") === "true",
|
||||
}
|
||||
}
|
||||
|
||||
const result = designSystemConfigSchema.safeParse(configInput)
|
||||
|
||||
if (!result.success) {
|
||||
return { success: false as const, error: result.error.issues[0].message }
|
||||
}
|
||||
|
||||
return { success: true as const, data: result.data as DesignSystemConfig }
|
||||
}
|
||||
@@ -1,54 +1,17 @@
|
||||
import { NextResponse, type NextRequest } from "next/server"
|
||||
import { track } from "@vercel/analytics/server"
|
||||
import { decodePreset, isPresetCode } from "shadcn/preset"
|
||||
import { registryItemSchema } from "shadcn/schema"
|
||||
|
||||
import { buildRegistryBase, designSystemConfigSchema } from "@/registry/config"
|
||||
import { buildRegistryBase } from "@/registry/config"
|
||||
import { parseDesignSystemConfig } from "@/app/(create)/init/parse-config"
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const searchParams = request.nextUrl.searchParams
|
||||
|
||||
// Decode preset code if present.
|
||||
let configInput: Record<string, unknown>
|
||||
const presetParam = searchParams.get("preset")
|
||||
|
||||
if (presetParam && isPresetCode(presetParam)) {
|
||||
const decoded = decodePreset(presetParam)
|
||||
if (!decoded) {
|
||||
return NextResponse.json(
|
||||
{ error: "Invalid preset code" },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
configInput = {
|
||||
...decoded,
|
||||
template: searchParams.get("template") ?? undefined,
|
||||
rtl: searchParams.get("rtl") === "true",
|
||||
}
|
||||
} else {
|
||||
configInput = {
|
||||
base: searchParams.get("base"),
|
||||
style: searchParams.get("style"),
|
||||
iconLibrary: searchParams.get("iconLibrary"),
|
||||
baseColor: searchParams.get("baseColor"),
|
||||
theme: searchParams.get("theme"),
|
||||
font: searchParams.get("font"),
|
||||
menuAccent: searchParams.get("menuAccent"),
|
||||
menuColor: searchParams.get("menuColor"),
|
||||
radius: searchParams.get("radius"),
|
||||
template: searchParams.get("template") ?? undefined,
|
||||
rtl: searchParams.get("rtl") === "true",
|
||||
}
|
||||
}
|
||||
|
||||
const result = designSystemConfigSchema.safeParse(configInput)
|
||||
const result = parseDesignSystemConfig(searchParams)
|
||||
|
||||
if (!result.success) {
|
||||
return NextResponse.json(
|
||||
{ error: result.error.issues[0].message },
|
||||
{ status: 400 }
|
||||
)
|
||||
return NextResponse.json({ error: result.error }, { status: 400 })
|
||||
}
|
||||
|
||||
const registryBase = buildRegistryBase(result.data)
|
||||
|
||||
@@ -8,12 +8,14 @@ import {
|
||||
Lora,
|
||||
Merriweather,
|
||||
Noto_Sans,
|
||||
Noto_Serif,
|
||||
Nunito_Sans,
|
||||
Outfit,
|
||||
Playfair_Display,
|
||||
Public_Sans,
|
||||
Raleway,
|
||||
Roboto,
|
||||
Roboto_Slab,
|
||||
} from "next/font/google"
|
||||
|
||||
const inter = Inter({
|
||||
@@ -76,9 +78,14 @@ const outfit = Outfit({
|
||||
variable: "--font-outfit",
|
||||
})
|
||||
|
||||
const lora = Lora({
|
||||
const notoSerif = Noto_Serif({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-lora",
|
||||
variable: "--font-noto-serif",
|
||||
})
|
||||
|
||||
const robotoSlab = Roboto_Slab({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-roboto-slab",
|
||||
})
|
||||
|
||||
const merriweather = Merriweather({
|
||||
@@ -86,6 +93,11 @@ const merriweather = Merriweather({
|
||||
variable: "--font-merriweather",
|
||||
})
|
||||
|
||||
const lora = Lora({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-lora",
|
||||
})
|
||||
|
||||
const playfairDisplay = Playfair_Display({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-playfair-display",
|
||||
@@ -165,9 +177,15 @@ export const FONTS = [
|
||||
type: "mono",
|
||||
},
|
||||
{
|
||||
name: "Lora",
|
||||
value: "lora",
|
||||
font: lora,
|
||||
name: "Noto Serif",
|
||||
value: "noto-serif",
|
||||
font: notoSerif,
|
||||
type: "serif",
|
||||
},
|
||||
{
|
||||
name: "Roboto Slab",
|
||||
value: "roboto-slab",
|
||||
font: robotoSlab,
|
||||
type: "serif",
|
||||
},
|
||||
{
|
||||
@@ -176,6 +194,12 @@ export const FONTS = [
|
||||
font: merriweather,
|
||||
type: "serif",
|
||||
},
|
||||
{
|
||||
name: "Lora",
|
||||
value: "lora",
|
||||
font: lora,
|
||||
type: "serif",
|
||||
},
|
||||
{
|
||||
name: "Playfair Display",
|
||||
value: "playfair-display",
|
||||
|
||||
65
apps/v4/lib/components.ts
Normal file
65
apps/v4/lib/components.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
// All available UI components.
|
||||
export const UI_COMPONENTS = [
|
||||
"accordion",
|
||||
"alert",
|
||||
"alert-dialog",
|
||||
"aspect-ratio",
|
||||
"avatar",
|
||||
"badge",
|
||||
"breadcrumb",
|
||||
"button",
|
||||
"button-group",
|
||||
"calendar",
|
||||
"card",
|
||||
"carousel",
|
||||
"chart",
|
||||
"checkbox",
|
||||
"collapsible",
|
||||
"combobox",
|
||||
"command",
|
||||
"context-menu",
|
||||
"data-table",
|
||||
"date-picker",
|
||||
"dialog",
|
||||
"direction",
|
||||
"drawer",
|
||||
"dropdown-menu",
|
||||
"empty",
|
||||
"field",
|
||||
"form",
|
||||
"hover-card",
|
||||
"input",
|
||||
"input-group",
|
||||
"input-otp",
|
||||
"item",
|
||||
"kbd",
|
||||
"label",
|
||||
"menubar",
|
||||
"native-select",
|
||||
"navigation-menu",
|
||||
"pagination",
|
||||
"popover",
|
||||
"progress",
|
||||
"radio-group",
|
||||
"resizable",
|
||||
"scroll-area",
|
||||
"select",
|
||||
"separator",
|
||||
"sheet",
|
||||
"sidebar",
|
||||
"skeleton",
|
||||
"slider",
|
||||
"sonner",
|
||||
"spinner",
|
||||
"switch",
|
||||
"table",
|
||||
"tabs",
|
||||
"textarea",
|
||||
"toast",
|
||||
"toggle",
|
||||
"toggle-group",
|
||||
"tooltip",
|
||||
"typography",
|
||||
] as const
|
||||
|
||||
export type UIComponent = (typeof UI_COMPONENTS)[number]
|
||||
@@ -121,6 +121,10 @@ const nextConfig = {
|
||||
source: "/docs/:path*.md",
|
||||
destination: "/llm/:path*",
|
||||
},
|
||||
{
|
||||
source: "/init.md",
|
||||
destination: "/init/md",
|
||||
},
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.0.0",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||
"tailwindcss": "^4",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^5",
|
||||
@@ -137,6 +137,8 @@
|
||||
"jsx",
|
||||
"decorators-legacy"
|
||||
],
|
||||
"tailwindStylesheet": "./styles/globals.css",
|
||||
"tailwindFunctions": ["cn", "cva"],
|
||||
"plugins": [
|
||||
"@ianvs/prettier-plugin-sort-imports",
|
||||
"prettier-plugin-tailwindcss"
|
||||
|
||||
18
pnpm-lock.yaml
generated
18
pnpm-lock.yaml
generated
@@ -336,8 +336,8 @@ importers:
|
||||
specifier: ^3.4.2
|
||||
version: 3.6.2
|
||||
prettier-plugin-tailwindcss:
|
||||
specifier: ^0.6.11
|
||||
version: 0.6.14(@ianvs/prettier-plugin-sort-imports@4.6.1(prettier@3.6.2))(prettier@3.6.2)
|
||||
specifier: ^0.7.2
|
||||
version: 0.7.2(@ianvs/prettier-plugin-sort-imports@4.6.1(prettier@3.6.2))(prettier@3.6.2)
|
||||
tailwindcss:
|
||||
specifier: ^4
|
||||
version: 4.1.18
|
||||
@@ -6511,9 +6511,9 @@ packages:
|
||||
resolution: {integrity: sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
prettier-plugin-tailwindcss@0.6.14:
|
||||
resolution: {integrity: sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
prettier-plugin-tailwindcss@0.7.2:
|
||||
resolution: {integrity: sha512-LkphyK3Fw+q2HdMOoiEHWf93fNtYJwfamoKPl7UwtjFQdei/iIBoX11G6j706FzN3ymX9mPVi97qIY8328vdnA==}
|
||||
engines: {node: '>=20.19'}
|
||||
peerDependencies:
|
||||
'@ianvs/prettier-plugin-sort-imports': '*'
|
||||
'@prettier/plugin-hermes': '*'
|
||||
@@ -6525,14 +6525,12 @@ packages:
|
||||
prettier: ^3.0
|
||||
prettier-plugin-astro: '*'
|
||||
prettier-plugin-css-order: '*'
|
||||
prettier-plugin-import-sort: '*'
|
||||
prettier-plugin-jsdoc: '*'
|
||||
prettier-plugin-marko: '*'
|
||||
prettier-plugin-multiline-arrays: '*'
|
||||
prettier-plugin-organize-attributes: '*'
|
||||
prettier-plugin-organize-imports: '*'
|
||||
prettier-plugin-sort-imports: '*'
|
||||
prettier-plugin-style-order: '*'
|
||||
prettier-plugin-svelte: '*'
|
||||
peerDependenciesMeta:
|
||||
'@ianvs/prettier-plugin-sort-imports':
|
||||
@@ -6553,8 +6551,6 @@ packages:
|
||||
optional: true
|
||||
prettier-plugin-css-order:
|
||||
optional: true
|
||||
prettier-plugin-import-sort:
|
||||
optional: true
|
||||
prettier-plugin-jsdoc:
|
||||
optional: true
|
||||
prettier-plugin-marko:
|
||||
@@ -6567,8 +6563,6 @@ packages:
|
||||
optional: true
|
||||
prettier-plugin-sort-imports:
|
||||
optional: true
|
||||
prettier-plugin-style-order:
|
||||
optional: true
|
||||
prettier-plugin-svelte:
|
||||
optional: true
|
||||
|
||||
@@ -14745,7 +14739,7 @@ snapshots:
|
||||
|
||||
prepend-http@2.0.0: {}
|
||||
|
||||
prettier-plugin-tailwindcss@0.6.14(@ianvs/prettier-plugin-sort-imports@4.6.1(prettier@3.6.2))(prettier@3.6.2):
|
||||
prettier-plugin-tailwindcss@0.7.2(@ianvs/prettier-plugin-sort-imports@4.6.1(prettier@3.6.2))(prettier@3.6.2):
|
||||
dependencies:
|
||||
prettier: 3.6.2
|
||||
optionalDependencies:
|
||||
|
||||
Reference in New Issue
Block a user