CLASSROOMIO-T-141: Reusable AI trigger all around the app

CLASSROOM-T-141: Dark mode improvements

CLASSROOMIO-T-141: Add ai widget to landing page settings

CLASSROOMIO-T-141: Enable AI button to text area in the landingpage settings

CLASSROOMIO-T-141: Complete AI flow

Merge branch 'main' into CLASSROOMIO-T-141

CLASSROOMIO-T-141: AI Button test


Co-authored-by: Rotimi Best <rotimiibitoyeemma@gmail.com>
Co-authored-by: Tunji Adeyemi <tunji@digdippa.com>


Merge-request: CLASSROOMIO-MR-74
Merged-by: Best Admin <best@digdippa.com>
This commit is contained in:
tunny17
2023-09-24 07:08:37 +00:00
committed by Space Cloud
co-authored by Rotimi Best
parent 5e77f9ca46
commit a2c83c7909
17 changed files with 525 additions and 271 deletions
@@ -1,18 +1,9 @@
<script>
import cloneDeep from 'lodash/cloneDeep';
import set from 'lodash/set';
import get from 'lodash/get';
import TextEditor from '$lib/components/TextEditor/index.svelte';
export let course;
function handleChange(html) {
const _course = cloneDeep(course);
set(_course, 'metadata.description', html);
course = _course;
}
export let value = '';
</script>
<div class="h-2/5">
<TextEditor value={get(course, 'metadata.description')} onChange={handleChange} />
<TextEditor bind:value />
</div>
@@ -1,18 +1,9 @@
<script>
import cloneDeep from 'lodash/cloneDeep';
import set from 'lodash/set';
import get from 'lodash/get';
import TextEditor from '$lib/components/TextEditor/index.svelte';
export let course;
function handleChange(html) {
const _course = cloneDeep(course);
set(_course, 'metadata.goals', html);
course = _course;
}
export let value = '';
</script>
<div class="h-2/5">
<TextEditor value={get(course, 'metadata.goals')} onChange={handleChange} />
<TextEditor bind:value />
</div>
@@ -1,18 +1,9 @@
<script>
import cloneDeep from 'lodash/cloneDeep';
import set from 'lodash/set';
import get from 'lodash/get';
<script lang="ts">
import TextEditor from '$lib/components/TextEditor/index.svelte';
export let course;
function handleChange(html) {
const _course = cloneDeep(course);
set(_course, 'metadata.requirements', html);
course = _course;
}
export let value: string;
</script>
<div class="h-2/5">
<TextEditor value={get(course, 'metadata.requirements')} onChange={handleChange} />
<TextEditor bind:value />
</div>
@@ -58,6 +58,9 @@
placeholder=""
bind:value={review.description}
errorMessage={errors.description}
isAIEnabled={true}
initAIPrompt="Generate a 20 word review from a student saying good things about me teaching"
aiAlignPopover="top-right"
/>
<div class="flex justify-between w-full items-center mt-2">
@@ -1,10 +1,11 @@
<script>
<script lang="ts">
import { goto } from '$app/navigation';
import cloneDeep from 'lodash/cloneDeep';
import set from 'lodash/set';
import ChevronRightIcon from 'carbon-icons-svelte/lib/ChevronRight.svelte';
import ArrowLeftIcon from 'carbon-icons-svelte/lib/ArrowLeft.svelte';
import ArrowUpRightIcon from 'carbon-icons-svelte/lib/ArrowUpRight.svelte';
import Container from './Container.svelte';
import IconButton from '$lib/components/IconButton/index.svelte';
import CloseButton from '$lib/components/Buttons/Close/index.svelte';
import HeaderForm from './HeaderForm.svelte';
@@ -21,47 +22,70 @@
import ChevronLeftIcon from 'carbon-icons-svelte/lib/ChevronLeft.svelte';
import { isMobile } from '$lib/utils/store/useMobile';
import CustomPromptBtn from '$lib/components/AI/AIButton/CustomPromptBtn.svelte';
import type { Course } from '$lib/utils/types';
export let course;
export let courseId;
export let course: Course;
export let courseId: string;
let borderBottomGrey = 'border-r-0 border-b border-l-0 border-gray-300';
let loading = false;
let show = false;
const sections = [
interface Section {
key: number;
path: string;
title: string;
enableAIWriter?: boolean;
initPrompt?: string;
}
const sections: Section[] = [
{
key: 1,
path: '',
title: 'Header'
},
{
key: 2,
title: 'Requirement'
path: 'metadata.requirements',
title: 'Requirement',
enableAIWriter: true,
initPrompt: 'Generate a course requirement for this given course:'
},
{
key: 3,
title: 'Description'
path: 'metadata.description',
title: 'Description',
enableAIWriter: true,
initPrompt: 'Generate a course description for this given course:'
},
{
key: 4,
title: 'Goals'
path: 'metadata.goals',
title: 'Goals',
enableAIWriter: true,
initPrompt: 'What should a student expect to learn from this given course:'
},
{
key: 5,
path: '',
title: 'Reviews'
},
{
key: 6,
path: '',
title: 'Instructor'
},
{
key: 7,
path: '',
title: 'Pricing'
}
];
let selectedSection = null;
let selectedSection: Section | null = null;
function handleClose() {
console.log('closing');
if (!selectedSection) {
goto(`/courses/${courseId}`);
}
@@ -69,11 +93,13 @@
selectedSection = null;
}
function handleSectionSelect(sectionKey) {
function handleSectionSelect(sectionKey: number) {
return () => {
selectedSection = sections.find((section) => section.key === sectionKey);
selectedSection = sections.find((section) => section.key === sectionKey) || null;
if (selectedSection) {
const sectionId = selectedSection.title.toLowerCase();
const sectionEl = document.getElementById(sectionId);
if (sectionEl) {
sectionEl.scrollIntoView({
@@ -120,8 +146,8 @@
<aside
class={`${
show ? '-translate-x-[100%] fixed z-[9999]' : 'translate-x-0 fixed z-[9999]'
} left-0 transition w-[280px] min-w-[280px] bg-gray-100 dark:bg-black h-full border border-l-0 border-t-0 border-b-0 border-r-1`}
show ? '-translate-x-[100%] fixed z-[50]' : 'translate-x-0 fixed z-[50]'
} left-0 transition w-[350px] min-w-[300px] bg-gray-100 dark:bg-black h-full border border-l-0 border-t-0 border-b-0 border-r-1`}
>
<div class="toggler rounded-full shadow-lg absolute">
<IconButton
@@ -185,18 +211,36 @@
<IconButton onClick={handleClose}>
<ArrowLeftIcon size={24} class="carbon-icon dark:text-white" title="Go back" />
</IconButton>
<h3 class="dark:text-white">{selectedSection.title}</h3>
<div class=" flex items-center">
<h3 class="dark:text-white">
{selectedSection.title}
</h3>
{#if selectedSection.enableAIWriter}
<CustomPromptBtn
className="w-fit ml-2"
alignPopover="bottom-left"
defaultPrompt={`${selectedSection.initPrompt} ${course.title}. Please format in html`}
isHTML={true}
handleInsert={(v) => {
if (!selectedSection) return;
const _course = cloneDeep(course);
set(_course, selectedSection.path, v);
course = _course;
}}
/>
{/if}
</div>
</div>
<div class="title-content p-2 overflow-y-auto">
{#if selectedSection.key === 1}
<HeaderForm bind:course />
{:else if selectedSection.key === 2}
<RequirementForm bind:course />
<RequirementForm bind:value={course.metadata.requirements} />
{:else if selectedSection.key === 3}
<DescriptionForm bind:course />
<DescriptionForm bind:value={course.metadata.description} />
{:else if selectedSection.key === 4}
<GoalsForm bind:course />
<GoalsForm bind:value={course.metadata.goals} />
{:else if selectedSection.key === 5}
<ReviewsForm bind:course />
{:else if selectedSection.key === 6}
@@ -63,7 +63,11 @@
/>
<!-- Pricing Details -->
<aside class="{className} price-container lg:sticky lg:top-10 lg:shadow-2xl lg:rounded-lg m-h-fit">
<aside
class="{className} price-container lg:sticky {editMode
? 'lg:top-0'
: 'lg:top-10'} lg:shadow-2xl lg:rounded-lg m-h-fit bg-neutral-800"
>
<div class="p-10">
<!-- Pricing -->
<div class="mb-6">
@@ -167,12 +167,14 @@
<!-- Course Details -->
<div class="course-content w-full p-3 lg:w-10/12 lg:mr-14">
<!-- Navigation -->
<nav class="flex items-center border-b border-gray-300 py-3 sticky top-11 bg-white">
<nav
class="flex items-center border-b border-gray-300 py-3 sticky top-11 bg-white dark:bg-neutral-800"
>
{#each NAV_ITEMS as navItem}
<a
href="{$page.url.pathname}{navItem.key}"
class="{navItem.key === activeNav &&
'active text-primary-700'} rounded-lg px-2 mr-6 text-slate-700 font-normal hover:bg-slate-100 hover:text-slate-900 dark:text-white"
'active text-primary-700'} rounded-lg px-2 mr-6 text-slate-700 font-normal hover:bg-neutral-600 hover:text-slate-900 dark:text-white"
>
{navItem.label}
</a>