From c2a8ebbd011ace204fd45bb91ea186c83358c703 Mon Sep 17 00:00:00 2001 From: tianyaxiang Date: Thu, 30 Jan 2025 10:03:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A8=A1=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/templates.ts | 63 ------------------ src/config/wechat-templates.ts | 116 +++++++++++++++++++++++++++------ src/lib/markdown.ts | 63 +++++++++++++----- 3 files changed, 142 insertions(+), 100 deletions(-) delete mode 100644 src/config/templates.ts diff --git a/src/config/templates.ts b/src/config/templates.ts deleted file mode 100644 index 77bc1ee..0000000 --- a/src/config/templates.ts +++ /dev/null @@ -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(/

/g, '

') - .replace(/

/g, '

') - } - }, - { - id: 'elegant', - name: '优雅简约', - styles: 'wechat-elegant', - transform: (content: string) => { - return content - .replace(/

/g, '

') - .replace(/

/g, '

') - } - }, - { - id: 'modern', - name: '现代商务', - styles: 'wechat-modern', - transform: (content: string) => { - return content - .replace(/

/g, '

') - .replace(/

/g, '

') - } - }, - { - id: 'creative', - name: '创意活力', - styles: 'wechat-creative', - transform: (content: string) => { - return content - .replace(/

/g, '

') - .replace(/

/g, '

') - } - } - ], - transform: (content: string) => content // 默认转换 - }, - { - id: 'xiaohongshu', - name: '小红书', - styles: 'xiaohongshu-template', - transform: (content: string) => { - // 小红书特定的转换逻辑 - return content - .replace(/

/g, '

') - .replace(/

/g, '

') - } - } -] \ No newline at end of file diff --git a/src/config/wechat-templates.ts b/src/config/wechat-templates.ts index cdcaa39..daa5f3d 100644 --- a/src/config/wechat-templates.ts +++ b/src/config/wechat-templates.ts @@ -158,14 +158,7 @@ export const templates: Template[] = [ } } }, - transform: (html) => ` -

- - ${html} -
- ` + transform: (html) => html }, { id: 'modern', @@ -233,13 +226,8 @@ export const templates: Template[] = [ } } }, - transform: (html) => ` -
-
- ${html} -
-
- ` + transform: (html) => html + }, { id: 'creative', @@ -376,10 +364,98 @@ export const templates: Template[] = [ } } }, - transform: (html) => ` -
- ${html} -
- ` + 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 } ] \ No newline at end of file diff --git a/src/lib/markdown.ts b/src/lib/markdown.ts index 80e5734..c7ff7f6 100644 --- a/src/lib/markdown.ts +++ b/src/lib/markdown.ts @@ -40,8 +40,11 @@ function baseStylesToString(base: RendererOptions['base'] = {}): string { // 预处理函数 function preprocessMarkdown(markdown: string): string { - // 处理 ** 语法,但排除已经是 HTML 的部分 - return markdown.replace(/(?]*)\*\*([^*]+)\*\*(?![^<]*>)/g, '$1') + return markdown + // 处理 ** 语法,但排除已经是 HTML 的部分 + .replace(/(?]*)\*\*([^*]+)\*\*(?![^<]*>)/g, '$1') + // 处理无序列表的 - 标记,但排除代码块内的部分 + .replace(/^(?!\s*```)([ \t]*)-\s+/gm, '$1• ') } // Initialize marked instance @@ -129,23 +132,49 @@ export function convertToWechat(markdown: string, options: RendererOptions = {}) return `${text}` } - 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}` - } +// 重写 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('')}` + } catch (error) { + console.error(`Error rendering list: ${error}`) + return `<${tag}>${token.items.map(item => customRenderer.listitem(item)).join('')}` + } +} - 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 `${content}` +// 重写 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 = ` ` + itemText = checkbox + itemText + } + + // 使用 Lexer 和 Parser 处理剩余的内联标记 + const tokens = marked.Lexer.lexInline(itemText) + const content = marked.Parser.parseInline(tokens, { renderer: customRenderer }) + + return `${content}` + } catch (error) { + console.error(`Error rendering list item: ${error}`) + return `
  • ${item.text}
  • ` + } } + + + // Convert Markdown to HTML using the custom renderer const html = marked.parse(markdown, { renderer: customRenderer }) as string