diff --git a/src/components/Inputs/Select.tsx b/src/components/Inputs/Select.tsx index 0eed39f..abf3f73 100644 --- a/src/components/Inputs/Select.tsx +++ b/src/components/Inputs/Select.tsx @@ -1,4 +1,10 @@ -import { Dispatch, Fragment, SetStateAction, useState } from "react"; +import { + Dispatch, + Fragment, + SetStateAction, + useCallback, + useState, +} from "react"; import { Ico, Icon } from "components/Ico"; import { cIf, cJoin } from "helpers/className"; import { useToggle } from "hooks/useToggle"; @@ -29,6 +35,11 @@ export const Select = ({ const [opened, setOpened] = useState(false); const toggleOpened = useToggle(setOpened); + const tryToggling = useCallback(() => { + const optionCount = options.length + (state === -1 ? 1 : 0); + if (optionCount > 1) toggleOpened(); + }, [options.length, state, toggleOpened]); + return (
-

+

{state === -1 ? "—" : options[state]}

{state >= 0 && allowEmpty && ( @@ -59,7 +70,7 @@ export const Select = ({ /> )}
diff --git a/src/components/Wiki/DefinitionCard.tsx b/src/components/Wiki/DefinitionCard.tsx index 75151d7..447278a 100644 --- a/src/components/Wiki/DefinitionCard.tsx +++ b/src/components/Wiki/DefinitionCard.tsx @@ -4,6 +4,8 @@ import { ToolTip } from "components/ToolTip"; import { AppStaticProps } from "graphql/getAppStaticProps"; import { getStatusDescription } from "helpers/others"; import { useSmartLanguage } from "hooks/useSmartLanguage"; +import Link from "next/link"; +import { Button } from "components/Inputs/Button"; /* * ╭─────────────╮ @@ -11,7 +13,10 @@ import { useSmartLanguage } from "hooks/useSmartLanguage"; */ interface Props { - source?: string; + source?: { + name?: string; + url?: string; + }; translations: { language: string | undefined; definition: string | null | undefined; @@ -79,9 +84,16 @@ const DefinitionCard = ({ )} -

{`${langui.source}: ${source}`}

-

{selectedTranslation?.definition}

+ + {source?.url && source.name && ( + +
+

{langui.source}:

+
+ + )} ); }; diff --git a/src/graphql/fragments/source.graphql b/src/graphql/fragments/source.graphql new file mode 100644 index 0000000..9316d6e --- /dev/null +++ b/src/graphql/fragments/source.graphql @@ -0,0 +1,24 @@ +fragment source on Source { + name + content { + data { + attributes { + slug + } + } + } + ranged_content { + data { + attributes { + slug + library_item { + data { + attributes { + slug + } + } + } + } + } + } +} diff --git a/src/graphql/operations/getWikiPage.graphql b/src/graphql/operations/getWikiPage.graphql index cc3a8e1..b22db19 100644 --- a/src/graphql/operations/getWikiPage.graphql +++ b/src/graphql/operations/getWikiPage.graphql @@ -20,6 +20,24 @@ query getWikiPage($slug: String, $language_code: String) { } } } + tags { + data { + id + attributes { + slug + titles(filters: { language: { code: { eq: $language_code } } }) { + language { + data { + attributes { + code + } + } + } + title + } + } + } + } translations { title aliases { @@ -73,7 +91,7 @@ query getWikiPage($slug: String, $language_code: String) { source { data { attributes { - name + ...source } } } diff --git a/src/graphql/operations/getWikiPagesPreviews.graphql b/src/graphql/operations/getWikiPagesPreviews.graphql index 3fc402c..9925e99 100644 --- a/src/graphql/operations/getWikiPagesPreviews.graphql +++ b/src/graphql/operations/getWikiPagesPreviews.graphql @@ -1,4 +1,4 @@ -query getWikiPagesPreviews { +query getWikiPagesPreviews($language_code: String) { wikiPages(pagination: { limit: -1 }) { data { id @@ -20,6 +20,24 @@ query getWikiPagesPreviews { } } } + tags { + data { + id + attributes { + slug + titles(filters: { language: { code: { eq: $language_code } } }) { + language { + data { + attributes { + code + } + } + } + title + } + } + } + } translations { title aliases { diff --git a/src/pages/wiki/[slug]/index.tsx b/src/pages/wiki/[slug]/index.tsx index 8854ade..d15223f 100644 --- a/src/pages/wiki/[slug]/index.tsx +++ b/src/pages/wiki/[slug]/index.tsx @@ -23,6 +23,9 @@ import { } from "helpers/others"; import { WikiPageWithTranslations } from "helpers/types"; import { useSmartLanguage } from "hooks/useSmartLanguage"; +import { prettySlug } from "helpers/formatters"; +import { useLightBox } from "hooks/useLightBox"; +import { getAssetURL, ImageQuality } from "helpers/img"; interface Props extends AppStaticProps { page: WikiPageWithTranslations; @@ -45,6 +48,8 @@ const WikiPage = ({ ), }); + const [openLightBox, LightBox] = useLightBox(); + const subPanel = useMemo( () => ( @@ -63,6 +68,8 @@ const WikiPage = ({ const contentPanel = useMemo( () => ( + + {`(${selectedTranslation.aliases .map((alias) => alias?.alias) - .join(", ")})`} + .join("・")})`}

)} @@ -93,19 +100,63 @@ const WikiPage = ({ text-center" > {page.thumbnail?.data?.attributes && ( - + { + if (page.thumbnail?.data?.attributes?.url) { + openLightBox([ + getAssetURL( + page.thumbnail.data.attributes.url, + ImageQuality.Large + ), + ]); + } + }} + /> )}
-

- {langui.categories} -

-
- {filterHasAttributes(page.categories?.data, [ - "attributes", - ] as const).map((category) => ( - - ))} -
+ {page.categories?.data && page.categories.data.length > 0 && ( + <> +

+ {langui.categories} +

+ +
+ {filterHasAttributes(page.categories.data, [ + "attributes", + ] as const).map((category) => ( + + ))} +
+ + )} + + {page.tags?.data && page.tags.data.length > 0 && ( + <> +

+ {/* TODO: Add Tags to langui */} + {"Tags"} +

+
+ {filterHasAttributes(page.tags?.data, [ + "attributes", + ] as const).map((tag) => ( + + ))} +
+ + )}
@@ -124,7 +175,13 @@ const WikiPage = ({ <> ({ language: translation?.language?.data?.attributes?.code, definition: translation?.definition, @@ -149,9 +206,7 @@ const WikiPage = ({ languageSwitcherProps, languages, langui, - page.categories?.data, - page.definitions, - page.thumbnail?.data?.attributes, + page, selectedTranslation, ] ); diff --git a/src/pages/wiki/index.tsx b/src/pages/wiki/index.tsx index 0f8d75a..c4d0a17 100644 --- a/src/pages/wiki/index.tsx +++ b/src/pages/wiki/index.tsx @@ -1,5 +1,5 @@ import { GetStaticProps } from "next"; -import { Fragment, useMemo, useState } from "react"; +import { useCallback, useMemo, useState } from "react"; import { AppLayout } from "components/AppLayout"; import { NavOption } from "components/PanelComponents/NavOption"; import { PanelHeader } from "components/PanelComponents/PanelHeader"; @@ -7,7 +7,7 @@ import { SubPanel } from "components/Panels/SubPanel"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { Icon } from "components/Ico"; import { getReadySdk } from "graphql/sdk"; -import { GetWikiPagesPreviewsQuery } from "graphql/generated"; +import { GetWikiPageQuery, GetWikiPagesPreviewsQuery } from "graphql/generated"; import { ContentPanel, ContentPanelWidthSizes, @@ -19,8 +19,12 @@ 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 { filterDefined, filterHasAttributes, isDefined } 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"; +import { prettySlug } from "helpers/formatters"; /* * ╭─────────────╮ @@ -30,6 +34,7 @@ import { ContentPlaceholder } from "components/PanelComponents/ContentPlaceholde const DEFAULT_FILTERS_STATE = { searchName: "", keepInfoVisible: true, + groupingMethod: -1, }; /* @@ -52,13 +57,13 @@ const Wiki = ({ const [searchName, setSearchName] = useState( DEFAULT_FILTERS_STATE.searchName ); - const [keepInfoVisible, setKeepInfoVisible] = useState( - DEFAULT_FILTERS_STATE.keepInfoVisible + + const [groupingMethod, setGroupingMethod] = useState( + DEFAULT_FILTERS_STATE.groupingMethod ); - const filteredPages = useMemo( - () => filterPages(pages, searchName), - [pages, searchName] + const [keepInfoVisible, setKeepInfoVisible] = useState( + DEFAULT_FILTERS_STATE.keepInfoVisible ); const subPanel = useMemo( @@ -77,6 +82,19 @@ const Wiki = ({ setState={setSearchName} /> + + } + /> + {hoverable && (
), - [hoverable, keepInfoVisible, langui, searchName] + [groupingMethod, hoverable, keepInfoVisible, langui, searchName] + ); + + const groupingFunction = useCallback( + ( + item: SelectiveNonNullable< + NonNullable["data"][number], + "attributes" | "id" + > + ): string[] => { + switch (groupingMethod) { + case 0: { + const categories = filterHasAttributes( + item.attributes.categories?.data, + ["attributes"] as const + ); + if (categories.length > 0) { + return categories.map((category) => category.attributes.name); + } + return [langui.no_category ?? "No category"]; + } + default: { + return [""]; + } + } + }, + [groupingMethod, langui] ); const contentPanel = useMemo( () => ( -
- {filteredPages.length === 0 && ( + item.id} + renderItem={({ item }) => ( + <> + {isDefined(item.attributes.translations) && ( + ({ + title: translation?.title, + subtitle: + translation?.aliases && translation.aliases.length > 0 + ? translation.aliases + .map((alias) => alias?.alias) + .join("・") + : undefined, + description: translation?.summary, + language: translation?.language?.data?.attributes?.code, + }) + )} + thumbnail={item.attributes.thumbnail?.data?.attributes} + thumbnailAspectRatio={"4/3"} + thumbnailRounded + thumbnailForceAspectRatio + languages={languages} + slug={item.attributes.slug} + keepInfoVisible={keepInfoVisible} + topChips={filterHasAttributes(item.attributes.tags?.data, [ + "attributes", + ] as const).map( + (tag) => + tag.attributes.titles?.[0]?.title ?? + prettySlug(tag.attributes.slug) + )} + bottomChips={filterHasAttributes( + item.attributes.categories?.data, + ["attributes"] as const + ).map((category) => category.attributes.short)} + /> + )} + + )} + renderWhenEmpty={() => ( )} - {filterHasAttributes(filteredPages, [ - "id", - "attributes.translations", - ] as const).map((page) => ( - - ({ - title: translation?.title, - subtitle: - translation?.aliases && translation.aliases.length > 0 - ? translation.aliases - .map((alias) => alias?.alias) - .join(" | ") - : undefined, - 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 ?? "" - )} - /> - - ))} -
+ langui={langui} + className="grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(20rem,1fr))]" + searchingTerm={searchName} + searchingBy={(item) => + filterDefined(item.attributes.translations) + .map( + (translation) => + `${translation.title} ${filterDefined(translation.aliases) + .map((alias) => alias.alias) + .join(" ")}` + ) + .join(" ") + } + groupingFunction={groupingFunction} + />
), - [filteredPages, keepInfoVisible, languages, langui] + [groupingFunction, keepInfoVisible, languages, langui, pages, searchName] ); return ( @@ -180,7 +244,9 @@ export default Wiki; export const getStaticProps: GetStaticProps = async (context) => { const sdk = getReadySdk(); - const pages = await sdk.getWikiPagesPreviews({}); + const pages = await sdk.getWikiPagesPreviews({ + language_code: context.locale ?? "en", + }); if (!pages.wikiPages?.data) return { notFound: true }; const props: Props = { ...(await getAppStaticProps(context)), @@ -202,20 +268,3 @@ const sortPages = (pages: Props["pages"]): Props["pages"] => const slugB = b.attributes?.slug ?? ""; return slugA.localeCompare(slugB); }); - -// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ - -const filterPages = (posts: Props["pages"], searchName: string) => - posts.filter((post) => { - if (searchName.length > 1) { - if ( - post.attributes?.translations?.[0]?.title - .toLowerCase() - .includes(searchName.toLowerCase()) === true - ) { - return true; - } - return false; - } - return true; - });