Merge pull request #1 from Accords-Library/develop
New translation system and filtering/group for Library Items
This commit is contained in:
		
						commit
						30a2b8ceda
					
				| @ -3,7 +3,7 @@ module.exports = { | ||||
|   swcMinify: true, | ||||
|   reactStrictMode: true, | ||||
|   i18n: { | ||||
|     locales: ["en", "fr", "ja", "es", "xx"], | ||||
|     locales: ["en", "fr", "ja", "es"], | ||||
|     defaultLocale: "en", | ||||
|   }, | ||||
|   images: { | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| npx next dev -p 12500 | ||||
| npx next dev -p 12499 | ||||
|  | ||||
| @ -88,7 +88,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { | ||||
| 
 | ||||
|   const metaDescription = props.description | ||||
|     ? props.description | ||||
|     : "Accord's Library aims at gathering and archiving all of Yoko Taro’s work. Yoko Taro is a Japanese video game director and scenario writer."; | ||||
|     : props.langui.default_description; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className={appLayout.darkMode ? "set-theme-dark" : "set-theme-light"}> | ||||
| @ -104,12 +104,8 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { | ||||
|             content={`${titlePrefix} - ${ogTitle}`} | ||||
|           ></meta> | ||||
| 
 | ||||
|           {props.description && ( | ||||
|             <> | ||||
|               <meta name="description" content={metaDescription} /> | ||||
|               <meta name="twitter:description" content={metaDescription}></meta> | ||||
|             </> | ||||
|           )} | ||||
|           <meta name="description" content={metaDescription} /> | ||||
|           <meta name="twitter:description" content={metaDescription}></meta> | ||||
| 
 | ||||
|           <meta property="og:image" content={metaImage.image}></meta> | ||||
|           <meta property="og:image:secure_url" content={metaImage.image}></meta> | ||||
| @ -160,7 +156,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { | ||||
|               <div className="text-dark border-dark border-2 border-dotted rounded-2xl p-8 grid grid-flow-col place-items-center gap-9 opacity-40"> | ||||
|                 <p className="text-4xl">❮</p> | ||||
|                 <p className="text-2xl w-64"> | ||||
|                   Select one of the options in the sidebar | ||||
|                   {props.langui.select_option_sidebar} | ||||
|                 </p> | ||||
|               </div> | ||||
|             </div> | ||||
| @ -238,7 +234,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { | ||||
|               appLayout.languagePanelOpen ? "scale-100" : "scale-0" | ||||
|             }`}
 | ||||
|           > | ||||
|             <h2 className="text-2xl">Select a language</h2> | ||||
|             <h2 className="text-2xl">{props.langui.select_language}</h2> | ||||
|             <div className="flex flex-wrap flex-row gap-2"> | ||||
|               {router.locales?.sort().map((locale) => ( | ||||
|                 <Button | ||||
|  | ||||
| @ -5,7 +5,7 @@ type ButtonProps = { | ||||
|   id?: string; | ||||
|   className?: string; | ||||
|   href?: string; | ||||
|   children: React.ReactChild | React.ReactChild[]; | ||||
|   children: React.ReactNode; | ||||
|   active?: boolean; | ||||
|   locale?: string; | ||||
|   onClick?: MouseEventHandler<HTMLDivElement>; | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| type ChipProps = { | ||||
|   className?: string; | ||||
|   children: React.ReactChild | React.ReactChild[]; | ||||
|   children: React.ReactNode; | ||||
|   "data-tip"?: string; | ||||
|   "data-for"?: string; | ||||
|   "data-html"?: boolean; | ||||
|  | ||||
| @ -55,7 +55,7 @@ export default function ThumbnailHeader( | ||||
|       <div className="grid grid-flow-col gap-8"> | ||||
|         {content.type ? ( | ||||
|           <div className="grid place-items-center place-content-start gap-2"> | ||||
|             <h3 className="text-xl">{langui.global_type}</h3> | ||||
|             <h3 className="text-xl">{langui.type}</h3> | ||||
|             <Button> | ||||
|               {content.type.data.attributes.titles.length > 0 | ||||
|                 ? content.type.data.attributes.titles[0].title | ||||
| @ -68,7 +68,7 @@ export default function ThumbnailHeader( | ||||
| 
 | ||||
|         {content.categories.data.length > 0 ? ( | ||||
|           <div className="grid place-items-center place-content-start gap-2"> | ||||
|             <h3 className="text-xl">{langui.global_categories}</h3> | ||||
|             <h3 className="text-xl">{langui.categories}</h3> | ||||
|             {content.categories.data.map((category) => ( | ||||
|               <Button key={category.id}>{category.attributes.name}</Button> | ||||
|             ))} | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| type InsetBoxProps = { | ||||
|   className?: string; | ||||
|   children: React.ReactChild | React.ReactChild[]; | ||||
|   children: React.ReactNode; | ||||
|   id?: string; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -30,7 +30,7 @@ export default function LibraryItemsPreview( | ||||
|         {item.thumbnail.data ? ( | ||||
|           <Img | ||||
|             image={item.thumbnail.data.attributes} | ||||
|             quality={ImageQuality.Medium} | ||||
|             quality={ImageQuality.Small} | ||||
|           /> | ||||
|         ) : ( | ||||
|           <div className="w-full aspect-[21/29.7] bg-light rounded-lg"></div> | ||||
|  | ||||
| @ -13,7 +13,7 @@ export default function ReturnButton(props: ReturnButtonProps): JSX.Element { | ||||
| 
 | ||||
|   return ( | ||||
|     <Button onClick={() => appLayout.setSubPanelOpen(false)} href={props.href}> | ||||
|       ❮ {props.langui.global_return_label} {props.title} | ||||
|       ❮ {props.langui.return_to} {props.title} | ||||
|     </Button> | ||||
|   ); | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| import Link from "next/link"; | ||||
| import NavOption from "components/PanelComponents/NavOption"; | ||||
| import SVG from "components/SVG"; | ||||
| import { useRouter } from "next/router"; | ||||
| import Button from "components/Button"; | ||||
| import HorizontalLine from "components/HorizontalLine"; | ||||
| @ -84,8 +83,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|       <NavOption | ||||
|         url="/library" | ||||
|         icon="library_books" | ||||
|         title={langui.main_library} | ||||
|         subtitle={langui.main_library_description} | ||||
|         title={langui.library} | ||||
|         subtitle={langui.library_short_description} | ||||
|         tooltipId="MainPanelTooltip" | ||||
|         reduced={appLayout.mainPanelReduced && isDesktop} | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
| @ -94,8 +93,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|       <NavOption | ||||
|         url="/contents" | ||||
|         icon="workspaces" | ||||
|         title="Contents" | ||||
|         subtitle="Explore all content and filter by type or category" | ||||
|         title={langui.contents} | ||||
|         subtitle={langui.contents_short_description} | ||||
|         tooltipId="MainPanelTooltip" | ||||
|         reduced={appLayout.mainPanelReduced && isDesktop} | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
| @ -104,8 +103,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|       <NavOption | ||||
|         url="/wiki" | ||||
|         icon="travel_explore" | ||||
|         title={langui.main_wiki} | ||||
|         subtitle={langui.main_wiki_description} | ||||
|         title={langui.wiki} | ||||
|         subtitle={langui.wiki_short_description} | ||||
|         tooltipId="MainPanelTooltip" | ||||
|         reduced={appLayout.mainPanelReduced && isDesktop} | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
| @ -114,8 +113,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|       <NavOption | ||||
|         url="/chronicles" | ||||
|         icon="watch_later" | ||||
|         title={langui.main_chronicles} | ||||
|         subtitle={langui.main_chronicles_description} | ||||
|         title={langui.chronicles} | ||||
|         subtitle={langui.chronicles_short_description} | ||||
|         tooltipId="MainPanelTooltip" | ||||
|         reduced={appLayout.mainPanelReduced && isDesktop} | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
| @ -126,7 +125,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|       <NavOption | ||||
|         url="/news" | ||||
|         icon="feed" | ||||
|         title={langui.main_news} | ||||
|         title={langui.news} | ||||
|         tooltipId="MainPanelTooltip" | ||||
|         reduced={appLayout.mainPanelReduced && isDesktop} | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
| @ -135,7 +134,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|       <NavOption | ||||
|         url="/merch" | ||||
|         icon="store" | ||||
|         title={langui.main_merch} | ||||
|         title={langui.merch} | ||||
|         tooltipId="MainPanelTooltip" | ||||
|         reduced={appLayout.mainPanelReduced && isDesktop} | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
| @ -144,7 +143,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|       <NavOption | ||||
|         url="/gallery" | ||||
|         icon="collections" | ||||
|         title={langui.main_gallery} | ||||
|         title={langui.gallery} | ||||
|         tooltipId="MainPanelTooltip" | ||||
|         reduced={appLayout.mainPanelReduced && isDesktop} | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
| @ -153,7 +152,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|       <NavOption | ||||
|         url="/archives" | ||||
|         icon="inventory" | ||||
|         title={langui.main_archives} | ||||
|         title={langui.archives} | ||||
|         tooltipId="MainPanelTooltip" | ||||
|         reduced={appLayout.mainPanelReduced && isDesktop} | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
| @ -162,7 +161,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|       <NavOption | ||||
|         url="/about-us" | ||||
|         icon="info" | ||||
|         title={langui.main_about_us} | ||||
|         title={langui.about_us} | ||||
|         tooltipId="MainPanelTooltip" | ||||
|         reduced={appLayout.mainPanelReduced && isDesktop} | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
| @ -176,8 +175,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|         }`}
 | ||||
|       > | ||||
|         <p> | ||||
|           {langui.main_licensing ? ( | ||||
|             <Markdown>{langui.main_licensing}</Markdown> | ||||
|           {langui.licensing_notice ? ( | ||||
|             <Markdown>{langui.licensing_notice}</Markdown> | ||||
|           ) : ( | ||||
|             "" | ||||
|           )} | ||||
| @ -194,8 +193,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|           </div> | ||||
|         </a> | ||||
|         <p> | ||||
|           {langui.main_copyright ? ( | ||||
|             <Markdown>{langui.main_copyright}</Markdown> | ||||
|           {langui.copyright_notice ? ( | ||||
|             <Markdown>{langui.copyright_notice}</Markdown> | ||||
|           ) : ( | ||||
|             "" | ||||
|           )} | ||||
|  | ||||
							
								
								
									
										67
									
								
								src/components/Select.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/components/Select.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | ||||
| import { Dispatch, SetStateAction, useState } from "react"; | ||||
| 
 | ||||
| export type SelectProps = { | ||||
|   setState: Dispatch<SetStateAction<number>>; | ||||
|   state: number; | ||||
|   options: string[]; | ||||
|   selected?: number; | ||||
|   allowEmpty?: boolean; | ||||
|   className?: string; | ||||
|   onChange?: Function; | ||||
| }; | ||||
| 
 | ||||
| export default function Select(props: SelectProps): JSX.Element { | ||||
|   const [opened, setOpened] = useState(false); | ||||
| 
 | ||||
|   return ( | ||||
|     <div | ||||
|       className={`relative transition-[filter] ${ | ||||
|         opened && "drop-shadow-shade-lg z-10" | ||||
|       } ${props.className}`}
 | ||||
|     > | ||||
|       <div | ||||
|         className={`outline outline-mid outline-2 outline-offset-[-2px] hover:outline-[transparent] bg-light rounded-[1em] p-1 grid grid-flow-col grid-cols-[1fr_auto_auto] place-items-center cursor-pointer hover:bg-mid transition-all ${ | ||||
|           opened && "outline-[transparent] rounded-b-none" | ||||
|         }`}
 | ||||
|       > | ||||
|         <p onClick={() => setOpened(!opened)} className="w-full"> | ||||
|           {props.state === -1 ? "—" : props.options[props.state]} | ||||
|         </p> | ||||
|         {props.state >= 0 && props.allowEmpty && ( | ||||
|           <span | ||||
|             onClick={() => props.setState(-1)} | ||||
|             className="material-icons !text-xs" | ||||
|           > | ||||
|             close | ||||
|           </span> | ||||
|         )} | ||||
|         <span onClick={() => setOpened(!opened)} className="material-icons"> | ||||
|           {opened ? "arrow_drop_up" : "arrow_drop_down"} | ||||
|         </span> | ||||
|       </div> | ||||
|       <div | ||||
|         className={`left-0 right-0 rounded-b-[1em] ${ | ||||
|           opened ? "absolute" : "hidden" | ||||
|         }`}
 | ||||
|       > | ||||
|         {props.options.map((option, index) => ( | ||||
|           <> | ||||
|             {index !== props.state && ( | ||||
|               <div | ||||
|                 className="bg-light hover:bg-mid transition-colors cursor-pointer p-1 last-of-type:rounded-b-[1em]" | ||||
|                 key={option} | ||||
|                 id={option} | ||||
|                 onClick={() => { | ||||
|                   setOpened(false); | ||||
|                   props.setState(index); | ||||
|                 }} | ||||
|               > | ||||
|                 {option} | ||||
|               </div> | ||||
|             )} | ||||
|           </> | ||||
|         ))} | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
							
								
								
									
										26
									
								
								src/components/Switch.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/components/Switch.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| import { Dispatch, SetStateAction } from "react"; | ||||
| 
 | ||||
| export type SwitchProps = { | ||||
|   setState: Dispatch<SetStateAction<boolean>>; | ||||
|   state: boolean; | ||||
|   className?: string; | ||||
| }; | ||||
| 
 | ||||
| export default function Select(props: SwitchProps): JSX.Element { | ||||
|   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"}`}
 | ||||
|       onClick={() => { | ||||
|         props.setState(!props.state); | ||||
|       }} | ||||
|     > | ||||
|       <div | ||||
|         className={`bg-dark aspect-square rounded-full absolute top-0 bottom-0 left-0 transition-transform ${ | ||||
|           props.state && "translate-x-[115%]" | ||||
|         }`}
 | ||||
|       ></div> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| @ -1,72 +1,87 @@ | ||||
| query getWebsiteInterface($language_code: String) { | ||||
|   websiteInterfaces(filters: { language: { code: { eq: $language_code } } }) { | ||||
|   websiteInterfaces( | ||||
|     filters: { ui_language: { code: { eq: $language_code } } } | ||||
|   ) { | ||||
|     data { | ||||
|       attributes { | ||||
|         main_library | ||||
|         main_library_description | ||||
|         main_news | ||||
|         main_merch | ||||
|         main_gallery | ||||
|         main_archives | ||||
|         main_about_us | ||||
|         main_licensing | ||||
|         main_copyright | ||||
|         library | ||||
|         contents | ||||
|         wiki | ||||
|         chronicles | ||||
|         library_short_description | ||||
|         contents_short_description | ||||
|         wiki_short_description | ||||
|         chronicles_short_description | ||||
|         news | ||||
|         merch | ||||
|         gallery | ||||
|         archives | ||||
|         about_us | ||||
|         licensing_notice | ||||
|         copyright_notice | ||||
|         contents_description | ||||
|         type | ||||
|         category | ||||
|         categories | ||||
|         size | ||||
|         release_date | ||||
|         release_year | ||||
|         details | ||||
|         price | ||||
|         width | ||||
|         height | ||||
|         thickness | ||||
|         subitem | ||||
|         subitems | ||||
|         subitem_of | ||||
|         variant | ||||
|         variants | ||||
|         variant_of | ||||
|         summary | ||||
|         audio | ||||
|         video | ||||
|         textual | ||||
|         game | ||||
|         other | ||||
|         return_to | ||||
|         left_to_right | ||||
|         right_to_left | ||||
|         page | ||||
|         pages | ||||
|         page_order | ||||
|         binding | ||||
|         type_information | ||||
|         front_matter | ||||
|         back_matter | ||||
|         open_content | ||||
|         read_content | ||||
|         watch_content | ||||
|         listen_content | ||||
|         view_scans | ||||
|         paperback | ||||
|         hardcover | ||||
|         languages | ||||
|         select_language | ||||
|         language | ||||
|         library_description | ||||
|         library_item_summary | ||||
|         library_item_gallery | ||||
|         library_item_details | ||||
|         library_item_subitems | ||||
|         library_item_variants | ||||
|         library_item_content | ||||
|         global_return_label | ||||
|         global_subitem_of | ||||
|         global_type | ||||
|         global_width | ||||
|         global_height | ||||
|         global_thickness | ||||
|         global_binding | ||||
|         global_language | ||||
|         global_languages | ||||
|         global_page | ||||
|         global_pages | ||||
|         global_page_order | ||||
|         global_release_date | ||||
|         global_price | ||||
|         library_item_physical_size | ||||
|         library_item_type_information | ||||
|         library_item_front_matter | ||||
|         library_item_back_matter | ||||
|         library_item_type_textual | ||||
|         library_item_type_audio | ||||
|         library_item_type_game | ||||
|         library_item_type_video | ||||
|         library_item_type_other | ||||
|         library_item_open_content | ||||
|         library_item_view_scans | ||||
|         content_read_content | ||||
|         content_watch_content | ||||
|         content_listen_content | ||||
|         global_category | ||||
|         global_categories | ||||
|         global_paperback | ||||
|         global_hardcover | ||||
|         global_left_to_right | ||||
|         global_right_to_left | ||||
|         main_wiki | ||||
|         main_wiki_description | ||||
|         main_chronicles | ||||
|         main_chronicles_description | ||||
|         library_items | ||||
|         library_items_description | ||||
|         library_content | ||||
|         library_content_description | ||||
|         wiki_description | ||||
|         news_description | ||||
|         chronicles_description | ||||
|         news_description | ||||
|         merch_description | ||||
|         gallery_description | ||||
|         archives_description | ||||
|         about_us_description | ||||
|         merch_description | ||||
|         page_not_found | ||||
|         default_description | ||||
|         name | ||||
|         show_subitems | ||||
|         show_primary_items | ||||
|         show_secondary_items | ||||
|         no_type | ||||
|         no_year | ||||
|         order_by | ||||
|         group_by | ||||
|         select_option_sidebar | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| @ -125,17 +140,14 @@ query getChronologyItems($language_code: String) { | ||||
| } | ||||
| 
 | ||||
| query getLibraryItemsPreview($language_code: String) { | ||||
|   libraryItems( | ||||
|     filters: { root_item: { eq: true } } | ||||
|     pagination: { limit: -1 } | ||||
|     sort: ["title:asc", "subtitle:asc"] | ||||
|   ) { | ||||
|   libraryItems(pagination: { limit: -1 }) { | ||||
|     data { | ||||
|       id | ||||
|       attributes { | ||||
|         title | ||||
|         subtitle | ||||
|         slug | ||||
|         root_item | ||||
|         thumbnail { | ||||
|           data { | ||||
|             attributes { | ||||
|  | ||||
| @ -86,71 +86,84 @@ export type GetWebsiteInterfaceQuery = { | ||||
|       __typename: "WebsiteInterfaceEntity"; | ||||
|       attributes: { | ||||
|         __typename: "WebsiteInterface"; | ||||
|         main_library: string; | ||||
|         main_library_description: string; | ||||
|         main_news: string; | ||||
|         main_merch: string; | ||||
|         main_gallery: string; | ||||
|         main_archives: string; | ||||
|         main_about_us: string; | ||||
|         main_licensing: string; | ||||
|         main_copyright: string; | ||||
|         library: string; | ||||
|         contents: string; | ||||
|         wiki: string; | ||||
|         chronicles: string; | ||||
|         library_short_description: string; | ||||
|         contents_short_description: string; | ||||
|         wiki_short_description: string; | ||||
|         chronicles_short_description: string; | ||||
|         news: string; | ||||
|         merch: string; | ||||
|         gallery: string; | ||||
|         archives: string; | ||||
|         about_us: string; | ||||
|         licensing_notice: string; | ||||
|         copyright_notice: string; | ||||
|         contents_description: string; | ||||
|         type: string; | ||||
|         category: string; | ||||
|         categories: string; | ||||
|         size: string; | ||||
|         release_date: string; | ||||
|         release_year: string; | ||||
|         details: string; | ||||
|         price: string; | ||||
|         width: string; | ||||
|         height: string; | ||||
|         thickness: string; | ||||
|         subitem: string; | ||||
|         subitems: string; | ||||
|         subitem_of: string; | ||||
|         variant: string; | ||||
|         variants: string; | ||||
|         variant_of: string; | ||||
|         summary: string; | ||||
|         audio: string; | ||||
|         video: string; | ||||
|         textual: string; | ||||
|         game: string; | ||||
|         other: string; | ||||
|         return_to: string; | ||||
|         left_to_right: string; | ||||
|         right_to_left: string; | ||||
|         page: string; | ||||
|         pages: string; | ||||
|         page_order: string; | ||||
|         binding: string; | ||||
|         type_information: string; | ||||
|         front_matter: string; | ||||
|         back_matter: string; | ||||
|         open_content: string; | ||||
|         read_content: string; | ||||
|         watch_content: string; | ||||
|         listen_content: string; | ||||
|         view_scans: string; | ||||
|         paperback: string; | ||||
|         hardcover: string; | ||||
|         languages: string; | ||||
|         select_language: string; | ||||
|         language: string; | ||||
|         library_description: string; | ||||
|         library_item_summary: string; | ||||
|         library_item_gallery: string; | ||||
|         library_item_details: string; | ||||
|         library_item_subitems: string; | ||||
|         library_item_variants: string; | ||||
|         library_item_content: string; | ||||
|         global_return_label: string; | ||||
|         global_subitem_of: string; | ||||
|         global_type: string; | ||||
|         global_width: string; | ||||
|         global_height: string; | ||||
|         global_thickness: string; | ||||
|         global_binding: string; | ||||
|         global_language: string; | ||||
|         global_languages: string; | ||||
|         global_page: string; | ||||
|         global_pages: string; | ||||
|         global_page_order: string; | ||||
|         global_release_date: string; | ||||
|         global_price: string; | ||||
|         library_item_physical_size: string; | ||||
|         library_item_type_information: string; | ||||
|         library_item_front_matter: string; | ||||
|         library_item_back_matter: string; | ||||
|         library_item_type_textual: string; | ||||
|         library_item_type_audio: string; | ||||
|         library_item_type_game: string; | ||||
|         library_item_type_video: string; | ||||
|         library_item_type_other: string; | ||||
|         library_item_open_content: string; | ||||
|         library_item_view_scans: string; | ||||
|         content_read_content: string; | ||||
|         content_watch_content: string; | ||||
|         content_listen_content: string; | ||||
|         global_category: string; | ||||
|         global_categories: string; | ||||
|         global_paperback: string; | ||||
|         global_hardcover: string; | ||||
|         global_left_to_right: string; | ||||
|         global_right_to_left: string; | ||||
|         main_wiki: string; | ||||
|         main_wiki_description: string; | ||||
|         main_chronicles: string; | ||||
|         main_chronicles_description: string; | ||||
|         library_items: string; | ||||
|         library_items_description: string; | ||||
|         library_content: string; | ||||
|         library_content_description: string; | ||||
|         wiki_description: string; | ||||
|         news_description: string; | ||||
|         chronicles_description: string; | ||||
|         news_description: string; | ||||
|         merch_description: string; | ||||
|         gallery_description: string; | ||||
|         archives_description: string; | ||||
|         about_us_description: string; | ||||
|         merch_description: string; | ||||
|         page_not_found: string; | ||||
|         default_description: string; | ||||
|         name: string; | ||||
|         show_subitems: string; | ||||
|         show_primary_items: string; | ||||
|         show_secondary_items: string; | ||||
|         no_type: string; | ||||
|         no_year: string; | ||||
|         order_by: string; | ||||
|         group_by: string; | ||||
|         select_option_sidebar: string; | ||||
|       }; | ||||
|     }>; | ||||
|   }; | ||||
| @ -238,6 +251,7 @@ export type GetLibraryItemsPreviewQuery = { | ||||
|         title: string; | ||||
|         subtitle: string; | ||||
|         slug: string; | ||||
|         root_item: boolean; | ||||
|         thumbnail: { | ||||
|           __typename: "UploadFileEntityResponse"; | ||||
|           data: { | ||||
|  | ||||
| @ -4,6 +4,7 @@ import { getWebsiteInterface } from "graphql/operations"; | ||||
| import { GetStaticProps } from "next"; | ||||
| import { GetWebsiteInterfaceQuery } from "graphql/operations-types"; | ||||
| import AppLayout from "components/AppLayout"; | ||||
| import ReturnButton from "components/PanelComponents/ReturnButton"; | ||||
| 
 | ||||
| type FourOhFourProps = { | ||||
|   langui: GetWebsiteInterfaceQuery; | ||||
| @ -13,13 +14,13 @@ export default function FourOhFour(props: FourOhFourProps): JSX.Element { | ||||
|   const langui = props.langui.websiteInterfaces.data[0].attributes; | ||||
|   const contentPanel = ( | ||||
|     <ContentPanel> | ||||
|       <h1>404 - Page Not Found</h1> | ||||
|       <Link href="/"> | ||||
|         <a>Go back home</a> | ||||
|       </Link> | ||||
|       <h1>404 - {langui.page_not_found}</h1> | ||||
|       <ReturnButton href="/" title="Home" langui={langui} /> | ||||
|     </ContentPanel> | ||||
|   ); | ||||
|   return <AppLayout navTitle="404" langui={langui} contentPanel={contentPanel} />; | ||||
|   return ( | ||||
|     <AppLayout navTitle="404" langui={langui} contentPanel={contentPanel} /> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export const getStaticProps: GetStaticProps = async (context) => { | ||||
|  | ||||
| @ -15,14 +15,14 @@ export default function AboutUs(props: AboutUsProps): JSX.Element { | ||||
|     <SubPanel> | ||||
|       <PanelHeader | ||||
|         icon="info" | ||||
|         title={langui.main_about_us} | ||||
|         title={langui.about_us} | ||||
|         description={langui.about_us_description} | ||||
|       /> | ||||
|     </SubPanel> | ||||
|   ); | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       navTitle={langui.main_about_us} | ||||
|       navTitle={langui.about_us} | ||||
|       langui={langui} | ||||
|       subPanel={subPanel} | ||||
|     /> | ||||
|  | ||||
| @ -15,14 +15,14 @@ export default function Archives(props: ArchivesProps): JSX.Element { | ||||
|     <SubPanel> | ||||
|       <PanelHeader | ||||
|         icon="inventory" | ||||
|         title={langui.main_archives} | ||||
|         title={langui.archives} | ||||
|         description={langui.archives_description} | ||||
|       /> | ||||
|     </SubPanel> | ||||
|   ); | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       navTitle={langui.main_archives} | ||||
|       navTitle={langui.archives} | ||||
|       langui={langui} | ||||
|       subPanel={subPanel} | ||||
|     /> | ||||
|  | ||||
| @ -15,14 +15,14 @@ export default function Chronicles(props: ChroniclesProps): JSX.Element { | ||||
|     <SubPanel> | ||||
|       <PanelHeader | ||||
|         icon="watch_later" | ||||
|         title={langui.main_chronicles} | ||||
|         title={langui.chronicles} | ||||
|         description={langui.chronicles_description} | ||||
|       /> | ||||
|     </SubPanel> | ||||
|   ); | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       navTitle={langui.main_chronicles} | ||||
|       navTitle={langui.chronicles} | ||||
|       langui={langui} | ||||
|       subPanel={subPanel} | ||||
|     /> | ||||
|  | ||||
| @ -40,7 +40,7 @@ export default function ContentIndex(props: ContentIndexProps): JSX.Element { | ||||
| 
 | ||||
|         {content.text_set.length > 0 ? ( | ||||
|           <Button href={`/contents/${content.slug}/read/`}> | ||||
|             {langui.content_read_content} | ||||
|             {langui.read_content} | ||||
|           </Button> | ||||
|         ) : ( | ||||
|           "" | ||||
| @ -48,7 +48,7 @@ export default function ContentIndex(props: ContentIndexProps): JSX.Element { | ||||
| 
 | ||||
|         {content.audio_set.length > 0 ? ( | ||||
|           <Button href={`/contents/${content.slug}/listen/`}> | ||||
|             {langui.content_listen_content} | ||||
|             {langui.listen_content} | ||||
|           </Button> | ||||
|         ) : ( | ||||
|           "" | ||||
| @ -56,7 +56,7 @@ export default function ContentIndex(props: ContentIndexProps): JSX.Element { | ||||
| 
 | ||||
|         {content.video_set.length > 0 ? ( | ||||
|           <Button href={`/contents/${content.slug}/watch/`}> | ||||
|             {langui.content_watch_content} | ||||
|             {langui.watch_content} | ||||
|           </Button> | ||||
|         ) : ( | ||||
|           "" | ||||
|  | ||||
| @ -18,7 +18,7 @@ export default function Gallery(props: GalleryProps): JSX.Element { | ||||
| 
 | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       navTitle={langui.main_gallery} | ||||
|       navTitle={langui.gallery} | ||||
|       langui={langui} | ||||
|       contentPanel={contentPanel} | ||||
|     /> | ||||
|  | ||||
| @ -141,13 +141,11 @@ export default function Home(props: HomeProps): JSX.Element { | ||||
|   ); | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       <AppLayout | ||||
|         navTitle={"Accord’s Library"} | ||||
|         langui={langui} | ||||
|         contentPanel={contentPanel} | ||||
|       /> | ||||
|     </> | ||||
|     <AppLayout | ||||
|       navTitle={"Home"} | ||||
|       langui={langui} | ||||
|       contentPanel={contentPanel} | ||||
|     /> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -58,16 +58,12 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
| 
 | ||||
|   const subPanel = ( | ||||
|     <SubPanel> | ||||
|       <ReturnButton | ||||
|         href="/library/" | ||||
|         title={langui.main_library} | ||||
|         langui={langui} | ||||
|       /> | ||||
|       <ReturnButton href="/library/" title={langui.library} langui={langui} /> | ||||
|       <HorizontalLine /> | ||||
| 
 | ||||
|       <div className="grid gap-4"> | ||||
|         <NavOption | ||||
|           title={langui.library_item_summary} | ||||
|           title={langui.summary} | ||||
|           url="#summary" | ||||
|           border | ||||
|           onClick={() => appLayout.setSubPanelOpen(false)} | ||||
| @ -75,7 +71,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
| 
 | ||||
|         {item.gallery.data.length > 0 ? ( | ||||
|           <NavOption | ||||
|             title={langui.library_item_gallery} | ||||
|             title={langui.gallery} | ||||
|             url="#gallery" | ||||
|             border | ||||
|             onClick={() => appLayout.setSubPanelOpen(false)} | ||||
| @ -85,7 +81,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|         )} | ||||
| 
 | ||||
|         <NavOption | ||||
|           title={langui.library_item_details} | ||||
|           title={langui.details} | ||||
|           url="#details" | ||||
|           border | ||||
|           onClick={() => appLayout.setSubPanelOpen(false)} | ||||
| @ -93,11 +89,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
| 
 | ||||
|         {item.subitems.data.length > 0 ? ( | ||||
|           <NavOption | ||||
|             title={ | ||||
|               isVariantSet | ||||
|                 ? langui.library_item_variants | ||||
|                 : langui.library_item_subitems | ||||
|             } | ||||
|             title={isVariantSet ? langui.variants : langui.subitems} | ||||
|             url={isVariantSet ? "#variants" : "#subitems"} | ||||
|             border | ||||
|             onClick={() => appLayout.setSubPanelOpen(false)} | ||||
| @ -107,11 +99,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|         )} | ||||
| 
 | ||||
|         {item.contents.data.length > 0 ? ( | ||||
|           <NavOption | ||||
|             title={langui.library_item_content} | ||||
|             url="#content" | ||||
|             border | ||||
|           /> | ||||
|           <NavOption title={langui.contents} url="#contents" border /> | ||||
|         ) : ( | ||||
|           "" | ||||
|         )} | ||||
| @ -140,7 +128,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|           <div className="w-[clamp(0px,100%,42rem)] grid place-items-center gap-8"> | ||||
|             {item.subitem_of.data.length > 0 ? ( | ||||
|               <div className="grid place-items-center"> | ||||
|                 <p>{langui.global_subitem_of}</p> | ||||
|                 <p>{langui.subitem_of}</p> | ||||
|                 <Button | ||||
|                   href={`/library/${item.subitem_of.data[0].attributes.slug}`} | ||||
|                 > | ||||
| @ -172,7 +160,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
| 
 | ||||
|         {item.gallery.data.length > 0 ? ( | ||||
|           <div id="gallery" className="grid place-items-center gap-8  w-full"> | ||||
|             <h2 className="text-2xl">{langui.library_item_gallery}</h2> | ||||
|             <h2 className="text-2xl">{langui.gallery}</h2> | ||||
|             <div className="grid w-full gap-8 items-end grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))]"> | ||||
|               {item.gallery.data.map((galleryItem) => ( | ||||
|                 <div | ||||
| @ -197,12 +185,12 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|         <InsetBox id="details" className="grid place-items-center"> | ||||
|           <div className="w-[clamp(0px,100%,42rem)] grid place-items gap-8"> | ||||
|             <h2 className="text-2xl text-center"> | ||||
|               {langui.library_item_details} | ||||
|               {langui.details} | ||||
|             </h2> | ||||
|             <div className="grid grid-flow-col w-full place-content-between"> | ||||
|               {item.metadata.length > 0 ? ( | ||||
|                 <div className="grid place-items-center"> | ||||
|                   <h3 className="text-xl">{langui.global_type}</h3> | ||||
|                   <h3 className="text-xl">{langui.type}</h3> | ||||
|                   <div className="grid grid-flow-col gap-1"> | ||||
|                     <Chip>{prettyItemType(item.metadata[0], langui)}</Chip> | ||||
|                     {"›"} | ||||
| @ -215,7 +203,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
| 
 | ||||
|               {item.release_date ? ( | ||||
|                 <div className="grid place-items-center"> | ||||
|                   <h3 className="text-xl">{langui.global_release_date}</h3> | ||||
|                   <h3 className="text-xl">{langui.release_date}</h3> | ||||
|                   <p>{prettyDate(item.release_date)}</p> | ||||
|                 </div> | ||||
|               ) : ( | ||||
| @ -224,7 +212,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
| 
 | ||||
|               {item.price ? ( | ||||
|                 <div className="grid place-items-center"> | ||||
|                   <h3 className="text-xl">{langui.global_price}</h3> | ||||
|                   <h3 className="text-xl">{langui.price}</h3> | ||||
|                   <p>{prettyPrice(item.price)}</p> | ||||
|                 </div> | ||||
|               ) : ( | ||||
| @ -233,17 +221,17 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|             </div> | ||||
|             {item.size ? ( | ||||
|               <> | ||||
|                 <h3 className="text-xl">{langui.library_item_physical_size}</h3> | ||||
|                 <h3 className="text-xl">{langui.size}</h3> | ||||
|                 <div className="grid grid-flow-col w-full place-content-between"> | ||||
|                   <div className="flex flex-row flex-wrap place-items-start gap-4"> | ||||
|                     <p className="font-bold">{langui.global_width}:</p> | ||||
|                     <p className="font-bold">{langui.width}:</p> | ||||
|                     <div> | ||||
|                       <p>{item.size.width} mm</p> | ||||
|                       <p>{convertMmToInch(item.size.width)} in</p> | ||||
|                     </div> | ||||
|                   </div> | ||||
|                   <div className="flex flex-row flex-wrap place-items-start gap-4"> | ||||
|                     <p className="font-bold">{langui.global_height}:</p> | ||||
|                     <p className="font-bold">{langui.height}:</p> | ||||
|                     <div> | ||||
|                       <p>{item.size.height} mm</p> | ||||
|                       <p>{convertMmToInch(item.size.height)} in</p> | ||||
| @ -251,7 +239,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|                   </div> | ||||
|                   {item.size.thickness ? ( | ||||
|                     <div className="flex flex-row flex-wrap place-items-start gap-4"> | ||||
|                       <p className="font-bold">{langui.global_thickness}:</p> | ||||
|                       <p className="font-bold">{langui.thickness}:</p> | ||||
|                       <div> | ||||
|                         <p>{item.size.thickness} mm</p> | ||||
|                         <p>{convertMmToInch(item.size.thickness)} in</p> | ||||
| @ -269,44 +257,44 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|             {item.metadata.length > 0 ? ( | ||||
|               <> | ||||
|                 <h3 className="text-xl"> | ||||
|                   {langui.library_item_type_information} | ||||
|                   {langui.type_information} | ||||
|                 </h3> | ||||
|                 <div className="grid grid-cols-2 w-full place-content-between"> | ||||
|                   {item.metadata[0].__typename === "ComponentMetadataBooks" ? ( | ||||
|                     <> | ||||
|                       <div className="flex flex-row place-content-start gap-4"> | ||||
|                         <p className="font-bold">{langui.global_pages}:</p> | ||||
|                         <p className="font-bold">{langui.pages}:</p> | ||||
|                         <p>{item.metadata[0].page_count}</p> | ||||
|                       </div> | ||||
| 
 | ||||
|                       <div className="flex flex-row place-content-start gap-4"> | ||||
|                         <p className="font-bold">{langui.global_binding}:</p> | ||||
|                         <p className="font-bold">{langui.binding}:</p> | ||||
|                         <p> | ||||
|                           {item.metadata[0].binding_type === | ||||
|                           Enum_Componentmetadatabooks_Binding_Type.Paperback | ||||
|                             ? langui.global_paperback | ||||
|                             ? langui.paperback | ||||
|                             : item.metadata[0].binding_type === | ||||
|                               Enum_Componentmetadatabooks_Binding_Type.Hardcover | ||||
|                             ? langui.global_hardcover | ||||
|                             ? langui.hardcover | ||||
|                             : ""} | ||||
|                         </p> | ||||
|                       </div> | ||||
| 
 | ||||
|                       <div className="flex flex-row place-content-start gap-4"> | ||||
|                         <p className="font-bold">{langui.global_page_order}:</p> | ||||
|                         <p className="font-bold">{langui.page_order}:</p> | ||||
|                         <p> | ||||
|                           {item.metadata[0].page_order === | ||||
|                           Enum_Componentmetadatabooks_Page_Order.LeftToRight | ||||
|                             ? langui.global_left_to_right | ||||
|                             ? langui.left_to_right | ||||
|                             : item.metadata[0].page_order === | ||||
|                               Enum_Componentmetadatabooks_Page_Order.RightToLeft | ||||
|                             ? langui.global_right_to_left | ||||
|                             ? langui.right_to_left | ||||
|                             : ""} | ||||
|                         </p> | ||||
|                       </div> | ||||
| 
 | ||||
|                       <div className="flex flex-row place-content-start gap-4"> | ||||
|                         <p className="font-bold">{langui.global_languages}:</p> | ||||
|                         <p className="font-bold">{langui.languages}:</p> | ||||
|                         {item.metadata[0].languages.data.map((lang) => ( | ||||
|                           <p key={lang.attributes.code}> | ||||
|                             {lang.attributes.name} | ||||
| @ -327,7 +315,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|                     "ComponentMetadataOther" ? ( | ||||
|                     <> | ||||
|                       <div className="flex flex-row place-content-start gap-4"> | ||||
|                         <p className="font-bold">{langui.global_type}:</p> | ||||
|                         <p className="font-bold">{langui.type}:</p> | ||||
|                         <Chip> | ||||
|                           {item.metadata[0].subtype.data.attributes.titles | ||||
|                             .length > 0 | ||||
| @ -357,8 +345,8 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|           > | ||||
|             <h2 className="text-2xl"> | ||||
|               {isVariantSet | ||||
|                 ? langui.library_item_variants | ||||
|                 : langui.library_item_subitems} | ||||
|                 ? langui.variants | ||||
|                 : langui.subitems} | ||||
|             </h2> | ||||
|             <div className="grid gap-8 items-end mobile:grid-cols-2 grid-cols-[repeat(auto-fill,minmax(15rem,1fr))] w-full"> | ||||
|               {item.subitems.data.map((subitem) => ( | ||||
| @ -374,8 +362,8 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|         )} | ||||
| 
 | ||||
|         {item.contents.data.length > 0 ? ( | ||||
|           <div id="content" className="w-full grid place-items-center gap-8"> | ||||
|             <h2 className="text-2xl">{langui.library_item_content}</h2> | ||||
|           <div id="contents" className="w-full grid place-items-center gap-8"> | ||||
|             <h2 className="text-2xl">{langui.contents}</h2> | ||||
|             <div className="grid gap-4 w-full"> | ||||
|               {item.contents.data.map((content) => ( | ||||
|                 <div | ||||
| @ -440,7 +428,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|                       <Button | ||||
|                         href={`/contents/${content.attributes.content.data.attributes.slug}/scans/`} | ||||
|                       > | ||||
|                         {langui.library_item_view_scans} | ||||
|                         {langui.view_scans} | ||||
|                       </Button> | ||||
|                     ) : ( | ||||
|                       "" | ||||
| @ -450,7 +438,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|                       <Button | ||||
|                         href={`/contents/${content.attributes.content.data.attributes.slug}`} | ||||
|                       > | ||||
|                         {langui.library_item_open_content} | ||||
|                         {langui.open_content} | ||||
|                       </Button> | ||||
|                     ) : ( | ||||
|                       "" | ||||
| @ -474,7 +462,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
| 
 | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       navTitle={langui.main_library} | ||||
|       navTitle={langui.library} | ||||
|       title={prettyinlineTitle("", item.title, item.subtitle)} | ||||
|       langui={langui} | ||||
|       contentPanel={contentPanel} | ||||
|  | ||||
| @ -14,35 +14,113 @@ import { | ||||
| import PanelHeader from "components/PanelComponents/PanelHeader"; | ||||
| import AppLayout from "components/AppLayout"; | ||||
| import LibraryItemsPreview from "components/Library/LibraryItemsPreview"; | ||||
| import Select from "components/Select"; | ||||
| import { useEffect, useState } from "react"; | ||||
| import { prettyDate, prettyinlineTitle } from "queries/helpers"; | ||||
| import Switch from "components/Switch"; | ||||
| 
 | ||||
| type LibraryProps = { | ||||
|   libraryItems: GetLibraryItemsPreviewQuery; | ||||
|   langui: GetWebsiteInterfaceQuery; | ||||
| }; | ||||
| 
 | ||||
| type GroupLibraryItems = Map< | ||||
|   string, | ||||
|   GetLibraryItemsPreviewQuery["libraryItems"]["data"] | ||||
| >; | ||||
| 
 | ||||
| export default function Library(props: LibraryProps): JSX.Element { | ||||
|   const langui = props.langui.websiteInterfaces.data[0].attributes; | ||||
| 
 | ||||
|   const [showSubitems, setShowSubitems] = useState<boolean>(false); | ||||
|   const [sortingMethod, setSortingMethod] = useState<number>(0); | ||||
|   const [groupingMethod, setGroupingMethod] = useState<number>(-1); | ||||
| 
 | ||||
|   const [filteredItems, setFilteredItems] = useState< | ||||
|     LibraryProps["libraryItems"]["libraryItems"]["data"] | ||||
|   >(filterItems(showSubitems, props.libraryItems.libraryItems.data)); | ||||
| 
 | ||||
|   const [sortedItems, setSortedItem] = useState< | ||||
|     LibraryProps["libraryItems"]["libraryItems"]["data"] | ||||
|   >(sortBy(groupingMethod, filteredItems)); | ||||
| 
 | ||||
|   const [groups, setGroups] = useState<GroupLibraryItems>( | ||||
|     getGroups(langui, groupingMethod, sortedItems) | ||||
|   ); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     setFilteredItems( | ||||
|       filterItems(showSubitems, props.libraryItems.libraryItems.data) | ||||
|     ); | ||||
|   }, [showSubitems, props.libraryItems.libraryItems.data]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     setSortedItem(sortBy(sortingMethod, filteredItems)); | ||||
|   }, [filteredItems, sortingMethod]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     setGroups(getGroups(langui, groupingMethod, sortedItems)); | ||||
|   }, [langui, groupingMethod, sortedItems]); | ||||
| 
 | ||||
|   const subPanel = ( | ||||
|     <SubPanel> | ||||
|       <PanelHeader | ||||
|         icon="library_books" | ||||
|         title={langui.main_library} | ||||
|         title={langui.library} | ||||
|         description={langui.library_description} | ||||
|       /> | ||||
| 
 | ||||
|       <div className="flex flex-row gap-2 place-items-center"> | ||||
|         <p className="flex-shrink-0">{langui.group_by}:</p> | ||||
|         <Select | ||||
|           className="w-full" | ||||
|           options={[langui.category, langui.type, langui.release_year]} | ||||
|           state={groupingMethod} | ||||
|           setState={setGroupingMethod} | ||||
|           allowEmpty | ||||
|         /> | ||||
|       </div> | ||||
| 
 | ||||
|       <div className="flex flex-row gap-2 place-items-center"> | ||||
|         <p className="flex-shrink-0">{langui.order_by}:</p> | ||||
|         <Select | ||||
|           className="w-full" | ||||
|           options={[langui.name, langui.price, langui.release_date]} | ||||
|           state={sortingMethod} | ||||
|           setState={setSortingMethod} | ||||
|         /> | ||||
|       </div> | ||||
| 
 | ||||
|       <div className="flex flex-row gap-2 place-items-center"> | ||||
|         <p className="flex-shrink-0">{langui.show_subitems}:</p> | ||||
|         <Switch state={showSubitems} setState={setShowSubitems} /> | ||||
|       </div> | ||||
|     </SubPanel> | ||||
|   ); | ||||
|   const contentPanel = ( | ||||
|     <ContentPanel width={ContentPanelWidthSizes.large}> | ||||
|       <div className="grid gap-8 items-end mobile:grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(13rem,1fr))]"> | ||||
|         {props.libraryItems.libraryItems.data.map((item) => ( | ||||
|           <LibraryItemsPreview key={item.id} item={item.attributes} /> | ||||
|         ))} | ||||
|       </div> | ||||
|       {[...groups].map(([name, items]) => ( | ||||
|         <> | ||||
|           {items.length > 0 && ( | ||||
|             <> | ||||
|               <h2 className="text-2xl pb-2 pt-10 first-of-type:pt-0">{name}</h2> | ||||
|               <div | ||||
|                 key={name} | ||||
|                 className="grid gap-8 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) => ( | ||||
|                   <LibraryItemsPreview key={item.id} item={item.attributes} /> | ||||
|                 ))} | ||||
|               </div> | ||||
|             </> | ||||
|           )} | ||||
|         </> | ||||
|       ))} | ||||
|     </ContentPanel> | ||||
|   ); | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       navTitle={langui.main_library} | ||||
|       navTitle={langui.library} | ||||
|       langui={langui} | ||||
|       subPanel={subPanel} | ||||
|       contentPanel={contentPanel} | ||||
| @ -67,3 +145,159 @@ export const getStaticProps: GetStaticProps = async (context) => { | ||||
|     return { props: {} }; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| function getGroups( | ||||
|   langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"], | ||||
|   groupByType: number, | ||||
|   items: LibraryProps["libraryItems"]["libraryItems"]["data"] | ||||
| ): GroupLibraryItems { | ||||
|   switch (groupByType) { | ||||
|     case 0: | ||||
|       return new Map(); | ||||
| 
 | ||||
|     case 1: | ||||
|       const groupType: GroupLibraryItems = new Map(); | ||||
|       groupType.set(langui.audio, []); | ||||
|       groupType.set(langui.game, []); | ||||
|       groupType.set(langui.textual, []); | ||||
|       groupType.set(langui.video, []); | ||||
|       groupType.set(langui.other, []); | ||||
|       groupType.set(langui.no_type, []); | ||||
|       items.map((item) => { | ||||
|         if (item.attributes.metadata.length > 0) { | ||||
|           switch (item.attributes.metadata[0].__typename) { | ||||
|             case "ComponentMetadataAudio": | ||||
|               groupType.get(langui.audio)?.push(item); | ||||
|               break; | ||||
|             case "ComponentMetadataGame": | ||||
|               groupType.get(langui.game)?.push(item); | ||||
|               break; | ||||
|             case "ComponentMetadataBooks": | ||||
|               groupType.get(langui.textual)?.push(item); | ||||
|               break; | ||||
|             case "ComponentMetadataVideo": | ||||
|               groupType.get(langui.video)?.push(item); | ||||
|               break; | ||||
|             case "ComponentMetadataOther": | ||||
|               switch ( | ||||
|                 item.attributes.metadata[0].subtype.data.attributes.slug | ||||
|               ) { | ||||
|                 case "audio-case": | ||||
|                   groupType.get(langui.audio)?.push(item); | ||||
|                   break; | ||||
| 
 | ||||
|                 case "video-case": | ||||
|                   groupType.get(langui.video)?.push(item); | ||||
|                   break; | ||||
| 
 | ||||
|                 case "game-case": | ||||
|                   groupType.get(langui.game)?.push(item); | ||||
|                   break; | ||||
| 
 | ||||
|                 default: | ||||
|                   groupType.get(langui.other)?.push(item); | ||||
|                   break; | ||||
|               } | ||||
| 
 | ||||
|               break; | ||||
|           } | ||||
|         } else { | ||||
|           groupType.get(langui.no_type)?.push(item); | ||||
|         } | ||||
|       }); | ||||
|       return groupType; | ||||
| 
 | ||||
|     case 2: | ||||
|       const years: number[] = []; | ||||
|       items.map((item) => { | ||||
|         if (item.attributes.release_date) { | ||||
|           if (!years.includes(item.attributes.release_date.year)) | ||||
|             years.push(item.attributes.release_date.year); | ||||
|         } | ||||
|       }); | ||||
|       const groupYear: GroupLibraryItems = new Map(); | ||||
|       years.sort(); | ||||
|       years.map((year) => { | ||||
|         groupYear.set(year.toString(), []); | ||||
|       }); | ||||
|       groupYear.set(langui.no_year, []); | ||||
|       items.map((item) => { | ||||
|         if (item.attributes.release_date) { | ||||
|           groupYear | ||||
|             .get(item.attributes.release_date.year.toString()) | ||||
|             ?.push(item); | ||||
|         } else { | ||||
|           groupYear.get(langui.no_year)?.push(item); | ||||
|         } | ||||
|       }); | ||||
| 
 | ||||
|       return groupYear; | ||||
| 
 | ||||
|     default: | ||||
|       const groupDefault: GroupLibraryItems = new Map(); | ||||
|       groupDefault.set("", items); | ||||
|       return groupDefault; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function filterItems( | ||||
|   showSubitems: boolean, | ||||
|   items: LibraryProps["libraryItems"]["libraryItems"]["data"] | ||||
| ): LibraryProps["libraryItems"]["libraryItems"]["data"] { | ||||
|   return [...items].filter((item) => { | ||||
|     let result = true; | ||||
|     if (!showSubitems && !item.attributes.root_item) result = false; | ||||
|     if ( | ||||
|       item.attributes.metadata.length > 0 && | ||||
|       item.attributes.metadata[0].__typename === "ComponentMetadataOther" && | ||||
|       (item.attributes.metadata[0].subtype.data.attributes.slug === | ||||
|         "variant-set" || | ||||
|         item.attributes.metadata[0].subtype.data.attributes.slug === | ||||
|           "relation-set") | ||||
|     ) | ||||
|       result = false; | ||||
|     return result; | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| function sortBy( | ||||
|   orderByType: number, | ||||
|   items: LibraryProps["libraryItems"]["libraryItems"]["data"] | ||||
| ): LibraryProps["libraryItems"]["libraryItems"]["data"] { | ||||
|   switch (orderByType) { | ||||
|     case 0: | ||||
|       return [...items].sort((a, b) => { | ||||
|         const titleA = prettyinlineTitle( | ||||
|           "", | ||||
|           a.attributes.title, | ||||
|           a.attributes.subtitle | ||||
|         ); | ||||
|         const titleB = prettyinlineTitle( | ||||
|           "", | ||||
|           b.attributes.title, | ||||
|           b.attributes.subtitle | ||||
|         ); | ||||
|         return titleA.localeCompare(titleB); | ||||
|       }); | ||||
|     case 1: | ||||
|       return [...items].sort((a, b) => { | ||||
|         const priceA = a.attributes.price ? a.attributes.price.amount : 99999; | ||||
|         const priceB = b.attributes.price ? b.attributes.price.amount : 99999; | ||||
|         return priceA - priceB; | ||||
|       }); | ||||
|     case 2: | ||||
|       return [...items].sort((a, b) => { | ||||
|         const dateA = | ||||
|           a.attributes.release_date !== null | ||||
|             ? prettyDate(a.attributes.release_date) | ||||
|             : "9999"; | ||||
|         const dateB = | ||||
|           b.attributes.release_date !== null | ||||
|             ? prettyDate(b.attributes.release_date) | ||||
|             : "9999"; | ||||
|         return dateA.localeCompare(dateB); | ||||
|       }); | ||||
|     default: | ||||
|       return items; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -15,7 +15,7 @@ export default function Merch(props: MerchProps): JSX.Element { | ||||
|     <SubPanel> | ||||
|       <PanelHeader | ||||
|         icon="store" | ||||
|         title={langui.main_merch} | ||||
|         title={langui.merch} | ||||
|         description={langui.merch_description} | ||||
|       /> | ||||
|     </SubPanel> | ||||
| @ -23,7 +23,7 @@ export default function Merch(props: MerchProps): JSX.Element { | ||||
| 
 | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       navTitle={langui.main_merch} | ||||
|       navTitle={langui.merch} | ||||
|       langui={langui} | ||||
|       subPanel={subPanel} | ||||
|     /> | ||||
|  | ||||
| @ -15,7 +15,7 @@ export default function News(props: NewsProps): JSX.Element { | ||||
|     <SubPanel> | ||||
|       <PanelHeader | ||||
|         icon="feed" | ||||
|         title={langui.main_news} | ||||
|         title={langui.news} | ||||
|         description={langui.news_description} | ||||
|       /> | ||||
|     </SubPanel> | ||||
| @ -23,7 +23,7 @@ export default function News(props: NewsProps): JSX.Element { | ||||
| 
 | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       navTitle={langui.main_news} | ||||
|       navTitle={langui.news} | ||||
|       langui={langui} | ||||
|       subPanel={subPanel} | ||||
|     /> | ||||
|  | ||||
| @ -16,7 +16,7 @@ export default function Hubs(props: WikiProps): JSX.Element { | ||||
|     <SubPanel> | ||||
|       <PanelHeader | ||||
|         icon="travel_explore" | ||||
|         title={langui.main_wiki} | ||||
|         title={langui.wiki} | ||||
|         description={langui.wiki_description} | ||||
|       /> | ||||
|     </SubPanel> | ||||
| @ -25,7 +25,7 @@ export default function Hubs(props: WikiProps): JSX.Element { | ||||
| 
 | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       navTitle={langui.main_wiki} | ||||
|       navTitle={langui.wiki} | ||||
|       langui={langui} | ||||
|       contentPanel={contentPanel} | ||||
|       subPanel={subPanel} | ||||
|  | ||||
| @ -64,15 +64,15 @@ export function prettyItemType( | ||||
|   const type = metadata.__typename; | ||||
|   switch (metadata.__typename) { | ||||
|     case "ComponentMetadataAudio": | ||||
|       return langui.library_item_type_audio; | ||||
|       return langui.audio; | ||||
|     case "ComponentMetadataBooks": | ||||
|       return langui.library_item_type_textual; | ||||
|       return langui.textual; | ||||
|     case "ComponentMetadataGame": | ||||
|       return langui.library_item_type_game; | ||||
|       return langui.game; | ||||
|     case "ComponentMetadataVideo": | ||||
|       return langui.library_item_type_video; | ||||
|       return langui.video; | ||||
|     case "ComponentMetadataOther": | ||||
|       return langui.library_item_type_other; | ||||
|       return langui.other; | ||||
|     default: | ||||
|       return ""; | ||||
|   } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint