feat: 🚀 😃 convert repo into a monorepo 🚀 😃 (#51)
* Merge main into turbo-monrepo * feat: rename apps * feat: remove supbase videos and serve all from project * feat: move supabase to root * feat: update README * docs: update link
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { SyncLoader } from 'svelte-loading-spinners';
|
||||
import PlayContainer from './Container.svelte';
|
||||
import PlayHeader from './Header/index.svelte';
|
||||
import { quizStore, playQuizStore } from '$lib/utils/store/org';
|
||||
import { STEPS } from '$lib/utils/constants/quiz';
|
||||
import { genQuizPin } from '$lib/utils/functions/org';
|
||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
|
||||
|
||||
let isGettingPin = true;
|
||||
|
||||
function getPin() {
|
||||
setTimeout(() => {
|
||||
$quizStore.pin = genQuizPin();
|
||||
isGettingPin = false;
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
function goToPlayersStep() {
|
||||
$playQuizStore.step = STEPS.WAIT_FOR_PLAYERS;
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
getPin();
|
||||
});
|
||||
</script>
|
||||
|
||||
<PlayContainer>
|
||||
<div slot="header">
|
||||
<PlayHeader startCount={true} showCountDown={true} />
|
||||
</div>
|
||||
|
||||
<div slot="body" class="w-full rounded-md bg-white dark:bg-neutral-800 py-7 px-5">
|
||||
<div class="mb-3">
|
||||
<p>1. Visit</p>
|
||||
<h3>play.classroomio.com</h3>
|
||||
</div>
|
||||
<div class="">
|
||||
<p>2. Enter Pin</p>
|
||||
{#if isGettingPin}
|
||||
<SyncLoader size="50" color="#1d4ed8" unit="px" duration="1s" />
|
||||
{:else}
|
||||
<h3>{$quizStore.pin}</h3>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div slot="footer" class="flex justify-center items-center">
|
||||
<p class="font-bold mr-3">Let's go</p>
|
||||
<PrimaryButton label="View Players" variant={VARIANTS.OUTLINED} onClick={goToPlayersStep} />
|
||||
</div>
|
||||
</PlayContainer>
|
||||
@@ -0,0 +1,43 @@
|
||||
<div class="root flex flex-col justify-between h-full m-auto">
|
||||
{#if $$slots.header}
|
||||
<!-- HEADER -->
|
||||
<div class="header">
|
||||
<slot name="header" />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $$slots.body}
|
||||
<!-- BODY -->
|
||||
<div class="body mb-3">
|
||||
<slot name="body" />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $$slots.footer}
|
||||
<!-- FOOTER -->
|
||||
<div class="footer bg-white dark:bg-neutral-800 py-6 px-2 m-auto">
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.root {
|
||||
max-width: 680px;
|
||||
width: 80%;
|
||||
height: 95vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 15%;
|
||||
}
|
||||
|
||||
.body {
|
||||
min-height: 60%;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
.footer {
|
||||
max-width: 400px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,7 @@
|
||||
<script>
|
||||
import CircleContent from './CircleContent.svelte';
|
||||
|
||||
export let answers = 0;
|
||||
</script>
|
||||
|
||||
<CircleContent value={answers} label="Answer(s)" />
|
||||
@@ -0,0 +1,45 @@
|
||||
<script>
|
||||
import { slide } from 'svelte/transition';
|
||||
|
||||
export let value = false;
|
||||
export let label = '';
|
||||
export let className = '';
|
||||
|
||||
function fadeSlide(node, options) {
|
||||
const slideTrans = slide(node, options);
|
||||
return {
|
||||
duration: options.duration,
|
||||
css: (t) => `
|
||||
${slideTrans.css(t)}
|
||||
opacity: ${t};
|
||||
`
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="circle flex items-center flex-col justify-center {className}">
|
||||
{#key value}
|
||||
<h3 class="text-primary-600" transition:fadeSlide={{ duration: 500 }}>
|
||||
{value}
|
||||
</h3>
|
||||
{/key}
|
||||
<p class="text-primary-600 text-md">{label}</p>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.circle {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
line-height: 100px;
|
||||
border-radius: 50%;
|
||||
font-size: 50px;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
}
|
||||
.circle h3 {
|
||||
font-size: 40px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,39 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import CircleContent from './CircleContent.svelte';
|
||||
|
||||
export let startCount = false;
|
||||
export let timelimit = '';
|
||||
|
||||
let countDownNo = 0;
|
||||
let started = false;
|
||||
|
||||
function triggerCountDown(start) {
|
||||
if (!start || started) return;
|
||||
|
||||
const getNum = (k) => parseInt(timelimit.replace(k, ''));
|
||||
|
||||
if (timelimit.includes('s')) {
|
||||
countDownNo = getNum('s');
|
||||
} else if (timelimit.includes('m')) {
|
||||
countDownNo = getNum('m') * 60;
|
||||
}
|
||||
|
||||
window.refreshIntervalId = setInterval(() => {
|
||||
if (--countDownNo <= 0) {
|
||||
clearInterval(window.refreshIntervalId);
|
||||
}
|
||||
}, 1000);
|
||||
started = true;
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (startCount) {
|
||||
triggerCountDown(startCount);
|
||||
}
|
||||
});
|
||||
|
||||
$: triggerCountDown(startCount);
|
||||
</script>
|
||||
|
||||
<CircleContent value={countDownNo} label="Second(s)" className="mr-3" />
|
||||
@@ -0,0 +1,18 @@
|
||||
<script>
|
||||
import { quizStore } from '$lib/utils/store/org';
|
||||
import Answer from './Answer.svelte';
|
||||
import Timer from './Timer.svelte';
|
||||
|
||||
export let startCount = false;
|
||||
export let showCountDown = false;
|
||||
</script>
|
||||
|
||||
<div class="flex justify-between items-center w-full">
|
||||
<h3 class="text-white">{$quizStore.title}</h3>
|
||||
{#if showCountDown}
|
||||
<div class="flex">
|
||||
<Timer {startCount} timelimit={$quizStore.timelimit} />
|
||||
<Answer />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
players
|
||||
@@ -0,0 +1 @@
|
||||
Podium
|
||||
@@ -0,0 +1,102 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { fly } from 'svelte/transition';
|
||||
import ChevronLeftIcon from 'carbon-icons-svelte/lib/ChevronLeft.svelte';
|
||||
import ChevronRightIcon from 'carbon-icons-svelte/lib/ChevronRight.svelte';
|
||||
import QuizQuestion from '../QuizQuestion.svelte';
|
||||
import PlayContainer from './Container.svelte';
|
||||
import PlayHeader from './Header/index.svelte';
|
||||
import { quizStore } from '$lib/utils/store/org';
|
||||
import { themeImages } from '$lib/utils/constants/quiz';
|
||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
|
||||
import IconButton from '$lib/components/IconButton/index.svelte';
|
||||
|
||||
export let exitPreview = () => {};
|
||||
|
||||
let bgImg;
|
||||
let totalQ = $quizStore.questions.length;
|
||||
let curQId = 0;
|
||||
let currentQuestion = $quizStore.questions[0] || {};
|
||||
|
||||
function handlePrev() {
|
||||
const prevQId = curQId - 1;
|
||||
console.log('prevQId', prevQId);
|
||||
const prev = $quizStore.questions[prevQId];
|
||||
console.log('prev', prev);
|
||||
if (prev) {
|
||||
currentQuestion = prev;
|
||||
curQId = prevQId;
|
||||
}
|
||||
}
|
||||
|
||||
function handleNext() {
|
||||
const nextQId = curQId + 1;
|
||||
console.log('nextqid', nextQId);
|
||||
const next = $quizStore.questions[nextQId];
|
||||
console.log('next', next);
|
||||
if (next) {
|
||||
currentQuestion = next;
|
||||
curQId = nextQId;
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
bgImg = themeImages[$quizStore.theme].play;
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if bgImg}
|
||||
<div
|
||||
class="absolute inset-0 z-50 bg-white h-screen w-screen"
|
||||
in:fly={{ y: 500, duration: 500 }}
|
||||
out:fly={{ y: 500, duration: 500 }}
|
||||
>
|
||||
<div
|
||||
class="p-5 h-full w-full"
|
||||
style="background: url({bgImg}) no-repeat center center fixed; -webkit-background-size: cover;-moz-background-size: cover;-o-background-size: cover;background-size: cover;min-height: 100vh;height: fit-content;"
|
||||
>
|
||||
<PlayContainer>
|
||||
<div slot="header">
|
||||
<PlayHeader startCount={true} showCountDown={true} />
|
||||
</div>
|
||||
|
||||
<div slot="body" class="quiz-body">
|
||||
{#if currentQuestion}
|
||||
<QuizQuestion {currentQuestion} isPreview={true} />
|
||||
{:else}
|
||||
<h2>No question added</h2>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div slot="footer" class="flex justify-center flex-col">
|
||||
{#if currentQuestion}
|
||||
<PrimaryButton
|
||||
label="Exit Preview"
|
||||
variant={VARIANTS.TEXT}
|
||||
onClick={exitPreview}
|
||||
className="w-fit"
|
||||
/>
|
||||
|
||||
<div class="flex justify-center items-center">
|
||||
<IconButton onClick={handlePrev} size="small">
|
||||
<ChevronLeftIcon size={16} class="carbon-icon dark:text-white" />
|
||||
</IconButton>
|
||||
<p class="mx-3">{curQId + 1} / {totalQ}</p>
|
||||
<IconButton onClick={handleNext} size="small">
|
||||
<ChevronRightIcon size={16} class="carbon-icon dark:text-white" />
|
||||
</IconButton>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</PlayContainer>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.quiz-body {
|
||||
width: 500px;
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1 @@
|
||||
Question
|
||||
@@ -0,0 +1 @@
|
||||
Scoreboard
|
||||
@@ -0,0 +1,47 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { fly } from 'svelte/transition';
|
||||
import { SyncLoader } from 'svelte-loading-spinners';
|
||||
import { themeImages, STEPS } from '$lib/utils/constants/quiz';
|
||||
import { quizStore, playQuizStore } from '$lib/utils/store/org';
|
||||
import ConnectToPlay from './ConnectToPlay.svelte';
|
||||
import Players from './Players.svelte';
|
||||
import Question from './Question.svelte';
|
||||
import Scoreboard from './Scoreboard.svelte';
|
||||
import Podium from './Podium.svelte';
|
||||
|
||||
let bgImg;
|
||||
|
||||
onMount(() => {
|
||||
bgImg = themeImages[$quizStore.theme].play;
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if bgImg}
|
||||
<div
|
||||
class="absolute inset-0 z-50 bg-white h-screen w-screen"
|
||||
in:fly={{ y: 500, duration: 500 }}
|
||||
out:fly={{ y: 500, duration: 500 }}
|
||||
>
|
||||
<div
|
||||
class="p-5 h-full w-full"
|
||||
style="background: url({bgImg}) no-repeat center center fixed; -webkit-background-size: cover;-moz-background-size: cover;-o-background-size: cover;background-size: cover;min-height: 100vh;height: fit-content;"
|
||||
>
|
||||
{#if $playQuizStore.step === STEPS.CONNECT_TO_PLAY}
|
||||
<ConnectToPlay />
|
||||
{:else if $playQuizStore.step === STEPS.WAIT_FOR_PLAYERS}
|
||||
<Players />
|
||||
{:else if $playQuizStore.step === STEPS.SHOW_NEXT_QUESTION}
|
||||
<Question />
|
||||
{:else if $playQuizStore.step === STEPS.SCOREBOARD}
|
||||
<Scoreboard />
|
||||
{:else if $playQuizStore.step === STEPS.PODIUM}
|
||||
<Podium />
|
||||
{:else}
|
||||
<div class="w-full m-auto">
|
||||
<SyncLoader size="20" color="#1d4ed8" unit="px" duration="1s" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
Reference in New Issue
Block a user