Improve Open Graph Metas

This commit is contained in:
DrMint 2023-05-22 20:07:04 +02:00
parent d5e7d704bf
commit ff89031123
5 changed files with 73 additions and 12 deletions

2
.gitignore vendored
View File

@ -1,6 +1,8 @@
# Generated content
src/graphql/generated.ts
public/robots.txt
# dependencies
/node_modules
/.pnp

View File

@ -2,6 +2,7 @@ import Head from "next/head";
import { useSwipeable } from "react-swipeable";
import { MaterialSymbol } from "material-symbols";
import { atom } from "jotai";
import { useRouter } from "next/router";
import { layout } from "../../design.config";
import { Ico } from "./Ico";
import { MainPanel } from "./Panels/MainPanel";
@ -54,6 +55,7 @@ export const AppLayout = ({
const is1ColumnLayout = useAtomGetter(atoms.containerQueries.is1ColumnLayout);
const isScreenAtLeastXs = useAtomGetter(atoms.containerQueries.isScreenAtLeastXs);
const isIOS = useAtomGetter(isIOSAtom);
const router = useRouter();
const { format } = useFormat();
@ -105,19 +107,41 @@ export const AppLayout = ({
<title>{openGraph.title}</title>
<meta name="description" content={openGraph.description} />
<meta name="twitter:site" content="@AccordsLibrary" />
<meta name="twitter:title" content={openGraph.title} />
<meta name="twitter:description" content={openGraph.description} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content={openGraph.thumbnail.image} />
<meta
property="og:type"
content={openGraph.video ? "video.movie" : openGraph.audio ? "music.song" : "website"}
/>
<meta property="og:locale" content={router.locale} />
<meta property="og:site_name" content="Accords Library" />
<meta property="og:title" content={openGraph.title} />
<meta property="og:description" content={openGraph.description} />
<meta property="og:image" content={openGraph.thumbnail.image} />
<meta property="og:image:secure_url" content={openGraph.thumbnail.image} />
<meta property="og:image:width" content={openGraph.thumbnail.width.toString()} />
<meta property="og:image:height" content={openGraph.thumbnail.height.toString()} />
<meta property="og:image:alt" content={openGraph.thumbnail.alt} />
<meta property="og:image:type" content="image/jpeg" />
{openGraph.audio && (
<>
<meta property="og:audio" content={openGraph.audio} />
<meta property="og:audio:type" content="audio/mpeg" />
</>
)}
{openGraph.video && (
<>
<meta property="og:video" content={openGraph.video} />{" "}
<meta property="og:video:type" content="video/mp4" />
</>
)}
</Head>
{/* Content panel */}

View File

@ -8,7 +8,7 @@ const DEFAULT_OG_THUMBNAIL: OgImage = {
image: `${process.env.NEXT_PUBLIC_URL_SELF}/default_og.jpg`,
width: 1200,
height: 630,
alt: "Accord's Library Logo",
alt: "Accords Library Logo",
};
export const TITLE_PREFIX = "Accords Library";
@ -18,13 +18,17 @@ export interface OpenGraph {
title: string;
description: string;
thumbnail: OgImage;
audio?: string;
video?: string;
}
export const getOpenGraph = (
format: ReturnType<typeof getFormat>["format"] | ReturnType<typeof useFormat>["format"],
title?: string | null | undefined,
description?: string | null | undefined,
thumbnail?: UploadImageFragment | string | null | undefined
thumbnail?: UploadImageFragment | string | null | undefined,
audio?: string,
video?: string
): OpenGraph => ({
title: `${TITLE_PREFIX}${isDefinedAndNotEmpty(title) ? `${TITLE_SEPARATOR}${title}` : ""}`,
description: isDefinedAndNotEmpty(description)
@ -33,6 +37,8 @@ export const getOpenGraph = (
: description
: format("default_description"),
thumbnail: thumbnail ? getOgImage(thumbnail) : DEFAULT_OG_THUMBNAIL,
...(audio ? { audio } : {}),
...(video ? { video } : {}),
});
const getOgImage = (image: UploadImageFragment | string): OgImage => {

View File

@ -167,7 +167,11 @@ export const getStaticProps: GetStaticProps = async (context) => {
getDescription(videos.videos.data[0].attributes.description, {
[format("channel")]: [videos.videos.data[0].attributes.channel?.data?.attributes?.title],
}),
getVideoThumbnailURL(videos.videos.data[0].attributes.uid)
getVideoThumbnailURL(videos.videos.data[0].attributes.uid),
undefined,
videos.videos.data[0].attributes.gone
? getVideoFile(videos.videos.data[0].attributes.uid)
: undefined
),
};
return {

View File

@ -275,30 +275,31 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
selectedSetType === "text_set" && selectedTranslation?.text_set?.text ? (
<Markdawn className="max-w-2xl" text={selectedTranslation.text_set.text} />
) : selectedSetType === "audio_set" && selectedTranslation?.audio_set ? (
) : selectedSetType === "audio_set" &&
selectedTranslation?.audio_set &&
selectedTranslation.language?.data?.attributes?.code ? (
<AudioPlayer
title={prettyInlineTitle(
selectedTranslation.pre_title,
selectedTranslation.title,
selectedTranslation.subtitle
)}
src={`${process.env.NEXT_PUBLIC_URL_ASSETS}/contents/audios/\
${content.slug}_${selectedTranslation.language?.data?.attributes?.code}.mp3`}
src={getAudioURL(content.slug, selectedTranslation.language.data.attributes.code)}
className="max-w-2xl"
/>
) : (
selectedSetType === "video_set" &&
selectedTranslation?.video_set && (
selectedTranslation?.video_set &&
selectedTranslation.language?.data?.attributes?.code && (
<VideoPlayer
title={prettyInlineTitle(
selectedTranslation.pre_title,
selectedTranslation.title,
selectedTranslation.subtitle
)}
src={`${process.env.NEXT_PUBLIC_URL_ASSETS}/contents/videos/\
${content.slug}_${selectedTranslation.language?.data?.attributes?.code}.mp4`}
src={getVideoURL(content.slug, selectedTranslation.language.data.attributes.code)}
subSrc={`${process.env.NEXT_PUBLIC_URL_ASSETS}/contents/videos/\
${content.slug}_${selectedTranslation.language?.data?.attributes?.code}.vtt`}
${content.slug}_${selectedTranslation.language.data.attributes.code}.vtt`}
className="max-w-[90vh]"
/>
)
@ -340,7 +341,7 @@ export const getStaticProps: GetStaticProps = async (context) => {
return { notFound: true };
}
const { title, description } = (() => {
const { title, description, audio, video } = (() => {
if (context.locale && context.locales) {
const selectedTranslation = staticSmartLanguage({
items: content.contents.data[0].attributes.translations,
@ -351,6 +352,7 @@ export const getStaticProps: GetStaticProps = async (context) => {
const rawDescription = isDefinedAndNotEmpty(selectedTranslation.description)
? selectedTranslation.description
: selectedTranslation.text_set?.text;
return {
title: prettyInlineTitle(
selectedTranslation.pre_title,
@ -366,12 +368,22 @@ export const getStaticProps: GetStaticProps = async (context) => {
["attributes"]
).map((category) => category.attributes.short),
}),
audio:
selectedTranslation.language?.data?.attributes?.code && selectedTranslation.audio_set
? getAudioURL(slug, selectedTranslation.language.data.attributes.code)
: undefined,
video:
selectedTranslation.language?.data?.attributes?.code && selectedTranslation.video_set
? getVideoURL(slug, selectedTranslation.language.data.attributes.code)
: undefined,
};
}
}
return {
title: prettySlug(content.contents.data[0].attributes.slug),
description: undefined,
audio: undefined,
video: undefined,
};
})();
@ -379,7 +391,7 @@ export const getStaticProps: GetStaticProps = async (context) => {
const props: Props = {
content: content.contents.data[0].attributes as ContentWithTranslations,
openGraph: getOpenGraph(format, title, description, thumbnail),
openGraph: getOpenGraph(format, title, description, thumbnail, audio, video),
};
return {
props: props,
@ -488,3 +500,16 @@ const RelatedContentPreview = ({
/>
);
};
/*
*
* PRIVATE METHODS
*/
const getAudioURL = (slug: string, langCode: string): string =>
`${process.env.NEXT_PUBLIC_URL_ASSETS}/contents/audios/\
${slug}_${langCode}.mp3`;
const getVideoURL = (slug: string, langCode: string): string =>
`${process.env.NEXT_PUBLIC_URL_ASSETS}/contents/videos/\
${slug}_${langCode}.mp4`;