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