viteboard 0.1.1 → 0.1.3

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 (83) hide show
  1. package/bin/content-api-plugin.mjs +722 -0
  2. package/bin/viteboard.mjs +3 -7
  3. package/content/docs/index.md +1 -1
  4. package/content/docs/product-roadmap.board.json +4 -4
  5. package/content/machine/board-v1.schema.json +138 -0
  6. package/content/machine/example.board.json +217 -0
  7. package/content/machine/guide.md +270 -0
  8. package/content/machine/llms.txt +31 -0
  9. package/content/machine/viteboard.json +62 -0
  10. package/dist/assets/index-D2W76uu9.js +96 -0
  11. package/dist/assets/index-rMkUjGXP.css +1 -0
  12. package/dist/index.html +4 -2
  13. package/package.json +10 -12
  14. package/vite.config.ts +619 -38
  15. package/dist/assets/index-C30zRPsW.js +0 -60
  16. package/dist/assets/index-e5aqtN8W.css +0 -1
  17. package/index.html +0 -13
  18. package/src/app/AppController.ts +0 -962
  19. package/src/app/BoardState.ts +0 -130
  20. package/src/app/ClipboardService.ts +0 -159
  21. package/src/app/CommandManager.ts +0 -66
  22. package/src/app/ElementActions.ts +0 -152
  23. package/src/app/EmbedRegionSelector.ts +0 -103
  24. package/src/app/ExportPng.ts +0 -107
  25. package/src/app/ImageInsertService.ts +0 -141
  26. package/src/app/KeyboardShortcuts.ts +0 -124
  27. package/src/app/main.ts +0 -6
  28. package/src/board/BoardPreview.ts +0 -189
  29. package/src/board/BoardService.ts +0 -222
  30. package/src/canvas/CanvasRenderer.ts +0 -253
  31. package/src/canvas/CanvasSurface.ts +0 -70
  32. package/src/canvas/HitTester.ts +0 -110
  33. package/src/canvas/ImageCache.ts +0 -123
  34. package/src/canvas/PerformanceMonitor.ts +0 -31
  35. package/src/canvas/RenderScheduler.ts +0 -26
  36. package/src/canvas/Viewport.ts +0 -77
  37. package/src/content/ContentApi.ts +0 -258
  38. package/src/content/Markdown.ts +0 -431
  39. package/src/content/MarkdownView.ts +0 -70
  40. package/src/editor/DocEditor.ts +0 -799
  41. package/src/editor/htmlToMarkdown.ts +0 -333
  42. package/src/elements/renderElement.ts +0 -598
  43. package/src/elements/types.ts +0 -119
  44. package/src/shell/Shell.ts +0 -2948
  45. package/src/shell/Sidebar.ts +0 -1651
  46. package/src/storage/AssetStore.ts +0 -86
  47. package/src/storage/BoardSerializer.ts +0 -114
  48. package/src/storage/ImportExportService.ts +0 -153
  49. package/src/storage/IndexedDbStore.ts +0 -92
  50. package/src/storage/LocalBoardStore.ts +0 -104
  51. package/src/styles.css +0 -3332
  52. package/src/templates/handoffTemplate.ts +0 -34
  53. package/src/templates/helpers.ts +0 -132
  54. package/src/templates/index.ts +0 -79
  55. package/src/templates/journeyMapTemplate.ts +0 -52
  56. package/src/templates/opportunityTreeTemplate.ts +0 -45
  57. package/src/templates/personaTemplate.ts +0 -41
  58. package/src/templates/prioritizationMatrixTemplate.ts +0 -44
  59. package/src/templates/requirementsFlowTemplate.ts +0 -45
  60. package/src/templates/screenshotReviewTemplate.ts +0 -52
  61. package/src/templates/systemDiagramTemplate.ts +0 -41
  62. package/src/templates/workflowTemplate.ts +0 -35
  63. package/src/testing/StressTestGenerator.ts +0 -134
  64. package/src/testing/StressTestPanel.ts +0 -64
  65. package/src/tools/ArrowTool.ts +0 -97
  66. package/src/tools/ImageTool.ts +0 -39
  67. package/src/tools/PanTool.ts +0 -34
  68. package/src/tools/SelectTool.ts +0 -377
  69. package/src/tools/ShapeTool.ts +0 -106
  70. package/src/tools/StickyTool.ts +0 -69
  71. package/src/tools/TaskTool.ts +0 -52
  72. package/src/tools/TextTool.ts +0 -45
  73. package/src/tools/ToolContext.ts +0 -51
  74. package/src/tools/ToolController.ts +0 -178
  75. package/src/ui/Modal.ts +0 -58
  76. package/src/ui/PerformanceOverlay.ts +0 -75
  77. package/src/ui/StorageManager.ts +0 -94
  78. package/src/ui/TemplatePicker.ts +0 -67
  79. package/src/ui/TextEditorOverlay.ts +0 -262
  80. package/src/ui/Toolbar.ts +0 -189
  81. package/src/ui/TopControls.ts +0 -137
  82. package/src/ui/icons.ts +0 -56
  83. package/tsconfig.json +0 -19
@@ -1,34 +0,0 @@
1
- import type { BoardElement } from "../elements/types";
2
- import { arrow, beginTemplate, label, palette, rect } from "./helpers";
3
-
4
- /** A neutral collaboration map for decisions, ownership, and feedback. */
5
- export function handoffTemplate(
6
- ox: number,
7
- oy: number,
8
- theme: "light" | "dark",
9
- baseZ: number
10
- ): BoardElement[] {
11
- const p = palette(theme);
12
- beginTemplate(baseZ);
13
- const els: BoardElement[] = [];
14
- els.push(label(ox, oy, 800, "Handoff map", 26, p.heading, "700"));
15
- const cards = [
16
- ["Explore", "#dbeafe"],
17
- ["Decide", "#fef3c7"],
18
- ["Act", "#dcfce7"],
19
- ] as const;
20
- cards.forEach(([text, fill], index) => {
21
- els.push(rect(ox + index * 270, oy + 150, 170, 92, {
22
- fill, stroke: p.cardStroke, strokeWidth: 1.5, borderRadius: 12,
23
- shadow: true, fontSize: 16, fontWeight: "650", textColor: "#1f2933",
24
- }, text));
25
- });
26
- els.push(arrow(ox + 170, oy + 196, ox + 270, oy + 196, p.accent, { label: "proposal" }));
27
- els.push(arrow(ox + 440, oy + 196, ox + 540, oy + 196, p.accent, { label: "owner | outcome", sides: true, arrowStart: true }));
28
- els.push(arrow(ox + 625, oy + 245, ox + 355, oy + 330, "#9ca3af", { label: "feedback", dashed: true }));
29
- els.push(rect(ox + 265, oy + 320, 180, 70, {
30
- fill: p.zone, stroke: p.cardStroke, strokeWidth: 1.5, borderRadius: 10,
31
- fontSize: 14, textColor: p.text,
32
- }, "Review signal"));
33
- return els;
34
- }
@@ -1,132 +0,0 @@
1
- import { createElement, type BoardElement, type ElementStyle } from "../elements/types";
2
-
3
- export type TemplateBuild = {
4
- name: string;
5
- elements: BoardElement[];
6
- };
7
-
8
- export type Palette = {
9
- card: string;
10
- cardStroke: string;
11
- heading: string;
12
- text: string;
13
- accent: string;
14
- sticky: string;
15
- zone: string;
16
- };
17
-
18
- export function palette(theme: "light" | "dark"): Palette {
19
- if (theme === "dark") {
20
- return {
21
- card: "#1e2126",
22
- cardStroke: "#3a3f46",
23
- heading: "#f2f2f2",
24
- text: "#c8cdd4",
25
- accent: "#4dabf7",
26
- sticky: "#fef08a",
27
- zone: "#22262c",
28
- };
29
- }
30
- return {
31
- card: "#ffffff",
32
- cardStroke: "#d8dade",
33
- heading: "#1f2933",
34
- text: "#4b5563",
35
- accent: "#6e6e6e",
36
- sticky: "#fef08a",
37
- zone: "#f0f0ed",
38
- };
39
- }
40
-
41
- let z = 0;
42
-
43
- export function beginTemplate(baseZ: number): void {
44
- z = baseZ;
45
- }
46
-
47
- export function rect(
48
- x: number,
49
- y: number,
50
- w: number,
51
- h: number,
52
- style: ElementStyle,
53
- text = ""
54
- ): BoardElement {
55
- return createElement("rectangle", {
56
- x, y, width: w, height: h,
57
- zIndex: ++z,
58
- style: { borderRadius: 10, ...style },
59
- data: { text },
60
- });
61
- }
62
-
63
- export function label(
64
- x: number,
65
- y: number,
66
- w: number,
67
- text: string,
68
- fontSize: number,
69
- color: string,
70
- fontWeight = "600"
71
- ): BoardElement {
72
- return createElement("text", {
73
- x, y, width: w, height: fontSize * 1.6,
74
- zIndex: ++z,
75
- style: { fontSize, textColor: color, fontWeight },
76
- data: { text },
77
- });
78
- }
79
-
80
- export function sticky(
81
- x: number,
82
- y: number,
83
- text: string,
84
- fill: string,
85
- w = 180,
86
- h = 120
87
- ): BoardElement {
88
- return createElement("sticky", {
89
- x, y, width: w, height: h,
90
- zIndex: ++z,
91
- style: { fill, borderRadius: 12, shadow: true, fontSize: 13, textColor: "#1f2933" },
92
- data: { text },
93
- });
94
- }
95
-
96
- export function arrow(
97
- x1: number,
98
- y1: number,
99
- x2: number,
100
- y2: number,
101
- stroke: string,
102
- options: { label?: string; dashed?: boolean; arrowStart?: boolean; sides?: boolean } = {}
103
- ): BoardElement {
104
- return createElement("arrow", {
105
- x: x1, y: y1, width: x2 - x1, height: y2 - y1,
106
- zIndex: ++z,
107
- style: {
108
- stroke,
109
- strokeWidth: 2,
110
- arrowEnd: true,
111
- arrowStart: options.arrowStart,
112
- strokeDash: options.dashed ? [8, 6] : undefined,
113
- },
114
- data: { text: options.label ?? "", labelPosition: options.sides ? "sides" : "center" },
115
- });
116
- }
117
-
118
- export function ellipseEl(
119
- x: number,
120
- y: number,
121
- w: number,
122
- h: number,
123
- style: ElementStyle,
124
- text = ""
125
- ): BoardElement {
126
- return createElement("ellipse", {
127
- x, y, width: w, height: h,
128
- zIndex: ++z,
129
- style,
130
- data: { text },
131
- });
132
- }
@@ -1,79 +0,0 @@
1
- import type { BoardElement } from "../elements/types";
2
- import { personaTemplate } from "./personaTemplate";
3
- import { journeyMapTemplate } from "./journeyMapTemplate";
4
- import { prioritizationMatrixTemplate } from "./prioritizationMatrixTemplate";
5
- import { requirementsFlowTemplate } from "./requirementsFlowTemplate";
6
- import { systemDiagramTemplate } from "./systemDiagramTemplate";
7
- import { opportunityTreeTemplate } from "./opportunityTreeTemplate";
8
- import { screenshotReviewTemplate } from "./screenshotReviewTemplate";
9
- import { workflowTemplate } from "./workflowTemplate";
10
- import { handoffTemplate } from "./handoffTemplate";
11
-
12
- export type TemplateDef = {
13
- id: string;
14
- name: string;
15
- description: string;
16
- build: (
17
- ox: number,
18
- oy: number,
19
- theme: "light" | "dark",
20
- baseZ: number
21
- ) => BoardElement[];
22
- };
23
-
24
- export const TEMPLATES: TemplateDef[] = [
25
- {
26
- id: "persona",
27
- name: "User Persona Card",
28
- description: "Name, role, goals, pain points, JTBD, success criteria.",
29
- build: personaTemplate,
30
- },
31
- {
32
- id: "journey",
33
- name: "User Journey Map",
34
- description: "Awareness → Retention stages with sticky note areas.",
35
- build: journeyMapTemplate,
36
- },
37
- {
38
- id: "matrix",
39
- name: "Prioritization Matrix",
40
- description: "Impact vs effort: quick wins, strategic bets, fill-ins, avoid.",
41
- build: prioritizationMatrixTemplate,
42
- },
43
- {
44
- id: "requirements",
45
- name: "Requirements Flow",
46
- description: "Problem, user, context, solution, edge cases, risks.",
47
- build: requirementsFlowTemplate,
48
- },
49
- {
50
- id: "system",
51
- name: "System Diagram Starter",
52
- description: "User, frontend, API, database, external services + arrows.",
53
- build: systemDiagramTemplate,
54
- },
55
- {
56
- id: "ost",
57
- name: "Opportunity Solution Tree",
58
- description: "Outcome, opportunities, solutions, experiments, signals.",
59
- build: opportunityTreeTemplate,
60
- },
61
- {
62
- id: "screenshot-review",
63
- name: "Screenshot Review Board",
64
- description: "Screenshot zone with observations, problems, UX notes.",
65
- build: screenshotReviewTemplate,
66
- },
67
- {
68
- id: "workflow",
69
- name: "Workflow Map",
70
- description: "Labeled handoffs, a dashed feedback loop, and editable steps.",
71
- build: workflowTemplate,
72
- },
73
- {
74
- id: "handoff",
75
- name: "Handoff Map",
76
- description: "A shared decision flow with ownership, outcomes, and feedback.",
77
- build: handoffTemplate,
78
- },
79
- ];
@@ -1,52 +0,0 @@
1
- import type { BoardElement } from "../elements/types";
2
- import { palette, beginTemplate, rect, label, sticky, arrow } from "./helpers";
3
-
4
- const STAGES = [
5
- "Awareness",
6
- "Discovery",
7
- "Evaluation",
8
- "Onboarding",
9
- "Activation",
10
- "Retention",
11
- ];
12
-
13
- const STAGE_COLORS = ["#93c5fd", "#a5b4fc", "#d8b4fe", "#f9a8d4", "#fdba74", "#86efac"];
14
-
15
- export function journeyMapTemplate(
16
- ox: number,
17
- oy: number,
18
- theme: "light" | "dark",
19
- baseZ: number
20
- ): BoardElement[] {
21
- const p = palette(theme);
22
- beginTemplate(baseZ);
23
- const els: BoardElement[] = [];
24
- const colW = 230;
25
- const totalW = STAGES.length * colW + 56;
26
-
27
- els.push(rect(ox, oy, totalW, 640, { fill: p.card, stroke: p.cardStroke, strokeWidth: 1.5, borderRadius: 16, shadow: true }));
28
- els.push(label(ox + 28, oy + 22, 500, "User Journey Map", 22, p.heading, "700"));
29
-
30
- STAGES.forEach((stage, i) => {
31
- const x = ox + 28 + i * colW;
32
- const y = oy + 70;
33
- els.push(rect(x, y, colW - 16, 48, { fill: STAGE_COLORS[i], borderRadius: 10 }, stage));
34
- if (i < STAGES.length - 1) {
35
- els.push(arrow(x + colW - 14, y + 24, x + colW - 2, y + 24, p.heading));
36
- }
37
- // sticky zones per stage
38
- els.push(rect(x, y + 64, colW - 16, 150, { fill: p.zone, borderRadius: 10 }, ""));
39
- els.push(label(x + 10, y + 70, colW - 36, "Actions", 12, p.accent));
40
- els.push(sticky(x + 14, y + 96, "", "#fef08a", colW - 44, 100));
41
-
42
- els.push(rect(x, y + 226, colW - 16, 150, { fill: p.zone, borderRadius: 10 }, ""));
43
- els.push(label(x + 10, y + 232, colW - 36, "Pain points", 12, p.accent));
44
- els.push(sticky(x + 14, y + 258, "", "#fca5a5", colW - 44, 100));
45
-
46
- els.push(rect(x, y + 388, colW - 16, 150, { fill: p.zone, borderRadius: 10 }, ""));
47
- els.push(label(x + 10, y + 394, colW - 36, "Opportunities", 12, p.accent));
48
- els.push(sticky(x + 14, y + 420, "", "#86efac", colW - 44, 100));
49
- });
50
-
51
- return els;
52
- }
@@ -1,45 +0,0 @@
1
- import type { BoardElement } from "../elements/types";
2
- import { palette, beginTemplate, rect, label, sticky, arrow } from "./helpers";
3
-
4
- export function opportunityTreeTemplate(
5
- ox: number,
6
- oy: number,
7
- theme: "light" | "dark",
8
- baseZ: number
9
- ): BoardElement[] {
10
- const p = palette(theme);
11
- beginTemplate(baseZ);
12
- const els: BoardElement[] = [];
13
-
14
- els.push(label(ox + 280, oy - 40, 500, "Opportunity Solution Tree", 22, p.heading, "700"));
15
-
16
- // outcome
17
- els.push(rect(ox + 300, oy, 280, 80, { fill: "#a5b4fc", borderRadius: 12, shadow: true, fontSize: 15, fontWeight: "600", textColor: "#1f2933" }, "Desired outcome"));
18
-
19
- // opportunities
20
- const oppY = oy + 160;
21
- const oppXs = [ox, ox + 300, ox + 600];
22
- for (const x of oppXs) {
23
- els.push(sticky(x, oppY, "Opportunity", "#93c5fd", 220, 100));
24
- els.push(arrow(ox + 440, oy + 85, x + 110, oppY - 5, p.heading));
25
- }
26
-
27
- // solutions
28
- const solY = oppY + 180;
29
- for (const x of oppXs) {
30
- els.push(sticky(x, solY, "Solution", "#86efac", 220, 100));
31
- els.push(arrow(x + 110, oppY + 105, x + 110, solY - 5, p.heading));
32
- }
33
-
34
- // experiments + signals
35
- const expY = solY + 180;
36
- for (const x of oppXs) {
37
- els.push(sticky(x, expY, "Experiment", "#fdba74", 220, 90));
38
- els.push(arrow(x + 110, solY + 105, x + 110, expY - 5, p.heading));
39
- }
40
-
41
- els.push(label(ox, expY + 120, 400, "Signals / metrics", 14, p.accent));
42
- els.push(sticky(ox, expY + 150, "What signal tells us this is working?", "#fef08a", 380, 100));
43
-
44
- return els;
45
- }
@@ -1,41 +0,0 @@
1
- import type { BoardElement } from "../elements/types";
2
- import { palette, beginTemplate, rect, label, sticky } from "./helpers";
3
-
4
- export function personaTemplate(
5
- ox: number,
6
- oy: number,
7
- theme: "light" | "dark",
8
- baseZ: number
9
- ): BoardElement[] {
10
- const p = palette(theme);
11
- beginTemplate(baseZ);
12
- const els: BoardElement[] = [];
13
-
14
- els.push(rect(ox, oy, 760, 560, { fill: p.card, stroke: p.cardStroke, strokeWidth: 1.5, borderRadius: 16, shadow: true }));
15
- els.push(label(ox + 28, oy + 22, 400, "User Persona", 22, p.heading, "700"));
16
- els.push(label(ox + 28, oy + 60, 300, "Name", 13, p.accent));
17
- els.push(sticky(ox + 28, oy + 86, "Jordan Lee", p.sticky, 200, 64));
18
- els.push(label(ox + 260, oy + 60, 300, "Role", 13, p.accent));
19
- els.push(sticky(ox + 260, oy + 86, "Senior Product Manager", "#a5b4fc", 220, 64));
20
- els.push(label(ox + 510, oy + 60, 300, "Buying trigger", 13, p.accent));
21
- els.push(sticky(ox + 510, oy + 86, "Team scaling pains", "#fdba74", 220, 64));
22
-
23
- const fields: [string, string, string][] = [
24
- ["Goals", "Ship the right features faster", "#86efac"],
25
- ["Pain points", "Scattered docs, unclear priorities", "#fca5a5"],
26
- ["Jobs to be done", "Align team on what to build next", "#93c5fd"],
27
- ["Current workaround", "Spreadsheets + slide decks", "#d8b4fe"],
28
- ["Success criteria", "Stakeholders aligned in 1 meeting", "#f9a8d4"],
29
- ["Key quote", '"I need clarity, not more tools."', "#fef08a"],
30
- ];
31
- fields.forEach(([title, text, color], i) => {
32
- const col = i % 3;
33
- const row = Math.floor(i / 3);
34
- const x = ox + 28 + col * 242;
35
- const y = oy + 188 + row * 178;
36
- els.push(label(x, y, 230, title, 13, p.accent));
37
- els.push(sticky(x, y + 26, text, color, 220, 124));
38
- });
39
-
40
- return els;
41
- }
@@ -1,44 +0,0 @@
1
- import type { BoardElement } from "../elements/types";
2
- import { palette, beginTemplate, rect, label, sticky, arrow } from "./helpers";
3
-
4
- export function prioritizationMatrixTemplate(
5
- ox: number,
6
- oy: number,
7
- theme: "light" | "dark",
8
- baseZ: number
9
- ): BoardElement[] {
10
- const p = palette(theme);
11
- beginTemplate(baseZ);
12
- const els: BoardElement[] = [];
13
- const size = 680;
14
-
15
- els.push(rect(ox, oy, size + 120, size + 130, { fill: p.card, stroke: p.cardStroke, strokeWidth: 1.5, borderRadius: 16, shadow: true }));
16
- els.push(label(ox + 28, oy + 22, 500, "Feature Prioritization Matrix", 22, p.heading, "700"));
17
-
18
- const gx = ox + 80;
19
- const gy = oy + 80;
20
- const half = size / 2;
21
-
22
- // quadrants
23
- els.push(rect(gx, gy, half, half, { fill: "#86efac55", borderRadius: 8 }));
24
- els.push(rect(gx + half, gy, half, half, { fill: "#93c5fd55", borderRadius: 8 }));
25
- els.push(rect(gx, gy + half, half, half, { fill: "#fef08a55", borderRadius: 8 }));
26
- els.push(rect(gx + half, gy + half, half, half, { fill: "#fca5a555", borderRadius: 8 }));
27
-
28
- els.push(label(gx + 16, gy + 12, 300, "Quick wins", 16, p.heading, "700"));
29
- els.push(label(gx + half + 16, gy + 12, 300, "Strategic bets", 16, p.heading, "700"));
30
- els.push(label(gx + 16, gy + half + 12, 300, "Fill-ins", 16, p.heading, "700"));
31
- els.push(label(gx + half + 16, gy + half + 12, 300, "Avoid", 16, p.heading, "700"));
32
-
33
- // axes
34
- els.push(arrow(gx - 24, gy + size, gx - 24, gy, p.heading));
35
- els.push(label(gx - 64, gy + half - 12, 60, "Impact", 14, p.text, "600"));
36
- els.push(arrow(gx, gy + size + 24, gx + size, gy + size + 24, p.heading));
37
- els.push(label(gx + half - 30, gy + size + 34, 80, "Effort", 14, p.text, "600"));
38
-
39
- // sample stickies
40
- els.push(sticky(gx + 40, gy + 60, "Feature idea", "#fef08a", 150, 90));
41
- els.push(sticky(gx + half + 40, gy + 60, "Big bet", "#a5b4fc", 150, 90));
42
-
43
- return els;
44
- }
@@ -1,45 +0,0 @@
1
- import type { BoardElement } from "../elements/types";
2
- import { palette, beginTemplate, rect, label, sticky } from "./helpers";
3
-
4
- const SECTIONS: [string, string][] = [
5
- ["Problem", "#fca5a5"],
6
- ["User", "#93c5fd"],
7
- ["Context", "#d8b4fe"],
8
- ["Current workflow", "#fdba74"],
9
- ["Proposed solution", "#86efac"],
10
- ["Edge cases", "#f9a8d4"],
11
- ["Acceptance criteria", "#a5b4fc"],
12
- ["Dependencies", "#fef08a"],
13
- ["Risks", "#fca5a5"],
14
- ];
15
-
16
- export function requirementsFlowTemplate(
17
- ox: number,
18
- oy: number,
19
- theme: "light" | "dark",
20
- baseZ: number
21
- ): BoardElement[] {
22
- const p = palette(theme);
23
- beginTemplate(baseZ);
24
- const els: BoardElement[] = [];
25
- const cols = 3;
26
- const cellW = 280;
27
- const cellH = 210;
28
- const w = cols * cellW + 56;
29
- const rows = Math.ceil(SECTIONS.length / cols);
30
- const h = rows * cellH + 100;
31
-
32
- els.push(rect(ox, oy, w, h, { fill: p.card, stroke: p.cardStroke, strokeWidth: 1.5, borderRadius: 16, shadow: true }));
33
- els.push(label(ox + 28, oy + 22, 500, "Product Requirements Flow", 22, p.heading, "700"));
34
-
35
- SECTIONS.forEach(([title, color], i) => {
36
- const col = i % cols;
37
- const row = Math.floor(i / cols);
38
- const x = ox + 28 + col * cellW;
39
- const y = oy + 72 + row * cellH;
40
- els.push(label(x, y, cellW - 30, `${i + 1}. ${title}`, 14, p.accent));
41
- els.push(sticky(x, y + 30, "", color, cellW - 28, cellH - 60));
42
- });
43
-
44
- return els;
45
- }
@@ -1,52 +0,0 @@
1
- import type { BoardElement } from "../elements/types";
2
- import { createElement } from "../elements/types";
3
- import { palette, beginTemplate, rect, label, sticky } from "./helpers";
4
-
5
- export function screenshotReviewTemplate(
6
- ox: number,
7
- oy: number,
8
- theme: "light" | "dark",
9
- baseZ: number
10
- ): BoardElement[] {
11
- const p = palette(theme);
12
- beginTemplate(baseZ);
13
- const els: BoardElement[] = [];
14
-
15
- els.push(rect(ox, oy, 1060, 620, { fill: p.card, stroke: p.cardStroke, strokeWidth: 1.5, borderRadius: 16, shadow: true }));
16
- els.push(label(ox + 28, oy + 22, 500, "Screenshot Review", 22, p.heading, "700"));
17
-
18
- // screenshot drop zone (placeholder image element with no asset = drop target visual)
19
- els.push(label(ox + 28, oy + 64, 300, "Screenshot", 13, p.accent));
20
- const placeholder = createElement("frame", {
21
- x: ox + 28,
22
- y: oy + 92,
23
- width: 480,
24
- height: 360,
25
- zIndex: baseZ + 100,
26
- style: { fill: p.zone, stroke: p.cardStroke, strokeWidth: 1.5, borderRadius: 12, fontSize: 13, textColor: p.text },
27
- data: { text: "Paste a screenshot here (Cmd/Ctrl+V)" },
28
- });
29
- els.push(placeholder);
30
-
31
- const sections: [string, string][] = [
32
- ["Observations", "#93c5fd"],
33
- ["Problems", "#fca5a5"],
34
- ["UX notes", "#d8b4fe"],
35
- ["Requirements", "#86efac"],
36
- ];
37
- sections.forEach(([title, color], i) => {
38
- const col = i % 2;
39
- const row = Math.floor(i / 2);
40
- const x = ox + 540 + col * 250;
41
- const y = oy + 64 + row * 200;
42
- els.push(label(x, y, 230, title, 13, p.accent));
43
- els.push(sticky(x, y + 28, "", color, 230, 140));
44
- });
45
-
46
- els.push(label(ox + 28, oy + 470, 300, "Follow-up tasks", 13, p.accent));
47
- els.push(sticky(ox + 28, oy + 498, "", "#fef08a", 480, 96));
48
- els.push(label(ox + 540, oy + 470, 300, "Decision", 13, p.accent));
49
- els.push(sticky(ox + 540, oy + 498, "", "#fdba74", 480, 96));
50
-
51
- return els;
52
- }
@@ -1,41 +0,0 @@
1
- import type { BoardElement } from "../elements/types";
2
- import { palette, beginTemplate, rect, label, arrow, ellipseEl } from "./helpers";
3
-
4
- export function systemDiagramTemplate(
5
- ox: number,
6
- oy: number,
7
- theme: "light" | "dark",
8
- baseZ: number
9
- ): BoardElement[] {
10
- const p = palette(theme);
11
- beginTemplate(baseZ);
12
- const els: BoardElement[] = [];
13
-
14
- els.push(label(ox, oy - 40, 400, "System Diagram", 22, p.heading, "700"));
15
-
16
- const box = (x: number, y: number, w: number, h: number, fill: string, text: string) =>
17
- rect(x, y, w, h, { fill, stroke: p.cardStroke, strokeWidth: 1.5, borderRadius: 12, shadow: true, fontSize: 15, fontWeight: "600", textColor: "#1f2933" }, text);
18
-
19
- // user
20
- els.push(ellipseEl(ox, oy + 130, 110, 110, { fill: "#f9a8d4", stroke: p.cardStroke, strokeWidth: 1.5, fontSize: 14, fontWeight: "600", textColor: "#1f2933" }, "User"));
21
-
22
- // frontend
23
- els.push(box(ox + 200, oy + 140, 180, 90, "#93c5fd", "Frontend"));
24
- // api
25
- els.push(box(ox + 470, oy + 140, 180, 90, "#a5b4fc", "API / Server"));
26
- // database
27
- els.push(box(ox + 740, oy + 60, 180, 90, "#86efac", "Database"));
28
- // external service
29
- els.push(box(ox + 740, oy + 200, 180, 90, "#fdba74", "External Service"));
30
- // notifications
31
- els.push(box(ox + 470, oy + 330, 180, 90, "#fef08a", "Notification Service"));
32
-
33
- els.push(arrow(ox + 115, oy + 185, ox + 195, oy + 185, p.heading, { label: "uses" }));
34
- els.push(arrow(ox + 385, oy + 185, ox + 465, oy + 185, p.heading, { label: "request | response", sides: true, arrowStart: true }));
35
- els.push(arrow(ox + 655, oy + 165, ox + 735, oy + 110, p.heading, { label: "read" }));
36
- els.push(arrow(ox + 655, oy + 205, ox + 735, oy + 240, p.heading, { label: "webhook", dashed: true }));
37
- els.push(arrow(ox + 560, oy + 235, ox + 560, oy + 325, p.heading, { label: "event", dashed: true }));
38
- els.push(arrow(ox + 470, oy + 375, ox + 80, oy + 245, p.heading, { label: "notify", dashed: true }));
39
-
40
- return els;
41
- }
@@ -1,35 +0,0 @@
1
- import type { BoardElement } from "../elements/types";
2
- import { arrow, beginTemplate, label, palette, rect } from "./helpers";
3
-
4
- /** A general-purpose process diagram that demonstrates labeled/dashed arrows. */
5
- export function workflowTemplate(
6
- ox: number,
7
- oy: number,
8
- theme: "light" | "dark",
9
- baseZ: number
10
- ): BoardElement[] {
11
- const p = palette(theme);
12
- beginTemplate(baseZ);
13
- const els: BoardElement[] = [];
14
- els.push(label(ox, oy, 880, "Workflow map", 26, p.heading, "700"));
15
- const steps = [
16
- ["Request", "#dbeafe"],
17
- ["Review", "#fef3c7"],
18
- ["Deliver", "#dcfce7"],
19
- ] as const;
20
- for (let i = 0; i < steps.length; i++) {
21
- const x = ox + i * 280;
22
- els.push(rect(x, oy + 130, 180, 96, {
23
- fill: steps[i][1], stroke: p.cardStroke, strokeWidth: 1.5, borderRadius: 12,
24
- fontSize: 16, fontWeight: "650", textColor: "#1f2933", shadow: true,
25
- }, steps[i][0]));
26
- }
27
- els.push(arrow(ox + 180, oy + 178, ox + 280, oy + 178, p.accent, { label: "approve" }));
28
- els.push(arrow(ox + 460, oy + 178, ox + 560, oy + 178, p.accent, { label: "ship" }));
29
- els.push(arrow(ox + 650, oy + 226, ox + 370, oy + 310, "#9ca3af", { label: "feedback", dashed: true }));
30
- els.push(rect(ox + 280, oy + 300, 180, 72, {
31
- fill: p.zone, stroke: p.cardStroke, strokeWidth: 1.5, borderRadius: 10,
32
- fontSize: 14, textColor: p.text,
33
- }, "Learn and iterate"));
34
- return els;
35
- }