Bug fixes and correct answer count in results
This commit is contained in:
@@ -216,7 +216,7 @@ async def register_as_admin(sid: str, data: dict):
|
|||||||
if await redis.get(f"game_session:{game_pin}") is not None:
|
if await redis.get(f"game_session:{game_pin}") is not None:
|
||||||
await sio.emit("already_registered_as_admin", room=sid)
|
await sio.emit("already_registered_as_admin", room=sid)
|
||||||
return
|
return
|
||||||
GameSession(admin=sid, game_id=game_id, answers=[]).save(game_pin)
|
await GameSession(admin=sid, game_id=game_id, answers=[]).save(game_pin)
|
||||||
await sio.emit(
|
await sio.emit(
|
||||||
"registered_as_admin",
|
"registered_as_admin",
|
||||||
{"game_id": game_id, "game": await redis.get(f"game:{game_pin}")},
|
{"game_id": game_id, "game": await redis.get(f"game:{game_pin}")},
|
||||||
@@ -251,7 +251,7 @@ async def set_question_number(sid: str, data: str):
|
|||||||
game_data = await PlayGame.get_from_redis(session["game_pin"])
|
game_data = await PlayGame.get_from_redis(session["game_pin"])
|
||||||
game_data.current_question = int(float(data))
|
game_data.current_question = int(float(data))
|
||||||
game_data.question_show = True
|
game_data.question_show = True
|
||||||
game_data.save(session["game_pin"])
|
await game_data.save(session["game_pin"])
|
||||||
await redis.set(f"game:{session['game_pin']}:current_time", datetime.now().isoformat(), ex=7200)
|
await redis.set(f"game:{session['game_pin']}:current_time", datetime.now().isoformat(), ex=7200)
|
||||||
temp_return = game_data.model_dump(include={"questions"})["questions"][int(float(data))]
|
temp_return = game_data.model_dump(include={"questions"})["questions"][int(float(data))]
|
||||||
if game_data.questions[int(float(data))].type == QuizQuestionType.SLIDE:
|
if game_data.questions[int(float(data))].type == QuizQuestionType.SLIDE:
|
||||||
@@ -296,7 +296,7 @@ async def submit_answer(sid: str, data: dict):
|
|||||||
if already_answered:
|
if already_answered:
|
||||||
await sio.emit("already_replied", room=sid)
|
await sio.emit("already_replied", room=sid)
|
||||||
return
|
return
|
||||||
(answer_right, answer) = check_answer(game_data, data)
|
answer_right, answer = check_answer(game_data, data)
|
||||||
latency = int(float(session["ping"]))
|
latency = int(float(session["ping"]))
|
||||||
time_q_started = datetime.fromisoformat(await redis.get(f"game:{session['game_pin']}:current_time"))
|
time_q_started = datetime.fromisoformat(await redis.get(f"game:{session['game_pin']}:current_time"))
|
||||||
diff = (time_q_started - now).total_seconds() * 1000 # - timedelta(milliseconds=latency)
|
diff = (time_q_started - now).total_seconds() * 1000 # - timedelta(milliseconds=latency)
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ async def check_captcha(captcha_data: str) -> bool:
|
|||||||
) as resp:
|
) as resp:
|
||||||
resp_data = await resp.model_dump_json()
|
resp_data = await resp.model_dump_json()
|
||||||
if not resp_data["success"]:
|
if not resp_data["success"]:
|
||||||
print("CAPTCHA FAILED")
|
|
||||||
return
|
return
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return False
|
return False
|
||||||
@@ -60,7 +59,7 @@ def check_answer(game_data: PlayGame, data: SubmitAnswerData) -> (bool, str):
|
|||||||
q_answers = game_data.questions[q_i].answers
|
q_answers = game_data.questions[q_i].answers
|
||||||
q_answer = data.answer
|
q_answer = data.answer
|
||||||
if q_type == QuizQuestionType.ABCD:
|
if q_type == QuizQuestionType.ABCD:
|
||||||
return (check_abcd_question, data.answer)
|
return (check_abcd_question(q_answer, q_answers), data.answer)
|
||||||
elif q_type == QuizQuestionType.RANGE:
|
elif q_type == QuizQuestionType.RANGE:
|
||||||
return (
|
return (
|
||||||
check_range_question(q_answer, q_answers),
|
check_range_question(q_answer, q_answers),
|
||||||
@@ -69,7 +68,7 @@ def check_answer(game_data: PlayGame, data: SubmitAnswerData) -> (bool, str):
|
|||||||
elif q_type == QuizQuestionType.VOTING:
|
elif q_type == QuizQuestionType.VOTING:
|
||||||
return (False, q_answer)
|
return (False, q_answer)
|
||||||
elif q_type == QuizQuestionType.ORDER:
|
elif q_type == QuizQuestionType.ORDER:
|
||||||
return check_order_question(q_answer, q_answers)
|
return check_order_question(data.complex_answer, q_answer, q_answers)
|
||||||
elif q_type == QuizQuestionType.TEXT:
|
elif q_type == QuizQuestionType.TEXT:
|
||||||
return (
|
return (
|
||||||
check_text_question(q_answer, q_answers),
|
check_text_question(q_answer, q_answers),
|
||||||
@@ -105,14 +104,11 @@ def check_order_question(
|
|||||||
) -> (bool, str):
|
) -> (bool, str):
|
||||||
if complex_answer is None:
|
if complex_answer is None:
|
||||||
return (False, answer)
|
return (False, answer)
|
||||||
correct_answers = []
|
correct_answers = [{"answer": a.answer} for a in answers]
|
||||||
for a in answers:
|
submitted_answers = [{"answer": a.answer} for a in complex_answer]
|
||||||
correct_answers.append({"answer": a.answer})
|
answer_str = ", ".join(a["answer"] for a in submitted_answers)
|
||||||
answer_order = []
|
is_correct = submitted_answers == correct_answers
|
||||||
for a in complex_answer.model_dump():
|
return is_correct, answer_str
|
||||||
answer_order.append(a["answer"])
|
|
||||||
answer = ", ".join(answer_order)
|
|
||||||
return (correct_answers == complex_answer.model_dump(), answer)
|
|
||||||
|
|
||||||
|
|
||||||
def check_text_question(answer: str, answers: list[TextQuizAnswer]) -> bool:
|
def check_text_question(answer: str, answers: list[TextQuizAnswer]) -> bool:
|
||||||
|
|||||||
@@ -5,19 +5,14 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createBubbler } from 'svelte/legacy';
|
|
||||||
|
|
||||||
const bubble = createBubbler();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
flex?: boolean;
|
flex?: boolean;
|
||||||
href?: undefined | string;
|
href?: undefined | string;
|
||||||
target?: undefined | string;
|
target?: undefined | string;
|
||||||
type?: undefined | string;
|
type?: 'button' | 'submit' | 'reset';
|
||||||
children?: import('svelte').Snippet;
|
children?: import('svelte').Snippet;
|
||||||
|
onclick?: (event: MouseEvent) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
@@ -26,7 +21,8 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
href = undefined,
|
href = undefined,
|
||||||
target = '_self',
|
target = '_self',
|
||||||
type = 'button',
|
type = 'button',
|
||||||
children
|
children,
|
||||||
|
onclick
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -39,7 +35,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
class:cursor-not-allowed={disabled}
|
class:cursor-not-allowed={disabled}
|
||||||
class:pointer-events-none={disabled}
|
class:pointer-events-none={disabled}
|
||||||
class="text-black hover:bg-bg-[#B07156]/80 w-full px-4 py-2 leading-5 transition-all duration-200 transform bg-[#B07156] rounded-sm text-center outline-hidden hover:cursor-pointer"
|
class="text-black hover:bg-bg-[#B07156]/80 w-full px-4 py-2 leading-5 transition-all duration-200 transform bg-[#B07156] rounded-sm text-center outline-hidden hover:cursor-pointer"
|
||||||
onclick={bubble('click')}
|
{onclick}
|
||||||
class:flex
|
class:flex
|
||||||
class:justify-center={flex}
|
class:justify-center={flex}
|
||||||
>
|
>
|
||||||
@@ -50,7 +46,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
{disabled}
|
{disabled}
|
||||||
{type}
|
{type}
|
||||||
class="text-black hover:cursor-pointer hover:opacity-80 w-full px-4 py-2 leading-5 transition-all duration-200 transform bg-[#B07156] rounded-sm text-center focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 outline-hidden"
|
class="text-black hover:cursor-pointer hover:opacity-80 w-full px-4 py-2 leading-5 transition-all duration-200 transform bg-[#B07156] rounded-sm text-center focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 outline-hidden"
|
||||||
onclick={bubble('click')}
|
{onclick}
|
||||||
class:flex
|
class:flex
|
||||||
class:justify-center={flex}
|
class:justify-center={flex}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -5,16 +5,13 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createBubbler } from 'svelte/legacy';
|
|
||||||
|
|
||||||
const bubble = createBubbler();
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
flex?: boolean;
|
flex?: boolean;
|
||||||
href?: undefined | string;
|
href?: undefined | string;
|
||||||
target?: undefined | string;
|
target?: undefined | string;
|
||||||
children?: import('svelte').Snippet;
|
children?: import('svelte').Snippet;
|
||||||
|
onclick?: (event: MouseEvent) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
@@ -22,7 +19,8 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
flex = false,
|
flex = false,
|
||||||
href = undefined,
|
href = undefined,
|
||||||
target = '_self',
|
target = '_self',
|
||||||
children
|
children,
|
||||||
|
onclick
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -31,7 +29,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
{href}
|
{href}
|
||||||
{target}
|
{target}
|
||||||
class="w-full px-4 py-2 leading-5 text-black dark:text-white transition-colors duration-200 transform bg-gray-50 dark:bg-gray-700 rounded-sm text-center hover:bg-gray-300 focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 dark:hover:bg-gray-600"
|
class="w-full px-4 py-2 leading-5 text-black dark:text-white transition-colors duration-200 transform bg-gray-50 dark:bg-gray-700 rounded-sm text-center hover:bg-gray-300 focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 dark:hover:bg-gray-600"
|
||||||
onclick={bubble('click')}
|
{onclick}
|
||||||
class:flex
|
class:flex
|
||||||
class:block={!flex}
|
class:block={!flex}
|
||||||
class:justify-center={flex}
|
class:justify-center={flex}
|
||||||
@@ -42,7 +40,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<button
|
<button
|
||||||
{disabled}
|
{disabled}
|
||||||
class="w-full px-4 py-2 leading-5 text-black dark:text-white transition-colors duration-200 transform bg-gray-50 dark:bg-gray-700 rounded-sm text-center hover:bg-gray-300 focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 dark:hover:bg-gray-600"
|
class="w-full px-4 py-2 leading-5 text-black dark:text-white transition-colors duration-200 transform bg-gray-50 dark:bg-gray-700 rounded-sm text-center hover:bg-gray-300 focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 dark:hover:bg-gray-600"
|
||||||
onclick={bubble('click')}
|
{onclick}
|
||||||
class:flex
|
class:flex
|
||||||
class:justify-center={flex}
|
class:justify-center={flex}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -34,7 +34,11 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
edit_id: string;
|
edit_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { data = $bindable(), selected_question = $bindable(), edit_id = $bindable() }: Props = $props();
|
let {
|
||||||
|
data = $bindable(),
|
||||||
|
selected_question = $bindable(),
|
||||||
|
edit_id = $bindable()
|
||||||
|
}: Props = $props();
|
||||||
|
|
||||||
let advanced_options_open = $state(false);
|
let advanced_options_open = $state(false);
|
||||||
|
|
||||||
@@ -155,9 +159,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
'questions[].question'
|
'questions[].question'
|
||||||
).isValidSync(data.questions[selected_question].question)}
|
).isValidSync(data.questions[selected_question].question)}
|
||||||
>
|
>
|
||||||
<c.default
|
<c.default bind:text={data.questions[selected_question].question} />
|
||||||
bind:text={data.questions[selected_question].question}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
{/await}
|
{/await}
|
||||||
{/key}
|
{/key}
|
||||||
@@ -287,7 +289,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<div class="mt-auto w-full">
|
<div class="mt-auto w-full">
|
||||||
<BrownButton on:click={() => (advanced_options_open = false)}
|
<BrownButton onclick={() => (advanced_options_open = false)}
|
||||||
>{$t('words.close')}</BrownButton
|
>{$t('words.close')}</BrownButton
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="h-screen relative">
|
<div class="h-screen relative">
|
||||||
<div class="h-10 flex justify-center w-full p-1 absolute z-20">
|
<div class="h-10 flex justify-center w-full p-1 absolute z-20">
|
||||||
<div>
|
<div>
|
||||||
<BrownButton on:click={() => (reorder_mode = !reorder_mode)}
|
<BrownButton onclick={() => (reorder_mode = !reorder_mode)}
|
||||||
>{#if reorder_mode}{$t('editor.disable_reorder')}{:else}{$t(
|
>{#if reorder_mode}{$t('editor.disable_reorder')}{:else}{$t(
|
||||||
'editor.enable_reorder'
|
'editor.enable_reorder'
|
||||||
)}{/if}</BrownButton
|
)}{/if}</BrownButton
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="flex flex-row gap-4">
|
<div class="flex flex-row gap-4">
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
selected_type = AvailableUploadTypes.Image;
|
selected_type = AvailableUploadTypes.Image;
|
||||||
}}
|
}}
|
||||||
>{$t('words.image')}
|
>{$t('words.image')}
|
||||||
@@ -159,7 +159,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
disabled={!video_upload}
|
disabled={!video_upload}
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
selected_type = AvailableUploadTypes.Video;
|
selected_type = AvailableUploadTypes.Video;
|
||||||
}}
|
}}
|
||||||
>{$t('words.video')}
|
>{$t('words.video')}
|
||||||
@@ -168,7 +168,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
{#if library_enabled}
|
{#if library_enabled}
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
selected_type = AvailableUploadTypes.Library;
|
selected_type = AvailableUploadTypes.Library;
|
||||||
}}
|
}}
|
||||||
>{$t('words.library')}
|
>{$t('words.library')}
|
||||||
@@ -177,7 +177,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
{/if}
|
{/if}
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
selected_type = AvailableUploadTypes.Pixabay;
|
selected_type = AvailableUploadTypes.Pixabay;
|
||||||
}}
|
}}
|
||||||
>Pixabay
|
>Pixabay
|
||||||
@@ -202,7 +202,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
{$t('uploader.upload_video_popup_notice')}
|
{$t('uploader.upload_video_popup_notice')}
|
||||||
</p>
|
</p>
|
||||||
{:else}
|
{:else}
|
||||||
<BrownButton on:click={upload_video} type="button"
|
<BrownButton onclick={upload_video} type="button"
|
||||||
>{$t('uploader.upload_video')}</BrownButton
|
>{$t('uploader.upload_video')}</BrownButton
|
||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</div>
|
</div>
|
||||||
<p class="text-center">{image.filename ?? 'No name available'}</p>
|
<p class="text-center">{image.filename ?? 'No name available'}</p>
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
set_image(image.id);
|
set_image(image.id);
|
||||||
}}>{$t('words.select')}</BrownButton
|
}}>{$t('words.select')}</BrownButton
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
set_image(image.id);
|
set_image(image.id);
|
||||||
}}>{$t('words.select')}</BrownButton
|
}}>{$t('words.select')}</BrownButton
|
||||||
>
|
>
|
||||||
@@ -102,14 +102,14 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
disabled={page < 2}
|
disabled={page < 2}
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
page -= 1;
|
page -= 1;
|
||||||
fetched_data = fetch_data();
|
fetched_data = fetch_data();
|
||||||
}}
|
}}
|
||||||
>{$t('uploader.previous_page')}
|
>{$t('uploader.previous_page')}
|
||||||
</BrownButton>
|
</BrownButton>
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
page += 1;
|
page += 1;
|
||||||
fetched_data = fetch_data();
|
fetched_data = fetch_data();
|
||||||
}}>{$t('uploader.next_page')}</BrownButton
|
}}>{$t('uploader.next_page')}</BrownButton
|
||||||
|
|||||||
@@ -378,7 +378,8 @@
|
|||||||
"time_taken": "benötigte Zeit",
|
"time_taken": "benötigte Zeit",
|
||||||
"player_name": "Spielername",
|
"player_name": "Spielername",
|
||||||
"correct_answer_plural": "{{count}} richtige Antworten",
|
"correct_answer_plural": "{{count}} richtige Antworten",
|
||||||
"player_score": "Spieler Score"
|
"player_score": "Spieler Score",
|
||||||
|
"player_correct_questions": "Richtige Antworten"
|
||||||
},
|
},
|
||||||
"navbar": {
|
"navbar": {
|
||||||
"donate": "Spenden"
|
"donate": "Spenden"
|
||||||
|
|||||||
@@ -366,7 +366,8 @@
|
|||||||
"correct_answer": "{{count}} correct answer",
|
"correct_answer": "{{count}} correct answer",
|
||||||
"correct_answer_plural": "{{count}} correct answers",
|
"correct_answer_plural": "{{count}} correct answers",
|
||||||
"time_taken": "Time taken",
|
"time_taken": "Time taken",
|
||||||
"player_score": "Player Score"
|
"player_score": "Player Score",
|
||||||
|
"player_correct_questions": "Correct Answers"
|
||||||
},
|
},
|
||||||
"controllers": {
|
"controllers": {
|
||||||
"add_new_controller": "Add new controller",
|
"add_new_controller": "Add new controller",
|
||||||
|
|||||||
@@ -18,12 +18,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
cqc_code: string;
|
cqc_code: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let { game_pin, players = $bindable(), socket, cqc_code = $bindable() }: Props = $props();
|
||||||
game_pin,
|
|
||||||
players = $bindable(),
|
|
||||||
socket,
|
|
||||||
cqc_code = $bindable()
|
|
||||||
}: Props = $props();
|
|
||||||
|
|
||||||
let fullscreen_open = $state(false);
|
let fullscreen_open = $state(false);
|
||||||
const { t } = getLocalization();
|
const { t } = getLocalization();
|
||||||
@@ -97,7 +92,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div>
|
<div>
|
||||||
<GrayButton
|
<GrayButton
|
||||||
disabled={players.length < 1}
|
disabled={players.length < 1}
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
socket.emit('start_game', '');
|
socket.emit('start_game', '');
|
||||||
}}
|
}}
|
||||||
>{$t('admin_page.start_game')}
|
>{$t('admin_page.start_game')}
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
username: any;
|
username: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { game_pin = $bindable(), game_mode = $bindable(), username = $bindable() }: Props = $props();
|
let {
|
||||||
|
game_pin = $bindable(),
|
||||||
|
game_mode = $bindable(),
|
||||||
|
username = $bindable()
|
||||||
|
}: Props = $props();
|
||||||
let custom_field = $state();
|
let custom_field = $state();
|
||||||
let custom_field_value = $state();
|
let custom_field_value = $state();
|
||||||
let captcha_enabled = $state();
|
let captcha_enabled = $state();
|
||||||
@@ -207,7 +211,10 @@ 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 onsubmit={preventDefault(bubble('submit'))} class="flex-col flex justify-center align-center mx-auto">
|
<form
|
||||||
|
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"
|
||||||
@@ -244,7 +251,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<BrownButton disabled={username.length <= 3} on:click={setUsername}
|
<BrownButton disabled={username.length <= 3} onclick={setUsername}
|
||||||
>{$t('words.submit')}</BrownButton
|
>{$t('words.submit')}</BrownButton
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -82,9 +82,6 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
});
|
});
|
||||||
|
|
||||||
const selectAnswer = (answer: string) => {
|
const selectAnswer = (answer: string) => {
|
||||||
if (selected_answer !== undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selected_answer = answer;
|
selected_answer = answer;
|
||||||
//timer_res = '0';
|
//timer_res = '0';
|
||||||
socket.emit('submit_answer', {
|
socket.emit('submit_answer', {
|
||||||
@@ -244,9 +241,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<BrownButton
|
<BrownButton onclick={() => selectAnswer(slider_value[0])}
|
||||||
disabled={selected_answer !== undefined}
|
|
||||||
on:click={() => selectAnswer(slider_value[0])}
|
|
||||||
>{$t('words.submit')}
|
>{$t('words.submit')}
|
||||||
</BrownButton>
|
</BrownButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -274,8 +269,8 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="w-1/3">
|
<div class="w-1/3">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
type="button"
|
type="button"
|
||||||
disabled={selected_answer !== undefined}
|
disabled={!text_input || text_input.length === 0}
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
selectAnswer(text_input);
|
selectAnswer(text_input);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -370,8 +365,8 @@ 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 !== undefined}
|
disabled={selected_answer}
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
select_complex_answer(question.answers);
|
select_complex_answer(question.answers);
|
||||||
}}>{$t('words.submit')}</BrownButton
|
}}>{$t('words.submit')}</BrownButton
|
||||||
>
|
>
|
||||||
@@ -383,17 +378,18 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<Spinner />
|
<Spinner />
|
||||||
{:then c}
|
{:then c}
|
||||||
<c.default
|
<c.default
|
||||||
bind:question
|
{question}
|
||||||
bind:selected_answer
|
bind:selected_answer
|
||||||
bind:game_mode
|
{game_mode}
|
||||||
{timer_res}
|
{timer_res}
|
||||||
{circular_progress}
|
{circular_progress}
|
||||||
/>
|
/>
|
||||||
<div class="flex justify-center h-[5%]">
|
<div class="flex justify-center h-[5%]">
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
disabled={selected_answer !== undefined}
|
type="button"
|
||||||
on:click={() => selectAnswer(selected_answer)}
|
disabled={selected_answer === undefined}
|
||||||
|
onclick={() => selectAnswer(selected_answer)}
|
||||||
>{$t('words.submit')}
|
>{$t('words.submit')}
|
||||||
</BrownButton>
|
</BrownButton>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
// import CircularTimer from '$lib/play/circular_progress.svelte';
|
// import CircularTimer from '$lib/play/circular_progress.svelte';
|
||||||
const default_colors = ['#D6EDC9', '#B07156', '#7F7057', '#4E6E58'];
|
const default_colors = ['#D6EDC9', '#B07156', '#7F7057', '#4E6E58'];
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
question: Question;
|
question: Question;
|
||||||
selected_answer?: string;
|
selected_answer?: string;
|
||||||
@@ -23,10 +22,10 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
|
|
||||||
let {
|
let {
|
||||||
question,
|
question,
|
||||||
selected_answer = $bindable(''),
|
selected_answer = $bindable(),
|
||||||
game_mode,
|
game_mode,
|
||||||
timer_res = $bindable(),
|
timer_res,
|
||||||
circular_progress = $bindable()
|
circular_progress
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
let _selected_answers = $state([false, false, false, false]);
|
let _selected_answers = $state([false, false, false, false]);
|
||||||
|
|
||||||
@@ -58,7 +57,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 bind:text={timer_res} bind:progress={circular_progress} color="#ef4444" />
|
<CircularTimer text={timer_res} 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">
|
||||||
|
|||||||
@@ -45,7 +45,10 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
if (question.type === QuizQuestionType.RANGE) {
|
if (question.type === QuizQuestionType.RANGE) {
|
||||||
slider_value[0] = (question.answers.max - question.answers.min) / 2 + question.answers.min;
|
slider_value[0] = (question.answers.max - question.answers.min) / 2 + question.answers.min;
|
||||||
}
|
}
|
||||||
let slider_values = $state([question.answers.min_correct ?? 0, question.answers.max_correct ?? 0]);
|
let slider_values = $state([
|
||||||
|
question.answers.min_correct ?? 0,
|
||||||
|
question.answers.max_correct ?? 0
|
||||||
|
]);
|
||||||
|
|
||||||
let text_input = $state();
|
let text_input = $state();
|
||||||
timer(question.time);
|
timer(question.time);
|
||||||
@@ -347,7 +350,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
{/each}
|
{/each}
|
||||||
<BrownButton
|
<BrownButton
|
||||||
type="button"
|
type="button"
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
timer_res = '0';
|
timer_res = '0';
|
||||||
}}>{$t('words.submit')}</BrownButton
|
}}>{$t('words.submit')}</BrownButton
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
{#if data.answers.length < 4}
|
{#if data.answers.length < 4}
|
||||||
<div class="rounded-sm p-6 bg-gray-700">
|
<div class="rounded-sm p-6 bg-gray-700">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
data.answers = [...data.answers, { ...{ answer: '', correct: false } }];
|
data.answers = [...data.answers, { ...{ answer: '', correct: false } }];
|
||||||
}}>{$t('editor_page.add_an_answer')}</BrownButton
|
}}>{$t('editor_page.add_an_answer')}</BrownButton
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-center p-2">
|
<div class="flex justify-center p-2">
|
||||||
<BrownButton on:click={add_card}
|
<BrownButton onclick={add_card}
|
||||||
>{$t('quiztivity.memory.editor.add_pair')}</BrownButton
|
>{$t('quiztivity.memory.editor.add_pair')}</BrownButton
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
@@ -115,13 +115,13 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 p-2 gap-2">
|
<div class="grid grid-cols-2 p-2 gap-2">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
move_card_left(i);
|
move_card_left(i);
|
||||||
}}
|
}}
|
||||||
disabled={i === 0}>{$t('quiztivity.editor.move_left')}</BrownButton
|
disabled={i === 0}>{$t('quiztivity.editor.move_left')}</BrownButton
|
||||||
>
|
>
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
move_card_right(i);
|
move_card_right(i);
|
||||||
}}
|
}}
|
||||||
disabled={i + 1 === data.cards.length}
|
disabled={i + 1 === data.cards.length}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
{#if data.id}
|
{#if data.id}
|
||||||
<div class="mr-auto w-fit pl-2">
|
<div class="mr-auto w-fit pl-2">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
shares_menu_open = true;
|
shares_menu_open = true;
|
||||||
}}>{$t('quiztivity.editor.open_shares_menu')}</BrownButton
|
}}>{$t('quiztivity.editor.open_shares_menu')}</BrownButton
|
||||||
>
|
>
|
||||||
@@ -99,7 +99,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="self-end pr-2 w-full">
|
<div class="self-end pr-2 w-full">
|
||||||
<div class="ml-auto w-fit">
|
<div class="ml-auto w-fit">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
dispatch('save');
|
dispatch('save');
|
||||||
}}
|
}}
|
||||||
disabled={!data.title}>{$t('words.save')}</BrownButton
|
disabled={!data.title}>{$t('words.save')}</BrownButton
|
||||||
@@ -109,20 +109,20 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row gap-2 w-full p-2">
|
<div class="flex flex-row gap-2 w-full p-2">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
selected_type = null;
|
selected_type = null;
|
||||||
}}>{$t('quiztivity.editor.add_new')}</BrownButton
|
}}>{$t('quiztivity.editor.add_new')}</BrownButton
|
||||||
>
|
>
|
||||||
<BrownButton on:click={delete_slide} disabled={selected_slide === null}
|
<BrownButton onclick={delete_slide} disabled={selected_slide === null}
|
||||||
>{$t('quiztivity.editor.delete')}</BrownButton
|
>{$t('quiztivity.editor.delete')}</BrownButton
|
||||||
>
|
>
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={move_slide_left}
|
onclick={move_slide_left}
|
||||||
disabled={selected_slide === null || selected_slide === 0}
|
disabled={selected_slide === null || selected_slide === 0}
|
||||||
>{$t('quiztivity.editor.move_left')}</BrownButton
|
>{$t('quiztivity.editor.move_left')}</BrownButton
|
||||||
>
|
>
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={move_slide_right}
|
onclick={move_slide_right}
|
||||||
disabled={selected_slide === null || selected_slide === data.pages.length - 1}
|
disabled={selected_slide === null || selected_slide === data.pages.length - 1}
|
||||||
>{$t('quiztivity.editor.move_right')}</BrownButton
|
>{$t('quiztivity.editor.move_right')}</BrownButton
|
||||||
>
|
>
|
||||||
@@ -140,7 +140,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
class:opacity-0={selected_slide !== i}
|
class:opacity-0={selected_slide !== i}
|
||||||
>
|
>
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
selected_slide = selected_slide === i ? null : i;
|
selected_slide = selected_slide === i ? null : i;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -149,7 +149,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
)}{/if}
|
)}{/if}
|
||||||
</BrownButton>
|
</BrownButton>
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
opened_slide = i;
|
opened_slide = i;
|
||||||
}}>{$t('words.edit')}</BrownButton
|
}}>{$t('words.edit')}</BrownButton
|
||||||
>
|
>
|
||||||
@@ -164,7 +164,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="h-full">
|
<div class="h-full">
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
opened_slide = null;
|
opened_slide = null;
|
||||||
}}>{$t('words.back')}</BrownButton
|
}}>{$t('words.back')}</BrownButton
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
? !navigator.canShare({
|
? !navigator.canShare({
|
||||||
title: 'title',
|
title: 'title',
|
||||||
url: `${window.location.origin}/quiztivity`
|
url: `${window.location.origin}/quiztivity`
|
||||||
})
|
})
|
||||||
: false;
|
: false;
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
@@ -137,7 +137,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
>
|
>
|
||||||
<div class="flex justify-center flex-col">
|
<div class="flex justify-center flex-col">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
add_shares_open = !add_shares_open;
|
add_shares_open = !add_shares_open;
|
||||||
}}>{$t('quiztivity.editor.shares.add_new_share')}</BrownButton
|
}}>{$t('quiztivity.editor.shares.add_new_share')}</BrownButton
|
||||||
>
|
>
|
||||||
@@ -175,7 +175,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<BrownButton
|
<BrownButton
|
||||||
flex={true}
|
flex={true}
|
||||||
disabled={share_available()}
|
disabled={share_available()}
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
navigator.share({
|
navigator.share({
|
||||||
title: 'Quiztivity on ClassQuiz',
|
title: 'Quiztivity on ClassQuiz',
|
||||||
text: 'Play this Quiztivity now on ClassQuiz!',
|
text: 'Play this Quiztivity now on ClassQuiz!',
|
||||||
@@ -204,7 +204,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="w-full mx-auto">
|
<div class="w-full mx-auto">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
flex={true}
|
flex={true}
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
copyToClipboard(
|
copyToClipboard(
|
||||||
`${window.location.origin}/quiztivity/share/${share.id}?ref=copy`
|
`${window.location.origin}/quiztivity/share/${share.id}?ref=copy`
|
||||||
);
|
);
|
||||||
@@ -242,7 +242,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</p>
|
</p>
|
||||||
<div class="w-fit my-auto ml-auto">
|
<div class="w-fit my-auto ml-auto">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
delete_share(share.id);
|
delete_share(share.id);
|
||||||
}}>{$t('words.delete')}</BrownButton
|
}}>{$t('words.delete')}</BrownButton
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</div>
|
</div>
|
||||||
<!--<div
|
<!--<div
|
||||||
class="m-2 rounded-lg p-2 bg-opacity-40 bg-white transition-all cursor-pointer lg:h-full"
|
class="m-2 rounded-lg p-2 bg-opacity-40 bg-white transition-all cursor-pointer lg:h-full"
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
selected_create_thing = SelectedCreateThing.Import;
|
selected_create_thing = SelectedCreateThing.Import;
|
||||||
}}
|
}}
|
||||||
class:shadow-2xl={selected_create_thing === SelectedCreateThing.Import}
|
class:shadow-2xl={selected_create_thing === SelectedCreateThing.Import}
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="mx-auto">
|
<div class="mx-auto">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
disabled={newest_version === controller.os_version}
|
disabled={newest_version === controller.os_version}
|
||||||
on:click={allow_update_to_version}
|
onclick={allow_update_to_version}
|
||||||
>
|
>
|
||||||
{#if newest_version === controller.os_version}
|
{#if newest_version === controller.os_version}
|
||||||
{$t('controllers.already_latest_version')}
|
{$t('controllers.already_latest_version')}
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</form>
|
</form>
|
||||||
<div>
|
<div>
|
||||||
<div class="w-fit">
|
<div class="w-fit">
|
||||||
<BrownButton on:click={add_api_key}
|
<BrownButton onclick={add_api_key}
|
||||||
>{$t('settings_page.add_api_key')}</BrownButton
|
>{$t('settings_page.add_api_key')}</BrownButton
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
@@ -226,7 +226,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
{key.key}
|
{key.key}
|
||||||
<div class="inline-block">
|
<div class="inline-block">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
delete_api_key(key.key);
|
delete_api_key(key.key);
|
||||||
}}
|
}}
|
||||||
>{$t('words.delete')}
|
>{$t('words.delete')}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="flex pl-2">
|
<div class="flex pl-2">
|
||||||
<div class="mr-auto">
|
<div class="mr-auto">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
index = index - 1;
|
index = index - 1;
|
||||||
}}
|
}}
|
||||||
disabled={index < 1}>{$t('words.back')}</BrownButton
|
disabled={index < 1}>{$t('words.back')}</BrownButton
|
||||||
@@ -150,12 +150,12 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
/>
|
/>
|
||||||
<div class="m-auto grid grid-cols-2 gap-4" in:fade|global={{ delay: 3500 }}>
|
<div class="m-auto grid grid-cols-2 gap-4" in:fade|global={{ delay: 3500 }}>
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
index = 0;
|
index = 0;
|
||||||
finished = false;
|
finished = false;
|
||||||
}}>{$t('avatar_settings.start_over')}</BrownButton
|
}}>{$t('avatar_settings.start_over')}</BrownButton
|
||||||
>
|
>
|
||||||
<BrownButton on:click={save_avatar} flex={true} disabled={save_finished === true}>
|
<BrownButton onclick={save_avatar} flex={true} disabled={save_finished === true}>
|
||||||
{#if save_finished === undefined}{$t('words.save')}
|
{#if save_finished === undefined}{$t('words.save')}
|
||||||
{:else if save_finished === true}
|
{:else if save_finished === true}
|
||||||
<svg
|
<svg
|
||||||
@@ -175,7 +175,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</BrownButton>
|
</BrownButton>
|
||||||
<BrownButton href="/account/settings">{$t('avatar_settings.go_back')}</BrownButton>
|
<BrownButton href="/account/settings">{$t('avatar_settings.go_back')}</BrownButton>
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
finished = false;
|
finished = false;
|
||||||
}}>{$t('words.close')}</BrownButton
|
}}>{$t('words.close')}</BrownButton
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<h2 class="text-center text-2xl">{$t('security_settings.backup_code')}</h2>
|
<h2 class="text-center text-2xl">{$t('security_settings.backup_code')}</h2>
|
||||||
<div class="flex h-full w-full justify-center">
|
<div class="flex h-full w-full justify-center">
|
||||||
<div class="m-auto">
|
<div class="m-auto">
|
||||||
<BrownButton on:click={get_backup_code}
|
<BrownButton onclick={get_backup_code}
|
||||||
>{$t('security_settings.get_backup_code')}</BrownButton
|
>{$t('security_settings.get_backup_code')}</BrownButton
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
@@ -238,7 +238,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<div class="m-auto">
|
<div class="m-auto">
|
||||||
<BrownButton on:click={add_security_key}
|
<BrownButton onclick={add_security_key}
|
||||||
>{$t('security_settings.add_security_key')}</BrownButton
|
>{$t('security_settings.add_security_key')}</BrownButton
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
@@ -271,11 +271,11 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<div class="m-auto">
|
<div class="m-auto">
|
||||||
{#if totp_activated}
|
{#if totp_activated}
|
||||||
<BrownButton on:click={disable_totp}
|
<BrownButton onclick={disable_totp}
|
||||||
>{$t('security_settings.disable_totp')}</BrownButton
|
>{$t('security_settings.disable_totp')}</BrownButton
|
||||||
>
|
>
|
||||||
{:else}
|
{:else}
|
||||||
<BrownButton on:click={enable_totp}
|
<BrownButton onclick={enable_totp}
|
||||||
>{$t('security_settings.enable_totp')}</BrownButton
|
>{$t('security_settings.enable_totp')}</BrownButton
|
||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="w-screen flex justify-center mt-16">
|
<div class="w-screen flex justify-center mt-16">
|
||||||
<div class="w-fit">
|
<div class="w-fit">
|
||||||
{#if export_token === undefined}
|
{#if export_token === undefined}
|
||||||
<GrayButton on:click={request_answer_export}
|
<GrayButton onclick={request_answer_export}
|
||||||
>{$t('admin_page.request_export_results')}</GrayButton
|
>{$t('admin_page.request_export_results')}</GrayButton
|
||||||
>
|
>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -179,7 +179,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-screen flex justify-center mt-2">
|
<div class="w-screen flex justify-center mt-2">
|
||||||
<div class="w-fit">
|
<div class="w-fit">
|
||||||
<GrayButton on:click={save_quiz} flex={true} disabled={results_saved}>
|
<GrayButton onclick={save_quiz} flex={true} disabled={results_saved}>
|
||||||
{#if results_saved}
|
{#if results_saved}
|
||||||
<svg
|
<svg
|
||||||
class="w-4 h-4"
|
class="w-4 h-4"
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
create_button_clicked = true;
|
create_button_clicked = true;
|
||||||
}}>{$t('words.create')}</BrownButton
|
}}>{$t('words.create')}</BrownButton
|
||||||
>
|
>
|
||||||
@@ -267,7 +267,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</BrownButton>
|
</BrownButton>
|
||||||
<BrownButton
|
<BrownButton
|
||||||
flex={true}
|
flex={true}
|
||||||
on:click={() => (analytics_quiz_selected = quiz)}
|
onclick={() => (analytics_quiz_selected = quiz)}
|
||||||
>
|
>
|
||||||
<!-- heroicons/legacy-outline/ChartBar -->
|
<!-- heroicons/legacy-outline/ChartBar -->
|
||||||
<svg
|
<svg
|
||||||
@@ -311,7 +311,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</BrownButton>
|
</BrownButton>
|
||||||
{#if quiz.type === 'quiz'}
|
{#if quiz.type === 'quiz'}
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
start_game = quiz.id;
|
start_game = quiz.id;
|
||||||
}}
|
}}
|
||||||
flex={true}
|
flex={true}
|
||||||
@@ -365,7 +365,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
deleteQuiz(quiz.id, quiz.type);
|
deleteQuiz(quiz.id, quiz.type);
|
||||||
}}
|
}}
|
||||||
flex={true}
|
flex={true}
|
||||||
@@ -387,7 +387,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</svg>
|
</svg>
|
||||||
</BrownButton>
|
</BrownButton>
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => (download_id = quiz.id)}
|
onclick={() => (download_id = quiz.id)}
|
||||||
flex={true}
|
flex={true}
|
||||||
disabled={quiz.type !== 'quiz'}
|
disabled={quiz.type !== 'quiz'}
|
||||||
><!-- heroicons/download -->
|
><!-- heroicons/download -->
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
{#if quiz}
|
{#if quiz}
|
||||||
<div
|
<div
|
||||||
class="fixed w-full h-full top-0 flex bg-black/50 z-50 overflow-scroll"
|
class="fixed w-full h-full top-0 flex bg-black/50 z-50 overflow-scroll"
|
||||||
on:click={on_parent_click}
|
onclick={on_parent_click}
|
||||||
transition:fade={{ duration: 100 }}
|
transition:fade={{ duration: 100 }}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -104,14 +104,14 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</p>
|
</p>
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
edit_popup = image;
|
edit_popup = image;
|
||||||
}}
|
}}
|
||||||
>{$t('file_dashboard.edit_details')}
|
>{$t('file_dashboard.edit_details')}
|
||||||
</BrownButton>
|
</BrownButton>
|
||||||
{#if image.quiztivities.length === 0 && image.quizzes.length === 0}
|
{#if image.quiztivities.length === 0 && image.quizzes.length === 0}
|
||||||
<BrownButton
|
<BrownButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
delete_image(image.id);
|
delete_image(image.id);
|
||||||
}}>{$t('file_dashboard.delete_image')}</BrownButton
|
}}>{$t('file_dashboard.delete_image')}</BrownButton
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
const { t } = getLocalization();
|
const { t } = getLocalization();
|
||||||
|
|
||||||
let file_input: HTMLInputElement = $state();
|
let file_input: HTMLInputElement = $state();
|
||||||
navbarVisible.visible= false;
|
navbarVisible.visible = false;
|
||||||
|
|
||||||
let stats: { progress: number; time_elapsed: number; speed: number } = $state({
|
let stats: { progress: number; time_elapsed: number; speed: number } = $state({
|
||||||
progress: 0,
|
progress: 0,
|
||||||
@@ -197,7 +197,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex relative my-2">
|
<div class="flex relative my-2">
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<BrownButton disabled={status !== Status.CompressDone} on:click={upload_video}>
|
<BrownButton disabled={status !== Status.CompressDone} onclick={upload_video}>
|
||||||
{$t('words.upload')}
|
{$t('words.upload')}
|
||||||
{file_size_in_mi ? `(${file_size_in_mi.toFixed(2)} Mi)` : ''}</BrownButton
|
{file_size_in_mi ? `(${file_size_in_mi.toFixed(2)} Mi)` : ''}</BrownButton
|
||||||
>
|
>
|
||||||
@@ -208,7 +208,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
></span>
|
></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<BrownButton on:click={compress_video} disabled={status !== Status.Idle}
|
<BrownButton onclick={compress_video} disabled={status !== Status.Idle}
|
||||||
>{$t('words.submit')}</BrownButton
|
>{$t('words.submit')}</BrownButton
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="my-auto justify-start ml-4">
|
<div class="my-auto justify-start ml-4">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
disabled={current_slide_index < 1}
|
disabled={current_slide_index < 1}
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
current_slide_index -= 1;
|
current_slide_index -= 1;
|
||||||
}}>{$t('words.back')}</BrownButton
|
}}>{$t('words.back')}</BrownButton
|
||||||
>
|
>
|
||||||
@@ -33,7 +33,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="my-auto justify-end mr-4">
|
<div class="my-auto justify-end mr-4">
|
||||||
<BrownButton
|
<BrownButton
|
||||||
disabled={current_slide_index === 1}
|
disabled={current_slide_index === 1}
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
current_slide_index += 1;
|
current_slide_index += 1;
|
||||||
}}>{$t('words.next')}</BrownButton
|
}}>{$t('words.next')}</BrownButton
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<tr class="text-left">
|
<tr class="text-left">
|
||||||
<td class="border-r dark:border-gray-500 p-1 border-gray-300"
|
<td class="border-r dark:border-gray-500 p-1 border-gray-300"
|
||||||
><a href="/results/{result.id}" class="underline text-lg"
|
><a href="/results/{result.id}" class="underline text-lg"
|
||||||
>{result.title}</a
|
>{@html result.title}</a
|
||||||
></td
|
></td
|
||||||
>
|
>
|
||||||
<td class="border-r dark:border-gray-500 p-1 border-gray-300"
|
<td class="border-r dark:border-gray-500 p-1 border-gray-300"
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<PlayerOverview
|
<PlayerOverview
|
||||||
custom_field={data.results.custom_field_data}
|
custom_field={data.results.custom_field_data}
|
||||||
scores={data.results.player_scores}
|
scores={data.results.player_scores}
|
||||||
|
answers={data.results.answers}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -10,30 +10,23 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
|
|
||||||
const { t } = getLocalization();
|
const { t } = getLocalization();
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
questions: Question[];
|
questions: Question[];
|
||||||
answers: {
|
answers: {
|
||||||
username: string;
|
username: string;
|
||||||
answer: string;
|
answer: string;
|
||||||
right: boolean;
|
right: boolean;
|
||||||
tike_taken: number;
|
tike_taken: number;
|
||||||
score: number;
|
score: number;
|
||||||
}[][];
|
}[][];
|
||||||
scores: {
|
scores: {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
};
|
};
|
||||||
title: string;
|
title: string;
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let { questions, answers, scores, title, timestamp }: Props = $props();
|
||||||
questions,
|
|
||||||
answers,
|
|
||||||
scores,
|
|
||||||
title,
|
|
||||||
timestamp
|
|
||||||
}: Props = $props();
|
|
||||||
|
|
||||||
const usernames = Object.keys(scores);
|
const usernames = Object.keys(scores);
|
||||||
|
|
||||||
@@ -49,7 +42,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<div class="flex justify-center w-full">
|
<div class="flex justify-center w-full">
|
||||||
<p class="text-3xl w-5/6 text-center">
|
<p class="text-3xl w-5/6 text-center">
|
||||||
{$t('results_page.general_overview.sentence', {
|
{@html $t('results_page.general_overview.sentence', {
|
||||||
title,
|
title,
|
||||||
date: new Date(timestamp).toLocaleString(),
|
date: new Date(timestamp).toLocaleString(),
|
||||||
player_count: usernames.length,
|
player_count: usernames.length,
|
||||||
|
|||||||
@@ -10,16 +10,29 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
const { t } = getLocalization();
|
const { t } = getLocalization();
|
||||||
interface Props {
|
interface Props {
|
||||||
scores: {
|
scores: {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
};
|
};
|
||||||
custom_field: {
|
custom_field: {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
};
|
};
|
||||||
|
answers: { [key: string]: any }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
let { scores, custom_field }: Props = $props();
|
let { scores, custom_field, answers }: Props = $props();
|
||||||
|
|
||||||
let usernames = Object.keys(scores);
|
let usernames = Object.keys(scores);
|
||||||
|
const correctCounts = {};
|
||||||
|
answers.forEach((questionAnswers) => {
|
||||||
|
questionAnswers.forEach((answer) => {
|
||||||
|
const user = answer.username;
|
||||||
|
if (!correctCounts[user]) {
|
||||||
|
correctCounts[user] = 0;
|
||||||
|
}
|
||||||
|
if (answer.right) {
|
||||||
|
correctCounts[user] += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
console.log(custom_field);
|
console.log(custom_field);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -31,6 +44,9 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<th class="border-r dark:border-gray-500 p-1 mx-auto border-gray-300"
|
<th class="border-r dark:border-gray-500 p-1 mx-auto border-gray-300"
|
||||||
>{$t('result_page.player_name')}
|
>{$t('result_page.player_name')}
|
||||||
</th>
|
</th>
|
||||||
|
<th class="border-r dark:border-gray-500 p-1 mx-auto border-gray-300"
|
||||||
|
>{$t('result_page.player_correct_questions')}
|
||||||
|
</th>
|
||||||
<th class="p-1 mx-auto">{$t('result_page.player_score')}</th>
|
<th class="p-1 mx-auto">{$t('result_page.player_score')}</th>
|
||||||
{#if Object.keys(custom_field).length !== 0}
|
{#if Object.keys(custom_field).length !== 0}
|
||||||
<th class="border-l dark:border-gray-500 p-1 mx-auto border-gray-300"
|
<th class="border-l dark:border-gray-500 p-1 mx-auto border-gray-300"
|
||||||
@@ -43,6 +59,9 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
{#each usernames as uname}
|
{#each usernames as uname}
|
||||||
<tr class="text-left">
|
<tr class="text-left">
|
||||||
<td class="border-r dark:border-gray-500 p-1 border-gray-300">{uname}</td>
|
<td class="border-r dark:border-gray-500 p-1 border-gray-300">{uname}</td>
|
||||||
|
<td class="border-r dark:border-gray-500 p-1 border-gray-300"
|
||||||
|
>{correctCounts[uname]}</td
|
||||||
|
>
|
||||||
<td class="p-1">{scores[uname]}</td>
|
<td class="p-1">{scores[uname]}</td>
|
||||||
{#if custom_field[uname]}
|
{#if custom_field[uname]}
|
||||||
<td class="border-l dark:border-gray-500 p-1 border-gray-300"
|
<td class="border-l dark:border-gray-500 p-1 border-gray-300"
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
{#if logged_in}
|
{#if logged_in}
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<GrayButton
|
<GrayButton
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
start_game = quiz.id;
|
start_game = quiz.id;
|
||||||
}}
|
}}
|
||||||
flex={true}
|
flex={true}
|
||||||
@@ -188,7 +188,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
{#if logged_in}
|
{#if logged_in}
|
||||||
<GrayButton flex={true} on:click={() => (download_id = quiz.id)}>
|
<GrayButton flex={true} onclick={() => (download_id = quiz.id)}>
|
||||||
<svg
|
<svg
|
||||||
class="w-5 h-5 inline-block"
|
class="w-5 h-5 inline-block"
|
||||||
fill="none"
|
fill="none"
|
||||||
|
|||||||
@@ -35,25 +35,25 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
|
|
||||||
<div class="rounded-sm border-2 border-[#B07156] flex flex-col w-fit gap-2 p-2">
|
<div class="rounded-sm border-2 border-[#B07156] flex flex-col w-fit gap-2 p-2">
|
||||||
<div class:opacity-50={mod_rating !== null && mod_rating !== undefined} class="transition">
|
<div class:opacity-50={mod_rating !== null && mod_rating !== undefined} class="transition">
|
||||||
<BrownButton on:click={() => (mod_rating = null)}>Not Checked</BrownButton>
|
<BrownButton onclick={() => (mod_rating = null)}>Not Checked</BrownButton>
|
||||||
</div>
|
</div>
|
||||||
<div class:opacity-50={mod_rating !== 0 && mod_rating !== undefined} class="transition">
|
<div class:opacity-50={mod_rating !== 0 && mod_rating !== undefined} class="transition">
|
||||||
<BrownButton on:click={() => (mod_rating = 0)}>Ok</BrownButton>
|
<BrownButton onclick={() => (mod_rating = 0)}>Ok</BrownButton>
|
||||||
</div>
|
</div>
|
||||||
<div class:opacity-50={mod_rating !== 1 && mod_rating !== undefined} class="transition">
|
<div class:opacity-50={mod_rating !== 1 && mod_rating !== undefined} class="transition">
|
||||||
<BrownButton on:click={() => (mod_rating = 1)}>Attention</BrownButton>
|
<BrownButton onclick={() => (mod_rating = 1)}>Attention</BrownButton>
|
||||||
</div>
|
</div>
|
||||||
<div class:opacity-50={mod_rating !== 2 && mod_rating !== undefined} class="transition">
|
<div class:opacity-50={mod_rating !== 2 && mod_rating !== undefined} class="transition">
|
||||||
<BrownButton on:click={() => (mod_rating = 2)}>NFSW</BrownButton>
|
<BrownButton onclick={() => (mod_rating = 2)}>NFSW</BrownButton>
|
||||||
</div>
|
</div>
|
||||||
<div class:opacity-50={mod_rating !== 3 && mod_rating !== undefined} class="transition">
|
<div class:opacity-50={mod_rating !== 3 && mod_rating !== undefined} class="transition">
|
||||||
<BrownButton on:click={() => (mod_rating = 3)}>Plausibility Checked</BrownButton>
|
<BrownButton onclick={() => (mod_rating = 3)}>Plausibility Checked</BrownButton>
|
||||||
</div>
|
</div>
|
||||||
<div class:opacity-50={mod_rating !== 4 && mod_rating !== undefined} class="transition">
|
<div class:opacity-50={mod_rating !== 4 && mod_rating !== undefined} class="transition">
|
||||||
<BrownButton on:click={() => (mod_rating = 4)}>Fact Checked</BrownButton>
|
<BrownButton onclick={() => (mod_rating = 4)}>Fact Checked</BrownButton>
|
||||||
</div>
|
</div>
|
||||||
<div class:opacity-50={mod_rating !== 5 && mod_rating !== undefined} class="transition">
|
<div class:opacity-50={mod_rating !== 5 && mod_rating !== undefined} class="transition">
|
||||||
<BrownButton on:click={() => (mod_rating = 5)}>Exceptional</BrownButton>
|
<BrownButton onclick={() => (mod_rating = 5)}>Exceptional</BrownButton>
|
||||||
</div>
|
</div>
|
||||||
<GrayButton on:click={submit} disabled={mod_rating === undefined}>Submit</GrayButton>
|
<GrayButton onclick={submit} disabled={mod_rating === undefined}>Submit</GrayButton>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user