Fixed key problems + search function
This commit is contained in:
parent
50e988f64f
commit
fa96469ebf
|
@ -46,11 +46,13 @@ export function AppLayout(props: Immutable<Props>): JSX.Element {
|
|||
const sensibilitySwipe = 1.1;
|
||||
|
||||
useMemo(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
router.events?.on("routeChangeStart", () => {
|
||||
appLayout.setConfigPanelOpen(false);
|
||||
appLayout.setMainPanelOpen(false);
|
||||
appLayout.setSubPanelOpen(false);
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
router.events?.on("hashChangeStart", () => {
|
||||
appLayout.setSubPanelOpen(false);
|
||||
});
|
||||
|
@ -425,7 +427,9 @@ export function AppLayout(props: Immutable<Props>): JSX.Element {
|
|||
)
|
||||
}
|
||||
>
|
||||
<span className="material-icons !text-base">text_decrease</span>
|
||||
<span className="material-icons !text-base">
|
||||
text_decrease
|
||||
</span>
|
||||
</Button>
|
||||
<Button
|
||||
className="rounded-l-none rounded-r-none border-x-0"
|
||||
|
@ -449,7 +453,9 @@ export function AppLayout(props: Immutable<Props>): JSX.Element {
|
|||
)
|
||||
}
|
||||
>
|
||||
<span className="material-icons !text-base">text_increase</span>
|
||||
<span className="material-icons !text-base">
|
||||
text_increase
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { AppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { prettyLanguage } from "helpers/formatters";
|
||||
import { Immutable } from "helpers/types";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
import { Dispatch, Fragment, SetStateAction } from "react";
|
||||
import { ToolTip } from "../ToolTip";
|
||||
import { Button } from "./Button";
|
||||
|
||||
|
@ -21,17 +21,16 @@ export function LanguageSwitcher(props: Immutable<Props>): JSX.Element {
|
|||
content={
|
||||
<div className={`flex flex-col gap-2 ${className}`}>
|
||||
{[...locales].map(([locale, value], index) => (
|
||||
<>
|
||||
<Fragment key={index}>
|
||||
{locale && (
|
||||
<Button
|
||||
key={index}
|
||||
active={value === localesIndex}
|
||||
onClick={() => setLocalesIndex(value)}
|
||||
>
|
||||
{prettyLanguage(locale, props.languages)}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { arrayMove } from "helpers/others";
|
||||
import { Immutable } from "helpers/types";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Fragment, useEffect, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
|
@ -25,7 +25,7 @@ export function OrderableList(props: Immutable<Props>): JSX.Element {
|
|||
return (
|
||||
<div className="grid gap-2">
|
||||
{[...items].map(([key, value], index) => (
|
||||
<>
|
||||
<Fragment key={key}>
|
||||
{props.insertLabels?.get(index) && (
|
||||
<p>{props.insertLabels.get(index)}</p>
|
||||
)}
|
||||
|
@ -60,7 +60,6 @@ export function OrderableList(props: Immutable<Props>): JSX.Element {
|
|||
border-[1px] transition-all hover:text-light hover:bg-dark
|
||||
hover:drop-shadow-shade-lg border-dark bg-light text-dark
|
||||
rounded-full cursor-grab select-none px-1 py-2 pr-4 gap-2"
|
||||
key={key}
|
||||
draggable
|
||||
>
|
||||
<div className="grid grid-rows-[.8em_.8em] place-items-center">
|
||||
|
@ -87,7 +86,7 @@ export function OrderableList(props: Immutable<Props>): JSX.Element {
|
|||
</div>
|
||||
{value}
|
||||
</div>
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Immutable } from "helpers/types";
|
||||
import { Dispatch, SetStateAction, useState } from "react";
|
||||
import { Dispatch, Fragment, SetStateAction, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
setState: Dispatch<SetStateAction<number>>;
|
||||
|
@ -47,12 +47,12 @@ export function Select(props: Immutable<Props>): JSX.Element {
|
|||
}`}
|
||||
>
|
||||
{props.options.map((option, index) => (
|
||||
<>
|
||||
<Fragment key={index}>
|
||||
{index !== props.state && (
|
||||
<div
|
||||
className="bg-light hover:bg-mid transition-colors
|
||||
cursor-pointer p-1 last-of-type:rounded-b-[1em]"
|
||||
key={index}
|
||||
|
||||
id={option}
|
||||
onClick={() => {
|
||||
setOpened(false);
|
||||
|
@ -62,7 +62,7 @@ export function Select(props: Immutable<Props>): JSX.Element {
|
|||
{option}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,23 +5,25 @@ interface Props {
|
|||
setState: Dispatch<SetStateAction<boolean>>;
|
||||
state: boolean;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export function Switch(props: Immutable<Props>): JSX.Element {
|
||||
const { state, setState, className, disabled } = props;
|
||||
return (
|
||||
<div
|
||||
className={`h-6 w-12 rounded-full border-2 border-mid grid
|
||||
transition-colors relative cursor-pointer ${props.className} ${
|
||||
props.state ? "bg-mid" : "bg-light"
|
||||
}`}
|
||||
transition-colors relative ${
|
||||
disabled ? "cursor-not-allowed" : "cursor-pointer"
|
||||
} ${className} ${state ? "bg-mid" : "bg-light"}`}
|
||||
onClick={() => {
|
||||
props.setState(!props.state);
|
||||
if (!disabled) setState(!state);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={`bg-dark aspect-square rounded-full absolute
|
||||
top-0 bottom-0 left-0 transition-transform ${
|
||||
props.state && "translate-x-[115%]"
|
||||
state && "translate-x-[115%]"
|
||||
}`}
|
||||
></div>
|
||||
</div>
|
||||
|
|
|
@ -10,6 +10,7 @@ import { isInteger } from "helpers/numbers";
|
|||
import { getStatusDescription } from "helpers/others";
|
||||
import { Immutable } from "helpers/types";
|
||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||
import { Fragment } from "react";
|
||||
|
||||
interface Props {
|
||||
openLightBox: (images: string[], index?: number) => void;
|
||||
|
@ -121,15 +122,14 @@ export function ScanSet(props: Immutable<Props>): JSX.Element {
|
|||
<p className="font-headers">{"Scanners"}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{selectedScan.scanners.data.map((scanner) => (
|
||||
<>
|
||||
<Fragment key={scanner.id}>
|
||||
{scanner.attributes && (
|
||||
<RecorderChip
|
||||
key={scanner.id}
|
||||
langui={langui}
|
||||
recorder={scanner.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -140,15 +140,14 @@ export function ScanSet(props: Immutable<Props>): JSX.Element {
|
|||
<p className="font-headers">{"Cleaners"}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{selectedScan.cleaners.data.map((cleaner) => (
|
||||
<>
|
||||
<Fragment key={cleaner.id}>
|
||||
{cleaner.attributes && (
|
||||
<RecorderChip
|
||||
key={cleaner.id}
|
||||
langui={langui}
|
||||
recorder={cleaner.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -160,15 +159,14 @@ export function ScanSet(props: Immutable<Props>): JSX.Element {
|
|||
<p className="font-headers">{"Typesetters"}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{selectedScan.typesetters.data.map((typesetter) => (
|
||||
<>
|
||||
<Fragment key={typesetter.id}>
|
||||
{typesetter.attributes && (
|
||||
<RecorderChip
|
||||
key={typesetter.id}
|
||||
langui={langui}
|
||||
recorder={typesetter.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -11,6 +11,7 @@ import { getAssetURL, ImageQuality } from "helpers/img";
|
|||
import { getStatusDescription } from "helpers/others";
|
||||
import { Immutable } from "helpers/types";
|
||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||
import { Fragment } from "react";
|
||||
|
||||
interface Props {
|
||||
openLightBox: (images: string[], index?: number) => void;
|
||||
|
@ -87,15 +88,14 @@ export function ScanSetCover(props: Immutable<Props>): JSX.Element {
|
|||
<p className="font-headers">{"Scanners"}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{selectedScan.scanners.data.map((scanner) => (
|
||||
<>
|
||||
<Fragment key={scanner.id}>
|
||||
{scanner.attributes && (
|
||||
<RecorderChip
|
||||
key={scanner.id}
|
||||
langui={langui}
|
||||
recorder={scanner.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -106,15 +106,14 @@ export function ScanSetCover(props: Immutable<Props>): JSX.Element {
|
|||
<p className="font-headers">{"Cleaners"}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{selectedScan.cleaners.data.map((cleaner) => (
|
||||
<>
|
||||
<Fragment key={cleaner.id}>
|
||||
{cleaner.attributes && (
|
||||
<RecorderChip
|
||||
key={cleaner.id}
|
||||
langui={langui}
|
||||
recorder={cleaner.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -126,15 +125,14 @@ export function ScanSetCover(props: Immutable<Props>): JSX.Element {
|
|||
<p className="font-headers">{"Typesetters"}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{selectedScan.typesetters.data.map((typesetter) => (
|
||||
<>
|
||||
<Fragment key={typesetter.id}>
|
||||
{typesetter.attributes && (
|
||||
<RecorderChip
|
||||
key={typesetter.id}
|
||||
langui={langui}
|
||||
recorder={typesetter.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { slugify } from "helpers/formatters";
|
||||
import { Immutable } from "helpers/types";
|
||||
import { useRouter } from "next/router";
|
||||
import { Fragment } from "react";
|
||||
import { preprocessMarkDawn } from "./Markdawn";
|
||||
|
||||
interface Props {
|
||||
|
@ -39,11 +40,8 @@ function TOCLevel(props: LevelProps): JSX.Element {
|
|||
return (
|
||||
<ol className="pl-4 text-left">
|
||||
{tocchildren.map((child, childIndex) => (
|
||||
<>
|
||||
<li
|
||||
key={child.slug}
|
||||
className="my-2 overflow-x-hidden w-full text-ellipsis whitespace-nowrap"
|
||||
>
|
||||
<Fragment key={child.slug}>
|
||||
<li className="my-2 overflow-x-hidden w-full text-ellipsis whitespace-nowrap">
|
||||
<span className="text-dark">{`${parentNumbering}${
|
||||
childIndex + 1
|
||||
}.`}</span>{" "}
|
||||
|
@ -55,7 +53,7 @@ function TOCLevel(props: LevelProps): JSX.Element {
|
|||
tocchildren={child.children}
|
||||
parentNumbering={`${parentNumbering}${childIndex + 1}.`}
|
||||
/>
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</ol>
|
||||
);
|
||||
|
|
|
@ -3,6 +3,7 @@ import { prettySlug } from "helpers/formatters";
|
|||
import { getStatusDescription } from "helpers/others";
|
||||
import { Immutable, PostWithTranslations } from "helpers/types";
|
||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||
import { Fragment } from "react";
|
||||
import { AppLayout } from "./AppLayout";
|
||||
import { Chip } from "./Chip";
|
||||
import { HorizontalLine } from "./HorizontalLine";
|
||||
|
@ -97,15 +98,14 @@ export function PostPage(props: Immutable<Props>): JSX.Element {
|
|||
<p className="font-headers">{"Authors"}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{post.authors.data.map((author) => (
|
||||
<>
|
||||
<Fragment key={author.id}>
|
||||
{author.attributes && (
|
||||
<RecorderChip
|
||||
key={author.id}
|
||||
langui={langui}
|
||||
recorder={author.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,6 +3,7 @@ import { RecorderChipFragment } from "graphql/generated";
|
|||
import { AppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { ImageQuality } from "helpers/img";
|
||||
import { Immutable } from "helpers/types";
|
||||
import { Fragment } from "react";
|
||||
import { Img } from "./Img";
|
||||
import { Markdawn } from "./Markdown/Markdawn";
|
||||
import { ToolTip } from "./ToolTip";
|
||||
|
@ -33,13 +34,11 @@ export function RecorderChip(props: Immutable<Props>): JSX.Element {
|
|||
<div className="flex flex-row flex-wrap gap-1">
|
||||
<p>{langui.languages}:</p>
|
||||
{recorder.languages.data.map((language) => (
|
||||
<>
|
||||
<Fragment key={language.attributes?.code}>
|
||||
{language.attributes && (
|
||||
<Chip key={language.attributes.code}>
|
||||
{language.attributes.code.toUpperCase()}
|
||||
</Chip>
|
||||
<Chip>{language.attributes.code.toUpperCase()}</Chip>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
import { AppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { getStatusDescription } from "helpers/others";
|
||||
import { Immutable } from "helpers/types";
|
||||
import { Fragment } from "react";
|
||||
|
||||
interface Props {
|
||||
item: NonNullable<GetChronologyItemsQuery["chronologyItems"]>["data"][number];
|
||||
|
@ -92,13 +93,13 @@ export function ChronologyItemComponent(props: Immutable<Props>): JSX.Element {
|
|||
|
||||
<div className="col-start-2 row-start-1 row-span-2 grid gap-4">
|
||||
{props.item.attributes.events?.map((event) => (
|
||||
<>
|
||||
<Fragment key={event?.id}>
|
||||
{event && (
|
||||
<div className="m-0" key={event.id}>
|
||||
{event.translations?.map((translation) => (
|
||||
<>
|
||||
<div className="m-0">
|
||||
{event.translations?.map((translation, translationIndex) => (
|
||||
<Fragment key={translationIndex}>
|
||||
{translation && (
|
||||
<>
|
||||
<Fragment>
|
||||
<div
|
||||
className="place-items-start
|
||||
place-content-start grid grid-flow-col gap-2"
|
||||
|
@ -140,9 +141,9 @@ export function ChronologyItemComponent(props: Immutable<Props>): JSX.Element {
|
|||
) : (
|
||||
""
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
|
||||
<p className="text-dark text-xs grid place-self-start grid-flow-col gap-1 mt-1">
|
||||
|
@ -157,7 +158,7 @@ export function ChronologyItemComponent(props: Immutable<Props>): JSX.Element {
|
|||
</p>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
GetStaticPathsResult,
|
||||
GetStaticPropsContext,
|
||||
} from "next";
|
||||
import { useState } from "react";
|
||||
import { Fragment, useState } from "react";
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
channel: NonNullable<
|
||||
|
@ -67,10 +67,9 @@ export default function Channel(props: Props): JSX.Element {
|
|||
pb-12 border-b-[3px] border-dotted last-of-type:border-0"
|
||||
>
|
||||
{channel?.videos?.data.map((video) => (
|
||||
<>
|
||||
<Fragment key={video.id}>
|
||||
{video.attributes && (
|
||||
<PreviewCard
|
||||
key={video.id}
|
||||
href={`/archives/videos/v/${video.attributes.uid}`}
|
||||
title={video.attributes.title}
|
||||
thumbnail={getVideoThumbnailURL(video.attributes.uid)}
|
||||
|
@ -88,7 +87,7 @@ export default function Channel(props: Props): JSX.Element {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</ContentPanel>
|
||||
|
|
|
@ -18,7 +18,7 @@ import { getReadySdk } from "graphql/sdk";
|
|||
import { prettyDate } from "helpers/formatters";
|
||||
import { getVideoThumbnailURL } from "helpers/videos";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
import { useState } from "react";
|
||||
import { Fragment, useState } from "react";
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
videos: NonNullable<GetVideosPreviewQuery["videos"]>["data"];
|
||||
|
@ -88,10 +88,9 @@ export default function Videos(props: Props): JSX.Element {
|
|||
pb-12 border-b-[3px] border-dotted last-of-type:border-0"
|
||||
>
|
||||
{paginatedVideos[page].map((video) => (
|
||||
<>
|
||||
<Fragment key={video.id}>
|
||||
{video.attributes && (
|
||||
<PreviewCard
|
||||
key={video.id}
|
||||
href={`/archives/videos/v/${video.attributes.uid}`}
|
||||
title={video.attributes.title}
|
||||
thumbnail={getVideoThumbnailURL(video.attributes.uid)}
|
||||
|
@ -109,7 +108,7 @@ export default function Videos(props: Props): JSX.Element {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import {
|
|||
GetStaticPathsResult,
|
||||
GetStaticPropsContext,
|
||||
} from "next";
|
||||
import { Fragment } from "react";
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
content: ContentWithTranslations;
|
||||
|
@ -116,15 +117,14 @@ export default function Content(props: Immutable<Props>): JSX.Element {
|
|||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{selectedTranslation.text_set.transcribers.data.map(
|
||||
(recorder) => (
|
||||
<>
|
||||
<Fragment key={recorder.id}>
|
||||
{recorder.attributes && (
|
||||
<RecorderChip
|
||||
key={recorder.id}
|
||||
langui={langui}
|
||||
recorder={recorder.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
|
@ -138,15 +138,14 @@ export default function Content(props: Immutable<Props>): JSX.Element {
|
|||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{selectedTranslation.text_set.translators.data.map(
|
||||
(recorder) => (
|
||||
<>
|
||||
<Fragment key={recorder.id}>
|
||||
{recorder.attributes && (
|
||||
<RecorderChip
|
||||
key={recorder.id}
|
||||
langui={langui}
|
||||
recorder={recorder.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
|
@ -160,15 +159,14 @@ export default function Content(props: Immutable<Props>): JSX.Element {
|
|||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{selectedTranslation.text_set.proofreaders.data.map(
|
||||
(recorder) => (
|
||||
<>
|
||||
<Fragment key={recorder.id}>
|
||||
{recorder.attributes && (
|
||||
<RecorderChip
|
||||
key={recorder.id}
|
||||
langui={langui}
|
||||
recorder={recorder.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -15,7 +15,7 @@ import { getReadySdk } from "graphql/sdk";
|
|||
import { prettyinlineTitle, prettySlug } from "helpers/formatters";
|
||||
import { Immutable } from "helpers/types";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Fragment, useEffect, useState } from "react";
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
contents: NonNullable<GetContentsQuery["contents"]>["data"];
|
||||
|
@ -30,9 +30,12 @@ export default function Contents(props: Immutable<Props>): JSX.Element {
|
|||
const [keepInfoVisible, setKeepInfoVisible] = useState(false);
|
||||
|
||||
const [combineRelatedContent, setCombineRelatedContent] = useState(true);
|
||||
const [effectiveCombineRelatedContent, setEffectiveCombineRelatedContent] =
|
||||
useState(true);
|
||||
const [searchName, setSearchName] = useState("");
|
||||
|
||||
const [filteredItems, setFilteredItems] = useState(
|
||||
filterContents(combineRelatedContent, contents)
|
||||
filterContents(contents, combineRelatedContent, searchName)
|
||||
);
|
||||
|
||||
const [groups, setGroups] = useState<GroupContentItems>(
|
||||
|
@ -40,8 +43,20 @@ export default function Contents(props: Immutable<Props>): JSX.Element {
|
|||
);
|
||||
|
||||
useEffect(() => {
|
||||
setFilteredItems(filterContents(combineRelatedContent, contents));
|
||||
}, [combineRelatedContent, contents]);
|
||||
if (searchName.length > 1) {
|
||||
setEffectiveCombineRelatedContent(false);
|
||||
} else {
|
||||
setEffectiveCombineRelatedContent(combineRelatedContent);
|
||||
}
|
||||
setFilteredItems(
|
||||
filterContents(contents, effectiveCombineRelatedContent, searchName)
|
||||
);
|
||||
}, [
|
||||
effectiveCombineRelatedContent,
|
||||
contents,
|
||||
searchName,
|
||||
combineRelatedContent,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
setGroups(getGroups(langui, groupingMethod, filteredItems));
|
||||
|
@ -55,6 +70,18 @@ export default function Contents(props: Immutable<Props>): JSX.Element {
|
|||
description={langui.contents_description}
|
||||
/>
|
||||
|
||||
<input
|
||||
className="w-full mb-6"
|
||||
type="text"
|
||||
name="name"
|
||||
id="name"
|
||||
placeholder="Search title..."
|
||||
onChange={(event) => {
|
||||
const input = event.target as HTMLInputElement;
|
||||
setSearchName(input.value);
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="flex flex-row gap-2 place-items-center">
|
||||
<p className="flex-shrink-0">{langui.group_by}:</p>
|
||||
<Select
|
||||
|
@ -66,11 +93,18 @@ export default function Contents(props: Immutable<Props>): JSX.Element {
|
|||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row gap-2 place-items-center coarse:hidden">
|
||||
<div
|
||||
className={`flex flex-row gap-2 place-items-center coarse:hidden ${
|
||||
searchName.length > 1
|
||||
? "text-dark grayscale contrast-75 brightness-150"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<p className="flex-shrink-0">{langui.combine_related_contents}:</p>
|
||||
<Switch
|
||||
setState={setCombineRelatedContent}
|
||||
state={combineRelatedContent}
|
||||
disabled={searchName.length > 1}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -83,9 +117,9 @@ export default function Contents(props: Immutable<Props>): JSX.Element {
|
|||
const contentPanel = (
|
||||
<ContentPanel width={ContentPanelWidthSizes.large}>
|
||||
{[...groups].map(([name, items]) => (
|
||||
<>
|
||||
<Fragment key={name}>
|
||||
{items.length > 0 && (
|
||||
<>
|
||||
<Fragment>
|
||||
{name && (
|
||||
<h2
|
||||
key={`h2${name}`}
|
||||
|
@ -94,7 +128,7 @@ export default function Contents(props: Immutable<Props>): JSX.Element {
|
|||
>
|
||||
{name}
|
||||
<Chip>{`${items.reduce((currentSum, item) => {
|
||||
if (combineRelatedContent) {
|
||||
if (effectiveCombineRelatedContent) {
|
||||
if (item.attributes?.group?.data?.attributes?.combine) {
|
||||
return (
|
||||
currentSum +
|
||||
|
@ -117,10 +151,9 @@ export default function Contents(props: Immutable<Props>): JSX.Element {
|
|||
desktop:grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))]"
|
||||
>
|
||||
{items.map((item) => (
|
||||
<>
|
||||
<Fragment key={item.id}>
|
||||
{item.attributes && (
|
||||
<PreviewCard
|
||||
key={item.id}
|
||||
href={`/contents/${item.attributes.slug}`}
|
||||
pre_title={item.attributes.translations?.[0]?.pre_title}
|
||||
title={
|
||||
|
@ -131,7 +164,7 @@ export default function Contents(props: Immutable<Props>): JSX.Element {
|
|||
thumbnail={item.attributes.thumbnail?.data?.attributes}
|
||||
thumbnailAspectRatio="3/2"
|
||||
stackNumber={
|
||||
combineRelatedContent &&
|
||||
effectiveCombineRelatedContent &&
|
||||
item.attributes.group?.data?.attributes?.combine
|
||||
? item.attributes.group.data.attributes.contents
|
||||
?.data.length
|
||||
|
@ -155,12 +188,12 @@ export default function Contents(props: Immutable<Props>): JSX.Element {
|
|||
keepInfoVisible={keepInfoVisible}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
</Fragment>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</ContentPanel>
|
||||
);
|
||||
|
@ -271,17 +304,33 @@ function getGroups(
|
|||
}
|
||||
|
||||
function filterContents(
|
||||
contents: Immutable<Props["contents"]>,
|
||||
combineRelatedContent: boolean,
|
||||
contents: Immutable<Props["contents"]>
|
||||
searchName: string
|
||||
): Immutable<Props["contents"]> {
|
||||
if (combineRelatedContent) {
|
||||
return [...contents].filter(
|
||||
(content) =>
|
||||
!content.attributes?.group?.data?.attributes ||
|
||||
!content.attributes.group.data.attributes.combine ||
|
||||
content.attributes.group.data.attributes.contents?.data[0].id ===
|
||||
return contents.filter((content) => {
|
||||
if (
|
||||
combineRelatedContent &&
|
||||
content.attributes?.group?.data?.attributes?.combine &&
|
||||
content.attributes.group.data.attributes.contents?.data[0].id !==
|
||||
content.id
|
||||
);
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return contents;
|
||||
if (searchName.length > 1) {
|
||||
if (
|
||||
prettyinlineTitle(
|
||||
content.attributes?.translations?.[0]?.pre_title,
|
||||
content.attributes?.translations?.[0]?.title,
|
||||
content.attributes?.translations?.[0]?.subtitle
|
||||
)
|
||||
.toLowerCase()
|
||||
.includes(searchName.toLowerCase())
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ import {
|
|||
GetStaticPathsResult,
|
||||
GetStaticPropsContext,
|
||||
} from "next";
|
||||
import { useState } from "react";
|
||||
import { Fragment, useState } from "react";
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
item: NonNullable<
|
||||
|
@ -185,18 +185,14 @@ export default function LibrarySlug(props: Immutable<Props>): JSX.Element {
|
|||
{item?.urls && item.urls.length ? (
|
||||
<div className="flex flex-row place-items-center gap-3">
|
||||
<p>{langui.available_at}</p>
|
||||
{item.urls.map((url) => (
|
||||
<>
|
||||
{item.urls.map((url, index) => (
|
||||
<Fragment key={index}>
|
||||
{url?.url && (
|
||||
<Button
|
||||
href={url.url}
|
||||
key={url.url}
|
||||
target={"_blank"}
|
||||
>
|
||||
<Button href={url.url} target={"_blank"}>
|
||||
{prettyURL(url.url)}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
|
@ -215,10 +211,9 @@ export default function LibrarySlug(props: Immutable<Props>): JSX.Element {
|
|||
grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))]"
|
||||
>
|
||||
{item.gallery.data.map((galleryItem, index) => (
|
||||
<>
|
||||
<Fragment key={galleryItem.id}>
|
||||
{galleryItem.attributes && (
|
||||
<div
|
||||
key={galleryItem.id}
|
||||
className="relative aspect-square hover:scale-[1.02]
|
||||
transition-transform cursor-pointer"
|
||||
onClick={() => {
|
||||
|
@ -244,7 +239,7 @@ export default function LibrarySlug(props: Immutable<Props>): JSX.Element {
|
|||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -405,10 +400,9 @@ export default function LibrarySlug(props: Immutable<Props>): JSX.Element {
|
|||
grid-cols-[repeat(auto-fill,minmax(15rem,1fr))] w-full"
|
||||
>
|
||||
{item.subitems.data.map((subitem) => (
|
||||
<>
|
||||
<Fragment key={subitem.id}>
|
||||
{subitem.attributes && (
|
||||
<PreviewCard
|
||||
key={subitem.id}
|
||||
href={`/library/${subitem.attributes.slug}`}
|
||||
title={subitem.attributes.title}
|
||||
subtitle={subitem.attributes.subtitle}
|
||||
|
@ -433,7 +427,7 @@ export default function LibrarySlug(props: Immutable<Props>): JSX.Element {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -23,6 +23,7 @@ import {
|
|||
GetStaticPathsResult,
|
||||
GetStaticPropsContext,
|
||||
} from "next";
|
||||
import { Fragment } from "react";
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
item: NonNullable<
|
||||
|
@ -89,10 +90,9 @@ export default function LibrarySlug(props: Immutable<Props>): JSX.Element {
|
|||
)}
|
||||
|
||||
{item?.contents?.data.map((content) => (
|
||||
<>
|
||||
<Fragment key={content.id}>
|
||||
{content.attributes?.scan_set?.[0] && (
|
||||
<ScanSet
|
||||
key={content.id}
|
||||
scanSet={content.attributes.scan_set}
|
||||
openLightBox={openLightBox}
|
||||
slug={content.attributes.slug}
|
||||
|
@ -102,7 +102,7 @@ export default function LibrarySlug(props: Immutable<Props>): JSX.Element {
|
|||
content={content.attributes.content}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</ContentPanel>
|
||||
);
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
import { convertPrice } from "helpers/numbers";
|
||||
import { Immutable } from "helpers/types";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Fragment, useEffect, useState } from "react";
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
items: NonNullable<GetLibraryItemsPreviewQuery["libraryItems"]>["data"];
|
||||
|
@ -31,6 +31,7 @@ type GroupLibraryItems = Map<string, Immutable<Props["items"]>>;
|
|||
export default function Library(props: Immutable<Props>): JSX.Element {
|
||||
const { langui, items: libraryItems, currencies } = props;
|
||||
|
||||
const [searchName, setSearchName] = useState("");
|
||||
const [showSubitems, setShowSubitems] = useState<boolean>(false);
|
||||
const [showPrimaryItems, setShowPrimaryItems] = useState<boolean>(true);
|
||||
const [showSecondaryItems, setShowSecondaryItems] = useState<boolean>(false);
|
||||
|
@ -40,10 +41,11 @@ export default function Library(props: Immutable<Props>): JSX.Element {
|
|||
|
||||
const [filteredItems, setFilteredItems] = useState(
|
||||
filterItems(
|
||||
libraryItems,
|
||||
searchName,
|
||||
showSubitems,
|
||||
showPrimaryItems,
|
||||
showSecondaryItems,
|
||||
libraryItems
|
||||
showSecondaryItems
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -58,13 +60,20 @@ export default function Library(props: Immutable<Props>): JSX.Element {
|
|||
useEffect(() => {
|
||||
setFilteredItems(
|
||||
filterItems(
|
||||
libraryItems,
|
||||
searchName,
|
||||
showSubitems,
|
||||
showPrimaryItems,
|
||||
showSecondaryItems,
|
||||
libraryItems
|
||||
showSecondaryItems
|
||||
)
|
||||
);
|
||||
}, [showSubitems, libraryItems, showPrimaryItems, showSecondaryItems]);
|
||||
}, [
|
||||
showSubitems,
|
||||
libraryItems,
|
||||
showPrimaryItems,
|
||||
showSecondaryItems,
|
||||
searchName,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
setSortedItem(sortBy(sortingMethod, filteredItems, currencies));
|
||||
|
@ -82,6 +91,18 @@ export default function Library(props: Immutable<Props>): JSX.Element {
|
|||
description={langui.library_description}
|
||||
/>
|
||||
|
||||
<input
|
||||
className="w-full mb-6"
|
||||
type="text"
|
||||
name="name"
|
||||
id="name"
|
||||
placeholder="Search title..."
|
||||
onChange={(event) => {
|
||||
const input = event.target as HTMLInputElement;
|
||||
setSearchName(input.value);
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="flex flex-row gap-2 place-items-center">
|
||||
<p className="flex-shrink-0">{langui.group_by}:</p>
|
||||
<Select
|
||||
|
@ -135,12 +156,11 @@ export default function Library(props: Immutable<Props>): JSX.Element {
|
|||
const contentPanel = (
|
||||
<ContentPanel width={ContentPanelWidthSizes.large}>
|
||||
{[...groups].map(([name, items]) => (
|
||||
<>
|
||||
<Fragment key={name}>
|
||||
{items.length > 0 && (
|
||||
<>
|
||||
{name && (
|
||||
<h2
|
||||
key={`h2${name}`}
|
||||
className="text-2xl pb-2 pt-10 first-of-type:pt-0
|
||||
flex flex-row place-items-center gap-2"
|
||||
>
|
||||
|
@ -153,16 +173,14 @@ export default function Library(props: Immutable<Props>): JSX.Element {
|
|||
</h2>
|
||||
)}
|
||||
<div
|
||||
key={`items${name}`}
|
||||
className="grid gap-8 mobile:gap-4 items-end mobile:grid-cols-2
|
||||
desktop:grid-cols-[repeat(auto-fill,_minmax(13rem,1fr))]
|
||||
pb-12 border-b-[3px] border-dotted last-of-type:border-0"
|
||||
>
|
||||
{items.map((item) => (
|
||||
<>
|
||||
<Fragment key={item.id}>
|
||||
{item.attributes && (
|
||||
<PreviewCard
|
||||
key={item.id}
|
||||
href={`/library/${item.attributes.slug}`}
|
||||
title={item.attributes.title}
|
||||
subtitle={item.attributes.subtitle}
|
||||
|
@ -187,12 +205,12 @@ export default function Library(props: Immutable<Props>): JSX.Element {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</ContentPanel>
|
||||
);
|
||||
|
@ -362,10 +380,11 @@ function getGroups(
|
|||
}
|
||||
|
||||
function filterItems(
|
||||
items: Immutable<Props["items"]>,
|
||||
searchName: string,
|
||||
showSubitems: boolean,
|
||||
showPrimaryItems: boolean,
|
||||
showSecondaryItems: boolean,
|
||||
items: Immutable<Props["items"]>
|
||||
showSecondaryItems: boolean
|
||||
): Immutable<Props["items"]> {
|
||||
return [...items].filter((item) => {
|
||||
if (!showSubitems && !item.attributes?.root_item) return false;
|
||||
|
@ -376,10 +395,21 @@ function filterItems(
|
|||
"variant-set" ||
|
||||
item.attributes.metadata[0].subtype?.data?.attributes?.slug ===
|
||||
"relation-set")
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (item.attributes?.primary && !showPrimaryItems) return false;
|
||||
if (!item.attributes?.primary && !showSecondaryItems) return false;
|
||||
if (searchName.length > 1) {
|
||||
if (
|
||||
prettyinlineTitle("", item.attributes?.title, item.attributes?.subtitle)
|
||||
.toLowerCase()
|
||||
.includes(searchName.toLowerCase())
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import { getReadySdk } from "graphql/sdk";
|
|||
import { prettyDate, prettySlug } from "helpers/formatters";
|
||||
import { Immutable } from "helpers/types";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
import { useState } from "react";
|
||||
import { Fragment, useState } from "react";
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
posts: NonNullable<GetPostsPreviewQuery["posts"]>["data"];
|
||||
|
@ -47,10 +47,9 @@ export default function News(props: Immutable<Props>): JSX.Element {
|
|||
desktop:grid-cols-[repeat(auto-fill,_minmax(20rem,1fr))]"
|
||||
>
|
||||
{posts.map((post) => (
|
||||
<>
|
||||
<Fragment key={post.id}>
|
||||
{post.attributes && (
|
||||
<PreviewCard
|
||||
key={post.id}
|
||||
href={`/news/${post.attributes.slug}`}
|
||||
title={
|
||||
post.attributes.translations?.[0]?.title ??
|
||||
|
@ -69,7 +68,7 @@ export default function News(props: Immutable<Props>): JSX.Element {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</ContentPanel>
|
||||
|
|
|
@ -8,12 +8,12 @@ import {
|
|||
import { ContentPanel } from "components/Panels/ContentPanel";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { ChronologyYearComponent } from "components/Wiki/Chronology/ChronologyYearComponent";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { GetChronologyItemsQuery, GetErasQuery } from "graphql/generated";
|
||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { prettySlug } from "helpers/formatters";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
import { Fragment } from "react";
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
chronologyItems: NonNullable<
|
||||
|
@ -24,7 +24,6 @@ interface Props extends AppStaticProps {
|
|||
|
||||
export default function Chronology(props: Props): JSX.Element {
|
||||
const { chronologyItems, chronologyEras, langui } = props;
|
||||
const appLayout = useAppLayout();
|
||||
|
||||
// Group by year the Chronology items
|
||||
const chronologyItemYearGroups: Props["chronologyItems"][number][][][] = [];
|
||||
|
@ -71,10 +70,9 @@ export default function Chronology(props: Props): JSX.Element {
|
|||
/>
|
||||
|
||||
{chronologyEras.map((era) => (
|
||||
<>
|
||||
<Fragment key={era.id}>
|
||||
{era.attributes && (
|
||||
<NavOption
|
||||
key={era.id}
|
||||
url={`#${era.attributes.slug}`}
|
||||
title={
|
||||
era.attributes.title &&
|
||||
|
@ -87,7 +85,7 @@ export default function Chronology(props: Props): JSX.Element {
|
|||
border
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</SubPanel>
|
||||
);
|
||||
|
@ -103,7 +101,7 @@ export default function Chronology(props: Props): JSX.Element {
|
|||
/>
|
||||
|
||||
{chronologyItemYearGroups.map((era, eraIndex) => (
|
||||
<>
|
||||
<Fragment key={eraIndex}>
|
||||
<InsetBox
|
||||
id={chronologyEras[eraIndex].attributes?.slug}
|
||||
className="grid text-center my-8 gap-4"
|
||||
|
@ -120,18 +118,17 @@ export default function Chronology(props: Props): JSX.Element {
|
|||
</p>
|
||||
</InsetBox>
|
||||
{era.map((items, index) => (
|
||||
<>
|
||||
<Fragment key={index}>
|
||||
{items[0].attributes?.year && (
|
||||
<ChronologyYearComponent
|
||||
key={`${eraIndex}-${index}`}
|
||||
year={items[0].attributes.year}
|
||||
items={items}
|
||||
langui={langui}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</ContentPanel>
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue