Improved wiki for mobile + removed old hook

This commit is contained in:
DrMint 2022-07-15 01:51:06 +02:00
parent 0df66815c8
commit c6ee213903
10 changed files with 99 additions and 97 deletions

View File

@ -1,7 +1,7 @@
import { Fragment, useCallback, useState } from "react"; import { Fragment, useCallback } from "react";
import { Ico, Icon } from "components/Ico"; import { Ico, Icon } from "components/Ico";
import { cIf, cJoin } from "helpers/className"; import { cIf, cJoin } from "helpers/className";
import { useToggle } from "hooks/useToggle"; import { useBoolean } from "hooks/useBoolean";
/* /*
* *
@ -26,8 +26,11 @@ export const Select = ({
allowEmpty, allowEmpty,
onChange, onChange,
}: Props): JSX.Element => { }: Props): JSX.Element => {
const [opened, setOpened] = useState(false); const {
const toggleOpened = useToggle(setOpened); state: isOpened,
setFalse: setClosed,
toggleState: toggleOpened,
} = useBoolean(false);
const tryToggling = useCallback(() => { const tryToggling = useCallback(() => {
const optionCount = options.length + (value === -1 ? 1 : 0); const optionCount = options.length + (value === -1 ? 1 : 0);
@ -38,7 +41,7 @@ export const Select = ({
<div <div
className={cJoin( className={cJoin(
"relative text-center transition-[filter]", "relative text-center transition-[filter]",
cIf(opened, "z-10 drop-shadow-shade-lg"), cIf(isOpened, "z-10 drop-shadow-shade-lg"),
className className
)} )}
> >
@ -47,7 +50,7 @@ export const Select = ({
`grid cursor-pointer grid-flow-col grid-cols-[1fr_auto_auto] place-items-center `grid cursor-pointer grid-flow-col grid-cols-[1fr_auto_auto] place-items-center
rounded-[1em] bg-light p-1 outline outline-2 outline-offset-[-2px] outline-mid rounded-[1em] bg-light p-1 outline outline-2 outline-offset-[-2px] outline-mid
transition-all hover:bg-mid hover:outline-[transparent]`, transition-all hover:bg-mid hover:outline-[transparent]`,
cIf(opened, "rounded-b-none bg-highlight outline-[transparent]") cIf(isOpened, "rounded-b-none bg-highlight outline-[transparent]")
)} )}
> >
<p onClick={tryToggling} className="w-full"> <p onClick={tryToggling} className="w-full">
@ -58,20 +61,20 @@ export const Select = ({
icon={Icon.Close} icon={Icon.Close}
className="!text-xs" className="!text-xs"
onClick={() => { onClick={() => {
setClosed();
onChange(-1); onChange(-1);
setOpened(false);
}} }}
/> />
)} )}
<Ico <Ico
onClick={tryToggling} onClick={tryToggling}
icon={opened ? Icon.ArrowDropUp : Icon.ArrowDropDown} icon={isOpened ? Icon.ArrowDropUp : Icon.ArrowDropDown}
/> />
</div> </div>
<div <div
className={cJoin( className={cJoin(
"left-0 right-0 rounded-b-[1em]", "left-0 right-0 rounded-b-[1em]",
cIf(opened, "absolute", "hidden") cIf(isOpened, "absolute", "hidden")
)} )}
> >
{options.map((option, index) => ( {options.map((option, index) => (
@ -80,11 +83,11 @@ export const Select = ({
<div <div
className={cJoin( className={cJoin(
"cursor-pointer p-1 transition-colors last-of-type:rounded-b-[1em] hover:bg-mid", "cursor-pointer p-1 transition-colors last-of-type:rounded-b-[1em] hover:bg-mid",
cIf(opened, "bg-highlight", "bg-light") cIf(isOpened, "bg-highlight", "bg-light")
)} )}
id={option} id={option}
onClick={() => { onClick={() => {
setOpened(false); setClosed();
onChange(index); onChange(index);
}} }}
> >

View File

@ -1,6 +1,7 @@
import { Fragment, useCallback, useEffect, useMemo, useState } from "react"; import { Fragment, useCallback, useEffect, useMemo, useState } from "react";
import { Chip } from "./Chip"; import { Chip } from "./Chip";
import { PageSelector } from "./Inputs/PageSelector"; import { PageSelector } from "./Inputs/PageSelector";
import { Ico, Icon } from "./Ico";
import { AppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps } from "graphql/getAppStaticProps";
import { cJoin } from "helpers/className"; import { cJoin } from "helpers/className";
import { isDefined, isDefinedAndNotEmpty, iterateMap } from "helpers/others"; import { isDefined, isDefinedAndNotEmpty, iterateMap } from "helpers/others";
@ -145,43 +146,47 @@ export const SmartList = <T,>({
)} )}
<div className="mb-8"> <div className="mb-8">
{groupedList.size > 0 {groupedList.size > 0 ? (
? iterateMap( iterateMap(
groupedList, groupedList,
(name, groupItems) => (name, groupItems) =>
groupItems.length > 0 && ( groupItems.length > 0 && (
<Fragment key={name}> <Fragment key={name}>
{name.length > 0 && ( {name.length > 0 && (
<h2 <h2
className="flex flex-row place-items-center gap-2 pb-2 pt-10 text-2xl className="flex flex-row place-items-center gap-2 pb-2 pt-10 text-2xl
first-of-type:pt-0" first-of-type:pt-0"
>
{name}
<Chip
text={`${groupItems.length} ${
groupItems.length <= 1
? langui.result?.toLowerCase() ?? ""
: langui.results?.toLowerCase() ?? ""
}`}
/>
</h2>
)}
<div
className={cJoin(
`grid items-start gap-8 border-b-[3px] border-dotted pb-12
last-of-type:border-0 mobile:gap-4`,
className
)}
> >
{groupItems.map((item) => ( {name}
<RenderItem item={item} key={getItemId(item)} /> <Chip
))} text={`${groupItems.length} ${
</div> groupItems.length <= 1
</Fragment> ? langui.result?.toLowerCase() ?? ""
), : langui.results?.toLowerCase() ?? ""
([a], [b]) => groupSortingFunction(a, b) }`}
) />
: isDefined(RenderWhenEmpty) && <RenderWhenEmpty />} </h2>
)}
<div
className={cJoin(
`grid items-start gap-8 border-b-[3px] border-dotted pb-12
last-of-type:border-0 mobile:gap-4`,
className
)}
>
{groupItems.map((item) => (
<RenderItem item={item} key={getItemId(item)} />
))}
</div>
</Fragment>
),
([a], [b]) => groupSortingFunction(a, b)
)
) : isDefined(RenderWhenEmpty) ? (
<RenderWhenEmpty />
) : (
<DefaultRenderWhenEmpty langui={langui} />
)}
</div> </div>
{pageCount > 1 && paginationSelectorBottom && ( {pageCount > 1 && paginationSelectorBottom && (
@ -190,3 +195,25 @@ export const SmartList = <T,>({
</> </>
); );
}; };
/*
*
* PRIVATE COMPONENTS
*/
interface DefaultRenderWhenEmptyProps {
langui: AppStaticProps["langui"];
}
const DefaultRenderWhenEmpty = ({ langui }: DefaultRenderWhenEmptyProps) => (
<div className="grid h-full place-content-center">
<div
className="grid grid-flow-col place-items-center gap-9 rounded-2xl border-2 border-dotted
border-dark p-8 text-dark opacity-40"
>
<Ico icon={Icon.ChevronLeft} className="!text-[300%] mobile:hidden" />
<p className="max-w-xs text-2xl"> {langui.no_results_message} </p>
<Ico icon={Icon.ChevronRight} className="!text-[300%] desktop:hidden" />
</div>
</div>
);

View File

@ -88,7 +88,7 @@ const DefinitionCard = ({
{source?.url && source.name && ( {source?.url && source.name && (
<Link href={source.url}> <Link href={source.url}>
<div className="mt-3 flex place-items-center gap-2"> <div className="mt-3 flex place-items-center gap-2 mobile:flex-col mobile:text-center">
<p>{langui.source}: </p> <p>{langui.source}: </p>
<Button size="small" text={source.name} /> <Button size="small" text={source.name} />
</div> </div>

View File

@ -1,8 +0,0 @@
import { Dispatch, SetStateAction, useCallback } from "react";
export const useToggle = (
setState: Dispatch<SetStateAction<boolean>>
): (() => void) =>
useCallback(() => {
setState((current) => !current);
}, [setState]);

View File

@ -6,7 +6,6 @@ import { Icon } from "components/Ico";
import { Switch } from "components/Inputs/Switch"; import { Switch } from "components/Inputs/Switch";
import { TextInput } from "components/Inputs/TextInput"; import { TextInput } from "components/Inputs/TextInput";
import { WithLabel } from "components/Inputs/WithLabel"; import { WithLabel } from "components/Inputs/WithLabel";
import { ContentPlaceholder } from "components/PanelComponents/ContentPlaceholder";
import { PanelHeader } from "components/PanelComponents/PanelHeader"; import { PanelHeader } from "components/PanelComponents/PanelHeader";
import { import {
ReturnButton, ReturnButton,
@ -120,12 +119,6 @@ const Videos = ({ langui, videos, ...otherProps }: Props): JSX.Element => {
/> />
</> </>
)} )}
renderWhenEmpty={() => (
<ContentPlaceholder
message={langui.no_results_message ?? "No results"}
icon={Icon.ChevronLeft}
/>
)}
className="desktop:grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))] mobile:grid-cols-2 className="desktop:grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))] mobile:grid-cols-2
thin:grid-cols-1" thin:grid-cols-1"
paginationItemPerPage={20} paginationItemPerPage={20}

View File

@ -20,7 +20,6 @@ import { Icon } from "components/Ico";
import { filterDefined, filterHasAttributes } from "helpers/others"; import { filterDefined, filterHasAttributes } from "helpers/others";
import { GetContentsQuery } from "graphql/generated"; import { GetContentsQuery } from "graphql/generated";
import { SmartList } from "components/SmartList"; import { SmartList } from "components/SmartList";
import { ContentPlaceholder } from "components/PanelComponents/ContentPlaceholder";
import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable"; import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable";
import { useBoolean } from "hooks/useBoolean"; import { useBoolean } from "hooks/useBoolean";
import { TranslatedPreviewCard } from "components/Translated"; import { TranslatedPreviewCard } from "components/Translated";
@ -259,12 +258,6 @@ const Contents = ({
keepInfoVisible={keepInfoVisible} keepInfoVisible={keepInfoVisible}
/> />
)} )}
renderWhenEmpty={() => (
<ContentPlaceholder
message={langui.no_results_message ?? "No results"}
icon={Icon.ChevronLeft}
/>
)}
className="grid-cols-2 items-end desktop:grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))]" className="grid-cols-2 items-end desktop:grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))]"
groupingFunction={groupingFunction} groupingFunction={groupingFunction}
filteringFunction={filteringFunction} filteringFunction={filteringFunction}

View File

@ -1,4 +1,4 @@
import { Fragment, useCallback, useMemo, useState } from "react"; import { Fragment, useCallback, useMemo } from "react";
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { AppLayout } from "components/AppLayout"; import { AppLayout } from "components/AppLayout";
import { Chip } from "components/Chip"; import { Chip } from "components/Chip";
@ -49,7 +49,6 @@ import { AnchorIds, useScrollTopOnChange } from "hooks/useScrollTopOnChange";
import { isUntangibleGroupItem } from "helpers/libraryItem"; import { isUntangibleGroupItem } from "helpers/libraryItem";
import { useMediaHoverable } from "hooks/useMediaQuery"; import { useMediaHoverable } from "hooks/useMediaQuery";
import { WithLabel } from "components/Inputs/WithLabel"; import { WithLabel } from "components/Inputs/WithLabel";
import { useToggle } from "hooks/useToggle";
import { Ico, Icon } from "components/Ico"; import { Ico, Icon } from "components/Ico";
import { cJoin, cIf } from "helpers/className"; import { cJoin, cIf } from "helpers/className";
import { useSmartLanguage } from "hooks/useSmartLanguage"; import { useSmartLanguage } from "hooks/useSmartLanguage";
@ -682,8 +681,7 @@ const ContentLine = ({
slug, slug,
parentSlug, parentSlug,
}: ContentLineProps): JSX.Element => { }: ContentLineProps): JSX.Element => {
const [opened, setOpened] = useState(false); const { state: isOpened, toggleState: toggleOpened } = useBoolean(false);
const toggleOpened = useToggle(setOpened);
const [selectedTranslation] = useSmartLanguage({ const [selectedTranslation] = useSmartLanguage({
items: content?.translations ?? [], items: content?.translations ?? [],
@ -700,7 +698,7 @@ const ContentLine = ({
<div <div
className={cJoin( className={cJoin(
"grid gap-2 rounded-lg px-4", "grid gap-2 rounded-lg px-4",
cIf(opened, "my-2 h-auto bg-mid py-3 shadow-inner-sm shadow-shade") cIf(isOpened, "my-2 h-auto bg-mid py-3 shadow-inner-sm shadow-shade")
)} )}
> >
<div <div
@ -733,7 +731,7 @@ const ContentLine = ({
</div> </div>
<div <div
className={`grid-flow-col place-content-start place-items-center gap-2 ${ className={`grid-flow-col place-content-start place-items-center gap-2 ${
opened ? "grid" : "hidden" isOpened ? "grid" : "hidden"
}`} }`}
> >
<Ico icon={Icon.SubdirectoryArrowRight} className="text-dark" /> <Ico icon={Icon.SubdirectoryArrowRight} className="text-dark" />

View File

@ -28,7 +28,6 @@ import { PreviewCard } from "components/PreviewCard";
import { useMediaHoverable } from "hooks/useMediaQuery"; import { useMediaHoverable } from "hooks/useMediaQuery";
import { ButtonGroup } from "components/Inputs/ButtonGroup"; import { ButtonGroup } from "components/Inputs/ButtonGroup";
import { filterHasAttributes, isDefined, isUndefined } from "helpers/others"; import { filterHasAttributes, isDefined, isUndefined } from "helpers/others";
import { ContentPlaceholder } from "components/PanelComponents/ContentPlaceholder";
import { useAppLayout } from "contexts/AppLayoutContext"; import { useAppLayout } from "contexts/AppLayoutContext";
import { convertPrice } from "helpers/numbers"; import { convertPrice } from "helpers/numbers";
import { SmartList } from "components/SmartList"; import { SmartList } from "components/SmartList";
@ -445,12 +444,6 @@ const Library = ({
} }
/> />
)} )}
renderWhenEmpty={() => (
<ContentPlaceholder
message={langui.no_results_message ?? "No results"}
icon={Icon.ChevronLeft}
/>
)}
className="grid-cols-2 items-end desktop:grid-cols-[repeat(auto-fill,_minmax(13rem,1fr))]" className="grid-cols-2 items-end desktop:grid-cols-[repeat(auto-fill,_minmax(13rem,1fr))]"
searchingTerm={searchName} searchingTerm={searchName}
sortingFunction={sortingFunction} sortingFunction={sortingFunction}

View File

@ -27,6 +27,11 @@ import { prettySlug } from "helpers/formatters";
import { useLightBox } from "hooks/useLightBox"; import { useLightBox } from "hooks/useLightBox";
import { getAssetURL, ImageQuality } from "helpers/img"; import { getAssetURL, ImageQuality } from "helpers/img";
/*
*
* PAGE
*/
interface Props extends AppStaticProps { interface Props extends AppStaticProps {
page: WikiPageWithTranslations; page: WikiPageWithTranslations;
} }
@ -78,7 +83,7 @@ const WikiPage = ({
className="mb-10" className="mb-10"
/> />
<div className="flex place-content-center gap-3"> <div className="flex flex-wrap place-content-center gap-3">
<h1 className="text-center text-3xl">{selectedTranslation?.title}</h1> <h1 className="text-center text-3xl">{selectedTranslation?.title}</h1>
{selectedTranslation?.aliases && {selectedTranslation?.aliases &&
selectedTranslation.aliases.length > 0 && ( selectedTranslation.aliases.length > 0 && (
@ -96,8 +101,8 @@ const WikiPage = ({
{selectedTranslation && ( {selectedTranslation && (
<div className="text-justify"> <div className="text-justify">
<div <div
className="float-right ml-8 mb-8 w-[25rem] overflow-hidden rounded-lg bg-mid className="mb-8 overflow-hidden rounded-lg bg-mid text-center desktop:float-right
text-center" desktop:ml-8 desktop:w-[25rem]"
> >
{page.thumbnail?.data?.attributes && ( {page.thumbnail?.data?.attributes && (
<Img <Img
@ -160,7 +165,7 @@ const WikiPage = ({
</div> </div>
{isDefinedAndNotEmpty(selectedTranslation.summary) && ( {isDefinedAndNotEmpty(selectedTranslation.summary) && (
<div className="mb-6"> <div className="mb-12">
<p className="font-headers text-lg font-bold"> <p className="font-headers text-lg font-bold">
{langui.summary} {langui.summary}
</p> </p>
@ -171,9 +176,8 @@ const WikiPage = ({
{filterHasAttributes(page.definitions, [ {filterHasAttributes(page.definitions, [
"translations", "translations",
] as const).map((definition, index) => ( ] as const).map((definition, index) => (
<> <div key={index} className="mb-12">
<DefinitionCard <DefinitionCard
key={index}
source={{ source={{
name: definition.source?.data?.attributes?.name, name: definition.source?.data?.attributes?.name,
url: definition.source?.data?.attributes?.content?.data url: definition.source?.data?.attributes?.content?.data
@ -193,8 +197,7 @@ const WikiPage = ({
"attributes", "attributes",
] as const).map((category) => category.attributes.short)} ] as const).map((category) => category.attributes.short)}
/> />
<br /> </div>
</>
))} ))}
</div> </div>
)} )}
@ -225,6 +228,11 @@ const WikiPage = ({
}; };
export default WikiPage; export default WikiPage;
/*
*
* NEXT DATA FETCHING
*/
export const getStaticProps: GetStaticProps = async (context) => { export const getStaticProps: GetStaticProps = async (context) => {
const sdk = getReadySdk(); const sdk = getReadySdk();
const slug = const slug =
@ -246,6 +254,8 @@ export const getStaticProps: GetStaticProps = async (context) => {
}; };
}; };
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
export const getStaticPaths: GetStaticPaths = async (context) => { export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk(); const sdk = getReadySdk();
const contents = await sdk.getWikiPagesSlugs(); const contents = await sdk.getWikiPagesSlugs();

View File

@ -19,7 +19,6 @@ import { TextInput } from "components/Inputs/TextInput";
import { WithLabel } from "components/Inputs/WithLabel"; import { WithLabel } from "components/Inputs/WithLabel";
import { useMediaHoverable } from "hooks/useMediaQuery"; import { useMediaHoverable } from "hooks/useMediaQuery";
import { filterDefined, filterHasAttributes } from "helpers/others"; import { filterDefined, filterHasAttributes } from "helpers/others";
import { ContentPlaceholder } from "components/PanelComponents/ContentPlaceholder";
import { SmartList } from "components/SmartList"; import { SmartList } from "components/SmartList";
import { Select } from "components/Inputs/Select"; import { Select } from "components/Inputs/Select";
import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable"; import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable";
@ -204,12 +203,6 @@ const Wiki = ({
).map((category) => category.attributes.short)} ).map((category) => category.attributes.short)}
/> />
)} )}
renderWhenEmpty={() => (
<ContentPlaceholder
message={langui.no_results_message ?? "No results"}
icon={Icon.ChevronLeft}
/>
)}
langui={langui} langui={langui}
className="grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(20rem,1fr))]" className="grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(20rem,1fr))]"
searchingTerm={searchName} searchingTerm={searchName}