优化模版
This commit is contained in:
parent
67eb412268
commit
c17182527d
@ -112,9 +112,6 @@
|
|||||||
.preview-content {
|
.preview-content {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
font-size: 15px;
|
|
||||||
line-height: 1.75;
|
|
||||||
color: hsl(var(--foreground));
|
|
||||||
padding:1rem 1.5rem;
|
padding:1rem 1.5rem;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
@ -200,290 +200,64 @@ export default function WechatEditor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// 创建临时容器来处理样式
|
||||||
const tempDiv = document.createElement('div')
|
const tempDiv = document.createElement('div')
|
||||||
tempDiv.innerHTML = previewContent.innerHTML
|
tempDiv.innerHTML = previewContent.innerHTML
|
||||||
|
// 获取当前模板
|
||||||
const template = templates.find(t => t.id === selectedTemplate)
|
const template = templates.find(t => t.id === selectedTemplate)
|
||||||
if (template) {
|
|
||||||
// 添加基础样式容器
|
|
||||||
const styleContainer = document.createElement('div')
|
|
||||||
styleContainer.style.cssText = `
|
|
||||||
max-width: 780px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 0 20px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
`
|
|
||||||
styleContainer.innerHTML = tempDiv.innerHTML
|
|
||||||
tempDiv.innerHTML = ''
|
|
||||||
tempDiv.appendChild(styleContainer)
|
|
||||||
|
|
||||||
// 处理 CSS 变量
|
// 处理 CSS 变量
|
||||||
const cssVariables = {
|
const cssVariables = {
|
||||||
'--md-primary-color': styleOptions.base?.primaryColor || template.options.base?.primaryColor || '#333333',
|
'--md-primary-color': styleOptions.base?.primaryColor || template?.options.base?.primaryColor || '#333333',
|
||||||
'--foreground': styleOptions.base?.themeColor || template.options.base?.themeColor || '#1a1a1a',
|
'--foreground': styleOptions.base?.themeColor || template?.options.base?.themeColor || '#1a1a1a',
|
||||||
'--background': '#ffffff',
|
'--background': '#ffffff',
|
||||||
'--muted': '#f1f5f9',
|
'--muted': '#f1f5f9',
|
||||||
'--muted-foreground': '#64748b',
|
'--muted-foreground': '#64748b',
|
||||||
'--border': '#e2e8f0',
|
'--blockquote-background': 'rgba(0, 0, 0, 0.05)'
|
||||||
'--ring': '#3b82f6',
|
|
||||||
'--accent': '#f8fafc',
|
|
||||||
'--accent-foreground': '#0f172a'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 替换 CSS 变量的函数
|
// 替换所有元素中的 CSS 变量
|
||||||
const replaceCSSVariables = (value: string) => {
|
const replaceVariables = (element: HTMLElement) => {
|
||||||
let result = value
|
const style = window.getComputedStyle(element)
|
||||||
Object.entries(cssVariables).forEach(([variable, replaceValue]) => {
|
const properties = ['color', 'background-color', 'border-color', 'border-left-color']
|
||||||
// 处理 var(--xxx) 格式
|
|
||||||
result = result.replace(
|
properties.forEach(prop => {
|
||||||
new RegExp(`var\\(${variable}\\)`, 'g'),
|
const value = style.getPropertyValue(prop)
|
||||||
replaceValue
|
if (value.includes('var(')) {
|
||||||
)
|
let finalValue = value
|
||||||
// 处理 hsl(var(--xxx)) 格式
|
Object.entries(cssVariables).forEach(([variable, replacement]) => {
|
||||||
result = result.replace(
|
finalValue = finalValue.replace(`var(${variable})`, replacement)
|
||||||
new RegExp(`hsl\\(var\\(${variable}\\)\\)`, 'g'),
|
|
||||||
replaceValue
|
|
||||||
)
|
|
||||||
// 处理 rgb(var(--xxx)) 格式
|
|
||||||
result = result.replace(
|
|
||||||
new RegExp(`rgb\\(var\\(${variable}\\)\\)`, 'g'),
|
|
||||||
replaceValue
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
return result
|
element.style[prop as any] = finalValue
|
||||||
}
|
|
||||||
|
|
||||||
// 合并基础样式
|
|
||||||
const baseStyles = {
|
|
||||||
fontSize: template.options.base?.fontSize || '15px',
|
|
||||||
lineHeight: template.options.base?.lineHeight || '1.75',
|
|
||||||
textAlign: template.options.base?.textAlign || 'left',
|
|
||||||
color: template.options.base?.themeColor || '#1a1a1a',
|
|
||||||
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
|
|
||||||
...(styleOptions.base || {})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理基础样式中的 CSS 变量
|
|
||||||
Object.entries(baseStyles).forEach(([key, value]) => {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
baseStyles[key] = replaceCSSVariables(value)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Object.assign(styleContainer.style, baseStyles)
|
|
||||||
|
|
||||||
// 应用基础样式到所有文本元素
|
// 递归处理子元素
|
||||||
const applyBaseStyles = () => {
|
Array.from(element.children).forEach(child => {
|
||||||
const textElements = styleContainer.querySelectorAll('h1, h2, h3, h4, h5, h6, p, blockquote, li, code, strong, em, a, span')
|
if (child instanceof HTMLElement) {
|
||||||
textElements.forEach(element => {
|
replaceVariables(child)
|
||||||
if (element instanceof HTMLElement) {
|
|
||||||
// 如果元素没有特定的字体和字号设置,应用基础样式
|
|
||||||
if (!element.style.fontFamily) {
|
|
||||||
element.style.fontFamily = baseStyles.fontFamily
|
|
||||||
}
|
|
||||||
if (!element.style.fontSize) {
|
|
||||||
// 根据元素类型设置不同的字号
|
|
||||||
const tagName = element.tagName.toLowerCase()
|
|
||||||
if (tagName === 'h1') {
|
|
||||||
element.style.fontSize = '24px'
|
|
||||||
} else if (tagName === 'h2') {
|
|
||||||
element.style.fontSize = '20px'
|
|
||||||
} else if (tagName === 'h3') {
|
|
||||||
element.style.fontSize = '18px'
|
|
||||||
} else if (tagName === 'code') {
|
|
||||||
element.style.fontSize = '14px'
|
|
||||||
} else {
|
|
||||||
element.style.fontSize = baseStyles.fontSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 确保颜色和行高也被应用
|
|
||||||
if (!element.style.color) {
|
|
||||||
element.style.color = baseStyles.color
|
|
||||||
}
|
|
||||||
if (!element.style.lineHeight) {
|
|
||||||
element.style.lineHeight = baseStyles.lineHeight as string
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 合并块级样式
|
// 处理所有元素
|
||||||
const applyBlockStyles = (selector: string, templateStyles: any, customStyles: any) => {
|
Array.from(tempDiv.children).forEach(child => {
|
||||||
styleContainer.querySelectorAll(selector).forEach(element => {
|
if (child instanceof HTMLElement) {
|
||||||
const effectiveStyles: Record<string, string> = {}
|
replaceVariables(child)
|
||||||
|
|
||||||
// 应用模板样式
|
|
||||||
if (templateStyles) {
|
|
||||||
Object.entries(templateStyles).forEach(([key, value]) => {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
effectiveStyles[key] = replaceCSSVariables(value)
|
|
||||||
} else {
|
|
||||||
effectiveStyles[key] = value as string
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 应用自定义样式
|
|
||||||
if (customStyles) {
|
|
||||||
Object.entries(customStyles).forEach(([key, value]) => {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
effectiveStyles[key] = replaceCSSVariables(value)
|
|
||||||
} else {
|
|
||||||
effectiveStyles[key] = value as string
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确保字体样式被应用
|
|
||||||
if (!effectiveStyles.fontFamily) {
|
|
||||||
effectiveStyles.fontFamily = baseStyles.fontFamily
|
|
||||||
}
|
|
||||||
// 确保字号被应用
|
|
||||||
if (!effectiveStyles.fontSize) {
|
|
||||||
const tagName = (element as HTMLElement).tagName.toLowerCase()
|
|
||||||
if (tagName === 'h1') {
|
|
||||||
effectiveStyles.fontSize = '24px'
|
|
||||||
} else if (tagName === 'h2') {
|
|
||||||
effectiveStyles.fontSize = '20px'
|
|
||||||
} else if (tagName === 'h3') {
|
|
||||||
effectiveStyles.fontSize = '18px'
|
|
||||||
} else if (tagName === 'code') {
|
|
||||||
effectiveStyles.fontSize = '14px'
|
|
||||||
} else {
|
|
||||||
effectiveStyles.fontSize = baseStyles.fontSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.assign((element as HTMLElement).style, effectiveStyles)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 应用标题样式
|
|
||||||
;['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].forEach(tag => {
|
|
||||||
applyBlockStyles(
|
|
||||||
tag,
|
|
||||||
template.options.block?.[tag],
|
|
||||||
styleOptions.block?.[tag]
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 应用段落样式
|
|
||||||
applyBlockStyles(
|
|
||||||
'p',
|
|
||||||
template.options.block?.p,
|
|
||||||
styleOptions.block?.p
|
|
||||||
)
|
|
||||||
|
|
||||||
// 应用引用样式
|
|
||||||
applyBlockStyles(
|
|
||||||
'blockquote',
|
|
||||||
template.options.block?.blockquote,
|
|
||||||
styleOptions.block?.blockquote
|
|
||||||
)
|
|
||||||
|
|
||||||
// 应用代码块样式
|
|
||||||
applyBlockStyles(
|
|
||||||
'pre',
|
|
||||||
template.options.block?.code_pre,
|
|
||||||
styleOptions.block?.code_pre
|
|
||||||
)
|
|
||||||
|
|
||||||
// 应用图片样式
|
|
||||||
applyBlockStyles(
|
|
||||||
'img',
|
|
||||||
template.options.block?.image,
|
|
||||||
styleOptions.block?.image
|
|
||||||
)
|
|
||||||
|
|
||||||
// 应用列表样式
|
|
||||||
applyBlockStyles(
|
|
||||||
'ul',
|
|
||||||
template.options.block?.ul,
|
|
||||||
styleOptions.block?.ul
|
|
||||||
)
|
|
||||||
applyBlockStyles(
|
|
||||||
'ol',
|
|
||||||
template.options.block?.ol,
|
|
||||||
styleOptions.block?.ol
|
|
||||||
)
|
|
||||||
|
|
||||||
// 应用内联样式
|
|
||||||
const applyInlineStyles = (selector: string, templateStyles: any, customStyles: any) => {
|
|
||||||
styleContainer.querySelectorAll(selector).forEach(element => {
|
|
||||||
const effectiveStyles: Record<string, string> = {}
|
|
||||||
|
|
||||||
// 应用模板样式
|
|
||||||
if (templateStyles) {
|
|
||||||
Object.entries(templateStyles).forEach(([key, value]) => {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
effectiveStyles[key] = replaceCSSVariables(value)
|
|
||||||
} else {
|
|
||||||
effectiveStyles[key] = value as string
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 应用自定义样式
|
|
||||||
if (customStyles) {
|
|
||||||
Object.entries(customStyles).forEach(([key, value]) => {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
effectiveStyles[key] = replaceCSSVariables(value)
|
|
||||||
} else {
|
|
||||||
effectiveStyles[key] = value as string
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.assign((element as HTMLElement).style, effectiveStyles)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 应用加粗样式
|
|
||||||
applyInlineStyles(
|
|
||||||
'strong',
|
|
||||||
template.options.inline?.strong,
|
|
||||||
styleOptions.inline?.strong
|
|
||||||
)
|
|
||||||
|
|
||||||
// 应用斜体样式
|
|
||||||
applyInlineStyles(
|
|
||||||
'em',
|
|
||||||
template.options.inline?.em,
|
|
||||||
styleOptions.inline?.em
|
|
||||||
)
|
|
||||||
|
|
||||||
// 应用行内代码样式
|
|
||||||
applyInlineStyles(
|
|
||||||
'code:not(pre code)',
|
|
||||||
template.options.inline?.codespan,
|
|
||||||
styleOptions.inline?.codespan
|
|
||||||
)
|
|
||||||
|
|
||||||
// 应用链接样式
|
|
||||||
applyInlineStyles(
|
|
||||||
'a',
|
|
||||||
template.options.inline?.link,
|
|
||||||
styleOptions.inline?.link
|
|
||||||
)
|
|
||||||
|
|
||||||
// 在应用所有样式后,确保基础样式被正确应用
|
|
||||||
applyBaseStyles()
|
|
||||||
}
|
|
||||||
|
|
||||||
const htmlBlob = new Blob([tempDiv.innerHTML], { type: 'text/html' })
|
|
||||||
const textBlob = new Blob([tempDiv.innerText], { type: 'text/plain' })
|
|
||||||
|
|
||||||
|
// 创建并写入剪贴板
|
||||||
await navigator.clipboard.write([
|
await navigator.clipboard.write([
|
||||||
new ClipboardItem({
|
new ClipboardItem({
|
||||||
'text/html': htmlBlob,
|
'text/html': new Blob([tempDiv.innerHTML], { type: 'text/html' }),
|
||||||
'text/plain': textBlob
|
'text/plain': new Blob([tempDiv.innerText], { type: 'text/plain' })
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: "复制成功",
|
title: "复制成功",
|
||||||
description: template
|
description: "已复制预览内容",
|
||||||
? "已复制预览内容(包含样式)"
|
|
||||||
: "已复制预览内容",
|
|
||||||
duration: 2000
|
duration: 2000
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -52,6 +52,7 @@ export const templates: Template[] = [
|
|||||||
lineHeight: 1.2
|
lineHeight: 1.2
|
||||||
},
|
},
|
||||||
p: {
|
p: {
|
||||||
|
fontSize:'12px',
|
||||||
margin: '1.5em 8px',
|
margin: '1.5em 8px',
|
||||||
letterSpacing: '0.1em',
|
letterSpacing: '0.1em',
|
||||||
color: 'hsl(var(--foreground))',
|
color: 'hsl(var(--foreground))',
|
||||||
|
Loading…
Reference in New Issue
Block a user