Added previous/next content recommendation

This commit is contained in:
DrMint 2022-04-24 14:28:21 +02:00
parent 2fe1ffb273
commit 1c2653ad07
3 changed files with 367 additions and 112 deletions

View File

@ -0,0 +1,68 @@
import { UploadImageFragment } from "graphql/generated";
import Link from "next/link";
import Chip from "./Chip";
import Img, { ImageQuality } from "./Img";
interface Props {
thumbnail?: UploadImageFragment | string | null | undefined;
thumbnailAspectRatio?: string;
href: string;
pre_title?: string | null | undefined;
title: string | null | undefined;
subtitle?: string | null | undefined;
topChips?: string[];
bottomChips?: string[];
}
export default function PreviewLine(props: Props): JSX.Element {
const {
href,
thumbnail,
pre_title,
title,
subtitle,
topChips,
bottomChips,
thumbnailAspectRatio,
} = props;
return (
<Link href={href} passHref>
<div
className="drop-shadow-shade-xl rounded-md bg-light cursor-pointer hover:scale-[1.02]
transition-transform flex flex-row gap-4 overflow-hidden place-items-center pr-4 w-full h-36"
>
{thumbnail ? (
<div className="h-full aspect-[3/2]">
<Img image={thumbnail} quality={ImageQuality.Medium} />
</div>
) : (
<div style={{ aspectRatio: thumbnailAspectRatio }}></div>
)}
<div className="grid gap-2">
{topChips && topChips.length > 0 && (
<div className="grid grid-flow-col gap-1 overflow-hidden place-content-start">
{topChips.map((text, index) => (
<Chip key={index}>{text}</Chip>
))}
</div>
)}
<div className="flex flex-col">
{pre_title && <p>{pre_title}</p>}
{title && <h1 className="text-lg">{title}</h1>}
{subtitle && <h2>{subtitle}</h2>}
</div>
{bottomChips && bottomChips.length > 0 && (
<div className="grid grid-flow-col gap-1 overflow-hidden place-content-start">
{bottomChips.map((text, index) => (
<Chip key={index} className="text-sm">
{text}
</Chip>
))}
</div>
)}
</div>
</div>
</Link>
);
}

View File

@ -1,112 +1,190 @@
query getContentText($slug: String, $language_code: String) {
contents(filters: { slug: { eq: $slug } }) {
data {
id
attributes {
slug
titles {
pre_title
title
subtitle
description
}
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
}
}
}
}
}
}
}
}
}
text_set {
status
text
language {
data {
attributes {
code
}
}
}
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
}
}
}
}
}
}
}
contents(filters: { slug: { eq: $slug } }) {
data {
id
attributes {
slug
titles {
pre_title
title
subtitle
description
}
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
}
}
}
}
}
}
}
}
}
text_set {
status
text
language {
data {
attributes {
code
}
}
}
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
titles(filters: { language: { code: { eq: $language_code } } }) {
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
titles(filters: { language: { code: { eq: $language_code } } }) {
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

@ -9,12 +9,14 @@ import ReturnButton, {
} from "components/PanelComponents/ReturnButton";
import ContentPanel from "components/Panels/ContentPanel";
import SubPanel from "components/Panels/SubPanel";
import PreviewLine from "components/PreviewLine";
import RecorderChip from "components/RecorderChip";
import ThumbnailHeader from "components/ThumbnailHeader";
import ToolTip from "components/ToolTip";
import { useAppLayout } from "contexts/AppLayoutContext";
import { GetContentTextQuery } from "graphql/generated";
import { getReadySdk } from "graphql/sdk";
import { useMediaMobile } from "hooks/useMediaQuery";
import {
GetStaticPathsContext,
GetStaticPathsResult,
@ -47,6 +49,8 @@ export default function Content(props: Props): JSX.Element {
const router = useRouter();
const appLayout = useAppLayout();
const isMobile = useMediaMobile();
const [selectedTextSet, setSelectedTextSet] = useState<
| Exclude<
Exclude<Props["content"], null | undefined>["text_set"],
@ -261,9 +265,111 @@ export default function Content(props: Props): JSX.Element {
}
/>
{content.previous_recommended?.data?.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}`}
pre_title={
content.previous_recommended.data.attributes.titles?.[0]
?.pre_title
}
title={
content.previous_recommended.data.attributes.titles?.[0]
?.title ??
prettySlug(content.previous_recommended.data.attributes.slug)
}
subtitle={
content.previous_recommended.data.attributes.titles?.[0]
?.subtitle
}
thumbnail={
content.previous_recommended.data.attributes.thumbnail?.data
?.attributes
}
thumbnailAspectRatio="3/2"
topChips={
isMobile
? undefined
: content.previous_recommended.data.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
: prettySlug(
content.previous_recommended.data.attributes.type
.data.attributes.slug
),
]
: undefined
}
bottomChips={
isMobile
? undefined
: content.previous_recommended.data.attributes.categories?.data.map(
(category) => category.attributes?.short ?? ""
)
}
/>
</div>
)}
<HorizontalLine />
<Markdawn text={selectedTextSet?.text ?? ""} />
<HorizontalLine />
{content.next_recommended?.data?.attributes && (
<>
<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.titles?.[0]
?.pre_title
}
title={
content.next_recommended.data.attributes.titles?.[0]?.title ??
prettySlug(content.next_recommended.data.attributes.slug)
}
subtitle={
content.next_recommended.data.attributes.titles?.[0]?.subtitle
}
thumbnail={
content.next_recommended.data.attributes.thumbnail?.data
?.attributes
}
thumbnailAspectRatio="3/2"
topChips={
isMobile
? undefined
: content.next_recommended.data.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
: prettySlug(
content.next_recommended.data.attributes.type.data
.attributes.slug
),
]
: undefined
}
bottomChips={
isMobile
? undefined
: content.next_recommended.data.attributes.categories?.data.map(
(category) => category.attributes?.short ?? ""
)
}
/>
</>
)}
</div>
)}
</ContentPanel>
@ -338,7 +444,10 @@ export async function getStaticPaths(
contents.contents?.data.map((item) => {
context.locales?.map((local) => {
if (item.attributes)
paths.push({ params: { slug: item.attributes.slug }, locale: local });
paths.push({
params: { slug: item.attributes.slug },
locale: local,
});
});
});
return {