Merge pull request #79 from TheRealOwenRees/feature/other

Various changed
This commit is contained in:
Owen Rees
2023-07-07 11:52:37 +02:00
committed by GitHub
16 changed files with 145 additions and 74 deletions
+3 -1
View File
@@ -25,5 +25,7 @@
"tournois", "tournois",
"unspiderfied", "unspiderfied",
"unspiderfy" "unspiderfy"
] ],
"css.customData": [".vscode/tailwindcss.json"],
} }
+55
View File
@@ -0,0 +1,55 @@
{
"version": 1.1,
"atDirectives": [
{
"name": "@tailwind",
"description": "Use the `@tailwind` directive to insert Tailwind's `base`, `components`, `utilities` and `screens` styles into your CSS.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#tailwind"
}
]
},
{
"name": "@apply",
"description": "Use the `@apply` directive to inline any existing utility classes into your own custom CSS. This is useful when you find a common utility pattern in your HTML that youd like to extract to a new component.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#apply"
}
]
},
{
"name": "@responsive",
"description": "You can generate responsive variants of your own classes by wrapping their definitions in the `@responsive` directive:\n```css\n@responsive {\n .alert {\n background-color: #E53E3E;\n }\n}\n```\n",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#responsive"
}
]
},
{
"name": "@screen",
"description": "The `@screen` directive allows you to create media queries that reference your breakpoints by **name** instead of duplicating their values in your own CSS:\n```css\n@screen sm {\n /* ... */\n}\n```\n…gets transformed into this:\n```css\n@media (min-width: 640px) {\n /* ... */\n}\n```\n",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#screen"
}
]
},
{
"name": "@variants",
"description": "Generate `hover`, `focus`, `active` and other **variants** of your own utilities by wrapping their definitions in the `@variants` directive:\n```css\n@variants hover, focus {\n .btn-brand {\n background-color: #3182CE;\n }\n}\n```\n",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#variants"
}
]
}
]
}
+11 -19
View File
@@ -6,6 +6,12 @@ import Hamburger from "./Hamburger";
export default function Navbar() { export default function Navbar() {
const t = useTranslations("Nav"); const t = useTranslations("Nav");
const links = [
{ title: t("tournaments"), route: "/tournois" },
{ title: t("about"), route: "/qui-sommes-nous" },
{ title: t("contact"), route: "/contactez-nous" },
];
return ( return (
<nav <nav
className="relative mt-0 h-16 w-full overflow-x-clip border-b-[1px] bg-white px-5 dark:border-gray-700 dark:bg-gray-800" className="relative mt-0 h-16 w-full overflow-x-clip border-b-[1px] bg-white px-5 dark:border-gray-700 dark:bg-gray-800"
@@ -29,30 +35,16 @@ export default function Navbar() {
data-test="desktop-menu" data-test="desktop-menu"
> >
<ul className="list-reset flex h-full flex-1 items-center justify-around text-gray-900 no-underline dark:text-white md:flex-none"> <ul className="list-reset flex h-full flex-1 items-center justify-around text-gray-900 no-underline dark:text-white md:flex-none">
<li className="mr-10 h-full"> {links.map(({ title, route }) => (
<li key={route} className="mr-10 h-full">
<Link <Link
className="inline-flex h-full items-center border-b-4 border-t-4 border-transparent transition-all duration-300 ease-in-out hover:border-b-teal-600" className="inline-flex h-full items-center border-b-4 border-t-4 border-transparent transition-all duration-300 ease-in-out hover:border-b-teal-600"
href="/tournois" href={route}
> >
{t("tournaments")} {title}
</Link>
</li>
<li className="mr-10 h-full">
<Link
className="inline-flex h-full items-center border-b-4 border-t-4 border-transparent transition-all duration-300 ease-in-out hover:border-b-teal-600"
href="/qui-sommes-nous"
>
{t("about")}
</Link>
</li>
<li className="mr-10 h-full">
<Link
className="inline-flex h-full items-center border-b-4 border-t-4 border-transparent transition-all duration-300 ease-in-out hover:border-b-teal-600"
href="/contactez-nous"
>
{t("contact")}
</Link> </Link>
</li> </li>
))}
</ul> </ul>
</div> </div>
</div> </div>
+2 -1
View File
@@ -1,7 +1,8 @@
import { NextIntlClientProvider, AbstractIntlMessages } from "next-intl"; import { NextIntlClientProvider, AbstractIntlMessages } from "next-intl";
import { ReactNode } from "react"; import { ReactNode } from "react";
import "@/app/globals.css"; import "@/css/globals.css";
import Navbar from "./Navbar"; import Navbar from "./Navbar";
import Footer from "./Footer"; import Footer from "./Footer";
+2 -1
View File
@@ -5,7 +5,8 @@ import { getTranslator } from "next-intl/server";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import { ReactNode } from "react"; import { ReactNode } from "react";
import "@/app/globals.css"; import "@/css/globals.css";
import Providers from "./providers"; import Providers from "./providers";
import TestableLayout from "./components/TestableLayout"; import TestableLayout from "./components/TestableLayout";
+31 -18
View File
@@ -1,12 +1,27 @@
import { useMap } from "react-leaflet"; import { useMap } from "react-leaflet";
import { useEffect } from "react"; import { useEffect, useMemo } from "react";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import L from "leaflet"; import L from "leaflet";
import { useAtomValue } from "jotai";
import { TimeControl } from "@/types"; import { TimeControl } from "@/types";
import { filteredTournamentsByTimeControlAtom } from "@/app/atoms";
const Legend = () => { const Legend = () => {
const t = useTranslations("Tournaments"); const t = useTranslations("Tournaments");
const map = useMap(); const map = useMap();
const tournaments = useAtomValue(filteredTournamentsByTimeControlAtom);
const timeControls = useMemo(
() =>
[
{ tc: TimeControl.Classic, colour: "#00ac39" },
{ tc: TimeControl.Rapid, colour: "#0086c7" },
{ tc: TimeControl.Blitz, colour: "#cec348" },
{ tc: TimeControl.Other, colour: "#d10c3e" },
].filter(({ tc }) => tournaments.some((t) => t.timeControl === tc)),
[tournaments]
);
useEffect(() => { useEffect(() => {
if (map) { if (map) {
@@ -19,30 +34,28 @@ const Legend = () => {
"style", "style",
"background: white; color: black; border: 2px solid grey; border-radius: 6px; padding: 10px;" "background: white; color: black; border: 2px solid grey; border-radius: 6px; padding: 10px;"
); );
div.innerHTML = `<ul>
<li><span style='background:#00ac39; display: block; height: 16px; width: 30px; border: 1px solid #999; float: left; margin-right: 5px'></span>${t( div.innerHTML = `
<ul>
${timeControls
.map(
({ tc, colour }) => `
<li>
<span class="block h-4 w-7 border border-[#999] float-left mr-1" style="background: ${colour}"></span>${t(
"timeControlEnum", "timeControlEnum",
{ tc: TimeControl.Classic } { tc }
)}</li> )}
<li><span style='background:#0086c7; display: block; height: 16px; width: 30px; border: 1px solid #999; float: left; margin-right: 5px'></span>${t( </li>
"timeControlEnum", `
{ tc: TimeControl.Rapid } )
)}</li> .join("")}
<li><span style='background:#cec348; display: block; height: 16px; width: 30px; border: 1px solid #999; float: left; margin-right: 5px'></span>${t(
"timeControlEnum",
{ tc: TimeControl.Blitz }
)}</li>
<li><span style='background:#d10c3e; display: block; height: 16px; width: 30px; border: 1px solid #999; float: left; margin-right: 5px'></span>${t(
"timeControlEnum",
{ tc: TimeControl.KO }
)}</li>
</ul>`; </ul>`;
return div; return div;
}; };
legend.addTo(map); legend.addTo(map);
} }
}, [map, t]); }, [map, t, timeControls]);
return null; return null;
}; };
+20 -12
View File
@@ -1,35 +1,43 @@
import { useAtom } from "jotai"; import { useAtom, useAtomValue } from "jotai";
import { classicAtom, rapidAtom, blitzAtom, oneHourKOAtom } from "@/app/atoms"; import {
classicAtom,
rapidAtom,
blitzAtom,
otherAtom,
tournamentsAtom,
} from "@/app/atoms";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { TimeControl } from "@/types"; import { TimeControl } from "@/types";
const TimeControlFilters = () => { const TimeControlFilters = () => {
const t = useTranslations("Tournaments"); const t = useTranslations("Tournaments");
const tournaments = useAtomValue(tournamentsAtom);
const classic = useAtom(classicAtom); const classic = useAtom(classicAtom);
const rapid = useAtom(rapidAtom); const rapid = useAtom(rapidAtom);
const blitz = useAtom(blitzAtom); const blitz = useAtom(blitzAtom);
const oneHourKO = useAtom(oneHourKOAtom); const other = useAtom(otherAtom);
const checkboxes = [ const checkboxes = [
{ title: t("timeControlEnum", { tc: TimeControl.Classic }), atom: classic }, { tc: TimeControl.Classic, atom: classic },
{ title: t("timeControlEnum", { tc: TimeControl.Rapid }), atom: rapid }, { tc: TimeControl.Rapid, atom: rapid },
{ title: t("timeControlEnum", { tc: TimeControl.Blitz }), atom: blitz }, { tc: TimeControl.Blitz, atom: blitz },
{ title: t("timeControlEnum", { tc: TimeControl.KO }), atom: oneHourKO }, { tc: TimeControl.Other, atom: other },
]; ].filter(({ tc }) => tournaments.some((t) => t.timeControl === tc));
return ( return (
<div className="flex flex-wrap gap-3"> <div className="flex flex-wrap gap-3">
{checkboxes.map((cb, i) => ( {checkboxes.map(({ tc, atom }, i) => (
<div key={i} className="text-gray-900 dark:text-white"> <div key={i} className="text-gray-900 dark:text-white">
<label> <label>
<input <input
type="checkbox" type="checkbox"
className="mr-2" className="mr-2"
checked={cb.atom[0]} checked={atom[0]}
onChange={() => cb.atom[1](!cb.atom[0])} onChange={() => atom[1](!atom[0])}
/> />
{cb.title} {t("timeControlEnum", { tc })}
</label> </label>
</div> </div>
))} ))}
+3 -3
View File
@@ -27,7 +27,7 @@ import {
classicAtom, classicAtom,
rapidAtom, rapidAtom,
blitzAtom, blitzAtom,
oneHourKOAtom, otherAtom,
} from "@/app/atoms"; } from "@/app/atoms";
import Legend from "./Legend"; import Legend from "./Legend";
@@ -249,7 +249,7 @@ export default function TournamentMap() {
const classic = useAtomValue(classicAtom); const classic = useAtomValue(classicAtom);
const rapid = useAtomValue(rapidAtom); const rapid = useAtomValue(rapidAtom);
const blitz = useAtomValue(blitzAtom); const blitz = useAtomValue(blitzAtom);
const other = useAtomValue(oneHourKOAtom); const other = useAtomValue(otherAtom);
useEffect(() => { useEffect(() => {
if (hoveredListTournamentId === null) { if (hoveredListTournamentId === null) {
@@ -300,7 +300,7 @@ export default function TournamentMap() {
<TimeControlGroup timeControl={TimeControl.Blitz} colour="yellow" /> <TimeControlGroup timeControl={TimeControl.Blitz} colour="yellow" />
)} )}
{other && ( {other && (
<TimeControlGroup timeControl={TimeControl.KO} colour="red" /> <TimeControlGroup timeControl={TimeControl.Other} colour="red" />
)} )}
</MapContainer> </MapContainer>
+1 -1
View File
@@ -29,7 +29,7 @@ export const TournamentMarker = forwardRef<
? -0.01 ? -0.01
: tournament.timeControl === TimeControl.Blitz : tournament.timeControl === TimeControl.Blitz
? 0.01 ? 0.01
: tournament.timeControl === TimeControl.KO : tournament.timeControl === TimeControl.Other
? 0.02 ? 0.02
: 0), : 0),
}); });
+2 -3
View File
@@ -14,7 +14,7 @@ export interface TournamentData {
department: string; department: string;
tournament: string; tournament: string;
url: string; url: string;
time_control: "Cadence Lente" | "Rapide" | "Blitz" | "1h KO"; time_control: "Cadence Lente" | "Rapide" | "Blitz" | string;
date: string; date: string;
coordinates: [number, number]; coordinates: [number, number];
} }
@@ -23,7 +23,6 @@ const tcMap: Record<TournamentData["time_control"], TimeControl> = {
"Cadence Lente": TimeControl.Classic, "Cadence Lente": TimeControl.Classic,
Rapide: TimeControl.Rapid, Rapide: TimeControl.Rapid,
Blitz: TimeControl.Blitz, Blitz: TimeControl.Blitz,
"1h KO": TimeControl.KO,
}; };
const getTournaments = async () => { const getTournaments = async () => {
@@ -57,7 +56,7 @@ const getTournaments = async () => {
return data.map<Tournament>((t) => ({ return data.map<Tournament>((t) => ({
...t, ...t,
_id: t._id.toString(), _id: t._id.toString(),
timeControl: tcMap[t.time_control], timeControl: tcMap[t.time_control] ?? TimeControl.Other,
latLng: { lat: t.coordinates[0], lng: t.coordinates[1] }, latLng: { lat: t.coordinates[0], lng: t.coordinates[1] },
})); }));
} catch (error) { } catch (error) {
+3 -3
View File
@@ -12,7 +12,7 @@ export const searchStringAtom = atom('');
export const classicAtom = atom(true); export const classicAtom = atom(true);
export const rapidAtom = atom(true); export const rapidAtom = atom(true);
export const blitzAtom = atom(true); export const blitzAtom = atom(true);
export const oneHourKOAtom = atom(true); export const otherAtom = atom(true);
export const { export const {
currentValueAtom: hoveredMapTournamentIdAtom, currentValueAtom: hoveredMapTournamentIdAtom,
@@ -29,13 +29,13 @@ export const filteredTournamentsByTimeControlAtom = atom((get) => {
const classic = get(classicAtom); const classic = get(classicAtom);
const rapid = get(rapidAtom); const rapid = get(rapidAtom);
const blitz = get(blitzAtom); const blitz = get(blitzAtom);
const oneHourKO = get(oneHourKOAtom); const other = get(otherAtom);
return tournaments.filter(tournament => return tournaments.filter(tournament =>
(tournament.timeControl === TimeControl.Classic && classic) || (tournament.timeControl === TimeControl.Classic && classic) ||
(tournament.timeControl === TimeControl.Rapid && rapid) || (tournament.timeControl === TimeControl.Rapid && rapid) ||
(tournament.timeControl === TimeControl.Blitz && blitz) || (tournament.timeControl === TimeControl.Blitz && blitz) ||
(tournament.timeControl === TimeControl.KO && oneHourKO)); (tournament.timeControl === TimeControl.Other && other));
}); });
export const filteredTournamentsListAtom = atom((get) => { export const filteredTournamentsListAtom = atom((get) => {
View File
+2 -2
View File
@@ -22,10 +22,10 @@
background-color: rgba(202, 196, 39, 0.6) background-color: rgba(202, 196, 39, 0.6)
} }
.marker-cluster-KO { .marker-cluster-Other {
background-color: rgba(211, 67, 84, 0.6); background-color: rgba(211, 67, 84, 0.6);
} }
.marker-cluster-KO div { .marker-cluster-Other div {
background-color: rgba(203, 41, 60, 0.6); background-color: rgba(203, 41, 60, 0.6);
} }
+1 -1
View File
@@ -35,7 +35,7 @@
"tournament": "Tournament", "tournament": "Tournament",
"timeControl": "Time Control", "timeControl": "Time Control",
"approx": "Géo-localisation is approximative", "approx": "Géo-localisation is approximative",
"timeControlEnum": "{tc, select, Classic {Classic} Rapid {Rapid} Blitz {Blitz} KO {1h KO} other {{tc}}}", "timeControlEnum": "{tc, select, Classic {Classic} Rapid {Rapid} Blitz {Blitz} Other {Other} other {{tc}}}",
"clearButton": "Clear" "clearButton": "Clear"
}, },
+1 -1
View File
@@ -35,7 +35,7 @@
"tournament": "Tournois", "tournament": "Tournois",
"timeControl": "Cadence", "timeControl": "Cadence",
"approx": "Géolocalisation approximative", "approx": "Géolocalisation approximative",
"timeControlEnum": "{tc, select, Classic {Cadence Lente} Rapid {Rapide} Blitz {Blitz} KO {1h KO} other {{tc}}}", "timeControlEnum": "{tc, select, Classic {Cadence Lente} Rapid {Rapide} Blitz {Blitz} Other {Autres} other {{tc}}}",
"clearButton": "Effacer" "clearButton": "Effacer"
}, },
+1 -1
View File
@@ -4,7 +4,7 @@ export enum TimeControl {
Classic = "Classic", Classic = "Classic",
Rapid = "Rapid", Rapid = "Rapid",
Blitz = "Blitz", Blitz = "Blitz",
KO = "KO", Other = "Other",
}; };
export interface Tournament { export interface Tournament {