Simplified some DTO
This commit is contained in:
parent
7efa43a630
commit
da916f898a
|
@ -22,7 +22,6 @@ import { useTypedRouter } from "hooks/useTypedRouter";
|
||||||
import { Select } from "components/Inputs/Select";
|
import { Select } from "components/Inputs/Select";
|
||||||
import { sendAnalytics } from "helpers/analytics";
|
import { sendAnalytics } from "helpers/analytics";
|
||||||
import { Button } from "components/Inputs/Button";
|
import { Button } from "components/Inputs/Button";
|
||||||
import { GetVideoChannelQuery } from "graphql/generated";
|
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
import { Paginator } from "components/Containers/Paginator";
|
import { Paginator } from "components/Containers/Paginator";
|
||||||
import { useFormat } from "hooks/useFormat";
|
import { useFormat } from "hooks/useFormat";
|
||||||
|
@ -56,9 +55,11 @@ const queryParamSchema = z.object({
|
||||||
*/
|
*/
|
||||||
|
|
||||||
interface Props extends AppLayoutRequired {
|
interface Props extends AppLayoutRequired {
|
||||||
channel: NonNullable<
|
channel: {
|
||||||
NonNullable<GetVideoChannelQuery["videoChannels"]>["data"][number]["attributes"]
|
uid: string;
|
||||||
>;
|
title: string;
|
||||||
|
subscribers: number;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Channel = ({ channel, ...otherProps }: Props): JSX.Element => {
|
const Channel = ({ channel, ...otherProps }: Props): JSX.Element => {
|
||||||
|
@ -282,14 +283,23 @@ export default Channel;
|
||||||
export const getStaticProps: GetStaticProps = async (context) => {
|
export const getStaticProps: GetStaticProps = async (context) => {
|
||||||
const sdk = getReadySdk();
|
const sdk = getReadySdk();
|
||||||
const { format } = getFormat(context.locale);
|
const { format } = getFormat(context.locale);
|
||||||
const channel = await sdk.getVideoChannel({
|
const videoChannel = (
|
||||||
channel: context.params && isDefined(context.params.uid) ? context.params.uid.toString() : "",
|
await sdk.getVideoChannel({
|
||||||
});
|
channel: context.params && isDefined(context.params.uid) ? context.params.uid.toString() : "",
|
||||||
if (!channel.videoChannels?.data[0]?.attributes) return { notFound: true };
|
})
|
||||||
|
).videoChannels?.data[0]?.attributes;
|
||||||
|
|
||||||
|
if (!videoChannel) return { notFound: true };
|
||||||
|
|
||||||
|
const channel: Props["channel"] = {
|
||||||
|
uid: videoChannel.uid,
|
||||||
|
subscribers: videoChannel.subscribers,
|
||||||
|
title: videoChannel.title,
|
||||||
|
};
|
||||||
|
|
||||||
const props: Props = {
|
const props: Props = {
|
||||||
channel: channel.videoChannels.data[0].attributes,
|
channel,
|
||||||
openGraph: getOpenGraph(format, channel.videoChannels.data[0].attributes.title),
|
openGraph: getOpenGraph(format, channel.title),
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
props: props,
|
props: props,
|
||||||
|
|
|
@ -9,10 +9,10 @@ import { NavOption } from "components/PanelComponents/NavOption";
|
||||||
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
import { ReturnButton } from "components/PanelComponents/ReturnButton";
|
||||||
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
|
||||||
import { SubPanel } from "components/Containers/SubPanel";
|
import { SubPanel } from "components/Containers/SubPanel";
|
||||||
import { GetVideoQuery } from "graphql/generated";
|
import { Enum_Video_Source } from "graphql/generated";
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
import { prettyShortenNumber } from "helpers/formatters";
|
import { prettyShortenNumber } from "helpers/formatters";
|
||||||
import { filterHasAttributes, isDefined } from "helpers/asserts";
|
import { filterHasAttributes, isDefined, isUndefined } from "helpers/asserts";
|
||||||
import { getVideoFile, getVideoThumbnailURL } from "helpers/videos";
|
import { getVideoFile, getVideoThumbnailURL } from "helpers/videos";
|
||||||
import { getOpenGraph } from "helpers/openGraph";
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
import { atoms } from "contexts/atoms";
|
import { atoms } from "contexts/atoms";
|
||||||
|
@ -29,15 +29,29 @@ import { Markdown } from "components/Markdown/Markdown";
|
||||||
*/
|
*/
|
||||||
|
|
||||||
interface Props extends AppLayoutRequired {
|
interface Props extends AppLayoutRequired {
|
||||||
video: NonNullable<NonNullable<GetVideoQuery["videos"]>["data"][number]["attributes"]>;
|
video: {
|
||||||
|
isGone: boolean;
|
||||||
|
uid: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
publishedDate: string;
|
||||||
|
views: number;
|
||||||
|
likes: number;
|
||||||
|
source?: Enum_Video_Source;
|
||||||
|
};
|
||||||
|
channel?: {
|
||||||
|
title: string;
|
||||||
|
href: string;
|
||||||
|
subscribers: number;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Video = ({ video, ...otherProps }: Props): JSX.Element => {
|
const Video = ({ video, channel, ...otherProps }: Props): JSX.Element => {
|
||||||
const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl);
|
const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl);
|
||||||
const is1ColumnLayout = useAtomGetter(atoms.containerQueries.is1ColumnLayout);
|
const is1ColumnLayout = useAtomGetter(atoms.containerQueries.is1ColumnLayout);
|
||||||
const setSubPanelOpened = useAtomSetter(atoms.layout.subPanelOpened);
|
const setSubPanelOpened = useAtomSetter(atoms.layout.subPanelOpened);
|
||||||
const closeSubPanel = useCallback(() => setSubPanelOpened(false), [setSubPanelOpened]);
|
const closeSubPanel = useCallback(() => setSubPanelOpened(false), [setSubPanelOpened]);
|
||||||
const { format, formatDate } = useFormat();
|
const { format } = useFormat();
|
||||||
|
|
||||||
const subPanel = (
|
const subPanel = (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
|
@ -62,7 +76,7 @@ const Video = ({ video, ...otherProps }: Props): JSX.Element => {
|
||||||
|
|
||||||
<div className="grid place-items-center gap-12">
|
<div className="grid place-items-center gap-12">
|
||||||
<div id="video" className="w-full overflow-hidden rounded-xl shadow-xl shadow-shade/80">
|
<div id="video" className="w-full overflow-hidden rounded-xl shadow-xl shadow-shade/80">
|
||||||
{video.gone ? (
|
{video.isGone ? (
|
||||||
<VideoPlayer className="w-full" src={getVideoFile(video.uid)} rounded={false} />
|
<VideoPlayer className="w-full" src={getVideoFile(video.uid)} rounded={false} />
|
||||||
) : (
|
) : (
|
||||||
<iframe
|
<iframe
|
||||||
|
@ -80,7 +94,7 @@ const Video = ({ video, ...otherProps }: Props): JSX.Element => {
|
||||||
<div className="flex w-full flex-row flex-wrap place-items-center gap-x-6">
|
<div className="flex w-full flex-row flex-wrap place-items-center gap-x-6">
|
||||||
<p>
|
<p>
|
||||||
<Ico icon="event" className="mr-1 translate-y-[.15em] !text-base" />
|
<Ico icon="event" className="mr-1 translate-y-[.15em] !text-base" />
|
||||||
{formatDate(video.published_date)}
|
{video.publishedDate}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<Ico icon="visibility" className="mr-1 translate-y-[.15em] !text-base" />
|
<Ico icon="visibility" className="mr-1 translate-y-[.15em] !text-base" />
|
||||||
|
@ -88,7 +102,7 @@ const Video = ({ video, ...otherProps }: Props): JSX.Element => {
|
||||||
? video.views.toLocaleString()
|
? video.views.toLocaleString()
|
||||||
: prettyShortenNumber(video.views)}
|
: prettyShortenNumber(video.views)}
|
||||||
</p>
|
</p>
|
||||||
{video.channel?.data?.attributes && (
|
{video.likes > 0 && (
|
||||||
<p>
|
<p>
|
||||||
<Ico icon="thumb_up" className="mr-1 translate-y-[.15em] !text-base" />
|
<Ico icon="thumb_up" className="mr-1 translate-y-[.15em] !text-base" />
|
||||||
{isContentPanelAtLeast4xl
|
{isContentPanelAtLeast4xl
|
||||||
|
@ -108,18 +122,14 @@ const Video = ({ video, ...otherProps }: Props): JSX.Element => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{video.channel?.data?.attributes && (
|
{channel && (
|
||||||
<InsetBox id="channel" className="grid place-items-center">
|
<InsetBox id="channel" className="grid place-items-center">
|
||||||
<div className="grid w-[clamp(0px,100%,42rem)] place-items-center gap-4 text-center">
|
<div className="grid w-[clamp(0px,100%,42rem)] place-items-center gap-4 text-center">
|
||||||
<h2 className="text-2xl">{format("channel")}</h2>
|
<h2 className="text-2xl">{format("channel")}</h2>
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button href={channel.href} text={channel.title} />
|
||||||
href={`/archives/videos/c/${video.channel.data.attributes.uid}\
|
|
||||||
?page=1&query=&sort=1&gone=`}
|
|
||||||
text={video.channel.data.attributes.title}
|
|
||||||
/>
|
|
||||||
<p>
|
<p>
|
||||||
{`${video.channel.data.attributes.subscribers.toLocaleString()}
|
{`${channel.subscribers.toLocaleString()}
|
||||||
${format("subscribers").toLowerCase()}`}
|
${format("subscribers").toLowerCase()}`}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -148,29 +158,48 @@ export default Video;
|
||||||
|
|
||||||
export const getStaticProps: GetStaticProps = async (context) => {
|
export const getStaticProps: GetStaticProps = async (context) => {
|
||||||
const sdk = getReadySdk();
|
const sdk = getReadySdk();
|
||||||
const { format } = getFormat(context.locale);
|
const { format, formatDate } = getFormat(context.locale);
|
||||||
const videos = await sdk.getVideo({
|
const videos = await sdk.getVideo({
|
||||||
uid: context.params && isDefined(context.params.uid) ? context.params.uid.toString() : "",
|
uid: context.params && isDefined(context.params.uid) ? context.params.uid.toString() : "",
|
||||||
});
|
});
|
||||||
if (!videos.videos?.data[0]?.attributes) return { notFound: true };
|
const rawVideo = videos.videos?.data[0]?.attributes;
|
||||||
|
if (isUndefined(rawVideo)) return { notFound: true };
|
||||||
|
|
||||||
|
const channel: Props["channel"] = rawVideo.channel?.data?.attributes
|
||||||
|
? {
|
||||||
|
href: `/archives/videos/c/${rawVideo.channel.data.attributes.uid}`,
|
||||||
|
subscribers: rawVideo.channel.data.attributes.subscribers,
|
||||||
|
title: rawVideo.channel.data.attributes.title,
|
||||||
|
}
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const video: Props["video"] = {
|
||||||
|
uid: rawVideo.uid,
|
||||||
|
isGone: rawVideo.gone,
|
||||||
|
description: rawVideo.description,
|
||||||
|
likes: rawVideo.likes,
|
||||||
|
source: rawVideo.source ?? undefined,
|
||||||
|
publishedDate: formatDate(rawVideo.published_date),
|
||||||
|
title: rawVideo.title,
|
||||||
|
views: rawVideo.views,
|
||||||
|
};
|
||||||
|
|
||||||
const props: Props = {
|
const props: Props = {
|
||||||
video: videos.videos.data[0].attributes,
|
video,
|
||||||
|
channel,
|
||||||
openGraph: getOpenGraph(
|
openGraph: getOpenGraph(
|
||||||
format,
|
format,
|
||||||
videos.videos.data[0].attributes.title,
|
rawVideo.title,
|
||||||
getDescription(videos.videos.data[0].attributes.description, {
|
getDescription(rawVideo.description, {
|
||||||
[format("channel")]: [videos.videos.data[0].attributes.channel?.data?.attributes?.title],
|
[format("channel")]: [rawVideo.channel?.data?.attributes?.title],
|
||||||
}),
|
}),
|
||||||
getVideoThumbnailURL(videos.videos.data[0].attributes.uid),
|
getVideoThumbnailURL(rawVideo.uid),
|
||||||
undefined,
|
undefined,
|
||||||
videos.videos.data[0].attributes.gone
|
rawVideo.gone ? getVideoFile(rawVideo.uid) : undefined
|
||||||
? getVideoFile(videos.videos.data[0].attributes.uid)
|
|
||||||
: undefined
|
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
props: props,
|
props: JSON.parse(JSON.stringify(props)),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/Cont
|
||||||
import { getOpenGraph } from "helpers/openGraph";
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
import { getReadySdk } from "graphql/sdk";
|
import { getReadySdk } from "graphql/sdk";
|
||||||
import { filterHasAttributes } from "helpers/asserts";
|
import { filterHasAttributes } from "helpers/asserts";
|
||||||
import { GetContentsFolderQuery, ParentFolderPreviewFragment } from "graphql/generated";
|
import { ParentFolderPreviewFragment, UploadImageFragment } from "graphql/generated";
|
||||||
import { getDefaultPreferredLanguages, staticSmartLanguage } from "helpers/locales";
|
import { getDefaultPreferredLanguages, staticSmartLanguage } from "helpers/locales";
|
||||||
import { prettySlug } from "helpers/formatters";
|
import { prettySlug } from "helpers/formatters";
|
||||||
import { Button } from "components/Inputs/Button";
|
import { Button } from "components/Inputs/Button";
|
||||||
|
@ -27,14 +27,32 @@ import { FolderPath } from "components/Contents/FolderPath";
|
||||||
*/
|
*/
|
||||||
|
|
||||||
interface Props extends AppLayoutRequired {
|
interface Props extends AppLayoutRequired {
|
||||||
folder: NonNullable<
|
subfolders: {
|
||||||
NonNullable<GetContentsFolderQuery["contentsFolders"]>["data"][number]["attributes"]
|
slug: string;
|
||||||
>;
|
href: string;
|
||||||
|
translations: { language: string; title: string }[];
|
||||||
|
fallback: { title: string };
|
||||||
|
}[];
|
||||||
|
contents: {
|
||||||
|
slug: string;
|
||||||
|
href: string;
|
||||||
|
translations: { language: string; pre_title?: string; title: string; subtitle?: string }[];
|
||||||
|
fallback: { title: string };
|
||||||
|
thumbnail?: UploadImageFragment;
|
||||||
|
topChips?: string[];
|
||||||
|
bottomChips?: string[];
|
||||||
|
}[];
|
||||||
path: ParentFolderPreviewFragment[];
|
path: ParentFolderPreviewFragment[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const ContentsFolder = ({ openGraph, folder, path, ...otherProps }: Props): JSX.Element => {
|
const ContentsFolder = ({
|
||||||
const { format, formatCategory, formatContentType } = useFormat();
|
openGraph,
|
||||||
|
path,
|
||||||
|
contents,
|
||||||
|
subfolders,
|
||||||
|
...otherProps
|
||||||
|
}: Props): JSX.Element => {
|
||||||
|
const { format } = useFormat();
|
||||||
const setSubPanelOpened = useAtomSetter(atoms.layout.subPanelOpened);
|
const setSubPanelOpened = useAtomSetter(atoms.layout.subPanelOpened);
|
||||||
const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl);
|
const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl);
|
||||||
|
|
||||||
|
@ -61,11 +79,11 @@ const ContentsFolder = ({ openGraph, folder, path, ...otherProps }: Props): JSX.
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||||
<FolderPath path={path} />
|
<FolderPath path={path} />
|
||||||
|
|
||||||
{folder.subfolders?.data && folder.subfolders.data.length > 0 && (
|
{subfolders.length > 0 && (
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<div className="mb-2 flex place-items-center gap-2">
|
<div className="mb-2 flex place-items-center gap-2">
|
||||||
<h2 className="text-2xl">{format("folders")}</h2>
|
<h2 className="text-2xl">{format("folders")}</h2>
|
||||||
<Chip text={format("x_results", { x: folder.subfolders.data.length })} />
|
<Chip text={format("x_results", { x: subfolders.length })} />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={cJoin(
|
className={cJoin(
|
||||||
|
@ -76,28 +94,18 @@ const ContentsFolder = ({ openGraph, folder, path, ...otherProps }: Props): JSX.
|
||||||
"grid-cols-2 gap-4"
|
"grid-cols-2 gap-4"
|
||||||
)
|
)
|
||||||
)}>
|
)}>
|
||||||
{filterHasAttributes(folder.subfolders.data, ["id", "attributes"]).map((subfolder) => (
|
{subfolders.map((subfolder) => (
|
||||||
<TranslatedPreviewFolder
|
<TranslatedPreviewFolder key={subfolder.slug} {...subfolder} />
|
||||||
key={subfolder.id}
|
|
||||||
href={`/contents/folder/${subfolder.attributes.slug}`}
|
|
||||||
translations={filterHasAttributes(subfolder.attributes.titles, [
|
|
||||||
"language.data.attributes.code",
|
|
||||||
]).map((title) => ({
|
|
||||||
title: title.title,
|
|
||||||
language: title.language.data.attributes.code,
|
|
||||||
}))}
|
|
||||||
fallback={{ title: prettySlug(subfolder.attributes.slug) }}
|
|
||||||
/>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{folder.contents?.data && folder.contents.data.length > 0 && (
|
{contents.length > 0 && (
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<div className="mb-2 flex place-items-center gap-2">
|
<div className="mb-2 flex place-items-center gap-2">
|
||||||
<h2 className="text-2xl">{format("contents")}</h2>
|
<h2 className="text-2xl">{format("contents")}</h2>
|
||||||
<Chip text={format("x_results", { x: folder.contents.data.length })} />
|
<Chip text={format("x_results", { x: contents.length })} />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={cJoin(
|
className={cJoin(
|
||||||
|
@ -108,30 +116,12 @@ const ContentsFolder = ({ openGraph, folder, path, ...otherProps }: Props): JSX.
|
||||||
"grid-cols-2 gap-4"
|
"grid-cols-2 gap-4"
|
||||||
)
|
)
|
||||||
)}>
|
)}>
|
||||||
{filterHasAttributes(folder.contents.data, ["id", "attributes"]).map((item) => (
|
{contents.map((item) => (
|
||||||
<TranslatedPreviewCard
|
<TranslatedPreviewCard
|
||||||
key={item.id}
|
key={item.slug}
|
||||||
href={`/contents/${item.attributes.slug}`}
|
{...item}
|
||||||
translations={filterHasAttributes(item.attributes.translations, [
|
|
||||||
"language.data.attributes.code",
|
|
||||||
]).map((translation) => ({
|
|
||||||
pre_title: translation.pre_title,
|
|
||||||
title: translation.title,
|
|
||||||
subtitle: translation.subtitle,
|
|
||||||
language: translation.language.data.attributes.code,
|
|
||||||
}))}
|
|
||||||
fallback={{ title: prettySlug(item.attributes.slug) }}
|
|
||||||
thumbnail={item.attributes.thumbnail?.data?.attributes}
|
|
||||||
thumbnailAspectRatio="3/2"
|
thumbnailAspectRatio="3/2"
|
||||||
thumbnailForceAspectRatio
|
thumbnailForceAspectRatio
|
||||||
topChips={
|
|
||||||
item.attributes.type?.data?.attributes
|
|
||||||
? [formatContentType(item.attributes.type.data.attributes.slug)]
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
bottomChips={filterHasAttributes(item.attributes.categories?.data, [
|
|
||||||
"attributes",
|
|
||||||
]).map((category) => formatCategory(category.attributes.slug))}
|
|
||||||
keepInfoVisible
|
keepInfoVisible
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
@ -139,9 +129,7 @@ const ContentsFolder = ({ openGraph, folder, path, ...otherProps }: Props): JSX.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{folder.contents?.data.length === 0 && folder.subfolders?.data.length === 0 && (
|
{contents.length === 0 && subfolders.length === 0 && <NoContentNorFolderMessage />}
|
||||||
<NoContentNorFolderMessage />
|
|
||||||
)}
|
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -163,7 +151,7 @@ export default ContentsFolder;
|
||||||
|
|
||||||
export const getStaticProps: GetStaticProps = async (context) => {
|
export const getStaticProps: GetStaticProps = async (context) => {
|
||||||
const sdk = getReadySdk();
|
const sdk = getReadySdk();
|
||||||
const { format } = getFormat(context.locale);
|
const { format, formatContentType, formatCategory } = getFormat(context.locale);
|
||||||
const slug = context.params?.slug ? context.params.slug.toString() : "";
|
const slug = context.params?.slug ? context.params.slug.toString() : "";
|
||||||
const contentsFolder = await sdk.getContentsFolder({ slug: slug });
|
const contentsFolder = await sdk.getContentsFolder({ slug: slug });
|
||||||
if (!contentsFolder.contentsFolders?.data[0]?.attributes) {
|
if (!contentsFolder.contentsFolders?.data[0]?.attributes) {
|
||||||
|
@ -189,13 +177,51 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
||||||
return prettySlug(folder.slug);
|
return prettySlug(folder.slug);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
const subfolders: Props["subfolders"] = filterHasAttributes(folder.subfolders?.data, [
|
||||||
|
"attributes",
|
||||||
|
]).map(({ attributes }) => ({
|
||||||
|
slug: attributes.slug,
|
||||||
|
href: `/contents/folder/${attributes.slug}`,
|
||||||
|
translations: filterHasAttributes(attributes.titles, ["language.data.attributes.code"]).map(
|
||||||
|
(translation) => ({
|
||||||
|
title: translation.title,
|
||||||
|
language: translation.language.data.attributes.code,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
fallback: { title: prettySlug(attributes.slug) },
|
||||||
|
}));
|
||||||
|
|
||||||
|
const contents: Props["contents"] = filterHasAttributes(folder.contents?.data, [
|
||||||
|
"attributes",
|
||||||
|
]).map(({ attributes }) => ({
|
||||||
|
slug: attributes.slug,
|
||||||
|
href: `/contents/${attributes.slug}`,
|
||||||
|
translations: filterHasAttributes(attributes.translations, [
|
||||||
|
"language.data.attributes.code",
|
||||||
|
]).map((translation) => ({
|
||||||
|
pre_title: translation.pre_title ?? undefined,
|
||||||
|
title: translation.title,
|
||||||
|
subtitle: translation.subtitle ?? undefined,
|
||||||
|
language: translation.language.data.attributes.code,
|
||||||
|
})),
|
||||||
|
fallback: { title: prettySlug(attributes.slug) },
|
||||||
|
thumbnail: attributes.thumbnail?.data?.attributes ?? undefined,
|
||||||
|
topChips: attributes.type?.data?.attributes
|
||||||
|
? [formatContentType(attributes.type.data.attributes.slug)]
|
||||||
|
: undefined,
|
||||||
|
bottomChips: filterHasAttributes(attributes.categories?.data, ["attributes"]).map((category) =>
|
||||||
|
formatCategory(category.attributes.slug)
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
|
||||||
const props: Props = {
|
const props: Props = {
|
||||||
openGraph: getOpenGraph(format, title),
|
openGraph: getOpenGraph(format, title),
|
||||||
folder,
|
subfolders,
|
||||||
|
contents,
|
||||||
path: getRecursiveParentFolderPreview(folder),
|
path: getRecursiveParentFolderPreview(folder),
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
props: props,
|
props: JSON.parse(JSON.stringify(props)),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue