Compare commits
2 Commits
facetted-s
...
main
Author | SHA1 | Date |
---|---|---|
DrMint | e88345f395 | |
DrMint | 34c4570688 |
|
@ -161,7 +161,6 @@ module.exports = {
|
||||||
"@typescript-eslint/no-invalid-void-type": "error",
|
"@typescript-eslint/no-invalid-void-type": "error",
|
||||||
"@typescript-eslint/no-meaningless-void-operator": "error",
|
"@typescript-eslint/no-meaningless-void-operator": "error",
|
||||||
"@typescript-eslint/no-non-null-asserted-nullish-coalescing": "error",
|
"@typescript-eslint/no-non-null-asserted-nullish-coalescing": "error",
|
||||||
"@typescript-eslint/no-parameter-properties": "error",
|
|
||||||
"@typescript-eslint/no-require-imports": "error",
|
"@typescript-eslint/no-require-imports": "error",
|
||||||
// "@typescript-eslint/no-type-alias": "warn",
|
// "@typescript-eslint/no-type-alias": "warn",
|
||||||
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "warn",
|
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "warn",
|
||||||
|
@ -182,7 +181,6 @@ module.exports = {
|
||||||
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
||||||
"@typescript-eslint/promise-function-async": "error",
|
"@typescript-eslint/promise-function-async": "error",
|
||||||
"@typescript-eslint/require-array-sort-compare": "error",
|
"@typescript-eslint/require-array-sort-compare": "error",
|
||||||
"@typescript-eslint/sort-type-union-intersection-members": "warn",
|
|
||||||
// "@typescript-eslint/strict-boolean-expressions": [
|
// "@typescript-eslint/strict-boolean-expressions": [
|
||||||
// "error",
|
// "error",
|
||||||
// { allowAny: true },
|
// { allowAny: true },
|
||||||
|
@ -192,7 +190,6 @@ module.exports = {
|
||||||
"@typescript-eslint/unified-signatures": "error",
|
"@typescript-eslint/unified-signatures": "error",
|
||||||
|
|
||||||
/* EXTENSION OF ESLINT */
|
/* EXTENSION OF ESLINT */
|
||||||
"@typescript-eslint/no-duplicate-imports": "error",
|
|
||||||
"@typescript-eslint/default-param-last": "warn",
|
"@typescript-eslint/default-param-last": "warn",
|
||||||
"@typescript-eslint/dot-notation": "warn",
|
"@typescript-eslint/dot-notation": "warn",
|
||||||
"@typescript-eslint/init-declarations": "warn",
|
"@typescript-eslint/init-declarations": "warn",
|
||||||
|
|
|
@ -3,5 +3,3 @@ interactive: true
|
||||||
format: "group"
|
format: "group"
|
||||||
reject:
|
reject:
|
||||||
- "react-hotkeys-hook" # we are stuck at version 3.4.7 because 4.X is not working well. Need more experimenting.
|
- "react-hotkeys-hook" # we are stuck at version 3.4.7 because 4.X is not working well. Need more experimenting.
|
||||||
- "graphql-request" # we are stuck at version 5.1.0 because 5.2.0 has a typescript bug see https://github.com/dotansimha/graphql-code-generator/issues/9046
|
|
||||||
- "@graphql-codegen/typescript-graphql-request" # same as for "graphql-request"
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
88
package.json
88
package.json
|
@ -21,71 +21,71 @@
|
||||||
"upgrade": "ncu"
|
"upgrade": "ncu"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/noto-serif-jp": "^5.0.2",
|
"@fontsource/noto-serif-jp": "^5.0.7",
|
||||||
"@fontsource/opendyslexic": "^5.0.2",
|
"@fontsource/opendyslexic": "^5.0.7",
|
||||||
"@fontsource/share-tech-mono": "^5.0.2",
|
"@fontsource/share-tech-mono": "^5.0.8",
|
||||||
"@fontsource/vollkorn": "^5.0.2",
|
"@fontsource/vollkorn": "^5.0.9",
|
||||||
"@fontsource/zen-maru-gothic": "^5.0.2",
|
"@fontsource/zen-maru-gothic": "^5.0.7",
|
||||||
"@formatjs/icu-messageformat-parser": "^2.4.0",
|
"@formatjs/icu-messageformat-parser": "^2.6.0",
|
||||||
"@tippyjs/react": "^4.2.6",
|
"@tippyjs/react": "^4.2.6",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.15",
|
||||||
"cuid": "^2.1.8",
|
"cuid": "^2.1.8",
|
||||||
"html-to-text": "^9.0.5",
|
"html-to-text": "^9.0.5",
|
||||||
"intl-messageformat": "^10.3.5",
|
"intl-messageformat": "^10.5.0",
|
||||||
"isomorphic-dompurify": "^1.6.0",
|
"isomorphic-dompurify": "^1.8.0",
|
||||||
"jotai": "^2.1.1",
|
"jotai": "^2.3.1",
|
||||||
"markdown-to-jsx": "^7.2.1",
|
"markdown-to-jsx": "^7.3.2",
|
||||||
"marked": "^4.3.0",
|
"marked": "^7.0.3",
|
||||||
"material-symbols": "^0.5.5",
|
"material-symbols": "^0.10.4",
|
||||||
"meilisearch": "^0.33.0",
|
"meilisearch": "^0.34.1",
|
||||||
"next": "^13.4.4",
|
"next": "^13.4.17",
|
||||||
"nodemailer": "^6.9.3",
|
"nodemailer": "^6.9.4",
|
||||||
"patch-package": "^7.0.0",
|
"patch-package": "^8.0.0",
|
||||||
"rc-slider": "^10.2.0",
|
"rc-slider": "^10.2.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-collapsible": "^2.10.0",
|
"react-collapsible": "^2.10.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-hotkeys-hook": "^3.4.7",
|
"react-hotkeys-hook": "^3.4.7",
|
||||||
"react-swipeable": "^7.0.1",
|
"react-swipeable": "^7.0.1",
|
||||||
"react-zoom-pan-pinch": "^3.0.8",
|
"react-zoom-pan-pinch": "^3.1.0",
|
||||||
"string-natural-compare": "^3.0.1",
|
"string-natural-compare": "^3.0.1",
|
||||||
"throttle-debounce": "^5.0.0",
|
"throttle-debounce": "^5.0.0",
|
||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
"turndown": "^7.1.2",
|
"turndown": "^7.1.2",
|
||||||
"ua-parser-js": "^1.0.35",
|
"ua-parser-js": "^1.0.35",
|
||||||
"usehooks-ts": "^2.9.1",
|
"usehooks-ts": "^2.9.1",
|
||||||
"zod": "^3.21.4"
|
"zod": "^3.22.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@digitak/esrun": "3.2.24",
|
"@digitak/esrun": "3.2.24",
|
||||||
"@graphql-codegen/cli": "^3.3.1",
|
"@graphql-codegen/cli": "5.0.0",
|
||||||
"@graphql-codegen/typescript": "3.0.4",
|
"@graphql-codegen/typescript": "4.0.1",
|
||||||
"@graphql-codegen/typescript-graphql-request": "^4.5.9",
|
"@graphql-codegen/typescript-graphql-request": "5.0.0",
|
||||||
"@graphql-codegen/typescript-operations": "^3.0.4",
|
"@graphql-codegen/typescript-operations": "4.0.1",
|
||||||
"@types/html-to-text": "^9.0.1",
|
"@types/html-to-text": "^9.0.1",
|
||||||
"@types/marked": "^4.3.0",
|
"@types/marked": "^5.0.1",
|
||||||
"@types/node": "20.2.5",
|
"@types/node": "20.5.0",
|
||||||
"@types/nodemailer": "^6.4.8",
|
"@types/nodemailer": "^6.4.9",
|
||||||
"@types/react": "^18.2.9",
|
"@types/react": "^18.2.20",
|
||||||
"@types/react-dom": "^18.2.4",
|
"@types/react-dom": "^18.2.7",
|
||||||
"@types/string-natural-compare": "^3.0.2",
|
"@types/string-natural-compare": "^3.0.2",
|
||||||
"@types/throttle-debounce": "^5.0.0",
|
"@types/throttle-debounce": "^5.0.0",
|
||||||
"@types/turndown": "^5.0.1",
|
"@types/turndown": "^5.0.1",
|
||||||
"@types/ua-parser-js": "^0.7.36",
|
"@types/ua-parser-js": "^0.7.36",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.59.9",
|
"@typescript-eslint/eslint-plugin": "^6.4.0",
|
||||||
"@typescript-eslint/parser": "^5.59.9",
|
"@typescript-eslint/parser": "^6.4.0",
|
||||||
"chalk": "^5.2.0",
|
"chalk": "^5.3.0",
|
||||||
"dotenv": "^16.1.4",
|
"dotenv": "^16.3.1",
|
||||||
"eslint": "^8.42.0",
|
"eslint": "^8.47.0",
|
||||||
"eslint-config-next": "13.4.4",
|
"eslint-config-next": "13.4.17",
|
||||||
"eslint-plugin-import": "^2.27.5",
|
"eslint-plugin-import": "^2.28.0",
|
||||||
"graphql": "^16.6.0",
|
"graphql": "16.8.0",
|
||||||
"graphql-request": "5.1.0",
|
"graphql-request": "6.1.0",
|
||||||
"next-sitemap": "^4.1.3",
|
"next-sitemap": "^4.2.2",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^3.0.2",
|
||||||
"prettier-plugin-tailwindcss": "^0.3.0",
|
"prettier-plugin-tailwindcss": "^0.5.3",
|
||||||
"tailwindcss": "^3.3.2",
|
"tailwindcss": "^3.3.3",
|
||||||
"ts-unused-exports": "^9.0.4",
|
"ts-unused-exports": "^10.0.0",
|
||||||
"typescript": "^5.1.3"
|
"typescript": "^5.1.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -19,7 +19,8 @@ interface Props {
|
||||||
export const ChroniclesLists = ({ chapters, currentChronicleSlug }: Props): JSX.Element => {
|
export const ChroniclesLists = ({ chapters, currentChronicleSlug }: Props): JSX.Element => {
|
||||||
const [openedIndex, setOpenedIndex] = useState(
|
const [openedIndex, setOpenedIndex] = useState(
|
||||||
currentChronicleSlug
|
currentChronicleSlug
|
||||||
? chapters.findIndex((chapter) =>
|
? chapters.findIndex(
|
||||||
|
(chapter) =>
|
||||||
chapter.attributes?.chronicles?.data.some(
|
chapter.attributes?.chronicles?.data.some(
|
||||||
(chronicle) => chronicle.attributes?.slug === currentChronicleSlug
|
(chronicle) => chronicle.attributes?.slug === currentChronicleSlug
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { TranslatedProps } from "types/TranslatedProps";
|
||||||
import { atoms } from "contexts/atoms";
|
import { atoms } from "contexts/atoms";
|
||||||
import { useAtomGetter } from "helpers/atoms";
|
import { useAtomGetter } from "helpers/atoms";
|
||||||
import { useFormat } from "hooks/useFormat";
|
import { useFormat } from "hooks/useFormat";
|
||||||
|
import { isDefined } from "helpers/asserts";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ╭─────────────╮
|
* ╭─────────────╮
|
||||||
|
@ -84,7 +85,7 @@ export const PreviewCard = ({
|
||||||
|
|
||||||
const metadataJSX = (
|
const metadataJSX = (
|
||||||
<>
|
<>
|
||||||
{metadata && (metadata.releaseDate || metadata.price) && (
|
{metadata && (isDefined(metadata.releaseDate) || isDefined(metadata.price)) && (
|
||||||
<div className="flex w-full flex-row flex-wrap gap-x-3">
|
<div className="flex w-full flex-row flex-wrap gap-x-3">
|
||||||
{metadata.releaseDate && (
|
{metadata.releaseDate && (
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { convert } from "html-to-text";
|
import { convert } from "html-to-text";
|
||||||
import { sanitize } from "isomorphic-dompurify";
|
import { sanitize } from "isomorphic-dompurify";
|
||||||
import { marked } from "marked";
|
import { Renderer, marked } from "marked";
|
||||||
import { isDefinedAndNotEmpty } from "./asserts";
|
import { isDefinedAndNotEmpty } from "./asserts";
|
||||||
|
|
||||||
export const prettySlug = (slug?: string, parentSlug?: string): string => {
|
export const prettySlug = (slug?: string, parentSlug?: string): string => {
|
||||||
|
@ -101,7 +101,7 @@ export const prettyMarkdown = (markdown: string): string => {
|
||||||
const newline = () => "\n";
|
const newline = () => "\n";
|
||||||
const empty = () => "";
|
const empty = () => "";
|
||||||
|
|
||||||
const TxtRenderer: marked.Renderer = {
|
const TxtRenderer: Renderer = {
|
||||||
// Block elements
|
// Block elements
|
||||||
code: escapeBlock,
|
code: escapeBlock,
|
||||||
blockquote: block,
|
blockquote: block,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
|
||||||
import { MeiliSearch } from "meilisearch";
|
import { MeiliSearch } from "meilisearch";
|
||||||
import type {
|
import type {
|
||||||
SearchParams,
|
SearchParams,
|
||||||
|
@ -73,7 +75,6 @@ export const filterHitsWithHighlight = <T extends MeiliDocumentsType["documents"
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
||||||
export const meiliSearch = async <I extends MeiliDocumentsType["index"]>(
|
export const meiliSearch = async <I extends MeiliDocumentsType["index"]>(
|
||||||
indexName: I,
|
indexName: I,
|
||||||
query: string,
|
query: string,
|
||||||
|
@ -91,24 +92,5 @@ export const meiliSearch = async <I extends MeiliDocumentsType["index"]>(
|
||||||
})) as unknown as CustomSearchResponse<Extract<MeiliDocumentsType, { index: I }>["documents"]>;
|
})) as unknown as CustomSearchResponse<Extract<MeiliDocumentsType, { index: I }>["documents"]>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MeiliFacetResult = { name: string; count: number }[];
|
|
||||||
|
|
||||||
export const meiliFacet = async <I extends MeiliDocumentsType["index"]>(
|
|
||||||
indexName: I,
|
|
||||||
facet: string
|
|
||||||
): Promise<MeiliFacetResult> => {
|
|
||||||
const index = meili.index(indexName);
|
|
||||||
const searchResult = await index.search<Extract<MeiliDocumentsType, { index: I }>["documents"]>(
|
|
||||||
"",
|
|
||||||
{
|
|
||||||
hitsPerPage: 0,
|
|
||||||
facets: [facet],
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return [...Object.entries(searchResult.facetDistribution?.[facet] ?? {})].map(
|
|
||||||
([name, count]) => ({ name, count })
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const containsHighlight = (text: string | null | undefined): boolean =>
|
export const containsHighlight = (text: string | null | undefined): boolean =>
|
||||||
isDefined(text) && text.includes("</mark>");
|
isDefined(text) && text.includes("</mark>");
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { GetStaticProps } from "next";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { useBoolean } from "usehooks-ts";
|
import { useBoolean } from "usehooks-ts";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import Collapsible from "react-collapsible";
|
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { Select } from "components/Inputs/Select";
|
import { Select } from "components/Inputs/Select";
|
||||||
import { Switch } from "components/Inputs/Switch";
|
import { Switch } from "components/Inputs/Switch";
|
||||||
|
@ -21,8 +20,6 @@ import {
|
||||||
containsHighlight,
|
containsHighlight,
|
||||||
CustomSearchResponse,
|
CustomSearchResponse,
|
||||||
filterHitsWithHighlight,
|
filterHitsWithHighlight,
|
||||||
meiliFacet,
|
|
||||||
MeiliFacetResult,
|
|
||||||
meiliSearch,
|
meiliSearch,
|
||||||
} from "helpers/search";
|
} from "helpers/search";
|
||||||
import { MeiliContent, MeiliIndices } from "shared/meilisearch-graphql-typings/meiliTypes";
|
import { MeiliContent, MeiliIndices } from "shared/meilisearch-graphql-typings/meiliTypes";
|
||||||
|
@ -34,7 +31,6 @@ import { useFormat } from "hooks/useFormat";
|
||||||
import { getFormat } from "helpers/i18n";
|
import { getFormat } from "helpers/i18n";
|
||||||
import { useAtomGetter, useAtomSetter } from "helpers/atoms";
|
import { useAtomGetter, useAtomSetter } from "helpers/atoms";
|
||||||
import { atoms } from "contexts/atoms";
|
import { atoms } from "contexts/atoms";
|
||||||
import { Ico } from "components/Ico";
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ╭─────────────╮
|
* ╭─────────────╮
|
||||||
|
@ -79,6 +75,17 @@ const Contents = (props: Props): JSX.Element => {
|
||||||
[format]
|
[format]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const languageOptions = useMemo(() => {
|
||||||
|
const memo =
|
||||||
|
router.locales?.map((language) => ({
|
||||||
|
meiliAttribute: language,
|
||||||
|
displayedName: formatLanguage(language),
|
||||||
|
})) ?? [];
|
||||||
|
|
||||||
|
memo.unshift({ meiliAttribute: "", displayedName: format("all") });
|
||||||
|
return memo;
|
||||||
|
}, [router.locales, formatLanguage, format]);
|
||||||
|
|
||||||
const [sortingMethod, setSortingMethod] = useState<number>(
|
const [sortingMethod, setSortingMethod] = useState<number>(
|
||||||
router.query.sort ?? DEFAULT_FILTERS_STATE.sortingMethod
|
router.query.sort ?? DEFAULT_FILTERS_STATE.sortingMethod
|
||||||
);
|
);
|
||||||
|
@ -96,15 +103,14 @@ const Contents = (props: Props): JSX.Element => {
|
||||||
router.query.lang ?? DEFAULT_FILTERS_STATE.lang
|
router.query.lang ?? DEFAULT_FILTERS_STATE.lang
|
||||||
);
|
);
|
||||||
|
|
||||||
const [selectedLocales, setSelectedLocales] = useState<string[]>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchPosts = async () => {
|
const fetchPosts = async () => {
|
||||||
const currentSortingMethod = sortingMethods[sortingMethod]?.meiliAttribute;
|
const currentSortingMethod = sortingMethods[sortingMethod]?.meiliAttribute;
|
||||||
|
const currentLanguageOption = languageOptions[languageOption]?.meiliAttribute;
|
||||||
|
|
||||||
const filter: string[] = [];
|
const filter: string[] = [];
|
||||||
if (selectedLocales.length !== 0) {
|
if (languageOption !== 0) {
|
||||||
filter.push(`filterable_languages IN [${selectedLocales.join()}]`);
|
filter.push(`filterable_languages = ${currentLanguageOption}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchResult = await meiliSearch(MeiliIndices.CONTENT, query, {
|
const searchResult = await meiliSearch(MeiliIndices.CONTENT, query, {
|
||||||
|
@ -117,10 +123,14 @@ const Contents = (props: Props): JSX.Element => {
|
||||||
sort: isDefined(currentSortingMethod) ? [currentSortingMethod] : undefined,
|
sort: isDefined(currentSortingMethod) ? [currentSortingMethod] : undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
setContents(filterHitsWithHighlight<MeiliContent>(searchResult, "translations"));
|
setContents(
|
||||||
|
languageOption === 0
|
||||||
|
? filterHitsWithHighlight<MeiliContent>(searchResult, "translations")
|
||||||
|
: searchResult
|
||||||
|
);
|
||||||
};
|
};
|
||||||
fetchPosts();
|
fetchPosts();
|
||||||
}, [query, page, sortingMethod, sortingMethods, selectedLocales]);
|
}, [query, page, sortingMethod, sortingMethods, languageOption, languageOptions]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (router.isReady)
|
if (router.isReady)
|
||||||
|
@ -143,14 +153,6 @@ const Contents = (props: Props): JSX.Element => {
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [router.isReady]);
|
}, [router.isReady]);
|
||||||
|
|
||||||
const [countForLanguages, setCountForLanguages] = useState<MeiliFacetResult>([]);
|
|
||||||
const [countForCategories, setCountForCategories] = useState<MeiliFacetResult>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
meiliFacet(MeiliIndices.CONTENT, "filterable_languages").then(setCountForLanguages);
|
|
||||||
meiliFacet(MeiliIndices.CONTENT, "filterable_categories").then(setCountForCategories);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const searchInput = (
|
const searchInput = (
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder={format("search_placeholder")}
|
placeholder={format("search_placeholder")}
|
||||||
|
@ -188,22 +190,6 @@ const Contents = (props: Props): JSX.Element => {
|
||||||
|
|
||||||
{!is1ColumnLayout && <div className="mb-6">{searchInput}</div>}
|
{!is1ColumnLayout && <div className="mb-6">{searchInput}</div>}
|
||||||
|
|
||||||
<CollapsibleFilters
|
|
||||||
title={format("language", { count: countForLanguages.length })}
|
|
||||||
facetResult={countForLanguages}
|
|
||||||
format={formatLanguage}
|
|
||||||
onValueChanged={setSelectedLocales}
|
|
||||||
selectedValues={selectedLocales}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<CollapsibleFilters
|
|
||||||
title={format("category", { count: countForCategories.length })}
|
|
||||||
facetResult={countForCategories}
|
|
||||||
format={formatCategory}
|
|
||||||
onValueChanged={setSelectedLocales}
|
|
||||||
selectedValues={selectedLocales}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<WithLabel label={format("order_by")}>
|
<WithLabel label={format("order_by")}>
|
||||||
<Select
|
<Select
|
||||||
className="w-full"
|
className="w-full"
|
||||||
|
@ -222,6 +208,24 @@ const Contents = (props: Props): JSX.Element => {
|
||||||
/>
|
/>
|
||||||
</WithLabel>
|
</WithLabel>
|
||||||
|
|
||||||
|
<WithLabel label={format("language", { count: Infinity })}>
|
||||||
|
<Select
|
||||||
|
className="w-full"
|
||||||
|
options={languageOptions.map((item) => item.displayedName)}
|
||||||
|
value={languageOption}
|
||||||
|
onChange={(newLanguageOption) => {
|
||||||
|
setPage(1);
|
||||||
|
setLanguageOption(newLanguageOption);
|
||||||
|
sendAnalytics(
|
||||||
|
"Contents/All",
|
||||||
|
`Change language filter (${
|
||||||
|
languageOptions.map((item) => item.meiliAttribute)[newLanguageOption]
|
||||||
|
})`
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</WithLabel>
|
||||||
|
|
||||||
{hoverable && (
|
{hoverable && (
|
||||||
<WithLabel label={format("always_show_info")}>
|
<WithLabel label={format("always_show_info")}>
|
||||||
<Switch
|
<Switch
|
||||||
|
@ -273,9 +277,8 @@ const Contents = (props: Props): JSX.Element => {
|
||||||
}))
|
}))
|
||||||
.filter(
|
.filter(
|
||||||
({ language }) =>
|
({ language }) =>
|
||||||
selectedLocales.length === 0 ||
|
languageOption === 0 ||
|
||||||
query !== "" ||
|
language === languageOptions[languageOption]?.meiliAttribute
|
||||||
selectedLocales.includes(language)
|
|
||||||
)}
|
)}
|
||||||
fallback={{ title: prettySlug(item.slug) }}
|
fallback={{ title: prettySlug(item.slug) }}
|
||||||
thumbnail={item.thumbnail?.data?.attributes}
|
thumbnail={item.thumbnail?.data?.attributes}
|
||||||
|
@ -318,63 +321,3 @@ export const getStaticProps: GetStaticProps = (context) => {
|
||||||
props: props,
|
props: props,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* ╭──────────────────────╮
|
|
||||||
* ───────────────────────────────────╯ PRIVATE COMPONENTS ╰──────────────────────────────────────
|
|
||||||
*/
|
|
||||||
|
|
||||||
interface CollapsibleFiltersProps {
|
|
||||||
title: string;
|
|
||||||
facetResult: MeiliFacetResult;
|
|
||||||
selectedValues: string[];
|
|
||||||
onValueChanged: (setStateFn: (current: string[]) => string[]) => void;
|
|
||||||
format: (name: string) => string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CollapsibleFilters = ({
|
|
||||||
title,
|
|
||||||
facetResult,
|
|
||||||
selectedValues,
|
|
||||||
onValueChanged,
|
|
||||||
format,
|
|
||||||
}: CollapsibleFiltersProps): JSX.Element => {
|
|
||||||
const [isOpened, setOpened] = useState(false);
|
|
||||||
|
|
||||||
if (facetResult.length === 0) return <></>;
|
|
||||||
return (
|
|
||||||
<Collapsible
|
|
||||||
open={isOpened}
|
|
||||||
onTriggerClosing={() => setOpened(false)}
|
|
||||||
onOpening={() => setOpened(true)}
|
|
||||||
trigger={
|
|
||||||
<div className="flex gap-2">
|
|
||||||
<p className="leading-5">{title}</p>
|
|
||||||
<Ico icon={isOpened ? "expand_less" : "expand_more"} />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
easing="ease-in-out"
|
|
||||||
transitionTime={400}
|
|
||||||
contentInnerClassName="flex flex-wrap gap-1 py-3"
|
|
||||||
overflowWhenOpen="visible">
|
|
||||||
{facetResult
|
|
||||||
.filter(({ count }) => count > 0)
|
|
||||||
.map(({ name, count }) => (
|
|
||||||
<Button
|
|
||||||
key={name}
|
|
||||||
text={`${format(name)} (${count})`}
|
|
||||||
size="small"
|
|
||||||
onClick={() =>
|
|
||||||
onValueChanged((current) => {
|
|
||||||
if (current.includes(name)) {
|
|
||||||
return current.filter((currentLocale) => currentLocale !== name);
|
|
||||||
}
|
|
||||||
return [...current, name];
|
|
||||||
})
|
|
||||||
}
|
|
||||||
active={selectedValues.includes(name)}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Collapsible>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
@ -807,9 +807,7 @@ const ContentItem = ({
|
||||||
<div className="grid grid-cols-[auto_auto_1fr_auto] items-center gap-3">
|
<div className="grid grid-cols-[auto_auto_1fr_auto] items-center gap-3">
|
||||||
<h3>{title}</h3>
|
<h3>{title}</h3>
|
||||||
<div className="flex flex-wrap place-content-center gap-1">
|
<div className="flex flex-wrap place-content-center gap-1">
|
||||||
{content?.categories?.map((category, index) => (
|
{content?.categories?.map((category, index) => <Chip key={index} text={category} />)}
|
||||||
<Chip key={index} text={category} />
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
<p className="h-4 w-full border-b-2 border-dotted border-mid" />
|
<p className="h-4 w-full border-b-2 border-dotted border-mid" />
|
||||||
{content?.type && <Chip className="justify-self-end" text={content.type} />}
|
{content?.type && <Chip className="justify-self-end" text={content.type} />}
|
||||||
|
|
|
@ -56,7 +56,7 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
|
||||||
const toc = getTocFromMarkdawn(selectedTranslation?.body?.body, selectedTranslation?.title);
|
const toc = getTocFromMarkdawn(selectedTranslation?.body?.body, selectedTranslation?.title);
|
||||||
|
|
||||||
const subPanel =
|
const subPanel =
|
||||||
toc || !is1ColumnLayout ? (
|
isDefined(toc) || !is1ColumnLayout ? (
|
||||||
<SubPanel>
|
<SubPanel>
|
||||||
<ElementsSeparator>
|
<ElementsSeparator>
|
||||||
{[
|
{[
|
||||||
|
@ -204,8 +204,9 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
|
||||||
page.definitions && page.definitions.length > 0
|
page.definitions && page.definitions.length > 0
|
||||||
? `${filterHasAttributes(page.definitions, ["translations"]).map(
|
? `${filterHasAttributes(page.definitions, ["translations"]).map(
|
||||||
(definition, index) =>
|
(definition, index) =>
|
||||||
`${prettyTerminalUnderlinedTitle(format("definition_x", { x: index + 1 }))}${
|
`${prettyTerminalUnderlinedTitle(
|
||||||
staticSmartLanguage({
|
format("definition_x", { x: index + 1 })
|
||||||
|
)}${staticSmartLanguage({
|
||||||
items: filterHasAttributes(definition.translations, [
|
items: filterHasAttributes(definition.translations, [
|
||||||
"language.data.attributes.code",
|
"language.data.attributes.code",
|
||||||
]),
|
]),
|
||||||
|
@ -214,8 +215,7 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
|
||||||
router.locale ?? "en",
|
router.locale ?? "en",
|
||||||
router.locales ?? ["en"]
|
router.locales ?? ["en"]
|
||||||
),
|
),
|
||||||
})?.definition
|
})?.definition}`
|
||||||
}`
|
|
||||||
)}`
|
)}`
|
||||||
: ""
|
: ""
|
||||||
}${
|
}${
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -34,7 +34,6 @@ export interface MeiliContent
|
||||||
})[];
|
})[];
|
||||||
sortable_updated_date: number;
|
sortable_updated_date: number;
|
||||||
filterable_languages: string[];
|
filterable_languages: string[];
|
||||||
filterable_categories: string[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MeiliVideo extends VideoAttributesFragment {
|
export interface MeiliVideo extends VideoAttributesFragment {
|
||||||
|
|
Loading…
Reference in New Issue