@openlearning/create-widget 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,9 +32,8 @@ my-widget/
32
32
  │ ├── DevApp.tsx
33
33
  │ ├── devMain.tsx
34
34
  │ └── index.css
35
- ├── html/
36
- ├── learner.html
37
- │ └── setup.html
35
+ ├── learner.html
36
+ ├── setup.html
38
37
  ├── index.html (dev server)
39
38
  ├── package.json
40
39
  ├── tsconfig.json
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA8dA,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyCrE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA2gBA,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyCrE"}
package/dist/index.js CHANGED
@@ -23,13 +23,17 @@ function getTemplateFiles(projectName) {
23
23
  "react-dom": "^19.2.0",
24
24
  },
25
25
  devDependencies: {
26
+ "@tailwindcss/postcss": "^4.1.18",
26
27
  "@types/node": "^20.0.0",
27
28
  "@types/react": "^19.0.0",
28
29
  "@types/react-dom": "^19.0.0",
29
30
  "@vitejs/plugin-react": "^4.0.0",
31
+ autoprefixer: "^10.4.23",
30
32
  eslint: "^8.0.0",
31
33
  "eslint-plugin-react-hooks": "^4.6.0",
32
34
  "eslint-plugin-react-refresh": "^0.4.0",
35
+ postcss: "^8.5.6",
36
+ tailwindcss: "^4.1.18",
33
37
  typescript: "^5.7.2",
34
38
  vite: "^7.3.1",
35
39
  },
@@ -84,18 +88,16 @@ function getTemplateFiles(projectName) {
84
88
  path: "vite.config.ts",
85
89
  content: `import { defineConfig } from "vite";
86
90
  import react from "@vitejs/plugin-react";
91
+ import { resolve } from "path";
87
92
 
88
93
  export default defineConfig({
94
+ base: "./",
89
95
  plugins: [react()],
90
96
  build: {
91
97
  rollupOptions: {
92
98
  input: {
93
- learner: "html/learner.html",
94
- setup: "html/setup.html",
95
- },
96
- output: {
97
- entryFileNames: "[name].js",
98
- dir: "dist",
99
+ learner: resolve(__dirname, "learner.html"),
100
+ setup: resolve(__dirname, "setup.html"),
99
101
  },
100
102
  },
101
103
  },
@@ -163,7 +165,8 @@ pnpm build
163
165
 
164
166
  - \`src/components/\` - React components (LearnerView, SetupView)
165
167
  - \`src/entries/\` - Widget entry points
166
- - \`html/\` - HTML template files
168
+ - \`learner.html\` - Learner view HTML template
169
+ - \`setup.html\` - Setup/admin view HTML template
167
170
  - \`src/types.ts\` - Widget configuration types
168
171
  - \`src/data.ts\` - Default configuration
169
172
 
@@ -184,14 +187,20 @@ The parent window communicates via \`postMessage\` protocol.
184
187
  // src/index.css
185
188
  {
186
189
  path: "src/index.css",
187
- content: `* {
190
+ content: `@import "tailwindcss";
191
+ @import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600&display=swap");
192
+
193
+ * {
188
194
  margin: 0;
189
195
  padding: 0;
190
196
  box-sizing: border-box;
191
197
  }
192
198
 
199
+ html {
200
+ font-family: "Open Sans", system-ui, -apple-system, sans-serif;
201
+ }
202
+
193
203
  body {
194
- font-family: system-ui, -apple-system, sans-serif;
195
204
  line-height: 1.5;
196
205
  }
197
206
  `,
@@ -260,6 +269,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
260
269
  {
261
270
  path: "src/components/LearnerView.tsx",
262
271
  content: `import React from "react";
272
+ import { Button } from "@openlearning/widget-framework";
263
273
  import type { LearnerViewProps } from "@openlearning/widget-framework";
264
274
  import type { WidgetConfig } from "../types";
265
275
 
@@ -276,10 +286,10 @@ export const LearnerView: React.FC<LearnerViewProps<WidgetConfig>> = ({
276
286
  <h1>Learner View</h1>
277
287
  <p>Implement your learner interface here.</p>
278
288
 
279
- <div style={{ marginTop: "1rem" }}>
280
- <button onClick={() => onComplete?.()}>Complete</button>
281
- <button onClick={() => onShare?.([])}>Share</button>
282
- <button onClick={() => onResize?.(400)}>Resize</button>
289
+ <div style={{ marginTop: "1rem", display: "flex", gap: "0.5rem" }}>
290
+ <Button variant="round-filled" onClick={() => onComplete?.()}>Complete</Button>
291
+ <Button variant="round-tonal" onClick={() => onShare?.([])}>Share</Button>
292
+ <Button variant="round-quiet" onClick={() => onResize?.(400)}>Resize</Button>
283
293
  </div>
284
294
  </div>
285
295
  );
@@ -290,6 +300,7 @@ export const LearnerView: React.FC<LearnerViewProps<WidgetConfig>> = ({
290
300
  {
291
301
  path: "src/components/SetupView.tsx",
292
302
  content: `import React from "react";
303
+ import { Button } from "@openlearning/widget-framework";
293
304
  import type { SetupViewProps } from "@openlearning/widget-framework";
294
305
  import type { WidgetConfig } from "../types";
295
306
 
@@ -304,9 +315,9 @@ export const SetupView: React.FC<SetupViewProps<WidgetConfig>> = ({
304
315
  <h1>Setup View</h1>
305
316
  <p>Implement your setup/configuration interface here.</p>
306
317
 
307
- <div style={{ marginTop: "1rem" }}>
308
- <button onClick={() => onChange?.(config)}>Save Configuration</button>
309
- <button onClick={() => onResize?.(400)}>Resize</button>
318
+ <div style={{ marginTop: "1rem", display: "flex", gap: "0.5rem" }}>
319
+ <Button variant="round-filled" onClick={() => onChange?.(config)}>Save Configuration</Button>
320
+ <Button variant="round-tonal" onClick={() => onResize?.(400)}>Resize</Button>
310
321
  </div>
311
322
  </div>
312
323
  );
@@ -317,6 +328,8 @@ export const SetupView: React.FC<SetupViewProps<WidgetConfig>> = ({
317
328
  {
318
329
  path: "src/entries/learner.tsx",
319
330
  content: `import { createLearnerEntry } from "@openlearning/widget-framework";
331
+ // Import Button CSS if you use the Button component
332
+ import "@openlearning/widget-framework/dist/styles/button.css";
320
333
  import { LearnerView } from "../components/LearnerView";
321
334
  import "../index.css";
322
335
 
@@ -327,6 +340,8 @@ createLearnerEntry(LearnerView);
327
340
  {
328
341
  path: "src/entries/setup.tsx",
329
342
  content: `import { createSetupEntry } from "@openlearning/widget-framework";
343
+ // Import Button CSS if you use the Button component
344
+ import "@openlearning/widget-framework/dist/styles/button.css";
330
345
  import { SetupView } from "../components/SetupView";
331
346
  import { DEFAULT_CONFIG } from "../data";
332
347
  import "../index.css";
@@ -341,7 +356,6 @@ createSetupEntry(SetupView, DEFAULT_CONFIG);
341
356
  <html lang="en">
342
357
  <head>
343
358
  <meta charset="UTF-8" />
344
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
345
359
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
346
360
  <title>${projectName}</title>
347
361
  </head>
@@ -352,9 +366,9 @@ createSetupEntry(SetupView, DEFAULT_CONFIG);
352
366
  </html>
353
367
  `,
354
368
  },
355
- // html/learner.html
369
+ // learner.html
356
370
  {
357
- path: "html/learner.html",
371
+ path: "learner.html",
358
372
  content: `<!doctype html>
359
373
  <html lang="en">
360
374
  <head>
@@ -364,14 +378,14 @@ createSetupEntry(SetupView, DEFAULT_CONFIG);
364
378
  </head>
365
379
  <body>
366
380
  <div id="root"></div>
367
- <script type="module" src="../src/entries/learner.tsx"></script>
381
+ <script type="module" src="./src/entries/learner.tsx"></script>
368
382
  </body>
369
383
  </html>
370
384
  `,
371
385
  },
372
- // html/setup.html
386
+ // setup.html
373
387
  {
374
- path: "html/setup.html",
388
+ path: "setup.html",
375
389
  content: `<!doctype html>
376
390
  <html lang="en">
377
391
  <head>
@@ -381,9 +395,38 @@ createSetupEntry(SetupView, DEFAULT_CONFIG);
381
395
  </head>
382
396
  <body>
383
397
  <div id="root"></div>
384
- <script type="module" src="../src/entries/setup.tsx"></script>
398
+ <script type="module" src="./src/entries/setup.tsx"></script>
385
399
  </body>
386
400
  </html>
401
+ `,
402
+ },
403
+ // tailwind.config.js
404
+ {
405
+ path: "tailwind.config.js",
406
+ content: `/** @type {import('tailwindcss').Config} */
407
+ export default {
408
+ content: [
409
+ "./index.html",
410
+ "./learner.html",
411
+ "./setup.html",
412
+ "./src/**/*.{js,ts,jsx,tsx}",
413
+ ],
414
+ theme: {
415
+ extend: {},
416
+ },
417
+ plugins: [],
418
+ };
419
+ `,
420
+ },
421
+ // postcss.config.js
422
+ {
423
+ path: "postcss.config.js",
424
+ content: `export default {
425
+ plugins: {
426
+ "@tailwindcss/postcss": {},
427
+ autoprefixer: {},
428
+ },
429
+ };
387
430
  `,
388
431
  },
389
432
  // eslint.config.js
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,16 +1,11 @@
1
1
  {
2
2
  "name": "@openlearning/create-widget",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
- "description": "Scaffold a new OpenLearning widget project with all necessary boilerplate",
5
+ "description": "Create a new OpenLearning widget project with all necessary boilerplate",
6
6
  "license": "MIT",
7
7
  "author": "OpenLearning",
8
- "homepage": "https://github.com/openlearning/widgets#readme",
9
- "repository": {
10
- "type": "git",
11
- "url": "https://github.com/openlearning/widgets.git",
12
- "directory": "libs/create-widget"
13
- },
8
+ "homepage": "https://widgets.openlearning.com",
14
9
  "bin": {
15
10
  "create-widget": "./bin/cli.js"
16
11
  },
@@ -19,6 +14,14 @@
19
14
  "import": "./dist/index.js"
20
15
  }
21
16
  },
17
+ "files": [
18
+ "bin",
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsc",
23
+ "dev": "tsc -w"
24
+ },
22
25
  "keywords": [
23
26
  "widget",
24
27
  "scaffold",
@@ -28,9 +31,5 @@
28
31
  "devDependencies": {
29
32
  "@types/node": "^20.0.0",
30
33
  "typescript": "^5.7.2"
31
- },
32
- "scripts": {
33
- "build": "tsc",
34
- "dev": "tsc -w"
35
34
  }
36
- }
35
+ }
package/src/index.ts DELETED
@@ -1,520 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { fileURLToPath } from "url";
4
-
5
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
-
7
- interface TemplateFile {
8
- path: string;
9
- content: string;
10
- }
11
-
12
- function getTemplateFiles(projectName: string): TemplateFile[] {
13
- const camelCase = projectName.replace(/-./g, (x) => x[1].toUpperCase());
14
-
15
- return [
16
- // package.json
17
- {
18
- path: "package.json",
19
- content: JSON.stringify(
20
- {
21
- name: projectName,
22
- version: "0.0.0",
23
- type: "module",
24
- scripts: {
25
- dev: "vite",
26
- build: "tsc -b && vite build",
27
- preview: "vite preview",
28
- },
29
- dependencies: {
30
- "@openlearning/widget-framework": "workspace:*",
31
- react: "^19.2.0",
32
- "react-dom": "^19.2.0",
33
- },
34
- devDependencies: {
35
- "@types/node": "^20.0.0",
36
- "@types/react": "^19.0.0",
37
- "@types/react-dom": "^19.0.0",
38
- "@vitejs/plugin-react": "^4.0.0",
39
- eslint: "^8.0.0",
40
- "eslint-plugin-react-hooks": "^4.6.0",
41
- "eslint-plugin-react-refresh": "^0.4.0",
42
- typescript: "^5.7.2",
43
- vite: "^7.3.1",
44
- },
45
- },
46
- null,
47
- 2
48
- ),
49
- },
50
-
51
- // tsconfig.json
52
- {
53
- path: "tsconfig.json",
54
- content: JSON.stringify(
55
- {
56
- compilerOptions: {
57
- target: "ES2020",
58
- useDefineForClassFields: true,
59
- lib: ["ES2020", "DOM", "DOM.Iterable"],
60
- module: "ES2020",
61
- skipLibCheck: true,
62
- esModuleInterop: true,
63
- jsx: "react-jsx",
64
- noEmit: true,
65
- },
66
- include: ["src"],
67
- references: [{ path: "./tsconfig.app.json" }],
68
- },
69
- null,
70
- 2
71
- ),
72
- },
73
-
74
- // tsconfig.app.json
75
- {
76
- path: "tsconfig.app.json",
77
- content: JSON.stringify(
78
- {
79
- extends: "./tsconfig.json",
80
- compilerOptions: {
81
- outDir: "./dist",
82
- rootDir: "./src",
83
- },
84
- include: ["src"],
85
- },
86
- null,
87
- 2
88
- ),
89
- },
90
-
91
- // tsconfig.node.json
92
- {
93
- path: "tsconfig.node.json",
94
- content: JSON.stringify(
95
- {
96
- compilerOptions: {
97
- composite: true,
98
- skipLibCheck: true,
99
- module: "ES2020",
100
- moduleResolution: "bundler",
101
- allowSyntheticDefaultImports: true,
102
- },
103
- include: ["vite.config.ts"],
104
- },
105
- null,
106
- 2
107
- ),
108
- },
109
-
110
- // vite.config.ts
111
- {
112
- path: "vite.config.ts",
113
- content: `import { defineConfig } from "vite";
114
- import react from "@vitejs/plugin-react";
115
-
116
- export default defineConfig({
117
- plugins: [react()],
118
- build: {
119
- rollupOptions: {
120
- input: {
121
- learner: "html/learner.html",
122
- setup: "html/setup.html",
123
- },
124
- output: {
125
- entryFileNames: "[name].js",
126
- dir: "dist",
127
- },
128
- },
129
- },
130
- });
131
- `,
132
- },
133
-
134
- // .prettierrc
135
- {
136
- path: ".prettierrc",
137
- content: JSON.stringify({
138
- semi: true,
139
- trailingComma: "es5",
140
- singleQuote: false,
141
- }),
142
- },
143
-
144
- // .gitignore
145
- {
146
- path: ".gitignore",
147
- content: `# Logs
148
- logs
149
- *.log
150
- npm-debug.log*
151
-
152
- # Dependencies
153
- node_modules
154
- dist
155
-
156
- # IDE
157
- .vscode
158
- .idea
159
- *.swp
160
- *.swo
161
-
162
- # Environment
163
- .env
164
- .env.local
165
- `,
166
- },
167
-
168
- // README.md
169
- {
170
- path: "README.md",
171
- content: `# ${projectName}
172
-
173
- A widget built with the OpenLearning widget framework.
174
-
175
- ## Setup
176
-
177
- \`\`\`bash
178
- pnpm install
179
- \`\`\`
180
-
181
- ## Development
182
-
183
- \`\`\`bash
184
- pnpm dev
185
- \`\`\`
186
-
187
- ## Build
188
-
189
- \`\`\`bash
190
- pnpm build
191
- \`\`\`
192
-
193
- ## Project Structure
194
-
195
- - \`src/components/\` - React components (LearnerView, SetupView)
196
- - \`src/entries/\` - Widget entry points
197
- - \`html/\` - HTML template files
198
- - \`src/types.ts\` - Widget configuration types
199
- - \`src/data.ts\` - Default configuration
200
-
201
- ## Adding the Widget to a Parent
202
-
203
- The widget exposes two HTML endpoints:
204
- - \`/learner.html\` - Learner view
205
- - \`/setup.html\` - Setup/admin view
206
-
207
- The parent window communicates via \`postMessage\` protocol.
208
- `,
209
- },
210
-
211
- // public/.gitkeep
212
- {
213
- path: "public/.gitkeep",
214
- content: "",
215
- },
216
-
217
- // src/index.css
218
- {
219
- path: "src/index.css",
220
- content: `* {
221
- margin: 0;
222
- padding: 0;
223
- box-sizing: border-box;
224
- }
225
-
226
- body {
227
- font-family: system-ui, -apple-system, sans-serif;
228
- line-height: 1.5;
229
- }
230
- `,
231
- },
232
-
233
- // src/types.ts
234
- {
235
- path: "src/types.ts",
236
- content: `import {
237
- LearnerViewProps,
238
- SetupViewProps,
239
- JSONValue,
240
- Attachment,
241
- } from "@openlearning/widget-framework";
242
-
243
- // Define your widget's configuration structure
244
- export type WidgetConfig = JSONValue;
245
-
246
- // Export framework types for use in your components
247
- export type { LearnerViewProps, SetupViewProps, JSONValue, Attachment };
248
- `,
249
- },
250
-
251
- // src/data.ts
252
- {
253
- path: "src/data.ts",
254
- content: `import { WidgetConfig } from "./types";
255
-
256
- // Default configuration for this widget
257
- export const DEFAULT_CONFIG: WidgetConfig = {
258
- // Add your default configuration here
259
- };
260
- `,
261
- },
262
-
263
- // src/DevApp.tsx
264
- {
265
- path: "src/DevApp.tsx",
266
- content: `import { DevApp as FrameworkDevApp } from "@openlearning/widget-framework";
267
- import { LearnerView } from "./components/LearnerView";
268
- import { SetupView } from "./components/SetupView";
269
- import { DEFAULT_CONFIG } from "./data";
270
-
271
- export const DevApp = () => (
272
- <FrameworkDevApp
273
- LearnerViewComponent={LearnerView}
274
- SetupViewComponent={SetupView}
275
- defaultConfig={DEFAULT_CONFIG}
276
- />
277
- );
278
- `,
279
- },
280
-
281
- // src/devMain.tsx
282
- {
283
- path: "src/devMain.tsx",
284
- content: `import React from "react";
285
- import ReactDOM from "react-dom/client";
286
- import { DevApp } from "./DevApp";
287
- import "./index.css";
288
-
289
- ReactDOM.createRoot(document.getElementById("root")!).render(
290
- <React.StrictMode>
291
- <DevApp />
292
- </React.StrictMode>
293
- );
294
- `,
295
- },
296
-
297
- // src/components/LearnerView.tsx
298
- {
299
- path: "src/components/LearnerView.tsx",
300
- content: `import React from "react";
301
- import type { LearnerViewProps } from "@openlearning/widget-framework";
302
- import type { WidgetConfig } from "../types";
303
-
304
- export const LearnerView: React.FC<LearnerViewProps<WidgetConfig>> = ({
305
- config,
306
- onComplete,
307
- onShare,
308
- onResize,
309
- onSave,
310
- onReinit,
311
- }) => {
312
- return (
313
- <div style={{ padding: "1rem" }}>
314
- <h1>Learner View</h1>
315
- <p>Implement your learner interface here.</p>
316
-
317
- <div style={{ marginTop: "1rem" }}>
318
- <button onClick={() => onComplete?.()}>Complete</button>
319
- <button onClick={() => onShare?.([])}>Share</button>
320
- <button onClick={() => onResize?.(400)}>Resize</button>
321
- </div>
322
- </div>
323
- );
324
- };
325
- `,
326
- },
327
-
328
- // src/components/SetupView.tsx
329
- {
330
- path: "src/components/SetupView.tsx",
331
- content: `import React from "react";
332
- import type { SetupViewProps } from "@openlearning/widget-framework";
333
- import type { WidgetConfig } from "../types";
334
-
335
- export const SetupView: React.FC<SetupViewProps<WidgetConfig>> = ({
336
- config,
337
- onChange,
338
- onResize,
339
- onReinit,
340
- }) => {
341
- return (
342
- <div style={{ padding: "1rem" }}>
343
- <h1>Setup View</h1>
344
- <p>Implement your setup/configuration interface here.</p>
345
-
346
- <div style={{ marginTop: "1rem" }}>
347
- <button onClick={() => onChange?.(config)}>Save Configuration</button>
348
- <button onClick={() => onResize?.(400)}>Resize</button>
349
- </div>
350
- </div>
351
- );
352
- };
353
- `,
354
- },
355
-
356
- // src/entries/learner.tsx
357
- {
358
- path: "src/entries/learner.tsx",
359
- content: `import { createLearnerEntry } from "@openlearning/widget-framework";
360
- import { LearnerView } from "../components/LearnerView";
361
- import "../index.css";
362
-
363
- createLearnerEntry(LearnerView);
364
- `,
365
- },
366
-
367
- // src/entries/setup.tsx
368
- {
369
- path: "src/entries/setup.tsx",
370
- content: `import { createSetupEntry } from "@openlearning/widget-framework";
371
- import { SetupView } from "../components/SetupView";
372
- import { DEFAULT_CONFIG } from "../data";
373
- import "../index.css";
374
-
375
- createSetupEntry(SetupView, DEFAULT_CONFIG);
376
- `,
377
- },
378
-
379
- // index.html (dev server)
380
- {
381
- path: "index.html",
382
- content: `<!doctype html>
383
- <html lang="en">
384
- <head>
385
- <meta charset="UTF-8" />
386
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
387
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
388
- <title>${projectName}</title>
389
- </head>
390
- <body>
391
- <div id="root"></div>
392
- <script type="module" src="/src/devMain.tsx"></script>
393
- </body>
394
- </html>
395
- `,
396
- },
397
-
398
- // html/learner.html
399
- {
400
- path: "html/learner.html",
401
- content: `<!doctype html>
402
- <html lang="en">
403
- <head>
404
- <meta charset="UTF-8" />
405
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
406
- <title>Learner</title>
407
- </head>
408
- <body>
409
- <div id="root"></div>
410
- <script type="module" src="../src/entries/learner.tsx"></script>
411
- </body>
412
- </html>
413
- `,
414
- },
415
-
416
- // html/setup.html
417
- {
418
- path: "html/setup.html",
419
- content: `<!doctype html>
420
- <html lang="en">
421
- <head>
422
- <meta charset="UTF-8" />
423
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
424
- <title>Setup</title>
425
- </head>
426
- <body>
427
- <div id="root"></div>
428
- <script type="module" src="../src/entries/setup.tsx"></script>
429
- </body>
430
- </html>
431
- `,
432
- },
433
-
434
- // eslint.config.js
435
- {
436
- path: "eslint.config.js",
437
- content: `import js from "@eslint/js";
438
- import globals from "globals";
439
- import react from "eslint-plugin-react/configs/recommended.js";
440
- import reactHooks from "eslint-plugin-react-hooks";
441
- import reactRefresh from "eslint-plugin-react-refresh";
442
-
443
- export default [
444
- { ignores: ["dist"] },
445
- {
446
- files: ["**/*.{js,jsx,ts,tsx}"],
447
- languageOptions: {
448
- ecmaVersion: 2020,
449
- globals: globals.browser,
450
- parserOptions: {
451
- ecmaVersion: "latest",
452
- ecmaFeatures: { jsx: true },
453
- sourceType: "module",
454
- },
455
- },
456
- settings: { react: { version: "18.3" } },
457
- plugins: {
458
- react,
459
- "react-hooks": reactHooks,
460
- "react-refresh": reactRefresh,
461
- },
462
- rules: {
463
- ...js.configs.recommended.rules,
464
- ...react.rules,
465
- ...reactHooks.configs.recommended.rules,
466
- "react/react-in-jsx-scope": "off",
467
- "react-refresh/only-export-components": [
468
- "warn",
469
- { allowConstantExport: true },
470
- ],
471
- },
472
- },
473
- ];
474
- `,
475
- },
476
- ];
477
- }
478
-
479
- export async function createWidget(projectName: string): Promise<void> {
480
- const projectDir = path.resolve(projectName);
481
-
482
- // Check if directory already exists
483
- if (fs.existsSync(projectDir)) {
484
- throw new Error(`Directory '${projectName}' already exists`);
485
- }
486
-
487
- console.log(`Creating widget project: ${projectName}`);
488
-
489
- // Create the project directory
490
- fs.mkdirSync(projectDir, { recursive: true });
491
-
492
- // Create all template files
493
- const files = getTemplateFiles(projectName);
494
-
495
- for (const file of files) {
496
- const filePath = path.join(projectDir, file.path);
497
- const dirname = path.dirname(filePath);
498
-
499
- // Create directories if they don't exist
500
- fs.mkdirSync(dirname, { recursive: true });
501
-
502
- // Write file
503
- fs.writeFileSync(filePath, file.content);
504
- console.log(` created ${file.path}`);
505
- }
506
-
507
- const nextSteps = `
508
- ✨ Widget project created!
509
-
510
- Next steps:
511
- cd ${projectName}
512
- pnpm install
513
- pnpm dev
514
-
515
- The widget is ready to customize. Edit components in:
516
- - src/components/LearnerView.tsx
517
- - src/components/SetupView.tsx
518
- `;
519
- console.log(nextSteps);
520
- }
package/tsconfig.json DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "lib": ["ES2020"],
5
- "module": "ES2020",
6
- "moduleResolution": "bundler",
7
- "outDir": "./dist",
8
- "rootDir": "./src",
9
- "declaration": true,
10
- "declarationMap": true,
11
- "sourceMap": true,
12
- "strict": true,
13
- "skipLibCheck": true,
14
- "esModuleInterop": true,
15
- "resolveJsonModule": true,
16
- "types": ["node"]
17
- },
18
- "include": ["src/**/*"],
19
- "exclude": ["node_modules", "dist"]
20
- }