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,105 @@
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 {number} args.height - 高度
17
+ * @param {string} args.label - 标签
18
+ * @param {string} args.value - 数值
19
+ * @param {string} args.change - 变化值(如 "+12.5%")
20
+ * @param {boolean} args.positive - 变化是否为正
21
+ * @param {string} args.icon - 图标
22
+ * @param {string} args.iconColor - 图标颜色
23
+ * @param {string} args.background - 背景色
24
+ * @param {string} args.border - 边框颜色
25
+ * @param {number} args.radius - 圆角半径
26
+ */
27
+ function createStatCard(project, canvas, args) {
28
+ const {
29
+ x, y,
30
+ width = 200,
31
+ height = 120,
32
+ label = 'Total Users',
33
+ value = '10,000',
34
+ change,
35
+ positive = true,
36
+ icon,
37
+ iconColor = '#6366f1',
38
+ background = '#ffffff',
39
+ border = '#e5e7eb',
40
+ radius = 12,
41
+ } = args
42
+
43
+ const elements = []
44
+
45
+ // 绘制背景
46
+ const bg = new paper.Path.Rectangle({
47
+ point: [x, y],
48
+ size: [width, height],
49
+ radius: radius,
50
+ })
51
+ bg.fillColor = new paper.Color(background)
52
+ bg.strokeColor = new paper.Color(border)
53
+ bg.strokeWidth = 1
54
+ elements.push({ type: 'rectangle', id: bg.id })
55
+
56
+ // 绘制图标
57
+ if (icon) {
58
+ const iconText = new paper.PointText({
59
+ point: [x + 20, y + 35],
60
+ content: icon,
61
+ fontSize: 24,
62
+ fillColor: new paper.Color(iconColor),
63
+ justification: 'left',
64
+ })
65
+ elements.push({ type: 'text', id: iconText.id })
66
+ }
67
+
68
+ // 绘制标签
69
+ const labelText = new paper.PointText({
70
+ point: [x + 20, y + 50 + (icon ? 10 : 0)],
71
+ content: label,
72
+ fontSize: 14,
73
+ fillColor: new paper.Color('#64748b'),
74
+ justification: 'left',
75
+ })
76
+ elements.push({ type: 'text', id: labelText.id })
77
+
78
+ // 绘制数值
79
+ const valueText = new paper.PointText({
80
+ point: [x + 20, y + 75 + (icon ? 10 : 0)],
81
+ content: value,
82
+ fontSize: 28,
83
+ fillColor: new paper.Color('#1e293b'),
84
+ justification: 'left',
85
+ })
86
+ elements.push({ type: 'text', id: valueText.id })
87
+
88
+ // 绘制变化值
89
+ if (change) {
90
+ const changeColor = positive ? '#22c55e' : '#ef4444'
91
+ const changeIcon = positive ? '↑' : '↓'
92
+ const changeText = new paper.PointText({
93
+ point: [x + 20, y + 95 + (icon ? 10 : 0)],
94
+ content: `${changeIcon} ${change}`,
95
+ fontSize: 14,
96
+ fillColor: new paper.Color(changeColor),
97
+ justification: 'left',
98
+ })
99
+ elements.push({ type: 'text', id: changeText.id })
100
+ }
101
+
102
+ return { success: true, elements }
103
+ }
104
+
105
+ module.exports = createStatCard
@@ -0,0 +1,118 @@
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 {Array} args.steps - 步骤数组 [{title, description}]
17
+ * @param {number} args.currentStep - 当前步骤(从0开始)
18
+ * @param {string} args.activeColor - 激活颜色
19
+ * @param {string} args.inactiveColor - 未激活颜色
20
+ * @param {string} args.completedColor - 已完成颜色
21
+ * @param {number} args.circleSize - 圆圈大小
22
+ */
23
+ function createStepper(project, canvas, args) {
24
+ const {
25
+ x, y,
26
+ width = 600,
27
+ steps = [],
28
+ currentStep = 0,
29
+ activeColor = '#6366f1',
30
+ inactiveColor = '#e5e7eb',
31
+ completedColor = '#22c55e',
32
+ circleSize = 40,
33
+ } = args
34
+
35
+ const elements = []
36
+ const stepWidth = steps.length > 1 ? width / (steps.length - 1) : width
37
+ const lineY = y + circleSize / 2
38
+
39
+ // 绘制连接线
40
+ if (steps.length > 1) {
41
+ const line = new paper.Path.Line({
42
+ from: [x + circleSize / 2, lineY],
43
+ to: [x + width - circleSize / 2, lineY],
44
+ strokeColor: new paper.Color(inactiveColor),
45
+ strokeWidth: 2,
46
+ })
47
+ elements.push({ type: 'line', id: line.id })
48
+
49
+ // 绘制已完成部分的覆盖线
50
+ if (currentStep > 0) {
51
+ const completedLine = new paper.Path.Line({
52
+ from: [x + circleSize / 2, lineY],
53
+ to: [x + circleSize / 2 + (currentStep) * stepWidth, lineY],
54
+ strokeColor: new paper.Color(completedColor),
55
+ strokeWidth: 2,
56
+ })
57
+ elements.push({ type: 'line', id: completedLine.id })
58
+ }
59
+ }
60
+
61
+ // 绘制每个步骤
62
+ for (let i = 0; i < steps.length; i++) {
63
+ const stepX = steps.length > 1 ? x + i * stepWidth : x
64
+ const step = steps[i]
65
+ let color = inactiveColor
66
+
67
+ if (i < currentStep) {
68
+ color = completedColor
69
+ } else if (i === currentStep) {
70
+ color = activeColor
71
+ }
72
+
73
+ // 绘制圆圈
74
+ const circle = new paper.Path.Circle({
75
+ center: [stepX + circleSize / 2, lineY],
76
+ radius: circleSize / 2,
77
+ })
78
+ circle.fillColor = new paper.Color(color)
79
+ elements.push({ type: 'circle', id: circle.id })
80
+
81
+ // 绘制步骤编号或勾选
82
+ const icon = i < currentStep ? '✓' : String(i + 1)
83
+ const iconText = new paper.PointText({
84
+ point: [stepX + circleSize / 2, lineY + circleSize / 6],
85
+ content: icon,
86
+ fontSize: 16,
87
+ fillColor: new paper.Color('#ffffff'),
88
+ justification: 'center',
89
+ })
90
+ elements.push({ type: 'text', id: iconText.id })
91
+
92
+ // 绘制标题
93
+ const titleText = new paper.PointText({
94
+ point: [stepX + circleSize / 2, y + circleSize + 20],
95
+ content: step.title || `Step ${i + 1}`,
96
+ fontSize: 14,
97
+ fillColor: new paper.Color(i <= currentStep ? '#1e293b' : '#94a3b8'),
98
+ justification: 'center',
99
+ })
100
+ elements.push({ type: 'text', id: titleText.id })
101
+
102
+ // 绘制描述
103
+ if (step.description) {
104
+ const descText = new paper.PointText({
105
+ point: [stepX + circleSize / 2, y + circleSize + 38],
106
+ content: step.description,
107
+ fontSize: 11,
108
+ fillColor: new paper.Color('#94a3b8'),
109
+ justification: 'center',
110
+ })
111
+ elements.push({ type: 'text', id: descText.id })
112
+ }
113
+ }
114
+
115
+ return { success: true, elements }
116
+ }
117
+
118
+ module.exports = createStepper
@@ -0,0 +1,159 @@
1
+ /**
2
+ * 表格组件
3
+ */
4
+
5
+ const paper = require('paper')
6
+
7
+ /**
8
+ * 创建表格组件
9
+ */
10
+ function createTable(project, canvas, params) {
11
+ const {
12
+ x,
13
+ y,
14
+ width,
15
+ columns = [],
16
+ rows = [],
17
+ rowHeight = 36,
18
+ headerBg = '#f0f0f0',
19
+ headerColor = '#333333',
20
+ borderColor = '#e0e0e0',
21
+ cellColor = '#333333',
22
+ fontSize = 12,
23
+ headerFontSize = 13,
24
+ striped = true,
25
+ stripeColor = '#fafafa'
26
+ } = params
27
+
28
+ const elements = []
29
+
30
+ if (columns.length === 0) {
31
+ return { success: true, elements, type: 'table' }
32
+ }
33
+
34
+ const totalHeight = rowHeight * (rows.length + 1)
35
+
36
+ // 绘制外边框
37
+ const outerBorder = new paper.Path.Rectangle({
38
+ point: [x, y],
39
+ size: [width, totalHeight]
40
+ })
41
+ outerBorder.fillColor = new paper.Color('transparent')
42
+ outerBorder.strokeColor = new paper.Color(borderColor)
43
+ outerBorder.strokeWidth = 1
44
+ if (project && project.activeLayer) {
45
+ project.activeLayer.addChild(outerBorder)
46
+ }
47
+ elements.push({ type: 'path', id: outerBorder.id })
48
+
49
+ // 绘制表头背景
50
+ const headerBgRect = new paper.Path.Rectangle({
51
+ point: [x, y],
52
+ size: [width, rowHeight]
53
+ })
54
+ headerBgRect.fillColor = new paper.Color(headerBg)
55
+ headerBgRect.strokeColor = new paper.Color(borderColor)
56
+ headerBgRect.strokeWidth = 0.5
57
+ if (project && project.activeLayer) {
58
+ project.activeLayer.addChild(headerBgRect)
59
+ }
60
+ elements.push({ type: 'path', id: headerBgRect.id })
61
+
62
+ // 绘制表头
63
+ let currentX = x
64
+ columns.forEach((col, index) => {
65
+ const colWidth = col.width || (width / columns.length)
66
+
67
+ // 列分隔线
68
+ if (index > 0) {
69
+ const line = new paper.Path.Line({
70
+ from: [currentX, y],
71
+ to: [currentX, y + totalHeight]
72
+ })
73
+ line.strokeColor = new paper.Color(borderColor)
74
+ line.strokeWidth = 0.5
75
+ if (project && project.activeLayer) {
76
+ project.activeLayer.addChild(line)
77
+ }
78
+ elements.push({ type: 'line', id: line.id })
79
+ }
80
+
81
+ // 表头文字
82
+ const headerText = new paper.PointText({
83
+ point: [currentX + colWidth / 2, y + rowHeight / 2 + fontSize / 3],
84
+ content: col.title || '',
85
+ fontSize: headerFontSize,
86
+ fillColor: new paper.Color(headerColor),
87
+ justification: col.align || 'center',
88
+ fontWeight: 'bold'
89
+ })
90
+ if (project && project.activeLayer) {
91
+ project.activeLayer.addChild(headerText)
92
+ }
93
+ elements.push({ type: 'text', id: headerText.id })
94
+
95
+ currentX += colWidth
96
+ })
97
+
98
+ // 绘制数据行
99
+ rows.forEach((row, rowIndex) => {
100
+ const rowY = y + rowHeight * (rowIndex + 1)
101
+
102
+ // 斑马纹背景
103
+ if (striped && rowIndex % 2 === 1) {
104
+ const stripeBg = new paper.Path.Rectangle({
105
+ point: [x, rowY],
106
+ size: [width, rowHeight]
107
+ })
108
+ stripeBg.fillColor = new paper.Color(stripeColor)
109
+ stripeBg.strokeColor = new paper.Color(borderColor)
110
+ stripeBg.strokeWidth = 0.5
111
+ if (project && project.activeLayer) {
112
+ project.activeLayer.addChild(stripeBg)
113
+ }
114
+ elements.push({ type: 'path', id: stripeBg.id })
115
+ }
116
+
117
+ // 行分隔线
118
+ const rowLine = new paper.Path.Line({
119
+ from: [x, rowY],
120
+ to: [x + width, rowY]
121
+ })
122
+ rowLine.strokeColor = new paper.Color(borderColor)
123
+ rowLine.strokeWidth = 0.5
124
+ if (project && project.activeLayer) {
125
+ project.activeLayer.addChild(rowLine)
126
+ }
127
+ elements.push({ type: 'line', id: rowLine.id })
128
+
129
+ // 单元格
130
+ let cellX = x
131
+ columns.forEach((col, colIndex) => {
132
+ const colWidth = col.width || (width / columns.length)
133
+ const cellValue = row[colIndex] || ''
134
+ const cellText = new paper.PointText({
135
+ point: [cellX + colWidth / 2, rowY + rowHeight / 2 + fontSize / 3],
136
+ content: String(cellValue),
137
+ fontSize: fontSize,
138
+ fillColor: new paper.Color(cellColor),
139
+ justification: col.align || 'center'
140
+ })
141
+ if (project && project.activeLayer) {
142
+ project.activeLayer.addChild(cellText)
143
+ }
144
+ elements.push({ type: 'text', id: cellText.id })
145
+
146
+ cellX += colWidth
147
+ })
148
+ })
149
+
150
+ return {
151
+ success: true,
152
+ elements,
153
+ width,
154
+ height: totalHeight,
155
+ type: 'table'
156
+ }
157
+ }
158
+
159
+ module.exports = createTable
@@ -0,0 +1,78 @@
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 {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
+ */
21
+ function createTagCloud(project, canvas, args) {
22
+ const {
23
+ x, y,
24
+ tags = [],
25
+ fontSize = 14,
26
+ padding = 12,
27
+ gap = 10,
28
+ maxWidth = 400,
29
+ } = args
30
+
31
+ const elements = []
32
+ let currentX = x
33
+ let currentY = y
34
+ let rowHeight = 0
35
+
36
+ for (const tag of tags) {
37
+ const textWidth = tag.text.length * fontSize * 0.6
38
+ const tagWidth = textWidth + padding * 2
39
+ const tagHeight = fontSize + padding * 2
40
+
41
+ // 换行处理
42
+ if (currentX + tagWidth > x + maxWidth && currentX > x) {
43
+ currentX = x
44
+ currentY += rowHeight + gap
45
+ rowHeight = 0
46
+ }
47
+
48
+ // 绘制标签背景
49
+ const tagBg = new paper.Path.Rectangle({
50
+ point: [currentX, currentY],
51
+ size: [tagWidth, tagHeight],
52
+ radius: tagHeight / 2,
53
+ })
54
+ tagBg.fillColor = new paper.Color(tag.bgColor || '#e0e7ff')
55
+ elements.push({ type: 'rectangle', id: tagBg.id })
56
+
57
+ // 绘制标签文字
58
+ const tagText = new paper.PointText({
59
+ point: [currentX + tagWidth / 2, currentY + tagHeight / 2 + fontSize / 3],
60
+ content: tag.text,
61
+ fontSize: fontSize,
62
+ fillColor: new paper.Color(tag.color || '#4338ca'),
63
+ justification: 'center',
64
+ })
65
+ elements.push({ type: 'text', id: tagText.id })
66
+
67
+ currentX += tagWidth + gap
68
+ rowHeight = Math.max(rowHeight, tagHeight)
69
+ }
70
+
71
+ return {
72
+ success: true,
73
+ elements,
74
+ height: rowHeight,
75
+ }
76
+ }
77
+
78
+ module.exports = createTagCloud
@@ -0,0 +1,105 @@
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 {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
+ */
22
+ function createTimeline(project, canvas, args) {
23
+ const {
24
+ x, y,
25
+ width = 500,
26
+ items = [],
27
+ lineColor = '#e2e8f0',
28
+ dotColor = '#6366f1',
29
+ activeColor = '#22c55e',
30
+ dotSize = 16,
31
+ gap = 60,
32
+ } = args
33
+
34
+ const elements = []
35
+ const centerX = x + 80
36
+ const contentX = x + 120
37
+
38
+ // 绘制主线
39
+ if (items.length > 1) {
40
+ const mainLine = new paper.Path.Line({
41
+ from: [centerX, y + dotSize / 2],
42
+ to: [centerX, y + (items.length - 1) * gap + dotSize / 2],
43
+ strokeColor: new paper.Color(lineColor),
44
+ strokeWidth: 2,
45
+ })
46
+ elements.push({ type: 'line', id: mainLine.id })
47
+ }
48
+
49
+ // 绘制每个项目
50
+ for (let i = 0; i < items.length; i++) {
51
+ const item = items[i]
52
+ const itemY = y + i * gap
53
+ const isActive = item.active !== false
54
+
55
+ // 绘制时间线点
56
+ const dot = new paper.Path.Circle({
57
+ center: [centerX, itemY + dotSize / 2],
58
+ radius: dotSize / 2,
59
+ })
60
+ dot.fillColor = new paper.Color(isActive ? dotColor : lineColor)
61
+ elements.push({ type: 'circle', id: dot.id })
62
+
63
+ // 绘制日期
64
+ if (item.date) {
65
+ const dateText = new paper.PointText({
66
+ point: [x + 10, itemY + dotSize / 2 + 5],
67
+ content: item.date,
68
+ fontSize: 12,
69
+ fillColor: new paper.Color('#94a3b8'),
70
+ justification: 'left',
71
+ })
72
+ elements.push({ type: 'text', id: dateText.id })
73
+ }
74
+
75
+ // 绘制标题
76
+ const titleText = new paper.PointText({
77
+ point: [contentX, itemY + dotSize / 2 + 5],
78
+ content: item.title || `Event ${i + 1}`,
79
+ fontSize: 16,
80
+ fillColor: new paper.Color(isActive ? '#1e293b' : '#94a3b8'),
81
+ justification: 'left',
82
+ })
83
+ elements.push({ type: 'text', id: titleText.id })
84
+
85
+ // 绘制描述
86
+ if (item.description) {
87
+ const descText = new paper.PointText({
88
+ point: [contentX, itemY + dotSize / 2 + 28],
89
+ content: item.description,
90
+ fontSize: 13,
91
+ fillColor: new paper.Color('#64748b'),
92
+ justification: 'left',
93
+ })
94
+ elements.push({ type: 'text', id: descText.id })
95
+ }
96
+ }
97
+
98
+ return {
99
+ success: true,
100
+ elements,
101
+ height: items.length * gap,
102
+ }
103
+ }
104
+
105
+ module.exports = createTimeline
@@ -0,0 +1,52 @@
1
+ /**
2
+ * 水印组件
3
+ */
4
+
5
+ const paper = require('paper')
6
+
7
+ /**
8
+ * 创建水印组件
9
+ */
10
+ function createWatermark(project, canvas, params) {
11
+ const {
12
+ text,
13
+ cx,
14
+ cy,
15
+ color = 'rgba(0,0,0,0.1)',
16
+ fontSize = 48,
17
+ fontFamily = 'sans-serif',
18
+ opacity = 0.1,
19
+ rotation = 0,
20
+ align = 'center'
21
+ } = params
22
+
23
+ const elements = []
24
+
25
+ const label = new paper.PointText({
26
+ point: [cx, cy],
27
+ content: text,
28
+ fontSize: fontSize,
29
+ fontFamily: fontFamily,
30
+ fillColor: new paper.Color(color),
31
+ justification: align,
32
+ opacity: opacity
33
+ })
34
+
35
+ // 应用旋转
36
+ if (rotation !== 0) {
37
+ label.rotate(rotation, new paper.Point(cx, cy))
38
+ }
39
+
40
+ if (project && project.activeLayer) {
41
+ project.activeLayer.addChild(label)
42
+ }
43
+ elements.push({ type: 'text', id: label.id })
44
+
45
+ return {
46
+ success: true,
47
+ elements,
48
+ type: 'watermark'
49
+ }
50
+ }
51
+
52
+ module.exports = createWatermark