blob: 686eb63c44f62d0610c4003fe92b56fdaf07e4f7 [file] [log] [blame] [view]
# Sketch Web Components Demo System
This directory contains an automated demo system for Sketch web components that reduces maintenance overhead and provides a consistent development experience.
## Overview
The demo system consists of:
- **TypeScript Demo Modules** (`*.demo.ts`) - Component-specific demo configurations
- **Demo Framework** (`demo-framework/`) - Shared infrastructure for loading and running demos
- **Shared Fixtures** (`demo-fixtures/`) - Common fake data and utilities
- **Demo Runner** (`demo-runner.html`) - Interactive demo browser
- **Auto-generated Index** - Automatically maintained list of available demos
## Quick Start
### Running Demos
```bash
# Start the demo server
npm run demo
# Visit the demo runner
open http://localhost:5173/src/web-components/demo/demo-runner.html
# Or view the auto-generated index
open http://localhost:5173/src/web-components/demo/index-generated.html
```
### Creating a New Demo
1. Create a new demo module file: `your-component.demo.ts`
```typescript
import { DemoModule } from "./demo-framework/types";
import { demoUtils, sampleData } from "./demo-fixtures/index";
const demo: DemoModule = {
title: "Your Component Demo",
description: "Interactive demo showing component functionality",
imports: ["your-component.ts"], // Component files to import
setup: async (container: HTMLElement) => {
// Create demo sections
const section = demoUtils.createDemoSection(
"Basic Usage",
"Description of what this demo shows",
);
// Create your component
const component = document.createElement("your-component") as any;
component.data = sampleData.yourData;
// Add to container
section.appendChild(component);
container.appendChild(section);
},
cleanup: async () => {
// Optional cleanup when demo is unloaded
},
};
export default demo;
```
2. Regenerate the index:
```bash
cd src/web-components/demo
npx tsx generate-index.ts
```
3. Your demo will automatically appear in the demo runner!
## Demo Module Structure
### Required Properties
- `title`: Display name for the demo
- `imports`: Array of component files to import (relative to parent directory)
- `setup`: Function that creates the demo content
### Optional Properties
- `description`: Brief description of what the demo shows
- `styles`: Additional CSS files to load
- `customStyles`: Inline CSS styles
- `cleanup`: Function called when demo is unloaded
### Setup Function
The setup function receives a container element and should populate it with demo content:
```typescript
setup: async (container: HTMLElement) => {
// Use demo utilities for consistent styling
const section = demoUtils.createDemoSection("Title", "Description");
// Create and configure your component
const component = document.createElement("my-component");
component.setAttribute("data", JSON.stringify(sampleData));
// Add interactive controls
const button = demoUtils.createButton("Reset", () => {
component.reset();
});
// Assemble the demo
section.appendChild(component);
section.appendChild(button);
container.appendChild(section);
};
```
## Shared Fixtures
The `demo-fixtures/` directory contains reusable fake data and utilities:
```typescript
import {
sampleToolCalls,
sampleTimelineMessages,
sampleContainerState,
demoUtils,
} from "./demo-fixtures/index";
```
### Available Fixtures
- `sampleToolCalls` - Various tool call examples
- `sampleTimelineMessages` - Chat/timeline message data
- `sampleContainerState` - Container status information
- `demoUtils` - Helper functions for creating demo UI elements
### Demo Utilities
- `demoUtils.createDemoSection(title, description)` - Create a styled demo section
- `demoUtils.createButton(text, onClick)` - Create a styled button
- `demoUtils.delay(ms)` - Promise-based delay function
## Benefits of This System
### For Developers
- **TypeScript Support**: Full type checking for demo code and shared data
- **Hot Module Replacement**: Instant updates when demo code changes
- **Shared Data**: Consistent fake data across all demos
- **Reusable Utilities**: Common demo patterns abstracted into utilities
- **Auto-discovery**: New demos automatically appear in the index
### For Maintenance
- **No Boilerplate**: No need to copy HTML structure between demos
- **Centralized Styling**: Demo appearance controlled in one place
- **Automated Index**: Never forget to update the index page
- **Type Safety**: Catch errors early with TypeScript compilation
## Vite Integration
The system is designed to work seamlessly with Vite:
- **Dynamic Imports**: Demo modules are loaded on demand
- **TypeScript Compilation**: `.demo.ts` files are compiled automatically
- **HMR Support**: Changes to demos or fixtures trigger instant reloads
- **Dependency Tracking**: Vite knows when to reload based on imports
## Migration from HTML Demos
To convert an existing HTML demo:
1. Extract the component setup JavaScript into a `setup` function
2. Move shared data to `demo-fixtures/`
3. Replace HTML boilerplate with `demoUtils` calls
4. Convert inline styles to `customStyles` property
5. Test with the demo runner
## File Structure
```
demo/
├── demo-framework/
│ ├── types.ts # TypeScript interfaces
│ └── demo-runner.ts # Demo loading and execution
├── demo-fixtures/
│ ├── tool-calls.ts # Tool call sample data
│ ├── timeline-messages.ts # Message sample data
│ ├── container-status.ts # Status sample data
│ └── index.ts # Centralized exports
├── generate-index.ts # Index generation script
├── demo-runner.html # Interactive demo browser
├── index-generated.html # Auto-generated index
├── *.demo.ts # Individual demo modules
└── readme.md # This file
```
## Advanced Usage
### Custom Styling
```typescript
const demo: DemoModule = {
// ...
customStyles: `
.my-demo-container {
background: #f0f0f0;
padding: 20px;
border-radius: 8px;
}
`,
setup: async (container) => {
container.className = "my-demo-container";
// ...
},
};
```
### Progressive Loading
```typescript
setup: async (container) => {
const messages = [];
const timeline = document.createElement("sketch-timeline");
// Add messages progressively
for (let i = 0; i < sampleMessages.length; i++) {
await demoUtils.delay(500);
messages.push(sampleMessages[i]);
timeline.messages = [...messages];
}
};
```
### Cleanup
```typescript
let intervalId: number;
const demo: DemoModule = {
// ...
setup: async (container) => {
// Set up interval for updates
intervalId = setInterval(() => {
updateComponent();
}, 1000);
},
cleanup: async () => {
// Clean up interval
if (intervalId) {
clearInterval(intervalId);
}
},
};
```
For more examples, see the existing demo modules in this directory.