From 7b682fd4ad2c4834f2083cedc598d24c07b2ec4a Mon Sep 17 00:00:00 2001
From: bingshuo <565183519@qq.com>
Date: Tue, 2 Jun 2026 15:22:31 +0800
Subject: [PATCH] D122: xhs widgets library - 16x widgets + randomized variants
---
.../xiaohongshu-widgets/widgets.js | 311 ++++++++++++++++++
1 file changed, 311 insertions(+)
create mode 100644 image-generator/xiaohongshu-widgets/widgets.js
diff --git a/image-generator/xiaohongshu-widgets/widgets.js b/image-generator/xiaohongshu-widgets/widgets.js
new file mode 100644
index 0000000..a714b67
--- /dev/null
+++ b/image-generator/xiaohongshu-widgets/widgets.js
@@ -0,0 +1,311 @@
+// 小红书风格小组件库 v1.0
+// 每个widget = 核心HTML模板 + 3~5个随机变体(variant) + CSS变量可覆写
+// 国作登字-2026-A-00037559
+// 设计原则: 每个widget是独立片段的HTML,可随机组合不打架
+
+export const WIDGETS = {
+
+ // ═══════════════════════════════════════
+ // 装饰类 Widgets
+ // ═══════════════════════════════════════
+
+ 'dot-grid': {
+ name: '圆点矩阵',
+ category: 'decor',
+ variants: [
+ { id: 'warm', css: { size: '6px', color: '#E07B39', opacity: '0.25', gap: '18px', cols: 8, rows: 3 } },
+ { id: 'cool', css: { size: '4px', color: '#4A90A4', opacity: '0.2', gap: '22px', cols: 10, rows: 2 } },
+ { id: 'mixed', css: { size: '5px', colors: ['#E07B39','#4A90A4','#5B8C5A'], opacity: '0.3', gap: '16px', cols: 6, rows: 4 } },
+ { id: 'large', css: { size: '8px', color: '#2D5016', opacity: '0.12', gap: '24px', cols: 5, rows: 2 } },
+ ],
+ render(v) {
+ const c = v.css, colors = c.colors || [c.color]
+ let dots = ''
+ const total = (c.cols || 6) * (c.rows || 3)
+ for (let i = 0; i < total; i++) {
+ const clr = colors[i % colors.length]
+ const r = Math.floor(i / c.cols), col = i % c.cols
+ const ox = (Math.random() - 0.5) * 4, oy = (Math.random() - 0.5) * 4
+ dots += ``
+ }
+ return ``
+ }
+ },
+
+ 'gradient-stripe': {
+ name: '渐变装饰条',
+ category: 'decor',
+ variants: [
+ { id: 'warm-sunset', css: { colors: ['#E07B39','#F5A623','#FFD700'], height: '6px', width: '80%', radius: '3px' } },
+ { id: 'cool-ocean', css: { colors: ['#4A90A4','#5B8C5A','#7BC47B'], height: '4px', width: '60%', radius: '2px' } },
+ { id: 'rose-gold', css: { colors: ['#E8435E','#C9A96E','#F5D0C5'], height: '5px', width: '70%', radius: '3px' } },
+ { id: 'forest', css: { colors: ['#2D5016','#5B8C5A','#A8D5A2'], height: '8px', width: '50%', radius: '4px' } },
+ ],
+ render(v) {
+ const c = v.css
+ const grad = c.colors.map((clr, i) => `${clr} ${(i / (c.colors.length - 1)) * 100}%`).join(', ')
+ return `
`
+ }
+ },
+
+ 'sticker-badge': {
+ name: '贴纸角标',
+ category: 'decor',
+ variants: [
+ { id: 'hot', text: 'HOT', bg: '#E8435E', color: '#FFF', rotate: '-8deg' },
+ { id: 'new', text: 'NEW', bg: '#E07B39', color: '#FFF', rotate: '5deg' },
+ { id: 'free', text: 'FREE', bg: '#5B8C5A', color: '#FFF', rotate: '-3deg' },
+ { id: 'top', text: 'TOP', bg: '#4A90A4', color: '#FFF', rotate: '10deg' },
+ { id: 'hand', text: '手写', bg: '#F5E6C8', color: '#8B4513', rotate: '-12deg' },
+ ],
+ render(v) {
+ return `${v.text}
`
+ }
+ },
+
+ 'hand-drawn-circle': {
+ name: '手绘圈线',
+ category: 'decor',
+ variants: [
+ { id: 'orange', stroke: '#E07B39', width: '3px', dash: 'none', radius: '60px' },
+ { id: 'green', stroke: '#5B8C5A', width: '2px', dash: '8,4', radius: '50px' },
+ { id: 'blue', stroke: '#4A90A4', width: '2.5px', dash: '12,6', radius: '45px' },
+ { id: 'pink', stroke: '#E8435E', width: '3px', dash: '6,3', radius: '55px' },
+ ],
+ render(v) {
+ const d = parseInt(v.radius) * 2
+ return ``
+ }
+ },
+
+ // ═══════════════════════════════════════
+ // 信息类 Widgets
+ // ═══════════════════════════════════════
+
+ 'photo-frame': {
+ name: '照片框',
+ category: 'info',
+ description: '带白边/阴影的照片展示框,支持随机占位色块',
+ variants: [
+ { id: 'polaroid', style: 'polaroid', borderColor: '#FFF', borderWidth: '12px 12px 40px 12px', rotate: '-2deg' },
+ { id: 'rounded', style: 'rounded', borderColor: '#FFF', borderRadius: '16px', shadow: true },
+ { id: 'film', style: 'film', borderColor: '#1A1A1A', borderWidth: '6px 6px 24px 6px', rotate: '1deg' },
+ { id: 'clean', style: 'clean', borderColor: 'transparent', borderRadius: '20px' },
+ ],
+ render(v) {
+ const w = v.width || 280, h = v.height || 210
+ const placeholderColors = ['#F5D0C5','#A8D5A2','#B5D4F4','#F5E6C8','#F4C0D1']
+ const bg = placeholderColors[Math.floor(Math.random() * placeholderColors.length)]
+ let style = `width:${w}px;height:${h}px;background:${bg}`
+ if (v.style === 'polaroid') style += `;border:${v.borderWidth} solid ${v.borderColor};transform:rotate(${v.rotate})`
+ else if (v.style === 'film') style += `;border:${v.borderWidth} solid ${v.borderColor};transform:rotate(${v.rotate})`
+ else if (v.style === 'rounded') style += `;border:4px solid ${v.borderColor};border-radius:${v.borderRadius}`
+ else style += `;border-radius:${v.borderRadius};overflow:hidden`
+
+ if (v.shadow) style += ';box-shadow:0 8px 30px rgba(0,0,0,.1)'
+ if (v.caption) {
+ return `${v.emoji ? `${v.emoji}` : ''}
${v.caption}
`
+ }
+ return `${v.emoji ? `${v.emoji}` : ''}
`
+ }
+ },
+
+ 'info-tag-row': {
+ name: '信息标签行',
+ category: 'info',
+ description: '一排小红书风格的信息标签:价格/难度/时长/评分等',
+ variants: [
+ { id: 'price', items: [{ icon: '💰', text: '均价', value: '¥28' }, { icon: '⭐', text: '评分', value: '4.8' }, { icon: '⏱', text: '耗时', value: '30min' }] },
+ { id: 'recipe', items: [{ icon: '👨🍳', text: '难度', value: '简单' }, { icon: '⏱', text: '时间', value: '20min' }, { icon: '🍽', text: '份量', value: '2人' }] },
+ { id: 'travel', items: [{ icon: '📍', text: '目的地', value: '杭州' }, { icon: '💰', text: '预算', value: '¥500' }, { icon: '📅', text: '天数', value: '3天' }] },
+ { id: 'study', items: [{ icon: '📚', text: '方法', value: '番茄钟' }, { icon: '⏱', text: '时长', value: '25min' }, { icon: '📈', text: '效果', value: '显著' }] },
+ ],
+ render(v) {
+ const items = (v.items || v.variant?.items || []).map(i =>
+ `
+
${i.icon} ${i.text}
+
${i.value}
+
`
+ ).join('')
+ return `${items}
`
+ }
+ },
+
+ 'bullet-list': {
+ name: '要点清单',
+ category: 'info',
+ description: '小红书风格的bullet point列表,支持emoji前缀',
+ variants: [
+ { id: 'check', bullet: '✅', color: '#5B8C5A', items: ['要点一','要点二','要点三'] },
+ { id: 'star', bullet: '✦', color: '#E07B39', items: ['关键点A','关键点B','关键点C'] },
+ { id: 'number', bullet: 'N', color: '#4A90A4', numbered: true, items: ['第一步','第二步','第三步'] },
+ { id: 'heart', bullet: '♡', color: '#E8435E', items: ['喜欢的原因','喜欢的原因','喜欢的原因'] },
+ ],
+ render(v) {
+ const items = (v.items || v.variant?.items || []).map((item, i) => {
+ const prefix = v.numbered ? `${String(i + 1).padStart(2, '0')}.` : v.bullet
+ return `
+ ${prefix}
+ ${item}
+
`
+ }).join('')
+ return `${items}
`
+ }
+ },
+
+ // ═══════════════════════════════════════
+ // 排版类 Widgets
+ // ═══════════════════════════════════════
+
+ 'split-layout': {
+ name: '左右分栏',
+ category: 'layout',
+ description: '左图右文或左文右图分栏,小红书经典排版',
+ variants: [
+ { id: 'image-left', direction: 'row', ratio: '45:55', gap: '16px' },
+ { id: 'image-right', direction: 'row-reverse', ratio: '45:55', gap: '16px' },
+ { id: 'equal', direction: 'row', ratio: '50:50', gap: '20px' },
+ { id: 'stack-top', direction: 'column', ratio: 'auto' },
+ ],
+ render(v) {
+ const [l, r] = (v.ratio || '50:50').split(':').map(Number)
+ const dir = v.direction === 'column' ? 'column' : 'row'
+ return {
+ wrapper: true,
+ style: `display:flex;flex-direction:${dir};gap:${v.gap || '16px'};align-items:center`,
+ leftStyle: dir === 'column' ? 'width:100%' : `flex:0 0 ${l}%`,
+ rightStyle: dir === 'column' ? 'width:100%' : `flex:1`,
+ }
+ }
+ },
+
+ 'card-grid': {
+ name: '卡片网格',
+ category: 'layout',
+ description: '小红书同款2x2或3列卡片网格',
+ variants: [
+ { id: '2x2', cols: 2, gap: '12px', cardHeight: '100px' },
+ { id: '1x3', cols: 3, gap: '10px', cardHeight: '140px' },
+ { id: '1x2-wide', cols: 2, gap: '16px', cardHeight: '180px' },
+ ],
+ render(v) {
+ return {
+ wrapper: true,
+ style: `display:grid;grid-template-columns:repeat(${v.cols},1fr);gap:${v.gap}`,
+ cardStyle: `height:${v.cardHeight};background:#FDF8F3;border-radius:16px;display:flex;align-items:center;justify-content:center`,
+ }
+ }
+ },
+
+ // ═══════════════════════════════════════
+ // 情感类 Widgets
+ // ═══════════════════════════════════════
+
+ 'sticky-note': {
+ name: '便签纸',
+ category: 'emotion',
+ variants: [
+ { id: 'yellow', bg: '#FFF9C4', shadow: '#E6D88A', rotate: '-3deg', pin: '#F5A623' },
+ { id: 'pink', bg: '#FCE4EC', shadow: '#F0D0D8', rotate: '2deg', pin: '#E8435E' },
+ { id: 'green', bg: '#E8F5E9', shadow: '#C8E6C9', rotate: '-1deg', pin: '#5B8C5A' },
+ { id: 'blue', bg: '#E3F2FD', shadow: '#BBDEFB', rotate: '4deg', pin: '#4A90A4' },
+ ],
+ render(v) {
+ return `
+
+
+ ${v.text || '便签内容'}
+
+
`
+ }
+ },
+
+ 'highlight-box': {
+ name: '高亮强调框',
+ category: 'emotion',
+ description: '小红书金句高亮框,荧光笔标注风格',
+ variants: [
+ { id: 'yellow-marker', bg: '#FFF3CD', border: '#FFE69C', text: '#856404', icon: '💡' },
+ { id: 'pink-marker', bg: '#FCE4EC', border: '#F48FB1', text: '#880E4F', icon: '❤️' },
+ { id: 'green-marker', bg: '#E8F5E9', border: '#A5D6A7', text: '#1B5E20', icon: '🌟' },
+ { id: 'blue-marker', bg: '#E3F2FD', border: '#90CAF9', text: '#0D47A1', icon: '📌' },
+ ],
+ render(v) {
+ return `
+ ${v.icon ? v.icon + ' ' : ''}${v.text || '金句内容'}
+
`
+ }
+ },
+
+ 'mood-indicator': {
+ name: '心情标识',
+ category: 'emotion',
+ variants: [
+ { id: 'happy', mood: '😊 开心', bg: '#FFF9C4', color: '#F5A623' },
+ { id: 'calm', mood: '😌 平静', bg: '#E8F5E9', color: '#5B8C5A' },
+ { id: 'excited', mood: '🤩 激动', bg: '#FCE4EC', color: '#E8435E' },
+ { id: 'focused', mood: '🧘 专注', bg: '#E3F2FD', color: '#4A90A4' },
+ ],
+ render(v) {
+ return `
+ ${v.mood}
+
`
+ }
+ },
+
+ // ═══════════════════════════════════════
+ // 特殊效果 Widgets
+ // ═══════════════════════════════════════
+
+ 'scribble-underline': {
+ name: '手写划线下划线',
+ category: 'decor',
+ variants: [
+ { id: 'orange-wavy', color: '#E07B39', style: 'wavy', offset: '4px', width: '3px' },
+ { id: 'green-straight', color: '#5B8C5A', style: 'solid', offset: '2px', width: '4px' },
+ { id: 'pink-dashed', color: '#E8435E', style: 'dashed', offset: '6px', width: '2px' },
+ ],
+ render(v) {
+ return {
+ cssClass: `text-decoration:underline;text-decoration-color:${v.color};text-decoration-thickness:${v.width};text-underline-offset:${v.offset};${v.style !== 'solid' ? `text-decoration-style:${v.style}` : ''}`,
+ inline: true,
+ }
+ }
+ },
+
+ 'corner-fold': {
+ name: '折角效果',
+ category: 'decor',
+ variants: [
+ { id: 'top-right', corner: 'top-right', color: '#FDF8F3', size: '30px' },
+ { id: 'top-left', corner: 'top-left', color: '#E8F0E0', size: '24px' },
+ ],
+ render(v) {
+ return ``
+ }
+ },
+}
+
+// 随机选择一个widget的变体
+export function randomVariant(widgetId) {
+ const w = WIDGETS[widgetId]
+ if (!w || !w.variants) return null
+ const idx = Math.floor(Math.random() * w.variants.length)
+ return w.variants[idx]
+}
+
+// 列举所有widget
+export function listWidgets() {
+ return Object.entries(WIDGETS).map(([id, w]) => ({
+ id,
+ name: w.name,
+ category: w.category,
+ description: w.description || '',
+ variantCount: (w.variants || []).length,
+ }))
+}
+
+// 按类别筛选
+export function widgetsByCategory(category) {
+ return listWidgets().filter(w => w.category === category)
+}