mirror of
https://github.com/TheRealOwenRees/echecsfrance.git
synced 2026-07-23 04:26:57 +00:00
Merge pull request #79 from TheRealOwenRees/feature/other
Various changed
This commit is contained in:
Vendored
+3
-1
@@ -25,5 +25,7 @@
|
|||||||
"tournois",
|
"tournois",
|
||||||
"unspiderfied",
|
"unspiderfied",
|
||||||
"unspiderfy"
|
"unspiderfy"
|
||||||
]
|
],
|
||||||
|
|
||||||
|
"css.customData": [".vscode/tailwindcss.json"],
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+55
@@ -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 you’d 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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
@@ -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) => {
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user