初始化项目启动器代码
This commit is contained in:
286
src/components/project-boot/shadcn/constants.ts
Normal file
286
src/components/project-boot/shadcn/constants.ts
Normal file
@@ -0,0 +1,286 @@
|
||||
// ── Preset encoding/decoding (matches shadcn v2 format) ─────────────
|
||||
|
||||
const PRESET_STYLES = [
|
||||
"nova",
|
||||
"vega",
|
||||
"maia",
|
||||
"lyra",
|
||||
"mira",
|
||||
] as const
|
||||
|
||||
const PRESET_BASE_COLORS = [
|
||||
"neutral",
|
||||
"stone",
|
||||
"zinc",
|
||||
"gray",
|
||||
"mauve",
|
||||
"olive",
|
||||
"mist",
|
||||
"taupe",
|
||||
] as const
|
||||
|
||||
const PRESET_THEMES = [
|
||||
"neutral",
|
||||
"stone",
|
||||
"zinc",
|
||||
"gray",
|
||||
"amber",
|
||||
"blue",
|
||||
"cyan",
|
||||
"emerald",
|
||||
"fuchsia",
|
||||
"green",
|
||||
"indigo",
|
||||
"lime",
|
||||
"orange",
|
||||
"pink",
|
||||
"purple",
|
||||
"red",
|
||||
"rose",
|
||||
"sky",
|
||||
"teal",
|
||||
"violet",
|
||||
"yellow",
|
||||
"mauve",
|
||||
"olive",
|
||||
"mist",
|
||||
"taupe",
|
||||
] as const
|
||||
|
||||
const PRESET_ICON_LIBRARIES = [
|
||||
"lucide",
|
||||
"hugeicons",
|
||||
"tabler",
|
||||
"phosphor",
|
||||
"remixicon",
|
||||
] as const
|
||||
|
||||
const PRESET_FONTS = [
|
||||
"inter",
|
||||
"noto-sans",
|
||||
"nunito-sans",
|
||||
"figtree",
|
||||
"roboto",
|
||||
"raleway",
|
||||
"dm-sans",
|
||||
"public-sans",
|
||||
"outfit",
|
||||
"jetbrains-mono",
|
||||
"geist",
|
||||
"geist-mono",
|
||||
"lora",
|
||||
"merriweather",
|
||||
"playfair-display",
|
||||
"noto-serif",
|
||||
"roboto-slab",
|
||||
"oxanium",
|
||||
"manrope",
|
||||
"space-grotesk",
|
||||
"montserrat",
|
||||
"ibm-plex-sans",
|
||||
"source-sans-3",
|
||||
"instrument-sans",
|
||||
] as const
|
||||
|
||||
const PRESET_FONT_HEADINGS = ["inherit", ...PRESET_FONTS] as const
|
||||
|
||||
const PRESET_RADII = [
|
||||
"default",
|
||||
"none",
|
||||
"small",
|
||||
"medium",
|
||||
"large",
|
||||
] as const
|
||||
|
||||
const PRESET_MENU_ACCENTS = ["subtle", "bold"] as const
|
||||
|
||||
const PRESET_MENU_COLORS = [
|
||||
"default",
|
||||
"inverted",
|
||||
"default-translucent",
|
||||
"inverted-translucent",
|
||||
] as const
|
||||
|
||||
/** V2 field layout for bit-packing (order must match shadcn exactly) */
|
||||
const PRESET_FIELDS_V2 = [
|
||||
{ key: "menuColor", values: PRESET_MENU_COLORS, bits: 3 },
|
||||
{ key: "menuAccent", values: PRESET_MENU_ACCENTS, bits: 3 },
|
||||
{ key: "radius", values: PRESET_RADII, bits: 4 },
|
||||
{ key: "font", values: PRESET_FONTS, bits: 6 },
|
||||
{ key: "iconLibrary", values: PRESET_ICON_LIBRARIES, bits: 6 },
|
||||
{ key: "theme", values: PRESET_THEMES, bits: 6 },
|
||||
{ key: "baseColor", values: PRESET_BASE_COLORS, bits: 6 },
|
||||
{ key: "style", values: PRESET_STYLES, bits: 6 },
|
||||
{ key: "chartColor", values: PRESET_THEMES, bits: 6 },
|
||||
{ key: "fontHeading", values: PRESET_FONT_HEADINGS, bits: 5 },
|
||||
] as const
|
||||
|
||||
const BASE62 =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
function toBase62(num: number): string {
|
||||
if (num === 0) return "0"
|
||||
let result = ""
|
||||
let n = num
|
||||
while (n > 0) {
|
||||
result = BASE62[n % 62] + result
|
||||
n = Math.floor(n / 62)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/** Encode a preset config into a compact base62 code (v2 format). */
|
||||
export function encodePreset(config: PresetCodeConfig): string {
|
||||
const defaults: Record<string, string> = {
|
||||
menuColor: "default",
|
||||
menuAccent: "subtle",
|
||||
radius: "default",
|
||||
font: "inter",
|
||||
iconLibrary: "lucide",
|
||||
theme: "neutral",
|
||||
baseColor: "neutral",
|
||||
style: "nova",
|
||||
chartColor: config.theme ?? "neutral",
|
||||
fontHeading: "inherit",
|
||||
}
|
||||
const merged: Record<string, string> = { ...defaults }
|
||||
for (const [k, v] of Object.entries(config)) {
|
||||
if (v) merged[k] = v
|
||||
}
|
||||
let bits = 0
|
||||
let offset = 0
|
||||
for (const field of PRESET_FIELDS_V2) {
|
||||
const idx = (field.values as readonly string[]).indexOf(
|
||||
merged[field.key] ?? ""
|
||||
)
|
||||
bits += (idx === -1 ? 0 : idx) * 2 ** offset
|
||||
offset += field.bits
|
||||
}
|
||||
return "b" + toBase62(bits)
|
||||
}
|
||||
|
||||
// ── Config types ────────────────────────────────────────────────────
|
||||
|
||||
/** Fields that are encoded into the preset code (sent to CLI & preview). */
|
||||
export interface PresetCodeConfig {
|
||||
style: string
|
||||
baseColor: string
|
||||
theme: string
|
||||
chartColor: string
|
||||
iconLibrary: string
|
||||
font: string
|
||||
fontHeading: string
|
||||
radius: string
|
||||
menuAccent: string
|
||||
menuColor: string
|
||||
}
|
||||
|
||||
/** Full UI config (preset fields + non-preset fields like base/template). */
|
||||
export interface ShadcnPresetConfig extends PresetCodeConfig {
|
||||
base: string
|
||||
template: string
|
||||
}
|
||||
|
||||
export const DEFAULT_PRESET_CONFIG: ShadcnPresetConfig = {
|
||||
base: "radix",
|
||||
style: "nova",
|
||||
baseColor: "neutral",
|
||||
theme: "neutral",
|
||||
chartColor: "neutral",
|
||||
iconLibrary: "lucide",
|
||||
font: "inter",
|
||||
fontHeading: "inherit",
|
||||
radius: "default",
|
||||
menuAccent: "subtle",
|
||||
menuColor: "default",
|
||||
template: "start",
|
||||
}
|
||||
|
||||
// ── UI option arrays ────────────────────────────────────────────────
|
||||
|
||||
export const BASE_OPTIONS = [
|
||||
{ value: "radix", label: "Radix" },
|
||||
{ value: "base", label: "Base" },
|
||||
]
|
||||
|
||||
export const STYLE_OPTIONS = PRESET_STYLES.map((v) => ({
|
||||
value: v,
|
||||
label: v.charAt(0).toUpperCase() + v.slice(1),
|
||||
}))
|
||||
|
||||
export const BASE_COLOR_OPTIONS = PRESET_BASE_COLORS.map((v) => ({
|
||||
value: v,
|
||||
label: v.charAt(0).toUpperCase() + v.slice(1),
|
||||
}))
|
||||
|
||||
export const THEME_OPTIONS = PRESET_THEMES.map((v) => ({
|
||||
value: v,
|
||||
label: v.charAt(0).toUpperCase() + v.slice(1),
|
||||
}))
|
||||
|
||||
export const ICON_LIBRARY_OPTIONS = PRESET_ICON_LIBRARIES.map((v) => ({
|
||||
value: v,
|
||||
label: v.charAt(0).toUpperCase() + v.slice(1),
|
||||
}))
|
||||
|
||||
export const FONT_OPTIONS = PRESET_FONTS.map((v) => ({
|
||||
value: v,
|
||||
label: v
|
||||
.split("-")
|
||||
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
||||
.join(" "),
|
||||
}))
|
||||
|
||||
export const FONT_HEADING_OPTIONS = PRESET_FONT_HEADINGS.map((v) => ({
|
||||
value: v,
|
||||
label:
|
||||
v === "inherit"
|
||||
? "Inherit"
|
||||
: v
|
||||
.split("-")
|
||||
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
||||
.join(" "),
|
||||
}))
|
||||
|
||||
export const MENU_ACCENT_OPTIONS = PRESET_MENU_ACCENTS.map((v) => ({
|
||||
value: v,
|
||||
label: v.charAt(0).toUpperCase() + v.slice(1),
|
||||
}))
|
||||
|
||||
export const MENU_COLOR_OPTIONS = PRESET_MENU_COLORS.map((v) => ({
|
||||
value: v,
|
||||
label: v
|
||||
.split("-")
|
||||
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
||||
.join(" "),
|
||||
}))
|
||||
|
||||
export const RADIUS_OPTIONS = PRESET_RADII.map((v) => ({
|
||||
value: v,
|
||||
label: v.charAt(0).toUpperCase() + v.slice(1),
|
||||
}))
|
||||
|
||||
export const TEMPLATE_OPTIONS = [{ value: "start", label: "Start" }]
|
||||
|
||||
export const FRAMEWORK_OPTIONS = [
|
||||
{ value: "next", label: "Next.js" },
|
||||
{ value: "vite", label: "Vite" },
|
||||
{ value: "start", label: "TanStack Start" },
|
||||
{ value: "react-router", label: "React Router" },
|
||||
{ value: "laravel", label: "Laravel" },
|
||||
{ value: "astro", label: "Astro" },
|
||||
]
|
||||
|
||||
export const PACKAGE_MANAGER_OPTIONS = [
|
||||
{ value: "pnpm", label: "pnpm" },
|
||||
{ value: "npm", label: "npm" },
|
||||
{ value: "yarn", label: "yarn" },
|
||||
{ value: "bun", label: "bun" },
|
||||
]
|
||||
|
||||
// ── URL builders ────────────────────────────────────────────────────
|
||||
|
||||
/** Build the preview iframe URL using a preset code. */
|
||||
export function buildPreviewUrl(base: string, presetCode: string): string {
|
||||
return `https://ui.shadcn.com/preview/${base}/preview?preset=${presetCode}`
|
||||
}
|
||||
Reference in New Issue
Block a user