铸渊 c1b3c02ef6 🎨 铸渊图片工作室 - 小红书/即刻/海报配图生成工具
为冰朔定制专属配图生成系统,支持三种卡片类型:
- 小红书竖版卡片 (1080×1440, 3:4)
- 即刻方卡 (1080×1080, 1:1)
- 海报 (1080×1920, 9:16)

特性:多套配色方案、多种布局风格、
      Puppeteer + HTML/CSS 渲染引擎、
      可部署 Web 服务 + 预览页面

使用方式:冰朔在对话里告诉铸渊内容和类型,
         铸渊运行脚本生成,冰朔直接下载使用。
2026-05-22 23:49:02 +00:00

317 lines
7.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* ═══════════════════════════════════════════════════
* 海报模板 · 1080×1920 (9:16)
* ═══════════════════════════════════════════════════
*
* 适用于:放假通知、收稿海报、活动公告等
*/
import { STYLES } from '../config.js'
const W = STYLES.sizes.poster.width
const H = STYLES.sizes.poster.height
/**
* 生成海报 HTML
* @param {object} data
* @param {string} data.title - 大标题
* @param {string} data.subtitle - 副标题(可选)
* @param {string} data.body - 正文内容
* @param {string[]} data.details - 详情列表(如时间/地点/要求)
* @param {string} data.cta - 行动号召(如「欢迎投稿」)
* @param {string} data.footer - 底部信息(如主办方/联系方式)
* @param {string} data.tag - 角标标签(如「通知」)
* @param {'default'|'notice'|'recruit'} data.style - 海报风格
*/
export function posterCard(data) {
const {
title = '',
subtitle = '',
body = '',
details = [],
cta = '',
footer = '',
tag = '',
style = 'default',
} = data
const C = STYLES.colors
const F = STYLES.fonts
const T = STYLES.typography
// 详情列表渲染
const detailsHtml = details.map((d, i) => {
// 支持 key: value 格式
const colonIdx = d.indexOf('')
if (colonIdx > 0 && colonIdx < 20) {
const key = d.slice(0, colonIdx)
const val = d.slice(colonIdx + 1)
return `
<div class="detail-item">
<span class="detail-key">${key}</span>
<span class="detail-colon"></span>
<span class="detail-val">${val}</span>
</div>`
}
return `<div class="detail-item">${d}</div>`
}).join('\n')
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
@import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600;700;900&family=Noto+Sans+SC:wght@300;400;500;700&display=swap');
body {
width: ${W}px;
height: ${H}px;
overflow: hidden;
background: ${C.bg};
font-family: ${F.body};
display: flex;
flex-direction: column;
position: relative;
}
/* ── 背景装饰 ── */
.bg-accent {
position: absolute;
top: 0;
right: 0;
width: 300px;
height: 300px;
background: radial-gradient(circle, ${C.accent}08 0%, transparent 70%);
}
.bg-accent-bl {
position: absolute;
bottom: 0;
left: 0;
width: 400px;
height: 400px;
background: radial-gradient(circle, ${C.highlight}06 0%, transparent 70%);
}
.container {
flex: 1;
padding: 72px 64px 48px;
display: flex;
flex-direction: column;
position: relative;
z-index: 1;
}
/* ── 标签 ── */
.tag {
display: inline-block;
padding: 6px 18px;
border: 1px solid ${C.accent};
color: ${C.accent};
font-size: ${T.captionSize}px;
border-radius: 4px;
margin-bottom: 32px;
align-self: flex-start;
letter-spacing: 3px;
}
/* ── 标题区 ── */
.title-section {
margin-bottom: 40px;
}
.title {
font-family: ${F.title};
font-size: 64px;
font-weight: 900;
line-height: 1.25;
color: ${C.primary};
letter-spacing: 4px;
}
.title-accent {
color: ${C.highlight};
}
.subtitle {
font-family: ${F.title};
font-size: ${T.subtitleSize}px;
font-weight: 300;
color: ${C.textMuted};
margin-top: 12px;
letter-spacing: 6px;
}
/* ── 分割线 ── */
.divider {
width: 80px;
height: 3px;
background: linear-gradient(90deg, ${C.gold}, ${C.highlight});
margin-bottom: 32px;
}
/* ── 正文 ── */
.body {
font-size: ${T.bodySize}px;
line-height: ${T.lineHeight};
color: ${C.text};
margin-bottom: 32px;
}
.body p {
margin-bottom: 12px;
}
/* ── 详情列表 ── */
.details {
flex: 1;
display: flex;
flex-direction: column;
gap: 16px;
margin-bottom: 32px;
padding: 32px;
background: ${C.warm}30;
border-radius: 8px;
border-left: 4px solid ${C.accent};
}
.detail-item {
font-size: ${T.bodySize}px;
line-height: 1.5;
color: ${C.text};
}
.detail-key {
font-weight: 600;
color: ${C.accent};
}
.detail-colon { color: ${C.textMuted}; }
.detail-val { color: ${C.text}; }
/* ── CTA ── */
.cta-section {
text-align: center;
padding: 24px 0;
margin-bottom: 16px;
}
.cta {
display: inline-block;
padding: 16px 48px;
background: linear-gradient(135deg, ${C.accent}, ${C.primary});
color: ${C.textLight};
font-size: ${T.subtitleSize}px;
font-weight: 600;
border-radius: 8px;
letter-spacing: 4px;
}
/* ── 底部 ── */
.footer {
text-align: center;
padding-top: 16px;
border-top: 1px solid ${C.divider};
font-size: ${T.captionSize}px;
color: ${C.textMuted};
line-height: 1.6;
}
.brand-line {
opacity: ${STYLES.brand.opacity};
margin-top: 4px;
}
/* ── 通知风格:更正式 ── */
.notice-title {
font-family: ${F.title};
font-size: 56px;
font-weight: 700;
text-align: center;
letter-spacing: 8px;
color: ${C.primary};
margin-bottom: 16px;
}
.notice-sub {
text-align: center;
font-size: ${T.smallSize}px;
color: ${C.textMuted};
letter-spacing: 4px;
margin-bottom: 32px;
}
/* ── 收稿风格:更有活力 ── */
.recruit-badge {
display: inline-block;
padding: 8px 24px;
background: ${C.highlight};
color: white;
font-size: ${T.smallSize}px;
border-radius: 4px;
letter-spacing: 2px;
margin-bottom: 20px;
align-self: center;
}
.recruit-title {
font-family: ${F.title};
font-size: 60px;
font-weight: 900;
text-align: center;
line-height: 1.3;
color: ${C.primary};
letter-spacing: 3px;
margin-bottom: 8px;
}
</style>
</head>
<body>
<div class="bg-accent"></div>
<div class="bg-accent-bl"></div>
<div class="container">
${style === 'notice' ? `
${tag ? `<div class="tag" style="align-self:center;">${tag}</div>` : ''}
<div class="notice-title">${title}</div>
${subtitle ? `<div class="notice-sub">${subtitle}</div>` : ''}
<div class="divider" style="align-self:center;"></div>
` : style === 'recruit' ? `
<div class="recruit-badge">${tag || '征稿启事'}</div>
<div class="recruit-title">${title}</div>
${subtitle ? `<div style="text-align:center;font-size:${T.smallSize}px;color:${C.textMuted};letter-spacing:2px;margin-bottom:24px;">${subtitle}</div>` : ''}
` : `
${tag ? `<div class="tag">${tag}</div>` : ''}
<div class="title-section">
<div class="title">${title}</div>
${subtitle ? `<div class="subtitle">${subtitle}</div>` : ''}
</div>
<div class="divider"></div>
`}
${body ? `<div class="body"><p>${body}</p></div>` : ''}
${details.length > 0 ? `<div class="details">${detailsHtml}</div>` : ''}
<div style="flex:1;"></div>
${cta ? `
<div class="cta-section">
<div class="cta">${cta}</div>
</div>
` : ''}
<div class="footer">
${footer ? `<div>${footer}</div>` : ''}
<div class="brand-line">${STYLES.brand.text}</div>
</div>
</div>
</body>
</html>`
}