mirror of
https://github.com/TheRealOwenRees/echecsfrance.git
synced 2026-07-23 04:26:57 +00:00
themes and dimensions
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
need a 'return to top' arrow button on smaller screens
|
||||
|
||||
muti-language i18n support
|
||||
muti-language i18n support- https://nextjs.org/docs/app/building-your-application/routing/internationalization
|
||||
|
||||
light/dark theme
|
||||
light/dark theme in all components
|
||||
|
||||
tests for tournois, testing the loading of map and table, then counting the markers
|
||||
|
||||
logo for navbar and favicon
|
||||
|
||||
hover on table needs fixing - this only seemed to happen once I moved the logic into its own hook
|
||||
hover on table needs fixing - this only seemed to happen once I moved the logic into its own hook <- error is occuring on all hovers at the moment. Client/SSR issue?
|
||||
|
||||
document my new hook
|
||||
|
||||
|
||||
@@ -1,14 +1,73 @@
|
||||
import Layout from "@/components/Layout";
|
||||
|
||||
// TODO fix page sizing
|
||||
export default function Contact() {
|
||||
return (
|
||||
<Layout>
|
||||
<header className="grid h-[calc(100%-216px)] md:h-[calc(100%-172px)] place-items-center">
|
||||
<div className="relative h-full w-full bg-amber-200"></div>
|
||||
<div className="absolute">
|
||||
<h1>Contactez-Nous</h1>
|
||||
<section className="grid place-items-center bg-white dark:bg-gray-800">
|
||||
<div className="pt-8 pb-32 lg:pt-16 px-4 mx-auto max-w-screen-md">
|
||||
<h2 className="mb-4 text-4xl tracking-tight font-extrabold text-center text-gray-900 dark:text-white">
|
||||
Contactez-Nous
|
||||
</h2>
|
||||
<p className="mb-8 lg:mb-16 font-light text-center text-gray-500 dark:text-gray-400 sm:text-xl">
|
||||
Vous souhaitez ajouter les tournois de votre fédération sur ce site?
|
||||
Vous avez un problème technique? Vous aimeriez participer à ce
|
||||
projet? Contactez-nous.
|
||||
</p>
|
||||
<form action="#" className="space-y-8">
|
||||
<div>
|
||||
<label
|
||||
htmlFor="email"
|
||||
className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"
|
||||
>
|
||||
Adresse e-mail
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
className="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500 dark:shadow-sm-light"
|
||||
placeholder="nom@exemple.com"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="subject"
|
||||
className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"
|
||||
>
|
||||
Sujet
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="subject"
|
||||
className="block p-3 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 shadow-sm focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500 dark:shadow-sm-light"
|
||||
placeholder="Le motif de ma demande"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="sm:col-span-2">
|
||||
<label
|
||||
htmlFor="message"
|
||||
className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"
|
||||
>
|
||||
Votre message
|
||||
</label>
|
||||
<textarea
|
||||
id="message"
|
||||
rows={6}
|
||||
className="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg shadow-sm border border-gray-300 focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
||||
placeholder="Détaillez ici votre demande..."
|
||||
></textarea>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
className="py-3 px-5 text-sm font-medium text-center text-white rounded-lg bg-teal-600 sm:w-fit hover:bg-primary-800 focus:ring-4 focus:outline-none focus:ring-primary-300 dark:hover:bg-primary-700 dark:focus:ring-primary-800 dark:text-white"
|
||||
>
|
||||
Send message
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</header>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import Layout from "@/components/Layout";
|
||||
export default function Home() {
|
||||
return (
|
||||
<Layout>
|
||||
<header className="grid h-[calc(100%-216px)] md:h-[calc(100%-172px)] place-items-center">
|
||||
<header className="grid h-[calc(100%-153px)] md:h-[calc(100%-173px)] place-items-center">
|
||||
<div className="relative h-full w-full bg-[url('/images/map-bg.jpg')] bg-cover bg-center brightness-[0.2]"></div>
|
||||
<div className="absolute text-center">
|
||||
<h1 className="text-5xl p-5">Echecs France</h1>
|
||||
|
||||
@@ -3,10 +3,15 @@ import Layout from "@/components/Layout";
|
||||
export default function About() {
|
||||
return (
|
||||
<Layout>
|
||||
<header className="grid h-[calc(100%-216px)] md:h-[calc(100%-172px)] place-items-center">
|
||||
<div className="relative h-full w-full bg-amber-200"></div>
|
||||
<header className="grid h-[calc(100%-216px)] md:h-[calc(100%-174px)] place-items-center">
|
||||
<div className="relative h-full w-full bg-white dark:bg-gray-800"></div>
|
||||
<div className="absolute">
|
||||
<h1>Qui Sommes-Nous</h1>
|
||||
<h2 className="mb-4 text-4xl tracking-tight font-extrabold text-center text-gray-900 dark:text-white">
|
||||
Qui Sommes-Nous?
|
||||
</h2>
|
||||
<p className="mb-8 lg:mb-16 font-light text-center text-gray-500 dark:text-gray-400 sm:text-xl">
|
||||
Prochainement
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
</Layout>
|
||||
|
||||
@@ -13,7 +13,7 @@ import getTournaments from "@/utils/getTournamentData";
|
||||
const TournamentMap = dynamic(() => import("@/components/TournamentMap"), {
|
||||
ssr: false,
|
||||
loading: () => (
|
||||
<div className="h-screen grid text-black place-items-center">
|
||||
<div className="h-screen grid place-items-center text-gray-900 bg-white dark:bg-gray-800 dark:text-white">
|
||||
<p>Loading map...</p>
|
||||
</div>
|
||||
),
|
||||
@@ -28,7 +28,7 @@ export default async function Tournaments() {
|
||||
<div className="">
|
||||
<TournamentMap tournamentData={tournamentData} />
|
||||
</div>
|
||||
<div className="bg-gray-800 lg:overflow-y-auto">
|
||||
<div className="bg-white dark:bg-gray-800 lg:overflow-y-auto">
|
||||
<TournamentTable tournamentData={tournamentData} />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
import Link from "next/link";
|
||||
import { FaGithub } from "react-icons/fa";
|
||||
import { FaGithub, FaRegEnvelope } from "react-icons/fa";
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className="grid justify-items-center bg-gray-800 text-white py-2 px-5">
|
||||
<footer className="grid w-full fixed bottom-0 justify-items-center py-2 px-5 text-white bg-teal-600 text-gray-900 dark:bg-gray-700">
|
||||
<div className="p-2">
|
||||
<p>© {new Date().getFullYear()} - Owen Rees</p>
|
||||
</div>
|
||||
<div className="p-2">
|
||||
<div className="flex p-2 space-x-4">
|
||||
<Link
|
||||
href="https://github.com/TheRealOwenRees/echecsfrance"
|
||||
target="_blank"
|
||||
>
|
||||
<FaGithub />
|
||||
</Link>
|
||||
<Link href="/contactez-nous">
|
||||
<FaRegEnvelope />
|
||||
</Link>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
"use client";
|
||||
|
||||
import HamburgerMenu from "@/components/HamburgerMenu";
|
||||
import { useState } from "react";
|
||||
|
||||
// TODO make hamburger menu slide in from the right instead of conditional rendering
|
||||
const Hamburger = () => {
|
||||
const [menuVisible, setMenuVisible] = useState(false);
|
||||
return (
|
||||
<>
|
||||
{" "}
|
||||
<div className="space-y-2" onClick={() => setMenuVisible(!menuVisible)}>
|
||||
<div className="w-8 h-0.5 bg-gray-600 dark:bg-white"></div>
|
||||
<div className="w-8 h-0.5 bg-gray-600 dark:bg-white"></div>
|
||||
<div className="w-8 h-0.5 bg-gray-600 dark:bg-white"></div>
|
||||
</div>
|
||||
{menuVisible && <HamburgerMenu />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Hamburger;
|
||||
@@ -0,0 +1,25 @@
|
||||
import Link from "next/link";
|
||||
import ThemeSwitcher from "@/components/ThemeSwitcher";
|
||||
|
||||
const HamburgerMenu = () => {
|
||||
return (
|
||||
<div className="hamburgerMenu absolute top-16 right-0 z-[9999] bg-teal-600 flex md:hidden dark:bg-gray-600">
|
||||
<ul className="list-reset text-white p-5">
|
||||
<li className="py-5">
|
||||
<Link href="/tournois">Tournois</Link>
|
||||
</li>
|
||||
<li className="py-5">
|
||||
<Link href="/qui-sommes-nous">Qui Sommes-Nous</Link>
|
||||
</li>
|
||||
<li className="py-5">
|
||||
<Link href="/contactez-nous">Contactez-Nous</Link>
|
||||
</li>
|
||||
<li className="py-5">
|
||||
<ThemeSwitcher />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HamburgerMenu;
|
||||
@@ -7,7 +7,7 @@ export default function Layout({
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<div className="h-screen min-h-[400px] bg-white font-sans leading-normal tracking-normal">
|
||||
<div className="h-screen min-h-[600px] bg-white dark:bg-gray-800 font-sans leading-normal tracking-normal">
|
||||
<Navbar />
|
||||
{children}
|
||||
<Footer />
|
||||
|
||||
+17
-8
@@ -1,19 +1,25 @@
|
||||
import Link from "next/link";
|
||||
import ThemeSwitcher from "@/components/ThemeSwitcher";
|
||||
import Hamburger from "@/components/Hamburger";
|
||||
|
||||
export default function Navbar() {
|
||||
return (
|
||||
<nav className="bg-gray-800 pt-5 mt-0 w-full md:pt-2 px-5">
|
||||
<div className="container mx-auto flex flex-wrap items-center">
|
||||
<div className="flex w-full md:w-1/2 justify-center md:justify-start text-white font-extrabold">
|
||||
<nav className="w-full relative border-b-[1px] pt-5 mt-0 px-5 md:pt-2 bg-white dark:bg-gray-800 dark:border-gray-700">
|
||||
<div className="container mx-auto flex items-center">
|
||||
<div className="pb-3 justify-center flex w-full md:w-1/2 md:pb-0 md:justify-start font-extrabold">
|
||||
<Link
|
||||
className="text-white no-underline hover:text-white hover:no-underline"
|
||||
className="text-gray-900 dark:text-white no-underline hover:no-underline"
|
||||
href="/"
|
||||
>
|
||||
<span className="text-2xl pl-2">Echecs France</span>
|
||||
<span className="text-2xl">Echecs France</span>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex w-full pt-2 justify-center md:w-1/2 md:justify-end">
|
||||
<ul className="list-reset text-white no-underline flex flex-1 justify-around md:flex-none items-center">
|
||||
<div className="pb-2 md:hidden">
|
||||
<Hamburger />
|
||||
</div>
|
||||
|
||||
<div className="hidden pt-2 justify-center md:flex md:w-1/2 md:justify-end">
|
||||
<ul className="list-reset text-gray-900 dark:text-white no-underline flex flex-1 justify-around md:flex-none items-center">
|
||||
<li className="mr-10">
|
||||
<Link
|
||||
className="inline-block border-b-4 py-5 border-transparent hover:border-teal-600 transition-all ease-in-out duration-300"
|
||||
@@ -30,7 +36,7 @@ export default function Navbar() {
|
||||
Qui Sommes-Nous
|
||||
</Link>
|
||||
</li>
|
||||
<li className="">
|
||||
<li className="mr-10">
|
||||
<Link
|
||||
className="inline-block border-b-4 py-5 border-transparent hover:border-teal-600 transition-all ease-in-out duration-300"
|
||||
href="/contactez-nous"
|
||||
@@ -38,6 +44,9 @@ export default function Navbar() {
|
||||
Contactez-Nous
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<ThemeSwitcher />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@ const SearchBar = ({
|
||||
}: SearchBarProps) => {
|
||||
return (
|
||||
<>
|
||||
<div className="p-3 bg-gray-800">
|
||||
<div className="p-3 bg-white dark:bg-gray-800">
|
||||
<label htmlFor="table-search" className="sr-only">
|
||||
Search
|
||||
</label>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import { MdOutlineDarkMode, MdLightbulbOutline } from "react-icons/md";
|
||||
import useDarkMode from "@/hooks/useDarkMode";
|
||||
|
||||
// TODO write tests for light/mode
|
||||
// TODO new SVG for light/dark theme
|
||||
// TODO fix TS error on setTheme
|
||||
const ThemeSwitcher = () => {
|
||||
const [colorTheme, setTheme] = useDarkMode();
|
||||
|
||||
return (
|
||||
<>
|
||||
{colorTheme === "light" ? (
|
||||
<MdOutlineDarkMode onClick={() => setTheme("light")} />
|
||||
) : (
|
||||
<MdLightbulbOutline onClick={() => setTheme("dark")} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemeSwitcher;
|
||||
@@ -24,7 +24,7 @@ export default function TournamentMap({ tournamentData }: TournamentDataProps) {
|
||||
return (
|
||||
<section
|
||||
id="tournament-map"
|
||||
className="grid h-[calc(100vh-128px)] md:h-[calc(100vh-82px)] lg:h-[calc(100vh-172px)]"
|
||||
className="grid h-[calc(100vh-153px)] md:h-[calc(100vh-82px)] lg:h-[calc(100vh-174px)]"
|
||||
>
|
||||
<MapContainer
|
||||
center={center}
|
||||
|
||||
@@ -18,16 +18,16 @@ export default function TournamentTable({
|
||||
|
||||
console.log(filteredTournamentData.length);
|
||||
|
||||
const stickyHeader = "sticky top-0 p-3 bg-gray-600";
|
||||
const stickyHeader = "sticky top-0 p-3 bg-teal-600 dark:bg-gray-600";
|
||||
|
||||
return (
|
||||
<section className="w-full grid auto-rows-max lg:h-[calc(100vh-172px)] lg:col-start-2 lg:col-end-3">
|
||||
<section className="w-full grid auto-rows-max pb-20 lg:h-[calc(100vh-174px)] lg:col-start-2 lg:col-end-3">
|
||||
<SearchBar
|
||||
tournamentFilter={tournamentFilter}
|
||||
setTournamentFilter={setTournamentFilter}
|
||||
/>
|
||||
<table className="relative table-fixed w-full text-center text-xs">
|
||||
<thead className="bg-gray-600 text-white">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className={stickyHeader}>Date</th>
|
||||
<th className={stickyHeader}>Ville</th>
|
||||
|
||||
@@ -31,7 +31,7 @@ describe("Verify component mount", () => {
|
||||
});
|
||||
|
||||
it("correct h1 tags with page title included", () => {
|
||||
cy.get("h1").contains("qui sommes-nous", { matchCase: false });
|
||||
cy.get("h2").contains("qui sommes-nous", { matchCase: false });
|
||||
});
|
||||
|
||||
navbarFooterCheck();
|
||||
@@ -43,7 +43,7 @@ describe("Verify component mount", () => {
|
||||
});
|
||||
|
||||
it("correct h1 tags with page title included", () => {
|
||||
cy.get("h1").contains("contactez-nous", { matchCase: false });
|
||||
cy.get("h2").contains("contactez-nous", { matchCase: false });
|
||||
});
|
||||
|
||||
navbarFooterCheck();
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function useDarkMode() {
|
||||
const [theme, setTheme] = useState(
|
||||
typeof window !== "undefined" ? localStorage.theme : "dark"
|
||||
);
|
||||
const colorTheme = theme === "dark" ? "light" : "dark";
|
||||
|
||||
useEffect(() => {
|
||||
const root = window.document.documentElement;
|
||||
|
||||
root.classList.remove(colorTheme);
|
||||
root.classList.add(theme);
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.setItem("theme", theme);
|
||||
}
|
||||
}, [theme]);
|
||||
|
||||
return [colorTheme, setTheme];
|
||||
}
|
||||
|
||||
export default useDarkMode;
|
||||
@@ -25,7 +25,7 @@ const useTournamentDataFilter = (
|
||||
} else {
|
||||
state = filtered.map((t) => (
|
||||
<tr
|
||||
className="border-b border-gray-700 border-opacity-20 bg-gray-800 text-white transition duration-300 ease-in-out hover:bg-gray-400 hover:text-black"
|
||||
className="text-gray-900 bg-white dark:bg-gray-800 dark:text-white hover:bg-gray-400 hover:text-black"
|
||||
key={t._id}
|
||||
>
|
||||
<td className="p-3">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: "class",
|
||||
content: [
|
||||
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./components/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
|
||||
Reference in New Issue
Block a user