@learnpack/learnpack 5.0.198 → 5.0.202
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.d.ts +5 -28
- package/lib/commands/serve.js +45 -14
- package/lib/creatorDist/assets/index-C_HbkVCg.js +38491 -0
- package/lib/creatorDist/index.html +1 -1
- package/lib/models/creator.d.ts +30 -0
- package/lib/models/creator.js +2 -0
- package/lib/utils/creatorUtilities.js +3 -2
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/src/commands/serve.ts +58 -49
- package/src/creator/package-lock.json +97 -1
- package/src/creator/package.json +3 -0
- package/src/creator/src/App.tsx +48 -22
- package/src/creator/src/components/FileUploader.tsx +6 -5
- package/src/creator/src/components/LinkUploader.tsx +3 -1
- package/src/creator/src/components/Login.tsx +33 -27
- package/src/creator/src/components/PurposeSelector.tsx +32 -25
- package/src/creator/src/components/StepWizard.tsx +8 -4
- package/src/creator/src/components/Uploader.tsx +8 -5
- package/src/creator/src/components/syllabus/ContentIndex.tsx +17 -11
- package/src/creator/src/components/syllabus/Sidebar.tsx +4 -3
- package/src/creator/src/components/syllabus/SyllabusEditor.tsx +18 -2
- package/src/creator/src/i18n.ts +28 -0
- package/src/creator/src/locales/en.json +110 -0
- package/src/creator/src/locales/es.json +110 -0
- package/src/creator/src/main.tsx +1 -0
- package/src/creator/src/utils/creatorUtils.ts +2 -2
- package/src/creator/src/utils/lib.ts +7 -0
- package/src/creator/src/utils/store.ts +8 -5
- package/src/creatorDist/assets/index-C_HbkVCg.js +38491 -0
- package/src/creatorDist/index.html +1 -1
- package/src/models/creator.ts +32 -0
- package/src/ui/_app/app.css +1 -1
- package/src/ui/_app/app.js +55 -55
- package/src/ui/app.tar.gz +0 -0
- package/src/utils/creatorUtilities.ts +4 -4
- package/lib/creatorDist/assets/index-DszesaEz.js +0 -35438
- package/src/creatorDist/assets/index-DszesaEz.js +0 -35438
@@ -8,6 +8,7 @@ import { motion, AnimatePresence } from "framer-motion"
|
|
8
8
|
// import { randomUUID } from "../../utils/creatorUtils"
|
9
9
|
import toast from "react-hot-toast"
|
10
10
|
import { randomUUID } from "../../utils/creatorUtils"
|
11
|
+
import { useTranslation } from "react-i18next"
|
11
12
|
|
12
13
|
const ContentIndexHeader = ({
|
13
14
|
messages,
|
@@ -16,13 +17,16 @@ const ContentIndexHeader = ({
|
|
16
17
|
messages: TMessage[]
|
17
18
|
syllabus: Syllabus
|
18
19
|
}) => {
|
20
|
+
const { t } = useTranslation()
|
19
21
|
const isFirst =
|
20
22
|
messages.filter((m) => m.type === "assistant" && m.content.length > 0)
|
21
23
|
.length === 2
|
22
24
|
|
23
25
|
const headerText = isFirst
|
24
|
-
?
|
25
|
-
|
26
|
+
? t("contentIndexHeader.firstMessage", {
|
27
|
+
title: syllabus.courseInfo.title,
|
28
|
+
})
|
29
|
+
: t("contentIndexHeader.secondMessage")
|
26
30
|
|
27
31
|
return (
|
28
32
|
<div className="mt-2 ">
|
@@ -47,15 +51,14 @@ const ContentSecondaryHeader = ({
|
|
47
51
|
{
|
48
52
|
messages: TMessage[]
|
49
53
|
}) => {
|
54
|
+
const { t } = useTranslation()
|
50
55
|
const isFirst =
|
51
56
|
messages.filter((m) => m.type === "assistant" && m.content.length > 0)
|
52
57
|
.length === 2
|
53
58
|
|
54
59
|
const subText = isFirst
|
55
|
-
?
|
56
|
-
|
57
|
-
there are any changes you'd like to make.`
|
58
|
-
: "Based on your input, here is the new syllabus, updates are highlighted in yellow"
|
60
|
+
? t("contentIndex.subText.first")
|
61
|
+
: t("contentIndex.subText.second")
|
59
62
|
|
60
63
|
return (
|
61
64
|
<AnimatePresence mode="wait">
|
@@ -80,6 +83,7 @@ export const GenerateButton = ({
|
|
80
83
|
handleSubmit: () => void
|
81
84
|
openLogin: () => void
|
82
85
|
}) => {
|
86
|
+
const { t } = useTranslation()
|
83
87
|
const history = useStore((state) => state.history)
|
84
88
|
const undo = useStore((state) => state.undo)
|
85
89
|
const auth = useStore((state) => state.auth)
|
@@ -92,12 +96,12 @@ export const GenerateButton = ({
|
|
92
96
|
<button
|
93
97
|
onClick={() => {
|
94
98
|
undo()
|
95
|
-
toast.success("
|
99
|
+
toast.success(t("contentIndex.changesReverted"))
|
96
100
|
}}
|
97
101
|
className="w-full sm:w-auto text-gray-500 bg-gray-200 rounded px-4 py-2 hover:bg-gray-300 flex items-center justify-center gap-2 cursor-pointer"
|
98
102
|
>
|
99
103
|
{SVGS.undo}
|
100
|
-
|
104
|
+
{t("contentIndex.revertChanges")}
|
101
105
|
</button>
|
102
106
|
)}
|
103
107
|
|
@@ -105,7 +109,7 @@ export const GenerateButton = ({
|
|
105
109
|
onClick={handleSubmit}
|
106
110
|
className="w-full sm:w-auto bg-blue-600 text-white rounded px-4 py-2 hover:bg-blue-700 flex items-center justify-center gap-2 cursor-pointer"
|
107
111
|
>
|
108
|
-
<span>
|
112
|
+
<span>{t("contentIndex.readyToCreate")}</span>
|
109
113
|
{SVGS.rigoSoftBlue}
|
110
114
|
</button>
|
111
115
|
</div>
|
@@ -116,7 +120,9 @@ export const GenerateButton = ({
|
|
116
120
|
className="text-sm text-gray-500 rounded px-4 py-2 flex items-center justify-center gap-1 "
|
117
121
|
>
|
118
122
|
<span>
|
119
|
-
|
123
|
+
{t("contentIndex.creatingCourseAs", {
|
124
|
+
name: auth.user.first_name,
|
125
|
+
})}
|
120
126
|
</span>
|
121
127
|
<button
|
122
128
|
className="text-sm rounded items-center justify-center cursor-pointer text-blue-600"
|
@@ -131,7 +137,7 @@ export const GenerateButton = ({
|
|
131
137
|
openLogin()
|
132
138
|
}}
|
133
139
|
>
|
134
|
-
|
140
|
+
{t("contentIndex.loginAsSomeoneElse")}
|
135
141
|
</button>
|
136
142
|
</div>
|
137
143
|
)}
|
@@ -4,6 +4,7 @@ import FileUploader from "../FileUploader"
|
|
4
4
|
import { SVGS } from "../../assets/svgs"
|
5
5
|
import { Message } from "../Message"
|
6
6
|
import { FileCard } from "../FileCard"
|
7
|
+
import { useTranslation } from "react-i18next"
|
7
8
|
|
8
9
|
export const Sidebar = ({
|
9
10
|
// messages,
|
@@ -14,6 +15,8 @@ export const Sidebar = ({
|
|
14
15
|
sendPrompt: (prompt: string) => void
|
15
16
|
handleSubmit: () => void
|
16
17
|
}) => {
|
18
|
+
const { t } = useTranslation()
|
19
|
+
|
17
20
|
const sidebarRef = useRef<HTMLDivElement>(null)
|
18
21
|
const inputRef = useRef<HTMLTextAreaElement>(null)
|
19
22
|
const uploadedFiles = useStore((state) => state.uploadedFiles)
|
@@ -44,9 +47,7 @@ export const Sidebar = ({
|
|
44
47
|
<div
|
45
48
|
className={`flex flex-row gap-3 cloudy bg-white rounded-md p-2 shadow-md bg-learnpack-blue duration-500 border-2 border-blue-600 mb-4`}
|
46
49
|
>
|
47
|
-
<span className="w-[280px]">
|
48
|
-
Chat with me to update the course content
|
49
|
-
</span>
|
50
|
+
<span className="w-[280px]">{t("sidebar.chatWithMe")}</span>
|
50
51
|
<button
|
51
52
|
className=" text-red-500 cursor-pointer bg-learnpack-blue p-2 rounded-md"
|
52
53
|
onClick={() => setShowBubble(false)}
|
@@ -13,6 +13,7 @@ import {
|
|
13
13
|
reWriteTitle,
|
14
14
|
useConsumableCall,
|
15
15
|
isValidRigoToken,
|
16
|
+
fixTitleLength,
|
16
17
|
} from "../../utils/lib"
|
17
18
|
|
18
19
|
import Loader from "../Loader"
|
@@ -27,9 +28,11 @@ import { useNavigate } from "react-router"
|
|
27
28
|
import { ParamsChecker } from "../ParamsChecker"
|
28
29
|
import { slugify } from "../../utils/creatorUtils"
|
29
30
|
import { RIGO_FLOAT_GIF } from "../../utils/constants"
|
31
|
+
import { useTranslation } from "react-i18next"
|
30
32
|
|
31
33
|
const SyllabusEditor: React.FC = () => {
|
32
34
|
const navigate = useNavigate()
|
35
|
+
const { t, i18n } = useTranslation()
|
33
36
|
|
34
37
|
const { history, auth, setAuth, push, cleanAll, messages, setMessages } =
|
35
38
|
useStore(
|
@@ -128,6 +131,8 @@ const SyllabusEditor: React.FC = () => {
|
|
128
131
|
auth.rigoToken && isValid ? false : true
|
129
132
|
)
|
130
133
|
|
134
|
+
console.log(res, "RES from rigobot")
|
135
|
+
|
131
136
|
const lessons: Lesson[] = res.parsed.listOfSteps.map((step: any) =>
|
132
137
|
parseLesson(step, syllabus.lessons)
|
133
138
|
)
|
@@ -136,11 +141,20 @@ const SyllabusEditor: React.FC = () => {
|
|
136
141
|
lessons: lessons,
|
137
142
|
courseInfo: {
|
138
143
|
...syllabus.courseInfo,
|
139
|
-
title: res.parsed.title || syllabus.courseInfo.title,
|
144
|
+
title: fixTitleLength(res.parsed.title) || syllabus.courseInfo.title,
|
140
145
|
description:
|
141
146
|
res.parsed.description || syllabus.courseInfo.description,
|
147
|
+
language:
|
148
|
+
res.parsed.languageCode || syllabus.courseInfo.language || "en",
|
149
|
+
technologies:
|
150
|
+
res.parsed.technologies || syllabus.courseInfo.technologies || [],
|
142
151
|
},
|
143
152
|
})
|
153
|
+
|
154
|
+
if (res.parsed.languageCode) {
|
155
|
+
i18n.changeLanguage(res.parsed.languageCode)
|
156
|
+
}
|
157
|
+
|
144
158
|
const newMessages: TMessage[] = [
|
145
159
|
...messages,
|
146
160
|
{
|
@@ -213,12 +227,14 @@ const SyllabusEditor: React.FC = () => {
|
|
213
227
|
setIsGenerating(false)
|
214
228
|
window.location.href = `/preview/${slugify(
|
215
229
|
syllabus.courseInfo.title || ""
|
216
|
-
)}?token=${auth.bcToken}`
|
230
|
+
)}?token=${auth.bcToken}&language=${syllabus.courseInfo.language}`
|
217
231
|
}, 3000)
|
218
232
|
}
|
219
233
|
|
220
234
|
if (!syllabus) return null
|
221
235
|
|
236
|
+
console.log(syllabus, "SYLLABUS")
|
237
|
+
|
222
238
|
return isGenerating ? (
|
223
239
|
<>
|
224
240
|
<Loader
|
@@ -0,0 +1,28 @@
|
|
1
|
+
// src/i18n.ts
|
2
|
+
import i18n from "i18next"
|
3
|
+
import { initReactI18next } from "react-i18next"
|
4
|
+
import LanguageDetector from "i18next-browser-languagedetector"
|
5
|
+
|
6
|
+
import enTranslation from "./locales/en.json"
|
7
|
+
import esTranslation from "./locales/es.json"
|
8
|
+
|
9
|
+
i18n
|
10
|
+
.use(LanguageDetector)
|
11
|
+
.use(initReactI18next)
|
12
|
+
.init({
|
13
|
+
resources: {
|
14
|
+
en: { translation: enTranslation },
|
15
|
+
es: { translation: esTranslation },
|
16
|
+
},
|
17
|
+
fallbackLng: "en",
|
18
|
+
interpolation: {
|
19
|
+
escapeValue: false,
|
20
|
+
},
|
21
|
+
detection: {
|
22
|
+
// Puedes personalizar el orden de detección si lo deseas
|
23
|
+
order: ["querystring", "localStorage", "navigator"],
|
24
|
+
caches: ["localStorage"],
|
25
|
+
},
|
26
|
+
})
|
27
|
+
|
28
|
+
export default i18n
|
@@ -0,0 +1,110 @@
|
|
1
|
+
{
|
2
|
+
"contentIndexHeader": {
|
3
|
+
"firstMessage": "I've created a detailed structure for your course: {{title}}",
|
4
|
+
"secondMessage": "I've updated the structure based on your feedback."
|
5
|
+
},
|
6
|
+
"stepWizard": {
|
7
|
+
"requiredFields": "Please fill out all required fields!",
|
8
|
+
"subtitle": "Setting up your tutorial",
|
9
|
+
"back": "Back",
|
10
|
+
"next": "Next",
|
11
|
+
"finish": "Finish 🚀",
|
12
|
+
"description": "What do you want to learn?",
|
13
|
+
"descriptionPlaceholder": "Describe your course",
|
14
|
+
"duration": "What is the estimated duration for this tutorial?",
|
15
|
+
"durationCard": {
|
16
|
+
"30": "Around 30 minutes",
|
17
|
+
"60": "Around 1 hour",
|
18
|
+
"120": "Around 2 hours"
|
19
|
+
},
|
20
|
+
"purpose": "How would you like to use learnpack?",
|
21
|
+
"verifyHuman": "Please verify you are a human",
|
22
|
+
"humanSuccess": "You are a human! 👌🏻",
|
23
|
+
"hasContentIndex": "Any materials to get this course started?",
|
24
|
+
"hasContentIndexCard": {
|
25
|
+
"no": "❌ No, help me create one",
|
26
|
+
"yes": "✅ Yes"
|
27
|
+
},
|
28
|
+
"contentIndex": "Any materials to get this course started?",
|
29
|
+
"contentIndexHelpText": "It could be just text, paste an URL or even upload a document."
|
30
|
+
},
|
31
|
+
"purposeSelector": {
|
32
|
+
"learnpack-lesson-writer": {
|
33
|
+
"label": "Understand a new topic",
|
34
|
+
"description": "Learn about a new concept (e.g., ISO 27001 or exponential decay)."
|
35
|
+
},
|
36
|
+
"homework-and-exam-preparation-aid": {
|
37
|
+
"label": "Practice for an exam or homework",
|
38
|
+
"description": "Solve math problems or certification questions."
|
39
|
+
},
|
40
|
+
"skill-building-facilitator": {
|
41
|
+
"label": "Build real-world skills",
|
42
|
+
"description": "Apply concepts to projects, data science, or security audits."
|
43
|
+
},
|
44
|
+
"certification-preparation-specialist": {
|
45
|
+
"label": "Prepare for a certification",
|
46
|
+
"description": "Get ready for exams like ISO 27001 Lead Auditor."
|
47
|
+
}
|
48
|
+
},
|
49
|
+
"uploader": {
|
50
|
+
"text": {
|
51
|
+
"description": "Write or paste a content table",
|
52
|
+
"placeholder": "Add your text here...",
|
53
|
+
"finish": "Finish"
|
54
|
+
},
|
55
|
+
"files": {
|
56
|
+
"description": "Upload files",
|
57
|
+
"descriptionLong": "Upload a PDF or DOCX file or drag it here",
|
58
|
+
"processing": "Processing...",
|
59
|
+
"drop": "Drop it here",
|
60
|
+
"finish": "🚀 Finish"
|
61
|
+
},
|
62
|
+
"youtube": {
|
63
|
+
"description": "Share a Youtube link",
|
64
|
+
"placeholder": "Paste your link here…"
|
65
|
+
}
|
66
|
+
},
|
67
|
+
"loader": {
|
68
|
+
"text": "Learnpack is setting up your tutorial. It may take a moment..."
|
69
|
+
},
|
70
|
+
"sidebar": {
|
71
|
+
"chatWithMe": "Chat with me to update the course content"
|
72
|
+
},
|
73
|
+
"contentIndex": {
|
74
|
+
"subText": {
|
75
|
+
"first": "It includes a mix of reading, coding exercises, and quizzes. Give it a look and let me know if it aligns with your expectations or if there are any changes you'd like to make.",
|
76
|
+
"second": "Based on your input, here is the new syllabus, updates are highlighted in yellow"
|
77
|
+
},
|
78
|
+
"revertChanges": "Revert changes",
|
79
|
+
"changesReverted": "Changes reverted!",
|
80
|
+
"readyToCreate": "I'm ready. Create the course for me!",
|
81
|
+
"creatingCourseAs": "Creating the course as {{name}}",
|
82
|
+
"loginAsSomeoneElse": "Login as someone else"
|
83
|
+
},
|
84
|
+
"login": {
|
85
|
+
"creatingAccount": "Creating account…",
|
86
|
+
"loggedInSuccessfully": "Logged in successfully",
|
87
|
+
"invalidCredentials": "Invalid credentials",
|
88
|
+
"pleaseFillAllFields": "Please fill all fields",
|
89
|
+
"loggingIn": "Logging in…",
|
90
|
+
"accountCreated": "Account created! Check your email.",
|
91
|
+
"registrationFailed": "Registration failed. Try again.",
|
92
|
+
"createYourAccount": "Create your account",
|
93
|
+
"firstName": "First name",
|
94
|
+
"lastName": "Last name",
|
95
|
+
"alreadyHaveAnAccount": "Already have an account?",
|
96
|
+
"logInHere": "Log in here",
|
97
|
+
"youNeedToHaveAnAccount": "You need to have a 4Geeks account with a creator plan to create a tutorial.",
|
98
|
+
"loginWithGithub": "LOGIN WITH GITHUB",
|
99
|
+
"loginWithGoogle": "LOGIN WITH GOOGLE",
|
100
|
+
"or": "or",
|
101
|
+
"password": "Password",
|
102
|
+
"logIn": "Log in",
|
103
|
+
"skip": "Skip",
|
104
|
+
"forgotPassword": "Forgot your password?",
|
105
|
+
"recoverItHere": "Recover it here",
|
106
|
+
"loginWithEmail": "Login with Email",
|
107
|
+
"youDontHaveAnAccount": "You don't have an account?",
|
108
|
+
"registerHere": "Register here."
|
109
|
+
}
|
110
|
+
}
|
@@ -0,0 +1,110 @@
|
|
1
|
+
{
|
2
|
+
"contentIndexHeader": {
|
3
|
+
"firstMessage": "He creado una estructura detallada para tu curso: {{title}}",
|
4
|
+
"secondMessage": "He actualizado la estructura según tu feedback."
|
5
|
+
},
|
6
|
+
"stepWizard": {
|
7
|
+
"requiredFields": "Por favor, completa todos los campos requeridos.",
|
8
|
+
"subtitle": "Configurando tu tutorial",
|
9
|
+
"back": "Atrás",
|
10
|
+
"next": "Siguiente",
|
11
|
+
"finish": "Finalizar 🚀",
|
12
|
+
"description": "¿Qué quieres aprender?",
|
13
|
+
"descriptionPlaceholder": "Describe tu curso",
|
14
|
+
"duration": "¿Cuál es la duración estimada para este tutorial?",
|
15
|
+
"durationCard": {
|
16
|
+
"30": "Alrededor de 30 minutos",
|
17
|
+
"60": "Alrededor de 1 hora",
|
18
|
+
"120": "Alrededor de 2 horas"
|
19
|
+
},
|
20
|
+
"purpose": "¿Cómo te gustaría usar learnpack?",
|
21
|
+
"verifyHuman": "Por favor, verifica que eres un humano",
|
22
|
+
"humanSuccess": "¡Eres un humano! 👌🏻",
|
23
|
+
"hasContentIndex": "¿Hay algún material para empezar este curso?",
|
24
|
+
"hasContentIndexCard": {
|
25
|
+
"no": "❌ No, ayúdame a crear uno",
|
26
|
+
"yes": "✅ Sí"
|
27
|
+
},
|
28
|
+
"contentIndex": "¿Hay algún material para empezar este curso?",
|
29
|
+
"contentIndexHelpText": "Puede ser solo texto, pegar una URL o incluso subir un documento."
|
30
|
+
},
|
31
|
+
"purposeSelector": {
|
32
|
+
"learnpack-lesson-writer": {
|
33
|
+
"label": "Entender un nuevo tema",
|
34
|
+
"description": "Aprender sobre un nuevo concepto (ej. ISO 27001 o decaimiento exponencial)."
|
35
|
+
},
|
36
|
+
"homework-and-exam-preparation-aid": {
|
37
|
+
"label": "Practicar para un examen o tarea",
|
38
|
+
"description": "Resolver problemas matemáticos o preguntas de certificación."
|
39
|
+
},
|
40
|
+
"skill-building-facilitator": {
|
41
|
+
"label": "Construir habilidades reales",
|
42
|
+
"description": "Aplicar conceptos a proyectos, ciencia de datos o auditorías de seguridad."
|
43
|
+
},
|
44
|
+
"certification-preparation-specialist": {
|
45
|
+
"label": "Prepararse para una certificación",
|
46
|
+
"description": "Prepararse para exámenes como ISO 27001 Lead Auditor."
|
47
|
+
}
|
48
|
+
},
|
49
|
+
"uploader": {
|
50
|
+
"text": {
|
51
|
+
"description": "Escribir o pegar una tabla de contenido",
|
52
|
+
"placeholder": "Agrega tu texto aquí...",
|
53
|
+
"finish": "Finalizar"
|
54
|
+
},
|
55
|
+
"files": {
|
56
|
+
"description": "Subir archivos",
|
57
|
+
"descriptionLong": "Subir un archivo PDF o DOCX o arrastralo aquí",
|
58
|
+
"processing": "Procesando...",
|
59
|
+
"drop": "Arrastra el archivo aquí",
|
60
|
+
"finish": "🚀 Finalizar"
|
61
|
+
},
|
62
|
+
"youtube": {
|
63
|
+
"description": "Compartir un enlace de Youtube",
|
64
|
+
"placeholder": "Pega tu enlace aquí…"
|
65
|
+
}
|
66
|
+
},
|
67
|
+
"loader": {
|
68
|
+
"text": "Learnpack está configurando tu tutorial. Puede que tarde un momento..."
|
69
|
+
},
|
70
|
+
"sidebar": {
|
71
|
+
"chatWithMe": "Chatea conmigo para actualizar el contenido del curso"
|
72
|
+
},
|
73
|
+
"contentIndex": {
|
74
|
+
"subText": {
|
75
|
+
"first": "Incluye una mezcla de lectura, ejercicios de codificación y cuestionarios. Dále un vistazo y dímelo si coincide con tus expectativas o si hay algún cambio que te gustaría hacer.",
|
76
|
+
"second": "Basado en tu entrada, aquí está el nuevo plan de estudios, los cambios se resaltan en amarillo"
|
77
|
+
},
|
78
|
+
"revertChanges": "Revertir cambios",
|
79
|
+
"changesReverted": "Cambios revertidos!",
|
80
|
+
"readyToCreate": "Estoy listo. ¡Crea el curso por mí!",
|
81
|
+
"creatingCourseAs": "Creando el curso como {{name}}",
|
82
|
+
"loginAsSomeoneElse": "Iniciar sesión como alguien más"
|
83
|
+
},
|
84
|
+
"login": {
|
85
|
+
"creatingAccount": "Creando cuenta…",
|
86
|
+
"loggedInSuccessfully": "Inicio de sesión exitoso",
|
87
|
+
"invalidCredentials": "Credenciales inválidas",
|
88
|
+
"pleaseFillAllFields": "Por favor, completa todos los campos",
|
89
|
+
"loggingIn": "Iniciando sesión…",
|
90
|
+
"accountCreated": "Cuenta creada! Revisa tu correo.",
|
91
|
+
"registrationFailed": "Registro fallido. Intenta de nuevo.",
|
92
|
+
"createYourAccount": "Crear tu cuenta",
|
93
|
+
"firstName": "Nombre",
|
94
|
+
"lastName": "Apellido",
|
95
|
+
"alreadyHaveAnAccount": "¿Ya tienes una cuenta?",
|
96
|
+
"logInHere": "Iniciar sesión aquí",
|
97
|
+
"youNeedToHaveAnAccount": "Necesitas tener una cuenta en 4Geeks con un plan de creador para crear un tutorial.",
|
98
|
+
"loginWithGithub": "INICIAR SESIÓN CON GITHUB",
|
99
|
+
"loginWithGoogle": "INICIAR SESIÓN CON GOOGLE",
|
100
|
+
"or": "o",
|
101
|
+
"password": "Contraseña",
|
102
|
+
"logIn": "Iniciar sesión",
|
103
|
+
"skip": "Saltar",
|
104
|
+
"forgotPassword": "¿Olvidaste tu contraseña?",
|
105
|
+
"recoverItHere": "Recuperarla aquí",
|
106
|
+
"loginWithEmail": "Iniciar sesión con Email",
|
107
|
+
"youDontHaveAnAccount": "¿No tienes una cuenta?",
|
108
|
+
"registerHere": "Regístrate aquí."
|
109
|
+
}
|
110
|
+
}
|
package/src/creator/src/main.tsx
CHANGED
@@ -5,6 +5,7 @@ import "./index.css"
|
|
5
5
|
import App from "./App.tsx"
|
6
6
|
import SyllabusEditor from "./components/syllabus/SyllabusEditor.tsx"
|
7
7
|
import { Toaster } from "react-hot-toast"
|
8
|
+
import "./i18n"
|
8
9
|
createRoot(document.getElementById("root")!).render(
|
9
10
|
<StrictMode>
|
10
11
|
<Toaster />
|
@@ -9,9 +9,9 @@ export const slugify = (text: string) => {
|
|
9
9
|
.toLowerCase()
|
10
10
|
.trim()
|
11
11
|
.replace(/\s+/g, "-")
|
12
|
-
.replace(/[
|
12
|
+
.replace(/[<>:"/\\|?*]/g, "")
|
13
|
+
.replace(/-+/g, "-")
|
13
14
|
}
|
14
|
-
|
15
15
|
export const randomUUID = () => {
|
16
16
|
return Math.random().toString(36).substring(2, 15)
|
17
17
|
}
|
@@ -426,3 +426,10 @@ export const isValidRigoToken = async (rigobotToken: string) => {
|
|
426
426
|
|
427
427
|
return true
|
428
428
|
}
|
429
|
+
|
430
|
+
export const fixTitleLength = (title: string) => {
|
431
|
+
const MAX_LENGTH = 49
|
432
|
+
let fixed = title.slice(0, MAX_LENGTH)
|
433
|
+
fixed = fixed.replace(/^[^a-zA-Z0-9]+|[^a-zA-Z0-9]+$/g, "")
|
434
|
+
return fixed
|
435
|
+
}
|
@@ -8,11 +8,10 @@ import { TMessage } from "../components/Message"
|
|
8
8
|
export type FormState = {
|
9
9
|
description: string
|
10
10
|
duration: number
|
11
|
-
targetAudience: string
|
12
11
|
hasContentIndex: boolean
|
13
12
|
contentIndex: string
|
14
13
|
purpose: string
|
15
|
-
|
14
|
+
language?: string
|
16
15
|
isCompleted: boolean
|
17
16
|
variables: string[]
|
18
17
|
currentStep: string
|
@@ -77,10 +76,11 @@ const useStore = create<Store>()(
|
|
77
76
|
formState: {
|
78
77
|
description: "",
|
79
78
|
duration: 0,
|
80
|
-
targetAudience: "",
|
81
79
|
hasContentIndex: false,
|
82
80
|
contentIndex: "",
|
83
81
|
purpose: "",
|
82
|
+
language: "en",
|
83
|
+
technologies: [],
|
84
84
|
// sources: [],
|
85
85
|
isCompleted: false,
|
86
86
|
currentStep: "description",
|
@@ -102,7 +102,8 @@ const useStore = create<Store>()(
|
|
102
102
|
currentStep: "description",
|
103
103
|
description: "",
|
104
104
|
duration: 0,
|
105
|
-
|
105
|
+
language: "en",
|
106
|
+
technologies: [],
|
106
107
|
hasContentIndex: false,
|
107
108
|
contentIndex: "",
|
108
109
|
purpose: "",
|
@@ -147,7 +148,9 @@ const useStore = create<Store>()(
|
|
147
148
|
formState: {
|
148
149
|
description: "",
|
149
150
|
duration: 0,
|
150
|
-
|
151
|
+
|
152
|
+
language: "en",
|
153
|
+
technologies: [],
|
151
154
|
hasContentIndex: false,
|
152
155
|
contentIndex: "",
|
153
156
|
purpose: "",
|