Fix layout issues & co-locate components (#46)

* Fix layout issues & co-locate components

* Fix front page

* Fix centering
This commit is contained in:
Timothy Armes
2023-07-04 13:26:25 +02:00
committed by GitHub
parent a9822b65fe
commit 75a6c74306
26 changed files with 306 additions and 305 deletions
+1
View File
@@ -11,6 +11,7 @@
"localisation", "localisation",
"randomisation", "randomisation",
"Rapide", "Rapide",
"Rees",
"sommes", "sommes",
"tournois" "tournois"
] ]
@@ -7,12 +7,13 @@ export default function Footer() {
return ( return (
<footer <footer
className="fixed bottom-0 z-30 grid w-full justify-items-center bg-teal-600 px-5 py-2 text-white dark:bg-gray-700" className="fixed bottom-0 z-30 flex h-20 w-full flex-col items-center justify-center justify-items-center bg-teal-600 px-5 py-2 text-white dark:bg-gray-700"
data-test="footer" data-test="footer"
> >
<div className="p-2"> <div>
<p>&copy; {new Date().getFullYear()} - Owen Rees</p> <p>&copy; {new Date().getFullYear()} - Owen Rees</p>
</div> </div>
<div className="flex space-x-4 p-2"> <div className="flex space-x-4 p-2">
<Link <Link
href="https://github.com/TheRealOwenRees/echecsfrance" href="https://github.com/TheRealOwenRees/echecsfrance"
@@ -1,6 +1,6 @@
"use client"; "use client";
import HamburgerMenu from "@/components/HamburgerMenu"; import HamburgerMenu from "./HamburgerMenu";
import { useRef, useState } from "react"; import { useRef, useState } from "react";
const Hamburger = () => { const Hamburger = () => {
@@ -30,13 +30,12 @@ const Hamburger = () => {
}`} }`}
></div> ></div>
</div> </div>
{
<HamburgerMenu <HamburgerMenu
menuVisible={menuVisible} menuVisible={menuVisible}
setMenuVisible={setMenuVisible} setMenuVisible={setMenuVisible}
hamburgerButtonRef={hamburgerButtonRef} hamburgerButtonRef={hamburgerButtonRef}
/> />
}
</> </>
); );
}; };
@@ -8,8 +8,8 @@ import { Dispatch, RefObject, SetStateAction, useRef, useState } from "react";
import Link from "next-intl/link"; import Link from "next-intl/link";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import ThemeSwitcher from "@/components/ThemeSwitcher";
import useHamburgerClose from "@/hooks/useHamburgerClose"; import useHamburgerClose from "@/hooks/useHamburgerClose";
import ThemeSwitcher from "./ThemeSwitcher";
const HamburgerMenu = ({ const HamburgerMenu = ({
menuVisible, menuVisible,
@@ -53,9 +53,9 @@ const HamburgerMenu = ({
return ( return (
<div <div
ref={menuRef} ref={menuRef}
className={`absolute -right-[173px] top-0 ${ className={`fixed right-0 top-0 ${
menuVisible ? "-translate-x-full" : "" menuVisible ? "" : "translate-x-full"
} z-[9999] flex bg-teal-600 transition-transform duration-500 ease-linear dark:bg-gray-600 md:hidden`} } z-[9999] flex bg-teal-600 transition-transform duration-200 ease-linear dark:bg-gray-600 md:hidden`}
onMouseEnter={handleMouseEnterMenu} onMouseEnter={handleMouseEnterMenu}
onMouseLeave={handleMouseLeaveMenu} onMouseLeave={handleMouseLeaveMenu}
> >
@@ -65,7 +65,7 @@ const HamburgerMenu = ({
href="/tournois" href="/tournois"
className="border-b-2 border-transparent transition-all duration-300 ease-in-out hover:border-white" className="border-b-2 border-transparent transition-all duration-300 ease-in-out hover:border-white"
> >
{t("competitions")} {t("tournaments")}
</Link> </Link>
</li> </li>
<li className="py-5"> <li className="py-5">
+65
View File
@@ -0,0 +1,65 @@
import Link from "next-intl/link";
import { useTranslations } from "next-intl";
import ThemeSwitcher from "./ThemeSwitcher";
import Hamburger from "./Hamburger";
export default function Navbar() {
const t = useTranslations("Nav");
return (
<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"
data-test="navbar"
>
<div className="container mx-auto flex h-full items-center">
<div className="flex w-full justify-center font-extrabold md:w-1/2 md:justify-start">
<Link
className="text-gray-900 no-underline hover:no-underline dark:text-white"
href="/"
>
<span className="text-2xl">{t("title")}</span>
</Link>
</div>
<div className="pb-2 md:hidden" data-test="mobile-menu">
<Hamburger />
</div>
<div
className="hidden h-full justify-center md:flex md:w-1/2 md:justify-end"
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">
<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="/tournois"
>
{t("tournaments")}
</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>
</li>
<li>
<ThemeSwitcher />
</li>
</ul>
</div>
</div>
</nav>
);
}
+30
View File
@@ -0,0 +1,30 @@
import { NextIntlClientProvider, AbstractIntlMessages } from "next-intl";
import { ReactNode } from "react";
import "@/app/globals.css";
import Navbar from "./Navbar";
import Footer from "./Footer";
const TestableLayout = ({
children,
locale,
messages,
}: {
children: ReactNode;
locale: string;
messages: AbstractIntlMessages;
}) => {
return (
<NextIntlClientProvider locale={locale} messages={messages}>
<div className="flex min-h-screen flex-col bg-white font-sans leading-normal tracking-normal dark:bg-gray-800">
<Navbar />
<div className="relative mb-20 flex flex-1 justify-center">
{children}
</div>
<Footer />
</div>
</NextIntlClientProvider>
);
};
export default TestableLayout;
+15 -18
View File
@@ -1,28 +1,25 @@
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import Layout from "@/components/Layout"; import ContactForm from "./ContactForm";
import ContactForm from "@/components/ContactForm";
// TODO fix page sizing // TODO fix page sizing
export default function Contact() { export default function Contact() {
const t = useTranslations("Contact"); const t = useTranslations("Contact");
return ( return (
<Layout> <section className="grid place-items-center bg-white dark:bg-gray-800">
<section className="grid place-items-center bg-white dark:bg-gray-800"> <div className="mx-auto max-w-screen-md px-4 pb-16 pt-8 lg:pt-16">
<div className="mx-auto max-w-screen-md px-4 pb-32 pt-8 lg:pt-16"> <h2
<h2 className="mb-4 text-center text-4xl font-extrabold tracking-tight text-gray-900 dark:text-white"
className="mb-4 text-center text-4xl font-extrabold tracking-tight text-gray-900 dark:text-white" data-test="header2"
data-test="header2" >
> {t("title")}
{t("title")} </h2>
</h2> <p className="mb-8 text-center font-light text-gray-500 dark:text-gray-400 sm:text-xl lg:mb-16">
<p className="mb-8 text-center font-light text-gray-500 dark:text-gray-400 sm:text-xl lg:mb-16"> {t("info")}
{t("info")} </p>
</p> <ContactForm />
<ContactForm /> </div>
</div> </section>
</section>
</Layout>
); );
} }
+4 -3
View File
@@ -1,11 +1,12 @@
import { Analytics } from "@vercel/analytics/react"; import { Analytics } from "@vercel/analytics/react";
import { Inter } from "next/font/google"; import { Inter } from "next/font/google";
import { useLocale, NextIntlClientProvider } from "next-intl"; import { useLocale } from "next-intl";
import { getTranslator } from "next-intl/server"; 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 "@/app/globals.css";
import TestableLayout from "./components/TestableLayout";
const inter = Inter({ subsets: ["latin"] }); const inter = Inter({ subsets: ["latin"] });
@@ -49,9 +50,9 @@ export default async function RootLayout({
return ( return (
<html lang={locale}> <html lang={locale}>
<body className={inter.className}> <body className={inter.className}>
<NextIntlClientProvider locale={locale} messages={messages}> <TestableLayout locale={locale} messages={messages}>
{children} {children}
</NextIntlClientProvider> </TestableLayout>
<Analytics /> <Analytics />
</body> </body>
</html> </html>
+31 -34
View File
@@ -2,45 +2,42 @@ import Link from "next/link";
import Image from "next/image"; import Image from "next/image";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import Layout from "@/components/Layout";
import bgImage from "@/public/images/map-bg.jpg"; import bgImage from "@/public/images/map-bg.jpg";
export default function Home() { export default function Home() {
const t = useTranslations("Home"); const t = useTranslations("Home");
return ( return (
<Layout> <header className="relative flex flex-1 items-center justify-center">
<header className="grid h-[calc(100%-153px)] md:h-[calc(100%-173px)] items-center"> <div className="absolute h-full w-full brightness-[0.2]">
<div className="relative h-full w-full brightness-[0.2]"> <Image
<Image src={bgImage}
src={bgImage} alt="Background image of France"
alt="Background image of France" fill={true}
fill={true} style={{ objectFit: "cover" }}
style={{ objectFit: "cover" }} />
/> </div>
</div> <div className="z-10 text-center text-white">
<div className="absolute flex flex-col items-center w-full text-center text-white"> <h1 className="p-5 text-5xl" data-test="header1">
<h1 className="p-5 text-5xl" data-test="header1"> {t("title")}
{t("title")} </h1>
</h1> <h2 className="p-5 text-3xl">{t("purpose")}</h2>
<h2 className="p-5 text-3xl">{t("purpose")}</h2> <h3 className="mb-5 p-5 text-xl">
<h3 className="mb-5 p-5 text-xl"> {t.rich("how", {
{t.rich("how", { link: (chunks) => (
link: (chunks) => ( <Link href="http://www.echecs.asso.fr/" target="_blank">
<Link href="http://www.echecs.asso.fr/" target="_blank"> <abbr title="Fédération Française des Échecs">{chunks}</abbr>
<abbr title="Fédération Française des Échecs">{chunks}</abbr> </Link>
</Link> ),
), })}
})} </h3>
</h3> <Link
<Link href="/tournois"
href="/tournois" className="mb-2 mr-2 rounded-lg bg-gradient-to-r from-teal-400 via-teal-500 to-teal-600 px-5 py-2.5 text-center text-sm font-medium text-white hover:bg-gradient-to-br focus:outline-none focus:ring-4 focus:ring-teal-300 dark:focus:ring-teal-800"
className="mb-2 mr-2 rounded-lg bg-gradient-to-r from-teal-400 via-teal-500 to-teal-600 px-5 py-2.5 text-center text-sm font-medium text-white hover:bg-gradient-to-br focus:outline-none focus:ring-4 focus:ring-teal-300 dark:focus:ring-teal-800" >
> {t("mapLink")}
{t("mapLink")} </Link>
</Link> </div>
</div> </header>
</header>
</Layout>
); );
} }
+105 -109
View File
@@ -1,121 +1,117 @@
import Link from "next-intl/link"; import Link from "next-intl/link";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import Layout from "@/components/Layout";
export default function About() { export default function About() {
const t = useTranslations("About"); const t = useTranslations("About");
return ( return (
<Layout> <header className="mb-16 grid place-items-center bg-white dark:bg-gray-800">
<header className="grid place-items-center bg-white dark:bg-gray-800"> <div className="h-full max-w-5xl bg-white px-4 pt-8 dark:bg-gray-800">
<div className="h-full max-w-5xl bg-white px-4 pb-12 pt-8 dark:bg-gray-800"> <h2
<h2 className="mb-8 text-center text-4xl font-extrabold tracking-tight text-gray-900 dark:text-white"
className="mb-8 text-center text-4xl font-extrabold tracking-tight text-gray-900 dark:text-white" data-test="header2"
data-test="header2" >
> {t("title")}
{t("title")} </h2>
</h2> <p className="mb-4 text-center font-light text-gray-500 dark:text-gray-400 md:text-xl">
<p className="mb-4 text-center font-light text-gray-500 dark:text-gray-400 md:text-xl"> {t("p1")}
{t("p1")} </p>
</p> <p className="mb-4 text-center font-light text-gray-500 dark:text-gray-400 md:text-xl">
<p className="mb-4 text-center font-light text-gray-500 dark:text-gray-400 md:text-xl"> {t.rich("p2", {
{t.rich("p2", { homeLink: (chunks) => (
homeLink: (chunks) => ( <Link href="/" className="text-teal-600">
<Link href="/" className="text-teal-600"> {chunks}
{chunks}
</Link>
),
})}
</p>
<p className="mb-4 text-center font-light text-gray-500 dark:text-gray-400 md:text-xl">
{t("p3")}
</p>
<h3
className="mb-4 mt-8 text-center text-2xl font-extrabold tracking-tight text-gray-900 dark:text-white"
data-test="header2"
>
{t("thanksTitle")}
</h3>
<ul className="mb-4 text-center text-teal-600">
<li>
<Link href="https://github.com/AlvaroNW" target="_blank">
AlvaroNW
</Link> </Link>
</li> ),
<li> })}
<Link href="https://github.com/Florifourchette" target="_blank"> </p>
Florifourchette <p className="mb-4 text-center font-light text-gray-500 dark:text-gray-400 md:text-xl">
{t("p3")}
</p>
<h3
className="mb-4 mt-8 text-center text-2xl font-extrabold tracking-tight text-gray-900 dark:text-white"
data-test="header2"
>
{t("thanksTitle")}
</h3>
<ul className="mb-4 text-center text-teal-600">
<li>
<Link href="https://github.com/AlvaroNW" target="_blank">
AlvaroNW
</Link>
</li>
<li>
<Link href="https://github.com/Florifourchette" target="_blank">
Florifourchette
</Link>
</li>
</ul>
<h3
className="mb-4 mt-8 text-center text-2xl font-extrabold tracking-tight text-gray-900 dark:text-white"
data-test="header2"
>
{t("techTitle")}
</h3>
<p className="mb-4 text-center font-light text-gray-500 dark:text-gray-400 md:text-xl">
{t.rich("techInfo", {
homeLink: (chunks) => (
<Link href="/" className="text-teal-600">
{chunks}
</Link> </Link>
</li> ),
</ul> })}
<h3 </p>
className="mb-4 mt-8 text-center text-2xl font-extrabold tracking-tight text-gray-900 dark:text-white" <ul className="mb-4 flex justify-around text-teal-600">
data-test="header2" <li>
> <Link href="https://nextjs.org/" target="_blank">
{t("techTitle")} NextJS
</h3> </Link>
<p className="mb-4 text-center font-light text-gray-500 dark:text-gray-400 md:text-xl"> </li>
{t.rich("techInfo", { <li>
homeLink: (chunks) => ( <Link href="#" target="_blank">
<Link href="/" className="text-teal-600"> Typescript
{chunks} </Link>
</Link> </li>
), <li>
})} <Link href="https://tailwindcss.com/" target="_blank">
</p> Tailwind
<ul className="mb-4 flex justify-around text-teal-600"> </Link>
<li> </li>
<Link href="https://nextjs.org/" target="_blank"> <li>
NextJS <Link href="https://mongodb.com/" target="_blank">
MongoDB
</Link>
</li>
</ul>
<p className="mb-4 text-center font-light text-gray-500 dark:text-gray-400 md:text-xl">
{t("techWith")}
</p>
<ul className="mb-4 flex justify-around text-teal-600">
<li>
<Link href="https://leafletjs.com/" target="_blank">
Leaflet
</Link>
</li>
<li>
<Link href="https://nodemailer.com/" target="_blank">
Nodemailer
</Link>
</li>
</ul>
<p className="text-center font-light text-gray-500 dark:text-gray-400 md:text-xl">
{t.rich("contribInfo", {
link: (chunks) => (
<Link
href="https://github.com/TheRealOwenRees/echecsfrance"
target="_blank"
className="text-teal-600"
>
{chunks}
</Link> </Link>
</li> ),
<li> })}
<Link href="#" target="_blank"> </p>
Typescript </div>
</Link> </header>
</li>
<li>
<Link href="https://tailwindcss.com/" target="_blank">
Tailwind
</Link>
</li>
<li>
<Link href="https://mongodb.com/" target="_blank">
MongoDB
</Link>
</li>
</ul>
<p className="mb-4 text-center font-light text-gray-500 dark:text-gray-400 md:text-xl">
{t("techWith")}
</p>
<ul className="mb-4 flex justify-around text-teal-600">
<li>
<Link href="https://leafletjs.com/" target="_blank">
Leaflet
</Link>
</li>
<li>
<Link href="https://nodemailer.com/" target="_blank">
Nodemailer
</Link>
</li>
</ul>
<p className="mb-16 text-center font-light text-gray-500 dark:text-gray-400 md:text-xl">
{t.rich("contribInfo", {
link: (chunks) => (
<Link
href="https://github.com/TheRealOwenRees/echecsfrance"
target="_blank"
className="text-teal-600"
>
{chunks}
</Link>
),
})}
</p>
</div>
</header>
</Layout>
); );
} }
@@ -10,7 +10,7 @@ const SearchBar = ({
tournamentFilter, tournamentFilter,
setTournamentFilter, setTournamentFilter,
}: SearchBarProps) => { }: SearchBarProps) => {
const t = useTranslations("Competitions"); const t = useTranslations("Tournaments");
return ( return (
<div className="bg-white p-3 dark:bg-gray-800"> <div className="bg-white p-3 dark:bg-gray-800">
@@ -10,7 +10,7 @@ import "leaflet-defaulticon-compatibility";
import { MapContainer, TileLayer, LayersControl } from "react-leaflet"; import { MapContainer, TileLayer, LayersControl } from "react-leaflet";
import { createLayerGroups } from "@/utils/layerGroups"; import { createLayerGroups } from "@/utils/layerGroups";
import Legend from "@/components/Legend"; import Legend from "./Legend";
export default function TournamentMap({ tournamentData }: TournamentDataProps) { export default function TournamentMap({ tournamentData }: TournamentDataProps) {
const center: LatLngLiteral = { lat: 47.0844, lng: 2.3964 }; const center: LatLngLiteral = { lat: 47.0844, lng: 2.3964 };
@@ -28,10 +28,7 @@ export default function TournamentMap({ tournamentData }: TournamentDataProps) {
const otherMarkers = createLayerGroups("1h KO", "red", { tournamentData }); const otherMarkers = createLayerGroups("1h KO", "red", { tournamentData });
return ( return (
<section <section id="tournament-map" className="grid h-[calc(100vh-144px)]">
id="tournament-map"
className="grid h-[calc(100vh-153px)] md:h-[calc(100vh-83px)] lg:h-[calc(100vh-173px)]"
>
<MapContainer <MapContainer
center={center} center={center}
zoom={5} zoom={5}
@@ -4,14 +4,14 @@ import { TournamentDataProps } from "@/types";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import SearchBar from "@/components/SearchBar"; import SearchBar from "./SearchBar";
import ScrollToTopButton from "@/components/ScrollToTopButton"; import ScrollToTopButton from "./ScrollToTopButton";
export default function TournamentTable({ export default function TournamentTable({
tournamentData, tournamentData,
}: TournamentDataProps) { }: TournamentDataProps) {
let tableData; let tableData;
const t = useTranslations("Competitions"); const t = useTranslations("Tournaments");
const [searchQuery, setSearchQuery] = useState(""); // text from search bar const [searchQuery, setSearchQuery] = useState(""); // text from search bar
const [filteredTournamentData, setFilteredTournamentData] = const [filteredTournamentData, setFilteredTournamentData] =
useState(tournamentData); useState(tournamentData);
@@ -63,7 +63,7 @@ export default function TournamentTable({
return ( return (
<section <section
className="tournament-table grid w-full auto-rows-max pb-20 lg:col-start-2 lg:col-end-3 lg:h-[calc(100vh-173px)] lg:overflow-y-scroll" className="tournament-table grid w-full auto-rows-max pb-20 lg:col-start-2 lg:col-end-3 lg:h-[calc(100vh-144px)] lg:overflow-y-scroll"
id="tournament-table" id="tournament-table"
data-test="tournament-table-div" data-test="tournament-table-div"
> >
@@ -89,7 +89,7 @@ export default function TournamentTable({
{t("town")} {t("town")}
</th> </th>
<th className="sticky top-0 bg-teal-600 p-3 text-white dark:bg-gray-600"> <th className="sticky top-0 bg-teal-600 p-3 text-white dark:bg-gray-600">
{t("competition")} {t("tournament")}
</th> </th>
<th className="sticky top-0 bg-teal-600 p-3 text-white dark:bg-gray-600"> <th className="sticky top-0 bg-teal-600 p-3 text-white dark:bg-gray-600">
{t("timeControl")} {t("timeControl")}
+12 -14
View File
@@ -2,15 +2,15 @@ import clientPromise from "@/lib/mongodb";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import Layout from "@/components/Layout";
import TournamentTable from "@/components/TournamentTable";
import { dateOrderingFrance } from "@/utils/dbDateOrdering"; import { dateOrderingFrance } from "@/utils/dbDateOrdering";
import { errorLog } from "@/utils/logger"; import { errorLog } from "@/utils/logger";
import TournamentTable from "./TournamentTable";
export const revalidate = 3600; // revalidate cache every 6 hours; export const revalidate = 3600; // revalidate cache every 6 hours;
const LoadingMap = () => { const LoadingMap = () => {
const t = useTranslations("Competitions"); const t = useTranslations("Tournaments");
return ( return (
<div className="grid h-screen place-items-center bg-white text-gray-900 dark:bg-gray-800 dark:text-white"> <div className="grid h-screen place-items-center bg-white text-gray-900 dark:bg-gray-800 dark:text-white">
<p>{t("loading")}</p> <p>{t("loading")}</p>
@@ -22,7 +22,7 @@ const LoadingMap = () => {
* Imports the tournament map component, ensuring CSR only. * Imports the tournament map component, ensuring CSR only.
* @remarks SSR is not supported by react-leaflet * @remarks SSR is not supported by react-leaflet
*/ */
const TournamentMap = dynamic(() => import("@/components/TournamentMap"), { const TournamentMap = dynamic(() => import("./TournamentMap"), {
ssr: false, ssr: false,
loading: LoadingMap, loading: LoadingMap,
}); });
@@ -43,15 +43,13 @@ export default async function Tournaments() {
const tournamentData = await getTournaments(); const tournamentData = await getTournaments();
return ( return (
<Layout> <main className="relative grid h-full lg:grid-cols-2">
<main className="relative grid lg:grid-cols-2"> <div className="">
<div className=""> <TournamentMap tournamentData={JSON.parse(tournamentData)} />
<TournamentMap tournamentData={JSON.parse(tournamentData)} /> </div>
</div> <div className="relative bg-white dark:bg-gray-800 lg:overflow-y-auto">
<div className="relative bg-white dark:bg-gray-800 lg:overflow-y-auto"> <TournamentTable tournamentData={JSON.parse(tournamentData)} />
<TournamentTable tournamentData={JSON.parse(tournamentData)} /> </div>
</div> </main>
</main>
</Layout>
); );
} }
-17
View File
@@ -1,17 +0,0 @@
import Navbar from "@/components/Navbar";
import Footer from "@/components/Footer";
import { ReactNode } from "react";
export default function Layout({
children, // will be a page or nested layout
}: {
children: ReactNode;
}) {
return (
<div className="h-screen min-h-[600px] bg-white dark:bg-gray-800 font-sans leading-normal tracking-normal">
<Navbar />
{children}
<Footer />
</div>
);
}
-65
View File
@@ -1,65 +0,0 @@
import Link from "next-intl/link";
import { useTranslations } from "next-intl";
import ThemeSwitcher from "@/components/ThemeSwitcher";
import Hamburger from "@/components/Hamburger";
export default function Navbar() {
const t = useTranslations("Nav");
return (
<nav
className="relative mt-0 w-full overflow-x-clip border-b-[1px] bg-white px-5 pt-5 dark:border-gray-700 dark:bg-gray-800 md:pt-2"
data-test="navbar"
>
<div className="container mx-auto flex items-center">
<div className="flex w-full justify-center pb-3 font-extrabold md:w-1/2 md:justify-start md:pb-0">
<Link
className="text-gray-900 no-underline hover:no-underline dark:text-white"
href="/"
>
<span className="text-2xl">{t("title")}</span>
</Link>
</div>
<div className="pb-2 md:hidden" data-test="mobile-menu">
<Hamburger />
</div>
<div
className="hidden justify-center pt-2 md:flex md:w-1/2 md:justify-end"
data-test="desktop-menu"
>
<ul className="list-reset flex flex-1 items-center justify-around text-gray-900 no-underline dark:text-white md:flex-none">
<li className="mr-10">
<Link
className="inline-block border-b-4 border-transparent py-5 transition-all duration-300 ease-in-out hover:border-teal-600"
href="/tournois"
>
{t("competitions")}
</Link>
</li>
<li className="mr-10">
<Link
className="inline-block border-b-4 border-transparent py-5 transition-all duration-300 ease-in-out hover:border-teal-600"
href="/qui-sommes-nous"
>
{t("about")}
</Link>
</li>
<li className="mr-10">
<Link
className="inline-block border-b-4 border-transparent py-5 transition-all duration-300 ease-in-out hover:border-teal-600"
href="/contactez-nous"
>
{t("contact")}
</Link>
</li>
<li>
<ThemeSwitcher />
</li>
</ul>
</div>
</div>
</nav>
);
}
+1 -1
View File
@@ -1,4 +1,4 @@
import ScrollToTopButton from "@/components/ScrollToTopButton"; import ScrollToTopButton from "@/app/[lang]/tournois/ScrollToTopButton";
describe("Scroll to top button", () => { describe("Scroll to top button", () => {
it("desktop scroll button clickable", () => { it("desktop scroll button clickable", () => {
+3 -2
View File
@@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import ThemeSwitcher from "../../components/ThemeSwitcher"; import ThemeSwitcher from "@/app/[lang]/components/ThemeSwitcher";
import "@/css/theme-toggle.css"; import "@/css/theme-toggle.css";
describe("ThemeSwitcher component", () => { describe("ThemeSwitcher component", () => {
@@ -14,8 +14,9 @@ describe("ThemeSwitcher component", () => {
"linear-gradient(rgb(0, 255, 255), rgb(135, 206, 235)" "linear-gradient(rgb(0, 255, 255), rgb(135, 206, 235)"
); );
}); });
// checking that the toggle is clickable and dark mode is active // checking that the toggle is clickable and dark mode is active
cy.getByData("toggle").click(); cy.getByData("toggle").last().click();
cy.getByData("toggle-dark").should("exist"); cy.getByData("toggle-dark").should("exist");
cy.getByData("toggle-dark").should(($toggle) => { cy.getByData("toggle-dark").should(($toggle) => {
const backgroundImage = $toggle.css("background-image"); const backgroundImage = $toggle.css("background-image");
+3 -3
View File
@@ -14,8 +14,8 @@
// *********************************************************** // ***********************************************************
import { mount } from "cypress/react18"; import { mount } from "cypress/react18";
import { NextIntlClientProvider } from "next-intl";
import TestableLayout from "@/app/[lang]/components/TestableLayout";
import messages from "@/messages/fr.json"; import messages from "@/messages/fr.json";
import "./commands"; import "./commands";
@@ -37,9 +37,9 @@ declare global {
Cypress.Commands.add("mount", (component, options) => { Cypress.Commands.add("mount", (component, options) => {
const wrapped = ( const wrapped = (
<NextIntlClientProvider locale="fr" messages={messages}> <TestableLayout locale="fr" messages={messages}>
{component} {component}
</NextIntlClientProvider> </TestableLayout>
); );
return mount(wrapped, options); return mount(wrapped, options);
+7 -7
View File
@@ -1,13 +1,13 @@
{ {
"Metadata": { "Metadata": {
"title": "Echecs France - Tournois d'Echecs", "title": "Echecs France - Tournois d'Echecs",
"description": "Find chess competitions, in France, on a map", "description": "Find chess tournaments, in France, on a map",
"keywords": "chess, France, competition, competitions, FFE, map" "keywords": "chess, France, tournament, tournaments, FFE, map"
}, },
"Nav": { "Nav": {
"title": "Echecs France", "title": "Echecs France",
"competitions": "Competitions", "tournaments": "Tournaments",
"about": "About Us", "about": "About Us",
"contact": "Contact" "contact": "Contact"
}, },
@@ -26,19 +26,19 @@
"Home": { "Home": {
"title": "France Echecs", "title": "France Echecs",
"purpose": "Find chess competitions, in France, on a map", "purpose": "Find chess tournaments, in France, on a map",
"how": "A graphical representation of all the chess competitions published by the <link>FFE</link>", "how": "A graphical representation of all the chess tournaments published by the <link>FFE</link>",
"mapLink": "See the Map" "mapLink": "See the Map"
}, },
"Competitions": { "Tournaments": {
"loading": "Loading...", "loading": "Loading...",
"searchLabel": "Search", "searchLabel": "Search",
"searchPlaceholder": "Search", "searchPlaceholder": "Search",
"noneFound": "No tournaments found", "noneFound": "No tournaments found",
"date": "Date", "date": "Date",
"town": "Town", "town": "Town",
"competition": "Competition", "tournament": "Tournament",
"timeControl": "Time Control", "timeControl": "Time Control",
"approx": "Géo-localisation is approximative" "approx": "Géo-localisation is approximative"
}, },
+3 -3
View File
@@ -7,7 +7,7 @@
"Nav": { "Nav": {
"title": "Échecs France", "title": "Échecs France",
"competitions": "Tournois", "tournaments": "Tournois",
"about": "Qui Sommes-Nous", "about": "Qui Sommes-Nous",
"contact": "Contactez-Nous" "contact": "Contactez-Nous"
}, },
@@ -31,14 +31,14 @@
"mapLink": "Voir La Carte" "mapLink": "Voir La Carte"
}, },
"Competitions": { "Tournaments": {
"loading": "Téléchargement...", "loading": "Téléchargement...",
"searchLabel": "Rechercher", "searchLabel": "Rechercher",
"searchPlaceholder": "Rechercher", "searchPlaceholder": "Rechercher",
"noneFound": "Pas de tournois trouvé", "noneFound": "Pas de tournois trouvé",
"date": "Date", "date": "Date",
"town": "Ville", "town": "Ville",
"competition": "Tournois", "tournament": "Tournois",
"timeControl": "Cadence", "timeControl": "Cadence",
"approx": "Géolocalisation approximative" "approx": "Géolocalisation approximative"
}, },
+3 -3
View File
@@ -22,12 +22,12 @@ type TournamentMarkerProps = {
colour: string; colour: string;
} & Omit<MarkerProps, "position">; } & Omit<MarkerProps, "position">;
export const CompetitionMarker = ({ export const TournamentMarker = ({
tournament, tournament,
colour, colour,
...markerProps ...markerProps
}: TournamentMarkerProps) => { }: TournamentMarkerProps) => {
const t = useTranslations("Competitions"); const t = useTranslations("Tournaments");
const iconOptions = new L.Icon({ const iconOptions = new L.Icon({
iconUrl: `/images/leaflet/marker-icon-2x-${colour}.png`, iconUrl: `/images/leaflet/marker-icon-2x-${colour}.png`,
@@ -72,7 +72,7 @@ export const createLayerGroups = (
const layerGroup = filteredTournaments.map((tournament) => { const layerGroup = filteredTournaments.map((tournament) => {
return ( return (
<CompetitionMarker <TournamentMarker
key={tournament._id} key={tournament._id}
tournament={tournament} tournament={tournament}
colour={colour} colour={colour}