From 0af5aeef9580bca331a308ed5b298ec154c76f78 Mon Sep 17 00:00:00 2001 From: Mawoka Date: Wed, 21 Dec 2022 22:03:37 +0100 Subject: [PATCH] :sparkles: Editor and backend! --- classquiz/db/models.py | 22 +- frontend/package.json | 1 + frontend/pnpm-lock.yaml | 9 + frontend/src/lib/editor.svelte | 2 + frontend/src/lib/editor/card.svelte | 14 +- frontend/src/lib/editor/sidebar.svelte | 10 +- frontend/src/lib/editor/slide.svelte | 332 +++++++++--------- .../editor/slides/element_selection.svelte | 52 +-- .../lib/editor/slides/settings_menu.svelte | 39 ++ .../lib/editor/slides/types/headline.svelte | 6 +- frontend/src/lib/editor/types.ts | 11 - frontend/src/lib/quiz_types.ts | 20 +- frontend/src/lib/yupSchemas.ts | 32 +- 13 files changed, 331 insertions(+), 219 deletions(-) create mode 100644 frontend/src/lib/editor/slides/settings_menu.svelte delete mode 100644 frontend/src/lib/editor/types.ts diff --git a/classquiz/db/models.py b/classquiz/db/models.py index 5b08633..8809d2e 100644 --- a/classquiz/db/models.py +++ b/classquiz/db/models.py @@ -112,23 +112,43 @@ class QuizQuestionType(str, Enum): ABCD = "ABCD" RANGE = "RANGE" VOTING = "VOTING" + SLIDE = "SLIDE" + + +class SlideElementTypes(str, Enum): + TEXT = "TEXT" + HEADLINE = "HEADLINE" + IMAGE = "IMAGE" + + +class SlideElement(BaseModel): + type: SlideElementTypes + x: float + y: float + height: float + width: float + data: str + id: int class QuizQuestion(BaseModel): question: str time: str # in Secs type: None | QuizQuestionType = QuizQuestionType.ABCD - answers: list[ABCDQuizAnswer] | RangeQuizAnswer | list[VotingQuizAnswer] + answers: list[ABCDQuizAnswer] | RangeQuizAnswer | list[VotingQuizAnswer] | list[SlideElement] image: str | None = None @validator("answers") def answers_not_none_if_abcd_type(cls, v, values): + print(values) if values["type"] == QuizQuestionType.ABCD and type(v[0]) != ABCDQuizAnswer: raise ValueError("Answers can't be none if type is ABCD") if values["type"] == QuizQuestionType.RANGE and type(v) != RangeQuizAnswer: raise ValueError("Answer must be from type RangeQuizAnswer if type is RANGE") if values["type"] == QuizQuestionType.VOTING and type(v[0]) != VotingQuizAnswer: raise ValueError("Answer must be from type VotingQuizAnswer if type is VOTING") + if values["type"] == QuizQuestionType.SLIDE and type(v[0]) != SlideElement: + raise ValueError("Answer must be from type SlideElement if type is SLIDE") return v diff --git a/frontend/package.json b/frontend/package.json index a359008..576843a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,6 +24,7 @@ "@felte/reporter-tippy": "^1.1.4", "@felte/validator-yup": "^1.0.10", "@fontsource/marck-script": "^4.5.11", + "@neodrag/svelte": "^1.2.4", "@sentry/browser": "^7.23.0", "@sentry/tracing": "^7.23.0", "@simplewebauthn/browser": "^6.2.2", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index db415aa..d7e3535 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -11,6 +11,7 @@ specifiers: '@felte/reporter-tippy': ^1.1.4 '@felte/validator-yup': ^1.0.10 '@fontsource/marck-script': ^4.5.11 + '@neodrag/svelte': ^1.2.4 '@sentry/browser': ^7.23.0 '@sentry/tracing': ^7.23.0 '@simplewebauthn/browser': ^6.2.2 @@ -91,6 +92,7 @@ devDependencies: '@felte/reporter-tippy': 1.1.4_tippy.js@6.3.7 '@felte/validator-yup': 1.0.10_yup@0.32.11 '@fontsource/marck-script': 4.5.11 + '@neodrag/svelte': 1.2.4 '@sentry/browser': 7.27.0 '@sentry/tracing': 7.27.0 '@simplewebauthn/browser': 6.2.2 @@ -1001,6 +1003,13 @@ packages: engines: { node: '>=6.0.0' } dev: true + /@neodrag/svelte/1.2.4: + resolution: + { + integrity: sha512-oGOxAgjtLbHyCJIWv35cvuHpgip9Kzn0ANrCidZb3rXV29w3AWhS7VtKAQfRinzFbmfK0Jeic7aSYdGmtKFKqw== + } + dev: true + /@nodelib/fs.scandir/2.1.5: resolution: { diff --git a/frontend/src/lib/editor.svelte b/frontend/src/lib/editor.svelte index eda9e46..574a0a8 100644 --- a/frontend/src/lib/editor.svelte +++ b/frontend/src/lib/editor.svelte @@ -39,11 +39,13 @@ } const validateInput = async (data: EditorData) => { + // console.log("input", data) try { await dataSchema.validate(data, { abortEarly: false }); schemaInvalid = false; yupErrorMessage = ''; } catch (err) { + console.log('erro!', err.errors); schemaInvalid = true; yupErrorMessage = err.errors ? err.errors[0] : ''; } diff --git a/frontend/src/lib/editor/card.svelte b/frontend/src/lib/editor/card.svelte index a79b74f..061b0ff 100644 --- a/frontend/src/lib/editor/card.svelte +++ b/frontend/src/lib/editor/card.svelte @@ -12,7 +12,7 @@ import Spinner from '../Spinner.svelte'; import { createTippy } from 'svelte-tippy'; import { getLocalization } from '$lib/i18n'; - import Slide from './slide.svelte'; + // import Slide from './slide.svelte'; const { t } = getLocalization(); @@ -50,6 +50,8 @@ data.questions[selected_question].type = QuizQuestionType.ABCD; } */ + + $: console.log();
@@ -67,7 +69,13 @@ />
- {#if data.questions[selected_question].time} + {#if data.questions[selected_question].type === QuizQuestionType.SLIDE} + {#await import('./slide.svelte')} + + {:then c} + + {/await} + {:else}
{#await import('$lib/inline-editor.svelte')} @@ -179,8 +187,6 @@ {$t('editor_page.right_click_to_delete')}

- {:else} - {/if}
diff --git a/frontend/src/lib/editor/sidebar.svelte b/frontend/src/lib/editor/sidebar.svelte index 0b0aa6f..19f2f42 100644 --- a/frontend/src/lib/editor/sidebar.svelte +++ b/frontend/src/lib/editor/sidebar.svelte @@ -28,6 +28,14 @@ type: QuizQuestionType.ABCD }; + const empy_slide: Question = { + type: QuizQuestionType.SLIDE, + time: '120', + question: 'Slide', + image: undefined, + answers: [] + }; + const setSelectedQuestion = (index: number): void => { selected_question = index; if (index === -1) { @@ -270,7 +278,7 @@ type="button" class="h-full flex justify-center w-full dark:text-black" on:click={() => { - data.questions = [...data.questions, { ...{} }]; + data.questions = [...data.questions, { ...empy_slide }]; }} > -
-
- {#each elements as el, i} -
- - - - - {#if el.type === ElementTypes.Text} -

Text

- - {:else if el.type === ElementTypes.Headline} -

Headline

- - {/if} -
- {/each} +
+
+ + {#if selected_element === null} + + {/if}
-
- {#each ghost_elements as el, i} -
- + {#if settings_menu_open} + + {/if} +
+ {#if main_el} + {#each data.answers as el, i} +
+ - {i} + - - - + d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4" + /> + + {#if el.type === ElementTypes.Text} + + {:else if el.type === ElementTypes.Headline} + + {/if}
{/each} -
+ {/if}
diff --git a/frontend/src/lib/editor/slides/element_selection.svelte b/frontend/src/lib/editor/slides/element_selection.svelte index 2639ac5..ac07cf1 100644 --- a/frontend/src/lib/editor/slides/element_selection.svelte +++ b/frontend/src/lib/editor/slides/element_selection.svelte @@ -4,10 +4,11 @@ - file, You can obtain one at https://mozilla.org/MPL/2.0/. -->
-
-
-

Select the element you want to add

-
-
    - {#each element_list as el} -
  • { - elementSelection.set({ data: el.type }); - }} - > -
    -

    {el.name}

    -

    {el.description}

    -
    - {el.shortcut} -
  • - {/each} -
-
+
    + {#each element_list as el} +
  • { + selected_element = el.type; + }} + > +
    +

    {el.name}

    +

    {el.description}

    +
    + {el.shortcut} +
  • + {/each} +
diff --git a/frontend/src/lib/editor/slides/settings_menu.svelte b/frontend/src/lib/editor/slides/settings_menu.svelte new file mode 100644 index 0000000..88171ef --- /dev/null +++ b/frontend/src/lib/editor/slides/settings_menu.svelte @@ -0,0 +1,39 @@ + + + +
+ + +
diff --git a/frontend/src/lib/editor/slides/types/headline.svelte b/frontend/src/lib/editor/slides/types/headline.svelte index 2272baf..5285a71 100644 --- a/frontend/src/lib/editor/slides/types/headline.svelte +++ b/frontend/src/lib/editor/slides/types/headline.svelte @@ -7,4 +7,8 @@ export let data; - + diff --git a/frontend/src/lib/editor/types.ts b/frontend/src/lib/editor/types.ts deleted file mode 100644 index a5a5cab..0000000 --- a/frontend/src/lib/editor/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -export enum ElementTypes { - Text = 'TEXT', - Headline = 'HEADLINE', - Image = 'IMAGE' -} diff --git a/frontend/src/lib/quiz_types.ts b/frontend/src/lib/quiz_types.ts index cca3897..fbda89c 100644 --- a/frontend/src/lib/quiz_types.ts +++ b/frontend/src/lib/quiz_types.ts @@ -4,6 +4,12 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +export enum ElementTypes { + Text = 'TEXT', + Headline = 'HEADLINE', + Image = 'IMAGE' +} + export interface QuizData { title: string; description: string; @@ -19,7 +25,8 @@ export interface QuizData { export enum QuizQuestionType { ABCD = 'ABCD', // eslint-disable-line no-unused-vars RANGE = 'RANGE', // eslint-disable-line no-unused-vars - VOTING = 'VOTING' // eslint-disable-line no-unused-vars + VOTING = 'VOTING', // eslint-disable-line no-unused-vars + SLIDE = 'SLIDE' // eslint-disable-line no-unused-vars } export interface RangeQuizAnswer { @@ -29,6 +36,16 @@ export interface RangeQuizAnswer { max_correct: number; } +export interface Slide { + type: ElementTypes; + x: number; + y: number; + height: number; + width: number; + data: string; + id: number; +} + export interface Question { time: string; question: string; @@ -42,6 +59,7 @@ export interface Answer { answer: string; color?: string; } + export interface VotingAnswer { answer: string; image?: string; diff --git a/frontend/src/lib/yupSchemas.ts b/frontend/src/lib/yupSchemas.ts index 3f81e4a..1f3e2f0 100644 --- a/frontend/src/lib/yupSchemas.ts +++ b/frontend/src/lib/yupSchemas.ts @@ -5,6 +5,7 @@ */ import * as yup from 'yup'; +import { ElementTypes } from '$lib/quiz_types'; export const ABCDQuestionSchema = yup .array() @@ -34,6 +35,18 @@ export const RangeQuestionSchema = yup.object({ min_correct: yup.number(), max_correct: yup.number() }); + +export const SlideQuestionSchema = yup.array().of( + yup.object({ + type: yup.string().required(), + x: yup.number(), + y: yup.number(), + height: yup.number(), + width: yup.number(), + data: yup.string().optional(), + id: yup.number().required() + }) +); export const dataSchema = yup.object({ public: yup.boolean().required(), type: yup.string(), @@ -63,12 +76,23 @@ export const dataSchema = yup.object({ .lowercase(), answers: yup.lazy((v) => { if (Array.isArray(v)) { - if (typeof v[0].right === 'boolean') { - return ABCDQuestionSchema; - } else { - return VotingQuestionSchema; + try { + if (typeof v[0].right === 'boolean') { + // console.log('ABCDQuestionSchema'); + return ABCDQuestionSchema; + } else if (v[0].answer !== undefined) { + // console.log('VotingQuestionSchema'); + return VotingQuestionSchema; + } else { + // console.log('SlideQuestionSchema'); + return SlideQuestionSchema; + } + } catch { + // console.log('SlideQuestionSchema'); + return SlideQuestionSchema; } } else { + // console.log('RangeQuestionSchema'); return RangeQuestionSchema; } })