Abstracted Image component for Strapi images + fixed key react problem
This commit is contained in:
		
							parent
							
								
									1a4b73f1f5
								
							
						
					
					
						commit
						c89fdbb499
					
				| @ -205,20 +205,14 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { | |||||||
|           <h2 className="text-2xl">Select a language</h2> |           <h2 className="text-2xl">Select a language</h2> | ||||||
|           <div className="flex flex-wrap flex-row gap-2"> |           <div className="flex flex-wrap flex-row gap-2"> | ||||||
|             {router.locales?.sort().map((locale) => ( |             {router.locales?.sort().map((locale) => ( | ||||||
|               <> |               <Button | ||||||
|                 {locale !== "xx" ? ( |                 key={locale} | ||||||
|                   <Button |                 active={locale === router.locale} | ||||||
|                     key={locale} |                 href={router.asPath} | ||||||
|                     active={locale === router.locale} |                 locale={locale} | ||||||
|                     href={router.asPath} |               > | ||||||
|                     locale={locale} |                 {prettyLanguage(locale)} | ||||||
|                   > |               </Button> | ||||||
|                     {prettyLanguage(locale)} |  | ||||||
|                   </Button> |  | ||||||
|                 ) : ( |  | ||||||
|                   "" |  | ||||||
|                 )} |  | ||||||
|               </> |  | ||||||
|             ))} |             ))} | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|  | |||||||
| @ -2,9 +2,9 @@ import { | |||||||
|   GetContentQuery, |   GetContentQuery, | ||||||
|   GetWebsiteInterfaceQuery, |   GetWebsiteInterfaceQuery, | ||||||
| } from "graphql/operations-types"; | } from "graphql/operations-types"; | ||||||
| import { getAssetURL, ImageQuality, prettySlug } from "queries/helpers"; | import { prettySlug } from "queries/helpers"; | ||||||
| import Image from "next/image"; |  | ||||||
| import Button from "components/Button"; | import Button from "components/Button"; | ||||||
|  | import Img, { ImageQuality } from "components/Img"; | ||||||
| 
 | 
 | ||||||
| export type ThumbnailHeaderProps = { | export type ThumbnailHeaderProps = { | ||||||
|   content: { |   content: { | ||||||
| @ -28,12 +28,11 @@ export default function ThumbnailHeader( | |||||||
|       <div className="grid place-items-center gap-12  mb-12"> |       <div className="grid place-items-center gap-12  mb-12"> | ||||||
|         <div className="drop-shadow-dark-lg"> |         <div className="drop-shadow-dark-lg"> | ||||||
|           {content.thumbnail.data ? ( |           {content.thumbnail.data ? ( | ||||||
|             <Image |             <Img | ||||||
|               className=" rounded-xl" |               className=" rounded-xl" | ||||||
|               src={getAssetURL(content.thumbnail.data.attributes.url, ImageQuality.Medium)} |               image={content.thumbnail.data.attributes} | ||||||
|               alt={content.thumbnail.data.attributes.alternativeText} |               quality={ImageQuality.Medium} | ||||||
|               width={content.thumbnail.data.attributes.width} |               priority | ||||||
|               height={content.thumbnail.data.attributes.height} |  | ||||||
|             /> |             /> | ||||||
|           ) : ( |           ) : ( | ||||||
|             <div className="w-full aspect-[4/3] bg-light rounded-xl"></div> |             <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 Link from "next/link"; | ||||||
| import { GetContentsQuery } from "graphql/operations-types"; | import { GetContentsQuery } from "graphql/operations-types"; | ||||||
| import { getAssetURL, prettySlug } from "queries/helpers"; | import { prettySlug } from "queries/helpers"; | ||||||
| import Image from "next/image"; |  | ||||||
| import Chip from "components/Chip"; | import Chip from "components/Chip"; | ||||||
|  | import Img, { ImageQuality } from "components/Img"; | ||||||
| 
 | 
 | ||||||
| export type LibraryContentPreviewProps = { | export type LibraryContentPreviewProps = { | ||||||
|   item: { |   item: { | ||||||
| @ -23,12 +23,10 @@ export default function LibraryContentPreview( | |||||||
|     <Link href={"/library/content/" + item.slug} passHref> |     <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"> |       <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 ? ( |         {item.thumbnail.data ? ( | ||||||
|           <Image |           <Img | ||||||
|             className="rounded-md coarse:rounded-b-none" |             className="rounded-md coarse:rounded-b-none" | ||||||
|             src={getAssetURL(item.thumbnail.data.attributes.url)} |             image={item.thumbnail.data.attributes} | ||||||
|             alt={item.thumbnail.data.attributes.alternativeText} |             quality={ImageQuality.Medium} | ||||||
|             height={item.thumbnail.data.attributes.height} |  | ||||||
|             width={item.thumbnail.data.attributes.width} |  | ||||||
|           /> |           /> | ||||||
|         ) : ( |         ) : ( | ||||||
|           <div className="w-full aspect-[3/2] bg-light rounded-lg"></div> |           <div className="w-full aspect-[3/2] bg-light rounded-lg"></div> | ||||||
|  | |||||||
| @ -1,20 +1,11 @@ | |||||||
| import Link from "next/link"; | import Link from "next/link"; | ||||||
| import { | import { GetLibraryItemsPreviewQuery } from "graphql/operations-types"; | ||||||
|   GetLibraryItemsPreviewQuery, | import { prettyDate, prettyPrice, prettyItemSubType } from "queries/helpers"; | ||||||
|   GetWebsiteInterfaceQuery, |  | ||||||
| } from "graphql/operations-types"; |  | ||||||
| import { |  | ||||||
|   getAssetURL, |  | ||||||
|   prettyDate, |  | ||||||
|   prettyPrice, |  | ||||||
|   prettyItemSubType, |  | ||||||
| } from "queries/helpers"; |  | ||||||
| import Image from "next/image"; |  | ||||||
| import Chip from "components/Chip"; | import Chip from "components/Chip"; | ||||||
|  | import Img, { ImageQuality } from "components/Img"; | ||||||
| 
 | 
 | ||||||
| export type LibraryItemsPreviewProps = { | export type LibraryItemsPreviewProps = { | ||||||
|   className?: string; |   className?: string; | ||||||
|   langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"]; |  | ||||||
|   item: { |   item: { | ||||||
|     slug: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["slug"]; |     slug: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["slug"]; | ||||||
|     thumbnail: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["thumbnail"]; |     thumbnail: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["thumbnail"]; | ||||||
| @ -30,7 +21,6 @@ export default function LibraryItemsPreview( | |||||||
|   props: LibraryItemsPreviewProps |   props: LibraryItemsPreviewProps | ||||||
| ): JSX.Element { | ): JSX.Element { | ||||||
|   const item = props.item; |   const item = props.item; | ||||||
|   const langui = props.langui; |  | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Link href={"/library/items/" + item.slug} passHref> |     <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}`} |         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 ? ( |         {item.thumbnail.data ? ( | ||||||
|           <Image |           <Img | ||||||
|             src={getAssetURL(item.thumbnail.data.attributes.url)} |             image={item.thumbnail.data.attributes} | ||||||
|             alt={item.thumbnail.data.attributes.alternativeText} |             quality={ImageQuality.Medium} | ||||||
|             height={item.thumbnail.data.attributes.height} |  | ||||||
|             width={item.thumbnail.data.attributes.width} |  | ||||||
|           /> |           /> | ||||||
|         ) : ( |         ) : ( | ||||||
|           <div className="w-full aspect-[21/29.7] bg-light rounded-lg"></div> |           <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={` |         data-tip={` | ||||||
|           <div class="px-4 py-3"> |           <div class="px-4 py-3"> | ||||||
|           <h3 class="text-2xl">${props.title}</h3> |           <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> |           </div> | ||||||
|         `}
 |         `}
 | ||||||
|         data-for={props.tooltipId} |         data-for={props.tooltipId} | ||||||
|  | |||||||
| @ -29,7 +29,9 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | |||||||
|   return ( |   return ( | ||||||
|     <div |     <div | ||||||
|       id="mainPanel" |       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 ? ( |       {mainPanelReduced && isDesktop ? ( | ||||||
|         <div className="grid place-items-center gap-4"> |         <div className="grid place-items-center gap-4"> | ||||||
|  | |||||||
| @ -38,10 +38,10 @@ export function useMediaThin() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function useMediaMobile() { | export function useMediaMobile() { | ||||||
|     return useMediaQuery("(max-width: 150ch)"); |     return useMediaQuery("(max-width: 120ch)"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function useMediaDesktop() { | 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:title" content={siteTitle}></meta> | ||||||
|           <meta name="twitter:description" content={siteDescription}></meta> |           <meta name="twitter:description" content={siteDescription}></meta> | ||||||
|           <meta name="twitter:image" content={thumbnailImage}></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" /> |           <link rel="manifest" href="manifest.json" /> | ||||||
|           <meta name="theme-color" content="#FFEDD8" /> |           <meta name="theme-color" content="#FFEDD8" /> | ||||||
|         </Head> |         </Head> | ||||||
|  | |||||||
| @ -20,7 +20,13 @@ export default function AboutUs(props: AboutUsProps): JSX.Element { | |||||||
|       /> |       /> | ||||||
|     </SubPanel> |     </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) => { | 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> |     </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) => { | export const getStaticProps: GetStaticProps = async (context) => { | ||||||
|  | |||||||
| @ -20,7 +20,13 @@ export default function Chronicles(props: ChroniclesProps): JSX.Element { | |||||||
|       /> |       /> | ||||||
|     </SubPanel> |     </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) => { | export const getStaticProps: GetStaticProps = async (context) => { | ||||||
|  | |||||||
| @ -58,7 +58,7 @@ export default function Editor(props: EditorProps): JSX.Element { | |||||||
|                 codeBlockStyle: "fenced", |                 codeBlockStyle: "fenced", | ||||||
|                 bulletListMarker: "-", |                 bulletListMarker: "-", | ||||||
|                 emDelimiter: "*", |                 emDelimiter: "*", | ||||||
|                 strongDelimiter: "**" |                 strongDelimiter: "**", | ||||||
|               }); |               }); | ||||||
| 
 | 
 | ||||||
|               let paste = event.clipboardData.getData("text/html"); |               let paste = event.clipboardData.getData("text/html"); | ||||||
|  | |||||||
| @ -17,7 +17,11 @@ export default function Gallery(props: GalleryProps): JSX.Element { | |||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   return ( |   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"; | } from "graphql/operations-types"; | ||||||
| import ContentPanel from "components/Panels/ContentPanel"; | import ContentPanel from "components/Panels/ContentPanel"; | ||||||
| import HorizontalLine from "components/HorizontalLine"; | import HorizontalLine from "components/HorizontalLine"; | ||||||
| import Markdown from "markdown-to-jsx"; |  | ||||||
| import SubPanel from "components/Panels/SubPanel"; | import SubPanel from "components/Panels/SubPanel"; | ||||||
| import ReturnButton from "components/PanelComponents/ReturnButton"; | import ReturnButton from "components/PanelComponents/ReturnButton"; | ||||||
| import SceneBreak from "components/Markdown/SceneBreak"; |  | ||||||
| import ThumbnailHeader from "components/Content/ThumbnailHeader"; | import ThumbnailHeader from "components/Content/ThumbnailHeader"; | ||||||
| import AppLayout from "components/AppLayout"; | import AppLayout from "components/AppLayout"; | ||||||
| import Markdawn from "components/Markdown/Markdawn"; | import Markdawn from "components/Markdown/Markdawn"; | ||||||
|  | |||||||
| @ -1,11 +1,7 @@ | |||||||
| import { GetStaticProps } from "next"; | import { GetStaticProps } from "next"; | ||||||
| import SubPanel from "components/Panels/SubPanel"; | import SubPanel from "components/Panels/SubPanel"; | ||||||
| import { | import { GetWebsiteInterfaceQuery } from "graphql/operations-types"; | ||||||
|   GetWebsiteInterfaceQuery, | import { getWebsiteInterface } from "graphql/operations"; | ||||||
| } from "graphql/operations-types"; |  | ||||||
| import { |  | ||||||
|   getWebsiteInterface, |  | ||||||
| } from "graphql/operations"; |  | ||||||
| import PanelHeader from "components/PanelComponents/PanelHeader"; | import PanelHeader from "components/PanelComponents/PanelHeader"; | ||||||
| import AppLayout from "components/AppLayout"; | import AppLayout from "components/AppLayout"; | ||||||
| import NavOption from "components/PanelComponents/NavOption"; | import NavOption from "components/PanelComponents/NavOption"; | ||||||
| @ -38,7 +34,13 @@ export default function Library(props: LibraryProps): JSX.Element { | |||||||
|     </SubPanel> |     </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) => { | export const getStaticProps: GetStaticProps = async (context) => { | ||||||
|  | |||||||
| @ -1,7 +1,6 @@ | |||||||
| import ContentPanel, { | import ContentPanel, { | ||||||
|   ContentPanelWidthSizes, |   ContentPanelWidthSizes, | ||||||
| } from "components/Panels/ContentPanel"; | } from "components/Panels/ContentPanel"; | ||||||
| import Image from "next/image"; |  | ||||||
| import { GetStaticPaths, GetStaticProps } from "next"; | import { GetStaticPaths, GetStaticProps } from "next"; | ||||||
| import { | import { | ||||||
|   getLibraryItem, |   getLibraryItem, | ||||||
| @ -16,14 +15,12 @@ import { | |||||||
| } from "graphql/operations-types"; | } from "graphql/operations-types"; | ||||||
| import { | import { | ||||||
|   convertMmToInch, |   convertMmToInch, | ||||||
|   getAssetURL, |  | ||||||
|   prettyDate, |   prettyDate, | ||||||
|   prettyinlineTitle, |   prettyinlineTitle, | ||||||
|   prettyItemType, |   prettyItemType, | ||||||
|   prettyItemSubType, |   prettyItemSubType, | ||||||
|   prettyPrice, |   prettyPrice, | ||||||
|   prettySlug, |   prettySlug, | ||||||
|   ImageQuality, |  | ||||||
| } from "queries/helpers"; | } from "queries/helpers"; | ||||||
| import SubPanel from "components/Panels/SubPanel"; | import SubPanel from "components/Panels/SubPanel"; | ||||||
| import ReturnButton from "components/PanelComponents/ReturnButton"; | import ReturnButton from "components/PanelComponents/ReturnButton"; | ||||||
| @ -36,6 +33,7 @@ import LibraryItemsPreview from "components/Library/LibraryItemsPreview"; | |||||||
| import InsetBox from "components/InsetBox"; | import InsetBox from "components/InsetBox"; | ||||||
| import { setSubPanelOpen } from "redux/AppLayoutSlice"; | import { setSubPanelOpen } from "redux/AppLayoutSlice"; | ||||||
| import { useDispatch } from "react-redux"; | import { useDispatch } from "react-redux"; | ||||||
|  | import Img, { ImageQuality } from "components/Img"; | ||||||
| 
 | 
 | ||||||
| type LibrarySlugProps = { | type LibrarySlugProps = { | ||||||
|   libraryItem: GetLibraryItemQuery; |   libraryItem: GetLibraryItemQuery; | ||||||
| @ -46,7 +44,12 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | |||||||
|   const item = props.libraryItem.libraryItems.data[0].attributes; |   const item = props.libraryItem.libraryItems.data[0].attributes; | ||||||
|   const langui = props.langui.websiteInterfaces.data[0].attributes; |   const langui = props.langui.websiteInterfaces.data[0].attributes; | ||||||
|   const dispatch = useDispatch(); |   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 = ( |   const subPanel = ( | ||||||
|     <SubPanel> |     <SubPanel> | ||||||
|       <ReturnButton |       <ReturnButton | ||||||
| @ -83,23 +86,16 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | |||||||
|         /> |         /> | ||||||
| 
 | 
 | ||||||
|         {item.subitems.data.length > 0 ? ( |         {item.subitems.data.length > 0 ? ( | ||||||
|           item.metadata.length > 0 && |           <NavOption | ||||||
|           item.metadata[0].__typename === "ComponentMetadataOther" && |             title={ | ||||||
|           item.metadata[0].subtype.data.attributes.slug === "variant-set" ? ( |               isVariantSet | ||||||
|             <NavOption |                 ? langui.library_item_variants | ||||||
|               title={langui.library_item_variants} |                 : langui.library_item_subitems | ||||||
|               url="#variants" |             } | ||||||
|               border={true} |             url={isVariantSet ? "#variants" : "#subitems"} | ||||||
|               onClick={() => dispatch(setSubPanelOpen(false))} |             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 = ( |   const contentPanel = ( | ||||||
|     <ContentPanel width={ContentPanelWidthSizes.large}> |     <ContentPanel width={ContentPanelWidthSizes.large}> | ||||||
|       <div className="grid place-items-center gap-12"> |       <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 ? ( |           {item.thumbnail.data ? ( | ||||||
|             <Image |             <Img | ||||||
|               src={getAssetURL( |               image={item.thumbnail.data.attributes} | ||||||
|                 item.thumbnail.data.attributes.url, |               quality={ImageQuality.Medium} | ||||||
|                 ImageQuality.Medium |  | ||||||
|               )} |  | ||||||
|               alt={item.thumbnail.data.attributes.alternativeText} |  | ||||||
|               width={item.thumbnail.data.attributes.width} |  | ||||||
|               height={item.thumbnail.data.attributes.height} |  | ||||||
|               layout="fill" |               layout="fill" | ||||||
|               objectFit="contain" |               objectFit="contain" | ||||||
|  |               priority | ||||||
|             /> |             /> | ||||||
|           ) : ( |           ) : ( | ||||||
|             <div className="w-full aspect-[21/29.7] bg-light rounded-xl"></div> |             <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" |                   className="relative aspect-square hover:scale-[1.02] transition-transform cursor-pointer" | ||||||
|                 > |                 > | ||||||
|                   <div className="bg-light absolute inset-0 rounded-lg shadow-md"></div> |                   <div className="bg-light absolute inset-0 rounded-lg shadow-md"></div> | ||||||
|                   <Image |                   <Img | ||||||
|                     className="rounded-lg" |                     className="rounded-lg" | ||||||
|                     src={getAssetURL(galleryItem.attributes.url)} |                     image={galleryItem.attributes} | ||||||
|                     alt={galleryItem.attributes.alternativeText} |  | ||||||
|                     width={galleryItem.attributes.width} |  | ||||||
|                     height={galleryItem.attributes.height} |  | ||||||
|                     layout="fill" |                     layout="fill" | ||||||
|                     objectFit="cover" |                     objectFit="cover" | ||||||
|                   /> |                   /> | ||||||
| @ -356,35 +345,24 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | |||||||
|         </InsetBox> |         </InsetBox> | ||||||
| 
 | 
 | ||||||
|         {item.subitems.data.length > 0 ? ( |         {item.subitems.data.length > 0 ? ( | ||||||
|           item.metadata.length > 0 && |           <div | ||||||
|           item.metadata[0].__typename === "ComponentMetadataOther" && |             id={isVariantSet ? "variants" : "subitems"} | ||||||
|           item.metadata[0].subtype.data.attributes.slug === "variant-set" ? ( |             className="grid place-items-center gap-8 w-full" | ||||||
|             <div id="variants" className="grid place-items-center gap-8 w-full"> |           > | ||||||
|               <h2 className="text-2xl">{langui.library_item_variants}</h2> |             <h2 className="text-2xl"> | ||||||
|               <div className="grid gap-8 items-end mobile:grid-cols-2 grid-cols-[repeat(auto-fill,minmax(15rem,1fr))] w-full"> |               {isVariantSet | ||||||
|                 {item.subitems.data.map((variant) => ( |                 ? langui.library_item_variants | ||||||
|                   <LibraryItemsPreview |                 : langui.library_item_subitems} | ||||||
|                     key={variant.id} |             </h2> | ||||||
|                     item={variant.attributes} |             <div className="grid gap-8 items-end mobile:grid-cols-2 grid-cols-[repeat(auto-fill,minmax(15rem,1fr))] w-full"> | ||||||
|                     langui={langui} |               {item.subitems.data.map((subitem) => ( | ||||||
|                   /> |                 <LibraryItemsPreview | ||||||
|                 ))} |                   key={subitem.id} | ||||||
|               </div> |                   item={subitem.attributes} | ||||||
|  |                 /> | ||||||
|  |               ))} | ||||||
|             </div> |             </div> | ||||||
|           ) : ( |           </div> | ||||||
|             <div id="subitems" className="grid place-items-center gap-8 w-full"> |  | ||||||
|               <h2 className="text-2xl">{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}> |     <ContentPanel width={ContentPanelWidthSizes.large}> | ||||||
|       <div className="grid gap-8 items-end mobile:grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(13rem,1fr))]"> |       <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) => ( |         {props.libraryItems.libraryItems.data.map((item) => ( | ||||||
|           <LibraryItemsPreview |           <LibraryItemsPreview key={item.id} item={item.attributes} /> | ||||||
|             key={item.id} |  | ||||||
|             item={item.attributes} |  | ||||||
|             langui={langui} |  | ||||||
|           /> |  | ||||||
|         ))} |         ))} | ||||||
|       </div> |       </div> | ||||||
|     </ContentPanel> |     </ContentPanel> | ||||||
|  | |||||||
| @ -21,7 +21,9 @@ export default function Merch(props: MerchProps): JSX.Element { | |||||||
|     </SubPanel> |     </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) => { | export const getStaticProps: GetStaticProps = async (context) => { | ||||||
|  | |||||||
| @ -21,7 +21,9 @@ export default function News(props: NewsProps): JSX.Element { | |||||||
|     </SubPanel> |     </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) => { | export const getStaticProps: GetStaticProps = async (context) => { | ||||||
|  | |||||||
| @ -72,7 +72,11 @@ export default function DataChronology( | |||||||
|         <NavOption |         <NavOption | ||||||
|           key={era.id} |           key={era.id} | ||||||
|           url={"#" + era.attributes.slug} |           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={ |           subtitle={ | ||||||
|             era.attributes.starting_year + " → " + era.attributes.ending_year |             era.attributes.starting_year + " → " + era.attributes.ending_year | ||||||
|           } |           } | ||||||
|  | |||||||
| @ -3,20 +3,6 @@ import { | |||||||
|   GetWebsiteInterfaceQuery, |   GetWebsiteInterfaceQuery, | ||||||
| } from "graphql/operations-types"; | } 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( | export function prettyDate( | ||||||
|   datePicker: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["release_date"] |   datePicker: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["release_date"] | ||||||
| ): string { | ): string { | ||||||
|  | |||||||
| @ -15,8 +15,8 @@ module.exports = { | |||||||
|       monospace: ["monospace"], |       monospace: ["monospace"], | ||||||
|     }, |     }, | ||||||
|     screens: { |     screens: { | ||||||
|       desktop: { min: "150ch" }, |       desktop: { min: "120ch" }, | ||||||
|       mobile: { max: "150ch" }, |       mobile: { max: "120ch" }, | ||||||
|       thin: { max: "50ch" }, |       thin: { max: "50ch" }, | ||||||
|       coarse: { raw: "(pointer: coarse)" }, |       coarse: { raw: "(pointer: coarse)" }, | ||||||
|       fine: { raw: "(pointer: fine)" }, |       fine: { raw: "(pointer: fine)" }, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint