Improved the filterHasAttributes + Chip
This commit is contained in:
parent
ae25df8d72
commit
de3f385458
|
@ -188,14 +188,13 @@ export const AppLayout = ({
|
|||
return memo;
|
||||
}, [router.locale, router.locales]);
|
||||
|
||||
const currencyOptions = useMemo(() => {
|
||||
const memo: string[] = [];
|
||||
filterHasAttributes(currencies).map((currentCurrency) => {
|
||||
if (isDefinedAndNotEmpty(currentCurrency.attributes.code))
|
||||
memo.push(currentCurrency.attributes.code);
|
||||
});
|
||||
return memo;
|
||||
}, [currencies]);
|
||||
const currencyOptions = useMemo(
|
||||
() =>
|
||||
filterHasAttributes(currencies, ["attributes"] as const).map(
|
||||
(currentCurrency) => currentCurrency.attributes.code
|
||||
),
|
||||
[currencies]
|
||||
);
|
||||
|
||||
const [currencySelect, setCurrencySelect] = useState<number>(-1);
|
||||
|
||||
|
|
|
@ -7,12 +7,12 @@ import { cJoin } from "helpers/className";
|
|||
|
||||
interface Props {
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
text: string;
|
||||
}
|
||||
|
||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
|
||||
export const Chip = ({ className, children }: Props): JSX.Element => (
|
||||
export const Chip = ({ className, text }: Props): JSX.Element => (
|
||||
<div
|
||||
className={cJoin(
|
||||
`grid place-content-center place-items-center whitespace-nowrap rounded-full
|
||||
|
@ -21,6 +21,6 @@ export const Chip = ({ className, children }: Props): JSX.Element => (
|
|||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
{text}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -103,7 +103,7 @@ export const ScanSet = ({
|
|||
});
|
||||
|
||||
const pages = useMemo(
|
||||
() => selectedScan && filterHasAttributes(selectedScan.pages?.data),
|
||||
() => filterHasAttributes(selectedScan?.pages?.data, ["attributes"]),
|
||||
[selectedScan]
|
||||
);
|
||||
|
||||
|
@ -119,12 +119,15 @@ export const ScanSet = ({
|
|||
{title}
|
||||
</h2>
|
||||
|
||||
<Chip>
|
||||
{selectedScan.language?.data?.attributes?.code ===
|
||||
{/* TODO: Add Scan and Scanlation to langui */}
|
||||
<Chip
|
||||
text={
|
||||
selectedScan.language?.data?.attributes?.code ===
|
||||
selectedScan.source_language?.data?.attributes?.code
|
||||
? "Scan"
|
||||
: "Scanlation"}
|
||||
</Chip>
|
||||
: "Scanlation"
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row flex-wrap place-items-center gap-4 pb-6">
|
||||
|
@ -144,7 +147,7 @@ export const ScanSet = ({
|
|||
content={getStatusDescription(selectedScan.status, langui)}
|
||||
maxWidth={"20rem"}
|
||||
>
|
||||
<Chip>{selectedScan.status}</Chip>
|
||||
<Chip text={selectedScan.status} />
|
||||
</ToolTip>
|
||||
</div>
|
||||
|
||||
|
@ -153,16 +156,17 @@ export const ScanSet = ({
|
|||
{/* TODO: Add Scanner to langui */}
|
||||
<p className="font-headers font-bold">{"Scanners"}:</p>
|
||||
<div className="grid place-content-center place-items-center gap-2">
|
||||
{filterHasAttributes(selectedScan.scanners.data).map(
|
||||
(scanner) => (
|
||||
{filterHasAttributes(selectedScan.scanners.data, [
|
||||
"id",
|
||||
"attributes",
|
||||
] as const).map((scanner) => (
|
||||
<Fragment key={scanner.id}>
|
||||
<RecorderChip
|
||||
langui={langui}
|
||||
recorder={scanner.attributes}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@ -172,16 +176,17 @@ export const ScanSet = ({
|
|||
{/* TODO: Add Cleaners to langui */}
|
||||
<p className="font-headers font-bold">{"Cleaners"}:</p>
|
||||
<div className="grid place-content-center place-items-center gap-2">
|
||||
{filterHasAttributes(selectedScan.cleaners.data).map(
|
||||
(cleaner) => (
|
||||
{filterHasAttributes(selectedScan.cleaners.data, [
|
||||
"id",
|
||||
"attributes",
|
||||
] as const).map((cleaner) => (
|
||||
<Fragment key={cleaner.id}>
|
||||
<RecorderChip
|
||||
langui={langui}
|
||||
recorder={cleaner.attributes}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@ -189,27 +194,28 @@ export const ScanSet = ({
|
|||
{selectedScan.typesetters &&
|
||||
selectedScan.typesetters.data.length > 0 && (
|
||||
<div>
|
||||
{/* TODO: Add Cleaners to Typesetters */}
|
||||
{/* TODO: Add typesetter to langui */}
|
||||
<p className="font-headers font-bold">{"Typesetters"}:</p>
|
||||
<div className="grid place-content-center place-items-center gap-2">
|
||||
{filterHasAttributes(selectedScan.typesetters.data).map(
|
||||
(typesetter) => (
|
||||
{filterHasAttributes(selectedScan.typesetters.data, [
|
||||
"id",
|
||||
"attributes",
|
||||
] as const).map((typesetter) => (
|
||||
<Fragment key={typesetter.id}>
|
||||
<RecorderChip
|
||||
langui={langui}
|
||||
recorder={typesetter.attributes}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isDefinedAndNotEmpty(selectedScan.notes) && (
|
||||
<ToolTip content={selectedScan.notes}>
|
||||
{/* TODO: Add Notes to Typesetters */}
|
||||
<Chip>{"Notes"}</Chip>
|
||||
{/* TODO: Add Notes to langui */}
|
||||
<Chip text={"Notes"} />
|
||||
</ToolTip>
|
||||
)}
|
||||
</div>
|
||||
|
@ -224,13 +230,9 @@ export const ScanSet = ({
|
|||
className="cursor-pointer transition-transform
|
||||
drop-shadow-shade-lg hover:scale-[1.02]"
|
||||
onClick={() => {
|
||||
const images: string[] = [];
|
||||
pages.map((image) => {
|
||||
if (isDefinedAndNotEmpty(image.attributes.url))
|
||||
images.push(
|
||||
const images = pages.map((image) =>
|
||||
getAssetURL(image.attributes.url, ImageQuality.Large)
|
||||
);
|
||||
});
|
||||
openLightBox(images, index);
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -80,12 +80,15 @@ export const ScanSetCover = ({
|
|||
{"Cover"}
|
||||
</h2>
|
||||
|
||||
<Chip>
|
||||
{selectedScan.language?.data?.attributes?.code ===
|
||||
{/* TODO: Add Scan and Scanlation to langui */}
|
||||
<Chip
|
||||
text={
|
||||
selectedScan.language?.data?.attributes?.code ===
|
||||
selectedScan.source_language?.data?.attributes?.code
|
||||
? "Scan"
|
||||
: "Scanlation"}
|
||||
</Chip>
|
||||
: "Scanlation"
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row flex-wrap place-items-center gap-4 pb-6">
|
||||
|
@ -97,7 +100,7 @@ export const ScanSetCover = ({
|
|||
content={getStatusDescription(selectedScan.status, langui)}
|
||||
maxWidth={"20rem"}
|
||||
>
|
||||
<Chip>{selectedScan.status}</Chip>
|
||||
<Chip text={selectedScan.status} />
|
||||
</ToolTip>
|
||||
</div>
|
||||
|
||||
|
@ -106,16 +109,17 @@ export const ScanSetCover = ({
|
|||
{/* TODO: Add Scanner to langui */}
|
||||
<p className="font-headers font-bold">{"Scanners"}:</p>
|
||||
<div className="grid place-content-center place-items-center gap-2">
|
||||
{filterHasAttributes(selectedScan.scanners.data).map(
|
||||
(scanner) => (
|
||||
{filterHasAttributes(selectedScan.scanners.data, [
|
||||
"id",
|
||||
"attributes",
|
||||
] as const).map((scanner) => (
|
||||
<Fragment key={scanner.id}>
|
||||
<RecorderChip
|
||||
langui={langui}
|
||||
recorder={scanner.attributes}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@ -125,16 +129,17 @@ export const ScanSetCover = ({
|
|||
{/* TODO: Add Cleaners to langui */}
|
||||
<p className="font-headers font-bold">{"Cleaners"}:</p>
|
||||
<div className="grid place-content-center place-items-center gap-2">
|
||||
{filterHasAttributes(selectedScan.cleaners.data).map(
|
||||
(cleaner) => (
|
||||
{filterHasAttributes(selectedScan.cleaners.data, [
|
||||
"id",
|
||||
"attributes",
|
||||
] as const).map((cleaner) => (
|
||||
<Fragment key={cleaner.id}>
|
||||
<RecorderChip
|
||||
langui={langui}
|
||||
recorder={cleaner.attributes}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@ -145,16 +150,17 @@ export const ScanSetCover = ({
|
|||
{/* TODO: Add Cleaners to Typesetters */}
|
||||
<p className="font-headers font-bold">{"Typesetters"}:</p>
|
||||
<div className="grid place-content-center place-items-center gap-2">
|
||||
{filterHasAttributes(selectedScan.typesetters.data).map(
|
||||
(typesetter) => (
|
||||
{filterHasAttributes(selectedScan.typesetters.data, [
|
||||
"id",
|
||||
"attributes",
|
||||
] as const).map((typesetter) => (
|
||||
<Fragment key={typesetter.id}>
|
||||
<RecorderChip
|
||||
langui={langui}
|
||||
recorder={typesetter.attributes}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@ -171,11 +177,10 @@ export const ScanSetCover = ({
|
|||
className="cursor-pointer transition-transform
|
||||
drop-shadow-shade-lg hover:scale-[1.02]"
|
||||
onClick={() => {
|
||||
const imgs: string[] = [];
|
||||
coverImages.map((img) => {
|
||||
if (img.url)
|
||||
imgs.push(getAssetURL(img.url, ImageQuality.Large));
|
||||
});
|
||||
const imgs = coverImages.map((img) =>
|
||||
getAssetURL(img.url, ImageQuality.Large)
|
||||
);
|
||||
|
||||
openLightBox(imgs, index);
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -104,7 +104,7 @@ export const PostPage = ({
|
|||
)}
|
||||
maxWidth={"20rem"}
|
||||
>
|
||||
<Chip>{selectedTranslation.status}</Chip>
|
||||
<Chip text={selectedTranslation.status} />
|
||||
</ToolTip>
|
||||
</div>
|
||||
)}
|
||||
|
@ -113,7 +113,10 @@ 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).map((author) => (
|
||||
{filterHasAttributes(post.authors.data, [
|
||||
"id",
|
||||
"attributes",
|
||||
] as const).map((author) => (
|
||||
<Fragment key={author.id}>
|
||||
<RecorderChip
|
||||
langui={langui}
|
||||
|
|
|
@ -262,7 +262,7 @@ export const PreviewCard = ({
|
|||
{topChips && topChips.length > 0 && (
|
||||
<div className="grid grid-flow-col place-content-start gap-1 overflow-hidden">
|
||||
{topChips.map((text, index) => (
|
||||
<Chip key={index}>{text}</Chip>
|
||||
<Chip key={index} text={text} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
@ -281,9 +281,7 @@ export const PreviewCard = ({
|
|||
{bottomChips && bottomChips.length > 0 && (
|
||||
<div className="grid grid-flow-col place-content-start gap-1 overflow-hidden">
|
||||
{bottomChips.map((text, index) => (
|
||||
<Chip key={index} className="text-sm">
|
||||
{text}
|
||||
</Chip>
|
||||
<Chip key={index} className="text-sm" text={text} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -52,7 +52,7 @@ const PreviewLine = ({
|
|||
{topChips && topChips.length > 0 && (
|
||||
<div className="grid grid-flow-col place-content-start gap-1 overflow-hidden">
|
||||
{topChips.map((text, index) => (
|
||||
<Chip key={index}>{text}</Chip>
|
||||
<Chip key={index} text={text} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
@ -68,9 +68,7 @@ const PreviewLine = ({
|
|||
{bottomChips && bottomChips.length > 0 && (
|
||||
<div className="grid grid-flow-col place-content-start gap-1 overflow-hidden">
|
||||
{bottomChips.map((text, index) => (
|
||||
<Chip key={index} className="text-sm">
|
||||
{text}
|
||||
</Chip>
|
||||
<Chip key={index} className="text-sm" text={text} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -38,19 +38,19 @@ export const RecorderChip = ({ recorder, langui }: Props): JSX.Element => (
|
|||
{recorder.languages?.data && recorder.languages.data.length > 0 && (
|
||||
<div className="flex flex-row flex-wrap gap-1">
|
||||
<p>{langui.languages}:</p>
|
||||
{filterHasAttributes(recorder.languages.data).map(
|
||||
(language) => (
|
||||
{filterHasAttributes(recorder.languages.data, [
|
||||
"attributes",
|
||||
] as const).map((language) => (
|
||||
<Fragment key={language.attributes.code}>
|
||||
<Chip>{language.attributes.code.toUpperCase()}</Chip>
|
||||
<Chip text={language.attributes.code.toUpperCase()} />
|
||||
</Fragment>
|
||||
)
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{recorder.pronouns && (
|
||||
<div className="flex flex-row flex-wrap gap-1">
|
||||
<p>{langui.pronouns}:</p>
|
||||
<Chip>{recorder.pronouns}</Chip>
|
||||
<Chip text={recorder.pronouns} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -60,10 +60,13 @@ export const RecorderChip = ({ recorder, langui }: Props): JSX.Element => (
|
|||
}
|
||||
placement="top"
|
||||
>
|
||||
<Chip key={recorder.anonymous_code}>
|
||||
{recorder.anonymize
|
||||
<Chip
|
||||
key={recorder.anonymous_code}
|
||||
text={
|
||||
recorder.anonymize
|
||||
? `Recorder#${recorder.anonymous_code}`
|
||||
: recorder.username}
|
||||
</Chip>
|
||||
: recorder.username
|
||||
}
|
||||
/>
|
||||
</ToolTip>
|
||||
);
|
||||
|
|
|
@ -146,11 +146,13 @@ export const SmartList = <T,>({
|
|||
first-of-type:pt-0"
|
||||
>
|
||||
{name}
|
||||
<Chip>{`${groupItems.length} ${
|
||||
<Chip
|
||||
text={`${groupItems.length} ${
|
||||
groupItems.length <= 1
|
||||
? langui.result?.toLowerCase() ?? ""
|
||||
: langui.results?.toLowerCase() ?? ""
|
||||
}`}</Chip>
|
||||
}`}
|
||||
/>
|
||||
</h2>
|
||||
)}
|
||||
<div
|
||||
|
|
|
@ -80,12 +80,12 @@ export const ThumbnailHeader = ({
|
|||
<div className="flex flex-col place-items-center gap-2">
|
||||
<h3 className="text-xl">{langui.type}</h3>
|
||||
<div className="flex flex-row flex-wrap">
|
||||
<Chip>
|
||||
{type.data.attributes.titles &&
|
||||
type.data.attributes.titles.length > 0
|
||||
? type.data.attributes.titles[0]?.title
|
||||
: prettySlug(type.data.attributes.slug)}
|
||||
</Chip>
|
||||
<Chip
|
||||
text={
|
||||
type.data.attributes.titles?.[0]?.title ??
|
||||
prettySlug(type.data.attributes.slug)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@ -94,8 +94,11 @@ export const ThumbnailHeader = ({
|
|||
<div className="flex flex-col place-items-center gap-2">
|
||||
<h3 className="text-xl">{langui.categories}</h3>
|
||||
<div className="flex flex-row flex-wrap place-content-center gap-2">
|
||||
{filterHasAttributes(categories.data).map((category) => (
|
||||
<Chip key={category.id}>{category.attributes.name}</Chip>
|
||||
{filterHasAttributes(categories.data, [
|
||||
"attributes",
|
||||
"id",
|
||||
] as const).map((category) => (
|
||||
<Chip key={category.id} text={category.attributes.name} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -57,7 +57,7 @@ export const ChronologyItemComponent = ({
|
|||
filterHasAttributes(item.attributes.events, [
|
||||
"id",
|
||||
"translations",
|
||||
]).map((event) => (
|
||||
] as const).map((event) => (
|
||||
<Fragment key={event.id}>
|
||||
<div className="m-0">
|
||||
{filterDefined(event.translations).map(
|
||||
|
@ -77,7 +77,7 @@ export const ChronologyItemComponent = ({
|
|||
)}
|
||||
maxWidth={"20rem"}
|
||||
>
|
||||
<Chip>{translation.status}</Chip>
|
||||
<Chip text={translation.status} />
|
||||
</ToolTip>
|
||||
)}
|
||||
{translation.title ? (
|
||||
|
|
|
@ -62,7 +62,7 @@ const DefinitionCard = ({
|
|||
content={getStatusDescription(selectedTranslation.status, langui)}
|
||||
maxWidth={"20rem"}
|
||||
>
|
||||
<Chip>{selectedTranslation.status}</Chip>
|
||||
<Chip text={selectedTranslation.status} />
|
||||
</ToolTip>
|
||||
</>
|
||||
)}
|
||||
|
@ -72,7 +72,7 @@ const DefinitionCard = ({
|
|||
<Separator />
|
||||
<div className="flex flex-row gap-1">
|
||||
{categories.map((category, categoryIndex) => (
|
||||
<Chip key={categoryIndex}>{category}</Chip>
|
||||
<Chip key={categoryIndex} text={category} />
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
|
|
|
@ -60,20 +60,20 @@ export const prettyinlineTitle = (
|
|||
export const prettyItemType = (
|
||||
metadata: any,
|
||||
langui: AppStaticProps["langui"]
|
||||
): string | null | undefined => {
|
||||
): string => {
|
||||
switch (metadata.__typename) {
|
||||
case "ComponentMetadataAudio":
|
||||
return langui.audio;
|
||||
return langui.audio ?? "Audio";
|
||||
case "ComponentMetadataBooks":
|
||||
return langui.textual;
|
||||
return langui.textual ?? "Textual";
|
||||
case "ComponentMetadataGame":
|
||||
return langui.game;
|
||||
return langui.game ?? "Game";
|
||||
case "ComponentMetadataVideo":
|
||||
return langui.video;
|
||||
return langui.video ?? "Video";
|
||||
case "ComponentMetadataGroup":
|
||||
return langui.group;
|
||||
return langui.group ?? "Group";
|
||||
case "ComponentMetadataOther":
|
||||
return langui.other;
|
||||
return langui.other ?? "Other";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { AppStaticProps } from "../graphql/getAppStaticProps";
|
||||
import { SelectiveRequiredNonNullable } from "./types";
|
||||
import { PathDot, SelectiveNonNullable } from "./types/SelectiveNonNullable";
|
||||
import {
|
||||
Enum_Componentsetstextset_Status,
|
||||
GetLibraryItemQuery,
|
||||
|
@ -71,21 +71,29 @@ export const filterDefined = <T>(t: T[] | null | undefined): NonNullable<T>[] =>
|
|||
? []
|
||||
: (t.filter((item) => isDefined(item)) as NonNullable<T>[]);
|
||||
|
||||
export const filterHasAttributes = <T, P extends keyof NonNullable<T>>(
|
||||
export const filterHasAttributes = <T, P extends PathDot<T>>(
|
||||
t: T[] | null | undefined,
|
||||
attributes?: P[]
|
||||
): SelectiveRequiredNonNullable<NonNullable<T>, P>[] =>
|
||||
paths: readonly P[]
|
||||
): SelectiveNonNullable<T, typeof paths[number]>[] =>
|
||||
isUndefined(t)
|
||||
? []
|
||||
: (t.filter((item) => {
|
||||
: (t.filter((item) =>
|
||||
hasAttributes(item, paths)
|
||||
) as unknown as SelectiveNonNullable<T, typeof paths[number]>[]);
|
||||
|
||||
const hasAttributes = <T>(item: T, paths: readonly PathDot<T>[]): boolean => {
|
||||
if (isDefined(item)) {
|
||||
const attributesToCheck = attributes ?? (Object.keys(item) as P[]);
|
||||
return attributesToCheck.every((attribute) =>
|
||||
isDefined(item[attribute])
|
||||
return paths.every((path) => {
|
||||
const attributeToCheck = (path as string).split(".")[0];
|
||||
return (
|
||||
isDefined(attributeToCheck) &&
|
||||
Object.keys(item).includes(attributeToCheck) &&
|
||||
isDefined(item[attributeToCheck as keyof T])
|
||||
);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}) as unknown as SelectiveRequiredNonNullable<NonNullable<T>, P>[]);
|
||||
};
|
||||
|
||||
export const iterateMap = <K, V, U>(
|
||||
map: Map<K, V>,
|
||||
|
@ -95,7 +103,6 @@ export const iterateMap = <K, V, U>(
|
|||
const toList = [...map];
|
||||
if (isDefined(sortingFunction)) {
|
||||
toList.sort(sortingFunction);
|
||||
console.log(toList.sort(sortingFunction));
|
||||
}
|
||||
return toList.map(([key, value], index) => callbackfn(key, value, index));
|
||||
};
|
||||
|
|
|
@ -4,6 +4,8 @@ import {
|
|||
GetWikiPageQuery,
|
||||
} from "graphql/generated";
|
||||
|
||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
|
||||
type Post = NonNullable<
|
||||
NonNullable<GetPostQuery["posts"]>["data"][number]["attributes"]
|
||||
>;
|
||||
|
@ -12,6 +14,8 @@ export interface PostWithTranslations extends Omit<Post, "translations"> {
|
|||
translations: NonNullable<Post["translations"]>;
|
||||
}
|
||||
|
||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
|
||||
export type Content = NonNullable<
|
||||
NonNullable<GetContentTextQuery["contents"]>["data"][number]["attributes"]
|
||||
>;
|
||||
|
@ -20,6 +24,8 @@ export interface ContentWithTranslations extends Omit<Content, "translations"> {
|
|||
translations: NonNullable<Content["translations"]>;
|
||||
}
|
||||
|
||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
|
||||
type WikiPage = NonNullable<
|
||||
NonNullable<GetWikiPageQuery["wikiPages"]>["data"][number]["attributes"]
|
||||
>;
|
||||
|
@ -29,13 +35,13 @@ export interface WikiPageWithTranslations
|
|||
translations: NonNullable<WikiPage["translations"]>;
|
||||
}
|
||||
|
||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
|
||||
export type RequiredNonNullable<T> = {
|
||||
[P in keyof T]-?: NonNullable<T[P]>;
|
||||
};
|
||||
|
||||
export type SelectiveRequiredNonNullable<T, K extends keyof T> = Omit<T, K> & {
|
||||
[P in K]-?: NonNullable<T[P]>;
|
||||
};
|
||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
|
||||
export enum LibraryItemUserStatus {
|
||||
None = 0,
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
type JoinDot<K extends string, P extends string> = `${K}${"" extends K
|
||||
? ""
|
||||
: "."}${P}`;
|
||||
|
||||
export type PathDot<T, Acc extends string = ""> = T extends object
|
||||
? {
|
||||
[K in keyof T]: K extends string
|
||||
? JoinDot<Acc, K> | PathDot<T[K], JoinDot<Acc, K>>
|
||||
: never;
|
||||
}[keyof T]
|
||||
: Acc;
|
||||
|
||||
type PathHead<T extends unknown[]> = T extends [infer head]
|
||||
? head
|
||||
: T extends [infer head, ...infer rest]
|
||||
? head
|
||||
: "";
|
||||
|
||||
type PathRest<T extends unknown[]> = T extends [infer head, ...infer rest]
|
||||
? rest extends []
|
||||
? never
|
||||
: rest
|
||||
: never;
|
||||
|
||||
type PathLast<T extends unknown[]> = T["length"] extends 1 ? true : false;
|
||||
|
||||
type Recursive<T, Path extends unknown[]> = PathHead<Path> extends keyof T
|
||||
? Omit<T, PathHead<Path>> & {
|
||||
[P in PathHead<Path>]-?: PathLast<Path> extends true
|
||||
? NonNullable<T[P]>
|
||||
: Recursive<NonNullable<T[P]>, PathRest<Path>>;
|
||||
}
|
||||
: T;
|
||||
|
||||
type Split<
|
||||
Str,
|
||||
Cache extends string[] = []
|
||||
> = Str extends `${infer Method}.${infer PathRest}`
|
||||
? Split<PathRest, [...Cache, Method]>
|
||||
: Str extends `${infer PathLast}`
|
||||
? [...Cache, PathLast]
|
||||
: never;
|
||||
|
||||
export type SelectiveNonNullable<T, P extends PathDot<T>> = Recursive<
|
||||
NonNullable<T>,
|
||||
Split<P>
|
||||
>;
|
|
@ -78,7 +78,9 @@ const Channel = ({ langui, channel, ...otherProps }: Props): JSX.Element => {
|
|||
className="grid items-start gap-8 border-b-[3px] border-dotted pb-12 last-of-type:border-0
|
||||
desktop:grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))] mobile:grid-cols-2"
|
||||
>
|
||||
{filterHasAttributes(channel?.videos?.data).map((video) => (
|
||||
{filterHasAttributes(channel?.videos?.data, [
|
||||
"attributes",
|
||||
] as const).map((video) => (
|
||||
<Fragment key={video.id}>
|
||||
<PreviewCard
|
||||
href={`/archives/videos/v/${video.attributes.uid}`}
|
||||
|
@ -152,7 +154,9 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
|
|||
const channels = await sdk.getVideoChannelsSlugs();
|
||||
const paths: GetStaticPathsResult["paths"] = [];
|
||||
if (channels.videoChannels?.data)
|
||||
filterHasAttributes(channels.videoChannels.data).map((channel) => {
|
||||
filterHasAttributes(channels.videoChannels.data, [
|
||||
"attributes",
|
||||
] as const).map((channel) => {
|
||||
context.locales?.map((local) => {
|
||||
paths.push({
|
||||
params: { uid: channel.attributes.uid },
|
||||
|
|
|
@ -92,7 +92,7 @@ const Videos = ({ langui, videos, ...otherProps }: Props): JSX.Element => {
|
|||
() => (
|
||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||
<SmartList
|
||||
items={filterHasAttributes(videos)}
|
||||
items={filterHasAttributes(videos, ["id", "attributes"] as const)}
|
||||
getItemId={(item) => item.id}
|
||||
renderItem={({ item }) => (
|
||||
<>
|
||||
|
|
|
@ -238,11 +238,13 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
|
|||
const videos = await sdk.getVideosSlugs();
|
||||
const paths: GetStaticPathsResult["paths"] = [];
|
||||
if (videos.videos?.data)
|
||||
filterHasAttributes(videos.videos.data).map((video) => {
|
||||
filterHasAttributes(videos.videos.data, ["attributes"] as const).map(
|
||||
(video) => {
|
||||
context.locales?.map((local) => {
|
||||
paths.push({ params: { uid: video.attributes.uid }, locale: local });
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
return {
|
||||
paths,
|
||||
fallback: "blocking",
|
||||
|
|
|
@ -114,13 +114,13 @@ const Content = ({
|
|||
<p className="font-headers font-bold">
|
||||
{langui.source_language}:
|
||||
</p>
|
||||
<Chip>
|
||||
{prettyLanguage(
|
||||
<Chip
|
||||
text={prettyLanguage(
|
||||
selectedTranslation.text_set.source_language.data.attributes
|
||||
.code,
|
||||
languages
|
||||
)}
|
||||
</Chip>
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
@ -134,7 +134,7 @@ const Content = ({
|
|||
)}
|
||||
maxWidth={"20rem"}
|
||||
>
|
||||
<Chip>{selectedTranslation.text_set.status}</Chip>
|
||||
<Chip text={selectedTranslation.text_set.status} />
|
||||
</ToolTip>
|
||||
</div>
|
||||
|
||||
|
@ -146,7 +146,8 @@ const Content = ({
|
|||
</p>
|
||||
<div className="grid place-content-center place-items-center gap-2">
|
||||
{filterHasAttributes(
|
||||
selectedTranslation.text_set.transcribers.data
|
||||
selectedTranslation.text_set.transcribers.data,
|
||||
["attributes", "id"] as const
|
||||
).map((recorder) => (
|
||||
<Fragment key={recorder.id}>
|
||||
<RecorderChip
|
||||
|
@ -167,7 +168,8 @@ const Content = ({
|
|||
</p>
|
||||
<div className="grid place-content-center place-items-center gap-2">
|
||||
{filterHasAttributes(
|
||||
selectedTranslation.text_set.translators.data
|
||||
selectedTranslation.text_set.translators.data,
|
||||
["attributes", "id"] as const
|
||||
).map((recorder) => (
|
||||
<Fragment key={recorder.id}>
|
||||
<RecorderChip
|
||||
|
@ -188,7 +190,8 @@ const Content = ({
|
|||
</p>
|
||||
<div className="grid place-content-center place-items-center gap-2">
|
||||
{filterHasAttributes(
|
||||
selectedTranslation.text_set.proofreaders.data
|
||||
selectedTranslation.text_set.proofreaders.data,
|
||||
["attributes", "id"] as const
|
||||
).map((recorder) => (
|
||||
<Fragment key={recorder.id}>
|
||||
<RecorderChip
|
||||
|
@ -221,10 +224,12 @@ const Content = ({
|
|||
{langui.source}
|
||||
</p>
|
||||
<div className="mt-6 grid place-items-center gap-6 text-left">
|
||||
{content.ranged_contents.data.map((rangedContent) => {
|
||||
{filterHasAttributes(content.ranged_contents.data, [
|
||||
"attributes.library_item.data.attributes",
|
||||
"attributes.library_item.data.id",
|
||||
] as const).map((rangedContent) => {
|
||||
const libraryItem =
|
||||
rangedContent.attributes?.library_item?.data;
|
||||
if (libraryItem?.attributes && libraryItem.id) {
|
||||
rangedContent.attributes.library_item.data;
|
||||
return (
|
||||
<div
|
||||
key={libraryItem.attributes.slug}
|
||||
|
@ -250,9 +255,10 @@ const Content = ({
|
|||
]
|
||||
: []
|
||||
}
|
||||
bottomChips={libraryItem.attributes.categories?.data.map(
|
||||
(category) => category.attributes?.short ?? ""
|
||||
)}
|
||||
bottomChips={filterHasAttributes(
|
||||
libraryItem.attributes.categories?.data,
|
||||
["attributes"] as const
|
||||
).map((category) => category.attributes.short)}
|
||||
metadata={{
|
||||
currencies: currencies,
|
||||
release_date: libraryItem.attributes.release_date,
|
||||
|
@ -272,8 +278,6 @@ const Content = ({
|
|||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return <></>;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -507,14 +511,16 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
|
|||
const sdk = getReadySdk();
|
||||
const contents = await sdk.getContentsSlugs();
|
||||
const paths: GetStaticPathsResult["paths"] = [];
|
||||
filterHasAttributes(contents.contents?.data).map((item) => {
|
||||
filterHasAttributes(contents.contents?.data, ["attributes"] as const).map(
|
||||
(item) => {
|
||||
context.locales?.map((local) => {
|
||||
paths.push({
|
||||
params: { slug: item.attributes.slug },
|
||||
locale: local,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
return {
|
||||
paths,
|
||||
fallback: "blocking",
|
||||
|
|
|
@ -21,8 +21,8 @@ import { Icon } from "components/Ico";
|
|||
import { filterDefined, filterHasAttributes } from "helpers/others";
|
||||
import { GetContentsQuery } from "graphql/generated";
|
||||
import { SmartList } from "components/SmartList";
|
||||
import { SelectiveRequiredNonNullable } from "helpers/types";
|
||||
import { ContentPlaceholder } from "components/PanelComponents/ContentPlaceholder";
|
||||
import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable";
|
||||
|
||||
/*
|
||||
* ╭─────────────╮
|
||||
|
@ -73,7 +73,7 @@ const Contents = ({
|
|||
|
||||
const groupingFunction = useCallback(
|
||||
(
|
||||
item: SelectiveRequiredNonNullable<
|
||||
item: SelectiveNonNullable<
|
||||
NonNullable<GetContentsQuery["contents"]>["data"][number],
|
||||
"attributes" | "id"
|
||||
>
|
||||
|
@ -81,7 +81,8 @@ const Contents = ({
|
|||
switch (groupingMethod) {
|
||||
case 0: {
|
||||
const categories = filterHasAttributes(
|
||||
item.attributes.categories?.data
|
||||
item.attributes.categories?.data,
|
||||
["attributes"] as const
|
||||
);
|
||||
if (categories.length > 0) {
|
||||
return categories.map((category) => category.attributes.name);
|
||||
|
@ -106,10 +107,7 @@ const Contents = ({
|
|||
|
||||
const filteringFunction = useCallback(
|
||||
(
|
||||
item: SelectiveRequiredNonNullable<
|
||||
Props["contents"][number],
|
||||
"attributes" | "id"
|
||||
>
|
||||
item: SelectiveNonNullable<Props["contents"][number], "attributes" | "id">
|
||||
) => {
|
||||
if (
|
||||
effectiveCombineRelatedContent &&
|
||||
|
@ -217,7 +215,7 @@ const Contents = ({
|
|||
() => (
|
||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||
<SmartList
|
||||
items={filterHasAttributes(contents)}
|
||||
items={filterHasAttributes(contents, ["attributes", "id"] as const)}
|
||||
getItemId={(item) => item.id}
|
||||
renderItem={({ item }) => (
|
||||
<>
|
||||
|
|
|
@ -60,7 +60,7 @@ const CheckupContents = ({ contents, ...otherProps }: Props): JSX.Element => {
|
|||
/>
|
||||
<p>{line.subitems.join(" -> ")}</p>
|
||||
<p>{line.name}</p>
|
||||
<Chip>{line.type}</Chip>
|
||||
<Chip text={line.type} />
|
||||
<Chip
|
||||
className={
|
||||
line.severity === "Very High"
|
||||
|
@ -71,9 +71,8 @@ const CheckupContents = ({ contents, ...otherProps }: Props): JSX.Element => {
|
|||
? "bg-[#fff344] !opacity-100"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
{line.severity}
|
||||
</Chip>
|
||||
text={line.severity}
|
||||
/>
|
||||
<ToolTip content={line.recommandation} placement="left">
|
||||
<p>{line.description}</p>
|
||||
</ToolTip>
|
||||
|
@ -138,7 +137,8 @@ const testingContent = (contents: Props["contents"]): Report => {
|
|||
lines: [],
|
||||
};
|
||||
|
||||
filterHasAttributes(contents.contents?.data).map((content) => {
|
||||
filterHasAttributes(contents.contents?.data, ["attributes"] as const).map(
|
||||
(content) => {
|
||||
const backendUrl = `${process.env.NEXT_PUBLIC_URL_CMS}/admin/content-manager/collectionType/api::content.content/${content.id}`;
|
||||
const frontendUrl = `${process.env.NEXT_PUBLIC_URL_SELF}/contents/${content.attributes.slug}`;
|
||||
|
||||
|
@ -452,6 +452,7 @@ const testingContent = (contents: Props["contents"]): Report => {
|
|||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
return report;
|
||||
};
|
||||
|
|
|
@ -65,7 +65,7 @@ const CheckupLibraryItems = ({
|
|||
/>
|
||||
<p>{line.subitems.join(" -> ")}</p>
|
||||
<p>{line.name}</p>
|
||||
<Chip>{line.type}</Chip>
|
||||
<Chip text={line.type} />
|
||||
<Chip
|
||||
className={
|
||||
line.severity === "Very High"
|
||||
|
@ -76,9 +76,8 @@ const CheckupLibraryItems = ({
|
|||
? "bg-[#fff344] !opacity-100"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
{line.severity}
|
||||
</Chip>
|
||||
text={line.severity}
|
||||
/>
|
||||
<ToolTip content={line.recommandation} placement="left">
|
||||
<p>{line.description}</p>
|
||||
</ToolTip>
|
||||
|
|
|
@ -221,7 +221,8 @@ const LibrarySlug = ({
|
|||
{item.urls?.length ? (
|
||||
<div className="flex flex-row place-items-center gap-3">
|
||||
<p>{langui.available_at}</p>
|
||||
{filterHasAttributes(item.urls).map((url, index) => (
|
||||
{filterHasAttributes(item.urls, ["url"] as const).map(
|
||||
(url, index) => (
|
||||
<Fragment key={index}>
|
||||
<Button
|
||||
href={url.url}
|
||||
|
@ -229,7 +230,8 @@ const LibrarySlug = ({
|
|||
text={prettyURL(url.url)}
|
||||
/>
|
||||
</Fragment>
|
||||
))}
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<p>{langui.item_not_available}</p>
|
||||
|
@ -246,20 +248,20 @@ const LibrarySlug = ({
|
|||
className="grid w-full grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))] items-end
|
||||
gap-8"
|
||||
>
|
||||
{filterHasAttributes(item.gallery.data).map(
|
||||
(galleryItem, index) => (
|
||||
{filterHasAttributes(item.gallery.data, [
|
||||
"id",
|
||||
"attributes",
|
||||
] as const).map((galleryItem, index) => (
|
||||
<Fragment key={galleryItem.id}>
|
||||
<div
|
||||
className="relative aspect-square cursor-pointer
|
||||
transition-transform hover:scale-[1.02]"
|
||||
onClick={() => {
|
||||
const images: string[] = filterHasAttributes(
|
||||
item.gallery?.data
|
||||
item.gallery?.data,
|
||||
["attributes"] as const
|
||||
).map((image) =>
|
||||
getAssetURL(
|
||||
image.attributes.url,
|
||||
ImageQuality.Large
|
||||
)
|
||||
getAssetURL(image.attributes.url, ImageQuality.Large)
|
||||
);
|
||||
openLightBox(images, index);
|
||||
}}
|
||||
|
@ -271,8 +273,7 @@ const LibrarySlug = ({
|
|||
/>
|
||||
</div>
|
||||
</Fragment>
|
||||
)
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@ -288,9 +289,9 @@ const LibrarySlug = ({
|
|||
<div className="grid place-content-start place-items-center">
|
||||
<h3 className="text-xl">{langui.type}</h3>
|
||||
<div className="grid grid-flow-col gap-1">
|
||||
<Chip>{prettyItemType(item.metadata[0], langui)}</Chip>
|
||||
<Chip text={prettyItemType(item.metadata[0], langui)} />
|
||||
{"›"}
|
||||
<Chip>{prettyItemSubType(item.metadata[0])}</Chip>
|
||||
<Chip text={prettyItemSubType(item.metadata[0])} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@ -331,8 +332,10 @@ const LibrarySlug = ({
|
|||
<div className="flex flex-col place-items-center gap-2">
|
||||
<h3 className="text-xl">{langui.categories}</h3>
|
||||
<div className="flex flex-row flex-wrap place-content-center gap-2">
|
||||
{item.categories.data.map((category) => (
|
||||
<Chip key={category.id}>{category.attributes?.name}</Chip>
|
||||
{filterHasAttributes(item.categories.data, [
|
||||
"attributes",
|
||||
] as const).map((category) => (
|
||||
<Chip key={category.id} text={category.attributes.name} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -458,7 +461,10 @@ const LibrarySlug = ({
|
|||
className="grid w-full grid-cols-[repeat(auto-fill,minmax(15rem,1fr))]
|
||||
items-end gap-8 mobile:grid-cols-2 thin:grid-cols-1"
|
||||
>
|
||||
{filterHasAttributes(item.subitems.data).map((subitem) => (
|
||||
{filterHasAttributes(item.subitems.data, [
|
||||
"id",
|
||||
"attributes",
|
||||
] as const).map((subitem) => (
|
||||
<Fragment key={subitem.id}>
|
||||
<PreviewCard
|
||||
href={`/library/${subitem.attributes.slug}`}
|
||||
|
@ -506,8 +512,9 @@ const LibrarySlug = ({
|
|||
/>
|
||||
)}
|
||||
<div className="grid w-full gap-4">
|
||||
{filterHasAttributes(item.contents.data).map(
|
||||
(rangedContent) => (
|
||||
{filterHasAttributes(item.contents.data, [
|
||||
"attributes",
|
||||
] as const).map((rangedContent) => (
|
||||
<ContentLine
|
||||
content={
|
||||
rangedContent.attributes.content?.data?.attributes
|
||||
|
@ -524,14 +531,15 @@ const LibrarySlug = ({
|
|||
})),
|
||||
categories: filterHasAttributes(
|
||||
rangedContent.attributes.content.data.attributes
|
||||
.categories?.data
|
||||
.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?.slug
|
||||
rangedContent.attributes.content.data.attributes
|
||||
.type?.data?.attributes?.slug
|
||||
),
|
||||
slug: rangedContent.attributes.content.data
|
||||
.attributes.slug,
|
||||
|
@ -554,8 +562,7 @@ const LibrarySlug = ({
|
|||
rangedContent.attributes.scan_set.length > 0
|
||||
}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@ -643,7 +650,9 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
|
|||
const sdk = getReadySdk();
|
||||
const libraryItems = await sdk.getLibraryItemsSlugs();
|
||||
const paths: GetStaticPathsResult["paths"] = [];
|
||||
filterHasAttributes(libraryItems.libraryItems?.data).map((item) => {
|
||||
filterHasAttributes(libraryItems.libraryItems?.data, [
|
||||
"attributes",
|
||||
] as const).map((item) => {
|
||||
context.locales?.map((local) =>
|
||||
paths.push({ params: { slug: item.attributes.slug }, locale: local })
|
||||
);
|
||||
|
@ -702,8 +711,6 @@ const ContentLine = ({
|
|||
),
|
||||
});
|
||||
|
||||
console.log(prettySlug(slug, parentSlug));
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cJoin(
|
||||
|
@ -730,13 +737,13 @@ const ContentLine = ({
|
|||
</a>
|
||||
<div className="flex flex-row flex-wrap gap-1">
|
||||
{content?.categories?.map((category, index) => (
|
||||
<Chip key={index}>{category}</Chip>
|
||||
<Chip key={index} text={category} />
|
||||
))}
|
||||
</div>
|
||||
<p className="h-4 w-full border-b-2 border-dotted border-black opacity-30"></p>
|
||||
<p>{rangeStart}</p>
|
||||
{content?.type && (
|
||||
<Chip className="justify-self-end thin:hidden">{content.type}</Chip>
|
||||
<Chip className="justify-self-end thin:hidden" text={content.type} />
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
|
|
|
@ -177,7 +177,9 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
|
|||
const sdk = getReadySdk();
|
||||
const libraryItems = await sdk.getLibraryItemsSlugs({});
|
||||
const paths: GetStaticPathsResult["paths"] = [];
|
||||
filterHasAttributes(libraryItems.libraryItems?.data).map((item) => {
|
||||
filterHasAttributes(libraryItems.libraryItems?.data, [
|
||||
"attributes",
|
||||
] as const).map((item) => {
|
||||
context.locales?.map((local) =>
|
||||
paths.push({ params: { slug: item.attributes.slug }, locale: local })
|
||||
);
|
||||
|
|
|
@ -17,10 +17,7 @@ import {
|
|||
prettyinlineTitle,
|
||||
prettyItemSubType,
|
||||
} from "helpers/formatters";
|
||||
import {
|
||||
LibraryItemUserStatus,
|
||||
SelectiveRequiredNonNullable,
|
||||
} from "helpers/types";
|
||||
import { LibraryItemUserStatus } from "helpers/types";
|
||||
import { Icon } from "components/Ico";
|
||||
import { WithLabel } from "components/Inputs/WithLabel";
|
||||
import { TextInput } from "components/Inputs/TextInput";
|
||||
|
@ -35,6 +32,7 @@ import { ContentPlaceholder } from "components/PanelComponents/ContentPlaceholde
|
|||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { convertPrice } from "helpers/numbers";
|
||||
import { SmartList } from "components/SmartList";
|
||||
import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable";
|
||||
|
||||
/*
|
||||
* ╭─────────────╮
|
||||
|
@ -97,10 +95,7 @@ const Library = ({
|
|||
|
||||
const filteringFunction = useCallback(
|
||||
(
|
||||
item: SelectiveRequiredNonNullable<
|
||||
Props["items"][number],
|
||||
"attributes" | "id"
|
||||
>
|
||||
item: SelectiveNonNullable<Props["items"][number], "attributes" | "id">
|
||||
) => {
|
||||
if (!showSubitems && !item.attributes.root_item) return false;
|
||||
if (
|
||||
|
@ -143,14 +138,8 @@ const Library = ({
|
|||
|
||||
const sortingFunction = useCallback(
|
||||
(
|
||||
a: SelectiveRequiredNonNullable<
|
||||
Props["items"][number],
|
||||
"attributes" | "id"
|
||||
>,
|
||||
b: SelectiveRequiredNonNullable<
|
||||
Props["items"][number],
|
||||
"attributes" | "id"
|
||||
>
|
||||
a: SelectiveNonNullable<Props["items"][number], "attributes" | "id">,
|
||||
b: SelectiveNonNullable<Props["items"][number], "attributes" | "id">
|
||||
) => {
|
||||
switch (sortingMethod) {
|
||||
case 0: {
|
||||
|
@ -193,15 +182,13 @@ const Library = ({
|
|||
|
||||
const groupingFunction = useCallback(
|
||||
(
|
||||
item: SelectiveRequiredNonNullable<
|
||||
Props["items"][number],
|
||||
"attributes" | "id"
|
||||
>
|
||||
item: SelectiveNonNullable<Props["items"][number], "attributes" | "id">
|
||||
): string[] => {
|
||||
switch (groupingMethod) {
|
||||
case 0: {
|
||||
const categories = filterHasAttributes(
|
||||
item.attributes.categories?.data
|
||||
item.attributes.categories?.data,
|
||||
["attributes"] as const
|
||||
);
|
||||
if (categories.length > 0) {
|
||||
return categories.map((category) => category.attributes.name);
|
||||
|
@ -406,7 +393,7 @@ const Library = ({
|
|||
() => (
|
||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||
<SmartList
|
||||
items={filterHasAttributes(items)}
|
||||
items={filterHasAttributes(items, ["id", "attributes"] as const)}
|
||||
getItemId={(item) => item.id}
|
||||
renderItem={({ item }) => (
|
||||
<PreviewCard
|
||||
|
|
|
@ -47,11 +47,13 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
|
|||
const posts = await sdk.getPostsSlugs();
|
||||
const paths: GetStaticPathsResult["paths"] = [];
|
||||
|
||||
filterHasAttributes(posts.posts?.data).map((item) => {
|
||||
filterHasAttributes(posts.posts?.data, ["attributes"] as const).map(
|
||||
(item) => {
|
||||
context.locales?.map((local) =>
|
||||
paths.push({ params: { slug: item.attributes.slug }, locale: local })
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
return {
|
||||
paths,
|
||||
fallback: "blocking",
|
||||
|
|
|
@ -97,7 +97,7 @@ const News = ({
|
|||
() => (
|
||||
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
||||
<SmartList
|
||||
items={filterHasAttributes(posts)}
|
||||
items={filterHasAttributes(posts, ["attributes", "id"] as const)}
|
||||
getItemId={(post) => post.id}
|
||||
langui={langui}
|
||||
renderItem={({ item: post }) => (
|
||||
|
|
|
@ -100,8 +100,10 @@ const WikiPage = ({
|
|||
{langui.categories}
|
||||
</p>
|
||||
<div className="flex flex-row flex-wrap place-content-center gap-2">
|
||||
{page.categories?.data.map((category) => (
|
||||
<Chip key={category.id}>{category.attributes?.name}</Chip>
|
||||
{filterHasAttributes(page.categories?.data, [
|
||||
"attributes",
|
||||
] as const).map((category) => (
|
||||
<Chip key={category.id} text={category.attributes.name} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -116,30 +118,28 @@ const WikiPage = ({
|
|||
</div>
|
||||
)}
|
||||
|
||||
{filterHasAttributes(page.definitions, ["translations"]).map(
|
||||
(definition, index) => (
|
||||
{filterHasAttributes(page.definitions, [
|
||||
"translations",
|
||||
] as const).map((definition, index) => (
|
||||
<>
|
||||
<DefinitionCard
|
||||
key={index}
|
||||
source={definition.source?.data?.attributes?.name}
|
||||
translations={filterHasAttributes(
|
||||
definition.translations
|
||||
).map((translation) => ({
|
||||
language: translation.language.data?.attributes?.code,
|
||||
definition: translation.definition,
|
||||
status: translation.status,
|
||||
translations={definition.translations.map((translation) => ({
|
||||
language: translation?.language?.data?.attributes?.code,
|
||||
definition: translation?.definition,
|
||||
status: translation?.status,
|
||||
}))}
|
||||
index={index + 1}
|
||||
languages={languages}
|
||||
langui={langui}
|
||||
categories={filterHasAttributes(
|
||||
definition.categories?.data
|
||||
).map((category) => category.attributes.short)}
|
||||
categories={filterHasAttributes(definition.categories?.data, [
|
||||
"attributes",
|
||||
] as const).map((category) => category.attributes.short)}
|
||||
/>
|
||||
<br />
|
||||
</>
|
||||
)
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</ContentPanel>
|
||||
|
@ -194,14 +194,16 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
|
|||
const sdk = getReadySdk();
|
||||
const contents = await sdk.getWikiPagesSlugs();
|
||||
const paths: GetStaticPathsResult["paths"] = [];
|
||||
filterHasAttributes(contents.wikiPages?.data).map((wikiPage) => {
|
||||
filterHasAttributes(contents.wikiPages?.data, ["attributes"] as const).map(
|
||||
(wikiPage) => {
|
||||
context.locales?.map((local) =>
|
||||
paths.push({
|
||||
params: { slug: wikiPage.attributes.slug },
|
||||
locale: local,
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
return {
|
||||
paths,
|
||||
fallback: "blocking",
|
||||
|
|
|
@ -74,7 +74,8 @@ const Chronology = ({
|
|||
horizontalLine
|
||||
/>
|
||||
|
||||
{filterHasAttributes(chronologyEras).map((era) => (
|
||||
{filterHasAttributes(chronologyEras, ["attributes", "id"] as const).map(
|
||||
(era) => (
|
||||
<Fragment key={era.id}>
|
||||
<NavOption
|
||||
url={`#${era.attributes.slug}`}
|
||||
|
@ -89,7 +90,8 @@ const Chronology = ({
|
|||
border
|
||||
/>
|
||||
</Fragment>
|
||||
))}
|
||||
)
|
||||
)}
|
||||
</SubPanel>
|
||||
),
|
||||
[chronologyEras, langui]
|
||||
|
|
|
@ -120,9 +120,11 @@ const Wiki = ({
|
|||
icon={Icon.ChevronLeft}
|
||||
/>
|
||||
)}
|
||||
{filterHasAttributes(filteredPages).map((page) => (
|
||||
{filterHasAttributes(filteredPages, [
|
||||
"id",
|
||||
"attributes.translations",
|
||||
] as const).map((page) => (
|
||||
<Fragment key={page.id}>
|
||||
{page.attributes.translations && (
|
||||
<TranslatedPreviewCard
|
||||
href={`/wiki/${page.attributes.slug}`}
|
||||
translations={page.attributes.translations.map(
|
||||
|
@ -149,7 +151,6 @@ const Wiki = ({
|
|||
(category) => category.attributes?.short ?? ""
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue