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