From 5adae324290f57f7f284c201534caee30c6ed076 Mon Sep 17 00:00:00 2001 From: DrMint <29893320+DrMint@users.noreply.github.com> Date: Sat, 18 Mar 2023 22:13:34 +0100 Subject: [PATCH] Some new stuff --- src/graphql/fragments/reinCostume.graphql | 27 +++ .../operations/getReinCostumes.graphql | 34 +++ .../getReinCostumesWithoutEmblem.graphql | 10 + src/graphql/operations/getReinEmblem.graphql | 30 +++ src/graphql/operations/getReinEmblems.graphql | 22 ++ .../operations/getReinEmblemsSlugs.graphql | 10 + src/pages/wiki/index.tsx | 7 + src/pages/wiki/rein/costumes.tsx | 206 ++++++++++++++++++ src/pages/wiki/rein/emblems/[slug].tsx | 148 +++++++++++++ src/types/types.ts | 13 ++ 10 files changed, 507 insertions(+) create mode 100644 src/graphql/fragments/reinCostume.graphql create mode 100644 src/graphql/operations/getReinCostumes.graphql create mode 100644 src/graphql/operations/getReinCostumesWithoutEmblem.graphql create mode 100644 src/graphql/operations/getReinEmblem.graphql create mode 100644 src/graphql/operations/getReinEmblems.graphql create mode 100644 src/graphql/operations/getReinEmblemsSlugs.graphql create mode 100644 src/pages/wiki/rein/costumes.tsx create mode 100644 src/pages/wiki/rein/emblems/[slug].tsx diff --git a/src/graphql/fragments/reinCostume.graphql b/src/graphql/fragments/reinCostume.graphql new file mode 100644 index 0000000..475ecbe --- /dev/null +++ b/src/graphql/fragments/reinCostume.graphql @@ -0,0 +1,27 @@ +fragment reinCostume on ReinCostume { + slug + sprite { + data { + attributes { + ...uploadImage + } + } + } + translations { + id + language { + data { + attributes { + code + } + } + } + name + description + } + emblem { + data { + id + } + } +} diff --git a/src/graphql/operations/getReinCostumes.graphql b/src/graphql/operations/getReinCostumes.graphql new file mode 100644 index 0000000..81a2f56 --- /dev/null +++ b/src/graphql/operations/getReinCostumes.graphql @@ -0,0 +1,34 @@ +query getReinCostumes { + reinCostumes(pagination: { limit: -1 }) { + data { + id + attributes { + slug + sprite { + data { + attributes { + ...uploadImage + } + } + } + translations { + id + language { + data { + attributes { + code + } + } + } + name + description + } + emblem { + data { + id + } + } + } + } + } +} diff --git a/src/graphql/operations/getReinCostumesWithoutEmblem.graphql b/src/graphql/operations/getReinCostumesWithoutEmblem.graphql new file mode 100644 index 0000000..2f70d11 --- /dev/null +++ b/src/graphql/operations/getReinCostumesWithoutEmblem.graphql @@ -0,0 +1,10 @@ +query getReinCostumesWithoutEmblem { + reinCostumes(filters: { emblem: { id: { null: true } } }, pagination: { limit: -1 }) { + data { + id + attributes { + ...reinCostume + } + } + } +} diff --git a/src/graphql/operations/getReinEmblem.graphql b/src/graphql/operations/getReinEmblem.graphql new file mode 100644 index 0000000..7fe4082 --- /dev/null +++ b/src/graphql/operations/getReinEmblem.graphql @@ -0,0 +1,30 @@ +query getReinEmblem($slug: String) { + reinEmblems(filters: { slug: { eq: $slug } }) { + data { + id + attributes { + slug + translations { + id + name + description + language { + data { + attributes { + code + } + } + } + } + costumes { + data { + id + attributes { + ...reinCostume + } + } + } + } + } + } +} diff --git a/src/graphql/operations/getReinEmblems.graphql b/src/graphql/operations/getReinEmblems.graphql new file mode 100644 index 0000000..f423dfa --- /dev/null +++ b/src/graphql/operations/getReinEmblems.graphql @@ -0,0 +1,22 @@ +query getReinEmblems { + reinEmblems(pagination: { limit: -1 }) { + data { + id + attributes { + slug + translations { + id + name + description + language { + data { + attributes { + code + } + } + } + } + } + } + } +} diff --git a/src/graphql/operations/getReinEmblemsSlugs.graphql b/src/graphql/operations/getReinEmblemsSlugs.graphql new file mode 100644 index 0000000..e662ef7 --- /dev/null +++ b/src/graphql/operations/getReinEmblemsSlugs.graphql @@ -0,0 +1,10 @@ +query getReinEmblemsSlugs { + reinEmblems(pagination: { limit: -1 }) { + data { + id + attributes { + slug + } + } + } +} diff --git a/src/pages/wiki/index.tsx b/src/pages/wiki/index.tsx index d1e8e94..ad41755 100644 --- a/src/pages/wiki/index.tsx +++ b/src/pages/wiki/index.tsx @@ -167,6 +167,13 @@ const Wiki = (props: Props): JSX.Element => { onClick={closeSubPanel} border /> + ); diff --git a/src/pages/wiki/rein/costumes.tsx b/src/pages/wiki/rein/costumes.tsx new file mode 100644 index 0000000..db5286d --- /dev/null +++ b/src/pages/wiki/rein/costumes.tsx @@ -0,0 +1,206 @@ +import { GetStaticProps } from "next"; +import { useCallback } from "react"; +import Markdown from "markdown-to-jsx"; +import { AppLayout, AppLayoutRequired } from "components/AppLayout"; +import { getFormat } from "helpers/i18n"; +import { getOpenGraph } from "helpers/openGraph"; +import { ReinCostume, ReinEmblemCostume } from "types/types"; +import { getReadySdk } from "graphql/sdk"; +import { filterHasAttributes, isDefinedAndNotEmpty, isUndefined } from "helpers/asserts"; +import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel"; +import { TranslatedProps } from "types/TranslatedProps"; +import { useSmartLanguage } from "hooks/useSmartLanguage"; +import { prettySlug } from "helpers/formatters"; +import { ElementsSeparator } from "helpers/component"; +import { SubPanel } from "components/Containers/SubPanel"; +import { ReturnButton } from "components/PanelComponents/ReturnButton"; +import { useFormat } from "hooks/useFormat"; +import { PanelHeader } from "components/PanelComponents/PanelHeader"; +import { TranslatedNavOption } from "components/PanelComponents/NavOption"; +import { Img } from "components/Img"; +import { TranslatedPreviewCard } from "components/PreviewCard"; + +/* + * ╭────────╮ + * ──────────────────────────────────────────╯ PAGE ╰───────────────────────────────────────────── + */ + +interface Props extends AppLayoutRequired { + emblems: ReinEmblemCostume[]; +} + +const ReincarnationCostumes = ({ emblems, ...otherProps }: Props): JSX.Element => { + const { format } = useFormat(); + + const subPanel = ( + + + {[ + <> + + + + , + + <> + {emblems.map((emblem) => ( + ({ + language: translation.language.data.attributes.code, + title: translation.name, + }))} + fallback={{ title: prettySlug(emblem.attributes.slug) }} + url={`#${emblem.attributes.slug}`} + /> + ))} + , + ]} + + + ); + + const contentPanel = ( + +
+ + {emblems.map((emblem) => ( + ({ + language: translation.language.data.attributes.code, + title: translation.name, + description: translation.description, + }))} + fallback={{ title: prettySlug(emblem.attributes.slug) }} + slug={emblem.attributes.slug} + costumes={emblem.attributes.costumes} + /> + ))} + +
+
+ ); + + return ; +}; +export default ReincarnationCostumes; + +/* + * ╭──────────────────────╮ + * ───────────────────────────────────╯ NEXT DATA FETCHING ╰────────────────────────────────────── + */ + +export const getStaticProps: GetStaticProps = async (context) => { + const sdk = getReadySdk(); + const { format } = getFormat(context.locale); + + const emblems = (await sdk.getReinEmblems()).reinEmblems?.data; + const costumes = (await sdk.getReinCostumes()).reinCostumes?.data; + + if (isUndefined(emblems) || isUndefined(costumes)) { + return { notFound: true }; + } + + const processedEmblems: ReinEmblemCostume[] = []; + + filterHasAttributes(emblems, ["id", "attributes"] as const).forEach(({ id, attributes }) => { + const costumesOfCurrentEmblem = costumes.filter( + (costume) => costume.attributes?.emblem?.data?.id === id + ); + const emblemCostume: ReinEmblemCostume = { + id, + attributes: { ...attributes, costumes: costumesOfCurrentEmblem }, + }; + processedEmblems.push(emblemCostume); + }); + + const costumesWithoutEmblem = costumes.filter((costume) => + isUndefined(costume.attributes?.emblem?.data) + ); + + processedEmblems.push({ + id: "others", + attributes: { slug: "others", costumes: costumesWithoutEmblem }, + }); + + const props: Props = { + emblems: processedEmblems, + openGraph: getOpenGraph(format, format("costume", { count: Infinity })), + }; + return { + props: props, + }; +}; + +/* + * ╭──────────────────────╮ + * ───────────────────────────────────╯ PRIVATE COMPONENTS ╰────────────────────────────────────── + */ + +interface EmblemCostumeProps { + slug: string; + title: string; + description?: string; + costumes: ReinCostume[]; +} + +const EmblemCostume = ({ slug, title, description, costumes }: EmblemCostumeProps): JSX.Element => ( +
+

+ {title} +

+ {isDefinedAndNotEmpty(description) && {description}} +
+ {costumes.map((costume) => ( + ({ + language: translation.language.data.attributes.code, + title: translation.name, + }))} + thumbnail={costume.attributes?.sprite?.data?.attributes} + keepInfoVisible + thumbnailAspectRatio="1/1" + thumbnailForceAspectRatio + thumbnailFitMethod="contain" + fallback={{ title: prettySlug(costume.attributes?.slug) }} + href="#" + /> + ))} +
+
+); + +export const TranslatedEmblemCostume = ({ + translations, + fallback, + ...otherProps +}: TranslatedProps): JSX.Element => { + const [selectedTranslation] = useSmartLanguage({ + items: translations, + languageExtractor: useCallback((item: { language: string }): string => item.language, []), + }); + return ( + + ); +}; diff --git a/src/pages/wiki/rein/emblems/[slug].tsx b/src/pages/wiki/rein/emblems/[slug].tsx new file mode 100644 index 0000000..884d541 --- /dev/null +++ b/src/pages/wiki/rein/emblems/[slug].tsx @@ -0,0 +1,148 @@ +import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; +import Markdown from "markdown-to-jsx"; +import { useCallback } from "react"; +import { getReadySdk } from "graphql/sdk"; +import { filterHasAttributes, isDefined, isDefinedAndNotEmpty, isUndefined } from "helpers/asserts"; +import { AppLayout, AppLayoutRequired } from "components/AppLayout"; +import { useFormat } from "hooks/useFormat"; +import { GetReinEmblemQuery, ReinCostumeFragment } from "graphql/generated"; +import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel"; +import { Img } from "components/Img"; +import { TranslatedProps } from "types/TranslatedProps"; +import { useSmartLanguage } from "hooks/useSmartLanguage"; +import { prettySlug } from "helpers/formatters"; +import { getFormat } from "helpers/i18n"; +import { getOpenGraph } from "helpers/openGraph"; + +/* + * ╭────────╮ + * ──────────────────────────────────────────╯ PAGE ╰───────────────────────────────────────────── + */ + +interface Props extends AppLayoutRequired { + emblem: NonNullable< + NonNullable["data"][number]>["attributes"] + >; +} + +const ReinEmblem = ({ emblem, ...otherProps }: Props): JSX.Element => { + const { format } = useFormat(); + + const contentPanel = ( + +
+ ({ + language: translation.language.data.attributes.code, + title: translation.name, + description: translation.description, + }))} + fallback={{ title: prettySlug(emblem.slug) }} + slug={emblem.slug} + costumes={filterHasAttributes(emblem.costumes?.data, ["attributes"] as const).map( + (costume) => costume.attributes + )} + /> +
+
+ ); + + return ; +}; +export default ReinEmblem; + +/* + * ╭──────────────────────╮ + * ───────────────────────────────────╯ NEXT DATA FETCHING ╰────────────────────────────────────── + */ + +export const getStaticProps: GetStaticProps = async (context) => { + const sdk = getReadySdk(); + const { format } = getFormat(context.locale); + + const slug = + context.params && isDefined(context.params.slug) ? context.params.slug.toString() : ""; + const emblem = (await sdk.getReinEmblem({ slug })).reinEmblems?.data?.[0]?.attributes; + + if (isUndefined(emblem)) { + return { notFound: true }; + } + + const props: Props = { + emblem, + openGraph: getOpenGraph(format, format("costume", { count: Infinity })), + }; + return { + props: props, + }; +}; + +// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + +export const getStaticPaths: GetStaticPaths = async (context) => { + const sdk = getReadySdk(); + const contents = await sdk.getReinEmblemsSlugs(); + const paths: GetStaticPathsResult["paths"] = []; + filterHasAttributes(contents.reinEmblems?.data, ["attributes"] as const).map((emblem) => { + context.locales?.map((local) => + paths.push({ + params: { slug: emblem.attributes.slug }, + locale: local, + }) + ); + }); + return { + paths, + fallback: "blocking", + }; +}; + +/* + * ╭──────────────────────╮ + * ───────────────────────────────────╯ PRIVATE COMPONENTS ╰────────────────────────────────────── + */ + +interface EmblemCostumeProps { + slug: string; + title: string; + description?: string; + costumes: ReinCostumeFragment[]; +} + +const EmblemCostume = ({ slug, title, description, costumes }: EmblemCostumeProps): JSX.Element => ( +
+

+ {title} +

+ {isDefinedAndNotEmpty(description) && {description}} +
+ {costumes.map((costume) => ( +
+ {costume.sprite?.data?.attributes && } +

{costume.translations?.[0]?.name}

+ {costume.translations?.[0]?.description ?? ""} +
+ ))} +
+
+); + +export const TranslatedEmblemCostume = ({ + translations, + fallback, + ...otherProps +}: TranslatedProps): JSX.Element => { + const [selectedTranslation] = useSmartLanguage({ + items: translations, + languageExtractor: useCallback((item: { language: string }): string => item.language, []), + }); + return ( + + ); +}; diff --git a/src/types/types.ts b/src/types/types.ts index 9a41097..e6da9aa 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -2,6 +2,8 @@ import { GetChronicleQuery, GetContentTextQuery, GetPostQuery, + GetReinCostumesQuery, + GetReinEmblemsQuery, GetWeaponQuery, GetWikiPageQuery, } from "graphql/generated"; @@ -68,6 +70,17 @@ export type WeaponGroupPreview = NonNullable< // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ +type ReinEmblem = NonNullable["data"][number]; + +export type ReinCostume = NonNullable["data"][number]; + +export type ReinEmblemCostume = { + id: ReinEmblem["id"]; + attributes: NonNullable & { costumes: ReinCostume[] }; +}; + +// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + export enum LibraryItemUserStatus { None = 0, Want = 1,