| Sean McCullough | 618bfb2 | 2025-06-25 20:52:30 +0000 | [diff] [blame] | 1 | # Sketch Web Components Demo System |
| Sean McCullough | 86b5686 | 2025-04-18 13:04:03 -0700 | [diff] [blame] | 2 | |
| Sean McCullough | 618bfb2 | 2025-06-25 20:52:30 +0000 | [diff] [blame] | 3 | This directory contains an automated demo system for Sketch web components that reduces maintenance overhead and provides a consistent development experience. |
| Sean McCullough | 86b5686 | 2025-04-18 13:04:03 -0700 | [diff] [blame] | 4 | |
| Sean McCullough | 618bfb2 | 2025-06-25 20:52:30 +0000 | [diff] [blame] | 5 | ## Overview |
| 6 | |
| 7 | The demo system consists of: |
| 8 | |
| 9 | - **TypeScript Demo Modules** (`*.demo.ts`) - Component-specific demo configurations |
| 10 | - **Demo Framework** (`demo-framework/`) - Shared infrastructure for loading and running demos |
| 11 | - **Shared Fixtures** (`demo-fixtures/`) - Common fake data and utilities |
| banksean | 581bd79 | 2025-07-20 18:30:12 -0700 | [diff] [blame] | 12 | - **Demo Runner** (`demo.html`) - Interactive demo browser |
| Sean McCullough | 618bfb2 | 2025-06-25 20:52:30 +0000 | [diff] [blame] | 13 | - **Auto-generated Index** - Automatically maintained list of available demos |
| 14 | |
| 15 | ## Quick Start |
| 16 | |
| 17 | ### Running Demos |
| 18 | |
| 19 | ```bash |
| 20 | # Start the demo server |
| 21 | npm run demo |
| 22 | |
| 23 | # Visit the demo runner |
| banksean | 581bd79 | 2025-07-20 18:30:12 -0700 | [diff] [blame] | 24 | open http://localhost:5173/src/web-components/demo/demo.html |
| Sean McCullough | 618bfb2 | 2025-06-25 20:52:30 +0000 | [diff] [blame] | 25 | |
| 26 | # Or view the auto-generated index |
| 27 | open http://localhost:5173/src/web-components/demo/index-generated.html |
| 28 | ``` |
| 29 | |
| 30 | ### Creating a New Demo |
| 31 | |
| 32 | 1. Create a new demo module file: `your-component.demo.ts` |
| 33 | |
| 34 | ```typescript |
| 35 | import { DemoModule } from "./demo-framework/types"; |
| 36 | import { demoUtils, sampleData } from "./demo-fixtures/index"; |
| 37 | |
| 38 | const demo: DemoModule = { |
| 39 | title: "Your Component Demo", |
| 40 | description: "Interactive demo showing component functionality", |
| 41 | imports: ["your-component.ts"], // Component files to import |
| 42 | |
| 43 | setup: async (container: HTMLElement) => { |
| 44 | // Create demo sections |
| 45 | const section = demoUtils.createDemoSection( |
| 46 | "Basic Usage", |
| 47 | "Description of what this demo shows", |
| 48 | ); |
| 49 | |
| 50 | // Create your component |
| 51 | const component = document.createElement("your-component") as any; |
| 52 | component.data = sampleData.yourData; |
| 53 | |
| 54 | // Add to container |
| 55 | section.appendChild(component); |
| 56 | container.appendChild(section); |
| 57 | }, |
| 58 | |
| 59 | cleanup: async () => { |
| 60 | // Optional cleanup when demo is unloaded |
| 61 | }, |
| 62 | }; |
| 63 | |
| 64 | export default demo; |
| 65 | ``` |
| 66 | |
| 67 | 2. Regenerate the index: |
| 68 | |
| 69 | ```bash |
| 70 | cd src/web-components/demo |
| 71 | npx tsx generate-index.ts |
| 72 | ``` |
| 73 | |
| 74 | 3. Your demo will automatically appear in the demo runner! |
| 75 | |
| 76 | ## Demo Module Structure |
| 77 | |
| 78 | ### Required Properties |
| 79 | |
| 80 | - `title`: Display name for the demo |
| 81 | - `imports`: Array of component files to import (relative to parent directory) |
| 82 | - `setup`: Function that creates the demo content |
| 83 | |
| 84 | ### Optional Properties |
| 85 | |
| 86 | - `description`: Brief description of what the demo shows |
| 87 | - `styles`: Additional CSS files to load |
| 88 | - `customStyles`: Inline CSS styles |
| 89 | - `cleanup`: Function called when demo is unloaded |
| 90 | |
| 91 | ### Setup Function |
| 92 | |
| 93 | The setup function receives a container element and should populate it with demo content: |
| 94 | |
| 95 | ```typescript |
| 96 | setup: async (container: HTMLElement) => { |
| 97 | // Use demo utilities for consistent styling |
| 98 | const section = demoUtils.createDemoSection("Title", "Description"); |
| 99 | |
| 100 | // Create and configure your component |
| 101 | const component = document.createElement("my-component"); |
| 102 | component.setAttribute("data", JSON.stringify(sampleData)); |
| 103 | |
| 104 | // Add interactive controls |
| 105 | const button = demoUtils.createButton("Reset", () => { |
| 106 | component.reset(); |
| 107 | }); |
| 108 | |
| 109 | // Assemble the demo |
| 110 | section.appendChild(component); |
| 111 | section.appendChild(button); |
| 112 | container.appendChild(section); |
| 113 | }; |
| 114 | ``` |
| 115 | |
| 116 | ## Shared Fixtures |
| 117 | |
| 118 | The `demo-fixtures/` directory contains reusable fake data and utilities: |
| 119 | |
| 120 | ```typescript |
| 121 | import { |
| 122 | sampleToolCalls, |
| 123 | sampleTimelineMessages, |
| 124 | sampleContainerState, |
| 125 | demoUtils, |
| 126 | } from "./demo-fixtures/index"; |
| 127 | ``` |
| 128 | |
| 129 | ### Available Fixtures |
| 130 | |
| 131 | - `sampleToolCalls` - Various tool call examples |
| 132 | - `sampleTimelineMessages` - Chat/timeline message data |
| 133 | - `sampleContainerState` - Container status information |
| 134 | - `demoUtils` - Helper functions for creating demo UI elements |
| 135 | |
| 136 | ### Demo Utilities |
| 137 | |
| 138 | - `demoUtils.createDemoSection(title, description)` - Create a styled demo section |
| 139 | - `demoUtils.createButton(text, onClick)` - Create a styled button |
| 140 | - `demoUtils.delay(ms)` - Promise-based delay function |
| 141 | |
| 142 | ## Benefits of This System |
| 143 | |
| 144 | ### For Developers |
| 145 | |
| 146 | - **TypeScript Support**: Full type checking for demo code and shared data |
| 147 | - **Hot Module Replacement**: Instant updates when demo code changes |
| 148 | - **Shared Data**: Consistent fake data across all demos |
| 149 | - **Reusable Utilities**: Common demo patterns abstracted into utilities |
| 150 | - **Auto-discovery**: New demos automatically appear in the index |
| 151 | |
| 152 | ### For Maintenance |
| 153 | |
| 154 | - **No Boilerplate**: No need to copy HTML structure between demos |
| 155 | - **Centralized Styling**: Demo appearance controlled in one place |
| 156 | - **Automated Index**: Never forget to update the index page |
| 157 | - **Type Safety**: Catch errors early with TypeScript compilation |
| 158 | |
| 159 | ## Vite Integration |
| 160 | |
| 161 | The system is designed to work seamlessly with Vite: |
| 162 | |
| 163 | - **Dynamic Imports**: Demo modules are loaded on demand |
| 164 | - **TypeScript Compilation**: `.demo.ts` files are compiled automatically |
| 165 | - **HMR Support**: Changes to demos or fixtures trigger instant reloads |
| 166 | - **Dependency Tracking**: Vite knows when to reload based on imports |
| 167 | |
| 168 | ## Migration from HTML Demos |
| 169 | |
| 170 | To convert an existing HTML demo: |
| 171 | |
| 172 | 1. Extract the component setup JavaScript into a `setup` function |
| 173 | 2. Move shared data to `demo-fixtures/` |
| 174 | 3. Replace HTML boilerplate with `demoUtils` calls |
| 175 | 4. Convert inline styles to `customStyles` property |
| 176 | 5. Test with the demo runner |
| 177 | |
| 178 | ## File Structure |
| 179 | |
| 180 | ``` |
| 181 | demo/ |
| 182 | ├── demo-framework/ |
| 183 | │ ├── types.ts # TypeScript interfaces |
| banksean | 581bd79 | 2025-07-20 18:30:12 -0700 | [diff] [blame] | 184 | │ └── demo.ts # Demo loading and execution |
| Sean McCullough | 618bfb2 | 2025-06-25 20:52:30 +0000 | [diff] [blame] | 185 | ├── demo-fixtures/ |
| 186 | │ ├── tool-calls.ts # Tool call sample data |
| 187 | │ ├── timeline-messages.ts # Message sample data |
| 188 | │ ├── container-status.ts # Status sample data |
| 189 | │ └── index.ts # Centralized exports |
| 190 | ├── generate-index.ts # Index generation script |
| banksean | 581bd79 | 2025-07-20 18:30:12 -0700 | [diff] [blame] | 191 | ├── demo.html # Interactive demo browser |
| Sean McCullough | 618bfb2 | 2025-06-25 20:52:30 +0000 | [diff] [blame] | 192 | ├── index-generated.html # Auto-generated index |
| 193 | ├── *.demo.ts # Individual demo modules |
| 194 | └── readme.md # This file |
| 195 | ``` |
| 196 | |
| 197 | ## Advanced Usage |
| 198 | |
| 199 | ### Custom Styling |
| 200 | |
| 201 | ```typescript |
| 202 | const demo: DemoModule = { |
| 203 | // ... |
| 204 | customStyles: ` |
| 205 | .my-demo-container { |
| 206 | background: #f0f0f0; |
| 207 | padding: 20px; |
| 208 | border-radius: 8px; |
| 209 | } |
| 210 | `, |
| 211 | setup: async (container) => { |
| 212 | container.className = "my-demo-container"; |
| 213 | // ... |
| 214 | }, |
| 215 | }; |
| 216 | ``` |
| 217 | |
| 218 | ### Progressive Loading |
| 219 | |
| 220 | ```typescript |
| 221 | setup: async (container) => { |
| 222 | const messages = []; |
| 223 | const timeline = document.createElement("sketch-timeline"); |
| 224 | |
| 225 | // Add messages progressively |
| 226 | for (let i = 0; i < sampleMessages.length; i++) { |
| 227 | await demoUtils.delay(500); |
| 228 | messages.push(sampleMessages[i]); |
| 229 | timeline.messages = [...messages]; |
| 230 | } |
| 231 | }; |
| 232 | ``` |
| 233 | |
| 234 | ### Cleanup |
| 235 | |
| 236 | ```typescript |
| 237 | let intervalId: number; |
| 238 | |
| 239 | const demo: DemoModule = { |
| 240 | // ... |
| 241 | setup: async (container) => { |
| 242 | // Set up interval for updates |
| 243 | intervalId = setInterval(() => { |
| 244 | updateComponent(); |
| 245 | }, 1000); |
| 246 | }, |
| 247 | |
| 248 | cleanup: async () => { |
| 249 | // Clean up interval |
| 250 | if (intervalId) { |
| 251 | clearInterval(intervalId); |
| 252 | } |
| 253 | }, |
| 254 | }; |
| 255 | ``` |
| 256 | |
| 257 | For more examples, see the existing demo modules in this directory. |