@learnpack/learnpack 5.0.152 → 5.0.156
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/creatorDist/assets/{index-CztA582_.css → index-C_YTggyk.css} +12 -3
- package/lib/creatorDist/assets/{index-l0lFNoeD.js → index-Df4pwBvU.js} +9076 -8939
- package/lib/creatorDist/index.html +2 -2
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/src/creator/src/App.tsx +77 -68
- package/src/creator/src/assets/svgs.tsx +46 -0
- package/src/creator/src/components/FileUploader.tsx +53 -31
- package/src/creator/src/components/Login.tsx +11 -0
- package/src/creator/src/components/PreviewGenerator.tsx +4 -4
- package/src/creator/src/components/Source.tsx +8 -10
- package/src/creator/src/components/StepWizard.tsx +10 -7
- package/src/creator/src/components/Uploader.tsx +7 -10
- package/src/creator/src/components/syllabus/ContentIndex.tsx +37 -1
- package/src/creator/src/components/syllabus/Sidebar.tsx +1 -8
- package/src/creator/src/components/syllabus/SyllabusEditor.tsx +3 -0
- package/src/creator/src/utils/store.ts +7 -6
- package/src/creatorDist/assets/{index-CztA582_.css → index-C_YTggyk.css} +12 -3
- package/src/creatorDist/assets/{index-l0lFNoeD.js → index-Df4pwBvU.js} +9076 -8939
- package/src/creatorDist/index.html +2 -2
@@ -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-Df4pwBvU.js"></script>
|
14
|
+
<link rel="stylesheet" crossorigin href="/creator/assets/index-C_YTggyk.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.156","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.156",
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
6
6
|
"contributors": [
|
7
7
|
{
|
package/src/creator/src/App.tsx
CHANGED
@@ -26,6 +26,7 @@ function App() {
|
|
26
26
|
push,
|
27
27
|
cleanHistory,
|
28
28
|
setPlanToRedirect,
|
29
|
+
uploadedFiles,
|
29
30
|
} = useStore(
|
30
31
|
useShallow((state) => ({
|
31
32
|
formState: state.formState,
|
@@ -34,6 +35,7 @@ function App() {
|
|
34
35
|
push: state.push,
|
35
36
|
cleanHistory: state.cleanHistory,
|
36
37
|
setPlanToRedirect: state.setPlanToRedirect,
|
38
|
+
uploadedFiles: state.uploadedFiles,
|
37
39
|
}))
|
38
40
|
)
|
39
41
|
|
@@ -58,24 +60,6 @@ function App() {
|
|
58
60
|
rigoToken: user.rigobot.key,
|
59
61
|
user: user,
|
60
62
|
})
|
61
|
-
setFormState({
|
62
|
-
variables: [
|
63
|
-
"description",
|
64
|
-
"duration",
|
65
|
-
"targetAudience",
|
66
|
-
"hasContentIndex",
|
67
|
-
],
|
68
|
-
})
|
69
|
-
} else {
|
70
|
-
setFormState({
|
71
|
-
variables: [
|
72
|
-
"description",
|
73
|
-
"login",
|
74
|
-
"duration",
|
75
|
-
"targetAudience",
|
76
|
-
"hasContentIndex",
|
77
|
-
],
|
78
|
-
})
|
79
63
|
}
|
80
64
|
}
|
81
65
|
|
@@ -113,33 +97,50 @@ function App() {
|
|
113
97
|
}
|
114
98
|
|
115
99
|
const handleCreateTutorial = async () => {
|
116
|
-
|
117
|
-
|
118
|
-
courseInfo: JSON.stringify(formState),
|
119
|
-
prevInteractions: "",
|
120
|
-
})
|
121
|
-
const lessons = res.parsed.listOfSteps.map((lesson: any) => {
|
122
|
-
return parseLesson(lesson, [])
|
123
|
-
})
|
100
|
+
try {
|
101
|
+
cleanHistory()
|
124
102
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
}
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
103
|
+
const res = await interactiveCreation({
|
104
|
+
courseInfo: `${JSON.stringify(formState)}
|
105
|
+
${
|
106
|
+
uploadedFiles.length > 0
|
107
|
+
? `These files where uploaded by the user: \n\n${JSON.stringify(
|
108
|
+
uploadedFiles
|
109
|
+
)}`
|
110
|
+
: ""
|
111
|
+
}`,
|
112
|
+
prevInteractions: "",
|
113
|
+
})
|
114
|
+
const lessons = res.parsed.listOfSteps.map((lesson: any) => {
|
115
|
+
return parseLesson(lesson, [])
|
116
|
+
})
|
117
|
+
|
118
|
+
push({
|
119
|
+
lessons,
|
120
|
+
courseInfo: {
|
121
|
+
...formState,
|
122
|
+
title: res.parsed.title,
|
123
|
+
description: res.parsed.description,
|
124
|
+
},
|
125
|
+
})
|
126
|
+
navigate("/creator/syllabus")
|
127
|
+
setFormState({
|
128
|
+
description: "",
|
129
|
+
duration: 0,
|
130
|
+
targetAudience: "",
|
131
|
+
hasContentIndex: false,
|
132
|
+
contentIndex: "",
|
133
|
+
isCompleted: false,
|
134
|
+
currentStep: "description",
|
135
|
+
})
|
136
|
+
} catch (error) {
|
137
|
+
console.error(error)
|
138
|
+
toast.error("Something went wrong. Please try again.")
|
139
|
+
setFormState({
|
140
|
+
isCompleted: false,
|
141
|
+
currentStep: "hasContentIndex",
|
142
|
+
})
|
143
|
+
}
|
143
144
|
}
|
144
145
|
|
145
146
|
const buildSteps = () => {
|
@@ -167,7 +168,8 @@ function App() {
|
|
167
168
|
{
|
168
169
|
title: "What is the estimated duration for this tutorial?",
|
169
170
|
slug: "duration",
|
170
|
-
isCompleted:
|
171
|
+
isCompleted: formState.duration > 0,
|
172
|
+
required: true,
|
171
173
|
content: (
|
172
174
|
<div className="flex flex-col md:flex-row gap-2">
|
173
175
|
<SelectableCard
|
@@ -214,24 +216,28 @@ function App() {
|
|
214
216
|
<>
|
215
217
|
<div className="flex flex-col md:flex-row gap-2 justify-center">
|
216
218
|
<SelectableCard
|
217
|
-
title="
|
219
|
+
title="❌ No, help me create one"
|
218
220
|
onClick={() => {
|
219
221
|
setFormState({
|
220
|
-
hasContentIndex:
|
221
|
-
currentStep: "
|
222
|
-
variables: [
|
223
|
-
|
222
|
+
hasContentIndex: false,
|
223
|
+
currentStep: "verifyHuman",
|
224
|
+
variables: [
|
225
|
+
...formState.variables.filter(
|
226
|
+
(v) => v !== "contentIndex"
|
227
|
+
),
|
228
|
+
],
|
229
|
+
// isCompleted: true,
|
224
230
|
})
|
225
231
|
}}
|
226
232
|
selected={false}
|
227
233
|
/>
|
228
234
|
<SelectableCard
|
229
|
-
title="
|
235
|
+
title="✅ Yes"
|
230
236
|
onClick={() => {
|
231
237
|
setFormState({
|
232
|
-
hasContentIndex:
|
233
|
-
currentStep: "
|
234
|
-
|
238
|
+
hasContentIndex: true,
|
239
|
+
currentStep: "contentIndex",
|
240
|
+
variables: [...formState.variables, "contentIndex"],
|
235
241
|
})
|
236
242
|
}}
|
237
243
|
selected={false}
|
@@ -245,7 +251,9 @@ function App() {
|
|
245
251
|
slug: "contentIndex",
|
246
252
|
helpText:
|
247
253
|
"It could be just text, paste an URL or even upload a document.",
|
248
|
-
isCompleted:
|
254
|
+
isCompleted:
|
255
|
+
formState.contentIndex.length > 0 || uploadedFiles.length > 0,
|
256
|
+
required: true,
|
249
257
|
content: (
|
250
258
|
<Uploader
|
251
259
|
onFinish={(text) => {
|
@@ -264,7 +272,7 @@ function App() {
|
|
264
272
|
isCompleted: false,
|
265
273
|
content: (
|
266
274
|
<TurnstileChallenge
|
267
|
-
siteKey={"
|
275
|
+
siteKey={"0x4AAAAAABeZ9tjEevGBsJFU"}
|
268
276
|
onSuccess={async (token) => {
|
269
277
|
const _isHuman = await isHuman(token)
|
270
278
|
if (_isHuman) {
|
@@ -282,12 +290,15 @@ function App() {
|
|
282
290
|
},
|
283
291
|
]
|
284
292
|
|
293
|
+
console.log(formState.variables, "FORM STATE VAIRABLEs")
|
294
|
+
|
285
295
|
return steps.filter(
|
286
296
|
(step) =>
|
287
297
|
formState.variables.includes(step.slug) ||
|
288
298
|
step.slug === formState.currentStep
|
289
299
|
)
|
290
300
|
}
|
301
|
+
|
291
302
|
return (
|
292
303
|
<>
|
293
304
|
<ParamsChecker />
|
@@ -297,18 +308,16 @@ function App() {
|
|
297
308
|
icon={<img src={RIGO_FLOAT_GIT} alt="rigo" className="w-20 h-20" />}
|
298
309
|
/>
|
299
310
|
) : (
|
300
|
-
<
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
/>
|
311
|
-
</div>
|
311
|
+
<StepWizard
|
312
|
+
formState={formState}
|
313
|
+
steps={buildSteps()}
|
314
|
+
setFormState={setFormState}
|
315
|
+
onFinish={() => {
|
316
|
+
setFormState({
|
317
|
+
isCompleted: true,
|
318
|
+
})
|
319
|
+
}}
|
320
|
+
/>
|
312
321
|
)}
|
313
322
|
</>
|
314
323
|
)
|
@@ -345,4 +345,50 @@ export const SVGS = {
|
|
345
345
|
/>
|
346
346
|
</svg>
|
347
347
|
),
|
348
|
+
google: (
|
349
|
+
<svg
|
350
|
+
width="20px"
|
351
|
+
height="20px"
|
352
|
+
viewBox="-0.5 0 48 48"
|
353
|
+
version="1.1"
|
354
|
+
xmlns="http://www.w3.org/2000/svg"
|
355
|
+
xmlnsXlink="http://www.w3.org/1999/xlink"
|
356
|
+
>
|
357
|
+
<title>Google-color</title>
|
358
|
+
<desc>Created with Sketch.</desc>
|
359
|
+
<defs></defs>
|
360
|
+
<g
|
361
|
+
id="Icons"
|
362
|
+
stroke="none"
|
363
|
+
stroke-width="1"
|
364
|
+
fill="none"
|
365
|
+
fill-rule="evenodd"
|
366
|
+
>
|
367
|
+
<g id="Color-" transform="translate(-401.000000, -860.000000)">
|
368
|
+
<g id="Google" transform="translate(401.000000, 860.000000)">
|
369
|
+
<path
|
370
|
+
d="M9.82727273,24 C9.82727273,22.4757333 10.0804318,21.0144 10.5322727,19.6437333 L2.62345455,13.6042667 C1.08206818,16.7338667 0.213636364,20.2602667 0.213636364,24 C0.213636364,27.7365333 1.081,31.2608 2.62025,34.3882667 L10.5247955,28.3370667 C10.0772273,26.9728 9.82727273,25.5168 9.82727273,24"
|
371
|
+
id="Fill-1"
|
372
|
+
fill="#FBBC05"
|
373
|
+
></path>
|
374
|
+
<path
|
375
|
+
d="M23.7136364,10.1333333 C27.025,10.1333333 30.0159091,11.3066667 32.3659091,13.2266667 L39.2022727,6.4 C35.0363636,2.77333333 29.6954545,0.533333333 23.7136364,0.533333333 C14.4268636,0.533333333 6.44540909,5.84426667 2.62345455,13.6042667 L10.5322727,19.6437333 C12.3545909,14.112 17.5491591,10.1333333 23.7136364,10.1333333"
|
376
|
+
id="Fill-2"
|
377
|
+
fill="#EB4335"
|
378
|
+
></path>
|
379
|
+
<path
|
380
|
+
d="M23.7136364,37.8666667 C17.5491591,37.8666667 12.3545909,33.888 10.5322727,28.3562667 L2.62345455,34.3946667 C6.44540909,42.1557333 14.4268636,47.4666667 23.7136364,47.4666667 C29.4455,47.4666667 34.9177955,45.4314667 39.0249545,41.6181333 L31.5177727,35.8144 C29.3995682,37.1488 26.7323182,37.8666667 23.7136364,37.8666667"
|
381
|
+
id="Fill-3"
|
382
|
+
fill="#34A853"
|
383
|
+
></path>
|
384
|
+
<path
|
385
|
+
d="M46.1454545,24 C46.1454545,22.6133333 45.9318182,21.12 45.6113636,19.7333333 L23.7136364,19.7333333 L23.7136364,28.8 L36.3181818,28.8 C35.6879545,31.8912 33.9724545,34.2677333 31.5177727,35.8144 L39.0249545,41.6181333 C43.3393409,37.6138667 46.1454545,31.6490667 46.1454545,24"
|
386
|
+
id="Fill-4"
|
387
|
+
fill="#4285F4"
|
388
|
+
></path>
|
389
|
+
</g>
|
390
|
+
</g>
|
391
|
+
</g>
|
392
|
+
</svg>
|
393
|
+
),
|
348
394
|
}
|
@@ -4,6 +4,7 @@ import mammoth from "mammoth"
|
|
4
4
|
import { SVGS } from "../assets/svgs"
|
5
5
|
import pdfWorker from "pdfjs-dist/build/pdf.worker?worker"
|
6
6
|
import { ContentCard } from "./ContentCard"
|
7
|
+
import useStore from "../utils/store"
|
7
8
|
|
8
9
|
pdfjsLib.GlobalWorkerOptions.workerPort = new pdfWorker()
|
9
10
|
|
@@ -20,16 +21,16 @@ export interface ParsedFile {
|
|
20
21
|
}
|
21
22
|
|
22
23
|
interface FileUploaderProps {
|
23
|
-
onResult: (files: ParsedFile[]) => void
|
24
|
+
// onResult: (files: ParsedFile[]) => void
|
24
25
|
styledAs?: "button" | "card"
|
25
26
|
}
|
26
27
|
|
27
|
-
const FileUploader: React.FC<FileUploaderProps> = ({
|
28
|
-
onResult,
|
29
|
-
styledAs = "button",
|
30
|
-
}) => {
|
28
|
+
const FileUploader: React.FC<FileUploaderProps> = ({ styledAs = "button" }) => {
|
31
29
|
const inputRef = useRef<HTMLInputElement>(null)
|
30
|
+
const uploadedFiles = useStore((state) => state.uploadedFiles)
|
31
|
+
const setUploadedFiles = useStore((state) => state.setUploadedFiles)
|
32
32
|
const [isDragging, setIsDragging] = useState(false)
|
33
|
+
// const [parsedFiles, setParsedFiles] = useState<ParsedFile[]>([]) F
|
33
34
|
|
34
35
|
const extractText = async (file: File): Promise<ParsedFile> => {
|
35
36
|
const { type, name } = file
|
@@ -66,13 +67,12 @@ const FileUploader: React.FC<FileUploaderProps> = ({
|
|
66
67
|
allowedTypes.includes(file.type)
|
67
68
|
)
|
68
69
|
const parsed = await Promise.all(validFiles.map(extractText))
|
69
|
-
|
70
|
-
onResult(parsed)
|
70
|
+
setUploadedFiles([...uploadedFiles, ...parsed])
|
71
71
|
}
|
72
72
|
|
73
|
-
const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
|
73
|
+
const handleInput = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
74
74
|
if (!e.target.files) return
|
75
|
-
parseFiles(e.target.files)
|
75
|
+
await parseFiles(e.target.files)
|
76
76
|
}
|
77
77
|
|
78
78
|
const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
|
@@ -84,14 +84,30 @@ const FileUploader: React.FC<FileUploaderProps> = ({
|
|
84
84
|
}
|
85
85
|
|
86
86
|
return (
|
87
|
-
|
87
|
+
<div className="flex flex-col gap-2 w-full">
|
88
|
+
{uploadedFiles.length > 0 && styledAs === "card" && (
|
89
|
+
<div className="w-full flex flex-row gap-2 flex-wrap justify-center items-center ">
|
90
|
+
{uploadedFiles.map((file, idx) => (
|
91
|
+
<div
|
92
|
+
key={idx}
|
93
|
+
className="p-3 rounded-md bg-white shadow-sm text-sm text-gray-800 text-left "
|
94
|
+
title={file.name}
|
95
|
+
>
|
96
|
+
<strong>{file.name.slice(0, 20)}...</strong>
|
97
|
+
<button
|
98
|
+
className="text-gray-600 mt-1 float-right cursor-pointer"
|
99
|
+
onClick={() =>
|
100
|
+
setUploadedFiles(uploadedFiles.filter((_, i) => i !== idx))
|
101
|
+
}
|
102
|
+
>
|
103
|
+
{SVGS.trash}
|
104
|
+
</button>
|
105
|
+
</div>
|
106
|
+
))}
|
107
|
+
</div>
|
108
|
+
)}
|
88
109
|
{styledAs === "button" && (
|
89
|
-
<div
|
90
|
-
className="flex items-center justify-center"
|
91
|
-
onDragOver={() => setIsDragging(true)}
|
92
|
-
onDragLeave={() => setIsDragging(false)}
|
93
|
-
onDrop={handleDrop}
|
94
|
-
>
|
110
|
+
<div className="flex items-center justify-end gap-2 w-100">
|
95
111
|
<button
|
96
112
|
type="button"
|
97
113
|
className="cursor-pointer blue-on-hover flex items-center justify-center w-6 h-6"
|
@@ -101,22 +117,28 @@ const FileUploader: React.FC<FileUploaderProps> = ({
|
|
101
117
|
</button>
|
102
118
|
</div>
|
103
119
|
)}
|
120
|
+
|
104
121
|
{styledAs === "card" && (
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
122
|
+
<>
|
123
|
+
<ContentCard
|
124
|
+
description={
|
125
|
+
isDragging
|
126
|
+
? "Drop it here"
|
127
|
+
: "Upload a PDF or DOCX file or drag it here"
|
128
|
+
}
|
129
|
+
icon={isDragging ? SVGS.clip : SVGS.pdf}
|
130
|
+
onClick={() => inputRef.current?.click()}
|
131
|
+
onDragOver={(e) => {
|
132
|
+
e.preventDefault()
|
133
|
+
setIsDragging(true)
|
134
|
+
}}
|
135
|
+
onDragLeave={() => setIsDragging(false)}
|
136
|
+
onDrop={handleDrop}
|
137
|
+
className={isDragging ? "border-blue-600 bg-blue-50" : ""}
|
138
|
+
/>
|
139
|
+
</>
|
119
140
|
)}
|
141
|
+
|
120
142
|
<input
|
121
143
|
ref={inputRef}
|
122
144
|
type="file"
|
@@ -125,7 +147,7 @@ const FileUploader: React.FC<FileUploaderProps> = ({
|
|
125
147
|
onChange={handleInput}
|
126
148
|
style={{ display: "none" }}
|
127
149
|
/>
|
128
|
-
|
150
|
+
</div>
|
129
151
|
)
|
130
152
|
}
|
131
153
|
|
@@ -59,6 +59,11 @@ export default function Login({ onFinish }: { onFinish: () => void }) {
|
|
59
59
|
window.location.href = `${BREATHECODE_HOST}/v1/auth/github/?url=${url}`
|
60
60
|
}
|
61
61
|
|
62
|
+
const redirectGoogle = () => {
|
63
|
+
const url = stringToBase64(getCurrentUrlWithQueryParams())
|
64
|
+
window.location.href = `${BREATHECODE_HOST}/v1/auth/google?url=${url}`
|
65
|
+
}
|
66
|
+
|
62
67
|
return (
|
63
68
|
<div
|
64
69
|
className="fixed inset-0 bg-black/50 flex items-center justify-center z-1000"
|
@@ -78,6 +83,12 @@ export default function Login({ onFinish }: { onFinish: () => void }) {
|
|
78
83
|
>
|
79
84
|
{SVGS.github} LOGIN WITH GITHUB
|
80
85
|
</button>
|
86
|
+
<button
|
87
|
+
onClick={redirectGoogle}
|
88
|
+
className="w-full border border-gray-300 py-2 rounded-md font-semibold flex items-center justify-center gap-2 mb-4 cursor-pointer"
|
89
|
+
>
|
90
|
+
{SVGS.google} LOGIN WITH GOOGLE
|
91
|
+
</button>
|
81
92
|
|
82
93
|
<div className="flex items-center mb-4">
|
83
94
|
<hr className="flex-grow border-gray-300" />
|
@@ -34,10 +34,10 @@ const PreviewGenerator: React.FC = () => {
|
|
34
34
|
html2canvas(previewElement, {
|
35
35
|
useCORS: true,
|
36
36
|
}).then(async (canvas) => {
|
37
|
-
const anchor = document.createElement("a")
|
38
|
-
anchor.href = canvas.toDataURL("image/png")
|
39
|
-
anchor.download = "preview.png"
|
40
|
-
anchor.click()
|
37
|
+
// const anchor = document.createElement("a")
|
38
|
+
// anchor.href = canvas.toDataURL("image/png")
|
39
|
+
// anchor.download = "preview.png"
|
40
|
+
// anchor.click()
|
41
41
|
|
42
42
|
const imageUrl = canvas.toDataURL("image/png")
|
43
43
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import React from "react"
|
2
2
|
import { ParsedLink } from "./LinkUploader"
|
3
|
-
import useStore from "../utils/store"
|
3
|
+
// import useStore from "../utils/store"
|
4
4
|
import { SVGS } from "../assets/svgs"
|
5
5
|
|
6
6
|
interface SourceProps {
|
@@ -14,8 +14,8 @@ interface SourceProps {
|
|
14
14
|
// }
|
15
15
|
|
16
16
|
const Source: React.FC<SourceProps> = ({ source }) => {
|
17
|
-
const setFormState = useStore((state) => state.setFormState)
|
18
|
-
const formState = useStore((state) => state.formState)
|
17
|
+
// const setFormState = useStore((state) => state.setFormState)
|
18
|
+
// const formState = useStore((state) => state.formState)
|
19
19
|
|
20
20
|
const {
|
21
21
|
url,
|
@@ -28,18 +28,16 @@ const Source: React.FC<SourceProps> = ({ source }) => {
|
|
28
28
|
// text,
|
29
29
|
} = source
|
30
30
|
|
31
|
-
|
32
|
-
|
33
31
|
return (
|
34
32
|
<div className="relative max-w-xs bg-white rounded-xl shadow-md overflow-hidden hover:shadow-lg transition-shadow">
|
35
33
|
<div className="p-4 flex flex-col space-y-2">
|
36
34
|
<button
|
37
35
|
className="absolute top-2 right-2"
|
38
|
-
onClick={() => {
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
}}
|
36
|
+
// onClick={() => {
|
37
|
+
// setFormState({
|
38
|
+
// sources: formState.sources.filter((s) => s !== source),
|
39
|
+
// })
|
40
|
+
// }}
|
43
41
|
>
|
44
42
|
{SVGS.redClose}
|
45
43
|
</button>
|
@@ -31,7 +31,7 @@ const StepWizard: React.FC<Props> = ({
|
|
31
31
|
|
32
32
|
const goNext = () => {
|
33
33
|
const index = steps.findIndex((step) => step.slug === currentStep)
|
34
|
-
if (steps[index].required && !
|
34
|
+
if (steps[index].required && !steps[index].isCompleted) {
|
35
35
|
toast.error("Please fill out all required fields!")
|
36
36
|
return
|
37
37
|
}
|
@@ -48,6 +48,8 @@ const StepWizard: React.FC<Props> = ({
|
|
48
48
|
setFormState({ ...formState, currentStep: steps[index - 1].slug })
|
49
49
|
}
|
50
50
|
|
51
|
+
console.log(index, totalSteps, steps)
|
52
|
+
|
51
53
|
return (
|
52
54
|
<div className="min-h-screen flex flex-col items-center justify-center text-center px-4">
|
53
55
|
<div className=" rounded-xl p-8 w-full max-w-xl">
|
@@ -87,22 +89,23 @@ const StepWizard: React.FC<Props> = ({
|
|
87
89
|
{steps.find((step) => step.slug === currentStep)?.content}
|
88
90
|
</div>
|
89
91
|
|
90
|
-
{/* Dot Indicators */}
|
91
|
-
|
92
|
-
{/* Navigation */}
|
93
92
|
<div className="flex justify-between">
|
94
93
|
<button
|
95
94
|
onClick={goBack}
|
96
95
|
disabled={index === 0}
|
97
|
-
className=
|
96
|
+
className={`text-sm text-gray-500 hover:text-gray-900 disabled:opacity-40 ${
|
97
|
+
index === 0 ? "cursor-not-allowed" : "cursor-pointer"
|
98
|
+
}`}
|
98
99
|
>
|
99
100
|
⬅ Back
|
100
101
|
</button>
|
101
102
|
<button
|
102
103
|
onClick={index === totalSteps - 1 ? onFinish : goNext}
|
103
|
-
className=
|
104
|
+
className={`text-sm text-blue-600 hover:text-blue-800 cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed p-2 rounded-md ${
|
105
|
+
index === totalSteps - 1 ? "bg-blue-600 text-white" : ""
|
106
|
+
}`}
|
104
107
|
>
|
105
|
-
Next ➡
|
108
|
+
{index === totalSteps - 1 ? "Finish 🚀" : "Next ➡"}
|
106
109
|
</button>
|
107
110
|
</div>
|
108
111
|
</div>
|
@@ -45,17 +45,12 @@ export const Uploader = ({
|
|
45
45
|
icon={SVGS.contentTable}
|
46
46
|
onClick={() => handleSelectOption("text")}
|
47
47
|
/>
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
onFinish(
|
53
|
-
`The following information comes from a PDF file uploaded by the user: ${JSON.stringify(
|
54
|
-
file
|
55
|
-
)}`
|
56
|
-
)
|
57
|
-
}}
|
48
|
+
<ContentCard
|
49
|
+
description="Upload files"
|
50
|
+
icon={SVGS.pdf}
|
51
|
+
onClick={() => handleSelectOption("files")}
|
58
52
|
/>
|
53
|
+
|
59
54
|
<ContentCard
|
60
55
|
description="Share a Youtube link"
|
61
56
|
icon={SVGS.youtube}
|
@@ -66,6 +61,8 @@ export const Uploader = ({
|
|
66
61
|
|
67
62
|
{selectedOption === "text" && <TextUploader onFinish={onFinish} />}
|
68
63
|
|
64
|
+
{selectedOption === "files" && <FileUploader styledAs="card" />}
|
65
|
+
|
69
66
|
{selectedOption === "youtube" && (
|
70
67
|
<LinkUploader
|
71
68
|
onResult={(link) => {
|