diff --git a/image-studio/templates/xiaohongshu.js b/image-studio/templates/xiaohongshu.js index bd5e069..41ddfe0 100644 --- a/image-studio/templates/xiaohongshu.js +++ b/image-studio/templates/xiaohongshu.js @@ -1,31 +1,32 @@ /** * ═══════════════════════════════════════════════════ - * 小红书卡片模板 · 1080×1440 (3:4) + * 小红书卡片模板 · 2026审美版 · 1080×1440 (3:4) * ═══════════════════════════════════════════════════ * - * 支持: - * - 单页卡片(封面/金句/干货) - * - 多页轮播(长内容自动分页) + * 风格:极简大标题 + 高对比度 + 大面积留白 + 渐变色块 + * 支持 CSS 变量驱动配色(从 registry 预设传入) + * + * 布局: + * - default: 标题 + 正文列表(教程/干货) + * - quote: 金句居中大字 + * - hero: 大标题 + 一句话副标题(封面) */ import { STYLES } from '../config.js' -const W = STYLES.sizes.xiaohongshu.width -const H = STYLES.sizes.xiaohongshu.height +const W = 1080 +const H = 1440 +/** + * 将 CSS 变量对象转换为 :root 样式 + */ +function cssVarBlock(vars = {}) { + const lines = Object.entries(vars).map(([k, v]) => ` ${k}: ${v};`) + return `:root {\n${lines.join('\n')}\n }` +} /** * 生成小红书卡片 HTML - * @param {object} data - * @param {string} data.title - 标题 - * @param {string} data.body - 正文(支持 \n 换行) - * @param {string} data.subtitle - 副标题(可选) - * @param {string} data.tag - 标签(可选,如「干货·教程」) - * @param {string} data.quote - 金句/引用(可选) - * @param {string} data.footer - 底部文字(可选,如账号名) - * @param {string} data.layout - 布局: 'default' | 'quote' | 'list' | 'minimal' - * @param {number} data.pageNum - 当前页码(多页时) - * @param {number} data.totalPages - 总页数(多页时) */ export function xiaohongshuCard(data) { const { @@ -33,33 +34,46 @@ export function xiaohongshuCard(data) { body = '', subtitle = '', tag = '', - quote = '', - footer = '', layout = 'default', pageNum = 1, totalPages = 1, + cssVars = {}, } = data - const C = STYLES.colors - const F = STYLES.fonts - const T = STYLES.typography - - // 正文按换行分段 const bodyLines = body.split('\n').filter(Boolean) + // 渲染正文:支持列表、小标题、加粗 const bodyHtml = bodyLines.map(line => { - // 检测是否以 - 开头(列表项) - if (line.trimStart().startsWith('- ')) { - return `
  • ${line.trimStart().slice(2)}
  • ` + const trimmed = line.trimStart() + if (trimmed.startsWith('- ') || trimmed.startsWith('• ')) { + const text = trimmed.replace(/^[-•]\s*/, '') + return `
  • ${text}
  • ` } - // 检测是否以 # 开头(小标题) - if (line.trimStart().startsWith('#')) { - return `

    ${line.trimStart().replace(/^#+\s*/, '')}

    ` + if (trimmed.startsWith('## ')) { + return `

    ${trimmed.slice(3)}

    ` } - return `

    ${line}

    ` + // 内联加粗 **text** + const formatted = trimmed.replace(/\*\*(.+?)\*\*/g, '$1') + return `

    ${formatted}

    ` }).join('\n') - const hasList = bodyLines.some(l => l.trimStart().startsWith('- ')) + const hasList = bodyLines.some(l => { + const t = l.trimStart() + return t.startsWith('- ') || t.startsWith('• ') + }) + + const C = { + bg: 'var(--bg, #faf8f5)', + primary: 'var(--primary, #1a1a2e)', + accent: 'var(--accent, #4f8cff)', + highlight: 'var(--highlight, #00d4ff)', + gold: 'var(--gold, #c9a96e)', + warm: 'var(--warm, #f5e6c8)', + text: 'var(--text, #1a1a2e)', + textMuted: 'var(--textMuted, #6b7280)', + cardBg: 'var(--cardBg, #ffffff)', + border: 'var(--border, #e5e7eb)', + } return ` @@ -68,219 +82,263 @@ export function xiaohongshuCard(data) { -
    -
    +
    +
    - ${tag ? `
    ${tag}
    ` : ''} + ${tag ? `
    ${tag.toUpperCase()}
    ` : ''} ${layout === 'quote' ? ` -
    -
    "
    -
    ${quote || title}
    - ${subtitle ? `
    ${subtitle}
    ` : ''} +
    +
    "
    +
    ${title}
    + ${subtitle ? `
    —— ${subtitle}
    ` : ''}
    - ` : layout === 'minimal' ? ` -
    -
    ${title}
    -
    - ${body ? `
    ${body}
    ` : ''} + ` : layout === 'hero' ? ` +
    +
    ${title}
    +
    + ${subtitle ? `
    ${subtitle}
    ` : ''}
    ` : ` +
    ${title}
    ${subtitle ? `
    ${subtitle}
    ` : ''}
    @@ -288,11 +346,11 @@ export function xiaohongshuCard(data) {
    `} -
    + - @@ -302,9 +360,6 @@ export function xiaohongshuCard(data) { /** * 生成小红书轮播(多页) - * @param {object} data - 同 xiaohongshuCard - * @param {string[]} pages - 每页正文内容数组 - * @returns {string[]} HTML 数组 */ export function xiaohongshuCarousel(data, pages) { return pages.map((body, i) => xiaohongshuCard({