@learnpack/learnpack 5.0.69 → 5.0.70

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.
@@ -0,0 +1,123 @@
1
+ import { useRef, useState } from "react"
2
+ import useStore from "../../utils/store"
3
+ import { TMessage } from "../Message"
4
+ import FileUploader from "../FileUploader"
5
+ import { SVGS } from "../../assets/svgs"
6
+ import { Message } from "../Message"
7
+
8
+ export const Sidebar = ({
9
+ messages,
10
+ sendPrompt,
11
+ handleSubmit,
12
+ }: {
13
+ messages: TMessage[]
14
+ sendPrompt: (prompt: string) => void
15
+ handleSubmit: () => void
16
+ }) => {
17
+ const inputRef = useRef<HTMLTextAreaElement>(null)
18
+ const syllabus = useStore((state) => state.syllabus)
19
+ const setSyllabus = useStore((state) => state.setSyllabus)
20
+
21
+ const [isOpen, setIsOpen] = useState(false)
22
+
23
+ return (
24
+ <>
25
+ {!isOpen && (
26
+ <button
27
+ className="fixed top-2 left-2 z-50 lg:hidden bg-white p-1 rounded shadow-md cursor-pointer"
28
+ onClick={() => setIsOpen(true)}
29
+ >
30
+
31
+ </button>
32
+ )}
33
+
34
+ <div
35
+ className={`fixed z-40 top-0 left-0 h-full w-4/5 max-w-sm bg-learnpack-blue text-sm text-gray-700 border-r overflow-y-auto scrollbar-hide p-6 transition-transform duration-300 ease-in-out lg:relative lg:transform-none lg:w-1/3 ${
36
+ isOpen ? "translate-x-0" : "-translate-x-full lg:translate-x-0"
37
+ }`}
38
+ >
39
+ {isOpen && (
40
+ <button
41
+ className="lg:hidden bg-white p-1 rounded shadow-md mb-4 cursor-pointer absolute top-2 left-2"
42
+ onClick={() => setIsOpen(false)}
43
+ >
44
+
45
+ </button>
46
+ )}
47
+ {/* This should have the same width as the input area */}
48
+ <div className="space-y-2 mb-6 ">
49
+ <p className="w-full bg-white p-2 rounded">
50
+ If you're satisfied, type "OK" in the chat.
51
+ </p>
52
+ <p className="w-full bg-white p-2 rounded">
53
+ If not, use the chat to give more context.
54
+ </p>
55
+ </div>
56
+
57
+ <div className="space-y-2 pb-32 h-[70%] overflow-y-auto scrollbar-hide">
58
+ {messages.map((message, index) => (
59
+ <Message
60
+ key={index}
61
+ type={message.type}
62
+ content={message.content}
63
+ />
64
+ ))}
65
+ </div>
66
+
67
+ <div className="relative w-full rounded-md bg-white text-gray-700 h-24">
68
+ <textarea
69
+ ref={inputRef}
70
+ style={{ resize: "none" }}
71
+ className="w-full h-full p-2"
72
+ placeholder="How can Learnpack help you?"
73
+ autoFocus
74
+ onKeyUp={(e) => {
75
+ if (e.key === "Enter" && !e.shiftKey) {
76
+ e.preventDefault()
77
+ sendPrompt(inputRef.current?.value || "")
78
+ inputRef.current!.value = ""
79
+ }
80
+ if (
81
+ e.key.toLowerCase() === "k" &&
82
+ inputRef.current?.value.toLowerCase().trim() === "ok"
83
+ ) {
84
+ e.preventDefault()
85
+ handleSubmit()
86
+ }
87
+ }}
88
+ />
89
+ <div className="absolute bottom-2 right-2 flex gap-1 items-center">
90
+ <div className="relative inline-block">
91
+ {syllabus.uploadedFiles?.length > 0 && (
92
+ <span
93
+ className="absolute -top-1 right-0 inline-flex items-center justify-center w-3 h-3 text-[10px] text-white bg-blue-200 rounded-full hover:bg-red-300 cursor-pointer"
94
+ title="Remove uploaded files"
95
+ onClick={() => {
96
+ setSyllabus({ ...syllabus, uploadedFiles: [] })
97
+ }}
98
+ >
99
+ {syllabus.uploadedFiles?.length}
100
+ </span>
101
+ )}
102
+ <FileUploader
103
+ onResult={(res) => {
104
+ setSyllabus({
105
+ ...syllabus,
106
+ uploadedFiles: [...syllabus.uploadedFiles, ...res],
107
+ })
108
+ }}
109
+ />
110
+ </div>
111
+
112
+ <button
113
+ className="cursor-pointer blue-on-hover flex items-center justify-center w-6 h-6"
114
+ onClick={() => sendPrompt(inputRef.current?.value || "")}
115
+ >
116
+ {SVGS.send}
117
+ </button>
118
+ </div>
119
+ </div>
120
+ </div>
121
+ </>
122
+ )
123
+ }
@@ -1,5 +1,4 @@
1
1
  import React, { useRef, useState } from "react"
2
- import { SVGS } from "../../assets/svgs"
3
2
  import { useShallow } from "zustand/react/shallow"
4
3
  import useStore from "../../utils/store"
5
4
  import { interactiveCreation } from "../../utils/rigo"
@@ -16,129 +15,12 @@ import {
16
15
  } from "../../utils/creatorUtils"
17
16
 
18
17
  import Loader from "../Loader"
19
- import { Message, TMessage } from "../Message"
18
+ import { TMessage } from "../Message"
20
19
  import { Lesson } from "../LessonItem"
21
- import FileUploader from "../FileUploader"
22
20
  import { ConsumablesManager } from "../ConsumablesManager"
23
21
  import toast from "react-hot-toast"
24
22
  import { ContentIndex } from "./ContentIndex"
25
- import { Syllabus } from "../../utils/store"
26
-
27
- const ContentIndexHeader = ({
28
- messages,
29
- syllabus,
30
- }: {
31
- messages: TMessage[]
32
- syllabus: Syllabus
33
- }) => {
34
- return (
35
- <div>
36
- <h2 className="text-lg font-semibold">
37
- {messages.filter((m) => m.type === "assistant" && m.content.length > 0)
38
- .length === 0
39
- ? "I've created a detailed structure for your course."
40
- : "I've updated the structure based on your feedback."}
41
- </h2>
42
- <p className="text-sm text-gray-600">
43
- {messages.filter((m) => m.type === "assistant" && m.content.length > 0)
44
- .length === 0
45
- ? `It includes a mix of reading, coding exercises, and quizzes. Give
46
- it a look and let me know if it aligns with your expectations or if
47
- there are any changes you'd like to make.`
48
- : "Based on your input, here is the new syllabus, updates are highlighted in yellow"}
49
- </p>
50
- <h3 className="text-sm text-gray-600 mt-2 font-bold">
51
- {syllabus.courseInfo.title}
52
- </h3>
53
- </div>
54
- )
55
- }
56
-
57
-
58
-
59
- const Sidebar = ({
60
- messages,
61
- sendPrompt,
62
- handleSubmit,
63
- }: {
64
- messages: TMessage[]
65
- sendPrompt: (prompt: string) => void
66
- handleSubmit: () => void
67
- }) => {
68
- const inputRef = useRef<HTMLTextAreaElement>(null)
69
- const syllabus = useStore((state) => state.syllabus)
70
- const setSyllabus = useStore((state) => state.setSyllabus)
71
- return (
72
- <div className="w-1/3 p-6 text-sm text-gray-700 border-r bg-learnpack-blue h-screen overflow-y-auto scrollbar-hide relative">
73
- <p className="mt-2">If you're satisfied, type "OK" in the chat.</p>
74
- <p className="mt-2">If not, use the chat to give more context.</p>
75
-
76
- <div className="mt-10 space-y-2 pb-16">
77
- {messages.map((message, index) => (
78
- <Message key={index} type={message.type} content={message.content} />
79
- ))}
80
- </div>
81
-
82
- <div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 w-[90%] border rounded-md bg-white text-gray-400 resize-none h-24 ">
83
- <textarea
84
- ref={inputRef}
85
- style={{ resize: "none" }}
86
- className="w-full h-full p-2"
87
- placeholder="How can Learnpack help you?"
88
- autoFocus
89
- onKeyUp={(e) => {
90
- if (e.key === "Enter" && !e.shiftKey) {
91
- e.preventDefault()
92
- sendPrompt(inputRef.current?.value || "")
93
- inputRef.current!.value = ""
94
- }
95
- // if the pressed key is K or k
96
- if (e.key === "K" || e.key === "k") {
97
- e.preventDefault()
98
-
99
- if (inputRef.current?.value.toLowerCase().trim() === "ok") {
100
- handleSubmit()
101
- }
102
- }
103
- }}
104
- />
105
- <div className="absolute bottom-2 right-2 flex gap-1 items-center">
106
- <div className="relative inline-block">
107
- {syllabus.uploadedFiles?.length > 0 && (
108
- <span
109
- className="absolute -top-1 right-0 inline-flex items-center justify-center w-3 h-3 text-[10px] text-white bg-blue-200 rounded-full hover:bg-red-300 cursor-pointer"
110
- title="Remove uploaded files"
111
- onClick={() => {
112
- setSyllabus({
113
- ...syllabus,
114
- uploadedFiles: [],
115
- })
116
- }}
117
- >
118
- {syllabus.uploadedFiles?.length}
119
- </span>
120
- )}
121
- <FileUploader
122
- onResult={(res) => {
123
- setSyllabus({
124
- ...syllabus,
125
- uploadedFiles: [...syllabus.uploadedFiles, ...res],
126
- })
127
- }}
128
- />
129
- </div>
130
-
131
- <button
132
- className="cursor-pointer blue-on-hover flex items-center justify-center w-6 h-6"
133
- onClick={() => sendPrompt(inputRef.current?.value || "")}
134
- >
135
- {SVGS.send}
136
- </button>
137
- </div>
138
- </div>
139
- </div>
140
- )
141
- }
23
+ import { Sidebar } from "./Sidebar"
142
24
 
143
25
  const SyllabusEditor: React.FC = () => {
144
26
  const [messages, setMessages] = useState<TMessage[]>([])
@@ -223,7 +105,7 @@ const SyllabusEditor: React.FC = () => {
223
105
  return isGenerating ? (
224
106
  <Loader
225
107
  listeningTo="course-generation"
226
- icon={SVGS.rigoSoftBlue}
108
+ icon={<img src={"rigo-float.gif"} alt="rigo" className="w-20 h-20" />}
227
109
  initialBuffer="🚀 Starting course generation..."
228
110
  text="Learnpack is setting up your tutorial.
229
111
  It may take a moment..."
@@ -231,18 +113,18 @@ It may take a moment..."
231
113
  ) : (
232
114
  <div className="flex w-full bg-white rounded-md shadow-md overflow-hidden h-screen ">
233
115
  <ConsumablesManager />
234
- {/* Sidebar */}
116
+
235
117
  <Sidebar
236
118
  messages={messages}
237
119
  sendPrompt={sendPrompt}
238
120
  handleSubmit={handleSubmit}
239
121
  />
240
122
 
241
- <div className="w-2/3 p-8 space-y-6">
242
- <ContentIndexHeader messages={messages} syllabus={syllabus} />
123
+ <div className="w-full p-8 space-y-6">
243
124
  <ContentIndex
244
125
  prevLessons={prevLessons.current}
245
126
  handleSubmit={handleSubmit}
127
+ messages={messages}
246
128
  />
247
129
  </div>
248
130
  </div>
@@ -88,15 +88,12 @@ h1 {
88
88
  .loader-icon {
89
89
  width: 40px;
90
90
  height: 40px;
91
-
92
- border: 2px solid var(--loader-color);
93
- border-top-color: transparent;
94
91
  position: relative;
95
92
  display: flex;
96
93
  align-items: center;
97
94
  justify-content: center;
98
95
  }
99
- .loader-icon::after {
96
+ /* .loader-icon::after {
100
97
  content: "";
101
98
  display: block;
102
99
  width: 100%;
@@ -106,11 +103,10 @@ h1 {
106
103
  height: 100%;
107
104
  border: 2px solid var(--gray-text);
108
105
  border-top: 2px solid var(--learnpack-blue);
109
- /* background-color: red; */
110
106
 
111
107
  border-radius: 50%;
112
108
  animation: spin 2s linear infinite;
113
- }
109
+ } */
114
110
 
115
111
  @keyframes glowing {
116
112
  0% {
@@ -9,7 +9,8 @@ export type FormState = {
9
9
  hasContentIndex: boolean
10
10
  contentIndex: string
11
11
  isCompleted: boolean
12
- currentStep: number
12
+ variables: string[]
13
+ currentStep: string
13
14
  title?: string
14
15
  }
15
16
 
@@ -57,7 +58,14 @@ const useStore = create<Store>()(
57
58
  hasContentIndex: false,
58
59
  contentIndex: "",
59
60
  isCompleted: false,
60
- currentStep: 0,
61
+ currentStep: "description",
62
+ variables: [
63
+ "description",
64
+ "duration",
65
+ "login",
66
+ "targetAudience",
67
+ "hasContentIndex",
68
+ ],
61
69
  },
62
70
  setFormState: (formState: Partial<FormState>) =>
63
71
  set((state) => ({ formState: { ...state.formState, ...formState } })),
@@ -71,8 +79,9 @@ const useStore = create<Store>()(
71
79
  hasContentIndex: false,
72
80
  contentIndex: "",
73
81
  isCompleted: false,
74
- currentStep: 0,
82
+ currentStep: "description",
75
83
  title: "",
84
+ variables: [],
76
85
  },
77
86
  uploadedFiles: [],
78
87
  },