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 === | ||||
|           content.id | ||||
|     ); | ||||
|   } | ||||
|   return contents; | ||||
|   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; | ||||
|     } | ||||
|     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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint