Content pages now display the table of content

This commit is contained in:
DrMint 2022-03-12 13:27:21 +01:00
parent 6d3a9c84b3
commit b213447c49
7 changed files with 100 additions and 27 deletions

View File

@ -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>

View File

@ -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"

View File

@ -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 = (

View File

@ -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);

View File

@ -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>

View File

@ -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);

View File

@ -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();
}