OpenGraph support
This commit is contained in:
parent
74b77431a9
commit
7832b71f5c
|
@ -19,13 +19,13 @@ import {
|
|||
isUndefined,
|
||||
iterateMap,
|
||||
} from "helpers/others";
|
||||
import { getOgImage, ImageQuality } from "helpers/img";
|
||||
import { prettyLanguage, prettySlug } from "helpers/formatters";
|
||||
import { prettyLanguage } from "helpers/formatters";
|
||||
import { cIf, cJoin } from "helpers/className";
|
||||
import { AppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { UploadImageFragment } from "graphql/generated";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
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 TITLE_PREFIX = "Accord’s Library";
|
||||
|
||||
/*
|
||||
* ╭─────────────╮
|
||||
* ───────────────────────────────────────╯ COMPONENT ╰───────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
export interface AppLayoutRequired {
|
||||
openGraph: OpenGraph;
|
||||
}
|
||||
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
subPanel?: React.ReactNode;
|
||||
subPanelIcon?: Icon;
|
||||
contentPanel?: React.ReactNode;
|
||||
title?: string;
|
||||
navTitle: string | null | undefined;
|
||||
thumbnail?: UploadImageFragment;
|
||||
description?: string;
|
||||
contentPanelScroolbar?: boolean;
|
||||
}
|
||||
|
||||
|
@ -59,10 +58,7 @@ export const AppLayout = ({
|
|||
languages,
|
||||
subPanel,
|
||||
contentPanel,
|
||||
thumbnail,
|
||||
title,
|
||||
navTitle,
|
||||
description,
|
||||
openGraph,
|
||||
subPanelIcon = Icon.Tune,
|
||||
contentPanelScroolbar = true,
|
||||
}: Props): JSX.Element => {
|
||||
|
@ -136,33 +132,6 @@ export const AppLayout = ({
|
|||
[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(() => {
|
||||
document.getElementsByTagName("html")[0].style.fontSize = `${
|
||||
(fontSize ?? 1) * 100
|
||||
|
@ -191,25 +160,13 @@ export const AppLayout = ({
|
|||
useEffect(() => {
|
||||
if (preferredLanguages) {
|
||||
if (preferredLanguages.length === 0) {
|
||||
let defaultPreferredLanguages: string[] = [];
|
||||
if (isDefinedAndNotEmpty(router.locale) && router.locales) {
|
||||
if (router.locale === "en") {
|
||||
defaultPreferredLanguages = [router.locale];
|
||||
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(
|
||||
getDefaultPreferredLanguages(router.locale, router.locales)
|
||||
);
|
||||
}
|
||||
setPreferredLanguages(defaultPreferredLanguages);
|
||||
} else if (router.locale !== preferredLanguages[0]) {
|
||||
router.push(router.asPath, router.asPath, {
|
||||
router.replace(router.asPath, router.asPath, {
|
||||
locale: preferredLanguages[0],
|
||||
});
|
||||
}
|
||||
|
@ -251,27 +208,36 @@ export const AppLayout = ({
|
|||
)}
|
||||
>
|
||||
<Head>
|
||||
<title>{metaTitle}</title>
|
||||
<meta name="description" content={metaDescription} />
|
||||
<title>{openGraph.title}</title>
|
||||
<meta name="description" content={openGraph.description} />
|
||||
|
||||
<meta name="twitter:title" content={metaTitle}></meta>
|
||||
<meta name="twitter:description" content={metaDescription}></meta>
|
||||
<meta name="twitter:title" content={openGraph.title}></meta>
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content={openGraph.description}
|
||||
></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:description" content={metaDescription} />
|
||||
<meta property="og:image" content={metaImage.image}></meta>
|
||||
<meta property="og:image:secure_url" content={metaImage.image}></meta>
|
||||
<meta property="og:title" content={openGraph.title} />
|
||||
<meta property="og:description" content={openGraph.description} />
|
||||
<meta property="og:image" content={openGraph.thumbnail.image}></meta>
|
||||
<meta
|
||||
property="og:image:secure_url"
|
||||
content={openGraph.thumbnail.image}
|
||||
></meta>
|
||||
<meta
|
||||
property="og:image:width"
|
||||
content={metaImage.width.toString()}
|
||||
content={openGraph.thumbnail.width.toString()}
|
||||
></meta>
|
||||
<meta
|
||||
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 property="og:image:alt" content={metaImage.alt}></meta>
|
||||
<meta property="og:image:type" content="image/jpeg"></meta>
|
||||
</Head>
|
||||
|
||||
|
@ -370,13 +336,13 @@ export const AppLayout = ({
|
|||
className={cJoin(
|
||||
"overflow-hidden text-center font-headers font-black",
|
||||
cIf(
|
||||
ogTitle && ogTitle.length > 30,
|
||||
openGraph.title.length > 30,
|
||||
"max-h-14 text-xl",
|
||||
"max-h-16 text-2xl"
|
||||
)
|
||||
)}
|
||||
>
|
||||
{ogTitle}
|
||||
{openGraph.title}
|
||||
</p>
|
||||
{isDefined(subPanel) && !turnSubIntoContent && (
|
||||
<Ico
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Fragment, useCallback, useMemo } from "react";
|
||||
import { AppLayout } from "./AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "./AppLayout";
|
||||
import { Chip } from "./Chip";
|
||||
import { HorizontalLine } from "./HorizontalLine";
|
||||
import { Markdawn, TableOfContents } from "./Markdown/Markdawn";
|
||||
|
@ -13,7 +13,6 @@ import { useSmartLanguage } from "hooks/useSmartLanguage";
|
|||
import { PostWithTranslations } from "helpers/types";
|
||||
import { filterHasAttributes, getStatusDescription } from "helpers/others";
|
||||
import { prettySlug } from "helpers/formatters";
|
||||
import { getDescription } from "helpers/description";
|
||||
import { AppStaticProps } from "graphql/getAppStaticProps";
|
||||
|
||||
/*
|
||||
|
@ -21,7 +20,7 @@ import { AppStaticProps } from "graphql/getAppStaticProps";
|
|||
* ───────────────────────────────────────╯ COMPONENT ╰───────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props {
|
||||
interface Props extends AppLayoutRequired {
|
||||
post: PostWithTranslations;
|
||||
langui: AppStaticProps["langui"];
|
||||
languages: AppStaticProps["languages"];
|
||||
|
@ -52,7 +51,7 @@ export const PostPage = ({
|
|||
appendBody,
|
||||
prependBody,
|
||||
displayTitle = true,
|
||||
currencies,
|
||||
...otherProps
|
||||
}: Props): JSX.Element => {
|
||||
const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] =
|
||||
useSmartLanguage({
|
||||
|
@ -221,16 +220,9 @@ export const PostPage = ({
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={title}
|
||||
description={getDescription({
|
||||
langui: langui,
|
||||
description: selectedTranslation?.excerpt,
|
||||
categories: post.categories,
|
||||
})}
|
||||
{...otherProps}
|
||||
contentPanel={contentPanel}
|
||||
subPanel={subPanel}
|
||||
thumbnail={thumbnail ?? undefined}
|
||||
currencies={currencies}
|
||||
languages={languages}
|
||||
langui={langui}
|
||||
/>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Link from "next/link";
|
||||
import { useMemo } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import { Chip } from "./Chip";
|
||||
import { Ico, Icon } from "./Ico";
|
||||
import { Img } from "./Img";
|
||||
|
@ -41,7 +42,8 @@ interface Props {
|
|||
stackNumber?: number;
|
||||
metadata?: {
|
||||
currencies?: AppStaticProps["currencies"];
|
||||
release_date?: DatePickerFragment | null;
|
||||
releaseDate?: DatePickerFragment | null;
|
||||
releaseDateFormat?: Intl.DateTimeFormatOptions["dateStyle"];
|
||||
price?: PricePickerFragment | null;
|
||||
views?: number;
|
||||
author?: string;
|
||||
|
@ -78,19 +80,20 @@ export const PreviewCard = ({
|
|||
}: Props): JSX.Element => {
|
||||
const { currency } = useAppLayout();
|
||||
const isHoverable = useMediaHoverable();
|
||||
const router = useRouter();
|
||||
|
||||
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">
|
||||
{metadata.release_date && (
|
||||
{metadata.releaseDate && (
|
||||
<p className="text-sm mobile:text-xs">
|
||||
<Ico
|
||||
icon={Icon.Event}
|
||||
className="mr-1 translate-y-[.15em] !text-base"
|
||||
/>
|
||||
{prettyDate(metadata.release_date)}
|
||||
{prettyDate(metadata.releaseDate, router.locale)}
|
||||
</p>
|
||||
)}
|
||||
{metadata.price && metadata.currencies && (
|
||||
|
@ -124,7 +127,7 @@ export const PreviewCard = ({
|
|||
)}
|
||||
</>
|
||||
),
|
||||
[currency, metadata]
|
||||
[currency, metadata, router.locale]
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -278,7 +281,7 @@ export const PreviewCard = ({
|
|||
{bottomChips && bottomChips.length > 0 && (
|
||||
<div
|
||||
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) => (
|
||||
<Chip key={index} className="text-sm" text={text} />
|
||||
|
|
|
@ -2,9 +2,18 @@ import { GetStaticProps } from "next";
|
|||
import { AppStaticProps, getAppStaticProps } from "./getAppStaticProps";
|
||||
import { getReadySdk } from "./sdk";
|
||||
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 {
|
||||
post: PostWithTranslations;
|
||||
openGraph: OpenGraph;
|
||||
}
|
||||
|
||||
export const getPostStaticProps =
|
||||
|
@ -15,10 +24,48 @@ export const getPostStaticProps =
|
|||
slug: slug,
|
||||
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 = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
post: post.posts.data[0].attributes as PostWithTranslations,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
title,
|
||||
description,
|
||||
thumbnail
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -20,19 +20,12 @@ query getWikiPage($slug: String, $language_code: String) {
|
|||
}
|
||||
}
|
||||
}
|
||||
tags(pagination: { limit: -1 }) {
|
||||
tags {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
slug
|
||||
titles(filters: { language: { code: { eq: $language_code } } }) {
|
||||
language {
|
||||
data {
|
||||
attributes {
|
||||
code
|
||||
}
|
||||
}
|
||||
}
|
||||
title
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import { isUndefined } from "./others";
|
||||
import { DatePickerFragment } from "graphql/generated";
|
||||
|
||||
export const compareDate = (
|
||||
a: DatePickerFragment,
|
||||
b: DatePickerFragment
|
||||
a: DatePickerFragment | null | undefined,
|
||||
b: DatePickerFragment | null | undefined
|
||||
): number => {
|
||||
if (isUndefined(a) || isUndefined(b)) {
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
return dateA - dateB;
|
||||
|
|
|
@ -1,52 +1,28 @@
|
|||
import { prettySlug } from "./formatters";
|
||||
import { isDefined } from "./others";
|
||||
import { Content } from "./types";
|
||||
import { AppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { isDefined, isDefinedAndNotEmpty } from "./others";
|
||||
|
||||
interface Description {
|
||||
langui: AppStaticProps["langui"];
|
||||
description?: string | null | undefined;
|
||||
type?: Content["type"];
|
||||
categories?: Content["categories"];
|
||||
}
|
||||
export const getDescription = (
|
||||
description: string | null | undefined,
|
||||
chipsGroups?: Record<string, (string | undefined)[]>
|
||||
): string => {
|
||||
let result = "";
|
||||
|
||||
export const getDescription = ({
|
||||
langui,
|
||||
description: text,
|
||||
type,
|
||||
categories,
|
||||
}: Description): string => {
|
||||
let description = "";
|
||||
|
||||
// TEXT
|
||||
if (text) {
|
||||
description += prettyMarkdown(text);
|
||||
description += "\n\n";
|
||||
if (isDefinedAndNotEmpty(description)) {
|
||||
result += prettyMarkdown(description);
|
||||
if (isDefined(chipsGroups)) {
|
||||
result += "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// TYPE
|
||||
if (type?.data) {
|
||||
description += `${langui.type}: `;
|
||||
|
||||
description += `(${
|
||||
type.data.attributes?.titles?.[0]?.title ??
|
||||
prettySlug(type.data.attributes?.slug)
|
||||
})`;
|
||||
|
||||
description += "\n";
|
||||
for (const key in chipsGroups) {
|
||||
if (Object.hasOwn(chipsGroups, key)) {
|
||||
const chipsGroup = chipsGroups[key];
|
||||
if (chipsGroup.length > 0) {
|
||||
result += `${key}: ${prettyChip(chipsGroup)}\n`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CATEGORIES
|
||||
if (categories?.data && categories.data.length > 0) {
|
||||
description += `${langui.categories}: `;
|
||||
description += prettyChip(
|
||||
categories.data.map((category) => category.attributes?.short)
|
||||
);
|
||||
|
||||
description += "\n";
|
||||
}
|
||||
|
||||
return description;
|
||||
return result;
|
||||
};
|
||||
|
||||
const prettyMarkdown = (markdown: string): string =>
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
import { AppStaticProps } from "../graphql/getAppStaticProps";
|
||||
import { convertPrice } from "./numbers";
|
||||
import { isDefinedAndNotEmpty } from "./others";
|
||||
import { isDefinedAndNotEmpty, isUndefined } from "./others";
|
||||
import { DatePickerFragment, PricePickerFragment } from "graphql/generated";
|
||||
|
||||
export const prettyDate = (datePicker: DatePickerFragment): string => {
|
||||
let result = "";
|
||||
if (datePicker.year) result += datePicker.year.toString();
|
||||
if (datePicker.month)
|
||||
result += `/${datePicker.month.toString().padStart(2, "0")}`;
|
||||
if (datePicker.day)
|
||||
result += `/${datePicker.day.toString().padStart(2, "0")}`;
|
||||
return result;
|
||||
};
|
||||
export const prettyDate = (
|
||||
datePicker: DatePickerFragment,
|
||||
locale = "en",
|
||||
dateStyle: Intl.DateTimeFormatOptions["dateStyle"] = "medium"
|
||||
): string =>
|
||||
new Date(
|
||||
datePicker.year ?? 0,
|
||||
datePicker.month ?? 0,
|
||||
datePicker.day ?? 1
|
||||
).toLocaleString(locale, { dateStyle });
|
||||
|
||||
export const prettyPrice = (
|
||||
pricePicker: PricePickerFragment,
|
||||
|
@ -19,19 +20,23 @@ export const prettyPrice = (
|
|||
targetCurrencyCode?: string
|
||||
): string => {
|
||||
if (!targetCurrencyCode) return "";
|
||||
let result = "";
|
||||
currencies.map((currency) => {
|
||||
if (currency.attributes?.code === targetCurrencyCode) {
|
||||
const amountInTargetCurrency = convertPrice(pricePicker, currency);
|
||||
result =
|
||||
currency.attributes.symbol +
|
||||
amountInTargetCurrency.toLocaleString(undefined, {
|
||||
minimumFractionDigits: currency.attributes.display_decimals ? 2 : 0,
|
||||
maximumFractionDigits: currency.attributes.display_decimals ? 2 : 0,
|
||||
});
|
||||
}
|
||||
if (isUndefined(pricePicker.amount)) return "";
|
||||
|
||||
const targetCurrency = currencies.find(
|
||||
(currency) => currency.attributes?.code === targetCurrencyCode
|
||||
);
|
||||
|
||||
if (targetCurrency?.attributes) {
|
||||
const amountInTargetCurrency = convertPrice(pricePicker, targetCurrency);
|
||||
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 => {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import { UploadImageFragment } from "graphql/generated";
|
||||
|
||||
export enum ImageQuality {
|
||||
Small = "small",
|
||||
Medium = "medium",
|
||||
|
@ -7,7 +5,7 @@ export enum ImageQuality {
|
|||
Og = "og",
|
||||
}
|
||||
|
||||
interface OgImage {
|
||||
export interface OgImage {
|
||||
image: string;
|
||||
width: number;
|
||||
height: number;
|
||||
|
@ -65,20 +63,3 @@ export const getImgSizesByQuality = (
|
|||
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 ?? "",
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -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 = "Accord’s 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 ?? "",
|
||||
};
|
||||
};
|
|
@ -17,7 +17,7 @@ export interface PostWithTranslations extends Omit<Post, "translations"> {
|
|||
|
||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
|
||||
export type Content = NonNullable<
|
||||
type Content = NonNullable<
|
||||
NonNullable<GetContentTextQuery["contents"]>["data"][number]["attributes"]
|
||||
>;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import { LanguageSwitcher } from "components/Inputs/LanguageSwitcher";
|
|||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { AppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { filterDefined, isDefined } from "helpers/others";
|
||||
import { getPreferredLanguage } from "helpers/locales";
|
||||
|
||||
interface Props<T> {
|
||||
items: T[];
|
||||
|
@ -12,18 +13,6 @@ interface Props<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>({
|
||||
items,
|
||||
languageExtractor,
|
||||
|
|
|
@ -1,25 +1,29 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import {
|
||||
ReturnButton,
|
||||
ReturnButtonType,
|
||||
} from "components/PanelComponents/ReturnButton";
|
||||
import { ContentPanel } from "components/Panels/ContentPanel";
|
||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ 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
|
||||
navTitle="404"
|
||||
contentPanel={
|
||||
<ContentPanel>
|
||||
<h1>404 - {langui.page_not_found}</h1>
|
||||
<h1>{openGraph.title}</h1>
|
||||
<ReturnButton
|
||||
href="/"
|
||||
title="Home"
|
||||
|
@ -28,6 +32,7 @@ const FourOhFour = ({ langui, ...otherProps }: Props): JSX.Element => (
|
|||
/>
|
||||
</ContentPanel>
|
||||
}
|
||||
openGraph={openGraph}
|
||||
langui={langui}
|
||||
{...otherProps}
|
||||
/>
|
||||
|
@ -40,8 +45,13 @@ export default FourOhFour;
|
|||
*/
|
||||
|
||||
export const getStaticProps: GetStaticProps = async (context) => {
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
`404 - ${appStaticProps.langui.page_not_found}`
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,25 +1,29 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import {
|
||||
ReturnButton,
|
||||
ReturnButtonType,
|
||||
} from "components/PanelComponents/ReturnButton";
|
||||
import { ContentPanel } from "components/Panels/ContentPanel";
|
||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ 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
|
||||
navTitle="500"
|
||||
contentPanel={
|
||||
<ContentPanel>
|
||||
<h1>500 - Internal Server Error</h1>
|
||||
<h1>{openGraph.title}</h1>
|
||||
<ReturnButton
|
||||
href="/"
|
||||
title="Home"
|
||||
|
@ -28,6 +32,7 @@ const FiveHundred = ({ langui, ...otherProps }: Props): JSX.Element => (
|
|||
/>
|
||||
</ContentPanel>
|
||||
}
|
||||
openGraph={openGraph}
|
||||
langui={langui}
|
||||
{...otherProps}
|
||||
/>
|
||||
|
@ -40,8 +45,13 @@ export default FiveHundred;
|
|||
*/
|
||||
|
||||
export const getStaticProps: GetStaticProps = async (context) => {
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
"500 - Internal Server Error"
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -9,19 +9,11 @@ import {
|
|||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
const AccordsHandbook = ({
|
||||
post,
|
||||
langui,
|
||||
languages,
|
||||
currencies,
|
||||
}: PostStaticProps): JSX.Element => (
|
||||
const AccordsHandbook = (props: PostStaticProps): JSX.Element => (
|
||||
<PostPage
|
||||
currencies={currencies}
|
||||
languages={languages}
|
||||
langui={langui}
|
||||
post={post}
|
||||
{...props}
|
||||
returnHref="/about-us/"
|
||||
returnTitle={langui.about_us}
|
||||
returnTitle={props.langui.about_us}
|
||||
displayToc
|
||||
displayLanguageSwitcher
|
||||
/>
|
||||
|
|
|
@ -15,12 +15,7 @@ import { RequestMailProps, ResponseMailProps } from "pages/api/mail";
|
|||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
const AboutUs = ({
|
||||
post,
|
||||
langui,
|
||||
languages,
|
||||
currencies,
|
||||
}: PostStaticProps): JSX.Element => {
|
||||
const AboutUs = ({ langui, ...otherProps }: PostStaticProps): JSX.Element => {
|
||||
const router = useRouter();
|
||||
const [formResponse, setFormResponse] = useState("");
|
||||
const [formState, setFormState] = useState<"completed" | "ongoing" | "stale">(
|
||||
|
@ -177,10 +172,8 @@ const AboutUs = ({
|
|||
|
||||
return (
|
||||
<PostPage
|
||||
currencies={currencies}
|
||||
languages={languages}
|
||||
{...otherProps}
|
||||
langui={langui}
|
||||
post={post}
|
||||
returnHref="/about-us/"
|
||||
returnTitle={langui.about_us}
|
||||
displayToc
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { Icon } from "components/Ico";
|
||||
import { NavOption } from "components/PanelComponents/NavOption";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {}
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {}
|
||||
|
||||
const AboutUs = ({ langui, ...otherProps }: Props): JSX.Element => (
|
||||
<AppLayout
|
||||
navTitle={langui.about_us}
|
||||
subPanel={
|
||||
<SubPanel>
|
||||
<PanelHeader
|
||||
|
@ -49,8 +49,13 @@ export default AboutUs;
|
|||
*/
|
||||
|
||||
export const getStaticProps: GetStaticProps = async (context) => {
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
appStaticProps.langui.about_us ?? "About us"
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -9,19 +9,11 @@ import {
|
|||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
const Legality = ({
|
||||
post,
|
||||
langui,
|
||||
languages,
|
||||
currencies,
|
||||
}: PostStaticProps): JSX.Element => (
|
||||
const Legality = (props: PostStaticProps): JSX.Element => (
|
||||
<PostPage
|
||||
currencies={currencies}
|
||||
languages={languages}
|
||||
langui={langui}
|
||||
post={post}
|
||||
{...props}
|
||||
returnHref="/about-us/"
|
||||
returnTitle={langui.about_us}
|
||||
returnTitle={props.langui.about_us}
|
||||
displayToc
|
||||
displayLanguageSwitcher
|
||||
/>
|
||||
|
|
|
@ -9,19 +9,11 @@ import {
|
|||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
const SharingPolicy = ({
|
||||
post,
|
||||
langui,
|
||||
languages,
|
||||
currencies,
|
||||
}: PostStaticProps): JSX.Element => (
|
||||
const SharingPolicy = (props: PostStaticProps): JSX.Element => (
|
||||
<PostPage
|
||||
currencies={currencies}
|
||||
languages={languages}
|
||||
langui={langui}
|
||||
post={post}
|
||||
{...props}
|
||||
returnHref="/about-us/"
|
||||
returnTitle={langui.about_us}
|
||||
returnTitle={props.langui.about_us}
|
||||
displayToc
|
||||
displayLanguageSwitcher
|
||||
/>
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { useMemo } from "react";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { NavOption } from "components/PanelComponents/NavOption";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { Icon } from "components/Ico";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {}
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {}
|
||||
|
||||
const Archives = ({ langui, ...otherProps }: Props): JSX.Element => {
|
||||
const subPanel = useMemo(
|
||||
|
@ -28,14 +29,7 @@ const Archives = ({ langui, ...otherProps }: Props): JSX.Element => {
|
|||
),
|
||||
[langui]
|
||||
);
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={langui.archives}
|
||||
subPanel={subPanel}
|
||||
langui={langui}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
return <AppLayout subPanel={subPanel} langui={langui} {...otherProps} />;
|
||||
};
|
||||
export default Archives;
|
||||
|
||||
|
@ -45,8 +39,13 @@ export default Archives;
|
|||
*/
|
||||
|
||||
export const getStaticProps: GetStaticProps = async (context) => {
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
appStaticProps.langui.archives ?? "Archives"
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
|
||||
import { Fragment, useMemo } from "react";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { Switch } from "components/Inputs/Switch";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import {
|
||||
|
@ -22,13 +22,14 @@ import { useMediaHoverable } from "hooks/useMediaQuery";
|
|||
import { WithLabel } from "components/Inputs/WithLabel";
|
||||
import { filterHasAttributes, isDefined } from "helpers/others";
|
||||
import { useBoolean } from "hooks/useBoolean";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
channel: NonNullable<
|
||||
GetVideoChannelQuery["videoChannels"]
|
||||
>["data"][number]["attributes"];
|
||||
|
@ -91,7 +92,7 @@ const Channel = ({ langui, channel, ...otherProps }: Props): JSX.Element => {
|
|||
thumbnailAspectRatio="16/9"
|
||||
keepInfoVisible={keepInfoVisible}
|
||||
metadata={{
|
||||
release_date: video.attributes.published_date,
|
||||
releaseDate: video.attributes.published_date,
|
||||
views: video.attributes.views,
|
||||
author: channel?.title,
|
||||
position: "Top",
|
||||
|
@ -116,7 +117,6 @@ const Channel = ({ langui, channel, ...otherProps }: Props): JSX.Element => {
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={langui.archives}
|
||||
subPanel={subPanel}
|
||||
contentPanel={contentPanel}
|
||||
langui={langui}
|
||||
|
@ -140,9 +140,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
: "",
|
||||
});
|
||||
if (!channel.videoChannels?.data[0].attributes) return { notFound: true };
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
channel: channel.videoChannels.data[0].attributes,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
channel.videoChannels.data[0].attributes.title
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { useMemo, useState } from "react";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { SmartList } from "components/SmartList";
|
||||
import { Icon } from "components/Ico";
|
||||
import { Switch } from "components/Inputs/Switch";
|
||||
|
@ -20,11 +20,12 @@ import { PreviewCard } from "components/PreviewCard";
|
|||
import { GetVideosPreviewQuery } from "graphql/generated";
|
||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { prettyDate } from "helpers/formatters";
|
||||
import { filterHasAttributes } from "helpers/others";
|
||||
import { getVideoThumbnailURL } from "helpers/videos";
|
||||
import { useMediaHoverable } from "hooks/useMediaQuery";
|
||||
import { useBoolean } from "hooks/useBoolean";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
import { compareDate } from "helpers/date";
|
||||
|
||||
/*
|
||||
* ╭─────────────╮
|
||||
|
@ -40,7 +41,7 @@ const DEFAULT_FILTERS_STATE = {
|
|||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
videos: NonNullable<GetVideosPreviewQuery["videos"]>["data"];
|
||||
}
|
||||
|
||||
|
@ -73,7 +74,7 @@ const Videos = ({ langui, videos, ...otherProps }: Props): JSX.Element => {
|
|||
|
||||
<TextInput
|
||||
className="mb-6 w-full"
|
||||
placeholder={langui.search_title ?? undefined}
|
||||
placeholder={langui.search_title ?? "Search title..."}
|
||||
value={searchName}
|
||||
onChange={setSearchName}
|
||||
/>
|
||||
|
@ -107,7 +108,7 @@ const Videos = ({ langui, videos, ...otherProps }: Props): JSX.Element => {
|
|||
thumbnailForceAspectRatio
|
||||
keepInfoVisible={keepInfoVisible}
|
||||
metadata={{
|
||||
release_date: item.attributes.published_date,
|
||||
releaseDate: item.attributes.published_date,
|
||||
views: item.attributes.views,
|
||||
author: item.attributes.channel?.data?.attributes?.title,
|
||||
position: "Top",
|
||||
|
@ -132,7 +133,6 @@ const Videos = ({ langui, videos, ...otherProps }: Props): JSX.Element => {
|
|||
);
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={langui.archives}
|
||||
subPanel={subPanel}
|
||||
contentPanel={contentPanel}
|
||||
langui={langui}
|
||||
|
@ -152,19 +152,18 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
const videos = await sdk.getVideosPreview();
|
||||
if (!videos.videos) return { notFound: true };
|
||||
videos.videos.data
|
||||
.sort((a, b) => {
|
||||
const dateA = a.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);
|
||||
})
|
||||
.sort((a, b) =>
|
||||
compareDate(a.attributes?.published_date, b.attributes?.published_date)
|
||||
)
|
||||
.reverse();
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
videos: videos.videos.data,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
appStaticProps.langui.videos ?? "Videos"
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
|
||||
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 { Ico, Icon } from "components/Ico";
|
||||
import { Button } from "components/Inputs/Button";
|
||||
|
@ -23,13 +24,14 @@ import { prettyDate, prettyShortenNumber } from "helpers/formatters";
|
|||
import { filterHasAttributes, isDefined } from "helpers/others";
|
||||
import { getVideoFile } from "helpers/videos";
|
||||
import { useMediaMobile } from "hooks/useMediaQuery";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
video: NonNullable<
|
||||
NonNullable<GetVideoQuery["videos"]>["data"][number]["attributes"]
|
||||
>;
|
||||
|
@ -38,6 +40,8 @@ interface Props extends AppStaticProps {
|
|||
const Video = ({ langui, video, ...otherProps }: Props): JSX.Element => {
|
||||
const isMobile = useMediaMobile();
|
||||
const { setSubPanelOpen } = useAppLayout();
|
||||
const router = useRouter();
|
||||
|
||||
const subPanel = useMemo(
|
||||
() => (
|
||||
<SubPanel>
|
||||
|
@ -118,7 +122,7 @@ const Video = ({ langui, video, ...otherProps }: Props): JSX.Element => {
|
|||
icon={Icon.Event}
|
||||
className="mr-1 translate-y-[.15em] !text-base"
|
||||
/>
|
||||
{prettyDate(video.published_date)}
|
||||
{prettyDate(video.published_date, router.locale)}
|
||||
</p>
|
||||
<p>
|
||||
<Ico
|
||||
|
@ -184,6 +188,7 @@ const Video = ({ langui, video, ...otherProps }: Props): JSX.Element => {
|
|||
[
|
||||
isMobile,
|
||||
langui,
|
||||
router.locale,
|
||||
video.channel?.data?.attributes,
|
||||
video.description,
|
||||
video.gone,
|
||||
|
@ -198,7 +203,6 @@ const Video = ({ langui, video, ...otherProps }: Props): JSX.Element => {
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={langui.archives}
|
||||
subPanel={subPanel}
|
||||
contentPanel={contentPanel}
|
||||
langui={langui}
|
||||
|
@ -222,9 +226,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
: "",
|
||||
});
|
||||
if (!videos.videos?.data[0]?.attributes) return { notFound: true };
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
video: videos.videos.data[0].attributes,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
videos.videos.data[0].attributes.title
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -4,7 +4,7 @@ import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
|||
import { getReadySdk } from "graphql/sdk";
|
||||
import { isDefined, filterHasAttributes } from "helpers/others";
|
||||
import { ChronicleWithTranslations } from "helpers/types";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||
import { ContentPanel } from "components/Panels/ContentPanel";
|
||||
import { Markdawn } from "components/Markdown/Markdawn";
|
||||
|
@ -12,20 +12,26 @@ import { SubPanel } from "components/Panels/SubPanel";
|
|||
import { ThumbnailHeader } from "components/ThumbnailHeader";
|
||||
import { HorizontalLine } from "components/HorizontalLine";
|
||||
import { GetChroniclesChaptersQuery } from "graphql/generated";
|
||||
import { prettySlug } from "helpers/formatters";
|
||||
import { prettyInlineTitle, prettySlug } from "helpers/formatters";
|
||||
import {
|
||||
ReturnButton,
|
||||
ReturnButtonType,
|
||||
} from "components/PanelComponents/ReturnButton";
|
||||
import { TranslatedChroniclesList } from "components/Translated";
|
||||
import { Icon } from "components/Ico";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
import {
|
||||
getDefaultPreferredLanguages,
|
||||
staticSmartLanguage,
|
||||
} from "helpers/locales";
|
||||
import { getDescription } from "helpers/description";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
chronicle: ChronicleWithTranslations;
|
||||
chapters: NonNullable<
|
||||
GetChroniclesChaptersQuery["chroniclesChapters"]
|
||||
|
@ -191,7 +197,6 @@ const Chronicle = ({
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={langui.chronicles}
|
||||
contentPanel={contentPanel}
|
||||
subPanel={subPanel}
|
||||
langui={langui}
|
||||
|
@ -220,15 +225,92 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
});
|
||||
const chronicles = await sdk.getChroniclesChapters();
|
||||
if (
|
||||
!chronicle.chronicles?.data[0].attributes?.translations ||
|
||||
!chronicle.chronicles?.data[0]?.attributes?.translations ||
|
||||
!chronicles.chroniclesChapters?.data
|
||||
)
|
||||
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 = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
chronicle: chronicle.chronicles.data[0]
|
||||
.attributes as ChronicleWithTranslations,
|
||||
chapters: chronicles.chroniclesChapters.data,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
title,
|
||||
description,
|
||||
thumbnail
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { useMemo } from "react";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||
|
@ -10,13 +10,14 @@ import { GetChroniclesChaptersQuery } from "graphql/generated";
|
|||
import { filterHasAttributes } from "helpers/others";
|
||||
import { prettySlug } from "helpers/formatters";
|
||||
import { TranslatedChroniclesList } from "components/Translated";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
chapters: NonNullable<
|
||||
GetChroniclesChaptersQuery["chroniclesChapters"]
|
||||
>["data"];
|
||||
|
@ -58,14 +59,7 @@ const Chronicles = ({
|
|||
[chapters, langui]
|
||||
);
|
||||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={langui.chronicles}
|
||||
subPanel={subPanel}
|
||||
langui={langui}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
return <AppLayout subPanel={subPanel} langui={langui} {...otherProps} />;
|
||||
};
|
||||
export default Chronicles;
|
||||
|
||||
|
@ -78,9 +72,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
const sdk = getReadySdk();
|
||||
const chronicles = await sdk.getChroniclesChapters();
|
||||
if (!chronicles.chroniclesChapters?.data) return { notFound: true };
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
chapters: chronicles.chroniclesChapters.data,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
appStaticProps.langui.chronicles ?? "Chronicles"
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
|
||||
import { Fragment, useCallback, useMemo } from "react";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { Chip } from "components/Chip";
|
||||
import { HorizontalLine } from "components/HorizontalLine";
|
||||
import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
|
||||
|
@ -17,7 +17,6 @@ import { ThumbnailHeader } from "components/ThumbnailHeader";
|
|||
import { ToolTip } from "components/ToolTip";
|
||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { getDescription } from "helpers/description";
|
||||
import {
|
||||
prettyInlineTitle,
|
||||
prettyLanguage,
|
||||
|
@ -35,13 +34,19 @@ import { useMediaMobile } from "hooks/useMediaQuery";
|
|||
import { AnchorIds, useScrollTopOnChange } from "hooks/useScrollTopOnChange";
|
||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||
import { TranslatedPreviewLine } from "components/Translated";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
import {
|
||||
getDefaultPreferredLanguages,
|
||||
staticSmartLanguage,
|
||||
} from "helpers/locales";
|
||||
import { getDescription } from "helpers/description";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
content: ContentWithTranslations;
|
||||
}
|
||||
|
||||
|
@ -260,7 +265,7 @@ const Content = ({
|
|||
).map((category) => category.attributes.short)}
|
||||
metadata={{
|
||||
currencies: currencies,
|
||||
release_date: libraryItem.attributes.release_date,
|
||||
releaseDate: libraryItem.attributes.release_date,
|
||||
price: libraryItem.attributes.price,
|
||||
position: "Bottom",
|
||||
}}
|
||||
|
@ -457,22 +462,6 @@ const Content = ({
|
|||
|
||||
return (
|
||||
<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}
|
||||
subPanel={subPanel}
|
||||
currencies={currencies}
|
||||
|
@ -500,9 +489,57 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
if (!content.contents?.data[0]?.attributes?.translations) {
|
||||
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 = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
content: content.contents.data[0].attributes as ContentWithTranslations,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
title,
|
||||
description,
|
||||
thumbnail
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { useState, useMemo, useCallback } from "react";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { Select } from "components/Inputs/Select";
|
||||
import { Switch } from "components/Inputs/Switch";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
|
@ -23,6 +23,7 @@ import { SmartList } from "components/SmartList";
|
|||
import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable";
|
||||
import { useBoolean } from "hooks/useBoolean";
|
||||
import { TranslatedPreviewCard } from "components/Translated";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭─────────────╮
|
||||
|
@ -41,7 +42,7 @@ const DEFAULT_FILTERS_STATE = {
|
|||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
contents: NonNullable<GetContentsQuery["contents"]>["data"];
|
||||
}
|
||||
|
||||
|
@ -164,7 +165,7 @@ const Contents = ({
|
|||
|
||||
<TextInput
|
||||
className="mb-6 w-full"
|
||||
placeholder={langui.search_title ?? undefined}
|
||||
placeholder={langui.search_title ?? "Search..."}
|
||||
value={searchName}
|
||||
onChange={setSearchName}
|
||||
/>
|
||||
|
@ -174,7 +175,7 @@ const Contents = ({
|
|||
input={
|
||||
<Select
|
||||
className="w-full"
|
||||
options={[langui.category ?? "", langui.type ?? ""]}
|
||||
options={[langui.category ?? "Category", langui.type ?? "Type"]}
|
||||
value={groupingMethod}
|
||||
onChange={setGroupingMethod}
|
||||
allowEmpty
|
||||
|
@ -317,7 +318,6 @@ const Contents = ({
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={langui.contents}
|
||||
subPanel={subPanel}
|
||||
contentPanel={contentPanel}
|
||||
subPanelIcon={Icon.Search}
|
||||
|
@ -346,9 +346,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
return titleA.localeCompare(titleB);
|
||||
});
|
||||
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
contents: contents.contents.data,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
appStaticProps.langui.contents ?? "Contents"
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { useMemo } from "react";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { Chip } from "components/Chip";
|
||||
import { Button } from "components/Inputs/Button";
|
||||
import {
|
||||
|
@ -13,13 +13,14 @@ import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
|||
import { getReadySdk } from "graphql/sdk";
|
||||
import { filterDefined, filterHasAttributes } from "helpers/others";
|
||||
import { Report, Severity } from "helpers/types/Report";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
contents: DevGetContentsQuery;
|
||||
}
|
||||
|
||||
|
@ -87,13 +88,7 @@ const CheckupContents = ({ contents, ...otherProps }: Props): JSX.Element => {
|
|||
[testReport.lines, testReport.title]
|
||||
);
|
||||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={"Checkup"}
|
||||
contentPanel={contentPanel}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
return <AppLayout contentPanel={contentPanel} {...otherProps} />;
|
||||
};
|
||||
export default CheckupContents;
|
||||
|
||||
|
@ -105,9 +100,11 @@ export default CheckupContents;
|
|||
export const getStaticProps: GetStaticProps = async (context) => {
|
||||
const sdk = getReadySdk();
|
||||
const contents = await sdk.devGetContents();
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
contents: contents,
|
||||
openGraph: getOpenGraph(appStaticProps.langui, "Checkup Contents"),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { useMemo } from "react";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { Chip } from "components/Chip";
|
||||
import { Button } from "components/Inputs/Button";
|
||||
import {
|
||||
|
@ -15,13 +15,14 @@ import {
|
|||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { Report, Severity } from "helpers/types/Report";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
libraryItems: DevGetLibraryItemsQuery;
|
||||
}
|
||||
|
||||
|
@ -92,13 +93,7 @@ const CheckupLibraryItems = ({
|
|||
[testReport.lines, testReport.title]
|
||||
);
|
||||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={"Checkup"}
|
||||
contentPanel={contentPanel}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
return <AppLayout contentPanel={contentPanel} {...otherProps} />;
|
||||
};
|
||||
export default CheckupLibraryItems;
|
||||
|
||||
|
@ -110,9 +105,11 @@ export default CheckupLibraryItems;
|
|||
export const getStaticProps: GetStaticProps = async (context) => {
|
||||
const sdk = getReadySdk();
|
||||
const libraryItems = await sdk.devGetLibraryItems();
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
libraryItems: libraryItems,
|
||||
openGraph: getOpenGraph(appStaticProps.langui, "Checkup Library Items"),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { useCallback, useMemo, useRef, useState } from "react";
|
||||
import TurndownService from "turndown";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { Button } from "components/Inputs/Button";
|
||||
import { Markdawn, TableOfContents } from "components/Markdown/Markdawn";
|
||||
import {
|
||||
|
@ -12,13 +12,14 @@ import { Popup } from "components/Popup";
|
|||
import { ToolTip } from "components/ToolTip";
|
||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { Icon } from "components/Ico";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {}
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {}
|
||||
|
||||
const Editor = ({ langui, ...otherProps }: Props): JSX.Element => {
|
||||
const handleInput = useCallback((text: string) => {
|
||||
|
@ -465,12 +466,7 @@ const Editor = ({ langui, ...otherProps }: Props): JSX.Element => {
|
|||
);
|
||||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle="Markdawn Editor"
|
||||
contentPanel={contentPanel}
|
||||
langui={langui}
|
||||
{...otherProps}
|
||||
/>
|
||||
<AppLayout contentPanel={contentPanel} langui={langui} {...otherProps} />
|
||||
);
|
||||
};
|
||||
export default Editor;
|
||||
|
@ -481,8 +477,10 @@ export default Editor;
|
|||
*/
|
||||
|
||||
export const getStaticProps: GetStaticProps = async (context) => {
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
openGraph: getOpenGraph(appStaticProps.langui, "Markdawn Editor"),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GetStaticProps } from "next";
|
||||
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 { ButtonGroup } from "components/Inputs/ButtonGroup";
|
||||
import {
|
||||
|
@ -9,6 +9,7 @@ import {
|
|||
} from "components/Panels/ContentPanel";
|
||||
import { ToolTip } from "components/ToolTip";
|
||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭─────────────╮
|
||||
|
@ -22,7 +23,7 @@ const SIZE_MULTIPLIER = 1000;
|
|||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {}
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {}
|
||||
|
||||
const replaceSelection = (
|
||||
text: string,
|
||||
|
@ -566,7 +567,6 @@ const Transcript = (props: Props): JSX.Element => {
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle="Transcript"
|
||||
contentPanel={contentPanel}
|
||||
{...props}
|
||||
contentPanelScroolbar={false}
|
||||
|
@ -581,8 +581,13 @@ export default Transcript;
|
|||
*/
|
||||
|
||||
export const getStaticProps: GetStaticProps = async (context) => {
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
"Japanese Transcription Tool"
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -9,17 +9,9 @@ import {
|
|||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
const Home = ({
|
||||
post,
|
||||
langui,
|
||||
languages,
|
||||
currencies,
|
||||
}: PostStaticProps): JSX.Element => (
|
||||
const Home = (props: PostStaticProps): JSX.Element => (
|
||||
<PostPage
|
||||
currencies={currencies}
|
||||
languages={languages}
|
||||
langui={langui}
|
||||
post={post}
|
||||
{...props}
|
||||
prependBody={
|
||||
<div className="grid w-full place-content-center place-items-center gap-5 text-center">
|
||||
<div
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Fragment, useCallback, useMemo } from "react";
|
||||
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 { Img } from "components/Img";
|
||||
import { Button } from "components/Inputs/Button";
|
||||
|
@ -52,15 +53,16 @@ import { WithLabel } from "components/Inputs/WithLabel";
|
|||
import { Ico, Icon } from "components/Ico";
|
||||
import { cJoin, cIf } from "helpers/className";
|
||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||
import { getDescription } from "helpers/description";
|
||||
import { useBoolean } from "hooks/useBoolean";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
import { getDescription } from "helpers/description";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
item: NonNullable<
|
||||
NonNullable<
|
||||
GetLibraryItemQuery["libraryItems"]
|
||||
|
@ -81,6 +83,7 @@ const LibrarySlug = ({
|
|||
}: Props): JSX.Element => {
|
||||
const { currency } = useAppLayout();
|
||||
const hoverable = useMediaHoverable();
|
||||
const router = useRouter();
|
||||
const [openLightBox, LightBox] = useLightBox();
|
||||
const { state: keepInfoVisible, toggleState: toggleKeepInfoVisible } =
|
||||
useBoolean(false);
|
||||
|
@ -300,7 +303,7 @@ const LibrarySlug = ({
|
|||
{item.release_date && (
|
||||
<div className="grid place-content-start place-items-center">
|
||||
<h3 className="text-xl">{langui.release_date}</h3>
|
||||
<p>{prettyDate(item.release_date)}</p>
|
||||
<p>{prettyDate(item.release_date, router.locale)}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
@ -483,7 +486,7 @@ const LibrarySlug = ({
|
|||
)}
|
||||
metadata={{
|
||||
currencies: currencies,
|
||||
release_date: subitem.attributes.release_date,
|
||||
releaseDate: subitem.attributes.release_date,
|
||||
price: subitem.attributes.price,
|
||||
position: "Bottom",
|
||||
}}
|
||||
|
@ -569,8 +572,23 @@ const LibrarySlug = ({
|
|||
[
|
||||
LightBox,
|
||||
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,
|
||||
router.locale,
|
||||
currencies,
|
||||
currency,
|
||||
isVariantSet,
|
||||
|
@ -585,14 +603,8 @@ const LibrarySlug = ({
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={prettyInlineTitle("", item.title, item.subtitle)}
|
||||
contentPanel={contentPanel}
|
||||
subPanel={subPanel}
|
||||
thumbnail={item.thumbnail?.data?.attributes ?? undefined}
|
||||
description={getDescription({
|
||||
langui,
|
||||
description: item.descriptions?.[0]?.description,
|
||||
})}
|
||||
currencies={currencies}
|
||||
languages={languages}
|
||||
langui={langui}
|
||||
|
@ -618,10 +630,42 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
});
|
||||
if (!item.libraryItems?.data[0]?.attributes) return { notFound: true };
|
||||
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 = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
item: item.libraryItems.data[0].attributes,
|
||||
itemId: item.libraryItems.data[0].id,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
title,
|
||||
description,
|
||||
thumbnail?.data?.attributes
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
|
||||
import { Fragment, useMemo } from "react";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { ScanSetCover } from "components/Library/ScanSetCover";
|
||||
import {
|
||||
ReturnButton,
|
||||
|
@ -30,13 +30,14 @@ import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
|
|||
import { PreviewCard } from "components/PreviewCard";
|
||||
import { HorizontalLine } from "components/HorizontalLine";
|
||||
import { TranslatedNavOption, TranslatedScanSet } from "components/Translated";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
item: NonNullable<
|
||||
NonNullable<
|
||||
GetLibraryItemScansQuery["libraryItems"]
|
||||
|
@ -87,7 +88,7 @@ const LibrarySlug = ({
|
|||
] as const).map((category) => category.attributes.short)}
|
||||
metadata={{
|
||||
currencies: currencies,
|
||||
release_date: item.release_date,
|
||||
releaseDate: item.release_date,
|
||||
price: item.price,
|
||||
position: "Bottom",
|
||||
}}
|
||||
|
@ -232,10 +233,8 @@ const LibrarySlug = ({
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={prettyInlineTitle("", item.title, item.subtitle)}
|
||||
contentPanel={contentPanel}
|
||||
subPanel={subPanel}
|
||||
thumbnail={item.thumbnail?.data?.attributes ?? undefined}
|
||||
languages={languages}
|
||||
langui={langui}
|
||||
currencies={currencies}
|
||||
|
@ -262,10 +261,17 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
if (!item.libraryItems?.data[0]?.attributes || !item.libraryItems.data[0]?.id)
|
||||
return { notFound: true };
|
||||
sortRangedContent(item.libraryItems.data[0].attributes.contents);
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
item: item.libraryItems.data[0].attributes,
|
||||
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 {
|
||||
props: props,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { useState, useMemo, useCallback } from "react";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { Select } from "components/Inputs/Select";
|
||||
import { Switch } from "components/Inputs/Switch";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
|
@ -12,11 +12,7 @@ import { SubPanel } from "components/Panels/SubPanel";
|
|||
import { GetLibraryItemsPreviewQuery } from "graphql/generated";
|
||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import {
|
||||
prettyDate,
|
||||
prettyInlineTitle,
|
||||
prettyItemSubType,
|
||||
} from "helpers/formatters";
|
||||
import { prettyInlineTitle, prettyItemSubType } from "helpers/formatters";
|
||||
import { LibraryItemUserStatus } from "helpers/types";
|
||||
import { Icon } from "components/Ico";
|
||||
import { WithLabel } from "components/Inputs/WithLabel";
|
||||
|
@ -33,6 +29,8 @@ import { convertPrice } from "helpers/numbers";
|
|||
import { SmartList } from "components/SmartList";
|
||||
import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable";
|
||||
import { useBoolean } from "hooks/useBoolean";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
import { compareDate } from "helpers/date";
|
||||
|
||||
/*
|
||||
* ╭─────────────╮
|
||||
|
@ -55,7 +53,7 @@ const DEFAULT_FILTERS_STATE = {
|
|||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
items: NonNullable<GetLibraryItemsPreviewQuery["libraryItems"]>["data"];
|
||||
}
|
||||
|
||||
|
@ -174,13 +172,10 @@ const Library = ({
|
|||
return priceA - priceB;
|
||||
}
|
||||
case 2: {
|
||||
const dateA = a.attributes.release_date
|
||||
? prettyDate(a.attributes.release_date)
|
||||
: "9999";
|
||||
const dateB = b.attributes.release_date
|
||||
? prettyDate(b.attributes.release_date)
|
||||
: "9999";
|
||||
return dateA.localeCompare(dateB);
|
||||
return compareDate(
|
||||
a.attributes.release_date,
|
||||
b.attributes.release_date
|
||||
);
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
|
@ -268,7 +263,7 @@ const Library = ({
|
|||
|
||||
<TextInput
|
||||
className="mb-6 w-full"
|
||||
placeholder={langui.search_title ?? undefined}
|
||||
placeholder={langui.search_title ?? "Search..."}
|
||||
value={searchName}
|
||||
onChange={setSearchName}
|
||||
/>
|
||||
|
@ -433,7 +428,7 @@ const Library = ({
|
|||
)}
|
||||
metadata={{
|
||||
currencies: currencies,
|
||||
release_date: item.attributes.release_date,
|
||||
releaseDate: item.attributes.release_date,
|
||||
price: item.attributes.price,
|
||||
position: "Bottom",
|
||||
}}
|
||||
|
@ -474,7 +469,6 @@ const Library = ({
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={langui.library}
|
||||
subPanel={subPanel}
|
||||
contentPanel={contentPanel}
|
||||
subPanelIcon={Icon.Search}
|
||||
|
@ -497,9 +491,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
language_code: context.locale ?? "en",
|
||||
});
|
||||
if (!items.libraryItems?.data) return { notFound: true };
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
items: items.libraryItems.data,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
appStaticProps.langui.library ?? "Library"
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { Icon } from "components/Ico";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {}
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {}
|
||||
const Merch = ({ langui, ...otherProps }: Props): JSX.Element => (
|
||||
<AppLayout
|
||||
navTitle={langui.merch}
|
||||
subPanel={
|
||||
<SubPanel>
|
||||
<PanelHeader
|
||||
|
@ -35,8 +35,13 @@ export default Merch;
|
|||
*/
|
||||
|
||||
export const getStaticProps: GetStaticProps = async (context) => {
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
appStaticProps.langui.merch ?? "Merch"
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { useMemo, useState } from "react";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { Switch } from "components/Inputs/Switch";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import {
|
||||
|
@ -11,7 +11,7 @@ import { SubPanel } from "components/Panels/SubPanel";
|
|||
import { GetPostsPreviewQuery } from "graphql/generated";
|
||||
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { prettyDate, prettySlug } from "helpers/formatters";
|
||||
import { prettySlug } from "helpers/formatters";
|
||||
import { Icon } from "components/Ico";
|
||||
import { WithLabel } from "components/Inputs/WithLabel";
|
||||
import { TextInput } from "components/Inputs/TextInput";
|
||||
|
@ -21,6 +21,8 @@ import { filterHasAttributes } from "helpers/others";
|
|||
import { SmartList } from "components/SmartList";
|
||||
import { useBoolean } from "hooks/useBoolean";
|
||||
import { TranslatedPreviewCard } from "components/Translated";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
import { compareDate } from "helpers/date";
|
||||
|
||||
/*
|
||||
* ╭─────────────╮
|
||||
|
@ -37,7 +39,7 @@ const DEFAULT_FILTERS_STATE = {
|
|||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
posts: NonNullable<GetPostsPreviewQuery["posts"]>["data"];
|
||||
}
|
||||
|
||||
|
@ -63,7 +65,7 @@ const News = ({ langui, posts, ...otherProps }: Props): JSX.Element => {
|
|||
|
||||
<TextInput
|
||||
className="mb-6 w-full"
|
||||
placeholder={langui.search_title ?? undefined}
|
||||
placeholder={langui.search_title ?? "Search..."}
|
||||
value={searchName}
|
||||
onChange={setSearchName}
|
||||
/>
|
||||
|
@ -124,7 +126,8 @@ const News = ({ langui, posts, ...otherProps }: Props): JSX.Element => {
|
|||
)}
|
||||
keepInfoVisible={keepInfoVisible}
|
||||
metadata={{
|
||||
release_date: post.attributes.date,
|
||||
releaseDate: post.attributes.date,
|
||||
releaseDateFormat: "long",
|
||||
position: "Top",
|
||||
}}
|
||||
/>
|
||||
|
@ -144,7 +147,6 @@ const News = ({ langui, posts, ...otherProps }: Props): JSX.Element => {
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={langui.news}
|
||||
subPanel={subPanel}
|
||||
contentPanel={contentPanel}
|
||||
subPanelIcon={Icon.Search}
|
||||
|
@ -164,9 +166,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
const sdk = getReadySdk();
|
||||
const posts = await sdk.getPostsPreview();
|
||||
if (!posts.posts) return { notFound: true };
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
posts: sortPosts(posts.posts.data),
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
appStaticProps.langui.news ?? "News"
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
@ -180,9 +187,5 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
|
||||
const sortPosts = (posts: Props["posts"]): Props["posts"] =>
|
||||
posts
|
||||
.sort((a, b) => {
|
||||
const dateA = a.attributes?.date ? prettyDate(a.attributes.date) : "9999";
|
||||
const dateB = b.attributes?.date ? prettyDate(b.attributes.date) : "9999";
|
||||
return dateA.localeCompare(dateB);
|
||||
})
|
||||
.sort((a, b) => compareDate(a.attributes?.date, b.attributes?.date))
|
||||
.reverse();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useCallback, useMemo } from "react";
|
||||
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { Chip } from "components/Chip";
|
||||
import { HorizontalLine } from "components/HorizontalLine";
|
||||
import { Img } from "components/Img";
|
||||
|
@ -26,13 +26,19 @@ import { useSmartLanguage } from "hooks/useSmartLanguage";
|
|||
import { prettySlug } from "helpers/formatters";
|
||||
import { useLightBox } from "hooks/useLightBox";
|
||||
import { getAssetURL, ImageQuality } from "helpers/img";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
import {
|
||||
getDefaultPreferredLanguages,
|
||||
staticSmartLanguage,
|
||||
} from "helpers/locales";
|
||||
import { getDescription } from "helpers/description";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
page: WikiPageWithTranslations;
|
||||
}
|
||||
|
||||
|
@ -217,7 +223,6 @@ const WikiPage = ({
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={langui.news}
|
||||
subPanel={subPanel}
|
||||
contentPanel={contentPanel}
|
||||
languages={languages}
|
||||
|
@ -245,9 +250,58 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
});
|
||||
if (!page.wikiPages?.data[0].attributes?.translations)
|
||||
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 = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
page: page.wikiPages.data[0].attributes as WikiPageWithTranslations,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
title,
|
||||
description,
|
||||
thumbnail
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { Fragment, useMemo } from "react";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { InsetBox } from "components/InsetBox";
|
||||
import { NavOption } from "components/PanelComponents/NavOption";
|
||||
import {
|
||||
|
@ -15,13 +15,14 @@ import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
|||
import { getReadySdk } from "graphql/sdk";
|
||||
import { prettySlug } from "helpers/formatters";
|
||||
import { filterHasAttributes, isDefined } from "helpers/others";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
chronologyItems: NonNullable<
|
||||
GetChronologyItemsQuery["chronologyItems"]
|
||||
>["data"];
|
||||
|
@ -145,7 +146,6 @@ const Chronology = ({
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={langui.chronology}
|
||||
contentPanel={contentPanel}
|
||||
subPanel={subPanel}
|
||||
langui={langui}
|
||||
|
@ -166,10 +166,15 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
const chronologyEras = await sdk.getEras();
|
||||
if (!chronologyItems.chronologyItems || !chronologyEras.chronologyEras)
|
||||
return { notFound: true };
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
chronologyItems: chronologyItems.chronologyItems.data,
|
||||
chronologyEras: chronologyEras.chronologyEras.data,
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
appStaticProps.langui.chronology ?? "Chronology"
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GetStaticProps } from "next";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||
import { NavOption } from "components/PanelComponents/NavOption";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import { SubPanel } from "components/Panels/SubPanel";
|
||||
|
@ -25,6 +25,7 @@ import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable";
|
|||
import { prettySlug } from "helpers/formatters";
|
||||
import { useBoolean } from "hooks/useBoolean";
|
||||
import { TranslatedPreviewCard } from "components/Translated";
|
||||
import { getOpenGraph } from "helpers/openGraph";
|
||||
|
||||
/*
|
||||
* ╭─────────────╮
|
||||
|
@ -42,7 +43,7 @@ const DEFAULT_FILTERS_STATE = {
|
|||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
interface Props extends AppStaticProps, AppLayoutRequired {
|
||||
pages: NonNullable<GetWikiPagesPreviewsQuery["wikiPages"]>["data"];
|
||||
}
|
||||
|
||||
|
@ -74,7 +75,7 @@ const Wiki = ({ langui, pages, ...otherProps }: Props): JSX.Element => {
|
|||
|
||||
<TextInput
|
||||
className="mb-6 w-full"
|
||||
placeholder={langui.search_title ?? undefined}
|
||||
placeholder={langui.search_title ?? "Search..."}
|
||||
value={searchName}
|
||||
onChange={setSearchName}
|
||||
/>
|
||||
|
@ -84,7 +85,7 @@ const Wiki = ({ langui, pages, ...otherProps }: Props): JSX.Element => {
|
|||
input={
|
||||
<Select
|
||||
className="w-full"
|
||||
options={[langui.category ?? ""]}
|
||||
options={[langui.category ?? "Category"]}
|
||||
value={groupingMethod}
|
||||
onChange={setGroupingMethod}
|
||||
allowEmpty
|
||||
|
@ -219,7 +220,6 @@ const Wiki = ({ langui, pages, ...otherProps }: Props): JSX.Element => {
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={langui.wiki}
|
||||
subPanel={subPanel}
|
||||
contentPanel={contentPanel}
|
||||
subPanelIcon={Icon.Search}
|
||||
|
@ -241,9 +241,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
language_code: context.locale ?? "en",
|
||||
});
|
||||
if (!pages.wikiPages?.data) return { notFound: true };
|
||||
const appStaticProps = await getAppStaticProps(context);
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
...appStaticProps,
|
||||
pages: sortPages(pages.wikiPages.data),
|
||||
openGraph: getOpenGraph(
|
||||
appStaticProps.langui,
|
||||
appStaticProps.langui.wiki ?? "Wiki"
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
Loading…
Reference in New Issue