✨ Finished Slides
This commit is contained in:
@@ -198,7 +198,6 @@ async def finish_edit(edit_id: str, quiz_input: QuizInput):
|
|||||||
quiz.description = quiz_input.description
|
quiz.description = quiz_input.description
|
||||||
quiz.updated_at = datetime.now()
|
quiz.updated_at = datetime.now()
|
||||||
quiz.questions = quiz_input.dict()["questions"]
|
quiz.questions = quiz_input.dict()["questions"]
|
||||||
print(quiz.questions)
|
|
||||||
quiz.cover_image = quiz_input.cover_image
|
quiz.cover_image = quiz_input.cover_image
|
||||||
quiz.background_color = quiz_input.background_color
|
quiz.background_color = quiz_input.background_color
|
||||||
for image in images_to_delete:
|
for image in images_to_delete:
|
||||||
|
|||||||
@@ -68,6 +68,7 @@
|
|||||||
"luxon": "^3.1.1",
|
"luxon": "^3.1.1",
|
||||||
"mapbox-gl": "^2.11.0",
|
"mapbox-gl": "^2.11.0",
|
||||||
"minisearch": "^5.1.0",
|
"minisearch": "^5.1.0",
|
||||||
|
"pikaso": "^2.7.4",
|
||||||
"plausible-tracker": "^0.3.8",
|
"plausible-tracker": "^0.3.8",
|
||||||
"postcss": "^8.4.19",
|
"postcss": "^8.4.19",
|
||||||
"postcss-import": "^14.1.0",
|
"postcss-import": "^14.1.0",
|
||||||
|
|||||||
Generated
+20
@@ -56,6 +56,7 @@ specifiers:
|
|||||||
luxon: ^3.1.1
|
luxon: ^3.1.1
|
||||||
mapbox-gl: ^2.11.0
|
mapbox-gl: ^2.11.0
|
||||||
minisearch: ^5.1.0
|
minisearch: ^5.1.0
|
||||||
|
pikaso: ^2.7.4
|
||||||
plausible-tracker: ^0.3.8
|
plausible-tracker: ^0.3.8
|
||||||
postcss: ^8.4.19
|
postcss: ^8.4.19
|
||||||
postcss-import: ^14.1.0
|
postcss-import: ^14.1.0
|
||||||
@@ -138,6 +139,7 @@ devDependencies:
|
|||||||
luxon: 3.1.1
|
luxon: 3.1.1
|
||||||
mapbox-gl: 2.11.1
|
mapbox-gl: 2.11.1
|
||||||
minisearch: 5.1.0
|
minisearch: 5.1.0
|
||||||
|
pikaso: 2.7.4
|
||||||
plausible-tracker: 0.3.8
|
plausible-tracker: 0.3.8
|
||||||
postcss: 8.4.20
|
postcss: 8.4.20
|
||||||
postcss-import: 14.1.0_postcss@8.4.20
|
postcss-import: 14.1.0_postcss@8.4.20
|
||||||
@@ -3911,6 +3913,13 @@ packages:
|
|||||||
engines: { node: '>=6' }
|
engines: { node: '>=6' }
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/konva/8.3.14:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-6I/TZppgY3Frs//AvZ87YVQLFxLywitb8wLS3qMM+Ih9e4QcB5Yy8br6eq7DdUzxPdbsYTz1FQBHzNxs08M1Tw==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/levn/0.3.0:
|
/levn/0.3.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -4646,6 +4655,17 @@ packages:
|
|||||||
engines: { node: '>=0.10.0' }
|
engines: { node: '>=0.10.0' }
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/pikaso/2.7.4:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-30nqF5+xBUIBKiHHfDfjA3oZChjirN3AmhfWb456iUvTpMY2D51PKjGHfgF2SoQP5Jad7i4Zv+wrQAp7BhcNmQ==
|
||||||
|
}
|
||||||
|
dependencies:
|
||||||
|
deepmerge: 4.2.2
|
||||||
|
konva: 8.3.14
|
||||||
|
typescript: 4.7.4
|
||||||
|
dev: true
|
||||||
|
|
||||||
/plausible-tracker/0.3.8:
|
/plausible-tracker/0.3.8:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,16 +27,21 @@
|
|||||||
let timer_res: string;
|
let timer_res: string;
|
||||||
let shown_question_now: number;
|
let shown_question_now: number;
|
||||||
let final_results_clicked = false;
|
let final_results_clicked = false;
|
||||||
|
let timer_interval;
|
||||||
|
|
||||||
export let player_scores;
|
export let player_scores;
|
||||||
|
|
||||||
export const set_question_number = (q_number: number) => {
|
export const set_question_number = (q_number: number) => {
|
||||||
|
timer_res = '0';
|
||||||
|
clearInterval(timer_interval);
|
||||||
|
// setTimeout(() => {
|
||||||
question_results = null;
|
question_results = null;
|
||||||
socket.emit('set_question_number', q_number.toString());
|
socket.emit('set_question_number', q_number.toString());
|
||||||
shown_question_now = q_number;
|
shown_question_now = q_number;
|
||||||
timer_res = quiz_data.questions[q_number].time;
|
timer_res = quiz_data.questions[q_number].time;
|
||||||
selected_question = selected_question + 1;
|
selected_question = selected_question + 1;
|
||||||
timer(timer_res);
|
timer(timer_res);
|
||||||
|
// }, 1000);
|
||||||
};
|
};
|
||||||
const get_question_results = () => {
|
const get_question_results = () => {
|
||||||
socket.emit('get_question_results', {
|
socket.emit('get_question_results', {
|
||||||
@@ -53,6 +58,7 @@
|
|||||||
const get_final_results = () => {
|
const get_final_results = () => {
|
||||||
socket.emit('get_final_results', {});
|
socket.emit('get_final_results', {});
|
||||||
final_results_clicked = true;
|
final_results_clicked = true;
|
||||||
|
timer_res = '0';
|
||||||
};
|
};
|
||||||
|
|
||||||
socket.on('final_results', (data) => {
|
socket.on('final_results', (data) => {
|
||||||
@@ -75,7 +81,7 @@
|
|||||||
|
|
||||||
const timer = (time: string) => {
|
const timer = (time: string) => {
|
||||||
let seconds = Number(time);
|
let seconds = Number(time);
|
||||||
let timer_interval = setInterval(() => {
|
timer_interval = setInterval(() => {
|
||||||
if (timer_res === '0') {
|
if (timer_res === '0') {
|
||||||
clearInterval(timer_interval);
|
clearInterval(timer_interval);
|
||||||
// socket.emit('show_solutions', {});
|
// socket.emit('show_solutions', {});
|
||||||
@@ -109,7 +115,7 @@
|
|||||||
/{quiz_data.questions.length}
|
/{quiz_data.questions.length}
|
||||||
</p>
|
</p>
|
||||||
<div class="justify-self-end ml-auto mr-0 col-start-3 col-end-3">
|
<div class="justify-self-end ml-auto mr-0 col-start-3 col-end-3">
|
||||||
{#if selected_question + 1 === quiz_data.questions.length && timer_res === '0' && question_results !== null}
|
{#if selected_question + 1 === quiz_data.questions.length && ((timer_res === '0' && question_results !== null) || quiz_data?.questions?.[selected_question]?.type === QuizQuestionType.SLIDE)}
|
||||||
{#if JSON.stringify(final_results) === JSON.stringify([null])}
|
{#if JSON.stringify(final_results) === JSON.stringify([null])}
|
||||||
<button on:click={get_final_results} class="admin-button"
|
<button on:click={get_final_results} class="admin-button"
|
||||||
>Get final results
|
>Get final results
|
||||||
@@ -126,12 +132,34 @@
|
|||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
{#if question_results === null && selected_question !== -1}
|
{#if question_results === null && selected_question !== -1}
|
||||||
<button on:click={get_question_results} class="admin-button">Show results</button>
|
{#if quiz_data.questions[selected_question].type === QuizQuestionType.SLIDE}
|
||||||
|
<button
|
||||||
|
on:click={() => {
|
||||||
|
set_question_number(selected_question + 1);
|
||||||
|
}}
|
||||||
|
class="admin-button"
|
||||||
|
>Next Question ({selected_question + 2})
|
||||||
|
</button>
|
||||||
|
{:else}
|
||||||
|
<button on:click={get_question_results} class="admin-button"
|
||||||
|
>Show results</button
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
{:else if selected_question !== -1}
|
{:else if selected_question !== -1}
|
||||||
<button on:click={show_solutions} class="admin-button"
|
{#if quiz_data.questions[selected_question].type === QuizQuestionType.SLIDE}
|
||||||
>Stop time and show solutions
|
<button
|
||||||
</button>
|
on:click={() => {
|
||||||
|
set_question_number(selected_question + 1);
|
||||||
|
}}
|
||||||
|
class="admin-button"
|
||||||
|
>Next Question ({selected_question + 2})
|
||||||
|
</button>
|
||||||
|
{:else}
|
||||||
|
<button on:click={show_solutions} class="admin-button"
|
||||||
|
>Stop time and show solutions
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<!-- <button
|
<!-- <button
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
import StartGamePopup from './start_game.svelte';
|
import StartGamePopup from './start_game.svelte';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import viewport from './useViewportAction.js';
|
import viewport from './useViewportAction.js';
|
||||||
|
import Spinner from '$lib/Spinner.svelte';
|
||||||
|
|
||||||
let copy_toast_open = false;
|
let copy_toast_open = false;
|
||||||
let start_game = null;
|
let start_game = null;
|
||||||
@@ -350,6 +351,28 @@
|
|||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
{:else if question.type === QuizQuestionType.SLIDE}
|
||||||
|
<div
|
||||||
|
use:viewport
|
||||||
|
on:enterViewport={() => {
|
||||||
|
visibleImages[i][q] = true;
|
||||||
|
}}
|
||||||
|
on:exitViewport={() => {
|
||||||
|
visibleImages[i][q] = false;
|
||||||
|
}}
|
||||||
|
class="flex justify-center align-middle items-center"
|
||||||
|
>
|
||||||
|
{#await import('$lib/play/admin/slide.svelte')}
|
||||||
|
<Spinner my={false} />
|
||||||
|
{:then c}
|
||||||
|
<div class="max-h-[50%] max-w-[60%]">
|
||||||
|
<svelte:component
|
||||||
|
this={c.default}
|
||||||
|
bind:question
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/await}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
|
|||||||
@@ -23,26 +23,11 @@
|
|||||||
let selected_element = undefined;
|
let selected_element = undefined;
|
||||||
let canvas_el: HTMLDivElement | undefined;
|
let canvas_el: HTMLDivElement | undefined;
|
||||||
let canvas: Pikaso;
|
let canvas: Pikaso;
|
||||||
let elements = [];
|
|
||||||
let selected_el: null | ShapeModel<Konva.Shape | Konva.Group, Konva.ShapeConfig> = null;
|
let selected_el: null | ShapeModel<Konva.Shape | Konva.Group, Konva.ShapeConfig> = null;
|
||||||
|
|
||||||
let elements_binds: Array<HTMLElement> | undefined = [];
|
let elements_binds: Array<HTMLElement> | undefined = [];
|
||||||
let main_el: undefined | HTMLElement;
|
let main_el: undefined | HTMLElement;
|
||||||
let settings_menu_open = false;
|
let settings_menu_open = false;
|
||||||
const get_location = (id: number): { row: number; col: number } => {
|
|
||||||
const numColumns = 12;
|
|
||||||
const row = Math.floor(id / numColumns);
|
|
||||||
const col = id % numColumns;
|
|
||||||
return { row, col };
|
|
||||||
};
|
|
||||||
|
|
||||||
const set_correct_position = (
|
|
||||||
e: CustomEvent<{ offsetX: number; offsetY: number; domRect: DOMRect }>
|
|
||||||
) => {
|
|
||||||
const id = parseInt(e.target.getAttribute('el_id'));
|
|
||||||
data.answers[id].x = e.detail.offsetX / main_el.offsetWidth;
|
|
||||||
data.answers[id].y = e.detail.offsetY / main_el.offsetHeight;
|
|
||||||
};
|
|
||||||
|
|
||||||
const set_correct_height = new ResizeObserver((e) => {
|
const set_correct_height = new ResizeObserver((e) => {
|
||||||
for (const i of e) {
|
for (const i of e) {
|
||||||
@@ -116,10 +101,6 @@
|
|||||||
assign_resize_handlers();
|
assign_resize_handlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
const set_correct_size = (e: UIEvent) => {
|
|
||||||
console.log(e, 'resized');
|
|
||||||
};
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
/* setTimeout(() => {
|
/* setTimeout(() => {
|
||||||
for (let i = 0; i < data.answers.length; i++) {
|
for (let i = 0; i < data.answers.length; i++) {
|
||||||
@@ -156,14 +137,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const get_shape_from_id = (id: number) => {
|
|
||||||
for (let i = 0; i < canvas.board.shapes.length; i++) {
|
|
||||||
if (canvas.board.shapes[i].node._id === id) {
|
|
||||||
return canvas.board.shapes[i].node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex h-full relative w-full" bind:this={main_el}>
|
<div class="flex h-full relative w-full" bind:this={main_el}>
|
||||||
|
|||||||
@@ -5,38 +5,36 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Question } from '$lib/quiz_types';
|
import type { Question } from '$lib/quiz_types';
|
||||||
import TextElement from '$lib/editor/slides/types/text.svelte';
|
import { onMount } from 'svelte';
|
||||||
import HeadlineElement from '$lib/editor/slides/types/headline.svelte';
|
import Pikaso from 'pikaso';
|
||||||
import { ElementTypes } from '$lib/quiz_types.js';
|
|
||||||
import { draggable } from '@neodrag/svelte';
|
|
||||||
|
|
||||||
export let question: Question;
|
export let question: Question;
|
||||||
|
|
||||||
let main_el: HTMLElement | undefined;
|
let canvas_el: HTMLDivElement | undefined;
|
||||||
|
let canvas: Pikaso;
|
||||||
|
let img_src = '';
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
canvas = new Pikaso({
|
||||||
|
container: canvas_el,
|
||||||
|
snapToGrid: {},
|
||||||
|
selection: {
|
||||||
|
interactive: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (typeof question.answers === 'string') {
|
||||||
|
const data = JSON.parse(question.answers);
|
||||||
|
canvas.import.json(data);
|
||||||
|
img_src = canvas.export.toImage();
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="w-full min-h-[calc(100vh-8rem)]" bind:this={main_el}>
|
<div class="w-full h-full">
|
||||||
{#if main_el}
|
<div class="hidden">
|
||||||
{#each question.answers as el, i}
|
<div bind:this={canvas_el} class="w-full h-full block" />
|
||||||
<div
|
</div>
|
||||||
use:draggable={{
|
<div class="w-full h-full flex justify-center">
|
||||||
bounds: 'parent',
|
<img src={img_src} />
|
||||||
handle: '.drag',
|
</div>
|
||||||
disabled: true,
|
|
||||||
defaultPosition: {
|
|
||||||
x: el.x * main_el.offsetWidth,
|
|
||||||
y: el.y * main_el.offsetHeight
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style="height: {el.height * main_el.offsetHeight}px; width: {el.width *
|
|
||||||
main_el.offsetWidth}px"
|
|
||||||
>
|
|
||||||
{#if el.type === ElementTypes.Text}
|
|
||||||
<TextElement bind:data={el.data} editor={false} />
|
|
||||||
{:else if el.type === ElementTypes.Headline}
|
|
||||||
<HeadlineElement bind:data={el.data} editor={false} />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -150,5 +150,13 @@
|
|||||||
{#if timer_res === '0'}
|
{#if timer_res === '0'}
|
||||||
<p>No correct answers, since this is a poll-question</p>
|
<p>No correct answers, since this is a poll-question</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
{:else if question.type === QuizQuestionType.SLIDE}
|
||||||
|
{#await import('$lib/play/admin/slide.svelte')}
|
||||||
|
<Spinner my={false} />
|
||||||
|
{:then c}
|
||||||
|
<div class="max-h-[90%] max-w-[90%]">
|
||||||
|
<svelte:component this={c.default} bind:question />
|
||||||
|
</div>
|
||||||
|
{/await}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as yup from 'yup';
|
import * as yup from 'yup';
|
||||||
import { ElementTypes } from '$lib/quiz_types';
|
|
||||||
|
|
||||||
export const ABCDQuestionSchema = yup
|
export const ABCDQuestionSchema = yup
|
||||||
.array()
|
.array()
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
import { QuizQuestionType } from '$lib/quiz_types.js';
|
import { QuizQuestionType } from '$lib/quiz_types.js';
|
||||||
import StartGamePopup from '$lib/dashboard/start_game.svelte';
|
import StartGamePopup from '$lib/dashboard/start_game.svelte';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import Spinner from '$lib/Spinner.svelte';
|
||||||
|
|
||||||
const tippy = createTippy({
|
const tippy = createTippy({
|
||||||
arrow: true,
|
arrow: true,
|
||||||
@@ -228,6 +229,14 @@
|
|||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
{:else if question.type === QuizQuestionType.SLIDE}
|
||||||
|
{#await import('$lib/play/admin/slide.svelte')}
|
||||||
|
<Spinner my={false} />
|
||||||
|
{:then c}
|
||||||
|
<div class="max-h-[90%] max-w-[90%]">
|
||||||
|
<svelte:component this={c.default} bind:question />
|
||||||
|
</div>
|
||||||
|
{/await}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</CollapsSection>
|
</CollapsSection>
|
||||||
|
|||||||
Reference in New Issue
Block a user