'use client' import { useState } from 'react' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' import { Settings2, Download, Upload, Star, Plus } from 'lucide-react' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Textarea } from '@/components/ui/textarea' import { templates as defaultTemplates, type Template } from '@/config/wechat-templates' import { useLocalStorage } from '@/hooks/use-local-storage' import { cn } from '@/lib/utils' interface TemplateManagerProps { onTemplateChange: () => void } interface StyleConfig { base: { '--md-primary-color': string 'text-align': string 'line-height': string } block: { container?: React.CSSProperties h1?: React.CSSProperties h2?: React.CSSProperties h3?: React.CSSProperties h4?: React.CSSProperties h5?: React.CSSProperties h6?: React.CSSProperties p?: React.CSSProperties blockquote?: React.CSSProperties blockquote_p?: React.CSSProperties code_pre?: React.CSSProperties code?: React.CSSProperties image?: React.CSSProperties ol?: React.CSSProperties ul?: React.CSSProperties footnotes?: React.CSSProperties figure?: React.CSSProperties hr?: React.CSSProperties } inline: { listitem?: React.CSSProperties codespan?: React.CSSProperties em?: React.CSSProperties link?: React.CSSProperties wx_link?: React.CSSProperties strong?: React.CSSProperties table?: React.CSSProperties thead?: React.CSSProperties td?: React.CSSProperties footnote?: React.CSSProperties figcaption?: React.CSSProperties } } export function TemplateManager({ onTemplateChange }: TemplateManagerProps) { const [customTemplates, setCustomTemplates] = useLocalStorage('custom-templates', []) const [favoriteIds, setFavoriteIds] = useLocalStorage('favorite-templates', []) const [newTemplate, setNewTemplate] = useState>({}) const allTemplates = [...defaultTemplates, ...customTemplates] const handleAddTemplate = () => { if (!newTemplate.id || !newTemplate.name) return const template: Template = { id: newTemplate.id, name: newTemplate.name, description: newTemplate.description || '', styles: newTemplate.styles || '', options: { fontSize: {}, colors: {}, spacing: {} }, transform: (html) => html } setCustomTemplates([...customTemplates, template]) setNewTemplate({}) onTemplateChange() } const handleExportTemplates = () => { const exportData = customTemplates.map(template => ({ id: template.id, name: template.name, description: template.description, styles: template.styles, styleConfig: { base: { '--md-primary-color': template.options.base?.primaryColor || '#000000', 'text-align': template.options.base?.textAlign || 'left', 'line-height': template.options.base?.lineHeight || '1.75' }, block: { h1: template.options.block?.h1, h2: template.options.block?.h2, h3: template.options.block?.h3, // ... 其他块级元素 }, inline: { strong: template.options.inline?.strong, em: template.options.inline?.em, codespan: template.options.inline?.codespan, // ... 其他内联元素 } } })) const data = JSON.stringify(exportData, null, 2) const blob = new Blob([data], { type: 'application/json' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = 'wechat-templates.json' a.click() URL.revokeObjectURL(url) } const handleImportTemplates = (event: React.ChangeEvent) => { const file = event.target.files?.[0] if (!file) return const reader = new FileReader() reader.onload = (e) => { try { const importData = JSON.parse(e.target?.result as string) const templates = importData.map((data: any) => ({ id: data.id, name: data.name, description: data.description, styles: data.styles, options: { base: { primaryColor: data.styleConfig.base['--md-primary-color'], textAlign: data.styleConfig.base['text-align'], lineHeight: data.styleConfig.base['line-height'] }, block: { h1: data.styleConfig.block.h1, h2: data.styleConfig.block.h2, h3: data.styleConfig.block.h3, // ... 其他块级元素 }, inline: { strong: data.styleConfig.inline.strong, em: data.styleConfig.inline.em, codespan: data.styleConfig.inline.codespan, // ... 其他内联元素 } }, transform: (html: string) => { return `
${html}
` } })) setCustomTemplates(prev => [...prev, ...templates]) onTemplateChange() } catch (error) { console.error('导入失败:', error) } } reader.readAsText(file) } const toggleFavorite = (templateId: string) => { setFavoriteIds(prev => prev.includes(templateId) ? prev.filter(id => id !== templateId) : [...prev, templateId] ) } return ( 模板管理 所有模板 收藏模板 自定义模板 添加模板
{allTemplates.map((template) => (

{template.name}

{template.description}

))}
{allTemplates .filter(template => favoriteIds.includes(template.id)) .map((template) => (

{template.name}

{template.description}

))}
{customTemplates.map((template) => (

{template.name}

{template.description}

))}
setNewTemplate({ ...newTemplate, id: e.target.value })} />
setNewTemplate({ ...newTemplate, name: e.target.value })} />