Content pages now display the table of content
This commit is contained in:
		
							parent
							
								
									6d3a9c84b3
								
							
						
					
					
						commit
						b213447c49
					
				| @ -2,10 +2,11 @@ import { | ||||
|   GetContentQuery, | ||||
|   GetWebsiteInterfaceQuery, | ||||
| } from "graphql/operations-types"; | ||||
| import { prettySlug } from "queries/helpers"; | ||||
| import { prettyinlineTitle, prettySlug, slugify } from "queries/helpers"; | ||||
| import Button from "components/Button"; | ||||
| import Img, { ImageQuality } from "components/Img"; | ||||
| import InsetBox from "components/InsetBox"; | ||||
| import Chip from "components/Chip"; | ||||
| 
 | ||||
| export type ThumbnailHeaderProps = { | ||||
|   content: { | ||||
| @ -39,7 +40,18 @@ export default function ThumbnailHeader( | ||||
|             <div className="w-full aspect-[4/3] bg-light rounded-xl"></div> | ||||
|           )} | ||||
|         </div> | ||||
|         <div className="grid place-items-center text-center"> | ||||
|         <div | ||||
|           id={slugify( | ||||
|             content.titles.length > 0 | ||||
|               ? prettyinlineTitle( | ||||
|                   content.titles[0].pre_title, | ||||
|                   content.titles[0].title, | ||||
|                   content.titles[0].subtitle | ||||
|                 ) | ||||
|               : prettySlug(content.slug) | ||||
|           )} | ||||
|           className="grid place-items-center text-center" | ||||
|         > | ||||
|           {content.titles.length > 0 ? ( | ||||
|             <> | ||||
|               <p className="text-2xl">{content.titles[0].pre_title}</p> | ||||
| @ -54,22 +66,26 @@ export default function ThumbnailHeader( | ||||
| 
 | ||||
|       <div className="grid grid-flow-col gap-8"> | ||||
|         {content.type && ( | ||||
|           <div className="grid place-items-center place-content-start gap-2"> | ||||
|           <div className="flex flex-col place-items-center gap-2"> | ||||
|             <h3 className="text-xl">{langui.type}</h3> | ||||
|             <Button> | ||||
|               {content.type.data.attributes.titles.length > 0 | ||||
|                 ? content.type.data.attributes.titles[0].title | ||||
|                 : prettySlug(content.type.data.attributes.slug)} | ||||
|             </Button> | ||||
|             <div className="flex flex-row flex-wrap"> | ||||
|               <Chip> | ||||
|                 {content.type.data.attributes.titles.length > 0 | ||||
|                   ? content.type.data.attributes.titles[0].title | ||||
|                   : prettySlug(content.type.data.attributes.slug)} | ||||
|               </Chip> | ||||
|             </div> | ||||
|           </div> | ||||
|         )} | ||||
| 
 | ||||
|         {content.categories.data.length > 0 && ( | ||||
|           <div className="grid place-items-center place-content-start gap-2"> | ||||
|           <div className="flex flex-col place-items-center gap-2"> | ||||
|             <h3 className="text-xl">{langui.categories}</h3> | ||||
|             {content.categories.data.map((category) => ( | ||||
|               <Button key={category.id}>{category.attributes.name}</Button> | ||||
|             ))} | ||||
|             <div className="flex flex-row flex-wrap place-content-center gap-2"> | ||||
|               {content.categories.data.map((category) => ( | ||||
|                 <Chip key={category.id}>{category.attributes.name}</Chip> | ||||
|               ))} | ||||
|             </div> | ||||
|           </div> | ||||
|         )} | ||||
|       </div> | ||||
|  | ||||
| @ -117,6 +117,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
|       /> | ||||
| 
 | ||||
|       {/* | ||||
|        | ||||
|       <NavOption | ||||
|         url="/wiki" | ||||
|         icon="travel_explore" | ||||
| @ -136,6 +138,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|         reduced={appLayout.mainPanelReduced && isDesktop} | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
|       /> | ||||
|        | ||||
|       */} | ||||
| 
 | ||||
|       <HorizontalLine /> | ||||
| 
 | ||||
| @ -147,7 +151,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|         reduced={appLayout.mainPanelReduced && isDesktop} | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
|       /> | ||||
| 
 | ||||
|       {/* | ||||
|       <NavOption | ||||
|         url="/merch" | ||||
|         icon="store" | ||||
| @ -156,6 +160,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|         reduced={appLayout.mainPanelReduced && isDesktop} | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
|       /> | ||||
|        | ||||
|       */} | ||||
| 
 | ||||
|       <NavOption | ||||
|         url="/gallery" | ||||
| @ -166,6 +172,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
|       /> | ||||
| 
 | ||||
|       {/* | ||||
| 
 | ||||
|       <NavOption | ||||
|         url="/archives" | ||||
|         icon="inventory" | ||||
| @ -175,6 +183,9 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|         onClick={() => appLayout.setMainPanelOpen(false)} | ||||
|       /> | ||||
| 
 | ||||
| 
 | ||||
|       */} | ||||
| 
 | ||||
|       <NavOption | ||||
|         url="/about-us" | ||||
|         icon="info" | ||||
|  | ||||
| @ -26,6 +26,7 @@ import Chip from "components/Chip"; | ||||
| import ReactTooltip from "react-tooltip"; | ||||
| import RecorderChip from "components/RecorderChip"; | ||||
| import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps"; | ||||
| import TOC from "components/Markdown/TOC"; | ||||
| 
 | ||||
| interface ContentReadProps extends AppStaticProps { | ||||
|   content: GetContentTextQuery["contents"]["data"][number]["attributes"]; | ||||
| @ -141,6 +142,20 @@ export default function ContentRead(props: ContentReadProps): JSX.Element { | ||||
|           )} | ||||
|         </div> | ||||
|       )} | ||||
| 
 | ||||
|       <HorizontalLine /> | ||||
|       <TOC | ||||
|         text={content.text_set[0].text} | ||||
|         title={ | ||||
|           content.titles.length > 0 | ||||
|             ? prettyinlineTitle( | ||||
|                 content.titles[0].pre_title, | ||||
|                 content.titles[0].title, | ||||
|                 content.titles[0].subtitle | ||||
|               ) | ||||
|             : prettySlug(content.slug) | ||||
|         } | ||||
|       /> | ||||
|     </SubPanel> | ||||
|   ); | ||||
|   const contentPanel = ( | ||||
|  | ||||
| @ -3,7 +3,10 @@ import SubPanel from "components/Panels/SubPanel"; | ||||
| import ContentPanel, { | ||||
|   ContentPanelWidthSizes, | ||||
| } from "components/Panels/ContentPanel"; | ||||
| import { GetContentsQuery } from "graphql/operations-types"; | ||||
| import { | ||||
|   GetContentsQuery, | ||||
|   GetWebsiteInterfaceQuery, | ||||
| } from "graphql/operations-types"; | ||||
| import { getContents } from "graphql/operations"; | ||||
| import PanelHeader from "components/PanelComponents/PanelHeader"; | ||||
| import AppLayout from "components/AppLayout"; | ||||
| @ -12,6 +15,7 @@ import { prettyinlineTitle, prettySlug } from "queries/helpers"; | ||||
| import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps"; | ||||
| import Select from "components/Select"; | ||||
| import { useEffect, useState } from "react"; | ||||
| import Chip from "components/Chip"; | ||||
| 
 | ||||
| interface ContentsProps extends AppStaticProps { | ||||
|   contents: GetContentsQuery["contents"]["data"]; | ||||
| @ -25,11 +29,11 @@ export default function Contents(props: ContentsProps): JSX.Element { | ||||
|   const [groupingMethod, setGroupingMethod] = useState<number>(-1); | ||||
| 
 | ||||
|   const [groups, setGroups] = useState<GroupContentItems>( | ||||
|     getGroups(groupingMethod, contents) | ||||
|     getGroups(langui, groupingMethod, contents) | ||||
|   ); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     setGroups(getGroups(groupingMethod, contents)); | ||||
|     setGroups(getGroups(langui, groupingMethod, contents)); | ||||
|   }, [langui, groupingMethod, contents]); | ||||
| 
 | ||||
|   const subPanel = ( | ||||
| @ -61,9 +65,14 @@ export default function Contents(props: ContentsProps): JSX.Element { | ||||
|               {name && ( | ||||
|                 <h2 | ||||
|                   key={"h2" + name} | ||||
|                   className="text-2xl pb-2 pt-10 first-of-type:pt-0" | ||||
|                   className="text-2xl pb-2 pt-10 first-of-type:pt-0 flex flex-row place-items-center gap-2" | ||||
|                 > | ||||
|                   {name} | ||||
|                   <Chip>{`${items.length} ${ | ||||
|                     items.length <= 1 | ||||
|                       ? langui.result.toLowerCase() | ||||
|                       : langui.results.toLowerCase() | ||||
|                   }`}</Chip>
 | ||||
|                 </h2> | ||||
|               )} | ||||
|               <div | ||||
| @ -127,6 +136,7 @@ export const getStaticProps: GetStaticProps = async (context) => { | ||||
| }; | ||||
| 
 | ||||
| function getGroups( | ||||
|   langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"], | ||||
|   groupByType: number, | ||||
|   items: ContentsProps["contents"] | ||||
| ): GroupContentItems { | ||||
| @ -150,11 +160,11 @@ function getGroups( | ||||
|       typeGroup.set("Bakuken", []); | ||||
|       typeGroup.set("YoRHa", []); | ||||
|       typeGroup.set("YoRHa Boys", []); | ||||
|       typeGroup.set("No category", []); | ||||
|       typeGroup.set(langui.no_category, []); | ||||
| 
 | ||||
|       items.map((item) => { | ||||
|         if (item.attributes.categories.data.length === 0) { | ||||
|           typeGroup.get("No category")?.push(item); | ||||
|           typeGroup.get(langui.no_category)?.push(item); | ||||
|         } else { | ||||
|           item.attributes.categories.data.map((category) => { | ||||
|             typeGroup.get(category.attributes.name)?.push(item); | ||||
|  | ||||
| @ -218,13 +218,11 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { | ||||
|             </div> | ||||
| 
 | ||||
|             {item.categories.data.length > 0 && ( | ||||
|               <div> | ||||
|               <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-items-center place-content-start gap-2"> | ||||
|                 <div className="flex flex-row flex-wrap place-content-center gap-2"> | ||||
|                   {item.categories.data.map((category) => ( | ||||
|                     <Chip key={category.id}> | ||||
|                       {category.attributes.short} | ||||
|                     </Chip> | ||||
|                     <Chip key={category.id}>{category.attributes.name}</Chip> | ||||
|                   ))} | ||||
|                 </div> | ||||
|               </div> | ||||
|  | ||||
| @ -17,6 +17,7 @@ import { useEffect, useState } from "react"; | ||||
| import { convertPrice, prettyDate, prettyinlineTitle } from "queries/helpers"; | ||||
| import Switch from "components/Switch"; | ||||
| import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps"; | ||||
| import Chip from "components/Chip"; | ||||
| 
 | ||||
| interface LibraryProps extends AppStaticProps { | ||||
|   items: GetLibraryItemsPreviewQuery["libraryItems"]["data"]; | ||||
| @ -116,9 +117,14 @@ export default function Library(props: LibraryProps): JSX.Element { | ||||
|               {name && ( | ||||
|                 <h2 | ||||
|                   key={"h2" + name} | ||||
|                   className="text-2xl pb-2 pt-10 first-of-type:pt-0" | ||||
|                   className="text-2xl pb-2 pt-10 first-of-type:pt-0 flex flex-row place-items-center gap-2" | ||||
|                 > | ||||
|                   {name} | ||||
|                   <Chip>{`${items.length} ${ | ||||
|                     items.length <= 1 | ||||
|                       ? langui.result.toLowerCase() | ||||
|                       : langui.results.toLowerCase() | ||||
|                   }`}</Chip>
 | ||||
|                 </h2> | ||||
|               )} | ||||
|               <div | ||||
| @ -188,11 +194,11 @@ function getGroups( | ||||
|       typeGroup.set("Bakuken", []); | ||||
|       typeGroup.set("YoRHa", []); | ||||
|       typeGroup.set("YoRHa Boys", []); | ||||
|       typeGroup.set("No category", []); | ||||
|       typeGroup.set(langui.no_category, []); | ||||
| 
 | ||||
|       items.map((item) => { | ||||
|         if (item.attributes.categories.data.length === 0) { | ||||
|           typeGroup.get("No category")?.push(item); | ||||
|           typeGroup.get(langui.no_category)?.push(item); | ||||
|         } else { | ||||
|           item.attributes.categories.data.map((category) => { | ||||
|             typeGroup.get(category.attributes.name)?.push(item); | ||||
|  | ||||
| @ -256,3 +256,20 @@ export function sortContent( | ||||
|     return 0; | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| export function slugify(str: string): string { | ||||
|   return str | ||||
|     .replace(/[ÀÁÂÃÄÅàáâãä忯]/g, "a") | ||||
|     .replace(/[çÇ]/g, "c") | ||||
|     .replace(/[ðÐ]/g, "d") | ||||
|     .replace(/[ÈÉÊËéèêë]/g, "e") | ||||
|     .replace(/[ÏïÎîÍíÌì]/g, "i") | ||||
|     .replace(/[Ññ]/g, "n") | ||||
|     .replace(/[øØœŒÕõÔôÓóÒò]/g, "o") | ||||
|     .replace(/[ÜüÛûÚúÙù]/g, "u") | ||||
|     .replace(/[ŸÿÝý]/g, "y") | ||||
|     .replace(/[^a-z0-9- ]/gi, "") | ||||
|     .trim() | ||||
|     .replace(/ /gi, "-") | ||||
|     .toLowerCase(); | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint