Added OG metadata per page

This commit is contained in:
DrMint 2022-02-24 04:50:00 +01:00
parent 506e5383da
commit 0b6366510c
22 changed files with 189 additions and 50 deletions

View File

@ -1,20 +1,27 @@
import { GetWebsiteInterfaceQuery } from "graphql/operations-types"; import {
GetWebsiteInterfaceQuery,
StrapiImage,
} from "graphql/operations-types";
import MainPanel from "./Panels/MainPanel"; import MainPanel from "./Panels/MainPanel";
import Head from "next/head"; import Head from "next/head";
import { useSwipeable } from "react-swipeable"; import { useSwipeable } from "react-swipeable";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import Button from "components/Button"; import Button from "components/Button";
import { prettyLanguage } from "queries/helpers"; import { getOgImage, prettyLanguage } from "queries/helpers";
import { useMediaCoarse, useMediaMobile } from "hooks/useMediaQuery"; import { useMediaCoarse, useMediaMobile } from "hooks/useMediaQuery";
import ReactTooltip from "react-tooltip"; import ReactTooltip from "react-tooltip";
import { useAppLayout } from "contexts/AppLayoutContext"; import { useAppLayout } from "contexts/AppLayoutContext";
import { ImageQuality } from "./Img";
type AppLayoutProps = { type AppLayoutProps = {
subPanel?: React.ReactNode; subPanel?: React.ReactNode;
subPanelIcon?: string; subPanelIcon?: string;
contentPanel?: React.ReactNode; contentPanel?: React.ReactNode;
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"]; langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
title: string; title?: string;
navTitle: string;
thumbnail?: StrapiImage;
description?: string;
}; };
export default function AppLayout(props: AppLayoutProps): JSX.Element { export default function AppLayout(props: AppLayoutProps): JSX.Element {
@ -68,6 +75,9 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
const turnSubIntoContent = props.subPanel && !props.contentPanel; const turnSubIntoContent = props.subPanel && !props.contentPanel;
const ogImage = getOgImage(ImageQuality.Og, props.thumbnail);
const ogTitle = props.title ? props.title : props.navTitle;
return ( return (
<div className={appLayout.darkMode ? "set-theme-dark" : "set-theme-light"}> <div className={appLayout.darkMode ? "set-theme-dark" : "set-theme-light"}>
<div <div
@ -75,9 +85,45 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
className="fixed inset-0 touch-pan-y p-0 m-0 bg-light text-black" className="fixed inset-0 touch-pan-y p-0 m-0 bg-light text-black"
> >
<Head> <Head>
<title> <title>{`${titlePrefix} - ${ogTitle}`}</title>
{props.title ? `${titlePrefix} - ${props.title}` : titlePrefix}
</title> <meta
name="twitter:title"
content={`${titlePrefix} - ${ogTitle}`}
></meta>
{props.description && (
<>
<meta name="description" content={props.description} />
<meta
name="twitter:description"
content={props.description}
></meta>
</>
)}
{ogImage && (
<>
<meta property="og:image" content={ogImage.image}></meta>
<meta
property="og:image:secure_url"
content={ogImage.image}
></meta>
<meta
property="og:image:width"
content={ogImage.width.toString()}
></meta>
<meta
property="og:image:height"
content={ogImage.height.toString()}
></meta>
<meta property="og:image:alt" content={ogImage.alt}></meta>
<meta property="og:image:type" content="image/jpeg"></meta>
<meta name="twitter:card" content="summary_large_image"></meta>
<meta name="twitter:image" content={ogImage.image}></meta>
</>
)}
</Head> </Head>
{/* Navbar */} {/* Navbar */}
@ -88,7 +134,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
> >
menu menu
</span> </span>
<p className="text-2xl font-black font-headers">{props.title}</p> <p className="text-2xl font-black font-headers">{props.navTitle}</p>
<span <span
className="material-icons mt-[.1em] cursor-pointer" className="material-icons mt-[.1em] cursor-pointer"
onClick={() => appLayout.setSubPanelOpen(true)} onClick={() => appLayout.setSubPanelOpen(true)}

View File

@ -1,4 +1,4 @@
import { GetLibraryItemsPreviewQuery } from "graphql/operations-types"; import { StrapiImage } from "graphql/operations-types";
import { ImageProps } from "next/image"; import { ImageProps } from "next/image";
import Image from "next/image"; import Image from "next/image";
@ -9,11 +9,11 @@ export enum ImageQuality {
Og = "og", Og = "og",
} }
export function getAssetURL(url: string, quality?: ImageQuality): string { export function getAssetURL(url: string, quality: ImageQuality): string {
if (!quality) quality = ImageQuality.Small;
url = url.replace(/^\/uploads/, "/" + quality); url = url.replace(/^\/uploads/, "/" + quality);
url = url.replace(/.jpg$/, ".webp"); url = url.replace(/.jpg$/, ".webp");
url = url.replace(/.png$/, ".webp"); url = url.replace(/.png$/, ".webp");
if (quality === ImageQuality.Og) url = url.replace(/.webp$/, ".jpg");
return process.env.NEXT_PUBLIC_URL_IMG + url; return process.env.NEXT_PUBLIC_URL_IMG + url;
} }
@ -50,7 +50,7 @@ export function getImgSizesByQuality(
type ImgProps = { type ImgProps = {
className?: string; className?: string;
image: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["thumbnail"]["data"]["attributes"]; image: StrapiImage;
quality?: ImageQuality; quality?: ImageQuality;
alt?: ImageProps["alt"]; alt?: ImageProps["alt"];
layout?: ImageProps["layout"]; layout?: ImageProps["layout"];
@ -67,7 +67,10 @@ export default function Img(props: ImgProps): JSX.Element {
return ( return (
<Image <Image
className={props.className} className={props.className}
src={getAssetURL(props.image.url, props.quality)} src={getAssetURL(
props.image.url,
props.quality ? props.quality : ImageQuality.Small
)}
alt={props.alt ? props.alt : props.image.alternativeText} alt={props.alt ? props.alt : props.image.alternativeText}
width={props.layout === "fill" ? undefined : imgSize.width} width={props.layout === "fill" ? undefined : imgSize.width}
height={props.layout === "fill" ? undefined : imgSize.height} height={props.layout === "fill" ? undefined : imgSize.height}

View File

@ -39,9 +39,6 @@ export default function LibraryItemsPreview(
<div className="linearbg-obi fine:drop-shadow-shade-lg fine:absolute place-items-start bottom-2 -inset-x-0.5 opacity-[var(--cover-opacity)] transition-opacity z-20 grid p-4 gap-2"> <div className="linearbg-obi fine:drop-shadow-shade-lg fine:absolute place-items-start bottom-2 -inset-x-0.5 opacity-[var(--cover-opacity)] transition-opacity z-20 grid p-4 gap-2">
{item.metadata && item.metadata.length > 0 ? ( {item.metadata && item.metadata.length > 0 ? (
<div className="flex flex-row gap-1"> <div className="flex flex-row gap-1">
{item.metadata[0].__typename === "ComponentMetadataOther"
? console.log(item.slug)
: ""}
<Chip>{prettyItemSubType(item.metadata[0])}</Chip> <Chip>{prettyItemSubType(item.metadata[0])}</Chip>
</div> </div>
) : ( ) : (

View File

@ -62,6 +62,16 @@ export enum Enum_Componentsetstextset_Status {
Done = "Done", Done = "Done",
} }
export type StrapiImage = {
__typename: "UploadFile";
name: string;
alternativeText: string;
caption: string;
width: number;
height: number;
url: string;
};
// __________________________________________________________________ // __________________________________________________________________
export type GetWebsiteInterfaceQueryVariables = Exact<{ export type GetWebsiteInterfaceQueryVariables = Exact<{

View File

@ -19,7 +19,7 @@ export default function FourOhFour(props: FourOhFourProps): JSX.Element {
</Link> </Link>
</ContentPanel> </ContentPanel>
); );
return <AppLayout title="404" langui={langui} contentPanel={contentPanel} />; return <AppLayout navTitle="404" langui={langui} contentPanel={contentPanel} />;
} }
export const getStaticProps: GetStaticProps = async (context) => { export const getStaticProps: GetStaticProps = async (context) => {

View File

@ -24,18 +24,46 @@ class MyDocument extends Document {
return ( return (
<Html> <Html>
<Head> <Head>
<meta name="description" content={siteDescription} /> <meta
<link rel="icon" href={siteFavicon} /> name="description"
<meta property="og:image" content={thumbnailImage}></meta> content={siteDescription}
<meta property="og:image:secure_url" content={thumbnailImage}></meta> key="description"
<meta property="og:image:width" content="1200"></meta> />
<meta property="og:image:height" content="630"></meta> <link rel="icon" href={siteFavicon} key="icon" />
<meta property="og:image:alt" content="Accord's Library"></meta> <meta property="og:image" content={thumbnailImage} key="ogImage" />
<meta property="og:image:type" content="image/jpeg"></meta> <meta
<meta name="twitter:card" content="summary_large_image"></meta> property="og:image:secure_url"
<meta name="twitter:title" content={siteTitle}></meta> content={thumbnailImage}
<meta name="twitter:description" content={siteDescription}></meta> key="ogImageSecure"
<meta name="twitter:image" content={thumbnailImage}></meta> />
<meta property="og:image:width" content="1200" key="ogImageWidth" />
<meta property="og:image:height" content="630" key="ogImageHeight" />
<meta
property="og:image:alt"
content="Accord's Library"
key="ogImageAlt"
/>
<meta
property="og:image:type"
content="image/jpeg"
key="ogImageType"
/>
<meta
name="twitter:card"
content="summary_large_image"
key="twitterCard"
/>
<meta name="twitter:title" content={siteTitle} key="twitterTitle" />
<meta
name="twitter:description"
content={siteDescription}
key="twitterDescription"
/>
<meta
name="twitter:image"
content={thumbnailImage}
key="twitterImage"
/>
<meta <meta
name="apple-mobile-web-app-status-bar-style" name="apple-mobile-web-app-status-bar-style"
content="black-translucent" content="black-translucent"

View File

@ -22,7 +22,7 @@ export default function AboutUs(props: AboutUsProps): JSX.Element {
); );
return ( return (
<AppLayout <AppLayout
title={langui.main_about_us} navTitle={langui.main_about_us}
langui={langui} langui={langui}
subPanel={subPanel} subPanel={subPanel}
/> />

View File

@ -22,7 +22,7 @@ export default function Archives(props: ArchivesProps): JSX.Element {
); );
return ( return (
<AppLayout <AppLayout
title={langui.main_archives} navTitle={langui.main_archives}
langui={langui} langui={langui}
subPanel={subPanel} subPanel={subPanel}
/> />

View File

@ -22,7 +22,7 @@ export default function Chronicles(props: ChroniclesProps): JSX.Element {
); );
return ( return (
<AppLayout <AppLayout
title={langui.main_chronicles} navTitle={langui.main_chronicles}
langui={langui} langui={langui}
subPanel={subPanel} subPanel={subPanel}
/> />

View File

@ -15,6 +15,7 @@ import ThumbnailHeader from "components/Content/ThumbnailHeader";
import AppLayout from "components/AppLayout"; import AppLayout from "components/AppLayout";
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 { prettyinlineTitle, prettySlug } from "queries/helpers";
type ContentIndexProps = { type ContentIndexProps = {
content: GetContentQuery; content: GetContentQuery;
@ -26,11 +27,7 @@ export default function ContentIndex(props: ContentIndexProps): JSX.Element {
const langui = props.langui.websiteInterfaces.data[0].attributes; const langui = props.langui.websiteInterfaces.data[0].attributes;
const subPanel = ( const subPanel = (
<SubPanel> <SubPanel>
<ReturnButton <ReturnButton href="/contents" title={"Contents"} langui={langui} />
href="/contents"
title={"Contents"}
langui={langui}
/>
<HorizontalLine /> <HorizontalLine />
</SubPanel> </SubPanel>
); );
@ -70,7 +67,13 @@ export default function ContentIndex(props: ContentIndexProps): JSX.Element {
return ( return (
<AppLayout <AppLayout
title={langui.library_content} navTitle="Contents"
title={
content.titles.length > 0
? prettyinlineTitle(content.titles[0].pre_title, content.titles[0].title, content.titles[0].subtitle)
: prettySlug(content.slug)
}
thumbnail={content.thumbnail.data.attributes}
langui={langui} langui={langui}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanel={subPanel} subPanel={subPanel}

View File

@ -15,6 +15,7 @@ import ReturnButton from "components/PanelComponents/ReturnButton";
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";
import { prettyinlineTitle, prettySlug } from "queries/helpers";
type ContentReadProps = { type ContentReadProps = {
content: GetContentTextQuery; content: GetContentTextQuery;
@ -51,7 +52,13 @@ export default function ContentRead(props: ContentReadProps): JSX.Element {
return ( return (
<AppLayout <AppLayout
title={langui.library_content} navTitle="Contents"
title={
content.titles.length > 0
? prettyinlineTitle(content.titles[0].pre_title, content.titles[0].title, content.titles[0].subtitle)
: prettySlug(content.slug)
}
thumbnail={content.thumbnail.data.attributes}
langui={langui} langui={langui}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanel={subPanel} subPanel={subPanel}

View File

@ -10,8 +10,6 @@ import {
import { getContents, getWebsiteInterface } from "graphql/operations"; import { getContents, 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 ReturnButton from "components/PanelComponents/ReturnButton";
import HorizontalLine from "components/HorizontalLine";
import LibraryContentPreview from "components/Library/LibraryContentPreview"; import LibraryContentPreview from "components/Library/LibraryContentPreview";
import { prettyinlineTitle } from "queries/helpers"; import { prettyinlineTitle } from "queries/helpers";
@ -63,7 +61,7 @@ export default function Library(props: LibraryProps): JSX.Element {
); );
return ( return (
<AppLayout <AppLayout
title={langui.library_content} navTitle="Contents"
langui={langui} langui={langui}
subPanel={subPanel} subPanel={subPanel}
contentPanel={contentPanel} contentPanel={contentPanel}

View File

@ -85,7 +85,7 @@ export default function Editor(props: EditorProps): JSX.Element {
); );
return ( return (
<AppLayout <AppLayout
title="Markdawn Editor" navTitle="Markdawn Editor"
langui={langui} langui={langui}
contentPanel={contentPanel} contentPanel={contentPanel}
/> />

View File

@ -18,7 +18,7 @@ export default function Gallery(props: GalleryProps): JSX.Element {
return ( return (
<AppLayout <AppLayout
title={langui.main_gallery} navTitle={langui.main_gallery}
langui={langui} langui={langui}
contentPanel={contentPanel} contentPanel={contentPanel}
/> />

View File

@ -143,7 +143,7 @@ export default function Home(props: HomeProps): JSX.Element {
return ( return (
<> <>
<AppLayout <AppLayout
title={"Accords Library"} navTitle={"Accords Library"}
langui={langui} langui={langui}
contentPanel={contentPanel} contentPanel={contentPanel}
/> />

View File

@ -481,10 +481,17 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
return ( return (
<AppLayout <AppLayout
title={langui.library_items} navTitle={langui.main_library}
title={prettyinlineTitle("", item.title, item.subtitle)}
langui={langui} langui={langui}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanel={subPanel} subPanel={subPanel}
thumbnail={item.thumbnail.data.attributes}
description={
item.descriptions.length > 0
? item.descriptions[0].description
: undefined
}
/> />
); );
} }

View File

@ -42,7 +42,7 @@ export default function Library(props: LibraryProps): JSX.Element {
); );
return ( return (
<AppLayout <AppLayout
title={langui.library_items} navTitle={langui.main_library}
langui={langui} langui={langui}
subPanel={subPanel} subPanel={subPanel}
contentPanel={contentPanel} contentPanel={contentPanel}

View File

@ -22,7 +22,11 @@ export default function Merch(props: MerchProps): JSX.Element {
); );
return ( return (
<AppLayout title={langui.main_merch} langui={langui} subPanel={subPanel} /> <AppLayout
navTitle={langui.main_merch}
langui={langui}
subPanel={subPanel}
/>
); );
} }

View File

@ -22,7 +22,11 @@ export default function News(props: NewsProps): JSX.Element {
); );
return ( return (
<AppLayout title={langui.main_news} langui={langui} subPanel={subPanel} /> <AppLayout
navTitle={langui.main_news}
langui={langui}
subPanel={subPanel}
/>
); );
} }

View File

@ -119,7 +119,7 @@ export default function DataChronology(
return ( return (
<AppLayout <AppLayout
title="Chronology" navTitle="Chronology"
langui={langui} langui={langui}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanel={subPanel} subPanel={subPanel}

View File

@ -25,7 +25,7 @@ export default function Hubs(props: WikiProps): JSX.Element {
return ( return (
<AppLayout <AppLayout
title={langui.main_wiki} navTitle={langui.main_wiki}
langui={langui} langui={langui}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanel={subPanel} subPanel={subPanel}

View File

@ -1,6 +1,12 @@
import {
getAssetURL,
getImgSizesByQuality,
ImageQuality,
} from "components/Img";
import { import {
GetLibraryItemsPreviewQuery, GetLibraryItemsPreviewQuery,
GetWebsiteInterfaceQuery, GetWebsiteInterfaceQuery,
StrapiImage,
} from "graphql/operations-types"; } from "graphql/operations-types";
export function prettyDate( export function prettyDate(
@ -119,3 +125,29 @@ export function capitalizeString(string: string): string {
export function convertMmToInch(mm: number): string { export function convertMmToInch(mm: number): string {
return (mm * 0.03937008).toPrecision(3); return (mm * 0.03937008).toPrecision(3);
} }
type OgImage = {
image: string;
width: number;
height: number;
alt: string;
};
export function getOgImage(
quality: ImageQuality,
image?: StrapiImage
): OgImage | undefined {
if (image) {
const imgSize = getImgSizesByQuality(
image.width,
image.height,
quality ? quality : ImageQuality.Small
);
return {
image: getAssetURL(image.url, quality),
width: imgSize.width,
height: imgSize.height,
alt: image.alternativeText,
};
}
}