import { Button } from "components/Inputs/Button"; import { useAppLayout } from "contexts/AppLayoutContext"; import { UploadImageFragment } from "graphql/generated"; import { AppStaticProps } from "graphql/getAppStaticProps"; import { cIf, cJoin } from "helpers/className"; import { prettyLanguage, prettySlug } from "helpers/formatters"; import { getOgImage, ImageQuality } from "helpers/img"; import { isDefined, isDefinedAndNotEmpty } from "helpers/others"; // import { getClient, Indexes, search, SearchResult } from "helpers/search"; import { Immutable } from "helpers/types"; import { useMediaMobile } from "hooks/useMediaQuery"; import { AnchorIds } from "hooks/useScrollTopOnChange"; import Head from "next/head"; import { useRouter } from "next/router"; import { useEffect, useLayoutEffect, useMemo, useState } from "react"; import { useSwipeable } from "react-swipeable"; import { Ico, Icon } from "./Ico"; import { ButtonGroup } from "./Inputs/ButtonGroup"; import { OrderableList } from "./Inputs/OrderableList"; import { Select } from "./Inputs/Select"; import { TextInput } from "./Inputs/TextInput"; import { MainPanel } from "./Panels/MainPanel"; import { Popup } from "./Popup"; interface Props extends AppStaticProps { subPanel?: React.ReactNode; subPanelIcon?: Icon; contentPanel?: React.ReactNode; title?: string; navTitle: string | null | undefined; thumbnail?: UploadImageFragment; description?: string; } const SENSIBILITY_SWIPE = 1.1; const TITLE_PREFIX = "Accord’s Library"; export function AppLayout(props: Immutable): JSX.Element { const { langui, currencies, languages, subPanel, contentPanel, thumbnail, title, navTitle, description, subPanelIcon = Icon.Tune, } = props; const { configPanelOpen, currency, darkMode, dyslexic, fontSize, mainPanelOpen, mainPanelReduced, menuGestures, playerName, preferredLanguages, selectedThemeMode, subPanelOpen, setConfigPanelOpen, setCurrency, setDarkMode, setDyslexic, setFontSize, setMainPanelOpen, setPlayerName, setPreferredLanguages, setSelectedThemeMode, setSubPanelOpen, toggleMainPanelOpen, toggleSubPanelOpen, } = useAppLayout(); const router = useRouter(); const isMobile = useMediaMobile(); useEffect(() => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition router.events?.on("routeChangeStart", () => { setConfigPanelOpen(false); setMainPanelOpen(false); setSubPanelOpen(false); }); // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition router.events?.on("hashChangeStart", () => { setSubPanelOpen(false); }); }, [router.events, setConfigPanelOpen, setMainPanelOpen, setSubPanelOpen]); const handlers = useSwipeable({ onSwipedLeft: (SwipeEventData) => { if (menuGestures) { if (SwipeEventData.velocity < SENSIBILITY_SWIPE) return; if (mainPanelOpen === true) { setMainPanelOpen(false); } else if (subPanel === true && contentPanel === true) { setSubPanelOpen(true); } } }, onSwipedRight: (SwipeEventData) => { if (menuGestures) { if (SwipeEventData.velocity < SENSIBILITY_SWIPE) return; if (subPanelOpen === true) { setSubPanelOpen(false); } else { setMainPanelOpen(true); } } }, }); const turnSubIntoContent = useMemo( () => isDefined(subPanel) && isDefined(contentPanel), [contentPanel, subPanel] ); const metaImage = useMemo( () => thumbnail ? getOgImage(ImageQuality.Og, thumbnail) : { image: "/default_og.jpg", width: 1200, height: 630, alt: "Accord's Library Logo", }, [thumbnail] ); const { ogTitle, metaTitle } = useMemo(() => { const resultTitle = title ?? navTitle ?? prettySlug(router.asPath.split("/").pop()); return { ogTitle: resultTitle, metaTitle: `${TITLE_PREFIX} - ${resultTitle}`, }; }, [navTitle, router.asPath, title]); const metaDescription = useMemo( () => description ?? langui.default_description ?? "", [description, langui.default_description] ); useLayoutEffect(() => { document.getElementsByTagName("html")[0].style.fontSize = `${ (fontSize ?? 1) * 100 }%`; }, [fontSize]); const defaultPreferredLanguages = useMemo(() => { let list: string[] = []; if (isDefinedAndNotEmpty(router.locale) && router.locales) { if (router.locale === "en") { list = [router.locale]; router.locales.map((locale) => { if (locale !== router.locale) list.push(locale); }); } else { list = [router.locale, "en"]; router.locales.map((locale) => { if (locale !== router.locale && locale !== "en") list.push(locale); }); } } return list; }, [router.locale, router.locales]); const currencyOptions = useMemo(() => { const list: string[] = []; currencies.map((currentCurrency) => { if ( currentCurrency.attributes && isDefinedAndNotEmpty(currentCurrency.attributes.code) ) list.push(currentCurrency.attributes.code); }); return list; }, [currencies]); const [currencySelect, setCurrencySelect] = useState(-1); useEffect(() => { if (isDefined(currency)) setCurrencySelect(currencyOptions.indexOf(currency)); }, [currency, currencyOptions]); useEffect(() => { if (currencySelect >= 0) setCurrency(currencyOptions[currencySelect]); }, [currencyOptions, currencySelect, setCurrency]); const gridCol = useMemo(() => { if (isDefined(subPanel)) { if (mainPanelReduced === true) { return "grid-cols-[6rem_20rem_1fr]"; } return "grid-cols-[20rem_20rem_1fr]"; } else if (mainPanelReduced === true) { return "grid-cols-[6rem_0px_1fr]"; } return "grid-cols-[20rem_0px_1fr]"; }, [mainPanelReduced, subPanel]); return (
{metaTitle} {/* Background when navbar is opened */}
{ setMainPanelOpen(false); setSubPanelOpen(false); }} >
{/* Content panel */}
{isDefined(contentPanel) ? ( contentPanel ) : (

{langui.select_option_sidebar}

)}
{/* Sub panel */} {isDefined(subPanel) && (
{subPanel}
)} {/* Main panel */}
{/* Navbar */}
{ toggleMainPanelOpen(); setSubPanelOpen(false); }} />

30, "max-h-14 text-xl", "max-h-16 text-2xl" ) )} > {ogTitle}

{isDefined(subPanel) && !turnSubIntoContent && ( { toggleSubPanelOpen(); setMainPanelOpen(false); }} /> )}

{langui.settings}

{router.locales && (

{langui.languages}

{preferredLanguages && ( 0 ? new Map( preferredLanguages.map((locale) => [ locale, prettyLanguage(locale, languages), ]) ) : new Map( defaultPreferredLanguages.map((locale) => [ locale, prettyLanguage(locale, languages), ]) ) } insertLabels={ new Map([ [0, langui.primary_language], [1, langui.secondary_language], ]) } onChange={(items) => { const newPreferredLanguages = [...items].map( ([code]) => code ); setPreferredLanguages(newPreferredLanguages); if (router.locale !== newPreferredLanguages[0]) { router.push(router.asPath, router.asPath, { locale: newPreferredLanguages[0], }); } }} /> )}
)}

{langui.theme}

{langui.currency}