diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 306ca62..042276c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -77,4 +77,9 @@ interface ComponentProps {} // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ export const Component = () => {}; + +/* + * ╭──────────────────────╮ + * ───────────────────────────────────╯ TRANSLATED VARIANT ╰────────────────────────────────────── + */ ``` diff --git a/next.config.js b/next.config.js index 69ca6d1..424c9e0 100644 --- a/next.config.js +++ b/next.config.js @@ -4,7 +4,7 @@ const locales = ["en", "es", "fr", "pt-br", "ja"]; /* END CONFIG */ -/** @type {import('next').NextConfig} */ +/* @type {import('next').NextConfig} */ module.exports = { swcMinify: true, reactStrictMode: true, @@ -15,9 +15,6 @@ module.exports = { images: { domains: ["img.accords-library.com", "watch.accords-library.com"], }, - serverRuntimeConfig: { - locales: locales, - }, async redirects() { return [ { diff --git a/src/components/AppLayout.tsx b/src/components/AppLayout.tsx index 65a3d5b..cc06165 100644 --- a/src/components/AppLayout.tsx +++ b/src/components/AppLayout.tsx @@ -3,12 +3,12 @@ import { useRouter } from "next/router"; import { useEffect, useLayoutEffect, useMemo, useState } from "react"; import { useSwipeable } from "react-swipeable"; import UAParser from "ua-parser-js"; +import { useBoolean, useIsClient } from "usehooks-ts"; 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 { ContentPlaceholder } from "./PanelComponents/ContentPlaceholder"; import { MainPanel } from "./Panels/MainPanel"; import { Popup } from "./Popup"; import { AnchorIds } from "hooks/useScrollTopOnChange"; @@ -27,8 +27,6 @@ import { useAppLayout } from "contexts/AppLayoutContext"; import { Button } from "components/Inputs/Button"; import { OpenGraph, TITLE_PREFIX } from "helpers/openGraph"; import { getDefaultPreferredLanguages } from "helpers/locales"; -import useIsClient from "hooks/useIsClient"; -import { useBoolean } from "hooks/useBoolean"; /* * ╭─────────────╮ @@ -195,7 +193,7 @@ export const AppLayout = ({ }, [mainPanelReduced, subPanel]); const isClient = useIsClient(); - const { state: hasDisgardSafariWarning, setTrue: disgardSafariWarning } = + const { value: hasDisgardSafariWarning, setTrue: disgardSafariWarning } = useBoolean(false); const isSafari = useMemo(() => { if (isClient) { @@ -548,3 +546,29 @@ export const AppLayout = ({ ); }; + +// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + +interface ContentPlaceholderProps { + message: string; + icon?: Icon; +} + +const ContentPlaceholder = ({ + message, + icon, +}: ContentPlaceholderProps): JSX.Element => ( +
+
+ {isDefined(icon) && } +

+ {message} +

+
+
+); diff --git a/src/components/Chronicles/ChroniclePreview.tsx b/src/components/Chronicles/ChroniclePreview.tsx index a6bfdcd..0e11282 100644 --- a/src/components/Chronicles/ChroniclePreview.tsx +++ b/src/components/Chronicles/ChroniclePreview.tsx @@ -1,6 +1,9 @@ +import { useCallback } from "react"; import { Link } from "components/Inputs/Link"; import { DatePickerFragment } from "graphql/generated"; import { cIf, cJoin } from "helpers/className"; +import { TranslatedProps } from "helpers/types/TranslatedProps"; +import { useSmartLanguage } from "hooks/useSmartLanguage"; /* * ╭─────────────╮ @@ -14,7 +17,7 @@ interface Props { isActive?: boolean; } -export const ChroniclePreview = ({ +const ChroniclePreview = ({ date, url, title, @@ -40,6 +43,35 @@ export const ChroniclePreview = ({ ); +/* + * ╭──────────────────────╮ + * ───────────────────────────────────╯ TRANSLATED VARIANT ╰────────────────────────────────────── + */ + +export const TranslatedChroniclePreview = ({ + translations, + fallback, + ...otherProps +}: TranslatedProps< + Parameters[0], + "title" +>): JSX.Element => { + const [selectedTranslation] = useSmartLanguage({ + items: translations, + languageExtractor: useCallback( + (item: { language: string }): string => item.language, + [] + ), + }); + + return ( + + ); +}; + /* * ╭───────────────────╮ * ─────────────────────────────────────╯ PRIVATE METHODS ╰─────────────────────────────────────── diff --git a/src/components/Chronicles/ChroniclesList.tsx b/src/components/Chronicles/ChroniclesList.tsx index c439e4f..239c484 100644 --- a/src/components/Chronicles/ChroniclesList.tsx +++ b/src/components/Chronicles/ChroniclesList.tsx @@ -1,10 +1,13 @@ +import { useCallback } from "react"; +import { useBoolean } from "usehooks-ts"; +import { TranslatedChroniclePreview } from "./ChroniclePreview"; import { GetChroniclesChaptersQuery } from "graphql/generated"; import { filterHasAttributes } from "helpers/others"; -import { TranslatedChroniclePreview } from "components/Translated"; import { prettyInlineTitle, prettySlug } from "helpers/formatters"; import { Ico, Icon } from "components/Ico"; -import { useBoolean } from "hooks/useBoolean"; import { compareDate } from "helpers/date"; +import { TranslatedProps } from "helpers/types/TranslatedProps"; +import { useSmartLanguage } from "hooks/useSmartLanguage"; /* * ╭─────────────╮ @@ -23,12 +26,12 @@ interface Props { title: string; } -export const ChroniclesList = ({ +const ChroniclesList = ({ chronicles, currentSlug, title, }: Props): JSX.Element => { - const { state: isOpen, toggleState: toggleOpen } = useBoolean( + const { value: isOpen, toggle: toggleOpen } = useBoolean( chronicles.some((chronicle) => chronicle.attributes?.slug === currentSlug) ); @@ -112,3 +115,29 @@ export const ChroniclesList = ({ ); }; + +/* + * ╭──────────────────────╮ + * ───────────────────────────────────╯ TRANSLATED VARIANT ╰────────────────────────────────────── + */ + +export const TranslatedChroniclesList = ({ + translations, + fallback, + ...otherProps +}: TranslatedProps): JSX.Element => { + const [selectedTranslation] = useSmartLanguage({ + items: translations, + languageExtractor: useCallback( + (item: { language: string }): string => item.language, + [] + ), + }); + + return ( + + ); +}; diff --git a/src/components/Inputs/Button.tsx b/src/components/Inputs/Button.tsx index 6c64087..e1ddbb4 100644 --- a/src/components/Inputs/Button.tsx +++ b/src/components/Inputs/Button.tsx @@ -1,9 +1,11 @@ -import React, { MouseEventHandler } from "react"; +import React, { MouseEventHandler, useCallback } from "react"; import { Link } from "./Link"; import { Ico, Icon } from "components/Ico"; import { cIf, cJoin } from "helpers/className"; import { ConditionalWrapper, Wrapper } from "helpers/component"; import { isDefined, isDefinedAndNotEmpty } from "helpers/others"; +import { TranslatedProps } from "helpers/types/TranslatedProps"; +import { useSmartLanguage } from "hooks/useSmartLanguage"; /* * ╭─────────────╮ @@ -89,6 +91,29 @@ export const Button = ({ ); +/* + * ╭──────────────────────╮ + * ───────────────────────────────────╯ TRANSLATED VARIANT ╰────────────────────────────────────── + */ + +export const TranslatedButton = ({ + translations, + fallback, + ...otherProps +}: TranslatedProps): JSX.Element => { + const [selectedTranslation] = useSmartLanguage({ + items: translations, + languageExtractor: useCallback( + (item: { language: string }): string => item.language, + [] + ), + }); + + return ( +