184 lines
5.7 KiB
TypeScript
184 lines
5.7 KiB
TypeScript
import { AppLayout } from "components/AppLayout";
|
|
import { NavOption } from "components/PanelComponents/NavOption";
|
|
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
|
import { SubPanel } from "components/Panels/SubPanel";
|
|
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
|
|
|
import { GetStaticPropsContext } from "next";
|
|
import { Icon } from "components/Ico";
|
|
import { getReadySdk } from "graphql/sdk";
|
|
import { GetWikiPagesPreviewsQuery } from "graphql/generated";
|
|
import {
|
|
ContentPanel,
|
|
ContentPanelWidthSizes,
|
|
} from "components/Panels/ContentPanel";
|
|
import { Fragment, useMemo, useState } from "react";
|
|
import { TranslatedPreviewCard } from "components/PreviewCard";
|
|
import { HorizontalLine } from "components/HorizontalLine";
|
|
import { Button } from "components/Inputs/Button";
|
|
import { Switch } from "components/Inputs/Switch";
|
|
import { TextInput } from "components/Inputs/TextInput";
|
|
import { WithLabel } from "components/Inputs/WithLabel";
|
|
import { useMediaHoverable } from "hooks/useMediaQuery";
|
|
import { filterHasAttributes } from "helpers/others";
|
|
import { ContentPlaceholder } from "components/PanelComponents/ContentPlaceholder";
|
|
|
|
interface Props extends AppStaticProps {
|
|
pages: NonNullable<GetWikiPagesPreviewsQuery["wikiPages"]>["data"];
|
|
}
|
|
|
|
const defaultFiltersState = {
|
|
searchName: "",
|
|
keepInfoVisible: true,
|
|
};
|
|
|
|
export default function Wiki(props: Props): JSX.Element {
|
|
const { langui, languages } = props;
|
|
const pages = sortPages(props.pages);
|
|
const hoverable = useMediaHoverable();
|
|
|
|
const [searchName, setSearchName] = useState(defaultFiltersState.searchName);
|
|
const [keepInfoVisible, setKeepInfoVisible] = useState(
|
|
defaultFiltersState.keepInfoVisible
|
|
);
|
|
|
|
const filteredPages = useMemo(
|
|
() => filterPages(pages, searchName),
|
|
[pages, searchName]
|
|
);
|
|
|
|
const subPanel = (
|
|
<SubPanel>
|
|
<PanelHeader
|
|
icon={Icon.TravelExplore}
|
|
title={langui.wiki}
|
|
description={langui.wiki_description}
|
|
/>
|
|
|
|
<TextInput
|
|
className="mb-6 w-full"
|
|
placeholder={langui.search_title ?? undefined}
|
|
state={searchName}
|
|
setState={setSearchName}
|
|
/>
|
|
|
|
{hoverable && (
|
|
<WithLabel
|
|
label={langui.always_show_info}
|
|
input={
|
|
<Switch setState={setKeepInfoVisible} state={keepInfoVisible} />
|
|
}
|
|
/>
|
|
)}
|
|
|
|
<Button
|
|
className="mt-8"
|
|
text={langui.reset_all_filters}
|
|
icon={Icon.Replay}
|
|
onClick={() => {
|
|
setSearchName(defaultFiltersState.searchName);
|
|
setKeepInfoVisible(defaultFiltersState.keepInfoVisible);
|
|
}}
|
|
/>
|
|
<HorizontalLine />
|
|
|
|
{/* TODO: Langui */}
|
|
<p className="mb-4 font-headers text-xl">Special Pages</p>
|
|
|
|
<NavOption title={langui.chronology} url="/wiki/chronology" border />
|
|
</SubPanel>
|
|
);
|
|
|
|
const contentPanel = (
|
|
<ContentPanel width={ContentPanelWidthSizes.Full}>
|
|
<div
|
|
className="grid grid-cols-2 items-end gap-8
|
|
desktop:grid-cols-[repeat(auto-fill,_minmax(20rem,1fr))] mobile:gap-4"
|
|
>
|
|
{/* TODO: Add to langui */}
|
|
{filteredPages.length === 0 && (
|
|
<ContentPlaceholder
|
|
message={
|
|
"No results. You can try changing or resetting the search parameters."
|
|
}
|
|
icon={Icon.ChevronLeft}
|
|
/>
|
|
)}
|
|
{filterHasAttributes(filteredPages).map((page) => (
|
|
<Fragment key={page.id}>
|
|
<TranslatedPreviewCard
|
|
href={`/wiki/${page.attributes.slug}`}
|
|
translations={page.attributes.translations?.map(
|
|
(translation) => ({
|
|
title: translation?.title,
|
|
description: translation?.summary,
|
|
language: translation?.language?.data?.attributes?.code,
|
|
})
|
|
)}
|
|
thumbnail={page.attributes.thumbnail?.data?.attributes}
|
|
thumbnailAspectRatio={"4/3"}
|
|
thumbnailRounded
|
|
thumbnailForceAspectRatio
|
|
languages={languages}
|
|
slug={page.attributes.slug}
|
|
keepInfoVisible={keepInfoVisible}
|
|
bottomChips={page.attributes.categories?.data.map(
|
|
(category) => category.attributes?.short ?? ""
|
|
)}
|
|
/>
|
|
</Fragment>
|
|
))}
|
|
</div>
|
|
</ContentPanel>
|
|
);
|
|
|
|
return (
|
|
<AppLayout
|
|
navTitle={langui.wiki}
|
|
subPanel={subPanel}
|
|
contentPanel={contentPanel}
|
|
subPanelIcon={Icon.Search}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export async function getStaticProps(
|
|
context: GetStaticPropsContext
|
|
): Promise<{ notFound: boolean } | { props: Props }> {
|
|
const sdk = getReadySdk();
|
|
const pages = await sdk.getWikiPagesPreviews({});
|
|
if (!pages.wikiPages?.data) return { notFound: true };
|
|
const props: Props = {
|
|
...(await getAppStaticProps(context)),
|
|
pages: pages.wikiPages.data,
|
|
};
|
|
return {
|
|
props: props,
|
|
};
|
|
}
|
|
|
|
function sortPages(pages: Props["pages"]): Props["pages"] {
|
|
return pages.sort((a, b) => {
|
|
const slugA = a.attributes?.slug ?? "";
|
|
const slugB = b.attributes?.slug ?? "";
|
|
return slugA.localeCompare(slugB);
|
|
});
|
|
}
|
|
|
|
function filterPages(posts: Props["pages"], searchName: string) {
|
|
return posts.filter((post) => {
|
|
if (searchName.length > 1) {
|
|
if (
|
|
post.attributes?.translations?.[0]?.title
|
|
.toLowerCase()
|
|
.includes(searchName.toLowerCase()) === true
|
|
) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|