viteboard 0.1.1 → 0.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 (81) hide show
  1. package/content/docs/index.md +1 -1
  2. package/content/docs/product-roadmap.board.json +4 -4
  3. package/content/machine/board-v1.schema.json +138 -0
  4. package/content/machine/example.board.json +217 -0
  5. package/content/machine/guide.md +270 -0
  6. package/content/machine/llms.txt +31 -0
  7. package/content/machine/viteboard.json +62 -0
  8. package/dist/assets/index-D2W76uu9.js +96 -0
  9. package/dist/assets/index-rMkUjGXP.css +1 -0
  10. package/dist/index.html +4 -2
  11. package/package.json +10 -12
  12. package/vite.config.ts +619 -38
  13. package/dist/assets/index-C30zRPsW.js +0 -60
  14. package/dist/assets/index-e5aqtN8W.css +0 -1
  15. package/index.html +0 -13
  16. package/src/app/AppController.ts +0 -962
  17. package/src/app/BoardState.ts +0 -130
  18. package/src/app/ClipboardService.ts +0 -159
  19. package/src/app/CommandManager.ts +0 -66
  20. package/src/app/ElementActions.ts +0 -152
  21. package/src/app/EmbedRegionSelector.ts +0 -103
  22. package/src/app/ExportPng.ts +0 -107
  23. package/src/app/ImageInsertService.ts +0 -141
  24. package/src/app/KeyboardShortcuts.ts +0 -124
  25. package/src/app/main.ts +0 -6
  26. package/src/board/BoardPreview.ts +0 -189
  27. package/src/board/BoardService.ts +0 -222
  28. package/src/canvas/CanvasRenderer.ts +0 -253
  29. package/src/canvas/CanvasSurface.ts +0 -70
  30. package/src/canvas/HitTester.ts +0 -110
  31. package/src/canvas/ImageCache.ts +0 -123
  32. package/src/canvas/PerformanceMonitor.ts +0 -31
  33. package/src/canvas/RenderScheduler.ts +0 -26
  34. package/src/canvas/Viewport.ts +0 -77
  35. package/src/content/ContentApi.ts +0 -258
  36. package/src/content/Markdown.ts +0 -431
  37. package/src/content/MarkdownView.ts +0 -70
  38. package/src/editor/DocEditor.ts +0 -799
  39. package/src/editor/htmlToMarkdown.ts +0 -333
  40. package/src/elements/renderElement.ts +0 -598
  41. package/src/elements/types.ts +0 -119
  42. package/src/shell/Shell.ts +0 -2948
  43. package/src/shell/Sidebar.ts +0 -1651
  44. package/src/storage/AssetStore.ts +0 -86
  45. package/src/storage/BoardSerializer.ts +0 -114
  46. package/src/storage/ImportExportService.ts +0 -153
  47. package/src/storage/IndexedDbStore.ts +0 -92
  48. package/src/storage/LocalBoardStore.ts +0 -104
  49. package/src/styles.css +0 -3332
  50. package/src/templates/handoffTemplate.ts +0 -34
  51. package/src/templates/helpers.ts +0 -132
  52. package/src/templates/index.ts +0 -79
  53. package/src/templates/journeyMapTemplate.ts +0 -52
  54. package/src/templates/opportunityTreeTemplate.ts +0 -45
  55. package/src/templates/personaTemplate.ts +0 -41
  56. package/src/templates/prioritizationMatrixTemplate.ts +0 -44
  57. package/src/templates/requirementsFlowTemplate.ts +0 -45
  58. package/src/templates/screenshotReviewTemplate.ts +0 -52
  59. package/src/templates/systemDiagramTemplate.ts +0 -41
  60. package/src/templates/workflowTemplate.ts +0 -35
  61. package/src/testing/StressTestGenerator.ts +0 -134
  62. package/src/testing/StressTestPanel.ts +0 -64
  63. package/src/tools/ArrowTool.ts +0 -97
  64. package/src/tools/ImageTool.ts +0 -39
  65. package/src/tools/PanTool.ts +0 -34
  66. package/src/tools/SelectTool.ts +0 -377
  67. package/src/tools/ShapeTool.ts +0 -106
  68. package/src/tools/StickyTool.ts +0 -69
  69. package/src/tools/TaskTool.ts +0 -52
  70. package/src/tools/TextTool.ts +0 -45
  71. package/src/tools/ToolContext.ts +0 -51
  72. package/src/tools/ToolController.ts +0 -178
  73. package/src/ui/Modal.ts +0 -58
  74. package/src/ui/PerformanceOverlay.ts +0 -75
  75. package/src/ui/StorageManager.ts +0 -94
  76. package/src/ui/TemplatePicker.ts +0 -67
  77. package/src/ui/TextEditorOverlay.ts +0 -262
  78. package/src/ui/Toolbar.ts +0 -189
  79. package/src/ui/TopControls.ts +0 -137
  80. package/src/ui/icons.ts +0 -56
  81. 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
- }