foliko 1.0.87 → 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 -108
  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/poster-plugin/README.md +304 -0
  12. package/.agent/plugins/poster-plugin/fonts/PatuaOne-Regular.ttf +0 -0
  13. package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221.ttf +0 -0
  14. 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
  15. package/.agent/plugins/poster-plugin/index.js +13 -0
  16. package/.agent/plugins/poster-plugin/package.json +28 -0
  17. package/.agent/plugins/poster-plugin/src/canvas.js +161 -0
  18. package/.agent/plugins/poster-plugin/src/components/arrow.js +84 -0
  19. package/.agent/plugins/poster-plugin/src/components/avatar.js +71 -0
  20. package/.agent/plugins/poster-plugin/src/components/badge.js +85 -0
  21. package/.agent/plugins/poster-plugin/src/components/card.js +88 -0
  22. package/.agent/plugins/poster-plugin/src/components/chart.js +127 -0
  23. package/.agent/plugins/poster-plugin/src/components/chip.js +88 -0
  24. package/.agent/plugins/poster-plugin/src/components/columns.js +107 -0
  25. package/.agent/plugins/poster-plugin/src/components/cta.js +85 -0
  26. package/.agent/plugins/poster-plugin/src/components/divider.js +55 -0
  27. package/.agent/plugins/poster-plugin/src/components/feature.js +85 -0
  28. package/.agent/plugins/poster-plugin/src/components/featureGrid.js +112 -0
  29. package/.agent/plugins/poster-plugin/src/components/grid.js +118 -0
  30. package/.agent/plugins/poster-plugin/src/components/imageFrame.js +155 -0
  31. package/.agent/plugins/poster-plugin/src/components/index.js +62 -0
  32. package/.agent/plugins/poster-plugin/src/components/listItem.js +146 -0
  33. package/.agent/plugins/poster-plugin/src/components/notification.js +123 -0
  34. package/.agent/plugins/poster-plugin/src/components/progress.js +79 -0
  35. package/.agent/plugins/poster-plugin/src/components/progressCircle.js +117 -0
  36. package/.agent/plugins/poster-plugin/src/components/quote.js +97 -0
  37. package/.agent/plugins/poster-plugin/src/components/rating.js +85 -0
  38. package/.agent/plugins/poster-plugin/src/components/star.js +70 -0
  39. package/.agent/plugins/poster-plugin/src/components/statCard.js +105 -0
  40. package/.agent/plugins/poster-plugin/src/components/stepper.js +118 -0
  41. package/.agent/plugins/poster-plugin/src/components/table.js +159 -0
  42. package/.agent/plugins/poster-plugin/src/components/tagCloud.js +78 -0
  43. package/.agent/plugins/poster-plugin/src/components/timeline.js +105 -0
  44. package/.agent/plugins/poster-plugin/src/components/watermark.js +52 -0
  45. package/.agent/plugins/poster-plugin/src/composer.js +1904 -0
  46. package/.agent/plugins/poster-plugin/src/elements/artText.js +60 -0
  47. package/.agent/plugins/poster-plugin/src/elements/background.js +52 -0
  48. package/.agent/plugins/poster-plugin/src/elements/circle.js +31 -0
  49. package/.agent/plugins/poster-plugin/src/elements/image.js +71 -0
  50. package/.agent/plugins/poster-plugin/src/elements/index.js +26 -0
  51. package/.agent/plugins/poster-plugin/src/elements/line.js +23 -0
  52. package/.agent/plugins/poster-plugin/src/elements/polygon.js +32 -0
  53. package/.agent/plugins/poster-plugin/src/elements/rectangle.js +32 -0
  54. package/.agent/plugins/poster-plugin/src/elements/svg.js +92 -0
  55. package/.agent/plugins/poster-plugin/src/elements/text.js +38 -0
  56. package/.agent/plugins/poster-plugin/src/fonts.js +118 -0
  57. package/.agent/plugins/poster-plugin/src/index.js +1659 -0
  58. package/.agent/plugins/poster-plugin/src/presets.js +36 -0
  59. package/.agent/plugins/poster-plugin/src/templates/business.js +60 -0
  60. package/.agent/plugins/poster-plugin/src/templates/gradient.js +64 -0
  61. package/.agent/plugins/poster-plugin/src/templates/index.js +43 -0
  62. package/.agent/plugins/poster-plugin/src/templates/modern.js +69 -0
  63. package/.agent/plugins/poster-plugin/src/templates/simple.js +58 -0
  64. package/.agent/plugins/poster-plugin/src/templates/social.js +62 -0
  65. package/.agent/plugins/poster-plugin/src/templates/tech.js +84 -0
  66. package/.agent/sessions/cli_default.json +24265 -0
  67. package/.agent/weixin.json +6 -0
  68. package/.claude/settings.local.json +5 -8
  69. package/CLAUDE.md +144 -108
  70. package/docs/CONTEXT_DESIGN.md +1596 -0
  71. package/examples/test-concurrent-chat.js +60 -60
  72. package/output/beef-love-poster.png +0 -0
  73. package/package.json +2 -2
  74. package/plugins/default-plugins.js +2 -1
  75. package/plugins/extension-executor-plugin.js +11 -0
  76. package/plugins/memory-plugin.js +984 -0
  77. package/plugins/session-plugin.js +57 -1
  78. package/plugins/weixin-plugin.js +24 -22
  79. package/skills/poster-guide/SKILL.md +743 -0
  80. package/skills/python-plugin-dev/SKILL.md +238 -238
  81. package/skills/skill-guide/SKILL.md +130 -108
  82. package/src/capabilities/skill-manager.js +99 -0
  83. package/src/core/agent-chat.js +538 -138
  84. package/src/core/agent-context.js +188 -0
  85. package/src/core/agent.js +6 -2
  86. package/src/core/context-manager.js +283 -0
  87. package/src/core/framework.js +264 -3
  88. package/src/core/plugin-manager.js +79 -2
  89. package/src/core/request-context.js +98 -0
  90. package/src/core/session-context.js +341 -0
  91. package/src/core/session-storage.js +274 -0
  92. package/src/executors/mcp-executor.js +2 -2
  93. package/src/utils/index.js +239 -67
  94. package/src/utils/plugin-helpers.js +17 -0
  95. package//346/265/267/346/212/245/346/217/222/344/273/266.md +621 -0
  96. package/.agent/plugins/__pycache__/test_plugin.cpython-312.pyc +0 -0
  97. package/.agent/plugins/temp-repo/LICENSE +0 -201
  98. package/.agent/plugins/temp-repo/puppeteer-plugin/README.md +0 -147
  99. package/.agent/plugins/temp-repo/puppeteer-plugin/index.js +0 -1418
  100. package/.agent/plugins/temp-repo/puppeteer-plugin/package.json +0 -9
  101. package/.agent/plugins/test_plugin.py +0 -304
  102. package/examples/test-chat-debug.js +0 -102
  103. package/examples/test-chat-result.js +0 -76
  104. package/examples/test-chat-stream-diff.js +0 -63
@@ -0,0 +1,107 @@
1
+ /**
2
+ * 分栏布局组件
3
+ * 支持左右分栏、三栏、四栏等多种布局
4
+ */
5
+
6
+ const createColumns = (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=2] - 列数
14
+ * @param {number} [params.gap=20] - 列间距
15
+ * @param {string} [params.background] - 背景色
16
+ * @param {string} [params.borderColor] - 边框颜色
17
+ * @param {number} [params.borderWidth] - 边框宽度
18
+ * @param {number} [params.radius=0] - 圆角
19
+ * @param {Array} [params.items] - 列内容配置 [{widthRatio, content}]
20
+ * @param {string} [params.direction='horizontal'] - 排列方向: horizontal, vertical
21
+ * @param {string} [params.align='top'] - 垂直对齐: top, center, bottom
22
+ */
23
+ draw({
24
+ x,
25
+ y,
26
+ width,
27
+ height,
28
+ columns = 2,
29
+ gap = 20,
30
+ background,
31
+ borderColor,
32
+ borderWidth = 1,
33
+ radius = 0,
34
+ items = [],
35
+ direction = 'horizontal',
36
+ align = 'top'
37
+ }) {
38
+ const elements = []
39
+
40
+ // 计算每列宽度
41
+ const totalGap = gap * (columns - 1)
42
+ const columnWidth = (width - totalGap) / columns
43
+
44
+ // 绘制背景
45
+ if (background) {
46
+ const bg = new ctx.Path.Rectangle({
47
+ point: [x, y],
48
+ size: [width, height],
49
+ radius: radius
50
+ })
51
+ bg.fillColor = new ctx.Color(background)
52
+ elements.push({ type: 'rectangle', id: bg.id })
53
+ }
54
+
55
+ // 绘制边框
56
+ if (borderColor && borderWidth > 0) {
57
+ const border = new ctx.Path.Rectangle({
58
+ point: [x, y],
59
+ size: [width, height],
60
+ radius: radius
61
+ })
62
+ border.fillColor = new ctx.Color('transparent')
63
+ border.strokeColor = new ctx.Color(borderColor)
64
+ border.strokeWidth = borderWidth
65
+ elements.push({ type: 'rectangle', id: border.id })
66
+ }
67
+
68
+ // 生成分割线
69
+ for (let i = 1; i < columns; i++) {
70
+ const lineX = x + columnWidth * i + gap * (i - 1) + gap / 2
71
+ const line = new ctx.Path.Line({
72
+ from: [lineX, y + 20],
73
+ to: [lineX, y + height - 20]
74
+ })
75
+ line.strokeColor = new ctx.Color('#e0e0e0')
76
+ line.strokeWidth = 1
77
+ elements.push({ type: 'line', id: line.id })
78
+ }
79
+
80
+ // 返回列位置信息
81
+ const columnPositions = []
82
+ for (let i = 0; i < columns; i++) {
83
+ const colX = x + (columnWidth + gap) * i
84
+ const colY = align === 'center' ? y + (height - height) / 2 : align === 'bottom' ? y + height - height : y
85
+
86
+ columnPositions.push({
87
+ index: i,
88
+ x: colX,
89
+ y: colY,
90
+ width: columnWidth,
91
+ height: height
92
+ })
93
+ }
94
+
95
+ return {
96
+ success: true,
97
+ elements,
98
+ columnPositions,
99
+ columnWidth,
100
+ totalWidth: width,
101
+ totalHeight: height,
102
+ type: 'columns'
103
+ }
104
+ }
105
+ })
106
+
107
+ module.exports = createColumns
@@ -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