Abstracted Image component for Strapi images + fixed key react problem
This commit is contained in:
		
							parent
							
								
									1a4b73f1f5
								
							
						
					
					
						commit
						c89fdbb499
					
				| @ -205,8 +205,6 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { | ||||
|           <h2 className="text-2xl">Select a language</h2> | ||||
|           <div className="flex flex-wrap flex-row gap-2"> | ||||
|             {router.locales?.sort().map((locale) => ( | ||||
|               <> | ||||
|                 {locale !== "xx" ? ( | ||||
|               <Button | ||||
|                 key={locale} | ||||
|                 active={locale === router.locale} | ||||
| @ -215,10 +213,6 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { | ||||
|               > | ||||
|                 {prettyLanguage(locale)} | ||||
|               </Button> | ||||
|                 ) : ( | ||||
|                   "" | ||||
|                 )} | ||||
|               </> | ||||
|             ))} | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
| @ -2,9 +2,9 @@ import { | ||||
|   GetContentQuery, | ||||
|   GetWebsiteInterfaceQuery, | ||||
| } from "graphql/operations-types"; | ||||
| import { getAssetURL, ImageQuality, prettySlug } from "queries/helpers"; | ||||
| import Image from "next/image"; | ||||
| import { prettySlug } from "queries/helpers"; | ||||
| import Button from "components/Button"; | ||||
| import Img, { ImageQuality } from "components/Img"; | ||||
| 
 | ||||
| export type ThumbnailHeaderProps = { | ||||
|   content: { | ||||
| @ -28,12 +28,11 @@ export default function ThumbnailHeader( | ||||
|       <div className="grid place-items-center gap-12  mb-12"> | ||||
|         <div className="drop-shadow-dark-lg"> | ||||
|           {content.thumbnail.data ? ( | ||||
|             <Image | ||||
|             <Img | ||||
|               className=" rounded-xl" | ||||
|               src={getAssetURL(content.thumbnail.data.attributes.url, ImageQuality.Medium)} | ||||
|               alt={content.thumbnail.data.attributes.alternativeText} | ||||
|               width={content.thumbnail.data.attributes.width} | ||||
|               height={content.thumbnail.data.attributes.height} | ||||
|               image={content.thumbnail.data.attributes} | ||||
|               quality={ImageQuality.Medium} | ||||
|               priority | ||||
|             /> | ||||
|           ) : ( | ||||
|             <div className="w-full aspect-[4/3] bg-light rounded-xl"></div> | ||||
|  | ||||
							
								
								
									
										88
									
								
								src/components/Img.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								src/components/Img.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | ||||
| import { GetLibraryItemsPreviewQuery } from "graphql/operations-types"; | ||||
| import { ImageProps } from "next/image"; | ||||
| import Image from "next/image"; | ||||
| 
 | ||||
| export enum ImageQuality { | ||||
|   Small = "small", | ||||
|   Medium = "medium", | ||||
|   Large = "large", | ||||
|   Og = "og", | ||||
| } | ||||
| 
 | ||||
| export function getAssetURL(url: string, quality?: ImageQuality): string { | ||||
|   if (!quality) quality = ImageQuality.Small; | ||||
|   url = url.replace(/^\/uploads/, "/" + quality); | ||||
|   url = url.replace(/.jpg$/, ".webp"); | ||||
|   url = url.replace(/.png$/, ".webp"); | ||||
|   return process.env.NEXT_PUBLIC_URL_IMG + url; | ||||
| } | ||||
| 
 | ||||
| export function getImgSizesByMaxSize( | ||||
|   width: number, | ||||
|   height: number, | ||||
|   maxSize: number | ||||
| ): { width: number; height: number } { | ||||
|   if (width > height) { | ||||
|     if (width < maxSize) return { width: width, height: height }; | ||||
|     return { width: maxSize, height: (height / width) * maxSize }; | ||||
|   } else { | ||||
|     if (height < maxSize) return { width: width, height: height }; | ||||
|     return { width: (width / height) * maxSize, height: maxSize }; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export function getImgSizesByQuality( | ||||
|   width: number, | ||||
|   height: number, | ||||
|   quality: ImageQuality | ||||
| ): { width: number; height: number } { | ||||
|   switch (quality) { | ||||
|     case ImageQuality.Og: | ||||
|       return getImgSizesByMaxSize(width, height, 512); | ||||
|     case ImageQuality.Small: | ||||
|       return getImgSizesByMaxSize(width, height, 512); | ||||
|     case ImageQuality.Medium: | ||||
|       return getImgSizesByMaxSize(width, height, 1024); | ||||
|     case ImageQuality.Large: | ||||
|       return getImgSizesByMaxSize(width, height, 2048); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| type ImgProps = { | ||||
|   className?: string; | ||||
|   image: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["thumbnail"]["data"]["attributes"]; | ||||
|   quality?: ImageQuality; | ||||
|   alt?: ImageProps["alt"]; | ||||
|   layout?: ImageProps["layout"]; | ||||
|   objectFit?: ImageProps["objectFit"]; | ||||
|   priority?: ImageProps["priority"]; | ||||
| }; | ||||
| 
 | ||||
| export default function Img(props: ImgProps): JSX.Element { | ||||
|   if (props.layout == "fill") { | ||||
|     return ( | ||||
|       <Image | ||||
|         src={getAssetURL(props.image.url, props.quality)} | ||||
|         alt={props.alt ? props.alt : props.image.alternativeText} | ||||
|         layout={props.layout} | ||||
|         objectFit={props.objectFit} | ||||
|         priority={props.priority} | ||||
|       /> | ||||
|     ); | ||||
|   } else { | ||||
|     return ( | ||||
|       <Image | ||||
|         src={getAssetURL(props.image.url, props.quality)} | ||||
|         alt={props.alt ? props.alt : props.image.alternativeText} | ||||
|         {...getImgSizesByQuality( | ||||
|           props.image.width, | ||||
|           props.image.height, | ||||
|           props.quality ? props.quality : ImageQuality.Small | ||||
|         )} | ||||
|         layout={props.layout} | ||||
|         objectFit={props.objectFit} | ||||
|         priority={props.priority} | ||||
|       /> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -1,8 +1,8 @@ | ||||
| import Link from "next/link"; | ||||
| import { GetContentsQuery } from "graphql/operations-types"; | ||||
| import { getAssetURL, prettySlug } from "queries/helpers"; | ||||
| import Image from "next/image"; | ||||
| import { prettySlug } from "queries/helpers"; | ||||
| import Chip from "components/Chip"; | ||||
| import Img, { ImageQuality } from "components/Img"; | ||||
| 
 | ||||
| export type LibraryContentPreviewProps = { | ||||
|   item: { | ||||
| @ -23,12 +23,10 @@ export default function LibraryContentPreview( | ||||
|     <Link href={"/library/content/" + item.slug} passHref> | ||||
|       <div className="drop-shadow-dark-xl cursor-pointer grid items-end fine:[--cover-opacity:0] hover:[--cover-opacity:1] hover:scale-[1.02] transition-transform"> | ||||
|         {item.thumbnail.data ? ( | ||||
|           <Image | ||||
|           <Img | ||||
|             className="rounded-md coarse:rounded-b-none" | ||||
|             src={getAssetURL(item.thumbnail.data.attributes.url)} | ||||
|             alt={item.thumbnail.data.attributes.alternativeText} | ||||
|             height={item.thumbnail.data.attributes.height} | ||||
|             width={item.thumbnail.data.attributes.width} | ||||
|             image={item.thumbnail.data.attributes} | ||||
|             quality={ImageQuality.Medium} | ||||
|           /> | ||||
|         ) : ( | ||||
|           <div className="w-full aspect-[3/2] bg-light rounded-lg"></div> | ||||
|  | ||||
| @ -1,20 +1,11 @@ | ||||
| import Link from "next/link"; | ||||
| import { | ||||
|   GetLibraryItemsPreviewQuery, | ||||
|   GetWebsiteInterfaceQuery, | ||||
| } from "graphql/operations-types"; | ||||
| import { | ||||
|   getAssetURL, | ||||
|   prettyDate, | ||||
|   prettyPrice, | ||||
|   prettyItemSubType, | ||||
| } from "queries/helpers"; | ||||
| import Image from "next/image"; | ||||
| import { GetLibraryItemsPreviewQuery } from "graphql/operations-types"; | ||||
| import { prettyDate, prettyPrice, prettyItemSubType } from "queries/helpers"; | ||||
| import Chip from "components/Chip"; | ||||
| import Img, { ImageQuality } from "components/Img"; | ||||
| 
 | ||||
| export type LibraryItemsPreviewProps = { | ||||
|   className?: string; | ||||
|   langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"]; | ||||
|   item: { | ||||
|     slug: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["slug"]; | ||||
|     thumbnail: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["thumbnail"]; | ||||
| @ -30,7 +21,6 @@ export default function LibraryItemsPreview( | ||||
|   props: LibraryItemsPreviewProps | ||||
| ): JSX.Element { | ||||
|   const item = props.item; | ||||
|   const langui = props.langui; | ||||
| 
 | ||||
|   return ( | ||||
|     <Link href={"/library/items/" + item.slug} passHref> | ||||
| @ -38,11 +28,9 @@ export default function LibraryItemsPreview( | ||||
|         className={`drop-shadow-dark-xl cursor-pointer grid items-end hover:rounded-3xl fine:[--cover-opacity:0] hover:[--cover-opacity:1] hover:scale-[1.02] transition-transform ${props.className}`} | ||||
|       > | ||||
|         {item.thumbnail.data ? ( | ||||
|           <Image | ||||
|             src={getAssetURL(item.thumbnail.data.attributes.url)} | ||||
|             alt={item.thumbnail.data.attributes.alternativeText} | ||||
|             height={item.thumbnail.data.attributes.height} | ||||
|             width={item.thumbnail.data.attributes.width} | ||||
|           <Img | ||||
|             image={item.thumbnail.data.attributes} | ||||
|             quality={ImageQuality.Medium} | ||||
|           /> | ||||
|         ) : ( | ||||
|           <div className="w-full aspect-[21/29.7] bg-light rounded-lg"></div> | ||||
|  | ||||
| @ -31,7 +31,11 @@ export default function NavOption(props: NavOptionProps): JSX.Element { | ||||
|         data-tip={` | ||||
|           <div class="px-4 py-3"> | ||||
|           <h3 class="text-2xl">${props.title}</h3> | ||||
|           ${props.subtitle ? `<p class="max-w-[10rem]">${props.subtitle}</p>` : ""} | ||||
|           ${ | ||||
|             props.subtitle | ||||
|               ? `<p class="max-w-[10rem]">${props.subtitle}</p>` | ||||
|               : "" | ||||
|           } | ||||
|           </div> | ||||
|         `}
 | ||||
|         data-for={props.tooltipId} | ||||
|  | ||||
| @ -29,7 +29,9 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|   return ( | ||||
|     <div | ||||
|       id="mainPanel" | ||||
|       className={`flex flex-col justify-center content-start gap-y-2 justify-items-center text-center p-8 ${mainPanelReduced && "px-4"}`} | ||||
|       className={`flex flex-col justify-center content-start gap-y-2 justify-items-center text-center p-8 ${ | ||||
|         mainPanelReduced && "px-4" | ||||
|       }`}
 | ||||
|     > | ||||
|       {mainPanelReduced && isDesktop ? ( | ||||
|         <div className="grid place-items-center gap-4"> | ||||
|  | ||||
| @ -38,10 +38,10 @@ export function useMediaThin() { | ||||
| } | ||||
| 
 | ||||
| export function useMediaMobile() { | ||||
|     return useMediaQuery("(max-width: 150ch)"); | ||||
|     return useMediaQuery("(max-width: 120ch)"); | ||||
| } | ||||
| 
 | ||||
| export function useMediaDesktop() { | ||||
|     return useMediaQuery("(min-width: 150ch)"); | ||||
|     return useMediaQuery("(min-width: 120ch)"); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -36,7 +36,10 @@ class MyDocument extends Document { | ||||
|           <meta name="twitter:title" content={siteTitle}></meta> | ||||
|           <meta name="twitter:description" content={siteDescription}></meta> | ||||
|           <meta name="twitter:image" content={thumbnailImage}></meta> | ||||
|           <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /> | ||||
|           <meta | ||||
|             name="apple-mobile-web-app-status-bar-style" | ||||
|             content="black-translucent" | ||||
|           /> | ||||
|           <link rel="manifest" href="manifest.json" /> | ||||
|           <meta name="theme-color" content="#FFEDD8" /> | ||||
|         </Head> | ||||
|  | ||||
| @ -20,7 +20,13 @@ export default function AboutUs(props: AboutUsProps): JSX.Element { | ||||
|       /> | ||||
|     </SubPanel> | ||||
|   ); | ||||
|   return <AppLayout title={langui.main_about_us} langui={langui} subPanel={subPanel} />; | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       title={langui.main_about_us} | ||||
|       langui={langui} | ||||
|       subPanel={subPanel} | ||||
|     /> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export const getStaticProps: GetStaticProps = async (context) => { | ||||
|  | ||||
| @ -1,13 +0,0 @@ | ||||
| // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
 | ||||
| import type { NextApiRequest, NextApiResponse } from "next"; | ||||
| 
 | ||||
| type Data = { | ||||
|   name: string; | ||||
| }; | ||||
| 
 | ||||
| export default function handler( | ||||
|   req: NextApiRequest, | ||||
|   res: NextApiResponse<Data> | ||||
| ) { | ||||
|   res.status(200).json({ name: "John Lenon" }); | ||||
| } | ||||
| @ -20,7 +20,13 @@ export default function Archives(props: ArchivesProps): JSX.Element { | ||||
|       /> | ||||
|     </SubPanel> | ||||
|   ); | ||||
|   return <AppLayout title={langui.main_archives} langui={langui} subPanel={subPanel} />; | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       title={langui.main_archives} | ||||
|       langui={langui} | ||||
|       subPanel={subPanel} | ||||
|     /> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export const getStaticProps: GetStaticProps = async (context) => { | ||||
|  | ||||
| @ -20,7 +20,13 @@ export default function Chronicles(props: ChroniclesProps): JSX.Element { | ||||
|       /> | ||||
|     </SubPanel> | ||||
|   ); | ||||
|   return <AppLayout title={langui.main_chronicles} langui={langui} subPanel={subPanel} />; | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       title={langui.main_chronicles} | ||||
|       langui={langui} | ||||
|       subPanel={subPanel} | ||||
|     /> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export const getStaticProps: GetStaticProps = async (context) => { | ||||
|  | ||||
| @ -58,7 +58,7 @@ export default function Editor(props: EditorProps): JSX.Element { | ||||
|                 codeBlockStyle: "fenced", | ||||
|                 bulletListMarker: "-", | ||||
|                 emDelimiter: "*", | ||||
|                 strongDelimiter: "**" | ||||
|                 strongDelimiter: "**", | ||||
|               }); | ||||
| 
 | ||||
|               let paste = event.clipboardData.getData("text/html"); | ||||
|  | ||||
| @ -17,7 +17,11 @@ export default function Gallery(props: GalleryProps): JSX.Element { | ||||
|   ); | ||||
| 
 | ||||
|   return ( | ||||
|     <AppLayout title={langui.main_gallery} langui={langui} contentPanel={contentPanel} /> | ||||
|     <AppLayout | ||||
|       title={langui.main_gallery} | ||||
|       langui={langui} | ||||
|       contentPanel={contentPanel} | ||||
|     /> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -10,10 +10,8 @@ import { | ||||
| } from "graphql/operations-types"; | ||||
| import ContentPanel from "components/Panels/ContentPanel"; | ||||
| import HorizontalLine from "components/HorizontalLine"; | ||||
| import Markdown from "markdown-to-jsx"; | ||||
| import SubPanel from "components/Panels/SubPanel"; | ||||
| import ReturnButton from "components/PanelComponents/ReturnButton"; | ||||
| import SceneBreak from "components/Markdown/SceneBreak"; | ||||
| import ThumbnailHeader from "components/Content/ThumbnailHeader"; | ||||
| import AppLayout from "components/AppLayout"; | ||||
| import Markdawn from "components/Markdown/Markdawn"; | ||||
|  | ||||
| @ -1,11 +1,7 @@ | ||||
| import { GetStaticProps } from "next"; | ||||
| import SubPanel from "components/Panels/SubPanel"; | ||||
| import { | ||||
|   GetWebsiteInterfaceQuery, | ||||
| } from "graphql/operations-types"; | ||||
| import { | ||||
|   getWebsiteInterface, | ||||
| } from "graphql/operations"; | ||||
| import { GetWebsiteInterfaceQuery } from "graphql/operations-types"; | ||||
| import { getWebsiteInterface } from "graphql/operations"; | ||||
| import PanelHeader from "components/PanelComponents/PanelHeader"; | ||||
| import AppLayout from "components/AppLayout"; | ||||
| import NavOption from "components/PanelComponents/NavOption"; | ||||
| @ -38,7 +34,13 @@ export default function Library(props: LibraryProps): JSX.Element { | ||||
|     </SubPanel> | ||||
|   ); | ||||
| 
 | ||||
|   return <AppLayout title={langui.main_library} langui={langui} subPanel={subPanel} />; | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       title={langui.main_library} | ||||
|       langui={langui} | ||||
|       subPanel={subPanel} | ||||
|     /> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export const getStaticProps: GetStaticProps = async (context) => { | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| import ContentPanel, { | ||||
|   ContentPanelWidthSizes, | ||||
| } from "components/Panels/ContentPanel"; | ||||
| import Image from "next/image"; | ||||
| import { GetStaticPaths, GetStaticProps } from "next"; | ||||
| import { | ||||
|   getLibraryItem, | ||||
| @ -16,14 +15,12 @@ import { | ||||
| } from "graphql/operations-types"; | ||||
| import { | ||||
|   convertMmToInch, | ||||
|   getAssetURL, | ||||
|   prettyDate, | ||||
|   prettyinlineTitle, | ||||
|   prettyItemType, | ||||
|   prettyItemSubType, | ||||
|   prettyPrice, | ||||
|   prettySlug, | ||||
|   ImageQuality, | ||||
| } from "queries/helpers"; | ||||
| import SubPanel from "components/Panels/SubPanel"; | ||||
| import ReturnButton from "components/PanelComponents/ReturnButton"; | ||||
| @ -36,6 +33,7 @@ import LibraryItemsPreview from "components/Library/LibraryItemsPreview"; | ||||
| import InsetBox from "components/InsetBox"; | ||||
| import { setSubPanelOpen } from "redux/AppLayoutSlice"; | ||||
| import { useDispatch } from "react-redux"; | ||||
| import Img, { ImageQuality } from "components/Img"; | ||||
| 
 | ||||
| type LibrarySlugProps = { | ||||
|   libraryItem: GetLibraryItemQuery; | ||||
| @ -47,6 +45,11 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|   const langui = props.langui.websiteInterfaces.data[0].attributes; | ||||
|   const dispatch = useDispatch(); | ||||
| 
 | ||||
|   const isVariantSet = | ||||
|     item.metadata.length > 0 && | ||||
|     item.metadata[0].__typename === "ComponentMetadataOther" && | ||||
|     item.metadata[0].subtype.data.attributes.slug === "variant-set"; | ||||
| 
 | ||||
|   const subPanel = ( | ||||
|     <SubPanel> | ||||
|       <ReturnButton | ||||
| @ -83,23 +86,16 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|         /> | ||||
| 
 | ||||
|         {item.subitems.data.length > 0 ? ( | ||||
|           item.metadata.length > 0 && | ||||
|           item.metadata[0].__typename === "ComponentMetadataOther" && | ||||
|           item.metadata[0].subtype.data.attributes.slug === "variant-set" ? ( | ||||
|           <NavOption | ||||
|               title={langui.library_item_variants} | ||||
|               url="#variants" | ||||
|             title={ | ||||
|               isVariantSet | ||||
|                 ? langui.library_item_variants | ||||
|                 : langui.library_item_subitems | ||||
|             } | ||||
|             url={isVariantSet ? "#variants" : "#subitems"} | ||||
|             border={true} | ||||
|             onClick={() => dispatch(setSubPanelOpen(false))} | ||||
|           /> | ||||
|           ) : ( | ||||
|             <NavOption | ||||
|               title={langui.library_item_subitems} | ||||
|               url="#subitems" | ||||
|               border={true} | ||||
|               onClick={() => dispatch(setSubPanelOpen(false))} | ||||
|             /> | ||||
|           ) | ||||
|         ) : ( | ||||
|           "" | ||||
|         )} | ||||
| @ -120,18 +116,14 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|   const contentPanel = ( | ||||
|     <ContentPanel width={ContentPanelWidthSizes.large}> | ||||
|       <div className="grid place-items-center gap-12"> | ||||
|         <div className="drop-shadow-dark-xl w-full h-[50vh] mobile:h-[80vh] mb-16 "> | ||||
|         <div className="drop-shadow-dark-xl w-full h-[50vh] mobile:h-[80vh] mb-16 relative"> | ||||
|           {item.thumbnail.data ? ( | ||||
|             <Image | ||||
|               src={getAssetURL( | ||||
|                 item.thumbnail.data.attributes.url, | ||||
|                 ImageQuality.Medium | ||||
|               )} | ||||
|               alt={item.thumbnail.data.attributes.alternativeText} | ||||
|               width={item.thumbnail.data.attributes.width} | ||||
|               height={item.thumbnail.data.attributes.height} | ||||
|             <Img | ||||
|               image={item.thumbnail.data.attributes} | ||||
|               quality={ImageQuality.Medium} | ||||
|               layout="fill" | ||||
|               objectFit="contain" | ||||
|               priority | ||||
|             /> | ||||
|           ) : ( | ||||
|             <div className="w-full aspect-[21/29.7] bg-light rounded-xl"></div> | ||||
| @ -182,12 +174,9 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|                   className="relative aspect-square hover:scale-[1.02] transition-transform cursor-pointer" | ||||
|                 > | ||||
|                   <div className="bg-light absolute inset-0 rounded-lg shadow-md"></div> | ||||
|                   <Image | ||||
|                   <Img | ||||
|                     className="rounded-lg" | ||||
|                     src={getAssetURL(galleryItem.attributes.url)} | ||||
|                     alt={galleryItem.attributes.alternativeText} | ||||
|                     width={galleryItem.attributes.width} | ||||
|                     height={galleryItem.attributes.height} | ||||
|                     image={galleryItem.attributes} | ||||
|                     layout="fill" | ||||
|                     objectFit="cover" | ||||
|                   /> | ||||
| @ -356,35 +345,24 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|         </InsetBox> | ||||
| 
 | ||||
|         {item.subitems.data.length > 0 ? ( | ||||
|           item.metadata.length > 0 && | ||||
|           item.metadata[0].__typename === "ComponentMetadataOther" && | ||||
|           item.metadata[0].subtype.data.attributes.slug === "variant-set" ? ( | ||||
|             <div id="variants" className="grid place-items-center gap-8 w-full"> | ||||
|               <h2 className="text-2xl">{langui.library_item_variants}</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((variant) => ( | ||||
|                   <LibraryItemsPreview | ||||
|                     key={variant.id} | ||||
|                     item={variant.attributes} | ||||
|                     langui={langui} | ||||
|                   /> | ||||
|                 ))} | ||||
|               </div> | ||||
|             </div> | ||||
|           ) : ( | ||||
|             <div id="subitems" className="grid place-items-center gap-8 w-full"> | ||||
|               <h2 className="text-2xl">{langui.library_item_subitems}</h2> | ||||
|           <div | ||||
|             id={isVariantSet ? "variants" : "subitems"} | ||||
|             className="grid place-items-center gap-8 w-full" | ||||
|           > | ||||
|             <h2 className="text-2xl"> | ||||
|               {isVariantSet | ||||
|                 ? langui.library_item_variants | ||||
|                 : langui.library_item_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) => ( | ||||
|                 <LibraryItemsPreview | ||||
|                   key={subitem.id} | ||||
|                   item={subitem.attributes} | ||||
|                     langui={langui} | ||||
|                 /> | ||||
|               ))} | ||||
|             </div> | ||||
|           </div> | ||||
|           ) | ||||
|         ) : ( | ||||
|           "" | ||||
|         )} | ||||
|  | ||||
| @ -43,11 +43,7 @@ export default function Library(props: LibraryProps): JSX.Element { | ||||
|     <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} | ||||
|             langui={langui} | ||||
|           /> | ||||
|           <LibraryItemsPreview key={item.id} item={item.attributes} /> | ||||
|         ))} | ||||
|       </div> | ||||
|     </ContentPanel> | ||||
|  | ||||
| @ -21,7 +21,9 @@ export default function Merch(props: MerchProps): JSX.Element { | ||||
|     </SubPanel> | ||||
|   ); | ||||
| 
 | ||||
|   return <AppLayout title={langui.main_merch} langui={langui} subPanel={subPanel} />; | ||||
|   return ( | ||||
|     <AppLayout title={langui.main_merch} langui={langui} subPanel={subPanel} /> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export const getStaticProps: GetStaticProps = async (context) => { | ||||
|  | ||||
| @ -21,7 +21,9 @@ export default function News(props: NewsProps): JSX.Element { | ||||
|     </SubPanel> | ||||
|   ); | ||||
| 
 | ||||
|   return <AppLayout title={langui.main_news} langui={langui} subPanel={subPanel} />; | ||||
|   return ( | ||||
|     <AppLayout title={langui.main_news} langui={langui} subPanel={subPanel} /> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export const getStaticProps: GetStaticProps = async (context) => { | ||||
|  | ||||
| @ -72,7 +72,11 @@ export default function DataChronology( | ||||
|         <NavOption | ||||
|           key={era.id} | ||||
|           url={"#" + era.attributes.slug} | ||||
|           title={era.attributes.title.length > 0 ? era.attributes.title[0].title : prettySlug(era.attributes.slug)} | ||||
|           title={ | ||||
|             era.attributes.title.length > 0 | ||||
|               ? era.attributes.title[0].title | ||||
|               : prettySlug(era.attributes.slug) | ||||
|           } | ||||
|           subtitle={ | ||||
|             era.attributes.starting_year + " → " + era.attributes.ending_year | ||||
|           } | ||||
|  | ||||
| @ -3,20 +3,6 @@ import { | ||||
|   GetWebsiteInterfaceQuery, | ||||
| } from "graphql/operations-types"; | ||||
| 
 | ||||
| export enum ImageQuality { | ||||
|   Small = "small", | ||||
|   Medium = "medium", | ||||
|   Large = "large" | ||||
| } | ||||
| 
 | ||||
| export function getAssetURL(url: string, quality?: ImageQuality): string { | ||||
|   if (!quality) quality = ImageQuality.Small; | ||||
|   url = url.replace(/^\/uploads/, "/" + quality); | ||||
|   url = url.replace(/.jpg$/, ".webp"); | ||||
|   url = url.replace(/.png$/, ".webp"); | ||||
|   return process.env.NEXT_PUBLIC_URL_IMG + url; | ||||
| } | ||||
| 
 | ||||
| export function prettyDate( | ||||
|   datePicker: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["release_date"] | ||||
| ): string { | ||||
|  | ||||
| @ -15,8 +15,8 @@ module.exports = { | ||||
|       monospace: ["monospace"], | ||||
|     }, | ||||
|     screens: { | ||||
|       desktop: { min: "150ch" }, | ||||
|       mobile: { max: "150ch" }, | ||||
|       desktop: { min: "120ch" }, | ||||
|       mobile: { max: "120ch" }, | ||||
|       thin: { max: "50ch" }, | ||||
|       coarse: { raw: "(pointer: coarse)" }, | ||||
|       fine: { raw: "(pointer: fine)" }, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint