feat: move away from carbon components and TinyMCE (#597)

* feat: remove tinymce & replace org sidebar

* chore: PR Fixes

* chore: move ui font into src dir

* remove files in vite config

* use google font import for loading font

* remove custom font

* more fonts update

* remove font bold

* more removals of font bold

* fix import

* checkpoint

* chore: checkpoint (add course & lms shadcn sidebar)

* minor css improvements and try out font sans

* chore: replace carbon components with shadcn's

* chore: replace carbon components with shadcn _ v3

* chore: ui fixes & storybook update

* feat: UI cleanup

* fix: quick ui fixes

* chore: update pnpm-lock.yaml with new dependencies and versions; fix output.css formatting

* chore: add isloading to button

* feat: add loading state to button stories

* chore: feedback fixes

* fix: feedback fixes

* chore: remove console

* fix: PR comments

* fix: PR comments

---------

Co-authored-by: Rotimi Best <best@classroomio.com>
This commit is contained in:
Adeyemi Adetunji
2025-11-21 12:18:04 +01:00
committed by GitHub
co-authored by Rotimi Best
parent 2145782385
commit cbf6ae7e63
499 changed files with 19708 additions and 15603 deletions
@@ -15,7 +15,7 @@
<section class="mx-auto w-full max-w-6xl">
<div class="px-5 py-10">
<div class="mb-10 flex items-center justify-between">
<h1 class="text-2xl font-bold md:text-3xl dark:text-white">Interactive Quizzes</h1>
<h1 class="text-2xl md:text-3xl dark:text-white">Interactive Quizzes</h1>
{#if $isMobile}
<PrimaryButton onClick={() => ($createQuizModal.open = true)}>
<PlusIcon size={16} />
@@ -1,23 +1,25 @@
<script lang="ts">
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import ArrowLeftIcon from '@lucide/svelte/icons/arrow-left';
import CircleCheckIcon from '$lib/components/Icons/CircleCheckIcon.svelte';
import CircleAlertIcon from '@lucide/svelte/icons/circle-alert';
import cloneDeep from 'lodash/cloneDeep';
import isBoolean from 'lodash/isBoolean';
import { onMount } from 'svelte';
import { Label } from '@cio/ui/base/label';
import * as Select from '@cio/ui/base/select';
import ArrowLeftIcon from '@lucide/svelte/icons/arrow-left';
import CircleAlertIcon from '@lucide/svelte/icons/circle-alert';
import CircleCheckIcon from '$lib/components/Icons/CircleCheckIcon.svelte';
import DeleteModal from '$lib/components/Org/Quiz/DeleteModal.svelte';
import Preview from '$lib/components/Org/Quiz/Play/Preview.svelte';
import QuizQuestion from '$lib/components/Org/Quiz/QuizQuestion.svelte';
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
import DeleteModal from '$lib/components/Org/Quiz/DeleteModal.svelte';
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
import { snackbar } from '$lib/components/Snackbar/store';
import { allOptions, allThemes, booleanOptions, themeImages } from '$lib/utils/constants/quiz';
import { supabase } from '$lib/utils/functions/supabase';
import QuizQuestion from '$lib/components/Org/Quiz/QuizQuestion.svelte';
import { t } from '$lib/utils/functions/translations';
import { supabase } from '$lib/utils/functions/supabase';
import { snackbar } from '$lib/components/Snackbar/store';
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
import { currentOrgPath, deleteModal, quizStore, quizesStore } from '$lib/utils/store/org';
import { Select, SelectItem } from 'carbon-components-svelte';
import { allOptions, allThemes, booleanOptions, themeImages } from '$lib/utils/constants/quiz';
interface QuizOption {
id: number;
@@ -58,10 +60,9 @@
isLabelEmpty?: boolean;
hasOneAnswer?: boolean;
id?: number;
options?: Array<{ id: number; error: boolean }>;
options: Array<{ id: number; error: boolean }>;
} = $state({});
let isFocused = $state(false);
let selectEl: Select | null = $state(null);
function activeClass(q, cq) {
if (q.id === cq.id) {
@@ -248,7 +249,7 @@
<div class="mb-3">
{#each $quizStore.questions as question, i}
<button
class="mb-3 flex w-full justify-between rounded p-3 text-left font-bold text-gray-500 dark:text-white {activeClass(
class="mb-3 flex w-full justify-between rounded p-3 text-left text-gray-500 dark:text-white {activeClass(
question,
currentQuestion
)}"
@@ -285,7 +286,7 @@
?.editor}) no-repeat center center fixed; -webkit-background-size: cover;-moz-background-size: cover;-o-background-size: cover;background-size: cover;"
>
<div class="content m-auto">
<h1 class="my-5 font-bold text-white">{$quizStore.title}</h1>
<h1 class="my-5 text-white">{$quizStore.title}</h1>
<QuizQuestion {currentQuestion} {optionHasError} {currentError} />
@@ -339,39 +340,44 @@
<div class="flex flex-col justify-evenly">
<div class="my-3">
<!-- Question type -->
<Select
labelText="Question type"
bind:this={selectEl}
bind:selected={type}
class="mb-3 flex items-center"
on:focus={() => (isFocused = true)}
on:blur={() => (isFocused = false)}
on:change={() => {
if (!isFocused) return;
// Blur after change
const onBlur = selectEl?.$$?.callbacks?.blur?.[0];
const onFocus = selectEl?.$$?.callbacks?.focus?.[0];
setTimeout(() => {
onBlur();
onFocus();
}, 1000);
handleQuestionTypeChange(type);
}}
>
<SelectItem value="multichoice" text="Multi-choice answers" />
<SelectItem value="boolean" text="True or False" />
</Select>
<div class="mb-3">
<Label class="mb-2">Question type</Label>
<Select.Root
type="single"
bind:value={type}
onValueChange={(value) => {
if (value) {
handleQuestionTypeChange(value);
}
}}
>
<Select.Trigger class="w-full">
<p>{type === 'multichoice' ? 'Multi-choice answers' : 'True or False'}</p>
</Select.Trigger>
<Select.Content>
<Select.Item value="multichoice">Multi-choice answers</Select.Item>
<Select.Item value="boolean">True or False</Select.Item>
</Select.Content>
</Select.Root>
</div>
<!-- -->
<Select labelText="Time limit" bind:selected={$quizStore.timelimit} class="mb-3 flex items-center">
<SelectItem value="10 seconds" text="10s" />
<SelectItem value="20 seconds" text="20s" />
<SelectItem value="30 seconds" text="30s" />
<SelectItem value="1 minute" text="1m" />
<SelectItem value="2 minute" text="2m" />
<SelectItem value="3 minute" text="3m" />
</Select>
<div class="mb-3">
<Label class="mb-2">Time limit</Label>
<Select.Root type="single" bind:value={$quizStore.timelimit}>
<Select.Trigger class="w-full">
<p>{$quizStore.timelimit || 'Select time limit'}</p>
</Select.Trigger>
<Select.Content>
<Select.Item value="10 seconds">10s</Select.Item>
<Select.Item value="20 seconds">20s</Select.Item>
<Select.Item value="30 seconds">30s</Select.Item>
<Select.Item value="1 minute">1m</Select.Item>
<Select.Item value="2 minute">2m</Select.Item>
<Select.Item value="3 minute">3m</Select.Item>
</Select.Content>
</Select.Root>
</div>
</div>
<!-- Theme settings -->