blob: 64ec4c70f031a89f434289f6e2297111ab1f89ac [file] [log] [blame]
Sean McCullough618bfb22025-06-25 20:52:30 +00001/**
2 * Build-time script to auto-generate demo index page
3 */
4
5import * as fs from "fs";
6import * as path from "path";
7
8interface DemoInfo {
9 name: string;
10 title: string;
11 description?: string;
12 fileName: string;
13}
14
15async function generateIndex() {
16 const demoDir = path.join(__dirname);
17 const files = await fs.promises.readdir(demoDir);
18
19 // Find all .demo.ts files
20 const demoFiles = files.filter((file) => file.endsWith(".demo.ts"));
21
22 const demos: DemoInfo[] = [];
23
24 for (const file of demoFiles) {
25 const componentName = file.replace(".demo.ts", "");
26 const filePath = path.join(demoDir, file);
27
28 try {
29 // Read the file content to extract title and description
30 const content = await fs.promises.readFile(filePath, "utf-8");
31
32 // Extract title from the demo module
33 const titleMatch = content.match(/title:\s*['"]([^'"]+)['"]/);
34 const descriptionMatch = content.match(/description:\s*['"]([^'"]+)['"]/);
35
36 demos.push({
37 name: componentName,
38 title: titleMatch ? titleMatch[1] : formatComponentName(componentName),
39 description: descriptionMatch ? descriptionMatch[1] : undefined,
40 fileName: file,
41 });
42 } catch (error) {
43 console.warn(`Failed to process demo file ${file}:`, error);
44 }
45 }
46
47 // Sort demos alphabetically
48 demos.sort((a, b) => a.title.localeCompare(b.title));
49
50 // Generate HTML index
51 const html = generateIndexHTML(demos);
52
53 // Write the generated index
54 const indexPath = path.join(demoDir, "index-generated.html");
55 await fs.promises.writeFile(indexPath, html, "utf-8");
56
57 console.log(`Generated demo index with ${demos.length} components`);
58 console.log("Available demos:", demos.map((d) => d.name).join(", "));
59}
60
61function formatComponentName(name: string): string {
62 return name
63 .replace(/^sketch-/, "")
64 .replace(/-/g, " ")
65 .replace(/\b\w/g, (l) => l.toUpperCase());
66}
67
68function generateIndexHTML(demos: DemoInfo[]): string {
69 const demoLinks = demos
70 .map((demo) => {
banksean581bd792025-07-20 18:30:12 -070071 const href = `demo.html#${demo.name}`;
Sean McCullough618bfb22025-06-25 20:52:30 +000072 const description = demo.description ? ` - ${demo.description}` : "";
73
74 return ` <li>
75 <a href="${href}">
76 <strong>${demo.title}</strong>${description}
77 </a>
78 </li>`;
79 })
80 .join("\n");
81
82 return `<!DOCTYPE html>
83<html lang="en">
84 <head>
85 <meta charset="UTF-8" />
86 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
87 <title>Sketch Web Components - Demo Index</title>
88 <link rel="stylesheet" href="demo.css" />
89 <style>
90 body {
91 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
92 max-width: 800px;
93 margin: 40px auto;
94 padding: 20px;
95 line-height: 1.6;
96 }
banksean581bd792025-07-20 18:30:12 -070097
Sean McCullough618bfb22025-06-25 20:52:30 +000098 h1 {
99 color: #24292f;
100 border-bottom: 1px solid #d1d9e0;
101 padding-bottom: 10px;
102 }
banksean581bd792025-07-20 18:30:12 -0700103
Sean McCullough618bfb22025-06-25 20:52:30 +0000104 .demo-list {
105 list-style: none;
106 padding: 0;
107 }
banksean581bd792025-07-20 18:30:12 -0700108
Sean McCullough618bfb22025-06-25 20:52:30 +0000109 .demo-list li {
110 margin: 15px 0;
111 padding: 15px;
112 border: 1px solid #d1d9e0;
113 border-radius: 6px;
114 background: #f6f8fa;
115 transition: background-color 0.2s;
116 }
banksean581bd792025-07-20 18:30:12 -0700117
Sean McCullough618bfb22025-06-25 20:52:30 +0000118 .demo-list li:hover {
119 background: #ffffff;
120 }
banksean581bd792025-07-20 18:30:12 -0700121
Sean McCullough618bfb22025-06-25 20:52:30 +0000122 .demo-list a {
123 text-decoration: none;
124 color: #0969da;
125 display: block;
126 }
banksean581bd792025-07-20 18:30:12 -0700127
Sean McCullough618bfb22025-06-25 20:52:30 +0000128 .demo-list a:hover {
129 text-decoration: underline;
130 }
banksean581bd792025-07-20 18:30:12 -0700131
Sean McCullough618bfb22025-06-25 20:52:30 +0000132 .demo-list strong {
133 font-size: 16px;
134 display: block;
135 margin-bottom: 5px;
136 }
banksean581bd792025-07-20 18:30:12 -0700137
Sean McCullough618bfb22025-06-25 20:52:30 +0000138 .stats {
139 background: #fff8dc;
140 padding: 15px;
141 border-radius: 6px;
142 margin: 20px 0;
143 border-left: 4px solid #f9c23c;
144 }
banksean581bd792025-07-20 18:30:12 -0700145
Sean McCullough618bfb22025-06-25 20:52:30 +0000146 .runner-link {
147 display: inline-block;
148 padding: 10px 20px;
149 background: #0969da;
150 color: white;
151 text-decoration: none;
152 border-radius: 6px;
153 margin-top: 20px;
154 }
banksean581bd792025-07-20 18:30:12 -0700155
Sean McCullough618bfb22025-06-25 20:52:30 +0000156 .runner-link:hover {
157 background: #0860ca;
158 }
159 </style>
160 </head>
161 <body>
162 <h1>Sketch Web Components Demo Index</h1>
banksean581bd792025-07-20 18:30:12 -0700163
Sean McCullough618bfb22025-06-25 20:52:30 +0000164 <div class="stats">
165 <strong>Auto-generated index</strong><br>
166 Found ${demos.length} demo component${demos.length === 1 ? "" : "s"} • Last updated: ${new Date().toLocaleString()}
167 </div>
banksean581bd792025-07-20 18:30:12 -0700168
Sean McCullough618bfb22025-06-25 20:52:30 +0000169 <p>
170 This page provides an overview of all available component demos.
171 Click on any component below to view its interactive demo.
172 </p>
banksean581bd792025-07-20 18:30:12 -0700173
174 <a href="demo.html" class="runner-link">🚀 Launch Demo Runner</a>
175
Sean McCullough618bfb22025-06-25 20:52:30 +0000176 <h2>Available Component Demos</h2>
banksean581bd792025-07-20 18:30:12 -0700177
Sean McCullough618bfb22025-06-25 20:52:30 +0000178 <ul class="demo-list">
179${demoLinks}
180 </ul>
banksean581bd792025-07-20 18:30:12 -0700181
Sean McCullough618bfb22025-06-25 20:52:30 +0000182 <hr style="margin: 40px 0; border: none; border-top: 1px solid #d1d9e0;">
banksean581bd792025-07-20 18:30:12 -0700183
Sean McCullough618bfb22025-06-25 20:52:30 +0000184 <p>
185 <em>This index is automatically generated from available <code>*.demo.ts</code> files.</em><br>
186 To add a new demo, create a <code>component-name.demo.ts</code> file in this directory.
187 </p>
188 </body>
189</html>
190`;
191}
192
193// Run the generator if this script is executed directly
194if (require.main === module) {
195 generateIndex().catch(console.error);
196}
197
198export { generateIndex };