Put an end to my useMemo craze + fixed ios

This commit is contained in:
DrMint 2022-12-04 15:31:11 +01:00
parent c356679813
commit 6a1be38613
44 changed files with 3887 additions and 3297 deletions

View File

@ -25,7 +25,7 @@
#### [Front](https://github.com/Accords-Library/accords-library.com) (this repository) #### [Front](https://github.com/Accords-Library/accords-library.com) (this repository)
- Language: [TypeScript](https://www.typescriptlang.org/) - Language: [TypeScript](https://www.typescriptlang.org/)
- Framework: [Next.js 12](https://nextjs.org/) (React 18) - Framework: [Next.js 13](https://nextjs.org/) (React 18)
- Queries: [GraphQL Code Generator](https://www.graphql-code-generator.com/) - Queries: [GraphQL Code Generator](https://www.graphql-code-generator.com/)
- Fetch the GraphQL schema from the GraphQL back-end endpoint - Fetch the GraphQL schema from the GraphQL back-end endpoint
- Read the operations and fragments stored as graphql files in the `src/graphql` folder - Read the operations and fragments stored as graphql files in the `src/graphql` folder

View File

@ -6,7 +6,6 @@ const locales = ["en", "es", "fr", "pt-br", "ja"];
/* @type {import('next').NextConfig} */ /* @type {import('next').NextConfig} */
module.exports = { module.exports = {
swcMinify: true,
reactStrictMode: true, reactStrictMode: true,
poweredByHeader: false, poweredByHeader: false,
i18n: { i18n: {

View File

@ -1 +1,91 @@
{"currencies":{"data":[{"id":"1","attributes":{"code":"EUR","symbol":"€","rate_to_usd":1.036166,"display_decimals":true}},{"id":"2","attributes":{"code":"CAD","symbol":"$","rate_to_usd":0.79319156,"display_decimals":true}},{"id":"3","attributes":{"code":"USD","symbol":"$","rate_to_usd":1,"display_decimals":true}},{"id":"4","attributes":{"code":"JPY","symbol":"¥","rate_to_usd":0.0083864261,"display_decimals":false}},{"id":"5","attributes":{"code":"BRL","symbol":"R$","rate_to_usd":0.19904328,"display_decimals":true}},{"id":"6","attributes":{"code":"GBP","symbol":"£","rate_to_usd":1.3181323,"display_decimals":true}},{"id":"7","attributes":{"code":"AUD","symbol":"$","rate_to_usd":0.7422,"display_decimals":true}},{"id":"8","attributes":{"code":"INR","symbol":"₹","rate_to_usd":0.013162881,"display_decimals":false}},{"id":"9","attributes":{"code":"NZD","symbol":"$","rate_to_usd":0.69089984,"display_decimals":true}},{"id":"10","attributes":{"code":"CHF","symbol":"CHF","rate_to_usd":1.0728706,"display_decimals":true}}]}} {
"currencies": {
"data": [
{
"id": "1",
"attributes": {
"code": "EUR",
"symbol": "€",
"rate_to_usd": 1.036166,
"display_decimals": true
}
},
{
"id": "2",
"attributes": {
"code": "CAD",
"symbol": "$",
"rate_to_usd": 0.79319156,
"display_decimals": true
}
},
{
"id": "3",
"attributes": { "code": "USD", "symbol": "$", "rate_to_usd": 1, "display_decimals": true }
},
{
"id": "4",
"attributes": {
"code": "JPY",
"symbol": "¥",
"rate_to_usd": 0.0083864261,
"display_decimals": false
}
},
{
"id": "5",
"attributes": {
"code": "BRL",
"symbol": "R$",
"rate_to_usd": 0.19904328,
"display_decimals": true
}
},
{
"id": "6",
"attributes": {
"code": "GBP",
"symbol": "£",
"rate_to_usd": 1.3181323,
"display_decimals": true
}
},
{
"id": "7",
"attributes": {
"code": "AUD",
"symbol": "$",
"rate_to_usd": 0.7422,
"display_decimals": true
}
},
{
"id": "8",
"attributes": {
"code": "INR",
"symbol": "₹",
"rate_to_usd": 0.013162881,
"display_decimals": false
}
},
{
"id": "9",
"attributes": {
"code": "NZD",
"symbol": "$",
"rate_to_usd": 0.69089984,
"display_decimals": true
}
},
{
"id": "10",
"attributes": {
"code": "CHF",
"symbol": "CHF",
"rate_to_usd": 1.0728706,
"display_decimals": true
}
}
]
}
}

View File

@ -1 +1,36 @@
{"languages":{"data":[{"id":"1","attributes":{"name":"French","code":"fr","localized_name":"Français"}},{"id":"2","attributes":{"name":"English","code":"en","localized_name":"English"}},{"id":"3","attributes":{"name":"Japanese","code":"ja","localized_name":"日本語"}},{"id":"4","attributes":{"name":"Spanish","code":"es","localized_name":"Español"}},{"id":"6","attributes":{"name":"Portuguese (Brazil)","code":"pt-br","localized_name":"Português (Brasil)"}},{"id":"8","attributes":{"name":"German","code":"de","localized_name":"Deutsch"}},{"id":"9","attributes":{"name":"Italian","code":"it","localized_name":"Italiano"}},{"id":"10","attributes":{"name":"Russian","code":"ru","localized_name":"русский"}},{"id":"11","attributes":{"name":"Korean","code":"ko","localized_name":"한국어"}},{"id":"12","attributes":{"name":"Chinese (Traditional)","code":"zh-cht","localized_name":"中文(繁體)"}}]}} {
"languages": {
"data": [
{ "id": "1", "attributes": { "name": "French", "code": "fr", "localized_name": "Français" } },
{ "id": "2", "attributes": { "name": "English", "code": "en", "localized_name": "English" } },
{ "id": "3", "attributes": { "name": "Japanese", "code": "ja", "localized_name": "日本語" } },
{ "id": "4", "attributes": { "name": "Spanish", "code": "es", "localized_name": "Español" } },
{
"id": "6",
"attributes": {
"name": "Portuguese (Brazil)",
"code": "pt-br",
"localized_name": "Português (Brasil)"
}
},
{ "id": "8", "attributes": { "name": "German", "code": "de", "localized_name": "Deutsch" } },
{
"id": "9",
"attributes": { "name": "Italian", "code": "it", "localized_name": "Italiano" }
},
{
"id": "10",
"attributes": { "name": "Russian", "code": "ru", "localized_name": "русский" }
},
{ "id": "11", "attributes": { "name": "Korean", "code": "ko", "localized_name": "한국어" } },
{
"id": "12",
"attributes": {
"name": "Chinese (Traditional)",
"code": "zh-cht",
"localized_name": "中文(繁體)"
}
}
]
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,8 @@
import Head from "next/head"; import Head from "next/head";
import { useMemo } from "react";
import { useSwipeable } from "react-swipeable"; import { useSwipeable } from "react-swipeable";
import { layout } from "../../design.config"; import { layout } from "../../design.config";
import { Ico, Icon } from "./Ico"; import { Ico, Icon } from "./Ico";
import { MainPanel } from "./Panels/MainPanel"; import { MainPanel } from "./Panels/MainPanel";
import { SafariPopup } from "./Panels/SafariPopup";
import { isDefined, isUndefined } from "helpers/others"; import { isDefined, isUndefined } from "helpers/others";
import { cIf, cJoin } from "helpers/className"; import { cIf, cJoin } from "helpers/className";
import { OpenGraph, TITLE_PREFIX, TITLE_SEPARATOR } from "helpers/openGraph"; import { OpenGraph, TITLE_PREFIX, TITLE_SEPARATOR } from "helpers/openGraph";
@ -77,10 +75,7 @@ export const AppLayout = ({
}, },
}); });
const turnSubIntoContent = useMemo( const turnSubIntoContent = isDefined(subPanel) && isUndefined(contentPanel);
() => isDefined(subPanel) && isUndefined(contentPanel),
[contentPanel, subPanel]
);
return ( return (
<div <div
@ -227,7 +222,6 @@ export const AppLayout = ({
/> />
)} )}
</div> </div>
<SafariPopup />
</div> </div>
); );
}; };

View File

@ -1,6 +1,6 @@
import Markdown from "markdown-to-jsx"; import Markdown from "markdown-to-jsx";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import React, { Fragment, useMemo } from "react"; import React, { Fragment } from "react";
import ReactDOMServer from "react-dom/server"; import ReactDOMServer from "react-dom/server";
import { HorizontalLine } from "components/HorizontalLine"; import { HorizontalLine } from "components/HorizontalLine";
import { Img } from "components/Img"; import { Img } from "components/Img";
@ -35,11 +35,8 @@ export const Markdawn = ({ className, text: rawText }: MarkdawnProps): JSX.Eleme
const { showLightBox } = useAtomGetter(atoms.lightBox); const { showLightBox } = useAtomGetter(atoms.lightBox);
/* eslint-disable no-irregular-whitespace */ /* eslint-disable no-irregular-whitespace */
const text = useMemo( const text = `${preprocessMarkDawn(rawText, playerName)}
() => `${preprocessMarkDawn(rawText, playerName)} `;
`,
[playerName, rawText]
);
/* eslint-enable no-irregular-whitespace */ /* eslint-enable no-irregular-whitespace */
if (isUndefined(text) || text === "") { if (isUndefined(text) || text === "") {
@ -219,19 +216,17 @@ export const Markdawn = ({ className, text: rawText }: MarkdawnProps): JSX.Eleme
interface TableOfContentsProps { interface TableOfContentsProps {
text: string; text: string;
title?: string; title?: string;
horizontalLine?: boolean; horizontalLine?: boolean;
} }
export const TableOfContents = ({ export const TableOfContents = ({
text, text,
title, title,
horizontalLine = false, horizontalLine = false,
}: TableOfContentsProps): JSX.Element => { }: TableOfContentsProps): JSX.Element => {
const router = useRouter(); const router = useRouter();
const langui = useAtomGetter(atoms.localData.langui); const langui = useAtomGetter(atoms.localData.langui);
const toc = useMemo(() => getTocFromMarkdawn(preprocessMarkDawn(text), title), [text, title]); const toc = getTocFromMarkdawn(preprocessMarkDawn(text), title);
return ( return (
<> <>
@ -268,8 +263,7 @@ interface HeaderProps {
const Header = ({ level, title, slug }: HeaderProps): JSX.Element => { const Header = ({ level, title, slug }: HeaderProps): JSX.Element => {
const isHoverable = useDeviceSupportsHover(); const isHoverable = useDeviceSupportsHover();
const innerComponent = useMemo( const innerComponent = (
() => (
<> <>
<div className="ml-10 flex place-items-center gap-4"> <div className="ml-10 flex place-items-center gap-4">
{title === "* * *" ? ( {title === "* * *" ? (
@ -287,8 +281,6 @@ const Header = ({ level, title, slug }: HeaderProps): JSX.Element => {
/> />
</div> </div>
</> </>
),
[isHoverable, slug, title]
); );
switch (level) { switch (level) {
@ -349,8 +341,7 @@ const TocLevel = ({
allowIntersection = true, allowIntersection = true,
}: LevelProps): JSX.Element => { }: LevelProps): JSX.Element => {
const router = useRouter(); const router = useRouter();
const ids = tocchildren.map((child) => child.slug);
const ids = useMemo(() => tocchildren.map((child) => child.slug), [tocchildren]);
const currentIntersection = useIntersectionList(ids); const currentIntersection = useIntersectionList(ids);
return ( return (

View File

@ -1,5 +1,5 @@
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { MouseEventHandler, useCallback, useMemo } from "react"; import { MouseEventHandler, useCallback } from "react";
import { Ico, Icon } from "components/Ico"; import { Ico, Icon } from "components/Ico";
import { ToolTip } from "components/ToolTip"; import { ToolTip } from "components/ToolTip";
import { cIf, cJoin } from "helpers/className"; import { cIf, cJoin } from "helpers/className";
@ -39,10 +39,7 @@ export const NavOption = ({
onClick, onClick,
}: Props): JSX.Element => { }: Props): JSX.Element => {
const router = useRouter(); const router = useRouter();
const isActive = useMemo( const isActive = active || router.asPath.startsWith(url);
() => active || router.asPath.startsWith(url),
[active, router.asPath, url]
);
return ( return (
<ToolTip <ToolTip

View File

@ -1,45 +0,0 @@
import { useMemo } from "react";
import UAParser from "ua-parser-js";
import { useIsClient, useSessionStorage } from "usehooks-ts";
import { Button } from "components/Inputs/Button";
import { Popup } from "components/Containers/Popup";
import { sendAnalytics } from "helpers/analytics";
export const SafariPopup = (): JSX.Element => {
const [hasDisgardedSafariWarning, setHasDisgardedSafariWarning] = useSessionStorage(
"hasDisgardedSafariWarning",
false
);
const isClient = useIsClient();
const isSafari = useMemo<boolean>(() => {
if (isClient) {
const parser = new UAParser();
return parser.getBrowser().name === "Safari" || parser.getOS().name === "iOS";
}
return false;
}, [isClient]);
return (
<Popup isVisible={isSafari && !hasDisgardedSafariWarning}>
<h1 className="text-2xl">Hi, you are using Safari!</h1>
<p className="max-w-lg text-center">
In most cases this wouldn&rsquo;t be a problem but our website isfor some obscure
reasonperforming terribly on Safari (WebKit). Because of that, we have decided to display
this message instead of letting you have a slow and painful experience. We are looking into
the problem, and are hoping to fix this soon.
</p>
<p>In the meanwhile, if you are using an iPhone/iPad, please try using another device.</p>
<p>If you are on macOS, please use another browser such as Firefox or Chrome.</p>
<Button
text="Let me in regardless"
className="mt-8"
onClick={() => {
setHasDisgardedSafariWarning(true);
sendAnalytics("Safari", "Disgard warning");
}}
/>
</Popup>
);
};

View File

@ -1,5 +1,5 @@
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { useEffect, useMemo, useState } from "react"; import { useEffect, useState } from "react";
import { Icon } from "components/Ico"; import { Icon } from "components/Ico";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
import { ButtonGroup } from "components/Inputs/ButtonGroup"; import { ButtonGroup } from "components/Inputs/ButtonGroup";
@ -34,12 +34,8 @@ export const SettingsPopup = (): JSX.Element => {
const router = useRouter(); const router = useRouter();
const currencyOptions = useMemo( const currencyOptions = filterHasAttributes(currencies, ["attributes"] as const).map(
() =>
filterHasAttributes(currencies, ["attributes"] as const).map(
(currentCurrency) => currentCurrency.attributes.code (currentCurrency) => currentCurrency.attributes.code
),
[currencies]
); );
const [currencySelect, setCurrencySelect] = useState<number>(-1); const [currencySelect, setCurrencySelect] = useState<number>(-1);

View File

@ -1,4 +1,4 @@
import { Fragment, useCallback, useMemo } from "react"; import { Fragment, useCallback } from "react";
import { AppLayout, AppLayoutRequired } from "./AppLayout"; import { AppLayout, AppLayoutRequired } from "./AppLayout";
import { Chip } from "./Chip"; import { Chip } from "./Chip";
import { HorizontalLine } from "./HorizontalLine"; import { HorizontalLine } from "./HorizontalLine";
@ -59,19 +59,13 @@ export const PostPage = ({
), ),
}); });
const { thumbnail, body, title, excerpt } = useMemo( const thumbnail =
() => ({ selectedTranslation?.thumbnail?.data?.attributes ?? post.thumbnail?.data?.attributes;
thumbnail: const body = selectedTranslation?.body ?? "";
selectedTranslation?.thumbnail?.data?.attributes ?? post.thumbnail?.data?.attributes, const title = selectedTranslation?.title ?? prettySlug(post.slug);
body: selectedTranslation?.body ?? "", const excerpt = selectedTranslation?.excerpt ?? "";
title: selectedTranslation?.title ?? prettySlug(post.slug),
excerpt: selectedTranslation?.excerpt ?? "",
}),
[post.slug, post.thumbnail, selectedTranslation]
);
const subPanel = useMemo( const subPanel =
() =>
returnHref || returnTitle || displayCredits || displayToc ? ( returnHref || returnTitle || displayCredits || displayToc ? (
<SubPanel> <SubPanel>
{returnHref && returnTitle && ( {returnHref && returnTitle && (
@ -113,22 +107,9 @@ export const PostPage = ({
{displayToc && <TableOfContents text={body} title={title} horizontalLine />} {displayToc && <TableOfContents text={body} title={title} horizontalLine />}
</SubPanel> </SubPanel>
) : undefined, ) : undefined;
[
body,
displayCredits,
displayToc,
langui,
post.authors,
returnHref,
returnTitle,
selectedTranslation,
title,
]
);
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel> <ContentPanel>
{returnHref && returnTitle && ( {returnHref && returnTitle && (
<ReturnButton <ReturnButton
@ -176,23 +157,6 @@ export const PostPage = ({
{appendBody} {appendBody}
</ContentPanel> </ContentPanel>
),
[
LanguageSwitcher,
appendBody,
body,
displayLanguageSwitcher,
displayThumbnailHeader,
displayTitle,
excerpt,
languageSwitcherProps,
post.categories,
prependBody,
returnHref,
returnTitle,
thumbnail,
title,
]
); );
return <AppLayout {...otherProps} contentPanel={contentPanel} subPanel={subPanel} />; return <AppLayout {...otherProps} contentPanel={contentPanel} subPanel={subPanel} />;

View File

@ -1,4 +1,4 @@
import { useCallback, useMemo } from "react"; import { useCallback } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { Chip } from "./Chip"; import { Chip } from "./Chip";
import { Ico, Icon } from "./Ico"; import { Ico, Icon } from "./Ico";
@ -75,8 +75,7 @@ export const PreviewCard = ({
const isHoverable = useDeviceSupportsHover(); const isHoverable = useDeviceSupportsHover();
const router = useRouter(); const router = useRouter();
const metadataJSX = useMemo( const metadataJSX = (
() => (
<> <>
{metadata && (metadata.releaseDate || metadata.price) && ( {metadata && (metadata.releaseDate || metadata.price) && (
<div className="flex w-full flex-row flex-wrap gap-x-3"> <div className="flex w-full flex-row flex-wrap gap-x-3">
@ -107,8 +106,6 @@ export const PreviewCard = ({
</div> </div>
)} )}
</> </>
),
[currencies, currency, metadata, router.locale]
); );
return ( return (

View File

@ -1,4 +1,4 @@
import { Fragment, useCallback, useEffect, useMemo, useState } from "react"; import { Fragment, useCallback, useEffect, useState } from "react";
import { useHotkeys } from "react-hotkeys-hook"; import { useHotkeys } from "react-hotkeys-hook";
import naturalCompare from "string-natural-compare"; import naturalCompare from "string-natural-compare";
import { Chip } from "./Chip"; import { Chip } from "./Chip";
@ -87,17 +87,11 @@ export const SmartList = <T,>({
return items; return items;
}, [items, searchingBy, searchingCaseInsensitive, searchingTerm]); }, [items, searchingBy, searchingCaseInsensitive, searchingTerm]);
const filteredItems = useMemo(() => { const filteredItems = searchFilter().filter(filteringFunction);
const filteredBySearch = searchFilter();
return filteredBySearch.filter(filteringFunction);
}, [filteringFunction, searchFilter]);
const sortedItem = useMemo( const sortedItem = filteredItems.sort(sortingFunction);
() => filteredItems.sort(sortingFunction),
[filteredItems, sortingFunction]
);
const groups = useMemo(() => { const groups = (() => {
const memo: Group<T>[] = []; const memo: Group<T>[] = [];
sortedItem.forEach((item) => { sortedItem.forEach((item) => {
@ -116,9 +110,9 @@ export const SmartList = <T,>({
}); });
}); });
return memo.sort(groupSortingFunction); return memo.sort(groupSortingFunction);
}, [groupCountingFunction, groupSortingFunction, groupingFunction, sortedItem]); })();
const pages = useMemo(() => { const pages = (() => {
const memo: Group<T>[][] = []; const memo: Group<T>[][] = [];
let currentPage: Group<T>[] = []; let currentPage: Group<T>[] = [];
let remainingSlots = paginationItemPerPage; let remainingSlots = paginationItemPerPage;
@ -162,7 +156,7 @@ export const SmartList = <T,>({
} }
return memo; return memo;
}, [groups, paginationItemPerPage]); })();
useHotkeys("left", () => setPage((current) => current - 1), { enabled: page > 0 }); useHotkeys("left", () => setPage((current) => current - 1), { enabled: page > 0 });
useHotkeys("right", () => setPage((current) => current + 1), { useHotkeys("right", () => setPage((current) => current + 1), {

View File

@ -84,6 +84,7 @@ export const useSettings = (): void => {
useEffect(() => { useEffect(() => {
if (preferredLanguages.length === 0) { if (preferredLanguages.length === 0) {
if (isDefinedAndNotEmpty(router.locale) && router.locales) { if (isDefinedAndNotEmpty(router.locale) && router.locales) {
console.log(router.locale, getDefaultPreferredLanguages(router.locale, router.locales));
setPreferredLanguages(getDefaultPreferredLanguages(router.locale, router.locales)); setPreferredLanguages(getDefaultPreferredLanguages(router.locale, router.locales));
} }
} else if (router.locale !== preferredLanguages[0]) { } else if (router.locale !== preferredLanguages[0]) {

View File

@ -0,0 +1,18 @@
import { useLayoutEffect } from "react";
import { isDefined } from "helpers/others";
import { useIsWebkit } from "hooks/useIsWebkit";
export const useWebkitFixes = (): void => {
const isWebkit = useIsWebkit();
useLayoutEffect(() => {
const next = document.getElementById("__next");
if (isDefined(next)) {
if (isWebkit) {
next.classList.add("webkit-fixes");
} else {
next.classList.remove("webkit-fixes");
}
}
}, [isWebkit]);
};

View File

@ -1,4 +1,4 @@
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { useIsClient } from "usehooks-ts"; import { useIsClient } from "usehooks-ts";
import { isDefined } from "helpers/others"; import { isDefined } from "helpers/others";
@ -13,7 +13,7 @@ export const useFullscreen = (
const [isFullscreen, setIsFullscreen] = useState(false); const [isFullscreen, setIsFullscreen] = useState(false);
const isClient = useIsClient(); const isClient = useIsClient();
const elem = useMemo(() => (isClient ? document.querySelector(`#${id}`) : null), [id, isClient]); const elem = isClient ? document.querySelector(`#${id}`) : null;
const requestFullscreen = useCallback(() => elem?.requestFullscreen(), [elem]); const requestFullscreen = useCallback(() => elem?.requestFullscreen(), [elem]);
const exitFullscreen = useCallback( const exitFullscreen = useCallback(

View File

@ -1,4 +1,4 @@
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { throttle } from "throttle-debounce"; import { throttle } from "throttle-debounce";
import { useIsClient } from "usehooks-ts"; import { useIsClient } from "usehooks-ts";
import { useOnScroll } from "./useOnScroll"; import { useOnScroll } from "./useOnScroll";
@ -10,10 +10,7 @@ export const useIntersectionList = (ids: string[]): number => {
const isClient = useIsClient(); const isClient = useIsClient();
const contentPanel = useMemo( const contentPanel = isClient ? document.getElementById(Ids.ContentPanel) : null;
() => (isClient ? document.getElementById(Ids.ContentPanel) : null),
[isClient]
);
const refreshCurrentIntersection = useCallback( const refreshCurrentIntersection = useCallback(
(scroll: number) => { (scroll: number) => {

14
src/hooks/useIsWebkit.ts Normal file
View File

@ -0,0 +1,14 @@
import { useMemo } from "react";
import UAParser from "ua-parser-js";
import { useIsClient } from "usehooks-ts";
export const useIsWebkit = (): boolean => {
const isClient = useIsClient();
return useMemo<boolean>(() => {
if (isClient) {
const parser = new UAParser();
return parser.getBrowser().name === "Safari" || parser.getOS().name === "iOS";
}
return false;
}, [isClient]);
};

View File

@ -1,10 +1,10 @@
import { useMemo, useCallback, useEffect } from "react"; import { useCallback, useEffect } from "react";
import { useIsClient } from "usehooks-ts"; import { useIsClient } from "usehooks-ts";
import { Ids } from "types/ids"; import { Ids } from "types/ids";
export const useOnScroll = (id: Ids, onScroll: (scroll: number) => void): void => { export const useOnScroll = (id: Ids, onScroll: (scroll: number) => void): void => {
const isClient = useIsClient(); const isClient = useIsClient();
const elem = useMemo(() => (isClient ? document.querySelector(`#${id}`) : null), [id, isClient]); const elem = isClient ? document.querySelector(`#${id}`) : null;
const listener = useCallback(() => { const listener = useCallback(() => {
if (elem?.scrollTop) { if (elem?.scrollTop) {
onScroll(elem.scrollTop); onScroll(elem.scrollTop);

View File

@ -1,4 +1,4 @@
import { Dispatch, SetStateAction, useCallback, useMemo } from "react"; import { Dispatch, SetStateAction, useCallback } from "react";
import { useLocalStorage } from "usehooks-ts"; import { useLocalStorage } from "usehooks-ts";
import { ImageQuality } from "helpers/img"; import { ImageQuality } from "helpers/img";
@ -94,13 +94,8 @@ export const useReaderSettings = (): {
setTeint, setTeint,
]); ]);
const filterSettings = useMemo(
() => ({ bookFold, lighting, paperTexture, teint, dropShadow }),
[bookFold, dropShadow, lighting, paperTexture, teint]
);
return { return {
filterSettings, filterSettings: { bookFold, lighting, paperTexture, teint, dropShadow },
isSidePagesEnabled, isSidePagesEnabled,
pageQuality, pageQuality,
toggleBookFold, toggleBookFold,

View File

@ -3,17 +3,20 @@ import { useEffect, useState } from "react";
import { useCounter } from "usehooks-ts"; import { useCounter } from "usehooks-ts";
import { isDefined } from "helpers/others"; import { isDefined } from "helpers/others";
const NUM_RETRIES = 10;
export const useScrollIntoView = (): void => { export const useScrollIntoView = (): void => {
const router = useRouter(); const router = useRouter();
const { count, increment } = useCounter(0); const { count, increment } = useCounter(0);
const [hasReachedElem, setHasReachedElem] = useState(false); const [hasReachedElem, setHasReachedElem] = useState(false);
useEffect(() => { useEffect(() => {
if (count < NUM_RETRIES)
if (!hasReachedElem) { if (!hasReachedElem) {
const indexHash = router.asPath.indexOf("#"); const indexHash = router.asPath.indexOf("#");
if (indexHash > 0) { if (indexHash > 0) {
const hash = router.asPath.slice(indexHash + 1); const hash = router.asPath.slice(indexHash + 1);
if (hash !== "") {
const element = document.getElementById(hash); const element = document.getElementById(hash);
console.log(element);
if (isDefined(element)) { if (isDefined(element)) {
console.log(`[useScrollIntoView] ${hash} found`); console.log(`[useScrollIntoView] ${hash} found`);
element.scrollIntoView(); element.scrollIntoView();
@ -22,11 +25,12 @@ export const useScrollIntoView = (): void => {
console.log(`[useScrollIntoView] ${hash} not found`); console.log(`[useScrollIntoView] ${hash} not found`);
setTimeout(() => { setTimeout(() => {
increment(); increment();
}, 100); }, 200);
} }
} }
} }
}, [increment, router.asPath, count, hasReachedElem, setHasReachedElem]); }
}, [router.asPath, hasReachedElem, setHasReachedElem, increment, count]);
useEffect(() => setHasReachedElem(false), [router.asPath]); useEffect(() => setHasReachedElem(false), [router.asPath]);
}; };

View File

@ -36,7 +36,7 @@ export const useSmartLanguage = <T>({
setSelectedTranslationIndex(getPreferredLanguage(preferredLanguages, availableLocales)); setSelectedTranslationIndex(getPreferredLanguage(preferredLanguages, availableLocales));
}, [preferredLanguages, availableLocales, router.locale]); }, [preferredLanguages, availableLocales, router.locale]);
const selectedTranslation = useMemo(() => { const selectedTranslation = (() => {
if (isDefined(selectedTranslationIndex)) { if (isDefined(selectedTranslationIndex)) {
const item = items[selectedTranslationIndex]; const item = items[selectedTranslationIndex];
if (isDefined(item)) { if (isDefined(item)) {
@ -44,7 +44,7 @@ export const useSmartLanguage = <T>({
} }
} }
return undefined; return undefined;
}, [items, selectedTranslationIndex, transform]); })();
const languageSwitcherProps = { const languageSwitcherProps = {
languages: languages, languages: languages,

View File

@ -22,12 +22,14 @@ import { LightBoxProvider } from "contexts/LightBoxProvider";
import { SettingsPopup } from "components/Panels/SettingsPopup"; import { SettingsPopup } from "components/Panels/SettingsPopup";
import { useSettings } from "contexts/settings"; import { useSettings } from "contexts/settings";
import { useContainerQueries } from "contexts/containerQueries"; import { useContainerQueries } from "contexts/containerQueries";
import { useWebkitFixes } from "contexts/webkitFixes";
const AccordsLibraryApp = (props: AppProps): JSX.Element => { const AccordsLibraryApp = (props: AppProps): JSX.Element => {
useLocalData(); useLocalData();
useAppLayout(); useAppLayout();
useSettings(); useSettings();
useContainerQueries(); useContainerQueries();
useWebkitFixes();
return ( return (
<> <>

View File

@ -1,5 +1,4 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useMemo } from "react";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { NavOption } from "components/PanelComponents/NavOption"; import { NavOption } from "components/PanelComponents/NavOption";
import { PanelHeader } from "components/PanelComponents/PanelHeader"; import { PanelHeader } from "components/PanelComponents/PanelHeader";
@ -20,8 +19,7 @@ interface Props extends AppLayoutRequired {}
const Archives = (props: Props): JSX.Element => { const Archives = (props: Props): JSX.Element => {
const langui = useAtomGetter(atoms.localData.langui); const langui = useAtomGetter(atoms.localData.langui);
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<PanelHeader <PanelHeader
icon={Icon.Inventory} icon={Icon.Inventory}
@ -31,9 +29,8 @@ const Archives = (props: Props): JSX.Element => {
<HorizontalLine /> <HorizontalLine />
<NavOption title={"Videos"} url="/archives/videos/" border /> <NavOption title={"Videos"} url="/archives/videos/" border />
</SubPanel> </SubPanel>
),
[langui]
); );
return <AppLayout subPanel={subPanel} {...props} />; return <AppLayout subPanel={subPanel} {...props} />;
}; };
export default Archives; export default Archives;

View File

@ -1,5 +1,5 @@
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { useMemo, useState } from "react"; import { useState } from "react";
import { useBoolean } from "usehooks-ts"; import { useBoolean } from "usehooks-ts";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Switch } from "components/Inputs/Switch"; import { Switch } from "components/Inputs/Switch";
@ -51,8 +51,7 @@ const Channel = ({ channel, ...otherProps }: Props): JSX.Element => {
const [searchName, setSearchName] = useState(DEFAULT_FILTERS_STATE.searchName); const [searchName, setSearchName] = useState(DEFAULT_FILTERS_STATE.searchName);
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<ReturnButton <ReturnButton
href="/archives/videos/" href="/archives/videos/"
@ -82,12 +81,9 @@ const Channel = ({ channel, ...otherProps }: Props): JSX.Element => {
</WithLabel> </WithLabel>
)} )}
</SubPanel> </SubPanel>
),
[hoverable, keepInfoVisible, langui, searchName, toggleKeepInfoVisible]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Full}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<SmartList <SmartList
items={filterHasAttributes(channel?.videos?.data, ["id", "attributes"] as const)} items={filterHasAttributes(channel?.videos?.data, ["id", "attributes"] as const)}
@ -123,8 +119,6 @@ const Channel = ({ channel, ...otherProps }: Props): JSX.Element => {
searchingBy={(item) => item.attributes.title} searchingBy={(item) => item.attributes.title}
/> />
</ContentPanel> </ContentPanel>
),
[channel?.title, channel?.videos?.data, isContentPanelAtLeast4xl, keepInfoVisible, searchName]
); );
return <AppLayout subPanel={subPanel} contentPanel={contentPanel} {...otherProps} />; return <AppLayout subPanel={subPanel} contentPanel={contentPanel} {...otherProps} />;

View File

@ -1,5 +1,5 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useMemo, useState } from "react"; import { useState } from "react";
import { useBoolean } from "usehooks-ts"; import { useBoolean } from "usehooks-ts";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { SmartList } from "components/SmartList"; import { SmartList } from "components/SmartList";
@ -52,8 +52,7 @@ const Videos = ({ videos, ...otherProps }: Props): JSX.Element => {
const [searchName, setSearchName] = useState(DEFAULT_FILTERS_STATE.searchName); const [searchName, setSearchName] = useState(DEFAULT_FILTERS_STATE.searchName);
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<ReturnButton <ReturnButton
href="/archives/" href="/archives/"
@ -79,12 +78,9 @@ const Videos = ({ videos, ...otherProps }: Props): JSX.Element => {
</WithLabel> </WithLabel>
)} )}
</SubPanel> </SubPanel>
),
[hoverable, keepInfoVisible, langui, searchName, toggleKeepInfoVisible]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Full}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<SmartList <SmartList
items={filterHasAttributes(videos, ["id", "attributes"] as const)} items={filterHasAttributes(videos, ["id", "attributes"] as const)}
@ -119,8 +115,6 @@ const Videos = ({ videos, ...otherProps }: Props): JSX.Element => {
searchingBy={(item) => item.attributes.title} searchingBy={(item) => item.attributes.title}
/> />
</ContentPanel> </ContentPanel>
),
[isContentPanelAtLeast4xl, keepInfoVisible, searchName, videos]
); );
return <AppLayout subPanel={subPanel} contentPanel={contentPanel} {...otherProps} />; return <AppLayout subPanel={subPanel} contentPanel={contentPanel} {...otherProps} />;
}; };

View File

@ -1,5 +1,4 @@
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { useMemo } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { HorizontalLine } from "components/HorizontalLine"; import { HorizontalLine } from "components/HorizontalLine";
@ -34,8 +33,7 @@ const Video = ({ video, ...otherProps }: Props): JSX.Element => {
const langui = useAtomGetter(atoms.localData.langui); const langui = useAtomGetter(atoms.localData.langui);
const router = useRouter(); const router = useRouter();
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<ReturnButton <ReturnButton
href="/archives/videos/" href="/archives/videos/"
@ -49,12 +47,9 @@ const Video = ({ video, ...otherProps }: Props): JSX.Element => {
<NavOption title={langui.channel} url="#channel" border /> <NavOption title={langui.channel} url="#channel" border />
<NavOption title={langui.description} url="#description" border /> <NavOption title={langui.description} url="#description" border />
</SubPanel> </SubPanel>
),
[langui]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Full}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<ReturnButton <ReturnButton
href="/library/" href="/library/"
@ -133,21 +128,6 @@ const Video = ({ video, ...otherProps }: Props): JSX.Element => {
</InsetBox> </InsetBox>
</div> </div>
</ContentPanel> </ContentPanel>
),
[
isContentPanelAtLeast4xl,
langui,
router.locale,
video.channel?.data?.attributes,
video.description,
video.gone,
video.likes,
video.published_date,
video.source,
video.title,
video.uid,
video.views,
]
); );
return <AppLayout subPanel={subPanel} contentPanel={contentPanel} {...otherProps} />; return <AppLayout subPanel={subPanel} contentPanel={contentPanel} {...otherProps} />;

View File

@ -67,8 +67,7 @@ const Chronicle = ({ chronicle, chapters, ...otherProps }: Props): JSX.Element =
), ),
}); });
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel> <ContentPanel>
<ReturnButton <ReturnButton
displayOnlyOn={"1ColumnLayout"} displayOnlyOn={"1ColumnLayout"}
@ -85,9 +84,7 @@ const Chronicle = ({ chronicle, chapters, ...otherProps }: Props): JSX.Element =
<LanguageSwitcher {...languageSwitcherProps} /> <LanguageSwitcher {...languageSwitcherProps} />
)} )}
{isDefined(selectedTranslation.body) && ( {isDefined(selectedTranslation.body) && <Markdawn text={selectedTranslation.body.body} />}
<Markdawn text={selectedTranslation.body.body} />
)}
</> </>
) : ( ) : (
<> <>
@ -119,35 +116,16 @@ const Chronicle = ({ chronicle, chapters, ...otherProps }: Props): JSX.Element =
</> </>
)} )}
</ContentPanel> </ContentPanel>
),
[
selectedTranslation,
languageSwitcherProps,
LanguageSwitcher,
selectedContentTranslation,
ContentLanguageSwitcherProps,
ContentLanguageSwitcher,
primaryContent?.categories,
primaryContent?.type,
primaryContent?.thumbnail?.data?.attributes,
langui,
]
); );
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<ReturnButton <ReturnButton displayOnlyOn={"3ColumnsLayout"} href="/chronicles" title={langui.chronicles} />
displayOnlyOn={"3ColumnsLayout"}
href="/chronicles"
title={langui.chronicles}
/>
<HorizontalLine /> <HorizontalLine />
<div className="grid gap-16"> <div className="grid gap-16">
{filterHasAttributes(chapters, ["attributes.chronicles", "id"] as const).map( {filterHasAttributes(chapters, ["attributes.chronicles", "id"] as const).map((chapter) => (
(chapter) => (
<TranslatedChroniclesList <TranslatedChroniclesList
key={chapter.id} key={chapter.id}
chronicles={chapter.attributes.chronicles.data} chronicles={chapter.attributes.chronicles.data}
@ -160,12 +138,9 @@ const Chronicle = ({ chronicle, chapters, ...otherProps }: Props): JSX.Element =
fallback={{ title: prettySlug(chapter.attributes.slug) }} fallback={{ title: prettySlug(chapter.attributes.slug) }}
currentSlug={chronicle.slug} currentSlug={chronicle.slug}
/> />
) ))}
)}
</div> </div>
</SubPanel> </SubPanel>
),
[chapters, chronicle.slug, langui]
); );
return ( return (

View File

@ -1,5 +1,4 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useMemo } from "react";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { PanelHeader } from "components/PanelComponents/PanelHeader"; import { PanelHeader } from "components/PanelComponents/PanelHeader";
import { SubPanel } from "components/Containers/SubPanel"; import { SubPanel } from "components/Containers/SubPanel";
@ -26,8 +25,7 @@ interface Props extends AppLayoutRequired {
const Chronicles = ({ chapters, ...otherProps }: Props): JSX.Element => { const Chronicles = ({ chapters, ...otherProps }: Props): JSX.Element => {
const langui = useAtomGetter(atoms.localData.langui); const langui = useAtomGetter(atoms.localData.langui);
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<PanelHeader <PanelHeader
icon={Icon.WatchLater} icon={Icon.WatchLater}
@ -38,8 +36,7 @@ const Chronicles = ({ chapters, ...otherProps }: Props): JSX.Element => {
<HorizontalLine /> <HorizontalLine />
<div className="grid gap-16"> <div className="grid gap-16">
{filterHasAttributes(chapters, ["attributes.chronicles", "id"] as const).map( {filterHasAttributes(chapters, ["attributes.chronicles", "id"] as const).map((chapter) => (
(chapter) => (
<TranslatedChroniclesList <TranslatedChroniclesList
key={chapter.id} key={chapter.id}
chronicles={chapter.attributes.chronicles.data} chronicles={chapter.attributes.chronicles.data}
@ -51,12 +48,9 @@ const Chronicles = ({ chapters, ...otherProps }: Props): JSX.Element => {
}))} }))}
fallback={{ title: prettySlug(chapter.attributes.slug) }} fallback={{ title: prettySlug(chapter.attributes.slug) }}
/> />
) ))}
)}
</div> </div>
</SubPanel> </SubPanel>
),
[chapters, langui]
); );
return <AppLayout subPanel={subPanel} {...otherProps} />; return <AppLayout subPanel={subPanel} {...otherProps} />;

View File

@ -1,5 +1,5 @@
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { Fragment, useCallback, useMemo } from "react"; import { Fragment, useCallback } from "react";
import naturalCompare from "string-natural-compare"; import naturalCompare from "string-natural-compare";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Chip } from "components/Chip"; import { Chip } from "components/Chip";
@ -62,22 +62,16 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
useScrollTopOnChange(Ids.ContentPanel, [selectedTranslation]); useScrollTopOnChange(Ids.ContentPanel, [selectedTranslation]);
const { previousContent, nextContent } = useMemo( const previousContent =
() => ({
previousContent:
content.folder?.data?.attributes?.contents && content.folder.data.attributes.sequence content.folder?.data?.attributes?.contents && content.folder.data.attributes.sequence
? getPreviousContent(content.folder.data.attributes.contents.data, content.slug) ? getPreviousContent(content.folder.data.attributes.contents.data, content.slug)
: undefined, : undefined;
nextContent: const nextContent =
content.folder?.data?.attributes?.contents && content.folder.data.attributes.sequence content.folder?.data?.attributes?.contents && content.folder.data.attributes.sequence
? getNextContent(content.folder.data.attributes.contents.data, content.slug) ? getNextContent(content.folder.data.attributes.contents.data, content.slug)
: undefined, : undefined;
}),
[content.folder, content.slug]
);
const returnButtonProps = useMemo( const returnButtonProps = {
() => ({
href: content.folder?.data?.attributes href: content.folder?.data?.attributes
? `/contents/folder/${content.folder.data.attributes.slug}` ? `/contents/folder/${content.folder.data.attributes.slug}`
: "/contents", : "/contents",
@ -94,12 +88,9 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
: langui.contents, : langui.contents,
}, },
langui, langui,
}), };
[content.folder?.data?.attributes, langui]
);
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<TranslatedReturnButton {...returnButtonProps} displayOnlyOn="3ColumnsLayout" /> <TranslatedReturnButton {...returnButtonProps} displayOnlyOn="3ColumnsLayout" />
@ -226,9 +217,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
] as const).map((rangedContent) => { ] as const).map((rangedContent) => {
const libraryItem = rangedContent.attributes.library_item.data; const libraryItem = rangedContent.attributes.library_item.data;
return ( return (
<div <div key={libraryItem.attributes.slug} className={cIf(is1ColumnLayout, "w-3/4")}>
key={libraryItem.attributes.slug}
className={cIf(is1ColumnLayout, "w-3/4")}>
<PreviewCard <PreviewCard
href={`/library/${libraryItem.attributes.slug}`} href={`/library/${libraryItem.attributes.slug}`}
title={libraryItem.attributes.title} title={libraryItem.attributes.title}
@ -265,19 +254,9 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
</> </>
)} )}
</SubPanel> </SubPanel>
),
[
content.ranged_contents?.data,
languages,
langui,
returnButtonProps,
selectedTranslation,
is1ColumnLayout,
]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel> <ContentPanel>
<TranslatedReturnButton <TranslatedReturnButton
{...returnButtonProps} {...returnButtonProps}
@ -382,24 +361,6 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
)} )}
</div> </div>
</ContentPanel> </ContentPanel>
),
[
LanguageSwitcher,
content.categories,
content.thumbnail?.data?.attributes,
content.type,
isContentPanelAtLeast2xl,
languageSwitcherProps,
langui,
nextContent?.attributes,
previousContent?.attributes,
returnButtonProps,
selectedTranslation?.description,
selectedTranslation?.pre_title,
selectedTranslation?.subtitle,
selectedTranslation?.text_set?.text,
selectedTranslation?.title,
]
); );
return <AppLayout contentPanel={contentPanel} subPanel={subPanel} {...otherProps} />; return <AppLayout contentPanel={contentPanel} subPanel={subPanel} {...otherProps} />;

View File

@ -1,5 +1,5 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useState, useMemo, useCallback } from "react"; import { useState, useCallback } from "react";
import { useBoolean } from "usehooks-ts"; import { useBoolean } from "usehooks-ts";
import naturalCompare from "string-natural-compare"; import naturalCompare from "string-natural-compare";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
@ -116,8 +116,7 @@ const Contents = ({ contents, ...otherProps }: Props): JSX.Element => {
[searchName] [searchName]
); );
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<PanelHeader <PanelHeader
icon={Icon.Workspaces} icon={Icon.Workspaces}
@ -185,28 +184,9 @@ const Contents = ({ contents, ...otherProps }: Props): JSX.Element => {
}} }}
/> />
</SubPanel> </SubPanel>
),
[
groupingMethod,
hoverable,
keepInfoVisible,
langui.always_show_info,
langui.category,
langui.contents,
langui.contents_description,
langui.group_by,
langui.reset_all_filters,
langui.search_title,
langui.switch_to_folder_view,
langui.type,
searchName,
setKeepInfoVisible,
toggleKeepInfoVisible,
]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Full}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<SmartList <SmartList
items={filterHasAttributes(contents, ["attributes", "id"] as const)} items={filterHasAttributes(contents, ["attributes", "id"] as const)}
@ -264,15 +244,6 @@ const Contents = ({ contents, ...otherProps }: Props): JSX.Element => {
paginationItemPerPage={50} paginationItemPerPage={50}
/> />
</ContentPanel> </ContentPanel>
),
[
isContentPanelAtLeast4xl,
contents,
filteringFunction,
groupingFunction,
keepInfoVisible,
searchName,
]
); );
return ( return (

View File

@ -1,5 +1,4 @@
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { useMemo } from "react";
import naturalCompare from "string-natural-compare"; import naturalCompare from "string-natural-compare";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel"; import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
@ -37,8 +36,7 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen
const langui = useAtomGetter(atoms.localData.langui); const langui = useAtomGetter(atoms.localData.langui);
const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl); const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl);
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<PanelHeader <PanelHeader
icon={Icon.Workspaces} icon={Icon.Workspaces}
@ -50,12 +48,9 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen
<Button href="/contents/all" text={langui.switch_to_grid_view} icon={Icon.Apps} /> <Button href="/contents/all" text={langui.switch_to_grid_view} icon={Icon.Apps} />
</SubPanel> </SubPanel>
),
[langui.contents, langui.contents_description, langui.switch_to_grid_view]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Full}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<div className="mb-10 grid grid-flow-col place-items-center justify-start gap-x-2"> <div className="mb-10 grid grid-flow-col place-items-center justify-start gap-x-2">
{folder.parent_folder?.data?.attributes && ( {folder.parent_folder?.data?.attributes && (
@ -171,16 +166,6 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen
<NoContentNorFolderMessage /> <NoContentNorFolderMessage />
)} )}
</ContentPanel> </ContentPanel>
),
[
folder.contents?.data,
folder.parent_folder?.data?.attributes,
folder.slug,
folder.subfolders?.data,
folder.titles,
isContentPanelAtLeast4xl,
langui,
]
); );
return ( return (

View File

@ -1,5 +1,4 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useMemo } from "react";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Chip } from "components/Chip"; import { Chip } from "components/Chip";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
@ -23,10 +22,9 @@ interface Props extends AppLayoutRequired {
} }
const CheckupContents = ({ contents, ...otherProps }: Props): JSX.Element => { const CheckupContents = ({ contents, ...otherProps }: Props): JSX.Element => {
const testReport = useMemo(() => testingContent(contents), [contents]); const testReport = testingContent(contents);
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Full}> <ContentPanel width={ContentPanelWidthSizes.Full}>
{<h2 className="text-2xl">{testReport.title}</h2>} {<h2 className="text-2xl">{testReport.title}</h2>}
@ -71,8 +69,6 @@ const CheckupContents = ({ contents, ...otherProps }: Props): JSX.Element => {
</div> </div>
))} ))}
</ContentPanel> </ContentPanel>
),
[testReport.lines, testReport.title]
); );
return <AppLayout contentPanel={contentPanel} {...otherProps} />; return <AppLayout contentPanel={contentPanel} {...otherProps} />;

View File

@ -1,5 +1,4 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useMemo } from "react";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Chip } from "components/Chip"; import { Chip } from "components/Chip";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
@ -27,8 +26,7 @@ interface Props extends AppLayoutRequired {
const CheckupLibraryItems = ({ libraryItems, ...otherProps }: Props): JSX.Element => { const CheckupLibraryItems = ({ libraryItems, ...otherProps }: Props): JSX.Element => {
const testReport = testingLibraryItem(libraryItems); const testReport = testingLibraryItem(libraryItems);
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Full}> <ContentPanel width={ContentPanelWidthSizes.Full}>
{<h2 className="text-2xl">{testReport.title}</h2>} {<h2 className="text-2xl">{testReport.title}</h2>}
@ -73,8 +71,6 @@ const CheckupLibraryItems = ({ libraryItems, ...otherProps }: Props): JSX.Elemen
</div> </div>
))} ))}
</ContentPanel> </ContentPanel>
),
[testReport.lines, testReport.title]
); );
return <AppLayout contentPanel={contentPanel} {...otherProps} />; return <AppLayout contentPanel={contentPanel} {...otherProps} />;

View File

@ -1,5 +1,5 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useCallback, useMemo, useRef, useState } from "react"; import { useCallback, useRef, useState } from "react";
import TurndownService from "turndown"; import TurndownService from "turndown";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
@ -156,8 +156,7 @@ const Editor = (props: Props): JSX.Element => {
[transformationWrapper] [transformationWrapper]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Full}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<Popup isVisible={converterOpened} onCloseRequest={() => setConverterOpened(false)}> <Popup isVisible={converterOpened} onCloseRequest={() => setConverterOpened(false)}>
<div className="text-center"> <div className="text-center">
@ -257,8 +256,8 @@ const Editor = (props: Props): JSX.Element => {
<> <>
<h3 className="text-lg">Transcripts</h3> <h3 className="text-lg">Transcripts</h3>
<p> <p>
Use this to create dialogues and transcripts. Start by adding a container, then Use this to create dialogues and transcripts. Start by adding a container, then add
add transcript speech line within. transcript speech line within.
</p> </p>
<div className="grid gap-2"> <div className="grid gap-2">
<ToolTip <ToolTip
@ -327,11 +326,7 @@ const Editor = (props: Props): JSX.Element => {
</p> </p>
</> </>
}> }>
<Button <Button onClick={() => wrap("IntraLink", {})} icon={Icon.Link} text={"Internal"} />
onClick={() => wrap("IntraLink", {})}
icon={Icon.Link}
text={"Internal"}
/>
</ToolTip> </ToolTip>
<ToolTip <ToolTip
placement="right" placement="right"
@ -398,8 +393,6 @@ const Editor = (props: Props): JSX.Element => {
<TableOfContents text={markdown} /> <TableOfContents text={markdown} />
</div> </div>
</ContentPanel> </ContentPanel>
),
[appendDoc, converterOpened, handleInput, insert, markdown, preline, toggleWrap, wrap]
); );
return <AppLayout contentPanel={contentPanel} {...props} />; return <AppLayout contentPanel={contentPanel} {...props} />;

View File

@ -1,5 +1,5 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useCallback, useMemo, useRef, useState } from "react"; import { useCallback, useRef, useState } from "react";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
import { ButtonGroup } from "components/Inputs/ButtonGroup"; import { ButtonGroup } from "components/Inputs/ButtonGroup";
@ -359,8 +359,7 @@ const Transcript = (props: Props): JSX.Element => {
[updateDisplayedText] [updateDisplayedText]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Full} className="overflow-hidden !pr-0 !pt-4"> <ContentPanel width={ContentPanelWidthSizes.Full} className="overflow-hidden !pr-0 !pt-4">
<div className="grid grid-flow-col grid-cols-[1fr_5rem]"> <div className="grid grid-flow-col grid-cols-[1fr_5rem]">
<textarea <textarea
@ -522,20 +521,6 @@ const Transcript = (props: Props): JSX.Element => {
</ToolTip> </ToolTip>
</div> </div>
</ContentPanel> </ContentPanel>
),
[
convertFullWidth,
convertPunctuation,
fontSize,
insert,
lineIndex,
text,
toggleDakuten,
toggleSmallForm,
updateDisplayedText,
updateLineIndex,
xOffset,
]
); );
return <AppLayout contentPanel={contentPanel} {...props} contentPanelScroolbar={false} />; return <AppLayout contentPanel={contentPanel} {...props} contentPanelScroolbar={false} />;

View File

@ -1,4 +1,4 @@
import { Fragment, useCallback, useMemo } from "react"; import { Fragment, useCallback } from "react";
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { useBoolean } from "usehooks-ts"; import { useBoolean } from "usehooks-ts";
@ -88,23 +88,15 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
useScrollTopOnChange(Ids.ContentPanel, [item]); useScrollTopOnChange(Ids.ContentPanel, [item]);
const currentIntersection = useIntersectionList(intersectionIds); const currentIntersection = useIntersectionList(intersectionIds);
const isVariantSet = useMemo( const isVariantSet =
() =>
item.metadata?.[0]?.__typename === "ComponentMetadataGroup" && item.metadata?.[0]?.__typename === "ComponentMetadataGroup" &&
item.metadata[0].subtype?.data?.attributes?.slug === "variant-set", item.metadata[0].subtype?.data?.attributes?.slug === "variant-set";
[item.metadata]
);
const displayOpenScans = useMemo( const displayOpenScans = item.contents?.data.some(
() =>
item.contents?.data.some(
(content) => content.attributes?.scan_set && content.attributes.scan_set.length > 0 (content) => content.attributes?.scan_set && content.attributes.scan_set.length > 0
),
[item.contents?.data]
); );
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<ReturnButton href="/library/" title={langui.library} displayOnlyOn="3ColumnsLayout" /> <ReturnButton href="/library/" title={langui.library} displayOnlyOn="3ColumnsLayout" />
@ -153,12 +145,9 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
)} )}
</div> </div>
</SubPanel> </SubPanel>
),
[currentIntersection, isVariantSet, item.contents, item.gallery, item.subitems, langui]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Full}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<ReturnButton <ReturnButton
href="/library/" href="/library/"
@ -203,9 +192,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
)} )}
<div className="grid place-items-center text-center"> <div className="grid place-items-center text-center">
<h1 className="text-3xl">{item.title}</h1> <h1 className="text-3xl">{item.title}</h1>
{isDefinedAndNotEmpty(item.subtitle) && ( {isDefinedAndNotEmpty(item.subtitle) && <h2 className="text-2xl">{item.subtitle}</h2>}
<h2 className="text-2xl">{item.subtitle}</h2>
)}
</div> </div>
{!isUntangibleGroupItem(item.metadata?.[0]) && isDefinedAndNotEmpty(itemId) && ( {!isUntangibleGroupItem(item.metadata?.[0]) && isDefinedAndNotEmpty(itemId) && (
@ -562,37 +549,6 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
)} )}
</div> </div>
</ContentPanel> </ContentPanel>
),
[
langui,
isContentPanelAtLeast3xl,
item.thumbnail?.data?.attributes,
item.subitem_of?.data,
item.title,
item.subtitle,
item.metadata,
item.descriptions,
item.urls,
item.gallery,
item.release_date,
item.price,
item.categories,
item.size,
item.subitems,
item.contents,
item.slug,
itemId,
router.locale,
currencies,
currency,
isContentPanelAtLeastSm,
isVariantSet,
hoverable,
toggleKeepInfoVisible,
keepInfoVisible,
displayOpenScans,
showLightBox,
]
); );
return <AppLayout contentPanel={contentPanel} subPanel={subPanel} {...otherProps} />; return <AppLayout contentPanel={contentPanel} subPanel={subPanel} {...otherProps} />;

View File

@ -1,5 +1,5 @@
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { Fragment, useCallback, useEffect, useMemo, useState } from "react"; import { Fragment, useCallback, useEffect, useState } from "react";
import { useHotkeys } from "react-hotkeys-hook"; import { useHotkeys } from "react-hotkeys-hook";
import Slider from "rc-slider"; import Slider from "rc-slider";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
@ -44,6 +44,7 @@ import { useFullscreen } from "hooks/useFullscreen";
import { atoms } from "contexts/atoms"; import { atoms } from "contexts/atoms";
import { useAtomGetter } from "helpers/atoms"; import { useAtomGetter } from "helpers/atoms";
import { FilterSettings, useReaderSettings } from "hooks/useReaderSettings"; import { FilterSettings, useReaderSettings } from "hooks/useReaderSettings";
import { useIsWebkit } from "hooks/useIsWebkit";
const CUSTOM_DARK_DROPSHADOW = ` const CUSTOM_DARK_DROPSHADOW = `
drop-shadow(0 0 0.5em rgb(var(--theme-color-shade) / 30%)) drop-shadow(0 0 0.5em rgb(var(--theme-color-shade) / 30%))
@ -112,19 +113,14 @@ const LibrarySlug = ({
is1ColumnLayout ? "single" : "double" is1ColumnLayout ? "single" : "double"
); );
const router = useRouter(); const router = useRouter();
const isWebkit = useIsWebkit();
const { isFullscreen, toggleFullscreen, requestFullscreen } = useFullscreen(Ids.ContentPanel); const { isFullscreen, toggleFullscreen, requestFullscreen } = useFullscreen(Ids.ContentPanel);
const effectiveDisplayMode = useMemo( const effectiveDisplayMode =
() => currentPageIndex === 0 || currentPageIndex === pages.length - 1 ? "single" : displayMode;
currentPageIndex === 0 || currentPageIndex === pages.length - 1 ? "single" : displayMode,
[currentPageIndex, displayMode, pages.length]
);
const ajustedSidepagesTotalWidth = useMemo( const ajustedSidepagesTotalWidth = pages.length * SIDEPAGES_PAGE_WIDTH * (120 / pageWidth);
() => pages.length * SIDEPAGES_PAGE_WIDTH * (120 / pageWidth),
[pageWidth, pages.length]
);
const changeCurrentPageIndex = useCallback( const changeCurrentPageIndex = useCallback(
(callbackFn: (current: number) => number) => { (callbackFn: (current: number) => number) => {
@ -185,61 +181,39 @@ const LibrarySlug = ({
handlePageNavigation, handlePageNavigation,
]); ]);
const firstPage = useMemo( const firstPage =
() =>
pages[ pages[
effectiveDisplayMode === "double" && currentPageIndex % 2 === 0 effectiveDisplayMode === "double" && currentPageIndex % 2 === 0
? currentPageIndex - 1 ? currentPageIndex - 1
: currentPageIndex : currentPageIndex
], ];
[currentPageIndex, effectiveDisplayMode, pages]
); const secondPage =
const secondPage = useMemo(
() =>
pages[ pages[
effectiveDisplayMode === "double" && currentPageIndex % 2 === 0 effectiveDisplayMode === "double" && currentPageIndex % 2 === 0
? currentPageIndex ? currentPageIndex
: currentPageIndex + 1 : currentPageIndex + 1
], ];
[currentPageIndex, effectiveDisplayMode, pages]
);
const leftSidePagesCount = useMemo( const leftSidePagesCount =
() => pageOrder === PageOrder.LeftToRight ? currentPageIndex : pages.length - 1 - currentPageIndex;
pageOrder === PageOrder.LeftToRight ? currentPageIndex : pages.length - 1 - currentPageIndex,
[currentPageIndex, pageOrder, pages.length]
);
const rightSidePagesCount = useMemo( const rightSidePagesCount =
() => pageOrder === PageOrder.LeftToRight ? pages.length - 1 - currentPageIndex : currentPageIndex;
pageOrder === PageOrder.LeftToRight ? pages.length - 1 - currentPageIndex : currentPageIndex,
[currentPageIndex, pageOrder, pages.length]
);
const leftSidePagesWidth = useMemo( const leftSidePagesWidth = `${
() =>
`${
pageOrder === PageOrder.LeftToRight pageOrder === PageOrder.LeftToRight
? (currentPageIndex / pages.length) * ajustedSidepagesTotalWidth ? (currentPageIndex / pages.length) * ajustedSidepagesTotalWidth
: ajustedSidepagesTotalWidth - : ajustedSidepagesTotalWidth - (currentPageIndex / pages.length) * ajustedSidepagesTotalWidth
(currentPageIndex / pages.length) * ajustedSidepagesTotalWidth }vmin`;
}vmin`,
[ajustedSidepagesTotalWidth, currentPageIndex, pageOrder, pages.length]
);
const rightSidePagesWidth = useMemo( const rightSidePagesWidth = `${
() =>
`${
pageOrder === PageOrder.LeftToRight pageOrder === PageOrder.LeftToRight
? ajustedSidepagesTotalWidth - ? ajustedSidepagesTotalWidth - (currentPageIndex / pages.length) * ajustedSidepagesTotalWidth
(currentPageIndex / pages.length) * ajustedSidepagesTotalWidth
: (currentPageIndex / pages.length) * ajustedSidepagesTotalWidth : (currentPageIndex / pages.length) * ajustedSidepagesTotalWidth
}vmin`, }vmin`;
[ajustedSidepagesTotalWidth, currentPageIndex, pageOrder, pages.length]
);
const leftSideClipPath = useMemo( const leftSideClipPath = `polygon(
() => `polygon(
${ ${
isSidePagesEnabled isSidePagesEnabled
? ` ? `
@ -265,12 +239,9 @@ const LibrarySlug = ({
: "101% 0%, 101% 100%," : "101% 0%, 101% 100%,"
} }
70% 100% 70% 100%
)`, )`;
[filterSettings.bookFold, isSidePagesEnabled, leftSidePagesWidth]
);
const rightSideClipPath = useMemo( const rightSideClipPath = `polygon(
() => `polygon(
${ ${
isSidePagesEnabled isSidePagesEnabled
? `calc(100% - ${rightSidePagesWidth}) 0%, ? `calc(100% - ${rightSidePagesWidth}) 0%,
@ -295,17 +266,11 @@ const LibrarySlug = ({
: "-1% 100%, -1% 0%," : "-1% 100%, -1% 0%,"
} }
30% 0% 30% 0%
)`, )`;
[filterSettings.bookFold, isSidePagesEnabled, rightSidePagesWidth]
);
const pageHeight = useMemo( const pageHeight = `calc(100vh - ${is1ColumnLayout ? 5 : 4}rem - 3rem)`;
() => `calc(100vh - ${is1ColumnLayout ? 5 : 4}rem - 3rem)`,
[is1ColumnLayout]
);
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<ReturnButton title={langui.item} href={`/library/${itemSlug}`} /> <ReturnButton title={langui.item} href={`/library/${itemSlug}`} />
@ -326,9 +291,11 @@ const LibrarySlug = ({
<Switch value={isSidePagesEnabled} onClick={toggleIsSidePagesEnabled} /> <Switch value={isSidePagesEnabled} onClick={toggleIsSidePagesEnabled} />
</WithLabel> </WithLabel>
{!isWebkit && (
<WithLabel label={langui.shadow}> <WithLabel label={langui.shadow}>
<Switch value={filterSettings.dropShadow} onClick={toggleDropShadow} /> <Switch value={filterSettings.dropShadow} onClick={toggleDropShadow} />
</WithLabel> </WithLabel>
)}
</div> </div>
<div className="mt-4 grid"> <div className="mt-4 grid">
@ -398,44 +365,9 @@ const LibrarySlug = ({
}} }}
/> />
</SubPanel> </SubPanel>
),
[
langui.item,
langui.paper_texture,
langui.book_fold,
langui.lighting,
langui.side_pages,
langui.shadow,
langui.night_reader,
langui.reading_layout,
langui.single_page_view,
langui.double_page_view,
langui.quality,
langui.reset_all_options,
itemSlug,
filterSettings.paperTexture,
filterSettings.bookFold,
filterSettings.lighting,
filterSettings.dropShadow,
filterSettings.teint,
togglePaperTexture,
toggleBookFold,
toggleLighting,
isSidePagesEnabled,
toggleIsSidePagesEnabled,
toggleDropShadow,
displayMode,
pageQuality,
setTeint,
changeDisplayMode,
setPageQuality,
resetReaderSettings,
is1ColumnLayout,
]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Full} className="grid place-content-center !p-0"> <ContentPanel width={ContentPanelWidthSizes.Full} className="grid place-content-center !p-0">
<div className={cJoin("mb-12 grid", cIf(is1ColumnLayout, "!p-0", "!p-8"))}> <div className={cJoin("mb-12 grid", cIf(is1ColumnLayout, "!p-0", "!p-8"))}>
<TransformWrapper <TransformWrapper
@ -451,11 +383,12 @@ const LibrarySlug = ({
gridAutoFlow: "column", gridAutoFlow: "column",
display: "grid", display: "grid",
placeContent: "center", placeContent: "center",
filter: filterSettings.dropShadow filter:
? isDarkMode !filterSettings.dropShadow || isWebkit
? undefined
: isDarkMode
? CUSTOM_DARK_DROPSHADOW ? CUSTOM_DARK_DROPSHADOW
: CUSTOM_LIGHT_DROPSHADOW : CUSTOM_LIGHT_DROPSHADOW,
: undefined,
}}> }}>
{effectiveDisplayMode === "single" ? ( {effectiveDisplayMode === "single" ? (
<div <div
@ -625,36 +558,6 @@ const LibrarySlug = ({
</div> </div>
</div> </div>
</ContentPanel> </ContentPanel>
),
[
is1ColumnLayout,
currentZoom,
filterSettings,
isDarkMode,
pageHeight,
effectiveDisplayMode,
firstPage,
pageQuality,
bookType,
leftSideClipPath,
isSidePagesEnabled,
leftSidePagesWidth,
leftSidePagesCount,
pageOrder,
secondPage,
rightSideClipPath,
rightSidePagesWidth,
rightSidePagesCount,
isGalleryMode,
currentPageIndex,
pages.length,
isFullscreen,
toggleFullscreen,
item.contents?.data,
item.slug,
handlePageNavigation,
changeCurrentPageIndex,
]
); );
return ( return (
@ -798,9 +701,9 @@ interface PageFiltersProps {
const PageFilters = ({ page, bookType, options }: PageFiltersProps) => { const PageFilters = ({ page, bookType, options }: PageFiltersProps) => {
const isDarkMode = useAtomGetter(atoms.settings.darkMode); const isDarkMode = useAtomGetter(atoms.settings.darkMode);
const commonCss = useMemo( const commonCss = cJoin(
() => cJoin("absolute inset-0", cIf(page === "right", "[background-position-x:-100%]")), "absolute inset-0",
[page] cIf(page === "right", "[background-position-x:-100%]")
); );
return ( return (
@ -929,10 +832,7 @@ const ScanSet = ({ onClickOnImage, scanSet, id, title, content }: ScanSetProps):
}, []), }, []),
}); });
const pages = useMemo( const pages = filterHasAttributes(selectedScan?.pages?.data, ["attributes"]);
() => filterHasAttributes(selectedScan?.pages?.data, ["attributes"]),
[selectedScan]
);
return ( return (
<> <>

View File

@ -1,5 +1,5 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useState, useMemo, useCallback } from "react"; import { useState, useCallback } from "react";
import { useBoolean } from "usehooks-ts"; import { useBoolean } from "usehooks-ts";
import naturalCompare from "string-natural-compare"; import naturalCompare from "string-natural-compare";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
@ -222,8 +222,7 @@ const Library = ({ items, ...otherProps }: Props): JSX.Element => {
[groupingMethod, langui] [groupingMethod, langui]
); );
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<PanelHeader <PanelHeader
icon={Icon.LibraryBooks} icon={Icon.LibraryBooks}
@ -387,31 +386,9 @@ const Library = ({ items, ...otherProps }: Props): JSX.Element => {
}} }}
/> />
</SubPanel> </SubPanel>
),
[
filterUserStatus,
groupingMethod,
hoverable,
keepInfoVisible,
langui,
searchName,
setKeepInfoVisible,
setShowPrimaryItems,
setShowSecondaryItems,
setShowSubitems,
showPrimaryItems,
showSecondaryItems,
showSubitems,
sortingMethod,
toggleKeepInfoVisible,
toggleShowPrimaryItems,
toggleShowSecondaryItems,
toggleShowSubitems,
]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Full}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<SmartList <SmartList
items={filterHasAttributes(items, ["id", "attributes"] as const)} items={filterHasAttributes(items, ["id", "attributes"] as const)}
@ -461,16 +438,6 @@ const Library = ({ items, ...otherProps }: Props): JSX.Element => {
paginationItemPerPage={25} paginationItemPerPage={25}
/> />
</ContentPanel> </ContentPanel>
),
[
filteringFunction,
groupingFunction,
isContentPanelAtLeast4xl,
items,
keepInfoVisible,
searchName,
sortingFunction,
]
); );
return ( return (

View File

@ -1,5 +1,5 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useMemo, useState } from "react"; import { useState } from "react";
import { useBoolean } from "usehooks-ts"; import { useBoolean } from "usehooks-ts";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Switch } from "components/Inputs/Switch"; import { Switch } from "components/Inputs/Switch";
@ -58,8 +58,7 @@ const News = ({ posts, ...otherProps }: Props): JSX.Element => {
} = useBoolean(DEFAULT_FILTERS_STATE.keepInfoVisible); } = useBoolean(DEFAULT_FILTERS_STATE.keepInfoVisible);
const isTerminalMode = useAtomGetter(atoms.layout.terminalMode); const isTerminalMode = useAtomGetter(atoms.layout.terminalMode);
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<PanelHeader icon={Icon.Feed} title={langui.news} description={langui.news_description} /> <PanelHeader icon={Icon.Feed} title={langui.news} description={langui.news_description} />
@ -102,12 +101,9 @@ const News = ({ posts, ...otherProps }: Props): JSX.Element => {
}} }}
/> />
</SubPanel> </SubPanel>
),
[hoverable, keepInfoVisible, langui, searchName, setKeepInfoVisible, toggleKeepInfoVisible]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Full}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<SmartList <SmartList
items={filterHasAttributes(posts, ["attributes", "id"] as const)} items={filterHasAttributes(posts, ["attributes", "id"] as const)}
@ -151,8 +147,6 @@ const News = ({ posts, ...otherProps }: Props): JSX.Element => {
paginationItemPerPage={25} paginationItemPerPage={25}
/> />
</ContentPanel> </ContentPanel>
),
[keepInfoVisible, posts, searchName, isContentPanelAtLeast4xl]
); );
if (isTerminalMode) { if (isTerminalMode) {

View File

@ -1,4 +1,4 @@
import { useCallback, useMemo } from "react"; import { useCallback } from "react";
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
@ -49,17 +49,13 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
}); });
const is3ColumnsLayout = useAtomGetter(atoms.containerQueries.is3ColumnsLayout); const is3ColumnsLayout = useAtomGetter(atoms.containerQueries.is3ColumnsLayout);
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<ReturnButton href={`/wiki`} title={langui.wiki} displayOnlyOn={"3ColumnsLayout"} /> <ReturnButton href={`/wiki`} title={langui.wiki} displayOnlyOn={"3ColumnsLayout"} />
</SubPanel> </SubPanel>
),
[langui]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Large}> <ContentPanel width={ContentPanelWidthSizes.Large}>
<ReturnButton <ReturnButton
href={`/wiki`} href={`/wiki`}
@ -173,22 +169,6 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
</> </>
)} )}
</ContentPanel> </ContentPanel>
),
[
LanguageSwitcher,
is3ColumnsLayout,
languageSwitcherProps,
langui.categories,
langui.summary,
langui.tags,
langui.wiki,
page.categories?.data,
page.definitions,
page.tags?.data,
page.thumbnail?.data?.attributes,
selectedTranslation,
showLightBox,
]
); );
if (isTerminalMode) { if (isTerminalMode) {

View File

@ -1,5 +1,5 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { Fragment, useCallback, useMemo } from "react"; import { Fragment, useCallback } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { InsetBox } from "components/Containers/InsetBox"; import { InsetBox } from "components/Containers/InsetBox";
@ -46,18 +46,13 @@ interface Props extends AppLayoutRequired {
const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props): JSX.Element => { const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props): JSX.Element => {
const langui = useAtomGetter(atoms.localData.langui); const langui = useAtomGetter(atoms.localData.langui);
const ids = useMemo( const ids = filterHasAttributes(chronologyEras, ["attributes"] as const).map(
() =>
filterHasAttributes(chronologyEras, ["attributes"] as const).map(
(era) => era.attributes.slug (era) => era.attributes.slug
),
[chronologyEras]
); );
const currentIntersection = useIntersectionList(ids); const currentIntersection = useIntersectionList(ids);
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<ReturnButton href="/wiki" title={langui.wiki} displayOnlyOn="3ColumnsLayout" /> <ReturnButton href="/wiki" title={langui.wiki} displayOnlyOn="3ColumnsLayout" />
@ -84,12 +79,9 @@ const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props):
</Fragment> </Fragment>
))} ))}
</SubPanel> </SubPanel>
),
[chronologyEras, currentIntersection, langui]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel> <ContentPanel>
<ReturnButton <ReturnButton
href="/wiki" href="/wiki"
@ -118,8 +110,6 @@ const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props):
/> />
))} ))}
</ContentPanel> </ContentPanel>
),
[chronologyEras, chronologyItems, langui]
); );
return <AppLayout contentPanel={contentPanel} subPanel={subPanel} {...otherProps} />; return <AppLayout contentPanel={contentPanel} subPanel={subPanel} {...otherProps} />;
@ -161,7 +151,7 @@ interface ChronologyEraProps {
} }
const ChronologyEra = ({ id, title, description, chronologyItems }: ChronologyEraProps) => { const ChronologyEra = ({ id, title, description, chronologyItems }: ChronologyEraProps) => {
const yearGroups = useMemo(() => { const yearGroups = (() => {
const memo: Props["chronologyItems"][] = []; const memo: Props["chronologyItems"][] = [];
let currentYear = -Infinity; let currentYear = -Infinity;
filterHasAttributes(chronologyItems, ["attributes"] as const).forEach((item) => { filterHasAttributes(chronologyItems, ["attributes"] as const).forEach((item) => {
@ -173,7 +163,7 @@ const ChronologyEra = ({ id, title, description, chronologyItems }: ChronologyEr
} }
}); });
return memo; return memo;
}, [chronologyItems]); })();
return ( return (
<div id={id}> <div id={id}>

View File

@ -1,5 +1,5 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useCallback, useMemo, useState } from "react"; import { useCallback, useState } from "react";
import { useBoolean } from "usehooks-ts"; import { useBoolean } from "usehooks-ts";
import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { NavOption } from "components/PanelComponents/NavOption"; import { NavOption } from "components/PanelComponents/NavOption";
@ -67,8 +67,7 @@ const Wiki = ({ pages, ...otherProps }: Props): JSX.Element => {
setValue: setKeepInfoVisible, setValue: setKeepInfoVisible,
} = useBoolean(DEFAULT_FILTERS_STATE.keepInfoVisible); } = useBoolean(DEFAULT_FILTERS_STATE.keepInfoVisible);
const subPanel = useMemo( const subPanel = (
() => (
<SubPanel> <SubPanel>
<PanelHeader <PanelHeader
icon={Icon.TravelExplore} icon={Icon.TravelExplore}
@ -135,16 +134,6 @@ const Wiki = ({ pages, ...otherProps }: Props): JSX.Element => {
<NavOption title={langui.chronology} url="/wiki/chronology" border /> <NavOption title={langui.chronology} url="/wiki/chronology" border />
</SubPanel> </SubPanel>
),
[
groupingMethod,
hoverable,
keepInfoVisible,
langui,
searchName,
setKeepInfoVisible,
toggleKeepInfoVisible,
]
); );
const groupingFunction = useCallback( const groupingFunction = useCallback(
@ -172,8 +161,7 @@ const Wiki = ({ pages, ...otherProps }: Props): JSX.Element => {
[groupingMethod, langui] [groupingMethod, langui]
); );
const contentPanel = useMemo( const contentPanel = (
() => (
<ContentPanel width={ContentPanelWidthSizes.Full}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<SmartList <SmartList
items={filterHasAttributes(pages, ["id", "attributes"] as const)} items={filterHasAttributes(pages, ["id", "attributes"] as const)}
@ -198,9 +186,7 @@ const Wiki = ({ pages, ...otherProps }: Props): JSX.Element => {
thumbnailRounded thumbnailRounded
thumbnailForceAspectRatio thumbnailForceAspectRatio
keepInfoVisible={keepInfoVisible} keepInfoVisible={keepInfoVisible}
topChips={filterHasAttributes(item.attributes.tags?.data, [ topChips={filterHasAttributes(item.attributes.tags?.data, ["attributes"] as const).map(
"attributes",
] as const).map(
(tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug) (tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug)
)} )}
bottomChips={filterHasAttributes(item.attributes.categories?.data, [ bottomChips={filterHasAttributes(item.attributes.categories?.data, [
@ -228,8 +214,6 @@ const Wiki = ({ pages, ...otherProps }: Props): JSX.Element => {
paginationItemPerPage={25} paginationItemPerPage={25}
/> />
</ContentPanel> </ContentPanel>
),
[groupingFunction, keepInfoVisible, pages, searchName, isContentPanelAtLeast4xl]
); );
if (isTerminalMode) { if (isTerminalMode) {

View File

@ -249,6 +249,21 @@ module.exports = {
}); });
}), }),
/* Webkit fixes */
plugin(({ addUtilities }) => {
addUtilities({
".webkit-fixes": {
"*": {
"--tw-drop-shadow": "unset !important",
"--tw-shadow": "unset !important",
},
".texture-paper-dots": {
backgroundImage: "unset !important",
},
},
});
}),
/* Add support for break-wrods CSS attribute */ /* Add support for break-wrods CSS attribute */
plugin(({ addUtilities }) => { plugin(({ addUtilities }) => {
addUtilities({ addUtilities({