优化模版

This commit is contained in:
tianyaxiang 2025-01-30 10:03:55 +08:00
parent cdca9d4d3f
commit c2a8ebbd01
3 changed files with 142 additions and 100 deletions

View File

@ -1,63 +0,0 @@
import { Template } from '@/types/template'
export const templates: Template[] = [
{
id: 'wechat',
name: '微信公众号',
styles: 'wechat-template',
subTemplates: [
{
id: 'default',
name: '默认样式',
styles: 'wechat-default',
transform: (content: string) => {
return content
.replace(/<h1>/g, '<h1 style="font-size: 24px; font-weight: bold; margin-bottom: 1em;">')
.replace(/<p>/g, '<p style="margin-bottom: 1em; color: #333; line-height: 1.75;">')
}
},
{
id: 'elegant',
name: '优雅简约',
styles: 'wechat-elegant',
transform: (content: string) => {
return content
.replace(/<h1>/g, '<h1 style="font-size: 26px; font-weight: 600; margin-bottom: 1.2em; color: #2c3e50;">')
.replace(/<p>/g, '<p style="margin-bottom: 1.2em; color: #34495e; line-height: 1.8; letter-spacing: 0.05em;">')
}
},
{
id: 'modern',
name: '现代商务',
styles: 'wechat-modern',
transform: (content: string) => {
return content
.replace(/<h1>/g, '<h1 style="font-size: 28px; font-weight: bold; margin-bottom: 1em; color: #1a202c; border-bottom: 2px solid #e2e8f0; padding-bottom: 0.5em;">')
.replace(/<p>/g, '<p style="margin-bottom: 1.1em; color: #4a5568; line-height: 1.85; font-size: 16px;">')
}
},
{
id: 'creative',
name: '创意活力',
styles: 'wechat-creative',
transform: (content: string) => {
return content
.replace(/<h1>/g, '<h1 style="font-size: 24px; font-weight: bold; margin-bottom: 1em; color: #2d3748; background: linear-gradient(to right, #4299e1, #667eea); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">')
.replace(/<p>/g, '<p style="margin-bottom: 1em; color: #4a5568; line-height: 1.75; border-left: 3px solid #4299e1; padding-left: 1em;">')
}
}
],
transform: (content: string) => content // 默认转换
},
{
id: 'xiaohongshu',
name: '小红书',
styles: 'xiaohongshu-template',
transform: (content: string) => {
// 小红书特定的转换逻辑
return content
.replace(/<h1>/g, '<h1 style="font-size: 20px; font-weight: bold; margin-bottom: 0.5em;">')
.replace(/<p>/g, '<p style="margin-bottom: 0.8em; color: #222; line-height: 1.6;">')
}
}
]

View File

@ -158,14 +158,7 @@ export const templates: Template[] = [
}
}
},
transform: (html) => `
<section style="font-family: 'Georgia', serif;">
<style>
:root { --md-primary-color: #16a34a; }
</style>
${html}
</section>
`
transform: (html) => html
},
{
id: 'modern',
@ -233,13 +226,8 @@ export const templates: Template[] = [
}
}
},
transform: (html) => `
<section style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
<div style="max-width: 100%; margin: 0 auto; color: #374151;">
${html}
</div>
</section>
`
transform: (html) => html
},
{
id: 'creative',
@ -376,10 +364,98 @@ export const templates: Template[] = [
}
}
},
transform: (html) => `
<section style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
${html}
</section>
`
transform: (html) => html
},
{
id: 'ios-notes',
name: '备忘录风格',
description: '仿 iOS 备忘录风格',
styles: 'prose-ios-notes',
options: {
base: {
primaryColor: '#FF9500',
textAlign: 'left',
lineHeight: '1.6'
},
block: {
h1: {
fontSize: '24px',
color: '#1C1C1E',
margin: '32px 0 16px',
fontWeight: '600',
fontFamily: '-apple-system, BlinkMacSystemFont, "SF Pro Text"'
},
h2: {
fontSize: '20px',
color: '#1C1C1E',
margin: '24px 0 12px',
fontWeight: '600',
fontFamily: '-apple-system, BlinkMacSystemFont, "SF Pro Text"'
},
h3: {
fontSize: '18px',
color: '#1C1C1E',
margin: '20px 0 10px',
fontWeight: '600',
fontFamily: '-apple-system, BlinkMacSystemFont, "SF Pro Text"'
},
p: {
fontSize: '17px',
color: '#333333',
margin: '16px 0',
lineHeight: 1.6,
fontFamily: '-apple-system, BlinkMacSystemFont, "SF Pro Text"'
},
blockquote: {
fontSize: '17px',
color: '#666666',
borderLeft: '4px solid #FF9500',
background: '#FAFAFA',
padding: '12px 16px',
margin: '16px 0',
borderRadius: '4px'
},
code_pre: {
fontSize: '15px',
background: '#F2F2F7',
padding: '12px 16px',
borderRadius: '8px',
margin: '16px 0',
fontFamily: 'Menlo, Monaco, "SF Mono", monospace'
},
ul: {
paddingLeft: '24px',
margin: '16px 0'
},
ol: {
paddingLeft: '24px',
margin: '16px 0'
}
},
inline: {
strong: {
color: '#1C1C1E',
fontWeight: '600'
},
em: {
color: '#666666',
fontStyle: 'italic'
},
link: {
color: '#007AFF',
textDecoration: 'none'
},
codespan: {
color: '#E73C3E',
background: '#F2F2F7',
padding: '2px 6px',
borderRadius: '4px',
fontSize: '90%',
fontFamily: 'Menlo, Monaco, "SF Mono", monospace'
}
}
},
transform: (html) => html
}
]

View File

@ -40,8 +40,11 @@ function baseStylesToString(base: RendererOptions['base'] = {}): string {
// 预处理函数
function preprocessMarkdown(markdown: string): string {
// 处理 ** 语法,但排除已经是 HTML 的部分
return markdown.replace(/(?<!<[^>]*)\*\*([^*]+)\*\*(?![^<]*>)/g, '<strong>$1</strong>')
return markdown
// 处理 ** 语法,但排除已经是 HTML 的部分
.replace(/(?<!<[^>]*)\*\*([^*]+)\*\*(?![^<]*>)/g, '<strong>$1</strong>')
// 处理无序列表的 - 标记,但排除代码块内的部分
.replace(/^(?!\s*```)([ \t]*)-\s+/gm, '$1• ')
}
// Initialize marked instance
@ -129,23 +132,49 @@ export function convertToWechat(markdown: string, options: RendererOptions = {})
return `<img src="${href}"${title ? ` title="${title}"` : ''} alt="${text}"${styleStr ? ` style="${styleStr}"` : ''} />`
}
customRenderer.list = function(body: Tokens.List) {
const ordered = body.ordered
const tag = ordered ? 'ol' : 'ul'
const style = options.block?.[ordered ? 'ol' : 'ul']
const styleStr = cssPropertiesToString(style)
const tokens = marked.Lexer.lexInline(body.raw)
const content = marked.Parser.parseInline(tokens, { renderer: customRenderer })
return `<${tag}${styleStr ? ` style="${styleStr}"` : ''}>${content}</${tag}>`
}
// 重写 list 方法
customRenderer.list = function(token: Tokens.List): string {
const tag = token.ordered ? 'ol' : 'ul'
try {
const style = options.block?.[token.ordered ? 'ol' : 'ul']
const styleStr = cssPropertiesToString(style)
const startAttr = token.ordered && token.start !== 1 ? ` start="${token.start}"` : ''
return `<${tag}${startAttr}${styleStr ? ` style="${styleStr}"` : ''}>${token.items.map(item => customRenderer.listitem(item)).join('')}</${tag}>`
} catch (error) {
console.error(`Error rendering list: ${error}`)
return `<${tag}>${token.items.map(item => customRenderer.listitem(item)).join('')}</${tag}>`
}
}
customRenderer.listitem = function(item: Tokens.ListItem) {
const style = options.inline?.listitem
const styleStr = cssPropertiesToString(style)
const tokens = marked.Lexer.lexInline(item.text)
const content = marked.Parser.parseInline(tokens, { renderer: customRenderer })
return `<li${styleStr ? ` style="${styleStr}"` : ''}>${content}</li>`
// 重写 listitem 方法
customRenderer.listitem = function(item: Tokens.ListItem) {
try {
const style = options.inline?.listitem
const styleStr = cssPropertiesToString(style)
// 移除列表项开头的破折号和空格
let itemText = item.text.replace(/^- /, '')
// 处理任务列表项
if (item.task) {
const checkbox = `<input type="checkbox"${item.checked ? ' checked=""' : ''} disabled="" /> `
itemText = checkbox + itemText
}
// 使用 Lexer 和 Parser 处理剩余的内联标记
const tokens = marked.Lexer.lexInline(itemText)
const content = marked.Parser.parseInline(tokens, { renderer: customRenderer })
return `<li${styleStr ? ` style="${styleStr}"` : ''}>${content}</li>`
} catch (error) {
console.error(`Error rendering list item: ${error}`)
return `<li>${item.text}</li>`
}
}
// Convert Markdown to HTML using the custom renderer
const html = marked.parse(markdown, { renderer: customRenderer }) as string