foliko 1.1.1 → 1.1.2

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 (57) hide show
  1. package/.agent/data/weixin-media/2026-04-08/img_1775618677512.jpg +0 -0
  2. package/.agent/data/weixin-media/2026-04-08/img_1775619073340.jpg +0 -0
  3. package/.agent/data/weixin-media/2026-04-08/img_1775619097536.jpg +0 -0
  4. package/.agent/data/weixin-media/2026-04-08/img_1775619209388.jpg +0 -0
  5. package/.agent/plugins/poster-plugin/package.json +2 -1
  6. package/.agent/plugins/poster-plugin/src/canvas.js +70 -7
  7. package/.agent/plugins/poster-plugin/src/components/barcode.js +120 -0
  8. package/.agent/plugins/poster-plugin/src/components/bubble.js +153 -0
  9. package/.agent/plugins/poster-plugin/src/components/button.js +124 -0
  10. package/.agent/plugins/poster-plugin/src/components/cta.js +26 -24
  11. package/.agent/plugins/poster-plugin/src/components/featureGrid.js +22 -17
  12. package/.agent/plugins/poster-plugin/src/components/frame.js +230 -0
  13. package/.agent/plugins/poster-plugin/src/components/highlightText.js +144 -0
  14. package/.agent/plugins/poster-plugin/src/components/icon.js +94 -0
  15. package/.agent/plugins/poster-plugin/src/components/index.js +19 -0
  16. package/.agent/plugins/poster-plugin/src/components/listItem.js +6 -5
  17. package/.agent/plugins/poster-plugin/src/components/qrcode.js +74 -0
  18. package/.agent/plugins/poster-plugin/src/components/ribbon.js +193 -0
  19. package/.agent/plugins/poster-plugin/src/components/seal.js +146 -0
  20. package/.agent/plugins/poster-plugin/src/components/table.js +17 -9
  21. package/.agent/plugins/poster-plugin/src/components/tagCloud.js +24 -17
  22. package/.agent/plugins/poster-plugin/src/components/timeline.js +24 -12
  23. package/.agent/plugins/poster-plugin/src/composer.js +392 -150
  24. package/.agent/plugins/poster-plugin/src/elements/background.js +36 -4
  25. package/.agent/plugins/poster-plugin/src/elements/image.js +4 -47
  26. package/.agent/plugins/poster-plugin/src/elements/index.js +2 -0
  27. package/.agent/plugins/poster-plugin/src/elements/richText.js +230 -0
  28. package/.agent/plugins/poster-plugin/src/elements/svg.js +35 -19
  29. package/.agent/plugins/poster-plugin/src/index.js +430 -7
  30. package/.agent/plugins/poster-plugin/src/utils/imageLoader.js +84 -0
  31. package/.agent/plugins/poster-plugin/test-background.svg +1 -0
  32. package/.agent/plugins/poster-plugin/test-full-poster.svg +2 -0
  33. package/.agent/plugins/poster-plugin/test-image.png +0 -0
  34. package/.agent/sessions/cli_default.json +1089 -145
  35. package/.agent/sessions/weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat.json +8902 -0
  36. package/.claude/settings.local.json +6 -1
  37. package/output/beef-love-poster.png +0 -0
  38. package/output/international-news-daily.png +0 -0
  39. package/package.json +2 -1
  40. package/plugins/extension-executor-plugin.js +33 -32
  41. package/plugins/file-system-plugin.js +4 -19
  42. package/plugins/subagent-plugin.js +37 -14
  43. package/plugins/weixin-plugin.js +167 -47
  44. package/poster-test-2.png +0 -0
  45. package/skills/poster-guide/SKILL.md +497 -5
  46. package/src/core/agent-chat.js +141 -8
  47. package/src/core/agent.js +6 -3
  48. package/calc_tokens_weixin.js +0 -81
  49. package/foliko-creative-3.png +0 -0
  50. package/foliko-creative-4.png +0 -0
  51. package/foliko-creative-5.png +0 -0
  52. package/story-cover-book-v2.png +0 -0
  53. package/story-cover-japanese-1.png +0 -0
  54. package/story-cover-japanese-2.png +0 -0
  55. package/story-cover-japanese-3.png +0 -0
  56. package/story-cover-moran.png +0 -0
  57. package/undefined.png +0 -0
@@ -0,0 +1,193 @@
1
+ /**
2
+ * 丝带/飘带组件
3
+ */
4
+
5
+ const paper = require('paper')
6
+
7
+ /**
8
+ * 创建丝带
9
+ */
10
+ function createRibbon(project, args) {
11
+ const {
12
+ x = 0,
13
+ y = 0,
14
+ width = 300,
15
+ text = '',
16
+ fontSize = 28,
17
+ fontFamily,
18
+ color = '#ffffff',
19
+ backgroundColor = '#e74c3c',
20
+ borderColor,
21
+ borderWidth = 2,
22
+ shadow,
23
+ position = 'top', // top, bottom, left, right
24
+ style = 'fold', // fold, diagonal, corner
25
+ opacity = 1,
26
+ } = args
27
+
28
+ const items = []
29
+
30
+ if (style === 'diagonal') {
31
+ // 对角丝带
32
+ const diagonalLength = Math.sqrt(width ** 2 + 60 ** 2)
33
+ const angle = Math.atan2(60, width) * 180 / Math.PI
34
+
35
+ const ribbon = new paper.Path.Rectangle({
36
+ point: [x, y],
37
+ size: [diagonalLength, 60],
38
+ radius: 4,
39
+ fillColor: new paper.Color(backgroundColor),
40
+ })
41
+ ribbon.rotate(angle, new paper.Point(x, y))
42
+
43
+ if (borderColor) {
44
+ ribbon.strokeColor = new paper.Color(borderColor)
45
+ ribbon.strokeWidth = borderWidth
46
+ }
47
+
48
+ if (shadow) {
49
+ ribbon.shadowColor = new paper.Color(shadow.color || '#000000')
50
+ ribbon.shadowBlur = shadow.blur || 8
51
+ ribbon.shadowOffset = new paper.Point(shadow.offsetX || 3, shadow.offsetY || 3)
52
+ }
53
+
54
+ if (opacity !== 1) ribbon.opacity = opacity
55
+ items.push(ribbon)
56
+
57
+ // 文字
58
+ const textItem = new paper.PointText({
59
+ point: [x + diagonalLength / 2, y + 60 / 2 + fontSize / 3],
60
+ content: text,
61
+ fontSize,
62
+ fontFamily: fontFamily || 'sans-serif',
63
+ fillColor: new paper.Color(color),
64
+ justification: 'center',
65
+ })
66
+ textItem.rotate(angle, new paper.Point(x + diagonalLength / 2, y + 60 / 2))
67
+
68
+ if (opacity !== 1) textItem.opacity = opacity
69
+ items.push(textItem)
70
+
71
+ } else if (style === 'corner') {
72
+ // 角落丝带
73
+ const ribbonWidth = width
74
+ const ribbonHeight = 50
75
+
76
+ // 主丝带
77
+ const ribbon = new paper.Path.Rectangle({
78
+ point: [x, y],
79
+ size: [ribbonWidth, ribbonHeight],
80
+ fillColor: new paper.Color(backgroundColor),
81
+ })
82
+
83
+ if (borderColor) {
84
+ ribbon.strokeColor = new paper.Color(borderColor)
85
+ ribbon.strokeWidth = borderWidth
86
+ }
87
+
88
+ if (shadow) {
89
+ ribbon.shadowColor = new paper.Color(shadow.color || '#000000')
90
+ ribbon.shadowBlur = shadow.blur || 8
91
+ ribbon.shadowOffset = new paper.Point(shadow.offsetX || 3, shadow.offsetY || 3)
92
+ }
93
+
94
+ if (opacity !== 1) ribbon.opacity = opacity
95
+ items.push(ribbon)
96
+
97
+ // 折叠部分
98
+ const foldSize = 20
99
+ const fold = new paper.Path()
100
+ fold.add(new paper.Point(x, y + ribbonHeight))
101
+ fold.add(new paper.Point(x, y + ribbonHeight + foldSize))
102
+ fold.add(new paper.Point(x + foldSize, y + ribbonHeight))
103
+ fold.closed = true
104
+ fold.fillColor = new paper.Color(backgroundColor).multiply(0.8)
105
+
106
+ if (borderColor) {
107
+ fold.strokeColor = new paper.Color(borderColor)
108
+ fold.strokeWidth = borderWidth
109
+ }
110
+
111
+ if (opacity !== 1) fold.opacity = opacity
112
+ items.push(fold)
113
+
114
+ // 文字
115
+ const textItem = new paper.PointText({
116
+ point: [x + ribbonWidth / 2, y + ribbonHeight / 2 + fontSize / 3],
117
+ content: text,
118
+ fontSize,
119
+ fontFamily: fontFamily || 'sans-serif',
120
+ fillColor: new paper.Color(color),
121
+ justification: 'center',
122
+ })
123
+
124
+ if (opacity !== 1) textItem.opacity = opacity
125
+ items.push(textItem)
126
+
127
+ } else {
128
+ // 折叠丝带 (默认)
129
+ const ribbonHeight = 50
130
+
131
+ // 主丝带
132
+ const ribbon = new paper.Path.Rectangle({
133
+ point: [x, y],
134
+ size: [width, ribbonHeight],
135
+ fillColor: new paper.Color(backgroundColor),
136
+ })
137
+
138
+ if (borderColor) {
139
+ ribbon.strokeColor = new paper.Color(borderColor)
140
+ ribbon.strokeWidth = borderWidth
141
+ }
142
+
143
+ if (shadow) {
144
+ ribbon.shadowColor = new paper.Color(shadow.color || '#000000')
145
+ ribbon.shadowBlur = shadow.blur || 8
146
+ ribbon.shadowOffset = new paper.Point(shadow.offsetX || 3, shadow.offsetY || 3)
147
+ }
148
+
149
+ if (opacity !== 1) ribbon.opacity = opacity
150
+ items.push(ribbon)
151
+
152
+ // 左右折叠三角
153
+ const foldSize = 15
154
+ const leftFold = new paper.Path()
155
+ leftFold.add(new paper.Point(x, y))
156
+ leftFold.add(new paper.Point(x - foldSize, y - foldSize))
157
+ leftFold.add(new paper.Point(x, y - foldSize))
158
+ leftFold.closed = true
159
+ leftFold.fillColor = new paper.Color(backgroundColor).multiply(0.8)
160
+ if (opacity !== 1) leftFold.opacity = opacity
161
+ items.push(leftFold)
162
+
163
+ const rightFold = new paper.Path()
164
+ rightFold.add(new paper.Point(x + width, y))
165
+ rightFold.add(new paper.Point(x + width + foldSize, y - foldSize))
166
+ rightFold.add(new paper.Point(x + width, y - foldSize))
167
+ rightFold.closed = true
168
+ rightFold.fillColor = new paper.Color(backgroundColor).multiply(0.8)
169
+ if (opacity !== 1) rightFold.opacity = opacity
170
+ items.push(rightFold)
171
+
172
+ // 文字
173
+ const textItem = new paper.PointText({
174
+ point: [x + width / 2, y + ribbonHeight / 2 + fontSize / 3],
175
+ content: text,
176
+ fontSize,
177
+ fontFamily: fontFamily || 'sans-serif',
178
+ fillColor: new paper.Color(color),
179
+ justification: 'center',
180
+ })
181
+
182
+ if (opacity !== 1) textItem.opacity = opacity
183
+ items.push(textItem)
184
+ }
185
+
186
+ return {
187
+ success: true,
188
+ type: 'ribbon',
189
+ items: items.map(i => i.id),
190
+ }
191
+ }
192
+
193
+ module.exports = createRibbon
@@ -0,0 +1,146 @@
1
+ /**
2
+ * 印章组件 - 印章效果
3
+ */
4
+
5
+ const paper = require('paper')
6
+
7
+ /**
8
+ * 创建印章
9
+ */
10
+ function createSeal(project, args) {
11
+ const {
12
+ x = 0,
13
+ y = 0,
14
+ size = 100,
15
+ text = '印章',
16
+ fontSize = 24,
17
+ fontFamily,
18
+ color = '#e74c3c',
19
+ borderColor,
20
+ style = 'circle', // circle, square, star, hexagon
21
+ borderWidth = 3,
22
+ opacity = 1,
23
+ } = args
24
+
25
+ const items = []
26
+ const centerX = x + size / 2
27
+ const centerY = y + size / 2
28
+
29
+ // 印章边框
30
+ let border
31
+ switch (style) {
32
+ case 'circle':
33
+ border = new paper.Path.Circle({
34
+ center: [centerX, centerY],
35
+ radius: size / 2 - borderWidth,
36
+ })
37
+ break
38
+ case 'square':
39
+ const squareSize = size - borderWidth * 2
40
+ border = new paper.Path.Rectangle({
41
+ point: [x + borderWidth, y + borderWidth],
42
+ size: [squareSize, squareSize],
43
+ radius: 4,
44
+ })
45
+ break
46
+ case 'star':
47
+ border = createStarPath(centerX, centerY, size / 2 - borderWidth, size / 2 - borderWidth - 10, 5)
48
+ break
49
+ case 'hexagon':
50
+ border = createPolygonPath(centerX, centerY, size / 2 - borderWidth, 6)
51
+ break
52
+ default:
53
+ border = new paper.Path.Circle({
54
+ center: [centerX, centerY],
55
+ radius: size / 2 - borderWidth,
56
+ })
57
+ }
58
+
59
+ border.strokeColor = new paper.Color(color)
60
+ border.strokeWidth = borderWidth
61
+ border.fillColor = null
62
+ if (opacity !== 1) border.opacity = opacity
63
+ items.push(border)
64
+
65
+ // 内边框
66
+ const innerBorder = border.clone()
67
+ innerBorder.scale(0.85, 0.85, new paper.Point(centerX, centerY))
68
+ innerBorder.strokeWidth = 1
69
+ if (opacity !== 1) innerBorder.opacity = opacity
70
+ items.push(innerBorder)
71
+
72
+ // 文字
73
+ const textItem = new paper.PointText({
74
+ point: [centerX, centerY + fontSize / 3],
75
+ content: text,
76
+ fontSize,
77
+ fontFamily: fontFamily || 'serif',
78
+ fillColor: new paper.Color(color),
79
+ justification: 'center',
80
+ })
81
+
82
+ if (opacity !== 1) textItem.opacity = opacity
83
+ items.push(textItem)
84
+
85
+ // 顶部文字(如果适用)
86
+ const topText = new paper.PointText({
87
+ point: [centerX, centerY - size / 4],
88
+ content: '★',
89
+ fontSize: 16,
90
+ fontFamily: fontFamily || 'serif',
91
+ fillColor: new paper.Color(color),
92
+ justification: 'center',
93
+ })
94
+ if (opacity !== 1) topText.opacity = opacity
95
+ items.push(topText)
96
+
97
+ // 底部星星装饰
98
+ const bottomStar = new paper.PointText({
99
+ point: [centerX, centerY + size / 3],
100
+ content: '★ ★ ★',
101
+ fontSize: 12,
102
+ fontFamily: fontFamily || 'serif',
103
+ fillColor: new paper.Color(color),
104
+ justification: 'center',
105
+ letterSpacing: 8,
106
+ })
107
+ if (opacity !== 1) bottomStar.opacity = opacity
108
+ items.push(bottomStar)
109
+
110
+ return {
111
+ success: true,
112
+ type: 'seal',
113
+ items: items.map(i => i.id),
114
+ }
115
+ }
116
+
117
+ /**
118
+ * 创建五角星路径
119
+ */
120
+ function createStarPath(cx, cy, outerR, innerR, points) {
121
+ const path = new paper.Path()
122
+ const angleStep = Math.PI / points
123
+
124
+ for (let i = 0; i < points * 2; i++) {
125
+ const r = i % 2 === 0 ? outerR : innerR
126
+ const angle = i * angleStep - Math.PI / 2
127
+ path.add(new paper.Point(cx + r * Math.cos(angle), cy + r * Math.sin(angle)))
128
+ }
129
+ path.closed = true
130
+ return path
131
+ }
132
+
133
+ /**
134
+ * 创建多边形路径
135
+ */
136
+ function createPolygonPath(cx, cy, radius, sides) {
137
+ const path = new paper.Path()
138
+ for (let i = 0; i < sides; i++) {
139
+ const angle = (i * 2 * Math.PI / sides) - Math.PI / 2
140
+ path.add(new paper.Point(cx + radius * Math.cos(angle), cy + radius * Math.sin(angle)))
141
+ }
142
+ path.closed = true
143
+ return path
144
+ }
145
+
146
+ module.exports = createSeal
@@ -12,8 +12,8 @@ function createTable(project, canvas, params) {
12
12
  x,
13
13
  y,
14
14
  width,
15
- columns = [],
16
- rows = [],
15
+ columns,
16
+ rows,
17
17
  rowHeight = 36,
18
18
  headerBg = '#f0f0f0',
19
19
  headerColor = '#333333',
@@ -27,16 +27,24 @@ function createTable(project, canvas, params) {
27
27
 
28
28
  const elements = []
29
29
 
30
- if (columns.length === 0) {
30
+ // 确保 columns 是数组且不为空
31
+ if (!Array.isArray(columns) || columns.length === 0) {
31
32
  return { success: true, elements, type: 'table' }
32
33
  }
33
34
 
35
+ // 确保 rows 是数组
36
+ if (!Array.isArray(rows)) {
37
+ rows = []
38
+ }
39
+
40
+ // 确保 width 有默认值
41
+ const tableWidth = width || 400
34
42
  const totalHeight = rowHeight * (rows.length + 1)
35
43
 
36
44
  // 绘制外边框
37
45
  const outerBorder = new paper.Path.Rectangle({
38
46
  point: [x, y],
39
- size: [width, totalHeight]
47
+ size: [tableWidth, totalHeight]
40
48
  })
41
49
  outerBorder.fillColor = new paper.Color('transparent')
42
50
  outerBorder.strokeColor = new paper.Color(borderColor)
@@ -49,7 +57,7 @@ function createTable(project, canvas, params) {
49
57
  // 绘制表头背景
50
58
  const headerBgRect = new paper.Path.Rectangle({
51
59
  point: [x, y],
52
- size: [width, rowHeight]
60
+ size: [tableWidth, rowHeight]
53
61
  })
54
62
  headerBgRect.fillColor = new paper.Color(headerBg)
55
63
  headerBgRect.strokeColor = new paper.Color(borderColor)
@@ -62,7 +70,7 @@ function createTable(project, canvas, params) {
62
70
  // 绘制表头
63
71
  let currentX = x
64
72
  columns.forEach((col, index) => {
65
- const colWidth = col.width || (width / columns.length)
73
+ const colWidth = col.width || (tableWidth / columns.length)
66
74
 
67
75
  // 列分隔线
68
76
  if (index > 0) {
@@ -103,7 +111,7 @@ function createTable(project, canvas, params) {
103
111
  if (striped && rowIndex % 2 === 1) {
104
112
  const stripeBg = new paper.Path.Rectangle({
105
113
  point: [x, rowY],
106
- size: [width, rowHeight]
114
+ size: [tableWidth, rowHeight]
107
115
  })
108
116
  stripeBg.fillColor = new paper.Color(stripeColor)
109
117
  stripeBg.strokeColor = new paper.Color(borderColor)
@@ -129,7 +137,7 @@ function createTable(project, canvas, params) {
129
137
  // 单元格
130
138
  let cellX = x
131
139
  columns.forEach((col, colIndex) => {
132
- const colWidth = col.width || (width / columns.length)
140
+ const colWidth = col.width || (tableWidth / columns.length)
133
141
  const cellValue = row[colIndex] || ''
134
142
  const cellText = new paper.PointText({
135
143
  point: [cellX + colWidth / 2, rowY + rowHeight / 2 + fontSize / 3],
@@ -150,7 +158,7 @@ function createTable(project, canvas, params) {
150
158
  return {
151
159
  success: true,
152
160
  elements,
153
- width,
161
+ width: tableWidth,
154
162
  height: totalHeight,
155
163
  type: 'table'
156
164
  }
@@ -6,21 +6,11 @@ const paper = require('paper')
6
6
 
7
7
  /**
8
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 {Array} args.tags - 标签数组 [{text, color, bgColor}]
16
- * @param {number} args.fontSize - 字体大小
17
- * @param {number} args.padding - 标签内边距
18
- * @param {number} args.gap - 标签间距
19
- * @param {number} args.maxWidth - 最大宽度(自动换行)
20
9
  */
21
10
  function createTagCloud(project, canvas, args) {
22
11
  const {
23
- x, y,
12
+ x = 0,
13
+ y = 0,
24
14
  tags = [],
25
15
  fontSize = 14,
26
16
  padding = 12,
@@ -29,12 +19,22 @@ function createTagCloud(project, canvas, args) {
29
19
  } = args
30
20
 
31
21
  const elements = []
22
+
23
+ // 确保 tags 是数组
24
+ if (!Array.isArray(tags) || tags.length === 0) {
25
+ return { success: true, elements, height: 0, type: 'tagCloud' }
26
+ }
27
+
32
28
  let currentX = x
33
29
  let currentY = y
34
30
  let rowHeight = 0
35
31
 
36
32
  for (const tag of tags) {
37
- const textWidth = tag.text.length * fontSize * 0.6
33
+ // 确保 tag.text 是字符串
34
+ const tagText = String(tag.text || '')
35
+ if (!tagText) continue
36
+
37
+ const textWidth = tagText.length * fontSize * 0.6
38
38
  const tagWidth = textWidth + padding * 2
39
39
  const tagHeight = fontSize + padding * 2
40
40
 
@@ -52,17 +52,23 @@ function createTagCloud(project, canvas, args) {
52
52
  radius: tagHeight / 2,
53
53
  })
54
54
  tagBg.fillColor = new paper.Color(tag.bgColor || '#e0e7ff')
55
+ if (project && project.activeLayer) {
56
+ project.activeLayer.addChild(tagBg)
57
+ }
55
58
  elements.push({ type: 'rectangle', id: tagBg.id })
56
59
 
57
60
  // 绘制标签文字
58
- const tagText = new paper.PointText({
61
+ const tagTextEl = new paper.PointText({
59
62
  point: [currentX + tagWidth / 2, currentY + tagHeight / 2 + fontSize / 3],
60
- content: tag.text,
63
+ content: tagText,
61
64
  fontSize: fontSize,
62
65
  fillColor: new paper.Color(tag.color || '#4338ca'),
63
66
  justification: 'center',
64
67
  })
65
- elements.push({ type: 'text', id: tagText.id })
68
+ if (project && project.activeLayer) {
69
+ project.activeLayer.addChild(tagTextEl)
70
+ }
71
+ elements.push({ type: 'text', id: tagTextEl.id })
66
72
 
67
73
  currentX += tagWidth + gap
68
74
  rowHeight = Math.max(rowHeight, tagHeight)
@@ -71,7 +77,8 @@ function createTagCloud(project, canvas, args) {
71
77
  return {
72
78
  success: true,
73
79
  elements,
74
- height: rowHeight,
80
+ height: currentY - y + rowHeight,
81
+ type: 'tagCloud',
75
82
  }
76
83
  }
77
84
 
@@ -6,18 +6,6 @@ const paper = require('paper')
6
6
 
7
7
  /**
8
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 {Array} args.items - 时间线项目 [{date, title, description}]
17
- * @param {string} args.lineColor - 线条颜色
18
- * @param {string} args.dotColor - 点颜色
19
- * @param {string} args.activeColor - 激活颜色
20
- * @param {number} args.dotSize - 点大小
21
9
  */
22
10
  function createTimeline(project, canvas, args) {
23
11
  const {
@@ -32,6 +20,12 @@ function createTimeline(project, canvas, args) {
32
20
  } = args
33
21
 
34
22
  const elements = []
23
+
24
+ // 确保 items 是数组
25
+ if (!Array.isArray(items) || items.length === 0) {
26
+ return { success: true, elements, height: 0, type: 'timeline' }
27
+ }
28
+
35
29
  const centerX = x + 80
36
30
  const contentX = x + 120
37
31
 
@@ -43,12 +37,17 @@ function createTimeline(project, canvas, args) {
43
37
  strokeColor: new paper.Color(lineColor),
44
38
  strokeWidth: 2,
45
39
  })
40
+ if (project && project.activeLayer) {
41
+ project.activeLayer.addChild(mainLine)
42
+ }
46
43
  elements.push({ type: 'line', id: mainLine.id })
47
44
  }
48
45
 
49
46
  // 绘制每个项目
50
47
  for (let i = 0; i < items.length; i++) {
51
48
  const item = items[i]
49
+ if (!item) continue
50
+
52
51
  const itemY = y + i * gap
53
52
  const isActive = item.active !== false
54
53
 
@@ -58,6 +57,9 @@ function createTimeline(project, canvas, args) {
58
57
  radius: dotSize / 2,
59
58
  })
60
59
  dot.fillColor = new paper.Color(isActive ? dotColor : lineColor)
60
+ if (project && project.activeLayer) {
61
+ project.activeLayer.addChild(dot)
62
+ }
61
63
  elements.push({ type: 'circle', id: dot.id })
62
64
 
63
65
  // 绘制日期
@@ -69,6 +71,9 @@ function createTimeline(project, canvas, args) {
69
71
  fillColor: new paper.Color('#94a3b8'),
70
72
  justification: 'left',
71
73
  })
74
+ if (project && project.activeLayer) {
75
+ project.activeLayer.addChild(dateText)
76
+ }
72
77
  elements.push({ type: 'text', id: dateText.id })
73
78
  }
74
79
 
@@ -80,6 +85,9 @@ function createTimeline(project, canvas, args) {
80
85
  fillColor: new paper.Color(isActive ? '#1e293b' : '#94a3b8'),
81
86
  justification: 'left',
82
87
  })
88
+ if (project && project.activeLayer) {
89
+ project.activeLayer.addChild(titleText)
90
+ }
83
91
  elements.push({ type: 'text', id: titleText.id })
84
92
 
85
93
  // 绘制描述
@@ -91,6 +99,9 @@ function createTimeline(project, canvas, args) {
91
99
  fillColor: new paper.Color('#64748b'),
92
100
  justification: 'left',
93
101
  })
102
+ if (project && project.activeLayer) {
103
+ project.activeLayer.addChild(descText)
104
+ }
94
105
  elements.push({ type: 'text', id: descText.id })
95
106
  }
96
107
  }
@@ -99,6 +110,7 @@ function createTimeline(project, canvas, args) {
99
110
  success: true,
100
111
  elements,
101
112
  height: items.length * gap,
113
+ type: 'timeline',
102
114
  }
103
115
  }
104
116