feat: timer
This commit is contained in:
parent
2dd913eb86
commit
fde6b26569
16 changed files with 127 additions and 78 deletions
50
src/lib/components/timer.svelte
Normal file
50
src/lib/components/timer.svelte
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { onDestroy } from 'svelte';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
date: string;
|
||||||
|
class?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
let { date, class: className }: Props = $props();
|
||||||
|
|
||||||
|
let days = $state(0);
|
||||||
|
let hours = $state(0);
|
||||||
|
let minutes = $state(0);
|
||||||
|
let seconds = $state(0);
|
||||||
|
|
||||||
|
let time = new Date(date).getTime();
|
||||||
|
|
||||||
|
let interval = setInterval(() => {
|
||||||
|
let now = new Date().getTime();
|
||||||
|
let distance = time - now;
|
||||||
|
|
||||||
|
days = Math.floor(distance / (1000 * 60 * 60 * 24));
|
||||||
|
hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||||
|
minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
||||||
|
seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
||||||
|
|
||||||
|
if (distance < 0) {
|
||||||
|
clearInterval(interval);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
clearInterval(interval);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span class={className}>
|
||||||
|
{#if days > 0}
|
||||||
|
{days}d
|
||||||
|
{/if}
|
||||||
|
{#if hours > 0}
|
||||||
|
{hours}h
|
||||||
|
{/if}
|
||||||
|
{#if minutes > 0}
|
||||||
|
{minutes}m
|
||||||
|
{/if}
|
||||||
|
{#if seconds > 0}
|
||||||
|
{seconds}s
|
||||||
|
{/if}
|
||||||
|
</span>
|
|
@ -1,14 +1,12 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Snippet } from 'svelte';
|
import type { LayoutProps } from './$types';
|
||||||
|
|
||||||
import AppSidebar from '$lib/components/app-sidebar.svelte';
|
import AppSidebar from '$lib/components/app-sidebar.svelte';
|
||||||
|
import Breadcrumb from '$lib/components/breadcrumb.svelte';
|
||||||
import * as Sidebar from '$lib/components/ui/sidebar';
|
import * as Sidebar from '$lib/components/ui/sidebar';
|
||||||
import { Toaster } from '$lib/components/ui/sonner';
|
import { Toaster } from '$lib/components/ui/sonner';
|
||||||
import Breadcrumb from '$lib/components/breadcrumb.svelte';
|
|
||||||
|
|
||||||
type Props = { children: Snippet };
|
let { children }: LayoutProps = $props();
|
||||||
|
|
||||||
let { children }: Props = $props();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Sidebar.Provider>
|
<Sidebar.Provider>
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PageData } from './$types';
|
import type { PageProps } from './$types';
|
||||||
|
|
||||||
import { Button } from '$lib/components/ui/button';
|
import { Button } from '$lib/components/ui/button';
|
||||||
import * as Card from '$lib/components/ui/card';
|
import * as Card from '$lib/components/ui/card';
|
||||||
|
|
||||||
type Props = { data: PageData };
|
let { data }: PageProps = $props();
|
||||||
|
|
||||||
let { data }: Props = $props();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="flex w-full flex-col gap-4">
|
<section class="flex w-full flex-col gap-4">
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PageData } from './$types';
|
import type { PageProps } from './$types';
|
||||||
|
|
||||||
import Chapter from '$lib/components/chapter.svelte';
|
import Chapter from '$lib/components/chapter.svelte';
|
||||||
import { Input } from '$lib/components/ui/input';
|
import { Input } from '$lib/components/ui/input';
|
||||||
|
|
||||||
type Props = { data: PageData };
|
let { data }: PageProps = $props();
|
||||||
|
|
||||||
let { data }: Props = $props();
|
|
||||||
|
|
||||||
// TODO: Handle search query
|
// TODO: Handle search query
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PageData, Snapshot } from './$types';
|
import type { PageProps, Snapshot } from './$types';
|
||||||
|
|
||||||
import BarChart from 'lucide-svelte/icons/bar-chart-2';
|
import BarChart from 'lucide-svelte/icons/bar-chart-2';
|
||||||
import Users from 'lucide-svelte/icons/users';
|
import Users from 'lucide-svelte/icons/users';
|
||||||
|
@ -7,9 +7,7 @@
|
||||||
import Puzzle from '$lib/components/puzzle.svelte';
|
import Puzzle from '$lib/components/puzzle.svelte';
|
||||||
import Button from '$lib/components/ui/button/button.svelte';
|
import Button from '$lib/components/ui/button/button.svelte';
|
||||||
|
|
||||||
type Props = { data: PageData };
|
let { data }: PageProps = $props();
|
||||||
|
|
||||||
let { data }: Props = $props();
|
|
||||||
|
|
||||||
// TODO: Refactor, this is for event purpose only, this is a mess
|
// TODO: Refactor, this is for event purpose only, this is a mess
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import type { PageProps } from './$types';
|
||||||
|
|
||||||
import { enhance } from '$app/forms';
|
import { enhance } from '$app/forms';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
import type { ActionData, PageData } from './$types';
|
|
||||||
|
import { toast } from 'svelte-sonner';
|
||||||
|
|
||||||
import Code from 'lucide-svelte/icons/code';
|
import Code from 'lucide-svelte/icons/code';
|
||||||
import Loader from 'lucide-svelte/icons/loader-circle';
|
import Loader from 'lucide-svelte/icons/loader-circle';
|
||||||
|
@ -12,28 +15,24 @@
|
||||||
|
|
||||||
import Button from '$lib/components/ui/button/button.svelte';
|
import Button from '$lib/components/ui/button/button.svelte';
|
||||||
import Input from '$lib/components/ui/input/input.svelte';
|
import Input from '$lib/components/ui/input/input.svelte';
|
||||||
import { toast } from 'svelte-sonner';
|
|
||||||
|
|
||||||
type Props = {
|
let { data, form }: PageProps = $props();
|
||||||
data: PageData;
|
|
||||||
form: ActionData;
|
|
||||||
};
|
|
||||||
|
|
||||||
let { data, form }: Props = $props();
|
|
||||||
|
|
||||||
let limit = 6;
|
let limit = 6;
|
||||||
|
|
||||||
let name = $state('');
|
let name = $state('');
|
||||||
let submitting = $state(false);
|
let submitting = $state(false);
|
||||||
|
|
||||||
const filteredGroups = $derived(data.groups.filter((group) => {
|
const filteredGroups = $derived(
|
||||||
|
data.groups.filter((group) => {
|
||||||
const regex = new RegExp(name, 'i');
|
const regex = new RegExp(name, 'i');
|
||||||
return regex.test(group.name);
|
return regex.test(group.name);
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const hasGroup = $derived(page.data.user?.groups.some((g) =>
|
const hasGroup = $derived(
|
||||||
data.groups.map((g) => g.name).includes(g.name)
|
page.data.user?.groups.some((g) => data.groups.map((g) => g.name).includes(g.name))
|
||||||
));
|
);
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (form?.message) {
|
if (form?.message) {
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import type { PageServerLoad } from "./$types";
|
||||||
|
import { API_URL } from "$env/static/private";
|
||||||
|
|
||||||
|
import { redirect } from "@sveltejs/kit";
|
||||||
|
|
||||||
|
import type { Chapter } from "$lib/types";
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async ({ locals, fetch, params: { chapterId } }) => {
|
||||||
|
if (!locals.user) {
|
||||||
|
redirect(302, "/login");
|
||||||
|
}
|
||||||
|
|
||||||
|
let chapter: Chapter | null = null;
|
||||||
|
|
||||||
|
const res = await fetch(API_URL + `/chapter/${chapterId}`);
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
redirect(302, "/chapters");
|
||||||
|
}
|
||||||
|
|
||||||
|
chapter = await res.json();
|
||||||
|
|
||||||
|
if (!chapter || !chapter.show && !(chapter.start && chapter.end)) redirect(302, "/chapter/" + chapterId)
|
||||||
|
|
||||||
|
return {
|
||||||
|
chapter
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,13 +1,18 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
|
|
||||||
|
import type { PageProps } from './$types';
|
||||||
|
|
||||||
import { onDestroy, onMount } from 'svelte';
|
import { onDestroy, onMount } from 'svelte';
|
||||||
import { derived } from 'svelte/store';
|
import { derived } from 'svelte/store';
|
||||||
|
|
||||||
|
import Timer from '$lib/components/timer.svelte';
|
||||||
|
|
||||||
import { createStateStore } from '$lib/stores/state';
|
import { createStateStore } from '$lib/stores/state';
|
||||||
import { connectWebSocket } from '$lib/stores/websocket';
|
import { connectWebSocket } from '$lib/stores/websocket';
|
||||||
|
|
||||||
|
let { data }: PageProps = $props();
|
||||||
|
|
||||||
type Broadcast = {
|
type Broadcast = {
|
||||||
message: string;
|
message: string;
|
||||||
};
|
};
|
||||||
|
@ -38,6 +43,7 @@
|
||||||
Ici vous pouvez voir les messages envoyés par les administrateurs
|
Ici vous pouvez voir les messages envoyés par les administrateurs
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<Timer class="text-xl font-bold" date={data.chapter.end!} />
|
||||||
</header>
|
</header>
|
||||||
<ul class="flex flex-col gap-2">
|
<ul class="flex flex-col gap-2">
|
||||||
{#if broadcasts.length === 0}
|
{#if broadcasts.length === 0}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PageData } from './$types';
|
import type { PageProps } from './$types';
|
||||||
|
|
||||||
import { zodClient } from 'sveltekit-superforms/adapters';
|
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||||
import { superForm } from 'sveltekit-superforms/client';
|
import { superForm } from 'sveltekit-superforms/client';
|
||||||
|
@ -10,11 +10,7 @@
|
||||||
import Loader from 'lucide-svelte/icons/loader-circle';
|
import Loader from 'lucide-svelte/icons/loader-circle';
|
||||||
import { formSchema } from './schema';
|
import { formSchema } from './schema';
|
||||||
|
|
||||||
type Props = {
|
let { data }: PageProps = $props();
|
||||||
data: PageData;
|
|
||||||
};
|
|
||||||
|
|
||||||
let { data }: Props = $props();
|
|
||||||
|
|
||||||
const form = superForm(data.form, {
|
const form = superForm(data.form, {
|
||||||
validators: zodClient(formSchema),
|
validators: zodClient(formSchema),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import './prism-night-owl.css';
|
import './prism-night-owl.css';
|
||||||
|
|
||||||
import type { PageData } from './$types';
|
import type { PageProps } from './$types';
|
||||||
|
|
||||||
import { enhance } from '$app/forms';
|
import { enhance } from '$app/forms';
|
||||||
|
|
||||||
|
@ -11,15 +11,10 @@
|
||||||
import { Input } from '$lib/components/ui/input';
|
import { Input } from '$lib/components/ui/input';
|
||||||
|
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { toast } from 'svelte-sonner';
|
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
|
import { toast } from 'svelte-sonner';
|
||||||
|
|
||||||
type Props = {
|
let { data }: PageProps = $props();
|
||||||
data: PageData;
|
|
||||||
};
|
|
||||||
|
|
||||||
// export let data: PageData;
|
|
||||||
let { data }: Props = $props();
|
|
||||||
|
|
||||||
let submitting = $state(false);
|
let submitting = $state(false);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PageData } from './$types';
|
import type { PageProps } from './$types';
|
||||||
|
|
||||||
import { LEADERBOARD } from '$lib/constants';
|
import { LEADERBOARD } from '$lib/constants';
|
||||||
import { cn } from '$lib/utils';
|
import { cn } from '$lib/utils';
|
||||||
|
|
||||||
type Props = { data: PageData };
|
let { data }: PageProps = $props();
|
||||||
|
|
||||||
let { data }: Props = $props();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="flex h-full w-full flex-col gap-4">
|
<section class="flex h-full w-full flex-col gap-4">
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Snippet } from 'svelte';
|
import type { LayoutProps } from './$types';
|
||||||
|
|
||||||
import { Toaster } from '$lib/components/ui/sonner';
|
import { Toaster } from '$lib/components/ui/sonner';
|
||||||
|
|
||||||
type Props = {
|
let { children }: LayoutProps = $props();
|
||||||
children: Snippet;
|
|
||||||
};
|
|
||||||
|
|
||||||
let { children }: Props = $props();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="container flex h-screen">
|
<div class="container flex h-screen">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
|
|
||||||
import type { PageData } from './$types';
|
import type { PageProps } from './$types';
|
||||||
|
|
||||||
import Loader from 'lucide-svelte/icons/loader-circle';
|
import Loader from 'lucide-svelte/icons/loader-circle';
|
||||||
import { superForm } from 'sveltekit-superforms';
|
import { superForm } from 'sveltekit-superforms';
|
||||||
|
@ -12,9 +12,7 @@
|
||||||
|
|
||||||
import { formSchema } from './schema';
|
import { formSchema } from './schema';
|
||||||
|
|
||||||
type Props = { data: PageData };
|
let { data }: PageProps = $props();
|
||||||
|
|
||||||
let { data }: Props = $props();
|
|
||||||
|
|
||||||
const links = [
|
const links = [
|
||||||
{ href: `/register${page.url.search}`, name: "S'inscrire" },
|
{ href: `/register${page.url.search}`, name: "S'inscrire" },
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
import type { PageData } from './$types';
|
import type { PageProps } from './$types';
|
||||||
|
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
|
|
||||||
|
@ -14,9 +14,7 @@
|
||||||
|
|
||||||
import { formConfirmationSchema, formSchema } from './schema';
|
import { formConfirmationSchema, formSchema } from './schema';
|
||||||
|
|
||||||
type Props = { data: PageData };
|
let { data }: PageProps = $props();
|
||||||
|
|
||||||
let { data }: Props = $props();
|
|
||||||
|
|
||||||
const links = [{ href: `/login${page.url.search}`, name: 'Se connecter' }];
|
const links = [{ href: `/login${page.url.search}`, name: 'Se connecter' }];
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
import type { PageData } from './$types';
|
import type { PageProps } from './$types';
|
||||||
|
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
|
|
||||||
|
@ -14,9 +14,7 @@
|
||||||
|
|
||||||
import { formConfirmationSchema, formSchema } from './schema';
|
import { formConfirmationSchema, formSchema } from './schema';
|
||||||
|
|
||||||
type Props = { data: PageData };
|
let { data }: PageProps = $props();
|
||||||
|
|
||||||
let { data }: Props = $props();
|
|
||||||
|
|
||||||
const links = [{ href: `/login${page.url.search}`, name: 'Se connecter' }];
|
const links = [{ href: `/login${page.url.search}`, name: 'Se connecter' }];
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '../app.css';
|
import '../app.css';
|
||||||
|
|
||||||
import type { Snippet } from 'svelte';
|
|
||||||
|
|
||||||
import Metadata from '$lib/components/metadata.svelte';
|
import Metadata from '$lib/components/metadata.svelte';
|
||||||
|
import type { LayoutProps } from './$types';
|
||||||
|
|
||||||
type Props = {
|
let { children }: LayoutProps = $props();
|
||||||
children: Snippet;
|
|
||||||
};
|
|
||||||
|
|
||||||
let { children }: Props = $props();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Metadata />
|
<Metadata />
|
||||||
|
|
Loading…
Add table
Reference in a new issue