优化项目启动器的配置样式
This commit is contained in:
@@ -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]}
|
|
||||||
onValueChange={(v) => onConfigChange(field.key, v)}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="h-8">
|
|
||||||
<SelectValue />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
{field.options.map((opt) => (
|
|
||||||
<SelectItem key={opt.value} value={opt.value}>
|
|
||||||
{opt.label}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
</div>
|
||||||
|
|
||||||
|
<Separator />
|
||||||
|
|
||||||
|
{/* Colors */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<SectionHeader>{t("config.sectionColors")}</SectionHeader>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{field("baseColor", "config.baseColor", BASE_COLOR_OPTIONS)}
|
||||||
|
<div className="grid grid-cols-2 gap-x-3 gap-y-2">
|
||||||
|
{field("theme", "config.theme", THEME_OPTIONS)}
|
||||||
|
{field("chartColor", "config.chartColor", THEME_OPTIONS)}
|
||||||
|
</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>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
|
|
||||||
|
|||||||
@@ -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>(
|
||||||
|
|||||||
@@ -1593,7 +1593,11 @@
|
|||||||
"menuColor": "لون القائمة",
|
"menuColor": "لون القائمة",
|
||||||
"radius": "نصف القطر",
|
"radius": "نصف القطر",
|
||||||
"template": "القالب",
|
"template": "القالب",
|
||||||
"createProject": "إنشاء مشروع"
|
"createProject": "إنشاء مشروع",
|
||||||
|
"sectionStyle": "النمط",
|
||||||
|
"sectionColors": "الألوان",
|
||||||
|
"sectionTypography": "الخطوط",
|
||||||
|
"sectionInterface": "الواجهة"
|
||||||
},
|
},
|
||||||
"preview": {
|
"preview": {
|
||||||
"loading": "جاري تحميل المعاينة..."
|
"loading": "جاري تحميل المعاينة..."
|
||||||
|
|||||||
@@ -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..."
|
||||||
|
|||||||
@@ -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..."
|
||||||
|
|||||||
@@ -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..."
|
||||||
|
|||||||
@@ -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..."
|
||||||
|
|||||||
@@ -1593,7 +1593,11 @@
|
|||||||
"menuColor": "メニューカラー",
|
"menuColor": "メニューカラー",
|
||||||
"radius": "角丸",
|
"radius": "角丸",
|
||||||
"template": "テンプレート",
|
"template": "テンプレート",
|
||||||
"createProject": "プロジェクトを作成"
|
"createProject": "プロジェクトを作成",
|
||||||
|
"sectionStyle": "スタイル",
|
||||||
|
"sectionColors": "カラー",
|
||||||
|
"sectionTypography": "タイポグラフィ",
|
||||||
|
"sectionInterface": "インターフェース"
|
||||||
},
|
},
|
||||||
"preview": {
|
"preview": {
|
||||||
"loading": "プレビューを読み込み中..."
|
"loading": "プレビューを読み込み中..."
|
||||||
|
|||||||
@@ -1593,7 +1593,11 @@
|
|||||||
"menuColor": "메뉴 색상",
|
"menuColor": "메뉴 색상",
|
||||||
"radius": "둥글기",
|
"radius": "둥글기",
|
||||||
"template": "템플릿",
|
"template": "템플릿",
|
||||||
"createProject": "프로젝트 만들기"
|
"createProject": "프로젝트 만들기",
|
||||||
|
"sectionStyle": "스타일",
|
||||||
|
"sectionColors": "색상",
|
||||||
|
"sectionTypography": "타이포그래피",
|
||||||
|
"sectionInterface": "인터페이스"
|
||||||
},
|
},
|
||||||
"preview": {
|
"preview": {
|
||||||
"loading": "미리보기 로딩 중..."
|
"loading": "미리보기 로딩 중..."
|
||||||
|
|||||||
@@ -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..."
|
||||||
|
|||||||
@@ -1593,7 +1593,11 @@
|
|||||||
"menuColor": "菜单颜色",
|
"menuColor": "菜单颜色",
|
||||||
"radius": "圆角",
|
"radius": "圆角",
|
||||||
"template": "模板",
|
"template": "模板",
|
||||||
"createProject": "创建项目"
|
"createProject": "创建项目",
|
||||||
|
"sectionStyle": "风格",
|
||||||
|
"sectionColors": "配色",
|
||||||
|
"sectionTypography": "排版",
|
||||||
|
"sectionInterface": "界面"
|
||||||
},
|
},
|
||||||
"preview": {
|
"preview": {
|
||||||
"loading": "加载预览..."
|
"loading": "加载预览..."
|
||||||
|
|||||||
@@ -1593,7 +1593,11 @@
|
|||||||
"menuColor": "選單顏色",
|
"menuColor": "選單顏色",
|
||||||
"radius": "圓角",
|
"radius": "圓角",
|
||||||
"template": "模板",
|
"template": "模板",
|
||||||
"createProject": "建立專案"
|
"createProject": "建立專案",
|
||||||
|
"sectionStyle": "風格",
|
||||||
|
"sectionColors": "配色",
|
||||||
|
"sectionTypography": "排版",
|
||||||
|
"sectionInterface": "介面"
|
||||||
},
|
},
|
||||||
"preview": {
|
"preview": {
|
||||||
"loading": "載入預覽..."
|
"loading": "載入預覽..."
|
||||||
|
|||||||
Reference in New Issue
Block a user