Added previous/next content recommendation
This commit is contained in:
		
							parent
							
								
									2fe1ffb273
								
							
						
					
					
						commit
						1c2653ad07
					
				
							
								
								
									
										68
									
								
								src/components/PreviewLine.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/components/PreviewLine.tsx
									
									
									
									
									
										Normal 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> | ||||
|   ); | ||||
| } | ||||
| @ -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 | ||||
| 									} | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -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 { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint