Further cleanup, mostly with svelte 5 migration placeholder cleanup

This commit is contained in:
Mawoka
2025-10-26 11:53:53 +01:00
parent 0c23d9b9c1
commit 41fe3e3ad5
74 changed files with 309 additions and 1154 deletions
+8 -2
View File
@@ -15,8 +15,14 @@ router = APIRouter()
@router.get("/list") @router.get("/list")
async def list_game_results(user: User = Depends(get_current_user)) -> list[GameResults]: async def list_game_results(
results = await GameResults.objects.select_related(GameResults.quiz).all(user=user.id) user: User = Depends(get_current_user),
) -> list[GameResults]:
results = (
await GameResults.objects.select_related(GameResults.quiz)
.order_by(GameResults.timestamp.desc())
.all(user=user.id)
)
return results return results
-1
View File
@@ -9,7 +9,6 @@ SPDX-License-Identifier: MPL-2.0
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="description" content="" /> <meta name="description" content="" />
<!-- <link rel="icon" href="%sveltekit.assets%/favicon.png" />-->
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<script> <script>
window.plausible = window.plausible =
+9 -2
View File
@@ -5,8 +5,15 @@
/// <reference types="vite/client" /> /// <reference types="vite/client" />
interface ImportMetaEnv { interface ImportMetaEnv {
readonly VITE_APP_TITLE: string; readonly VITE_GOOGLE_AUTH_ENABLED?: string;
// more env variables... readonly VITE_GITHUB_AUTH_ENABLED?: string;
readonly VITE_CAPTCHA_ENABLED?: string;
readonly VITE_CUSTOM_OAUTH_NAME?: string;
readonly VITE_REGISTRATION_DISABLED?: string;
readonly VITE_HCAPTCHA?: string;
readonly VITE_RECAPTCHA?: string;
readonly VITE_SENTRY?: string;
readonly VITE_PLAUSIBLE_DATA_URL?: string;
} }
interface ImportMeta { interface ImportMeta {
-7
View File
@@ -36,10 +36,3 @@ export const handle: Handle = async ({ event, resolve }) => {
event.locals.email = jwt.payload.sub; event.locals.email = jwt.payload.sub;
return resolve(event); return resolve(event);
}; };
/*export const getSession: GetSession = async (event) => {
return {
email: event.locals.email,
authenticated: Boolean(event.locals.email)
};
};*/
+5 -11
View File
@@ -15,7 +15,6 @@ SPDX-License-Identifier: MPL-2.0
import Controls from '$lib/play/admin/controls.svelte'; import Controls from '$lib/play/admin/controls.svelte';
import Question from '$lib/play/admin/question.svelte'; import Question from '$lib/play/admin/question.svelte';
const { t } = getLocalization(); const { t } = getLocalization();
const default_colors = ['#D6EDC9', '#B07156', '#7F7057', '#4E6E58']; const default_colors = ['#D6EDC9', '#B07156', '#7F7057', '#4E6E58'];
@@ -24,13 +23,12 @@ SPDX-License-Identifier: MPL-2.0
let timer_res: string = $state(); let timer_res: string = $state();
let shown_question_now: number = $state(); let shown_question_now: number = $state();
let final_results_clicked = $state(false); let final_results_clicked = $state(false);
let timer_interval; let timer_interval: NodeJS.Timeout;
let answer_count = $state(0); let answer_count = $state(0);
interface Props { interface Props {
game_token: string; game_token: string;
quiz_data: QuizData; quiz_data: QuizData;
game_mode: string;
bg_color: string; bg_color: string;
final_results?: Array<null> | Array<Array<PlayerAnswer>>; final_results?: Array<null> | Array<Array<PlayerAnswer>>;
control_visible: boolean; control_visible: boolean;
@@ -40,7 +38,6 @@ SPDX-License-Identifier: MPL-2.0
let { let {
game_token, game_token,
quiz_data = $bindable(), quiz_data = $bindable(),
game_mode,
bg_color, bg_color,
final_results = $bindable([null]), final_results = $bindable([null]),
control_visible, control_visible,
@@ -92,7 +89,6 @@ SPDX-License-Identifier: MPL-2.0
timer_interval = setInterval(() => { timer_interval = setInterval(() => {
if (timer_res === '0') { if (timer_res === '0') {
clearInterval(timer_interval); clearInterval(timer_interval);
// socket.emit('show_solutions', {});
return; return;
} else { } else {
seconds--; seconds--;
@@ -132,9 +128,7 @@ SPDX-License-Identifier: MPL-2.0
{#await import('$lib/play/admin/slide.svelte')} {#await import('$lib/play/admin/slide.svelte')}
<Spinner my_20={false} /> <Spinner my_20={false} />
{:then c} {:then c}
<c.default <c.default question={quiz_data.questions[selected_question]} />
bind:question={quiz_data.questions[selected_question]}
/>
{/await} {/await}
{:else} {:else}
<Question {quiz_data} {selected_question} {timer_res} {answer_count} {default_colors} /> <Question {quiz_data} {selected_question} {timer_res} {answer_count} {default_colors} />
@@ -153,8 +147,8 @@ SPDX-License-Identifier: MPL-2.0
<Spinner /> <Spinner />
{:then c} {:then c}
<c.default <c.default
bind:data={question_results} data={question_results}
bind:question={quiz_data.questions[selected_question]} question={quiz_data.questions[selected_question]}
/> />
{/await} {/await}
{:else} {:else}
@@ -164,7 +158,7 @@ SPDX-License-Identifier: MPL-2.0
<c.default <c.default
bind:data={player_scores} bind:data={player_scores}
question={quiz_data.questions[selected_question]} question={quiz_data.questions[selected_question]}
bind:new_data={question_results} new_data={question_results}
/> />
{/await} {/await}
{/if} {/if}
@@ -8,8 +8,6 @@ SPDX-License-Identifier: MPL-2.0
This should be okay, right? This should be okay, right?
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { tinykeys } from '$lib/tinykeys'; import { tinykeys } from '$lib/tinykeys';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
@@ -104,7 +102,6 @@ This should be okay, right?
const toggle_open = (e: KeyboardEvent | undefined) => { const toggle_open = (e: KeyboardEvent | undefined) => {
e.preventDefault(); e.preventDefault();
open = !open; open = !open;
console.log('TOGGLE!');
}; };
const close_cp = (e: KeyboardEvent | undefined) => { const close_cp = (e: KeyboardEvent | undefined) => {
@@ -159,7 +156,6 @@ This should be okay, right?
visible_items = []; visible_items = [];
console.log(res);
for (const quiz_data of res) { for (const quiz_data of res) {
visible_items.push(actions[quiz_data.id]); visible_items.push(actions[quiz_data.id]);
} }
@@ -206,13 +202,6 @@ This should be okay, right?
input = ''; input = '';
}; };
run(() => {
search(input);
});
// $: input = lower_input(input)
run(() => {
input = input.toLowerCase();
});
onMount(async () => { onMount(async () => {
tinykeys(window, { tinykeys(window, {
'$mod+k': toggle_open, '$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" class="fixed top-0 left-0 w-screen h-screen flex bg-black/50 z-50"
onclick={close_on_outside} onclick={close_on_outside}
onkeyup={close_on_outside} onkeyup={close_on_outside}
role="generic" role="button"
aria-label="Close"
tabindex="0"
transition:fade|global={{ duration: 60 }} transition:fade|global={{ duration: 60 }}
> >
<div class="m-auto w-1/3 h-2/3 rounded-sm bg-black flex flex-col"> <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> </p>
<input <input
type="text" 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} bind:value={input}
oninput={() => search(input)}
autofocus autofocus
/> />
</div> </div>
@@ -5,17 +5,12 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import { fly } from 'svelte/transition'; import { fly } from 'svelte/transition';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
import { createEventDispatcher } from 'svelte';
import { PopoverTypes } from './smalltop'; import { PopoverTypes } from './smalltop';
const { t } = getLocalization(); const { t } = getLocalization();
const dispatch = createEventDispatcher();
interface Props { interface Props {
open?: boolean; open?: boolean;
type: PopoverTypes; type: PopoverTypes;
@@ -23,10 +18,6 @@ SPDX-License-Identifier: MPL-2.0
} }
let { open = $bindable(false), type, data = undefined }: Props = $props(); let { open = $bindable(false), type, data = undefined }: Props = $props();
run(() => {
dispatch('open', open);
});
</script> </script>
{#if open} {#if open}
+7 -37
View File
@@ -5,9 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run, preventDefault } from 'svelte/legacy';
// import { mint } from '$lib/hashcash';
import { dataSchema } from '$lib/yupSchemas'; import { dataSchema } from '$lib/yupSchemas';
import type { EditorData, Question } from './quiz_types'; import type { EditorData, Question } from './quiz_types';
import Sidebar from '$lib/editor/sidebar.svelte'; 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 { data = $bindable(), quiz_id }: Props = $props();
let selected_question = $state(-1); let selected_question = $state(-1);
let imgur_links_valid = $state(false);
const validateInput = async (data: EditorData) => { const validateInput = async (data: EditorData) => {
// console.log("input", data)
try { try {
await dataSchema.validate(data, { abortEarly: false }); await dataSchema.validate(data, { abortEarly: false });
schemaInvalid = false; schemaInvalid = false;
yupErrorMessage = ''; yupErrorMessage = '';
} catch (err) { } catch (err) {
console.log('erro!', err.errors);
schemaInvalid = true; schemaInvalid = true;
yupErrorMessage = err.errors ? err.errors[0] : ''; yupErrorMessage = err.errors ? err.errors[0] : '';
} }
}; };
run(() => { $effect(() => {
validateInput(data); validateInput(data);
}); });
let edit_id: string = $state();
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 confirm_to_leave = true; let confirm_to_leave = true;
run(() => {
console.log('data', data);
});
const getEditID = async () => { const getEditID = async () => {
let res; let res: Response;
if (quiz_id === null) { if (quiz_id === null) {
res = await fetch(`/api/v1/editor/start?edit=false`, { res = await fetch(`/api/v1/editor/start?edit=false`, {
method: 'POST' method: 'POST'
@@ -91,8 +61,7 @@ SPDX-License-Identifier: MPL-2.0
} }
}; };
const confirmUnload = (event) => { const confirmUnload = (event: BeforeUnloadEvent) => {
console.log(confirm_to_leave);
if (!confirm_to_leave) { if (!confirm_to_leave) {
return; return;
} }
@@ -101,7 +70,8 @@ SPDX-License-Identifier: MPL-2.0
localStorage.setItem('edit_game', JSON.stringify(data)); localStorage.setItem('edit_game', JSON.stringify(data));
return 'unload'; return 'unload';
}; };
const saveQuiz = async () => { const saveQuiz = async (e: Event) => {
e.preventDefault();
if (schemaInvalid) { if (schemaInvalid) {
return; return;
} }
@@ -126,7 +96,7 @@ SPDX-License-Identifier: MPL-2.0
{#await getEditID()} {#await getEditID()}
<Spinner /> <Spinner />
{:then _} {:then _}
<form onsubmit={preventDefault(saveQuiz)}> <form onsubmit={saveQuiz}>
<div class="grid grid-cols-6 h-screen w-screen"> <div class="grid grid-cols-6 h-screen w-screen">
<div> <div>
<Sidebar bind:data bind:selected_question /> <Sidebar bind:data bind:selected_question />
+2 -11
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import { browser } from '$app/environment'; import { browser } from '$app/environment';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
import { thumbHashToDataURL } from 'thumbhash'; import { thumbHashToDataURL } from 'thumbhash';
@@ -36,7 +34,7 @@ SPDX-License-Identifier: MPL-2.0
return Uint8Array.from(binString, (m) => m.codePointAt(0)); return Uint8Array.from(binString, (m) => m.codePointAt(0));
} }
const get_media = async () => { const get_media = async (_: string) => {
if (!browser) { if (!browser) {
return; return;
} }
@@ -55,14 +53,7 @@ SPDX-License-Identifier: MPL-2.0
thumbhash_data = undefined; thumbhash_data = undefined;
} }
}; };
const update_url = () => { let media = $derived(get_media(src));
media = get_media();
};
let media = $state(get_media());
run(() => {
src;
update_url();
});
let fullscreen_open = $state(false); let fullscreen_open = $state(false);
@@ -5,7 +5,7 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run, preventDefault } from 'svelte/legacy'; import { run } from 'svelte/legacy';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
import type { EditorData, OrderQuizAnswer } from '$lib/quiz_types'; 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" class="rounded-lg p-1 border-black border"
type="color" type="color"
bind:value={answer.color} bind:value={answer.color}
oncontextmenu={preventDefault(() => { oncontextmenu={(e) => {
e.preventDefault();
answer.color = null; answer.color = null;
})} }}
/> />
</div> </div>
{/each} {/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 answer = question.answers;
let range_arr = $state([answer.min_correct, answer.max_correct]); let range_arr = $state([answer.min_correct, answer.max_correct]);
run(() => { run(() => {
@@ -5,7 +5,7 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run, preventDefault } from 'svelte/legacy'; import { run } from 'svelte/legacy';
import type { EditorData } from '../quiz_types'; import type { EditorData } from '../quiz_types';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
@@ -103,9 +103,10 @@ SPDX-License-Identifier: MPL-2.0
class="rounded-lg p-1 border-black border" class="rounded-lg p-1 border-black border"
type="color" type="color"
bind:value={answer.color} bind:value={answer.color}
oncontextmenu={preventDefault(() => { oncontextmenu={(e) => {
e.preventDefault();
answer.color = default_colors[index]; answer.color = default_colors[index];
})} }}
/> />
</div> </div>
{/each} {/each}
+8 -22
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run, preventDefault } from 'svelte/legacy';
import type { EditorData } from '$lib/quiz_types'; import type { EditorData } from '$lib/quiz_types';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
import Spinner from '$lib/Spinner.svelte'; import Spinner from '$lib/Spinner.svelte';
@@ -30,7 +28,7 @@ SPDX-License-Identifier: MPL-2.0
animation: 'perspective-subtle' animation: 'perspective-subtle'
}); });
run(() => { $effect(() => {
data.background_color = custom_bg_color ? data.background_color : undefined; data.background_color = custom_bg_color ? data.background_color : undefined;
}); });
</script> </script>
@@ -57,11 +55,6 @@ SPDX-License-Identifier: MPL-2.0
: `unset`}" : `unset`}"
> >
<div class="flex justify-center pt-10 w-full"> <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')} {#await import('$lib/inline-editor.svelte')}
<Spinner my_20={false} /> <Spinner my_20={false} />
{:then c} {:then c}
@@ -70,7 +63,6 @@ SPDX-License-Identifier: MPL-2.0
</div> </div>
<div class="flex justify-center pt-10 w-full max-h-32"> <div class="flex justify-center pt-10 w-full max-h-32">
<textarea <textarea
type="text"
placeholder="Description" placeholder="Description"
bind:value={data.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" 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> </div>
{#if data.cover_image != undefined && data.cover_image !== ''} {#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 <img
src="/api/v1/storage/download/{data.cover_image}" src="/api/v1/storage/download/{data.cover_image}"
alt="not available" alt="not available"
class="max-h-72 h-auto w-auto" class="max-h-72 h-auto w-auto"
oncontextmenu={preventDefault(() => { oncontextmenu={(e: Event) => {
e.preventDefault();
data.cover_image = null; data.cover_image = null;
})} }}
/> />
</div> </div>
{:else} {:else}
{#await import('$lib/editor/uploader.svelte')} {#await import('$lib/editor/uploader.svelte')}
<Spinner my_20={false} /> <Spinner my_20={false} />
{:then c} {:then c}
<c.default <c.default bind:modalOpen={uppyOpen} {data} video_upload={false} />
bind:modalOpen={uppyOpen}
bind:edit_id
bind:data
video_upload={false}
/>
{/await} {/await}
{/if} {/if}
<div class="pt-10 w-full flex justify-center"> <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="bg-gray-200 rounded-lg w-full h-full p-1"
class:pointer-events-none={custom_bg_color} class:pointer-events-none={custom_bg_color}
> >
<span <span class="inline-block w-full h-full bg-[#d6edc9] dark:bg-[#4e6e58]"
class="inline-block w-full h-full bg-[#d6edc9] dark:bg-[#4e6e58]"
></span> ></span>
</div> </div>
</div> </div>
@@ -209,8 +196,7 @@ SPDX-License-Identifier: MPL-2.0
{:then c} {:then c}
<c.default <c.default
bind:modalOpen={bg_uppy_open} bind:modalOpen={bg_uppy_open}
bind:edit_id {data}
bind:data
selected_question={-1} selected_question={-1}
video_upload={false} video_upload={false}
/> />
@@ -5,14 +5,12 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
let { title = $bindable(), time = $bindable() } = $props(); let { title = $bindable(), time = $bindable() } = $props();
let time_local = $state(120); let time_local = $state(120);
/*eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }]*/ /*eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }]*/
run(() => { $effect(() => {
time = String(time_local); time = String(time_local);
}); });
if (time) { if (time) {
+8 -6
View File
@@ -27,19 +27,17 @@ SPDX-License-Identifier: MPL-2.0
const { t } = getLocalization(); const { t } = getLocalization();
let { let {
modalOpen = false, modalOpen = $bindable(),
edit_id,
data, data,
selected_question, selected_question,
video_upload = false, video_upload = false,
library_enabled = true library_enabled = true
}: { }: {
modalOpen: boolean; modalOpen: boolean;
edit_id: string;
data: EditorData; data: EditorData;
selected_question: number; selected_question?: number;
video_upload: boolean; video_upload: boolean;
library_enabled: boolean; library_enabled?: boolean;
} = $props(); } = $props();
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
@@ -83,7 +81,7 @@ SPDX-License-Identifier: MPL-2.0
// allowedFileTypes: ['.gif', '.jpg', '.jpeg', '.png', '.svg', '.webp'] // allowedFileTypes: ['.gif', '.jpg', '.jpeg', '.png', '.svg', '.webp']
} }
}; };
let image_id; let image_id: string;
uppy.on('upload-success', (file, response) => { uppy.on('upload-success', (file, response) => {
image_id = response.body.id; image_id = response.body.id;
}); });
@@ -142,6 +140,10 @@ SPDX-License-Identifier: MPL-2.0
<div <div
class="w-screen h-screen fixed top-0 left-0 bg-black/50 z-20 flex justify-center" class="w-screen h-screen fixed top-0 left-0 bg-black/50 z-20 flex justify-center"
onclick={handle_on_click} 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 }} transition:fade={{ duration: 100 }}
> >
{#if selected_type === null} {#if selected_type === null}
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { preventDefault } from 'svelte/legacy';
import type { EditorData } from '$lib/quiz_types'; import type { EditorData } from '$lib/quiz_types';
import Spinner from '$lib/Spinner.svelte'; import Spinner from '$lib/Spinner.svelte';
import BrownButton from '$lib/components/buttons/brown.svelte'; import BrownButton from '$lib/components/buttons/brown.svelte';
@@ -70,7 +68,10 @@ SPDX-License-Identifier: MPL-2.0
<form <form
class="w-full flex gap-2" class="w-full flex gap-2"
onsubmit={preventDefault(() => (fetched_data = fetch_data()))} onsubmit={(e) => {
e.preventDefault();
fetched_data = fetch_data();
}}
> >
<input <input
class="w-full outline-hidden p-1 rounded-sm dark:bg-gray-500 bg-gray-300" class="w-full outline-hidden p-1 rounded-sm dark:bg-gray-500 bg-gray-300"
-13
View File
@@ -22,24 +22,17 @@ import vi from './locales/vi.json';
import ta from './locales/ta.json'; import ta from './locales/ta.json';
import pt_BR from './locales/pt_BR.json'; import pt_BR from './locales/pt_BR.json';
import ja from './locales/ja.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 LanguageDetector from 'i18next-browser-languagedetector';
import type { i18n } from 'i18next'; import type { i18n } from 'i18next';
export class I18nService { export class I18nService {
// expose i18next
i18n: i18n; i18n: i18n;
constructor() { constructor() {
this.i18n = i18next; this.i18n = i18next;
this.initialize(); this.initialize();
// this.changeLanguage("de")
//this.changeLanguage(INITIAL_LANGUAGE);
} }
// Our translation function
t(key: string, replacements?: Record<string, unknown>): string { t(key: string, replacements?: Record<string, unknown>): string {
return this.i18n.t(key, replacements); return this.i18n.t(key, replacements);
} }
@@ -57,10 +50,6 @@ export class I18nService {
}, },
returnEmptyString: false, returnEmptyString: false,
simplifyPluralSuffix: true, simplifyPluralSuffix: true,
// detection: {
// order: ['browser', 'querystring', 'navigator', 'localStorage', 'htmlTag'],
// lookupQuerystring: 'lng'
// }
detection: { detection: {
order: ['querystring', 'cookie', 'localStorage', 'navigator'], order: ['querystring', 'cookie', 'localStorage', 'navigator'],
lookupQuerystring: 'lng', lookupQuerystring: 'lng',
@@ -88,8 +77,6 @@ export class I18nService {
this.i18n.addResourceBundle('ta', 'translation', ta); this.i18n.addResourceBundle('ta', 'translation', ta);
this.i18n.addResourceBundle('pt_BR', 'translation', pt_BR); this.i18n.addResourceBundle('pt_BR', 'translation', pt_BR);
this.i18n.addResourceBundle('ja', 'translation', ja); this.i18n.addResourceBundle('ja', 'translation', ja);
// this.i18n.addResourceBundle('uz', 'translation', uz);
} }
changeLanguage(language: string): void { changeLanguage(language: string): void {
-35
View File
@@ -20,14 +20,6 @@ SPDX-License-Identifier: MPL-2.0
Strikethrough Strikethrough
} from 'ckeditor5'; } from 'ckeditor5';
import 'ckeditor5/ckeditor5.css'; 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 = () => { const triggerChange = () => {
text = editor.getData(); text = editor.getData();
@@ -46,33 +38,6 @@ SPDX-License-Identifier: MPL-2.0
run(() => { run(() => {
text = text.replace('<p>', '').replace('</p>', ''); 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; let editor;
onMount(() => { onMount(() => {
class Editor extends BalloonEditor { 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 = '&#xfeff;';
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 = '&lt;- 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} />
+1 -48
View File
@@ -3,53 +3,6 @@ SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
SPDX-License-Identifier: MPL-2.0 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"> <script lang="ts">
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { browser } from '$app/environment'; import { browser } from '$app/environment';
@@ -164,7 +117,7 @@ SPDX-License-Identifier: MPL-2.0
const get_selected_language = (): string => { const get_selected_language = (): string => {
return localStorage.getItem('language'); return localStorage.getItem('language');
}; };
let selected_language = $state(); let selected_language: string = $state();
onMount(() => { onMount(() => {
selected_language = get_selected_language(); selected_language = get_selected_language();
}); });
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
@@ -16,13 +14,14 @@ SPDX-License-Identifier: MPL-2.0
import confetti from 'canvas-confetti'; import confetti from 'canvas-confetti';
interface Props { interface Props {
data: any; data: any;
username: any; username?: any;
show_final_results: boolean; show_final_results: boolean;
} }
let { data = $bindable(), username, show_final_results }: Props = $props(); let { data = $bindable(), username, show_final_results }: Props = $props();
let sorted_data = $derived(sortObjectbyValue(data));
function sortObjectbyValue(obj) { function sortObjectbyValue(obj: object) {
const ret = {}; const ret = {};
Object.keys(obj) Object.keys(obj)
.sort((a, b) => obj[b] - obj[a]) .sort((a, b) => obj[b] - obj[a])
@@ -30,30 +29,22 @@ SPDX-License-Identifier: MPL-2.0
return ret; return ret;
} }
run(() => { let player_names = $derived(Object.keys(sorted_data));
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_count_or_five = $derived(player_names.length >= 5 ? 5 : player_names.length); let player_count_or_five = $derived(player_names.length >= 5 ? 5 : player_names.length);
let canvas: HTMLCanvasElement = $state();
let canvas = $state();
onMount(() => { onMount(() => {
setTimeout(() => { setTimeout(
() => {
confetti.create(canvas, { confetti.create(canvas, {
resize: true, resize: true,
useWorker: true useWorker: true
}); });
confetti({ particleCount: 200, spread: 160 }); confetti({ particleCount: 200, spread: 160 });
}, player_count_or_five * 1200 - 800); },
player_count_or_five * 1200 - 800
);
}); });
</script> </script>
@@ -70,13 +61,13 @@ SPDX-License-Identifier: MPL-2.0
{$t('play_page.final_result_rank', { {$t('play_page.final_result_rank', {
place: i + 1, place: i + 1,
username: player, username: player,
points: data[player] points: sorted_data[player]
})} })}
</p> </p>
{/if} {/if}
{/each} {/each}
</div> </div>
{#if data[username]} {#if sorted_data[username]}
<div class="fixed bottom-0 left-0 flex justify-center w-full mb-6"> <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"> <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> <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" class="fixed top-0 left-0 z-50 w-screen h-screen bg-black/50 flex p-2"
transition:fade|global={{ duration: 80 }} transition:fade|global={{ duration: 80 }}
onclick={() => (fullscreen_open = false)} onclick={() => (fullscreen_open = false)}
tabindex="0"
role="button"
aria-label="Close modal"
onkeydown={(e) =>
e.key === 'Enter' || e.key === ' '
? () => {
fullscreen_open = false;
}
: null}
> >
<img <img
alt="QR code to join the game" alt="QR code to join the game"
+6 -13
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import { QuizQuestionType } from '$lib/quiz_types'; import { QuizQuestionType } from '$lib/quiz_types';
import type { QuizData } from '$lib/quiz_types'; import type { QuizData } from '$lib/quiz_types';
import { get_foreground_color } from '$lib/helpers.js'; 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 MediaComponent from '$lib/editor/MediaComponent.svelte';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
interface Props { interface Props {
quiz_data: QuizData; quiz_data: QuizData;
selected_question: number; selected_question: number;
@@ -34,16 +31,16 @@ SPDX-License-Identifier: MPL-2.0
const { t } = getLocalization(); const { t } = getLocalization();
let circular_progress = $state(0); let circular_progress = $derived.by(() => {
run(() => {
try { try {
circular_progress = return (
1 - 1 -
((100 / parseInt(quiz_data.questions[selected_question].time)) * ((100 / parseInt(quiz_data.questions[selected_question].time)) *
parseInt(timer_res)) / parseInt(timer_res)) /
100; 100
);
} catch { } catch {
circular_progress = 0; return 0;
} }
}); });
</script> </script>
@@ -56,11 +53,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="grid grid-cols-3 my-2"> <div class="grid grid-cols-3 my-2">
<span></span> <span></span>
<div class="m-auto"> <div class="m-auto">
<CircularTimer <CircularTimer text={timer_res} progress={circular_progress} color="#ef4444" />
bind:text={timer_res}
bind:progress={circular_progress}
color="#ef4444"
/>
</div> </div>
<p class="m-auto text-3xl"> <p class="m-auto text-3xl">
{$t('admin_page.answers_submitted', { answer_count: answer_count })} {$t('admin_page.answers_submitted', { answer_count: answer_count })}
+10 -26
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import VotingResults from './voting_results.svelte'; import VotingResults from './voting_results.svelte';
import { flip } from 'svelte/animate'; import { flip } from 'svelte/animate';
import { fly } from 'svelte/transition'; import { fly } from 'svelte/transition';
@@ -31,7 +29,7 @@ SPDX-License-Identifier: MPL-2.0
let { data = $bindable(), question, new_data }: Props = $props(); let { data = $bindable(), question, new_data }: Props = $props();
function sortObjectbyValue(obj) { function sortObjectbyValue(obj: object) {
const ret = {}; const ret = {};
Object.keys(obj) Object.keys(obj)
.sort((a, b) => obj[b] - obj[a]) .sort((a, b) => obj[b] - obj[a])
@@ -39,26 +37,20 @@ SPDX-License-Identifier: MPL-2.0
return ret; return ret;
} }
let sorted_data = $derived(sortObjectbyValue(data));
// let data_by_username = {}; // 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) { 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(() => { let player_names = $derived(Object.keys(sorted_data));
new_data;
score_by_username;
do_sth();
});
let player_names = $derived(
Object.keys(data).sort(function (a, b) {
return data[b] - data[a];
})
);
if (JSON.stringify(data) === '{}') { if (JSON.stringify(data) === '{}') {
for (const i of new_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); let show_new_score_clicked = $state(false);
const show_new_score = () => { const show_new_score = () => {
// for (let i = 0; i++; i < player_names.length) {
// console.log(data)
for (const i of player_names) { for (const i of player_names) {
if (isNaN(data[i])) { if (isNaN(data[i])) {
data[i] = 0; data[i] = 0;
@@ -91,8 +77,6 @@ SPDX-License-Identifier: MPL-2.0
setTimeout(() => { setTimeout(() => {
data = data; data = data;
}, 800); }, 800);
// console.log(data)
}; };
onMount(() => { onMount(() => {
@@ -127,7 +111,7 @@ SPDX-License-Identifier: MPL-2.0
<td class:hidden={i > 3} class="p-2 border-r border-r-black" <td class:hidden={i > 3} class="p-2 border-r border-r-black"
>{player}</td >{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} {#if show_new_score_clicked}
<td <td
in:fly|global={{ x: 300 }} in:fly|global={{ x: 300 }}
+1 -1
View File
@@ -40,6 +40,6 @@ SPDX-License-Identifier: MPL-2.0
<div bind:this={canvas_el} class="w-full h-full block"></div> <div bind:this={canvas_el} class="w-full h-full block"></div>
</div> </div>
<div class="w-full h-full flex justify-center"> <div class="w-full h-full flex justify-center">
<img src={img_src} /> <img src={img_src} alt="Slide image" />
</div> </div>
</div> </div>
+2 -4
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import Audio1 from '$lib/assets/music/1-128.mp3'; import Audio1 from '$lib/assets/music/1-128.mp3';
interface Props { interface Props {
@@ -25,10 +23,10 @@ SPDX-License-Identifier: MPL-2.0
audio.pause(); audio.pause();
} }
}; };
run(() => { $effect(() => {
audio.volume = volume / 100; audio.volume = volume / 100;
}); });
run(() => { $effect(() => {
control_audio(play); control_audio(play);
}); });
</script> </script>
+3 -18
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
interface Props { interface Props {
progress: number; progress: number;
text: string; text: string;
@@ -14,25 +12,12 @@ SPDX-License-Identifier: MPL-2.0
} }
let { progress, text, color }: Props = $props(); let { progress, text, color }: Props = $props();
let angle = $state(360 * progress); let angle = $derived(360 * progress);
run(() => {
angle = 360 * progress;
});
run(() => {
console.log(angle);
});
// Adapt the logic according to the approach // Adapt the logic according to the approach
let background = $state(`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(transparent 0deg ${angle}deg, gainsboro ${angle}deg 360deg),
conic-gradient(green 0deg, green 90deg, green 180deg, green);`); conic-gradient(${color} 0deg, ${color} 90deg, ${color} 180deg, ${color});`);
run(() => {
background = `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});`;
});
let cssVarStyles = $derived(`--background:${background}`); let cssVarStyles = $derived(`--background:${background}`);
</script> </script>
-5
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
const { t } = getLocalization(); const { t } = getLocalization();
@@ -85,9 +83,6 @@ SPDX-License-Identifier: MPL-2.0
} }
}; };
let winners = getWinnersSorted(); let winners = getWinnersSorted();
run(() => {
console.log(winners, winners_arr);
});
</script> </script>
<div> <div>
+11 -21
View File
@@ -5,14 +5,10 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run, createBubbler, preventDefault } from 'svelte/legacy';
const bubble = createBubbler();
import { socket } from '$lib/socket'; import { socket } from '$lib/socket';
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import { browser } from '$app/environment'; import { browser } from '$app/environment';
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
// import { alertModal } from '../stores';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import BrownButton from '$lib/components/buttons/brown.svelte'; 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) { if (game_pin.length > 5) {
console.log('Setting game pin');
set_game_pin(); set_game_pin();
} }
}); });
const setUsername = async () => { const setUsername = async (e: Event) => {
e.preventDefault();
if (username.length <= 3) { if (username.length <= 3) {
return; return;
} }
@@ -189,12 +185,12 @@ SPDX-License-Identifier: MPL-2.0
alert('Game not found'); alert('Game not found');
} }
}); });
$effect(() => {
run(() => { const cleaned = game_pin.replace(/\D/g, '');
console.log(game_pin, game_pin.length > 6); if (game_pin.replace(/\D/g, '') === game_pin) {
}); return;
run(() => { }
game_pin = game_pin.replace(/\D/g, ''); game_pin = cleaned;
}); });
</script> </script>
@@ -211,10 +207,7 @@ SPDX-License-Identifier: MPL-2.0
{#if game_pin === '' || game_pin.length < 6} {#if game_pin === '' || game_pin.length < 6}
<div class="flex flex-col justify-center align-center w-screen h-screen"> <div class="flex flex-col justify-center align-center w-screen h-screen">
<form <form class="flex-col flex justify-center align-center mx-auto">
onsubmit={preventDefault(bubble('submit'))}
class="flex-col flex justify-center align-center mx-auto"
>
<h1 class="text-lg text-center">{$t('words.game_pin')}</h1> <h1 class="text-lg text-center">{$t('words.game_pin')}</h1>
<input <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" 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> </div>
{:else} {:else}
<div class="flex flex-col justify-center align-center w-screen h-screen"> <div class="flex flex-col justify-center align-center w-screen h-screen">
<form <form onsubmit={setUsername} class="flex-col flex justify-center align-center mx-auto">
onsubmit={preventDefault(setUsername)}
class="flex-col flex justify-center align-center mx-auto"
>
<h1 class="text-lg text-center">{$t('words.username')}</h1> <h1 class="text-lg text-center">{$t('words.username')}</h1>
<input <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" class="border border-gray-400 self-center text-center text-black ring-0 outline-hidden p-2 rounded-lg focus:shadow-2xl transition-all"
+11 -53
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import type { Question } from '$lib/quiz_types'; import type { Question } from '$lib/quiz_types';
import { QuizQuestionType } from '$lib/quiz_types'; import { QuizQuestionType } from '$lib/quiz_types';
import { socket } from '$lib/socket'; import { socket } from '$lib/socket';
@@ -35,23 +33,12 @@ SPDX-License-Identifier: MPL-2.0
solution solution
}: Props = $props(); }: Props = $props();
run(() => {
console.log(question_index, question, 'hi!');
});
console.log(question);
if (question.type === undefined) { if (question.type === undefined) {
question.type = QuizQuestionType.ABCD; question.type = QuizQuestionType.ABCD;
} else { } else {
question.type = QuizQuestionType[question.type]; 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 timer_res = $state(question.time);
let selected_answer: string = $state(); let selected_answer: string = $state();
@@ -75,7 +62,7 @@ SPDX-License-Identifier: MPL-2.0
timer(question.time); timer(question.time);
run(() => { $effect(() => {
if (solution !== undefined) { if (solution !== undefined) {
timer_res = '0'; timer_res = '0';
} }
@@ -83,7 +70,6 @@ SPDX-License-Identifier: MPL-2.0
const selectAnswer = (answer: string) => { const selectAnswer = (answer: string) => {
selected_answer = answer; selected_answer = answer;
//timer_res = '0';
socket.emit('submit_answer', { socket.emit('submit_answer', {
question_index: question_index, question_index: question_index,
answer: answer answer: answer
@@ -132,15 +118,14 @@ SPDX-License-Identifier: MPL-2.0
_arr[b] = temp; _arr[b] = temp;
return _arr; return _arr;
}; };
run(() => { $effect(() => {
set_answer_if_not_set_range(timer_res); set_answer_if_not_set_range(timer_res);
}); });
let circular_progress = $state(0); let circular_progress = $derived.by(() => {
run(() => {
try { try {
circular_progress = 1 - ((100 / question.time) * parseInt(timer_res)) / 100; return 1 - ((100 / question.time) * parseInt(timer_res)) / 100;
} catch { } catch {
circular_progress = 0; return 0;
} }
}); });
@@ -155,9 +140,6 @@ SPDX-License-Identifier: MPL-2.0
return '100'; return '100';
} }
}; };
run(() => {
console.log(slider_value, 'values');
});
const default_colors = ['#D6EDC9', '#B07156', '#7F7057', '#4E6E58']; const default_colors = ['#D6EDC9', '#B07156', '#7F7057', '#4E6E58'];
</script> </script>
@@ -189,11 +171,7 @@ SPDX-License-Identifier: MPL-2.0
<div <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" 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 <CircularTimer text={timer_res} progress={circular_progress} color="#ef4444" />
bind:text={timer_res}
bind:progress={circular_progress}
color="#ef4444"
/>
</div> </div>
<div class="grid grid-rows-2 grid-flow-col auto-cols-auto gap-2 w-full p-4 h-full"> <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> </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} {:else if question.type === QuizQuestionType.ORDER}
<!-- {#if solution === undefined} <!-- {#if solution === undefined}
<Spinner /> <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" 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" type="button"
disabled={i === 0 || selected_answer} aria-label="Move item up"
disabled={i === 0 || Boolean(selected_answer)}
> >
<svg <svg
class="w-8 h-8" 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" 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" 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 <svg
class="w-8 h-8" class="w-8 h-8"
@@ -365,7 +331,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="w-full mt-2"> <div class="w-full mt-2">
<BrownButton <BrownButton
type="button" type="button"
disabled={selected_answer} disabled={Boolean(selected_answer)}
onclick={() => { onclick={() => {
select_complex_answer(question.answers); select_complex_answer(question.answers);
}}>{$t('words.submit')}</BrownButton }}>{$t('words.submit')}</BrownButton
@@ -396,13 +362,5 @@ SPDX-License-Identifier: MPL-2.0
</div> </div>
{/await} {/await}
{/if} {/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} {/if}
</div> </div>
+4 -20
View File
@@ -5,10 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
function sortObjectbyValue(obj) { function sortObjectbyValue(obj) {
const ret = {}; const ret = {};
Object.keys(obj) Object.keys(obj)
@@ -37,26 +33,14 @@ SPDX-License-Identifier: MPL-2.0
scores[i.username] = 0; scores[i.username] = 0;
} }
} }
run(() => {
console.log(score_by_username, scores, 'dieter');
});
for (const i of question_results) { for (const i of question_results) {
score_by_username[i.username] = i.score; score_by_username[i.username] = i.score;
} }
for (const username of Object.keys(score_by_username)) {
run(() => { scores[username] = (score_by_username[username] ?? 0) + (scores[username] ?? 0);
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; scores = scores;
}; let sorted_scores = $derived(sortObjectbyValue(scores));
do_sth();
</script> </script>
<div> <div>
@@ -65,7 +49,7 @@ SPDX-License-Identifier: MPL-2.0
<p class="p-4 bg-black/40 rounded-lg text-2xl"> <p class="p-4 bg-black/40 rounded-lg text-2xl">
+{score_by_username[username] ?? '0'} +{score_by_username[username] ?? '0'}
</p> </p>
<p>Total score: {scores[username] ?? '0'}</p> <p>Total score: {sorted_scores[username] ?? '0'}</p>
</div> </div>
</div> </div>
</div> </div>
-123
View File
@@ -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"> <script lang="ts">
import { preventDefault } from 'svelte/legacy';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
import { fly } from 'svelte/transition'; import { fly } from 'svelte/transition';
@@ -15,7 +13,11 @@ SPDX-License-Identifier: MPL-2.0
const { t } = getLocalization(); const { t } = getLocalization();
</script> </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="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="h-fit bg-gray-300 rounded-t-lg dark:bg-gray-500">
<div class="flex align-middle p-4 gap-3"> <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}" src="/api/v1/storage/download/{data.cover_image}"
alt="not available" alt="not available"
class="max-h-72 h-auto w-auto" class="max-h-72 h-auto w-auto"
oncontextmenu={preventDefault(() => { oncontextmenu={(e) => {
e.preventDefault();
data.cover_image = ''; data.cover_image = '';
})} }}
/> />
</div> </div>
{/if} {/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"> <script lang="ts">
import { run } from 'svelte/legacy';
import type { Markdown } from '$lib/quiztivity/types'; import type { Markdown } from '$lib/quiztivity/types';
import { marked } from 'marked'; import { marked } from 'marked';
import { browser } from '$app/environment'; import { browser } from '$app/environment';
@@ -23,11 +21,7 @@ SPDX-License-Identifier: MPL-2.0
}; };
} }
let rendered_html = $state(''); let rendered_html = $derived(browser ? marked.parse(data.markdown) : '');
run(() => {
rendered_html = browser ? marked.parse(data.markdown) : '';
});
</script> </script>
<div class="w-full h-[70vh] flex flex-row p-4 gap-4"> <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"> <script lang="ts">
import { run } from 'svelte/legacy';
import type { Markdown } from '$lib/quiztivity/types'; import type { Markdown } from '$lib/quiztivity/types';
import DOMPurify from 'dompurify'; import DOMPurify from 'dompurify';
import { marked } from 'marked'; import { marked } from 'marked';
@@ -18,11 +16,9 @@ SPDX-License-Identifier: MPL-2.0
let { data }: Props = $props(); let { data }: Props = $props();
let rendered_html = $state(''); let rendered_html = $derived(
browser ? DOMPurify.sanitize(marked.parse(data.markdown ?? '')) : ''
run(() => { );
rendered_html = browser ? DOMPurify.sanitize(marked.parse(data.markdown ?? '')) : '';
});
</script> </script>
<div class="prose dark:prose-invert"> <div class="prose dark:prose-invert">
+1 -3
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import type { Data } from './types'; import type { Data } from './types';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
import BrownButton from '$lib/components/buttons/brown.svelte'; 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 }); data.pages.push({ title: undefined, data: undefined, type, id });
opened_slide = data.pages.length - 1; opened_slide = data.pages.length - 1;
}; };
run(() => { $effect(() => {
handle_slide_add(selected_type); handle_slide_add(selected_type);
}); });
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { preventDefault } from 'svelte/legacy';
import BrownButton from '$lib/components/buttons/brown.svelte'; import BrownButton from '$lib/components/buttons/brown.svelte';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
import Spinner from '$lib/Spinner.svelte'; import Spinner from '$lib/Spinner.svelte';
@@ -81,7 +79,8 @@ SPDX-License-Identifier: MPL-2.0
}); });
let never_expires_checked = $state(true); let never_expires_checked = $state(true);
let selected_date = $state(undefined); let selected_date = $state(undefined);
const create_share = async () => { const create_share = async (e: Event) => {
e.preventDefault();
if (!selected_date && !never_expires_checked) { if (!selected_date && !never_expires_checked) {
return; return;
} }
@@ -145,7 +144,7 @@ SPDX-License-Identifier: MPL-2.0
<form <form
class="flex justify-center p-2 border-b-2 border-l-2 border-r-2 border-[#B07156] flex-col gap-2" 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 }} transition:fly={{ duration: 100, y: -10 }}
onsubmit={preventDefault(create_share)} onsubmit={create_share}
> >
<div class="grid grid-cols-2"> <div class="grid grid-cols-2">
<input <input
-4
View File
@@ -15,10 +15,6 @@ SPDX-License-Identifier: MPL-2.0
<div class="flex justify-center"> <div class="flex justify-center">
<a href="/view/{quiz.id}" class="h-max w-fit"> <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="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>
<div class="flex w-full items-center"> <div class="flex w-full items-center">
<h2 <h2
+1 -62
View File
@@ -9,8 +9,7 @@ SPDX-License-Identifier: MPL-2.0
import Navbar from '$lib/navbar.svelte'; import Navbar from '$lib/navbar.svelte';
import { pathname } from '$lib/stores'; import { pathname } from '$lib/stores';
import { navbarVisible } from '$lib/stores.svelte'; import { navbarVisible } from '$lib/stores.svelte';
// import * as Sentry from '@sentry/browser';
// import { BrowserTracing } from '@sentry/tracing';
import { initLocalizationContext } from '$lib/i18n'; import { initLocalizationContext } from '$lib/i18n';
import { browser } from '$app/environment'; import { browser } from '$app/environment';
import CommandPalette from '$lib/components/commandpalette.svelte'; import CommandPalette from '$lib/components/commandpalette.svelte';
@@ -19,19 +18,6 @@ SPDX-License-Identifier: MPL-2.0
} }
let { children }: Props = $props(); let { children }: Props = $props();
// import Alert from '$lib/modals/alert.svelte';
/* afterNavigate(() => {
if (browser) {
if (latestPageVisitURl === window.location.href) {
return;
} else {
latestPageVisitURl = window.location.href;
plausible.trackPageview();
}
console.log('After nav');
}
});*/
const plausible_data_url = import.meta.env.VITE_PLAUSIBLE_DATA_URL; const plausible_data_url = import.meta.env.VITE_PLAUSIBLE_DATA_URL;
if (browser) { if (browser) {
@@ -45,34 +31,12 @@ SPDX-License-Identifier: MPL-2.0
} else { } else {
document.documentElement.classList.remove('dark'); document.documentElement.classList.remove('dark');
} }
// Whenever the user explicitly chooses light mode
// localStorage.theme = 'light';
//
// // Whenever the user explicitly chooses dark mode
// localStorage.theme = 'dark';
//
// // Whenever the user explicitly chooses to respect the OS preference
// localStorage.removeItem('theme');
} }
let start_language = 'en'; let start_language = 'en';
if (browser) { if (browser) {
start_language = localStorage.getItem('language') ?? 'en'; start_language = localStorage.getItem('language') ?? 'en';
} }
initLocalizationContext(start_language); initLocalizationContext(start_language);
/*
if (import.meta.env.VITE_SENTRY !== undefined && import.meta.env.PROD) {
Sentry.init({
dsn: String(import.meta.env.VITE_SENTRY),
integrations: [new BrowserTracing()],
// Set tracesSampleRate to 1.0 to capture 100%
// of transactions for performance monitoring.
// We recommend adjusting this value in production
tracesSampleRate: 0.5
});
}
*/
</script> </script>
<svelte:head> <svelte:head>
@@ -92,40 +56,15 @@ SPDX-License-Identifier: MPL-2.0
{/if} {/if}
</svelte:head> </svelte:head>
<!-- {#if navbarVisible.visible = true.visible}
<Navbar />
<div class="pt-16 h-screen">
<div class="z-40"></div>
<slot />
</div>
{:else}
<slot />
{/if} -->
{#if navbarVisible.visible} {#if navbarVisible.visible}
<Navbar /> <Navbar />
<div class="pt-16"> <div class="pt-16">
<div class="z-40"></div> <div class="z-40"></div>
<!-- extra content above slot -->
</div> </div>
{/if} {/if}
{@render children?.()} {@render children?.()}
<CommandPalette /> <CommandPalette />
<!--{#if $alertModal.open ?? false}
<div
class="fixed inset-0 h-screen w-screen bg-black z-30 bg-opacity-60 items-center justify-center content-center"
class:hidden={!$alertModal.open}
class:flex={$alertModal.open}
class:visible={$alertModal.open}
>
<Alert
bind:title={$alertModal.title}
bind:body={$alertModal.body}
bind:open={$alertModal.open}
/>
</div>
{/if}-->
<style lang="scss"> <style lang="scss">
:global(html:not(.dark)) { :global(html:not(.dark)) {
// height: 100%; // height: 100%;
-1
View File
@@ -2,7 +2,6 @@
// //
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
// import { redirect } from '@sveltejs/kit';
import { signedIn } from '$lib/stores'; import { signedIn } from '$lib/stores';
import type { LayoutLoad } from './$types'; import type { LayoutLoad } from './$types';
+2 -1
View File
@@ -3,8 +3,9 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
import { redirect } from '@sveltejs/kit'; import { redirect } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load = async ({ parent }) => { export const load: PageServerLoad = async ({ parent }) => {
const { email } = await parent(); const { email } = await parent();
if (email) { if (email) {
redirect(302, '/dashboard'); redirect(302, '/dashboard');
+17 -111
View File
@@ -13,8 +13,6 @@ SPDX-License-Identifier: MPL-2.0
import Newsletter from '$lib/landing/newsletter.svelte'; import Newsletter from '$lib/landing/newsletter.svelte';
import { fly, fade } from 'svelte/transition'; import { fly, fade } from 'svelte/transition';
/* import LandingPromo from '$lib/landing/landing-promo.svelte';*/
import FindScreenshot from '$lib/assets/landing_new/find.webp'; import FindScreenshot from '$lib/assets/landing_new/find.webp';
import ImportScreenshot from '$lib/assets/landing_new/import.webp'; import ImportScreenshot from '$lib/assets/landing_new/import.webp';
import EditScreenshot from '$lib/assets/landing_new/edit.webp'; import EditScreenshot from '$lib/assets/landing_new/edit.webp';
@@ -27,16 +25,7 @@ SPDX-License-Identifier: MPL-2.0
navbarVisible.visible = true; navbarVisible.visible = true;
/* interface StatsData { let newsletterModalOpen: boolean = $state();
quiz_count: number;
user_count: number;
}*/
/* const getStats = async (): Promise<StatsData> => {
const response = await fetch('/api/v1/stats/combined');
return await response.json();
};*/
let newsletterModalOpen = $state();
onMount(() => { onMount(() => {
const ls = localStorage.getItem('newsletter'); const ls = localStorage.getItem('newsletter');
newsletterModalOpen = ls === null; newsletterModalOpen = ls === null;
@@ -65,18 +54,6 @@ SPDX-License-Identifier: MPL-2.0
let selected_create_thing = $state(SelectedCreateThing.Create); let selected_create_thing = $state(SelectedCreateThing.Create);
let selected_play_thing = $state(SelectedPlayThing.Select); let selected_play_thing = $state(SelectedPlayThing.Select);
/* <li>No;
Tracking < /li>
< li > Self - hostable < /li>
< li > German;
Server < /li>
< li > user - friendly < /li>
< li > Completely;
free < /li>
< li > Quiz - results;
are;
downloadable < /li>;*/
const classquiz_reasons = [ const classquiz_reasons = [
{ {
headline: $t('index_page.no_player_limit'), headline: $t('index_page.no_player_limit'),
@@ -154,57 +131,6 @@ SPDX-License-Identifier: MPL-2.0
/> />
<meta name="twitter:image" content={WebPOpenGraph} /> <meta name="twitter:image" content={WebPOpenGraph} />
</svelte:head> </svelte:head>
<!--<div class="min-h-screen flex flex-col">
<section class="pb-40">
<div class="pt-12 text-center">
<h1 class="sm:text-8xl text-6xl mt-6 marck-script">ClassQuiz</h1>
<p class="text-xl mt-4">{$t('index_page.slogan')}</p>
</div>
</section>
<section id="features" class="mt-8">
<div class="text-center snap-y">
<h1 class="sm:text-6xl text-4xl">{$t('words.features')}</h1>
<p class="text-xl pt-4">
{$t('index_page.features_description.1')}
<br />
{$t('index_page.features_description.2')}
<br />
{$t('index_page.features_description.3')}
</p>
</div>
</section>
<section class="py-8">
<h1 class="sm:text-6xl text-4xl text-center break-words">
{$t('words.screenshot', { count: 2 })}
</h1>
<div>
<LandingPromo />
</div>
</section>
<section>
<h1 class="sm:text-6xl text-4xl text-center">Testimonials</h1>
{#await import('$lib/landing/testimonials.svelte') then testimonials}
<svelte:component this={testimonials.default} />
{/await}
</section>
<section id="stats">
<div class="text-center pb-20 pt-10 snap-y">
<h1 class="sm:text-6xl text-4xl">{$t('words.stats')}</h1>
<p class="text-xl pt-4">
{#await getStats() then stats}
{$t('index_page.stats', {
user_count: stats.user_count,
quiz_count: stats.quiz_count
})}
{/await}
</p>
</div>
</section>
</div>-->
<div class="min-h-screen flex flex-col"> <div class="min-h-screen flex flex-col">
<section class="pb-40"> <section class="pb-40">
<div class="pt-12 text-center"> <div class="pt-12 text-center">
@@ -264,6 +190,8 @@ SPDX-License-Identifier: MPL-2.0
}} }}
class:shadow-2xl={selected_create_thing === SelectedCreateThing.Create} class:shadow-2xl={selected_create_thing === SelectedCreateThing.Create}
class:opacity-70={selected_create_thing !== SelectedCreateThing.Create} class:opacity-70={selected_create_thing !== SelectedCreateThing.Create}
role="button"
tabindex="0"
> >
<div <div
class="rounded-lg w-fit p-1 bg-lime-500 hover:bg-lime-400 transition shadow-lg" class="rounded-lg w-fit p-1 bg-lime-500 hover:bg-lime-400 transition shadow-lg"
@@ -295,6 +223,8 @@ SPDX-License-Identifier: MPL-2.0
onkeyup={() => { onkeyup={() => {
selected_create_thing = SelectedCreateThing.Find; selected_create_thing = SelectedCreateThing.Find;
}} }}
role="button"
tabindex="0"
class:shadow-2xl={selected_create_thing === SelectedCreateThing.Find} class:shadow-2xl={selected_create_thing === SelectedCreateThing.Find}
class:opacity-70={selected_create_thing !== SelectedCreateThing.Find} class:opacity-70={selected_create_thing !== SelectedCreateThing.Find}
> >
@@ -320,38 +250,6 @@ SPDX-License-Identifier: MPL-2.0
<h5 class="text-xl dark:text-black">{$t('words.find')}</h5> <h5 class="text-xl dark:text-black">{$t('words.find')}</h5>
<p class="dark:text-black">{$t('index_page.find_or_explore')}</p> <p class="dark:text-black">{$t('index_page.find_or_explore')}</p>
</div> </div>
<!--<div
class="m-2 rounded-lg p-2 bg-opacity-40 bg-white transition-all cursor-pointer lg:h-full"
onclick={() => {
selected_create_thing = SelectedCreateThing.Import;
}}
class:shadow-2xl={selected_create_thing === SelectedCreateThing.Import}
class:opacity-70={selected_create_thing !== SelectedCreateThing.Import}
>
<div
class="rounded-lg w-fit p-1 bg-lime-500 hover:bg-lime-400 transition shadow-lg"
>
<svg
class="w-8 h-8 text-black"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
aria-label="Cloud with arrow pointing down"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M9 19l3 3m0 0l3-3m-3 3V10"
/>
</svg>
</div>
<h5 class="text-xl dark:text-black">{$t('words.import')}</h5>
<p class="dark:text-black">
{$t('index_page.import_quiz_from_kahoot_and_edit')}
</p>
</div>-->
</div> </div>
</div> </div>
</section> </section>
@@ -405,11 +303,13 @@ SPDX-License-Identifier: MPL-2.0
onkeyup={() => { onkeyup={() => {
selected_play_thing = SelectedPlayThing.Select; selected_play_thing = SelectedPlayThing.Select;
}} }}
role="button"
tabindex="0"
class:shadow-2xl={selected_play_thing === SelectedPlayThing.Select} class:shadow-2xl={selected_play_thing === SelectedPlayThing.Select}
class:opacity-70={selected_play_thing !== SelectedPlayThing.Select} class:opacity-70={selected_play_thing !== SelectedPlayThing.Select}
> >
<div <div
class="rounded-lg bg-emerald-300 w-fit p-1 bg-lime-500 hover:bg-lime-400 transition shadow-lg" class="rounded-lg bg-emerald-300 w-fit p-1 hover:bg-lime-400 transition shadow-lg"
> >
<svg <svg
aria-label="Mouse-Click icon" aria-label="Mouse-Click icon"
@@ -432,6 +332,8 @@ SPDX-License-Identifier: MPL-2.0
</div> </div>
<div <div
class="m-2 rounded-lg p-2 bg-white/40 transition-all cursor-pointer lg:h-full" class="m-2 rounded-lg p-2 bg-white/40 transition-all cursor-pointer lg:h-full"
role="button"
tabindex="0"
onclick={() => { onclick={() => {
selected_play_thing = SelectedPlayThing.Results; selected_play_thing = SelectedPlayThing.Results;
}} }}
@@ -442,7 +344,7 @@ SPDX-License-Identifier: MPL-2.0
class:opacity-70={selected_play_thing !== SelectedPlayThing.Results} class:opacity-70={selected_play_thing !== SelectedPlayThing.Results}
> >
<div <div
class="rounded-lg bg-emerald-300 w-fit p-1 bg-lime-500 hover:bg-lime-400 transition shadow-lg" class="rounded-lg bg-emerald-300 w-fit p-1 hover:bg-lime-400 transition shadow-lg"
> >
<svg <svg
aria-label="context-menu icon" aria-label="context-menu icon"
@@ -465,6 +367,8 @@ SPDX-License-Identifier: MPL-2.0
</div> </div>
<div <div
class="m-2 rounded-lg p-2 bg-white/40 transition-all cursor-pointer lg:h-full" class="m-2 rounded-lg p-2 bg-white/40 transition-all cursor-pointer lg:h-full"
role="button"
tabindex="0"
onclick={() => { onclick={() => {
selected_play_thing = SelectedPlayThing.Winners; selected_play_thing = SelectedPlayThing.Winners;
}} }}
@@ -475,7 +379,7 @@ SPDX-License-Identifier: MPL-2.0
class:opacity-70={selected_play_thing !== SelectedPlayThing.Winners} class:opacity-70={selected_play_thing !== SelectedPlayThing.Winners}
> >
<div <div
class="rounded-lg bg-emerald-300 w-fit p-1 bg-lime-500 hover:bg-lime-400 transition shadow-lg" class="rounded-lg bg-emerald-300 w-fit p-1 hover:bg-lime-400 transition shadow-lg"
> >
<svg <svg
aria-label="sparkling stars-icon" aria-label="sparkling stars-icon"
@@ -523,6 +427,8 @@ SPDX-License-Identifier: MPL-2.0
{#each classquiz_reasons as reason, index} {#each classquiz_reasons as reason, index}
<div <div
class="m-2 rounded-lg p-2 bg-white/40 transition-all cursor-pointer lg:h-full" class="m-2 rounded-lg p-2 bg-white/40 transition-all cursor-pointer lg:h-full"
role="button"
tabindex="0"
onclick={() => { onclick={() => {
selected_classquiz_reason = index; selected_classquiz_reason = index;
}} }}
@@ -541,7 +447,7 @@ SPDX-License-Identifier: MPL-2.0
</div> </div>
{#if newsletterModalOpen} {#if newsletterModalOpen}
<div <div
class="fixed bottom-8 right-5 bg-white rounded-lg h-fit w-11/12 ml-5 lg:w-2/12 z-50 p-2 bg-white dark:bg-gray-700" class="fixed bottom-8 right-5 bg-white rounded-lg h-fit w-11/12 ml-5 lg:w-2/12 z-50 p-2 dark:bg-gray-700"
transition:fly|global transition:fly|global
> >
<Newsletter bind:open={newsletterModalOpen} /> <Newsletter bind:open={newsletterModalOpen} />
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run, preventDefault } from 'svelte/legacy';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import type { PageData } from './$types'; import type { PageData } from './$types';
@@ -20,14 +18,11 @@ SPDX-License-Identifier: MPL-2.0
name: '' name: ''
}); });
let isValid = $state(false); let isValid = $derived(input_data.name.length !== 0 && input_data.player_name.length !== 0);
let isSubmitting = false; let isSubmitting = false;
run(() => { const submit = async (e: Event) => {
isValid = input_data.name.length !== 0 && input_data.player_name.length !== 0; e.preventDefault();
});
const submit = async () => {
if (!isValid) { if (!isValid) {
return; return;
} }
@@ -59,7 +54,7 @@ SPDX-License-Identifier: MPL-2.0
Add a controller Add a controller
</h3> </h3>
<form onsubmit={preventDefault(submit)}> <form onsubmit={submit}>
<div class="w-full mt-4"> <div class="w-full mt-4">
<div class="dark:bg-gray-800 bg-white p-4 rounded-lg"> <div class="dark:bg-gray-800 bg-white p-4 rounded-lg">
<div class="relative bg-inherit w-full"> <div class="relative bg-inherit w-full">
+6 -11
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import { alertModal } from '$lib/stores'; import { alertModal } from '$lib/stores';
import { navbarVisible } from '$lib/stores.svelte'; import { navbarVisible } from '$lib/stores.svelte';
import { slide } from 'svelte/transition'; import { slide } from 'svelte/transition';
@@ -23,7 +21,7 @@ SPDX-License-Identifier: MPL-2.0
navbarVisible.visible = true; navbarVisible.visible = true;
let { data } = $props(); let { data } = $props();
const { verified }: boolean = data; const { verified: boolean } = data;
let session_data = $state({}); let session_data = $state({});
let step = $state(0); let step = $state(0);
@@ -38,7 +36,7 @@ SPDX-License-Identifier: MPL-2.0
} }
}; };
let alertModalOpen = false; let alertModalOpen = false;
run(() => { $effect(() => {
redirect_back(done); redirect_back(done);
}); });
@@ -51,8 +49,8 @@ SPDX-License-Identifier: MPL-2.0
} }
}); });
const check_auto = () => { const check_auto = (stp: number) => {
if (step === 1) { if (stp === 1) {
if (!browserSupportsWebAuthn()) { if (!browserSupportsWebAuthn()) {
for (let i = 0; i < session_data.step_1.length; i++) { for (let i = 0; i < session_data.step_1.length; i++) {
if (session_data.step_1[i] === 'PASSKEY') { if (session_data.step_1[i] === 'PASSKEY') {
@@ -65,7 +63,7 @@ SPDX-License-Identifier: MPL-2.0
selected_method = session_data.step_1[0]; selected_method = session_data.step_1[0];
} }
} }
if (step === 2) { if (stp === 2) {
if (!browserSupportsWebAuthn()) { if (!browserSupportsWebAuthn()) {
for (let i = 0; i < session_data.step_2.length; i++) { for (let i = 0; i < session_data.step_2.length; i++) {
if (session_data.step_2[i] === 'PASSKEY') { if (session_data.step_2[i] === 'PASSKEY') {
@@ -79,10 +77,7 @@ SPDX-License-Identifier: MPL-2.0
} }
} }
}; };
run(() => { $effect(() => check_auto(step));
check_auto();
step;
});
</script> </script>
<svelte:head> <svelte:head>
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run, preventDefault } from 'svelte/legacy';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
const { t } = getLocalization(); const { t } = getLocalization();
@@ -20,12 +18,10 @@ SPDX-License-Identifier: MPL-2.0
let backup_code = $state(''); let backup_code = $state('');
let isSubmitting = $state(false); let isSubmitting = $state(false);
let backup_code_valid = $state(false); let backup_code_valid = $derived(backup_code.length === 64);
run(() => {
backup_code_valid = backup_code.length === 64;
});
const continue_in_login = async () => { const continue_in_login = async (e: Event) => {
e.preventDefault();
if (!backup_code_valid) { if (!backup_code_valid) {
return; return;
} }
@@ -50,7 +46,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="px-6 py-4"> <div class="px-6 py-4">
<h2 class="text-3xl font-bold text-center text-gray-700 dark:text-white">ClassQuiz</h2> <h2 class="text-3xl font-bold text-center text-gray-700 dark:text-white">ClassQuiz</h2>
<form onsubmit={preventDefault(continue_in_login)}> <form onsubmit={continue_in_login}>
<div class="w-full mt-4"> <div class="w-full mt-4">
<div class="dark:bg-gray-800 bg-white p-4 rounded-lg"> <div class="dark:bg-gray-800 bg-white p-4 rounded-lg">
<div class="relative bg-inherit w-full"> <div class="relative bg-inherit w-full">
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { preventDefault } from 'svelte/legacy';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
let { let {
@@ -20,7 +18,8 @@ SPDX-License-Identifier: MPL-2.0
let isSubmitting; let isSubmitting;
let password = $state(); let password = $state();
const continue_in_login = async () => { const continue_in_login = async (e: Event) => {
e.preventDefault();
if (!password) { if (!password) {
return; return;
} }
@@ -60,7 +59,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="px-6 py-4"> <div class="px-6 py-4">
<h2 class="text-3xl font-bold text-center text-gray-700 dark:text-white">ClassQuiz</h2> <h2 class="text-3xl font-bold text-center text-gray-700 dark:text-white">ClassQuiz</h2>
<form onsubmit={preventDefault(continue_in_login)}> <form onsubmit={continue_in_login}>
<div class="w-full mt-4"> <div class="w-full mt-4">
<div class="dark:bg-gray-800 bg-white p-4 rounded-lg"> <div class="dark:bg-gray-800 bg-white p-4 rounded-lg">
<div class="relative bg-inherit w-full"> <div class="relative bg-inherit w-full">
@@ -4,8 +4,6 @@ SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
SPDX-License-Identifier: MPL-2.0 SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
let { session_data = {}, step, selected_method = $bindable() } = $props(); let { session_data = {}, step, selected_method = $bindable() } = $props();
let available_methods = $state(); let available_methods = $state();
@@ -18,7 +16,7 @@ SPDX-License-Identifier: MPL-2.0
} }
}; };
run(() => { $effect(() => {
set_available_methods(step); set_available_methods(step);
}); });
</script> </script>
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run, preventDefault } from 'svelte/legacy';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
import OAuthBlock from './oauth_block.svelte'; import OAuthBlock from './oauth_block.svelte';
@@ -14,14 +12,11 @@ SPDX-License-Identifier: MPL-2.0
const { t } = getLocalization(); const { t } = getLocalization();
let email = $state(''); let email = $state('');
let emailEmpty = $state(true); let emailEmpty = $derived(email === '');
let isSubmitting = $state(false); let isSubmitting = $state(false);
run(() => { const start_login = async (e: Event): Promise<void> => {
emailEmpty = email === ''; e.preventDefault();
});
const start_login = async (): Promise<void> => {
if (emailEmpty) { if (emailEmpty) {
return; return;
} }
@@ -50,7 +45,7 @@ SPDX-License-Identifier: MPL-2.0
{$t('login_page.login_or_create_account')} {$t('login_page.login_or_create_account')}
</p> </p>
<form onsubmit={preventDefault(start_login)}> <form onsubmit={start_login}>
<div class="w-full mt-4"> <div class="w-full mt-4">
<div class="dark:bg-gray-800 bg-white p-4 rounded-lg"> <div class="dark:bg-gray-800 bg-white p-4 rounded-lg">
<div class="relative bg-inherit w-full"> <div class="relative bg-inherit w-full">
@@ -5,13 +5,9 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run, preventDefault } from 'svelte/legacy';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
interface Props { interface Props {
// import { alertModal } from '$lib/stores';
session_data: any; session_data: any;
selected_method: any; selected_method: any;
done: any; done: any;
@@ -26,16 +22,13 @@ SPDX-License-Identifier: MPL-2.0
}: Props = $props(); }: Props = $props();
const { t } = getLocalization(); const { t } = getLocalization();
let isSubmitting; let isSubmitting: boolean;
let totp = $state(''); let totp = $state('');
let totp_valid = $state(false); let totp_valid = $derived(totp.length === 6);
run(() => { const continue_in_login = async (e: Event) => {
totp_valid = totp.length === 6; e.preventDefault();
});
const continue_in_login = async () => {
if (!totp_valid) { if (!totp_valid) {
return; return;
} }
@@ -84,7 +77,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="px-6 py-4"> <div class="px-6 py-4">
<h2 class="text-3xl font-bold text-center text-gray-700 dark:text-white">ClassQuiz</h2> <h2 class="text-3xl font-bold text-center text-gray-700 dark:text-white">ClassQuiz</h2>
<form onsubmit={preventDefault(continue_in_login)}> <form onsubmit={continue_in_login}>
<div class="w-full mt-4"> <div class="w-full mt-4">
<div class="dark:bg-gray-800 bg-white p-4 rounded-lg"> <div class="dark:bg-gray-800 bg-white p-4 rounded-lg">
<div class="relative bg-inherit w-full"> <div class="relative bg-inherit w-full">
@@ -5,13 +5,11 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run, preventDefault } from 'svelte/legacy';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
const { t } = getLocalization(); const { t } = getLocalization();
let { data } = $props(); let { data } = $props();
let { token }: string = data; let { token: string } = data;
let isSubmitting = $state(false); let isSubmitting = $state(false);
interface PasswordData { interface PasswordData {
password1: string; password1: string;
@@ -21,15 +19,12 @@ SPDX-License-Identifier: MPL-2.0
password1: '', password1: '',
password2: '' password2: ''
}); });
let passwordsValid = $state(false); let passwordsValid = $derived(
const checkIfPasswordsValid = (pwdata: PasswordData): void => { passwordData.password1 === passwordData.password2 && passwordData.password1.length >= 8
passwordsValid = pwdata.password1 === pwdata.password2 && pwdata.password1.length >= 8; );
};
run(() => {
checkIfPasswordsValid(passwordData);
});
const submit = async () => { const submit = async (e: Event) => {
e.preventDefault();
if (!passwordsValid) { if (!passwordsValid) {
return; return;
} }
@@ -77,7 +72,7 @@ SPDX-License-Identifier: MPL-2.0
{$t('password_reset_page.reset_password')} {$t('password_reset_page.reset_password')}
</p> </p>
<form onsubmit={preventDefault(submit)}> <form onsubmit={submit}>
<div class="w-full mt-4"> <div class="w-full mt-4">
<div class="dark:bg-gray-800 bg-white p-4 rounded-lg"> <div class="dark:bg-gray-800 bg-white p-4 rounded-lg">
<div class="relative bg-inherit w-full"> <div class="relative bg-inherit w-full">
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { preventDefault } from 'svelte/legacy';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
import { navbarVisible } from '$lib/stores.svelte.ts'; import { navbarVisible } from '$lib/stores.svelte.ts';
@@ -16,7 +14,8 @@ SPDX-License-Identifier: MPL-2.0
let isSubmitting = $state(false); let isSubmitting = $state(false);
const submit = async () => { const submit = async (e: Event) => {
e.preventDefault();
isSubmitting = true; isSubmitting = true;
const res = await fetch('/api/v1/users/forgot-password', { const res = await fetch('/api/v1/users/forgot-password', {
method: 'POST', method: 'POST',
@@ -62,7 +61,7 @@ SPDX-License-Identifier: MPL-2.0
{$t('password_reset_page.reset_password')} {$t('password_reset_page.reset_password')}
</p> </p>
<form onsubmit={preventDefault(submit)}> <form onsubmit={submit}>
<div class="w-full mt-4"> <div class="w-full mt-4">
<div class="dark:bg-gray-800 bg-white p-4 rounded-lg"> <div class="dark:bg-gray-800 bg-white p-4 rounded-lg">
<div class="relative bg-inherit w-full"> <div class="relative bg-inherit w-full">
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run, preventDefault } from 'svelte/legacy';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import { UAParser } from 'ua-parser-js'; import { UAParser } from 'ua-parser-js';
@@ -39,18 +37,15 @@ SPDX-License-Identifier: MPL-2.0
let locationData; let locationData;
let this_session = $state(); let this_session = $state();
let passwordChangeDataValid = $state(false); let passwordChangeDataValid = $derived(
const checkPasswords = (data: ChangePasswordData): void => { changePasswordData.newPassword === changePasswordData.newPasswordConfirm &&
passwordChangeDataValid = changePasswordData.newPassword.length >= 8 &&
data.newPassword === data.newPasswordConfirm && changePasswordData.oldPassword !== changePasswordData.newPassword &&
data.newPassword.length >= 8 && changePasswordData.oldPassword !== ''
data.oldPassword !== data.newPassword && );
data.oldPassword !== '';
}; const changePassword = async (e: Event) => {
run(() => { e.preventDefault();
checkPasswords(changePasswordData);
});
const changePassword = async () => {
if (!passwordChangeDataValid) { if (!passwordChangeDataValid) {
return; return;
} }
@@ -184,7 +179,7 @@ SPDX-License-Identifier: MPL-2.0
</div> </div>
</div> </div>
<div> <div>
<form class="flex flex-col md:flex-row" onsubmit={preventDefault(changePassword)}> <form class="flex flex-col md:flex-row" onsubmit={changePassword}>
<label <label
>{$t('settings_page.old_password')}:<input >{$t('settings_page.old_password')}:<input
type="password" type="password"
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import BrownButton from '$lib/components/buttons/brown.svelte'; import BrownButton from '$lib/components/buttons/brown.svelte';
import { fade, fly } from 'svelte/transition'; import { fade, fly } from 'svelte/transition';
import { bounceOut } from 'svelte/easing'; import { bounceOut } from 'svelte/easing';
@@ -71,10 +69,6 @@ SPDX-License-Identifier: MPL-2.0
let image_url = $derived(get_image_url(data)); let image_url = $derived(get_image_url(data));
run(() => {
console.log('index', index);
});
const save_avatar = async () => { const save_avatar = async () => {
save_finished = false; save_finished = false;
const res = await fetch(`/api/v1/avatar/save?${new URLSearchParams(data).toString()}`, { const res = await fetch(`/api/v1/avatar/save?${new URLSearchParams(data).toString()}`, {
+11 -17
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run, preventDefault } from 'svelte/legacy';
import type { QuizData } from '$lib/quiz_types'; import type { QuizData } from '$lib/quiz_types';
import { socket } from '$lib/socket'; import { socket } from '$lib/socket';
@@ -124,11 +122,12 @@ SPDX-License-Identifier: MPL-2.0
} }
}; };
const request_answer_export = async () => { const request_answer_export = (e: Event) => {
await socket.emit('get_export_token'); e.preventDefault();
socket.emit('get_export_token');
}; };
const save_quiz = async () => { const save_quiz = () => {
await socket.emit('save_quiz'); socket.emit('save_quiz');
}; };
let darkMode = false; let darkMode = false;
@@ -143,10 +142,7 @@ SPDX-License-Identifier: MPL-2.0
let bg_image = $derived(quiz_data ? quiz_data.background_image : undefined); let bg_image = $derived(quiz_data ? quiz_data.background_image : undefined);
let results_saved = $state(false); let results_saved = $state(false);
let show_final_results = $state(false); let show_final_results = $derived(JSON.stringify(final_results) !== JSON.stringify([null]));
run(() => {
show_final_results = JSON.stringify(final_results) !== JSON.stringify([null]);
});
</script> </script>
<svelte:window onbeforeunload={confirmUnload} /> <svelte:window onbeforeunload={confirmUnload} />
@@ -201,7 +197,7 @@ SPDX-License-Identifier: MPL-2.0
</div> </div>
</div> </div>
{/if} {/if}
<FinalResults bind:data={player_scores} bind:show_final_results /> <FinalResults bind:data={player_scores} {show_final_results} />
{/if} {/if}
{#if !success} {#if !success}
{#if errorMessage !== ''} {#if errorMessage !== ''}
@@ -217,18 +213,16 @@ SPDX-License-Identifier: MPL-2.0
{:else} {:else}
<SomeAdminScreen <SomeAdminScreen
bind:final_results bind:final_results
{game_pin} {game_token}
bind:game_token
bind:quiz_data bind:quiz_data
bind:game_mode {bg_color}
bind:bg_color
bind:player_scores bind:player_scores
bind:control_visible {control_visible}
/> />
{/if} {/if}
</div> </div>
<a <a
onclick={preventDefault(request_answer_export)} onclick={request_answer_export}
href="#" href="#"
target="_blank" target="_blank"
bind:this={dataexport_download_a} bind:this={dataexport_download_a}
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import DownloadQuiz from '$lib/components/DownloadQuiz.svelte'; import DownloadQuiz from '$lib/components/DownloadQuiz.svelte';
import type { QuizData } from '$lib/quiz_types'; import type { QuizData } from '$lib/quiz_types';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
@@ -50,23 +48,6 @@ SPDX-License-Identifier: MPL-2.0
let id_to_position_map = {}; let id_to_position_map = {};
const getData = async (): Promise<{ items: Array<QuizData>; fuse: Fuse<any> }> => { const getData = async (): Promise<{ items: Array<QuizData>; fuse: Fuse<any> }> => {
/* items_to_show = [];
for (let i = 0; i < data.quizzes.length; i++) {
items_to_show.push({ ...data.quizzes[i], type: 'quiz' });
}
for (let i = 0; i < data.quiztivities.length; i++) {
items_to_show.push({ ...data.quiztivities[i], type: 'quiztivity' });
}
fuse = new Fuse(items_to_show, {
keys: ['title', 'description', 'questions.title'],
findAllMatches: true
});
all_items = items_to_show;
for (let i = 0; i < all_items.length; i++) {
id_to_position_map[all_items[i].id] = i;
}
return all_items;
*/
const items: any[] = []; const items: any[] = [];
for (const q of data.quizzes) items.push({ ...q, type: 'quiz' }); for (const q of data.quizzes) items.push({ ...q, type: 'quiz' });
+3 -4
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { preventDefault } from 'svelte/legacy';
import type { PageData } from './$types'; import type { PageData } from './$types';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
// import MediaComponent from '$lib/editor/MediaComponent.svelte'; // import MediaComponent from '$lib/editor/MediaComponent.svelte';
@@ -37,7 +35,8 @@ SPDX-License-Identifier: MPL-2.0
}; };
}); });
const save_image_metadata = async () => { const save_image_metadata = async (e: Event) => {
e.preventDefault();
await fetch(`/api/v1/storage/meta/${edit_popup.id}`, { await fetch(`/api/v1/storage/meta/${edit_popup.id}`, {
method: 'PUT', method: 'PUT',
headers: { headers: {
@@ -131,7 +130,7 @@ SPDX-License-Identifier: MPL-2.0
> >
<div class="w-auto h-auto m-auto rounded-sm bg-white dark:bg-gray-700 p-4"> <div class="w-auto h-auto m-auto rounded-sm bg-white dark:bg-gray-700 p-4">
<h1 class="text-2xl text-center">{$t('file_dashboard.edit_the_image')}</h1> <h1 class="text-2xl text-center">{$t('file_dashboard.edit_the_image')}</h1>
<form class="flex flex-col" onsubmit={preventDefault(save_image_metadata)}> <form class="flex flex-col" onsubmit={save_image_metadata}>
<div class="flex flex-row"> <div class="flex flex-row">
<div class="flex flex-col mr-4"> <div class="flex flex-col mr-4">
<label for="name" class="m-auto">{$t('file_dashboard.filename_word')}</label <label for="name" class="m-auto">{$t('file_dashboard.filename_word')}</label
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import Spinner from '$lib/Spinner.svelte'; import Spinner from '$lib/Spinner.svelte';
let uppyOpen = $state(false); let uppyOpen = $state(false);
@@ -14,7 +12,7 @@ SPDX-License-Identifier: MPL-2.0
let selected_question = $state(undefined); let selected_question = $state(undefined);
let data = $state({ cover_image: undefined }); let data = $state({ cover_image: undefined });
run(() => { $effect(() => {
if (data.cover_image) { if (data.cover_image) {
window.location.reload(); window.location.reload();
} }
+8 -33
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run, preventDefault } from 'svelte/legacy';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
import { navbarVisible } from '$lib/stores.svelte.ts'; import { navbarVisible } from '$lib/stores.svelte.ts';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
@@ -17,16 +15,13 @@ SPDX-License-Identifier: MPL-2.0
const { t } = getLocalization(); const { t } = getLocalization();
let url_input = $state(''); let url_input = $state('');
let file_input: File[] = $state(); let file_input: File[] = $state();
let url_valid = $state(false);
let kahoot_regex = /^https:\/\/create\.kahoot\.it\/details\/([a-zA-Z-\d]{36})\/?$/; let kahoot_regex = /^https:\/\/create\.kahoot\.it\/details\/([a-zA-Z-\d]{36})\/?$/;
let url_valid = $derived(kahoot_regex.test(url_input));
let is_loading = $state(false); let is_loading = $state(false);
run(() => { const submit = async (e: Event) => {
url_valid = kahoot_regex.test(url_input); e.preventDefault();
});
const submit = async () => {
if (!url_valid) { if (!url_valid) {
return; return;
} }
@@ -61,7 +56,8 @@ SPDX-License-Identifier: MPL-2.0
is_loading = false; is_loading = false;
}; };
const file_submit = async () => { const file_submit = async (e: Event) => {
e.preventDefault();
is_loading = true; is_loading = true;
const formdata = new FormData(); const formdata = new FormData();
formdata.append('file', file_input[0]); formdata.append('file', file_input[0]);
@@ -95,10 +91,6 @@ SPDX-License-Identifier: MPL-2.0
is_loading = false; is_loading = false;
}; };
run(() => {
console.log(file_input);
});
onMount(() => { onMount(() => {
let url_from_path = page.url.searchParams.get('url'); let url_from_path = page.url.searchParams.get('url');
if (url_from_path === '') { if (url_from_path === '') {
@@ -112,23 +104,6 @@ SPDX-License-Identifier: MPL-2.0
<title>ClassQuiz - Import</title> <title>ClassQuiz - Import</title>
</svelte:head> </svelte:head>
<!--{#if is_loading}
<svg class='h-8 w-8 animate-spin mx-auto my-20' viewBox='3 3 18 18'>
<path
class='fill-black'
d='M12 5C8.13401 5 5 8.13401 5 12C5 15.866 8.13401 19 12 19C15.866 19 19 15.866 19 12C19 8.13401 15.866 5 12 5ZM3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12Z'
/>
<path
class='fill-blue-100'
d='M16.9497 7.05015C14.2161 4.31648 9.78392 4.31648 7.05025 7.05015C6.65973 7.44067 6.02656 7.44067 5.63604 7.05015C5.24551 6.65962 5.24551 6.02646 5.63604 5.63593C9.15076 2.12121 14.8492 2.12121 18.364 5.63593C18.7545 6.02646 18.7545 6.65962 18.364 7.05015C17.9734 7.44067 17.3403 7.44067 16.9497 7.05015Z'
/>
</svg>
{:else}-->
<!-- <form on:submit|preventDefault={submit}>
<input type='text' class="text-black w-2/5" bind:value={url_input} />
<button type='submit' disabled={!url_valid}>Submit</button>
</form>-->
<div class="flex items-center justify-center h-full px-4"> <div class="flex items-center justify-center h-full px-4">
<div> <div>
<span class="p-4"></span> <span class="p-4"></span>
@@ -149,7 +124,7 @@ SPDX-License-Identifier: MPL-2.0
Login or create account Login or create account
</p>--> </p>-->
<div class="grid grid-cols-2"> <div class="grid grid-cols-2">
<form onsubmit={preventDefault(submit)}> <form onsubmit={submit}>
<div class="w-full mt-4 h-full flex flex-col"> <div class="w-full mt-4 h-full flex flex-col">
<h2 class="text-center text-2xl">{$t('import_page.a_kahoot_quiz')}</h2> <h2 class="text-center text-2xl">{$t('import_page.a_kahoot_quiz')}</h2>
<div class="dark:bg-gray-800 bg-white p-4 rounded-lg"> <div class="dark:bg-gray-800 bg-white p-4 rounded-lg">
@@ -208,7 +183,7 @@ SPDX-License-Identifier: MPL-2.0
</div> </div>
</div> </div>
</form> </form>
<form onsubmit={preventDefault(file_submit)}> <form onsubmit={file_submit}>
<div class="w-full mt-4 border-l-2 border-gray-600 h-full flex flex-col"> <div class="w-full mt-4 border-l-2 border-gray-600 h-full flex flex-col">
<h2 class="text-center text-2xl">{$t('import_page.classquiz_quiz')}</h2> <h2 class="text-center text-2xl">{$t('import_page.classquiz_quiz')}</h2>
<div class="dark:bg-gray-800 bg-white p-4 rounded-lg"> <div class="dark:bg-gray-800 bg-white p-4 rounded-lg">
+10 -27
View File
@@ -11,8 +11,7 @@ SPDX-License-Identifier: MPL-2.0
import type { Answer, Question as QuestionType } from '$lib/quiz_types'; import type { Answer, Question as QuestionType } from '$lib/quiz_types';
import ShowTitle from '$lib/play/title.svelte'; import ShowTitle from '$lib/play/title.svelte';
import Question from '$lib/play/question.svelte'; import Question from '$lib/play/question.svelte';
// import ShowResults from '$lib/play/show_results.svelte'; import { navbarVisible } from '$lib/stores.svelte.ts';
import { navbarVisible} from '$lib/stores.svelte.ts';
import ShowEndScreen from '$lib/play/admin/final_results.svelte'; import ShowEndScreen from '$lib/play/admin/final_results.svelte';
import KahootResults from '$lib/play/results_kahoot.svelte'; import KahootResults from '$lib/play/results_kahoot.svelte';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
@@ -44,8 +43,7 @@ SPDX-License-Identifier: MPL-2.0
// Variables init // Variables init
let question_index = $state(''); let question_index = $state('');
let unique = $state({}); let unique = $state({});
navbarVisible.visible=false; navbarVisible.visible = false;
let game_pin_valid: boolean;
let answer_results: Array<Answer> = $state(); let answer_results: Array<Answer> = $state();
let gameData = $state(); let gameData = $state();
let solution: QuestionType = $state(); let solution: QuestionType = $state();
@@ -55,7 +53,7 @@ SPDX-License-Identifier: MPL-2.0
started: false started: false
}); });
let question = $state(); let question: Question = $state();
let preventReload = true; let preventReload = true;
@@ -64,7 +62,7 @@ SPDX-License-Identifier: MPL-2.0
unique = {}; unique = {};
} }
const confirmUnload = () => { const confirmUnload = (event: Event) => {
if (preventReload) { if (preventReload) {
event.preventDefault(); event.preventDefault();
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -76,9 +74,6 @@ SPDX-License-Identifier: MPL-2.0
socket.on('time_sync', (data) => { socket.on('time_sync', (data) => {
socket.emit('echo_time_sync', data); socket.emit('echo_time_sync', data);
}); });
socket.on('session_id', (d) => {
const session_id = d.session_id;
});
socket.on('connect', async () => { socket.on('connect', async () => {
console.log('Connected!'); console.log('Connected!');
@@ -120,7 +115,6 @@ SPDX-License-Identifier: MPL-2.0
window.location.reload(); window.location.reload();
return; return;
} }
game_pin_valid = false;
}); });
socket.on('set_question_number', (data) => { socket.on('set_question_number', (data) => {
@@ -169,13 +163,6 @@ SPDX-License-Identifier: MPL-2.0
<svelte:window onbeforeunload={confirmUnload} /> <svelte:window onbeforeunload={confirmUnload} />
<svelte:head> <svelte:head>
<title>ClassQuiz - Play</title> <title>ClassQuiz - Play</title>
<!-- {#if gameData !== undefined && game_mode !== 'kahoot'}
{#each gameData.questions as question}
{#if question.image !== undefined}
<link rel="preload" as="image" href={question.image} />
{/if}
{/each}
{/if}-->
</svelte:head> </svelte:head>
<div <div
class="min-h-screen min-w-full" class="min-h-screen min-w-full"
@@ -186,17 +173,17 @@ SPDX-License-Identifier: MPL-2.0
{#if !gameMeta.started && gameData === undefined} {#if !gameMeta.started && gameData === undefined}
<JoinGame bind:game_pin bind:game_mode bind:username /> <JoinGame bind:game_pin bind:game_mode bind:username />
{:else if JSON.stringify(final_results) !== JSON.stringify([null])} {:else if JSON.stringify(final_results) !== JSON.stringify([null])}
<ShowEndScreen bind:data={scores} show_final_results={true} bind:username /> <ShowEndScreen bind:data={scores} show_final_results={true} {username} />
{:else if gameData !== undefined && question_index === ''} {:else if gameData !== undefined && question_index === ''}
<ShowTitle <ShowTitle
bind:title={gameData.title} title={gameData.title}
bind:description={gameData.description} description={gameData.description}
bind:cover_image={gameData.cover_image} cover_image={gameData.cover_image}
/> />
{:else if gameMeta.started && gameData !== undefined && question_index !== '' && answer_results === undefined} {:else if gameMeta.started && gameData !== undefined && question_index !== '' && answer_results === undefined}
{#key unique} {#key unique}
<div class="text-black dark:text-black"> <div class="text-black dark:text-black">
<Question bind:game_mode bind:question bind:question_index bind:solution /> <Question bind:game_mode bind:question {question_index} {solution} />
</div> </div>
{/key} {/key}
{:else if gameMeta.started && answer_results !== undefined} {:else if gameMeta.started && answer_results !== undefined}
@@ -209,11 +196,7 @@ SPDX-License-Identifier: MPL-2.0
<h2 class="text-center text-3xl mb-8">{$t('words.result', { count: 2 })}</h2> <h2 class="text-center text-3xl mb-8">{$t('words.result', { count: 2 })}</h2>
</div> </div>
{#key unique} {#key unique}
<KahootResults <KahootResults {username} question_results={answer_results} bind:scores />
bind:username
bind:question_results={answer_results}
bind:scores
/>
{/key} {/key}
{/if} {/if}
{/if} {/if}
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import type { PageData } from './$types'; import type { PageData } from './$types';
import type { QuizTivityPage } from '$lib/quiztivity/types'; import type { QuizTivityPage } from '$lib/quiztivity/types';
import { QuizTivityTypes } from '$lib/quiztivity/types'; import { QuizTivityTypes } from '$lib/quiztivity/types';
@@ -25,10 +23,7 @@ SPDX-License-Identifier: MPL-2.0
} }
let current_slide_index = $state(0); let current_slide_index = $state(0);
let current_slide: QuizTivityPage = $state(quiztivity.pages[current_slide_index]); let current_slide: QuizTivityPage = $derived(quiztivity.pages[current_slide_index]);
run(() => {
current_slide = quiztivity.pages[current_slide_index];
});
</script> </script>
<div class="w-full h-full flex flex-col overflow-scroll"> <div class="w-full h-full flex flex-col overflow-scroll">
+16 -21
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { run, preventDefault } from 'svelte/legacy';
import { page } from '$app/state'; import { page } from '$app/state';
import { socket } from '$lib/socket'; import { socket } from '$lib/socket';
import type { QuizData } from '$lib/quiz_types'; import type { QuizData } from '$lib/quiz_types';
@@ -24,19 +22,19 @@ SPDX-License-Identifier: MPL-2.0
navbarVisible.visible = false; navbarVisible.visible = false;
const { t } = getLocalization(); const { t } = getLocalization();
let timer_interval; let timer_interval: NodeJS.Timeout;
let timer_res = $state(undefined); let timer_res = $state(undefined);
let selected_question = $state(-1); let selected_question = $state(-1);
let game_started = $state(false); let game_started = $state(false);
let question_results = $state(); let question_results = $state();
let final_results = $state([null]); let final_results = $state([null]);
let warnToLeave = true; let warnToLeave = true;
let dataexport_download_a = $state(); let dataexport_download_a: HTMLAnchorElement = $state();
let players: Array<{ sid: string; username: string }> = $state([]); let players: Array<{ sid: string; username: string }> = $state([]);
let game_data: QuizData = $state(); let game_data: QuizData = $state();
let shown_question_now; let shown_question_now: number;
let control_visible = $state(false); let control_visible = $state(false);
if (!data.game_id || !data.game_pin) { if (!data.game_id || !data.game_pin) {
@@ -90,12 +88,12 @@ SPDX-License-Identifier: MPL-2.0
socket.emit('get_final_results', {}); socket.emit('get_final_results', {});
}; };
const request_answer_export = async () => { const request_answer_export = async (e: Event) => {
await socket.emit('get_export_token'); e.preventDefault();
socket.emit('get_export_token');
}; };
const get_already_joined_players = async () => { const get_already_joined_players = async () => {
console.log('GETTING PLAYERS');
const res = await fetch( const res = await fetch(
`/api/v1/live/players?game_pin=${data.game_pin}&game_id=${data.game_id}` `/api/v1/live/players?game_pin=${data.game_pin}&game_id=${data.game_id}`
); );
@@ -103,15 +101,16 @@ SPDX-License-Identifier: MPL-2.0
players = await res.json(); players = await res.json();
} }
}; };
let circular_progress = $derived.by(() => {
let circular_progress = $state(0);
run(() => {
try { try {
circular_progress = return (
1 - 1 -
((100 / game_data.questions[selected_question].time) * parseInt(timer_res)) / 100; ((100 / parseInt(game_data.questions[selected_question].time)) *
parseInt(timer_res)) /
100
);
} catch { } catch {
circular_progress = 0; return 0;
} }
}); });
@@ -235,7 +234,7 @@ SPDX-License-Identifier: MPL-2.0
{#await import('$lib/play/admin/slide.svelte')} {#await import('$lib/play/admin/slide.svelte')}
<Spinner my_20={false} /> <Spinner my_20={false} />
{:then c} {:then c}
<c.default bind:question={game_data.questions[selected_question]} /> <c.default question={game_data.questions[selected_question]} />
{/await} {/await}
{:else} {:else}
<div class="flex flex-col justify-center w-screen h-1/6"> <div class="flex flex-col justify-center w-screen h-1/6">
@@ -244,11 +243,7 @@ SPDX-License-Identifier: MPL-2.0
</h1> </h1>
<!-- <span class='text-center py-2 text-lg'>{$t('admin_page.time_left')}: {timer_res}</span>--> <!-- <span class='text-center py-2 text-lg'>{$t('admin_page.time_left')}: {timer_res}</span>-->
<div class="mx-auto my-2"> <div class="mx-auto my-2">
<CircularTimer <CircularTimer text={timer_res} progress={circular_progress} color="#ef4444" />
bind:text={timer_res}
bind:progress={circular_progress}
color="#ef4444"
/>
</div> </div>
{#if game_data.questions[selected_question].image !== null} {#if game_data.questions[selected_question].image !== null}
<div> <div>
@@ -328,7 +323,7 @@ SPDX-License-Identifier: MPL-2.0
</div> </div>
<a <a
onclick={preventDefault(request_answer_export)} onclick={request_answer_export}
href="#" href="#"
bind:this={dataexport_download_a} bind:this={dataexport_download_a}
class="absolute -top-3/4 -left-3/4 opacity-0 hidden">Download</a class="absolute -top-3/4 -left-3/4 opacity-0 hidden">Download</a
+2 -2
View File
@@ -2,9 +2,9 @@
// //
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
// import type { PageLoad } from './$types'; import type { PageLoad } from './$types';
export const load = async ({ fetch }) => { export const load: PageLoad = async ({ fetch }) => {
const res = await fetch('/api/v1/results/list?include_quiz=true'); const res = await fetch('/api/v1/results/list?include_quiz=true');
let json; let json;
if (res.ok) { if (res.ok) {
@@ -79,8 +79,6 @@ SPDX-License-Identifier: MPL-2.0
{#if selected_tab === SelectedTab.Overview} {#if selected_tab === SelectedTab.Overview}
<div in:fade|global={{ duration: 150 }}> <div in:fade|global={{ duration: 150 }}>
<GeneralOverview <GeneralOverview
questions={data.results.questions}
answers={data.results.answers}
scores={data.results.player_scores} scores={data.results.player_scores}
title={data.results.title} title={data.results.title}
timestamp={data.results.timestamp} timestamp={data.results.timestamp}
@@ -1,10 +1,9 @@
// SPDX-FileCopyrightText: 2023 Marlon W (Mawoka) // SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
// //
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
import type { PageLoad } from './$types';
// import type { PageLoad } from './$types'; export const load: PageLoad = async ({ params, fetch }) => {
export const load = async ({ params, fetch }) => {
const res = await fetch(`/api/v1/results/${params.result_id}?include_quiz=true`); const res = await fetch(`/api/v1/results/${params.result_id}?include_quiz=true`);
let json; let json;
if (res.ok) { if (res.ok) {
@@ -15,4 +14,4 @@ export const load = async ({ params, fetch }) => {
return { return {
results: json results: json
}; };
}; //satisfies PageLoad; };
@@ -11,14 +11,6 @@ SPDX-License-Identifier: MPL-2.0
const { t } = getLocalization(); const { t } = getLocalization();
interface Props { interface Props {
questions: Question[];
answers: {
username: string;
answer: string;
right: boolean;
tike_taken: number;
score: number;
}[][];
scores: { scores: {
[key: string]: string; [key: string]: string;
}; };
@@ -26,7 +18,7 @@ SPDX-License-Identifier: MPL-2.0
timestamp: string; timestamp: string;
} }
let { questions, answers, scores, title, timestamp }: Props = $props(); let { scores, title, timestamp }: Props = $props();
const usernames = Object.keys(scores); const usernames = Object.keys(scores);
@@ -33,7 +33,6 @@ SPDX-License-Identifier: MPL-2.0
} }
}); });
}); });
console.log(custom_field);
</script> </script>
<div class="w-full"> <div class="w-full">
@@ -7,7 +7,7 @@ SPDX-License-Identifier: MPL-2.0
<script lang="ts"> <script lang="ts">
import type { Question } from '$lib/quiz_types'; import type { Question } from '$lib/quiz_types';
import { fly } from 'svelte/transition'; import { fly } from 'svelte/transition';
import QuestionTab from './question_tab_thing.svelte'; import QuestionTab from './question_tab_dropdown.svelte';
import { QuizQuestionType } from '$lib/quiz_types'; import { QuizQuestionType } from '$lib/quiz_types';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
@@ -57,7 +57,7 @@ SPDX-License-Identifier: MPL-2.0
</script> </script>
<div class="w-full flex justify-center"> <div class="w-full flex justify-center">
<div class="w-11/12 flex flex-col w-full gap-4"> <div class="flex flex-col w-full gap-4">
{#each questions as question, i} {#each questions as question, i}
<div class="transition-all"> <div class="transition-all">
<div <div
@@ -11,7 +11,6 @@ SPDX-License-Identifier: MPL-2.0
const { t } = getLocalization(); const { t } = getLocalization();
interface Answer { interface Answer {
username: string; username: string;
answer: string; answer: string;
@@ -26,7 +25,6 @@ SPDX-License-Identifier: MPL-2.0
} }
let { question, answers }: Props = $props(); let { question, answers }: Props = $props();
// console.log(question);
const get_answer_count_for_answer = (answer: string): number => { const get_answer_count_for_answer = (answer: string): number => {
let count = 0; let count = 0;
+5 -3
View File
@@ -4,8 +4,6 @@ SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
SPDX-License-Identifier: MPL-2.0 SPDX-License-Identifier: MPL-2.0
--> -->
<script lang="ts"> <script lang="ts">
import { preventDefault } from 'svelte/legacy';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
const { t } = getLocalization(); const { t } = getLocalization();
import SearchCard from '$lib/search-card.svelte'; import SearchCard from '$lib/search-card.svelte';
@@ -52,7 +50,10 @@ SPDX-License-Identifier: MPL-2.0
<div class="mb-3 xl:w-96"> <div class="mb-3 xl:w-96">
<form <form
class="input-group relative flex items-stretch flex-row w-full mb-4" class="input-group relative flex items-stretch flex-row w-full mb-4"
onsubmit={preventDefault(submit)} onsubmit={(e: Event) => {
e.preventDefault();
submit();
}}
> >
<input <input
type="search" type="search"
@@ -65,6 +66,7 @@ SPDX-License-Identifier: MPL-2.0
<button <button
class="px-6 py-2.5 bg-blue-600 text-white font-medium text-xs leading-tight uppercase rounded-sm shadow-md hover:bg-blue-700 hover:shadow-lg focus:bg-blue-700 focus:shadow-lg focus:outline-hidden focus:ring-0 active:bg-blue-800 active:shadow-lg transition duration-150 ease-in-out flex items-center disabled:opacity-50 disabled:cursor-not-allowed" class="px-6 py-2.5 bg-blue-600 text-white font-medium text-xs leading-tight uppercase rounded-sm shadow-md hover:bg-blue-700 hover:shadow-lg focus:bg-blue-700 focus:shadow-lg focus:outline-hidden focus:ring-0 active:bg-blue-800 active:shadow-lg transition duration-150 ease-in-out flex items-center disabled:opacity-50 disabled:cursor-not-allowed"
id="button-addon2" id="button-addon2"
aria-label="Search"
disabled={search_term.length <= 2} disabled={search_term.length <= 2}
type="submit" type="submit"
> >
@@ -13,7 +13,6 @@ SPDX-License-Identifier: MPL-2.0
import StartGamePopup from '$lib/dashboard/start_game.svelte'; import StartGamePopup from '$lib/dashboard/start_game.svelte';
const { t } = getLocalization(); const { t } = getLocalization();
// import { DateTime } from 'luxon';
let start_game = $state(null); let start_game = $state(null);
const tippy = createTippy({ const tippy = createTippy({
@@ -71,12 +70,6 @@ SPDX-License-Identifier: MPL-2.0
class="rounded-lg border-2 border-black hover:outline transition-all outline-[#B07156] -outline-offset-2 outline-8" class="rounded-lg border-2 border-black hover:outline transition-all outline-[#B07156] -outline-offset-2 outline-8"
> >
<div class="grid grid-cols-6 h-[25vh]"> <div class="grid grid-cols-6 h-[25vh]">
<!-- <p
style='writing-mode: vertical-lr'
class='text-center h-full text-xl p-2'
>
{@html quiz.title}
</p>-->
<div class="col-start-2 col-end-6"> <div class="col-start-2 col-end-6">
<h3 class="text-center text-2xl">{@html quiz.title}</h3> <h3 class="text-center text-2xl">{@html quiz.title}</h3>
<p class="text-center"> <p class="text-center">
@@ -95,15 +88,6 @@ SPDX-License-Identifier: MPL-2.0
</div> </div>
{/if} {/if}
</div> </div>
<!-- <div class='flex justify-end'>
<p
style='writing-mode: sideways-lr'
class='text-center text-xl p-2'
>
{@html quiz.title}
</p>
</div>-->
</div> </div>
<div class="flex justify-center"> <div class="flex justify-center">
<a href="/view/{quiz.id}" class="action-button w-1/6" <a href="/view/{quiz.id}" class="action-button w-1/6"
@@ -166,6 +150,7 @@ SPDX-License-Identifier: MPL-2.0
> >
<button <button
disabled disabled
aria-label="Download"
class="action-button w-full flex justify-center" class="action-button w-full flex justify-center"
> >
<svg <svg
+3 -3
View File
@@ -2,9 +2,9 @@
// //
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
// import type { PageLoad } from './$types'; import type { PageLoad } from './$types';
export const load = async ({ params, fetch }) => { export const load: PageLoad = async ({ params, fetch }) => {
const user_req = await fetch(`/api/v1/community/user/${params.user_id}`); const user_req = await fetch(`/api/v1/community/user/${params.user_id}`);
const user = await user_req.json(); const user = await user_req.json();
if (!user) { if (!user) {
@@ -24,4 +24,4 @@ export const load = async ({ params, fetch }) => {
user, user,
quizzes quizzes
}; };
}; // satisfies PageLoad; };
@@ -3,8 +3,9 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
import { error } from '@sveltejs/kit'; import { error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load = async ({ params, parent }) => { export const load: PageServerLoad = async ({ params, parent }) => {
const { quiz_id } = params; const { quiz_id } = params;
const res = await fetch(`${process.env.API_URL}/api/v1/quiz/get/public/${quiz_id}`); const res = await fetch(`${process.env.API_URL}/api/v1/quiz/get/public/${quiz_id}`);
const { email } = await parent(); const { email } = await parent();
@@ -245,10 +245,6 @@ SPDX-License-Identifier: MPL-2.0
<h3 class="text-3xl m-1 text-center"> <h3 class="text-3xl m-1 text-center">
{index_question + 1}: {@html question.question} {index_question + 1}: {@html question.question}
</h3> </h3>
<!-- <label class='m-1 flex flex-row gap-2 w-3/5'>-->
<!-- </label>-->
{#if question.image} {#if question.image}
<span> <span>
<MediaComponent <MediaComponent
@@ -316,7 +312,7 @@ SPDX-License-Identifier: MPL-2.0
</ul> </ul>
{:else if question.type === QuizQuestionType.VOTING || question.type === QuizQuestionType.TEXT} {:else if question.type === QuizQuestionType.VOTING || question.type === QuizQuestionType.TEXT}
<div class="grid grid-cols-2 gap-4 m-4 p-6"> <div class="grid grid-cols-2 gap-4 m-4 p-6">
{#each question.answers as answer, index_answer} {#each question.answers as _, index_answer}
<div class="p-1 rounded-lg py-4 dark:bg-gray-500 bg-gray-300"> <div class="p-1 rounded-lg py-4 dark:bg-gray-500 bg-gray-300">
<h4 class="text-center"> <h4 class="text-center">
{quiz.questions[index_question].answers[index_answer] {quiz.questions[index_question].answers[index_answer]
@@ -327,10 +323,10 @@ SPDX-License-Identifier: MPL-2.0
</div> </div>
{:else if question.type === QuizQuestionType.SLIDE} {:else if question.type === QuizQuestionType.SLIDE}
{#await import('$lib/play/admin/slide.svelte')} {#await import('$lib/play/admin/slide.svelte')}
<Spinner my={false} /> <Spinner my_20={false} />
{:then c} {:then c}
<div class="max-h-[90%] max-w-[90%]"> <div class="max-h-[90%] max-w-[90%]">
<c.default bind:question={questions[index_question]} /> <c.default question={quiz.questions[index_question]} />
</div> </div>
{/await} {/await}
{/if} {/if}