Further cleanup, mostly with svelte 5 migration placeholder cleanup
This commit is contained in:
@@ -15,7 +15,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
import Controls from '$lib/play/admin/controls.svelte';
|
||||
import Question from '$lib/play/admin/question.svelte';
|
||||
|
||||
|
||||
const { t } = getLocalization();
|
||||
const default_colors = ['#D6EDC9', '#B07156', '#7F7057', '#4E6E58'];
|
||||
|
||||
@@ -24,13 +23,12 @@ SPDX-License-Identifier: MPL-2.0
|
||||
let timer_res: string = $state();
|
||||
let shown_question_now: number = $state();
|
||||
let final_results_clicked = $state(false);
|
||||
let timer_interval;
|
||||
let timer_interval: NodeJS.Timeout;
|
||||
let answer_count = $state(0);
|
||||
|
||||
interface Props {
|
||||
game_token: string;
|
||||
quiz_data: QuizData;
|
||||
game_mode: string;
|
||||
bg_color: string;
|
||||
final_results?: Array<null> | Array<Array<PlayerAnswer>>;
|
||||
control_visible: boolean;
|
||||
@@ -40,7 +38,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
let {
|
||||
game_token,
|
||||
quiz_data = $bindable(),
|
||||
game_mode,
|
||||
bg_color,
|
||||
final_results = $bindable([null]),
|
||||
control_visible,
|
||||
@@ -92,7 +89,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
timer_interval = setInterval(() => {
|
||||
if (timer_res === '0') {
|
||||
clearInterval(timer_interval);
|
||||
// socket.emit('show_solutions', {});
|
||||
return;
|
||||
} else {
|
||||
seconds--;
|
||||
@@ -132,9 +128,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
{#await import('$lib/play/admin/slide.svelte')}
|
||||
<Spinner my_20={false} />
|
||||
{:then c}
|
||||
<c.default
|
||||
bind:question={quiz_data.questions[selected_question]}
|
||||
/>
|
||||
<c.default question={quiz_data.questions[selected_question]} />
|
||||
{/await}
|
||||
{:else}
|
||||
<Question {quiz_data} {selected_question} {timer_res} {answer_count} {default_colors} />
|
||||
@@ -153,8 +147,8 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<Spinner />
|
||||
{:then c}
|
||||
<c.default
|
||||
bind:data={question_results}
|
||||
bind:question={quiz_data.questions[selected_question]}
|
||||
data={question_results}
|
||||
question={quiz_data.questions[selected_question]}
|
||||
/>
|
||||
{/await}
|
||||
{:else}
|
||||
@@ -164,7 +158,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<c.default
|
||||
bind:data={player_scores}
|
||||
question={quiz_data.questions[selected_question]}
|
||||
bind:new_data={question_results}
|
||||
new_data={question_results}
|
||||
/>
|
||||
{/await}
|
||||
{/if}
|
||||
|
||||
@@ -8,8 +8,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
This should be okay, right?
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import { tinykeys } from '$lib/tinykeys';
|
||||
import { fade } from 'svelte/transition';
|
||||
@@ -104,7 +102,6 @@ This should be okay, right?
|
||||
const toggle_open = (e: KeyboardEvent | undefined) => {
|
||||
e.preventDefault();
|
||||
open = !open;
|
||||
console.log('TOGGLE!');
|
||||
};
|
||||
|
||||
const close_cp = (e: KeyboardEvent | undefined) => {
|
||||
@@ -159,7 +156,6 @@ This should be okay, right?
|
||||
|
||||
visible_items = [];
|
||||
|
||||
console.log(res);
|
||||
for (const quiz_data of res) {
|
||||
visible_items.push(actions[quiz_data.id]);
|
||||
}
|
||||
@@ -206,13 +202,6 @@ This should be okay, right?
|
||||
input = '';
|
||||
};
|
||||
|
||||
run(() => {
|
||||
search(input);
|
||||
});
|
||||
// $: input = lower_input(input)
|
||||
run(() => {
|
||||
input = input.toLowerCase();
|
||||
});
|
||||
onMount(async () => {
|
||||
tinykeys(window, {
|
||||
'$mod+k': toggle_open,
|
||||
@@ -240,7 +229,9 @@ This should be okay, right?
|
||||
class="fixed top-0 left-0 w-screen h-screen flex bg-black/50 z-50"
|
||||
onclick={close_on_outside}
|
||||
onkeyup={close_on_outside}
|
||||
role="generic"
|
||||
role="button"
|
||||
aria-label="Close"
|
||||
tabindex="0"
|
||||
transition:fade|global={{ duration: 60 }}
|
||||
>
|
||||
<div class="m-auto w-1/3 h-2/3 rounded-sm bg-black flex flex-col">
|
||||
@@ -252,8 +243,9 @@ This should be okay, right?
|
||||
</p>
|
||||
<input
|
||||
type="text"
|
||||
class="col-start-1 row-start-1 bg-transparent w-full p-4 outline-hidden bg-gray-700 rounded-sm"
|
||||
class="col-start-1 row-start-1 w-full p-4 outline-hidden bg-gray-700 rounded-sm"
|
||||
bind:value={input}
|
||||
oninput={() => search(input)}
|
||||
autofocus
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -5,17 +5,12 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { fly } from 'svelte/transition';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { PopoverTypes } from './smalltop';
|
||||
|
||||
const { t } = getLocalization();
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
interface Props {
|
||||
open?: boolean;
|
||||
type: PopoverTypes;
|
||||
@@ -23,10 +18,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
}
|
||||
|
||||
let { open = $bindable(false), type, data = undefined }: Props = $props();
|
||||
|
||||
run(() => {
|
||||
dispatch('open', open);
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if open}
|
||||
|
||||
@@ -5,9 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run, preventDefault } from 'svelte/legacy';
|
||||
|
||||
// import { mint } from '$lib/hashcash';
|
||||
import { dataSchema } from '$lib/yupSchemas';
|
||||
import type { EditorData, Question } from './quiz_types';
|
||||
import Sidebar from '$lib/editor/sidebar.svelte';
|
||||
@@ -28,52 +25,25 @@ SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
let { data = $bindable(), quiz_id }: Props = $props();
|
||||
let selected_question = $state(-1);
|
||||
let imgur_links_valid = $state(false);
|
||||
|
||||
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] : '';
|
||||
}
|
||||
};
|
||||
run(() => {
|
||||
$effect(() => {
|
||||
validateInput(data);
|
||||
});
|
||||
|
||||
const checkIfAllQuestionImagesComplyWithRegex = (questions: Array<Question>) => {
|
||||
let NoteverythingValid = false;
|
||||
// const regex = /^https:\/\/i\.imgur\.com\/.{7}.(jpg|png|gif)$/;
|
||||
// const local_regex = /^http(|s):\/\/\w*(|:)\d*\/api\/v1\/storage\/download\/.{36}--.{36}$/g;
|
||||
const main_regex =
|
||||
/^(http(|s):\/\/.*(|:)\d*\/api\/v1\/storage\/download\/.{36}--.{36}|https:\/\/i\.imgur\.com\/.{7}.(jpg|png|gif))$/;
|
||||
for (let i = 0; i < questions.length; i++) {
|
||||
const question = questions[i];
|
||||
|
||||
if (question.image && !main_regex.test(question.image)) {
|
||||
NoteverythingValid = true;
|
||||
}
|
||||
}
|
||||
return NoteverythingValid;
|
||||
};
|
||||
|
||||
run(() => {
|
||||
imgur_links_valid = checkIfAllQuestionImagesComplyWithRegex(data.questions);
|
||||
});
|
||||
let edit_id = $state();
|
||||
let edit_id: string = $state();
|
||||
let confirm_to_leave = true;
|
||||
|
||||
run(() => {
|
||||
console.log('data', data);
|
||||
});
|
||||
|
||||
const getEditID = async () => {
|
||||
let res;
|
||||
let res: Response;
|
||||
if (quiz_id === null) {
|
||||
res = await fetch(`/api/v1/editor/start?edit=false`, {
|
||||
method: 'POST'
|
||||
@@ -91,8 +61,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
}
|
||||
};
|
||||
|
||||
const confirmUnload = (event) => {
|
||||
console.log(confirm_to_leave);
|
||||
const confirmUnload = (event: BeforeUnloadEvent) => {
|
||||
if (!confirm_to_leave) {
|
||||
return;
|
||||
}
|
||||
@@ -101,7 +70,8 @@ SPDX-License-Identifier: MPL-2.0
|
||||
localStorage.setItem('edit_game', JSON.stringify(data));
|
||||
return 'unload';
|
||||
};
|
||||
const saveQuiz = async () => {
|
||||
const saveQuiz = async (e: Event) => {
|
||||
e.preventDefault();
|
||||
if (schemaInvalid) {
|
||||
return;
|
||||
}
|
||||
@@ -126,7 +96,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
{#await getEditID()}
|
||||
<Spinner />
|
||||
{:then _}
|
||||
<form onsubmit={preventDefault(saveQuiz)}>
|
||||
<form onsubmit={saveQuiz}>
|
||||
<div class="grid grid-cols-6 h-screen w-screen">
|
||||
<div>
|
||||
<Sidebar bind:data bind:selected_question />
|
||||
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { browser } from '$app/environment';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { thumbHashToDataURL } from 'thumbhash';
|
||||
@@ -36,7 +34,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
return Uint8Array.from(binString, (m) => m.codePointAt(0));
|
||||
}
|
||||
|
||||
const get_media = async () => {
|
||||
const get_media = async (_: string) => {
|
||||
if (!browser) {
|
||||
return;
|
||||
}
|
||||
@@ -55,14 +53,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
thumbhash_data = undefined;
|
||||
}
|
||||
};
|
||||
const update_url = () => {
|
||||
media = get_media();
|
||||
};
|
||||
let media = $state(get_media());
|
||||
run(() => {
|
||||
src;
|
||||
update_url();
|
||||
});
|
||||
let media = $derived(get_media(src));
|
||||
|
||||
let fullscreen_open = $state(false);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run, preventDefault } from 'svelte/legacy';
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
import type { EditorData, OrderQuizAnswer } from '$lib/quiz_types';
|
||||
@@ -170,9 +170,10 @@ SPDX-License-Identifier: MPL-2.0
|
||||
class="rounded-lg p-1 border-black border"
|
||||
type="color"
|
||||
bind:value={answer.color}
|
||||
oncontextmenu={preventDefault(() => {
|
||||
oncontextmenu={(e) => {
|
||||
e.preventDefault();
|
||||
answer.color = null;
|
||||
})}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
@@ -27,19 +27,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
const correct_numbers = (data: number[]) => {
|
||||
console.log(data, data[1] <= data[0])
|
||||
if (data[1] <= data[0]) {
|
||||
range_arr[1] = range_arr[0] + 2
|
||||
}
|
||||
if (data[0] <= data[1]) {
|
||||
range_arr[0] = range_arr[1] - 2
|
||||
}
|
||||
}
|
||||
$: correct_numbers(range_arr)
|
||||
|
||||
*/
|
||||
let answer = question.answers;
|
||||
let range_arr = $state([answer.min_correct, answer.max_correct]);
|
||||
run(() => {
|
||||
|
||||
@@ -5,7 +5,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run, preventDefault } from 'svelte/legacy';
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import type { EditorData } from '../quiz_types';
|
||||
import { fade } from 'svelte/transition';
|
||||
@@ -103,9 +103,10 @@ SPDX-License-Identifier: MPL-2.0
|
||||
class="rounded-lg p-1 border-black border"
|
||||
type="color"
|
||||
bind:value={answer.color}
|
||||
oncontextmenu={preventDefault(() => {
|
||||
oncontextmenu={(e) => {
|
||||
e.preventDefault();
|
||||
answer.color = default_colors[index];
|
||||
})}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run, preventDefault } from 'svelte/legacy';
|
||||
|
||||
import type { EditorData } from '$lib/quiz_types';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
import Spinner from '$lib/Spinner.svelte';
|
||||
@@ -30,7 +28,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
animation: 'perspective-subtle'
|
||||
});
|
||||
|
||||
run(() => {
|
||||
$effect(() => {
|
||||
data.background_color = custom_bg_color ? data.background_color : undefined;
|
||||
});
|
||||
</script>
|
||||
@@ -57,11 +55,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
: `unset`}"
|
||||
>
|
||||
<div class="flex justify-center pt-10 w-full">
|
||||
<!--<input
|
||||
type="text"
|
||||
bind:value={data.title}
|
||||
class="p-3 rounded-lg border-gray-500 border text-center w-1/3 text-lg font-semibold dark:bg-gray-500"
|
||||
/>-->
|
||||
{#await import('$lib/inline-editor.svelte')}
|
||||
<Spinner my_20={false} />
|
||||
{:then c}
|
||||
@@ -70,7 +63,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
</div>
|
||||
<div class="flex justify-center pt-10 w-full max-h-32">
|
||||
<textarea
|
||||
type="text"
|
||||
placeholder="Description"
|
||||
bind:value={data.description}
|
||||
class="p-3 rounded-lg border-gray-500 border text-center w-1/3 h-20 resize-none dark:bg-gray-500 outline-hidden focus:shadow-2xl transition-all"
|
||||
@@ -78,26 +70,22 @@ SPDX-License-Identifier: MPL-2.0
|
||||
</div>
|
||||
|
||||
{#if data.cover_image != undefined && data.cover_image !== ''}
|
||||
<div class="flex justify-center pt-10 w-full max-h-72 w-full">
|
||||
<div class="flex justify-center pt-10 w-full max-h-72">
|
||||
<img
|
||||
src="/api/v1/storage/download/{data.cover_image}"
|
||||
alt="not available"
|
||||
class="max-h-72 h-auto w-auto"
|
||||
oncontextmenu={preventDefault(() => {
|
||||
oncontextmenu={(e: Event) => {
|
||||
e.preventDefault();
|
||||
data.cover_image = null;
|
||||
})}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
{#await import('$lib/editor/uploader.svelte')}
|
||||
<Spinner my_20={false} />
|
||||
{:then c}
|
||||
<c.default
|
||||
bind:modalOpen={uppyOpen}
|
||||
bind:edit_id
|
||||
bind:data
|
||||
video_upload={false}
|
||||
/>
|
||||
<c.default bind:modalOpen={uppyOpen} {data} video_upload={false} />
|
||||
{/await}
|
||||
{/if}
|
||||
<div class="pt-10 w-full flex justify-center">
|
||||
@@ -154,8 +142,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
class="bg-gray-200 rounded-lg w-full h-full p-1"
|
||||
class:pointer-events-none={custom_bg_color}
|
||||
>
|
||||
<span
|
||||
class="inline-block w-full h-full bg-[#d6edc9] dark:bg-[#4e6e58]"
|
||||
<span class="inline-block w-full h-full bg-[#d6edc9] dark:bg-[#4e6e58]"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -209,8 +196,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
{:then c}
|
||||
<c.default
|
||||
bind:modalOpen={bg_uppy_open}
|
||||
bind:edit_id
|
||||
bind:data
|
||||
{data}
|
||||
selected_question={-1}
|
||||
video_upload={false}
|
||||
/>
|
||||
|
||||
@@ -5,14 +5,12 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
let { title = $bindable(), time = $bindable() } = $props();
|
||||
let time_local = $state(120);
|
||||
/*eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }]*/
|
||||
run(() => {
|
||||
$effect(() => {
|
||||
time = String(time_local);
|
||||
});
|
||||
if (time) {
|
||||
|
||||
@@ -27,19 +27,17 @@ SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
const { t } = getLocalization();
|
||||
let {
|
||||
modalOpen = false,
|
||||
edit_id,
|
||||
modalOpen = $bindable(),
|
||||
data,
|
||||
selected_question,
|
||||
video_upload = false,
|
||||
library_enabled = true
|
||||
}: {
|
||||
modalOpen: boolean;
|
||||
edit_id: string;
|
||||
data: EditorData;
|
||||
selected_question: number;
|
||||
selected_question?: number;
|
||||
video_upload: boolean;
|
||||
library_enabled: boolean;
|
||||
library_enabled?: boolean;
|
||||
} = $props();
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
@@ -83,7 +81,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
// allowedFileTypes: ['.gif', '.jpg', '.jpeg', '.png', '.svg', '.webp']
|
||||
}
|
||||
};
|
||||
let image_id;
|
||||
let image_id: string;
|
||||
uppy.on('upload-success', (file, response) => {
|
||||
image_id = response.body.id;
|
||||
});
|
||||
@@ -142,6 +140,10 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<div
|
||||
class="w-screen h-screen fixed top-0 left-0 bg-black/50 z-20 flex justify-center"
|
||||
onclick={handle_on_click}
|
||||
tabindex="0"
|
||||
role="button"
|
||||
aria-label="Close modal"
|
||||
onkeydown={(e) => (e.key === 'Enter' || e.key === ' ' ? handle_on_click(e) : null)}
|
||||
transition:fade={{ duration: 100 }}
|
||||
>
|
||||
{#if selected_type === null}
|
||||
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { preventDefault } from 'svelte/legacy';
|
||||
|
||||
import type { EditorData } from '$lib/quiz_types';
|
||||
import Spinner from '$lib/Spinner.svelte';
|
||||
import BrownButton from '$lib/components/buttons/brown.svelte';
|
||||
@@ -70,7 +68,10 @@ SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
<form
|
||||
class="w-full flex gap-2"
|
||||
onsubmit={preventDefault(() => (fetched_data = fetch_data()))}
|
||||
onsubmit={(e) => {
|
||||
e.preventDefault();
|
||||
fetched_data = fetch_data();
|
||||
}}
|
||||
>
|
||||
<input
|
||||
class="w-full outline-hidden p-1 rounded-sm dark:bg-gray-500 bg-gray-300"
|
||||
|
||||
@@ -22,24 +22,17 @@ import vi from './locales/vi.json';
|
||||
import ta from './locales/ta.json';
|
||||
import pt_BR from './locales/pt_BR.json';
|
||||
import ja from './locales/ja.json';
|
||||
// import uz from './locales/uz.json'
|
||||
// import zh_Hans from './locales/zh_Hans.json';
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
|
||||
import type { i18n } from 'i18next';
|
||||
|
||||
export class I18nService {
|
||||
// expose i18next
|
||||
i18n: i18n;
|
||||
|
||||
constructor() {
|
||||
this.i18n = i18next;
|
||||
this.initialize();
|
||||
// this.changeLanguage("de")
|
||||
//this.changeLanguage(INITIAL_LANGUAGE);
|
||||
}
|
||||
|
||||
// Our translation function
|
||||
t(key: string, replacements?: Record<string, unknown>): string {
|
||||
return this.i18n.t(key, replacements);
|
||||
}
|
||||
@@ -57,10 +50,6 @@ export class I18nService {
|
||||
},
|
||||
returnEmptyString: false,
|
||||
simplifyPluralSuffix: true,
|
||||
// detection: {
|
||||
// order: ['browser', 'querystring', 'navigator', 'localStorage', 'htmlTag'],
|
||||
// lookupQuerystring: 'lng'
|
||||
// }
|
||||
detection: {
|
||||
order: ['querystring', 'cookie', 'localStorage', 'navigator'],
|
||||
lookupQuerystring: 'lng',
|
||||
@@ -88,8 +77,6 @@ export class I18nService {
|
||||
this.i18n.addResourceBundle('ta', 'translation', ta);
|
||||
this.i18n.addResourceBundle('pt_BR', 'translation', pt_BR);
|
||||
this.i18n.addResourceBundle('ja', 'translation', ja);
|
||||
|
||||
// this.i18n.addResourceBundle('uz', 'translation', uz);
|
||||
}
|
||||
|
||||
changeLanguage(language: string): void {
|
||||
|
||||
@@ -20,14 +20,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
Strikethrough
|
||||
} from 'ckeditor5';
|
||||
import 'ckeditor5/ckeditor5.css';
|
||||
// import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
|
||||
// import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold.js';
|
||||
// import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic.js';
|
||||
// import Strikethrough from '@ckeditor/ckeditor5-basic-styles/src/strikethrough';
|
||||
// import Subscript from '@ckeditor/ckeditor5-basic-styles/src/subscript.js';
|
||||
// import Superscript from '@ckeditor/ckeditor5-basic-styles/src/superscript.js';
|
||||
|
||||
|
||||
|
||||
const triggerChange = () => {
|
||||
text = editor.getData();
|
||||
@@ -46,33 +38,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
run(() => {
|
||||
text = text.replace('<p>', '').replace('</p>', '');
|
||||
});
|
||||
|
||||
/* Editor.builtinPlugins = [
|
||||
Autoformat,
|
||||
Bold,
|
||||
Essentials,
|
||||
Italic,
|
||||
Paragraph,
|
||||
Strikethrough,
|
||||
Subscript,
|
||||
Superscript,
|
||||
TextTransformation
|
||||
];*/
|
||||
/*Editor.defaultConfig = {
|
||||
toolbar: {
|
||||
items: [
|
||||
'bold',
|
||||
'italic',
|
||||
'strikethrough',
|
||||
'superscript',
|
||||
'subscript',
|
||||
'|',
|
||||
'undo',
|
||||
'redo'
|
||||
]
|
||||
},
|
||||
language: 'en'
|
||||
};*/
|
||||
let editor;
|
||||
onMount(() => {
|
||||
class Editor extends BalloonEditor {
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
let { text } = $props();
|
||||
let internal_text = $state('');
|
||||
/*
|
||||
const markSelection = (function() {
|
||||
const markerTextChar = '\ufeff';
|
||||
const markerTextCharEntity = '';
|
||||
|
||||
let markerEl, markerId = 'sel_' + new Date().getTime() + '_' + Math.random().toString().substr(2);
|
||||
|
||||
let selectionEl;
|
||||
|
||||
return function(win) {
|
||||
win = win || window;
|
||||
const doc = win.document;
|
||||
let sel, range;
|
||||
// Branch for IE <= 8
|
||||
if (doc.selection && doc.selection.createRange) {
|
||||
// Clone the TextRange and collapse
|
||||
range = doc.selection.createRange().duplicate();
|
||||
range.collapse(false);
|
||||
|
||||
// Create the marker element containing a single invisible character by creating literal HTML and insert it
|
||||
range.pasteHTML('<span id="' + markerId + '" style="position: relative;">' + markerTextCharEntity + '</span>');
|
||||
markerEl = doc.getElementById(markerId);
|
||||
} else if (win.getSelection) {
|
||||
sel = win.getSelection();
|
||||
range = sel.getRangeAt(0).cloneRange();
|
||||
range.collapse(false);
|
||||
|
||||
// Create the marker element containing a single invisible character using DOM methods and insert it
|
||||
markerEl = doc.createElement('span');
|
||||
markerEl.id = markerId;
|
||||
markerEl.appendChild(doc.createTextNode(markerTextChar));
|
||||
range.insertNode(markerEl);
|
||||
}
|
||||
|
||||
if (markerEl) {
|
||||
// Lazily create element to be placed next to the selection
|
||||
if (!selectionEl) {
|
||||
selectionEl = doc.createElement('div');
|
||||
selectionEl.style.border = 'solid darkblue 1px';
|
||||
selectionEl.style.backgroundColor = 'lightgoldenrodyellow';
|
||||
selectionEl.innerHTML = '<- selection';
|
||||
selectionEl.style.position = 'absolute';
|
||||
|
||||
doc.body.appendChild(selectionEl);
|
||||
}
|
||||
|
||||
// Find markerEl position http://www.quirksmode.org/js/findpos.html
|
||||
var obj = markerEl;
|
||||
var left = 0, top = 0;
|
||||
do {
|
||||
left += obj.offsetLeft;
|
||||
top += obj.offsetTop;
|
||||
} while (obj = obj.offsetParent);
|
||||
|
||||
// Move the button into place.
|
||||
// Substitute your jQuery stuff in here
|
||||
selectionEl.style.left = left + 'px';
|
||||
selectionEl.style.top = top + 'px';
|
||||
|
||||
markerEl.parentNode.removeChild(markerEl);
|
||||
}
|
||||
};
|
||||
})();*/
|
||||
// $: console.log(document.getSelection().toString())
|
||||
/*
|
||||
const markSelection = () => {
|
||||
const sel = document.getSelection();
|
||||
console.log(sel.toString());
|
||||
};
|
||||
*/
|
||||
const bold_regex = /.*\*\*(.+)\*\*.*/gm; // **bold**
|
||||
const italic_regex = /.*\|\|(.+)\|\|.*/gm; // *italic*
|
||||
const strikethrough_regex = /.*~~(.+)~~.*/gm; // ~~strikethrough~~
|
||||
const sub_regex = /.*__(.+)__.*/gm; // __sub__
|
||||
const sup_regex = /.*--(.+)--.*/gm; // --sup--
|
||||
const process_input = () => {
|
||||
let output = internal_text;
|
||||
output = output.replace(bold_regex, '<b>$1</b>');
|
||||
output = output.replace(italic_regex, '<i>$1</i>');
|
||||
output = output.replace(strikethrough_regex, '<del>$1</del>');
|
||||
output = output.replace(sub_regex, '<sub>$1</sub>');
|
||||
output = output.replace(sup_regex, '<sup>$1</sup>');
|
||||
console.log(output);
|
||||
};
|
||||
|
||||
run(() => {
|
||||
process_input();
|
||||
internal_text;
|
||||
});
|
||||
</script>
|
||||
|
||||
<input bind:value={internal_text} />
|
||||
@@ -3,53 +3,6 @@ SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<!--
|
||||
<script context='module' lang='ts'>
|
||||
export const prerender = true;
|
||||
export const load = async ({}) => {
|
||||
return {};
|
||||
const languages = [
|
||||
{
|
||||
code: 'de',
|
||||
name: 'Deutsch',
|
||||
flag: '🇩🇪'
|
||||
},
|
||||
{
|
||||
code: 'en',
|
||||
name: 'English',
|
||||
flag: '🇺🇲'
|
||||
},
|
||||
{
|
||||
code: 'tr',
|
||||
name: 'Türkçe',
|
||||
flag: '🇹🇷'
|
||||
},
|
||||
{
|
||||
code: 'fr',
|
||||
name: 'Français',
|
||||
flag: '🇫🇷'
|
||||
}
|
||||
];
|
||||
let final_arr = [];
|
||||
const set_percents = async () => {
|
||||
for (const lang of languages) {
|
||||
const res = await fetch(`https://translate.mawoka.eu/api/translations/classquiz/frontend/${lang.code}/?format=json`);
|
||||
const json = await res.json();
|
||||
console.log(json);
|
||||
// return Math.floor(json.translated_percent);
|
||||
final_arr.push({ ...lang, percent: json.translated_percent });
|
||||
}
|
||||
};
|
||||
await set_percents();
|
||||
return {
|
||||
slot: {
|
||||
final_arr
|
||||
}
|
||||
};
|
||||
};
|
||||
</script>
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { browser } from '$app/environment';
|
||||
@@ -164,7 +117,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
const get_selected_language = (): string => {
|
||||
return localStorage.getItem('language');
|
||||
};
|
||||
let selected_language = $state();
|
||||
let selected_language: string = $state();
|
||||
onMount(() => {
|
||||
selected_language = get_selected_language();
|
||||
});
|
||||
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
@@ -16,13 +14,14 @@ SPDX-License-Identifier: MPL-2.0
|
||||
import confetti from 'canvas-confetti';
|
||||
interface Props {
|
||||
data: any;
|
||||
username: any;
|
||||
username?: any;
|
||||
show_final_results: boolean;
|
||||
}
|
||||
|
||||
let { data = $bindable(), username, show_final_results }: Props = $props();
|
||||
let sorted_data = $derived(sortObjectbyValue(data));
|
||||
|
||||
function sortObjectbyValue(obj) {
|
||||
function sortObjectbyValue(obj: object) {
|
||||
const ret = {};
|
||||
Object.keys(obj)
|
||||
.sort((a, b) => obj[b] - obj[a])
|
||||
@@ -30,30 +29,22 @@ SPDX-License-Identifier: MPL-2.0
|
||||
return ret;
|
||||
}
|
||||
|
||||
run(() => {
|
||||
data = sortObjectbyValue(data);
|
||||
});
|
||||
run(() => {
|
||||
console.log(data, 'sorted, fina');
|
||||
});
|
||||
|
||||
let player_names = $derived(Object.keys(data).sort(function (a, b) {
|
||||
return data[b] - data[a];
|
||||
}));
|
||||
|
||||
let player_names = $derived(Object.keys(sorted_data));
|
||||
|
||||
let player_count_or_five = $derived(player_names.length >= 5 ? 5 : player_names.length);
|
||||
|
||||
|
||||
let canvas = $state();
|
||||
let canvas: HTMLCanvasElement = $state();
|
||||
onMount(() => {
|
||||
setTimeout(() => {
|
||||
confetti.create(canvas, {
|
||||
resize: true,
|
||||
useWorker: true
|
||||
});
|
||||
confetti({ particleCount: 200, spread: 160 });
|
||||
}, player_count_or_five * 1200 - 800);
|
||||
setTimeout(
|
||||
() => {
|
||||
confetti.create(canvas, {
|
||||
resize: true,
|
||||
useWorker: true
|
||||
});
|
||||
confetti({ particleCount: 200, spread: 160 });
|
||||
},
|
||||
player_count_or_five * 1200 - 800
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -70,13 +61,13 @@ SPDX-License-Identifier: MPL-2.0
|
||||
{$t('play_page.final_result_rank', {
|
||||
place: i + 1,
|
||||
username: player,
|
||||
points: data[player]
|
||||
points: sorted_data[player]
|
||||
})}
|
||||
</p>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{#if data[username]}
|
||||
{#if sorted_data[username]}
|
||||
<div class="fixed bottom-0 left-0 flex justify-center w-full mb-6">
|
||||
<div class="mx-auto p-2 border-[#B07156] border-4 rounded-sm">
|
||||
<p class="text-center">{$t('play_page.your_score', { score: data[username] })}</p>
|
||||
|
||||
@@ -121,6 +121,15 @@ SPDX-License-Identifier: MPL-2.0
|
||||
class="fixed top-0 left-0 z-50 w-screen h-screen bg-black/50 flex p-2"
|
||||
transition:fade|global={{ duration: 80 }}
|
||||
onclick={() => (fullscreen_open = false)}
|
||||
tabindex="0"
|
||||
role="button"
|
||||
aria-label="Close modal"
|
||||
onkeydown={(e) =>
|
||||
e.key === 'Enter' || e.key === ' '
|
||||
? () => {
|
||||
fullscreen_open = false;
|
||||
}
|
||||
: null}
|
||||
>
|
||||
<img
|
||||
alt="QR code to join the game"
|
||||
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { QuizQuestionType } from '$lib/quiz_types';
|
||||
import type { QuizData } from '$lib/quiz_types';
|
||||
import { get_foreground_color } from '$lib/helpers.js';
|
||||
@@ -15,7 +13,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
import MediaComponent from '$lib/editor/MediaComponent.svelte';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
|
||||
interface Props {
|
||||
quiz_data: QuizData;
|
||||
selected_question: number;
|
||||
@@ -34,16 +31,16 @@ SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
const { t } = getLocalization();
|
||||
|
||||
let circular_progress = $state(0);
|
||||
run(() => {
|
||||
let circular_progress = $derived.by(() => {
|
||||
try {
|
||||
circular_progress =
|
||||
return (
|
||||
1 -
|
||||
((100 / parseInt(quiz_data.questions[selected_question].time)) *
|
||||
parseInt(timer_res)) /
|
||||
100;
|
||||
100
|
||||
);
|
||||
} catch {
|
||||
circular_progress = 0;
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -56,11 +53,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<div class="grid grid-cols-3 my-2">
|
||||
<span></span>
|
||||
<div class="m-auto">
|
||||
<CircularTimer
|
||||
bind:text={timer_res}
|
||||
bind:progress={circular_progress}
|
||||
color="#ef4444"
|
||||
/>
|
||||
<CircularTimer text={timer_res} progress={circular_progress} color="#ef4444" />
|
||||
</div>
|
||||
<p class="m-auto text-3xl">
|
||||
{$t('admin_page.answers_submitted', { answer_count: answer_count })}
|
||||
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import VotingResults from './voting_results.svelte';
|
||||
import { flip } from 'svelte/animate';
|
||||
import { fly } from 'svelte/transition';
|
||||
@@ -31,7 +29,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
let { data = $bindable(), question, new_data }: Props = $props();
|
||||
|
||||
function sortObjectbyValue(obj) {
|
||||
function sortObjectbyValue(obj: object) {
|
||||
const ret = {};
|
||||
Object.keys(obj)
|
||||
.sort((a, b) => obj[b] - obj[a])
|
||||
@@ -39,26 +37,20 @@ SPDX-License-Identifier: MPL-2.0
|
||||
return ret;
|
||||
}
|
||||
|
||||
let sorted_data = $derived(sortObjectbyValue(data));
|
||||
|
||||
// let data_by_username = {};
|
||||
let score_by_username = $state({});
|
||||
|
||||
const do_sth = () => {
|
||||
const group_username_by_score = (new_d: any[]): object => {
|
||||
let ret_data = {};
|
||||
for (const i of new_data) {
|
||||
score_by_username[i.username] = i.score;
|
||||
ret_data[i.username] = i.score;
|
||||
}
|
||||
return ret_data;
|
||||
};
|
||||
let score_by_username = $derived(group_username_by_score(new_data));
|
||||
|
||||
run(() => {
|
||||
new_data;
|
||||
score_by_username;
|
||||
do_sth();
|
||||
});
|
||||
|
||||
let player_names = $derived(
|
||||
Object.keys(data).sort(function (a, b) {
|
||||
return data[b] - data[a];
|
||||
})
|
||||
);
|
||||
let player_names = $derived(Object.keys(sorted_data));
|
||||
|
||||
if (JSON.stringify(data) === '{}') {
|
||||
for (const i of new_data) {
|
||||
@@ -66,15 +58,9 @@ SPDX-License-Identifier: MPL-2.0
|
||||
}
|
||||
}
|
||||
|
||||
run(() => {
|
||||
data = sortObjectbyValue(data);
|
||||
});
|
||||
|
||||
let show_new_score_clicked = $state(false);
|
||||
|
||||
const show_new_score = () => {
|
||||
// for (let i = 0; i++; i < player_names.length) {
|
||||
// console.log(data)
|
||||
for (const i of player_names) {
|
||||
if (isNaN(data[i])) {
|
||||
data[i] = 0;
|
||||
@@ -91,8 +77,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
setTimeout(() => {
|
||||
data = data;
|
||||
}, 800);
|
||||
|
||||
// console.log(data)
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
@@ -127,7 +111,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<td class:hidden={i > 3} class="p-2 border-r border-r-black"
|
||||
>{player}</td
|
||||
>
|
||||
<td class:hidden={i > 3} class="p-2">{data[player]}</td>
|
||||
<td class:hidden={i > 3} class="p-2">{sorted_data[player]}</td>
|
||||
{#if show_new_score_clicked}
|
||||
<td
|
||||
in:fly|global={{ x: 300 }}
|
||||
|
||||
@@ -40,6 +40,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<div bind:this={canvas_el} class="w-full h-full block"></div>
|
||||
</div>
|
||||
<div class="w-full h-full flex justify-center">
|
||||
<img src={img_src} />
|
||||
<img src={img_src} alt="Slide image" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import Audio1 from '$lib/assets/music/1-128.mp3';
|
||||
|
||||
interface Props {
|
||||
@@ -25,10 +23,10 @@ SPDX-License-Identifier: MPL-2.0
|
||||
audio.pause();
|
||||
}
|
||||
};
|
||||
run(() => {
|
||||
$effect(() => {
|
||||
audio.volume = volume / 100;
|
||||
});
|
||||
run(() => {
|
||||
$effect(() => {
|
||||
control_audio(play);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
interface Props {
|
||||
progress: number;
|
||||
text: string;
|
||||
@@ -14,25 +12,12 @@ SPDX-License-Identifier: MPL-2.0
|
||||
}
|
||||
|
||||
let { progress, text, color }: Props = $props();
|
||||
let angle = $state(360 * progress);
|
||||
|
||||
run(() => {
|
||||
angle = 360 * progress;
|
||||
});
|
||||
run(() => {
|
||||
console.log(angle);
|
||||
});
|
||||
let angle = $derived(360 * progress);
|
||||
|
||||
// Adapt the logic according to the approach
|
||||
let background = $state(`radial-gradient(white 50%, transparent 51%),
|
||||
conic-gradient(transparent 0deg ${angle}deg, gainsboro ${angle}deg 360deg),
|
||||
conic-gradient(green 0deg, green 90deg, green 180deg, green);`);
|
||||
|
||||
run(() => {
|
||||
background = `radial-gradient(white 50%, transparent 51%),
|
||||
let background = $derived(`radial-gradient(white 50%, transparent 51%),
|
||||
conic-gradient(transparent 0deg ${angle}deg, gainsboro ${angle}deg 360deg),
|
||||
conic-gradient(${color} 0deg, ${color} 90deg, ${color} 180deg, ${color});`;
|
||||
});
|
||||
conic-gradient(${color} 0deg, ${color} 90deg, ${color} 180deg, ${color});`);
|
||||
|
||||
let cssVarStyles = $derived(`--background:${background}`);
|
||||
</script>
|
||||
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
const { t } = getLocalization();
|
||||
@@ -85,9 +83,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
}
|
||||
};
|
||||
let winners = getWinnersSorted();
|
||||
run(() => {
|
||||
console.log(winners, winners_arr);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div>
|
||||
|
||||
@@ -5,14 +5,10 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run, createBubbler, preventDefault } from 'svelte/legacy';
|
||||
|
||||
const bubble = createBubbler();
|
||||
import { socket } from '$lib/socket';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { browser } from '$app/environment';
|
||||
import * as Sentry from '@sentry/browser';
|
||||
// import { alertModal } from '../stores';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
import Cookies from 'js-cookie';
|
||||
import BrownButton from '$lib/components/buttons/brown.svelte';
|
||||
@@ -116,14 +112,14 @@ SPDX-License-Identifier: MPL-2.0
|
||||
}
|
||||
};
|
||||
|
||||
run(() => {
|
||||
$effect(() => {
|
||||
if (game_pin.length > 5) {
|
||||
console.log('Setting game pin');
|
||||
set_game_pin();
|
||||
}
|
||||
});
|
||||
|
||||
const setUsername = async () => {
|
||||
const setUsername = async (e: Event) => {
|
||||
e.preventDefault();
|
||||
if (username.length <= 3) {
|
||||
return;
|
||||
}
|
||||
@@ -189,12 +185,12 @@ SPDX-License-Identifier: MPL-2.0
|
||||
alert('Game not found');
|
||||
}
|
||||
});
|
||||
|
||||
run(() => {
|
||||
console.log(game_pin, game_pin.length > 6);
|
||||
});
|
||||
run(() => {
|
||||
game_pin = game_pin.replace(/\D/g, '');
|
||||
$effect(() => {
|
||||
const cleaned = game_pin.replace(/\D/g, '');
|
||||
if (game_pin.replace(/\D/g, '') === game_pin) {
|
||||
return;
|
||||
}
|
||||
game_pin = cleaned;
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -211,10 +207,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
{#if game_pin === '' || game_pin.length < 6}
|
||||
<div class="flex flex-col justify-center align-center w-screen h-screen">
|
||||
<form
|
||||
onsubmit={preventDefault(bubble('submit'))}
|
||||
class="flex-col flex justify-center align-center mx-auto"
|
||||
>
|
||||
<form class="flex-col flex justify-center align-center mx-auto">
|
||||
<h1 class="text-lg text-center">{$t('words.game_pin')}</h1>
|
||||
<input
|
||||
class="border border-gray-400 self-center text-center text-black ring-0 outline-hidden p-2 rounded-lg focus:shadow-2xl transition-all"
|
||||
@@ -232,10 +225,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-col justify-center align-center w-screen h-screen">
|
||||
<form
|
||||
onsubmit={preventDefault(setUsername)}
|
||||
class="flex-col flex justify-center align-center mx-auto"
|
||||
>
|
||||
<form onsubmit={setUsername} class="flex-col flex justify-center align-center mx-auto">
|
||||
<h1 class="text-lg text-center">{$t('words.username')}</h1>
|
||||
<input
|
||||
class="border border-gray-400 self-center text-center text-black ring-0 outline-hidden p-2 rounded-lg focus:shadow-2xl transition-all"
|
||||
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import type { Question } from '$lib/quiz_types';
|
||||
import { QuizQuestionType } from '$lib/quiz_types';
|
||||
import { socket } from '$lib/socket';
|
||||
@@ -35,23 +33,12 @@ SPDX-License-Identifier: MPL-2.0
|
||||
solution
|
||||
}: Props = $props();
|
||||
|
||||
run(() => {
|
||||
console.log(question_index, question, 'hi!');
|
||||
});
|
||||
|
||||
console.log(question);
|
||||
if (question.type === undefined) {
|
||||
question.type = QuizQuestionType.ABCD;
|
||||
} else {
|
||||
question.type = QuizQuestionType[question.type];
|
||||
}
|
||||
|
||||
/* if (typeof question_index === 'string') {
|
||||
question_index = parseInt(question_index);
|
||||
} else {
|
||||
throw new Error('question_index must be a string or number');
|
||||
}*/
|
||||
|
||||
let timer_res = $state(question.time);
|
||||
let selected_answer: string = $state();
|
||||
|
||||
@@ -75,7 +62,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
timer(question.time);
|
||||
|
||||
run(() => {
|
||||
$effect(() => {
|
||||
if (solution !== undefined) {
|
||||
timer_res = '0';
|
||||
}
|
||||
@@ -83,7 +70,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
const selectAnswer = (answer: string) => {
|
||||
selected_answer = answer;
|
||||
//timer_res = '0';
|
||||
socket.emit('submit_answer', {
|
||||
question_index: question_index,
|
||||
answer: answer
|
||||
@@ -132,15 +118,14 @@ SPDX-License-Identifier: MPL-2.0
|
||||
_arr[b] = temp;
|
||||
return _arr;
|
||||
};
|
||||
run(() => {
|
||||
$effect(() => {
|
||||
set_answer_if_not_set_range(timer_res);
|
||||
});
|
||||
let circular_progress = $state(0);
|
||||
run(() => {
|
||||
let circular_progress = $derived.by(() => {
|
||||
try {
|
||||
circular_progress = 1 - ((100 / question.time) * parseInt(timer_res)) / 100;
|
||||
return 1 - ((100 / question.time) * parseInt(timer_res)) / 100;
|
||||
} catch {
|
||||
circular_progress = 0;
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -155,9 +140,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
return '100';
|
||||
}
|
||||
};
|
||||
run(() => {
|
||||
console.log(slider_value, 'values');
|
||||
});
|
||||
const default_colors = ['#D6EDC9', '#B07156', '#7F7057', '#4E6E58'];
|
||||
</script>
|
||||
|
||||
@@ -189,11 +171,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<div
|
||||
class="absolute top-0 bottom-0 left-0 right-0 m-auto rounded-full h-fit w-fit border-2 border-black shadow-2xl z-40"
|
||||
>
|
||||
<CircularTimer
|
||||
bind:text={timer_res}
|
||||
bind:progress={circular_progress}
|
||||
color="#ef4444"
|
||||
/>
|
||||
<CircularTimer text={timer_res} progress={circular_progress} color="#ef4444" />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-rows-2 grid-flow-col auto-cols-auto gap-2 w-full p-4 h-full">
|
||||
@@ -279,20 +257,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:else if question.type === QuizQuestionType.RANGE}
|
||||
{#if solution === undefined}
|
||||
<Spinner />
|
||||
{:else}
|
||||
<p class="text-center">
|
||||
Every number between {solution.answers.min_correct} and {solution.answers
|
||||
.max_correct} was correct. You got {selected_answer}, so you have been
|
||||
{#if solution.answers.min_correct <= parseInt(selected_answer) && parseInt(selected_answer) <= solution.answers.max_correct}
|
||||
correct
|
||||
{:else}
|
||||
wrong.
|
||||
{/if}
|
||||
</p>
|
||||
{/if}
|
||||
{:else if question.type === QuizQuestionType.ORDER}
|
||||
<!-- {#if solution === undefined}
|
||||
<Spinner />
|
||||
@@ -314,7 +278,8 @@ SPDX-License-Identifier: MPL-2.0
|
||||
}}
|
||||
class="disabled:opacity-50 shadow-lg bg-black/30 w-full flex justify-center rounded-lg p-2 hover:bg-black/20 transition"
|
||||
type="button"
|
||||
disabled={i === 0 || selected_answer}
|
||||
aria-label="Move item up"
|
||||
disabled={i === 0 || Boolean(selected_answer)}
|
||||
>
|
||||
<svg
|
||||
class="w-8 h-8"
|
||||
@@ -341,7 +306,8 @@ SPDX-License-Identifier: MPL-2.0
|
||||
}}
|
||||
class="disabled:opacity-50 shadow-lg bg-black/30 w-full flex justify-center rounded-lg p-2 hover:bg-black/20 transition"
|
||||
type="button"
|
||||
disabled={i === question.answers.length - 1 || selected_answer}
|
||||
aria-label="Move item down"
|
||||
disabled={i === question.answers.length - 1 || Boolean(selected_answer)}
|
||||
>
|
||||
<svg
|
||||
class="w-8 h-8"
|
||||
@@ -365,7 +331,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<div class="w-full mt-2">
|
||||
<BrownButton
|
||||
type="button"
|
||||
disabled={selected_answer}
|
||||
disabled={Boolean(selected_answer)}
|
||||
onclick={() => {
|
||||
select_complex_answer(question.answers);
|
||||
}}>{$t('words.submit')}</BrownButton
|
||||
@@ -396,13 +362,5 @@ SPDX-License-Identifier: MPL-2.0
|
||||
</div>
|
||||
{/await}
|
||||
{/if}
|
||||
|
||||
<!--{:else if question.type === QuizQuestionType.VOTING}
|
||||
{#await import('$lib/play/admin/voting_results.svelte')}
|
||||
<Spinner />
|
||||
{:then c}
|
||||
<svelte:component this={c.default} bind:data={question_results}
|
||||
bind:question={quiz_data.questions[selected_question]} />
|
||||
{/await}-->
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -5,10 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
|
||||
|
||||
function sortObjectbyValue(obj) {
|
||||
const ret = {};
|
||||
Object.keys(obj)
|
||||
@@ -20,12 +16,12 @@ SPDX-License-Identifier: MPL-2.0
|
||||
interface Props {
|
||||
scores: any;
|
||||
question_results: Array<{
|
||||
username: string;
|
||||
answer: string;
|
||||
right: boolean;
|
||||
time_taken: number;
|
||||
score: number;
|
||||
}>;
|
||||
username: string;
|
||||
answer: string;
|
||||
right: boolean;
|
||||
time_taken: number;
|
||||
score: number;
|
||||
}>;
|
||||
username: any;
|
||||
}
|
||||
|
||||
@@ -37,26 +33,14 @@ SPDX-License-Identifier: MPL-2.0
|
||||
scores[i.username] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
run(() => {
|
||||
console.log(score_by_username, scores, 'dieter');
|
||||
});
|
||||
for (const i of question_results) {
|
||||
score_by_username[i.username] = i.score;
|
||||
}
|
||||
|
||||
run(() => {
|
||||
scores = sortObjectbyValue(scores);
|
||||
});
|
||||
|
||||
const do_sth = () => {
|
||||
for (const i of Object.keys(score_by_username)) {
|
||||
scores[i] = (score_by_username[i] ?? 0) + (scores[i] ?? 0);
|
||||
}
|
||||
scores = scores;
|
||||
};
|
||||
|
||||
do_sth();
|
||||
for (const username of Object.keys(score_by_username)) {
|
||||
scores[username] = (score_by_username[username] ?? 0) + (scores[username] ?? 0);
|
||||
}
|
||||
scores = scores;
|
||||
let sorted_scores = $derived(sortObjectbyValue(scores));
|
||||
</script>
|
||||
|
||||
<div>
|
||||
@@ -65,7 +49,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<p class="p-4 bg-black/40 rounded-lg text-2xl">
|
||||
+{score_by_username[username] ?? '0'}
|
||||
</p>
|
||||
<p>Total score: {scores[username] ?? '0'}</p>
|
||||
<p>Total score: {sorted_scores[username] ?? '0'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Answer, Question, QuizData } from '$lib/quiz_types';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
import { QuizQuestionType } from '../quiz_types.js';
|
||||
import Spinner from '$lib/Spinner.svelte';
|
||||
|
||||
const { t } = getLocalization();
|
||||
interface Props {
|
||||
results: Array<Answer>;
|
||||
game_data: QuizData;
|
||||
solution: Question;
|
||||
question_index: string;
|
||||
}
|
||||
|
||||
let {
|
||||
results,
|
||||
game_data,
|
||||
solution = $bindable(),
|
||||
question_index
|
||||
}: Props = $props();
|
||||
let data_store = $state({});
|
||||
|
||||
const question = solution.answers;
|
||||
for (let i = 0; i < question.length; i++) {
|
||||
data_store[question[i].answer] = 0;
|
||||
}
|
||||
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
data_store[results[i].answer] += 1;
|
||||
}
|
||||
|
||||
let slider_values = $state([solution.answers.min_correct ?? 0, solution.answers.max_correct ?? 0]);
|
||||
console.log(slider_values, solution.answers);
|
||||
</script>
|
||||
|
||||
<!-- Show the results from the results object -->
|
||||
<!-- Language: SvelteHTML -->
|
||||
<!-- Path: frontend/src/lib/play/show_results.svelte -->
|
||||
|
||||
<div>
|
||||
<h2 class="text-center text-3xl mb-8">{$t('words.result', { count: 2 })}</h2>
|
||||
<div class="w-screen flex justify-center">
|
||||
{#if solution.type === QuizQuestionType.ABCD}
|
||||
<div class="relative overflow-x-auto shadow-md rounded-lg">
|
||||
<table class="w-fit text-sm text-left text-gray-500 dark:text-gray-400">
|
||||
<thead class="bg-gray-50 dark:bg-gray-700">
|
||||
<tr>
|
||||
<th
|
||||
scope="col"
|
||||
class="py-3 px-6 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400"
|
||||
>
|
||||
{$t('words.answer')}
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="py-3 px-6 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400"
|
||||
>
|
||||
{$t('words.count')}
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="py-3 px-6 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400"
|
||||
>
|
||||
{$t('words.correct')}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each solution.answers as answer}
|
||||
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
|
||||
<td
|
||||
class="py-4 px-6 text-sm font-medium text-gray-900 whitespace-nowrap dark:text-white"
|
||||
>
|
||||
{answer.answer}
|
||||
</td>
|
||||
<td
|
||||
class="py-4 px-6 text-sm text-gray-500 whitespace-nowrap dark:text-gray-400"
|
||||
>
|
||||
{data_store[answer.answer]}
|
||||
</td>
|
||||
<td
|
||||
class="py-4 px-6 text-sm text-gray-500 whitespace-nowrap dark:text-gray-400"
|
||||
>
|
||||
{#if answer.right}
|
||||
✅
|
||||
{:else}
|
||||
❌
|
||||
{/if}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{:else if solution.type === QuizQuestionType.RANGE}
|
||||
<!--<p class="text-center">
|
||||
Every number between {solution.answers
|
||||
.min_correct} and {solution.answers
|
||||
.max_correct} was correct.
|
||||
</p>-->
|
||||
{#await import('svelte-range-slider-pips')}
|
||||
<Spinner />
|
||||
{:then c}
|
||||
<div class="grayscale pointer-events-none w-full">
|
||||
<c.default
|
||||
bind:values={slider_values}
|
||||
bind:min={solution.answers.min}
|
||||
bind:max={solution.answers.max}
|
||||
pips
|
||||
float
|
||||
all="label"
|
||||
/>
|
||||
</div>
|
||||
{/await}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { preventDefault } from 'svelte/legacy';
|
||||
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
import { fly } from 'svelte/transition';
|
||||
@@ -15,7 +13,11 @@ SPDX-License-Identifier: MPL-2.0
|
||||
const { t } = getLocalization();
|
||||
</script>
|
||||
|
||||
<div class="w-full px-6 lg:px-20 h-[80vh] absolute" in:fly|global={{ x: 100 }} out:fly|global={{ x: -100 }}>
|
||||
<div
|
||||
class="w-full px-6 lg:px-20 h-[80vh] absolute"
|
||||
in:fly|global={{ x: 100 }}
|
||||
out:fly|global={{ x: -100 }}
|
||||
>
|
||||
<div class="rounded-lg bg-white w-full h-full border-gray-500 dark:bg-gray-700">
|
||||
<div class="h-fit bg-gray-300 rounded-t-lg dark:bg-gray-500">
|
||||
<div class="flex align-middle p-4 gap-3">
|
||||
@@ -52,9 +54,10 @@ SPDX-License-Identifier: MPL-2.0
|
||||
src="/api/v1/storage/download/{data.cover_image}"
|
||||
alt="not available"
|
||||
class="max-h-72 h-auto w-auto"
|
||||
oncontextmenu={preventDefault(() => {
|
||||
oncontextmenu={(e) => {
|
||||
e.preventDefault();
|
||||
data.cover_image = '';
|
||||
})}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import type { Markdown } from '$lib/quiztivity/types';
|
||||
import { marked } from 'marked';
|
||||
import { browser } from '$app/environment';
|
||||
@@ -23,11 +21,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
};
|
||||
}
|
||||
|
||||
let rendered_html = $state('');
|
||||
|
||||
run(() => {
|
||||
rendered_html = browser ? marked.parse(data.markdown) : '';
|
||||
});
|
||||
let rendered_html = $derived(browser ? marked.parse(data.markdown) : '');
|
||||
</script>
|
||||
|
||||
<div class="w-full h-[70vh] flex flex-row p-4 gap-4">
|
||||
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import type { Markdown } from '$lib/quiztivity/types';
|
||||
import DOMPurify from 'dompurify';
|
||||
import { marked } from 'marked';
|
||||
@@ -18,11 +16,9 @@ SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
let { data }: Props = $props();
|
||||
|
||||
let rendered_html = $state('');
|
||||
|
||||
run(() => {
|
||||
rendered_html = browser ? DOMPurify.sanitize(marked.parse(data.markdown ?? '')) : '';
|
||||
});
|
||||
let rendered_html = $derived(
|
||||
browser ? DOMPurify.sanitize(marked.parse(data.markdown ?? '')) : ''
|
||||
);
|
||||
</script>
|
||||
|
||||
<div class="prose dark:prose-invert">
|
||||
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import type { Data } from './types';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
import BrownButton from '$lib/components/buttons/brown.svelte';
|
||||
@@ -48,7 +46,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
data.pages.push({ title: undefined, data: undefined, type, id });
|
||||
opened_slide = data.pages.length - 1;
|
||||
};
|
||||
run(() => {
|
||||
$effect(() => {
|
||||
handle_slide_add(selected_type);
|
||||
});
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { preventDefault } from 'svelte/legacy';
|
||||
|
||||
import BrownButton from '$lib/components/buttons/brown.svelte';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
import Spinner from '$lib/Spinner.svelte';
|
||||
@@ -81,7 +79,8 @@ SPDX-License-Identifier: MPL-2.0
|
||||
});
|
||||
let never_expires_checked = $state(true);
|
||||
let selected_date = $state(undefined);
|
||||
const create_share = async () => {
|
||||
const create_share = async (e: Event) => {
|
||||
e.preventDefault();
|
||||
if (!selected_date && !never_expires_checked) {
|
||||
return;
|
||||
}
|
||||
@@ -145,7 +144,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<form
|
||||
class="flex justify-center p-2 border-b-2 border-l-2 border-r-2 border-[#B07156] flex-col gap-2"
|
||||
transition:fly={{ duration: 100, y: -10 }}
|
||||
onsubmit={preventDefault(create_share)}
|
||||
onsubmit={create_share}
|
||||
>
|
||||
<div class="grid grid-cols-2">
|
||||
<input
|
||||
|
||||
@@ -15,10 +15,6 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<div class="flex justify-center">
|
||||
<a href="/view/{quiz.id}" class="h-max w-fit">
|
||||
<div class="max-w-md py-4 px-8 bg-white shadow-lg rounded-lg my-20 dark:bg-slate-800">
|
||||
<!-- <div class='flex justify-center md:justify-end -mt-16'>
|
||||
<img class='w-20 h-20 object-cover rounded-full border-2 border-indigo-500'
|
||||
src='https://images.unsplash.com/photo-1499714608240-22fc6ad53fb2?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=334&q=80'>
|
||||
</div>-->
|
||||
<div>
|
||||
<div class="flex w-full items-center">
|
||||
<h2
|
||||
|
||||
Reference in New Issue
Block a user