Remove Backups and copies

This commit is contained in:
Mawoka
2024-07-08 10:33:11 +02:00
parent 8be0172396
commit 6ac607594b
11 changed files with 0 additions and 2072 deletions
@@ -1,279 +0,0 @@
<!--
SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
SPDX-License-Identifier: MPL-2.0
-->
<script lang="ts">
import { onMount } from 'svelte';
import { tinykeys } from '$lib/tinykeys';
import { fade } from 'svelte/transition';
import MiniSearch from 'minisearch';
let open = false;
let input = '';
let bg_text = '';
let title_ms: MiniSearch;
let command_ms: MiniSearch;
let selected: null | number = null;
// eslint-disable-next-line no-unused-vars
type ActionFunction = (args: string[]) => void;
const actions: {
id: number;
title: string;
description?: string;
command?: string;
args?: string[];
action: ActionFunction;
}[] = [
{
id: 0,
title: 'Close CommandPalette',
description: 'Closes CommandPalette',
command: 'close',
action: () => close_cp(undefined)
},
{
id: 1,
title: 'Create Quiz',
description: 'Opens editor to create a new quiz',
command: 'newquiz',
args: ['title'],
action: (args) => window.location.assign(`/create?title=${args.join(' ')}`)
},
{
id: 2,
title: 'Import a Quiz',
description: 'Opens the import page',
command: 'import',
args: ['url'],
action: (args) => window.location.assign(`/import?url=${args?.[0] ?? ''}`)
},
{
id: 3,
title: 'Create Quiztivity',
description: 'Opens the editor for quiztivities',
command: 'newquiztivity',
args: ['title'],
action: (args) => window.location.assign(`/quiztivity/create?title=${args.join(' ')}`)
},
{
id: 4,
title: 'View Results',
description: 'Opens the Results viewer',
command: 'results',
action: () => window.location.assign('/results')
},
{
id: 5,
title: 'Explore Quizzes',
description: 'Opens the Explore-page',
command: 'explore',
action: () => window.location.assign('/explore')
},
{
id: 6,
title: 'Dashboard',
description: 'Go to Dashboard',
command: 'dash',
action: () => window.location.assign('/dashboard')
},
{
id: 7,
title: 'Docs',
description: 'Go to documentation',
command: 'docs',
action: () => window.location.assign('/docs')
},
{
id: 8,
title: 'Settings',
description: 'Opens the Settings page',
command: 'settings',
action: () => window.location.assign('/account/settings')
}
];
let visible_items = actions;
const toggle_open = (e: KeyboardEvent | undefined) => {
e.preventDefault();
open = !open;
console.log('TOGGLE!');
};
const close_cp = (e: KeyboardEvent | undefined) => {
if (e) {
e.preventDefault();
}
open = false;
};
const close_on_outside = (e: Event) => {
if (e.target == e.currentTarget) {
open = false;
}
};
const execute_action = () => {
let args = [];
const entry = visible_items[selected];
if (input.startsWith('/')) {
const tokens = input.split(' ');
args = tokens.slice(1);
}
console.log(args);
entry.action(args);
};
const search = (term: string) => {
if (!command_ms || !title_ms) {
return;
}
if (term === '' || term === '/') {
selected = 0;
visible_items = actions;
bg_text = '';
return;
}
let suggestions;
let res;
if (term.startsWith('/')) {
term = term.substring(1);
suggestions = command_ms.autoSuggest(term, { boost: { command: 2 }, prefix: true });
res = command_ms.search(term, { boost: { command: 2 }, prefix: true });
bg_text = suggestions[0]?.suggestion;
bg_text ??= '';
bg_text = `/${bg_text}`;
} else {
suggestions = title_ms.autoSuggest(term, { boost: { command: 2 }, prefix: true });
res = title_ms.search(term, { boost: { command: 2 }, prefix: true });
bg_text = suggestions[0]?.suggestion;
bg_text ??= '';
}
visible_items = [];
console.log(res);
for (const quiz_data of res) {
visible_items.push(actions[quiz_data.id]);
}
visible_items = visible_items;
if (visible_items.length === 1) {
selected = 0;
}
if (visible_items.length === 0) {
selected = null;
}
};
const autocomplete_on_tab = (e: KeyboardEvent) => {
e.preventDefault();
input = bg_text;
};
const on_arrow_down = (e: KeyboardEvent) => {
e.preventDefault();
if (visible_items.length < 1) {
return;
}
if (selected + 1 === visible_items.length) {
return;
}
selected += 1;
};
const on_arrow_up = (e: KeyboardEvent) => {
e.preventDefault();
if (visible_items.length < 1) {
return;
}
if (selected === 0) {
return;
}
selected -= 1;
};
const on_enter = (e: KeyboardEvent) => {
e.preventDefault();
if (selected === null) {
return;
}
execute_action();
input = '';
};
$: search(input);
// $: input = lower_input(input)
$: input = input.toLowerCase();
onMount(async () => {
tinykeys(window, {
'$mod+k': toggle_open,
Escape: close_cp,
Tab: autocomplete_on_tab,
ArrowDown: on_arrow_down,
ArrowUp: on_arrow_up,
Enter: on_enter
});
title_ms = new MiniSearch<any>({
fields: ['title'],
storeFields: ['id']
});
title_ms.addAll(actions);
command_ms = new MiniSearch<any>({
fields: ['command'],
storeFields: ['id']
});
command_ms.addAll(actions);
});
</script>
{#if open}
<div
class="fixed top-0 left-0 w-screen h-screen flex bg-black bg-opacity-50 z-50"
on:click={close_on_outside}
transition:fade={{ duration: 60 }}
>
<div class="m-auto w-1/3 h-2/3 rounded bg-black flex flex-col">
<div class="grid grid-cols-1 grid-rows-1 border-b border-b-white">
<p
class="col-start-1 row-start-1 w-full p-4 outline-none bg-gray-700 rounded-t text-gray-400"
>
{bg_text}
</p>
<input
type="text"
autofocus
class="col-start-1 row-start-1 bg-transparent w-full p-4 outline-none bg-gray-700 rounded"
bind:value={input}
/>
</div>
<div class="flex flex-col p-2 gap-2 overflow-scroll">
{#each visible_items as vi, i}
<div
transition:fade|local={{ duration: 60 }}
class="p-2 transition rounded"
class:bg-[#B07156]={selected === i}
class:bg-gray-700={selected !== i}
on:mouseenter={() => (selected = i)}
on:mousedown={execute_action}
>
<div class="flex">
<h3 class="text-lg my-auto">{vi.title}</h3>
<p
class="font-mono my-auto ml-auto h-fit bg-black bg-opacity-50 rounded p-0.5"
>
/{vi.command}
{#if vi.args}
{#each vi.args as arg}
&lbrace;<span class="text-indigo-400">{arg}</span
>&rbrace;{/each}
{/if}
</p>
</div>
<p class="text-sm">{vi.description}</p>
</div>
{/each}
</div>
</div>
</div>
{/if}
@@ -1,555 +0,0 @@
<!--
SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
SPDX-License-Identifier: MPL-2.0
-->
<script lang="ts">
import { navbarVisible } from '$lib/stores';
import { getLocalization } from '$lib/i18n';
import Footer from '$lib/footer.svelte';
import WebPOpenGraph from '$lib/assets/landing/opengraph-home.webp';
import JpgOpenGraph from '$lib/assets/landing/opengraph-home.jpg';
import Newsletter from '$lib/landing/newsletter.svelte';
import { fly, fade } from 'svelte/transition';
/* import LandingPromo from '$lib/landing/landing-promo.svelte';*/
import FindScreenshot from '$lib/assets/landing_new/find.webp';
import ImportScreenshot from '$lib/assets/landing_new/import.webp';
import EditScreenshot from '$lib/assets/landing_new/edit.webp';
import SelectScreenshot from '$lib/assets/landing_new/select.webp';
import ResultScreenshot from '$lib/assets/landing_new/result.webp';
import WinnersScreenshot from '$lib/assets/landing_new/winners.webp';
import { onMount } from 'svelte';
const { t } = getLocalization();
navbarVisible.set(true);
/* interface StatsData {
quiz_count: number;
user_count: number;
}*/
/* const getStats = async (): Promise<StatsData> => {
const response = await fetch('/api/v1/stats/combined');
return await response.json();
};*/
let newsletterModalOpen;
onMount(() => {
const ls = localStorage.getItem('newsletter');
newsletterModalOpen = ls === null;
});
// eslint-disable-next-line no-unused-vars
enum SelectedCreateThing {
// eslint-disable-next-line no-unused-vars
Create,
// eslint-disable-next-line no-unused-vars
Find,
// eslint-disable-next-line no-unused-vars
Import
}
// eslint-disable-next-line no-unused-vars
enum SelectedPlayThing {
// eslint-disable-next-line no-unused-vars
Select,
// eslint-disable-next-line no-unused-vars
Results,
// eslint-disable-next-line no-unused-vars
Winners
}
let selected_create_thing = SelectedCreateThing.Create;
let selected_play_thing = SelectedPlayThing.Select;
/* <li>No;
Tracking < /li>
< li > Self - hostable < /li>
< li > German;
Server < /li>
< li > user - friendly < /li>
< li > Completely;
free < /li>
< li > Quiz - results;
are;
downloadable < /li>;*/
const classquiz_reasons = [
{
headline: $t('index_page.no_player_limit'),
content: $t('index_page.no_player_limit_content')
},
{
headline: $t('index_page.no_tracking'),
content: $t('index_page.no_tracking_content')
},
{
headline: $t('index_page.self_hostable'),
content: $t('index_page.self_hostable_content')
},
{
headline: $t('index_page.german_server'),
content: $t('index_page.german_server_content')
},
{
headline: $t('index_page.user_friendly'),
content: $t('index_page.user_friendly_content')
},
{
headline: $t('index_page.completely_free'),
content: $t('index_page.completely_free_content')
},
{
headline: $t('index_page.quiz_results_downloadable'),
content: $t('index_page.quiz_results_downloadable_content')
},
{
headline: $t('index_page.multilingual'),
content: $t('index_page.multilingual_content')
},
{
headline: $t('index_page.dark_mode'),
content: $t('index_page.dark_mode_content')
},
{
headline: $t('index_page.download_quizzes'),
content: $t('index_page.download_quizzes_content')
},
{
headline: $t('index_page.community_driven'),
content: $t('index_page.community_driven_content')
}
];
let selected_classquiz_reason = 0;
</script>
<svelte:head>
<title>ClassQuiz - {$t('index_page.meta.title')}</title>
<meta name="description" content={$t('index_page.meta.description')} />
<title>ClassQuiz - Home</title>
<meta
name="description"
content="ClassQuiz is a quiz-application like KAHOOT!, but open-source. You can create quizzes and play them remotely with other people."
/>
<meta property="og:url" content="https://classquiz.de/" />
<meta property="og:type" content="website" />
<meta property="og:title" content="ClassQuiz - {$t('index_page.meta.title')}" />
<meta
property="og:description"
content="ClassQuiz is a quiz-application like KAHOOT!, but open-source. You can create quizzes and play them remotely with other people."
/>
<meta property="og:image" content={JpgOpenGraph} />
<meta name="twitter:card" content="summary_large_image" />
<meta property="twitter:domain" content="classquiz.de" />
<meta property="twitter:url" content="https://classquiz.de/" />
<meta name="twitter:title" content="ClassQuiz - {$t('index_page.meta.title')}" />
<meta
name="twitter:description"
content="ClassQuiz is a quiz-application like KAHOOT!, but open-source. You can create quizzes and play them remotely with other people."
/>
<meta name="twitter:image" content={WebPOpenGraph} />
</svelte:head>
<!--<div class="min-h-screen flex flex-col">
<section class="pb-40">
<div class="pt-12 text-center">
<h1 class="sm:text-8xl text-6xl mt-6 marck-script">ClassQuiz</h1>
<p class="text-xl mt-4">{$t('index_page.slogan')}</p>
</div>
</section>
<section id="features" class="mt-8">
<div class="text-center snap-y">
<h1 class="sm:text-6xl text-4xl">{$t('words.features')}</h1>
<p class="text-xl pt-4">
{$t('index_page.features_description.1')}
<br />
{$t('index_page.features_description.2')}
<br />
{$t('index_page.features_description.3')}
</p>
</div>
</section>
<section class="py-8">
<h1 class="sm:text-6xl text-4xl text-center break-words">
{$t('words.screenshot', { count: 2 })}
</h1>
<div>
<LandingPromo />
</div>
</section>
<section>
<h1 class="sm:text-6xl text-4xl text-center">Testimonials</h1>
{#await import('$lib/landing/testimonials.svelte') then testimonials}
<svelte:component this={testimonials.default} />
{/await}
</section>
<section id="stats">
<div class="text-center pb-20 pt-10 snap-y">
<h1 class="sm:text-6xl text-4xl">{$t('words.stats')}</h1>
<p class="text-xl pt-4">
{#await getStats() then stats}
{$t('index_page.stats', {
user_count: stats.user_count,
quiz_count: stats.quiz_count
})}
{/await}
</p>
</div>
</section>
</div>-->
<div class="min-h-screen flex flex-col">
<section class="pb-40">
<div class="pt-12 text-center">
<h1 class="sm:text-8xl text-6xl mt-6 marck-script">ClassQuiz</h1>
<p class="text-xl mt-4">{$t('index_page.slogan')}</p>
</div>
</section>
<section>
<h2 class="text-center text-5xl mb-6">{$t('index_page.how_does_classquiz_work')}</h2>
<div class="flex justify-center w-full">
<h3 class="text-center text-3xl rounded-t-lg bg-opacity-40 bg-white py-2 px-6">
{$t('index_page.get_a_quiz')}
</h3>
</div>
<div
class="grid grid-rows-2 lg:grid-rows-1 lg:grid-cols-2 bg-opacity-40 bg-white shadow-lg mb-12 lg:mx-12 mx-4 rounded-lg"
>
<div>
<div class="p-2 rounded-lg">
{#if selected_create_thing === SelectedCreateThing.Create}
<img
class="rounded-lg relative"
src={EditScreenshot}
in:fade
alt="Screenshot of the import-page showing an URL to Kahoot! entered"
/>
{:else if selected_create_thing === SelectedCreateThing.Find}
<img
class="rounded-lg relative"
src={FindScreenshot}
in:fade
alt="Screenshot of the search-page showing one found quiz for the term 'Country'"
/>
{:else if selected_create_thing === SelectedCreateThing.Import}
<img
class="rounded-lg relative"
src={ImportScreenshot}
in:fade
alt="Screenshot of the import-page showing an URL to Kahoot! entered"
/>
{:else}
<p>Shouldn't happen!</p>
{/if}
</div>
</div>
<div
class="lg:border-l lg:border-l-black lg:border-t-0 border-t border-t-black flex lg:flex-col flex-row stretch"
>
<div
class="m-2 rounded-lg p-2 bg-opacity-40 bg-white transition-all cursor-pointer lg:h-full"
on:click={() => {
selected_create_thing = SelectedCreateThing.Create;
}}
class:shadow-2xl={selected_create_thing === SelectedCreateThing.Create}
class:opacity-70={selected_create_thing !== SelectedCreateThing.Create}
>
<div
class="rounded-lg w-fit p-1 bg-lime-500 hover:bg-lime-400 transition shadow-lg"
>
<svg
aria-label="Pencil-Icon"
class="w-8 h-8 text-black"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"
/>
</svg>
</div>
<h5 class="text-xl w-fit dark:text-black">{$t('words.create')}</h5>
<p class="dark:text-black">{$t('index_page.create_a_quiz_from_scratch')}</p>
</div>
<div
class="m-2 rounded-lg p-2 bg-opacity-40 bg-white transition-all cursor-pointer lg:h-full"
on:click={() => {
selected_create_thing = SelectedCreateThing.Find;
}}
class:shadow-2xl={selected_create_thing === SelectedCreateThing.Find}
class:opacity-70={selected_create_thing !== SelectedCreateThing.Find}
>
<div
class="rounded-lg w-fit p-1 bg-lime-500 hover:bg-lime-400 transition shadow-lg"
>
<svg
class="w-8 h-8 text-black"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
aria-label="magnifying glass-Icon"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>
</div>
<h5 class="text-xl dark:text-black">{$t('words.find')}</h5>
<p class="dark:text-black">{$t('index_page.find_or_explore')}</p>
</div>
<!--<div
class="m-2 rounded-lg p-2 bg-opacity-40 bg-white transition-all cursor-pointer lg:h-full"
on:click={() => {
selected_create_thing = SelectedCreateThing.Import;
}}
class:shadow-2xl={selected_create_thing === SelectedCreateThing.Import}
class:opacity-70={selected_create_thing !== SelectedCreateThing.Import}
>
<div
class="rounded-lg w-fit p-1 bg-lime-500 hover:bg-lime-400 transition shadow-lg"
>
<svg
class="w-8 h-8 text-black"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
aria-label="Cloud with arrow pointing down"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M9 19l3 3m0 0l3-3m-3 3V10"
/>
</svg>
</div>
<h5 class="text-xl dark:text-black">{$t('words.import')}</h5>
<p class="dark:text-black">
{$t('index_page.import_quiz_from_kahoot_and_edit')}
</p>
</div>-->
</div>
</div>
</section>
<section class="mt-24">
<div class="flex justify-center w-full">
<h2 class="text-center text-3xl rounded-t-lg bg-opacity-40 bg-white py-2 px-6">
{$t('index_page.play_quiz')}
</h2>
</div>
<div
class="grid grid-rows-2 lg:grid-rows-1 lg:grid-cols-2 bg-opacity-40 bg-white shadow-lg mb-12 lg:mx-12 mx-4 rounded-lg"
>
<div>
<div class="p-2 rounded-lg">
{#if selected_play_thing === SelectedPlayThing.Select}
<img
class="rounded-lg relative"
src={SelectScreenshot}
in:fade
alt="Screenshot of the screen where an answer can be selected"
/>
{:else if selected_play_thing === SelectedPlayThing.Results}
<img
class="rounded-lg relative"
src={ResultScreenshot}
in:fade
alt="Screenshot of the results with a table showing how many players chose which answer"
/>
{:else if selected_play_thing === SelectedPlayThing.Winners}
<img
class="rounded-lg relative"
src={WinnersScreenshot}
in:fade
alt="Screenshot of the import-page showing an URL to Kahoot! entered"
/>
{:else}
<p>Shouldn't happen!</p>
{/if}
</div>
</div>
<div
class="lg:border-l lg:border-l-black lg:border-t-0 border-t border-t-black flex lg:flex-col flex-row stretch"
>
<div
class="m-2 rounded-lg p-2 bg-opacity-40 bg-white transition-all cursor-pointer lg:h-full"
on:click={() => {
selected_play_thing = SelectedPlayThing.Select;
}}
class:shadow-2xl={selected_play_thing === SelectedPlayThing.Select}
class:opacity-70={selected_play_thing !== SelectedPlayThing.Select}
>
<div
class="rounded-lg bg-emerald-300 w-fit p-1 bg-lime-500 hover:bg-lime-400 transition shadow-lg"
>
<svg
aria-label="Mouse-Click icon"
class="w-8 h-8 text-black"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15 15l-2 5L9 9l11 4-5 2zm0 0l5 5M7.188 2.239l.777 2.897M5.136 7.965l-2.898-.777M13.95 4.05l-2.122 2.122m-5.657 5.656l-2.12 2.122"
/>
</svg>
</div>
<h5 class="text-xl w-fit dark:text-black">{$t('index_page.select_answer')}</h5>
<p class="dark:text-black">{$t('index_page.choose_answer_wisely')}</p>
</div>
<div
class="m-2 rounded-lg p-2 bg-opacity-40 bg-white transition-all cursor-pointer lg:h-full"
on:click={() => {
selected_play_thing = SelectedPlayThing.Results;
}}
class:shadow-2xl={selected_play_thing === SelectedPlayThing.Results}
class:opacity-70={selected_play_thing !== SelectedPlayThing.Results}
>
<div
class="rounded-lg bg-emerald-300 w-fit p-1 bg-lime-500 hover:bg-lime-400 transition shadow-lg"
>
<svg
aria-label="context-menu icon"
class="w-8 h-8 text-black"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 10h16M4 14h16M4 18h16"
/>
</svg>
</div>
<h5 class="text-xl dark:text-black">{$t('index_page.view_results')}</h5>
<p class="dark:text-black">{$t('index_page.check_if_chosen_wisely')}</p>
</div>
<div
class="m-2 rounded-lg p-2 bg-opacity-40 bg-white transition-all cursor-pointer lg:h-full"
on:click={() => {
selected_play_thing = SelectedPlayThing.Winners;
}}
class:shadow-2xl={selected_play_thing === SelectedPlayThing.Winners}
class:opacity-70={selected_play_thing !== SelectedPlayThing.Winners}
>
<div
class="rounded-lg bg-emerald-300 w-fit p-1 bg-lime-500 hover:bg-lime-400 transition shadow-lg"
>
<svg
aria-label="sparkling stars-icon"
class="w-8 h-8 text-black"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z"
/>
</svg>
</div>
<h5 class="text-xl dark:text-black">{$t('index_page.list_winners')}</h5>
<p class="dark:text-black">{$t('index_page.get_ranking_and_winners')}</p>
</div>
</div>
</div>
</section>
<section class="mt-24">
<div class="flex justify-center w-full">
<h2 class="text-center text-3xl rounded-t-lg bg-opacity-40 bg-white py-2 px-6">
{$t('index_page.why_classquiz')}
</h2>
</div>
<div
class="grid grid-rows-2 lg:grid-rows-1 lg:grid-cols-2 bg-opacity-40 bg-white shadow-lg mb-12 lg:mx-12 mx-4 rounded-lg"
>
<div>
<div class="p-12 rounded-lg flex justify-center items-center h-full">
<p class="dark:text-black">
{classquiz_reasons[selected_classquiz_reason].content}
</p>
</div>
</div>
<div
class="lg:border-l lg:border-l-black lg:border-t-0 border-t border-t-black flex lg:flex-col flex-row stretch overflow-x-auto why-classquiz"
>
{#each classquiz_reasons as reason, index}
<div
class="m-2 rounded-lg p-2 bg-opacity-40 bg-white transition-all cursor-pointer lg:h-full"
on:click={() => {
selected_classquiz_reason = index;
}}
class:shadow-2xl={selected_classquiz_reason === index}
class:opacity-70={selected_classquiz_reason !== index}
>
<h5 class="text-xl dark:text-black">{reason.headline}</h5>
</div>
{/each}
</div>
</div>
</section>
</div>
{#if newsletterModalOpen}
<div
class="fixed bottom-8 right-5 bg-white rounded-lg h-fit w-11/12 ml-5 lg:w-2/12 z-50 p-2 bg-white dark:bg-gray-700"
transition:fly
>
<Newsletter bind:open={newsletterModalOpen} />
</div>
{/if}
<Footer />
<style>
.why-classquiz::-webkit-scrollbar {
height: 0.8rem;
margin-bottom: 5rem;
}
.why-classquiz::-webkit-scrollbar-track {
box-shadow: inset 0 0 10px 10px transparent;
border: solid 3px transparent;
}
.why-classquiz::-webkit-scrollbar-thumb {
box-shadow: inset 0 0 10px 10px #374151;
border: solid 3px transparent;
border-radius: 15px;
}
.why-classquiz::-webkit-scrollbar-thumb:hover {
box-shadow: inset 0 0 10px 10px #555;
border: solid 3px transparent;
}
</style>
@@ -1,141 +0,0 @@
<!--
SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
SPDX-License-Identifier: MPL-2.0
-->
<script lang="ts">
export let session_data = {};
export let step;
export let selected_method;
let available_methods;
const set_available_methods = (step_var: number) => {
if (step_var === 1) {
available_methods = session_data.step_1;
} else if (step_var === 2) {
available_methods = session_data.step_2;
}
};
$: set_available_methods(step);
</script>
<div class="px-6 py-4">
<h2 class="text-3xl font-bold text-center text-gray-700 dark:text-white">ClassQuiz</h2>
<div class="w-full mt-4">
<div class="dark:bg-gray-800 bg-white p-4 rounded-lg">
<ul class="flex flex-col gap-4">
{#if available_methods.includes('PASSKEY')}
<div
class="flex flex-row bg-gray-100 dark:bg-gray-700 rounded-lg p-2 hover:cursor-pointer hover:bg-gray-200 transition"
on:click={() => {
selected_method = 'PASSKEY';
}}
on:keyup={() => {
selected_method = 'PASSKEY';
}}
>
<!-- heroicons/key -->
<svg
class="w-12 h-12"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"
/>
</svg>
<div class="ml-2">
<p>Key</p>
<p class="text-sm">Authenticate using a security key</p>
</div>
</div>
{/if}
{#if available_methods.includes('PASSWORD')}
<div
class="flex flex-row bg-gray-100 dark:bg-gray-700 rounded-lg p-2 hover:cursor-pointer hover:bg-gray-200 transition"
on:click={() => {
selected_method = 'PASSWORD';
}}
on:keyup={() => {
selected_method = 'PASSWORD';
}}
>
<!-- iconoir/password-cursor -->
<svg
class="w-12 h-12 dark:text-white"
stroke-width="2"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M21 13V8a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h7"
stroke="currentColor"
stroke-width="2.03"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
clip-rule="evenodd"
d="M20.879 16.917c.494.304.463 1.043-.045 1.101l-2.567.291-1.151 2.312c-.228.459-.933.234-1.05-.334l-1.255-6.116c-.099-.48.333-.782.75-.525l5.318 3.271z"
stroke="currentColor"
stroke-width="2.03"
/>
<path
d="M12 11.01l.01-.011M16 11.01l.01-.011M8 11.01l.01-.011"
stroke="currentColor"
stroke-width="2.03"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<div class="ml-2">
<p>Password</p>
<p class="text-sm">Authenticate using a Password</p>
</div>
</div>
{/if}
{#if available_methods.includes('TOTP')}
<div
class="flex flex-row bg-gray-100 rounded-lg p-2 hover:cursor-pointer hover:bg-gray-200 transition"
on:click={() => {
selected_method = 'TOTP';
}}
on:keyup={() => {
selected_method = 'TOTP';
}}
>
<!-- heroicons/clock -->
<svg
class="w-12 h-12"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<div class="ml-2">
<p>Totp</p>
<p class="text-sm">Authenticate using a one-time password</p>
</div>
</div>
{/if}
</ul>
</div>
</div>
</div>
@@ -1,113 +0,0 @@
<!--
SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
SPDX-License-Identifier: MPL-2.0
-->
<script lang="ts">
import { getLocalization } from '$lib/i18n';
import OAuthBlock from './oauth_block.svelte';
export let session_data = {};
export let step;
const { t } = getLocalization();
let email = '';
let emailEmpty = true;
let isSubmitting = false;
$: emailEmpty = email === '';
const start_login = async (): Promise<void> => {
if (emailEmpty) {
return;
}
isSubmitting = true;
// alert("Alert message");
const res = await fetch('/api/v1/login/start', {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email: email })
});
session_data = await res.json();
step = 1;
};
</script>
<div class="px-6 py-4">
<h2 class="text-3xl font-bold text-center text-gray-700 dark:text-white">ClassQuiz</h2>
<h3 class="mt-1 text-xl font-medium text-center text-gray-600 dark:text-gray-200">
{$t('login_page.welcome_back')}
</h3>
<p class="mt-1 text-center text-gray-500 dark:text-gray-400">
{$t('login_page.login_or_create_account')}
</p>
<form on:submit|preventDefault={start_login}>
<div class="w-full mt-4">
<div class="dark:bg-gray-800 bg-white p-4 rounded-lg">
<div class="relative bg-inherit w-full">
<input
id="email"
bind:value={email}
name="email"
type="text"
class="w-full peer bg-transparent h-10 rounded-lg text-gray-700 dark:text-white placeholder-transparent ring-2 px-2 ring-gray-500 focus:ring-sky-600 focus:outline-none focus:border-rose-600"
placeholder={$t('login_page.email_or_username')}
autocomplete="email"
/>
<label
for="email"
class="absolute cursor-text left-0 -top-3 text-sm text-gray-700 dark:text-white bg-inherit mx-1 px-1 peer-placeholder-shown:text-base peer-placeholder-shown:text-gray-500 peer-placeholder-shown:top-2 peer-focus:-top-3 peer-focus:text-sky-600 peer-focus:text-sm transition-all"
>
{$t('login_page.email_or_username')}
</label>
</div>
</div>
<div class="flex items-center justify-between mt-4">
<a
href="/account/reset-password"
class="text-sm text-gray-600 dark:text-gray-200 hover:text-gray-500"
>{$t('register_page.forgot_password?')}</a
>
<button
class="px-4 py-2 leading-5 text-white transition-colors duration-200 transform bg-gray-700 rounded hover:bg-gray-600 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50"
disabled={emailEmpty}
type="submit"
>
{#if isSubmitting}
<svg class="h-4 w-4 animate-spin mx-auto" viewBox="3 3 18 18">
<path
class="fill-black"
d="M12 5C8.13401 5 5 8.13401 5 12C5 15.866 8.13401 19 12 19C15.866 19 19 15.866 19 12C19 8.13401 15.866 5 12 5ZM3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12Z"
/>
<path
class="fill-blue-100"
d="M16.9497 7.05015C14.2161 4.31648 9.78392 4.31648 7.05025 7.05015C6.65973 7.44067 6.02656 7.44067 5.63604 7.05015C5.24551 6.65962 5.24551 6.02646 5.63604 5.63593C9.15076 2.12121 14.8492 2.12121 18.364 5.63593C18.7545 6.02646 18.7545 6.65962 18.364 7.05015C17.9734 7.44067 17.3403 7.44067 16.9497 7.05015Z"
/>
</svg>
{:else}
{$t('words.continue')}
{/if}
</button>
</div>
<OAuthBlock />
</div>
</form>
</div>
<div class="flex items-center justify-center py-4 text-center bg-gray-50 dark:bg-gray-700">
<span class="text-sm text-gray-600 dark:text-gray-200"
>{$t('login_page.already_have_account')}
</span>
<a
href="/account/register"
class="mx-2 text-sm font-bold text-blue-500 dark:text-blue-400 hover:underline"
>{$t('words.register')}</a
>
</div>