Added covers in the scanset
This commit is contained in:
parent
b3f3ddf60e
commit
822adbec48
|
@ -1,10 +1,14 @@
|
||||||
|
import Button from "components/Button";
|
||||||
|
import Chip from "components/Chip";
|
||||||
import Img, { getAssetURL, ImageQuality } from "components/Img";
|
import Img, { getAssetURL, ImageQuality } from "components/Img";
|
||||||
import LanguageSwitcher from "components/LanguageSwitcher";
|
import LanguageSwitcher from "components/LanguageSwitcher";
|
||||||
|
import RecorderChip from "components/RecorderChip";
|
||||||
|
import ToolTip from "components/ToolTip";
|
||||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||||
import { GetLibraryItemScansQuery } from "graphql/generated";
|
import { GetLibraryItemScansQuery } from "graphql/generated";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||||
import { getPreferredLanguage } from "queries/helpers";
|
import { getPreferredLanguage, getStatusDescription } from "queries/helpers";
|
||||||
import { Dispatch, SetStateAction, useEffect, useMemo, useState } from "react";
|
import { Dispatch, SetStateAction, useEffect, useMemo, useState } from "react";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -30,6 +34,20 @@ interface Props {
|
||||||
slug: string;
|
slug: string;
|
||||||
title: string;
|
title: string;
|
||||||
languages: AppStaticProps["languages"];
|
languages: AppStaticProps["languages"];
|
||||||
|
langui: AppStaticProps["langui"];
|
||||||
|
content: Exclude<
|
||||||
|
Exclude<
|
||||||
|
Exclude<
|
||||||
|
Exclude<
|
||||||
|
GetLibraryItemScansQuery["libraryItems"],
|
||||||
|
null | undefined
|
||||||
|
>["data"][number]["attributes"],
|
||||||
|
null | undefined
|
||||||
|
>["contents"],
|
||||||
|
null | undefined
|
||||||
|
>["data"][number]["attributes"],
|
||||||
|
null | undefined
|
||||||
|
>["content"];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ScanSet(props: Props): JSX.Element {
|
export default function ScanSet(props: Props): JSX.Element {
|
||||||
|
@ -41,6 +59,8 @@ export default function ScanSet(props: Props): JSX.Element {
|
||||||
slug,
|
slug,
|
||||||
title,
|
title,
|
||||||
languages,
|
languages,
|
||||||
|
langui,
|
||||||
|
content,
|
||||||
} = props;
|
} = props;
|
||||||
const appLayout = useAppLayout();
|
const appLayout = useAppLayout();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -73,24 +93,113 @@ export default function ScanSet(props: Props): JSX.Element {
|
||||||
}, [selectedScanIndex]);
|
}, [selectedScanIndex]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
{selectedScan && (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex flex-row place-items-center gap-4 text-base pb-6 pt-10 first-of-type:pt-0">
|
<div className="flex flex-row flex-wrap place-items-center gap-6 text-base pt-10 first-of-type:pt-0">
|
||||||
<h2
|
<h2 id={slug} className="text-2xl">
|
||||||
id={slug}
|
|
||||||
className="text-2xl"
|
|
||||||
>
|
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
|
<Chip>
|
||||||
|
{selectedScan.language?.data?.attributes?.code ===
|
||||||
|
selectedScan.source_language?.data?.attributes?.code
|
||||||
|
? "Scan"
|
||||||
|
: "Scanlation"}
|
||||||
|
</Chip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-row flex-wrap gap-4 pb-6 place-items-center">
|
||||||
|
{content?.data?.attributes?.slug && (
|
||||||
|
<Button href={`/contents/${content?.data?.attributes?.slug}`}>
|
||||||
|
{langui.open_content}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
<LanguageSwitcher
|
<LanguageSwitcher
|
||||||
languages={languages}
|
languages={languages}
|
||||||
locales={scanLocales}
|
locales={scanLocales}
|
||||||
localesIndex={selectedScanIndex}
|
localesIndex={selectedScanIndex}
|
||||||
setLocalesIndex={setSelectedScanIndex}
|
setLocalesIndex={setSelectedScanIndex}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div className="grid place-items-center place-content-center">
|
||||||
|
<p className="font-headers">{langui.status}:</p>
|
||||||
|
<ToolTip
|
||||||
|
content={getStatusDescription(selectedScan.status, langui)}
|
||||||
|
maxWidth={"20rem"}
|
||||||
|
>
|
||||||
|
<Chip>{selectedScan.status}</Chip>
|
||||||
|
</ToolTip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{selectedScan.scanners && selectedScan.scanners.data.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<p className="font-headers">{"Scanners"}:</p>
|
||||||
|
<div className="grid place-items-center place-content-center gap-2">
|
||||||
|
{selectedScan.scanners.data.map((scanner) => (
|
||||||
|
<>
|
||||||
|
{scanner.attributes && (
|
||||||
|
<RecorderChip
|
||||||
|
key={scanner.id}
|
||||||
|
langui={langui}
|
||||||
|
recorder={scanner.attributes}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{selectedScan.cleaners && selectedScan.cleaners.data.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<p className="font-headers">{"Cleaners"}:</p>
|
||||||
|
<div className="grid place-items-center place-content-center gap-2">
|
||||||
|
{selectedScan.cleaners.data.map((cleaner) => (
|
||||||
|
<>
|
||||||
|
{cleaner.attributes && (
|
||||||
|
<RecorderChip
|
||||||
|
key={cleaner.id}
|
||||||
|
langui={langui}
|
||||||
|
recorder={cleaner.attributes}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{selectedScan.typesetters &&
|
||||||
|
selectedScan.typesetters.data.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<p className="font-headers">{"Typesetters"}:</p>
|
||||||
|
<div className="grid place-items-center place-content-center gap-2">
|
||||||
|
{selectedScan.typesetters.data.map((typesetter) => (
|
||||||
|
<>
|
||||||
|
{typesetter.attributes && (
|
||||||
|
<RecorderChip
|
||||||
|
key={typesetter.id}
|
||||||
|
langui={langui}
|
||||||
|
recorder={typesetter.attributes}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{selectedScan.notes && (
|
||||||
|
<ToolTip content={selectedScan.notes}>
|
||||||
|
<Chip>{"Notes"}</Chip>
|
||||||
|
</ToolTip>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid gap-8 items-end mobile:grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(10rem,1fr))] pb-12 border-b-[3px] border-dotted last-of-type:border-0">
|
<div className="grid gap-8 items-end mobile:grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(10rem,1fr))] pb-12 border-b-[3px] border-dotted last-of-type:border-0">
|
||||||
{selectedScan?.pages?.data.map((page, index) => (
|
{selectedScan.pages?.data.map((page, index) => (
|
||||||
<div
|
<div
|
||||||
key={page.id}
|
key={page.id}
|
||||||
className="drop-shadow-shade-lg hover:scale-[1.02] cursor-pointer transition-transform"
|
className="drop-shadow-shade-lg hover:scale-[1.02] cursor-pointer transition-transform"
|
||||||
|
@ -114,5 +223,7 @@ export default function ScanSet(props: Props): JSX.Element {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
import Img, { getAssetURL, ImageQuality } from "components/Img";
|
||||||
|
import LanguageSwitcher from "components/LanguageSwitcher";
|
||||||
|
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||||
|
import {
|
||||||
|
GetLibraryItemScansQuery,
|
||||||
|
UploadImageFragment,
|
||||||
|
} from "graphql/generated";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||||
|
import { getPreferredLanguage } from "queries/helpers";
|
||||||
|
import { Dispatch, SetStateAction, useEffect, useMemo, useState } from "react";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
setLightboxOpen: Dispatch<SetStateAction<boolean>>;
|
||||||
|
setLightboxImages: Dispatch<SetStateAction<string[]>>;
|
||||||
|
setLightboxIndex: Dispatch<SetStateAction<number>>;
|
||||||
|
images: Exclude<
|
||||||
|
Exclude<
|
||||||
|
Exclude<
|
||||||
|
GetLibraryItemScansQuery["libraryItems"],
|
||||||
|
null | undefined
|
||||||
|
>["data"][number]["attributes"],
|
||||||
|
null | undefined
|
||||||
|
>["images"],
|
||||||
|
null | undefined
|
||||||
|
>;
|
||||||
|
languages: AppStaticProps["languages"];
|
||||||
|
langui: AppStaticProps["langui"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ScanSetCover(props: Props): JSX.Element {
|
||||||
|
const {
|
||||||
|
setLightboxOpen,
|
||||||
|
setLightboxImages,
|
||||||
|
setLightboxIndex,
|
||||||
|
images,
|
||||||
|
languages,
|
||||||
|
langui,
|
||||||
|
} = props;
|
||||||
|
const appLayout = useAppLayout();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const [selectedScan, setSelectedScan] = useState<Props["images"][number]>();
|
||||||
|
const scanLocales: Map<string, number> = new Map();
|
||||||
|
|
||||||
|
const [selectedScanIndex, setSelectedScanIndex] = useState<
|
||||||
|
number | undefined
|
||||||
|
>();
|
||||||
|
|
||||||
|
images.map((scan, index) => {
|
||||||
|
if (scan?.language?.data?.attributes?.code) {
|
||||||
|
scanLocales.set(scan.language.data.attributes.code, index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
useMemo(() => {
|
||||||
|
setSelectedScanIndex(
|
||||||
|
getPreferredLanguage(
|
||||||
|
appLayout.preferredLanguages ?? [router.locale],
|
||||||
|
scanLocales
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}, [appLayout.preferredLanguages]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedScanIndex !== undefined)
|
||||||
|
setSelectedScan(images[selectedScanIndex]);
|
||||||
|
}, [selectedScanIndex]);
|
||||||
|
|
||||||
|
const coverImages: UploadImageFragment[] = [];
|
||||||
|
if (selectedScan?.obi_belt?.full?.data?.attributes)
|
||||||
|
coverImages.push(selectedScan.obi_belt?.full?.data?.attributes);
|
||||||
|
if (selectedScan?.obi_belt?.inside_full?.data?.attributes)
|
||||||
|
coverImages.push(selectedScan.obi_belt?.inside_full?.data?.attributes);
|
||||||
|
if (selectedScan?.dust_jacket?.full?.data?.attributes)
|
||||||
|
coverImages.push(selectedScan.dust_jacket?.full?.data?.attributes);
|
||||||
|
if (selectedScan?.dust_jacket?.inside_full?.data?.attributes)
|
||||||
|
coverImages.push(selectedScan.dust_jacket?.inside_full?.data?.attributes);
|
||||||
|
if (selectedScan?.cover?.full?.data?.attributes)
|
||||||
|
coverImages.push(selectedScan.cover?.full?.data?.attributes);
|
||||||
|
if (selectedScan?.cover?.inside_full?.data?.attributes)
|
||||||
|
coverImages.push(selectedScan.cover?.inside_full?.data?.attributes);
|
||||||
|
|
||||||
|
if (coverImages.length > 0) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{selectedScan && (
|
||||||
|
<div>
|
||||||
|
<div className="flex flex-row flex-wrap place-items-center gap-6 text-base pt-10 first-of-type:pt-0">
|
||||||
|
<h2 className="text-2xl">{"Cover"}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-row flex-wrap gap-4 pb-6 place-items-center">
|
||||||
|
<LanguageSwitcher
|
||||||
|
languages={languages}
|
||||||
|
locales={scanLocales}
|
||||||
|
localesIndex={selectedScanIndex}
|
||||||
|
setLocalesIndex={setSelectedScanIndex}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid gap-8 items-end mobile:grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(10rem,1fr))] pb-12 border-b-[3px] border-dotted last-of-type:border-0">
|
||||||
|
{coverImages.map((image, index) => (
|
||||||
|
<div
|
||||||
|
key={image.url}
|
||||||
|
className="drop-shadow-shade-lg hover:scale-[1.02] cursor-pointer transition-transform"
|
||||||
|
onClick={() => {
|
||||||
|
const imgs: string[] = [];
|
||||||
|
coverImages.map((img) => {
|
||||||
|
if (img.url)
|
||||||
|
imgs.push(getAssetURL(img.url, ImageQuality.Large));
|
||||||
|
});
|
||||||
|
setLightboxOpen(true);
|
||||||
|
setLightboxImages(imgs);
|
||||||
|
setLightboxIndex(index);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Img image={image} quality={ImageQuality.Small} />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return <></>;
|
||||||
|
}
|
|
@ -6,6 +6,63 @@ query getLibraryItemScans($slug: String, $language_code: String) {
|
||||||
slug
|
slug
|
||||||
title
|
title
|
||||||
subtitle
|
subtitle
|
||||||
|
images {
|
||||||
|
cover {
|
||||||
|
full {
|
||||||
|
data {
|
||||||
|
attributes {
|
||||||
|
...uploadImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inside_full {
|
||||||
|
data {
|
||||||
|
attributes {
|
||||||
|
...uploadImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dust_jacket {
|
||||||
|
full {
|
||||||
|
data {
|
||||||
|
attributes {
|
||||||
|
...uploadImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inside_full {
|
||||||
|
data {
|
||||||
|
attributes {
|
||||||
|
...uploadImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obi_belt {
|
||||||
|
full {
|
||||||
|
data {
|
||||||
|
attributes {
|
||||||
|
...uploadImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inside_full {
|
||||||
|
data {
|
||||||
|
attributes {
|
||||||
|
...uploadImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
language {
|
||||||
|
data {
|
||||||
|
attributes {
|
||||||
|
code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
thumbnail {
|
thumbnail {
|
||||||
data {
|
data {
|
||||||
attributes {
|
attributes {
|
||||||
|
@ -29,6 +86,13 @@ query getLibraryItemScans($slug: String, $language_code: String) {
|
||||||
ending_time
|
ending_time
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
content {
|
||||||
|
data {
|
||||||
|
attributes {
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
scan_set {
|
scan_set {
|
||||||
status
|
status
|
||||||
language {
|
language {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import AppLayout from "components/AppLayout";
|
import AppLayout from "components/AppLayout";
|
||||||
import ScanSet from "components/Library/ScanSet";
|
import ScanSet from "components/Library/ScanSet";
|
||||||
|
import ScanSetCover from "components/Library/ScanSetCover";
|
||||||
import LightBox from "components/LightBox";
|
import LightBox from "components/LightBox";
|
||||||
import NavOption from "components/PanelComponents/NavOption";
|
import NavOption from "components/PanelComponents/NavOption";
|
||||||
import ReturnButton, {
|
import ReturnButton, {
|
||||||
|
@ -87,10 +88,23 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
displayOn={ReturnButtonType.mobile}
|
displayOn={ReturnButtonType.mobile}
|
||||||
className="mb-10"
|
className="mb-10"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{item?.images && (
|
||||||
|
<ScanSetCover
|
||||||
|
images={item.images}
|
||||||
|
setLightboxImages={setLightboxImages}
|
||||||
|
setLightboxIndex={setLightboxIndex}
|
||||||
|
setLightboxOpen={setLightboxOpen}
|
||||||
|
languages={languages}
|
||||||
|
langui={langui}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{item?.contents?.data.map((content) => (
|
{item?.contents?.data.map((content) => (
|
||||||
<>
|
<>
|
||||||
{content.attributes?.scan_set?.[0] && (
|
{content.attributes?.scan_set?.[0] && (
|
||||||
<ScanSet
|
<ScanSet
|
||||||
|
key={content.id}
|
||||||
scanSet={content.attributes.scan_set}
|
scanSet={content.attributes.scan_set}
|
||||||
setLightboxImages={setLightboxImages}
|
setLightboxImages={setLightboxImages}
|
||||||
setLightboxIndex={setLightboxIndex}
|
setLightboxIndex={setLightboxIndex}
|
||||||
|
@ -98,6 +112,8 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
||||||
slug={content.attributes.slug}
|
slug={content.attributes.slug}
|
||||||
title={prettySlug(content.attributes.slug, item.slug)}
|
title={prettySlug(content.attributes.slug, item.slug)}
|
||||||
languages={languages}
|
languages={languages}
|
||||||
|
langui={langui}
|
||||||
|
content={content.attributes.content}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
Loading…
Reference in New Issue