diff --git a/package.json b/package.json index 3a6d8993..710ddfb3 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "axios": "^1.4.0", "body-parser": "^1.20.2", "canvas-confetti": "^1.6.0", + "cl-editor": "^2.3.0", "cookie-parser": "^1.4.6", "copy-to-clipboard": "^3.3.3", "form-data": "^4.0.0", diff --git a/src/lib/components/ClEditor/index.svelte b/src/lib/components/ClEditor/index.svelte new file mode 100644 index 00000000..135380cf --- /dev/null +++ b/src/lib/components/ClEditor/index.svelte @@ -0,0 +1,46 @@ + + + (html = evt.detail)} /> diff --git a/src/lib/components/Course/components/Lesson/Materials/index.svelte b/src/lib/components/Course/components/Lesson/Materials/index.svelte index a91cf698..2b101cd2 100644 --- a/src/lib/components/Course/components/Lesson/Materials/index.svelte +++ b/src/lib/components/Course/components/Lesson/Materials/index.svelte @@ -17,6 +17,7 @@ import { VARIANTS } from '$lib/components/PrimaryButton/constants'; import TextField from '$lib/components/Form/TextField.svelte'; import TextEditor from '$lib/components/TextEditor/index.svelte'; + // import ClEditor from '$lib/components/ClEditor/index.svelte'; import { lesson, lessons, @@ -28,6 +29,7 @@ import VideoUploader from '$lib/components/Course/components/Lesson/Materials/Video/Index.svelte'; import { course } from '$lib/components/Course/store'; import * as CONSTANTS from './constants'; + import isEmpty from 'lodash/isEmpty'; export let mode = MODES.view; export let prevMode = ''; @@ -61,6 +63,14 @@ handleUpdateLessonMaterials(_lesson, lessonId); } + function isNoteEmpty(note) { + if (!note || typeof note !== 'string') return true; + if (!note.trim()) return true; + if (note.trim() === '


') return true; + + return false; + } + function handleSave(prevMode: string) { if (prevMode === MODES.edit) { saveLesson(); @@ -71,19 +81,15 @@ const { slide_url, videos, note } = materials; tabs = tabs.map((tab) => { - const badgeValue = - tab.value === 1 - ? note?.length > 15 - ? 1 - : 0 - : tab.value === 2 - ? !!slide_url - ? 1 - : 0 - : Array.isArray(videos) - ? videos.length - : 0; + let badgeValue = 0; + if (tab.value === 1 && !isNoteEmpty(note)) { + badgeValue = 1; + } else if (tab.value === 2 && !!slide_url) { + badgeValue = 1; + } else if (tab.value === 3 && !isEmpty(videos)) { + badgeValue = 1; + } tab.badgeValue = badgeValue; return tab; }); @@ -227,8 +233,9 @@ bind:content={$lesson.materials.note} onChange={(c) => ($lesson.materials.note = c)} /> + - {:else if $lesson.materials?.note?.length > 15} + {:else if !isNoteEmpty($lesson.materials?.note)}
{@html $lesson.materials.note}
diff --git a/src/lib/components/TextEditor/index.svelte b/src/lib/components/TextEditor/index.svelte index 93c90fa7..3a481464 100644 --- a/src/lib/components/TextEditor/index.svelte +++ b/src/lib/components/TextEditor/index.svelte @@ -29,6 +29,7 @@ }; let quill = null; + let isUserTyping = false; function resetContent(docId) { if (quill && quill.setText) { @@ -64,6 +65,16 @@ quill.on('text-change', function () { onChange(quill.getHTML()); }); + quill.getModule('toolbar').container.addEventListener('mousedown', (e) => { + e.preventDefault(); + isUserTyping = true; + }); + quill.root.addEventListener('focus', () => { + isUserTyping = true; + }); + quill.root.addEventListener('blur', () => { + isUserTyping = false; + }); }); $: { @@ -76,7 +87,9 @@ } } - $: setQuillHTML(content); + $: if (!isUserTyping) { + setQuillHTML(content); + } $: resetContent(docId); diff --git a/src/routes/api/completion/+server.js b/src/routes/api/completion/+server.js index 5d613f37..c52402c5 100644 --- a/src/routes/api/completion/+server.js +++ b/src/routes/api/completion/+server.js @@ -22,19 +22,16 @@ const instruction = { export async function POST({ request }) { const { prompt } = await request.json(); const { courseTitle, lessonTitle, type } = prompt; - console.log('prompt', prompt); - console.time('debugOpenAi'); const response = await openai.createChatCompletion({ model: 'gpt-3.5-turbo', messages: [ { role: 'user', - content: `Generate a ${instruction[type]} given the course title is "${courseTitle}" and the lesson is "${lessonTitle}". Format in HTML without any styling, don't include the title of the course and title of the lesson in the result & make sure the content is well detailed.` + content: `Generate a ${instruction[type]} given the course title is "${courseTitle}" and the lesson is "${lessonTitle}". Format in HTML without any styling, no ul, ol or li tags, don't include the title of the course and title of the lesson in the result & make sure the content is well detailed.` } ], stream: true }); - console.timeEnd('debugOpenAi'); // Convert the response into a friendly text-stream const stream = OpenAIStream(response); // Respond with the stream