Use new content groups instead of previous/next

This commit is contained in:
DrMint 2022-05-15 01:15:29 +02:00
parent 461bd08a3d
commit 2e62f25fb5
6 changed files with 346 additions and 338 deletions

View File

@ -28,7 +28,7 @@ interface Props {
topChips?: string[];
bottomChips?: string[];
keepInfoVisible?: boolean;
stackEffect?: boolean;
stackNumber?: number;
metadata?: {
currencies?: AppStaticProps["currencies"];
release_date?: DatePickerFragment | null;
@ -53,7 +53,7 @@ export function PreviewCard(props: Immutable<Props>): JSX.Element {
title,
subtitle,
description,
stackEffect = false,
stackNumber = 0,
topChips,
bottomChips,
keepInfoVisible,
@ -117,20 +117,27 @@ export function PreviewCard(props: Immutable<Props>): JSX.Element {
hover:[--play-opacity:100] transition-transform
[--stacked-top:0] hover:[--stacked-top:1]"
>
{thumbnail && stackEffect && (
{thumbnail && stackNumber > 0 && (
<>
<Img
className={`rounded-t-md absolute -top-[var(--stacked-top)*1.3rem]
opacity-30 scale-[0.88] transition-[top]`}
image={thumbnail}
quality={ImageQuality.Medium}
/>
<Img
className={`rounded-t-md absolute -top-[var(--stacked-top)*0.6rem]
opacity-60 scale-95 transition-[top]`}
className="opacity-30 rounded-t-md overflow-hidden absolute transition-[top_transform]
-top-[var(--stacked-top)*1.5rem]
scale-[calc(1-0.15*var(--stacked-top))]"
image={thumbnail}
quality={ImageQuality.Medium}
/>
<div
className="bg-light rounded-t-md overflow-hidden absolute transition-[top_transform]
-top-[var(--stacked-top)*0.7rem]
scale-[calc(1-0.06*var(--stacked-top))]"
>
<Img
className="opacity-70"
image={thumbnail}
quality={ImageQuality.Medium}
/>
</div>
</>
)}
@ -145,6 +152,14 @@ export function PreviewCard(props: Immutable<Props>): JSX.Element {
image={thumbnail}
quality={ImageQuality.Medium}
/>
{stackNumber > 0 && (
<div
className="absolute right-2 top-2 text-light bg-black
bg-opacity-60 px-2 rounded-full"
>
{stackNumber}
</div>
)}
{hoverlay && hoverlay.__typename === "Video" && (
<>
<div

View File

@ -1,75 +1,64 @@
query devGetContents {
contents(pagination: { limit: -1 }) {
data {
id
attributes {
slug
categories {
data {
id
}
}
type {
data {
id
}
}
contents(pagination: { limit: -1 }) {
data {
id
attributes {
slug
categories {
data {
id
}
}
type {
data {
id
}
}
ranged_contents {
data {
id
}
}
translations {
language {
data {
id
}
}
title
description
text_set {
source_language {
data {
id
}
}
status
transcribers {
data {
id
}
}
translators {
data {
id
}
}
proofreaders {
data {
id
}
}
text
}
}
thumbnail {
data {
id
}
}
next_recommended {
data {
id
}
}
previous_recommended {
data {
id
}
}
}
}
}
ranged_contents {
data {
id
}
}
translations {
language {
data {
id
}
}
title
description
text_set {
source_language {
data {
id
}
}
status
transcribers {
data {
id
}
}
translators {
data {
id
}
}
proofreaders {
data {
id
}
}
text
}
}
thumbnail {
data {
id
}
}
}
}
}
}

View File

@ -1,192 +1,161 @@
query getContentText($slug: String, $language_code: String) {
contents(filters: { slug: { eq: $slug } }) {
data {
id
attributes {
slug
contents(filters: { slug: { eq: $slug } }) {
data {
id
attributes {
slug
categories {
data {
id
attributes {
name
short
}
}
}
type {
data {
attributes {
slug
titles(filters: { language: { code: { eq: $language_code } } }) {
title
}
}
}
}
ranged_contents {
data {
id
attributes {
slug
scan_set {
id
}
library_item {
data {
attributes {
slug
title
subtitle
thumbnail {
data {
attributes {
...uploadImage
}
}
}
}
}
}
}
}
}
translations {
language {
data {
attributes {
code
}
}
}
pre_title
title
subtitle
description
text_set {
status
text
source_language {
data {
attributes {
code
}
}
}
transcribers {
data {
id
attributes {
...recorderChip
}
}
}
translators {
data {
id
attributes {
...recorderChip
}
}
}
proofreaders {
data {
id
attributes {
...recorderChip
}
}
}
notes
}
}
categories {
data {
id
attributes {
name
short
}
}
}
type {
data {
attributes {
slug
titles(filters: { language: { code: { eq: $language_code } } }) {
title
}
}
}
}
ranged_contents {
data {
id
attributes {
slug
scan_set {
id
}
library_item {
data {
attributes {
slug
title
subtitle
thumbnail {
data {
attributes {
...uploadImage
}
}
}
}
}
}
}
}
}
translations {
language {
data {
attributes {
code
}
}
}
pre_title
title
subtitle
description
text_set {
status
text
source_language {
data {
attributes {
code
}
}
}
transcribers {
data {
id
attributes {
...recorderChip
}
}
}
translators {
data {
id
attributes {
...recorderChip
}
}
}
proofreaders {
data {
id
attributes {
...recorderChip
}
}
}
notes
}
}
thumbnail {
data {
attributes {
...uploadImage
}
}
}
previous_recommended {
data {
attributes {
slug
translations {
pre_title
title
subtitle
}
categories {
data {
id
attributes {
short
}
}
}
type {
data {
attributes {
slug
titles(
filters: { language: { code: { eq: $language_code } } }
) {
title
}
}
}
}
thumbnail {
data {
attributes {
...uploadImage
}
}
}
}
}
}
next_recommended {
data {
attributes {
slug
translations {
pre_title
title
subtitle
}
categories {
data {
id
attributes {
short
}
}
}
type {
data {
attributes {
slug
titles(
filters: { language: { code: { eq: $language_code } } }
) {
title
}
}
}
}
thumbnail {
data {
attributes {
...uploadImage
}
}
}
}
}
}
}
}
}
thumbnail {
data {
attributes {
...uploadImage
}
}
}
group {
data {
attributes {
contents {
data {
attributes {
slug
translations {
pre_title
title
subtitle
}
categories {
data {
id
attributes {
short
}
}
}
type {
data {
attributes {
slug
titles(
filters: {
language: { code: { eq: $language_code } }
}
) {
title
}
}
}
}
thumbnail {
data {
attributes {
...uploadImage
}
}
}
}
}
}
}
}
}
}
}
}
}

View File

@ -5,13 +5,6 @@ query getContents($language_code: String) {
attributes {
slug
translations {
language {
data {
attributes {
code
}
}
}
pre_title
title
subtitle
@ -62,14 +55,16 @@ query getContents($language_code: String) {
}
}
}
next_recommended {
group {
data {
id
}
}
previous_recommended {
data {
id
attributes {
combine
contents {
data {
id
}
}
}
}
}
thumbnail {

View File

@ -34,6 +34,48 @@ interface Props extends AppStaticProps {
content: ContentWithTranslations;
}
function getPreviousContent(
group: Immutable<
NonNullable<
NonNullable<
NonNullable<
NonNullable<ContentWithTranslations["group"]>["data"]
>["attributes"]
>["contents"]
>["data"]
>,
currentSlug: string
) {
for (let index = 0; index < group.length; index += 1) {
const content = group[index];
if (content.attributes?.slug === currentSlug && index > 0) {
return group[index - 1];
}
}
return undefined;
}
function getNextContent(
group: Immutable<
NonNullable<
NonNullable<
NonNullable<
NonNullable<ContentWithTranslations["group"]>["data"]
>["attributes"]
>["contents"]
>["data"]
>,
currentSlug: string
) {
for (let index = 0; index < group.length; index += 1) {
const content = group[index];
if (content.attributes?.slug === currentSlug && index < group.length - 1) {
return group[index + 1];
}
}
return undefined;
}
export default function Content(props: Immutable<Props>): JSX.Element {
const { langui, content, languages } = props;
const isMobile = useMediaMobile();
@ -44,6 +86,17 @@ export default function Content(props: Immutable<Props>): JSX.Element {
languageExtractor: (item) => item.language?.data?.attributes?.code,
});
const previousContent = content.group?.data?.attributes?.contents
? getPreviousContent(
content.group.data.attributes.contents.data,
content.slug
)
: undefined;
const nextContent = content.group?.data?.attributes?.contents
? getNextContent(content.group.data.attributes.contents.data, content.slug)
: undefined;
const subPanel = (
<SubPanel>
<ReturnButton
@ -210,42 +263,37 @@ export default function Content(props: Immutable<Props>): JSX.Element {
languageSwitcher={<LanguageSwitcher />}
/>
{content.previous_recommended?.data?.attributes && (
{previousContent?.attributes && (
<div className="mt-12 mb-8 w-full">
<h2 className="text-center text-2xl mb-4">Previous content</h2>
<PreviewLine
href={`/contents/${content.previous_recommended.data.attributes.slug}`}
href={`/contents/${previousContent.attributes.slug}`}
pre_title={
content.previous_recommended.data.attributes.translations?.[0]
?.pre_title
previousContent.attributes.translations?.[0]?.pre_title
}
title={
content.previous_recommended.data.attributes.translations?.[0]
?.title ??
prettySlug(content.previous_recommended.data.attributes.slug)
previousContent.attributes.translations?.[0]?.title ??
prettySlug(previousContent.attributes.slug)
}
subtitle={
content.previous_recommended.data.attributes.translations?.[0]
?.subtitle
previousContent.attributes.translations?.[0]?.subtitle
}
thumbnail={
content.previous_recommended.data.attributes.thumbnail?.data
?.attributes
previousContent.attributes.thumbnail?.data?.attributes
}
thumbnailAspectRatio="3/2"
topChips={
isMobile
? undefined
: content.previous_recommended.data.attributes.type?.data
?.attributes
: previousContent.attributes.type?.data?.attributes
? [
content.previous_recommended.data.attributes.type.data
.attributes.titles?.[0]
? content.previous_recommended.data.attributes.type
.data.attributes.titles[0]?.title
previousContent.attributes.type.data.attributes
.titles?.[0]
? previousContent.attributes.type.data.attributes
.titles[0]?.title
: prettySlug(
content.previous_recommended.data.attributes.type
.data.attributes.slug
previousContent.attributes.type.data.attributes
.slug
),
]
: undefined
@ -253,7 +301,7 @@ export default function Content(props: Immutable<Props>): JSX.Element {
bottomChips={
isMobile
? undefined
: content.previous_recommended.data.attributes.categories?.data.map(
: previousContent.attributes.categories?.data.map(
(category) => category.attributes?.short ?? ""
)
}
@ -265,43 +313,30 @@ export default function Content(props: Immutable<Props>): JSX.Element {
<Markdawn text={selectedTranslation?.text_set?.text ?? ""} />
{content.next_recommended?.data?.attributes && (
{nextContent?.attributes && (
<>
<HorizontalLine />
<h2 className="text-center text-2xl mb-4">Follow-up content</h2>
<PreviewLine
href={`/contents/${content.next_recommended.data.attributes.slug}`}
pre_title={
content.next_recommended.data.attributes.translations?.[0]
?.pre_title
}
href={`/contents/${nextContent.attributes.slug}`}
pre_title={nextContent.attributes.translations?.[0]?.pre_title}
title={
content.next_recommended.data.attributes.translations?.[0]
?.title ??
prettySlug(content.next_recommended.data.attributes.slug)
}
subtitle={
content.next_recommended.data.attributes.translations?.[0]
?.subtitle
}
thumbnail={
content.next_recommended.data.attributes.thumbnail?.data
?.attributes
nextContent.attributes.translations?.[0]?.title ??
prettySlug(nextContent.attributes.slug)
}
subtitle={nextContent.attributes.translations?.[0]?.subtitle}
thumbnail={nextContent.attributes.thumbnail?.data?.attributes}
thumbnailAspectRatio="3/2"
topChips={
isMobile
? undefined
: content.next_recommended.data.attributes.type?.data
?.attributes
: nextContent.attributes.type?.data?.attributes
? [
content.next_recommended.data.attributes.type.data
.attributes.titles?.[0]
? content.next_recommended.data.attributes.type.data
.attributes.titles[0]?.title
nextContent.attributes.type.data.attributes.titles?.[0]
? nextContent.attributes.type.data.attributes
.titles[0]?.title
: prettySlug(
content.next_recommended.data.attributes.type.data
.attributes.slug
nextContent.attributes.type.data.attributes.slug
),
]
: undefined
@ -309,7 +344,7 @@ export default function Content(props: Immutable<Props>): JSX.Element {
bottomChips={
isMobile
? undefined
: content.next_recommended.data.attributes.categories?.data.map(
: nextContent.attributes.categories?.data.map(
(category) => category.attributes?.short ?? ""
)
}

View File

@ -18,7 +18,7 @@ import { GetStaticPropsContext } from "next";
import { useEffect, useState } from "react";
interface Props extends AppStaticProps {
contents: Exclude<GetContentsQuery["contents"], null | undefined>["data"];
contents: NonNullable<GetContentsQuery["contents"]>["data"];
}
type GroupContentItems = Map<string, Immutable<Props["contents"]>>;
@ -119,11 +119,12 @@ export default function Contents(props: Immutable<Props>): JSX.Element {
subtitle={item.attributes.translations?.[0]?.subtitle}
thumbnail={item.attributes.thumbnail?.data?.attributes}
thumbnailAspectRatio="3/2"
stackEffect={
item.attributes.next_recommended?.data?.id !== null &&
item.attributes.next_recommended?.data?.id !==
undefined &&
combineRelatedContent
stackNumber={
combineRelatedContent &&
item.attributes.group?.data?.attributes?.combine
? item.attributes.group?.data?.attributes.contents
?.data.length
: 0
}
topChips={
item.attributes.type?.data?.attributes
@ -263,7 +264,11 @@ function filterContents(
): Immutable<Props["contents"]> {
if (combineRelatedContent) {
return [...contents].filter(
(content) => !content.attributes?.previous_recommended?.data?.id
(content) =>
!content.attributes?.group?.data?.attributes ||
!content.attributes.group.data.attributes.combine ||
content.attributes.group.data.attributes.contents?.data?.[0].id ===
content.id
);
}
return contents;