mirror of
https://github.com/TheRealOwenRees/echecsfrance.git
synced 2026-07-22 20:16:57 +00:00
import grouping and sorting with Prettier plugin
This commit is contained in:
+5
-1
@@ -1,5 +1,9 @@
|
||||
{
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true,
|
||||
"plugins": ["prettier-plugin-tailwindcss"]
|
||||
"plugins": ["@trivago/prettier-plugin-sort-imports", "prettier-plugin-tailwindcss"],
|
||||
"importOrder": ["^react$", "^@?\\w", "^@\\\\", "<THIRD_PARTY_MODULES>", "^\\.\\.", "^\\."],
|
||||
"importOrderSeparation": true,
|
||||
"importOrderSortSpecifiers": true,
|
||||
"tailwindFunctions": ["twMerge"]
|
||||
}
|
||||
|
||||
Vendored
+3
@@ -23,9 +23,12 @@
|
||||
"spiderfied",
|
||||
"Spiderfy",
|
||||
"spiderified",
|
||||
"superjson",
|
||||
"tailwindcss",
|
||||
"timothyarmes",
|
||||
"tournois",
|
||||
"trivago",
|
||||
"TRPC",
|
||||
"unspiderfied",
|
||||
"unspiderfy"
|
||||
],
|
||||
|
||||
@@ -23,6 +23,18 @@ and is deployed on [Vercel](https://vercel.com/)
|
||||
- [Leaflet](https://leafletjs.com/) - a Javascript library for interactive maps
|
||||
- [Nodemailer](https://nodemailer.com/) - a module for Node.js applications to allow easy as cake email sending
|
||||
|
||||
## Required VSCode plugins
|
||||
|
||||
- ESLint
|
||||
- Prettier - Code formatter
|
||||
|
||||
## Recommended VSCode plugins
|
||||
|
||||
- Tailwind CSS IntelliSense
|
||||
- Tailwind Docs
|
||||
- Code Spell Checker (to avoid English spelling mistakes in the code)
|
||||
- Console Ninja (for easier debugging)
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are encouraged. Please open an issue to discuss your ideas.
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import { MapProps } from "@/types";
|
||||
import { useMemo, useRef, ChangeEvent } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useSetAtom } from "jotai";
|
||||
import { mapBoundsAtom } from "@/app/atoms";
|
||||
import { ChangeEvent, useMemo, useRef } from "react";
|
||||
|
||||
import { useSetAtom } from "jotai";
|
||||
import L from "leaflet";
|
||||
import { MapContainer, TileLayer, Marker } from "react-leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css";
|
||||
import "leaflet-defaulticon-compatibility";
|
||||
import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { MapContainer, Marker, TileLayer } from "react-leaflet";
|
||||
|
||||
import MapEvents from "@/app/[lang]/components/MapEvents";
|
||||
import { mapBoundsAtom } from "@/app/atoms";
|
||||
import { MapProps } from "@/types";
|
||||
|
||||
const Map = ({ position, setPosition, center }: MapProps) => {
|
||||
const t = useTranslations("Map");
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
"use client";
|
||||
|
||||
import dynamic from "next/dynamic";
|
||||
import { useState } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
import { useAtomValue } from "jotai";
|
||||
import { franceCenterAtom } from "@/app/atoms";
|
||||
import useTournamentForm from "@/hooks/useTournamentForm";
|
||||
import { useTranslations } from "next-intl";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
import InfoMessage from "@/app/[lang]/components/InfoMessage";
|
||||
import {
|
||||
handleTournamentSubmit,
|
||||
handleClearTournamentForm,
|
||||
} from "@/handlers/formHandlers";
|
||||
import LoadingMap from "@/app/[lang]/components/LoadingMap";
|
||||
import { franceCenterAtom } from "@/app/atoms";
|
||||
import {
|
||||
handleClearTournamentForm,
|
||||
handleTournamentSubmit,
|
||||
} from "@/handlers/formHandlers";
|
||||
import useTournamentForm from "@/hooks/useTournamentForm";
|
||||
|
||||
const Map = dynamic(() => import("./Map"), {
|
||||
ssr: false,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useTranslations } from "next-intl";
|
||||
import Link from "next-intl/link";
|
||||
import { FaGithub, FaRegEnvelope } from "react-icons/fa";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
import ThemeSwitcher from "@/app/[lang]/components/ThemeSwitcher";
|
||||
|
||||
export default function Footer() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useRef, useState } from "react";
|
||||
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import HamburgerMenu from "./HamburgerMenu";
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { Dispatch, RefObject, SetStateAction, useRef, useState } from "react";
|
||||
|
||||
import { useTranslations } from "next-intl";
|
||||
import Link from "next-intl/link";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import useHamburgerClose from "@/hooks/useHamburgerClose";
|
||||
|
||||
interface HamburgerMenuState {
|
||||
menuVisible: boolean;
|
||||
setMenuVisible: Dispatch<SetStateAction<boolean>>;
|
||||
hamburgerButtonRef: RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
import { Dispatch, RefObject, SetStateAction, useRef, useState } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import Link from "next-intl/link";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
import useHamburgerClose from "@/hooks/useHamburgerClose";
|
||||
|
||||
const HamburgerMenu = ({
|
||||
menuVisible,
|
||||
setMenuVisible,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ResponseMessage } from "@/types";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
|
||||
import { ResponseMessage } from "@/types";
|
||||
|
||||
const InfoMessage = ({
|
||||
responseMessage,
|
||||
}: {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { useSetAtom } from "jotai";
|
||||
import { mapBoundsAtom } from "@/app/atoms";
|
||||
import L from "leaflet";
|
||||
import { useMapEvent } from "react-leaflet";
|
||||
|
||||
import { mapBoundsAtom } from "@/app/atoms";
|
||||
|
||||
const MapEvents = () => {
|
||||
const setMapBounds = useSetAtom(mapBoundsAtom);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Link from "next-intl/link";
|
||||
import { useTranslations } from "next-intl";
|
||||
import Link from "next-intl/link";
|
||||
|
||||
import Hamburger from "./Hamburger";
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { NextIntlClientProvider, AbstractIntlMessages } from "next-intl";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
import { AbstractIntlMessages, NextIntlClientProvider } from "next-intl";
|
||||
|
||||
import "@/css/globals.css";
|
||||
|
||||
import Navbar from "./Navbar";
|
||||
import Footer from "./Footer";
|
||||
import Navbar from "./Navbar";
|
||||
|
||||
const TestableLayout = ({
|
||||
children,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import useDarkMode from "@/hooks/useDarkMode";
|
||||
|
||||
const ThemeSwitcher = () => {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
import useContactForm from "@/hooks/useContactForm";
|
||||
import { handleEmailSubmit } from "@/handlers/formHandlers";
|
||||
|
||||
import InfoMessage from "@/app/[lang]/components/InfoMessage";
|
||||
import { handleEmailSubmit } from "@/handlers/formHandlers";
|
||||
import useContactForm from "@/hooks/useContactForm";
|
||||
|
||||
const ContactForm = () => {
|
||||
const t = useTranslations("Contact");
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import Script from "next/script";
|
||||
import { Inter, Julius_Sans_One } from "next/font/google";
|
||||
import { useLocale, NextIntlClientProvider } from "next-intl";
|
||||
import { getTranslator } from "next-intl/server";
|
||||
import { notFound } from "next/navigation";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
import { NextIntlClientProvider, useLocale } from "next-intl";
|
||||
import { getTranslator } from "next-intl/server";
|
||||
import { Inter, Julius_Sans_One } from "next/font/google";
|
||||
import { notFound } from "next/navigation";
|
||||
import Script from "next/script";
|
||||
|
||||
import "@/css/globals.css";
|
||||
|
||||
import Providers from "./providers";
|
||||
import Navbar from "./components/Navbar";
|
||||
import Footer from "./components/Footer";
|
||||
import Navbar from "./components/Navbar";
|
||||
import Providers from "./providers";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });
|
||||
const title = Julius_Sans_One({
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { useTranslations } from "next-intl";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
import bgImage from "@/public/images/map-bg.jpg";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Link from "next-intl/link";
|
||||
import { useTranslations } from "next-intl";
|
||||
import Link from "next-intl/link";
|
||||
|
||||
export default function About() {
|
||||
const t = useTranslations("About");
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { useMap } from "react-leaflet";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import L from "leaflet";
|
||||
import { useAtomValue } from "jotai";
|
||||
|
||||
import { TimeControl } from "@/types";
|
||||
import { useAtomValue } from "jotai";
|
||||
import L from "leaflet";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useMap } from "react-leaflet";
|
||||
|
||||
import { filteredTournamentsByTimeControlAtom } from "@/app/atoms";
|
||||
import { TimeControlColours } from "@/app/constants";
|
||||
import { TimeControl } from "@/types";
|
||||
|
||||
const Legend = () => {
|
||||
const t = useTranslations("Tournaments");
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { ScrollableElement } from "@/types";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import { FaArrowUp } from "react-icons/fa";
|
||||
|
||||
import { handleScrollToTop } from "@/handlers/scrollHandlers";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useBreakpoint } from "@/hooks/tailwind";
|
||||
import { ScrollableElement } from "@/types";
|
||||
|
||||
const ScrollToTopButton = () => {
|
||||
const scrollToTopElementRef = useRef<ScrollableElement | null>(null);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useAtom } from "jotai/index";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { IoCloseOutline } from "react-icons/io5";
|
||||
|
||||
import { searchStringAtom } from "@/app/atoms";
|
||||
|
||||
const SearchBar = () => {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useAtom, useAtomValue } from "jotai";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
import {
|
||||
classicAtom,
|
||||
rapidAtom,
|
||||
blitzAtom,
|
||||
classicAtom,
|
||||
otherAtom,
|
||||
rapidAtom,
|
||||
tournamentsAtom,
|
||||
} from "@/app/atoms";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { TimeControl } from "@/types";
|
||||
|
||||
const TimeControlFilters = () => {
|
||||
|
||||
@@ -1,34 +1,32 @@
|
||||
"use client";
|
||||
|
||||
import { TimeControl } from "@/types";
|
||||
import { useCallback, useEffect, useMemo, useRef } from "react";
|
||||
|
||||
import { useMemo, useRef, useCallback, useEffect } from "react";
|
||||
import L, { LatLngLiteral, Marker, DomUtil } from "leaflet";
|
||||
import { MapContainer, TileLayer, LayerGroup } from "react-leaflet";
|
||||
import MarkerClusterGroup from "react-leaflet-cluster";
|
||||
import { FaAngleDoubleDown } from "react-icons/fa";
|
||||
import { useAtomValue, useSetAtom } from "jotai";
|
||||
import L, { DomUtil, LatLngLiteral, Marker } from "leaflet";
|
||||
import "leaflet-defaulticon-compatibility";
|
||||
import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css";
|
||||
import "leaflet.smooth_marker_bouncing";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import { countBy, groupBy } from "lodash";
|
||||
|
||||
import {
|
||||
mapBoundsAtom,
|
||||
debouncedHoveredListTournamentIdAtom,
|
||||
filteredTournamentsByTimeControlAtom,
|
||||
normsOnlyAtom,
|
||||
} from "@/app/atoms";
|
||||
import { generatePieSVG } from "@/lib/pie";
|
||||
import { TimeControlColours } from "@/app/constants";
|
||||
|
||||
import Legend from "./Legend";
|
||||
import { TournamentMarker, TournamentMarkerRef } from "./TournamentMarker";
|
||||
import TimeControlFilters from "./TimeControlFilters";
|
||||
import { FaAngleDoubleDown } from "react-icons/fa";
|
||||
import { LayerGroup, MapContainer, TileLayer } from "react-leaflet";
|
||||
import MarkerClusterGroup from "react-leaflet-cluster";
|
||||
|
||||
import MapEvents from "@/app/[lang]/components/MapEvents";
|
||||
import {
|
||||
debouncedHoveredListTournamentIdAtom,
|
||||
filteredTournamentsByTimeControlAtom,
|
||||
mapBoundsAtom,
|
||||
normsOnlyAtom,
|
||||
} from "@/app/atoms";
|
||||
import { TimeControlColours } from "@/app/constants";
|
||||
import { generatePieSVG } from "@/lib/pie";
|
||||
import { TimeControl } from "@/types";
|
||||
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css";
|
||||
import "leaflet-defaulticon-compatibility";
|
||||
import "leaflet.smooth_marker_bouncing";
|
||||
import Legend from "./Legend";
|
||||
import TimeControlFilters from "./TimeControlFilters";
|
||||
import { TournamentMarker, TournamentMarkerRef } from "./TournamentMarker";
|
||||
|
||||
// Declare a class type that adds in methods etc. defined by leaflet.smooth_marker_bouncing
|
||||
// to keep Typescript happy
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import { forwardRef, useMemo, useImperativeHandle, useRef } from "react";
|
||||
import { Tournament } from "@/types";
|
||||
import L from "leaflet";
|
||||
import { Marker, Popup, MarkerProps } from "react-leaflet";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useSetAtom } from "jotai";
|
||||
import { FaTrophy } from "react-icons/fa";
|
||||
import { last } from "lodash";
|
||||
import { forwardRef, useImperativeHandle, useMemo, useRef } from "react";
|
||||
|
||||
import { useSetAtom } from "jotai";
|
||||
import L from "leaflet";
|
||||
import { last } from "lodash";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { FaTrophy } from "react-icons/fa";
|
||||
import { Marker, MarkerProps, Popup } from "react-leaflet";
|
||||
|
||||
import type { BouncingMarker } from "@/leafletTypes";
|
||||
import { debouncedHoveredMapTournamentGroupIdAtom } from "@/app/atoms";
|
||||
import { TimeControlColours } from "@/app/constants";
|
||||
import type { BouncingMarker } from "@/leafletTypes";
|
||||
import { Tournament } from "@/types";
|
||||
|
||||
export type TournamentMarkerRef = {
|
||||
getMarker: () => L.Marker<any>;
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useAtomValue, useSetAtom, useAtom } from "jotai";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { FaExternalLinkAlt } from "react-icons/fa";
|
||||
import { FaTrophy } from "react-icons/fa";
|
||||
import { Tooltip } from "react-tooltip";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import {
|
||||
filteredTournamentsListAtom,
|
||||
syncVisibleAtom,
|
||||
normsOnlyAtom,
|
||||
hoveredMapTournamentGroupIdAtom,
|
||||
debouncedHoveredMapTournamentGroupIdAtom,
|
||||
debouncedHoveredListTournamentIdAtom,
|
||||
debouncedHoveredMapTournamentGroupIdAtom,
|
||||
filteredTournamentsListAtom,
|
||||
hoveredMapTournamentGroupIdAtom,
|
||||
normsOnlyAtom,
|
||||
syncVisibleAtom,
|
||||
} from "@/app/atoms";
|
||||
import { useBreakpoint } from "@/hooks/tailwind";
|
||||
|
||||
import ScrollToTopButton from "./ScrollToTopButton";
|
||||
import SearchBar from "./SearchBar";
|
||||
import TimeControlFilters from "./TimeControlFilters";
|
||||
import ScrollToTopButton from "./ScrollToTopButton";
|
||||
|
||||
export default function TournamentTable() {
|
||||
const t = useTranslations("Tournaments");
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import { useHydrateAtoms } from "jotai/utils";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
import LoadingMap from "@/app/[lang]/components/LoadingMap";
|
||||
import { tournamentsAtom } from "@/app/atoms";
|
||||
import { Tournament } from "@/types";
|
||||
|
||||
import TournamentTable from "./TournamentTable";
|
||||
|
||||
type TournamentsDisplayProps = {
|
||||
tournaments: Tournament[];
|
||||
};
|
||||
|
||||
import { Tournament } from "@/types";
|
||||
|
||||
import dynamic from "next/dynamic";
|
||||
import { useHydrateAtoms } from "jotai/utils";
|
||||
import { tournamentsAtom } from "@/app/atoms";
|
||||
|
||||
import TournamentTable from "./TournamentTable";
|
||||
import LoadingMap from "@/app/[lang]/components/LoadingMap";
|
||||
|
||||
/**
|
||||
* Imports the tournament map component, ensuring CSR only.
|
||||
* @remarks SSR is not supported by react-leaflet
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import clientPromise from "@/lib/mongodb";
|
||||
|
||||
import { errorLog } from "@/utils/logger";
|
||||
import { Tournament, TimeControl } from "@/types";
|
||||
import { differenceInDays, isSameDay, parse } from "date-fns";
|
||||
import { groupBy } from "lodash";
|
||||
import { parse, differenceInDays, isSameDay } from "date-fns";
|
||||
import { ObjectId } from "mongodb";
|
||||
|
||||
import clientPromise from "@/lib/mongodb";
|
||||
import { TimeControl, Tournament } from "@/types";
|
||||
import { errorLog } from "@/utils/logger";
|
||||
|
||||
import TournamentsDisplay from "./TournamentsDisplay";
|
||||
import { ObjectId } from "mongodb";
|
||||
|
||||
export const revalidate = 3600; // Revalidate cache every 6 hours
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import clientPromise from "@/lib/mongodb";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import clientPromise from "@/lib/mongodb";
|
||||
import { errorLog } from "@/utils/logger";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import NodeMailer from "nodemailer";
|
||||
import { NextResponse } from "next/server";
|
||||
import { infoLog, errorLog } from "@/utils/logger";
|
||||
import NodeMailer from "nodemailer";
|
||||
|
||||
import { errorLog, infoLog } from "@/utils/logger";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const { email, subject, message } = await req.json();
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { TimeControl, Tournament } from "@/types";
|
||||
import { atom } from "jotai";
|
||||
import { LatLngBounds, LatLngLiteral } from "leaflet";
|
||||
|
||||
import { TimeControl, Tournament } from "@/types";
|
||||
import atomWithDebounce from "@/utils/atomWithDebounce";
|
||||
import { normalizedContains } from "@/utils/string";
|
||||
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import { TimeControl } from "@/types"
|
||||
import { TimeControl } from "@/types";
|
||||
|
||||
export const TimeControlColours = {
|
||||
[TimeControl.Classic]: "#00ac39",
|
||||
[TimeControl.Rapid]: "#0086c7",
|
||||
[TimeControl.Blitz]: "#ddce20",
|
||||
[TimeControl.Other]: "#ea5f17",
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { ResponseMessage, TournamentFormProps } from "@/types";
|
||||
import { LatLngLiteral } from "leaflet";
|
||||
import { Dispatch, FormEvent, SetStateAction } from "react";
|
||||
|
||||
import { LatLngLiteral } from "leaflet";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
import { clearMessage } from "@/app/[lang]/components/InfoMessage";
|
||||
import { errorLog } from "@/utils/logger";
|
||||
import discordWebhook from "@/lib/discordWebhook";
|
||||
import sendMail from "@/lib/sendMail";
|
||||
import tournamentFormToDB from "@/lib/tournamentFormToDB";
|
||||
import discordWebhook from "@/lib/discordWebhook";
|
||||
import { ResponseMessage, TournamentFormProps } from "@/types";
|
||||
import { errorLog } from "@/utils/logger";
|
||||
|
||||
export const handleClearTournamentForm = (
|
||||
formRefs: TournamentFormProps,
|
||||
|
||||
+24
-7
@@ -1,11 +1,15 @@
|
||||
import { useLayoutEffect, useEffect, useState, useRef, useMemo } from "react";
|
||||
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
import resolveConfig from "tailwindcss/resolveConfig";
|
||||
|
||||
import tailwindConfig from "@/tailwind.config.js";
|
||||
|
||||
const config = resolveConfig(tailwindConfig);
|
||||
|
||||
const isSSR =
|
||||
typeof window === "undefined" || !window.navigator || /ServerSideRendering|^Deno\//.test(window.navigator.userAgent);
|
||||
typeof window === "undefined" ||
|
||||
!window.navigator ||
|
||||
/ServerSideRendering|^Deno\//.test(window.navigator.userAgent);
|
||||
|
||||
const isBrowser = !isSSR;
|
||||
const useIsomorphicEffect = isBrowser ? useLayoutEffect : useEffect;
|
||||
@@ -18,7 +22,9 @@ export type CreatorReturnType = {
|
||||
|
||||
function create(screens: object | undefined) {
|
||||
if (!screens) {
|
||||
throw new Error("Failed to create breakpoint hooks, given `screens` value is invalid.");
|
||||
throw new Error(
|
||||
"Failed to create breakpoint hooks, given `screens` value is invalid.",
|
||||
);
|
||||
}
|
||||
|
||||
function useBreakpoint(breakpoint: string, defaultValue: boolean = false) {
|
||||
@@ -46,15 +52,25 @@ function create(screens: object | undefined) {
|
||||
return match;
|
||||
}
|
||||
|
||||
function useBreakpointEffect<Breakpoint extends string>(breakpoint: Breakpoint, effect: (match: boolean) => void) {
|
||||
function useBreakpointEffect<Breakpoint extends string>(
|
||||
breakpoint: Breakpoint,
|
||||
effect: (match: boolean) => void,
|
||||
) {
|
||||
const match = useBreakpoint(breakpoint);
|
||||
useEffect(() => effect(match));
|
||||
return null;
|
||||
}
|
||||
|
||||
function useBreakpointValue<Breakpoint extends string, T, U>(breakpoint: Breakpoint, valid: T, invalid: U) {
|
||||
function useBreakpointValue<Breakpoint extends string, T, U>(
|
||||
breakpoint: Breakpoint,
|
||||
valid: T,
|
||||
invalid: U,
|
||||
) {
|
||||
const match = useBreakpoint(breakpoint);
|
||||
const value = useMemo(() => (match ? valid : invalid), [invalid, match, valid]);
|
||||
const value = useMemo(
|
||||
() => (match ? valid : invalid),
|
||||
[invalid, match, valid],
|
||||
);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -65,4 +81,5 @@ function create(screens: object | undefined) {
|
||||
} as CreatorReturnType;
|
||||
}
|
||||
|
||||
export const { useBreakpoint, useBreakpointEffect, useBreakpointValue } = create(config.theme!.screens);
|
||||
export const { useBreakpoint, useBreakpointEffect, useBreakpointValue } =
|
||||
create(config.theme!.screens);
|
||||
|
||||
@@ -1,31 +1,36 @@
|
||||
export const useDynamicViewportUnits = () => {
|
||||
const setVh = function () {
|
||||
var svh = document.documentElement.clientHeight * 0.01;
|
||||
document.documentElement.style.setProperty('--1svh', (svh + "px"));
|
||||
document.documentElement.style.setProperty("--1svh", svh + "px");
|
||||
var dvh = window.innerHeight * 0.01;
|
||||
document.documentElement.style.setProperty('--1dvh', (dvh + "px"));
|
||||
document.documentElement.style.setProperty("--1dvh", dvh + "px");
|
||||
};
|
||||
|
||||
const isMobile = function() {
|
||||
if(/Android|iPhone|iPad|iPod/i.test(navigator.userAgent) || (navigator.userAgent.match(/Mac/) && navigator.maxTouchPoints && navigator.maxTouchPoints > 2)) {
|
||||
return true;
|
||||
const isMobile = function () {
|
||||
if (
|
||||
/Android|iPhone|iPad|iPod/i.test(navigator.userAgent) ||
|
||||
(navigator.userAgent.match(/Mac/) &&
|
||||
navigator.maxTouchPoints &&
|
||||
navigator.maxTouchPoints > 2)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// SSR support
|
||||
if (typeof window === 'undefined') {
|
||||
if (typeof window === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't run polyfill if browser supports the units natively
|
||||
if ('CSS' in window &&
|
||||
'supports' in window.CSS &&
|
||||
window.CSS.supports('height: 100svh') &&
|
||||
window.CSS.supports('height: 100dvh') &&
|
||||
window.CSS.supports('height: 100lvh')
|
||||
if (
|
||||
"CSS" in window &&
|
||||
"supports" in window.CSS &&
|
||||
window.CSS.supports("height: 100svh") &&
|
||||
window.CSS.supports("height: 100dvh") &&
|
||||
window.CSS.supports("height: 100lvh")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@@ -35,10 +40,10 @@ export const useDynamicViewportUnits = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener('resize', setVh);
|
||||
window.addEventListener("resize", setVh);
|
||||
setVh();
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', setVh);
|
||||
}
|
||||
}
|
||||
window.removeEventListener("resize", setVh);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Dispatch, RefObject, SetStateAction, useEffect } from "react";
|
||||
|
||||
interface HamburgerClose {
|
||||
menuVisible: boolean;
|
||||
setMenuVisible: Dispatch<SetStateAction<boolean>>;
|
||||
@@ -9,8 +11,6 @@ interface HamburgerClose {
|
||||
menuTimeout: () => void;
|
||||
}
|
||||
|
||||
import { Dispatch, RefObject, SetStateAction, useEffect } from "react";
|
||||
|
||||
const useHamburgerClose = ({
|
||||
menuVisible,
|
||||
setMenuVisible,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { TournamentFormProps } from "@/types";
|
||||
import { useRef, useState } from "react";
|
||||
import { LatLngLiteral } from "leaflet";
|
||||
|
||||
import { useAtomValue } from "jotai";
|
||||
import { LatLngLiteral } from "leaflet";
|
||||
|
||||
import { franceCenterAtom } from "@/app/atoms";
|
||||
import { TournamentFormProps } from "@/types";
|
||||
|
||||
export const useTournamentForm = (): TournamentFormProps => {
|
||||
const center = useAtomValue(franceCenterAtom);
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { Marker } from "leaflet";
|
||||
import { Marker } from "leaflet";
|
||||
|
||||
declare class BouncingOptions {
|
||||
bounceHeight: number;
|
||||
|
||||
+28
-12
@@ -3,11 +3,11 @@ function round(n: number) {
|
||||
}
|
||||
|
||||
function polarToCartesian(radius: number, angleInDegrees: number) {
|
||||
var radians = (angleInDegrees - 90) * Math.PI / 180;
|
||||
var radians = ((angleInDegrees - 90) * Math.PI) / 180;
|
||||
|
||||
return {
|
||||
x: round(radius + (radius * Math.cos(radians))),
|
||||
y: round(radius + (radius * Math.sin(radians)))
|
||||
x: round(radius + radius * Math.cos(radians)),
|
||||
y: round(radius + radius * Math.sin(radians)),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -21,8 +21,17 @@ function getDAttribute(radius: number, startAngle: number, endAngle: number) {
|
||||
|
||||
const largeArcFlag = endAngle - startAngle <= 180 ? 0 : 1;
|
||||
const d = [
|
||||
"M", start.x, start.y,
|
||||
"A", radius, radius, 0, largeArcFlag, 1, end.x, end.y
|
||||
"M",
|
||||
start.x,
|
||||
start.y,
|
||||
"A",
|
||||
radius,
|
||||
radius,
|
||||
0,
|
||||
largeArcFlag,
|
||||
1,
|
||||
end.x,
|
||||
end.y,
|
||||
];
|
||||
|
||||
if (isCircle) {
|
||||
@@ -37,32 +46,39 @@ function path(d: string, colour: string) {
|
||||
return `<path d='${d}' style="fill: ${colour}" />`;
|
||||
}
|
||||
|
||||
function svg(className: string, width: number, content: string ) {
|
||||
function svg(className: string, width: number, content: string) {
|
||||
return `<svg class="${className}" viewBox="0 0 ${width} ${width}"><g class='pie'>${content}</g></svg>`;
|
||||
}
|
||||
|
||||
type PieSlice = {
|
||||
value: number;
|
||||
colour: string;
|
||||
}
|
||||
};
|
||||
|
||||
export function generatePieSVG(className: string, radius: number, values: PieSlice[]) {
|
||||
export function generatePieSVG(
|
||||
className: string,
|
||||
radius: number,
|
||||
values: PieSlice[],
|
||||
) {
|
||||
type Sector = {
|
||||
colour: string;
|
||||
degrees: number;
|
||||
from?: number;
|
||||
to?: number;
|
||||
}
|
||||
};
|
||||
|
||||
const total = values.reduce((a, b) => a + b.value, 0);
|
||||
const data: Sector[] = values.map(({ value, colour }) => ({ colour, degrees: value / total * 360 }));
|
||||
const data: Sector[] = values.map(({ value, colour }) => ({
|
||||
colour,
|
||||
degrees: (value / total) * 360,
|
||||
}));
|
||||
|
||||
const paths = data.reduce<[number, string][]>((prev, value, i) => {
|
||||
const from = i === 0 ? 0 : prev[i - 1][0];
|
||||
const to = from + value.degrees;
|
||||
|
||||
return [...prev, [to, path(getDAttribute(radius, from, to ), value.colour)]];
|
||||
return [...prev, [to, path(getDAttribute(radius, from, to), value.colour)]];
|
||||
}, []);
|
||||
|
||||
return svg(className, radius * 2, paths.map(([to, path]) => path) .join(''));
|
||||
return svg(className, radius * 2, paths.map(([to, path]) => path).join(""));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { LatLngLiteral } from "leaflet";
|
||||
|
||||
import { TournamentFormProps } from "@/types";
|
||||
import formatDate from "@/utils/formatDate";
|
||||
|
||||
|
||||
Generated
+312
-26
@@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"@kodingdotninja/use-tailwind-breakpoint": "^0.0.5",
|
||||
"@next/bundle-analyzer": "^13.4.12",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.2.0",
|
||||
"@types/node": "20.5.1",
|
||||
"@types/react": "18.2.21",
|
||||
"@types/react-dom": "18.2.7",
|
||||
@@ -82,34 +83,198 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
|
||||
"integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
|
||||
"dev": true,
|
||||
"version": "7.22.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
|
||||
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
|
||||
"dependencies": {
|
||||
"@babel/highlight": "^7.22.5"
|
||||
"@babel/highlight": "^7.22.13",
|
||||
"chalk": "^2.4.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"node_modules/@babel/code-frame/node_modules/ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame/node_modules/chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame/node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame/node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"node_modules/@babel/code-frame/node_modules/escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame/node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.17.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz",
|
||||
"integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.17.0",
|
||||
"jsesc": "^2.5.1",
|
||||
"source-map": "^0.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-environment-visitor": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
|
||||
"integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
|
||||
"dev": true,
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
|
||||
"integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-function-name": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
|
||||
"integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.22.5",
|
||||
"@babel/types": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-function-name/node_modules/@babel/types": {
|
||||
"version": "7.22.17",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz",
|
||||
"integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.22.5",
|
||||
"@babel/helper-validator-identifier": "^7.22.15",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-hoist-variables": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
|
||||
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-hoist-variables/node_modules/@babel/types": {
|
||||
"version": "7.22.17",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz",
|
||||
"integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.22.5",
|
||||
"@babel/helper-validator-identifier": "^7.22.15",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-split-export-declaration": {
|
||||
"version": "7.22.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
|
||||
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-split-export-declaration/node_modules/@babel/types": {
|
||||
"version": "7.22.17",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz",
|
||||
"integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.22.5",
|
||||
"@babel/helper-validator-identifier": "^7.22.15",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
|
||||
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz",
|
||||
"integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
|
||||
"integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
|
||||
"dev": true,
|
||||
"version": "7.22.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz",
|
||||
"integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.22.5",
|
||||
"chalk": "^2.0.0",
|
||||
"chalk": "^2.4.2",
|
||||
"js-tokens": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -120,7 +285,6 @@
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.0"
|
||||
},
|
||||
@@ -132,7 +296,6 @@
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
@@ -146,7 +309,6 @@
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
@@ -154,14 +316,12 @@
|
||||
"node_modules/@babel/highlight/node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
@@ -170,7 +330,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
@@ -179,7 +338,6 @@
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
@@ -187,6 +345,17 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.22.16",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz",
|
||||
"integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==",
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.22.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz",
|
||||
@@ -198,6 +367,72 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
|
||||
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.22.13",
|
||||
"@babel/parser": "^7.22.15",
|
||||
"@babel/types": "^7.22.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template/node_modules/@babel/types": {
|
||||
"version": "7.22.17",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz",
|
||||
"integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.22.5",
|
||||
"@babel/helper-validator-identifier": "^7.22.15",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.17.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz",
|
||||
"integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.16.7",
|
||||
"@babel/generator": "^7.17.3",
|
||||
"@babel/helper-environment-visitor": "^7.16.7",
|
||||
"@babel/helper-function-name": "^7.16.7",
|
||||
"@babel/helper-hoist-variables": "^7.16.7",
|
||||
"@babel/helper-split-export-declaration": "^7.16.7",
|
||||
"@babel/parser": "^7.17.3",
|
||||
"@babel/types": "^7.17.0",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse/node_modules/globals": {
|
||||
"version": "11.12.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
|
||||
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz",
|
||||
"integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.16.7",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
|
||||
@@ -815,6 +1050,28 @@
|
||||
"react-dom": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@trivago/prettier-plugin-sort-imports": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.2.0.tgz",
|
||||
"integrity": "sha512-YBepjbt+ZNBVmN3ev1amQH3lWCmHyt5qTbLCp/syXJRu/Kw2koXh44qayB1gMRxcL/gV8egmjN5xWSrYyfUtyw==",
|
||||
"dependencies": {
|
||||
"@babel/generator": "7.17.7",
|
||||
"@babel/parser": "^7.20.5",
|
||||
"@babel/traverse": "7.17.3",
|
||||
"@babel/types": "7.17.0",
|
||||
"javascript-natural-sort": "0.7.1",
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/compiler-sfc": "3.x",
|
||||
"prettier": "2.x - 3.x"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/compiler-sfc": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@types/aria-query": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz",
|
||||
@@ -1725,7 +1982,6 @@
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
@@ -3584,6 +3840,11 @@
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/javascript-natural-sort": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
|
||||
"integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw=="
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
"version": "1.19.1",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz",
|
||||
@@ -3625,6 +3886,17 @@
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/jsesc": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
|
||||
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
|
||||
"bin": {
|
||||
"jsesc": "bin/jsesc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
@@ -3942,8 +4214,7 @@
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
@@ -4663,7 +4934,6 @@
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz",
|
||||
"integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
@@ -5416,6 +5686,14 @@
|
||||
"npm": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||
@@ -5802,6 +6080,14 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
"integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
|
||||
+4
-1
@@ -6,11 +6,14 @@
|
||||
"dev": "next dev",
|
||||
"build": "ANALYZE=true next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"lint": "next lint",
|
||||
"format": "prettier --check \"**/*.{js,jsx,ts,tsx}\"",
|
||||
"format:fix": "prettier --write \"**/*.{js,jsx,ts,tsx}\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@kodingdotninja/use-tailwind-breakpoint": "^0.0.5",
|
||||
"@next/bundle-analyzer": "^13.4.12",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.2.0",
|
||||
"@types/node": "20.5.1",
|
||||
"@types/react": "18.2.21",
|
||||
"@types/react-dom": "18.2.7",
|
||||
|
||||
+24
-18
@@ -9,35 +9,41 @@ module.exports = {
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['var(--font-inter)'],
|
||||
title: ['var(--font-title)'],
|
||||
sans: ["var(--font-inter)"],
|
||||
title: ["var(--font-title)"],
|
||||
},
|
||||
colors: {
|
||||
'primary': {
|
||||
DEFAULT: '#0086C7',
|
||||
50: '#A8E3FF',
|
||||
100: '#94DCFF',
|
||||
200: '#6BCFFF',
|
||||
300: '#42C1FF',
|
||||
400: '#1AB4FF',
|
||||
500: '#00A1F0',
|
||||
600: '#0086C7',
|
||||
700: '#00608F',
|
||||
800: '#003A57',
|
||||
900: '#00151F',
|
||||
950: '#000203'
|
||||
primary: {
|
||||
DEFAULT: "#0086C7",
|
||||
50: "#A8E3FF",
|
||||
100: "#94DCFF",
|
||||
200: "#6BCFFF",
|
||||
300: "#42C1FF",
|
||||
400: "#1AB4FF",
|
||||
500: "#00A1F0",
|
||||
600: "#0086C7",
|
||||
700: "#00608F",
|
||||
800: "#003A57",
|
||||
900: "#00151F",
|
||||
950: "#000203",
|
||||
},
|
||||
},
|
||||
minHeight: {
|
||||
// We use 100svh, falling back to the the --1svh var that we add as a polyfill for older browsers.
|
||||
// The 9rem is for the header and footer.
|
||||
// In the event that the polyfill fails, we fall back to 0.9vh as a guess of how much 1svh is.
|
||||
content: ["calc(var(--1svh, 0.9vh) * 100 - 9rem)", "calc(100svh - 9rem)"],
|
||||
content: [
|
||||
"calc(var(--1svh, 0.9vh) * 100 - 9rem)",
|
||||
"calc(100svh - 9rem)",
|
||||
],
|
||||
},
|
||||
height: {
|
||||
content: ["calc(var(--1svh, 0.9vh) * 100 - 9rem)", "calc(100svh - 9rem)"],
|
||||
content: [
|
||||
"calc(var(--1svh, 0.9vh) * 100 - 9rem)",
|
||||
"calc(100svh - 9rem)",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require('@tailwindcss/forms')],
|
||||
plugins: [require("@tailwindcss/forms")],
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { LatLngLiteral } from "leaflet";
|
||||
import { Dispatch, MutableRefObject, SetStateAction } from "react";
|
||||
|
||||
import { LatLngLiteral } from "leaflet";
|
||||
|
||||
export enum TimeControl {
|
||||
Classic = "Classic",
|
||||
Rapid = "Rapid",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { atom, SetStateAction } from "jotai";
|
||||
import { SetStateAction, atom } from "jotai";
|
||||
|
||||
export default function atomWithDebounce<T>(
|
||||
initialValue: T,
|
||||
@@ -37,9 +37,14 @@ export default function atomWithDebounce<T>(
|
||||
|
||||
onDebounceStart();
|
||||
|
||||
const nextTimeoutId = setTimeout(() => {
|
||||
onDebounceEnd();
|
||||
}, nextValue === initialValue ? delayOnResetMilliseconds : delayMilliseconds);
|
||||
const nextTimeoutId = setTimeout(
|
||||
() => {
|
||||
onDebounceEnd();
|
||||
},
|
||||
nextValue === initialValue
|
||||
? delayOnResetMilliseconds
|
||||
: delayMilliseconds,
|
||||
);
|
||||
|
||||
// set previous timeout atom in case it needs to get cleared
|
||||
set(prevTimeoutAtom, nextTimeoutId);
|
||||
|
||||
Reference in New Issue
Block a user