Typescript updated to 5.0, removed pesky as const
This commit is contained in:
		
							parent
							
								
									bfb753bf21
								
							
						
					
					
						commit
						b6882cd1e5
					
				
							
								
								
									
										30
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										30
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -59,13 +59,13 @@ | ||||
|         "eslint-config-next": "13.2.4", | ||||
|         "eslint-plugin-import": "^2.27.5", | ||||
|         "graphql": "^16.6.0", | ||||
|         "graphql-request": "5.2.0", | ||||
|         "graphql-request": "5.1.0", | ||||
|         "next-sitemap": "^4.0.6", | ||||
|         "prettier": "^2.8.4", | ||||
|         "prettier-plugin-tailwindcss": "^0.2.5", | ||||
|         "tailwindcss": "^3.2.7", | ||||
|         "ts-unused-exports": "^9.0.4", | ||||
|         "typescript": "^4.9.5" | ||||
|         "typescript": "^5.0.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@ampproject/remapping": { | ||||
| @ -6797,9 +6797,9 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/graphql-request": { | ||||
|       "version": "5.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-5.2.0.tgz", | ||||
|       "integrity": "sha512-pLhKIvnMyBERL0dtFI3medKqWOz/RhHdcgbZ+hMMIb32mEPa5MJSzS4AuXxfI4sRAu6JVVk5tvXuGfCWl9JYWQ==", | ||||
|       "version": "5.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-5.1.0.tgz", | ||||
|       "integrity": "sha512-0OeRVYigVwIiXhNmqnPDt+JhMzsjinxHE7TVy3Lm6jUzav0guVcL0lfSbi6jVTRAxcbwgyr6yrZioSHxf9gHzw==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@graphql-typed-document-node/core": "^3.1.1", | ||||
| @ -10261,16 +10261,16 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/typescript": { | ||||
|       "version": "4.9.5", | ||||
|       "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", | ||||
|       "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", | ||||
|       "version": "5.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", | ||||
|       "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", | ||||
|       "dev": true, | ||||
|       "bin": { | ||||
|         "tsc": "bin/tsc", | ||||
|         "tsserver": "bin/tsserver" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=4.2.0" | ||||
|         "node": ">=12.20" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/ua-parser-js": { | ||||
| @ -16008,9 +16008,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "graphql-request": { | ||||
|       "version": "5.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-5.2.0.tgz", | ||||
|       "integrity": "sha512-pLhKIvnMyBERL0dtFI3medKqWOz/RhHdcgbZ+hMMIb32mEPa5MJSzS4AuXxfI4sRAu6JVVk5tvXuGfCWl9JYWQ==", | ||||
|       "version": "5.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-5.1.0.tgz", | ||||
|       "integrity": "sha512-0OeRVYigVwIiXhNmqnPDt+JhMzsjinxHE7TVy3Lm6jUzav0guVcL0lfSbi6jVTRAxcbwgyr6yrZioSHxf9gHzw==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@graphql-typed-document-node/core": "^3.1.1", | ||||
| @ -18487,9 +18487,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "typescript": { | ||||
|       "version": "4.9.5", | ||||
|       "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", | ||||
|       "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", | ||||
|       "version": "5.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", | ||||
|       "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "ua-parser-js": { | ||||
|  | ||||
| @ -71,13 +71,13 @@ | ||||
|     "eslint-config-next": "13.2.4", | ||||
|     "eslint-plugin-import": "^2.27.5", | ||||
|     "graphql": "^16.6.0", | ||||
|     "graphql-request": "5.2.0", | ||||
|     "graphql-request": "5.1.0", | ||||
|     "next-sitemap": "^4.0.6", | ||||
|     "prettier": "^2.8.4", | ||||
|     "prettier-plugin-tailwindcss": "^0.2.5", | ||||
|     "tailwindcss": "^3.2.7", | ||||
|     "ts-unused-exports": "^9.0.4", | ||||
|     "typescript": "^4.9.5" | ||||
|     "typescript": "^5.0.2" | ||||
|   }, | ||||
|   "overrides": { | ||||
|     "react-zoom-pan-pinch": { | ||||
|  | ||||
| @ -45,10 +45,7 @@ const ChroniclesList = ({ chronicles, currentSlug, title }: Props): JSX.Element | ||||
|       <div | ||||
|         className="grid gap-4 overflow-hidden transition-height duration-500" | ||||
|         style={{ maxHeight: isOpen ? `${8 * chronicles.length}rem` : 0 }}> | ||||
|         {filterHasAttributes(chronicles, [ | ||||
|           "attributes.contents", | ||||
|           "attributes.translations", | ||||
|         ] as const) | ||||
|         {filterHasAttributes(chronicles, ["attributes.contents", "attributes.translations"]) | ||||
|           .sort((a, b) => compareDate(a.attributes.date_start, b.attributes.date_start)) | ||||
|           .map((chronicle) => ( | ||||
|             <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 | ||||
|                 ? filterHasAttributes(chronicle.attributes.contents.data, [ | ||||
|                     "attributes.translations", | ||||
|                   ] as const).map((content, index) => ( | ||||
|                   ]).map((content, index) => ( | ||||
|                     <TranslatedChroniclePreview | ||||
|                       key={index} | ||||
|                       active={chronicle.attributes.slug === currentSlug} | ||||
|                       date={chronicle.attributes.date_start} | ||||
|                       translations={filterHasAttributes(content.attributes.translations, [ | ||||
|                         "language.data.attributes.code", | ||||
|                       ] as const).map((translation) => ({ | ||||
|                       ]).map((translation) => ({ | ||||
|                         title: prettyInlineTitle( | ||||
|                           translation.pre_title, | ||||
|                           translation.title, | ||||
| @ -90,7 +87,7 @@ const ChroniclesList = ({ chronicles, currentSlug, title }: Props): JSX.Element | ||||
|                       translations={filterHasAttributes(chronicle.attributes.translations, [ | ||||
|                         "language.data.attributes.code", | ||||
|                         "title", | ||||
|                       ] as const).map((translation) => ({ | ||||
|                       ]).map((translation) => ({ | ||||
|                         title: translation.title, | ||||
|                         language: translation.language.data.attributes.code, | ||||
|                       }))} | ||||
|  | ||||
| @ -223,7 +223,7 @@ export const SearchPopup = (): JSX.Element => { | ||||
|                   onClick={() => setSearchOpened(false)} | ||||
|                   translations={filterHasAttributes(item._formatted.descriptions, [ | ||||
|                     "language.data.attributes.code", | ||||
|                   ] as const).map((translation) => ({ | ||||
|                   ]).map((translation) => ({ | ||||
|                     language: translation.language.data.attributes.code, | ||||
|                     title: item.title, | ||||
|                     subtitle: item.subtitle, | ||||
| @ -270,7 +270,7 @@ export const SearchPopup = (): JSX.Element => { | ||||
|                   onClick={() => setSearchOpened(false)} | ||||
|                   translations={filterHasAttributes(item._formatted.translations, [ | ||||
|                     "language.data.attributes.code", | ||||
|                   ] as const).map(({ displayable_description, language, ...otherAttributes }) => ({ | ||||
|                   ]).map(({ displayable_description, language, ...otherAttributes }) => ({ | ||||
|                     ...otherAttributes, | ||||
|                     description: containsHighlight(displayable_description) | ||||
|                       ? displayable_description | ||||
| @ -315,7 +315,7 @@ export const SearchPopup = (): JSX.Element => { | ||||
|                   onClick={() => setSearchOpened(false)} | ||||
|                   translations={filterHasAttributes(item._formatted.translations, [ | ||||
|                     "language.data.attributes.code", | ||||
|                   ] as const).map( | ||||
|                   ]).map( | ||||
|                     ({ | ||||
|                       aliases, | ||||
|                       summary, | ||||
| @ -340,12 +340,12 @@ export const SearchPopup = (): JSX.Element => { | ||||
|                   thumbnailRounded | ||||
|                   thumbnailForceAspectRatio | ||||
|                   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) | ||||
|                   )} | ||||
|                   bottomChips={filterHasAttributes(item.categories?.data, [ | ||||
|                     "attributes", | ||||
|                   ] as const).map((category) => category.attributes.short)} | ||||
|                   bottomChips={filterHasAttributes(item.categories?.data, ["attributes"]).map( | ||||
|                     (category) => category.attributes.short | ||||
|                   )} | ||||
|                 /> | ||||
|               ))} | ||||
|             </div> | ||||
| @ -367,7 +367,7 @@ export const SearchPopup = (): JSX.Element => { | ||||
|                   onClick={() => setSearchOpened(false)} | ||||
|                   translations={filterHasAttributes(item._formatted.translations, [ | ||||
|                     "language.data.attributes.code", | ||||
|                   ] as const).map(({ excerpt, body, language, ...otherAttributes }) => ({ | ||||
|                   ]).map(({ excerpt, body, language, ...otherAttributes }) => ({ | ||||
|                     ...otherAttributes, | ||||
|                     description: containsHighlight(excerpt) | ||||
|                       ? excerpt | ||||
| @ -449,14 +449,12 @@ export const SearchPopup = (): JSX.Element => { | ||||
|                   href={"/"} | ||||
|                   translations={filterHasAttributes(item._formatted.translations, [ | ||||
|                     "language.data.attributes.code", | ||||
|                   ] as const).map( | ||||
|                     ({ description, language, names: [primaryName, ...aliases] }) => ({ | ||||
|                       language: language.data.attributes.code, | ||||
|                       title: primaryName, | ||||
|                       subtitle: aliases.join("・"), | ||||
|                       description: containsHighlight(description) ? description : undefined, | ||||
|                     }) | ||||
|                   )} | ||||
|                   ]).map(({ description, language, names: [primaryName, ...aliases] }) => ({ | ||||
|                     language: language.data.attributes.code, | ||||
|                     title: primaryName, | ||||
|                     subtitle: aliases.join("・"), | ||||
|                     description: containsHighlight(description) ? description : undefined, | ||||
|                   }))} | ||||
|                   fallback={{ title: prettySlug(item.slug) }} | ||||
|                   thumbnail={item.thumbnail?.data?.attributes} | ||||
|                   thumbnailAspectRatio="1/1" | ||||
| @ -468,9 +466,9 @@ export const SearchPopup = (): JSX.Element => { | ||||
|                       ? [prettySlug(item.type.data.attributes.slug)] | ||||
|                       : undefined | ||||
|                   } | ||||
|                   bottomChips={filterHasAttributes(item.categories, [ | ||||
|                     "attributes.short", | ||||
|                   ] as const).map((category) => category.attributes.short)} | ||||
|                   bottomChips={filterHasAttributes(item.categories, ["attributes.short"]).map( | ||||
|                     (category) => category.attributes.short | ||||
|                   )} | ||||
|                 /> | ||||
|               ))} | ||||
|             </div> | ||||
|  | ||||
| @ -41,7 +41,7 @@ export const SettingsPopup = (): JSX.Element => { | ||||
| 
 | ||||
|   const router = useRouter(); | ||||
| 
 | ||||
|   const currencyOptions = filterHasAttributes(currencies, ["attributes"] as const).map( | ||||
|   const currencyOptions = filterHasAttributes(currencies, ["attributes"]).map( | ||||
|     (currentCurrency) => currentCurrency.attributes.code | ||||
|   ); | ||||
| 
 | ||||
|  | ||||
| @ -94,13 +94,11 @@ export const PostPage = ({ | ||||
|           <div> | ||||
|             <p className="font-headers font-bold">{"Authors"}:</p> | ||||
|             <div className="grid place-content-center place-items-center gap-2"> | ||||
|               {filterHasAttributes(post.authors.data, ["id", "attributes"] as const).map( | ||||
|                 (author) => ( | ||||
|                   <Fragment key={author.id}> | ||||
|                     <RecorderChip recorder={author.attributes} /> | ||||
|                   </Fragment> | ||||
|                 ) | ||||
|               )} | ||||
|               {filterHasAttributes(post.authors.data, ["id", "attributes"]).map((author) => ( | ||||
|                 <Fragment key={author.id}> | ||||
|                   <RecorderChip recorder={author.attributes} /> | ||||
|                 </Fragment> | ||||
|               ))} | ||||
|             </div> | ||||
|           </div> | ||||
|         )} | ||||
|  | ||||
| @ -40,13 +40,11 @@ export const RecorderChip = ({ recorder }: Props): JSX.Element => { | ||||
|               {recorder.languages?.data && recorder.languages.data.length > 0 && ( | ||||
|                 <div className="flex flex-row flex-wrap gap-1"> | ||||
|                   <p>{format("language", { count: recorder.languages.data.length })}:</p> | ||||
|                   {filterHasAttributes(recorder.languages.data, ["attributes"] as const).map( | ||||
|                     (language) => ( | ||||
|                       <Fragment key={language.__typename}> | ||||
|                         <Chip text={language.attributes.code.toUpperCase()} /> | ||||
|                       </Fragment> | ||||
|                     ) | ||||
|                   )} | ||||
|                   {filterHasAttributes(recorder.languages.data, ["attributes"]).map((language) => ( | ||||
|                     <Fragment key={language.__typename}> | ||||
|                       <Chip text={language.attributes.code.toUpperCase()} /> | ||||
|                     </Fragment> | ||||
|                   ))} | ||||
|                 </div> | ||||
|               )} | ||||
|               {recorder.pronouns && ( | ||||
|  | ||||
| @ -88,11 +88,9 @@ export const ThumbnailHeader = ({ | ||||
|           <div className="flex flex-col place-items-center gap-2"> | ||||
|             <h3 className="text-xl">{format("category", { count: categories.data.length })}</h3> | ||||
|             <div className="flex flex-row flex-wrap place-content-center gap-2"> | ||||
|               {filterHasAttributes(categories.data, ["attributes", "id"] as const).map( | ||||
|                 (category) => ( | ||||
|                   <Chip key={category.id} text={category.attributes.name} /> | ||||
|                 ) | ||||
|               )} | ||||
|               {filterHasAttributes(categories.data, ["attributes", "id"]).map((category) => ( | ||||
|                 <Chip key={category.id} text={category.attributes.name} /> | ||||
|               ))} | ||||
|             </div> | ||||
|           </div> | ||||
|         )} | ||||
|  | ||||
| @ -41,7 +41,7 @@ export const getPostStaticProps = | ||||
|         [format("release_date")]: [prettyDate(post.posts.data[0].attributes.date, context.locale)], | ||||
|         [format("category", { count: Infinity })]: filterHasAttributes( | ||||
|           post.posts.data[0].attributes.categories?.data, | ||||
|           ["attributes"] as const | ||||
|           ["attributes"] | ||||
|         ).map((category) => category.attributes.short), | ||||
|       }); | ||||
| 
 | ||||
|  | ||||
| @ -2,12 +2,18 @@ | ||||
| import { createWriteStream } from "fs"; | ||||
| import { parse, TYPE } from "@formatjs/icu-messageformat-parser"; | ||||
| import { getLangui } from "./fetchLocalData"; | ||||
| import { filterDefined } from "helpers/asserts"; | ||||
| import { getLogger } from "helpers/logger"; | ||||
| 
 | ||||
| const OUTPUT_FOLDER = `${process.cwd()}/src/graphql`; | ||||
| 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 = () => { | ||||
|   // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|   const { ui_language, ...langui } = getLangui("en"); | ||||
|  | ||||
| @ -48,7 +48,7 @@ export const isDefinedAndNotEmpty = (string: string | null | undefined): string | ||||
| export const filterDefined = <T>(t: T[] | null | undefined): 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, | ||||
|   paths: readonly P[] | ||||
| ): SelectiveNonNullable<T, (typeof paths)[number]>[] => | ||||
| @ -77,3 +77,5 @@ const hasAttribute = <T>(item: T, path: string): boolean => { | ||||
|   } | ||||
|   return false; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -201,7 +201,7 @@ const Revalidate = async ( | ||||
|         }); | ||||
|         filterHasAttributes(libraryItem.libraryItems?.data[0]?.attributes?.subitem_of?.data, [ | ||||
|           "attributes.slug", | ||||
|         ] as const).forEach((parentItem) => paths.push(`/library/${parentItem.attributes.slug}`)); | ||||
|         ]).forEach((parentItem) => paths.push(`/library/${parentItem.attributes.slug}`)); | ||||
|       } | ||||
| 
 | ||||
|       break; | ||||
| @ -227,7 +227,7 @@ const Revalidate = async ( | ||||
| 
 | ||||
|         filterHasAttributes(content.contents?.data[0]?.attributes?.ranged_contents?.data, [ | ||||
|           "attributes.library_item.data.attributes.slug", | ||||
|         ] as const).forEach((ranged_content) => { | ||||
|         ]).forEach((ranged_content) => { | ||||
|           const parentSlug = ranged_content.attributes.library_item.data.attributes.slug; | ||||
|           paths.push(`/library/${parentSlug}`); | ||||
|           paths.push(`/library/${parentSlug}/reader`); | ||||
| @ -285,12 +285,10 @@ const Revalidate = async ( | ||||
|         } | ||||
|         filterHasAttributes(folder.contentsFolders?.data[0]?.attributes?.subfolders?.data, [ | ||||
|           "attributes.slug", | ||||
|         ] as const).forEach((subfolder) => | ||||
|           paths.push(`/contents/folder/${subfolder.attributes.slug}`) | ||||
|         ); | ||||
|         ]).forEach((subfolder) => paths.push(`/contents/folder/${subfolder.attributes.slug}`)); | ||||
|         filterHasAttributes(folder.contentsFolders?.data[0]?.attributes?.contents?.data, [ | ||||
|           "attributes.slug", | ||||
|         ] as const).forEach((content) => paths.push(`/contents/${content.attributes.slug}`)); | ||||
|         ]).forEach((content) => paths.push(`/contents/${content.attributes.slug}`)); | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
| @ -339,7 +337,7 @@ const Revalidate = async ( | ||||
|       }); | ||||
|       filterHasAttributes(group.weaponStoryGroup?.data?.attributes?.weapons?.data, [ | ||||
|         "attributes.slug", | ||||
|       ] as const).forEach((weapon) => paths.push(`/wiki/weapons/${weapon.attributes.slug}`)); | ||||
|       ]).forEach((weapon) => paths.push(`/wiki/weapons/${weapon.attributes.slug}`)); | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -300,7 +300,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => { | ||||
|   const paths: GetStaticPathsResult["paths"] = []; | ||||
| 
 | ||||
|   if (channels.videoChannels?.data) | ||||
|     filterHasAttributes(channels.videoChannels.data, ["attributes"] as const).map((channel) => { | ||||
|     filterHasAttributes(channels.videoChannels.data, ["attributes"]).map((channel) => { | ||||
|       context.locales?.map((local) => { | ||||
|         paths.push({ | ||||
|           params: { uid: channel.attributes.uid }, | ||||
|  | ||||
| @ -168,7 +168,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => { | ||||
|   const videos = await sdk.getVideosSlugs(); | ||||
|   const paths: GetStaticPathsResult["paths"] = []; | ||||
|   if (videos.videos?.data) | ||||
|     filterHasAttributes(videos.videos.data, ["attributes"] as const).map((video) => { | ||||
|     filterHasAttributes(videos.videos.data, ["attributes"]).map((video) => { | ||||
|       context.locales?.map((local) => { | ||||
|         paths.push({ params: { uid: video.attributes.uid }, locale: local }); | ||||
|       }); | ||||
|  | ||||
| @ -47,8 +47,7 @@ const Chronicle = ({ chronicle, chapters, ...otherProps }: Props): JSX.Element = | ||||
|   }); | ||||
| 
 | ||||
|   const primaryContent = chronicle.contents | ||||
|     ? filterHasAttributes(chronicle.contents.data, ["attributes.translations"] as const)[0] | ||||
|         ?.attributes | ||||
|     ? filterHasAttributes(chronicle.contents.data, ["attributes.translations"])[0]?.attributes | ||||
|     : undefined; | ||||
| 
 | ||||
|   const [selectedContentTranslation, ContentLanguageSwitcher, ContentLanguageSwitcherProps] = | ||||
| @ -128,13 +127,13 @@ const Chronicle = ({ chronicle, chapters, ...otherProps }: Props): JSX.Element = | ||||
|       <HorizontalLine /> | ||||
| 
 | ||||
|       <div className="grid gap-16"> | ||||
|         {filterHasAttributes(chapters, ["attributes.chronicles", "id"] as const).map((chapter) => ( | ||||
|         {filterHasAttributes(chapters, ["attributes.chronicles", "id"]).map((chapter) => ( | ||||
|           <TranslatedChroniclesList | ||||
|             key={chapter.id} | ||||
|             chronicles={chapter.attributes.chronicles.data} | ||||
|             translations={filterHasAttributes(chapter.attributes.titles, [ | ||||
|               "language.data.attributes.code", | ||||
|             ] as const).map((translation) => ({ | ||||
|             ]).map((translation) => ({ | ||||
|               title: translation.title, | ||||
|               language: translation.language.data.attributes.code, | ||||
|             }))} | ||||
| @ -201,7 +200,7 @@ export const getStaticProps: GetStaticProps = async (context) => { | ||||
|               [format("category", { count: Infinity })]: filterHasAttributes( | ||||
|                 chronicle.chronicles.data[0].attributes.contents.data[0].attributes.categories | ||||
|                   ?.data, | ||||
|                 ["attributes"] as const | ||||
|                 ["attributes"] | ||||
|               ).map((category) => category.attributes.short), | ||||
|             }), | ||||
|           }; | ||||
| @ -248,7 +247,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => { | ||||
|   const sdk = getReadySdk(); | ||||
|   const contents = await sdk.getChroniclesSlugs(); | ||||
|   const paths: GetStaticPathsResult["paths"] = []; | ||||
|   filterHasAttributes(contents.chronicles?.data, ["attributes"] as const).map((wikiPage) => { | ||||
|   filterHasAttributes(contents.chronicles?.data, ["attributes"]).map((wikiPage) => { | ||||
|     context.locales?.map((local) => | ||||
|       paths.push({ | ||||
|         params: { slug: wikiPage.attributes.slug }, | ||||
|  | ||||
| @ -34,13 +34,13 @@ const Chronicles = ({ chapters, ...otherProps }: Props): JSX.Element => { | ||||
|       <HorizontalLine /> | ||||
| 
 | ||||
|       <div className="grid gap-16"> | ||||
|         {filterHasAttributes(chapters, ["attributes.chronicles", "id"] as const).map((chapter) => ( | ||||
|         {filterHasAttributes(chapters, ["attributes.chronicles", "id"]).map((chapter) => ( | ||||
|           <TranslatedChroniclesList | ||||
|             key={chapter.id} | ||||
|             chronicles={chapter.attributes.chronicles.data} | ||||
|             translations={filterHasAttributes(chapter.attributes.titles, [ | ||||
|               "language.data.attributes.code", | ||||
|             ] as const).map((translation) => ({ | ||||
|             ]).map((translation) => ({ | ||||
|               title: translation.title, | ||||
|               language: translation.language.data.attributes.code, | ||||
|             }))} | ||||
|  | ||||
| @ -80,7 +80,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => { | ||||
| 
 | ||||
|     translations: filterHasAttributes(content.folder?.data?.attributes?.titles, [ | ||||
|       "language.data.attributes.code", | ||||
|     ] as const).map((title) => ({ | ||||
|     ]).map((title) => ({ | ||||
|       language: title.language.data.attributes.code, | ||||
|       title: title.title, | ||||
|     })), | ||||
| @ -146,7 +146,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => { | ||||
|                       {filterHasAttributes(selectedTranslation.text_set.transcribers.data, [ | ||||
|                         "attributes", | ||||
|                         "id", | ||||
|                       ] as const).map((recorder) => ( | ||||
|                       ]).map((recorder) => ( | ||||
|                         <Fragment key={recorder.id}> | ||||
|                           <RecorderChip recorder={recorder.attributes} /> | ||||
|                         </Fragment> | ||||
| @ -163,7 +163,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => { | ||||
|                       {filterHasAttributes(selectedTranslation.text_set.translators.data, [ | ||||
|                         "attributes", | ||||
|                         "id", | ||||
|                       ] as const).map((recorder) => ( | ||||
|                       ]).map((recorder) => ( | ||||
|                         <Fragment key={recorder.id}> | ||||
|                           <RecorderChip recorder={recorder.attributes} /> | ||||
|                         </Fragment> | ||||
| @ -180,7 +180,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => { | ||||
|                       {filterHasAttributes(selectedTranslation.text_set.proofreaders.data, [ | ||||
|                         "attributes", | ||||
|                         "id", | ||||
|                       ] as const).map((recorder) => ( | ||||
|                       ]).map((recorder) => ( | ||||
|                         <Fragment key={recorder.id}> | ||||
|                           <RecorderChip recorder={recorder.attributes} /> | ||||
|                         </Fragment> | ||||
| @ -209,7 +209,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => { | ||||
|                 {filterHasAttributes(content.ranged_contents.data, [ | ||||
|                   "attributes.library_item.data.attributes", | ||||
|                   "attributes.library_item.data.id", | ||||
|                 ] as const).map((rangedContent) => { | ||||
|                 ]).map((rangedContent) => { | ||||
|                   const libraryItem = rangedContent.attributes.library_item.data; | ||||
|                   return ( | ||||
|                     <div | ||||
| @ -231,7 +231,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => { | ||||
|                         } | ||||
|                         bottomChips={filterHasAttributes(libraryItem.attributes.categories?.data, [ | ||||
|                           "attributes", | ||||
|                         ] as const).map((category) => category.attributes.short)} | ||||
|                         ]).map((category) => category.attributes.short)} | ||||
|                         metadata={{ | ||||
|                           releaseDate: libraryItem.attributes.release_date, | ||||
|                           price: libraryItem.attributes.price, | ||||
| @ -288,7 +288,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => { | ||||
|                   href={`/contents/${previousContent.attributes.slug}`} | ||||
|                   translations={filterHasAttributes(previousContent.attributes.translations, [ | ||||
|                     "language.data.attributes.code", | ||||
|                   ] as const).map((translation) => ({ | ||||
|                   ]).map((translation) => ({ | ||||
|                     pre_title: translation.pre_title, | ||||
|                     title: translation.title, | ||||
|                     subtitle: translation.subtitle, | ||||
| @ -329,7 +329,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => { | ||||
|                   href={`/contents/${nextContent.attributes.slug}`} | ||||
|                   translations={filterHasAttributes(nextContent.attributes.translations, [ | ||||
|                     "language.data.attributes.code", | ||||
|                   ] as const).map((translation) => ({ | ||||
|                   ]).map((translation) => ({ | ||||
|                     pre_title: translation.pre_title, | ||||
|                     title: translation.title, | ||||
|                     subtitle: translation.subtitle, | ||||
| @ -404,7 +404,7 @@ export const getStaticProps: GetStaticProps = async (context) => { | ||||
|             ], | ||||
|             [format("category", { count: Infinity })]: filterHasAttributes( | ||||
|               content.contents.data[0].attributes.categories?.data, | ||||
|               ["attributes"] as const | ||||
|               ["attributes"] | ||||
|             ).map((category) => category.attributes.short), | ||||
|           }), | ||||
|         }; | ||||
| @ -437,7 +437,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => { | ||||
|   const sdk = getReadySdk(); | ||||
|   const contents = await sdk.getContentsSlugs(); | ||||
|   const paths: GetStaticPathsResult["paths"] = []; | ||||
|   filterHasAttributes(contents.contents?.data, ["attributes"] as const).map((item) => { | ||||
|   filterHasAttributes(contents.contents?.data, ["attributes"]).map((item) => { | ||||
|     context.locales?.map((local) => { | ||||
|       paths.push({ | ||||
|         params: { slug: item.attributes.slug }, | ||||
|  | ||||
| @ -220,7 +220,7 @@ const Contents = (props: Props): JSX.Element => { | ||||
|               href={`/contents/${item.slug}`} | ||||
|               translations={filterHasAttributes(item._formatted.translations, [ | ||||
|                 "language.data.attributes.code", | ||||
|               ] as const).map(({ displayable_description, language, ...otherAttributes }) => ({ | ||||
|               ]).map(({ displayable_description, language, ...otherAttributes }) => ({ | ||||
|                 ...otherAttributes, | ||||
|                 description: containsHighlight(displayable_description) | ||||
|                   ? displayable_description | ||||
|  | ||||
| @ -69,7 +69,7 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen | ||||
|                 href={`/contents/folder/${folder.parent_folder.data.attributes.slug}`} | ||||
|                 translations={filterHasAttributes(folder.parent_folder.data.attributes.titles, [ | ||||
|                   "language.data.attributes.code", | ||||
|                 ] as const).map((title) => ({ | ||||
|                 ]).map((title) => ({ | ||||
|                   language: title.language.data.attributes.code, | ||||
|                   text: title.title, | ||||
|                 }))} | ||||
| @ -86,12 +86,12 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen | ||||
|           <Button href="/contents" icon="home" active /> | ||||
|         ) : ( | ||||
|           <TranslatedButton | ||||
|             translations={filterHasAttributes(folder.titles, [ | ||||
|               "language.data.attributes.code", | ||||
|             ] as const).map((title) => ({ | ||||
|               language: title.language.data.attributes.code, | ||||
|               text: title.title, | ||||
|             }))} | ||||
|             translations={filterHasAttributes(folder.titles, ["language.data.attributes.code"]).map( | ||||
|               (title) => ({ | ||||
|                 language: title.language.data.attributes.code, | ||||
|                 text: title.title, | ||||
|               }) | ||||
|             )} | ||||
|             fallback={{ | ||||
|               text: prettySlug(folder.slug), | ||||
|             }} | ||||
| @ -115,21 +115,19 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen | ||||
|                 "grid-cols-2 gap-4" | ||||
|               ) | ||||
|             )}> | ||||
|             {filterHasAttributes(folder.subfolders.data, ["id", "attributes"] as const).map( | ||||
|               (subfolder) => ( | ||||
|                 <TranslatedPreviewFolder | ||||
|                   key={subfolder.id} | ||||
|                   href={`/contents/folder/${subfolder.attributes.slug}`} | ||||
|                   translations={filterHasAttributes(subfolder.attributes.titles, [ | ||||
|                     "language.data.attributes.code", | ||||
|                   ] as const).map((title) => ({ | ||||
|                     title: title.title, | ||||
|                     language: title.language.data.attributes.code, | ||||
|                   }))} | ||||
|                   fallback={{ title: prettySlug(subfolder.attributes.slug) }} | ||||
|                 /> | ||||
|               ) | ||||
|             )} | ||||
|             {filterHasAttributes(folder.subfolders.data, ["id", "attributes"]).map((subfolder) => ( | ||||
|               <TranslatedPreviewFolder | ||||
|                 key={subfolder.id} | ||||
|                 href={`/contents/folder/${subfolder.attributes.slug}`} | ||||
|                 translations={filterHasAttributes(subfolder.attributes.titles, [ | ||||
|                   "language.data.attributes.code", | ||||
|                 ]).map((title) => ({ | ||||
|                   title: title.title, | ||||
|                   language: title.language.data.attributes.code, | ||||
|                 }))} | ||||
|                 fallback={{ title: prettySlug(subfolder.attributes.slug) }} | ||||
|               /> | ||||
|             ))} | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
| @ -149,39 +147,37 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen | ||||
|                 "grid-cols-2 gap-4" | ||||
|               ) | ||||
|             )}> | ||||
|             {filterHasAttributes(folder.contents.data, ["id", "attributes"] as const).map( | ||||
|               (item) => ( | ||||
|                 <TranslatedPreviewCard | ||||
|                   key={item.id} | ||||
|                   href={`/contents/${item.attributes.slug}`} | ||||
|                   translations={filterHasAttributes(item.attributes.translations, [ | ||||
|                     "language.data.attributes.code", | ||||
|                   ] as const).map((translation) => ({ | ||||
|                     pre_title: translation.pre_title, | ||||
|                     title: translation.title, | ||||
|                     subtitle: translation.subtitle, | ||||
|                     language: translation.language.data.attributes.code, | ||||
|                   }))} | ||||
|                   fallback={{ title: prettySlug(item.attributes.slug) }} | ||||
|                   thumbnail={item.attributes.thumbnail?.data?.attributes} | ||||
|                   thumbnailAspectRatio="3/2" | ||||
|                   thumbnailForceAspectRatio | ||||
|                   topChips={ | ||||
|                     item.attributes.type?.data?.attributes | ||||
|                       ? [ | ||||
|                           item.attributes.type.data.attributes.titles?.[0] | ||||
|                             ? item.attributes.type.data.attributes.titles[0]?.title | ||||
|                             : prettySlug(item.attributes.type.data.attributes.slug), | ||||
|                         ] | ||||
|                       : undefined | ||||
|                   } | ||||
|                   bottomChips={item.attributes.categories?.data.map( | ||||
|                     (category) => category.attributes?.short ?? "" | ||||
|                   )} | ||||
|                   keepInfoVisible | ||||
|                 /> | ||||
|               ) | ||||
|             )} | ||||
|             {filterHasAttributes(folder.contents.data, ["id", "attributes"]).map((item) => ( | ||||
|               <TranslatedPreviewCard | ||||
|                 key={item.id} | ||||
|                 href={`/contents/${item.attributes.slug}`} | ||||
|                 translations={filterHasAttributes(item.attributes.translations, [ | ||||
|                   "language.data.attributes.code", | ||||
|                 ]).map((translation) => ({ | ||||
|                   pre_title: translation.pre_title, | ||||
|                   title: translation.title, | ||||
|                   subtitle: translation.subtitle, | ||||
|                   language: translation.language.data.attributes.code, | ||||
|                 }))} | ||||
|                 fallback={{ title: prettySlug(item.attributes.slug) }} | ||||
|                 thumbnail={item.attributes.thumbnail?.data?.attributes} | ||||
|                 thumbnailAspectRatio="3/2" | ||||
|                 thumbnailForceAspectRatio | ||||
|                 topChips={ | ||||
|                   item.attributes.type?.data?.attributes | ||||
|                     ? [ | ||||
|                         item.attributes.type.data.attributes.titles?.[0] | ||||
|                           ? item.attributes.type.data.attributes.titles[0]?.title | ||||
|                           : prettySlug(item.attributes.type.data.attributes.slug), | ||||
|                       ] | ||||
|                     : undefined | ||||
|                 } | ||||
|                 bottomChips={item.attributes.categories?.data.map( | ||||
|                   (category) => category.attributes?.short ?? "" | ||||
|                 )} | ||||
|                 keepInfoVisible | ||||
|               /> | ||||
|             ))} | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
| @ -262,7 +258,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => { | ||||
|   const sdk = getReadySdk(); | ||||
|   const contents = await sdk.getContentsFoldersSlugs(); | ||||
|   const paths: GetStaticPathsResult["paths"] = []; | ||||
|   filterHasAttributes(contents.contentsFolders?.data, ["attributes"] as const).map((item) => { | ||||
|   filterHasAttributes(contents.contentsFolders?.data, ["attributes"]).map((item) => { | ||||
|     context.locales?.map((local) => { | ||||
|       paths.push({ | ||||
|         params: { slug: item.attributes.slug }, | ||||
|  | ||||
| @ -105,7 +105,7 @@ const testingContent = (contents: Props["contents"]): Report => { | ||||
|     lines: [], | ||||
|   }; | ||||
| 
 | ||||
|   filterHasAttributes(contents.contents?.data, ["attributes"] as const).map((content) => { | ||||
|   filterHasAttributes(contents.contents?.data, ["attributes"]).map((content) => { | ||||
|     const backendUrl = sJoin( | ||||
|       process.env.NEXT_PUBLIC_URL_CMS, | ||||
|       "/admin/content-manager/collectionType/api::content.content/", | ||||
|  | ||||
| @ -230,7 +230,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => { | ||||
|                 {item.urls?.length ? ( | ||||
|                   <div className="flex flex-row place-items-center gap-3"> | ||||
|                     <p>{format("available_at")}</p> | ||||
|                     {filterHasAttributes(item.urls, ["url"] as const).map((url, index) => ( | ||||
|                     {filterHasAttributes(item.urls, ["url"]).map((url, index) => ( | ||||
|                       <Fragment key={index}> | ||||
|                         <Button href={url.url} text={prettyURL(url.url)} alwaysNewTab /> | ||||
|                       </Fragment> | ||||
| @ -250,7 +250,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => { | ||||
|             <div | ||||
|               className="grid w-full grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))] items-end | ||||
|               gap-8"> | ||||
|               {filterHasAttributes(item.gallery.data, ["id", "attributes"] as const).map( | ||||
|               {filterHasAttributes(item.gallery.data, ["id", "attributes"]).map( | ||||
|                 (galleryItem, index) => ( | ||||
|                   <Fragment key={galleryItem.id}> | ||||
|                     <div | ||||
| @ -258,7 +258,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => { | ||||
|                       transition-transform hover:scale-102" | ||||
|                       onClick={() => { | ||||
|                         showLightBox( | ||||
|                           filterHasAttributes(item.gallery?.data, ["attributes"] as const).map( | ||||
|                           filterHasAttributes(item.gallery?.data, ["attributes"]).map( | ||||
|                             (image) => image.attributes | ||||
|                           ), | ||||
|                           index | ||||
| @ -329,11 +329,9 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => { | ||||
|                   {format("category", { count: item.categories.data.length })} | ||||
|                 </h3> | ||||
|                 <div className="flex flex-row flex-wrap place-content-center gap-2"> | ||||
|                   {filterHasAttributes(item.categories.data, ["attributes"] as const).map( | ||||
|                     (category) => ( | ||||
|                       <Chip key={category.id} text={category.attributes.name} /> | ||||
|                     ) | ||||
|                   )} | ||||
|                   {filterHasAttributes(item.categories.data, ["attributes"]).map((category) => ( | ||||
|                     <Chip key={category.id} text={category.attributes.name} /> | ||||
|                   ))} | ||||
|                 </div> | ||||
|               </div> | ||||
|             )} | ||||
| @ -482,41 +480,39 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => { | ||||
|             <div | ||||
|               className="grid w-full grid-cols-[repeat(auto-fill,minmax(13rem,1fr))] | ||||
|               items-end gap-8"> | ||||
|               {filterHasAttributes(item.subitems.data, ["id", "attributes"] as const).map( | ||||
|                 (subitem) => ( | ||||
|                   <Fragment key={subitem.id}> | ||||
|                     <PreviewCard | ||||
|                       href={`/library/${subitem.attributes.slug}`} | ||||
|                       title={subitem.attributes.title} | ||||
|                       subtitle={subitem.attributes.subtitle} | ||||
|                       thumbnail={subitem.attributes.thumbnail?.data?.attributes} | ||||
|                       thumbnailAspectRatio="21/29.7" | ||||
|                       thumbnailRounded={false} | ||||
|                       keepInfoVisible={keepInfoVisible} | ||||
|                       topChips={ | ||||
|                         subitem.attributes.metadata && | ||||
|                         subitem.attributes.metadata.length > 0 && | ||||
|                         subitem.attributes.metadata[0] | ||||
|                           ? [prettyItemSubType(subitem.attributes.metadata[0])] | ||||
|                           : [] | ||||
|                       } | ||||
|                       bottomChips={subitem.attributes.categories?.data.map( | ||||
|                         (category) => category.attributes?.short ?? "" | ||||
|                       )} | ||||
|                       metadata={{ | ||||
|                         releaseDate: subitem.attributes.release_date, | ||||
|                         price: subitem.attributes.price, | ||||
|                         position: "Bottom", | ||||
|                       }} | ||||
|                       infoAppend={ | ||||
|                         !isUntangibleGroupItem(subitem.attributes.metadata?.[0]) && ( | ||||
|                           <PreviewCardCTAs id={subitem.id} /> | ||||
|                         ) | ||||
|                       } | ||||
|                     /> | ||||
|                   </Fragment> | ||||
|                 ) | ||||
|               )} | ||||
|               {filterHasAttributes(item.subitems.data, ["id", "attributes"]).map((subitem) => ( | ||||
|                 <Fragment key={subitem.id}> | ||||
|                   <PreviewCard | ||||
|                     href={`/library/${subitem.attributes.slug}`} | ||||
|                     title={subitem.attributes.title} | ||||
|                     subtitle={subitem.attributes.subtitle} | ||||
|                     thumbnail={subitem.attributes.thumbnail?.data?.attributes} | ||||
|                     thumbnailAspectRatio="21/29.7" | ||||
|                     thumbnailRounded={false} | ||||
|                     keepInfoVisible={keepInfoVisible} | ||||
|                     topChips={ | ||||
|                       subitem.attributes.metadata && | ||||
|                       subitem.attributes.metadata.length > 0 && | ||||
|                       subitem.attributes.metadata[0] | ||||
|                         ? [prettyItemSubType(subitem.attributes.metadata[0])] | ||||
|                         : [] | ||||
|                     } | ||||
|                     bottomChips={subitem.attributes.categories?.data.map( | ||||
|                       (category) => category.attributes?.short ?? "" | ||||
|                     )} | ||||
|                     metadata={{ | ||||
|                       releaseDate: subitem.attributes.release_date, | ||||
|                       price: subitem.attributes.price, | ||||
|                       position: "Bottom", | ||||
|                     }} | ||||
|                     infoAppend={ | ||||
|                       !isUntangibleGroupItem(subitem.attributes.metadata?.[0]) && ( | ||||
|                         <PreviewCardCTAs id={subitem.id} /> | ||||
|                       ) | ||||
|                     } | ||||
|                   /> | ||||
|                 </Fragment> | ||||
|               ))} | ||||
|             </div> | ||||
|           </div> | ||||
|         )} | ||||
| @ -530,51 +526,49 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => { | ||||
|               </div> | ||||
|             )} | ||||
|             <div className="max-w- grid w-full gap-4"> | ||||
|               {filterHasAttributes(item.contents.data, ["attributes"] as const).map( | ||||
|                 (rangedContent) => ( | ||||
|                   <ContentLine | ||||
|                     content={ | ||||
|                       rangedContent.attributes.content?.data?.attributes | ||||
|                         ? { | ||||
|                             translations: filterDefined( | ||||
|                               rangedContent.attributes.content.data.attributes.translations | ||||
|                             ).map((translation) => ({ | ||||
|                               pre_title: translation.pre_title, | ||||
|                               title: translation.title, | ||||
|                               subtitle: translation.subtitle, | ||||
|                               language: translation.language?.data?.attributes?.code, | ||||
|                             })), | ||||
|                             categories: filterHasAttributes( | ||||
|                               rangedContent.attributes.content.data.attributes.categories?.data, | ||||
|                               ["attributes"] | ||||
|                             ).map((category) => category.attributes.short), | ||||
|                             type: | ||||
|               {filterHasAttributes(item.contents.data, ["attributes"]).map((rangedContent) => ( | ||||
|                 <ContentLine | ||||
|                   content={ | ||||
|                     rangedContent.attributes.content?.data?.attributes | ||||
|                       ? { | ||||
|                           translations: filterDefined( | ||||
|                             rangedContent.attributes.content.data.attributes.translations | ||||
|                           ).map((translation) => ({ | ||||
|                             pre_title: translation.pre_title, | ||||
|                             title: translation.title, | ||||
|                             subtitle: translation.subtitle, | ||||
|                             language: translation.language?.data?.attributes?.code, | ||||
|                           })), | ||||
|                           categories: filterHasAttributes( | ||||
|                             rangedContent.attributes.content.data.attributes.categories?.data, | ||||
|                             ["attributes"] | ||||
|                           ).map((category) => category.attributes.short), | ||||
|                           type: | ||||
|                             rangedContent.attributes.content.data.attributes.type?.data?.attributes | ||||
|                               ?.titles?.[0]?.title ?? | ||||
|                             prettySlug( | ||||
|                               rangedContent.attributes.content.data.attributes.type?.data | ||||
|                                 ?.attributes?.titles?.[0]?.title ?? | ||||
|                               prettySlug( | ||||
|                                 rangedContent.attributes.content.data.attributes.type?.data | ||||
|                                   ?.attributes?.slug | ||||
|                               ), | ||||
|                             slug: rangedContent.attributes.content.data.attributes.slug, | ||||
|                           } | ||||
|                         : undefined | ||||
|                     } | ||||
|                     rangeStart={ | ||||
|                       rangedContent.attributes.range[0]?.__typename === "ComponentRangePageRange" | ||||
|                         ? `${rangedContent.attributes.range[0].starting_page}` | ||||
|                         : "" | ||||
|                     } | ||||
|                     slug={rangedContent.attributes.slug} | ||||
|                     parentSlug={item.slug} | ||||
|                     key={rangedContent.id} | ||||
|                     hasScanSet={ | ||||
|                       isDefined(rangedContent.attributes.scan_set) && | ||||
|                       rangedContent.attributes.scan_set.length > 0 | ||||
|                     } | ||||
|                     condensed={!isContentPanelAtLeast3xl} | ||||
|                   /> | ||||
|                 ) | ||||
|               )} | ||||
|                                 ?.attributes?.slug | ||||
|                             ), | ||||
|                           slug: rangedContent.attributes.content.data.attributes.slug, | ||||
|                         } | ||||
|                       : undefined | ||||
|                   } | ||||
|                   rangeStart={ | ||||
|                     rangedContent.attributes.range[0]?.__typename === "ComponentRangePageRange" | ||||
|                       ? `${rangedContent.attributes.range[0].starting_page}` | ||||
|                       : "" | ||||
|                   } | ||||
|                   slug={rangedContent.attributes.slug} | ||||
|                   parentSlug={item.slug} | ||||
|                   key={rangedContent.id} | ||||
|                   hasScanSet={ | ||||
|                     isDefined(rangedContent.attributes.scan_set) && | ||||
|                     rangedContent.attributes.scan_set.length > 0 | ||||
|                   } | ||||
|                   condensed={!isContentPanelAtLeast3xl} | ||||
|                 /> | ||||
|               ))} | ||||
|             </div> | ||||
|           </div> | ||||
|         )} | ||||
| @ -637,7 +631,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => { | ||||
|   const sdk = getReadySdk(); | ||||
|   const libraryItems = await sdk.getLibraryItemsSlugs(); | ||||
|   const paths: GetStaticPathsResult["paths"] = []; | ||||
|   filterHasAttributes(libraryItems.libraryItems?.data, ["attributes"] as const).map((item) => { | ||||
|   filterHasAttributes(libraryItems.libraryItems?.data, ["attributes"]).map((item) => { | ||||
|     context.locales?.map((local) => | ||||
|       paths.push({ params: { slug: item.attributes.slug }, locale: local }) | ||||
|     ); | ||||
|  | ||||
| @ -537,7 +537,7 @@ const LibrarySlug = ({ | ||||
|                   id={content.attributes.slug} | ||||
|                   translations={filterHasAttributes( | ||||
|                     content.attributes.content?.data?.attributes?.translations, | ||||
|                     ["language.data.attributes"] as const | ||||
|                     ["language.data.attributes"] | ||||
|                   ).map((translation) => ({ | ||||
|                     language: translation.language.data.attributes.code, | ||||
|                     title: prettyInlineTitle( | ||||
| @ -596,9 +596,9 @@ export const getStaticProps: GetStaticProps = async (context) => { | ||||
| 
 | ||||
|   filterHasAttributes(item.libraryItems.data[0].attributes.contents?.data, [ | ||||
|     "attributes.scan_set", | ||||
|   ] as const).forEach((content) => | ||||
|     filterHasAttributes(content.attributes.scan_set, ["pages.data"] as const).forEach((scanSet) => | ||||
|       filterHasAttributes(scanSet.pages.data, ["attributes"] as const) | ||||
|   ]).forEach((content) => | ||||
|     filterHasAttributes(content.attributes.scan_set, ["pages.data"]).forEach((scanSet) => | ||||
|       filterHasAttributes(scanSet.pages.data, ["attributes"]) | ||||
|         .sort((a, b) => { | ||||
|           if (isDefinedAndNotEmpty(a.attributes.url) && isDefinedAndNotEmpty(b.attributes.url)) { | ||||
|             let aName = getAssetFilename(a.attributes.url); | ||||
| @ -675,7 +675,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => { | ||||
|   const sdk = getReadySdk(); | ||||
|   const libraryItems = await sdk.getLibraryItemsSlugs({}); | ||||
|   const paths: GetStaticPathsResult["paths"] = []; | ||||
|   filterHasAttributes(libraryItems.libraryItems?.data, ["attributes"] as const).map((item) => { | ||||
|   filterHasAttributes(libraryItems.libraryItems?.data, ["attributes"]).map((item) => { | ||||
|     context.locales?.map((local) => | ||||
|       paths.push({ params: { slug: item.attributes.slug }, locale: local }) | ||||
|     ); | ||||
| @ -874,14 +874,13 @@ const ScanSet = ({ onClickOnImage, scanSet, id, title, content }: ScanSetProps): | ||||
|               <div> | ||||
|                 <p className="font-headers font-bold">{format("scanners")}:</p> | ||||
|                 <div className="grid place-content-center place-items-center gap-2"> | ||||
|                   {filterHasAttributes(selectedScan.scanners.data, [ | ||||
|                     "id", | ||||
|                     "attributes", | ||||
|                   ] as const).map((scanner) => ( | ||||
|                     <Fragment key={scanner.id}> | ||||
|                       <RecorderChip recorder={scanner.attributes} /> | ||||
|                     </Fragment> | ||||
|                   ))} | ||||
|                   {filterHasAttributes(selectedScan.scanners.data, ["id", "attributes"]).map( | ||||
|                     (scanner) => ( | ||||
|                       <Fragment key={scanner.id}> | ||||
|                         <RecorderChip recorder={scanner.attributes} /> | ||||
|                       </Fragment> | ||||
|                     ) | ||||
|                   )} | ||||
|                 </div> | ||||
|               </div> | ||||
|             )} | ||||
| @ -890,14 +889,13 @@ const ScanSet = ({ onClickOnImage, scanSet, id, title, content }: ScanSetProps): | ||||
|               <div> | ||||
|                 <p className="font-headers font-bold">{format("cleaners")}:</p> | ||||
|                 <div className="grid place-content-center place-items-center gap-2"> | ||||
|                   {filterHasAttributes(selectedScan.cleaners.data, [ | ||||
|                     "id", | ||||
|                     "attributes", | ||||
|                   ] as const).map((cleaner) => ( | ||||
|                     <Fragment key={cleaner.id}> | ||||
|                       <RecorderChip recorder={cleaner.attributes} /> | ||||
|                     </Fragment> | ||||
|                   ))} | ||||
|                   {filterHasAttributes(selectedScan.cleaners.data, ["id", "attributes"]).map( | ||||
|                     (cleaner) => ( | ||||
|                       <Fragment key={cleaner.id}> | ||||
|                         <RecorderChip recorder={cleaner.attributes} /> | ||||
|                       </Fragment> | ||||
|                     ) | ||||
|                   )} | ||||
|                 </div> | ||||
|               </div> | ||||
|             )} | ||||
| @ -906,14 +904,13 @@ const ScanSet = ({ onClickOnImage, scanSet, id, title, content }: ScanSetProps): | ||||
|               <div> | ||||
|                 <p className="font-headers font-bold">{format("typesetters")}:</p> | ||||
|                 <div className="grid place-content-center place-items-center gap-2"> | ||||
|                   {filterHasAttributes(selectedScan.typesetters.data, [ | ||||
|                     "id", | ||||
|                     "attributes", | ||||
|                   ] as const).map((typesetter) => ( | ||||
|                     <Fragment key={typesetter.id}> | ||||
|                       <RecorderChip recorder={typesetter.attributes} /> | ||||
|                     </Fragment> | ||||
|                   ))} | ||||
|                   {filterHasAttributes(selectedScan.typesetters.data, ["id", "attributes"]).map( | ||||
|                     (typesetter) => ( | ||||
|                       <Fragment key={typesetter.id}> | ||||
|                         <RecorderChip recorder={typesetter.attributes} /> | ||||
|                       </Fragment> | ||||
|                     ) | ||||
|                   )} | ||||
|                 </div> | ||||
|               </div> | ||||
|             )} | ||||
|  | ||||
| @ -408,7 +408,7 @@ const Library = (props: Props): JSX.Element => { | ||||
|               href={`/library/${item.slug}`} | ||||
|               translations={filterHasAttributes(item._formatted.descriptions, [ | ||||
|                 "language.data.attributes.code", | ||||
|               ] as const).map((translation) => ({ | ||||
|               ]).map((translation) => ({ | ||||
|                 language: translation.language.data.attributes.code, | ||||
|                 title: item.title, | ||||
|                 subtitle: item.subtitle, | ||||
|  | ||||
| @ -65,7 +65,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => { | ||||
|   const posts = await sdk.getPostsSlugs(); | ||||
|   const paths: GetStaticPathsResult["paths"] = []; | ||||
| 
 | ||||
|   filterHasAttributes(posts.posts?.data, ["attributes"] as const).map((item) => { | ||||
|   filterHasAttributes(posts.posts?.data, ["attributes"]).map((item) => { | ||||
|     context.locales?.map((local) => | ||||
|       paths.push({ params: { slug: item.attributes.slug }, locale: local }) | ||||
|     ); | ||||
| @ -80,7 +80,7 @@ const terminalPostPage = (post: PostWithTranslations, router: NextRouter): strin | ||||
|   let result = ""; | ||||
|   if (router.locales && router.locale) { | ||||
|     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, | ||||
|       preferredLanguages: getDefaultPreferredLanguages(router.locale, router.locales), | ||||
|     }); | ||||
|  | ||||
| @ -176,7 +176,7 @@ const News = ({ ...otherProps }: Props): JSX.Element => { | ||||
|               href={`/news/${item.slug}`} | ||||
|               translations={filterHasAttributes(item._formatted.translations, [ | ||||
|                 "language.data.attributes.code", | ||||
|               ] as const).map(({ excerpt, body, language, ...otherAttributes }) => ({ | ||||
|               ]).map(({ excerpt, body, language, ...otherAttributes }) => ({ | ||||
|                 ...otherAttributes, | ||||
|                 description: containsHighlight(excerpt) | ||||
|                   ? excerpt | ||||
|  | ||||
| @ -125,11 +125,9 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => { | ||||
|                     </p> | ||||
| 
 | ||||
|                     <div className="flex flex-row flex-wrap place-content-center gap-2"> | ||||
|                       {filterHasAttributes(page.categories.data, ["attributes"] as const).map( | ||||
|                         (category) => ( | ||||
|                           <Chip key={category.id} text={category.attributes.name} /> | ||||
|                         ) | ||||
|                       )} | ||||
|                       {filterHasAttributes(page.categories.data, ["attributes"]).map((category) => ( | ||||
|                         <Chip key={category.id} text={category.attributes.name} /> | ||||
|                       ))} | ||||
|                     </div> | ||||
|                   </> | ||||
|                 )} | ||||
| @ -138,7 +136,7 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => { | ||||
|                   <> | ||||
|                     <p className="font-headers text-xl font-bold">{format("tags")}</p> | ||||
|                     <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 | ||||
|                           key={tag.id} | ||||
|                           text={ | ||||
| @ -159,36 +157,34 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => { | ||||
|               </div> | ||||
|             )} | ||||
| 
 | ||||
|             {filterHasAttributes(page.definitions, ["translations"] as const).map( | ||||
|               (definition, index) => ( | ||||
|                 <div key={index} className="mb-12"> | ||||
|                   <DefinitionCard | ||||
|                     source={{ | ||||
|                       name: definition.source?.data?.attributes?.name, | ||||
|                       url: definition.source?.data?.attributes?.content?.data?.attributes?.slug | ||||
|                         ? sJoin( | ||||
|                             "/contents/", | ||||
|                             definition.source.data.attributes.content.data.attributes.slug | ||||
|                           ) | ||||
|                         : sJoin( | ||||
|                             "/library/", | ||||
|                             definition.source?.data?.attributes?.ranged_content?.data?.attributes | ||||
|                               ?.library_item?.data?.attributes?.slug | ||||
|                           ), | ||||
|                     }} | ||||
|                     translations={definition.translations.map((translation) => ({ | ||||
|                       language: translation?.language?.data?.attributes?.code, | ||||
|                       definition: translation?.definition, | ||||
|                       status: translation?.status, | ||||
|                     }))} | ||||
|                     index={index + 1} | ||||
|                     categories={filterHasAttributes(definition.categories?.data, [ | ||||
|                       "attributes", | ||||
|                     ] as const).map((category) => category.attributes.short)} | ||||
|                   /> | ||||
|                 </div> | ||||
|               ) | ||||
|             )} | ||||
|             {filterHasAttributes(page.definitions, ["translations"]).map((definition, index) => ( | ||||
|               <div key={index} className="mb-12"> | ||||
|                 <DefinitionCard | ||||
|                   source={{ | ||||
|                     name: definition.source?.data?.attributes?.name, | ||||
|                     url: definition.source?.data?.attributes?.content?.data?.attributes?.slug | ||||
|                       ? sJoin( | ||||
|                           "/contents/", | ||||
|                           definition.source.data.attributes.content.data.attributes.slug | ||||
|                         ) | ||||
|                       : sJoin( | ||||
|                           "/library/", | ||||
|                           definition.source?.data?.attributes?.ranged_content?.data?.attributes | ||||
|                             ?.library_item?.data?.attributes?.slug | ||||
|                         ), | ||||
|                   }} | ||||
|                   translations={definition.translations.map((translation) => ({ | ||||
|                     language: translation?.language?.data?.attributes?.code, | ||||
|                     definition: translation?.definition, | ||||
|                     status: translation?.status, | ||||
|                   }))} | ||||
|                   index={index + 1} | ||||
|                   categories={filterHasAttributes(definition.categories?.data, ["attributes"]).map( | ||||
|                     (category) => category.attributes.short | ||||
|                   )} | ||||
|                 /> | ||||
|               </div> | ||||
|             ))} | ||||
| 
 | ||||
|             {isDefined(selectedTranslation.body) && ( | ||||
|               <div> | ||||
| @ -218,13 +214,13 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => { | ||||
|             : "" | ||||
|         }${ | ||||
|           page.definitions && page.definitions.length > 0 | ||||
|             ? `${filterHasAttributes(page.definitions, ["translations"] as const).map( | ||||
|             ? `${filterHasAttributes(page.definitions, ["translations"]).map( | ||||
|                 (definition, index) => | ||||
|                   `${prettyTerminalUnderlinedTitle(format("definition_x", { x: index + 1 }))}${ | ||||
|                     staticSmartLanguage({ | ||||
|                       items: filterHasAttributes(definition.translations, [ | ||||
|                         "language.data.attributes.code", | ||||
|                       ] as const), | ||||
|                       ]), | ||||
|                       languageExtractor: (item) => item.language.data.attributes.code, | ||||
|                       preferredLanguages: getDefaultPreferredLanguages( | ||||
|                         router.locale ?? "en", | ||||
| @ -267,12 +263,10 @@ export const getStaticProps: GetStaticProps = async (context) => { | ||||
|     const chipsGroups = { | ||||
|       [format("tags")]: filterHasAttributes(page.wikiPages.data[0].attributes.tags?.data, [ | ||||
|         "attributes", | ||||
|       ] as const).map( | ||||
|         (tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug) | ||||
|       ), | ||||
|       ]).map((tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug)), | ||||
|       [format("category", { count: Infinity })]: filterHasAttributes( | ||||
|         page.wikiPages.data[0].attributes.categories?.data, | ||||
|         ["attributes"] as const | ||||
|         ["attributes"] | ||||
|       ).map((category) => category.attributes.short), | ||||
|     }; | ||||
| 
 | ||||
| @ -313,7 +307,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => { | ||||
|   const sdk = getReadySdk(); | ||||
|   const contents = await sdk.getWikiPagesSlugs(); | ||||
|   const paths: GetStaticPathsResult["paths"] = []; | ||||
|   filterHasAttributes(contents.wikiPages?.data, ["attributes"] as const).map((wikiPage) => { | ||||
|   filterHasAttributes(contents.wikiPages?.data, ["attributes"]).map((wikiPage) => { | ||||
|     context.locales?.map((local) => | ||||
|       paths.push({ | ||||
|         params: { slug: wikiPage.attributes.slug }, | ||||
|  | ||||
| @ -45,10 +45,7 @@ const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props): | ||||
|   const setSubPanelOpened = useAtomSetter(atoms.layout.subPanelOpened); | ||||
|   const closeSubPanel = useCallback(() => setSubPanelOpened(false), [setSubPanelOpened]); | ||||
|   const ids = useMemo( | ||||
|     () => | ||||
|       filterHasAttributes(chronologyEras, ["attributes"] as const).map( | ||||
|         (era) => era.attributes.slug | ||||
|       ), | ||||
|     () => filterHasAttributes(chronologyEras, ["attributes"]).map((era) => era.attributes.slug), | ||||
|     [chronologyEras] | ||||
|   ); | ||||
| 
 | ||||
| @ -60,12 +57,12 @@ const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props): | ||||
| 
 | ||||
|       <HorizontalLine /> | ||||
| 
 | ||||
|       {filterHasAttributes(chronologyEras, ["attributes", "id"] as const).map((era, index) => ( | ||||
|       {filterHasAttributes(chronologyEras, ["attributes", "id"]).map((era, index) => ( | ||||
|         <Fragment key={era.id}> | ||||
|           <TranslatedNavOption | ||||
|             translations={filterHasAttributes(era.attributes.title, [ | ||||
|               "language.data.attributes.code", | ||||
|             ] as const).map((translation) => ({ | ||||
|             ]).map((translation) => ({ | ||||
|               language: translation.language.data.attributes.code, | ||||
|               title: translation.title, | ||||
|               subtitle: `${era.attributes.starting_year} → ${era.attributes.ending_year}`, | ||||
| @ -93,19 +90,19 @@ const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props): | ||||
|         className="mb-10" | ||||
|       /> | ||||
| 
 | ||||
|       {filterHasAttributes(chronologyEras, ["attributes"] as const).map((era) => ( | ||||
|       {filterHasAttributes(chronologyEras, ["attributes"]).map((era) => ( | ||||
|         <TranslatedChronologyEra | ||||
|           key={era.attributes.slug} | ||||
|           id={era.attributes.slug} | ||||
|           translations={filterHasAttributes(era.attributes.title, [ | ||||
|             "language.data.attributes.code", | ||||
|           ] as const).map((translation) => ({ | ||||
|           ]).map((translation) => ({ | ||||
|             language: translation.language.data.attributes.code, | ||||
|             title: translation.title, | ||||
|             description: translation.description, | ||||
|           }))} | ||||
|           fallback={{ title: prettySlug(era.attributes.slug) }} | ||||
|           chronologyItems={filterHasAttributes(chronologyItems, ["attributes"] as const).filter( | ||||
|           chronologyItems={filterHasAttributes(chronologyItems, ["attributes"]).filter( | ||||
|             (item) => | ||||
|               item.attributes.year >= era.attributes.starting_year && | ||||
|               item.attributes.year < era.attributes.ending_year | ||||
| @ -157,7 +154,7 @@ const ChronologyEra = ({ id, title, description, chronologyItems }: ChronologyEr | ||||
|   const yearGroups = (() => { | ||||
|     const memo: Props["chronologyItems"][] = []; | ||||
|     let currentYear = -Infinity; | ||||
|     filterHasAttributes(chronologyItems, ["attributes"] as const).forEach((item) => { | ||||
|     filterHasAttributes(chronologyItems, ["attributes"]).forEach((item) => { | ||||
|       if (currentYear === item.attributes.year) { | ||||
|         memo[memo.length - 1]?.push(item); | ||||
|       } else { | ||||
| @ -218,7 +215,7 @@ const ChronologyYear = ({ items }: ChronologyYearProps) => ( | ||||
|   <div | ||||
|     className="rounded-2xl target:my-4 target:bg-mid target:py-4" | ||||
|     id={generateAnchor(items[0]?.attributes?.year)}> | ||||
|     {filterHasAttributes(items, ["attributes.events"] as const).map((item, index) => ( | ||||
|     {filterHasAttributes(items, ["attributes.events"]).map((item, index) => ( | ||||
|       <ChronologyDate | ||||
|         key={index} | ||||
|         date={{ | ||||
| @ -284,7 +281,7 @@ export const ChronologyDate = ({ date, events }: ChronologyDateProps): JSX.Eleme | ||||
|       </p> | ||||
| 
 | ||||
|       <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 | ||||
|             id={generateAnchor(date.year, date.month, date.day)} | ||||
|             key={event.id} | ||||
|  | ||||
| @ -182,7 +182,7 @@ const Wiki = (props: Props): JSX.Element => { | ||||
|               href={`/wiki/${item.slug}`} | ||||
|               translations={filterHasAttributes(item._formatted.translations, [ | ||||
|                 "language.data.attributes.code", | ||||
|               ] as const).map( | ||||
|               ]).map( | ||||
|                 ({ aliases, summary, displayable_description, language, ...otherAttributes }) => ({ | ||||
|                   ...otherAttributes, | ||||
|                   subtitle: | ||||
| @ -201,10 +201,10 @@ const Wiki = (props: Props): JSX.Element => { | ||||
|               thumbnailRounded | ||||
|               thumbnailForceAspectRatio | ||||
|               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) | ||||
|               )} | ||||
|               bottomChips={filterHasAttributes(item.categories?.data, ["attributes"] as const).map( | ||||
|               bottomChips={filterHasAttributes(item.categories?.data, ["attributes"]).map( | ||||
|                 (category) => category.attributes.short | ||||
|               )} | ||||
|             /> | ||||
|  | ||||
| @ -43,7 +43,7 @@ interface WeaponPreviewProps { | ||||
| const WeaponPreview = ({ weapon }: WeaponPreviewProps): JSX.Element => ( | ||||
|   <TranslatedPreviewCard | ||||
|     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 }) => ({ | ||||
|         language: language.data.attributes.code, | ||||
|         title: name, | ||||
| @ -111,7 +111,7 @@ const WeaponPage = ({ weapon, primaryName, aliases, ...otherProps }: Props): JSX | ||||
|               <div className="grid gap-8"> | ||||
|                 {filterHasAttributes(weapon.weapon_group.data.attributes.weapons.data, [ | ||||
|                   "attributes", | ||||
|                 ] as const).map((groupWeapon) => ( | ||||
|                 ]).map((groupWeapon) => ( | ||||
|                   <WeaponPreview key={groupWeapon.id} weapon={groupWeapon.attributes} /> | ||||
|                 ))} | ||||
|               </div> | ||||
| @ -140,7 +140,7 @@ const WeaponPage = ({ weapon, primaryName, aliases, ...otherProps }: Props): JSX | ||||
| 
 | ||||
|       <div className="grid gap-8"> | ||||
|         <ElementsSeparator> | ||||
|           {filterHasAttributes(weapon.stories, ["translations"] as const).map((story, index) => ( | ||||
|           {filterHasAttributes(weapon.stories, ["translations"]).map((story, index) => ( | ||||
|             <WeaponStory | ||||
|               key={story.id} | ||||
|               id={intersectionIds[index]} | ||||
| @ -201,7 +201,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => { | ||||
|   const sdk = getReadySdk(); | ||||
|   const weapons = await sdk.getWeaponsSlugs(); | ||||
|   const paths: GetStaticPathsResult["paths"] = []; | ||||
|   filterHasAttributes(weapons.weaponStories?.data, ["attributes"] as const).map((item) => { | ||||
|   filterHasAttributes(weapons.weaponStories?.data, ["attributes"]).map((item) => { | ||||
|     context.locales?.map((local) => { | ||||
|       paths.push({ | ||||
|         params: { slug: item.attributes.slug }, | ||||
| @ -247,11 +247,9 @@ const WeaponStory = ({ story, storyNumber, id }: WeaponStoryProps): JSX.Element | ||||
| 
 | ||||
|       {story.categories && story.categories.data.length > 0 && ( | ||||
|         <div className="mb-12 flex flex-row flex-wrap place-content-center gap-2"> | ||||
|           {filterHasAttributes(story.categories.data, ["attributes.name"] as const).map( | ||||
|             (category) => ( | ||||
|               <Chip key={category.id} text={category.attributes.name} /> | ||||
|             ) | ||||
|           )} | ||||
|           {filterHasAttributes(story.categories.data, ["attributes.name"]).map((category) => ( | ||||
|             <Chip key={category.id} text={category.attributes.name} /> | ||||
|           ))} | ||||
|         </div> | ||||
|       )} | ||||
| 
 | ||||
| @ -286,7 +284,7 @@ export const getFilteredNames = ( | ||||
|   preferredLanguages: string[] | ||||
| ): string[] => { | ||||
|   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 | ||||
|     ); | ||||
|     if (filteredNames.length > 0) { | ||||
|  | ||||
| @ -186,7 +186,7 @@ const Weapons = (props: Props): JSX.Element => { | ||||
|               href={`/wiki/weapons/${item.slug}`} | ||||
|               translations={filterHasAttributes(item._formatted.translations, [ | ||||
|                 "language.data.attributes.code", | ||||
|               ] as const).map(({ description, language, names: [primaryName, ...aliases] }) => ({ | ||||
|               ]).map(({ description, language, names: [primaryName, ...aliases] }) => ({ | ||||
|                 language: language.data.attributes.code, | ||||
|                 title: primaryName, | ||||
|                 subtitle: aliases.join("・"), | ||||
| @ -203,7 +203,7 @@ const Weapons = (props: Props): JSX.Element => { | ||||
|                   ? [prettySlug(item.type.data.attributes.slug)] | ||||
|                   : undefined | ||||
|               } | ||||
|               bottomChips={filterHasAttributes(item.categories, ["attributes.short"] as const).map( | ||||
|               bottomChips={filterHasAttributes(item.categories, ["attributes.short"]).map( | ||||
|                 (category) => category.attributes.short | ||||
|               )} | ||||
|             /> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint