foliko 1.0.86 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/.agent/data/default.json +3 -4310
  2. package/.agent/data/plugins-state.json +34 -1
  3. package/.agent/mcp_config.json +0 -1
  4. package/.agent/memory/core.md +1 -0
  5. package/.agent/memory/project/mnn93ogy-ypjn27.md +9 -0
  6. package/.agent/memory/project/mnn98fqy-5nhc1u.md +25 -0
  7. package/.agent/memory/user/mnm67t9m-x8rekk.md +9 -0
  8. package/.agent/memory/user/mnn5mmqh-w6aktx.md +11 -0
  9. package/.agent/memory/user/mnnbfhhn-dk1bd1.md +22 -0
  10. package/.agent/plugins/__pycache__/file_writer.cpython-312.pyc +0 -0
  11. package/.agent/plugins/marknative/index.js +2 -7
  12. package/.agent/plugins/poster-plugin/README.md +304 -0
  13. package/.agent/plugins/poster-plugin/fonts/PatuaOne-Regular.ttf +0 -0
  14. package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221.ttf +0 -0
  15. package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221/347/262/227/344/275/223.ttf +0 -0
  16. package/.agent/plugins/poster-plugin/index.js +13 -0
  17. package/.agent/plugins/poster-plugin/package.json +28 -0
  18. package/.agent/plugins/poster-plugin/src/canvas.js +161 -0
  19. package/.agent/plugins/poster-plugin/src/components/arrow.js +84 -0
  20. package/.agent/plugins/poster-plugin/src/components/avatar.js +71 -0
  21. package/.agent/plugins/poster-plugin/src/components/badge.js +85 -0
  22. package/.agent/plugins/poster-plugin/src/components/card.js +88 -0
  23. package/.agent/plugins/poster-plugin/src/components/chart.js +127 -0
  24. package/.agent/plugins/poster-plugin/src/components/chip.js +88 -0
  25. package/.agent/plugins/poster-plugin/src/components/columns.js +107 -0
  26. package/.agent/plugins/poster-plugin/src/components/cta.js +85 -0
  27. package/.agent/plugins/poster-plugin/src/components/divider.js +55 -0
  28. package/.agent/plugins/poster-plugin/src/components/feature.js +85 -0
  29. package/.agent/plugins/poster-plugin/src/components/featureGrid.js +112 -0
  30. package/.agent/plugins/poster-plugin/src/components/grid.js +118 -0
  31. package/.agent/plugins/poster-plugin/src/components/imageFrame.js +155 -0
  32. package/.agent/plugins/poster-plugin/src/components/index.js +62 -0
  33. package/.agent/plugins/poster-plugin/src/components/listItem.js +146 -0
  34. package/.agent/plugins/poster-plugin/src/components/notification.js +123 -0
  35. package/.agent/plugins/poster-plugin/src/components/progress.js +79 -0
  36. package/.agent/plugins/poster-plugin/src/components/progressCircle.js +117 -0
  37. package/.agent/plugins/poster-plugin/src/components/quote.js +97 -0
  38. package/.agent/plugins/poster-plugin/src/components/rating.js +85 -0
  39. package/.agent/plugins/poster-plugin/src/components/star.js +70 -0
  40. package/.agent/plugins/poster-plugin/src/components/statCard.js +105 -0
  41. package/.agent/plugins/poster-plugin/src/components/stepper.js +118 -0
  42. package/.agent/plugins/poster-plugin/src/components/table.js +159 -0
  43. package/.agent/plugins/poster-plugin/src/components/tagCloud.js +78 -0
  44. package/.agent/plugins/poster-plugin/src/components/timeline.js +105 -0
  45. package/.agent/plugins/poster-plugin/src/components/watermark.js +52 -0
  46. package/.agent/plugins/poster-plugin/src/composer.js +1904 -0
  47. package/.agent/plugins/poster-plugin/src/elements/artText.js +60 -0
  48. package/.agent/plugins/poster-plugin/src/elements/background.js +52 -0
  49. package/.agent/plugins/poster-plugin/src/elements/circle.js +31 -0
  50. package/.agent/plugins/poster-plugin/src/elements/image.js +71 -0
  51. package/.agent/plugins/poster-plugin/src/elements/index.js +26 -0
  52. package/.agent/plugins/poster-plugin/src/elements/line.js +23 -0
  53. package/.agent/plugins/poster-plugin/src/elements/polygon.js +32 -0
  54. package/.agent/plugins/poster-plugin/src/elements/rectangle.js +32 -0
  55. package/.agent/plugins/poster-plugin/src/elements/svg.js +92 -0
  56. package/.agent/plugins/poster-plugin/src/elements/text.js +38 -0
  57. package/.agent/plugins/poster-plugin/src/fonts.js +118 -0
  58. package/.agent/plugins/poster-plugin/src/index.js +1659 -0
  59. package/.agent/plugins/poster-plugin/src/presets.js +36 -0
  60. package/.agent/plugins/poster-plugin/src/templates/business.js +60 -0
  61. package/.agent/plugins/poster-plugin/src/templates/gradient.js +64 -0
  62. package/.agent/plugins/poster-plugin/src/templates/index.js +43 -0
  63. package/.agent/plugins/poster-plugin/src/templates/modern.js +69 -0
  64. package/.agent/plugins/poster-plugin/src/templates/simple.js +58 -0
  65. package/.agent/plugins/poster-plugin/src/templates/social.js +62 -0
  66. package/.agent/plugins/poster-plugin/src/templates/tech.js +84 -0
  67. package/.agent/sessions/cli_default.json +24265 -0
  68. package/.agent/weixin.json +6 -0
  69. package/.claude/settings.local.json +176 -171
  70. package/CLAUDE.md +144 -108
  71. package/docs/CONTEXT_DESIGN.md +1596 -0
  72. package/examples/test-concurrent-chat.js +60 -0
  73. package/examples/test-long-chat.js +77 -0
  74. package/examples/test-session-chat.js +93 -0
  75. package/output/beef-love-poster.png +0 -0
  76. package/package.json +2 -2
  77. package/plugins/default-plugins.js +2 -1
  78. package/plugins/extension-executor-plugin.js +11 -0
  79. package/plugins/memory-plugin.js +984 -0
  80. package/plugins/session-plugin.js +78 -1
  81. package/plugins/weixin-plugin.js +24 -22
  82. package/skills/poster-guide/SKILL.md +743 -0
  83. package/skills/python-plugin-dev/SKILL.md +238 -238
  84. package/skills/skill-guide/SKILL.md +130 -108
  85. package/src/capabilities/skill-manager.js +99 -0
  86. package/src/core/agent-chat.js +627 -180
  87. package/src/core/agent-context.js +188 -0
  88. package/src/core/agent.js +9 -63
  89. package/src/core/context-manager.js +283 -0
  90. package/src/core/framework.js +264 -3
  91. package/src/core/plugin-manager.js +79 -2
  92. package/src/core/request-context.js +98 -0
  93. package/src/core/session-context.js +341 -0
  94. package/src/core/session-storage.js +274 -0
  95. package/src/executors/mcp-executor.js +2 -2
  96. package/src/utils/index.js +239 -67
  97. package/src/utils/plugin-helpers.js +17 -0
  98. package//346/265/267/346/212/245/346/217/222/344/273/266.md +621 -0
  99. package/.agent/plugins/__pycache__/test_plugin.cpython-312.pyc +0 -0
  100. package/.agent/plugins/temp-repo/LICENSE +0 -201
  101. package/.agent/plugins/temp-repo/puppeteer-plugin/README.md +0 -147
  102. package/.agent/plugins/temp-repo/puppeteer-plugin/index.js +0 -1418
  103. package/.agent/plugins/temp-repo/puppeteer-plugin/package.json +0 -9
  104. package/.agent/plugins/test_plugin.py +0 -304
@@ -0,0 +1,85 @@
1
+ /**
2
+ * CTA(行动号召)按钮组件
3
+ */
4
+
5
+ const paper = require('paper')
6
+
7
+ /**
8
+ * 创建 CTA 按钮
9
+ *
10
+ * @param {Object} project - Paper.js 项目
11
+ * @param {Object} canvas - 画布对象
12
+ * @param {Object} args - 组件参数
13
+ * @param {number} args.x - X坐标(居中)
14
+ * @param {number} args.y - Y坐标
15
+ * @param {string} args.text - 按钮文字
16
+ * @param {string} args.background - 背景色
17
+ * @param {string} args.color - 文字颜色
18
+ * @param {string} args.border - 边框颜色
19
+ * @param {number} args.fontSize - 字体大小
20
+ * @param {number} args.padding - 内边距
21
+ * @param {number} args.radius - 圆角半径
22
+ * @param {Object} args.shadow - 阴影设置
23
+ */
24
+ function createCTA(project, canvas, args) {
25
+ const {
26
+ x, y,
27
+ text,
28
+ background = '#007bff',
29
+ color = '#ffffff',
30
+ border,
31
+ fontSize = 20,
32
+ padding = 25,
33
+ radius = 8,
34
+ shadow,
35
+ } = args
36
+
37
+ const elements = []
38
+
39
+ // 计算按钮尺寸
40
+ const textWidth = text.length * fontSize * 0.7
41
+ const btnWidth = textWidth + padding * 2
42
+ const btnHeight = fontSize + padding * 2
43
+
44
+ const btnX = x - btnWidth / 2
45
+
46
+ // 绘制按钮背景
47
+ const button = new paper.Path.Rectangle({
48
+ point: [btnX, y],
49
+ size: [btnWidth, btnHeight],
50
+ radius: radius,
51
+ })
52
+ button.fillColor = new paper.Color(background)
53
+
54
+ if (border) {
55
+ button.strokeColor = new paper.Color(border)
56
+ button.strokeWidth = 1
57
+ }
58
+
59
+ if (shadow) {
60
+ button.shadowColor = new paper.Color(shadow.color || 'rgba(0,0,0,0.3)')
61
+ button.shadowBlur = shadow.blur || 10
62
+ button.shadowOffset = new paper.Point(shadow.offsetX || 0, shadow.offsetY || 4)
63
+ }
64
+
65
+ elements.push({ type: 'rectangle', id: button.id })
66
+
67
+ // 绘制文字
68
+ const buttonText = new paper.PointText({
69
+ point: [x, y + btnHeight / 2 + fontSize / 3],
70
+ content: text,
71
+ fontSize: fontSize,
72
+ fillColor: new paper.Color(color),
73
+ justification: 'center',
74
+ })
75
+ elements.push({ type: 'text', id: buttonText.id })
76
+
77
+ return {
78
+ success: true,
79
+ elements,
80
+ width: btnWidth,
81
+ height: btnHeight,
82
+ }
83
+ }
84
+
85
+ module.exports = createCTA
@@ -0,0 +1,55 @@
1
+ /**
2
+ * 分隔线组件
3
+ */
4
+
5
+ const paper = require('paper')
6
+
7
+ /**
8
+ * 创建分隔线
9
+ *
10
+ * @param {Object} project - Paper.js 项目
11
+ * @param {Object} canvas - 画布对象
12
+ * @param {Object} args - 组件参数
13
+ * @param {number} args.x - X坐标
14
+ * @param {number} args.y - Y坐标
15
+ * @param {number} args.width - 宽度
16
+ * @param {string} args.color - 颜色
17
+ * @param {number} args.thickness - 厚度
18
+ * @param {string} args.style - 样式: solid, dashed
19
+ * @param {string} args.align - 对齐: left, center, right
20
+ */
21
+ function createDivider(project, canvas, args) {
22
+ const {
23
+ x, y, width,
24
+ color = '#00d9ff',
25
+ thickness = 1,
26
+ style = 'solid',
27
+ align = 'center',
28
+ } = args
29
+
30
+ let startX = x
31
+ let endX = x + width
32
+
33
+ if (align === 'center') {
34
+ startX = x - width / 2
35
+ endX = x + width / 2
36
+ } else if (align === 'right') {
37
+ startX = x - width
38
+ endX = x
39
+ }
40
+
41
+ const line = new paper.Path.Line({
42
+ from: [startX, y],
43
+ to: [endX, y],
44
+ strokeColor: new paper.Color(color),
45
+ strokeWidth: thickness,
46
+ })
47
+
48
+ if (style === 'dashed') {
49
+ line.dashArray = [10, 5]
50
+ }
51
+
52
+ return { success: true, id: line.id, type: 'line' }
53
+ }
54
+
55
+ module.exports = createDivider
@@ -0,0 +1,85 @@
1
+ /**
2
+ * 特性展示组件
3
+ */
4
+
5
+ const paper = require('paper')
6
+
7
+ /**
8
+ * 创建特性展示块
9
+ *
10
+ * @param {Object} project - Paper.js 项目
11
+ * @param {Object} canvas - 画布对象
12
+ * @param {Object} args - 组件参数
13
+ * @param {number} args.x - X坐标
14
+ * @param {number} args.y - Y坐标
15
+ * @param {number} args.width - 总宽度
16
+ * @param {string} args.icon - 图标(emoji)
17
+ * @param {string} args.title - 标题
18
+ * @param {string} args.description - 描述
19
+ * @param {string} args.iconColor - 图标颜色
20
+ * @param {string} args.titleColor - 标题颜色
21
+ * @param {string} args.descColor - 描述颜色
22
+ * @param {number} args.iconSize - 图标大小
23
+ * @param {number} args.titleSize - 标题大小
24
+ * @param {number} args.descSize - 描述大小
25
+ */
26
+ function createFeature(project, canvas, args) {
27
+ const {
28
+ x, y, width,
29
+ icon,
30
+ title,
31
+ description,
32
+ iconColor = '#007bff',
33
+ titleColor = '#ffffff',
34
+ descColor = '#aaaaaa',
35
+ iconSize = 32,
36
+ titleSize = 20,
37
+ descSize = 14,
38
+ } = args
39
+
40
+ const elements = []
41
+ const padding = 15
42
+ let currentY = y
43
+
44
+ // 绘制图标
45
+ if (icon) {
46
+ const iconText = new paper.PointText({
47
+ point: [x + padding, currentY + iconSize],
48
+ content: icon,
49
+ fontSize: iconSize,
50
+ fillColor: new paper.Color(iconColor),
51
+ justification: 'left',
52
+ })
53
+ elements.push({ type: 'text', id: iconText.id })
54
+ }
55
+
56
+ // 绘制标题
57
+ if (title) {
58
+ currentY += icon ? iconSize + 5 : 0
59
+ const titleText = new paper.PointText({
60
+ point: [x + padding, currentY + titleSize],
61
+ content: title,
62
+ fontSize: titleSize,
63
+ fillColor: new paper.Color(titleColor),
64
+ justification: 'left',
65
+ })
66
+ elements.push({ type: 'text', id: titleText.id })
67
+ }
68
+
69
+ // 绘制描述
70
+ if (description) {
71
+ currentY += title ? titleSize + 5 : 0
72
+ const descText = new paper.PointText({
73
+ point: [x + padding, currentY + descSize],
74
+ content: description,
75
+ fontSize: descSize,
76
+ fillColor: new paper.Color(descColor),
77
+ justification: 'left',
78
+ })
79
+ elements.push({ type: 'text', id: descText.id })
80
+ }
81
+
82
+ return { success: true, elements }
83
+ }
84
+
85
+ module.exports = createFeature
@@ -0,0 +1,112 @@
1
+ /**
2
+ * 特性网格组件
3
+ */
4
+
5
+ const paper = require('paper')
6
+
7
+ /**
8
+ * 创建特性网格
9
+ *
10
+ * @param {Object} project - Paper.js 项目
11
+ * @param {Object} canvas - 画布对象
12
+ * @param {Object} args - 组件参数
13
+ * @param {number} args.x - X坐标
14
+ * @param {number} args.y - Y坐标
15
+ * @param {number} args.columns - 列数
16
+ * @param {number} args.itemWidth - 每个特性宽度
17
+ * @param {number} args.itemHeight - 每个特性高度
18
+ * @param {number} args.gap - 间距
19
+ * @param {Array} args.items - 特性数组 [{icon, title, description}]
20
+ * @param {string} args.background - 背景色
21
+ * @param {string} args.borderColor - 边框颜色
22
+ * @param {number} args.radius - 圆角半径
23
+ */
24
+ function createFeatureGrid(project, canvas, args) {
25
+ const {
26
+ x, y,
27
+ columns = 3,
28
+ itemWidth = 200,
29
+ itemHeight = 120,
30
+ gap = 20,
31
+ items = [],
32
+ background = '#1a1a2e',
33
+ borderColor = '#00d9ff',
34
+ radius = 8,
35
+ } = args
36
+
37
+ const elements = []
38
+ const rows = Math.ceil(items.length / columns)
39
+
40
+ for (let i = 0; i < items.length; i++) {
41
+ const item = items[i]
42
+ const col = i % columns
43
+ const row = Math.floor(i / columns)
44
+
45
+ const itemX = x + col * (itemWidth + gap)
46
+ const itemY = y + row * (itemHeight + gap)
47
+
48
+ // 绘制每个特性的背景
49
+ const bg = new paper.Path.Rectangle({
50
+ point: [itemX, itemY],
51
+ size: [itemWidth, itemHeight],
52
+ radius: radius,
53
+ })
54
+ bg.fillColor = new paper.Color(background)
55
+ bg.strokeColor = new paper.Color(borderColor)
56
+ bg.strokeWidth = 0.5
57
+ bg.opacity = 0.8
58
+ elements.push({ type: 'rectangle', id: bg.id })
59
+
60
+ const padding = 15
61
+ let itemYOffset = itemY + padding
62
+
63
+ // 绘制图标
64
+ if (item.icon) {
65
+ const iconText = new paper.PointText({
66
+ point: [itemX + padding, itemYOffset + 24],
67
+ content: item.icon,
68
+ fontSize: 28,
69
+ fillColor: new paper.Color(item.iconColor || '#00ff88'),
70
+ justification: 'left',
71
+ })
72
+ elements.push({ type: 'text', id: iconText.id })
73
+ itemYOffset += 35
74
+ }
75
+
76
+ // 绘制标题
77
+ if (item.title) {
78
+ const titleText = new paper.PointText({
79
+ point: [itemX + padding, itemYOffset + 18],
80
+ content: item.title,
81
+ fontSize: 16,
82
+ fillColor: new paper.Color(item.titleColor || '#ffffff'),
83
+ justification: 'left',
84
+ })
85
+ elements.push({ type: 'text', id: titleText.id })
86
+ itemYOffset += 22
87
+ }
88
+
89
+ // 绘制描述
90
+ if (item.description) {
91
+ const descText = new paper.PointText({
92
+ point: [itemX + padding, itemYOffset + 14],
93
+ content: item.description,
94
+ fontSize: 12,
95
+ fillColor: new paper.Color(item.descColor || '#888888'),
96
+ justification: 'left',
97
+ })
98
+ elements.push({ type: 'text', id: descText.id })
99
+ }
100
+ }
101
+
102
+ return {
103
+ success: true,
104
+ elements,
105
+ width: columns * itemWidth + (columns - 1) * gap,
106
+ height: rows * itemHeight + (rows - 1) * gap,
107
+ rows,
108
+ cols: columns,
109
+ }
110
+ }
111
+
112
+ module.exports = createFeatureGrid
@@ -0,0 +1,118 @@
1
+ /**
2
+ * 网格布局组件
3
+ * 支持任意行列的网格布局
4
+ */
5
+
6
+ const createGrid = (ctx) => ({
7
+ /**
8
+ * @param {Object} params
9
+ * @param {number} params.x - 起始X坐标
10
+ * @param {number} params.y - 起始Y坐标
11
+ * @param {number} params.width - 总宽度
12
+ * @param {number} params.height - 总高度
13
+ * @param {number} [params.columns=3] - 列数
14
+ * @param {number} [params.rows=2] - 行数
15
+ * @param {number} [params.gapX=20] - 水平间距
16
+ * @param {number} [params.gapY=20] - 垂直间距
17
+ * @param {string} [params.background] - 背景色
18
+ * @param {string} [params.borderColor] - 边框颜色
19
+ * @param {number} [params.borderWidth] - 边框宽度
20
+ * @param {number} [params.radius=0] - 圆角
21
+ * @param {string} [params.direction='row'] - 排列方向: row(行优先), column(列优先)
22
+ */
23
+ draw({
24
+ x,
25
+ y,
26
+ width,
27
+ height,
28
+ columns = 3,
29
+ rows = 2,
30
+ gapX = 20,
31
+ gapY = 20,
32
+ background,
33
+ borderColor,
34
+ borderWidth = 1,
35
+ radius = 0,
36
+ direction = 'row'
37
+ }) {
38
+ const elements = []
39
+
40
+ // 计算单元格尺寸
41
+ const totalGapX = gapX * (columns - 1)
42
+ const totalGapY = gapY * (rows - 1)
43
+ const cellWidth = (width - totalGapX) / columns
44
+ const cellHeight = (height - totalGapY) / rows
45
+
46
+ // 绘制背景
47
+ if (background) {
48
+ const bg = new ctx.Path.Rectangle({
49
+ point: [x, y],
50
+ size: [width, height],
51
+ radius: radius
52
+ })
53
+ bg.fillColor = new ctx.Color(background)
54
+ elements.push({ type: 'rectangle', id: bg.id })
55
+ }
56
+
57
+ // 绘制边框
58
+ if (borderColor && borderWidth > 0) {
59
+ const border = new ctx.Path.Rectangle({
60
+ point: [x, y],
61
+ size: [width, height],
62
+ radius: radius
63
+ })
64
+ border.fillColor = new ctx.Color('transparent')
65
+ border.strokeColor = new ctx.Color(borderColor)
66
+ border.strokeWidth = borderWidth
67
+ elements.push({ type: 'rectangle', id: border.id })
68
+ }
69
+
70
+ // 生成网格位置信息
71
+ const cellPositions = []
72
+ const totalCells = columns * rows
73
+
74
+ for (let i = 0; i < totalCells; i++) {
75
+ let col, row
76
+
77
+ if (direction === 'row') {
78
+ col = i % columns
79
+ row = Math.floor(i / columns)
80
+ } else {
81
+ row = i % rows
82
+ col = Math.floor(i / rows)
83
+ }
84
+
85
+ const cellX = x + col * (cellWidth + gapX)
86
+ const cellY = y + row * (cellHeight + gapY)
87
+
88
+ cellPositions.push({
89
+ index: i,
90
+ column: col,
91
+ row: row,
92
+ x: cellX,
93
+ y: cellY,
94
+ width: cellWidth,
95
+ height: cellHeight,
96
+ centerX: cellX + cellWidth / 2,
97
+ centerY: cellY + cellHeight / 2
98
+ })
99
+ }
100
+
101
+ // 返回网格布局信息
102
+ return {
103
+ success: true,
104
+ elements,
105
+ cellPositions,
106
+ cellWidth,
107
+ cellHeight,
108
+ columns,
109
+ rows,
110
+ totalCells,
111
+ totalWidth: width,
112
+ totalHeight: height,
113
+ type: 'grid'
114
+ }
115
+ }
116
+ })
117
+
118
+ module.exports = createGrid
@@ -0,0 +1,155 @@
1
+ /**
2
+ * 图片框组件 - 带装饰边框的图片
3
+ */
4
+ const createImageFrame = (ctx) => ({
5
+ /**
6
+ * @param {Object} params
7
+ * @param {string} params.src - 图片路径或URL
8
+ * @param {number} params.x - X坐标
9
+ * @param {number} params.y - Y坐标
10
+ * @param {number} params.width - 图片宽度
11
+ * @param {number} params.height - 图片高度
12
+ * @param {string} [params.borderColor='#ffffff'] - 边框颜色
13
+ * @param {number} [params.borderWidth=3] - 边框宽度
14
+ * @param {string} [params.outerColor='#1a1a2e'] - 外边框颜色
15
+ * @param {number} [params.outerWidth=6] - 外边框宽度
16
+ * @param {number} [params.shadowBlur=0] - 阴影模糊
17
+ * @param {number} [params.shadowOffsetX=0] - 阴影X偏移
18
+ * @param {number} [params.shadowOffsetY=0] - 阴影Y偏移
19
+ * @param {string} [params.shadowColor='rgba(0,0,0,0.3)'] - 阴影颜色
20
+ * @param {number} [params.radius=0] - 圆角半径
21
+ * @param {string} [params.overlayColor] - 叠加颜色
22
+ * @param {number} [params.overlayOpacity=0] - 叠加透明度
23
+ * @param {string} [params.fit='cover'] - 图片填充方式: cover, contain, fill
24
+ */
25
+ async draw({
26
+ src,
27
+ x,
28
+ y,
29
+ width,
30
+ height,
31
+ borderColor = '#ffffff',
32
+ borderWidth = 3,
33
+ outerColor = '#1a1a2e',
34
+ outerWidth = 6,
35
+ shadowBlur = 0,
36
+ shadowOffsetX = 0,
37
+ shadowOffsetY = 0,
38
+ shadowColor = 'rgba(0,0,0,0.3)',
39
+ radius = 0,
40
+ overlayColor,
41
+ overlayOpacity = 0,
42
+ fit = 'cover'
43
+ }) {
44
+ // 绘制外边框(装饰层)
45
+ if (outerWidth > 0) {
46
+ ctx.fillStyle = outerColor
47
+ await _roundRect(ctx, x - outerWidth, y - outerWidth, width + outerWidth * 2, height + outerWidth * 2, radius + outerWidth)
48
+ ctx.fill()
49
+ }
50
+
51
+ // 绘制内边框
52
+ if (borderWidth > 0) {
53
+ ctx.fillStyle = borderColor
54
+ await _roundRect(ctx, x - borderWidth, y - borderWidth, width + borderWidth * 2, height + borderWidth * 2, radius + borderWidth)
55
+ ctx.fill()
56
+ }
57
+
58
+ // 绘制阴影
59
+ if (shadowBlur > 0) {
60
+ ctx.shadowColor = shadowColor
61
+ ctx.shadowBlur = shadowBlur
62
+ ctx.shadowOffsetX = shadowOffsetX
63
+ ctx.shadowOffsetY = shadowOffsetY
64
+ }
65
+
66
+ // 加载并绘制图片
67
+ const image = await _loadImage(src)
68
+ const imgWidth = image.width
69
+ const imgHeight = image.height
70
+ const imgRatio = imgWidth / imgHeight
71
+ const boxRatio = width / height
72
+
73
+ let drawX = x, drawY = y, drawW = width, drawH = height
74
+
75
+ if (fit === 'cover') {
76
+ if (imgRatio > boxRatio) {
77
+ drawH = height
78
+ drawW = height * imgRatio
79
+ drawX = x - (drawW - width) / 2
80
+ } else {
81
+ drawW = width
82
+ drawH = width / imgRatio
83
+ drawY = y - (drawH - height) / 2
84
+ }
85
+ } else if (fit === 'contain') {
86
+ if (imgRatio > boxRatio) {
87
+ drawW = width
88
+ drawH = width / imgRatio
89
+ drawY = y + (height - drawH) / 2
90
+ } else {
91
+ drawH = height
92
+ drawW = height * imgRatio
93
+ drawX = x + (width - drawW) / 2
94
+ }
95
+ }
96
+
97
+ // 裁剪并绘制图片
98
+ ctx.save()
99
+ await _roundRect(ctx, x, y, width, height, radius)
100
+ ctx.clip()
101
+ ctx.drawImage(image, drawX, drawY, drawW, drawH)
102
+ ctx.restore()
103
+
104
+ // 重置阴影
105
+ ctx.shadowColor = 'transparent'
106
+ ctx.shadowBlur = 0
107
+ ctx.shadowOffsetX = 0
108
+ ctx.shadowOffsetY = 0
109
+
110
+ // 叠加颜色
111
+ if (overlayColor && overlayOpacity > 0) {
112
+ ctx.fillStyle = overlayColor
113
+ ctx.globalAlpha = overlayOpacity
114
+ await _roundRect(ctx, x, y, width, height, radius)
115
+ ctx.fill()
116
+ ctx.globalAlpha = 1
117
+ }
118
+ }
119
+ })
120
+
121
+ // 辅助函数:圆角矩形
122
+ async function _roundRect(ctx, x, y, width, height, radius) {
123
+ const r = Math.min(radius, width / 2, height / 2)
124
+ ctx.beginPath()
125
+ ctx.moveTo(x + r, y)
126
+ ctx.lineTo(x + width - r, y)
127
+ ctx.quadraticCurveTo(x + width, y, x + width, y + r)
128
+ ctx.lineTo(x + width, y + height - r)
129
+ ctx.quadraticCurveTo(x + width, y + height, x + width - r, y + height)
130
+ ctx.lineTo(x + r, y + height)
131
+ ctx.quadraticCurveTo(x, y + height, x, y + height - r)
132
+ ctx.lineTo(x, y + r)
133
+ ctx.quadraticCurveTo(x, y, x + r, y)
134
+ ctx.closePath()
135
+ }
136
+
137
+ // 辅助函数:加载图片
138
+ async function _loadImage(src) {
139
+ return new Promise((resolve, reject) => {
140
+ const img = new Image()
141
+ img.crossOrigin = 'anonymous'
142
+ img.onload = () => resolve(img)
143
+ img.onerror = (e) => {
144
+ // 尝试 data URL 格式
145
+ if (src.startsWith('data:')) {
146
+ img.src = src
147
+ } else {
148
+ reject(new Error(`Failed to load image: ${src}`))
149
+ }
150
+ }
151
+ img.src = src
152
+ })
153
+ }
154
+
155
+ module.exports = createImageFrame
@@ -0,0 +1,62 @@
1
+ /**
2
+ * 高级组件模块导出
3
+ */
4
+
5
+ const createCard = require('./card')
6
+ const createBadge = require('./badge')
7
+ const createCTA = require('./cta')
8
+ const createFeature = require('./feature')
9
+ const createFeatureGrid = require('./featureGrid')
10
+ const createDivider = require('./divider')
11
+ const createAvatar = require('./avatar')
12
+ const createProgress = require('./progress')
13
+ const createRating = require('./rating')
14
+ const createQuote = require('./quote')
15
+ const createStatCard = require('./statCard')
16
+ const createTagCloud = require('./tagCloud')
17
+ const createStepper = require('./stepper')
18
+ const createTimeline = require('./timeline')
19
+ const { createListItem, createList } = require('./listItem')
20
+ const createNotification = require('./notification')
21
+ const createImageFrame = require('./imageFrame')
22
+ const createColumns = require('./columns')
23
+ const createGrid = require('./grid')
24
+ const createStar = require('./star')
25
+ const createArrow = require('./arrow')
26
+ const createProgressCircle = require('./progressCircle')
27
+ const createChip = require('./chip')
28
+ const createChart = require('./chart')
29
+ const createWatermark = require('./watermark')
30
+ const createTable = require('./table')
31
+
32
+ module.exports = {
33
+ // 原有组件
34
+ createCard,
35
+ createBadge,
36
+ createCTA,
37
+ createFeature,
38
+ createFeatureGrid,
39
+ createDivider,
40
+ createAvatar,
41
+ createProgress,
42
+ createRating,
43
+ createQuote,
44
+ createStatCard,
45
+ createTagCloud,
46
+ createStepper,
47
+ createTimeline,
48
+ createListItem,
49
+ createList,
50
+ createNotification,
51
+ createImageFrame,
52
+ createColumns,
53
+ createGrid,
54
+ // 新增组件
55
+ createStar,
56
+ createArrow,
57
+ createProgressCircle,
58
+ createChip,
59
+ createChart,
60
+ createWatermark,
61
+ createTable,
62
+ }