blob: a1011014c657cd1716dc5956c947ad88c3fb400d [file] [log] [blame]
bankseanc5147482025-06-29 00:41:58 +00001/**
2 * Demo module for sketch-timeline-message component
3 */
4
5import { DemoModule } from "./demo-framework/types";
6import { demoUtils, longTimelineMessage } from "./demo-fixtures/index";
7import type { AgentMessage } from "../../types";
8
9const demo: DemoModule = {
10 title: "Timeline Message Demo",
11 description:
12 "Interactive timeline message component with various message types and features",
13 imports: ["../sketch-timeline-message"],
14 styles: ["/dist/tailwind.css"],
15
16 setup: async (container: HTMLElement) => {
17 // Create demo sections
18 const messageTypesSection = demoUtils.createDemoSection(
19 "Message Types",
20 "Different types of timeline messages with various content",
21 );
22
23 const interactiveSection = demoUtils.createDemoSection(
24 "Interactive Features",
25 "Test copy buttons, info panels, and commit interactions",
26 );
27
28 const advancedSection = demoUtils.createDemoSection(
29 "Advanced Examples",
30 "Complex messages with tool calls, commits, and markdown content",
31 );
32
33 // Mock state for components
34 const mockState = {
35 session_id: "demo-session",
36 git_username: "demo.user",
37 link_to_github: true,
38 git_origin: "https://github.com/boldsoftware/bold.git",
39 };
40
41 // Helper function to create timeline message component
42 const createTimelineMessage = (
43 message: AgentMessage,
44 label: string,
45 state = mockState,
46 ) => {
47 const wrapper = document.createElement("div");
banksean3d1308e2025-07-29 17:20:10 +000048 wrapper.className =
49 "my-4 p-4 border border-gray-200 dark:border-gray-700 rounded bg-white dark:bg-gray-800";
bankseanc5147482025-06-29 00:41:58 +000050
51 const labelEl = document.createElement("h4");
52 labelEl.textContent = label;
53 labelEl.style.cssText =
banksean1ee0bc62025-07-22 23:24:18 +000054 "margin: 0 0 10px 0; color: var(--demo-label-color); font-size: 14px; font-weight: 600;";
bankseanc5147482025-06-29 00:41:58 +000055
56 const messageComponent = document.createElement(
57 "sketch-timeline-message",
58 ) as any;
59 messageComponent.message = message;
60 messageComponent.state = state;
61 messageComponent.open = true;
62
63 wrapper.appendChild(labelEl);
64 wrapper.appendChild(messageComponent);
65 return wrapper;
66 };
67
68 // Create sample messages
69 const userMessage: AgentMessage = {
70 idx: 0,
71 type: "user",
72 content:
73 "Hello, can you help me fix this bug in my code?\n\n```javascript\nfunction broken() {\n // This function is broken\n return undefined;\n}\n```",
74 timestamp: "2023-05-15T12:00:00Z",
75 elapsed: 1500000000,
76 end_of_turn: false,
77 conversation_id: "demo-conversation",
78 tool_calls: [],
79 };
80
81 const agentMessage: AgentMessage = {
82 idx: 1,
83 type: "agent",
84 content:
85 "I can help you fix that bug! Here's the corrected version:\n\n```javascript\nfunction fixed() {\n // This function now works correctly\n return \"success\";\n}\n```\n\nThe issue was that the function wasn't returning a meaningful value.",
86 timestamp: "2023-05-15T12:01:00Z",
87 elapsed: 2500000000,
88 end_of_turn: true,
89 conversation_id: "demo-conversation",
90 tool_calls: [],
91 usage: {
92 input_tokens: 150,
93 output_tokens: 300,
94 cost_usd: 0.025,
95 cache_read_input_tokens: 50,
96 cache_creation_input_tokens: 0,
97 },
98 };
99
100 const toolCallMessage: AgentMessage = {
101 idx: 2,
102 type: "agent",
103 content: "Let me run some tests to verify the fix:",
104 timestamp: "2023-05-15T12:02:00Z",
105 elapsed: 3500000000,
106 end_of_turn: false,
107 conversation_id: "demo-conversation",
108 tool_calls: [
109 {
110 name: "bash",
111 input: '{command:"npm test"}',
112 tool_call_id: "toolu_bash_123",
113 result:
114 "āœ“ All tests passed!\nāœ“ 15 tests completed\nāœ“ Code coverage: 95%",
115 },
116 ],
117 };
118
119 const commitMessage: AgentMessage = {
120 idx: 3,
121 type: "agent",
122 content: "Perfect! I've committed the changes:",
123 timestamp: "2023-05-15T12:03:00Z",
124 elapsed: 1000000000,
125 end_of_turn: true,
126 conversation_id: "demo-conversation",
127 tool_calls: [],
128 commits: [
129 {
130 hash: "1234567890abcdef",
131 subject: "Fix broken function return value",
132 body: "Updated function to return meaningful value instead of undefined\n\nSigned-off-by: Demo User <demo@example.com>",
133 pushed_branch: "main",
134 },
135 ],
136 };
137
138 const errorMessage: AgentMessage = {
139 idx: 4,
140 type: "error",
141 content:
142 "An error occurred while processing your request. Please check the logs for more details.",
143 timestamp: "2023-05-15T12:04:00Z",
144 elapsed: 500000000,
145 end_of_turn: true,
146 conversation_id: "demo-conversation",
147 tool_calls: [],
148 };
149
150 // Create message type examples
151 const userMessageExample = createTimelineMessage(
152 userMessage,
153 "User Message - With code block and username",
154 );
155 const agentMessageExample = createTimelineMessage(
156 agentMessage,
157 "Agent Message - With usage info and end-of-turn",
158 );
159 const errorMessageExample = createTimelineMessage(
160 errorMessage,
161 "Error Message - Error state styling",
162 );
163
164 messageTypesSection.appendChild(userMessageExample);
165 messageTypesSection.appendChild(agentMessageExample);
166 messageTypesSection.appendChild(errorMessageExample);
167
168 // Interactive message component
169 const interactiveMessage = document.createElement(
170 "sketch-timeline-message",
171 ) as any;
172 interactiveMessage.message = {
173 ...agentMessage,
174 content:
175 "This is an interactive message. Try clicking the info button to see message details, or hover to see the copy button.",
176 };
177 interactiveMessage.state = mockState;
178 interactiveMessage.open = true;
179
180 const interactiveWrapper = document.createElement("div");
banksean3d1308e2025-07-29 17:20:10 +0000181 interactiveWrapper.className =
182 "p-4 border border-gray-200 dark:border-gray-700 rounded bg-white dark:bg-gray-800";
bankseanc5147482025-06-29 00:41:58 +0000183 interactiveWrapper.appendChild(interactiveMessage);
184
185 // Control buttons for interactive demo
186 const controlsDiv = document.createElement("div");
187 controlsDiv.style.cssText =
188 "margin-top: 20px; display: flex; flex-wrap: wrap; gap: 10px;";
189
190 const toggleInfoButton = demoUtils.createButton("Toggle Info Panel", () => {
191 interactiveMessage.showInfo = !interactiveMessage.showInfo;
192 });
193
194 const changeTypeButton = demoUtils.createButton(
195 "Change Message Type",
196 () => {
197 const types = ["user", "agent", "error", "tool"];
198 const currentIndex = types.indexOf(interactiveMessage.message.type);
199 const nextIndex = (currentIndex + 1) % types.length;
200 interactiveMessage.message = {
201 ...interactiveMessage.message,
202 type: types[nextIndex],
203 };
204 },
205 );
206
207 const toggleCompactButton = demoUtils.createButton(
208 "Toggle Compact Padding",
209 () => {
210 interactiveMessage.compactPadding = !interactiveMessage.compactPadding;
211 },
212 );
213
214 const changeContentButton = demoUtils.createButton("Change Content", () => {
215 const contents = [
216 "Simple message with plain text.",
217 "Message with **markdown** formatting and `code`.",
218 "# Heading\n\nMessage with heading and list:\n\n- Item 1\n- Item 2\n- Item 3",
219 "```python\ndef hello_world():\n print('Hello, World!')\n```\n\nMessage with code block.",
220 ];
221 const currentIndex = contents.indexOf(interactiveMessage.message.content);
222 const nextIndex = (currentIndex + 1) % contents.length;
223 interactiveMessage.message = {
224 ...interactiveMessage.message,
225 content: contents[nextIndex],
226 };
227 });
228
229 controlsDiv.appendChild(toggleInfoButton);
230 controlsDiv.appendChild(changeTypeButton);
231 controlsDiv.appendChild(toggleCompactButton);
232 controlsDiv.appendChild(changeContentButton);
233
234 interactiveWrapper.appendChild(controlsDiv);
235 interactiveSection.appendChild(interactiveWrapper);
236
237 // Advanced examples
238 const toolCallExample = createTimelineMessage(
239 toolCallMessage,
240 "Agent Message with Tool Calls",
241 );
242 const commitExample = createTimelineMessage(
243 commitMessage,
244 "Agent Message with Git Commits",
245 );
246 const longMessageExample = createTimelineMessage(
247 longTimelineMessage,
248 "Long Message with Complex Markdown",
249 );
250
251 advancedSection.appendChild(toolCallExample);
252 advancedSection.appendChild(commitExample);
253 advancedSection.appendChild(longMessageExample);
254
255 // Event listeners for commit interactions
256 container.addEventListener("show-commit-diff", (event: any) => {
257 const commitHash = event.detail.commitHash;
258 alert(`Commit diff requested for: ${commitHash}`);
259 });
260
261 // Assemble the demo
262 container.appendChild(messageTypesSection);
263 container.appendChild(interactiveSection);
264 container.appendChild(advancedSection);
265
266 // Add demo-specific styles
267 const demoStyles = document.createElement("style");
268 demoStyles.textContent = `
269 /* Demo-specific enhancements */
270 .demo-container sketch-timeline-message {
271 max-width: 100%;
272 }
273
274 /* Ensure proper spacing for demo layout */
275 .demo-section {
276 margin-bottom: 30px;
277 }
278 `;
279 document.head.appendChild(demoStyles);
280 },
281
282 cleanup: async () => {
283 // Remove demo-specific styles
284 const demoStyles = document.querySelector(
285 'style[data-demo="timeline-message"]',
286 );
287 if (demoStyles) {
288 demoStyles.remove();
289 }
290 },
291};
292
293export default demo;