CLASSROOMIO-T-116: Replace Markdown with WYSIWIG
CLASSROOMIO-T-116: Resolved Feedbacks CLASSROOMIO-T-116: Replace Markdown with WYSIWIG Co-authored-by: Tunji Adeyemi <tunji@digdippa.com> Merge-request: CLASSROOMIO-MR-52 Merged-by: Best Admin <best@digdippa.com>
This commit is contained in:
@@ -12,12 +12,11 @@
|
|||||||
import MachineLearningModel from 'carbon-icons-svelte/lib/MachineLearningModel.svelte';
|
import MachineLearningModel from 'carbon-icons-svelte/lib/MachineLearningModel.svelte';
|
||||||
import Tabs from '$lib/components/Tabs/index.svelte';
|
import Tabs from '$lib/components/Tabs/index.svelte';
|
||||||
import TabContent from '$lib/components/TabContent/index.svelte';
|
import TabContent from '$lib/components/TabContent/index.svelte';
|
||||||
import MarkdownRender from '$lib/components/MarkdownRender/index.svelte';
|
|
||||||
import Box from '$lib/components/Box/index.svelte';
|
import Box from '$lib/components/Box/index.svelte';
|
||||||
import EditContent from '$lib/components/EditContent/index.svelte';
|
|
||||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||||
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
|
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
|
||||||
import TextField from '$lib/components/Form/TextField.svelte';
|
import TextField from '$lib/components/Form/TextField.svelte';
|
||||||
|
import TextEditor from '$lib/components/TextEditor/index.svelte';
|
||||||
import {
|
import {
|
||||||
lesson,
|
lesson,
|
||||||
lessons,
|
lessons,
|
||||||
@@ -74,7 +73,7 @@
|
|||||||
tabs = tabs.map((tab) => {
|
tabs = tabs.map((tab) => {
|
||||||
const badgeValue =
|
const badgeValue =
|
||||||
tab.value === 1
|
tab.value === 1
|
||||||
? !!note
|
? note.length > 15
|
||||||
? 1
|
? 1
|
||||||
: 0
|
: 0
|
||||||
: tab.value === 2
|
: tab.value === 2
|
||||||
@@ -100,8 +99,9 @@
|
|||||||
|
|
||||||
function updateNoteByCompletion(completion) {
|
function updateNoteByCompletion(completion) {
|
||||||
$lesson.materials.note = completion;
|
$lesson.materials.note = completion;
|
||||||
if (textareaRef) {
|
if (textareaRef && textareaRef?.children?.[0]) {
|
||||||
textareaRef.scrollTop = textareaRef.scrollHeight;
|
let qlEditor = textareaRef?.children?.[0];
|
||||||
|
qlEditor.scrollTop = qlEditor.scrollHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,54 +183,55 @@
|
|||||||
<slot:fragment slot="content">
|
<slot:fragment slot="content">
|
||||||
<TabContent value={tabs[0].value} index={currentTab}>
|
<TabContent value={tabs[0].value} index={currentTab}>
|
||||||
{#if mode === MODES.edit}
|
{#if mode === MODES.edit}
|
||||||
<EditContent
|
<div bind:this={aiButtonRef} class="w-full flex flex-row-reverse">
|
||||||
writeLabel="Note"
|
<PrimaryButton
|
||||||
bind:value={$lesson.materials.note}
|
className="flex items-center relative"
|
||||||
placeholder="Start typing your lesson"
|
onClick={() => {
|
||||||
on:change={handleInputChange}
|
openPopover = !openPopover;
|
||||||
bind:textareaRef
|
}}
|
||||||
bind:buttonRef={aiButtonRef}
|
isLoading={$isLoading}
|
||||||
>
|
isDisabled={$isLoading}
|
||||||
<div slot="buttons" class="flex items-center">
|
variant={VARIANTS.OUTLINED}
|
||||||
<PrimaryButton
|
>
|
||||||
className="flex items-center relative"
|
<MachineLearningModel size={20} class="carbon-icon mr-3" />
|
||||||
onClick={() => {
|
AI
|
||||||
openPopover = !openPopover;
|
<Popover
|
||||||
|
caret
|
||||||
|
align="left"
|
||||||
|
bind:open={openPopover}
|
||||||
|
on:click:outside={({ detail }) => {
|
||||||
|
openPopover = aiButtonRef?.contains(detail.target);
|
||||||
}}
|
}}
|
||||||
isLoading={$isLoading}
|
|
||||||
isDisabled={$isLoading}
|
|
||||||
variant={VARIANTS.OUTLINED}
|
|
||||||
>
|
>
|
||||||
<MachineLearningModel size={20} class="carbon-icon mr-3" />
|
<div class="p-2">
|
||||||
AI
|
<button class={aiButtonClass} on:click={() => callAI('outline')}>
|
||||||
<Popover
|
<ListIcon class="carbon-icon mr-2" />
|
||||||
caret
|
Generate Lesson Outline
|
||||||
align="left"
|
</button>
|
||||||
bind:open={openPopover}
|
<button class={aiButtonClass} on:click={() => callAI('note')}>
|
||||||
on:click:outside={({ detail }) => {
|
<AlignBoxTopLeftIcon class="carbon-icon mr-2" />
|
||||||
openPopover = aiButtonRef?.contains(detail.target);
|
Generate Lesson Note
|
||||||
}}
|
</button>
|
||||||
>
|
<button class={aiButtonClass} on:click={() => callAI('activities')}>
|
||||||
<div class="p-2">
|
<IbmWatsonKnowledgeStudioIcon class="carbon-icon mr-2" />
|
||||||
<button class={aiButtonClass} on:click={() => callAI('outline')}>
|
Generate Lesson Activities
|
||||||
<ListIcon class="carbon-icon mr-2" />
|
</button>
|
||||||
Generate Lesson Outline
|
</div>
|
||||||
</button>
|
</Popover>
|
||||||
<button class={aiButtonClass} on:click={() => callAI('note')}>
|
</PrimaryButton>
|
||||||
<AlignBoxTopLeftIcon class="carbon-icon mr-2" />
|
</div>
|
||||||
Generate Lesson Note
|
|
||||||
</button>
|
<div class="h-[60vh]">
|
||||||
<button class={aiButtonClass} on:click={() => callAI('activities')}>
|
<TextEditor
|
||||||
<IbmWatsonKnowledgeStudioIcon class="carbon-icon mr-2" />
|
bind:container={textareaRef}
|
||||||
Generate Lesson Activities
|
bind:content={$lesson.materials.note}
|
||||||
</button>
|
onChange={(c) => ($lesson.materials.note = c)}
|
||||||
</div>
|
/>
|
||||||
</Popover>
|
</div>
|
||||||
</PrimaryButton>
|
{:else if $lesson.materials.note.length > 15}
|
||||||
</div>
|
<div>
|
||||||
</EditContent>
|
{@html $lesson.materials.note}
|
||||||
{:else if $lesson.materials.note}
|
</div>
|
||||||
<MarkdownRender content={$lesson.materials.note} />
|
|
||||||
{:else}
|
{:else}
|
||||||
<Box>
|
<Box>
|
||||||
<div class="flex justify-between flex-col items-center w-96">
|
<div class="flex justify-between flex-col items-center w-96">
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import TextEditor from '$lib/components/TextEditor/index.svelte';
|
||||||
import { marked } from 'marked';
|
import { marked } from 'marked';
|
||||||
import RoleBasedSecurity from '../RoleBasedSecurity/index.svelte';
|
import RoleBasedSecurity from '../RoleBasedSecurity/index.svelte';
|
||||||
import PageNav from '../PageNav/index.svelte';
|
import PageNav from '../PageNav/index.svelte';
|
||||||
@@ -41,13 +42,11 @@
|
|||||||
|
|
||||||
<PageBody width="max-w-3xl px-3">
|
<PageBody width="max-w-3xl px-3">
|
||||||
{#if mode === MODES.edit}
|
{#if mode === MODES.edit}
|
||||||
<EditContent
|
<TextEditor
|
||||||
writeLabel="Note"
|
bind:content={$course.overview}
|
||||||
bind:value={$course.overview}
|
onChange={(c) => {
|
||||||
placeholder="Start typing your lesson"
|
$course.overview = c;
|
||||||
onInputChange={() => {
|
|
||||||
isDirty = true;
|
isDirty = true;
|
||||||
console.log('input change');
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
export let docId;
|
export let docId;
|
||||||
export let placeholder = 'Type something...';
|
export let placeholder = 'Type something...';
|
||||||
export let errorMessage;
|
export let errorMessage;
|
||||||
|
export let container;
|
||||||
|
|
||||||
const settings = {
|
const settings = {
|
||||||
modules: {
|
modules: {
|
||||||
@@ -16,19 +17,18 @@
|
|||||||
toolbar: [
|
toolbar: [
|
||||||
[{ header: [1, 2, 3, false] }],
|
[{ header: [1, 2, 3, false] }],
|
||||||
['bold', 'italic', 'underline', 'strike'],
|
['bold', 'italic', 'underline', 'strike'],
|
||||||
['link', 'code-block'],
|
['link', 'code-block']
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
placeholder: 'Type something...',
|
placeholder: 'Type something...',
|
||||||
theme: 'snow',
|
theme: 'snow'
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
theme: 'snow',
|
theme: 'snow',
|
||||||
placeholder,
|
placeholder
|
||||||
};
|
};
|
||||||
|
|
||||||
let quill = null;
|
let quill = null;
|
||||||
let container = null;
|
|
||||||
|
|
||||||
function resetContent(docId) {
|
function resetContent(docId) {
|
||||||
if (quill && quill.setText) {
|
if (quill && quill.setText) {
|
||||||
@@ -40,6 +40,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setQuillHTML(html) {
|
||||||
|
console.log('outside if');
|
||||||
|
if (quill) {
|
||||||
|
console.log('inside if', html);
|
||||||
|
quill.setHTML(html);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
const { default: Quill } = await import('quill');
|
const { default: Quill } = await import('quill');
|
||||||
|
|
||||||
@@ -70,6 +78,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: setQuillHTML(content);
|
||||||
|
|
||||||
$: resetContent(docId);
|
$: resetContent(docId);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -94,4 +104,16 @@
|
|||||||
:global(.dark .ql-editor.ql-blank::before) {
|
:global(.dark .ql-editor.ql-blank::before) {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global(.ql-editor) {
|
||||||
|
white-space: normal !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.ql-editor p),
|
||||||
|
:global(.ql-editor h1),
|
||||||
|
:global(.ql-editor h2),
|
||||||
|
:global(.ql-editor h3),
|
||||||
|
:global(.ql-editor h4) {
|
||||||
|
line-height: 2.2;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export async function POST({ request }) {
|
|||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: `Generate a ${instruction[type]} given the course title is "${courseTitle}" and the lesson is "${lessonTitle}". Format in markdown`
|
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.`
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
stream: true
|
stream: true
|
||||||
|
|||||||
Reference in New Issue
Block a user