foliko 1.1.7 → 1.1.9

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 (113) hide show
  1. package/.agent/agents/poster-expert.md +228 -0
  2. package/.agent/data/default.json +10 -0
  3. package/.agent/data/plugins-state.json +1 -1
  4. package/.agent/mcp_config.json +0 -6
  5. package/.agent/plugins/test-plugin.py +15 -0
  6. package/.agent/plugins/test_nested_plugin.py +85 -0
  7. package/.agent/sessions/cli_default.json +83 -803
  8. package/.agent/sessions/weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat.json +189 -0
  9. package/.claude/settings.local.json +8 -1
  10. package/cli/src/ui/chat-ui.js +32 -21
  11. package/foliko_poster.png +0 -0
  12. package/output/business_poster_final.png +0 -0
  13. package/output/emoji_test_v2.png +0 -0
  14. package/output/foliko-ai-launch-poster.png +0 -0
  15. package/output/foliko-poster.png +0 -0
  16. package/output/muji_style_poster.png +0 -0
  17. package/output/new_product_launch.png +0 -0
  18. package/output/news_poster_625yi_subsidy.png +0 -0
  19. package/output/tech_future_2026.png +0 -0
  20. package/output/tech_future_poster.png +0 -0
  21. package/package.json +2 -2
  22. package/plugins/default-plugins.js +60 -7
  23. package/plugins/extension-executor-plugin.js +32 -22
  24. package/plugins/feishu-plugin.js +2 -2
  25. package/plugins/python-plugin-loader.js +461 -40
  26. package/plugins/python-plugin-loader.js.bak +856 -0
  27. package/plugins/subagent-plugin.js +0 -121
  28. package/plugins/telegram-plugin.js +2 -2
  29. package/plugins/weixin-plugin.js +40 -31
  30. package/poster.png +0 -0
  31. package/skills/foliko-dev/SKILL.md +6 -0
  32. package/skills/python-plugin-dev/SKILL.md +124 -2
  33. package/src/core/agent-chat.js +220 -281
  34. package/src/core/agent.js +127 -29
  35. package/src/executors/mcp-executor.js +282 -26
  36. package/src/utils/plugin-helpers.js +22 -4
  37. package/system.md +362 -109
  38. package/test-scan.js +18 -0
  39. package/.agent/memory/feedback/mnt7jrlt-d67qs7.md +0 -15
  40. package/.agent/memory/feedback/mnt88ja3-al4fuy.md +0 -9
  41. package/.agent/plugins/poster-plugin/README.md +0 -304
  42. package/.agent/plugins/poster-plugin/emojis/rocket.png +0 -1
  43. package/.agent/plugins/poster-plugin/fonts/PatuaOne-Regular.ttf +0 -0
  44. package/.agent/plugins/poster-plugin/fonts/SegoeUI Emoji.ttf +0 -0
  45. package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221.ttf +0 -0
  46. 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
  47. package/.agent/plugins/poster-plugin/index.js +0 -13
  48. package/.agent/plugins/poster-plugin/package.json +0 -29
  49. package/.agent/plugins/poster-plugin/src/canvas.js +0 -224
  50. package/.agent/plugins/poster-plugin/src/components/arrow.js +0 -84
  51. package/.agent/plugins/poster-plugin/src/components/avatar.js +0 -71
  52. package/.agent/plugins/poster-plugin/src/components/badge.js +0 -85
  53. package/.agent/plugins/poster-plugin/src/components/barcode.js +0 -120
  54. package/.agent/plugins/poster-plugin/src/components/bubble.js +0 -153
  55. package/.agent/plugins/poster-plugin/src/components/button.js +0 -124
  56. package/.agent/plugins/poster-plugin/src/components/card.js +0 -88
  57. package/.agent/plugins/poster-plugin/src/components/chart.js +0 -127
  58. package/.agent/plugins/poster-plugin/src/components/chip.js +0 -88
  59. package/.agent/plugins/poster-plugin/src/components/columns.js +0 -107
  60. package/.agent/plugins/poster-plugin/src/components/cta.js +0 -87
  61. package/.agent/plugins/poster-plugin/src/components/divider.js +0 -55
  62. package/.agent/plugins/poster-plugin/src/components/feature.js +0 -85
  63. package/.agent/plugins/poster-plugin/src/components/featureGrid.js +0 -117
  64. package/.agent/plugins/poster-plugin/src/components/frame.js +0 -230
  65. package/.agent/plugins/poster-plugin/src/components/grid.js +0 -118
  66. package/.agent/plugins/poster-plugin/src/components/highlightText.js +0 -144
  67. package/.agent/plugins/poster-plugin/src/components/icon.js +0 -94
  68. package/.agent/plugins/poster-plugin/src/components/imageFrame.js +0 -155
  69. package/.agent/plugins/poster-plugin/src/components/index.js +0 -81
  70. package/.agent/plugins/poster-plugin/src/components/listItem.js +0 -147
  71. package/.agent/plugins/poster-plugin/src/components/notification.js +0 -123
  72. package/.agent/plugins/poster-plugin/src/components/progress.js +0 -79
  73. package/.agent/plugins/poster-plugin/src/components/progressCircle.js +0 -117
  74. package/.agent/plugins/poster-plugin/src/components/qrcode.js +0 -74
  75. package/.agent/plugins/poster-plugin/src/components/quote.js +0 -97
  76. package/.agent/plugins/poster-plugin/src/components/rating.js +0 -85
  77. package/.agent/plugins/poster-plugin/src/components/ribbon.js +0 -193
  78. package/.agent/plugins/poster-plugin/src/components/seal.js +0 -146
  79. package/.agent/plugins/poster-plugin/src/components/star.js +0 -70
  80. package/.agent/plugins/poster-plugin/src/components/statCard.js +0 -105
  81. package/.agent/plugins/poster-plugin/src/components/stepper.js +0 -118
  82. package/.agent/plugins/poster-plugin/src/components/table.js +0 -167
  83. package/.agent/plugins/poster-plugin/src/components/tagCloud.js +0 -85
  84. package/.agent/plugins/poster-plugin/src/components/timeline.js +0 -117
  85. package/.agent/plugins/poster-plugin/src/components/watermark.js +0 -52
  86. package/.agent/plugins/poster-plugin/src/composer.js +0 -2146
  87. package/.agent/plugins/poster-plugin/src/elements/artText.js +0 -60
  88. package/.agent/plugins/poster-plugin/src/elements/background.js +0 -84
  89. package/.agent/plugins/poster-plugin/src/elements/circle.js +0 -31
  90. package/.agent/plugins/poster-plugin/src/elements/image.js +0 -28
  91. package/.agent/plugins/poster-plugin/src/elements/index.js +0 -28
  92. package/.agent/plugins/poster-plugin/src/elements/line.js +0 -23
  93. package/.agent/plugins/poster-plugin/src/elements/polygon.js +0 -63
  94. package/.agent/plugins/poster-plugin/src/elements/rectangle.js +0 -32
  95. package/.agent/plugins/poster-plugin/src/elements/richText.js +0 -230
  96. package/.agent/plugins/poster-plugin/src/elements/svg.js +0 -108
  97. package/.agent/plugins/poster-plugin/src/elements/text.js +0 -109
  98. package/.agent/plugins/poster-plugin/src/fonts.js +0 -243
  99. package/.agent/plugins/poster-plugin/src/index.js +0 -2081
  100. package/.agent/plugins/poster-plugin/src/presets.js +0 -36
  101. package/.agent/plugins/poster-plugin/src/templates/business.js +0 -60
  102. package/.agent/plugins/poster-plugin/src/templates/gradient.js +0 -64
  103. package/.agent/plugins/poster-plugin/src/templates/index.js +0 -43
  104. package/.agent/plugins/poster-plugin/src/templates/modern.js +0 -69
  105. package/.agent/plugins/poster-plugin/src/templates/simple.js +0 -58
  106. package/.agent/plugins/poster-plugin/src/templates/social.js +0 -62
  107. package/.agent/plugins/poster-plugin/src/templates/tech.js +0 -84
  108. package/.agent/plugins/poster-plugin/src/utils/imageLoader.js +0 -84
  109. package/.agent/plugins/poster-plugin/test-background.svg +0 -1
  110. package/.agent/plugins/poster-plugin/test-full-poster.svg +0 -2
  111. package/.agent/plugins/poster-plugin/test-image.png +0 -0
  112. package/.agent/plugins/poster-plugin/yarn.lock +0 -1007
  113. package/output/zen_silence.png +0 -0
@@ -1,84 +0,0 @@
1
- /**
2
- * 箭头组件
3
- */
4
-
5
- const paper = require('paper')
6
-
7
- /**
8
- * 创建箭头组件
9
- */
10
- function createArrow(project, canvas, params) {
11
- const {
12
- x1, y1, x2, y2,
13
- color = '#333333',
14
- strokeWidth = 2,
15
- headSize = 12,
16
- style = 'solid',
17
- direction = 'end'
18
- } = params
19
-
20
- const elements = []
21
-
22
- // 创建主线
23
- const line = new paper.Path.Line({
24
- from: [x1, y1],
25
- to: [x2, y2]
26
- })
27
- line.strokeColor = new paper.Color(color)
28
- line.strokeWidth = strokeWidth
29
- if (style === 'dashed') {
30
- line.dashArray = [10, 5]
31
- }
32
-
33
- if (project && project.activeLayer) {
34
- project.activeLayer.addChild(line)
35
- }
36
- elements.push({ type: 'line', id: line.id })
37
-
38
- // 创建箭头头部
39
- function createArrowHead(x, y, angle) {
40
- const path = new paper.Path()
41
- const angle1 = angle + Math.PI * 0.8
42
- const angle2 = angle - Math.PI * 0.8
43
-
44
- path.moveTo(x, y)
45
- path.lineTo(
46
- x + headSize * Math.cos(angle1),
47
- y + headSize * Math.sin(angle1)
48
- )
49
- path.moveTo(x, y)
50
- path.lineTo(
51
- x + headSize * Math.cos(angle2),
52
- y + headSize * Math.sin(angle2)
53
- )
54
-
55
- path.strokeColor = new paper.Color(color)
56
- path.strokeWidth = strokeWidth
57
- path.strokeCap = 'round'
58
-
59
- if (project && project.activeLayer) {
60
- project.activeLayer.addChild(path)
61
- }
62
- return path
63
- }
64
-
65
- const angle = Math.atan2(y2 - y1, x2 - x1)
66
-
67
- if (direction === 'end' || direction === 'both') {
68
- const head = createArrowHead(x2, y2, angle)
69
- elements.push({ type: 'path', id: head.id })
70
- }
71
-
72
- if (direction === 'start' || direction === 'both') {
73
- const head = createArrowHead(x1, y1, angle + Math.PI)
74
- elements.push({ type: 'path', id: head.id })
75
- }
76
-
77
- return {
78
- success: true,
79
- elements,
80
- type: 'arrow'
81
- }
82
- }
83
-
84
- module.exports = createArrow
@@ -1,71 +0,0 @@
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.size - 头像大小
16
- * @param {string} args.src - 图片路径(可选,不提供则显示首字母)
17
- * @param {string} args.initials - 首字母(无图片时显示)
18
- * @param {string} args.background - 背景色
19
- * @param {string} args.border - 边框颜色
20
- * @param {number} args.borderWidth - 边框宽度
21
- * @param {string} args.color - 文字颜色
22
- */
23
- function createAvatar(project, canvas, args) {
24
- const {
25
- x, y,
26
- size = 80,
27
- src,
28
- initials,
29
- background = '#6366f1',
30
- border,
31
- borderWidth = 0,
32
- color = '#ffffff',
33
- } = args
34
-
35
- const elements = []
36
- const radius = size / 2
37
-
38
- // 绘制圆形背景
39
- const circle = new paper.Path.Circle({
40
- center: [x, y],
41
- radius: radius,
42
- })
43
- circle.fillColor = new paper.Color(background)
44
-
45
- if (border) {
46
- circle.strokeColor = new paper.Color(border)
47
- circle.strokeWidth = borderWidth
48
- }
49
-
50
- elements.push({ type: 'circle', id: circle.id })
51
-
52
- // 如果没有图片,显示首字母
53
- if (!src && initials) {
54
- const text = new paper.PointText({
55
- point: [x, y + size / 6],
56
- content: initials.charAt(0).toUpperCase(),
57
- fontSize: size * 0.4,
58
- fillColor: new paper.Color(color),
59
- justification: 'center',
60
- })
61
- elements.push({ type: 'text', id: text.id })
62
- }
63
-
64
- return {
65
- success: true,
66
- elements,
67
- size,
68
- }
69
- }
70
-
71
- module.exports = createAvatar
@@ -1,85 +0,0 @@
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 {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 {string} args.align - 对齐方式: left, center, right
21
- * @param {number} args.padding - 内边距
22
- * @param {number} args.radius - 圆角半径
23
- */
24
- function createBadge(project, canvas, args) {
25
- const {
26
- x, y,
27
- text,
28
- background = '#007bff',
29
- color = '#ffffff',
30
- border,
31
- fontSize = 18,
32
- align = 'center',
33
- padding = 15,
34
- radius = 4,
35
- } = args
36
-
37
- const elements = []
38
-
39
- // 计算文字宽度(估算)
40
- const textWidth = text.length * fontSize * 0.6
41
- const badgeWidth = textWidth + padding * 2
42
- const badgeHeight = fontSize + padding * 2
43
-
44
- // 计算X位置
45
- let badgeX = x
46
- if (align === 'center') {
47
- badgeX = x - badgeWidth / 2
48
- } else if (align === 'right') {
49
- badgeX = x - badgeWidth
50
- }
51
-
52
- // 绘制徽章背景
53
- const badge = new paper.Path.Rectangle({
54
- point: [badgeX, y],
55
- size: [badgeWidth, badgeHeight],
56
- radius: radius,
57
- })
58
- badge.fillColor = new paper.Color(background)
59
-
60
- if (border) {
61
- badge.strokeColor = new paper.Color(border)
62
- badge.strokeWidth = 1
63
- }
64
-
65
- elements.push({ type: 'rectangle', id: badge.id })
66
-
67
- // 绘制文字
68
- const badgeText = new paper.PointText({
69
- point: [badgeX + badgeWidth / 2, y + badgeHeight / 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: badgeText.id })
76
-
77
- return {
78
- success: true,
79
- elements,
80
- width: badgeWidth,
81
- height: badgeHeight,
82
- }
83
- }
84
-
85
- module.exports = createBadge
@@ -1,120 +0,0 @@
1
- /**
2
- * 条形码组件 - 静态图片
3
- */
4
-
5
- const paper = require('paper')
6
- const { loadImageAsRaster, downloadImage } = require('../utils/imageLoader')
7
-
8
- /**
9
- * 创建条形码
10
- */
11
- async function createBarcode(project, args) {
12
- const {
13
- x = 0,
14
- y = 0,
15
- width = 300,
16
- height = 100,
17
- content = '1234567890',
18
- showText = true,
19
- textColor = '#000000',
20
- fontSize = 16,
21
- opacity = 1,
22
- } = args
23
-
24
- // 内容太短或像URL,回退到简单条形码
25
- if (content.length < 8 || content.startsWith('http')) {
26
- return createSimpleBarcode(project, { x, y, width, height, content, showText, textColor, fontSize, opacity })
27
- }
28
-
29
- try {
30
- const barcodeUrl = `https://api.qrserver.com/v1/create-qr-code/?size=${width}x${height}&data=${encodeURIComponent(content)}&format=png`
31
- const { raster } = await loadImageAsRaster(project, barcodeUrl, { x, y, width, height }, opacity)
32
- const items = [raster]
33
-
34
- // 文字
35
- if (showText) {
36
- const textItem = new paper.PointText({
37
- point: [x + width / 2, y + height + fontSize + 5],
38
- content: content,
39
- fontSize,
40
- fontFamily: 'monospace',
41
- fillColor: new paper.Color(textColor),
42
- justification: 'center',
43
- })
44
- if (opacity !== 1) textItem.opacity = opacity
45
- items.push(textItem)
46
- }
47
-
48
- return {
49
- success: true,
50
- type: 'barcode',
51
- items: items.map(i => i.id),
52
- }
53
- } catch (err) {
54
- // 回退到简单条形码
55
- return createSimpleBarcode(project, { x, y, width, height, content, showText, textColor, fontSize, opacity })
56
- }
57
- }
58
-
59
- /**
60
- * 创建简单的条形码(使用线条绘制)
61
- */
62
- function createSimpleBarcode(project, args) {
63
- const {
64
- x = 0,
65
- y = 0,
66
- width = 300,
67
- height = 80,
68
- content = '123456',
69
- color = '#000000',
70
- showText = true,
71
- textColor = '#000000',
72
- fontSize = 14,
73
- opacity = 1,
74
- } = args
75
-
76
- const items = []
77
- const barHeight = showText ? height - 25 : height
78
- const barWidth = width / (content.length * 15)
79
-
80
- // 生成简单的条形图案
81
- for (let i = 0; i < content.length; i++) {
82
- const charCode = content.charCodeAt(i)
83
- const density = (charCode % 3) + 1
84
-
85
- for (let d = 0; d < density; d++) {
86
- const isWide = (charCode + d) % 2 === 0
87
- const barW = isWide ? barWidth * 2 : barWidth
88
-
89
- const bar = new paper.Path.Rectangle({
90
- point: [x + (i * density + d) * barWidth, y],
91
- size: [barW * 0.8, barHeight],
92
- fillColor: new paper.Color(color),
93
- })
94
- if (opacity !== 1) bar.opacity = opacity
95
- items.push(bar)
96
- }
97
- }
98
-
99
- // 文字
100
- if (showText) {
101
- const textItem = new paper.PointText({
102
- point: [x + width / 2, y + barHeight + fontSize + 3],
103
- content: content,
104
- fontSize,
105
- fontFamily: 'monospace',
106
- fillColor: new paper.Color(textColor),
107
- justification: 'center',
108
- })
109
- if (opacity !== 1) textItem.opacity = opacity
110
- items.push(textItem)
111
- }
112
-
113
- return {
114
- success: true,
115
- type: 'barcode',
116
- items: items.map(i => i.id),
117
- }
118
- }
119
-
120
- module.exports = createBarcode
@@ -1,153 +0,0 @@
1
- /**
2
- * 对话气泡组件
3
- */
4
-
5
- const paper = require('paper')
6
-
7
- /**
8
- * 创建对话气泡
9
- */
10
- function createBubble(project, args) {
11
- const {
12
- x = 0,
13
- y = 0,
14
- width = 300,
15
- height = 100,
16
- text = '',
17
- fontSize = 24,
18
- fontFamily,
19
- color = '#000000',
20
- backgroundColor = '#ffffff',
21
- borderColor,
22
- borderWidth = 1,
23
- radius = 20,
24
- tailDirection = 'bottom', // bottom, top, left, right
25
- tailPosition = 'left', // left, center, right
26
- shadow,
27
- opacity = 1,
28
- } = args
29
-
30
- const items = []
31
-
32
- // 气泡主体
33
- const bubbleX = tailDirection === 'left' ? x + 15 : x
34
- const bubbleY = tailDirection === 'top' ? y + 15 : y
35
- const bubbleWidth = tailDirection === 'left' ? width - 15 : width
36
- const bubbleHeight = tailDirection === 'top' ? height - 15 : height
37
-
38
- const bgOpts = {
39
- point: [bubbleX, bubbleY],
40
- size: [bubbleWidth, bubbleHeight],
41
- radius: radius,
42
- }
43
-
44
- if (borderColor) {
45
- bgOpts.strokeColor = new paper.Color(borderColor)
46
- bgOpts.strokeWidth = borderWidth
47
- }
48
-
49
- const bg = new paper.Path.Rectangle(bgOpts)
50
- bg.fillColor = new paper.Color(backgroundColor)
51
-
52
- if (shadow) {
53
- bg.shadowColor = new paper.Color(shadow.color || '#000000')
54
- bg.shadowBlur = shadow.blur || 10
55
- bg.shadowOffset = new paper.Point(shadow.offsetX || 3, shadow.offsetY || 3)
56
- }
57
-
58
- if (opacity !== 1) bg.opacity = opacity
59
- items.push(bg)
60
-
61
- // 气泡尾巴
62
- const tailSize = 20
63
- let tailX, tailY, tailRotation
64
-
65
- // 计算尾巴位置
66
- switch (tailDirection) {
67
- case 'bottom':
68
- tailY = bubbleY + bubbleHeight - 5
69
- if (tailPosition === 'left') tailX = bubbleX + 30
70
- else if (tailPosition === 'right') tailX = bubbleX + bubbleWidth - 30
71
- else tailX = bubbleX + bubbleWidth / 2
72
- tailRotation = 0
73
- break
74
- case 'top':
75
- tailY = bubbleY + 5
76
- if (tailPosition === 'left') tailX = bubbleX + 30
77
- else if (tailPosition === 'right') tailX = bubbleX + bubbleWidth - 30
78
- else tailX = bubbleX + bubbleWidth / 2
79
- tailRotation = 180
80
- break
81
- case 'left':
82
- tailX = bubbleX + 5
83
- if (tailPosition === 'left') tailY = bubbleY + 30
84
- else if (tailPosition === 'right') tailY = bubbleY + bubbleHeight - 30
85
- else tailY = bubbleY + bubbleHeight / 2
86
- tailRotation = 90
87
- break
88
- case 'right':
89
- tailX = bubbleX + bubbleWidth - 5
90
- if (tailPosition === 'left') tailY = bubbleY + 30
91
- else if (tailPosition === 'right') tailY = bubbleY + bubbleHeight - 30
92
- else tailY = bubbleY + bubbleHeight / 2
93
- tailRotation = 270
94
- break
95
- }
96
-
97
- const tail = new paper.Path()
98
- tail.add(new paper.Point(tailX - tailSize, tailY))
99
- tail.add(new paper.Point(tailX, tailY + tailSize * 0.7))
100
- tail.add(new paper.Point(tailX, tailY - tailSize * 0.7))
101
- tail.closed = true
102
- tail.fillColor = new paper.Color(backgroundColor)
103
- if (borderColor) {
104
- tail.strokeColor = new paper.Color(borderColor)
105
- tail.strokeWidth = borderWidth
106
- }
107
- tail.rotate(tailRotation, new paper.Point(tailX, tailY))
108
-
109
- if (opacity !== 1) tail.opacity = opacity
110
- items.push(tail)
111
-
112
- // 文字
113
- const padding = 25
114
- const textItem = new paper.PointText({
115
- point: [bubbleX + padding, bubbleY + bubbleHeight / 2 + fontSize / 3],
116
- content: text,
117
- fontSize,
118
- fontFamily: fontFamily || 'sans-serif',
119
- fillColor: new paper.Color(color),
120
- justification: tailPosition === 'left' ? 'left' : tailPosition === 'right' ? 'right' : 'center',
121
- })
122
-
123
- // 限制文字宽度
124
- const maxTextWidth = bubbleWidth - padding * 2
125
- if (textItem.bounds.width > maxTextWidth) {
126
- textItem.justification = 'left'
127
- const charsPerLine = Math.floor((text.length * maxTextWidth) / textItem.bounds.width)
128
- // 简单换行处理
129
- let lines = []
130
- let currentLine = ''
131
- for (const char of text) {
132
- currentLine += char
133
- const testText = new paper.PointText({ content: currentLine, fontSize, fontFamily: fontFamily || 'sans-serif' })
134
- if (testText.bounds.width > maxTextWidth) {
135
- lines.push(currentLine.slice(0, -1))
136
- currentLine = char
137
- }
138
- }
139
- if (currentLine) lines.push(currentLine)
140
- textItem.content = lines.join('\n')
141
- }
142
-
143
- if (opacity !== 1) textItem.opacity = opacity
144
- items.push(textItem)
145
-
146
- return {
147
- success: true,
148
- type: 'bubble',
149
- items: items.map(i => i.id),
150
- }
151
- }
152
-
153
- module.exports = createBubble
@@ -1,124 +0,0 @@
1
- /**
2
- * 按钮组件
3
- */
4
-
5
- const paper = require('paper')
6
- const { loadImageAsRaster } = require('../utils/imageLoader')
7
-
8
- /**
9
- * 创建按钮
10
- */
11
- async function createButton(project, args) {
12
- const {
13
- x = 0,
14
- y = 0,
15
- width = 200,
16
- height = 60,
17
- text = '按钮',
18
- fontSize = 24,
19
- fontFamily,
20
- color = '#ffffff',
21
- backgroundColor = '#3b82f6',
22
- borderColor,
23
- borderWidth = 0,
24
- radius = 8,
25
- shadow,
26
- gradient,
27
- icon,
28
- iconPosition = 'left',
29
- opacity = 1,
30
- } = args
31
-
32
- // 创建按钮背景
33
- const bgOptions = {
34
- point: [x, y],
35
- size: [width, height],
36
- radius: radius,
37
- }
38
-
39
- if (borderColor) {
40
- bgOptions.strokeColor = new paper.Color(borderColor)
41
- bgOptions.strokeWidth = borderWidth
42
- }
43
-
44
- const bg = new paper.Path.Rectangle(bgOptions)
45
-
46
- // 渐变或纯色填充
47
- if (gradient && gradient.colors && gradient.colors.length > 0) {
48
- const colors = gradient.colors.map(c => new paper.Color(c))
49
- bg.fillColor = new paper.Color({
50
- gradient: { stops: colors },
51
- origin: bg.bounds.topLeft,
52
- destination: bg.bounds.bottomLeft,
53
- })
54
- } else {
55
- bg.fillColor = new paper.Color(backgroundColor)
56
- }
57
-
58
- // 阴影
59
- if (shadow) {
60
- bg.shadowColor = new paper.Color(shadow.color || '#000000')
61
- bg.shadowBlur = shadow.blur || 10
62
- bg.shadowOffset = new paper.Point(shadow.offsetX || 0, shadow.offsetY || 4)
63
- }
64
-
65
- if (opacity !== 1) {
66
- bg.opacity = opacity
67
- }
68
-
69
- const items = [bg]
70
- let textX = x + width / 2
71
-
72
- // 添加图标
73
- if (icon) {
74
- const iconSize = Math.min(height * 0.5, 40)
75
- const iconX = iconPosition === 'left' ? x + 20 : x + width - 40 - iconSize
76
-
77
- if (icon.startsWith('http') || icon.startsWith('data:')) {
78
- // URL图片图标
79
- const { raster } = await loadImageAsRaster(project, icon, {
80
- x: iconX,
81
- y: y + (height - iconSize) / 2,
82
- width: iconSize,
83
- height: iconSize
84
- }, opacity)
85
- items.push(raster)
86
- } else {
87
- // Emoji 或文本图标
88
- const iconText = new paper.PointText({
89
- point: [iconX + iconSize / 2, y + height / 2 + fontSize / 3],
90
- content: icon,
91
- fontSize: iconSize,
92
- justification: 'center',
93
- })
94
- if (opacity !== 1) iconText.opacity = opacity
95
- items.push(iconText)
96
- }
97
-
98
- textX = iconPosition === 'left' ? x + width / 2 + 25 : x + width / 2 - 25
99
- }
100
-
101
- // 添加文字
102
- const textItem = new paper.PointText({
103
- point: [textX, y + height / 2 + fontSize / 3],
104
- content: text,
105
- fontSize,
106
- fontFamily: fontFamily || 'sans-serif',
107
- fillColor: new paper.Color(color),
108
- justification: 'center',
109
- })
110
-
111
- if (opacity !== 1) {
112
- textItem.opacity = opacity
113
- }
114
-
115
- items.push(textItem)
116
-
117
- return {
118
- success: true,
119
- type: 'button',
120
- items: items.map(i => i.id),
121
- }
122
- }
123
-
124
- module.exports = createButton