Typescript updated to 5.0, removed pesky as const

This commit is contained in:
DrMint 2023-03-18 23:43:55 +01:00
parent bfb753bf21
commit b6882cd1e5
30 changed files with 312 additions and 342 deletions

30
package-lock.json generated
View File

@ -59,13 +59,13 @@
"eslint-config-next": "13.2.4", "eslint-config-next": "13.2.4",
"eslint-plugin-import": "^2.27.5", "eslint-plugin-import": "^2.27.5",
"graphql": "^16.6.0", "graphql": "^16.6.0",
"graphql-request": "5.2.0", "graphql-request": "5.1.0",
"next-sitemap": "^4.0.6", "next-sitemap": "^4.0.6",
"prettier": "^2.8.4", "prettier": "^2.8.4",
"prettier-plugin-tailwindcss": "^0.2.5", "prettier-plugin-tailwindcss": "^0.2.5",
"tailwindcss": "^3.2.7", "tailwindcss": "^3.2.7",
"ts-unused-exports": "^9.0.4", "ts-unused-exports": "^9.0.4",
"typescript": "^4.9.5" "typescript": "^5.0.2"
} }
}, },
"node_modules/@ampproject/remapping": { "node_modules/@ampproject/remapping": {
@ -6797,9 +6797,9 @@
"dev": true "dev": true
}, },
"node_modules/graphql-request": { "node_modules/graphql-request": {
"version": "5.2.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-5.2.0.tgz", "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-5.1.0.tgz",
"integrity": "sha512-pLhKIvnMyBERL0dtFI3medKqWOz/RhHdcgbZ+hMMIb32mEPa5MJSzS4AuXxfI4sRAu6JVVk5tvXuGfCWl9JYWQ==", "integrity": "sha512-0OeRVYigVwIiXhNmqnPDt+JhMzsjinxHE7TVy3Lm6jUzav0guVcL0lfSbi6jVTRAxcbwgyr6yrZioSHxf9gHzw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@graphql-typed-document-node/core": "^3.1.1", "@graphql-typed-document-node/core": "^3.1.1",
@ -10261,16 +10261,16 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.9.5", "version": "5.0.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==",
"dev": true, "dev": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
}, },
"engines": { "engines": {
"node": ">=4.2.0" "node": ">=12.20"
} }
}, },
"node_modules/ua-parser-js": { "node_modules/ua-parser-js": {
@ -16008,9 +16008,9 @@
} }
}, },
"graphql-request": { "graphql-request": {
"version": "5.2.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-5.2.0.tgz", "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-5.1.0.tgz",
"integrity": "sha512-pLhKIvnMyBERL0dtFI3medKqWOz/RhHdcgbZ+hMMIb32mEPa5MJSzS4AuXxfI4sRAu6JVVk5tvXuGfCWl9JYWQ==", "integrity": "sha512-0OeRVYigVwIiXhNmqnPDt+JhMzsjinxHE7TVy3Lm6jUzav0guVcL0lfSbi6jVTRAxcbwgyr6yrZioSHxf9gHzw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@graphql-typed-document-node/core": "^3.1.1", "@graphql-typed-document-node/core": "^3.1.1",
@ -18487,9 +18487,9 @@
} }
}, },
"typescript": { "typescript": {
"version": "4.9.5", "version": "5.0.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==",
"dev": true "dev": true
}, },
"ua-parser-js": { "ua-parser-js": {

View File

@ -71,13 +71,13 @@
"eslint-config-next": "13.2.4", "eslint-config-next": "13.2.4",
"eslint-plugin-import": "^2.27.5", "eslint-plugin-import": "^2.27.5",
"graphql": "^16.6.0", "graphql": "^16.6.0",
"graphql-request": "5.2.0", "graphql-request": "5.1.0",
"next-sitemap": "^4.0.6", "next-sitemap": "^4.0.6",
"prettier": "^2.8.4", "prettier": "^2.8.4",
"prettier-plugin-tailwindcss": "^0.2.5", "prettier-plugin-tailwindcss": "^0.2.5",
"tailwindcss": "^3.2.7", "tailwindcss": "^3.2.7",
"ts-unused-exports": "^9.0.4", "ts-unused-exports": "^9.0.4",
"typescript": "^4.9.5" "typescript": "^5.0.2"
}, },
"overrides": { "overrides": {
"react-zoom-pan-pinch": { "react-zoom-pan-pinch": {

View File

@ -45,10 +45,7 @@ const ChroniclesList = ({ chronicles, currentSlug, title }: Props): JSX.Element
<div <div
className="grid gap-4 overflow-hidden transition-height duration-500" className="grid gap-4 overflow-hidden transition-height duration-500"
style={{ maxHeight: isOpen ? `${8 * chronicles.length}rem` : 0 }}> style={{ maxHeight: isOpen ? `${8 * chronicles.length}rem` : 0 }}>
{filterHasAttributes(chronicles, [ {filterHasAttributes(chronicles, ["attributes.contents", "attributes.translations"])
"attributes.contents",
"attributes.translations",
] as const)
.sort((a, b) => compareDate(a.attributes.date_start, b.attributes.date_start)) .sort((a, b) => compareDate(a.attributes.date_start, b.attributes.date_start))
.map((chronicle) => ( .map((chronicle) => (
<div key={chronicle.id} id={`chronicle-${chronicle.attributes.slug}`}> <div key={chronicle.id} id={`chronicle-${chronicle.attributes.slug}`}>
@ -56,14 +53,14 @@ const ChroniclesList = ({ chronicles, currentSlug, title }: Props): JSX.Element
chronicle.attributes.contents.data.length === 1 chronicle.attributes.contents.data.length === 1
? filterHasAttributes(chronicle.attributes.contents.data, [ ? filterHasAttributes(chronicle.attributes.contents.data, [
"attributes.translations", "attributes.translations",
] as const).map((content, index) => ( ]).map((content, index) => (
<TranslatedChroniclePreview <TranslatedChroniclePreview
key={index} key={index}
active={chronicle.attributes.slug === currentSlug} active={chronicle.attributes.slug === currentSlug}
date={chronicle.attributes.date_start} date={chronicle.attributes.date_start}
translations={filterHasAttributes(content.attributes.translations, [ translations={filterHasAttributes(content.attributes.translations, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map((translation) => ({ ]).map((translation) => ({
title: prettyInlineTitle( title: prettyInlineTitle(
translation.pre_title, translation.pre_title,
translation.title, translation.title,
@ -90,7 +87,7 @@ const ChroniclesList = ({ chronicles, currentSlug, title }: Props): JSX.Element
translations={filterHasAttributes(chronicle.attributes.translations, [ translations={filterHasAttributes(chronicle.attributes.translations, [
"language.data.attributes.code", "language.data.attributes.code",
"title", "title",
] as const).map((translation) => ({ ]).map((translation) => ({
title: translation.title, title: translation.title,
language: translation.language.data.attributes.code, language: translation.language.data.attributes.code,
}))} }))}

View File

@ -223,7 +223,7 @@ export const SearchPopup = (): JSX.Element => {
onClick={() => setSearchOpened(false)} onClick={() => setSearchOpened(false)}
translations={filterHasAttributes(item._formatted.descriptions, [ translations={filterHasAttributes(item._formatted.descriptions, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map((translation) => ({ ]).map((translation) => ({
language: translation.language.data.attributes.code, language: translation.language.data.attributes.code,
title: item.title, title: item.title,
subtitle: item.subtitle, subtitle: item.subtitle,
@ -270,7 +270,7 @@ export const SearchPopup = (): JSX.Element => {
onClick={() => setSearchOpened(false)} onClick={() => setSearchOpened(false)}
translations={filterHasAttributes(item._formatted.translations, [ translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map(({ displayable_description, language, ...otherAttributes }) => ({ ]).map(({ displayable_description, language, ...otherAttributes }) => ({
...otherAttributes, ...otherAttributes,
description: containsHighlight(displayable_description) description: containsHighlight(displayable_description)
? displayable_description ? displayable_description
@ -315,7 +315,7 @@ export const SearchPopup = (): JSX.Element => {
onClick={() => setSearchOpened(false)} onClick={() => setSearchOpened(false)}
translations={filterHasAttributes(item._formatted.translations, [ translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map( ]).map(
({ ({
aliases, aliases,
summary, summary,
@ -340,12 +340,12 @@ export const SearchPopup = (): JSX.Element => {
thumbnailRounded thumbnailRounded
thumbnailForceAspectRatio thumbnailForceAspectRatio
keepInfoVisible keepInfoVisible
topChips={filterHasAttributes(item.tags?.data, ["attributes"] as const).map( topChips={filterHasAttributes(item.tags?.data, ["attributes"]).map(
(tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug) (tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug)
)} )}
bottomChips={filterHasAttributes(item.categories?.data, [ bottomChips={filterHasAttributes(item.categories?.data, ["attributes"]).map(
"attributes", (category) => category.attributes.short
] as const).map((category) => category.attributes.short)} )}
/> />
))} ))}
</div> </div>
@ -367,7 +367,7 @@ export const SearchPopup = (): JSX.Element => {
onClick={() => setSearchOpened(false)} onClick={() => setSearchOpened(false)}
translations={filterHasAttributes(item._formatted.translations, [ translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map(({ excerpt, body, language, ...otherAttributes }) => ({ ]).map(({ excerpt, body, language, ...otherAttributes }) => ({
...otherAttributes, ...otherAttributes,
description: containsHighlight(excerpt) description: containsHighlight(excerpt)
? excerpt ? excerpt
@ -449,14 +449,12 @@ export const SearchPopup = (): JSX.Element => {
href={"/"} href={"/"}
translations={filterHasAttributes(item._formatted.translations, [ translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map( ]).map(({ description, language, names: [primaryName, ...aliases] }) => ({
({ description, language, names: [primaryName, ...aliases] }) => ({ language: language.data.attributes.code,
language: language.data.attributes.code, title: primaryName,
title: primaryName, subtitle: aliases.join("・"),
subtitle: aliases.join("・"), description: containsHighlight(description) ? description : undefined,
description: containsHighlight(description) ? description : undefined, }))}
})
)}
fallback={{ title: prettySlug(item.slug) }} fallback={{ title: prettySlug(item.slug) }}
thumbnail={item.thumbnail?.data?.attributes} thumbnail={item.thumbnail?.data?.attributes}
thumbnailAspectRatio="1/1" thumbnailAspectRatio="1/1"
@ -468,9 +466,9 @@ export const SearchPopup = (): JSX.Element => {
? [prettySlug(item.type.data.attributes.slug)] ? [prettySlug(item.type.data.attributes.slug)]
: undefined : undefined
} }
bottomChips={filterHasAttributes(item.categories, [ bottomChips={filterHasAttributes(item.categories, ["attributes.short"]).map(
"attributes.short", (category) => category.attributes.short
] as const).map((category) => category.attributes.short)} )}
/> />
))} ))}
</div> </div>

View File

@ -41,7 +41,7 @@ export const SettingsPopup = (): JSX.Element => {
const router = useRouter(); const router = useRouter();
const currencyOptions = filterHasAttributes(currencies, ["attributes"] as const).map( const currencyOptions = filterHasAttributes(currencies, ["attributes"]).map(
(currentCurrency) => currentCurrency.attributes.code (currentCurrency) => currentCurrency.attributes.code
); );

View File

@ -94,13 +94,11 @@ export const PostPage = ({
<div> <div>
<p className="font-headers font-bold">{"Authors"}:</p> <p className="font-headers font-bold">{"Authors"}:</p>
<div className="grid place-content-center place-items-center gap-2"> <div className="grid place-content-center place-items-center gap-2">
{filterHasAttributes(post.authors.data, ["id", "attributes"] as const).map( {filterHasAttributes(post.authors.data, ["id", "attributes"]).map((author) => (
(author) => ( <Fragment key={author.id}>
<Fragment key={author.id}> <RecorderChip recorder={author.attributes} />
<RecorderChip recorder={author.attributes} /> </Fragment>
</Fragment> ))}
)
)}
</div> </div>
</div> </div>
)} )}

View File

@ -40,13 +40,11 @@ export const RecorderChip = ({ recorder }: Props): JSX.Element => {
{recorder.languages?.data && recorder.languages.data.length > 0 && ( {recorder.languages?.data && recorder.languages.data.length > 0 && (
<div className="flex flex-row flex-wrap gap-1"> <div className="flex flex-row flex-wrap gap-1">
<p>{format("language", { count: recorder.languages.data.length })}:</p> <p>{format("language", { count: recorder.languages.data.length })}:</p>
{filterHasAttributes(recorder.languages.data, ["attributes"] as const).map( {filterHasAttributes(recorder.languages.data, ["attributes"]).map((language) => (
(language) => ( <Fragment key={language.__typename}>
<Fragment key={language.__typename}> <Chip text={language.attributes.code.toUpperCase()} />
<Chip text={language.attributes.code.toUpperCase()} /> </Fragment>
</Fragment> ))}
)
)}
</div> </div>
)} )}
{recorder.pronouns && ( {recorder.pronouns && (

View File

@ -88,11 +88,9 @@ export const ThumbnailHeader = ({
<div className="flex flex-col place-items-center gap-2"> <div className="flex flex-col place-items-center gap-2">
<h3 className="text-xl">{format("category", { count: categories.data.length })}</h3> <h3 className="text-xl">{format("category", { count: categories.data.length })}</h3>
<div className="flex flex-row flex-wrap place-content-center gap-2"> <div className="flex flex-row flex-wrap place-content-center gap-2">
{filterHasAttributes(categories.data, ["attributes", "id"] as const).map( {filterHasAttributes(categories.data, ["attributes", "id"]).map((category) => (
(category) => ( <Chip key={category.id} text={category.attributes.name} />
<Chip key={category.id} text={category.attributes.name} /> ))}
)
)}
</div> </div>
</div> </div>
)} )}

View File

@ -41,7 +41,7 @@ export const getPostStaticProps =
[format("release_date")]: [prettyDate(post.posts.data[0].attributes.date, context.locale)], [format("release_date")]: [prettyDate(post.posts.data[0].attributes.date, context.locale)],
[format("category", { count: Infinity })]: filterHasAttributes( [format("category", { count: Infinity })]: filterHasAttributes(
post.posts.data[0].attributes.categories?.data, post.posts.data[0].attributes.categories?.data,
["attributes"] as const ["attributes"]
).map((category) => category.attributes.short), ).map((category) => category.attributes.short),
}); });

View File

@ -2,12 +2,18 @@
import { createWriteStream } from "fs"; import { createWriteStream } from "fs";
import { parse, TYPE } from "@formatjs/icu-messageformat-parser"; import { parse, TYPE } from "@formatjs/icu-messageformat-parser";
import { getLangui } from "./fetchLocalData"; import { getLangui } from "./fetchLocalData";
import { filterDefined } from "helpers/asserts";
import { getLogger } from "helpers/logger"; import { getLogger } from "helpers/logger";
const OUTPUT_FOLDER = `${process.cwd()}/src/graphql`; const OUTPUT_FOLDER = `${process.cwd()}/src/graphql`;
const logger = getLogger("💽 [ICU to TS]", "server"); const logger = getLogger("💽 [ICU to TS]", "server");
const isDefined = <T>(t: T): t is NonNullable<T> => t !== null && t !== undefined;
const isUndefined = <T>(t: T | null | undefined): t is null | undefined => !isDefined(t);
const filterDefined = <T>(t: T[] | null | undefined): NonNullable<T>[] =>
isUndefined(t) ? [] : (t.filter((item) => isDefined(item)) as NonNullable<T>[]);
const icuToTypescript = () => { const icuToTypescript = () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const { ui_language, ...langui } = getLangui("en"); const { ui_language, ...langui } = getLangui("en");

View File

@ -48,7 +48,7 @@ export const isDefinedAndNotEmpty = (string: string | null | undefined): string
export const filterDefined = <T>(t: T[] | null | undefined): NonNullable<T>[] => export const filterDefined = <T>(t: T[] | null | undefined): NonNullable<T>[] =>
isUndefined(t) ? [] : (t.filter((item) => isDefined(item)) as NonNullable<T>[]); isUndefined(t) ? [] : (t.filter((item) => isDefined(item)) as NonNullable<T>[]);
export const filterHasAttributes = <T, P extends PathDot<T>>( export const filterHasAttributes = <T, const P extends PathDot<T>>(
t: T[] | null | undefined, t: T[] | null | undefined,
paths: readonly P[] paths: readonly P[]
): SelectiveNonNullable<T, (typeof paths)[number]>[] => ): SelectiveNonNullable<T, (typeof paths)[number]>[] =>
@ -77,3 +77,5 @@ const hasAttribute = <T>(item: T, path: string): boolean => {
} }
return false; return false;
}; };

View File

@ -201,7 +201,7 @@ const Revalidate = async (
}); });
filterHasAttributes(libraryItem.libraryItems?.data[0]?.attributes?.subitem_of?.data, [ filterHasAttributes(libraryItem.libraryItems?.data[0]?.attributes?.subitem_of?.data, [
"attributes.slug", "attributes.slug",
] as const).forEach((parentItem) => paths.push(`/library/${parentItem.attributes.slug}`)); ]).forEach((parentItem) => paths.push(`/library/${parentItem.attributes.slug}`));
} }
break; break;
@ -227,7 +227,7 @@ const Revalidate = async (
filterHasAttributes(content.contents?.data[0]?.attributes?.ranged_contents?.data, [ filterHasAttributes(content.contents?.data[0]?.attributes?.ranged_contents?.data, [
"attributes.library_item.data.attributes.slug", "attributes.library_item.data.attributes.slug",
] as const).forEach((ranged_content) => { ]).forEach((ranged_content) => {
const parentSlug = ranged_content.attributes.library_item.data.attributes.slug; const parentSlug = ranged_content.attributes.library_item.data.attributes.slug;
paths.push(`/library/${parentSlug}`); paths.push(`/library/${parentSlug}`);
paths.push(`/library/${parentSlug}/reader`); paths.push(`/library/${parentSlug}/reader`);
@ -285,12 +285,10 @@ const Revalidate = async (
} }
filterHasAttributes(folder.contentsFolders?.data[0]?.attributes?.subfolders?.data, [ filterHasAttributes(folder.contentsFolders?.data[0]?.attributes?.subfolders?.data, [
"attributes.slug", "attributes.slug",
] as const).forEach((subfolder) => ]).forEach((subfolder) => paths.push(`/contents/folder/${subfolder.attributes.slug}`));
paths.push(`/contents/folder/${subfolder.attributes.slug}`)
);
filterHasAttributes(folder.contentsFolders?.data[0]?.attributes?.contents?.data, [ filterHasAttributes(folder.contentsFolders?.data[0]?.attributes?.contents?.data, [
"attributes.slug", "attributes.slug",
] as const).forEach((content) => paths.push(`/contents/${content.attributes.slug}`)); ]).forEach((content) => paths.push(`/contents/${content.attributes.slug}`));
} }
break; break;
} }
@ -339,7 +337,7 @@ const Revalidate = async (
}); });
filterHasAttributes(group.weaponStoryGroup?.data?.attributes?.weapons?.data, [ filterHasAttributes(group.weaponStoryGroup?.data?.attributes?.weapons?.data, [
"attributes.slug", "attributes.slug",
] as const).forEach((weapon) => paths.push(`/wiki/weapons/${weapon.attributes.slug}`)); ]).forEach((weapon) => paths.push(`/wiki/weapons/${weapon.attributes.slug}`));
break; break;
} }

View File

@ -300,7 +300,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const paths: GetStaticPathsResult["paths"] = []; const paths: GetStaticPathsResult["paths"] = [];
if (channels.videoChannels?.data) if (channels.videoChannels?.data)
filterHasAttributes(channels.videoChannels.data, ["attributes"] as const).map((channel) => { filterHasAttributes(channels.videoChannels.data, ["attributes"]).map((channel) => {
context.locales?.map((local) => { context.locales?.map((local) => {
paths.push({ paths.push({
params: { uid: channel.attributes.uid }, params: { uid: channel.attributes.uid },

View File

@ -168,7 +168,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const videos = await sdk.getVideosSlugs(); const videos = await sdk.getVideosSlugs();
const paths: GetStaticPathsResult["paths"] = []; const paths: GetStaticPathsResult["paths"] = [];
if (videos.videos?.data) if (videos.videos?.data)
filterHasAttributes(videos.videos.data, ["attributes"] as const).map((video) => { filterHasAttributes(videos.videos.data, ["attributes"]).map((video) => {
context.locales?.map((local) => { context.locales?.map((local) => {
paths.push({ params: { uid: video.attributes.uid }, locale: local }); paths.push({ params: { uid: video.attributes.uid }, locale: local });
}); });

View File

@ -47,8 +47,7 @@ const Chronicle = ({ chronicle, chapters, ...otherProps }: Props): JSX.Element =
}); });
const primaryContent = chronicle.contents const primaryContent = chronicle.contents
? filterHasAttributes(chronicle.contents.data, ["attributes.translations"] as const)[0] ? filterHasAttributes(chronicle.contents.data, ["attributes.translations"])[0]?.attributes
?.attributes
: undefined; : undefined;
const [selectedContentTranslation, ContentLanguageSwitcher, ContentLanguageSwitcherProps] = const [selectedContentTranslation, ContentLanguageSwitcher, ContentLanguageSwitcherProps] =
@ -128,13 +127,13 @@ const Chronicle = ({ chronicle, chapters, ...otherProps }: Props): JSX.Element =
<HorizontalLine /> <HorizontalLine />
<div className="grid gap-16"> <div className="grid gap-16">
{filterHasAttributes(chapters, ["attributes.chronicles", "id"] as const).map((chapter) => ( {filterHasAttributes(chapters, ["attributes.chronicles", "id"]).map((chapter) => (
<TranslatedChroniclesList <TranslatedChroniclesList
key={chapter.id} key={chapter.id}
chronicles={chapter.attributes.chronicles.data} chronicles={chapter.attributes.chronicles.data}
translations={filterHasAttributes(chapter.attributes.titles, [ translations={filterHasAttributes(chapter.attributes.titles, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map((translation) => ({ ]).map((translation) => ({
title: translation.title, title: translation.title,
language: translation.language.data.attributes.code, language: translation.language.data.attributes.code,
}))} }))}
@ -201,7 +200,7 @@ export const getStaticProps: GetStaticProps = async (context) => {
[format("category", { count: Infinity })]: filterHasAttributes( [format("category", { count: Infinity })]: filterHasAttributes(
chronicle.chronicles.data[0].attributes.contents.data[0].attributes.categories chronicle.chronicles.data[0].attributes.contents.data[0].attributes.categories
?.data, ?.data,
["attributes"] as const ["attributes"]
).map((category) => category.attributes.short), ).map((category) => category.attributes.short),
}), }),
}; };
@ -248,7 +247,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk(); const sdk = getReadySdk();
const contents = await sdk.getChroniclesSlugs(); const contents = await sdk.getChroniclesSlugs();
const paths: GetStaticPathsResult["paths"] = []; const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(contents.chronicles?.data, ["attributes"] as const).map((wikiPage) => { filterHasAttributes(contents.chronicles?.data, ["attributes"]).map((wikiPage) => {
context.locales?.map((local) => context.locales?.map((local) =>
paths.push({ paths.push({
params: { slug: wikiPage.attributes.slug }, params: { slug: wikiPage.attributes.slug },

View File

@ -34,13 +34,13 @@ const Chronicles = ({ chapters, ...otherProps }: Props): JSX.Element => {
<HorizontalLine /> <HorizontalLine />
<div className="grid gap-16"> <div className="grid gap-16">
{filterHasAttributes(chapters, ["attributes.chronicles", "id"] as const).map((chapter) => ( {filterHasAttributes(chapters, ["attributes.chronicles", "id"]).map((chapter) => (
<TranslatedChroniclesList <TranslatedChroniclesList
key={chapter.id} key={chapter.id}
chronicles={chapter.attributes.chronicles.data} chronicles={chapter.attributes.chronicles.data}
translations={filterHasAttributes(chapter.attributes.titles, [ translations={filterHasAttributes(chapter.attributes.titles, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map((translation) => ({ ]).map((translation) => ({
title: translation.title, title: translation.title,
language: translation.language.data.attributes.code, language: translation.language.data.attributes.code,
}))} }))}

View File

@ -80,7 +80,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
translations: filterHasAttributes(content.folder?.data?.attributes?.titles, [ translations: filterHasAttributes(content.folder?.data?.attributes?.titles, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map((title) => ({ ]).map((title) => ({
language: title.language.data.attributes.code, language: title.language.data.attributes.code,
title: title.title, title: title.title,
})), })),
@ -146,7 +146,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
{filterHasAttributes(selectedTranslation.text_set.transcribers.data, [ {filterHasAttributes(selectedTranslation.text_set.transcribers.data, [
"attributes", "attributes",
"id", "id",
] as const).map((recorder) => ( ]).map((recorder) => (
<Fragment key={recorder.id}> <Fragment key={recorder.id}>
<RecorderChip recorder={recorder.attributes} /> <RecorderChip recorder={recorder.attributes} />
</Fragment> </Fragment>
@ -163,7 +163,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
{filterHasAttributes(selectedTranslation.text_set.translators.data, [ {filterHasAttributes(selectedTranslation.text_set.translators.data, [
"attributes", "attributes",
"id", "id",
] as const).map((recorder) => ( ]).map((recorder) => (
<Fragment key={recorder.id}> <Fragment key={recorder.id}>
<RecorderChip recorder={recorder.attributes} /> <RecorderChip recorder={recorder.attributes} />
</Fragment> </Fragment>
@ -180,7 +180,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
{filterHasAttributes(selectedTranslation.text_set.proofreaders.data, [ {filterHasAttributes(selectedTranslation.text_set.proofreaders.data, [
"attributes", "attributes",
"id", "id",
] as const).map((recorder) => ( ]).map((recorder) => (
<Fragment key={recorder.id}> <Fragment key={recorder.id}>
<RecorderChip recorder={recorder.attributes} /> <RecorderChip recorder={recorder.attributes} />
</Fragment> </Fragment>
@ -209,7 +209,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
{filterHasAttributes(content.ranged_contents.data, [ {filterHasAttributes(content.ranged_contents.data, [
"attributes.library_item.data.attributes", "attributes.library_item.data.attributes",
"attributes.library_item.data.id", "attributes.library_item.data.id",
] as const).map((rangedContent) => { ]).map((rangedContent) => {
const libraryItem = rangedContent.attributes.library_item.data; const libraryItem = rangedContent.attributes.library_item.data;
return ( return (
<div <div
@ -231,7 +231,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
} }
bottomChips={filterHasAttributes(libraryItem.attributes.categories?.data, [ bottomChips={filterHasAttributes(libraryItem.attributes.categories?.data, [
"attributes", "attributes",
] as const).map((category) => category.attributes.short)} ]).map((category) => category.attributes.short)}
metadata={{ metadata={{
releaseDate: libraryItem.attributes.release_date, releaseDate: libraryItem.attributes.release_date,
price: libraryItem.attributes.price, price: libraryItem.attributes.price,
@ -288,7 +288,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
href={`/contents/${previousContent.attributes.slug}`} href={`/contents/${previousContent.attributes.slug}`}
translations={filterHasAttributes(previousContent.attributes.translations, [ translations={filterHasAttributes(previousContent.attributes.translations, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map((translation) => ({ ]).map((translation) => ({
pre_title: translation.pre_title, pre_title: translation.pre_title,
title: translation.title, title: translation.title,
subtitle: translation.subtitle, subtitle: translation.subtitle,
@ -329,7 +329,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
href={`/contents/${nextContent.attributes.slug}`} href={`/contents/${nextContent.attributes.slug}`}
translations={filterHasAttributes(nextContent.attributes.translations, [ translations={filterHasAttributes(nextContent.attributes.translations, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map((translation) => ({ ]).map((translation) => ({
pre_title: translation.pre_title, pre_title: translation.pre_title,
title: translation.title, title: translation.title,
subtitle: translation.subtitle, subtitle: translation.subtitle,
@ -404,7 +404,7 @@ export const getStaticProps: GetStaticProps = async (context) => {
], ],
[format("category", { count: Infinity })]: filterHasAttributes( [format("category", { count: Infinity })]: filterHasAttributes(
content.contents.data[0].attributes.categories?.data, content.contents.data[0].attributes.categories?.data,
["attributes"] as const ["attributes"]
).map((category) => category.attributes.short), ).map((category) => category.attributes.short),
}), }),
}; };
@ -437,7 +437,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk(); const sdk = getReadySdk();
const contents = await sdk.getContentsSlugs(); const contents = await sdk.getContentsSlugs();
const paths: GetStaticPathsResult["paths"] = []; const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(contents.contents?.data, ["attributes"] as const).map((item) => { filterHasAttributes(contents.contents?.data, ["attributes"]).map((item) => {
context.locales?.map((local) => { context.locales?.map((local) => {
paths.push({ paths.push({
params: { slug: item.attributes.slug }, params: { slug: item.attributes.slug },

View File

@ -220,7 +220,7 @@ const Contents = (props: Props): JSX.Element => {
href={`/contents/${item.slug}`} href={`/contents/${item.slug}`}
translations={filterHasAttributes(item._formatted.translations, [ translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map(({ displayable_description, language, ...otherAttributes }) => ({ ]).map(({ displayable_description, language, ...otherAttributes }) => ({
...otherAttributes, ...otherAttributes,
description: containsHighlight(displayable_description) description: containsHighlight(displayable_description)
? displayable_description ? displayable_description

View File

@ -69,7 +69,7 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen
href={`/contents/folder/${folder.parent_folder.data.attributes.slug}`} href={`/contents/folder/${folder.parent_folder.data.attributes.slug}`}
translations={filterHasAttributes(folder.parent_folder.data.attributes.titles, [ translations={filterHasAttributes(folder.parent_folder.data.attributes.titles, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map((title) => ({ ]).map((title) => ({
language: title.language.data.attributes.code, language: title.language.data.attributes.code,
text: title.title, text: title.title,
}))} }))}
@ -86,12 +86,12 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen
<Button href="/contents" icon="home" active /> <Button href="/contents" icon="home" active />
) : ( ) : (
<TranslatedButton <TranslatedButton
translations={filterHasAttributes(folder.titles, [ translations={filterHasAttributes(folder.titles, ["language.data.attributes.code"]).map(
"language.data.attributes.code", (title) => ({
] as const).map((title) => ({ language: title.language.data.attributes.code,
language: title.language.data.attributes.code, text: title.title,
text: title.title, })
}))} )}
fallback={{ fallback={{
text: prettySlug(folder.slug), text: prettySlug(folder.slug),
}} }}
@ -115,21 +115,19 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen
"grid-cols-2 gap-4" "grid-cols-2 gap-4"
) )
)}> )}>
{filterHasAttributes(folder.subfolders.data, ["id", "attributes"] as const).map( {filterHasAttributes(folder.subfolders.data, ["id", "attributes"]).map((subfolder) => (
(subfolder) => ( <TranslatedPreviewFolder
<TranslatedPreviewFolder key={subfolder.id}
key={subfolder.id} href={`/contents/folder/${subfolder.attributes.slug}`}
href={`/contents/folder/${subfolder.attributes.slug}`} translations={filterHasAttributes(subfolder.attributes.titles, [
translations={filterHasAttributes(subfolder.attributes.titles, [ "language.data.attributes.code",
"language.data.attributes.code", ]).map((title) => ({
] as const).map((title) => ({ title: title.title,
title: title.title, language: title.language.data.attributes.code,
language: title.language.data.attributes.code, }))}
}))} fallback={{ title: prettySlug(subfolder.attributes.slug) }}
fallback={{ title: prettySlug(subfolder.attributes.slug) }} />
/> ))}
)
)}
</div> </div>
</div> </div>
)} )}
@ -149,39 +147,37 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen
"grid-cols-2 gap-4" "grid-cols-2 gap-4"
) )
)}> )}>
{filterHasAttributes(folder.contents.data, ["id", "attributes"] as const).map( {filterHasAttributes(folder.contents.data, ["id", "attributes"]).map((item) => (
(item) => ( <TranslatedPreviewCard
<TranslatedPreviewCard key={item.id}
key={item.id} href={`/contents/${item.attributes.slug}`}
href={`/contents/${item.attributes.slug}`} translations={filterHasAttributes(item.attributes.translations, [
translations={filterHasAttributes(item.attributes.translations, [ "language.data.attributes.code",
"language.data.attributes.code", ]).map((translation) => ({
] as const).map((translation) => ({ pre_title: translation.pre_title,
pre_title: translation.pre_title, title: translation.title,
title: translation.title, subtitle: translation.subtitle,
subtitle: translation.subtitle, language: translation.language.data.attributes.code,
language: translation.language.data.attributes.code, }))}
}))} fallback={{ title: prettySlug(item.attributes.slug) }}
fallback={{ title: prettySlug(item.attributes.slug) }} thumbnail={item.attributes.thumbnail?.data?.attributes}
thumbnail={item.attributes.thumbnail?.data?.attributes} thumbnailAspectRatio="3/2"
thumbnailAspectRatio="3/2" thumbnailForceAspectRatio
thumbnailForceAspectRatio topChips={
topChips={ item.attributes.type?.data?.attributes
item.attributes.type?.data?.attributes ? [
? [ item.attributes.type.data.attributes.titles?.[0]
item.attributes.type.data.attributes.titles?.[0] ? item.attributes.type.data.attributes.titles[0]?.title
? item.attributes.type.data.attributes.titles[0]?.title : prettySlug(item.attributes.type.data.attributes.slug),
: prettySlug(item.attributes.type.data.attributes.slug), ]
] : undefined
: undefined }
} bottomChips={item.attributes.categories?.data.map(
bottomChips={item.attributes.categories?.data.map( (category) => category.attributes?.short ?? ""
(category) => category.attributes?.short ?? "" )}
)} keepInfoVisible
keepInfoVisible />
/> ))}
)
)}
</div> </div>
</div> </div>
)} )}
@ -262,7 +258,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk(); const sdk = getReadySdk();
const contents = await sdk.getContentsFoldersSlugs(); const contents = await sdk.getContentsFoldersSlugs();
const paths: GetStaticPathsResult["paths"] = []; const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(contents.contentsFolders?.data, ["attributes"] as const).map((item) => { filterHasAttributes(contents.contentsFolders?.data, ["attributes"]).map((item) => {
context.locales?.map((local) => { context.locales?.map((local) => {
paths.push({ paths.push({
params: { slug: item.attributes.slug }, params: { slug: item.attributes.slug },

View File

@ -105,7 +105,7 @@ const testingContent = (contents: Props["contents"]): Report => {
lines: [], lines: [],
}; };
filterHasAttributes(contents.contents?.data, ["attributes"] as const).map((content) => { filterHasAttributes(contents.contents?.data, ["attributes"]).map((content) => {
const backendUrl = sJoin( const backendUrl = sJoin(
process.env.NEXT_PUBLIC_URL_CMS, process.env.NEXT_PUBLIC_URL_CMS,
"/admin/content-manager/collectionType/api::content.content/", "/admin/content-manager/collectionType/api::content.content/",

View File

@ -230,7 +230,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
{item.urls?.length ? ( {item.urls?.length ? (
<div className="flex flex-row place-items-center gap-3"> <div className="flex flex-row place-items-center gap-3">
<p>{format("available_at")}</p> <p>{format("available_at")}</p>
{filterHasAttributes(item.urls, ["url"] as const).map((url, index) => ( {filterHasAttributes(item.urls, ["url"]).map((url, index) => (
<Fragment key={index}> <Fragment key={index}>
<Button href={url.url} text={prettyURL(url.url)} alwaysNewTab /> <Button href={url.url} text={prettyURL(url.url)} alwaysNewTab />
</Fragment> </Fragment>
@ -250,7 +250,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
<div <div
className="grid w-full grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))] items-end className="grid w-full grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))] items-end
gap-8"> gap-8">
{filterHasAttributes(item.gallery.data, ["id", "attributes"] as const).map( {filterHasAttributes(item.gallery.data, ["id", "attributes"]).map(
(galleryItem, index) => ( (galleryItem, index) => (
<Fragment key={galleryItem.id}> <Fragment key={galleryItem.id}>
<div <div
@ -258,7 +258,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
transition-transform hover:scale-102" transition-transform hover:scale-102"
onClick={() => { onClick={() => {
showLightBox( showLightBox(
filterHasAttributes(item.gallery?.data, ["attributes"] as const).map( filterHasAttributes(item.gallery?.data, ["attributes"]).map(
(image) => image.attributes (image) => image.attributes
), ),
index index
@ -329,11 +329,9 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
{format("category", { count: item.categories.data.length })} {format("category", { count: item.categories.data.length })}
</h3> </h3>
<div className="flex flex-row flex-wrap place-content-center gap-2"> <div className="flex flex-row flex-wrap place-content-center gap-2">
{filterHasAttributes(item.categories.data, ["attributes"] as const).map( {filterHasAttributes(item.categories.data, ["attributes"]).map((category) => (
(category) => ( <Chip key={category.id} text={category.attributes.name} />
<Chip key={category.id} text={category.attributes.name} /> ))}
)
)}
</div> </div>
</div> </div>
)} )}
@ -482,41 +480,39 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
<div <div
className="grid w-full grid-cols-[repeat(auto-fill,minmax(13rem,1fr))] className="grid w-full grid-cols-[repeat(auto-fill,minmax(13rem,1fr))]
items-end gap-8"> items-end gap-8">
{filterHasAttributes(item.subitems.data, ["id", "attributes"] as const).map( {filterHasAttributes(item.subitems.data, ["id", "attributes"]).map((subitem) => (
(subitem) => ( <Fragment key={subitem.id}>
<Fragment key={subitem.id}> <PreviewCard
<PreviewCard href={`/library/${subitem.attributes.slug}`}
href={`/library/${subitem.attributes.slug}`} title={subitem.attributes.title}
title={subitem.attributes.title} subtitle={subitem.attributes.subtitle}
subtitle={subitem.attributes.subtitle} thumbnail={subitem.attributes.thumbnail?.data?.attributes}
thumbnail={subitem.attributes.thumbnail?.data?.attributes} thumbnailAspectRatio="21/29.7"
thumbnailAspectRatio="21/29.7" thumbnailRounded={false}
thumbnailRounded={false} keepInfoVisible={keepInfoVisible}
keepInfoVisible={keepInfoVisible} topChips={
topChips={ subitem.attributes.metadata &&
subitem.attributes.metadata && subitem.attributes.metadata.length > 0 &&
subitem.attributes.metadata.length > 0 && subitem.attributes.metadata[0]
subitem.attributes.metadata[0] ? [prettyItemSubType(subitem.attributes.metadata[0])]
? [prettyItemSubType(subitem.attributes.metadata[0])] : []
: [] }
} bottomChips={subitem.attributes.categories?.data.map(
bottomChips={subitem.attributes.categories?.data.map( (category) => category.attributes?.short ?? ""
(category) => category.attributes?.short ?? "" )}
)} metadata={{
metadata={{ releaseDate: subitem.attributes.release_date,
releaseDate: subitem.attributes.release_date, price: subitem.attributes.price,
price: subitem.attributes.price, position: "Bottom",
position: "Bottom", }}
}} infoAppend={
infoAppend={ !isUntangibleGroupItem(subitem.attributes.metadata?.[0]) && (
!isUntangibleGroupItem(subitem.attributes.metadata?.[0]) && ( <PreviewCardCTAs id={subitem.id} />
<PreviewCardCTAs id={subitem.id} /> )
) }
} />
/> </Fragment>
</Fragment> ))}
)
)}
</div> </div>
</div> </div>
)} )}
@ -530,51 +526,49 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
</div> </div>
)} )}
<div className="max-w- grid w-full gap-4"> <div className="max-w- grid w-full gap-4">
{filterHasAttributes(item.contents.data, ["attributes"] as const).map( {filterHasAttributes(item.contents.data, ["attributes"]).map((rangedContent) => (
(rangedContent) => ( <ContentLine
<ContentLine content={
content={ rangedContent.attributes.content?.data?.attributes
rangedContent.attributes.content?.data?.attributes ? {
? { translations: filterDefined(
translations: filterDefined( rangedContent.attributes.content.data.attributes.translations
rangedContent.attributes.content.data.attributes.translations ).map((translation) => ({
).map((translation) => ({ pre_title: translation.pre_title,
pre_title: translation.pre_title, title: translation.title,
title: translation.title, subtitle: translation.subtitle,
subtitle: translation.subtitle, language: translation.language?.data?.attributes?.code,
language: translation.language?.data?.attributes?.code, })),
})), categories: filterHasAttributes(
categories: filterHasAttributes( rangedContent.attributes.content.data.attributes.categories?.data,
rangedContent.attributes.content.data.attributes.categories?.data, ["attributes"]
["attributes"] ).map((category) => category.attributes.short),
).map((category) => category.attributes.short), type:
type: rangedContent.attributes.content.data.attributes.type?.data?.attributes
?.titles?.[0]?.title ??
prettySlug(
rangedContent.attributes.content.data.attributes.type?.data rangedContent.attributes.content.data.attributes.type?.data
?.attributes?.titles?.[0]?.title ?? ?.attributes?.slug
prettySlug( ),
rangedContent.attributes.content.data.attributes.type?.data slug: rangedContent.attributes.content.data.attributes.slug,
?.attributes?.slug }
), : undefined
slug: rangedContent.attributes.content.data.attributes.slug, }
} rangeStart={
: undefined rangedContent.attributes.range[0]?.__typename === "ComponentRangePageRange"
} ? `${rangedContent.attributes.range[0].starting_page}`
rangeStart={ : ""
rangedContent.attributes.range[0]?.__typename === "ComponentRangePageRange" }
? `${rangedContent.attributes.range[0].starting_page}` slug={rangedContent.attributes.slug}
: "" parentSlug={item.slug}
} key={rangedContent.id}
slug={rangedContent.attributes.slug} hasScanSet={
parentSlug={item.slug} isDefined(rangedContent.attributes.scan_set) &&
key={rangedContent.id} rangedContent.attributes.scan_set.length > 0
hasScanSet={ }
isDefined(rangedContent.attributes.scan_set) && condensed={!isContentPanelAtLeast3xl}
rangedContent.attributes.scan_set.length > 0 />
} ))}
condensed={!isContentPanelAtLeast3xl}
/>
)
)}
</div> </div>
</div> </div>
)} )}
@ -637,7 +631,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk(); const sdk = getReadySdk();
const libraryItems = await sdk.getLibraryItemsSlugs(); const libraryItems = await sdk.getLibraryItemsSlugs();
const paths: GetStaticPathsResult["paths"] = []; const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(libraryItems.libraryItems?.data, ["attributes"] as const).map((item) => { filterHasAttributes(libraryItems.libraryItems?.data, ["attributes"]).map((item) => {
context.locales?.map((local) => context.locales?.map((local) =>
paths.push({ params: { slug: item.attributes.slug }, locale: local }) paths.push({ params: { slug: item.attributes.slug }, locale: local })
); );

View File

@ -537,7 +537,7 @@ const LibrarySlug = ({
id={content.attributes.slug} id={content.attributes.slug}
translations={filterHasAttributes( translations={filterHasAttributes(
content.attributes.content?.data?.attributes?.translations, content.attributes.content?.data?.attributes?.translations,
["language.data.attributes"] as const ["language.data.attributes"]
).map((translation) => ({ ).map((translation) => ({
language: translation.language.data.attributes.code, language: translation.language.data.attributes.code,
title: prettyInlineTitle( title: prettyInlineTitle(
@ -596,9 +596,9 @@ export const getStaticProps: GetStaticProps = async (context) => {
filterHasAttributes(item.libraryItems.data[0].attributes.contents?.data, [ filterHasAttributes(item.libraryItems.data[0].attributes.contents?.data, [
"attributes.scan_set", "attributes.scan_set",
] as const).forEach((content) => ]).forEach((content) =>
filterHasAttributes(content.attributes.scan_set, ["pages.data"] as const).forEach((scanSet) => filterHasAttributes(content.attributes.scan_set, ["pages.data"]).forEach((scanSet) =>
filterHasAttributes(scanSet.pages.data, ["attributes"] as const) filterHasAttributes(scanSet.pages.data, ["attributes"])
.sort((a, b) => { .sort((a, b) => {
if (isDefinedAndNotEmpty(a.attributes.url) && isDefinedAndNotEmpty(b.attributes.url)) { if (isDefinedAndNotEmpty(a.attributes.url) && isDefinedAndNotEmpty(b.attributes.url)) {
let aName = getAssetFilename(a.attributes.url); let aName = getAssetFilename(a.attributes.url);
@ -675,7 +675,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk(); const sdk = getReadySdk();
const libraryItems = await sdk.getLibraryItemsSlugs({}); const libraryItems = await sdk.getLibraryItemsSlugs({});
const paths: GetStaticPathsResult["paths"] = []; const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(libraryItems.libraryItems?.data, ["attributes"] as const).map((item) => { filterHasAttributes(libraryItems.libraryItems?.data, ["attributes"]).map((item) => {
context.locales?.map((local) => context.locales?.map((local) =>
paths.push({ params: { slug: item.attributes.slug }, locale: local }) paths.push({ params: { slug: item.attributes.slug }, locale: local })
); );
@ -874,14 +874,13 @@ const ScanSet = ({ onClickOnImage, scanSet, id, title, content }: ScanSetProps):
<div> <div>
<p className="font-headers font-bold">{format("scanners")}:</p> <p className="font-headers font-bold">{format("scanners")}:</p>
<div className="grid place-content-center place-items-center gap-2"> <div className="grid place-content-center place-items-center gap-2">
{filterHasAttributes(selectedScan.scanners.data, [ {filterHasAttributes(selectedScan.scanners.data, ["id", "attributes"]).map(
"id", (scanner) => (
"attributes", <Fragment key={scanner.id}>
] as const).map((scanner) => ( <RecorderChip recorder={scanner.attributes} />
<Fragment key={scanner.id}> </Fragment>
<RecorderChip recorder={scanner.attributes} /> )
</Fragment> )}
))}
</div> </div>
</div> </div>
)} )}
@ -890,14 +889,13 @@ const ScanSet = ({ onClickOnImage, scanSet, id, title, content }: ScanSetProps):
<div> <div>
<p className="font-headers font-bold">{format("cleaners")}:</p> <p className="font-headers font-bold">{format("cleaners")}:</p>
<div className="grid place-content-center place-items-center gap-2"> <div className="grid place-content-center place-items-center gap-2">
{filterHasAttributes(selectedScan.cleaners.data, [ {filterHasAttributes(selectedScan.cleaners.data, ["id", "attributes"]).map(
"id", (cleaner) => (
"attributes", <Fragment key={cleaner.id}>
] as const).map((cleaner) => ( <RecorderChip recorder={cleaner.attributes} />
<Fragment key={cleaner.id}> </Fragment>
<RecorderChip recorder={cleaner.attributes} /> )
</Fragment> )}
))}
</div> </div>
</div> </div>
)} )}
@ -906,14 +904,13 @@ const ScanSet = ({ onClickOnImage, scanSet, id, title, content }: ScanSetProps):
<div> <div>
<p className="font-headers font-bold">{format("typesetters")}:</p> <p className="font-headers font-bold">{format("typesetters")}:</p>
<div className="grid place-content-center place-items-center gap-2"> <div className="grid place-content-center place-items-center gap-2">
{filterHasAttributes(selectedScan.typesetters.data, [ {filterHasAttributes(selectedScan.typesetters.data, ["id", "attributes"]).map(
"id", (typesetter) => (
"attributes", <Fragment key={typesetter.id}>
] as const).map((typesetter) => ( <RecorderChip recorder={typesetter.attributes} />
<Fragment key={typesetter.id}> </Fragment>
<RecorderChip recorder={typesetter.attributes} /> )
</Fragment> )}
))}
</div> </div>
</div> </div>
)} )}

View File

@ -408,7 +408,7 @@ const Library = (props: Props): JSX.Element => {
href={`/library/${item.slug}`} href={`/library/${item.slug}`}
translations={filterHasAttributes(item._formatted.descriptions, [ translations={filterHasAttributes(item._formatted.descriptions, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map((translation) => ({ ]).map((translation) => ({
language: translation.language.data.attributes.code, language: translation.language.data.attributes.code,
title: item.title, title: item.title,
subtitle: item.subtitle, subtitle: item.subtitle,

View File

@ -65,7 +65,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const posts = await sdk.getPostsSlugs(); const posts = await sdk.getPostsSlugs();
const paths: GetStaticPathsResult["paths"] = []; const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(posts.posts?.data, ["attributes"] as const).map((item) => { filterHasAttributes(posts.posts?.data, ["attributes"]).map((item) => {
context.locales?.map((local) => context.locales?.map((local) =>
paths.push({ params: { slug: item.attributes.slug }, locale: local }) paths.push({ params: { slug: item.attributes.slug }, locale: local })
); );
@ -80,7 +80,7 @@ const terminalPostPage = (post: PostWithTranslations, router: NextRouter): strin
let result = ""; let result = "";
if (router.locales && router.locale) { if (router.locales && router.locale) {
const selectedTranslation = staticSmartLanguage({ const selectedTranslation = staticSmartLanguage({
items: filterHasAttributes(post.translations, ["language.data.attributes.code"] as const), items: filterHasAttributes(post.translations, ["language.data.attributes.code"]),
languageExtractor: (item) => item.language.data.attributes.code, languageExtractor: (item) => item.language.data.attributes.code,
preferredLanguages: getDefaultPreferredLanguages(router.locale, router.locales), preferredLanguages: getDefaultPreferredLanguages(router.locale, router.locales),
}); });

View File

@ -176,7 +176,7 @@ const News = ({ ...otherProps }: Props): JSX.Element => {
href={`/news/${item.slug}`} href={`/news/${item.slug}`}
translations={filterHasAttributes(item._formatted.translations, [ translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map(({ excerpt, body, language, ...otherAttributes }) => ({ ]).map(({ excerpt, body, language, ...otherAttributes }) => ({
...otherAttributes, ...otherAttributes,
description: containsHighlight(excerpt) description: containsHighlight(excerpt)
? excerpt ? excerpt

View File

@ -125,11 +125,9 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
</p> </p>
<div className="flex flex-row flex-wrap place-content-center gap-2"> <div className="flex flex-row flex-wrap place-content-center gap-2">
{filterHasAttributes(page.categories.data, ["attributes"] as const).map( {filterHasAttributes(page.categories.data, ["attributes"]).map((category) => (
(category) => ( <Chip key={category.id} text={category.attributes.name} />
<Chip key={category.id} text={category.attributes.name} /> ))}
)
)}
</div> </div>
</> </>
)} )}
@ -138,7 +136,7 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
<> <>
<p className="font-headers text-xl font-bold">{format("tags")}</p> <p className="font-headers text-xl font-bold">{format("tags")}</p>
<div className="flex flex-row flex-wrap place-content-center gap-2"> <div className="flex flex-row flex-wrap place-content-center gap-2">
{filterHasAttributes(page.tags.data, ["attributes"] as const).map((tag) => ( {filterHasAttributes(page.tags.data, ["attributes"]).map((tag) => (
<Chip <Chip
key={tag.id} key={tag.id}
text={ text={
@ -159,36 +157,34 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
</div> </div>
)} )}
{filterHasAttributes(page.definitions, ["translations"] as const).map( {filterHasAttributes(page.definitions, ["translations"]).map((definition, index) => (
(definition, index) => ( <div key={index} className="mb-12">
<div key={index} className="mb-12"> <DefinitionCard
<DefinitionCard source={{
source={{ name: definition.source?.data?.attributes?.name,
name: definition.source?.data?.attributes?.name, url: definition.source?.data?.attributes?.content?.data?.attributes?.slug
url: definition.source?.data?.attributes?.content?.data?.attributes?.slug ? sJoin(
? sJoin( "/contents/",
"/contents/", definition.source.data.attributes.content.data.attributes.slug
definition.source.data.attributes.content.data.attributes.slug )
) : sJoin(
: sJoin( "/library/",
"/library/", definition.source?.data?.attributes?.ranged_content?.data?.attributes
definition.source?.data?.attributes?.ranged_content?.data?.attributes ?.library_item?.data?.attributes?.slug
?.library_item?.data?.attributes?.slug ),
), }}
}} translations={definition.translations.map((translation) => ({
translations={definition.translations.map((translation) => ({ language: translation?.language?.data?.attributes?.code,
language: translation?.language?.data?.attributes?.code, definition: translation?.definition,
definition: translation?.definition, status: translation?.status,
status: translation?.status, }))}
}))} index={index + 1}
index={index + 1} categories={filterHasAttributes(definition.categories?.data, ["attributes"]).map(
categories={filterHasAttributes(definition.categories?.data, [ (category) => category.attributes.short
"attributes", )}
] as const).map((category) => category.attributes.short)} />
/> </div>
</div> ))}
)
)}
{isDefined(selectedTranslation.body) && ( {isDefined(selectedTranslation.body) && (
<div> <div>
@ -218,13 +214,13 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
: "" : ""
}${ }${
page.definitions && page.definitions.length > 0 page.definitions && page.definitions.length > 0
? `${filterHasAttributes(page.definitions, ["translations"] as const).map( ? `${filterHasAttributes(page.definitions, ["translations"]).map(
(definition, index) => (definition, index) =>
`${prettyTerminalUnderlinedTitle(format("definition_x", { x: index + 1 }))}${ `${prettyTerminalUnderlinedTitle(format("definition_x", { x: index + 1 }))}${
staticSmartLanguage({ staticSmartLanguage({
items: filterHasAttributes(definition.translations, [ items: filterHasAttributes(definition.translations, [
"language.data.attributes.code", "language.data.attributes.code",
] as const), ]),
languageExtractor: (item) => item.language.data.attributes.code, languageExtractor: (item) => item.language.data.attributes.code,
preferredLanguages: getDefaultPreferredLanguages( preferredLanguages: getDefaultPreferredLanguages(
router.locale ?? "en", router.locale ?? "en",
@ -267,12 +263,10 @@ export const getStaticProps: GetStaticProps = async (context) => {
const chipsGroups = { const chipsGroups = {
[format("tags")]: filterHasAttributes(page.wikiPages.data[0].attributes.tags?.data, [ [format("tags")]: filterHasAttributes(page.wikiPages.data[0].attributes.tags?.data, [
"attributes", "attributes",
] as const).map( ]).map((tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug)),
(tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug)
),
[format("category", { count: Infinity })]: filterHasAttributes( [format("category", { count: Infinity })]: filterHasAttributes(
page.wikiPages.data[0].attributes.categories?.data, page.wikiPages.data[0].attributes.categories?.data,
["attributes"] as const ["attributes"]
).map((category) => category.attributes.short), ).map((category) => category.attributes.short),
}; };
@ -313,7 +307,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk(); const sdk = getReadySdk();
const contents = await sdk.getWikiPagesSlugs(); const contents = await sdk.getWikiPagesSlugs();
const paths: GetStaticPathsResult["paths"] = []; const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(contents.wikiPages?.data, ["attributes"] as const).map((wikiPage) => { filterHasAttributes(contents.wikiPages?.data, ["attributes"]).map((wikiPage) => {
context.locales?.map((local) => context.locales?.map((local) =>
paths.push({ paths.push({
params: { slug: wikiPage.attributes.slug }, params: { slug: wikiPage.attributes.slug },

View File

@ -45,10 +45,7 @@ const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props):
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 ids = useMemo( const ids = useMemo(
() => () => filterHasAttributes(chronologyEras, ["attributes"]).map((era) => era.attributes.slug),
filterHasAttributes(chronologyEras, ["attributes"] as const).map(
(era) => era.attributes.slug
),
[chronologyEras] [chronologyEras]
); );
@ -60,12 +57,12 @@ const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props):
<HorizontalLine /> <HorizontalLine />
{filterHasAttributes(chronologyEras, ["attributes", "id"] as const).map((era, index) => ( {filterHasAttributes(chronologyEras, ["attributes", "id"]).map((era, index) => (
<Fragment key={era.id}> <Fragment key={era.id}>
<TranslatedNavOption <TranslatedNavOption
translations={filterHasAttributes(era.attributes.title, [ translations={filterHasAttributes(era.attributes.title, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map((translation) => ({ ]).map((translation) => ({
language: translation.language.data.attributes.code, language: translation.language.data.attributes.code,
title: translation.title, title: translation.title,
subtitle: `${era.attributes.starting_year}${era.attributes.ending_year}`, subtitle: `${era.attributes.starting_year}${era.attributes.ending_year}`,
@ -93,19 +90,19 @@ const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props):
className="mb-10" className="mb-10"
/> />
{filterHasAttributes(chronologyEras, ["attributes"] as const).map((era) => ( {filterHasAttributes(chronologyEras, ["attributes"]).map((era) => (
<TranslatedChronologyEra <TranslatedChronologyEra
key={era.attributes.slug} key={era.attributes.slug}
id={era.attributes.slug} id={era.attributes.slug}
translations={filterHasAttributes(era.attributes.title, [ translations={filterHasAttributes(era.attributes.title, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map((translation) => ({ ]).map((translation) => ({
language: translation.language.data.attributes.code, language: translation.language.data.attributes.code,
title: translation.title, title: translation.title,
description: translation.description, description: translation.description,
}))} }))}
fallback={{ title: prettySlug(era.attributes.slug) }} fallback={{ title: prettySlug(era.attributes.slug) }}
chronologyItems={filterHasAttributes(chronologyItems, ["attributes"] as const).filter( chronologyItems={filterHasAttributes(chronologyItems, ["attributes"]).filter(
(item) => (item) =>
item.attributes.year >= era.attributes.starting_year && item.attributes.year >= era.attributes.starting_year &&
item.attributes.year < era.attributes.ending_year item.attributes.year < era.attributes.ending_year
@ -157,7 +154,7 @@ const ChronologyEra = ({ id, title, description, chronologyItems }: ChronologyEr
const yearGroups = (() => { const yearGroups = (() => {
const memo: Props["chronologyItems"][] = []; const memo: Props["chronologyItems"][] = [];
let currentYear = -Infinity; let currentYear = -Infinity;
filterHasAttributes(chronologyItems, ["attributes"] as const).forEach((item) => { filterHasAttributes(chronologyItems, ["attributes"]).forEach((item) => {
if (currentYear === item.attributes.year) { if (currentYear === item.attributes.year) {
memo[memo.length - 1]?.push(item); memo[memo.length - 1]?.push(item);
} else { } else {
@ -218,7 +215,7 @@ const ChronologyYear = ({ items }: ChronologyYearProps) => (
<div <div
className="rounded-2xl target:my-4 target:bg-mid target:py-4" className="rounded-2xl target:my-4 target:bg-mid target:py-4"
id={generateAnchor(items[0]?.attributes?.year)}> id={generateAnchor(items[0]?.attributes?.year)}>
{filterHasAttributes(items, ["attributes.events"] as const).map((item, index) => ( {filterHasAttributes(items, ["attributes.events"]).map((item, index) => (
<ChronologyDate <ChronologyDate
key={index} key={index}
date={{ date={{
@ -284,7 +281,7 @@ export const ChronologyDate = ({ date, events }: ChronologyDateProps): JSX.Eleme
</p> </p>
<div className="col-start-2 row-span-2 row-start-1 grid gap-4"> <div className="col-start-2 row-span-2 row-start-1 grid gap-4">
{filterHasAttributes(events, ["id", "translations"] as const).map((event) => ( {filterHasAttributes(events, ["id", "translations"]).map((event) => (
<ChronologyEvent <ChronologyEvent
id={generateAnchor(date.year, date.month, date.day)} id={generateAnchor(date.year, date.month, date.day)}
key={event.id} key={event.id}

View File

@ -182,7 +182,7 @@ const Wiki = (props: Props): JSX.Element => {
href={`/wiki/${item.slug}`} href={`/wiki/${item.slug}`}
translations={filterHasAttributes(item._formatted.translations, [ translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map( ]).map(
({ aliases, summary, displayable_description, language, ...otherAttributes }) => ({ ({ aliases, summary, displayable_description, language, ...otherAttributes }) => ({
...otherAttributes, ...otherAttributes,
subtitle: subtitle:
@ -201,10 +201,10 @@ const Wiki = (props: Props): JSX.Element => {
thumbnailRounded thumbnailRounded
thumbnailForceAspectRatio thumbnailForceAspectRatio
keepInfoVisible keepInfoVisible
topChips={filterHasAttributes(item.tags?.data, ["attributes"] as const).map( topChips={filterHasAttributes(item.tags?.data, ["attributes"]).map(
(tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug) (tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug)
)} )}
bottomChips={filterHasAttributes(item.categories?.data, ["attributes"] as const).map( bottomChips={filterHasAttributes(item.categories?.data, ["attributes"]).map(
(category) => category.attributes.short (category) => category.attributes.short
)} )}
/> />

View File

@ -43,7 +43,7 @@ interface WeaponPreviewProps {
const WeaponPreview = ({ weapon }: WeaponPreviewProps): JSX.Element => ( const WeaponPreview = ({ weapon }: WeaponPreviewProps): JSX.Element => (
<TranslatedPreviewCard <TranslatedPreviewCard
href={`/wiki/weapons/${weapon.slug}`} href={`/wiki/weapons/${weapon.slug}`}
translations={filterHasAttributes(weapon.name, ["language.data.attributes.code"] as const).map( translations={filterHasAttributes(weapon.name, ["language.data.attributes.code"]).map(
({ name, language }) => ({ ({ name, language }) => ({
language: language.data.attributes.code, language: language.data.attributes.code,
title: name, title: name,
@ -111,7 +111,7 @@ const WeaponPage = ({ weapon, primaryName, aliases, ...otherProps }: Props): JSX
<div className="grid gap-8"> <div className="grid gap-8">
{filterHasAttributes(weapon.weapon_group.data.attributes.weapons.data, [ {filterHasAttributes(weapon.weapon_group.data.attributes.weapons.data, [
"attributes", "attributes",
] as const).map((groupWeapon) => ( ]).map((groupWeapon) => (
<WeaponPreview key={groupWeapon.id} weapon={groupWeapon.attributes} /> <WeaponPreview key={groupWeapon.id} weapon={groupWeapon.attributes} />
))} ))}
</div> </div>
@ -140,7 +140,7 @@ const WeaponPage = ({ weapon, primaryName, aliases, ...otherProps }: Props): JSX
<div className="grid gap-8"> <div className="grid gap-8">
<ElementsSeparator> <ElementsSeparator>
{filterHasAttributes(weapon.stories, ["translations"] as const).map((story, index) => ( {filterHasAttributes(weapon.stories, ["translations"]).map((story, index) => (
<WeaponStory <WeaponStory
key={story.id} key={story.id}
id={intersectionIds[index]} id={intersectionIds[index]}
@ -201,7 +201,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk(); const sdk = getReadySdk();
const weapons = await sdk.getWeaponsSlugs(); const weapons = await sdk.getWeaponsSlugs();
const paths: GetStaticPathsResult["paths"] = []; const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(weapons.weaponStories?.data, ["attributes"] as const).map((item) => { filterHasAttributes(weapons.weaponStories?.data, ["attributes"]).map((item) => {
context.locales?.map((local) => { context.locales?.map((local) => {
paths.push({ paths.push({
params: { slug: item.attributes.slug }, params: { slug: item.attributes.slug },
@ -247,11 +247,9 @@ const WeaponStory = ({ story, storyNumber, id }: WeaponStoryProps): JSX.Element
{story.categories && story.categories.data.length > 0 && ( {story.categories && story.categories.data.length > 0 && (
<div className="mb-12 flex flex-row flex-wrap place-content-center gap-2"> <div className="mb-12 flex flex-row flex-wrap place-content-center gap-2">
{filterHasAttributes(story.categories.data, ["attributes.name"] as const).map( {filterHasAttributes(story.categories.data, ["attributes.name"]).map((category) => (
(category) => ( <Chip key={category.id} text={category.attributes.name} />
<Chip key={category.id} text={category.attributes.name} /> ))}
)
)}
</div> </div>
)} )}
@ -286,7 +284,7 @@ export const getFilteredNames = (
preferredLanguages: string[] preferredLanguages: string[]
): string[] => { ): string[] => {
for (const language of preferredLanguages) { for (const language of preferredLanguages) {
const filteredNames = filterHasAttributes(names, ["name"] as const).filter( const filteredNames = filterHasAttributes(names, ["name"]).filter(
(name) => name.language?.data?.attributes?.code === language (name) => name.language?.data?.attributes?.code === language
); );
if (filteredNames.length > 0) { if (filteredNames.length > 0) {

View File

@ -186,7 +186,7 @@ const Weapons = (props: Props): JSX.Element => {
href={`/wiki/weapons/${item.slug}`} href={`/wiki/weapons/${item.slug}`}
translations={filterHasAttributes(item._formatted.translations, [ translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map(({ description, language, names: [primaryName, ...aliases] }) => ({ ]).map(({ description, language, names: [primaryName, ...aliases] }) => ({
language: language.data.attributes.code, language: language.data.attributes.code,
title: primaryName, title: primaryName,
subtitle: aliases.join("・"), subtitle: aliases.join("・"),
@ -203,7 +203,7 @@ const Weapons = (props: Props): JSX.Element => {
? [prettySlug(item.type.data.attributes.slug)] ? [prettySlug(item.type.data.attributes.slug)]
: undefined : undefined
} }
bottomChips={filterHasAttributes(item.categories, ["attributes.short"] as const).map( bottomChips={filterHasAttributes(item.categories, ["attributes.short"]).map(
(category) => category.attributes.short (category) => category.attributes.short
)} )}
/> />