flnxi-Wu/app/admin/_components/template-manager/BuiltInTemplateGrid.tsx
WuYongJie e4dcb6260a
Some checks failed
CI Check / check (push) Has been cancelled
feat: Admin页面重构 & UI三层架构系统
- 创建统一UI三层架构系统(基础层、颜色层、组合层)
- 拆分Admin页面为独立Tab组件(MonitorTab、UsersTab、DepartmentsTab等)
- 提取公共逻辑到Hooks(useToast、useDataFetch、useUserOperations等)
- 提取工具函数(validators、formatters、api等)
- 创建统一弹窗组件(Modal)和useModal Hook
- 添加错误边界和统一状态组件
- 完善类型定义和可访问性支持
- 更新文档(优化记录、优化计划、更新日志)
2025-11-22 15:17:10 +08:00

77 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import { cardStyles, buttonStyles, buttonModifiers, cn } from '@/lib/ui-styles'
import type { BuiltinTemplateConfig } from './types'
interface BuiltInTemplateGridProps {
presets: BuiltinTemplateConfig[]
onPreview: (presetKey: string) => void
onQuickCreate: (presetKey: string) => void
}
export default function BuiltInTemplateGrid({
presets,
onPreview,
onQuickCreate,
}: BuiltInTemplateGridProps) {
return (
<div className="px-6 pt-5 pb-4 border-b border-slate-200/70 dark:border-slate-700/70">
<div className="flex items-center justify-between gap-4 mb-3">
<div>
<h3 className="text-sm font-semibold text-slate-900 dark:text-white">预制模板(推荐)</h3>
<p className="text-xs text-slate-500 dark:text-slate-400 mt-0.5">常用场景一键启用,也可作为自定义模板的起点</p>
<p className="text-[11px] text-slate-400 dark:text-slate-500">
点击卡片仅预览示例,内容不可直接编辑,需复制为自定义模板后才可修改。
</p>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
{presets.map((preset) => {
const fieldCount = preset.getFields().length
return (
<div
key={preset.key}
className={cn(cardStyles.hover, 'group relative overflow-hidden cursor-pointer')}
onClick={() => onPreview(preset.key)}
>
<div className="absolute inset-x-0 top-0 h-1 bg-gradient-to-r from-blue-500/70 via-purple-500/60 to-blue-500/70 opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
<div className="flex items-start justify-between gap-3">
<div className="space-y-1">
<p className="text-sm font-semibold text-slate-900 dark:text-white tracking-tight">{preset.name}</p>
<p className="text-xs text-slate-500 dark:text-slate-400 leading-snug">{preset.description}</p>
</div>
<span className="px-2.5 py-0.5 rounded-full text-[11px] font-medium text-blue-600 dark:text-blue-300 bg-blue-50/70 dark:bg-blue-900/30 border border-blue-100/70 dark:border-blue-800/60">
推荐
</span>
</div>
<div className="mt-4 flex items-center justify-between gap-3">
<div className="flex items-center gap-1.5 text-[11px] text-slate-400 dark:text-slate-500">
<svg className="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.8} d="M4 7h16M4 12h10m-10 5h7" />
</svg>
<span>{fieldCount} 个字段</span>
</div>
<button
type="button"
onClick={(e) => {
e.stopPropagation()
onQuickCreate(preset.key)
}}
className={cn(buttonStyles.success, buttonModifiers.compactXs, buttonModifiers.pill, 'inline-flex items-center gap-1.5 shadow-none')}
>
<svg className="w-3.5 h-3.5" viewBox="0 0 20 20" fill="currentColor">
<path d="M10 3.5a.75.75 0 01.75.75v5h5a.75.75 0 010 1.5h-5v5a.75.75 0 01-1.5 0v-5h-5a.75.75 0 010-1.5h5v-5A.75.75 0 0110 3.5z" />
</svg>
一键创建并启用
</button>
</div>
</div>
)
})}
</div>
</div>
)
}