@learnpack/learnpack 5.0.98 → 5.0.106
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 +13 -13
- package/lib/commands/serve.js +81 -7
- package/lib/creatorDist/assets/{index-ldEC0yWM.css → index-Cvdi97GX.css} +119 -6
- package/lib/creatorDist/assets/{index-DayC-cyC.js → index-Sn-039yT.js} +45271 -37550
- package/lib/creatorDist/index.html +2 -2
- package/oclif.manifest.json +1 -1
- package/package.json +6 -2
- package/src/commands/serve.ts +126 -29
- package/src/creator/package-lock.json +60 -0
- package/src/creator/package.json +2 -0
- package/src/creator/src/App.tsx +32 -45
- package/src/creator/src/assets/svgs.tsx +14 -0
- package/src/creator/src/components/LinkUploader.tsx +109 -0
- package/src/creator/src/components/PreviewGenerator.tsx +95 -0
- package/src/creator/src/components/Source.tsx +68 -0
- package/src/creator/src/components/syllabus/Sidebar.tsx +35 -10
- package/src/creator/src/components/syllabus/SyllabusEditor.tsx +17 -7
- package/src/creator/src/index.css +4 -0
- package/src/creator/src/main.tsx +2 -0
- package/src/creator/src/utils/creatorUtils.ts +1 -0
- package/src/creator/src/utils/store.ts +4 -1
- package/src/creatorDist/assets/{index-ldEC0yWM.css → index-Cvdi97GX.css} +119 -6
- package/src/creatorDist/assets/{index-DayC-cyC.js → index-Sn-039yT.js} +45271 -37550
- package/src/creatorDist/index.html +2 -2
- package/src/utils/convertCreds.js +4 -0
- package/src/utils/creds.json +0 -13
@@ -10,8 +10,8 @@
|
|
10
10
|
/>
|
11
11
|
|
12
12
|
<title>Learnpack Creator: Craft tutorials in seconds!</title>
|
13
|
-
<script type="module" crossorigin src="/creator/assets/index-
|
14
|
-
<link rel="stylesheet" crossorigin href="/creator/assets/index-
|
13
|
+
<script type="module" crossorigin src="/creator/assets/index-Sn-039yT.js"></script>
|
14
|
+
<link rel="stylesheet" crossorigin href="/creator/assets/index-Cvdi97GX.css">
|
15
15
|
</head>
|
16
16
|
<body>
|
17
17
|
<div id="root"></div>
|
package/oclif.manifest.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":"5.0.
|
1
|
+
{"version":"5.0.106","commands":{"audit":{"id":"audit","description":"learnpack audit is the command in charge of creating an auditory of the repository\n...\nlearnpack audit checks for the following information in a repository:\n 1. The configuration object has slug, repository and description. (Error)\n 2. The command learnpack clean has been run. (Error)\n 3. If a markdown or test file doesn't have any content. (Error)\n 4. The links are accessing to valid servers. (Error)\n 5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)\n 6. The external images are working (If they are pointing to a valid server). (Error)\n 7. The exercises directory names are valid. (Error)\n 8. If an exercise doesn't have a README file. (Error)\n 9. The exercises array (Of the config file) has content. (Error)\n 10. The exercses have the same translations. (Warning)\n 11. The .gitignore file exists. (Warning)\n 12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false}},"args":[]},"breakToken":{"id":"breakToken","description":"Break the token","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"clean":{"id":"clean","description":"Clean the configuration object\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[]},"download":{"id":"download","description":"Describe the command here\n...\nExtra documentation goes here\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"init":{"id":"init","description":"Create a new learning package: Book, Tutorial or Exercise","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"login":{"id":"login","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"logout":{"id":"logout","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"publish":{"id":"publish","description":"Builds the project by copying necessary files and directories into a zip file","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"serve":{"id":"serve","description":"Runs a small server to build tutorials","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"start":{"id":"start","description":"Runs a small server with all the exercise instructions","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"disableGrading":{"name":"disableGrading","type":"boolean","char":"D","description":"disble grading functionality","allowNo":false},"watch":{"name":"watch","type":"boolean","char":"w","description":"Watch for file changes","allowNo":false},"editor":{"name":"editor","type":"option","char":"e","description":"[preview, extension]","options":["extension","preview"]},"version":{"name":"version","type":"option","char":"v","description":"E.g: 1.0.1"},"grading":{"name":"grading","type":"option","char":"g","description":"[isolated, incremental]","options":["isolated","incremental"]},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"test":{"id":"test","description":"Test exercises","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[{"name":"exerciseSlug","description":"The name of the exercise to test","required":false,"hidden":false}]},"translate":{"id":"translate","description":"List all the lessons, the user is able of select many of them to translate to the given languages","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[]}}}
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@learnpack/learnpack",
|
3
3
|
"description": "Seamlessly build, sell and/or take interactive & auto-graded tutorials, start learning now or build a new tutorial to your audience.",
|
4
|
-
"version": "5.0.
|
4
|
+
"version": "5.0.106",
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
6
6
|
"contributors": [
|
7
7
|
{
|
@@ -28,6 +28,7 @@
|
|
28
28
|
"@oclif/plugin-plugins": "^1.8.0",
|
29
29
|
"@oclif/plugin-warn-if-update-available": "^1.7.0",
|
30
30
|
"@types/archiver": "^6.0.2",
|
31
|
+
"@types/html-to-text": "^9.0.4",
|
31
32
|
"archiver": "^7.0.1",
|
32
33
|
"axios": "^1.7.7",
|
33
34
|
"body-parser": "^1.19.0",
|
@@ -45,6 +46,7 @@
|
|
45
46
|
"express": "^4.17.1",
|
46
47
|
"form-data": "^4.0.2",
|
47
48
|
"front-matter": "^4.0.2",
|
49
|
+
"html-to-text": "^9.0.5",
|
48
50
|
"js-yaml": "^4.1.0",
|
49
51
|
"markdown-it": "^14.1.0",
|
50
52
|
"mkdirp": "^3.0.1",
|
@@ -62,7 +64,9 @@
|
|
62
64
|
"text-readability": "^1.1.0",
|
63
65
|
"tslib": "^1",
|
64
66
|
"validator": "^13.1.1",
|
65
|
-
"xxhashjs": "^0.2.2"
|
67
|
+
"xxhashjs": "^0.2.2",
|
68
|
+
"youtube-transcript": "^1.2.1",
|
69
|
+
"ytdl-core": "^4.11.5"
|
66
70
|
},
|
67
71
|
"devDependencies": {
|
68
72
|
"@oclif/dev-cli": "^1.22.2",
|
package/src/commands/serve.ts
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
import { flags } from "@oclif/command"
|
2
|
+
// import * as ytdl from "ytdl-core"
|
3
|
+
import { YoutubeTranscript } from "youtube-transcript"
|
2
4
|
import * as express from "express"
|
3
5
|
import * as cors from "cors"
|
4
6
|
import * as path from "path"
|
5
7
|
import * as os from "os"
|
6
8
|
import * as archiver from "archiver"
|
7
9
|
import * as mkdirp from "mkdirp"
|
10
|
+
import { convert } from "html-to-text"
|
8
11
|
import * as rimraf from "rimraf"
|
9
12
|
import SessionCommand from "../utils/SessionCommand"
|
10
13
|
import { Storage } from "@google-cloud/storage"
|
@@ -23,6 +26,26 @@ dotenv.config()
|
|
23
26
|
|
24
27
|
const frontMatter = require("front-matter")
|
25
28
|
|
29
|
+
const fixPreviewUrl = (slug: string, previewUrl: string) => {
|
30
|
+
if (!previewUrl) {
|
31
|
+
return null
|
32
|
+
}
|
33
|
+
|
34
|
+
if (previewUrl.startsWith("http")) {
|
35
|
+
return previewUrl
|
36
|
+
}
|
37
|
+
|
38
|
+
const expectedUrl = `https://${slug}.learn-pack.com/preview.png`
|
39
|
+
console.log("EXPECTED URL", expectedUrl)
|
40
|
+
return expectedUrl
|
41
|
+
}
|
42
|
+
|
43
|
+
const getTitleFromHTML = (html: string) => {
|
44
|
+
const titleRegex = /<title>(.*?)<\/title>/
|
45
|
+
const titleMatch = html.match(titleRegex)
|
46
|
+
return titleMatch ? titleMatch[1] : null
|
47
|
+
}
|
48
|
+
|
26
49
|
export default class ServeCommand extends SessionCommand {
|
27
50
|
static description = "Runs a small server to build tutorials"
|
28
51
|
|
@@ -126,39 +149,43 @@ export default class ServeCommand extends SessionCommand {
|
|
126
149
|
stream.end(buffer)
|
127
150
|
})
|
128
151
|
|
129
|
-
app.post(
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
}
|
136
|
-
|
137
|
-
try {
|
138
|
-
const response = await fetch(image_url)
|
139
|
-
if (!response.ok) {
|
152
|
+
app.post(
|
153
|
+
"/upload-image",
|
154
|
+
express.json({ limit: "20mb" }),
|
155
|
+
async (req, res) => {
|
156
|
+
const { image_url, destination } = req.body
|
157
|
+
if (!image_url || !destination) {
|
140
158
|
return res
|
141
159
|
.status(400)
|
142
|
-
.json({ error:
|
160
|
+
.json({ error: "image_url and destination are required" })
|
143
161
|
}
|
144
162
|
|
145
|
-
|
146
|
-
response
|
147
|
-
|
163
|
+
try {
|
164
|
+
const response = await fetch(image_url)
|
165
|
+
if (!response.ok) {
|
166
|
+
return res.status(400).json({
|
167
|
+
error: `Failed to download image: ${response.statusText}`,
|
168
|
+
})
|
169
|
+
}
|
148
170
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
contentType,
|
153
|
-
})
|
171
|
+
const contentType =
|
172
|
+
response.headers.get("content-type") || "application/octet-stream"
|
173
|
+
const buffer = await response.arrayBuffer()
|
154
174
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
175
|
+
const file = bucket.file(destination)
|
176
|
+
await file.save(Buffer.from(buffer), {
|
177
|
+
resumable: false,
|
178
|
+
contentType,
|
179
|
+
})
|
180
|
+
|
181
|
+
console.log(`✅ Image uploaded to ${file.name}`)
|
182
|
+
res.json({ message: "Image uploaded successfully", path: file.name })
|
183
|
+
} catch (error) {
|
184
|
+
console.error("❌ upload-image error:", error)
|
185
|
+
res.status(500).json({ error: (error as Error).message })
|
186
|
+
}
|
160
187
|
}
|
161
|
-
|
188
|
+
)
|
162
189
|
|
163
190
|
app.get("/create", (req, res) => {
|
164
191
|
console.log("GET /create")
|
@@ -403,7 +430,6 @@ export default class ServeCommand extends SessionCommand {
|
|
403
430
|
|
404
431
|
app.post("/actions/publish/:slug", async (req, res) => {
|
405
432
|
try {
|
406
|
-
// 1) Extraer token y body
|
407
433
|
const { slug } = req.params
|
408
434
|
const rigoToken = req.header("x-rigo-token")
|
409
435
|
const bcToken = req.header("x-breathecode-token")
|
@@ -453,14 +479,13 @@ export default class ServeCommand extends SessionCommand {
|
|
453
479
|
.replace(/{{description}}/g, config.description.us)
|
454
480
|
.replace(
|
455
481
|
/{{preview}}/g,
|
456
|
-
config.preview ||
|
482
|
+
fixPreviewUrl(slug, config.preview) ||
|
457
483
|
"https://raw.githubusercontent.com/learnpack/ide/master/public/learnpack.svg"
|
458
484
|
)
|
459
485
|
.replace(/{{slug}}/g, slug)
|
460
486
|
.replace(/{{duration}}/g, minutesToISO8601Duration(config.duration))
|
461
487
|
fs.writeFileSync(path.join(buildRoot, "index.html"), idxHtml)
|
462
488
|
|
463
|
-
// 6) Inyectar placeholders en manifest.webmanifest
|
464
489
|
const mfTpl = fs.readFileSync(
|
465
490
|
path.join(uiSrc, "manifest.webmanifest"),
|
466
491
|
"utf-8"
|
@@ -542,6 +567,54 @@ export default class ServeCommand extends SessionCommand {
|
|
542
567
|
}
|
543
568
|
})
|
544
569
|
|
570
|
+
const YT_REGEX =
|
571
|
+
/(?:youtube\.com\/watch\?v=|youtu\.be\/)([\w-]{11})/
|
572
|
+
|
573
|
+
app.get("/actions/fetch/:link", async (req, res) => {
|
574
|
+
const { link } = req.params
|
575
|
+
try {
|
576
|
+
// 1) Decode the URL
|
577
|
+
const decoded = Buffer.from(link, "base64url").toString("utf-8")
|
578
|
+
const ytMatch = decoded.match(YT_REGEX)
|
579
|
+
|
580
|
+
if (ytMatch) {
|
581
|
+
const videoId = ytMatch[1]
|
582
|
+
// fetch metadata
|
583
|
+
const items = await YoutubeTranscript.fetchTranscript(videoId)
|
584
|
+
const transcript = items.map(i => i.text).join(" ")
|
585
|
+
|
586
|
+
const { data: meta } = await axios.get(
|
587
|
+
"https://www.youtube.com/oembed",
|
588
|
+
{
|
589
|
+
params: { url: decoded, format: "json" },
|
590
|
+
}
|
591
|
+
)
|
592
|
+
|
593
|
+
return res.json({
|
594
|
+
url: decoded,
|
595
|
+
title: meta.title,
|
596
|
+
author: meta.author_name,
|
597
|
+
thumbnail: meta.thumbnail_url,
|
598
|
+
transcript,
|
599
|
+
})
|
600
|
+
}
|
601
|
+
|
602
|
+
const response = await axios.get(decoded, { responseType: "text" })
|
603
|
+
const html = response.data as string
|
604
|
+
const title = getTitleFromHTML(html)
|
605
|
+
console.log("TITLE", title)
|
606
|
+
|
607
|
+
const text = convert(html)
|
608
|
+
return res.json({
|
609
|
+
url: decoded,
|
610
|
+
text,
|
611
|
+
title,
|
612
|
+
})
|
613
|
+
} catch (error: any) {
|
614
|
+
console.error("❌ /actions/fetch error:", error.message || error)
|
615
|
+
res.status(500).json({ error: error.message || "Failed to fetch link" })
|
616
|
+
}
|
617
|
+
})
|
545
618
|
app.delete("/packages/:slug", async (req, res) => {
|
546
619
|
console.log("DELETE /packages/:slug")
|
547
620
|
|
@@ -580,6 +653,30 @@ export default class ServeCommand extends SessionCommand {
|
|
580
653
|
}
|
581
654
|
})
|
582
655
|
|
656
|
+
app.get("/proxy", async (req, res) => {
|
657
|
+
const { url } = req.query
|
658
|
+
|
659
|
+
if (!url) {
|
660
|
+
return res.status(400).json({ error: "URL is required" })
|
661
|
+
}
|
662
|
+
|
663
|
+
try {
|
664
|
+
const decodedUrl = Buffer.from(url as string, "base64url").toString(
|
665
|
+
"utf-8"
|
666
|
+
)
|
667
|
+
|
668
|
+
const response = await axios.get(decodedUrl, {
|
669
|
+
responseType: "arraybuffer",
|
670
|
+
})
|
671
|
+
|
672
|
+
res.set(response.headers)
|
673
|
+
res.status(response.status).send(response.data)
|
674
|
+
} catch (error) {
|
675
|
+
console.error("Error in /proxy:", error)
|
676
|
+
res.status(500).json({ error: "Failed to fetch the resource" })
|
677
|
+
}
|
678
|
+
})
|
679
|
+
|
583
680
|
app.listen(PORT, () => {
|
584
681
|
console.log(
|
585
682
|
`🚀 Creator UI server running at http://localhost:${PORT}/creator`
|
@@ -13,6 +13,7 @@
|
|
13
13
|
"axios": "^1.8.4",
|
14
14
|
"framer-motion": "^12.9.2",
|
15
15
|
"front-matter": "^4.0.2",
|
16
|
+
"html2canvas": "^1.4.1",
|
16
17
|
"js-yaml": "^4.1.0",
|
17
18
|
"mammoth": "^1.9.0",
|
18
19
|
"mitt": "^3.0.1",
|
@@ -23,6 +24,7 @@
|
|
23
24
|
"react-markdown": "^10.1.0",
|
24
25
|
"react-router": "^7.5.0",
|
25
26
|
"syllable": "^5.0.1",
|
27
|
+
"youtube-transcript": "^1.2.1",
|
26
28
|
"zustand": "^5.0.3"
|
27
29
|
},
|
28
30
|
"devDependencies": {
|
@@ -2216,6 +2218,15 @@
|
|
2216
2218
|
"dev": true,
|
2217
2219
|
"license": "MIT"
|
2218
2220
|
},
|
2221
|
+
"node_modules/base64-arraybuffer": {
|
2222
|
+
"version": "1.0.2",
|
2223
|
+
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
2224
|
+
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
2225
|
+
"license": "MIT",
|
2226
|
+
"engines": {
|
2227
|
+
"node": ">= 0.6.0"
|
2228
|
+
}
|
2229
|
+
},
|
2219
2230
|
"node_modules/base64-js": {
|
2220
2231
|
"version": "1.5.1",
|
2221
2232
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
@@ -2504,6 +2515,15 @@
|
|
2504
2515
|
"node": ">= 8"
|
2505
2516
|
}
|
2506
2517
|
},
|
2518
|
+
"node_modules/css-line-break": {
|
2519
|
+
"version": "2.1.0",
|
2520
|
+
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
2521
|
+
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
2522
|
+
"license": "MIT",
|
2523
|
+
"dependencies": {
|
2524
|
+
"utrie": "^1.0.2"
|
2525
|
+
}
|
2526
|
+
},
|
2507
2527
|
"node_modules/csstype": {
|
2508
2528
|
"version": "3.1.3",
|
2509
2529
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
@@ -3557,6 +3577,19 @@
|
|
3557
3577
|
"url": "https://opencollective.com/unified"
|
3558
3578
|
}
|
3559
3579
|
},
|
3580
|
+
"node_modules/html2canvas": {
|
3581
|
+
"version": "1.4.1",
|
3582
|
+
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
3583
|
+
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
3584
|
+
"license": "MIT",
|
3585
|
+
"dependencies": {
|
3586
|
+
"css-line-break": "^2.1.0",
|
3587
|
+
"text-segmentation": "^1.0.3"
|
3588
|
+
},
|
3589
|
+
"engines": {
|
3590
|
+
"node": ">=8.0.0"
|
3591
|
+
}
|
3592
|
+
},
|
3560
3593
|
"node_modules/http-proxy-agent": {
|
3561
3594
|
"version": "5.0.0",
|
3562
3595
|
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
|
@@ -5790,6 +5823,15 @@
|
|
5790
5823
|
"uuid": "dist/bin/uuid"
|
5791
5824
|
}
|
5792
5825
|
},
|
5826
|
+
"node_modules/text-segmentation": {
|
5827
|
+
"version": "1.0.3",
|
5828
|
+
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
5829
|
+
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
5830
|
+
"license": "MIT",
|
5831
|
+
"dependencies": {
|
5832
|
+
"utrie": "^1.0.2"
|
5833
|
+
}
|
5834
|
+
},
|
5793
5835
|
"node_modules/to-regex-range": {
|
5794
5836
|
"version": "5.0.1",
|
5795
5837
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
@@ -6050,6 +6092,15 @@
|
|
6050
6092
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
6051
6093
|
"license": "MIT"
|
6052
6094
|
},
|
6095
|
+
"node_modules/utrie": {
|
6096
|
+
"version": "1.0.2",
|
6097
|
+
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
6098
|
+
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
6099
|
+
"license": "MIT",
|
6100
|
+
"dependencies": {
|
6101
|
+
"base64-arraybuffer": "^1.0.2"
|
6102
|
+
}
|
6103
|
+
},
|
6053
6104
|
"node_modules/uuid": {
|
6054
6105
|
"version": "8.3.2",
|
6055
6106
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
@@ -6227,6 +6278,15 @@
|
|
6227
6278
|
"url": "https://github.com/sponsors/sindresorhus"
|
6228
6279
|
}
|
6229
6280
|
},
|
6281
|
+
"node_modules/youtube-transcript": {
|
6282
|
+
"version": "1.2.1",
|
6283
|
+
"resolved": "https://registry.npmjs.org/youtube-transcript/-/youtube-transcript-1.2.1.tgz",
|
6284
|
+
"integrity": "sha512-TvEGkBaajKw+B6y91ziLuBLsa5cawgowou+Bk0ciGpjELDfAzSzTGXaZmeSSkUeknCPpEr/WGApOHDwV7V+Y9Q==",
|
6285
|
+
"license": "MIT",
|
6286
|
+
"engines": {
|
6287
|
+
"node": ">=18.0.0"
|
6288
|
+
}
|
6289
|
+
},
|
6230
6290
|
"node_modules/zustand": {
|
6231
6291
|
"version": "5.0.3",
|
6232
6292
|
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz",
|
package/src/creator/package.json
CHANGED
@@ -15,6 +15,7 @@
|
|
15
15
|
"axios": "^1.8.4",
|
16
16
|
"framer-motion": "^12.9.2",
|
17
17
|
"front-matter": "^4.0.2",
|
18
|
+
"html2canvas": "^1.4.1",
|
18
19
|
"js-yaml": "^4.1.0",
|
19
20
|
"mammoth": "^1.9.0",
|
20
21
|
"mitt": "^3.0.1",
|
@@ -25,6 +26,7 @@
|
|
25
26
|
"react-markdown": "^10.1.0",
|
26
27
|
"react-router": "^7.5.0",
|
27
28
|
"syllable": "^5.0.1",
|
29
|
+
"youtube-transcript": "^1.2.1",
|
28
30
|
"zustand": "^5.0.3"
|
29
31
|
},
|
30
32
|
"devDependencies": {
|
package/src/creator/src/App.tsx
CHANGED
@@ -9,6 +9,8 @@ import useStore from "./utils/store"
|
|
9
9
|
import { interactiveCreation } from "./utils/rigo"
|
10
10
|
import { checkParams, loginWithToken, parseLesson } from "./utils/lib"
|
11
11
|
import FileUploader from "./components/FileUploader"
|
12
|
+
// import LinkUploader from "./components/LinkUploader"
|
13
|
+
import Source from "./components/Source"
|
12
14
|
|
13
15
|
// const exampleContentIndex = `-Introduction to AI: Explain what is AI and its applications
|
14
16
|
// -Introduction to Machine Learning: Explain What is machine learning and its aplications
|
@@ -116,21 +118,7 @@ function App() {
|
|
116
118
|
/>
|
117
119
|
),
|
118
120
|
},
|
119
|
-
|
120
|
-
// title:
|
121
|
-
// "First you need to login with 4Geeks.com to use AI Generation tool for creators. ",
|
122
|
-
// slug: "login",
|
123
|
-
// isCompleted: false,
|
124
|
-
// content: (
|
125
|
-
// <Login
|
126
|
-
// onFinish={() => {
|
127
|
-
// setFormState({
|
128
|
-
// currentStep: "duration",
|
129
|
-
// })
|
130
|
-
// }}
|
131
|
-
// />
|
132
|
-
// ),
|
133
|
-
// },
|
121
|
+
|
134
122
|
{
|
135
123
|
title: "What is the estimated duration for this tutorial?",
|
136
124
|
slug: "duration",
|
@@ -173,25 +161,6 @@ function App() {
|
|
173
161
|
</div>
|
174
162
|
),
|
175
163
|
},
|
176
|
-
{
|
177
|
-
title: "What is the target audience for this tutorial?",
|
178
|
-
slug: "targetAudience",
|
179
|
-
isCompleted: false,
|
180
|
-
content: (
|
181
|
-
<div className="flex flex-row gap-4">
|
182
|
-
<textarea
|
183
|
-
placeholder="Describe the target audience for this tutorial"
|
184
|
-
className="w-full h-24 border-2 border-gray-300 rounded-md p-2 bg-white"
|
185
|
-
defaultValue={formState.targetAudience}
|
186
|
-
onBlur={(e) => {
|
187
|
-
setFormState({
|
188
|
-
targetAudience: e.target.value,
|
189
|
-
})
|
190
|
-
}}
|
191
|
-
/>
|
192
|
-
</div>
|
193
|
-
),
|
194
|
-
},
|
195
164
|
{
|
196
165
|
title: "Do you have a content index for this tutorial?",
|
197
166
|
slug: "hasContentIndex",
|
@@ -205,6 +174,7 @@ function App() {
|
|
205
174
|
hasContentIndex: true,
|
206
175
|
currentStep: "contentIndex",
|
207
176
|
variables: [...formState.variables, "contentIndex"],
|
177
|
+
// variables: [...formState.variables.filter((v) => v !== "hasContentIndex"), "contentIndex"],
|
208
178
|
})
|
209
179
|
}}
|
210
180
|
selected={false}
|
@@ -224,7 +194,7 @@ function App() {
|
|
224
194
|
},
|
225
195
|
{
|
226
196
|
title:
|
227
|
-
"
|
197
|
+
"Any materials to get this course started?",
|
228
198
|
slug: "contentIndex",
|
229
199
|
isCompleted: false,
|
230
200
|
content: (
|
@@ -240,6 +210,18 @@ function App() {
|
|
240
210
|
})
|
241
211
|
}}
|
242
212
|
/>
|
213
|
+
<ul className="space-y-3">
|
214
|
+
{formState.sources?.map((it, i) => (
|
215
|
+
<Source key={i} source={it} />
|
216
|
+
))}
|
217
|
+
</ul>
|
218
|
+
{/* <LinkUploader
|
219
|
+
onResult={(links) => {
|
220
|
+
setFormState({
|
221
|
+
sources: [...formState.sources, ...links],
|
222
|
+
})
|
223
|
+
}}
|
224
|
+
/> */}
|
243
225
|
<FileUploader
|
244
226
|
onResult={(files) => {
|
245
227
|
// toast.success("File uploaded successfully")
|
@@ -277,16 +259,21 @@ function App() {
|
|
277
259
|
}
|
278
260
|
/>
|
279
261
|
) : (
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
}
|
288
|
-
|
289
|
-
|
262
|
+
<>
|
263
|
+
{/* <div className="flex flex-col gap-4">
|
264
|
+
<h1 className="text-2xl font-bold">{formState.sources?.length}</h1>
|
265
|
+
</div> */}
|
266
|
+
<StepWizard
|
267
|
+
formState={formState}
|
268
|
+
steps={buildSteps()}
|
269
|
+
setFormState={setFormState}
|
270
|
+
onFinish={() => {
|
271
|
+
setFormState({
|
272
|
+
isCompleted: true,
|
273
|
+
})
|
274
|
+
}}
|
275
|
+
/>
|
276
|
+
</>
|
290
277
|
)}
|
291
278
|
</>
|
292
279
|
)
|
@@ -281,4 +281,18 @@ export const SVGS = {
|
|
281
281
|
/>
|
282
282
|
</svg>
|
283
283
|
),
|
284
|
+
redClose: (
|
285
|
+
<svg
|
286
|
+
width="10"
|
287
|
+
height="10"
|
288
|
+
viewBox="0 0 10 11"
|
289
|
+
fill="none"
|
290
|
+
xmlns="http://www.w3.org/2000/svg"
|
291
|
+
>
|
292
|
+
<path
|
293
|
+
d="M5.875 5.19922L9.8125 1.26172C10.0625 1.01172 10.0625 0.636719 9.8125 0.386719C9.5625 0.136719 9.1875 0.136719 8.9375 0.386719L5 4.32422L1.0625 0.386719C0.8125 0.136719 0.4375 0.136719 0.1875 0.386719C-0.0624999 0.636719 -0.0624999 1.01172 0.1875 1.26172L4.125 5.19922L0.1875 9.13672C0.0625001 9.26172 0 9.38672 0 9.57422C0 9.94922 0.25 10.1992 0.625 10.1992C0.8125 10.1992 0.9375 10.1367 1.0625 10.0117L5 6.07422L8.9375 10.0117C9.0625 10.1367 9.1875 10.1992 9.375 10.1992C9.5625 10.1992 9.6875 10.1367 9.8125 10.0117C10.0625 9.76172 10.0625 9.38672 9.8125 9.13672L5.875 5.19922Z"
|
294
|
+
fill="#EB5757"
|
295
|
+
/>
|
296
|
+
</svg>
|
297
|
+
),
|
284
298
|
}
|