优化项目启动器的配置样式

This commit is contained in:
xintaofei
2026-03-27 17:05:06 +08:00
parent 298ecb9ff6
commit c013876bbd
12 changed files with 149 additions and 84 deletions

View File

@@ -12,6 +12,7 @@ import {
SelectValue, SelectValue,
} from "@/components/ui/select" } from "@/components/ui/select"
import { ScrollArea } from "@/components/ui/scroll-area" import { ScrollArea } from "@/components/ui/scroll-area"
import { Separator } from "@/components/ui/separator"
import { import {
STYLE_OPTIONS, STYLE_OPTIONS,
BASE_COLOR_OPTIONS, BASE_COLOR_OPTIONS,
@@ -33,56 +34,43 @@ interface ShadcnConfigPanelProps {
presetCode: string presetCode: string
} }
type ConfigI18nKey = function ConfigField({
| "config.style" label,
| "config.baseColor" value,
| "config.theme" options,
| "config.chartColor" onChange,
| "config.iconLibrary" }: {
| "config.font" label: string
| "config.fontHeading" value: string
| "config.menuAccent"
| "config.menuColor"
| "config.radius"
| "config.template"
const CONFIG_FIELDS: {
key: keyof ShadcnPresetConfig
i18nKey: ConfigI18nKey
options: { value: string; label: string }[] options: { value: string; label: string }[]
}[] = [ onChange: (v: string) => void
{ key: "style", i18nKey: "config.style", options: STYLE_OPTIONS }, }) {
{ return (
key: "baseColor", <div className="space-y-1">
i18nKey: "config.baseColor", <Label className="text-xs text-muted-foreground">{label}</Label>
options: BASE_COLOR_OPTIONS, <Select value={value} onValueChange={onChange}>
}, <SelectTrigger className="h-8">
{ key: "theme", i18nKey: "config.theme", options: THEME_OPTIONS }, <SelectValue />
{ key: "chartColor", i18nKey: "config.chartColor", options: THEME_OPTIONS }, </SelectTrigger>
{ <SelectContent>
key: "iconLibrary", {options.map((opt) => (
i18nKey: "config.iconLibrary", <SelectItem key={opt.value} value={opt.value}>
options: ICON_LIBRARY_OPTIONS, {opt.label}
}, </SelectItem>
{ key: "font", i18nKey: "config.font", options: FONT_OPTIONS }, ))}
{ </SelectContent>
key: "fontHeading", </Select>
i18nKey: "config.fontHeading", </div>
options: FONT_HEADING_OPTIONS, )
}, }
{
key: "menuAccent", function SectionHeader({ children }: { children: React.ReactNode }) {
i18nKey: "config.menuAccent", return (
options: MENU_ACCENT_OPTIONS, <h4 className="text-[11px] font-medium uppercase tracking-wider text-muted-foreground/70">
}, {children}
{ </h4>
key: "menuColor", )
i18nKey: "config.menuColor", }
options: MENU_COLOR_OPTIONS,
},
{ key: "radius", i18nKey: "config.radius", options: RADIUS_OPTIONS },
{ key: "template", i18nKey: "config.template", options: TEMPLATE_OPTIONS },
]
export function ShadcnConfigPanel({ export function ShadcnConfigPanel({
config, config,
@@ -92,32 +80,69 @@ export function ShadcnConfigPanel({
const t = useTranslations("ProjectBoot") const t = useTranslations("ProjectBoot")
const [createOpen, setCreateOpen] = useState(false) const [createOpen, setCreateOpen] = useState(false)
const field = (
key: keyof ShadcnPresetConfig,
i18nKey: string,
options: { value: string; label: string }[]
) => (
<ConfigField
label={t(i18nKey as Parameters<typeof t>[0])}
value={config[key]}
options={options}
onChange={(v) => onConfigChange(key, v)}
/>
)
return ( return (
<div className="flex h-full flex-col"> <div className="flex h-full flex-col">
<ScrollArea className="min-h-0 flex-1 px-4 py-3"> <ScrollArea className="min-h-0 flex-1 px-4 py-3">
<div className="space-y-3"> <div className="space-y-4">
{CONFIG_FIELDS.map((field) => ( {/* Style & Template */}
<div key={field.key} className="space-y-1"> <div className="space-y-2">
<Label className="text-xs text-muted-foreground"> <SectionHeader>{t("config.sectionStyle")}</SectionHeader>
{t(field.i18nKey)} <div className="grid grid-cols-2 gap-x-3 gap-y-2">
</Label> {field("style", "config.style", STYLE_OPTIONS)}
<Select {field("template", "config.template", TEMPLATE_OPTIONS)}
value={config[field.key]} </div>
onValueChange={(v) => onConfigChange(field.key, v)} </div>
>
<SelectTrigger className="h-8"> <Separator />
<SelectValue />
</SelectTrigger> {/* Colors */}
<SelectContent> <div className="space-y-2">
{field.options.map((opt) => ( <SectionHeader>{t("config.sectionColors")}</SectionHeader>
<SelectItem key={opt.value} value={opt.value}> <div className="space-y-2">
{opt.label} {field("baseColor", "config.baseColor", BASE_COLOR_OPTIONS)}
</SelectItem> <div className="grid grid-cols-2 gap-x-3 gap-y-2">
))} {field("theme", "config.theme", THEME_OPTIONS)}
</SelectContent> {field("chartColor", "config.chartColor", THEME_OPTIONS)}
</Select> </div>
</div>
</div>
<Separator />
{/* Typography */}
<div className="space-y-2">
<SectionHeader>{t("config.sectionTypography")}</SectionHeader>
<div className="grid grid-cols-2 gap-x-3 gap-y-2">
{field("font", "config.font", FONT_OPTIONS)}
{field("fontHeading", "config.fontHeading", FONT_HEADING_OPTIONS)}
</div>
</div>
<Separator />
{/* Interface */}
<div className="space-y-2">
<SectionHeader>{t("config.sectionInterface")}</SectionHeader>
<div className="grid grid-cols-2 gap-x-3 gap-y-2">
{field("iconLibrary", "config.iconLibrary", ICON_LIBRARY_OPTIONS)}
{field("radius", "config.radius", RADIUS_OPTIONS)}
{field("menuAccent", "config.menuAccent", MENU_ACCENT_OPTIONS)}
{field("menuColor", "config.menuColor", MENU_COLOR_OPTIONS)}
</div>
</div> </div>
))}
</div> </div>
</ScrollArea> </ScrollArea>

View File

@@ -11,9 +11,9 @@ import {
type ShadcnPresetConfig, type ShadcnPresetConfig,
} from "./constants" } from "./constants"
const MIN_WIDTH = 280 const MIN_WIDTH = 260
const MAX_WIDTH = 480 const MAX_WIDTH = 420
const DEFAULT_WIDTH = 360 const DEFAULT_WIDTH = 320
export function ShadcnLauncher() { export function ShadcnLauncher() {
const [config, setConfig] = useState<ShadcnPresetConfig>( const [config, setConfig] = useState<ShadcnPresetConfig>(

View File

@@ -1593,7 +1593,11 @@
"menuColor": "لون القائمة", "menuColor": "لون القائمة",
"radius": "نصف القطر", "radius": "نصف القطر",
"template": "القالب", "template": "القالب",
"createProject": "إنشاء مشروع" "createProject": "إنشاء مشروع",
"sectionStyle": "النمط",
"sectionColors": "الألوان",
"sectionTypography": "الخطوط",
"sectionInterface": "الواجهة"
}, },
"preview": { "preview": {
"loading": "جاري تحميل المعاينة..." "loading": "جاري تحميل المعاينة..."

View File

@@ -1593,7 +1593,11 @@
"menuColor": "Menü-Farbe", "menuColor": "Menü-Farbe",
"radius": "Radius", "radius": "Radius",
"template": "Vorlage", "template": "Vorlage",
"createProject": "Projekt erstellen" "createProject": "Projekt erstellen",
"sectionStyle": "Stil",
"sectionColors": "Farben",
"sectionTypography": "Typografie",
"sectionInterface": "Oberfläche"
}, },
"preview": { "preview": {
"loading": "Vorschau wird geladen..." "loading": "Vorschau wird geladen..."

View File

@@ -1593,7 +1593,11 @@
"menuColor": "Menu Color", "menuColor": "Menu Color",
"radius": "Radius", "radius": "Radius",
"template": "Template", "template": "Template",
"createProject": "Create Project" "createProject": "Create Project",
"sectionStyle": "Style",
"sectionColors": "Colors",
"sectionTypography": "Typography",
"sectionInterface": "Interface"
}, },
"preview": { "preview": {
"loading": "Loading preview..." "loading": "Loading preview..."

View File

@@ -1593,7 +1593,11 @@
"menuColor": "Color del menú", "menuColor": "Color del menú",
"radius": "Radio", "radius": "Radio",
"template": "Plantilla", "template": "Plantilla",
"createProject": "Crear proyecto" "createProject": "Crear proyecto",
"sectionStyle": "Estilo",
"sectionColors": "Colores",
"sectionTypography": "Tipografía",
"sectionInterface": "Interfaz"
}, },
"preview": { "preview": {
"loading": "Cargando vista previa..." "loading": "Cargando vista previa..."

View File

@@ -1593,7 +1593,11 @@
"menuColor": "Couleur du menu", "menuColor": "Couleur du menu",
"radius": "Rayon", "radius": "Rayon",
"template": "Modèle", "template": "Modèle",
"createProject": "Créer un projet" "createProject": "Créer un projet",
"sectionStyle": "Style",
"sectionColors": "Couleurs",
"sectionTypography": "Typographie",
"sectionInterface": "Interface"
}, },
"preview": { "preview": {
"loading": "Chargement de l'aperçu..." "loading": "Chargement de l'aperçu..."

View File

@@ -1593,7 +1593,11 @@
"menuColor": "メニューカラー", "menuColor": "メニューカラー",
"radius": "角丸", "radius": "角丸",
"template": "テンプレート", "template": "テンプレート",
"createProject": "プロジェクトを作成" "createProject": "プロジェクトを作成",
"sectionStyle": "スタイル",
"sectionColors": "カラー",
"sectionTypography": "タイポグラフィ",
"sectionInterface": "インターフェース"
}, },
"preview": { "preview": {
"loading": "プレビューを読み込み中..." "loading": "プレビューを読み込み中..."

View File

@@ -1593,7 +1593,11 @@
"menuColor": "메뉴 색상", "menuColor": "메뉴 색상",
"radius": "둥글기", "radius": "둥글기",
"template": "템플릿", "template": "템플릿",
"createProject": "프로젝트 만들기" "createProject": "프로젝트 만들기",
"sectionStyle": "스타일",
"sectionColors": "색상",
"sectionTypography": "타이포그래피",
"sectionInterface": "인터페이스"
}, },
"preview": { "preview": {
"loading": "미리보기 로딩 중..." "loading": "미리보기 로딩 중..."

View File

@@ -1593,7 +1593,11 @@
"menuColor": "Cor do menu", "menuColor": "Cor do menu",
"radius": "Raio", "radius": "Raio",
"template": "Modelo", "template": "Modelo",
"createProject": "Criar projeto" "createProject": "Criar projeto",
"sectionStyle": "Estilo",
"sectionColors": "Cores",
"sectionTypography": "Tipografia",
"sectionInterface": "Interface"
}, },
"preview": { "preview": {
"loading": "Carregando visualização..." "loading": "Carregando visualização..."

View File

@@ -1593,7 +1593,11 @@
"menuColor": "菜单颜色", "menuColor": "菜单颜色",
"radius": "圆角", "radius": "圆角",
"template": "模板", "template": "模板",
"createProject": "创建项目" "createProject": "创建项目",
"sectionStyle": "风格",
"sectionColors": "配色",
"sectionTypography": "排版",
"sectionInterface": "界面"
}, },
"preview": { "preview": {
"loading": "加载预览..." "loading": "加载预览..."

View File

@@ -1593,7 +1593,11 @@
"menuColor": "選單顏色", "menuColor": "選單顏色",
"radius": "圓角", "radius": "圓角",
"template": "模板", "template": "模板",
"createProject": "建立專案" "createProject": "建立專案",
"sectionStyle": "風格",
"sectionColors": "配色",
"sectionTypography": "排版",
"sectionInterface": "介面"
}, },
"preview": { "preview": {
"loading": "載入預覽..." "loading": "載入預覽..."