Compare commits
No commits in common. "e6cd69f0ad6af56b56474526329fda1358df10fc" and "b158d725d117bf07911b2a528e2d4c496c07fd31" have entirely different histories.
e6cd69f0ad
...
b158d725d1
22 changed files with 47 additions and 529 deletions
|
@ -19,7 +19,6 @@ export const handle = (async ({ event, resolve }) => {
|
||||||
event.locals.user = user;
|
event.locals.user = user;
|
||||||
} else {
|
} else {
|
||||||
event.locals.user = undefined;
|
event.locals.user = undefined;
|
||||||
event.cookies.delete('session');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import { cn } from '$lib/Utils';
|
|
||||||
import type { Chapter } from '$lib/types';
|
|
||||||
|
|
||||||
import ChevronRight from './Icons/ChevronRight.svelte';
|
|
||||||
|
|
||||||
export let chapter: Chapter;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<li
|
|
||||||
class={cn(
|
|
||||||
'font-code group relative flex h-full w-full rounded-md bg-primary-700 transition-colors duration-150 hover:bg-primary-600'
|
|
||||||
// 'cursor-not-allowed': !isStarted(chapter)
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<a class="flex h-full w-full items-center gap-4 p-4" href="/dashboard/chapters/{chapter.id}">
|
|
||||||
<div class="flex w-full flex-col justify-between gap-2 sm:flex-row">
|
|
||||||
<h2 class="text-base font-semibold">
|
|
||||||
{chapter.name}
|
|
||||||
</h2>
|
|
||||||
<!-- <div class="flex items-center gap-x-6">
|
|
||||||
{#if puzzle.tags?.length}
|
|
||||||
<div class="flex gap-x-2 text-sm">
|
|
||||||
{#each puzzle.tags as tag}
|
|
||||||
<span
|
|
||||||
class="inline-block rounded-md bg-primary-800 px-2 py-1 text-highlight-secondary"
|
|
||||||
>
|
|
||||||
{tag.name}
|
|
||||||
</span>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div> -->
|
|
||||||
</div>
|
|
||||||
<span class="translate-x-0 transform-gpu duration-300 group-hover:translate-x-2">
|
|
||||||
<ChevronRight />
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
|
@ -1,19 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import { cn } from '$lib';
|
|
||||||
|
|
||||||
let className: string | undefined | null = undefined;
|
|
||||||
|
|
||||||
export { className as class };
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svg
|
|
||||||
class={cn(className)}
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
height="24"
|
|
||||||
width="24"
|
|
||||||
viewBox="0 0 640 512"
|
|
||||||
fill="currentColor"
|
|
||||||
><path
|
|
||||||
d="M524.531,69.836a1.5,1.5,0,0,0-.764-.7A485.065,485.065,0,0,0,404.081,32.03a1.816,1.816,0,0,0-1.923.91,337.461,337.461,0,0,0-14.9,30.6,447.848,447.848,0,0,0-134.426,0,309.541,309.541,0,0,0-15.135-30.6,1.89,1.89,0,0,0-1.924-.91A483.689,483.689,0,0,0,116.085,69.137a1.712,1.712,0,0,0-.788.676C39.068,183.651,18.186,294.69,28.43,404.354a2.016,2.016,0,0,0,.765,1.375A487.666,487.666,0,0,0,176.02,479.918a1.9,1.9,0,0,0,2.063-.676A348.2,348.2,0,0,0,208.12,430.4a1.86,1.86,0,0,0-1.019-2.588,321.173,321.173,0,0,1-45.868-21.853,1.885,1.885,0,0,1-.185-3.126c3.082-2.309,6.166-4.711,9.109-7.137a1.819,1.819,0,0,1,1.9-.256c96.229,43.917,200.41,43.917,295.5,0a1.812,1.812,0,0,1,1.924.233c2.944,2.426,6.027,4.851,9.132,7.16a1.884,1.884,0,0,1-.162,3.126,301.407,301.407,0,0,1-45.89,21.83,1.875,1.875,0,0,0-1,2.611,391.055,391.055,0,0,0,30.014,48.815,1.864,1.864,0,0,0,2.063.7A486.048,486.048,0,0,0,610.7,405.729a1.882,1.882,0,0,0,.765-1.352C623.729,277.594,590.933,167.465,524.531,69.836ZM222.491,337.58c-28.972,0-52.844-26.587-52.844-59.239S193.056,219.1,222.491,219.1c29.665,0,53.306,26.82,52.843,59.239C275.334,310.993,251.924,337.58,222.491,337.58Zm195.38,0c-28.971,0-52.843-26.587-52.843-59.239S388.437,219.1,417.871,219.1c29.667,0,53.307,26.82,52.844,59.239C470.715,310.993,447.538,337.58,417.871,337.58Z"
|
|
||||||
/></svg
|
|
||||||
>
|
|
|
@ -1,23 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import { cn } from '$lib';
|
|
||||||
|
|
||||||
let className: string | undefined | null = undefined;
|
|
||||||
|
|
||||||
export { className as class };
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svg
|
|
||||||
class={cn(className)}
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
><path
|
|
||||||
d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"
|
|
||||||
/><path d="M9 18c-4.51 2-5-2-7-2" /></svg
|
|
||||||
>
|
|
|
@ -1,23 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import { cn } from '$lib';
|
|
||||||
|
|
||||||
let className: string | undefined | null = undefined;
|
|
||||||
|
|
||||||
export { className as class };
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svg
|
|
||||||
class={cn(className)}
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
><circle cx="12" cy="12" r="10" /><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" /><path
|
|
||||||
d="M12 17h.01"
|
|
||||||
/></svg
|
|
||||||
>
|
|
|
@ -12,6 +12,7 @@
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import { cn } from '$lib';
|
|
||||||
|
|
||||||
let className: string | undefined | null = undefined;
|
|
||||||
|
|
||||||
export { className as class };
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svg
|
|
||||||
class={cn(className)}
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
><path d="M22 10.5V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v12c0 1.1.9 2 2 2h12.5" /><path
|
|
||||||
d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"
|
|
||||||
/><path d="M18 15.28c.2-.4.5-.8.9-1a2.1 2.1 0 0 1 2.6.4c.3.4.5.8.5 1.3 0 1.3-2 2-2 2" /><path
|
|
||||||
d="M20 22v.01"
|
|
||||||
/></svg
|
|
||||||
>
|
|
|
@ -7,10 +7,7 @@
|
||||||
export let isOpen: boolean;
|
export let isOpen: boolean;
|
||||||
|
|
||||||
$: user = $page.data.user;
|
$: user = $page.data.user;
|
||||||
$: segments = $page.url.pathname.slice(1).split('/');
|
$: segment = $page.url.pathname.slice(1).replaceAll('/', ' / ');
|
||||||
$: breadcrumb = segments.map((segment, index) => {
|
|
||||||
return { name: segment, href: '/' + segments.slice(0, index + 1).join('/') };
|
|
||||||
}) as { name: string; href: string }[];
|
|
||||||
|
|
||||||
function handleToggle() {
|
function handleToggle() {
|
||||||
isOpen = !isOpen;
|
isOpen = !isOpen;
|
||||||
|
@ -30,24 +27,11 @@
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{#if !isOpen && segments.length}
|
{#if !isOpen && segment}
|
||||||
<div class="flex items-center justify-center capitalize text-highlight-secondary">
|
|
||||||
{#each breadcrumb as segment}
|
|
||||||
{@const last = segment === breadcrumb[breadcrumb.length - 1]}
|
|
||||||
<a class="hover:underline hover:text-primary" href={segment.href}>
|
|
||||||
{segment.name}
|
|
||||||
</a>
|
|
||||||
{#if !last}
|
|
||||||
<span class="mx-1 text-highlight-secondary">/</span>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<!-- {#if !isOpen && segment}
|
|
||||||
<div class="flex items-center justify-center capitalize text-highlight-secondary">
|
<div class="flex items-center justify-center capitalize text-highlight-secondary">
|
||||||
{segment}
|
{segment}
|
||||||
</div>
|
</div>
|
||||||
{/if} -->
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row items-center gap-2">
|
<div class="flex flex-row items-center gap-2">
|
||||||
<Avatar />
|
<Avatar />
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores';
|
|
||||||
import { cn } from '$lib/Utils';
|
import { cn } from '$lib/Utils';
|
||||||
import type { Puzzle } from '$lib/types';
|
import type { Puzzle } from '$lib/types';
|
||||||
import ChevronRight from './Icons/ChevronRight.svelte';
|
import ChevronRight from './Icons/ChevronRight.svelte';
|
||||||
|
|
||||||
export let puzzle: Puzzle;
|
export let puzzle: Puzzle;
|
||||||
|
|
||||||
const chapterId = $page.params.chapterId;
|
|
||||||
|
|
||||||
$: tags = puzzle.tags?.filter((tag) => !['easy', 'medium', 'hard'].includes(tag.name));
|
$: tags = puzzle.tags?.filter((tag) => !['easy', 'medium', 'hard'].includes(tag.name));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -23,10 +20,7 @@
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<a
|
<a class="flex h-full w-full items-center gap-4 p-4" href="/dashboard/puzzles/{puzzle.id}">
|
||||||
class="flex h-full w-full items-center gap-4 p-4"
|
|
||||||
href="/dashboard/chapters/{chapterId}/puzzle/{puzzle.id}"
|
|
||||||
>
|
|
||||||
<div class="flex w-full flex-col justify-between gap-2 sm:flex-row">
|
<div class="flex w-full flex-col justify-between gap-2 sm:flex-row">
|
||||||
<h2 class="text-base font-semibold">
|
<h2 class="text-base font-semibold">
|
||||||
{puzzle.name}
|
{puzzle.name}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
|
|
||||||
import { cn } from '$lib/Utils';
|
import { cn } from '$lib/Utils';
|
||||||
|
|
||||||
import Badge from '$lib/components/Icons/Badge.svelte';
|
import Badge from '$lib/components/Icons/Badge.svelte';
|
||||||
|
@ -8,10 +7,6 @@
|
||||||
import Dashboard from '$lib/components/Icons/Dashboard.svelte';
|
import Dashboard from '$lib/components/Icons/Dashboard.svelte';
|
||||||
import Leaderboard from '$lib/components/Icons/Leaderboard.svelte';
|
import Leaderboard from '$lib/components/Icons/Leaderboard.svelte';
|
||||||
import Settings from '$lib/components/Icons/Settings.svelte';
|
import Settings from '$lib/components/Icons/Settings.svelte';
|
||||||
import Discord from './Icons/Discord.svelte';
|
|
||||||
import Git from './Icons/Git.svelte';
|
|
||||||
import Help from './Icons/Help.svelte';
|
|
||||||
import Mail from './Icons/Mail.svelte';
|
|
||||||
|
|
||||||
$: path = $page.url.pathname;
|
$: path = $page.url.pathname;
|
||||||
$: isActive = (slug: string) => path === slug;
|
$: isActive = (slug: string) => path === slug;
|
||||||
|
@ -30,8 +25,8 @@
|
||||||
icon: Leaderboard
|
icon: Leaderboard
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Chapitres',
|
name: 'Puzzles',
|
||||||
slug: '/dashboard/chapters',
|
slug: '/dashboard/puzzles',
|
||||||
icon: Code
|
icon: Code
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -88,13 +83,7 @@
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<svelte:component
|
<svelte:component this={item.icon} />
|
||||||
this={item.icon}
|
|
||||||
class={cn({
|
|
||||||
'stroke-highlight-secondary transition-colors duration-150 group-hover:stroke-primary-0':
|
|
||||||
!isActive(item.slug)
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<span
|
<span
|
||||||
class={cn('hidden lg:block', {
|
class={cn('hidden lg:block', {
|
||||||
'block sm:hidden': isOpen,
|
'block sm:hidden': isOpen,
|
||||||
|
@ -117,108 +106,28 @@
|
||||||
<div class="px-4 pt-4">
|
<div class="px-4 pt-4">
|
||||||
<ul class="flex flex-col gap-4">
|
<ul class="flex flex-col gap-4">
|
||||||
<li>
|
<li>
|
||||||
<a
|
<!-- <NavItem
|
||||||
on:click={() => {
|
item={{
|
||||||
isOpen = false;
|
name: 'Discord',
|
||||||
}}
|
slug: 'https://discord.gg/72vuHcwUkE',
|
||||||
href="/dashboard/help"
|
icon: Icons.Discord,
|
||||||
class="group flex justify-center rounded-md px-3 py-3 text-sm transition-colors duration-150 hover:bg-primary-700 lg:justify-start"
|
disabled: false
|
||||||
>
|
}}
|
||||||
<div class="flex items-center gap-2">
|
isOpen={isOpen}
|
||||||
<Help
|
onClick={toggle}
|
||||||
class="stroke-highlight-secondary transition-colors duration-150 group-hover:stroke-primary-0"
|
/> -->
|
||||||
/>
|
|
||||||
<span
|
|
||||||
class={cn(
|
|
||||||
'hidden text-highlight-secondary transition-colors duration-150 group-hover:text-primary lg:block',
|
|
||||||
{
|
|
||||||
'block sm:hidden': isOpen,
|
|
||||||
hidden: !isOpen
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
Aide
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<!-- <NavItem
|
||||||
on:click={() => {
|
item={{
|
||||||
isOpen = false;
|
name: 'Git',
|
||||||
}}
|
slug: 'https://git.peerat.dev/Peer-at-Code',
|
||||||
href="mailto:cyberbottle@peerat.dev"
|
icon: Github,
|
||||||
class="group flex justify-center rounded-md px-3 py-3 text-sm transition-colors duration-150 hover:bg-primary-700 lg:justify-start"
|
disabled: false
|
||||||
>
|
}}
|
||||||
<div class="flex items-center gap-2">
|
isOpen={isOpen}
|
||||||
<Mail
|
onClick={toggle}
|
||||||
class="stroke-highlight-secondary transition-colors duration-150 group-hover:stroke-primary-0"
|
/> -->
|
||||||
/>
|
|
||||||
<span
|
|
||||||
class={cn(
|
|
||||||
'hidden text-highlight-secondary transition-colors duration-150 group-hover:text-primary lg:block',
|
|
||||||
{
|
|
||||||
'block sm:hidden': isOpen,
|
|
||||||
hidden: !isOpen
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
Mail
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
on:click={() => {
|
|
||||||
isOpen = false;
|
|
||||||
}}
|
|
||||||
href="//discord.gg/72vuHcwUkE"
|
|
||||||
class="group flex justify-center rounded-md px-3 py-3 text-sm transition-colors duration-150 hover:bg-primary-700 lg:justify-start"
|
|
||||||
>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<Discord
|
|
||||||
class="fill-highlight-secondary transition-colors duration-150 group-hover:fill-primary-0"
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
class={cn(
|
|
||||||
'hidden text-highlight-secondary transition-colors duration-150 group-hover:text-primary lg:block',
|
|
||||||
{
|
|
||||||
'block sm:hidden': isOpen,
|
|
||||||
hidden: !isOpen
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
Discord
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
on:click={() => {
|
|
||||||
isOpen = false;
|
|
||||||
}}
|
|
||||||
href="//git.peerat.dev"
|
|
||||||
class="group flex justify-center rounded-md px-3 py-3 text-sm transition-colors duration-150 hover:bg-primary-700 lg:justify-start"
|
|
||||||
>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<Git
|
|
||||||
class="stroke-highlight-secondary transition-colors duration-150 group-hover:stroke-primary-0"
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
class={cn(
|
|
||||||
'hidden text-highlight-secondary transition-colors duration-150 group-hover:text-primary lg:block',
|
|
||||||
{
|
|
||||||
'block sm:hidden': isOpen,
|
|
||||||
hidden: !isOpen
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
Git
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
import { browser } from '$app/environment';
|
|
||||||
import { writable } from 'svelte/store';
|
|
||||||
|
|
||||||
const defaultValue = true;
|
|
||||||
const initialValue = browser
|
|
||||||
? window.localStorage.getItem('plausible_ignore') === 'true'
|
|
||||||
: defaultValue;
|
|
||||||
|
|
||||||
const plausible = writable<boolean>(initialValue);
|
|
||||||
|
|
||||||
plausible.subscribe((value) => {
|
|
||||||
if (browser) {
|
|
||||||
window.localStorage.setItem('plausible_ignore', value ? 'true' : 'false');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default plausible;
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '../app.css';
|
import '../global.css';
|
||||||
|
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
|
|
||||||
|
@ -33,8 +33,6 @@
|
||||||
property="twitter:description"
|
property="twitter:description"
|
||||||
content="Apprendre la programmation et la cybersécurité en s'amusant."
|
content="Apprendre la programmation et la cybersécurité en s'amusant."
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<script defer data-domain="app.peerat.dev" src="https://plosibl.peerat.dev/js/script.js"></script>
|
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
import { API_URL } from '$env/static/private';
|
|
||||||
|
|
||||||
import type { PageServerLoad } from './$types';
|
|
||||||
|
|
||||||
import type { Chapter } from '$lib/types';
|
|
||||||
|
|
||||||
export const load = (async ({ parent, fetch, cookies }) => {
|
|
||||||
await parent();
|
|
||||||
|
|
||||||
const session = cookies.get('session');
|
|
||||||
|
|
||||||
const res = await fetch(`${API_URL}/chapters`, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${session}`
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
return {
|
|
||||||
chapters: []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const chapters = (await res.json()) as Chapter[];
|
|
||||||
|
|
||||||
return {
|
|
||||||
chapters
|
|
||||||
};
|
|
||||||
}) satisfies PageServerLoad;
|
|
|
@ -1,22 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import Chapter from '$lib/components/Chapter.svelte';
|
|
||||||
|
|
||||||
export let data;
|
|
||||||
|
|
||||||
$: chapters = data.chapters;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<section class="flex w-full flex-col space-y-6">
|
|
||||||
<header class="sticky flex items-center justify-between">
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<h1 class="text-xl font-semibold">Chaptires</h1>
|
|
||||||
<p class="text-muted">
|
|
||||||
Les chapitres sont les différentes parties du jeu. Chaque chapitre est composé de plusieurs
|
|
||||||
puzzles.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
{#each chapters as chapter}
|
|
||||||
<Chapter {chapter} />
|
|
||||||
{/each}
|
|
||||||
</section>
|
|
|
@ -1,28 +0,0 @@
|
||||||
import { API_URL } from '$env/static/private';
|
|
||||||
|
|
||||||
import type { PageServerLoad } from './$types';
|
|
||||||
|
|
||||||
import type { Chapter } from '$lib/types';
|
|
||||||
import { redirect } from '@sveltejs/kit';
|
|
||||||
|
|
||||||
export const load = (async ({ parent, fetch, cookies, params: { chapterId } }) => {
|
|
||||||
await parent();
|
|
||||||
|
|
||||||
const session = cookies.get('session');
|
|
||||||
|
|
||||||
const res = await fetch(`${API_URL}/chapter/${chapterId}`, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${session}`
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
throw redirect(302, '/dashboard/chapters');
|
|
||||||
}
|
|
||||||
|
|
||||||
const chapter = (await res.json()) as Chapter;
|
|
||||||
|
|
||||||
return {
|
|
||||||
chapter
|
|
||||||
};
|
|
||||||
}) satisfies PageServerLoad;
|
|
|
@ -1,97 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import Puzzle from '$lib/components/Puzzle.svelte';
|
|
||||||
|
|
||||||
export let data;
|
|
||||||
|
|
||||||
$: chapter = data.chapter;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<section class="flex w-full flex-col space-y-6">
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<div class="flex flex-col justify-between md:flex-row md:items-center">
|
|
||||||
<div class="flex items-center gap-x-2">
|
|
||||||
<h1 class="text-xl font-semibold">{chapter.name}</h1>
|
|
||||||
<!-- {!isInEventGroup(chapter) && isBeforeStart(chapter) && (
|
|
||||||
<Dialog
|
|
||||||
key={chapter.id}
|
|
||||||
title={chapter.name}
|
|
||||||
open={isOpen[chapter.id]}
|
|
||||||
onOpenChange={() => handleClick(chapter.id)}
|
|
||||||
trigger={
|
|
||||||
<button class="flex items-center gap-x-2 text-sm font-semibold text-muted hover:text-brand">
|
|
||||||
{/* <Icon name="group-line" /> */}
|
|
||||||
Rejoindre un groupe
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
class="right-96 p-4"
|
|
||||||
>
|
|
||||||
<GroupForm chapter={chapter} token={token} />
|
|
||||||
</Dialog>
|
|
||||||
)} -->
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col">
|
|
||||||
{#if chapter.startDate && chapter.endDate}
|
|
||||||
<div class="flex items-center justify-start gap-x-2 md:justify-end">
|
|
||||||
<!-- {/* <Icon name="calendar-line" class="text-sm text-muted" /> */} -->
|
|
||||||
<span class="text-sm text-muted">
|
|
||||||
{new Date(chapter.startDate).toLocaleDateString('fr-FR', {
|
|
||||||
day: 'numeric',
|
|
||||||
month: 'long',
|
|
||||||
year: 'numeric',
|
|
||||||
hour: 'numeric',
|
|
||||||
minute: 'numeric'
|
|
||||||
})}{' '}
|
|
||||||
-{' '}
|
|
||||||
{new Date(chapter.endDate).toLocaleDateString('fr-FR', {
|
|
||||||
day: 'numeric',
|
|
||||||
month: 'long',
|
|
||||||
year: 'numeric',
|
|
||||||
hour: 'numeric',
|
|
||||||
minute: 'numeric'
|
|
||||||
})}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
<div class="h-1 w-1/4 rounded-lg bg-gray-200">
|
|
||||||
<div class="h-1 w-1/2 rounded-lg bg-gradient-to-tl from-brand to-brand-accent" />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<div class="mt-1 flex justify-start gap-x-2">
|
|
||||||
<!-- {isInEventGroup(chapter) && (
|
|
||||||
<>
|
|
||||||
<FilterDifficulty
|
|
||||||
chapters={data}
|
|
||||||
chapter={chapter}
|
|
||||||
filter={filterDifficulty}
|
|
||||||
setFilter={setFilterDifficulty}
|
|
||||||
setFilterChapter={setFilterChapter}
|
|
||||||
/>
|
|
||||||
<FilterTags
|
|
||||||
chapters={data}
|
|
||||||
chapter={chapter}
|
|
||||||
filter={filterTags}
|
|
||||||
setFilter={setFilterTags}
|
|
||||||
setFilterChapter={setFilterChapter}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)} -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ul class="mt-4 flex flex-col space-y-4">
|
|
||||||
{#each chapter.puzzles as puzzle}
|
|
||||||
<Puzzle {puzzle} />
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
<!-- {isInEventGroup(chapter) && (
|
|
||||||
<ul class="mt-4 flex flex-col space-y-4">
|
|
||||||
{filteredData &&
|
|
||||||
filteredData
|
|
||||||
.sort((a, b) => a.scoreMax - b.scoreMax)
|
|
||||||
.map((puzzle) => (
|
|
||||||
<PuzzleProp key={puzzle.id} puzzle={puzzle} chapter={chapter} />
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
)} -->
|
|
||||||
</div>
|
|
||||||
</section>
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { API_URL } from '$env/static/private';
|
|
||||||
import { redirect, type Actions } from '@sveltejs/kit';
|
|
||||||
import type { PageServerLoad } from './$types';
|
|
||||||
|
|
||||||
export const load = (async ({ parent, fetch, cookies, params: { chapterId } }) => {
|
|
||||||
await parent();
|
|
||||||
throw redirect(303, chapterId ? `/dashboard/chapters/${chapterId}` : `/dashboard/chapters`);
|
|
||||||
}) satisfies PageServerLoad;
|
|
|
@ -24,8 +24,6 @@
|
||||||
)} -->
|
)} -->
|
||||||
<ul class="flex flex-col space-y-2">
|
<ul class="flex flex-col space-y-2">
|
||||||
{#each groups as group}
|
{#each groups as group}
|
||||||
{@const players = group.players.sort((a, b) => b.score - a.score)}
|
|
||||||
{@const last = players[players.length - 1]}
|
|
||||||
<li class="flex justify-between space-x-2">
|
<li class="flex justify-between space-x-2">
|
||||||
<div class="flex items-center space-x-4">
|
<div class="flex items-center space-x-4">
|
||||||
<span
|
<span
|
||||||
|
@ -37,10 +35,15 @@
|
||||||
<div class="flex flex-col gap-x-2 sm:flex-row sm:items-center">
|
<div class="flex flex-col gap-x-2 sm:flex-row sm:items-center">
|
||||||
<span class="text-lg">{group.name}</span>
|
<span class="text-lg">{group.name}</span>
|
||||||
<span class="text-sm text-highlight-secondary">
|
<span class="text-sm text-highlight-secondary">
|
||||||
{#if players.length > 1}
|
<!-- {group.players && group.players.length > 1
|
||||||
{#each players as player}
|
? group.players
|
||||||
{player.pseudo || 'Anonyme'}{#if player !== last}, {/if}
|
.map((player) => player.pseudo || 'Anonyme')
|
||||||
{' '}
|
.sort((a, b) => a.localeCompare(b))
|
||||||
|
.join(', ')
|
||||||
|
: group.players[0].pseudo} -->
|
||||||
|
{#if group.players.length > 1}
|
||||||
|
{#each group.players as player}
|
||||||
|
{player.pseudo || 'Anonyme'} {' '}
|
||||||
{/each}
|
{/each}
|
||||||
{:else}
|
{:else}
|
||||||
{group.players[0].pseudo}
|
{group.players[0].pseudo}
|
||||||
|
@ -51,12 +54,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-4">
|
<div class="flex items-center space-x-4">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<span class="text-sm font-semibold"
|
<span class="text-sm font-semibold">Essai{group.players.reduce((a, b) => a + b.tries, 0) || 0 ? 's' : ''}</span>
|
||||||
>Essai{group.players.reduce((a, b) => a + b.tries, 0) || 0 ? 's' : ''}</span
|
<span class="text-lg text-highlight-secondary">{group.players.reduce((a, b) => a + b.tries, 0) || 0}</span>
|
||||||
>
|
|
||||||
<span class="text-lg text-highlight-secondary"
|
|
||||||
>{group.players.reduce((a, b) => a + b.tries, 0) || 0}</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<span class="text-sm font-semibold">Score</span>
|
<span class="text-sm font-semibold">Score</span>
|
||||||
|
|
|
@ -1,35 +1,18 @@
|
||||||
|
import type { PageServerLoad } from './$types';
|
||||||
import { API_URL } from '$env/static/private';
|
import { API_URL } from '$env/static/private';
|
||||||
import { error, redirect, type Actions } from '@sveltejs/kit';
|
import { error, redirect, type Actions } from '@sveltejs/kit';
|
||||||
import type Puzzle from '$lib/components/Puzzle.svelte';
|
import type Puzzle from '$lib/components/Puzzle.svelte';
|
||||||
import type { PageServerLoad } from './$types';
|
|
||||||
|
|
||||||
export const load = (async ({ parent, fetch, cookies, params: { chapterId, puzzleId } }) => {
|
export const load = (async ({ parent, fetch, cookies, params: { id } }) => {
|
||||||
await parent();
|
await parent();
|
||||||
|
|
||||||
const session = cookies.get('session');
|
const session = cookies.get('session');
|
||||||
|
|
||||||
if (isNaN(parseInt(puzzleId))) {
|
if (isNaN(parseInt(id))) {
|
||||||
throw redirect(303, `/dashboard/chapters/${chapterId}`);
|
throw redirect(303, '/dashboard/puzzles');
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if puzzle is from the chapter
|
const res = await fetch(`${API_URL}/puzzle/${id}`, {
|
||||||
let res = await fetch(`${API_URL}/chapter/${chapterId}`, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${session}`
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
throw redirect(303, `/dashboard/chapters`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { puzzles } = (await res.json()) as { puzzles: Puzzle[] };
|
|
||||||
|
|
||||||
if (!puzzles.some((puzzle) => puzzle.id === parseInt(puzzleId))) {
|
|
||||||
throw redirect(303, `/dashboard/chapters/${chapterId}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = await fetch(`${API_URL}/puzzle/${puzzleId}`, {
|
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${session}`
|
Authorization: `Bearer ${session}`
|
||||||
}
|
}
|
|
@ -7,13 +7,11 @@
|
||||||
import Button from '$lib/components/ui/Button.svelte';
|
import Button from '$lib/components/ui/Button.svelte';
|
||||||
import Input from '$lib/components/ui/Input.svelte';
|
import Input from '$lib/components/ui/Input.svelte';
|
||||||
|
|
||||||
import plausible from '$lib/stores/Plausible';
|
|
||||||
|
|
||||||
$: user = $page.data.user;
|
$: user = $page.data.user;
|
||||||
|
|
||||||
export let form: ActionData;
|
export let form: ActionData;
|
||||||
|
|
||||||
$: optedOut = $plausible;
|
$: console.log(form);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form class="flex flex-col gap-4" method="POST" use:enhance>
|
<form class="flex flex-col gap-4" method="POST" use:enhance>
|
||||||
|
@ -37,23 +35,6 @@
|
||||||
value={user?.description}
|
value={user?.description}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- TODO -->
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<label for="optout"> Ne pas me tracer de manière anonyme </label>
|
|
||||||
<input
|
|
||||||
class="h-4 w-4"
|
|
||||||
name="optout"
|
|
||||||
type="checkbox"
|
|
||||||
value={optedOut}
|
|
||||||
on:change={() => plausible.set(!optedOut)}
|
|
||||||
checked={optedOut}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p class="text-sm text-highlight-secondary">
|
|
||||||
Nous utilisons Plausible pour analyser l'utilisation de notre site web de manière anonyme.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<Button variant="brand">
|
<Button variant="brand">
|
||||||
<!-- {isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} -->
|
<!-- {isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} -->
|
||||||
Modifier
|
Modifier
|
||||||
|
|
Loading…
Add table
Reference in a new issue