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