@learnpack/learnpack 5.0.112 → 5.0.116

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.
@@ -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-Bw3XbAoy.js"></script>
14
- <link rel="stylesheet" crossorigin href="/creator/assets/index-VqUlNIHR.css">
13
+ <script type="module" crossorigin src="/creator/assets/index-eOf2cL3F.js"></script>
14
+ <link rel="stylesheet" crossorigin href="/creator/assets/index-CNNlfS1s.css">
15
15
  </head>
16
16
  <body>
17
17
  <div id="root"></div>
@@ -1 +1 @@
1
- {"version":"5.0.112","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":[]}}}
1
+ {"version":"5.0.116","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.112",
4
+ "version": "5.0.116",
5
5
  "author": "Alejandro Sanchez @alesanchezr",
6
6
  "contributors": [
7
7
  {
@@ -8,9 +8,8 @@ import useStore from "./utils/store"
8
8
 
9
9
  import { interactiveCreation } from "./utils/rigo"
10
10
  import { checkParams, loginWithToken, parseLesson } from "./utils/lib"
11
- import FileUploader from "./components/FileUploader"
12
- // import LinkUploader from "./components/LinkUploader"
13
- import Source from "./components/Source"
11
+
12
+ import { Uploader } from "./components/Uploader"
14
13
 
15
14
  // const exampleContentIndex = `-Introduction to AI: Explain what is AI and its applications
16
15
  // -Introduction to Machine Learning: Explain What is machine learning and its aplications
@@ -85,7 +84,6 @@ function App() {
85
84
  courseInfo: {
86
85
  ...formState,
87
86
  title: res.parsed.title,
88
- description: res.parsed.description,
89
87
  },
90
88
  })
91
89
  navigate("/creator/syllabus")
@@ -196,45 +194,18 @@ function App() {
196
194
  {
197
195
  title: "Any materials to get this course started?",
198
196
  slug: "contentIndex",
197
+ helpText:
198
+ "It could be just text, paste an URL or even upload a document.",
199
199
  isCompleted: false,
200
200
  content: (
201
- <>
202
- <textarea
203
- placeholder="Provide a content index for this tutorial"
204
- className="w-full h-40 border-2 border-gray-300 rounded-md p-2"
205
- value={formState.contentIndex}
206
- onChange={(e) => {
207
- setFormState({
208
- contentIndex: e.target.value,
209
- // isCompleted: true,
210
- })
211
- }}
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
- /> */}
225
- <FileUploader
226
- onResult={(files) => {
227
- // toast.success("File uploaded successfully")
228
- let allFilesText = ``
229
- files.forEach((file) => {
230
- allFilesText += `<FILE NAME="${file.name}">${file.text}</FILE>\n`
231
- })
232
- setFormState({
233
- contentIndex: allFilesText,
234
- })
235
- }}
236
- />
237
- </>
201
+ <Uploader
202
+ onFinish={(text) => {
203
+ setFormState({
204
+ contentIndex: text,
205
+ isCompleted: true,
206
+ })
207
+ }}
208
+ />
238
209
  ),
239
210
  },
240
211
  ]
@@ -295,4 +295,54 @@ export const SVGS = {
295
295
  />
296
296
  </svg>
297
297
  ),
298
+ contentTable: (
299
+ <svg
300
+ width="33"
301
+ height="33"
302
+ viewBox="0 0 33 33"
303
+ fill="none"
304
+ xmlns="http://www.w3.org/2000/svg"
305
+ >
306
+ <path
307
+ d="M12.668 7.31052L9.52511 10.4368L8.28702 9.20525C7.90606 8.82631 7.33464 8.82631 6.95368 9.20525C6.57273 9.5842 6.57273 10.1526 6.95368 10.5316L8.85844 12.4263C9.04892 12.6158 9.2394 12.7105 9.52511 12.7105C9.81083 12.7105 10.0013 12.6158 10.1918 12.4263L14.0013 8.63683C14.3823 8.25788 14.3823 7.68946 14.0013 7.31052C13.6203 6.93157 13.0489 6.93157 12.668 7.31052ZM12.668 13.9421L9.52511 17.0684L8.28702 15.8368C7.90606 15.4579 7.33464 15.4579 6.95368 15.8368C6.57273 16.2158 6.57273 16.7842 6.95368 17.1631L8.85844 19.0579C9.04892 19.2474 9.2394 19.3421 9.52511 19.3421C9.81083 19.3421 10.0013 19.2474 10.1918 19.0579L14.0013 15.2684C14.3823 14.8895 14.3823 14.321 14.0013 13.9421C13.6203 13.5631 13.0489 13.5631 12.668 13.9421ZM12.668 20.5737L9.52511 23.7L8.28702 22.4684C7.90606 22.0895 7.33464 22.0895 6.95368 22.4684C6.57273 22.8474 6.57273 23.4158 6.95368 23.7947L8.85844 25.6895C9.04892 25.8789 9.2394 25.9737 9.52511 25.9737C9.81083 25.9737 10.0013 25.8789 10.1918 25.6895L14.0013 21.9C14.3823 21.521 14.3823 20.9526 14.0013 20.5737C13.6203 20.1947 13.0489 20.1947 12.668 20.5737ZM18.0965 11.7631H25.7156C26.287 11.7631 26.668 11.3842 26.668 10.8158C26.668 10.2474 26.287 9.86841 25.7156 9.86841H18.0965C17.5251 9.86841 17.1442 10.2474 17.1442 10.8158C17.1442 11.3842 17.5251 11.7631 18.0965 11.7631ZM25.7156 16.5H18.0965C17.5251 16.5 17.1442 16.8789 17.1442 17.4474C17.1442 18.0158 17.5251 18.3947 18.0965 18.3947H25.7156C26.287 18.3947 26.668 18.0158 26.668 17.4474C26.668 16.8789 26.287 16.5 25.7156 16.5ZM25.7156 23.1316H18.0965C17.5251 23.1316 17.1442 23.5105 17.1442 24.0789C17.1442 24.6474 17.5251 25.0263 18.0965 25.0263H25.7156C26.287 25.0263 26.668 24.6474 26.668 24.0789C26.668 23.5105 26.287 23.1316 25.7156 23.1316Z"
308
+ fill="#0084FF"
309
+ />
310
+ </svg>
311
+ ),
312
+ pdf: (
313
+ <svg
314
+ width="32"
315
+ height="33"
316
+ viewBox="0 0 32 33"
317
+ fill="none"
318
+ xmlns="http://www.w3.org/2000/svg"
319
+ >
320
+ <path
321
+ d="M27.5 14.1667H27V8.56667C27 8.56667 27 8.56667 27 8.53867C26.9975 8.49737 26.9891 8.45656 26.975 8.41733V8.37533C26.952 8.3254 26.9199 8.2796 26.88 8.24L20.88 2.64C20.8376 2.60279 20.7885 2.57278 20.735 2.55133H20.69C20.6402 2.52586 20.5861 2.5085 20.53 2.5H5.5C5.36739 2.5 5.24021 2.54917 5.14645 2.63668C5.05268 2.7242 5 2.8429 5 2.96667V14.1667H4.5C4.36739 14.1667 4.24021 14.2158 4.14645 14.3033C4.05268 14.3909 4 14.5096 4 14.6333V23.9667C4 24.0904 4.05268 24.2091 4.14645 24.2966C4.24021 24.3842 4.36739 24.4333 4.5 24.4333H5V30.0333C5 30.1571 5.05268 30.2758 5.14645 30.3633C5.24021 30.4508 5.36739 30.5 5.5 30.5H26.5C26.6326 30.5 26.7598 30.4508 26.8536 30.3633C26.9473 30.2758 27 30.1571 27 30.0333V24.4333H27.5C27.6326 24.4333 27.7598 24.3842 27.8536 24.2966C27.9473 24.2091 28 24.0904 28 23.9667V14.6333C28 14.5096 27.9473 14.3909 27.8536 14.3033C27.7598 14.2158 27.6326 14.1667 27.5 14.1667ZM21 4.09133L25.295 8.1H21V4.09133ZM26 29.5667H6V24.4333H26V29.5667ZM10.535 22.4827V16.2527H12.12C12.3368 16.2437 12.5532 16.2777 12.7549 16.3526C12.9565 16.4274 13.1389 16.5412 13.29 16.6867C13.5656 16.9764 13.7107 17.3542 13.695 17.7413V18.6467C13.6985 18.8423 13.6595 19.0366 13.5805 19.2179C13.5014 19.3991 13.3839 19.5636 13.235 19.7013C13.092 19.8427 12.919 19.9547 12.727 20.0303C12.535 20.1058 12.3283 20.1432 12.12 20.14H11.545V22.4733L10.535 22.4827ZM14.505 22.4827V16.248H16.085C16.2941 16.2442 16.5018 16.2812 16.6947 16.3568C16.8876 16.4323 17.0614 16.5447 17.205 16.6867C17.3537 16.8236 17.4712 16.9872 17.5503 17.1677C17.6293 17.3481 17.6684 17.5417 17.665 17.7367V21.0033C17.6681 21.1994 17.6285 21.3939 17.5486 21.5752C17.4686 21.7565 17.35 21.9208 17.2 22.058C17.0564 22.2 16.8826 22.3123 16.6897 22.3879C16.4968 22.4634 16.2891 22.5005 16.08 22.4967L14.505 22.4827ZM20.92 18.894V19.8273H19.56V22.4733H18.56V16.248H21.425V17.1813H19.56V18.88L20.92 18.894ZM26 14.1667H6V3.43333H20V8.56667C20 8.69043 20.0527 8.80913 20.1464 8.89665C20.2402 8.98417 20.3674 9.03333 20.5 9.03333H26V14.1667Z"
322
+ fill="#EB5757"
323
+ />
324
+ </svg>
325
+ ),
326
+ youtube: (
327
+ <svg
328
+ width="33"
329
+ height="33"
330
+ viewBox="0 0 33 33"
331
+ fill="none"
332
+ xmlns="http://www.w3.org/2000/svg"
333
+ >
334
+ <path
335
+ fillRule="evenodd"
336
+ clipRule="evenodd"
337
+ d="M31.3483 8.95829C30.9895 7.61238 29.9277 6.55075 28.5769 6.18687C26.1345 5.53381 16.3347 5.53381 16.3347 5.53381C16.3347 5.53381 6.53991 5.53381 4.09244 6.18687C2.74666 6.54572 1.6849 7.60748 1.32102 8.95829C0.667969 11.4007 0.667969 16.5 0.667969 16.5C0.667969 16.5 0.667969 21.5993 1.32102 24.0418C1.67988 25.3877 2.74164 26.4493 4.09244 26.8132C6.53991 27.4662 16.3347 27.4662 16.3347 27.4662C16.3347 27.4662 26.1345 27.4662 28.5769 26.8132C29.9228 26.4543 30.9845 25.3926 31.3483 24.0418C32.0014 21.5993 32.0014 16.5001 32.0014 16.5001C32.0014 16.5001 32.0014 11.4007 31.3483 8.95829Z"
338
+ fill="#FF0000"
339
+ />
340
+ <path
341
+ fillRule="evenodd"
342
+ clipRule="evenodd"
343
+ d="M13.2031 21.2001L21.343 16.4995L13.2031 11.7991V21.2001Z"
344
+ fill="white"
345
+ />
346
+ </svg>
347
+ ),
298
348
  }
@@ -0,0 +1,21 @@
1
+ export const ContentCard = ({
2
+ description,
3
+ icon,
4
+ onClick,
5
+ }: {
6
+ description: string
7
+ icon: React.ReactNode
8
+ onClick: () => void
9
+ }) => {
10
+ return (
11
+ <div
12
+ className="flex flex-col items-center justify-center gap-2 bg-white card p-2 rounded-lg shadow-md min-w-[250px] w-full h-[150px] cursor-pointer"
13
+ onClick={onClick}
14
+ >
15
+ <div className="text-blue-500 flex justify-center items-center">
16
+ {icon}
17
+ </div>
18
+ <span className="text-sm text-center">{description}</span>
19
+ </div>
20
+ )
21
+ }
@@ -3,6 +3,7 @@ import * as pdfjsLib from "pdfjs-dist"
3
3
  import mammoth from "mammoth"
4
4
  import { SVGS } from "../assets/svgs"
5
5
  import pdfWorker from "pdfjs-dist/build/pdf.worker?worker"
6
+ import { ContentCard } from "./ContentCard"
6
7
 
7
8
  pdfjsLib.GlobalWorkerOptions.workerPort = new pdfWorker()
8
9
 
@@ -20,9 +21,13 @@ export interface ParsedFile {
20
21
 
21
22
  interface FileUploaderProps {
22
23
  onResult: (files: ParsedFile[]) => void
24
+ styledAs?: "button" | "card"
23
25
  }
24
26
 
25
- const FileUploader: React.FC<FileUploaderProps> = ({ onResult }) => {
27
+ const FileUploader: React.FC<FileUploaderProps> = ({
28
+ onResult,
29
+ styledAs = "button",
30
+ }) => {
26
31
  const inputRef = useRef<HTMLInputElement>(null)
27
32
 
28
33
  const extractText = async (file: File): Promise<ParsedFile> => {
@@ -68,13 +73,22 @@ const FileUploader: React.FC<FileUploaderProps> = ({ onResult }) => {
68
73
 
69
74
  return (
70
75
  <>
71
- <button
72
- type="button"
73
- className="cursor-pointer blue-on-hover flex items-center justify-center w-6 h-6"
74
- onClick={() => inputRef.current?.click()}
75
- >
76
- {SVGS.clip}
77
- </button>
76
+ {styledAs === "button" && (
77
+ <button
78
+ type="button"
79
+ className="cursor-pointer blue-on-hover flex items-center justify-center w-6 h-6"
80
+ onClick={() => inputRef.current?.click()}
81
+ >
82
+ {SVGS.clip}
83
+ </button>
84
+ )}
85
+ {styledAs === "card" && (
86
+ <ContentCard
87
+ description="Upload a PDF"
88
+ icon={SVGS.pdf}
89
+ onClick={() => inputRef.current?.click()}
90
+ />
91
+ )}
78
92
 
79
93
  <input
80
94
  ref={inputRef}
@@ -12,17 +12,13 @@ export interface ParsedLink {
12
12
  }
13
13
 
14
14
  interface LinkUploaderProps {
15
- onResult: (links: ParsedLink[]) => void
16
- apiBase?: string
15
+ onResult: (links: ParsedLink) => void
17
16
  }
18
17
 
19
18
  const toBase64Url = (str: string) =>
20
19
  btoa(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "")
21
20
 
22
- const LinkUploader: React.FC<LinkUploaderProps> = ({
23
- onResult,
24
- apiBase = "http://localhost:3000",
25
- }) => {
21
+ const LinkUploader: React.FC<LinkUploaderProps> = ({ onResult }) => {
26
22
  const [url, setUrl] = useState("")
27
23
  const [loading, setLoading] = useState(false)
28
24
  const [error, setError] = useState<string | null>(null)
@@ -35,12 +31,12 @@ const LinkUploader: React.FC<LinkUploaderProps> = ({
35
31
 
36
32
  try {
37
33
  const key = toBase64Url(raw)
38
- const resp = await fetch(`${apiBase}/actions/fetch/${key}`)
34
+ const resp = await fetch(`actions/fetch/${key}`)
39
35
  if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
40
36
  const data = (await resp.json()) as ParsedLink
41
37
 
42
- onResult([data]) // emit the parsed link immediately
43
- setUrl("") // clear input
38
+ onResult(data) // emit the parsed link immediately
39
+ setUrl("") // clear input
44
40
  } catch (err: any) {
45
41
  console.error(err)
46
42
  setError(err.message || "Failed to fetch link.")
@@ -1,8 +1,10 @@
1
1
  import React from "react"
2
+ import { SVGS } from "../assets/svgs"
2
3
 
3
4
  export type Step = {
4
5
  title: string
5
6
  subtitle?: string
7
+ helpText?: string
6
8
  content: React.ReactNode
7
9
  slug: string
8
10
  isCompleted: boolean
@@ -52,11 +54,18 @@ const StepWizard: React.FC<Props> = ({
52
54
  {steps.find((step) => step.slug === currentStep)?.title}
53
55
  </h2>
54
56
 
55
- <div className="mb-6">
56
- {steps.find((step) => step.slug === currentStep)?.content}
57
- </div>
58
-
59
- {/* Dot Indicators */}
57
+ {steps.find((step) => step.slug === currentStep)?.helpText && (
58
+ <div className="text-sm text-gray-500 bg-white p-2 rounded-md flex flex-row gap-2 align-center border border-gray-200 mb-4">
59
+ <div className="text-blue-500 align-center justify-center flex bg-heavy-blue p-2 flex rounded">
60
+ {SVGS.rigoSoftBlue}
61
+ </div>
62
+ <div className="flex flex-col gap-2 align-center justify-center">
63
+ <span className="">
64
+ {steps.find((step) => step.slug === currentStep)?.helpText}
65
+ </span>
66
+ </div>
67
+ </div>
68
+ )}
60
69
  <div className="flex justify-center mb-4 space-x-2">
61
70
  {steps.map((_, i) => (
62
71
  <span
@@ -68,6 +77,12 @@ const StepWizard: React.FC<Props> = ({
68
77
  ))}
69
78
  </div>
70
79
 
80
+ <div className="mb-6">
81
+ {steps.find((step) => step.slug === currentStep)?.content}
82
+ </div>
83
+
84
+ {/* Dot Indicators */}
85
+
71
86
  {/* Navigation */}
72
87
  <div className="flex justify-between">
73
88
  <button
@@ -0,0 +1,82 @@
1
+ import { useState } from "react"
2
+ import { SVGS } from "../assets/svgs"
3
+ import { ContentCard } from "./ContentCard"
4
+ import LinkUploader from "./LinkUploader"
5
+ import FileUploader from "./FileUploader"
6
+
7
+ const TextUploader = ({ onFinish }: { onFinish: (text: string) => void }) => {
8
+ const [text, setText] = useState("")
9
+
10
+ return (
11
+ <div className="flex flex-col gap-2 w-full">
12
+ <textarea
13
+ className="mt-4 p-2 border rounded w-full bg-white border-heavy-blue"
14
+ placeholder="Add your text here..."
15
+ value={text}
16
+ onChange={(e) => setText(e.target.value)}
17
+ />
18
+ <button
19
+ className="mt-4 p-2 border rounded w-full bg-learnpack text-white"
20
+ onClick={() => onFinish(text)}
21
+ >
22
+ Finish
23
+ </button>
24
+ </div>
25
+ )
26
+ }
27
+
28
+ export const Uploader = ({
29
+ onFinish,
30
+ }: {
31
+ onFinish: (text: string) => void
32
+ }) => {
33
+ const [selectedOption, setSelectedOption] = useState<string | null>(null)
34
+
35
+ const handleSelectOption = (option: string) => {
36
+ setSelectedOption(option)
37
+ }
38
+
39
+ return (
40
+ <div className="flex flex-col md:flex-row gap-2 justify-center items-center">
41
+ {!selectedOption && (
42
+ <>
43
+ <ContentCard
44
+ description="Write or paste a content table"
45
+ icon={SVGS.contentTable}
46
+ onClick={() => handleSelectOption("text")}
47
+ />
48
+
49
+ <FileUploader
50
+ styledAs="card"
51
+ onResult={(file) => {
52
+ onFinish(
53
+ `The following information comes from a PDF file uploaded by the user: ${JSON.stringify(
54
+ file
55
+ )}`
56
+ )
57
+ }}
58
+ />
59
+ <ContentCard
60
+ description="Share a Youtube link"
61
+ icon={SVGS.youtube}
62
+ onClick={() => handleSelectOption("youtube")}
63
+ />
64
+ </>
65
+ )}
66
+
67
+ {selectedOption === "text" && <TextUploader onFinish={onFinish} />}
68
+
69
+ {selectedOption === "youtube" && (
70
+ <LinkUploader
71
+ onResult={(link) => {
72
+ onFinish(
73
+ `The following information comes from a Youtube video uploaded by the user. Use the transcript to create the course: ${JSON.stringify(
74
+ link
75
+ )}`
76
+ )
77
+ }}
78
+ />
79
+ )}
80
+ </div>
81
+ )
82
+ }
@@ -192,3 +192,14 @@ h1 {
192
192
  transform: scaleY(1) translateY(0);
193
193
  }
194
194
  }
195
+
196
+ .bg-heavy-blue {
197
+ background-color: #9fbdf0;
198
+ }
199
+
200
+ .border-heavy-blue {
201
+ border-color: #9fbdf0;
202
+ &:focus {
203
+ outline: 1px solid #9fbdf0;
204
+ }
205
+ }
@@ -526,6 +526,9 @@
526
526
  .inline-block {
527
527
  display: inline-block;
528
528
  }
529
+ .table {
530
+ display: table;
531
+ }
529
532
  .h-2 {
530
533
  height: calc(var(--spacing) * 2);
531
534
  }
@@ -550,15 +553,15 @@
550
553
  .h-24 {
551
554
  height: calc(var(--spacing) * 24);
552
555
  }
553
- .h-40 {
554
- height: calc(var(--spacing) * 40);
555
- }
556
556
  .h-60 {
557
557
  height: calc(var(--spacing) * 60);
558
558
  }
559
559
  .h-\[85\%\] {
560
560
  height: 85%;
561
561
  }
562
+ .h-\[150px\] {
563
+ height: 150px;
564
+ }
562
565
  .h-full {
563
566
  height: 100%;
564
567
  }
@@ -622,6 +625,9 @@
622
625
  .max-w-xs {
623
626
  max-width: var(--container-xs);
624
627
  }
628
+ .min-w-\[250px\] {
629
+ min-width: 250px;
630
+ }
625
631
  .flex-1 {
626
632
  flex: 1;
627
633
  }
@@ -665,6 +671,9 @@
665
671
  .flex-col {
666
672
  flex-direction: column;
667
673
  }
674
+ .flex-row {
675
+ flex-direction: row;
676
+ }
668
677
  .items-center {
669
678
  align-items: center;
670
679
  }
@@ -1335,6 +1344,15 @@ h1 {
1335
1344
  transform: scaleY(1) translateY(0);
1336
1345
  }
1337
1346
  }
1347
+ .bg-heavy-blue {
1348
+ background-color: #9fbdf0;
1349
+ }
1350
+ .border-heavy-blue {
1351
+ border-color: #9fbdf0;
1352
+ }
1353
+ .border-heavy-blue:focus {
1354
+ outline: 1px solid #9fbdf0;
1355
+ }
1338
1356
  @property --tw-translate-x {
1339
1357
  syntax: "*";
1340
1358
  inherits: false;