Improved wiki for mobile + removed old hook
This commit is contained in:
parent
0df66815c8
commit
c6ee213903
|
@ -1,7 +1,7 @@
|
|||
import { Fragment, useCallback, useState } from "react";
|
||||
import { Fragment, useCallback } from "react";
|
||||
import { Ico, Icon } from "components/Ico";
|
||||
import { cIf, cJoin } from "helpers/className";
|
||||
import { useToggle } from "hooks/useToggle";
|
||||
import { useBoolean } from "hooks/useBoolean";
|
||||
|
||||
/*
|
||||
* ╭─────────────╮
|
||||
|
@ -26,8 +26,11 @@ export const Select = ({
|
|||
allowEmpty,
|
||||
onChange,
|
||||
}: Props): JSX.Element => {
|
||||
const [opened, setOpened] = useState(false);
|
||||
const toggleOpened = useToggle(setOpened);
|
||||
const {
|
||||
state: isOpened,
|
||||
setFalse: setClosed,
|
||||
toggleState: toggleOpened,
|
||||
} = useBoolean(false);
|
||||
|
||||
const tryToggling = useCallback(() => {
|
||||
const optionCount = options.length + (value === -1 ? 1 : 0);
|
||||
|
@ -38,7 +41,7 @@ export const Select = ({
|
|||
<div
|
||||
className={cJoin(
|
||||
"relative text-center transition-[filter]",
|
||||
cIf(opened, "z-10 drop-shadow-shade-lg"),
|
||||
cIf(isOpened, "z-10 drop-shadow-shade-lg"),
|
||||
className
|
||||
)}
|
||||
>
|
||||
|
@ -47,7 +50,7 @@ export const Select = ({
|
|||
`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
|
||||
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">
|
||||
|
@ -58,20 +61,20 @@ export const Select = ({
|
|||
icon={Icon.Close}
|
||||
className="!text-xs"
|
||||
onClick={() => {
|
||||
setClosed();
|
||||
onChange(-1);
|
||||
setOpened(false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Ico
|
||||
onClick={tryToggling}
|
||||
icon={opened ? Icon.ArrowDropUp : Icon.ArrowDropDown}
|
||||
icon={isOpened ? Icon.ArrowDropUp : Icon.ArrowDropDown}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={cJoin(
|
||||
"left-0 right-0 rounded-b-[1em]",
|
||||
cIf(opened, "absolute", "hidden")
|
||||
cIf(isOpened, "absolute", "hidden")
|
||||
)}
|
||||
>
|
||||
{options.map((option, index) => (
|
||||
|
@ -80,11 +83,11 @@ export const Select = ({
|
|||
<div
|
||||
className={cJoin(
|
||||
"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}
|
||||
onClick={() => {
|
||||
setOpened(false);
|
||||
setClosed();
|
||||
onChange(index);
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Fragment, useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { Chip } from "./Chip";
|
||||
import { PageSelector } from "./Inputs/PageSelector";
|
||||
import { Ico, Icon } from "./Ico";
|
||||
import { AppStaticProps } from "graphql/getAppStaticProps";
|
||||
import { cJoin } from "helpers/className";
|
||||
import { isDefined, isDefinedAndNotEmpty, iterateMap } from "helpers/others";
|
||||
|
@ -145,43 +146,47 @@ export const SmartList = <T,>({
|
|||
)}
|
||||
|
||||
<div className="mb-8">
|
||||
{groupedList.size > 0
|
||||
? iterateMap(
|
||||
groupedList,
|
||||
(name, groupItems) =>
|
||||
groupItems.length > 0 && (
|
||||
<Fragment key={name}>
|
||||
{name.length > 0 && (
|
||||
<h2
|
||||
className="flex flex-row place-items-center gap-2 pb-2 pt-10 text-2xl
|
||||
{groupedList.size > 0 ? (
|
||||
iterateMap(
|
||||
groupedList,
|
||||
(name, groupItems) =>
|
||||
groupItems.length > 0 && (
|
||||
<Fragment key={name}>
|
||||
{name.length > 0 && (
|
||||
<h2
|
||||
className="flex flex-row place-items-center gap-2 pb-2 pt-10 text-2xl
|
||||
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) => (
|
||||
<RenderItem item={item} key={getItemId(item)} />
|
||||
))}
|
||||
</div>
|
||||
</Fragment>
|
||||
),
|
||||
([a], [b]) => groupSortingFunction(a, b)
|
||||
)
|
||||
: isDefined(RenderWhenEmpty) && <RenderWhenEmpty />}
|
||||
{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) => (
|
||||
<RenderItem item={item} key={getItemId(item)} />
|
||||
))}
|
||||
</div>
|
||||
</Fragment>
|
||||
),
|
||||
([a], [b]) => groupSortingFunction(a, b)
|
||||
)
|
||||
) : isDefined(RenderWhenEmpty) ? (
|
||||
<RenderWhenEmpty />
|
||||
) : (
|
||||
<DefaultRenderWhenEmpty langui={langui} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{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>
|
||||
);
|
||||
|
|
|
@ -88,7 +88,7 @@ const DefinitionCard = ({
|
|||
|
||||
{source?.url && source.name && (
|
||||
<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>
|
||||
<Button size="small" text={source.name} />
|
||||
</div>
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
import { Dispatch, SetStateAction, useCallback } from "react";
|
||||
|
||||
export const useToggle = (
|
||||
setState: Dispatch<SetStateAction<boolean>>
|
||||
): (() => void) =>
|
||||
useCallback(() => {
|
||||
setState((current) => !current);
|
||||
}, [setState]);
|
|
@ -6,7 +6,6 @@ import { Icon } from "components/Ico";
|
|||
import { Switch } from "components/Inputs/Switch";
|
||||
import { TextInput } from "components/Inputs/TextInput";
|
||||
import { WithLabel } from "components/Inputs/WithLabel";
|
||||
import { ContentPlaceholder } from "components/PanelComponents/ContentPlaceholder";
|
||||
import { PanelHeader } from "components/PanelComponents/PanelHeader";
|
||||
import {
|
||||
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
|
||||
thin:grid-cols-1"
|
||||
paginationItemPerPage={20}
|
||||
|
|
|
@ -20,7 +20,6 @@ import { Icon } from "components/Ico";
|
|||
import { filterDefined, filterHasAttributes } from "helpers/others";
|
||||
import { GetContentsQuery } from "graphql/generated";
|
||||
import { SmartList } from "components/SmartList";
|
||||
import { ContentPlaceholder } from "components/PanelComponents/ContentPlaceholder";
|
||||
import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable";
|
||||
import { useBoolean } from "hooks/useBoolean";
|
||||
import { TranslatedPreviewCard } from "components/Translated";
|
||||
|
@ -259,12 +258,6 @@ const Contents = ({
|
|||
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))]"
|
||||
groupingFunction={groupingFunction}
|
||||
filteringFunction={filteringFunction}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Fragment, useCallback, useMemo, useState } from "react";
|
||||
import { Fragment, useCallback, useMemo } from "react";
|
||||
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
|
||||
import { AppLayout } from "components/AppLayout";
|
||||
import { Chip } from "components/Chip";
|
||||
|
@ -49,7 +49,6 @@ import { AnchorIds, useScrollTopOnChange } from "hooks/useScrollTopOnChange";
|
|||
import { isUntangibleGroupItem } from "helpers/libraryItem";
|
||||
import { useMediaHoverable } from "hooks/useMediaQuery";
|
||||
import { WithLabel } from "components/Inputs/WithLabel";
|
||||
import { useToggle } from "hooks/useToggle";
|
||||
import { Ico, Icon } from "components/Ico";
|
||||
import { cJoin, cIf } from "helpers/className";
|
||||
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
||||
|
@ -682,8 +681,7 @@ const ContentLine = ({
|
|||
slug,
|
||||
parentSlug,
|
||||
}: ContentLineProps): JSX.Element => {
|
||||
const [opened, setOpened] = useState(false);
|
||||
const toggleOpened = useToggle(setOpened);
|
||||
const { state: isOpened, toggleState: toggleOpened } = useBoolean(false);
|
||||
|
||||
const [selectedTranslation] = useSmartLanguage({
|
||||
items: content?.translations ?? [],
|
||||
|
@ -700,7 +698,7 @@ const ContentLine = ({
|
|||
<div
|
||||
className={cJoin(
|
||||
"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
|
||||
|
@ -733,7 +731,7 @@ const ContentLine = ({
|
|||
</div>
|
||||
<div
|
||||
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" />
|
||||
|
|
|
@ -28,7 +28,6 @@ import { PreviewCard } from "components/PreviewCard";
|
|||
import { useMediaHoverable } from "hooks/useMediaQuery";
|
||||
import { ButtonGroup } from "components/Inputs/ButtonGroup";
|
||||
import { filterHasAttributes, isDefined, isUndefined } from "helpers/others";
|
||||
import { ContentPlaceholder } from "components/PanelComponents/ContentPlaceholder";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { convertPrice } from "helpers/numbers";
|
||||
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))]"
|
||||
searchingTerm={searchName}
|
||||
sortingFunction={sortingFunction}
|
||||
|
|
|
@ -27,6 +27,11 @@ import { prettySlug } from "helpers/formatters";
|
|||
import { useLightBox } from "hooks/useLightBox";
|
||||
import { getAssetURL, ImageQuality } from "helpers/img";
|
||||
|
||||
/*
|
||||
* ╭────────╮
|
||||
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
page: WikiPageWithTranslations;
|
||||
}
|
||||
|
@ -78,7 +83,7 @@ const WikiPage = ({
|
|||
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>
|
||||
{selectedTranslation?.aliases &&
|
||||
selectedTranslation.aliases.length > 0 && (
|
||||
|
@ -96,8 +101,8 @@ const WikiPage = ({
|
|||
{selectedTranslation && (
|
||||
<div className="text-justify">
|
||||
<div
|
||||
className="float-right ml-8 mb-8 w-[25rem] overflow-hidden rounded-lg bg-mid
|
||||
text-center"
|
||||
className="mb-8 overflow-hidden rounded-lg bg-mid text-center desktop:float-right
|
||||
desktop:ml-8 desktop:w-[25rem]"
|
||||
>
|
||||
{page.thumbnail?.data?.attributes && (
|
||||
<Img
|
||||
|
@ -160,7 +165,7 @@ const WikiPage = ({
|
|||
</div>
|
||||
|
||||
{isDefinedAndNotEmpty(selectedTranslation.summary) && (
|
||||
<div className="mb-6">
|
||||
<div className="mb-12">
|
||||
<p className="font-headers text-lg font-bold">
|
||||
{langui.summary}
|
||||
</p>
|
||||
|
@ -171,9 +176,8 @@ const WikiPage = ({
|
|||
{filterHasAttributes(page.definitions, [
|
||||
"translations",
|
||||
] as const).map((definition, index) => (
|
||||
<>
|
||||
<div key={index} className="mb-12">
|
||||
<DefinitionCard
|
||||
key={index}
|
||||
source={{
|
||||
name: definition.source?.data?.attributes?.name,
|
||||
url: definition.source?.data?.attributes?.content?.data
|
||||
|
@ -193,8 +197,7 @@ const WikiPage = ({
|
|||
"attributes",
|
||||
] as const).map((category) => category.attributes.short)}
|
||||
/>
|
||||
<br />
|
||||
</>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
@ -225,6 +228,11 @@ const WikiPage = ({
|
|||
};
|
||||
export default WikiPage;
|
||||
|
||||
/*
|
||||
* ╭──────────────────────╮
|
||||
* ───────────────────────────────────╯ NEXT DATA FETCHING ╰──────────────────────────────────────
|
||||
*/
|
||||
|
||||
export const getStaticProps: GetStaticProps = async (context) => {
|
||||
const sdk = getReadySdk();
|
||||
const slug =
|
||||
|
@ -246,6 +254,8 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|||
};
|
||||
};
|
||||
|
||||
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
|
||||
export const getStaticPaths: GetStaticPaths = async (context) => {
|
||||
const sdk = getReadySdk();
|
||||
const contents = await sdk.getWikiPagesSlugs();
|
||||
|
|
|
@ -19,7 +19,6 @@ import { TextInput } from "components/Inputs/TextInput";
|
|||
import { WithLabel } from "components/Inputs/WithLabel";
|
||||
import { useMediaHoverable } from "hooks/useMediaQuery";
|
||||
import { filterDefined, filterHasAttributes } from "helpers/others";
|
||||
import { ContentPlaceholder } from "components/PanelComponents/ContentPlaceholder";
|
||||
import { SmartList } from "components/SmartList";
|
||||
import { Select } from "components/Inputs/Select";
|
||||
import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable";
|
||||
|
@ -204,12 +203,6 @@ const Wiki = ({
|
|||
).map((category) => category.attributes.short)}
|
||||
/>
|
||||
)}
|
||||
renderWhenEmpty={() => (
|
||||
<ContentPlaceholder
|
||||
message={langui.no_results_message ?? "No results"}
|
||||
icon={Icon.ChevronLeft}
|
||||
/>
|
||||
)}
|
||||
langui={langui}
|
||||
className="grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(20rem,1fr))]"
|
||||
searchingTerm={searchName}
|
||||
|
|
Loading…
Reference in New Issue