2023-02-22 12:43:39 +01:00
|
|
|
<script lang="ts">
|
2023-02-23 17:11:57 +01:00
|
|
|
import { page } from "$app/stores";
|
|
|
|
import {
|
|
|
|
getRoom
|
|
|
|
} from "../../../requests/room.request";
|
|
|
|
import { getContext, onDestroy, onMount, setContext } from "svelte";
|
|
|
|
import { writable, type Writable } from "svelte/store";
|
|
|
|
import { messages, connect, events, handlers } from "../../../store/ws";
|
|
|
|
import type { Member, ParcoursRead, Room } from "../../../types/room.type";
|
|
|
|
import { afterNavigate, beforeNavigate, goto } from "$app/navigation";
|
|
|
|
import AskPseudo from "../../../components/rooms/AskPseudo.svelte";
|
|
|
|
import Members from "../../../components/rooms/Members.svelte";
|
|
|
|
import ExerciceSelector from "../../../components/exos/ExerciceSelector.svelte";
|
|
|
|
import RoomHead from "../../../components/rooms/RoomHead.svelte";
|
|
|
|
import ParcoursList from "../../../components/rooms/ParcoursList.svelte";
|
|
|
|
import ParcoursCreate from "../../../components/rooms/ParcoursCreate.svelte";
|
|
|
|
import ParcoursDetails from "../../../components/rooms/ParcoursDetails.svelte";
|
|
|
|
import Challenge from "../../../components/rooms/Challenge.svelte";
|
|
|
|
import { refreshRequest } from "../../../requests/auth.request";
|
|
|
|
import Waiting from "../../../components/rooms/Waiting.svelte";
|
|
|
|
|
|
|
|
const p = "p";
|
|
|
|
|
|
|
|
const { isAuth } = getContext<{ isAuth: Writable<boolean> }>("auth");
|
|
|
|
|
|
|
|
const room = writable<Room | null>(null);
|
|
|
|
const member = writable<Member | null>(null);
|
|
|
|
const parcours = writable<ParcoursRead | null>(null);
|
2023-02-26 11:35:37 +01:00
|
|
|
const ws = connect("ws://127.0.0.1:8002/api/ws/room/" + $page.params.slug);
|
2023-02-23 17:11:57 +01:00
|
|
|
|
|
|
|
setContext("room", room);
|
|
|
|
setContext("member", member);
|
|
|
|
setContext("parcours", parcours);
|
|
|
|
setContext("ws", { send: (type: string, data: Object) => ws.send({ type, data }), ws: ws.ws });
|
2023-02-26 11:35:37 +01:00
|
|
|
const { error, info } = getContext("notif");
|
2023-02-23 17:11:57 +01:00
|
|
|
const onMessage = (payload: { type: string; data: any }) => {
|
|
|
|
if (payload == undefined) return;
|
|
|
|
const { type, data } = payload;
|
|
|
|
switch (type) {
|
|
|
|
case "loggedIn":
|
|
|
|
close();
|
|
|
|
member.set(data.member);
|
|
|
|
if (data.member.reconnect_code != "") {
|
|
|
|
sessionStorage.setItem("reconnect", data.member.reconnect_code);
|
|
|
|
}
|
|
|
|
getRoom($page.params.slug, !$isAuth ? data.member.clientId : null).then((r) => {
|
|
|
|
room.set(r);
|
|
|
|
});
|
2023-02-22 12:43:39 +01:00
|
|
|
|
2023-02-23 17:11:57 +01:00
|
|
|
const parcoursId =
|
|
|
|
$page.url.searchParams.get("p") ||
|
|
|
|
$page.url.searchParams.get("corr") ||
|
|
|
|
$page.url.searchParams.get("c");
|
|
|
|
if (parcoursId != null) {
|
|
|
|
ws.send({ type: "sub_parcours", data: { parcours_id: parcoursId } });
|
|
|
|
}
|
2023-02-22 12:43:39 +01:00
|
|
|
|
2023-02-23 17:11:57 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
case "accepted":
|
|
|
|
close();
|
|
|
|
if ($page.url.searchParams.get("a") == "waiting") {
|
|
|
|
goto(`?`);
|
2023-02-22 12:43:39 +01:00
|
|
|
}
|
2023-02-23 17:11:57 +01:00
|
|
|
console.log("ACCEPTED", data.member);
|
|
|
|
member.set(data.member);
|
|
|
|
|
|
|
|
getRoom($page.params.slug, !$isAuth ? data.member.clientId : null).then((r) => {
|
|
|
|
room.set(r);
|
|
|
|
});
|
|
|
|
if (!$isAuth) {
|
|
|
|
sessionStorage.setItem("reconnect", data.member.reconnect_code);
|
|
|
|
}
|
|
|
|
const parcours_id =
|
|
|
|
$page.url.searchParams.get("p") ||
|
|
|
|
$page.url.searchParams.get("corr") ||
|
|
|
|
$page.url.searchParams.get("c");
|
|
|
|
if (parcours_id != null) {
|
|
|
|
ws.send({ type: "sub_parcours", data: { parcours_id: parcours_id } });
|
2023-02-22 12:43:39 +01:00
|
|
|
}
|
2023-02-23 17:11:57 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
case "waiting":
|
2023-02-26 11:35:37 +01:00
|
|
|
close()
|
2023-02-23 17:11:57 +01:00
|
|
|
$member = { ...data.waiter, room: data.room };
|
|
|
|
goto(`?${new URLSearchParams({ a: "waiting" })}`);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case "refused":
|
2023-02-26 11:35:37 +01:00
|
|
|
error("Refusé", "L'administrateur a refusé votre demande");
|
2023-02-23 17:11:57 +01:00
|
|
|
close();
|
|
|
|
ws?.close(1000);
|
|
|
|
goto("/room/join");
|
|
|
|
return;
|
|
|
|
|
|
|
|
case "leaved":
|
|
|
|
if (data.member.id_code == $member!.id_code) {
|
|
|
|
ws?.close(1000);
|
|
|
|
goto("/room/join");
|
|
|
|
sessionStorage.removeItem("reconnect");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ($room != null) {
|
|
|
|
$room.members = [
|
|
|
|
...$room.members.filter((r) => "waiter_id" in r || r.id_code != data.member.id_code)
|
|
|
|
];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case "banned":
|
2023-02-26 11:35:37 +01:00
|
|
|
error("Ban", "Vous avez été banni de la salle par l'administrateur");
|
2023-02-23 17:11:57 +01:00
|
|
|
ws?.close(1000);
|
|
|
|
goto("/room/join");
|
|
|
|
sessionStorage.removeItem("reconnect");
|
|
|
|
return;
|
|
|
|
|
2023-02-26 11:35:37 +01:00
|
|
|
case "deleted":
|
|
|
|
info("Suppression", "La salle a été supprimée par l'administrateur");
|
|
|
|
ws.close(1000)
|
|
|
|
goto("/room/join")
|
|
|
|
return
|
|
|
|
|
2023-02-23 17:11:57 +01:00
|
|
|
case "error":
|
|
|
|
const { code, msg } = data;
|
|
|
|
if (code == 401) {
|
|
|
|
if ($isAuth) {
|
|
|
|
ws.send({ type: "join", data: { token: localStorage.getItem("token") } });
|
|
|
|
} else {
|
|
|
|
show(
|
|
|
|
//Ask for pseudo and try join
|
|
|
|
AskPseudo,
|
|
|
|
{
|
|
|
|
validate: (p: string) => {
|
|
|
|
console.log("OH", p, p.startsWith("#"));
|
|
|
|
if (p.startsWith("#")) {
|
|
|
|
ws.send({ type: "login", data: { reconnect_code: p.replace("#", "") } });
|
|
|
|
} else {
|
|
|
|
ws.send({ type: "join", data: { username: p } });
|
|
|
|
}
|
|
|
|
|
|
|
|
//close();
|
2023-02-22 12:43:39 +01:00
|
|
|
}
|
2023-02-23 17:11:57 +01:00
|
|
|
},
|
|
|
|
() => {
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (code == 422 && msg.toLowerCase().indexOf("signature expired") > -1) {
|
|
|
|
const refresh = localStorage.getItem("refresh");
|
|
|
|
if (refresh == null) return;
|
|
|
|
refreshRequest(refresh).then((r) => {
|
|
|
|
localStorage.setItem("access", r.access_token);
|
|
|
|
ws.send({ type: "join", data: { token: r.access_token } });
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
error("Erreur", "Message : " + msg);
|
|
|
|
}
|
2023-02-26 11:35:37 +01:00
|
|
|
if(code == 404){
|
|
|
|
ws.close(1000)
|
|
|
|
goto("/room/join")
|
|
|
|
}
|
2023-02-23 17:11:57 +01:00
|
|
|
return;
|
|
|
|
case "waiter":
|
2023-02-22 12:43:39 +01:00
|
|
|
|
2023-02-23 17:11:57 +01:00
|
|
|
if ($room != null) {
|
|
|
|
$room.members = [...$room?.members, data.waiter];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case "disconnect_waiter":
|
|
|
|
if ($room != null) {
|
|
|
|
$room.members = [
|
|
|
|
...$room?.members.filter((m) => "id_code" in m || m.waiter_id != data.waiter.waiter_id)
|
|
|
|
];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case "successfullyRefused":
|
|
|
|
if ($room != null) {
|
|
|
|
$room.members = [
|
|
|
|
...$room?.members.filter((m) => "id_code" in m || m.waiter_id != data.waiter_id)
|
|
|
|
];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case "update_parcours":
|
|
|
|
if ($room != null) {
|
|
|
|
$room.parcours = [
|
|
|
|
...$room.parcours.map((c) => {
|
|
|
|
if (c.id_code == data.parcours.id_code) {
|
|
|
|
return data.parcours;
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
})
|
|
|
|
];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case "parcours_stats":
|
|
|
|
if ($room != null) {
|
|
|
|
$room.parcours = [
|
|
|
|
...$room.parcours.map((c) => {
|
|
|
|
if (c.id_code == data.parcours.id_code) {
|
|
|
|
return data.parcours;
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
})
|
|
|
|
];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case "joined":
|
|
|
|
if ($room != null) {
|
|
|
|
$room.members = [
|
|
|
|
...$room?.members.filter(
|
|
|
|
(m) =>
|
|
|
|
("id_code" in m && m.id_code != data.member.id_code) ||
|
|
|
|
("waiter_id" in m && m.waiter_id != data.member.id_code)
|
|
|
|
),
|
|
|
|
data.member
|
|
|
|
];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case "connect":
|
|
|
|
if ($room != null) {
|
|
|
|
$room.members = [
|
|
|
|
...$room?.members.map((r) => {
|
|
|
|
if ("id_code" in r && r.id_code == data.member.id_code) {
|
|
|
|
return data.member;
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
})
|
|
|
|
];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case "disconnect":
|
|
|
|
if ($room != null) {
|
|
|
|
$room.members = [
|
|
|
|
...$room?.members.map((r) => {
|
|
|
|
if ("id_code" in r && r.id_code == data.member.id_code) {
|
|
|
|
return data.member;
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
})
|
|
|
|
];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case "add_parcours":
|
|
|
|
if ($room != null) {
|
|
|
|
$room.parcours = [...$room?.parcours, data.parcours];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case "del_parcours":
|
|
|
|
if ($room != null) {
|
|
|
|
$room.parcours = [...$room?.parcours.filter((p) => p.id_code != data.parcours_id)];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case "new_visibility":
|
|
|
|
if ($room != null) {
|
|
|
|
$room.public = data.public;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case "new_name":
|
|
|
|
if ($room != null) {
|
|
|
|
$room.name = data.name;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
const { show, close } = getContext<{ show: Function; close: Function }>("modal");
|
|
|
|
const onEvent = (event: { type: string; e: Event | CloseEvent }) => {
|
|
|
|
if (event == undefined) return;
|
|
|
|
const { type, e } = event;
|
|
|
|
if (type == "open") {
|
|
|
|
//On the open of ws
|
|
|
|
if ($isAuth) {
|
|
|
|
ws.send({ type: "login", data: { token: localStorage.getItem("token") } }); // try to login, if denied the message handler tries to join
|
|
|
|
} else {
|
|
|
|
const reconnect_code = sessionStorage.getItem("reconnect");
|
|
|
|
if (reconnect_code !== null) {
|
|
|
|
// Try to log in if a reconnect code is found
|
|
|
|
ws.send({ type: "login", data: { reconnect_code } });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
show(
|
|
|
|
//Ask for pseudo and try join
|
|
|
|
AskPseudo,
|
|
|
|
{
|
|
|
|
validate: (p: string) => {
|
|
|
|
if (p.startsWith("#")) {
|
|
|
|
ws.send({ type: "login", data: { reconnect_code: p.replace("#", "") } });
|
|
|
|
} else {
|
|
|
|
ws.send({ type: "join", data: { username: p } });
|
|
|
|
}
|
|
|
|
//close();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
() => {
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const parcoursMessage = (payload: { type: string; data: any }) => {
|
|
|
|
if (payload == undefined || ($parcours == null && $member == null)) return;
|
|
|
|
|
|
|
|
const { type, data } = payload;
|
|
|
|
switch (type) {
|
|
|
|
case "challenge":
|
|
|
|
if ($parcours != null && $member != null) {
|
|
|
|
if (!!$parcours.challenges[data.challenger.id_code]) {
|
|
|
|
$parcours.challenges[data.challenger.id_code].challenges = [
|
|
|
|
...$parcours.challenges[data.challenger.id_code].challenges,
|
|
|
|
{ ...data.challenges[0] }
|
|
|
|
];
|
|
|
|
} else {
|
|
|
|
$parcours.challenges[data.challenger.id_code] = { ...data };
|
|
|
|
}
|
|
|
|
if (data.challenges[0].validated == true && data.challenger.id_code == $member.id_code) {
|
|
|
|
$parcours.validated = true;
|
|
|
|
}
|
2023-02-22 12:43:39 +01:00
|
|
|
}
|
2023-02-23 17:11:57 +01:00
|
|
|
return;
|
2023-02-22 12:43:39 +01:00
|
|
|
|
2023-02-23 17:11:57 +01:00
|
|
|
case "newRanks":
|
|
|
|
if ($parcours != null) {
|
|
|
|
$parcours.rank = data.rank;
|
|
|
|
$parcours.memberRank = data.avgRank;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case "newTops":
|
|
|
|
if ($parcours != null) {
|
|
|
|
$parcours.tops = data.tops;
|
|
|
|
$parcours.ranking = data.avgTops;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case "edit_parcours":
|
|
|
|
if ($parcours != null && data.parcours.id_code == $parcours.id_code) {
|
|
|
|
parcours.update((p) => {
|
|
|
|
if (p == null) return p;
|
|
|
|
return {
|
|
|
|
...p,
|
|
|
|
name: data.parcours.name,
|
|
|
|
time: data.parcours.time,
|
|
|
|
max_mistakes: data.parcours.max_mistakes
|
|
|
|
};
|
|
|
|
});
|
|
|
|
if (data.parcours.update_challenges) {
|
|
|
|
$parcours.exercices = data.parcours.exercices;
|
|
|
|
$parcours.challenges = {};
|
|
|
|
$parcours.tops = [];
|
|
|
|
$parcours.ranking = [];
|
|
|
|
$parcours.validated = false;
|
|
|
|
} else {
|
|
|
|
$parcours.validated = $parcours.pb.mistakes <= $parcours.max_mistakes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case "challenge_change":
|
|
|
|
if ($parcours != null && !!$parcours.challenges[data.member]) {
|
|
|
|
$parcours.challenges[data.member].challenges = $parcours.challenges[
|
|
|
|
data.member
|
|
|
|
].challenges.map((c) => {
|
|
|
|
if (c.id_code == data.challenge.id_code) {
|
|
|
|
return data.challenge;
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
});
|
|
|
|
$parcours.validated = data.validated;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
handlers.update((h) => {
|
|
|
|
return { ...h, [$page.params.slug]: onMessage };
|
|
|
|
});
|
|
|
|
handlers.update((h) => {
|
|
|
|
return { ...h, parcours: parcoursMessage };
|
|
|
|
});
|
|
|
|
onDestroy(() => {
|
2023-02-22 12:43:39 +01:00
|
|
|
handlers.update((h) => {
|
2023-02-23 17:11:57 +01:00
|
|
|
return { ...h, [$page.params.slug]: null };
|
2023-02-22 12:43:39 +01:00
|
|
|
});
|
|
|
|
handlers.update((h) => {
|
2023-02-23 17:11:57 +01:00
|
|
|
return { ...h, parcours: null };
|
2023-02-22 12:43:39 +01:00
|
|
|
});
|
2023-02-23 17:11:57 +01:00
|
|
|
});
|
|
|
|
$: onEvent($events[0]);
|
|
|
|
$: console.log($page.params.slug, $page, $page.params, $page.url.searchParams.get("p"));
|
|
|
|
let fade = false;
|
|
|
|
|
|
|
|
beforeNavigate((n) => {
|
|
|
|
if (fade == false && !!n.to?.url) {
|
|
|
|
fade = true;
|
|
|
|
n.cancel();
|
|
|
|
setTimeout(() => {
|
|
|
|
if (!!n.to?.url) {
|
|
|
|
goto(n.to?.url);
|
2023-02-22 12:43:39 +01:00
|
|
|
}
|
2023-02-23 17:11:57 +01:00
|
|
|
}, 100);
|
|
|
|
} else {
|
|
|
|
fade = false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
afterNavigate((n) => {
|
|
|
|
console.log("AGTER", n);
|
|
|
|
let oldParcoursId =
|
|
|
|
n.from?.url.searchParams.get("p") ||
|
|
|
|
n.from?.url.searchParams.get("corr") ||
|
|
|
|
n.from?.url.searchParams.get("c");
|
|
|
|
let newParcoursId =
|
|
|
|
n.to?.url.searchParams.get("p") ||
|
|
|
|
n.to?.url.searchParams.get("corr") ||
|
|
|
|
n.to?.url.searchParams.get("c");
|
|
|
|
|
|
|
|
oldParcoursId = oldParcoursId == "new" ? null : oldParcoursId;
|
|
|
|
newParcoursId = newParcoursId == "new" ? null : newParcoursId;
|
|
|
|
|
|
|
|
if (oldParcoursId != null && newParcoursId == null) {
|
|
|
|
ws.send({ type: "unsub_parcours", data: { parcours_id: oldParcoursId } });
|
|
|
|
$parcours = null;
|
|
|
|
}
|
|
|
|
/* if (oldParcoursId == newParcoursId) return;
|
|
|
|
if (oldParcoursId == null && newParcoursId != null) {
|
|
|
|
|
|
|
|
//ws.send({ type: 'sub_parcours', data: { parcours_id: newParcoursId } });
|
|
|
|
} else */
|
|
|
|
});
|
|
|
|
|
|
|
|
$: console.log("edit", $page.url.searchParams.get("a"));
|
|
|
|
onDestroy(() => {
|
|
|
|
ws.close(1000);
|
|
|
|
});
|
2023-02-22 12:43:39 +01:00
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<div class="container">
|
2023-02-23 17:11:57 +01:00
|
|
|
<div class="full" class:fade>
|
|
|
|
{#if $page.url.searchParams.get('a') == "waiting"}
|
|
|
|
<Waiting />
|
|
|
|
{/if}
|
|
|
|
{#if $room != null}
|
|
|
|
{#if $page.url.searchParams.get("p") == null && $page.url.searchParams.get('c') == null && $page.url.searchParams.get('corr') == null}
|
|
|
|
<div class="room">
|
|
|
|
<div class="head">
|
|
|
|
<RoomHead />
|
|
|
|
</div>
|
|
|
|
<div class="parcours">
|
|
|
|
<ParcoursList />
|
|
|
|
</div>
|
|
|
|
<div class="members">
|
|
|
|
<Members />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
|
|
{#if $page.url.searchParams.get('p') == 'new'}
|
|
|
|
<ParcoursCreate />
|
|
|
|
{:else if $page.url.searchParams.get('p') != 'new' && $page.url.searchParams.get('p') != null}
|
|
|
|
{#if $page.url.searchParams.get('edit') != '1'}
|
|
|
|
<ParcoursDetails id_code={$page.url.searchParams.get('p')} />
|
|
|
|
{:else}
|
|
|
|
<ParcoursCreate id_code={$page.url.searchParams.get('p')} />
|
2023-02-22 12:43:39 +01:00
|
|
|
{/if}
|
2023-02-23 17:11:57 +01:00
|
|
|
{/if}
|
|
|
|
{#if $page.url.searchParams.get('c') != null}
|
|
|
|
<Challenge id_code={$page.url.searchParams.get('c')} />
|
|
|
|
{/if}
|
|
|
|
{#if $page.url.searchParams.get('corr') != null}
|
|
|
|
<Challenge id_code={$page.url.searchParams.get('corr')} corrige />
|
|
|
|
{/if}
|
|
|
|
{/if}
|
|
|
|
</div>
|
2023-02-22 12:43:39 +01:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<style lang="scss">
|
2023-02-23 17:11:57 +01:00
|
|
|
@import "../../../mixins.scss";
|
|
|
|
|
2023-02-22 12:43:39 +01:00
|
|
|
.full {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
transition: 0.2s;
|
|
|
|
opacity: 1;
|
2023-02-23 17:11:57 +01:00
|
|
|
|
2023-02-22 12:43:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
.fade {
|
|
|
|
opacity: 0;
|
|
|
|
transform: translateX(-50px);
|
|
|
|
transform: scale(0.95);
|
|
|
|
}
|
|
|
|
|
|
|
|
.co {
|
|
|
|
color: red;
|
|
|
|
}
|
|
|
|
|
|
|
|
.head {
|
|
|
|
grid-row: 1/2;
|
|
|
|
grid-column: 1/3;
|
|
|
|
}
|
|
|
|
|
|
|
|
.members {
|
|
|
|
grid-row: 2/3;
|
|
|
|
grid-column: 1/2;
|
|
|
|
}
|
|
|
|
|
|
|
|
.parcours {
|
|
|
|
grid-row: 2/2;
|
|
|
|
grid-column: 2/2;
|
|
|
|
}
|
|
|
|
|
|
|
|
.room {
|
|
|
|
display: grid;
|
|
|
|
grid-template-columns: 1fr 3fr;
|
|
|
|
grid-template-rows: 60px 1fr;
|
|
|
|
column-gap: 50px;
|
|
|
|
row-gap: 10px;
|
|
|
|
height: 100%;
|
2023-02-26 11:35:37 +01:00
|
|
|
padding: 7px 15px;
|
2023-02-23 17:11:57 +01:00
|
|
|
@include down(800) {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
padding: 13px;
|
|
|
|
gap: 10px;
|
|
|
|
}
|
2023-02-22 12:43:39 +01:00
|
|
|
}
|
|
|
|
</style>
|