@learnpack/learnpack 5.0.146 → 5.0.150
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 +11 -6
- package/lib/creatorDist/assets/{index-CzMCewx6.js → index-CkzbY9Qa.js} +32902 -36358
- package/lib/creatorDist/assets/{index-DSOj0E0h.css → index-CztA582_.css} +25 -20
- package/lib/creatorDist/index.html +2 -2
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/src/commands/serve.ts +15 -6
- package/src/creator/src/App.tsx +31 -16
- package/src/creator/src/components/ConsumablesManager.tsx +1 -0
- package/src/creator/src/components/ContentCard.tsx +28 -7
- package/src/creator/src/components/FileUploader.tsx +44 -17
- package/src/creator/src/components/Loader.tsx +1 -1
- package/src/creator/src/components/PreviewGenerator.tsx +13 -11
- package/src/creator/src/components/TurnstileChallenge.tsx +2 -9
- package/src/creator/src/components/syllabus/ContentIndex.tsx +2 -2
- package/src/creator/src/components/syllabus/Sidebar.tsx +23 -23
- package/src/creator/src/components/syllabus/SyllabusEditor.tsx +4 -1
- package/src/creator/src/index.css +0 -5
- package/src/creator/src/utils/creatorUtils.ts +1 -141
- package/src/creator/src/utils/rigo.ts +22 -377
- package/src/creatorDist/assets/{index-CzMCewx6.js → index-CkzbY9Qa.js} +32902 -36358
- package/src/creatorDist/assets/{index-DSOj0E0h.css → index-CztA582_.css} +25 -20
- package/src/creatorDist/index.html +2 -2
- package/src/ui/_app/app.css +1 -1
- package/src/ui/_app/app.js +245 -245
- package/src/ui/app.tar.gz +0 -0
@@ -98,6 +98,8 @@
|
|
98
98
|
--text-2xl--line-height: calc(2 / 1.5);
|
99
99
|
--text-4xl: 2.25rem;
|
100
100
|
--text-4xl--line-height: calc(2.5 / 2.25);
|
101
|
+
--text-7xl: 4.5rem;
|
102
|
+
--text-7xl--line-height: 1;
|
101
103
|
--font-weight-medium: 500;
|
102
104
|
--font-weight-semibold: 600;
|
103
105
|
--font-weight-bold: 700;
|
@@ -393,9 +395,6 @@
|
|
393
395
|
.top-2 {
|
394
396
|
top: calc(var(--spacing) * 2);
|
395
397
|
}
|
396
|
-
.right-0 {
|
397
|
-
right: calc(var(--spacing) * 0);
|
398
|
-
}
|
399
398
|
.right-2 {
|
400
399
|
right: calc(var(--spacing) * 2);
|
401
400
|
}
|
@@ -426,11 +425,11 @@
|
|
426
425
|
.z-10 {
|
427
426
|
z-index: 10;
|
428
427
|
}
|
429
|
-
.z-
|
430
|
-
z-index:
|
428
|
+
.z-30 {
|
429
|
+
z-index: 30;
|
431
430
|
}
|
432
|
-
.z-
|
433
|
-
z-index:
|
431
|
+
.z-31 {
|
432
|
+
z-index: 31;
|
434
433
|
}
|
435
434
|
.z-50 {
|
436
435
|
z-index: 50;
|
@@ -496,6 +495,12 @@
|
|
496
495
|
.mt-6 {
|
497
496
|
margin-top: calc(var(--spacing) * 6);
|
498
497
|
}
|
498
|
+
.mt-10 {
|
499
|
+
margin-top: calc(var(--spacing) * 10);
|
500
|
+
}
|
501
|
+
.mt-14 {
|
502
|
+
margin-top: calc(var(--spacing) * 14);
|
503
|
+
}
|
499
504
|
.mr-1 {
|
500
505
|
margin-right: calc(var(--spacing) * 1);
|
501
506
|
}
|
@@ -517,18 +522,12 @@
|
|
517
522
|
.ml-auto {
|
518
523
|
margin-left: auto;
|
519
524
|
}
|
520
|
-
.block {
|
521
|
-
display: block;
|
522
|
-
}
|
523
525
|
.flex {
|
524
526
|
display: flex;
|
525
527
|
}
|
526
528
|
.hidden {
|
527
529
|
display: none;
|
528
530
|
}
|
529
|
-
.inline {
|
530
|
-
display: inline;
|
531
|
-
}
|
532
531
|
.inline-block {
|
533
532
|
display: inline-block;
|
534
533
|
}
|
@@ -613,6 +612,9 @@
|
|
613
612
|
.w-\[100px\] {
|
614
613
|
width: 100px;
|
615
614
|
}
|
615
|
+
.w-\[280px\] {
|
616
|
+
width: 280px;
|
617
|
+
}
|
616
618
|
.w-full {
|
617
619
|
width: 100%;
|
618
620
|
}
|
@@ -707,9 +709,6 @@
|
|
707
709
|
.gap-3 {
|
708
710
|
gap: calc(var(--spacing) * 3);
|
709
711
|
}
|
710
|
-
.gap-4 {
|
711
|
-
gap: calc(var(--spacing) * 4);
|
712
|
-
}
|
713
712
|
:where(.space-y-2 > :not(:last-child)) {
|
714
713
|
--tw-space-y-reverse: 0;
|
715
714
|
margin-block-start: calc(
|
@@ -899,6 +898,9 @@
|
|
899
898
|
.p-8 {
|
900
899
|
padding: calc(var(--spacing) * 8);
|
901
900
|
}
|
901
|
+
.p-10 {
|
902
|
+
padding: calc(var(--spacing) * 10);
|
903
|
+
}
|
902
904
|
.px-2 {
|
903
905
|
padding-inline: calc(var(--spacing) * 2);
|
904
906
|
}
|
@@ -908,6 +910,9 @@
|
|
908
910
|
.px-4 {
|
909
911
|
padding-inline: calc(var(--spacing) * 4);
|
910
912
|
}
|
913
|
+
.px-20 {
|
914
|
+
padding-inline: calc(var(--spacing) * 20);
|
915
|
+
}
|
911
916
|
.py-1 {
|
912
917
|
padding-block: calc(var(--spacing) * 1);
|
913
918
|
}
|
@@ -943,6 +948,10 @@
|
|
943
948
|
font-size: var(--text-4xl);
|
944
949
|
line-height: var(--tw-leading, var(--text-4xl--line-height));
|
945
950
|
}
|
951
|
+
.text-7xl {
|
952
|
+
font-size: var(--text-7xl);
|
953
|
+
line-height: var(--tw-leading, var(--text-7xl--line-height));
|
954
|
+
}
|
946
955
|
.text-lg {
|
947
956
|
font-size: var(--text-lg);
|
948
957
|
line-height: var(--tw-leading, var(--text-lg--line-height));
|
@@ -1257,10 +1266,6 @@ body {
|
|
1257
1266
|
min-height: 100vh;
|
1258
1267
|
margin: 0;
|
1259
1268
|
}
|
1260
|
-
h1 {
|
1261
|
-
font-size: 3.2em;
|
1262
|
-
line-height: 1.1;
|
1263
|
-
}
|
1264
1269
|
.bg-learnpack-blue {
|
1265
1270
|
background-color: var(--soft-blue);
|
1266
1271
|
}
|
@@ -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-CkzbY9Qa.js"></script>
|
14
|
+
<link rel="stylesheet" crossorigin href="/creator/assets/index-CztA582_.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.150","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.150",
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
6
6
|
"contributors": [
|
7
7
|
{
|
package/src/commands/serve.ts
CHANGED
@@ -45,6 +45,11 @@ dotenv.config()
|
|
45
45
|
export const createLearnJson = (courseInfo: FormState) => {
|
46
46
|
console.log("courseInfo to create learn json", courseInfo)
|
47
47
|
|
48
|
+
const expectedPreviewUrl = `https://${slugify(
|
49
|
+
courseInfo.title as string
|
50
|
+
)}.learn-pack.com/preview.png`
|
51
|
+
console.log("Preview url in generated learn.json", expectedPreviewUrl)
|
52
|
+
|
48
53
|
const learnJson = {
|
49
54
|
slug: slugify(courseInfo.title as string),
|
50
55
|
title: {
|
@@ -59,7 +64,7 @@ export const createLearnJson = (courseInfo: FormState) => {
|
|
59
64
|
telemetry: {
|
60
65
|
batch: "https://breathecode.herokuapp.com/v1/assignment/me/telemetry",
|
61
66
|
},
|
62
|
-
preview:
|
67
|
+
preview: expectedPreviewUrl,
|
63
68
|
}
|
64
69
|
return learnJson
|
65
70
|
}
|
@@ -292,7 +297,7 @@ const fixPreviewUrl = (slug: string, previewUrl: string) => {
|
|
292
297
|
}
|
293
298
|
|
294
299
|
const expectedUrl = `https://${slug}.learn-pack.com/preview.png`
|
295
|
-
console.log("
|
300
|
+
console.log("Preview url fixed!", expectedUrl)
|
296
301
|
return expectedUrl
|
297
302
|
}
|
298
303
|
|
@@ -473,8 +478,13 @@ export default class ServeCommand extends SessionCommand {
|
|
473
478
|
|
474
479
|
app.get("/config", async (req, res) => {
|
475
480
|
const courseSlug = req.query.slug as string
|
481
|
+
// GEt the x-rigo-token
|
482
|
+
// const rigoToken = req.header("x-rigo-token")
|
483
|
+
|
476
484
|
if (!courseSlug) {
|
477
|
-
return res
|
485
|
+
return res
|
486
|
+
.status(400)
|
487
|
+
.json({ error: "Course slug and rigo token required" })
|
478
488
|
}
|
479
489
|
|
480
490
|
try {
|
@@ -878,15 +888,14 @@ export default class ServeCommand extends SessionCommand {
|
|
878
888
|
const { slug } = req.params
|
879
889
|
const rigoToken = req.header("x-rigo-token")
|
880
890
|
const bcToken = req.header("x-breathecode-token")
|
881
|
-
const { academyId, categoryId } = req.body
|
891
|
+
// const { academyId, categoryId } = req.body
|
882
892
|
|
883
|
-
if (!rigoToken || !bcToken
|
893
|
+
if (!rigoToken || !bcToken) {
|
884
894
|
return res
|
885
895
|
.status(400)
|
886
896
|
.json({ error: "Faltan tokens o academy/category" })
|
887
897
|
}
|
888
898
|
|
889
|
-
// 2) Leer y construir config.json vía buildConfig
|
890
899
|
const { config, exercises }: ConfigResponse = await buildConfig(
|
891
900
|
bucket,
|
892
901
|
slug
|
package/src/creator/src/App.tsx
CHANGED
@@ -6,13 +6,14 @@ import { useNavigate } from "react-router"
|
|
6
6
|
import { useShallow } from "zustand/react/shallow"
|
7
7
|
import useStore from "./utils/store"
|
8
8
|
|
9
|
-
import { interactiveCreation } from "./utils/rigo"
|
9
|
+
import { interactiveCreation, isHuman } from "./utils/rigo"
|
10
10
|
import { checkParams, loginWithToken, parseLesson } from "./utils/lib"
|
11
11
|
|
12
12
|
import { Uploader } from "./components/Uploader"
|
13
13
|
import toast from "react-hot-toast"
|
14
14
|
import { ParamsChecker } from "./components/ParamsChecker"
|
15
15
|
import { RIGO_FLOAT_GIT } from "./utils/constants"
|
16
|
+
import TurnstileChallenge from "./components/TurnstileChallenge"
|
16
17
|
// import TurnstileChallenge from "./components/TurnstileChallenge"
|
17
18
|
|
18
19
|
function App() {
|
@@ -126,6 +127,7 @@ function App() {
|
|
126
127
|
courseInfo: {
|
127
128
|
...formState,
|
128
129
|
title: res.parsed.title,
|
130
|
+
description: res.parsed.description,
|
129
131
|
},
|
130
132
|
})
|
131
133
|
navigate("/creator/syllabus")
|
@@ -212,7 +214,7 @@ function App() {
|
|
212
214
|
<>
|
213
215
|
<div className="flex flex-col md:flex-row gap-2 justify-center">
|
214
216
|
<SelectableCard
|
215
|
-
title="Yes"
|
217
|
+
title="📄 Yes"
|
216
218
|
onClick={() => {
|
217
219
|
setFormState({
|
218
220
|
hasContentIndex: true,
|
@@ -224,20 +226,12 @@ function App() {
|
|
224
226
|
selected={false}
|
225
227
|
/>
|
226
228
|
<SelectableCard
|
227
|
-
title="No, help me create one"
|
229
|
+
title="🛠️ No, help me create one"
|
228
230
|
onClick={() => {
|
229
|
-
if (!formState.contentIndex && !formState.description) {
|
230
|
-
toast.error(
|
231
|
-
"Please provide at least a description for your course!"
|
232
|
-
)
|
233
|
-
setFormState({
|
234
|
-
currentStep: "description",
|
235
|
-
})
|
236
|
-
return
|
237
|
-
}
|
238
231
|
setFormState({
|
239
232
|
hasContentIndex: false,
|
240
|
-
|
233
|
+
currentStep: "verifyHuman",
|
234
|
+
// isCompleted: true,
|
241
235
|
})
|
242
236
|
}}
|
243
237
|
selected={false}
|
@@ -257,12 +251,35 @@ function App() {
|
|
257
251
|
onFinish={(text) => {
|
258
252
|
setFormState({
|
259
253
|
contentIndex: text,
|
260
|
-
|
254
|
+
currentStep: "verifyHuman",
|
255
|
+
// isCompleted: true,
|
261
256
|
})
|
262
257
|
}}
|
263
258
|
/>
|
264
259
|
),
|
265
260
|
},
|
261
|
+
{
|
262
|
+
title: "Please verify you are a human",
|
263
|
+
slug: "verifyHuman",
|
264
|
+
isCompleted: false,
|
265
|
+
content: (
|
266
|
+
<TurnstileChallenge
|
267
|
+
siteKey={"0x4AAAAAABeKMBYYinMU4Ib0"}
|
268
|
+
onSuccess={async (token) => {
|
269
|
+
const _isHuman = await isHuman(token)
|
270
|
+
if (_isHuman) {
|
271
|
+
toast.success("You are a human! 👌🏻")
|
272
|
+
setFormState({ isCompleted: true })
|
273
|
+
} else {
|
274
|
+
toast.error("You are not a human! 🤖")
|
275
|
+
setFormState({
|
276
|
+
currentStep: "hasContentIndex",
|
277
|
+
})
|
278
|
+
}
|
279
|
+
}}
|
280
|
+
/>
|
281
|
+
),
|
282
|
+
},
|
266
283
|
]
|
267
284
|
|
268
285
|
return steps.filter(
|
@@ -274,8 +291,6 @@ function App() {
|
|
274
291
|
return (
|
275
292
|
<>
|
276
293
|
<ParamsChecker />
|
277
|
-
{/* <div id="turnstile-container" style={{ display: "none" }} /> */}
|
278
|
-
|
279
294
|
{formState.isCompleted ? (
|
280
295
|
<Loader
|
281
296
|
text="Learnpack is setting up your tutorial. It may take a moment..."
|
@@ -16,6 +16,7 @@ export const ConsumablesManager = () => {
|
|
16
16
|
const fetchConsumables = async () => {
|
17
17
|
try {
|
18
18
|
const consumables = await getConsumables(auth.bcToken)
|
19
|
+
console.log("CONSUMABLES", parseConsumables(consumables.voids))
|
19
20
|
setConsumables(parseConsumables(consumables.voids))
|
20
21
|
} catch (error) {
|
21
22
|
setAuth({
|
@@ -1,21 +1,42 @@
|
|
1
|
-
|
1
|
+
import React from "react"
|
2
|
+
|
3
|
+
interface ContentCardProps {
|
4
|
+
description: string
|
5
|
+
icon: React.ReactNode
|
6
|
+
className?: string
|
7
|
+
children?: React.ReactNode
|
8
|
+
onClick?: () => void
|
9
|
+
onDragOver?: (e: React.DragEvent<HTMLDivElement>) => void
|
10
|
+
onDrop?: (e: React.DragEvent<HTMLDivElement>) => void
|
11
|
+
onDragEnter?: (e: React.DragEvent<HTMLDivElement>) => void
|
12
|
+
onDragLeave?: (e: React.DragEvent<HTMLDivElement>) => void
|
13
|
+
}
|
14
|
+
|
15
|
+
export const ContentCard: React.FC<ContentCardProps> = ({
|
2
16
|
description,
|
3
17
|
icon,
|
18
|
+
className = "",
|
19
|
+
children,
|
4
20
|
onClick,
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
21
|
+
onDragOver,
|
22
|
+
onDrop,
|
23
|
+
onDragEnter,
|
24
|
+
onDragLeave,
|
9
25
|
}) => {
|
10
26
|
return (
|
11
27
|
<div
|
12
|
-
className=
|
28
|
+
className={`flex flex-col items-center justify-center gap-2 bg-white card p-4 rounded-lg shadow-md min-w-[250px] w-full h-[150px] cursor-pointer transition border border-gray-200 hover:shadow-lg ${className}`}
|
13
29
|
onClick={onClick}
|
30
|
+
onDragOver={onDragOver}
|
31
|
+
onDrop={onDrop}
|
32
|
+
onDragEnter={onDragEnter}
|
33
|
+
onDragLeave={onDragLeave}
|
14
34
|
>
|
15
35
|
<div className="text-blue-500 flex justify-center items-center">
|
16
36
|
{icon}
|
17
37
|
</div>
|
18
|
-
<span className="text-sm text-center">{description}</span>
|
38
|
+
<span className="text-sm text-center text-gray-700">{description}</span>
|
39
|
+
{children}
|
19
40
|
</div>
|
20
41
|
)
|
21
42
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, { useRef } from "react"
|
1
|
+
import React, { useRef, useState } from "react"
|
2
2
|
import * as pdfjsLib from "pdfjs-dist"
|
3
3
|
import mammoth from "mammoth"
|
4
4
|
import { SVGS } from "../assets/svgs"
|
@@ -29,6 +29,7 @@ const FileUploader: React.FC<FileUploaderProps> = ({
|
|
29
29
|
styledAs = "button",
|
30
30
|
}) => {
|
31
31
|
const inputRef = useRef<HTMLInputElement>(null)
|
32
|
+
const [isDragging, setIsDragging] = useState(false)
|
32
33
|
|
33
34
|
const extractText = async (file: File): Promise<ParsedFile> => {
|
34
35
|
const { type, name } = file
|
@@ -60,42 +61,68 @@ const FileUploader: React.FC<FileUploaderProps> = ({
|
|
60
61
|
return { name, text }
|
61
62
|
}
|
62
63
|
|
63
|
-
const
|
64
|
-
const
|
65
|
-
if (!inputFiles) return
|
66
|
-
|
67
|
-
const files = Array.from(inputFiles).filter((file) =>
|
64
|
+
const parseFiles = async (files: FileList | File[]) => {
|
65
|
+
const validFiles = Array.from(files).filter((file) =>
|
68
66
|
allowedTypes.includes(file.type)
|
69
67
|
)
|
70
|
-
const parsed = await Promise.all(
|
68
|
+
const parsed = await Promise.all(validFiles.map(extractText))
|
69
|
+
console.log(parsed, "parsed files")
|
71
70
|
onResult(parsed)
|
72
71
|
}
|
73
72
|
|
73
|
+
const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
|
74
|
+
if (!e.target.files) return
|
75
|
+
parseFiles(e.target.files)
|
76
|
+
}
|
77
|
+
|
78
|
+
const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
|
79
|
+
e.preventDefault()
|
80
|
+
setIsDragging(false)
|
81
|
+
if (e.dataTransfer.files.length > 0) {
|
82
|
+
parseFiles(e.dataTransfer.files)
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
74
86
|
return (
|
75
87
|
<>
|
76
88
|
{styledAs === "button" && (
|
77
|
-
<
|
78
|
-
|
79
|
-
|
80
|
-
|
89
|
+
<div
|
90
|
+
className="flex items-center justify-center"
|
91
|
+
onDragOver={() => setIsDragging(true)}
|
92
|
+
onDragLeave={() => setIsDragging(false)}
|
93
|
+
onDrop={handleDrop}
|
81
94
|
>
|
82
|
-
|
83
|
-
|
95
|
+
<button
|
96
|
+
type="button"
|
97
|
+
className="cursor-pointer blue-on-hover flex items-center justify-center w-6 h-6"
|
98
|
+
onClick={() => inputRef.current?.click()}
|
99
|
+
>
|
100
|
+
{SVGS.clip}
|
101
|
+
</button>
|
102
|
+
</div>
|
84
103
|
)}
|
85
104
|
{styledAs === "card" && (
|
86
105
|
<ContentCard
|
87
|
-
description=
|
88
|
-
|
106
|
+
description={
|
107
|
+
isDragging ? "Drop it here" : "Upload a PDF or drag it here"
|
108
|
+
}
|
109
|
+
icon={isDragging ? SVGS.clip : SVGS.pdf}
|
89
110
|
onClick={() => inputRef.current?.click()}
|
111
|
+
onDragOver={(e) => {
|
112
|
+
e.preventDefault()
|
113
|
+
setIsDragging(true)
|
114
|
+
}}
|
115
|
+
onDragLeave={() => setIsDragging(false)}
|
116
|
+
onDrop={handleDrop}
|
117
|
+
className={isDragging ? "border-blue-600 bg-blue-50" : ""}
|
90
118
|
/>
|
91
119
|
)}
|
92
|
-
|
93
120
|
<input
|
94
121
|
ref={inputRef}
|
95
122
|
type="file"
|
96
123
|
multiple
|
97
124
|
accept=".pdf,.docx,.txt,.md"
|
98
|
-
onChange={
|
125
|
+
onChange={handleInput}
|
99
126
|
style={{ display: "none" }}
|
100
127
|
/>
|
101
128
|
</>
|
@@ -46,7 +46,7 @@ const Loader: React.FC<LoaderProps> = ({
|
|
46
46
|
className={`flex flex-col items-center justify-center bg-gray-50 text-center space-y-6 ${minheight}`}
|
47
47
|
>
|
48
48
|
<div className="text-blue-500 text-4xl animate-pulse">{icon}</div>
|
49
|
-
<p className="text-gray-800 text-lg whitespace-pre-line">{text}</p>
|
49
|
+
<p className="text-gray-800 text-lg whitespace-pre-line px-4">{text}</p>
|
50
50
|
{!buffer && (
|
51
51
|
<div className="flex space-x-2 mt-2">
|
52
52
|
{[0, 1, 2, 3].map((i) => (
|
@@ -34,10 +34,10 @@ const PreviewGenerator: React.FC = () => {
|
|
34
34
|
html2canvas(previewElement, {
|
35
35
|
useCORS: true,
|
36
36
|
}).then(async (canvas) => {
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|
|
@@ -55,7 +55,7 @@ const PreviewGenerator: React.FC = () => {
|
|
55
55
|
}, [])
|
56
56
|
|
57
57
|
return (
|
58
|
-
<div className="fixed">
|
58
|
+
<div className="fixed bg-white z-50 border-2 border-gray-200 ">
|
59
59
|
<div
|
60
60
|
id="preview"
|
61
61
|
style={{
|
@@ -64,18 +64,20 @@ const PreviewGenerator: React.FC = () => {
|
|
64
64
|
background: "white",
|
65
65
|
}}
|
66
66
|
>
|
67
|
-
<div className="bg-learnpack-blue p-
|
68
|
-
<div className="px-
|
69
|
-
<h1 className="text-
|
70
|
-
|
71
|
-
|
67
|
+
<div className="bg-learnpack-blue p-10 rounded-md" />
|
68
|
+
<div className="px-20 -mt-5">
|
69
|
+
<h1 className="text-7xl font-bold mt-14">
|
70
|
+
{syllabus.courseInfo?.title}
|
71
|
+
</h1>
|
72
|
+
{/* <p className="mt-5 text-sm">{syllabus.courseInfo?.description}</p> */}
|
73
|
+
<div className="flex items-center gap-2 mt-10">
|
72
74
|
<img
|
73
75
|
src={proxify(auth.user?.profile?.avatar_url || "")}
|
74
76
|
alt="Profile"
|
75
77
|
className="w-10 h-10 rounded-full mt-3"
|
76
78
|
/>
|
77
79
|
<div>
|
78
|
-
<p className=" text-sm font-bold">
|
80
|
+
<p className=" text-sm font-bold ">
|
79
81
|
Author: {auth.user?.first_name} {auth.user?.last_name}
|
80
82
|
</p>
|
81
83
|
<small className=" text-sm">
|
@@ -61,18 +61,11 @@ const TurnstileChallenge = ({
|
|
61
61
|
return () => clearInterval(interval)
|
62
62
|
}, [siteKey, autoStart, onSuccess, onError])
|
63
63
|
|
64
|
-
// const reset = () => {
|
65
|
-
// if (widgetId.current && window.turnstile) {
|
66
|
-
// window.turnstile.reset(widgetId.current)
|
67
|
-
// }
|
68
|
-
// }
|
69
64
|
|
70
65
|
return (
|
71
|
-
|
66
|
+
|
72
67
|
<div className="">
|
73
|
-
|
74
|
-
We must verify you are human
|
75
|
-
</h3> */}
|
68
|
+
|
76
69
|
<div id={containerId} data-refresh-timeout="auto" />
|
77
70
|
{!ready && <p className="">...</p>}
|
78
71
|
{/* <button onClick={reset}>RESET</button> */}
|
@@ -244,11 +244,11 @@ export const ContentIndex = ({
|
|
244
244
|
{showScrollHint && !isThinking && (
|
245
245
|
<div className="pointer-events-none relative">
|
246
246
|
<div className="absolute bottom-0 left-0 w-full h-60 bg-gradient-to-t from-white to-transparent z-10" />
|
247
|
-
<div className="absolute bottom-10 left-0 w-full flex justify-center z-
|
247
|
+
<div className="absolute bottom-10 left-0 w-full flex justify-center z-31">
|
248
248
|
<button
|
249
249
|
style={{ color: "#0084FF" }}
|
250
250
|
onClick={() => scrollToBottom("bottom")}
|
251
|
-
className="px-4 py-1 bg-white text-sm rounded hover:bg-blue-50 cursor-pointer pointer-events-auto font-bold flex items-center gap-2"
|
251
|
+
className="px-4 py-1 bg-white text-sm rounded hover:bg-blue-50 cursor-pointer pointer-events-auto font-bold flex items-center gap-2 "
|
252
252
|
>
|
253
253
|
Continue scrolling
|
254
254
|
{SVGS.downArrow}
|