mirror of
https://github.com/AnimeThemes/animethemes-web.git
synced 2026-07-11 01:24:31 +02:00
feat: Migrated anime detail page
This commit is contained in:
+4
-1
@@ -7,7 +7,7 @@ const config: CodegenConfig = {
|
||||
"src/pages/about/dump.tsx",
|
||||
"src/pages/blog/index.tsx",
|
||||
"src/pages/anime/index.tsx",
|
||||
// "src/pages/anime/[animeSlug]/index.tsx",
|
||||
"src/pages/anime/[animeSlug]/index.tsx",
|
||||
"src/pages/artist/[artistSlug]/index.tsx",
|
||||
"src/pages/artist/index.tsx",
|
||||
"src/pages/series/index.tsx",
|
||||
@@ -24,9 +24,11 @@ const config: CodegenConfig = {
|
||||
"src/components/card/ArtistSummaryCard.tsx",
|
||||
"src/components/card/PlaylistSummaryCard.tsx",
|
||||
"src/components/card/StudioSummaryCard.tsx",
|
||||
"src/components/card/ThemeDetailCard.tsx",
|
||||
"src/components/card/ThemeSummaryCard.tsx",
|
||||
"src/components/card/VideoSummaryCard.tsx",
|
||||
"src/components/featured-theme/FeaturedTheme.tsx",
|
||||
"src/components/filter/AnimeThemeFilter.tsx",
|
||||
"src/components/image/MultiCoverImage.tsx",
|
||||
"src/components/image/StudioCoverImage.tsx",
|
||||
"src/components/menu/ThemeMenu.tsx",
|
||||
@@ -44,6 +46,7 @@ const config: CodegenConfig = {
|
||||
"src/components/table/ThemeTable.tsx",
|
||||
"src/components/tag/ContentWarningTags.tsx",
|
||||
"src/components/tag/EpisodeTag.tsx",
|
||||
"src/components/tag/ThemeEntryTags.tsx",
|
||||
"src/components/tag/VideoTags.tsx",
|
||||
"src/components/utils/SongTitle.tsx",
|
||||
"src/components/utils/SongTitleWithArtists.tsx",
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
import gql from "graphql-tag";
|
||||
|
||||
import { Row } from "@/components/box/Flex";
|
||||
import { VideoButton } from "@/components/button/VideoButton";
|
||||
import { Card } from "@/components/card/Card";
|
||||
import { ThemeMenu } from "@/components/menu/ThemeMenu";
|
||||
import { ThemeEntryTags } from "@/components/tag/ThemeEntryTags";
|
||||
import { VideoTags } from "@/components/tag/VideoTags";
|
||||
import { Text } from "@/components/text/Text";
|
||||
import { Performances } from "@/components/utils/Performances";
|
||||
import { SongTitle } from "@/components/utils/SongTitle";
|
||||
import type { ThemeDetailCardThemeFragment } from "@/generated/graphql";
|
||||
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
|
||||
import theme from "@/theme";
|
||||
import { entryVersionComparator } from "@/utils/comparators";
|
||||
|
||||
@@ -45,11 +42,48 @@ const StyledVideoList = styled(Row)`
|
||||
}
|
||||
`;
|
||||
|
||||
const fragments = {
|
||||
theme: graphql(`
|
||||
fragment ThemeDetailCardTheme on AnimeTheme {
|
||||
...ThemeMenuTheme
|
||||
...VideoButtonTheme
|
||||
type
|
||||
sequence
|
||||
group {
|
||||
name
|
||||
slug
|
||||
}
|
||||
anime {
|
||||
...VideoButtonAnime
|
||||
slug
|
||||
name
|
||||
}
|
||||
song {
|
||||
...SongTitleSong
|
||||
...PerformancesSong
|
||||
}
|
||||
animethemeentries {
|
||||
...ThemeEntryTagsEntry
|
||||
...VideoButtonEntry
|
||||
version
|
||||
videos {
|
||||
nodes {
|
||||
...VideoButtonVideo
|
||||
filename
|
||||
tags
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`),
|
||||
};
|
||||
|
||||
interface ThemeDetailCardProps {
|
||||
theme: ThemeDetailCardThemeFragment;
|
||||
theme: FragmentType<typeof fragments.theme>;
|
||||
}
|
||||
|
||||
export function ThemeDetailCard({ theme }: ThemeDetailCardProps) {
|
||||
export function ThemeDetailCard({ theme: themeFragment }: ThemeDetailCardProps) {
|
||||
const theme = getFragmentData(fragments.theme, themeFragment);
|
||||
const { anime } = theme;
|
||||
|
||||
if (!anime) {
|
||||
@@ -69,10 +103,10 @@ export function ThemeDetailCard({ theme }: ThemeDetailCardProps) {
|
||||
</Text>
|
||||
<ThemeMenu theme={theme} />
|
||||
</StyledRow>
|
||||
{theme.entries.sort(entryVersionComparator).map((entry) => (
|
||||
<StyledRow key={entry.version || 0}>
|
||||
{[...theme.animethemeentries].sort(entryVersionComparator).map((entry) => (
|
||||
<StyledRow key={entry.version ?? 0}>
|
||||
<Text variant="small" color="text-muted">
|
||||
{!!entry.version && `v${entry.version}`}
|
||||
v{entry.version ?? 1}
|
||||
</Text>
|
||||
<Text color="text-muted">
|
||||
<ThemeEntryTags entry={entry} />
|
||||
@@ -80,7 +114,7 @@ export function ThemeDetailCard({ theme }: ThemeDetailCardProps) {
|
||||
<StyledVideoListContainer>
|
||||
{!!entry.videos && (
|
||||
<StyledVideoList>
|
||||
{entry.videos.map((video, index) => (
|
||||
{entry.videos.nodes.map((video, index) => (
|
||||
<VideoButton key={index} anime={anime} theme={theme} entry={entry} video={video} />
|
||||
))}
|
||||
</StyledVideoList>
|
||||
@@ -91,46 +125,3 @@ export function ThemeDetailCard({ theme }: ThemeDetailCardProps) {
|
||||
</StyledThemeCard>
|
||||
);
|
||||
}
|
||||
|
||||
ThemeDetailCard.fragments = {
|
||||
theme: gql`
|
||||
${ThemeMenu.fragments.theme}
|
||||
${VideoTags.fragments.video}
|
||||
|
||||
fragment ThemeDetailCardTheme on Theme {
|
||||
...ThemeMenuTheme
|
||||
type
|
||||
sequence
|
||||
group {
|
||||
name
|
||||
slug
|
||||
}
|
||||
anime {
|
||||
slug
|
||||
name
|
||||
}
|
||||
song {
|
||||
title
|
||||
performances {
|
||||
alias
|
||||
as
|
||||
artist {
|
||||
slug
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
entries {
|
||||
version
|
||||
episodes
|
||||
spoiler
|
||||
nsfw
|
||||
videos {
|
||||
...VideoTagsVideo
|
||||
filename
|
||||
tags
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -1,20 +1,35 @@
|
||||
import { memo, useMemo, useState } from "react";
|
||||
|
||||
import gql from "graphql-tag";
|
||||
|
||||
import { Column, Row } from "@/components/box/Flex";
|
||||
import { ThemeDetailCard } from "@/components/card/ThemeDetailCard";
|
||||
import { Listbox, ListboxOption } from "@/components/listbox/Listbox";
|
||||
import { Text } from "@/components/text/Text";
|
||||
import { HorizontalScroll } from "@/components/utils/HorizontalScroll";
|
||||
import type { AnimeThemeFilterThemeFragment } from "@/generated/graphql";
|
||||
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
|
||||
import { either, themeGroupComparator, themeIndexComparator, themeTypeComparator } from "@/utils/comparators";
|
||||
|
||||
const fragments = {
|
||||
theme: graphql(`
|
||||
fragment AnimeThemeFilterTheme on AnimeTheme {
|
||||
...ThemeDetailCardTheme
|
||||
id
|
||||
type
|
||||
sequence
|
||||
group {
|
||||
name
|
||||
slug
|
||||
}
|
||||
}
|
||||
`),
|
||||
};
|
||||
|
||||
interface AnimeThemeFilterProps {
|
||||
themes: Array<AnimeThemeFilterThemeFragment>;
|
||||
themes: Array<FragmentType<typeof fragments.theme>>;
|
||||
}
|
||||
|
||||
function AnimeThemeFilterInternal({ themes }: AnimeThemeFilterProps) {
|
||||
function AnimeThemeFilterInternal({ themes: themesFragment }: AnimeThemeFilterProps) {
|
||||
const themes = getFragmentData(fragments.theme, themesFragment);
|
||||
|
||||
const hasMultipleTypes = themes.some((theme) => theme.type === "OP") && themes.some((theme) => theme.type === "ED");
|
||||
const [filterType, setFilterType] = useState<string | null>(null);
|
||||
|
||||
@@ -116,19 +131,4 @@ function AnimeThemeFilterInternal({ themes }: AnimeThemeFilterProps) {
|
||||
);
|
||||
}
|
||||
|
||||
AnimeThemeFilterInternal.fragments = {
|
||||
theme: gql`
|
||||
${ThemeDetailCard.fragments.theme}
|
||||
|
||||
fragment AnimeThemeFilterTheme on Theme {
|
||||
...ThemeDetailCardTheme
|
||||
type
|
||||
group {
|
||||
name
|
||||
slug
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const AnimeThemeFilter = memo(AnimeThemeFilterInternal);
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
import type { ComponentPropsWithoutRef } from "react";
|
||||
|
||||
import gql from "graphql-tag";
|
||||
|
||||
import { FullWidthImage } from "@/components/image/FullWidthImage";
|
||||
import { AspectRatio } from "@/components/utils/AspectRatio";
|
||||
import type { CoverImageResourceWithImagesFragment } from "@/generated/graphql";
|
||||
import extractImages from "@/utils/extractImages";
|
||||
|
||||
interface CoverImageProps extends ComponentPropsWithoutRef<typeof FullWidthImage> {
|
||||
resourceWithImages: CoverImageResourceWithImagesFragment;
|
||||
smallCover: string | undefined;
|
||||
largeCover: string | undefined;
|
||||
}
|
||||
|
||||
export function CoverImage({ resourceWithImages, ...props }: CoverImageProps) {
|
||||
const { smallCover, largeCover } = extractImages(resourceWithImages);
|
||||
|
||||
export function CoverImage({ smallCover, largeCover, ...props }: CoverImageProps) {
|
||||
return (
|
||||
<AspectRatio $ratio={2 / 3}>
|
||||
<FullWidthImage
|
||||
@@ -25,13 +20,3 @@ export function CoverImage({ resourceWithImages, ...props }: CoverImageProps) {
|
||||
</AspectRatio>
|
||||
);
|
||||
}
|
||||
|
||||
CoverImage.fragments = {
|
||||
resourceWithImages: gql`
|
||||
${extractImages.fragments.resourceWithImages}
|
||||
|
||||
fragment CoverImageResourceWithImages on ResourceWithImages {
|
||||
...extractImagesResourceWithImages
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
import gql from "graphql-tag";
|
||||
|
||||
import { Row } from "@/components/box/Flex";
|
||||
import { ContentWarningTags } from "@/components/tag/ContentWarningTags";
|
||||
import { EpisodeTag } from "@/components/tag/EpisodeTag";
|
||||
import type { ThemeEntryTagsEntryFragment } from "@/generated/graphql";
|
||||
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
|
||||
|
||||
type ThemeEntryTagsProps = {
|
||||
entry: ThemeEntryTagsEntryFragment;
|
||||
const fragments = {
|
||||
entry: graphql(`
|
||||
fragment ThemeEntryTagsEntry on AnimeThemeEntry {
|
||||
...EpisodeTagEntry
|
||||
...ContentWarningTagsEntry
|
||||
}
|
||||
`),
|
||||
};
|
||||
|
||||
export function ThemeEntryTags({ entry }: ThemeEntryTagsProps) {
|
||||
interface ThemeEntryTagsProps {
|
||||
entry: FragmentType<typeof fragments.entry>;
|
||||
}
|
||||
|
||||
export function ThemeEntryTags({ entry: entryFragment }: ThemeEntryTagsProps) {
|
||||
const entry = getFragmentData(fragments.entry, entryFragment);
|
||||
|
||||
return (
|
||||
<Row style={{ "--gap": "8px", "--align-items": "baseline" }}>
|
||||
<EpisodeTag entry={entry} />
|
||||
@@ -17,15 +26,3 @@ export function ThemeEntryTags({ entry }: ThemeEntryTagsProps) {
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
ThemeEntryTags.fragments = {
|
||||
entry: gql`
|
||||
${EpisodeTag.fragments.entry}
|
||||
${ContentWarningTags.fragments.entry}
|
||||
|
||||
fragment ThemeEntryTagsEntry on Entry {
|
||||
...EpisodeTagEntry
|
||||
...ContentWarningTagsEntry
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -4,7 +4,6 @@ import type { GetStaticPaths, GetStaticProps } from "next";
|
||||
import Link from "next/link";
|
||||
import type { MDXRemoteSerializeResult } from "next-mdx-remote";
|
||||
|
||||
import type { ResultOf } from "@graphql-typed-document-node/core";
|
||||
import type { ParsedUrlQuery } from "querystring";
|
||||
|
||||
import { Column } from "@/components/box/Flex";
|
||||
@@ -19,15 +18,8 @@ import { SEO } from "@/components/seo/SEO";
|
||||
import { Text } from "@/components/text/Text";
|
||||
import { HeightTransition } from "@/components/utils/HeightTransition";
|
||||
import createApolloClient from "@/graphql/createApolloClient";
|
||||
import { getFragmentData, graphql } from "@/graphql/generated";
|
||||
import {
|
||||
either,
|
||||
resourceAsComparator,
|
||||
resourceSiteComparator,
|
||||
seriesNameComparator,
|
||||
sortTransformed,
|
||||
studioNameComparator,
|
||||
} from "@/utils/comparators";
|
||||
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
|
||||
import { compare, seriesNameComparator, studioNameComparator } from "@/utils/comparators";
|
||||
import extractImages from "@/utils/extractImages";
|
||||
import fetchStaticPaths from "@/utils/fetchStaticPaths";
|
||||
import type { SharedPageProps } from "@/utils/getSharedPageProps";
|
||||
@@ -42,52 +34,74 @@ const StyledList = styled.div`
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
const propsQuery = graphql(`
|
||||
fragment AnimeDetailPageAnime on Anime {
|
||||
slug
|
||||
name
|
||||
season
|
||||
year
|
||||
synopsis
|
||||
mediaFormatLocalized
|
||||
animesynonyms {
|
||||
text
|
||||
}
|
||||
series {
|
||||
nodes {
|
||||
slug
|
||||
name
|
||||
const fragments = {
|
||||
anime: graphql(`
|
||||
fragment AnimeDetailPageAnime on Anime {
|
||||
slug
|
||||
name
|
||||
season
|
||||
seasonLocalized
|
||||
year
|
||||
synopsis
|
||||
mediaFormatLocalized
|
||||
animesynonyms {
|
||||
text
|
||||
}
|
||||
}
|
||||
studios {
|
||||
nodes {
|
||||
slug
|
||||
name
|
||||
}
|
||||
}
|
||||
resources {
|
||||
edges {
|
||||
node {
|
||||
site
|
||||
siteLocalized
|
||||
link
|
||||
series {
|
||||
nodes {
|
||||
slug
|
||||
name
|
||||
}
|
||||
as
|
||||
}
|
||||
studios {
|
||||
nodes {
|
||||
slug
|
||||
name
|
||||
}
|
||||
}
|
||||
resources {
|
||||
edges {
|
||||
node {
|
||||
site
|
||||
siteLocalized
|
||||
link
|
||||
}
|
||||
as
|
||||
}
|
||||
}
|
||||
images {
|
||||
nodes {
|
||||
...extractImagesImage
|
||||
}
|
||||
}
|
||||
animethemes {
|
||||
...AnimeThemeFilterTheme
|
||||
}
|
||||
}
|
||||
images {
|
||||
nodes {
|
||||
...extractImagesImage
|
||||
}
|
||||
`),
|
||||
};
|
||||
|
||||
const propsQuery = graphql(`
|
||||
query AnimeDetailPage($animeSlug: String!) {
|
||||
anime(slug: $animeSlug) {
|
||||
...AnimeDetailPageAnime
|
||||
}
|
||||
animethemes {
|
||||
...ThemeDetailCardTheme
|
||||
}
|
||||
`);
|
||||
|
||||
const pathsQuery = graphql(`
|
||||
query AnimeDetailPageAll {
|
||||
animePagination {
|
||||
data {
|
||||
...AnimeDetailPageAnime
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
interface AnimeDetailPageProps extends SharedPageProps {
|
||||
anime: ResultOf<typeof propsQuery>;
|
||||
anime: FragmentType<typeof fragments.anime>;
|
||||
synopsisMarkdownSource: MDXRemoteSerializeResult | null;
|
||||
}
|
||||
|
||||
@@ -95,9 +109,11 @@ interface AnimeDetailPageParams extends ParsedUrlQuery {
|
||||
animeSlug: string;
|
||||
}
|
||||
|
||||
export default function AnimeDetailPage({ anime, synopsisMarkdownSource }: AnimeDetailPageProps) {
|
||||
export default function AnimeDetailPage({ anime: animeFragment, synopsisMarkdownSource }: AnimeDetailPageProps) {
|
||||
const anime = getFragmentData(fragments.anime, animeFragment);
|
||||
|
||||
const [collapseSynopsis, setCollapseSynopsis] = useState(true);
|
||||
const { largeCover } = extractImages(anime.images.nodes);
|
||||
const { smallCover, largeCover } = extractImages(anime.images.nodes);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -105,12 +121,12 @@ export default function AnimeDetailPage({ anime, synopsisMarkdownSource }: Anime
|
||||
<Text variant="h1">{anime.name}</Text>
|
||||
<SidebarContainer>
|
||||
<Column style={{ "--gap": "24px" }}>
|
||||
<CoverImage resourceWithImages={anime} alt={`Cover image of ${anime.name}`} />
|
||||
<CoverImage smallCover={smallCover} largeCover={largeCover} alt={`Cover image of ${anime.name}`} />
|
||||
<DescriptionList>
|
||||
{anime.animesynonyms.data.length ? (
|
||||
{anime.animesynonyms.length ? (
|
||||
<DescriptionList.Item title="Alternative Titles">
|
||||
<StyledList>
|
||||
{anime.animesynonyms.data.map((synonym) => (
|
||||
{anime.animesynonyms.map((synonym) => (
|
||||
<Text key={synonym.text}>{synonym.text}</Text>
|
||||
))}
|
||||
</StyledList>
|
||||
@@ -122,7 +138,7 @@ export default function AnimeDetailPage({ anime, synopsisMarkdownSource }: Anime
|
||||
href={`/year/${anime.year}${anime.season ? `/${anime.season.toLowerCase()}` : ""}`}
|
||||
link
|
||||
>
|
||||
{(anime.season ? anime.season + " " : "") + anime.year}
|
||||
{(anime.seasonLocalized ? anime.seasonLocalized + " " : "") + anime.year}
|
||||
</Text>
|
||||
</DescriptionList.Item>
|
||||
{anime.series.nodes.length ? (
|
||||
@@ -153,13 +169,8 @@ export default function AnimeDetailPage({ anime, synopsisMarkdownSource }: Anime
|
||||
{anime.resources.edges.length ? (
|
||||
<DescriptionList.Item title="Links">
|
||||
<StyledList>
|
||||
{anime.resources.edges
|
||||
.sort(
|
||||
sortTransformed(
|
||||
either(resourceSiteComparator).or(resourceAsComparator).chain(),
|
||||
(resource) => ({ ...resource.node, ...resource }),
|
||||
),
|
||||
)
|
||||
{[...anime.resources.edges]
|
||||
.sort((a, b) => compare(a.node.site, b.node.site) || compare(a.as, b.as))
|
||||
.map((resource) => (
|
||||
<ExternalLink key={resource.node.link} href={resource.node.link}>
|
||||
{resource.node.siteLocalized}
|
||||
@@ -186,10 +197,10 @@ export default function AnimeDetailPage({ anime, synopsisMarkdownSource }: Anime
|
||||
)}
|
||||
<Text variant="h2">
|
||||
Themes
|
||||
<Text color="text-disabled"> ({anime.themes?.length || 0})</Text>
|
||||
<Text color="text-disabled"> ({anime.animethemes.length || 0})</Text>
|
||||
</Text>
|
||||
{anime.themes?.length ? (
|
||||
<AnimeThemeFilter themes={anime.themes.map((theme) => ({ ...theme, anime }))} />
|
||||
{anime.animethemes.length ? (
|
||||
<AnimeThemeFilter themes={anime.animethemes} />
|
||||
) : (
|
||||
<Text as="p">There are no themes for this anime, yet.</Text>
|
||||
)}
|
||||
@@ -199,44 +210,35 @@ export default function AnimeDetailPage({ anime, synopsisMarkdownSource }: Anime
|
||||
);
|
||||
}
|
||||
|
||||
const buildTimeCache: Map<string, ResultOf<typeof propsQuery>> = new Map();
|
||||
const buildTimeCache: Map<string, FragmentType<typeof fragments.anime>> = new Map();
|
||||
|
||||
export const getStaticProps: GetStaticProps<AnimeDetailPageProps, AnimeDetailPageParams> = async ({ params }) => {
|
||||
const client = createApolloClient();
|
||||
|
||||
let data = params ? buildTimeCache.get(params.animeSlug) : null;
|
||||
let animeFragment = params ? buildTimeCache.get(params.animeSlug) : null;
|
||||
|
||||
if (!data) {
|
||||
data =
|
||||
(
|
||||
await client.query({
|
||||
query: graphql(`
|
||||
query AnimeDetailPage($animeSlug: String!) {
|
||||
animePaginator(slug: $animeSlug) {
|
||||
data {
|
||||
...AnimeDetailPageAnime
|
||||
}
|
||||
}
|
||||
}
|
||||
`),
|
||||
variables: params,
|
||||
})
|
||||
).data.animes.data?.[0] ?? null;
|
||||
if (!animeFragment) {
|
||||
animeFragment = (
|
||||
await client.query({
|
||||
query: propsQuery,
|
||||
variables: params,
|
||||
})
|
||||
).data.anime;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
if (!animeFragment) {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
}
|
||||
|
||||
const anime = getFragmentData(fragments.anime, animeFragment);
|
||||
|
||||
return {
|
||||
props: {
|
||||
...getSharedPageProps(1),
|
||||
anime: data.anime,
|
||||
synopsisMarkdownSource: data.anime.synopsis
|
||||
? (await serializeMarkdownSafe(data.anime.synopsis)).source
|
||||
: null,
|
||||
...getSharedPageProps(),
|
||||
anime: animeFragment,
|
||||
synopsisMarkdownSource: anime.synopsis ? (await serializeMarkdownSafe(anime.synopsis)).source : null,
|
||||
},
|
||||
// Revalidate after 1 hour (= 3600 seconds).
|
||||
revalidate: 3600,
|
||||
@@ -248,21 +250,14 @@ export const getStaticPaths: GetStaticPaths<AnimeDetailPageParams> = () => {
|
||||
const client = createApolloClient();
|
||||
|
||||
const { data } = await client.query({
|
||||
query: graphql(`
|
||||
query AnimeDetailPageAll {
|
||||
animePaginator {
|
||||
data {
|
||||
slug
|
||||
...AnimeDetailPageAnime
|
||||
}
|
||||
}
|
||||
}
|
||||
`),
|
||||
query: pathsQuery,
|
||||
});
|
||||
|
||||
data.animes.data.forEach((anime) => buildTimeCache.set(anime.slug, getFragmentData(propsQuery, anime)));
|
||||
for (const anime of data.animePagination.data) {
|
||||
buildTimeCache.set(anime.slug, anime);
|
||||
}
|
||||
|
||||
return data.animes.data.map((anime) => ({
|
||||
return data.animePagination.data.map((anime) => ({
|
||||
params: {
|
||||
animeSlug: anime.slug,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user