OpenGraph support

This commit is contained in:
DrMint 2022-07-23 10:24:13 +02:00
parent 74b77431a9
commit 7832b71f5c
41 changed files with 747 additions and 447 deletions

View File

@ -19,13 +19,13 @@ import {
isUndefined, isUndefined,
iterateMap, iterateMap,
} from "helpers/others"; } from "helpers/others";
import { getOgImage, ImageQuality } from "helpers/img"; import { prettyLanguage } from "helpers/formatters";
import { prettyLanguage, prettySlug } from "helpers/formatters";
import { cIf, cJoin } from "helpers/className"; import { cIf, cJoin } from "helpers/className";
import { AppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps } from "graphql/getAppStaticProps";
import { UploadImageFragment } from "graphql/generated";
import { useAppLayout } from "contexts/AppLayoutContext"; import { useAppLayout } from "contexts/AppLayoutContext";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
import { OpenGraph } from "helpers/openGraph";
import { getDefaultPreferredLanguages } from "helpers/locales";
/* /*
* *
@ -33,21 +33,20 @@ import { Button } from "components/Inputs/Button";
*/ */
const SENSIBILITY_SWIPE = 1.1; const SENSIBILITY_SWIPE = 1.1;
const TITLE_PREFIX = "Accords Library";
/* /*
* *
* COMPONENT * COMPONENT
*/ */
interface Props extends AppStaticProps { export interface AppLayoutRequired {
openGraph: OpenGraph;
}
interface Props extends AppStaticProps, AppLayoutRequired {
subPanel?: React.ReactNode; subPanel?: React.ReactNode;
subPanelIcon?: Icon; subPanelIcon?: Icon;
contentPanel?: React.ReactNode; contentPanel?: React.ReactNode;
title?: string;
navTitle: string | null | undefined;
thumbnail?: UploadImageFragment;
description?: string;
contentPanelScroolbar?: boolean; contentPanelScroolbar?: boolean;
} }
@ -59,10 +58,7 @@ export const AppLayout = ({
languages, languages,
subPanel, subPanel,
contentPanel, contentPanel,
thumbnail, openGraph,
title,
navTitle,
description,
subPanelIcon = Icon.Tune, subPanelIcon = Icon.Tune,
contentPanelScroolbar = true, contentPanelScroolbar = true,
}: Props): JSX.Element => { }: Props): JSX.Element => {
@ -136,33 +132,6 @@ export const AppLayout = ({
[contentPanel, subPanel] [contentPanel, subPanel]
); );
const metaImage = useMemo(
() =>
thumbnail
? getOgImage(ImageQuality.Og, thumbnail)
: {
image: "/default_og.jpg",
width: 1200,
height: 630,
alt: "Accord's Library Logo",
},
[thumbnail]
);
const { ogTitle, metaTitle } = useMemo(() => {
const resultTitle =
title ?? navTitle ?? prettySlug(router.asPath.split("/").pop());
return {
ogTitle: resultTitle,
metaTitle: `${TITLE_PREFIX} - ${resultTitle}`,
};
}, [navTitle, router.asPath, title]);
const metaDescription = useMemo(
() => description ?? langui.default_description ?? "",
[description, langui.default_description]
);
useLayoutEffect(() => { useLayoutEffect(() => {
document.getElementsByTagName("html")[0].style.fontSize = `${ document.getElementsByTagName("html")[0].style.fontSize = `${
(fontSize ?? 1) * 100 (fontSize ?? 1) * 100
@ -191,25 +160,13 @@ export const AppLayout = ({
useEffect(() => { useEffect(() => {
if (preferredLanguages) { if (preferredLanguages) {
if (preferredLanguages.length === 0) { if (preferredLanguages.length === 0) {
let defaultPreferredLanguages: string[] = [];
if (isDefinedAndNotEmpty(router.locale) && router.locales) { if (isDefinedAndNotEmpty(router.locale) && router.locales) {
if (router.locale === "en") { setPreferredLanguages(
defaultPreferredLanguages = [router.locale]; getDefaultPreferredLanguages(router.locale, router.locales)
router.locales.map((locale) => { );
if (locale !== router.locale)
defaultPreferredLanguages.push(locale);
});
} else {
defaultPreferredLanguages = [router.locale, "en"];
router.locales.map((locale) => {
if (locale !== router.locale && locale !== "en")
defaultPreferredLanguages.push(locale);
});
}
} }
setPreferredLanguages(defaultPreferredLanguages);
} else if (router.locale !== preferredLanguages[0]) { } else if (router.locale !== preferredLanguages[0]) {
router.push(router.asPath, router.asPath, { router.replace(router.asPath, router.asPath, {
locale: preferredLanguages[0], locale: preferredLanguages[0],
}); });
} }
@ -251,27 +208,36 @@ export const AppLayout = ({
)} )}
> >
<Head> <Head>
<title>{metaTitle}</title> <title>{openGraph.title}</title>
<meta name="description" content={metaDescription} /> <meta name="description" content={openGraph.description} />
<meta name="twitter:title" content={metaTitle}></meta> <meta name="twitter:title" content={openGraph.title}></meta>
<meta name="twitter:description" content={metaDescription}></meta> <meta
name="twitter:description"
content={openGraph.description}
></meta>
<meta name="twitter:card" content="summary_large_image"></meta> <meta name="twitter:card" content="summary_large_image"></meta>
<meta name="twitter:image" content={metaImage.image}></meta> <meta name="twitter:image" content={openGraph.thumbnail.image}></meta>
<meta property="og:title" content={metaTitle} /> <meta property="og:title" content={openGraph.title} />
<meta property="og:description" content={metaDescription} /> <meta property="og:description" content={openGraph.description} />
<meta property="og:image" content={metaImage.image}></meta> <meta property="og:image" content={openGraph.thumbnail.image}></meta>
<meta property="og:image:secure_url" content={metaImage.image}></meta> <meta
property="og:image:secure_url"
content={openGraph.thumbnail.image}
></meta>
<meta <meta
property="og:image:width" property="og:image:width"
content={metaImage.width.toString()} content={openGraph.thumbnail.width.toString()}
></meta> ></meta>
<meta <meta
property="og:image:height" property="og:image:height"
content={metaImage.height.toString()} content={openGraph.thumbnail.height.toString()}
></meta>
<meta
property="og:image:alt"
content={openGraph.thumbnail.alt}
></meta> ></meta>
<meta property="og:image:alt" content={metaImage.alt}></meta>
<meta property="og:image:type" content="image/jpeg"></meta> <meta property="og:image:type" content="image/jpeg"></meta>
</Head> </Head>
@ -370,13 +336,13 @@ export const AppLayout = ({
className={cJoin( className={cJoin(
"overflow-hidden text-center font-headers font-black", "overflow-hidden text-center font-headers font-black",
cIf( cIf(
ogTitle && ogTitle.length > 30, openGraph.title.length > 30,
"max-h-14 text-xl", "max-h-14 text-xl",
"max-h-16 text-2xl" "max-h-16 text-2xl"
) )
)} )}
> >
{ogTitle} {openGraph.title}
</p> </p>
{isDefined(subPanel) && !turnSubIntoContent && ( {isDefined(subPanel) && !turnSubIntoContent && (
<Ico <Ico

View File

@ -1,5 +1,5 @@
import { Fragment, useCallback, useMemo } from "react"; import { Fragment, useCallback, useMemo } from "react";
import { AppLayout } from "./AppLayout"; import { AppLayout, AppLayoutRequired } from "./AppLayout";
import { Chip } from "./Chip"; import { Chip } from "./Chip";
import { HorizontalLine } from "./HorizontalLine"; import { HorizontalLine } from "./HorizontalLine";
import { Markdawn, TableOfContents } from "./Markdown/Markdawn"; import { Markdawn, TableOfContents } from "./Markdown/Markdawn";
@ -13,7 +13,6 @@ import { useSmartLanguage } from "hooks/useSmartLanguage";
import { PostWithTranslations } from "helpers/types"; import { PostWithTranslations } from "helpers/types";
import { filterHasAttributes, getStatusDescription } from "helpers/others"; import { filterHasAttributes, getStatusDescription } from "helpers/others";
import { prettySlug } from "helpers/formatters"; import { prettySlug } from "helpers/formatters";
import { getDescription } from "helpers/description";
import { AppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps } from "graphql/getAppStaticProps";
/* /*
@ -21,7 +20,7 @@ import { AppStaticProps } from "graphql/getAppStaticProps";
* COMPONENT * COMPONENT
*/ */
interface Props { interface Props extends AppLayoutRequired {
post: PostWithTranslations; post: PostWithTranslations;
langui: AppStaticProps["langui"]; langui: AppStaticProps["langui"];
languages: AppStaticProps["languages"]; languages: AppStaticProps["languages"];
@ -52,7 +51,7 @@ export const PostPage = ({
appendBody, appendBody,
prependBody, prependBody,
displayTitle = true, displayTitle = true,
currencies, ...otherProps
}: Props): JSX.Element => { }: Props): JSX.Element => {
const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] = const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] =
useSmartLanguage({ useSmartLanguage({
@ -221,16 +220,9 @@ export const PostPage = ({
return ( return (
<AppLayout <AppLayout
navTitle={title} {...otherProps}
description={getDescription({
langui: langui,
description: selectedTranslation?.excerpt,
categories: post.categories,
})}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanel={subPanel} subPanel={subPanel}
thumbnail={thumbnail ?? undefined}
currencies={currencies}
languages={languages} languages={languages}
langui={langui} langui={langui}
/> />

View File

@ -1,5 +1,6 @@
import Link from "next/link"; import Link from "next/link";
import { useMemo } from "react"; import { useMemo } from "react";
import { useRouter } from "next/router";
import { Chip } from "./Chip"; import { Chip } from "./Chip";
import { Ico, Icon } from "./Ico"; import { Ico, Icon } from "./Ico";
import { Img } from "./Img"; import { Img } from "./Img";
@ -41,7 +42,8 @@ interface Props {
stackNumber?: number; stackNumber?: number;
metadata?: { metadata?: {
currencies?: AppStaticProps["currencies"]; currencies?: AppStaticProps["currencies"];
release_date?: DatePickerFragment | null; releaseDate?: DatePickerFragment | null;
releaseDateFormat?: Intl.DateTimeFormatOptions["dateStyle"];
price?: PricePickerFragment | null; price?: PricePickerFragment | null;
views?: number; views?: number;
author?: string; author?: string;
@ -78,19 +80,20 @@ export const PreviewCard = ({
}: Props): JSX.Element => { }: Props): JSX.Element => {
const { currency } = useAppLayout(); const { currency } = useAppLayout();
const isHoverable = useMediaHoverable(); const isHoverable = useMediaHoverable();
const router = useRouter();
const metadataJSX = useMemo( const metadataJSX = useMemo(
() => ( () => (
<> <>
{metadata && (metadata.release_date || metadata.price) && ( {metadata && (metadata.releaseDate || metadata.price) && (
<div className="flex w-full flex-row flex-wrap gap-x-3"> <div className="flex w-full flex-row flex-wrap gap-x-3">
{metadata.release_date && ( {metadata.releaseDate && (
<p className="text-sm mobile:text-xs"> <p className="text-sm mobile:text-xs">
<Ico <Ico
icon={Icon.Event} icon={Icon.Event}
className="mr-1 translate-y-[.15em] !text-base" className="mr-1 translate-y-[.15em] !text-base"
/> />
{prettyDate(metadata.release_date)} {prettyDate(metadata.releaseDate, router.locale)}
</p> </p>
)} )}
{metadata.price && metadata.currencies && ( {metadata.price && metadata.currencies && (
@ -124,7 +127,7 @@ export const PreviewCard = ({
)} )}
</> </>
), ),
[currency, metadata] [currency, metadata, router.locale]
); );
return ( return (
@ -278,7 +281,7 @@ export const PreviewCard = ({
{bottomChips && bottomChips.length > 0 && ( {bottomChips && bottomChips.length > 0 && (
<div <div
className="grid grid-flow-col place-content-start gap-1 overflow-x-scroll className="grid grid-flow-col place-content-start gap-1 overflow-x-scroll
[scrollbar-width:none] webkit-scrollbar:w-0" [scrollbar-width:none] webkit-scrollbar:h-0"
> >
{bottomChips.map((text, index) => ( {bottomChips.map((text, index) => (
<Chip key={index} className="text-sm" text={text} /> <Chip key={index} className="text-sm" text={text} />

View File

@ -2,9 +2,18 @@ import { GetStaticProps } from "next";
import { AppStaticProps, getAppStaticProps } from "./getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "./getAppStaticProps";
import { getReadySdk } from "./sdk"; import { getReadySdk } from "./sdk";
import { PostWithTranslations } from "helpers/types"; import { PostWithTranslations } from "helpers/types";
import { OpenGraph, getOpenGraph } from "helpers/openGraph";
import { prettyDate, prettySlug } from "helpers/formatters";
import {
getDefaultPreferredLanguages,
staticSmartLanguage,
} from "helpers/locales";
import { filterHasAttributes, isDefined } from "helpers/others";
import { getDescription } from "helpers/description";
export interface PostStaticProps extends AppStaticProps { export interface PostStaticProps extends AppStaticProps {
post: PostWithTranslations; post: PostWithTranslations;
openGraph: OpenGraph;
} }
export const getPostStaticProps = export const getPostStaticProps =
@ -15,10 +24,48 @@ export const getPostStaticProps =
slug: slug, slug: slug,
language_code: context.locale ?? "en", language_code: context.locale ?? "en",
}); });
if (post.posts?.data[0]?.attributes?.translations) { if (
post.posts?.data &&
post.posts.data.length > 0 &&
post.posts.data[0].attributes?.translations &&
isDefined(context.locale) &&
isDefined(context.locales)
) {
const appStaticProps = await getAppStaticProps(context);
const selectedTranslation = staticSmartLanguage({
items: post.posts.data[0].attributes.translations,
languageExtractor: (item) => item.language?.data?.attributes?.code,
preferredLanguages: getDefaultPreferredLanguages(
context.locale,
context.locales
),
});
const title = selectedTranslation?.title ?? prettySlug(slug);
const description = getDescription(selectedTranslation?.excerpt, {
[appStaticProps.langui.release_date ?? "Release date"]: [
prettyDate(post.posts.data[0].attributes.date, context.locale),
],
[appStaticProps.langui.categories ?? "Categories"]: filterHasAttributes(
post.posts.data[0].attributes.categories?.data,
["attributes"] as const
).map((category) => category.attributes.short),
});
const thumbnail =
selectedTranslation?.thumbnail?.data?.attributes ??
post.posts.data[0].attributes.thumbnail?.data?.attributes;
const props: PostStaticProps = { const props: PostStaticProps = {
...(await getAppStaticProps(context)), ...appStaticProps,
post: post.posts.data[0].attributes as PostWithTranslations, post: post.posts.data[0].attributes as PostWithTranslations,
openGraph: getOpenGraph(
appStaticProps.langui,
title,
description,
thumbnail
),
}; };
return { return {
props: props, props: props,

View File

@ -20,19 +20,12 @@ query getWikiPage($slug: String, $language_code: String) {
} }
} }
} }
tags(pagination: { limit: -1 }) { tags {
data { data {
id id
attributes { attributes {
slug slug
titles(filters: { language: { code: { eq: $language_code } } }) { titles(filters: { language: { code: { eq: $language_code } } }) {
language {
data {
attributes {
code
}
}
}
title title
} }
} }

View File

@ -1,9 +1,13 @@
import { isUndefined } from "./others";
import { DatePickerFragment } from "graphql/generated"; import { DatePickerFragment } from "graphql/generated";
export const compareDate = ( export const compareDate = (
a: DatePickerFragment, a: DatePickerFragment | null | undefined,
b: DatePickerFragment b: DatePickerFragment | null | undefined
): number => { ): number => {
if (isUndefined(a) || isUndefined(b)) {
return 0;
}
const dateA = (a.year ?? 99999) * 365 + (a.month ?? 12) * 31 + (a.day ?? 31); const dateA = (a.year ?? 99999) * 365 + (a.month ?? 12) * 31 + (a.day ?? 31);
const dateB = (b.year ?? 99999) * 365 + (b.month ?? 12) * 31 + (b.day ?? 31); const dateB = (b.year ?? 99999) * 365 + (b.month ?? 12) * 31 + (b.day ?? 31);
return dateA - dateB; return dateA - dateB;

View File

@ -1,52 +1,28 @@
import { prettySlug } from "./formatters"; import { isDefined, isDefinedAndNotEmpty } from "./others";
import { isDefined } from "./others";
import { Content } from "./types";
import { AppStaticProps } from "graphql/getAppStaticProps";
interface Description { export const getDescription = (
langui: AppStaticProps["langui"]; description: string | null | undefined,
description?: string | null | undefined; chipsGroups?: Record<string, (string | undefined)[]>
type?: Content["type"]; ): string => {
categories?: Content["categories"]; let result = "";
}
export const getDescription = ({ if (isDefinedAndNotEmpty(description)) {
langui, result += prettyMarkdown(description);
description: text, if (isDefined(chipsGroups)) {
type, result += "\n\n";
categories, }
}: Description): string => {
let description = "";
// TEXT
if (text) {
description += prettyMarkdown(text);
description += "\n\n";
} }
// TYPE for (const key in chipsGroups) {
if (type?.data) { if (Object.hasOwn(chipsGroups, key)) {
description += `${langui.type}: `; const chipsGroup = chipsGroups[key];
if (chipsGroup.length > 0) {
description += `(${ result += `${key}: ${prettyChip(chipsGroup)}\n`;
type.data.attributes?.titles?.[0]?.title ?? }
prettySlug(type.data.attributes?.slug) }
})`;
description += "\n";
} }
// CATEGORIES return result;
if (categories?.data && categories.data.length > 0) {
description += `${langui.categories}: `;
description += prettyChip(
categories.data.map((category) => category.attributes?.short)
);
description += "\n";
}
return description;
}; };
const prettyMarkdown = (markdown: string): string => const prettyMarkdown = (markdown: string): string =>

View File

@ -1,17 +1,18 @@
import { AppStaticProps } from "../graphql/getAppStaticProps"; import { AppStaticProps } from "../graphql/getAppStaticProps";
import { convertPrice } from "./numbers"; import { convertPrice } from "./numbers";
import { isDefinedAndNotEmpty } from "./others"; import { isDefinedAndNotEmpty, isUndefined } from "./others";
import { DatePickerFragment, PricePickerFragment } from "graphql/generated"; import { DatePickerFragment, PricePickerFragment } from "graphql/generated";
export const prettyDate = (datePicker: DatePickerFragment): string => { export const prettyDate = (
let result = ""; datePicker: DatePickerFragment,
if (datePicker.year) result += datePicker.year.toString(); locale = "en",
if (datePicker.month) dateStyle: Intl.DateTimeFormatOptions["dateStyle"] = "medium"
result += `/${datePicker.month.toString().padStart(2, "0")}`; ): string =>
if (datePicker.day) new Date(
result += `/${datePicker.day.toString().padStart(2, "0")}`; datePicker.year ?? 0,
return result; datePicker.month ?? 0,
}; datePicker.day ?? 1
).toLocaleString(locale, { dateStyle });
export const prettyPrice = ( export const prettyPrice = (
pricePicker: PricePickerFragment, pricePicker: PricePickerFragment,
@ -19,19 +20,23 @@ export const prettyPrice = (
targetCurrencyCode?: string targetCurrencyCode?: string
): string => { ): string => {
if (!targetCurrencyCode) return ""; if (!targetCurrencyCode) return "";
let result = ""; if (isUndefined(pricePicker.amount)) return "";
currencies.map((currency) => {
if (currency.attributes?.code === targetCurrencyCode) { const targetCurrency = currencies.find(
const amountInTargetCurrency = convertPrice(pricePicker, currency); (currency) => currency.attributes?.code === targetCurrencyCode
result = );
currency.attributes.symbol +
amountInTargetCurrency.toLocaleString(undefined, { if (targetCurrency?.attributes) {
minimumFractionDigits: currency.attributes.display_decimals ? 2 : 0, const amountInTargetCurrency = convertPrice(pricePicker, targetCurrency);
maximumFractionDigits: currency.attributes.display_decimals ? 2 : 0, return amountInTargetCurrency.toLocaleString("en", {
}); style: "currency",
} currency: targetCurrency.attributes.code,
});
}
return pricePicker.amount.toLocaleString("en", {
style: "currency",
currency: pricePicker.currency?.data?.attributes?.code,
}); });
return result;
}; };
export const prettySlug = (slug?: string, parentSlug?: string): string => { export const prettySlug = (slug?: string, parentSlug?: string): string => {

View File

@ -1,5 +1,3 @@
import { UploadImageFragment } from "graphql/generated";
export enum ImageQuality { export enum ImageQuality {
Small = "small", Small = "small",
Medium = "medium", Medium = "medium",
@ -7,7 +5,7 @@ export enum ImageQuality {
Og = "og", Og = "og",
} }
interface OgImage { export interface OgImage {
image: string; image: string;
width: number; width: number;
height: number; height: number;
@ -65,20 +63,3 @@ export const getImgSizesByQuality = (
return { width: 0, height: 0 }; return { width: 0, height: 0 };
} }
}; };
export const getOgImage = (
quality: ImageQuality,
image: UploadImageFragment
): OgImage => {
const imgSize = getImgSizesByQuality(
image.width ?? 0,
image.height ?? 0,
quality
);
return {
image: getAssetURL(image.url, quality),
width: imgSize.width,
height: imgSize.height,
alt: image.alternativeText ?? "",
};
};

54
src/helpers/locales.ts Normal file
View File

@ -0,0 +1,54 @@
import { isDefined } from "./others";
export const getDefaultPreferredLanguages = (
routerLocal: string,
locales: string[]
): string[] => {
let defaultPreferredLanguages: string[] = [];
if (routerLocal === "en") {
defaultPreferredLanguages = [routerLocal];
locales.map((locale) => {
if (locale !== routerLocal) defaultPreferredLanguages.push(locale);
});
} else {
defaultPreferredLanguages = [routerLocal, "en"];
locales.map((locale) => {
if (locale !== routerLocal && locale !== "en")
defaultPreferredLanguages.push(locale);
});
}
return defaultPreferredLanguages;
};
export const getPreferredLanguage = (
preferredLanguages: (string | undefined)[],
availableLanguages: Map<string, number>
): number | undefined => {
for (const locale of preferredLanguages) {
if (isDefined(locale) && availableLanguages.has(locale)) {
return availableLanguages.get(locale);
}
}
return undefined;
};
interface StaticSmartLanguageProps<T> {
items: T[];
preferredLanguages: string[];
languageExtractor: (item: NonNullable<T>) => string | undefined;
}
export const staticSmartLanguage = <T>({
languageExtractor,
preferredLanguages,
items,
}: StaticSmartLanguageProps<T>): T | undefined => {
for (const language of preferredLanguages) {
for (const item of items) {
if (isDefined(item) && languageExtractor(item) === language) {
return item;
}
}
}
return undefined;
};

51
src/helpers/openGraph.ts Normal file
View File

@ -0,0 +1,51 @@
import {
OgImage,
getImgSizesByQuality,
ImageQuality,
getAssetURL,
} from "./img";
import { isDefinedAndNotEmpty } from "./others";
import { UploadImageFragment } from "graphql/generated";
import { AppStaticProps } from "graphql/getAppStaticProps";
const DEFAULT_OG_THUMBNAIL = {
image: `${process.env.NEXT_PUBLIC_URL_SELF}/default_og.jpg`,
width: 1200,
height: 630,
alt: "Accord's Library Logo",
};
const TITLE_PREFIX = "Accords Library";
export interface OpenGraph {
title: string;
description: string;
thumbnail: OgImage;
}
export const getOpenGraph = (
langui: AppStaticProps["langui"],
title: string,
description?: string | null | undefined,
thumbnail?: UploadImageFragment | null | undefined
): OpenGraph => ({
title: `${TITLE_PREFIX}${isDefinedAndNotEmpty(title) && ` - ${title}`}`,
description: isDefinedAndNotEmpty(description)
? description
: langui.default_description ?? "",
thumbnail: thumbnail ? getOgImage(thumbnail) : DEFAULT_OG_THUMBNAIL,
});
const getOgImage = (image: UploadImageFragment): OgImage => {
const imgSize = getImgSizesByQuality(
image.width ?? 0,
image.height ?? 0,
ImageQuality.Og
);
return {
image: getAssetURL(image.url, ImageQuality.Og),
width: imgSize.width,
height: imgSize.height,
alt: image.alternativeText ?? "",
};
};

View File

@ -17,7 +17,7 @@ export interface PostWithTranslations extends Omit<Post, "translations"> {
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
export type Content = NonNullable< type Content = NonNullable<
NonNullable<GetContentTextQuery["contents"]>["data"][number]["attributes"] NonNullable<GetContentTextQuery["contents"]>["data"][number]["attributes"]
>; >;

View File

@ -4,6 +4,7 @@ import { LanguageSwitcher } from "components/Inputs/LanguageSwitcher";
import { useAppLayout } from "contexts/AppLayoutContext"; import { useAppLayout } from "contexts/AppLayoutContext";
import { AppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps } from "graphql/getAppStaticProps";
import { filterDefined, isDefined } from "helpers/others"; import { filterDefined, isDefined } from "helpers/others";
import { getPreferredLanguage } from "helpers/locales";
interface Props<T> { interface Props<T> {
items: T[]; items: T[];
@ -12,18 +13,6 @@ interface Props<T> {
transform?: (item: NonNullable<T>) => NonNullable<T>; transform?: (item: NonNullable<T>) => NonNullable<T>;
} }
const getPreferredLanguage = (
preferredLanguages: (string | undefined)[],
availableLanguages: Map<string, number>
): number | undefined => {
for (const locale of preferredLanguages) {
if (isDefined(locale) && availableLanguages.has(locale)) {
return availableLanguages.get(locale);
}
}
return undefined;
};
export const useSmartLanguage = <T>({ export const useSmartLanguage = <T>({
items, items,
languageExtractor, languageExtractor,

View File

@ -1,25 +1,29 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { import {
ReturnButton, ReturnButton,
ReturnButtonType, ReturnButtonType,
} from "components/PanelComponents/ReturnButton"; } from "components/PanelComponents/ReturnButton";
import { ContentPanel } from "components/Panels/ContentPanel"; import { ContentPanel } from "components/Panels/ContentPanel";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps {} interface Props extends AppStaticProps, AppLayoutRequired {}
const FourOhFour = ({ langui, ...otherProps }: Props): JSX.Element => ( const FourOhFour = ({
langui,
openGraph,
...otherProps
}: Props): JSX.Element => (
<AppLayout <AppLayout
navTitle="404"
contentPanel={ contentPanel={
<ContentPanel> <ContentPanel>
<h1>404 - {langui.page_not_found}</h1> <h1>{openGraph.title}</h1>
<ReturnButton <ReturnButton
href="/" href="/"
title="Home" title="Home"
@ -28,6 +32,7 @@ const FourOhFour = ({ langui, ...otherProps }: Props): JSX.Element => (
/> />
</ContentPanel> </ContentPanel>
} }
openGraph={openGraph}
langui={langui} langui={langui}
{...otherProps} {...otherProps}
/> />
@ -40,8 +45,13 @@ export default FourOhFour;
*/ */
export const getStaticProps: GetStaticProps = async (context) => { export const getStaticProps: GetStaticProps = async (context) => {
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
openGraph: getOpenGraph(
appStaticProps.langui,
`404 - ${appStaticProps.langui.page_not_found}`
),
}; };
return { return {
props: props, props: props,

View File

@ -1,25 +1,29 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { import {
ReturnButton, ReturnButton,
ReturnButtonType, ReturnButtonType,
} from "components/PanelComponents/ReturnButton"; } from "components/PanelComponents/ReturnButton";
import { ContentPanel } from "components/Panels/ContentPanel"; import { ContentPanel } from "components/Panels/ContentPanel";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps {} interface Props extends AppStaticProps, AppLayoutRequired {}
const FiveHundred = ({ langui, ...otherProps }: Props): JSX.Element => ( const FiveHundred = ({
langui,
openGraph,
...otherProps
}: Props): JSX.Element => (
<AppLayout <AppLayout
navTitle="500"
contentPanel={ contentPanel={
<ContentPanel> <ContentPanel>
<h1>500 - Internal Server Error</h1> <h1>{openGraph.title}</h1>
<ReturnButton <ReturnButton
href="/" href="/"
title="Home" title="Home"
@ -28,6 +32,7 @@ const FiveHundred = ({ langui, ...otherProps }: Props): JSX.Element => (
/> />
</ContentPanel> </ContentPanel>
} }
openGraph={openGraph}
langui={langui} langui={langui}
{...otherProps} {...otherProps}
/> />
@ -40,8 +45,13 @@ export default FiveHundred;
*/ */
export const getStaticProps: GetStaticProps = async (context) => { export const getStaticProps: GetStaticProps = async (context) => {
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
openGraph: getOpenGraph(
appStaticProps.langui,
"500 - Internal Server Error"
),
}; };
return { return {
props: props, props: props,

View File

@ -9,19 +9,11 @@ import {
* PAGE * PAGE
*/ */
const AccordsHandbook = ({ const AccordsHandbook = (props: PostStaticProps): JSX.Element => (
post,
langui,
languages,
currencies,
}: PostStaticProps): JSX.Element => (
<PostPage <PostPage
currencies={currencies} {...props}
languages={languages}
langui={langui}
post={post}
returnHref="/about-us/" returnHref="/about-us/"
returnTitle={langui.about_us} returnTitle={props.langui.about_us}
displayToc displayToc
displayLanguageSwitcher displayLanguageSwitcher
/> />

View File

@ -15,12 +15,7 @@ import { RequestMailProps, ResponseMailProps } from "pages/api/mail";
* PAGE * PAGE
*/ */
const AboutUs = ({ const AboutUs = ({ langui, ...otherProps }: PostStaticProps): JSX.Element => {
post,
langui,
languages,
currencies,
}: PostStaticProps): JSX.Element => {
const router = useRouter(); const router = useRouter();
const [formResponse, setFormResponse] = useState(""); const [formResponse, setFormResponse] = useState("");
const [formState, setFormState] = useState<"completed" | "ongoing" | "stale">( const [formState, setFormState] = useState<"completed" | "ongoing" | "stale">(
@ -177,10 +172,8 @@ const AboutUs = ({
return ( return (
<PostPage <PostPage
currencies={currencies} {...otherProps}
languages={languages}
langui={langui} langui={langui}
post={post}
returnHref="/about-us/" returnHref="/about-us/"
returnTitle={langui.about_us} returnTitle={langui.about_us}
displayToc displayToc

View File

@ -1,21 +1,21 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Icon } from "components/Ico"; import { Icon } from "components/Ico";
import { NavOption } from "components/PanelComponents/NavOption"; import { NavOption } from "components/PanelComponents/NavOption";
import { PanelHeader } from "components/PanelComponents/PanelHeader"; import { PanelHeader } from "components/PanelComponents/PanelHeader";
import { SubPanel } from "components/Panels/SubPanel"; import { SubPanel } from "components/Panels/SubPanel";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps {} interface Props extends AppStaticProps, AppLayoutRequired {}
const AboutUs = ({ langui, ...otherProps }: Props): JSX.Element => ( const AboutUs = ({ langui, ...otherProps }: Props): JSX.Element => (
<AppLayout <AppLayout
navTitle={langui.about_us}
subPanel={ subPanel={
<SubPanel> <SubPanel>
<PanelHeader <PanelHeader
@ -49,8 +49,13 @@ export default AboutUs;
*/ */
export const getStaticProps: GetStaticProps = async (context) => { export const getStaticProps: GetStaticProps = async (context) => {
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
openGraph: getOpenGraph(
appStaticProps.langui,
appStaticProps.langui.about_us ?? "About us"
),
}; };
return { return {
props: props, props: props,

View File

@ -9,19 +9,11 @@ import {
* PAGE * PAGE
*/ */
const Legality = ({ const Legality = (props: PostStaticProps): JSX.Element => (
post,
langui,
languages,
currencies,
}: PostStaticProps): JSX.Element => (
<PostPage <PostPage
currencies={currencies} {...props}
languages={languages}
langui={langui}
post={post}
returnHref="/about-us/" returnHref="/about-us/"
returnTitle={langui.about_us} returnTitle={props.langui.about_us}
displayToc displayToc
displayLanguageSwitcher displayLanguageSwitcher
/> />

View File

@ -9,19 +9,11 @@ import {
* PAGE * PAGE
*/ */
const SharingPolicy = ({ const SharingPolicy = (props: PostStaticProps): JSX.Element => (
post,
langui,
languages,
currencies,
}: PostStaticProps): JSX.Element => (
<PostPage <PostPage
currencies={currencies} {...props}
languages={languages}
langui={langui}
post={post}
returnHref="/about-us/" returnHref="/about-us/"
returnTitle={langui.about_us} returnTitle={props.langui.about_us}
displayToc displayToc
displayLanguageSwitcher displayLanguageSwitcher
/> />

View File

@ -1,18 +1,19 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useMemo } from "react"; import { useMemo } from "react";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { NavOption } from "components/PanelComponents/NavOption"; import { NavOption } from "components/PanelComponents/NavOption";
import { PanelHeader } from "components/PanelComponents/PanelHeader"; import { PanelHeader } from "components/PanelComponents/PanelHeader";
import { SubPanel } from "components/Panels/SubPanel"; import { SubPanel } from "components/Panels/SubPanel";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { Icon } from "components/Ico"; import { Icon } from "components/Ico";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps {} interface Props extends AppStaticProps, AppLayoutRequired {}
const Archives = ({ langui, ...otherProps }: Props): JSX.Element => { const Archives = ({ langui, ...otherProps }: Props): JSX.Element => {
const subPanel = useMemo( const subPanel = useMemo(
@ -28,14 +29,7 @@ const Archives = ({ langui, ...otherProps }: Props): JSX.Element => {
), ),
[langui] [langui]
); );
return ( return <AppLayout subPanel={subPanel} langui={langui} {...otherProps} />;
<AppLayout
navTitle={langui.archives}
subPanel={subPanel}
langui={langui}
{...otherProps}
/>
);
}; };
export default Archives; export default Archives;
@ -45,8 +39,13 @@ export default Archives;
*/ */
export const getStaticProps: GetStaticProps = async (context) => { export const getStaticProps: GetStaticProps = async (context) => {
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
openGraph: getOpenGraph(
appStaticProps.langui,
appStaticProps.langui.archives ?? "Archives"
),
}; };
return { return {
props: props, props: props,

View File

@ -1,6 +1,6 @@
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { Fragment, useMemo } from "react"; import { Fragment, useMemo } from "react";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Switch } from "components/Inputs/Switch"; import { Switch } from "components/Inputs/Switch";
import { PanelHeader } from "components/PanelComponents/PanelHeader"; import { PanelHeader } from "components/PanelComponents/PanelHeader";
import { import {
@ -22,13 +22,14 @@ import { useMediaHoverable } from "hooks/useMediaQuery";
import { WithLabel } from "components/Inputs/WithLabel"; import { WithLabel } from "components/Inputs/WithLabel";
import { filterHasAttributes, isDefined } from "helpers/others"; import { filterHasAttributes, isDefined } from "helpers/others";
import { useBoolean } from "hooks/useBoolean"; import { useBoolean } from "hooks/useBoolean";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
channel: NonNullable< channel: NonNullable<
GetVideoChannelQuery["videoChannels"] GetVideoChannelQuery["videoChannels"]
>["data"][number]["attributes"]; >["data"][number]["attributes"];
@ -91,7 +92,7 @@ const Channel = ({ langui, channel, ...otherProps }: Props): JSX.Element => {
thumbnailAspectRatio="16/9" thumbnailAspectRatio="16/9"
keepInfoVisible={keepInfoVisible} keepInfoVisible={keepInfoVisible}
metadata={{ metadata={{
release_date: video.attributes.published_date, releaseDate: video.attributes.published_date,
views: video.attributes.views, views: video.attributes.views,
author: channel?.title, author: channel?.title,
position: "Top", position: "Top",
@ -116,7 +117,6 @@ const Channel = ({ langui, channel, ...otherProps }: Props): JSX.Element => {
return ( return (
<AppLayout <AppLayout
navTitle={langui.archives}
subPanel={subPanel} subPanel={subPanel}
contentPanel={contentPanel} contentPanel={contentPanel}
langui={langui} langui={langui}
@ -140,9 +140,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
: "", : "",
}); });
if (!channel.videoChannels?.data[0].attributes) return { notFound: true }; if (!channel.videoChannels?.data[0].attributes) return { notFound: true };
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
channel: channel.videoChannels.data[0].attributes, channel: channel.videoChannels.data[0].attributes,
openGraph: getOpenGraph(
appStaticProps.langui,
channel.videoChannels.data[0].attributes.title
),
}; };
return { return {
props: props, props: props,

View File

@ -1,6 +1,6 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { SmartList } from "components/SmartList"; import { SmartList } from "components/SmartList";
import { Icon } from "components/Ico"; import { Icon } from "components/Ico";
import { Switch } from "components/Inputs/Switch"; import { Switch } from "components/Inputs/Switch";
@ -20,11 +20,12 @@ import { PreviewCard } from "components/PreviewCard";
import { GetVideosPreviewQuery } from "graphql/generated"; import { GetVideosPreviewQuery } from "graphql/generated";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getReadySdk } from "graphql/sdk"; import { getReadySdk } from "graphql/sdk";
import { prettyDate } from "helpers/formatters";
import { filterHasAttributes } from "helpers/others"; import { filterHasAttributes } from "helpers/others";
import { getVideoThumbnailURL } from "helpers/videos"; import { getVideoThumbnailURL } from "helpers/videos";
import { useMediaHoverable } from "hooks/useMediaQuery"; import { useMediaHoverable } from "hooks/useMediaQuery";
import { useBoolean } from "hooks/useBoolean"; import { useBoolean } from "hooks/useBoolean";
import { getOpenGraph } from "helpers/openGraph";
import { compareDate } from "helpers/date";
/* /*
* *
@ -40,7 +41,7 @@ const DEFAULT_FILTERS_STATE = {
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
videos: NonNullable<GetVideosPreviewQuery["videos"]>["data"]; videos: NonNullable<GetVideosPreviewQuery["videos"]>["data"];
} }
@ -73,7 +74,7 @@ const Videos = ({ langui, videos, ...otherProps }: Props): JSX.Element => {
<TextInput <TextInput
className="mb-6 w-full" className="mb-6 w-full"
placeholder={langui.search_title ?? undefined} placeholder={langui.search_title ?? "Search title..."}
value={searchName} value={searchName}
onChange={setSearchName} onChange={setSearchName}
/> />
@ -107,7 +108,7 @@ const Videos = ({ langui, videos, ...otherProps }: Props): JSX.Element => {
thumbnailForceAspectRatio thumbnailForceAspectRatio
keepInfoVisible={keepInfoVisible} keepInfoVisible={keepInfoVisible}
metadata={{ metadata={{
release_date: item.attributes.published_date, releaseDate: item.attributes.published_date,
views: item.attributes.views, views: item.attributes.views,
author: item.attributes.channel?.data?.attributes?.title, author: item.attributes.channel?.data?.attributes?.title,
position: "Top", position: "Top",
@ -132,7 +133,6 @@ const Videos = ({ langui, videos, ...otherProps }: Props): JSX.Element => {
); );
return ( return (
<AppLayout <AppLayout
navTitle={langui.archives}
subPanel={subPanel} subPanel={subPanel}
contentPanel={contentPanel} contentPanel={contentPanel}
langui={langui} langui={langui}
@ -152,19 +152,18 @@ export const getStaticProps: GetStaticProps = async (context) => {
const videos = await sdk.getVideosPreview(); const videos = await sdk.getVideosPreview();
if (!videos.videos) return { notFound: true }; if (!videos.videos) return { notFound: true };
videos.videos.data videos.videos.data
.sort((a, b) => { .sort((a, b) =>
const dateA = a.attributes?.published_date compareDate(a.attributes?.published_date, b.attributes?.published_date)
? prettyDate(a.attributes.published_date) )
: "9999";
const dateB = b.attributes?.published_date
? prettyDate(b.attributes.published_date)
: "9999";
return dateA.localeCompare(dateB);
})
.reverse(); .reverse();
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
videos: videos.videos.data, videos: videos.videos.data,
openGraph: getOpenGraph(
appStaticProps.langui,
appStaticProps.langui.videos ?? "Videos"
),
}; };
return { return {
props: props, props: props,

View File

@ -1,6 +1,7 @@
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { useMemo } from "react"; import { useMemo } from "react";
import { AppLayout } from "components/AppLayout"; import { useRouter } from "next/router";
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { HorizontalLine } from "components/HorizontalLine"; import { HorizontalLine } from "components/HorizontalLine";
import { Ico, Icon } from "components/Ico"; import { Ico, Icon } from "components/Ico";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
@ -23,13 +24,14 @@ import { prettyDate, prettyShortenNumber } from "helpers/formatters";
import { filterHasAttributes, isDefined } from "helpers/others"; import { filterHasAttributes, isDefined } from "helpers/others";
import { getVideoFile } from "helpers/videos"; import { getVideoFile } from "helpers/videos";
import { useMediaMobile } from "hooks/useMediaQuery"; import { useMediaMobile } from "hooks/useMediaQuery";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
video: NonNullable< video: NonNullable<
NonNullable<GetVideoQuery["videos"]>["data"][number]["attributes"] NonNullable<GetVideoQuery["videos"]>["data"][number]["attributes"]
>; >;
@ -38,6 +40,8 @@ interface Props extends AppStaticProps {
const Video = ({ langui, video, ...otherProps }: Props): JSX.Element => { const Video = ({ langui, video, ...otherProps }: Props): JSX.Element => {
const isMobile = useMediaMobile(); const isMobile = useMediaMobile();
const { setSubPanelOpen } = useAppLayout(); const { setSubPanelOpen } = useAppLayout();
const router = useRouter();
const subPanel = useMemo( const subPanel = useMemo(
() => ( () => (
<SubPanel> <SubPanel>
@ -118,7 +122,7 @@ const Video = ({ langui, video, ...otherProps }: Props): JSX.Element => {
icon={Icon.Event} icon={Icon.Event}
className="mr-1 translate-y-[.15em] !text-base" className="mr-1 translate-y-[.15em] !text-base"
/> />
{prettyDate(video.published_date)} {prettyDate(video.published_date, router.locale)}
</p> </p>
<p> <p>
<Ico <Ico
@ -184,6 +188,7 @@ const Video = ({ langui, video, ...otherProps }: Props): JSX.Element => {
[ [
isMobile, isMobile,
langui, langui,
router.locale,
video.channel?.data?.attributes, video.channel?.data?.attributes,
video.description, video.description,
video.gone, video.gone,
@ -198,7 +203,6 @@ const Video = ({ langui, video, ...otherProps }: Props): JSX.Element => {
return ( return (
<AppLayout <AppLayout
navTitle={langui.archives}
subPanel={subPanel} subPanel={subPanel}
contentPanel={contentPanel} contentPanel={contentPanel}
langui={langui} langui={langui}
@ -222,9 +226,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
: "", : "",
}); });
if (!videos.videos?.data[0]?.attributes) return { notFound: true }; if (!videos.videos?.data[0]?.attributes) return { notFound: true };
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
video: videos.videos.data[0].attributes, video: videos.videos.data[0].attributes,
openGraph: getOpenGraph(
appStaticProps.langui,
videos.videos.data[0].attributes.title
),
}; };
return { return {
props: props, props: props,

View File

@ -4,7 +4,7 @@ import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getReadySdk } from "graphql/sdk"; import { getReadySdk } from "graphql/sdk";
import { isDefined, filterHasAttributes } from "helpers/others"; import { isDefined, filterHasAttributes } from "helpers/others";
import { ChronicleWithTranslations } from "helpers/types"; import { ChronicleWithTranslations } from "helpers/types";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { useSmartLanguage } from "hooks/useSmartLanguage"; import { useSmartLanguage } from "hooks/useSmartLanguage";
import { ContentPanel } from "components/Panels/ContentPanel"; import { ContentPanel } from "components/Panels/ContentPanel";
import { Markdawn } from "components/Markdown/Markdawn"; import { Markdawn } from "components/Markdown/Markdawn";
@ -12,20 +12,26 @@ import { SubPanel } from "components/Panels/SubPanel";
import { ThumbnailHeader } from "components/ThumbnailHeader"; import { ThumbnailHeader } from "components/ThumbnailHeader";
import { HorizontalLine } from "components/HorizontalLine"; import { HorizontalLine } from "components/HorizontalLine";
import { GetChroniclesChaptersQuery } from "graphql/generated"; import { GetChroniclesChaptersQuery } from "graphql/generated";
import { prettySlug } from "helpers/formatters"; import { prettyInlineTitle, prettySlug } from "helpers/formatters";
import { import {
ReturnButton, ReturnButton,
ReturnButtonType, ReturnButtonType,
} from "components/PanelComponents/ReturnButton"; } from "components/PanelComponents/ReturnButton";
import { TranslatedChroniclesList } from "components/Translated"; import { TranslatedChroniclesList } from "components/Translated";
import { Icon } from "components/Ico"; import { Icon } from "components/Ico";
import { getOpenGraph } from "helpers/openGraph";
import {
getDefaultPreferredLanguages,
staticSmartLanguage,
} from "helpers/locales";
import { getDescription } from "helpers/description";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
chronicle: ChronicleWithTranslations; chronicle: ChronicleWithTranslations;
chapters: NonNullable< chapters: NonNullable<
GetChroniclesChaptersQuery["chroniclesChapters"] GetChroniclesChaptersQuery["chroniclesChapters"]
@ -191,7 +197,6 @@ const Chronicle = ({
return ( return (
<AppLayout <AppLayout
navTitle={langui.chronicles}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanel={subPanel} subPanel={subPanel}
langui={langui} langui={langui}
@ -220,15 +225,92 @@ export const getStaticProps: GetStaticProps = async (context) => {
}); });
const chronicles = await sdk.getChroniclesChapters(); const chronicles = await sdk.getChroniclesChapters();
if ( if (
!chronicle.chronicles?.data[0].attributes?.translations || !chronicle.chronicles?.data[0]?.attributes?.translations ||
!chronicles.chroniclesChapters?.data !chronicles.chroniclesChapters?.data
) )
return { notFound: true }; return { notFound: true };
const appStaticProps = await getAppStaticProps(context);
const { title, description } = (() => {
if (context.locale && context.locales) {
if (
chronicle.chronicles.data[0].attributes.contents?.data[0]?.attributes
?.translations
) {
const selectedContentTranslation = staticSmartLanguage({
items:
chronicle.chronicles.data[0].attributes.contents.data[0].attributes
.translations,
languageExtractor: (item) => item.language?.data?.attributes?.code,
preferredLanguages: getDefaultPreferredLanguages(
context.locale,
context.locales
),
});
if (selectedContentTranslation) {
return {
title: prettyInlineTitle(
selectedContentTranslation.pre_title,
selectedContentTranslation.title,
selectedContentTranslation.subtitle
),
description: getDescription(
selectedContentTranslation.description,
{
[appStaticProps.langui.type ?? "Type"]: [
chronicle.chronicles.data[0].attributes.contents.data[0]
.attributes.type?.data?.attributes?.titles?.[0]?.title,
],
[appStaticProps.langui.categories ?? "Categories"]:
filterHasAttributes(
chronicle.chronicles.data[0].attributes.contents.data[0]
.attributes.categories?.data,
["attributes"] as const
).map((category) => category.attributes.short),
}
),
};
}
} else {
const selectedTranslation = staticSmartLanguage({
items: chronicle.chronicles.data[0].attributes.translations,
languageExtractor: (item) => item.language?.data?.attributes?.code,
preferredLanguages: getDefaultPreferredLanguages(
context.locale,
context.locales
),
});
if (selectedTranslation) {
return {
title: selectedTranslation.title,
description: selectedTranslation.summary,
};
}
}
}
return {
title: prettySlug(chronicle.chronicles.data[0].attributes.slug),
description: undefined,
};
})();
const thumbnail =
chronicle.chronicles.data[0].attributes.translations.length === 0
? chronicle.chronicles.data[0].attributes.contents?.data[0]?.attributes
?.thumbnail?.data?.attributes
: undefined;
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
chronicle: chronicle.chronicles.data[0] chronicle: chronicle.chronicles.data[0]
.attributes as ChronicleWithTranslations, .attributes as ChronicleWithTranslations,
chapters: chronicles.chroniclesChapters.data, chapters: chronicles.chroniclesChapters.data,
openGraph: getOpenGraph(
appStaticProps.langui,
title,
description,
thumbnail
),
}; };
return { return {
props: props, props: props,

View File

@ -1,6 +1,6 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useMemo } from "react"; import { useMemo } from "react";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { PanelHeader } from "components/PanelComponents/PanelHeader"; import { PanelHeader } from "components/PanelComponents/PanelHeader";
import { SubPanel } from "components/Panels/SubPanel"; import { SubPanel } from "components/Panels/SubPanel";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
@ -10,13 +10,14 @@ import { GetChroniclesChaptersQuery } from "graphql/generated";
import { filterHasAttributes } from "helpers/others"; import { filterHasAttributes } from "helpers/others";
import { prettySlug } from "helpers/formatters"; import { prettySlug } from "helpers/formatters";
import { TranslatedChroniclesList } from "components/Translated"; import { TranslatedChroniclesList } from "components/Translated";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
chapters: NonNullable< chapters: NonNullable<
GetChroniclesChaptersQuery["chroniclesChapters"] GetChroniclesChaptersQuery["chroniclesChapters"]
>["data"]; >["data"];
@ -58,14 +59,7 @@ const Chronicles = ({
[chapters, langui] [chapters, langui]
); );
return ( return <AppLayout subPanel={subPanel} langui={langui} {...otherProps} />;
<AppLayout
navTitle={langui.chronicles}
subPanel={subPanel}
langui={langui}
{...otherProps}
/>
);
}; };
export default Chronicles; export default Chronicles;
@ -78,9 +72,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
const sdk = getReadySdk(); const sdk = getReadySdk();
const chronicles = await sdk.getChroniclesChapters(); const chronicles = await sdk.getChroniclesChapters();
if (!chronicles.chroniclesChapters?.data) return { notFound: true }; if (!chronicles.chroniclesChapters?.data) return { notFound: true };
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
chapters: chronicles.chroniclesChapters.data, chapters: chronicles.chroniclesChapters.data,
openGraph: getOpenGraph(
appStaticProps.langui,
appStaticProps.langui.chronicles ?? "Chronicles"
),
}; };
return { return {
props: props, props: props,

View File

@ -1,6 +1,6 @@
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { Fragment, useCallback, useMemo } from "react"; import { Fragment, useCallback, useMemo } from "react";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Chip } from "components/Chip"; import { Chip } from "components/Chip";
import { HorizontalLine } from "components/HorizontalLine"; import { HorizontalLine } from "components/HorizontalLine";
import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs"; import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
@ -17,7 +17,6 @@ import { ThumbnailHeader } from "components/ThumbnailHeader";
import { ToolTip } from "components/ToolTip"; import { ToolTip } from "components/ToolTip";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getReadySdk } from "graphql/sdk"; import { getReadySdk } from "graphql/sdk";
import { getDescription } from "helpers/description";
import { import {
prettyInlineTitle, prettyInlineTitle,
prettyLanguage, prettyLanguage,
@ -35,13 +34,19 @@ import { useMediaMobile } from "hooks/useMediaQuery";
import { AnchorIds, useScrollTopOnChange } from "hooks/useScrollTopOnChange"; import { AnchorIds, useScrollTopOnChange } from "hooks/useScrollTopOnChange";
import { useSmartLanguage } from "hooks/useSmartLanguage"; import { useSmartLanguage } from "hooks/useSmartLanguage";
import { TranslatedPreviewLine } from "components/Translated"; import { TranslatedPreviewLine } from "components/Translated";
import { getOpenGraph } from "helpers/openGraph";
import {
getDefaultPreferredLanguages,
staticSmartLanguage,
} from "helpers/locales";
import { getDescription } from "helpers/description";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
content: ContentWithTranslations; content: ContentWithTranslations;
} }
@ -260,7 +265,7 @@ const Content = ({
).map((category) => category.attributes.short)} ).map((category) => category.attributes.short)}
metadata={{ metadata={{
currencies: currencies, currencies: currencies,
release_date: libraryItem.attributes.release_date, releaseDate: libraryItem.attributes.release_date,
price: libraryItem.attributes.price, price: libraryItem.attributes.price,
position: "Bottom", position: "Bottom",
}} }}
@ -457,22 +462,6 @@ const Content = ({
return ( return (
<AppLayout <AppLayout
navTitle={
selectedTranslation
? prettyInlineTitle(
selectedTranslation.pre_title,
selectedTranslation.title,
selectedTranslation.subtitle
)
: prettySlug(content.slug)
}
description={getDescription({
langui: langui,
description: selectedTranslation?.description,
type: content.type,
categories: content.categories,
})}
thumbnail={content.thumbnail?.data?.attributes ?? undefined}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanel={subPanel} subPanel={subPanel}
currencies={currencies} currencies={currencies}
@ -500,9 +489,57 @@ export const getStaticProps: GetStaticProps = async (context) => {
if (!content.contents?.data[0]?.attributes?.translations) { if (!content.contents?.data[0]?.attributes?.translations) {
return { notFound: true }; return { notFound: true };
} }
const appStaticProps = await getAppStaticProps(context);
const { title, description } = (() => {
if (context.locale && context.locales) {
const selectedTranslation = staticSmartLanguage({
items: content.contents.data[0].attributes.translations,
languageExtractor: (item) => item.language?.data?.attributes?.code,
preferredLanguages: getDefaultPreferredLanguages(
context.locale,
context.locales
),
});
if (selectedTranslation) {
return {
title: prettyInlineTitle(
selectedTranslation.pre_title,
selectedTranslation.title,
selectedTranslation.subtitle
),
description: getDescription(selectedTranslation.description, {
[appStaticProps.langui.type ?? "Type"]: [
content.contents.data[0].attributes.type?.data?.attributes
?.titles?.[0]?.title,
],
[appStaticProps.langui.categories ?? "Categories"]:
filterHasAttributes(
content.contents.data[0].attributes.categories?.data,
["attributes"] as const
).map((category) => category.attributes.short),
}),
};
}
}
return {
title: prettySlug(content.contents.data[0].attributes.slug),
description: undefined,
};
})();
const thumbnail =
content.contents.data[0].attributes.thumbnail?.data?.attributes;
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
content: content.contents.data[0].attributes as ContentWithTranslations, content: content.contents.data[0].attributes as ContentWithTranslations,
openGraph: getOpenGraph(
appStaticProps.langui,
title,
description,
thumbnail
),
}; };
return { return {
props: props, props: props,

View File

@ -1,6 +1,6 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useState, useMemo, useCallback } from "react"; import { useState, useMemo, useCallback } from "react";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Select } from "components/Inputs/Select"; import { Select } from "components/Inputs/Select";
import { Switch } from "components/Inputs/Switch"; import { Switch } from "components/Inputs/Switch";
import { PanelHeader } from "components/PanelComponents/PanelHeader"; import { PanelHeader } from "components/PanelComponents/PanelHeader";
@ -23,6 +23,7 @@ import { SmartList } from "components/SmartList";
import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable"; import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable";
import { useBoolean } from "hooks/useBoolean"; import { useBoolean } from "hooks/useBoolean";
import { TranslatedPreviewCard } from "components/Translated"; import { TranslatedPreviewCard } from "components/Translated";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
@ -41,7 +42,7 @@ const DEFAULT_FILTERS_STATE = {
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
contents: NonNullable<GetContentsQuery["contents"]>["data"]; contents: NonNullable<GetContentsQuery["contents"]>["data"];
} }
@ -164,7 +165,7 @@ const Contents = ({
<TextInput <TextInput
className="mb-6 w-full" className="mb-6 w-full"
placeholder={langui.search_title ?? undefined} placeholder={langui.search_title ?? "Search..."}
value={searchName} value={searchName}
onChange={setSearchName} onChange={setSearchName}
/> />
@ -174,7 +175,7 @@ const Contents = ({
input={ input={
<Select <Select
className="w-full" className="w-full"
options={[langui.category ?? "", langui.type ?? ""]} options={[langui.category ?? "Category", langui.type ?? "Type"]}
value={groupingMethod} value={groupingMethod}
onChange={setGroupingMethod} onChange={setGroupingMethod}
allowEmpty allowEmpty
@ -317,7 +318,6 @@ const Contents = ({
return ( return (
<AppLayout <AppLayout
navTitle={langui.contents}
subPanel={subPanel} subPanel={subPanel}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanelIcon={Icon.Search} subPanelIcon={Icon.Search}
@ -346,9 +346,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
return titleA.localeCompare(titleB); return titleA.localeCompare(titleB);
}); });
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
contents: contents.contents.data, contents: contents.contents.data,
openGraph: getOpenGraph(
appStaticProps.langui,
appStaticProps.langui.contents ?? "Contents"
),
}; };
return { return {
props: props, props: props,

View File

@ -1,6 +1,6 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useMemo } from "react"; import { useMemo } from "react";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Chip } from "components/Chip"; import { Chip } from "components/Chip";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
import { import {
@ -13,13 +13,14 @@ import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getReadySdk } from "graphql/sdk"; import { getReadySdk } from "graphql/sdk";
import { filterDefined, filterHasAttributes } from "helpers/others"; import { filterDefined, filterHasAttributes } from "helpers/others";
import { Report, Severity } from "helpers/types/Report"; import { Report, Severity } from "helpers/types/Report";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
contents: DevGetContentsQuery; contents: DevGetContentsQuery;
} }
@ -87,13 +88,7 @@ const CheckupContents = ({ contents, ...otherProps }: Props): JSX.Element => {
[testReport.lines, testReport.title] [testReport.lines, testReport.title]
); );
return ( return <AppLayout contentPanel={contentPanel} {...otherProps} />;
<AppLayout
navTitle={"Checkup"}
contentPanel={contentPanel}
{...otherProps}
/>
);
}; };
export default CheckupContents; export default CheckupContents;
@ -105,9 +100,11 @@ export default CheckupContents;
export const getStaticProps: GetStaticProps = async (context) => { export const getStaticProps: GetStaticProps = async (context) => {
const sdk = getReadySdk(); const sdk = getReadySdk();
const contents = await sdk.devGetContents(); const contents = await sdk.devGetContents();
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
contents: contents, contents: contents,
openGraph: getOpenGraph(appStaticProps.langui, "Checkup Contents"),
}; };
return { return {
props: props, props: props,

View File

@ -1,6 +1,6 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useMemo } from "react"; import { useMemo } from "react";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Chip } from "components/Chip"; import { Chip } from "components/Chip";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
import { import {
@ -15,13 +15,14 @@ import {
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getReadySdk } from "graphql/sdk"; import { getReadySdk } from "graphql/sdk";
import { Report, Severity } from "helpers/types/Report"; import { Report, Severity } from "helpers/types/Report";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
libraryItems: DevGetLibraryItemsQuery; libraryItems: DevGetLibraryItemsQuery;
} }
@ -92,13 +93,7 @@ const CheckupLibraryItems = ({
[testReport.lines, testReport.title] [testReport.lines, testReport.title]
); );
return ( return <AppLayout contentPanel={contentPanel} {...otherProps} />;
<AppLayout
navTitle={"Checkup"}
contentPanel={contentPanel}
{...otherProps}
/>
);
}; };
export default CheckupLibraryItems; export default CheckupLibraryItems;
@ -110,9 +105,11 @@ export default CheckupLibraryItems;
export const getStaticProps: GetStaticProps = async (context) => { export const getStaticProps: GetStaticProps = async (context) => {
const sdk = getReadySdk(); const sdk = getReadySdk();
const libraryItems = await sdk.devGetLibraryItems(); const libraryItems = await sdk.devGetLibraryItems();
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
libraryItems: libraryItems, libraryItems: libraryItems,
openGraph: getOpenGraph(appStaticProps.langui, "Checkup Library Items"),
}; };
return { return {
props: props, props: props,

View File

@ -1,7 +1,7 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useCallback, useMemo, useRef, useState } from "react"; import { useCallback, useMemo, useRef, useState } from "react";
import TurndownService from "turndown"; import TurndownService from "turndown";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
import { Markdawn, TableOfContents } from "components/Markdown/Markdawn"; import { Markdawn, TableOfContents } from "components/Markdown/Markdawn";
import { import {
@ -12,13 +12,14 @@ import { Popup } from "components/Popup";
import { ToolTip } from "components/ToolTip"; import { ToolTip } from "components/ToolTip";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { Icon } from "components/Ico"; import { Icon } from "components/Ico";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps {} interface Props extends AppStaticProps, AppLayoutRequired {}
const Editor = ({ langui, ...otherProps }: Props): JSX.Element => { const Editor = ({ langui, ...otherProps }: Props): JSX.Element => {
const handleInput = useCallback((text: string) => { const handleInput = useCallback((text: string) => {
@ -465,12 +466,7 @@ const Editor = ({ langui, ...otherProps }: Props): JSX.Element => {
); );
return ( return (
<AppLayout <AppLayout contentPanel={contentPanel} langui={langui} {...otherProps} />
navTitle="Markdawn Editor"
contentPanel={contentPanel}
langui={langui}
{...otherProps}
/>
); );
}; };
export default Editor; export default Editor;
@ -481,8 +477,10 @@ export default Editor;
*/ */
export const getStaticProps: GetStaticProps = async (context) => { export const getStaticProps: GetStaticProps = async (context) => {
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
openGraph: getOpenGraph(appStaticProps.langui, "Markdawn Editor"),
}; };
return { return {
props: props, props: props,

View File

@ -1,6 +1,6 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useCallback, useMemo, useRef, useState } from "react"; import { useCallback, useMemo, useRef, useState } from "react";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
import { ButtonGroup } from "components/Inputs/ButtonGroup"; import { ButtonGroup } from "components/Inputs/ButtonGroup";
import { import {
@ -9,6 +9,7 @@ import {
} from "components/Panels/ContentPanel"; } from "components/Panels/ContentPanel";
import { ToolTip } from "components/ToolTip"; import { ToolTip } from "components/ToolTip";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
@ -22,7 +23,7 @@ const SIZE_MULTIPLIER = 1000;
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps {} interface Props extends AppStaticProps, AppLayoutRequired {}
const replaceSelection = ( const replaceSelection = (
text: string, text: string,
@ -566,7 +567,6 @@ const Transcript = (props: Props): JSX.Element => {
return ( return (
<AppLayout <AppLayout
navTitle="Transcript"
contentPanel={contentPanel} contentPanel={contentPanel}
{...props} {...props}
contentPanelScroolbar={false} contentPanelScroolbar={false}
@ -581,8 +581,13 @@ export default Transcript;
*/ */
export const getStaticProps: GetStaticProps = async (context) => { export const getStaticProps: GetStaticProps = async (context) => {
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
openGraph: getOpenGraph(
appStaticProps.langui,
"Japanese Transcription Tool"
),
}; };
return { return {
props: props, props: props,

View File

@ -9,17 +9,9 @@ import {
* PAGE * PAGE
*/ */
const Home = ({ const Home = (props: PostStaticProps): JSX.Element => (
post,
langui,
languages,
currencies,
}: PostStaticProps): JSX.Element => (
<PostPage <PostPage
currencies={currencies} {...props}
languages={languages}
langui={langui}
post={post}
prependBody={ prependBody={
<div className="grid w-full place-content-center place-items-center gap-5 text-center"> <div className="grid w-full place-content-center place-items-center gap-5 text-center">
<div <div

View File

@ -1,6 +1,7 @@
import { Fragment, useCallback, useMemo } from "react"; import { Fragment, useCallback, useMemo } from "react";
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { AppLayout } from "components/AppLayout"; import { useRouter } from "next/router";
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Chip } from "components/Chip"; import { Chip } from "components/Chip";
import { Img } from "components/Img"; import { Img } from "components/Img";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
@ -52,15 +53,16 @@ import { WithLabel } from "components/Inputs/WithLabel";
import { Ico, Icon } from "components/Ico"; import { Ico, Icon } from "components/Ico";
import { cJoin, cIf } from "helpers/className"; import { cJoin, cIf } from "helpers/className";
import { useSmartLanguage } from "hooks/useSmartLanguage"; import { useSmartLanguage } from "hooks/useSmartLanguage";
import { getDescription } from "helpers/description";
import { useBoolean } from "hooks/useBoolean"; import { useBoolean } from "hooks/useBoolean";
import { getOpenGraph } from "helpers/openGraph";
import { getDescription } from "helpers/description";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
item: NonNullable< item: NonNullable<
NonNullable< NonNullable<
GetLibraryItemQuery["libraryItems"] GetLibraryItemQuery["libraryItems"]
@ -81,6 +83,7 @@ const LibrarySlug = ({
}: Props): JSX.Element => { }: Props): JSX.Element => {
const { currency } = useAppLayout(); const { currency } = useAppLayout();
const hoverable = useMediaHoverable(); const hoverable = useMediaHoverable();
const router = useRouter();
const [openLightBox, LightBox] = useLightBox(); const [openLightBox, LightBox] = useLightBox();
const { state: keepInfoVisible, toggleState: toggleKeepInfoVisible } = const { state: keepInfoVisible, toggleState: toggleKeepInfoVisible } =
useBoolean(false); useBoolean(false);
@ -300,7 +303,7 @@ const LibrarySlug = ({
{item.release_date && ( {item.release_date && (
<div className="grid place-content-start place-items-center"> <div className="grid place-content-start place-items-center">
<h3 className="text-xl">{langui.release_date}</h3> <h3 className="text-xl">{langui.release_date}</h3>
<p>{prettyDate(item.release_date)}</p> <p>{prettyDate(item.release_date, router.locale)}</p>
</div> </div>
)} )}
@ -483,7 +486,7 @@ const LibrarySlug = ({
)} )}
metadata={{ metadata={{
currencies: currencies, currencies: currencies,
release_date: subitem.attributes.release_date, releaseDate: subitem.attributes.release_date,
price: subitem.attributes.price, price: subitem.attributes.price,
position: "Bottom", position: "Bottom",
}} }}
@ -569,8 +572,23 @@ const LibrarySlug = ({
[ [
LightBox, LightBox,
langui, langui,
item, item.thumbnail?.data?.attributes,
item.subitem_of?.data,
item.title,
item.subtitle,
item.metadata,
item.descriptions,
item.urls,
item.gallery,
item.release_date,
item.price,
item.categories,
item.size,
item.subitems,
item.contents,
item.slug,
itemId, itemId,
router.locale,
currencies, currencies,
currency, currency,
isVariantSet, isVariantSet,
@ -585,14 +603,8 @@ const LibrarySlug = ({
return ( return (
<AppLayout <AppLayout
navTitle={prettyInlineTitle("", item.title, item.subtitle)}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanel={subPanel} subPanel={subPanel}
thumbnail={item.thumbnail?.data?.attributes ?? undefined}
description={getDescription({
langui,
description: item.descriptions?.[0]?.description,
})}
currencies={currencies} currencies={currencies}
languages={languages} languages={languages}
langui={langui} langui={langui}
@ -618,10 +630,42 @@ export const getStaticProps: GetStaticProps = async (context) => {
}); });
if (!item.libraryItems?.data[0]?.attributes) return { notFound: true }; if (!item.libraryItems?.data[0]?.attributes) return { notFound: true };
sortRangedContent(item.libraryItems.data[0].attributes.contents); sortRangedContent(item.libraryItems.data[0].attributes.contents);
const appStaticProps = await getAppStaticProps(context);
const { title, thumbnail } = item.libraryItems.data[0].attributes;
const description = getDescription(
item.libraryItems.data[0].attributes.descriptions?.[0]?.description,
{
[appStaticProps.langui.categories ?? "Categories"]: filterHasAttributes(
item.libraryItems.data[0].attributes.categories?.data,
["attributes.short"]
).map((category) => category.attributes.short),
[appStaticProps.langui.type ?? "Type"]: item.libraryItems.data[0]
.attributes.metadata?.[0]
? [prettyItemSubType(item.libraryItems.data[0].attributes.metadata[0])]
: [],
[appStaticProps.langui.release_date ?? "Release date"]: [
item.libraryItems.data[0].attributes.release_date
? prettyDate(
item.libraryItems.data[0].attributes.release_date,
context.locale
)
: undefined,
],
}
);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
item: item.libraryItems.data[0].attributes, item: item.libraryItems.data[0].attributes,
itemId: item.libraryItems.data[0].id, itemId: item.libraryItems.data[0].id,
openGraph: getOpenGraph(
appStaticProps.langui,
title,
description,
thumbnail?.data?.attributes
),
}; };
return { return {
props: props, props: props,

View File

@ -1,6 +1,6 @@
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { Fragment, useMemo } from "react"; import { Fragment, useMemo } from "react";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { ScanSetCover } from "components/Library/ScanSetCover"; import { ScanSetCover } from "components/Library/ScanSetCover";
import { import {
ReturnButton, ReturnButton,
@ -30,13 +30,14 @@ import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
import { PreviewCard } from "components/PreviewCard"; import { PreviewCard } from "components/PreviewCard";
import { HorizontalLine } from "components/HorizontalLine"; import { HorizontalLine } from "components/HorizontalLine";
import { TranslatedNavOption, TranslatedScanSet } from "components/Translated"; import { TranslatedNavOption, TranslatedScanSet } from "components/Translated";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
item: NonNullable< item: NonNullable<
NonNullable< NonNullable<
GetLibraryItemScansQuery["libraryItems"] GetLibraryItemScansQuery["libraryItems"]
@ -87,7 +88,7 @@ const LibrarySlug = ({
] as const).map((category) => category.attributes.short)} ] as const).map((category) => category.attributes.short)}
metadata={{ metadata={{
currencies: currencies, currencies: currencies,
release_date: item.release_date, releaseDate: item.release_date,
price: item.price, price: item.price,
position: "Bottom", position: "Bottom",
}} }}
@ -232,10 +233,8 @@ const LibrarySlug = ({
return ( return (
<AppLayout <AppLayout
navTitle={prettyInlineTitle("", item.title, item.subtitle)}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanel={subPanel} subPanel={subPanel}
thumbnail={item.thumbnail?.data?.attributes ?? undefined}
languages={languages} languages={languages}
langui={langui} langui={langui}
currencies={currencies} currencies={currencies}
@ -262,10 +261,17 @@ export const getStaticProps: GetStaticProps = async (context) => {
if (!item.libraryItems?.data[0]?.attributes || !item.libraryItems.data[0]?.id) if (!item.libraryItems?.data[0]?.attributes || !item.libraryItems.data[0]?.id)
return { notFound: true }; return { notFound: true };
sortRangedContent(item.libraryItems.data[0].attributes.contents); sortRangedContent(item.libraryItems.data[0].attributes.contents);
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
item: item.libraryItems.data[0].attributes, item: item.libraryItems.data[0].attributes,
itemId: item.libraryItems.data[0].id, itemId: item.libraryItems.data[0].id,
openGraph: getOpenGraph(
appStaticProps.langui,
item.libraryItems.data[0].attributes.title,
undefined,
item.libraryItems.data[0].attributes.thumbnail?.data?.attributes
),
}; };
return { return {
props: props, props: props,

View File

@ -1,6 +1,6 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useState, useMemo, useCallback } from "react"; import { useState, useMemo, useCallback } from "react";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Select } from "components/Inputs/Select"; import { Select } from "components/Inputs/Select";
import { Switch } from "components/Inputs/Switch"; import { Switch } from "components/Inputs/Switch";
import { PanelHeader } from "components/PanelComponents/PanelHeader"; import { PanelHeader } from "components/PanelComponents/PanelHeader";
@ -12,11 +12,7 @@ import { SubPanel } from "components/Panels/SubPanel";
import { GetLibraryItemsPreviewQuery } from "graphql/generated"; import { GetLibraryItemsPreviewQuery } from "graphql/generated";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getReadySdk } from "graphql/sdk"; import { getReadySdk } from "graphql/sdk";
import { import { prettyInlineTitle, prettyItemSubType } from "helpers/formatters";
prettyDate,
prettyInlineTitle,
prettyItemSubType,
} from "helpers/formatters";
import { LibraryItemUserStatus } from "helpers/types"; import { LibraryItemUserStatus } from "helpers/types";
import { Icon } from "components/Ico"; import { Icon } from "components/Ico";
import { WithLabel } from "components/Inputs/WithLabel"; import { WithLabel } from "components/Inputs/WithLabel";
@ -33,6 +29,8 @@ import { convertPrice } from "helpers/numbers";
import { SmartList } from "components/SmartList"; import { SmartList } from "components/SmartList";
import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable"; import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable";
import { useBoolean } from "hooks/useBoolean"; import { useBoolean } from "hooks/useBoolean";
import { getOpenGraph } from "helpers/openGraph";
import { compareDate } from "helpers/date";
/* /*
* *
@ -55,7 +53,7 @@ const DEFAULT_FILTERS_STATE = {
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
items: NonNullable<GetLibraryItemsPreviewQuery["libraryItems"]>["data"]; items: NonNullable<GetLibraryItemsPreviewQuery["libraryItems"]>["data"];
} }
@ -174,13 +172,10 @@ const Library = ({
return priceA - priceB; return priceA - priceB;
} }
case 2: { case 2: {
const dateA = a.attributes.release_date return compareDate(
? prettyDate(a.attributes.release_date) a.attributes.release_date,
: "9999"; b.attributes.release_date
const dateB = b.attributes.release_date );
? prettyDate(b.attributes.release_date)
: "9999";
return dateA.localeCompare(dateB);
} }
default: default:
return 0; return 0;
@ -268,7 +263,7 @@ const Library = ({
<TextInput <TextInput
className="mb-6 w-full" className="mb-6 w-full"
placeholder={langui.search_title ?? undefined} placeholder={langui.search_title ?? "Search..."}
value={searchName} value={searchName}
onChange={setSearchName} onChange={setSearchName}
/> />
@ -433,7 +428,7 @@ const Library = ({
)} )}
metadata={{ metadata={{
currencies: currencies, currencies: currencies,
release_date: item.attributes.release_date, releaseDate: item.attributes.release_date,
price: item.attributes.price, price: item.attributes.price,
position: "Bottom", position: "Bottom",
}} }}
@ -474,7 +469,6 @@ const Library = ({
return ( return (
<AppLayout <AppLayout
navTitle={langui.library}
subPanel={subPanel} subPanel={subPanel}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanelIcon={Icon.Search} subPanelIcon={Icon.Search}
@ -497,9 +491,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
language_code: context.locale ?? "en", language_code: context.locale ?? "en",
}); });
if (!items.libraryItems?.data) return { notFound: true }; if (!items.libraryItems?.data) return { notFound: true };
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
items: items.libraryItems.data, items: items.libraryItems.data,
openGraph: getOpenGraph(
appStaticProps.langui,
appStaticProps.langui.library ?? "Library"
),
}; };
return { return {
props: props, props: props,

View File

@ -1,19 +1,19 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { PanelHeader } from "components/PanelComponents/PanelHeader"; import { PanelHeader } from "components/PanelComponents/PanelHeader";
import { SubPanel } from "components/Panels/SubPanel"; import { SubPanel } from "components/Panels/SubPanel";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { Icon } from "components/Ico"; import { Icon } from "components/Ico";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps {} interface Props extends AppStaticProps, AppLayoutRequired {}
const Merch = ({ langui, ...otherProps }: Props): JSX.Element => ( const Merch = ({ langui, ...otherProps }: Props): JSX.Element => (
<AppLayout <AppLayout
navTitle={langui.merch}
subPanel={ subPanel={
<SubPanel> <SubPanel>
<PanelHeader <PanelHeader
@ -35,8 +35,13 @@ export default Merch;
*/ */
export const getStaticProps: GetStaticProps = async (context) => { export const getStaticProps: GetStaticProps = async (context) => {
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
openGraph: getOpenGraph(
appStaticProps.langui,
appStaticProps.langui.merch ?? "Merch"
),
}; };
return { return {
props: props, props: props,

View File

@ -1,6 +1,6 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Switch } from "components/Inputs/Switch"; import { Switch } from "components/Inputs/Switch";
import { PanelHeader } from "components/PanelComponents/PanelHeader"; import { PanelHeader } from "components/PanelComponents/PanelHeader";
import { import {
@ -11,7 +11,7 @@ import { SubPanel } from "components/Panels/SubPanel";
import { GetPostsPreviewQuery } from "graphql/generated"; import { GetPostsPreviewQuery } from "graphql/generated";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getReadySdk } from "graphql/sdk"; import { getReadySdk } from "graphql/sdk";
import { prettyDate, prettySlug } from "helpers/formatters"; import { prettySlug } from "helpers/formatters";
import { Icon } from "components/Ico"; import { Icon } from "components/Ico";
import { WithLabel } from "components/Inputs/WithLabel"; import { WithLabel } from "components/Inputs/WithLabel";
import { TextInput } from "components/Inputs/TextInput"; import { TextInput } from "components/Inputs/TextInput";
@ -21,6 +21,8 @@ import { filterHasAttributes } from "helpers/others";
import { SmartList } from "components/SmartList"; import { SmartList } from "components/SmartList";
import { useBoolean } from "hooks/useBoolean"; import { useBoolean } from "hooks/useBoolean";
import { TranslatedPreviewCard } from "components/Translated"; import { TranslatedPreviewCard } from "components/Translated";
import { getOpenGraph } from "helpers/openGraph";
import { compareDate } from "helpers/date";
/* /*
* *
@ -37,7 +39,7 @@ const DEFAULT_FILTERS_STATE = {
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
posts: NonNullable<GetPostsPreviewQuery["posts"]>["data"]; posts: NonNullable<GetPostsPreviewQuery["posts"]>["data"];
} }
@ -63,7 +65,7 @@ const News = ({ langui, posts, ...otherProps }: Props): JSX.Element => {
<TextInput <TextInput
className="mb-6 w-full" className="mb-6 w-full"
placeholder={langui.search_title ?? undefined} placeholder={langui.search_title ?? "Search..."}
value={searchName} value={searchName}
onChange={setSearchName} onChange={setSearchName}
/> />
@ -124,7 +126,8 @@ const News = ({ langui, posts, ...otherProps }: Props): JSX.Element => {
)} )}
keepInfoVisible={keepInfoVisible} keepInfoVisible={keepInfoVisible}
metadata={{ metadata={{
release_date: post.attributes.date, releaseDate: post.attributes.date,
releaseDateFormat: "long",
position: "Top", position: "Top",
}} }}
/> />
@ -144,7 +147,6 @@ const News = ({ langui, posts, ...otherProps }: Props): JSX.Element => {
return ( return (
<AppLayout <AppLayout
navTitle={langui.news}
subPanel={subPanel} subPanel={subPanel}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanelIcon={Icon.Search} subPanelIcon={Icon.Search}
@ -164,9 +166,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
const sdk = getReadySdk(); const sdk = getReadySdk();
const posts = await sdk.getPostsPreview(); const posts = await sdk.getPostsPreview();
if (!posts.posts) return { notFound: true }; if (!posts.posts) return { notFound: true };
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
posts: sortPosts(posts.posts.data), posts: sortPosts(posts.posts.data),
openGraph: getOpenGraph(
appStaticProps.langui,
appStaticProps.langui.news ?? "News"
),
}; };
return { return {
props: props, props: props,
@ -180,9 +187,5 @@ export const getStaticProps: GetStaticProps = async (context) => {
const sortPosts = (posts: Props["posts"]): Props["posts"] => const sortPosts = (posts: Props["posts"]): Props["posts"] =>
posts posts
.sort((a, b) => { .sort((a, b) => compareDate(a.attributes?.date, b.attributes?.date))
const dateA = a.attributes?.date ? prettyDate(a.attributes.date) : "9999";
const dateB = b.attributes?.date ? prettyDate(b.attributes.date) : "9999";
return dateA.localeCompare(dateB);
})
.reverse(); .reverse();

View File

@ -1,6 +1,6 @@
import { useCallback, useMemo } from "react"; import { useCallback, useMemo } from "react";
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Chip } from "components/Chip"; import { Chip } from "components/Chip";
import { HorizontalLine } from "components/HorizontalLine"; import { HorizontalLine } from "components/HorizontalLine";
import { Img } from "components/Img"; import { Img } from "components/Img";
@ -26,13 +26,19 @@ import { useSmartLanguage } from "hooks/useSmartLanguage";
import { prettySlug } from "helpers/formatters"; import { prettySlug } from "helpers/formatters";
import { useLightBox } from "hooks/useLightBox"; import { useLightBox } from "hooks/useLightBox";
import { getAssetURL, ImageQuality } from "helpers/img"; import { getAssetURL, ImageQuality } from "helpers/img";
import { getOpenGraph } from "helpers/openGraph";
import {
getDefaultPreferredLanguages,
staticSmartLanguage,
} from "helpers/locales";
import { getDescription } from "helpers/description";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
page: WikiPageWithTranslations; page: WikiPageWithTranslations;
} }
@ -217,7 +223,6 @@ const WikiPage = ({
return ( return (
<AppLayout <AppLayout
navTitle={langui.news}
subPanel={subPanel} subPanel={subPanel}
contentPanel={contentPanel} contentPanel={contentPanel}
languages={languages} languages={languages}
@ -245,9 +250,58 @@ export const getStaticProps: GetStaticProps = async (context) => {
}); });
if (!page.wikiPages?.data[0].attributes?.translations) if (!page.wikiPages?.data[0].attributes?.translations)
return { notFound: true }; return { notFound: true };
const appStaticProps = await getAppStaticProps(context);
const { title, description } = (() => {
const chipsGroups = {
[appStaticProps.langui.tags ?? "Tags"]: filterHasAttributes(
page.wikiPages.data[0].attributes.tags?.data,
["attributes"] as const
).map(
(tag) =>
tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug)
),
[appStaticProps.langui.categories ?? "Categories"]: filterHasAttributes(
page.wikiPages.data[0].attributes.categories?.data,
["attributes"] as const
).map((category) => category.attributes.short),
};
if (context.locale && context.locales) {
const selectedTranslation = staticSmartLanguage({
items: page.wikiPages.data[0].attributes.translations,
languageExtractor: (item) => item.language?.data?.attributes?.code,
preferredLanguages: getDefaultPreferredLanguages(
context.locale,
context.locales
),
});
if (selectedTranslation) {
return {
title: selectedTranslation.title,
description: getDescription(selectedTranslation.summary, chipsGroups),
};
}
}
return {
title: prettySlug(page.wikiPages.data[0].attributes.slug),
description: getDescription(undefined, chipsGroups),
};
})();
const thumbnail =
page.wikiPages.data[0].attributes.thumbnail?.data?.attributes;
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
page: page.wikiPages.data[0].attributes as WikiPageWithTranslations, page: page.wikiPages.data[0].attributes as WikiPageWithTranslations,
openGraph: getOpenGraph(
appStaticProps.langui,
title,
description,
thumbnail
),
}; };
return { return {
props: props, props: props,

View File

@ -1,6 +1,6 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { Fragment, useMemo } from "react"; import { Fragment, useMemo } from "react";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { InsetBox } from "components/InsetBox"; import { InsetBox } from "components/InsetBox";
import { NavOption } from "components/PanelComponents/NavOption"; import { NavOption } from "components/PanelComponents/NavOption";
import { import {
@ -15,13 +15,14 @@ import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getReadySdk } from "graphql/sdk"; import { getReadySdk } from "graphql/sdk";
import { prettySlug } from "helpers/formatters"; import { prettySlug } from "helpers/formatters";
import { filterHasAttributes, isDefined } from "helpers/others"; import { filterHasAttributes, isDefined } from "helpers/others";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
chronologyItems: NonNullable< chronologyItems: NonNullable<
GetChronologyItemsQuery["chronologyItems"] GetChronologyItemsQuery["chronologyItems"]
>["data"]; >["data"];
@ -145,7 +146,6 @@ const Chronology = ({
return ( return (
<AppLayout <AppLayout
navTitle={langui.chronology}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanel={subPanel} subPanel={subPanel}
langui={langui} langui={langui}
@ -166,10 +166,15 @@ export const getStaticProps: GetStaticProps = async (context) => {
const chronologyEras = await sdk.getEras(); const chronologyEras = await sdk.getEras();
if (!chronologyItems.chronologyItems || !chronologyEras.chronologyEras) if (!chronologyItems.chronologyItems || !chronologyEras.chronologyEras)
return { notFound: true }; return { notFound: true };
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
chronologyItems: chronologyItems.chronologyItems.data, chronologyItems: chronologyItems.chronologyItems.data,
chronologyEras: chronologyEras.chronologyEras.data, chronologyEras: chronologyEras.chronologyEras.data,
openGraph: getOpenGraph(
appStaticProps.langui,
appStaticProps.langui.chronology ?? "Chronology"
),
}; };
return { return {
props: props, props: props,

View File

@ -1,6 +1,6 @@
import { GetStaticProps } from "next"; import { GetStaticProps } from "next";
import { useCallback, useMemo, useState } from "react"; import { useCallback, useMemo, useState } from "react";
import { AppLayout } from "components/AppLayout"; import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { NavOption } from "components/PanelComponents/NavOption"; import { NavOption } from "components/PanelComponents/NavOption";
import { PanelHeader } from "components/PanelComponents/PanelHeader"; import { PanelHeader } from "components/PanelComponents/PanelHeader";
import { SubPanel } from "components/Panels/SubPanel"; import { SubPanel } from "components/Panels/SubPanel";
@ -25,6 +25,7 @@ import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable";
import { prettySlug } from "helpers/formatters"; import { prettySlug } from "helpers/formatters";
import { useBoolean } from "hooks/useBoolean"; import { useBoolean } from "hooks/useBoolean";
import { TranslatedPreviewCard } from "components/Translated"; import { TranslatedPreviewCard } from "components/Translated";
import { getOpenGraph } from "helpers/openGraph";
/* /*
* *
@ -42,7 +43,7 @@ const DEFAULT_FILTERS_STATE = {
* PAGE * PAGE
*/ */
interface Props extends AppStaticProps { interface Props extends AppStaticProps, AppLayoutRequired {
pages: NonNullable<GetWikiPagesPreviewsQuery["wikiPages"]>["data"]; pages: NonNullable<GetWikiPagesPreviewsQuery["wikiPages"]>["data"];
} }
@ -74,7 +75,7 @@ const Wiki = ({ langui, pages, ...otherProps }: Props): JSX.Element => {
<TextInput <TextInput
className="mb-6 w-full" className="mb-6 w-full"
placeholder={langui.search_title ?? undefined} placeholder={langui.search_title ?? "Search..."}
value={searchName} value={searchName}
onChange={setSearchName} onChange={setSearchName}
/> />
@ -84,7 +85,7 @@ const Wiki = ({ langui, pages, ...otherProps }: Props): JSX.Element => {
input={ input={
<Select <Select
className="w-full" className="w-full"
options={[langui.category ?? ""]} options={[langui.category ?? "Category"]}
value={groupingMethod} value={groupingMethod}
onChange={setGroupingMethod} onChange={setGroupingMethod}
allowEmpty allowEmpty
@ -219,7 +220,6 @@ const Wiki = ({ langui, pages, ...otherProps }: Props): JSX.Element => {
return ( return (
<AppLayout <AppLayout
navTitle={langui.wiki}
subPanel={subPanel} subPanel={subPanel}
contentPanel={contentPanel} contentPanel={contentPanel}
subPanelIcon={Icon.Search} subPanelIcon={Icon.Search}
@ -241,9 +241,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
language_code: context.locale ?? "en", language_code: context.locale ?? "en",
}); });
if (!pages.wikiPages?.data) return { notFound: true }; if (!pages.wikiPages?.data) return { notFound: true };
const appStaticProps = await getAppStaticProps(context);
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...appStaticProps,
pages: sortPages(pages.wikiPages.data), pages: sortPages(pages.wikiPages.data),
openGraph: getOpenGraph(
appStaticProps.langui,
appStaticProps.langui.wiki ?? "Wiki"
),
}; };
return { return {
props: props, props: props,