Umami events + natural sort

This commit is contained in:
DrMint 2022-08-28 13:42:31 +02:00
parent bd0185358c
commit 40d893eba8
17 changed files with 327 additions and 77 deletions

24
package-lock.json generated
View File

@ -23,6 +23,7 @@
"react-dom": "18.2.0",
"react-hot-keys": "^2.7.2",
"react-swipeable": "^7.0.0",
"string-natural-compare": "^3.0.1",
"throttle-debounce": "^5.0.0",
"tippy.js": "^6.3.7",
"turndown": "^7.1.1",
@ -39,6 +40,7 @@
"@types/nodemailer": "^6.4.5",
"@types/react": "18.0.17",
"@types/react-dom": "^18.0.6",
"@types/string-natural-compare": "^3.0.2",
"@types/throttle-debounce": "^5.0.0",
"@types/turndown": "^5.0.1",
"@typescript-eslint/eslint-plugin": "^5.35.1",
@ -2660,6 +2662,12 @@
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
"dev": true
},
"node_modules/@types/string-natural-compare": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@types/string-natural-compare/-/string-natural-compare-3.0.2.tgz",
"integrity": "sha512-teA6gjoKrX+eeweVnk3bbQsbKUQyrP6CDJGsu0x33U4wyq2aF4y6CwPC/ygnLL0rf8twMXRmLdXo7DVhp1XBBw==",
"dev": true
},
"node_modules/@types/throttle-debounce": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@types/throttle-debounce/-/throttle-debounce-5.0.0.tgz",
@ -8160,6 +8168,11 @@
"integrity": "sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg==",
"dev": true
},
"node_modules/string-natural-compare": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz",
"integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw=="
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@ -11115,6 +11128,12 @@
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
"dev": true
},
"@types/string-natural-compare": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@types/string-natural-compare/-/string-natural-compare-3.0.2.tgz",
"integrity": "sha512-teA6gjoKrX+eeweVnk3bbQsbKUQyrP6CDJGsu0x33U4wyq2aF4y6CwPC/ygnLL0rf8twMXRmLdXo7DVhp1XBBw==",
"dev": true
},
"@types/throttle-debounce": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@types/throttle-debounce/-/throttle-debounce-5.0.0.tgz",
@ -15107,6 +15126,11 @@
"integrity": "sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg==",
"dev": true
},
"string-natural-compare": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz",
"integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw=="
},
"string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",

View File

@ -34,6 +34,7 @@
"react-dom": "18.2.0",
"react-hot-keys": "^2.7.2",
"react-swipeable": "^7.0.0",
"string-natural-compare": "^3.0.1",
"throttle-debounce": "^5.0.0",
"tippy.js": "^6.3.7",
"turndown": "^7.1.1",
@ -50,6 +51,7 @@
"@types/nodemailer": "^6.4.5",
"@types/react": "18.0.17",
"@types/react-dom": "^18.0.6",
"@types/string-natural-compare": "^3.0.2",
"@types/throttle-debounce": "^5.0.0",
"@types/turndown": "^5.0.1",
"@typescript-eslint/eslint-plugin": "^5.35.1",

View File

@ -382,13 +382,19 @@ export const AppLayout = ({
<Button
text="Let me in regardless"
className="mt-8"
onClick={disgardSafariWarning}
onClick={() => {
disgardSafariWarning();
umami("[Safari] Disgard warning");
}}
/>
</Popup>
<Popup
state={configPanelOpen}
onClose={() => setConfigPanelOpen(false)}
onClose={() => {
setConfigPanelOpen(false);
umami("[Settings] Close settings");
}}
>
<h2 className="text-2xl">{langui.settings}</h2>
@ -423,6 +429,7 @@ export const AppLayout = ({
(item) => item.code
);
setPreferredLanguages(newPreferredLanguages);
umami("[Settings] Change preferred languages");
}}
/>
)}
@ -442,6 +449,7 @@ export const AppLayout = ({
onClick: () => {
setDarkMode(false);
setSelectedThemeMode(true);
umami("[Settings] Change theme (light)");
},
active: selectedThemeMode && !darkMode,
text: langui.light,
@ -449,6 +457,7 @@ export const AppLayout = ({
{
onClick: () => {
setSelectedThemeMode(false);
umami("[Settings] Change theme (auto)");
},
active: !selectedThemeMode,
text: langui.auto,
@ -457,6 +466,7 @@ export const AppLayout = ({
onClick: () => {
setDarkMode(true);
setSelectedThemeMode(true);
umami("[Settings] Change theme (dark)");
},
active: selectedThemeMode && darkMode,
text: langui.dark,
@ -471,7 +481,12 @@ export const AppLayout = ({
<Select
options={currencyOptions}
value={currencySelect}
onChange={setCurrencySelect}
onChange={(newCurrency) => {
setCurrencySelect(newCurrency);
umami(
`[Settings] Change currency (${currencyOptions[newCurrency]})}`
);
}}
className="w-28"
/>
</div>
@ -482,17 +497,41 @@ export const AppLayout = ({
<ButtonGroup
buttonsProps={[
{
onClick: () => setFontSize(fontSize / 1.05),
onClick: () => {
setFontSize((current) => current / 1.05);
umami(
`[Settings] Change font size (${(
(fontSize / 1.05) *
100
).toLocaleString(undefined, {
maximumFractionDigits: 0,
})}%)`
);
},
icon: Icon.TextDecrease,
},
{
onClick: () => setFontSize(1),
onClick: () => {
setFontSize(1);
umami("[Settings] Change font size (100%)");
},
text: `${(fontSize * 100).toLocaleString(undefined, {
maximumFractionDigits: 0,
})}%`,
},
{
onClick: () => setFontSize(fontSize * 1.05),
onClick: () => {
setFontSize((current) => current * 1.05);
umami(
`[Settings] Change font size (${(
fontSize *
1.05 *
100
).toLocaleString(undefined, {
maximumFractionDigits: 0,
})}%)`
);
},
icon: Icon.TextIncrease,
},
]}
@ -504,13 +543,19 @@ export const AppLayout = ({
<div className="grid gap-2">
<Button
active={!dyslexic}
onClick={() => setDyslexic(false)}
onClick={() => {
setDyslexic(false);
umami("[Settings] Change font (Zen Maru Gothic)");
}}
className="font-zenMaruGothic"
text="Zen Maru Gothic"
/>
<Button
active={dyslexic}
onClick={() => setDyslexic(true)}
onClick={() => {
setDyslexic(true);
umami("[Settings] Change font (OpenDyslexic)");
}}
className="font-openDyslexic"
text="OpenDyslexic"
/>
@ -523,7 +568,10 @@ export const AppLayout = ({
placeholder="<player>"
className="w-48"
value={playerName}
onChange={setPlayerName}
onChange={(newName) => {
setPlayerName(newName);
umami("[Settings] Change username");
}}
/>
</div>
</div>

View File

@ -40,7 +40,10 @@ export const LanguageSwitcher = ({
<Fragment key={index}>
<Button
active={value === localesIndex}
onClick={() => onLanguageChanged(value)}
onClick={() => {
onLanguageChanged(value);
umami(`[Language Switcher] Switch language (${locale})`);
}}
text={prettyLanguage(locale, languages)}
/>
</Fragment>

View File

@ -38,9 +38,16 @@ export const MainPanel = (): JSX.Element => {
"fixed top-1/2",
cIf(mainPanelReduced, "left-[4.65rem]", "left-[18.65rem]")
)}
onClick={toggleMainPanelReduced}
>
<Button
onClick={() => {
if (mainPanelReduced) {
umami("[MainPanel] Expand");
} else {
umami("[MainPanel] Reduce");
}
toggleMainPanelReduced();
}}
className="bg-light !px-2"
icon={mainPanelReduced ? Icon.ChevronRight : Icon.ChevronLeft}
/>
@ -83,24 +90,11 @@ export const MainPanel = (): JSX.Element => {
<Button
onClick={() => {
setConfigPanelOpen(true);
umami("[Settings] Open settings");
}}
icon={Icon.Settings}
/>
</ToolTip>
{/* <ToolTip
content={<h3 className="text-2xl">{langui.open_search}</h3>}
placement="right"
className="text-left"
disabled={!mainPanelReduced}
>
<Button
onClick={() => {
setSearchPanelOpen(true);
}}
icon={Icon.Search}
/>
</ToolTip> */}
</div>
</div>
</div>
@ -193,6 +187,7 @@ export const MainPanel = (): JSX.Element => {
)}
<div className="mt-4 mb-8 grid place-content-center">
<a
onClick={() => umami("[MainPanel] Visit license")}
aria-label="Read more about the license we use for this website"
className="group grid grid-flow-col place-content-center gap-1 transition-[filter]"
href="https://creativecommons.org/licenses/by-sa/4.0/"
@ -222,6 +217,7 @@ export const MainPanel = (): JSX.Element => {
<div className="mt-12 mb-4 grid h-4 grid-flow-col place-content-center gap-8">
<a
aria-label="Browse our GitHub repository, which include this website source code"
onClick={() => umami("[MainPanel] Visit GitHub")}
className="aspect-square w-10
bg-black transition-colors [mask:url('/icons/github-brands.svg')]
![mask-size:contain] ![mask-repeat:no-repeat] ![mask-position:center] hover:bg-dark"
@ -231,6 +227,7 @@ export const MainPanel = (): JSX.Element => {
></a>
<a
aria-label="Follow us on Twitter"
onClick={() => umami("[MainPanel] Visit Twitter")}
className="aspect-square w-10
bg-black transition-colors [mask:url('/icons/twitter-brands.svg')]
![mask-size:contain] ![mask-repeat:no-repeat] ![mask-position:center] hover:bg-dark"
@ -240,6 +237,7 @@ export const MainPanel = (): JSX.Element => {
></a>
<a
aria-label="Join our Discord server!"
onClick={() => umami("[MainPanel] Visit Discord")}
className="aspect-square w-10
bg-black transition-colors [mask:url('/icons/discord-brands.svg')]
![mask-size:contain] ![mask-repeat:no-repeat] ![mask-position:center] hover:bg-dark"

View File

@ -1,4 +1,5 @@
import { Fragment, useCallback, useEffect, useMemo, useState } from "react";
import naturalCompare from "string-natural-compare";
import { Chip } from "./Chip";
import { PageSelector } from "./Inputs/PageSelector";
import { Ico, Icon } from "./Ico";
@ -15,7 +16,7 @@ interface Group<T> {
}
const defaultGroupSortingFunction = <T,>(a: Group<T>, b: Group<T>) =>
a.name.localeCompare(b.name);
naturalCompare(a.name, b.name);
const defaultGroupCountingFunction = () => 1;
const defaultFilteringFunction = () => true;
const defaultSortingFunction = () => 0;

View File

@ -75,17 +75,19 @@ const AboutUs = (props: PostStaticProps): JSX.Element => {
case "OKAY":
setFormResponse(langui.response_email_success ?? "");
setFormState("completed");
umami("[Contact] Send email (success)");
break;
case "EENVELOPE":
setFormResponse(langui.response_invalid_email ?? "");
setFormState("stale");
umami("[Contact] Send email (invalid email)");
break;
default:
setFormResponse(response.message ?? "");
setFormState("stale");
umami("[Contact] Send email (error)");
break;
}
});

View File

@ -1,6 +1,7 @@
import { GetStaticProps } from "next";
import { useState, useMemo, useCallback } from "react";
import { useBoolean } from "usehooks-ts";
import naturalCompare from "string-natural-compare";
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Select } from "components/Inputs/Select";
import { Switch } from "components/Inputs/Switch";
@ -17,7 +18,11 @@ import { WithLabel } from "components/Inputs/WithLabel";
import { Button } from "components/Inputs/Button";
import { useDeviceSupportsHover } from "hooks/useMediaQuery";
import { Icon } from "components/Ico";
import { filterDefined, filterHasAttributes } from "helpers/others";
import {
filterDefined,
filterHasAttributes,
isDefinedAndNotEmpty,
} from "helpers/others";
import { GetContentsQuery } from "graphql/generated";
import { SmartList } from "components/SmartList";
import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable";
@ -150,7 +155,14 @@ const Contents = ({ contents, ...otherProps }: Props): JSX.Element => {
className="mb-6 w-full"
placeholder={langui.search_title ?? "Search..."}
value={searchName}
onChange={setSearchName}
onChange={(name) => {
setSearchName(name);
if (isDefinedAndNotEmpty(name)) {
umami("[Contents/All] Change search term");
} else {
umami("[News] Clear search term");
}
}}
/>
<WithLabel label={langui.group_by}>
@ -158,14 +170,31 @@ const Contents = ({ contents, ...otherProps }: Props): JSX.Element => {
className="w-full"
options={[langui.category ?? "Category", langui.type ?? "Type"]}
value={groupingMethod}
onChange={setGroupingMethod}
onChange={(value) => {
setGroupingMethod(value);
umami(
`[Contents/All] Change grouping method (${
["none", "category", "type"][value + 1]
})`
);
}}
allowEmpty
/>
</WithLabel>
{hoverable && (
<WithLabel label={langui.always_show_info}>
<Switch onClick={toggleKeepInfoVisible} value={keepInfoVisible} />
<Switch
value={keepInfoVisible}
onClick={() => {
toggleKeepInfoVisible();
umami(
`[Contents/All] Always ${
keepInfoVisible ? "hide" : "show"
} info`
);
}}
/>
</WithLabel>
)}
@ -177,6 +206,7 @@ const Contents = ({ contents, ...otherProps }: Props): JSX.Element => {
setSearchName(DEFAULT_FILTERS_STATE.searchName);
setGroupingMethod(DEFAULT_FILTERS_STATE.groupingMethod);
setKeepInfoVisible(DEFAULT_FILTERS_STATE.keepInfoVisible);
umami("[Contents/All] Reset all filters");
}}
/>
</SubPanel>
@ -299,7 +329,7 @@ export const getStaticProps: GetStaticProps = async (context) => {
contents.contents.data.sort((a, b) => {
const titleA = a.attributes?.slug ?? "";
const titleB = b.attributes?.slug ?? "";
return titleA.localeCompare(titleB);
return naturalCompare(titleA, titleB);
});
const props: Props = {

View File

@ -1,5 +1,6 @@
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { useCallback, useMemo } from "react";
import naturalCompare from "string-natural-compare";
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import {
ContentPanel,
@ -237,6 +238,23 @@ export const getStaticProps: GetStaticProps = async (context) => {
const folder = contentsFolder.contentsFolders.data[0].attributes;
const subFolders = {
// eslint-disable-next-line id-denylist
data: filterHasAttributes(folder.subfolders?.data, [
"attributes.slug",
]).sort((a, b) => naturalCompare(a.attributes.slug, b.attributes.slug)),
};
const contents = {
// eslint-disable-next-line id-denylist
data: filterHasAttributes(folder.contents?.data, ["attributes.slug"]).sort(
(a, b) => naturalCompare(a.attributes.slug, b.attributes.slug)
),
};
folder.contents = contents;
folder.subfolders = subFolders;
const title = (() => {
if (slug === "root") {
return langui.contents ?? "Contents";

5
src/pages/global.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
export {};
declare global {
function umami(eventName: string): void;
}

View File

@ -1,15 +1,19 @@
import { PostPage } from "components/PostPage";
import { useAppLayout } from "contexts/AppLayoutContext";
import {
getPostStaticProps,
PostStaticProps,
} from "graphql/getPostStaticProps";
import { getOpenGraph } from "helpers/openGraph";
/*
*
* PAGE
*/
const Home = ({ ...otherProps }: PostStaticProps): JSX.Element => (
const Home = ({ ...otherProps }: PostStaticProps): JSX.Element => {
const { langui } = useAppLayout();
return (
<PostPage
{...otherProps}
prependBody={
@ -25,9 +29,11 @@ const Home = ({ ...otherProps }: PostStaticProps): JSX.Element => (
</div>
}
displayTitle={false}
openGraph={getOpenGraph(langui)}
displayLanguageSwitcher
/>
);
);
};
export default Home;

View File

@ -471,7 +471,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
)}
>
<h3 className="text-xl">{langui.type_information}</h3>
<div className="grid w-full grid-cols-2 place-content-between">
<div className="flex flex-wrap place-content-between gap-x-8">
{item.metadata?.[0]?.__typename ===
"ComponentMetadataBooks" && (
<>

View File

@ -1,5 +1,5 @@
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { Fragment, useCallback, useEffect, useMemo } from "react";
import { Fragment, useCallback, useMemo } from "react";
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { ReturnButton } from "components/PanelComponents/ReturnButton";
import {

View File

@ -1,6 +1,7 @@
import { GetStaticProps } from "next";
import { useState, useMemo, useCallback } from "react";
import { useBoolean } from "usehooks-ts";
import naturalCompare from "string-natural-compare";
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Select } from "components/Inputs/Select";
import { Switch } from "components/Inputs/Switch";
@ -23,7 +24,12 @@ import { isUntangibleGroupItem } from "helpers/libraryItem";
import { PreviewCard } from "components/PreviewCard";
import { useDeviceSupportsHover } from "hooks/useMediaQuery";
import { ButtonGroup } from "components/Inputs/ButtonGroup";
import { filterHasAttributes, isDefined, isUndefined } from "helpers/others";
import {
filterHasAttributes,
isDefined,
isDefinedAndNotEmpty,
isUndefined,
} from "helpers/others";
import { useAppLayout } from "contexts/AppLayoutContext";
import { convertPrice } from "helpers/numbers";
import { SmartList } from "components/SmartList";
@ -162,7 +168,7 @@ const Library = ({ items, ...otherProps }: Props): JSX.Element => {
b.attributes.title,
b.attributes.subtitle
);
return titleA.localeCompare(titleB);
return naturalCompare(titleA, titleB);
}
case 1: {
const priceA = a.attributes.price
@ -269,7 +275,14 @@ const Library = ({ items, ...otherProps }: Props): JSX.Element => {
className="mb-6 w-full"
placeholder={langui.search_title ?? "Search..."}
value={searchName}
onChange={setSearchName}
onChange={(name) => {
setSearchName(name);
if (isDefinedAndNotEmpty(name)) {
umami("[Library] Change search term");
} else {
umami("[Library] Clear search term");
}
}}
/>
<WithLabel label={langui.group_by}>
@ -281,7 +294,14 @@ const Library = ({ items, ...otherProps }: Props): JSX.Element => {
langui.release_year ?? "Year",
]}
value={groupingMethod}
onChange={setGroupingMethod}
onChange={(value) => {
setGroupingMethod(value);
umami(
`[Library] Change grouping method (${
["none", "category", "type", "year"][value + 1]
})`
);
}}
allowEmpty
/>
</WithLabel>
@ -295,28 +315,64 @@ const Library = ({ items, ...otherProps }: Props): JSX.Element => {
langui.release_date ?? "Release date",
]}
value={sortingMethod}
onChange={setSortingMethod}
onChange={(value) => {
setSortingMethod(value);
umami(
`[Library] Change sorting method (${
["name", "price", "release date"][value]
})`
);
}}
/>
</WithLabel>
<WithLabel label={langui.show_subitems}>
<Switch value={showSubitems} onClick={toggleShowSubitems} />
<Switch
value={showSubitems}
onClick={() => {
toggleShowSubitems();
umami(`[Library] ${showSubitems ? "Hide" : "Show"} subitems`);
}}
/>
</WithLabel>
<WithLabel label={langui.show_primary_items}>
<Switch value={showPrimaryItems} onClick={toggleShowPrimaryItems} />
<Switch
value={showPrimaryItems}
onClick={() => {
toggleShowPrimaryItems();
umami(
`[Library] ${showPrimaryItems ? "Hide" : "Show"} primary items`
);
}}
/>
</WithLabel>
<WithLabel label={langui.show_secondary_items}>
<Switch
value={showSecondaryItems}
onClick={toggleShowSecondaryItems}
onClick={() => {
toggleShowSecondaryItems();
umami(
`[Library] ${
showSecondaryItems ? "Hide" : "Show"
} secondary items`
);
}}
/>
</WithLabel>
{hoverable && (
<WithLabel label={langui.always_show_info}>
<Switch value={keepInfoVisible} onClick={toggleKeepInfoVisible} />
<Switch
value={keepInfoVisible}
onClick={() => {
toggleKeepInfoVisible();
umami(
`[Library] Always ${keepInfoVisible ? "hide" : "show"} info`
);
}}
/>
</WithLabel>
)}
@ -326,25 +382,37 @@ const Library = ({ items, ...otherProps }: Props): JSX.Element => {
{
tooltip: langui.only_display_items_i_want,
icon: Icon.Favorite,
onClick: () => setFilterUserStatus(LibraryItemUserStatus.Want),
onClick: () => {
setFilterUserStatus(LibraryItemUserStatus.Want);
umami("[Library] Set filter status (I want)");
},
active: filterUserStatus === LibraryItemUserStatus.Want,
},
{
tooltip: langui.only_display_items_i_have,
icon: Icon.BackHand,
onClick: () => setFilterUserStatus(LibraryItemUserStatus.Have),
onClick: () => {
setFilterUserStatus(LibraryItemUserStatus.Have);
umami("[Library] Set filter status (I have)");
},
active: filterUserStatus === LibraryItemUserStatus.Have,
},
{
tooltip: langui.only_display_unmarked_items,
icon: Icon.RadioButtonUnchecked,
onClick: () => setFilterUserStatus(LibraryItemUserStatus.None),
onClick: () => {
setFilterUserStatus(LibraryItemUserStatus.None);
umami("[Library] Set filter status (unmarked)");
},
active: filterUserStatus === LibraryItemUserStatus.None,
},
{
tooltip: langui.only_display_unmarked_items,
text: langui.all,
onClick: () => setFilterUserStatus(undefined),
onClick: () => {
setFilterUserStatus(undefined);
umami("[Library] Set filter status (all)");
},
active: isUndefined(filterUserStatus),
},
]}
@ -363,6 +431,7 @@ const Library = ({ items, ...otherProps }: Props): JSX.Element => {
setGroupingMethod(DEFAULT_FILTERS_STATE.groupingMethod);
setKeepInfoVisible(DEFAULT_FILTERS_STATE.keepInfoVisible);
setFilterUserStatus(DEFAULT_FILTERS_STATE.filterUserStatus);
umami("[Library] Reset all filters");
}}
/>
</SubPanel>

View File

@ -17,7 +17,7 @@ import { WithLabel } from "components/Inputs/WithLabel";
import { TextInput } from "components/Inputs/TextInput";
import { Button } from "components/Inputs/Button";
import { useDeviceSupportsHover } from "hooks/useMediaQuery";
import { filterHasAttributes } from "helpers/others";
import { filterHasAttributes, isDefinedAndNotEmpty } from "helpers/others";
import { SmartList } from "components/SmartList";
import { getOpenGraph } from "helpers/openGraph";
import { compareDate } from "helpers/date";
@ -75,12 +75,27 @@ const News = ({ posts, ...otherProps }: Props): JSX.Element => {
className="mb-6 w-full"
placeholder={langui.search_title ?? "Search..."}
value={searchName}
onChange={setSearchName}
onChange={(name) => {
setSearchName(name);
if (isDefinedAndNotEmpty(name)) {
umami("[News] Change search term");
} else {
umami("[News] Clear search term");
}
}}
/>
{hoverable && (
<WithLabel label={langui.always_show_info}>
<Switch onClick={toggleKeepInfoVisible} value={keepInfoVisible} />
<Switch
value={keepInfoVisible}
onClick={() => {
toggleKeepInfoVisible();
umami(
`[News] Always ${keepInfoVisible ? "hide" : "show"} info`
);
}}
/>
</WithLabel>
)}
@ -91,6 +106,7 @@ const News = ({ posts, ...otherProps }: Props): JSX.Element => {
onClick={() => {
setSearchName(DEFAULT_FILTERS_STATE.searchName);
setKeepInfoVisible(DEFAULT_FILTERS_STATE.keepInfoVisible);
umami("[News] Reset all filters");
}}
/>
</SubPanel>

View File

@ -18,7 +18,11 @@ import { Switch } from "components/Inputs/Switch";
import { TextInput } from "components/Inputs/TextInput";
import { WithLabel } from "components/Inputs/WithLabel";
import { useDeviceSupportsHover } from "hooks/useMediaQuery";
import { filterDefined, filterHasAttributes } from "helpers/others";
import {
filterDefined,
filterHasAttributes,
isDefinedAndNotEmpty,
} from "helpers/others";
import { SmartList } from "components/SmartList";
import { Select } from "components/Inputs/Select";
import { SelectiveNonNullable } from "helpers/types/SelectiveNonNullable";
@ -84,7 +88,14 @@ const Wiki = ({ pages, ...otherProps }: Props): JSX.Element => {
className="mb-6 w-full"
placeholder={langui.search_title ?? "Search..."}
value={searchName}
onChange={setSearchName}
onChange={(name) => {
setSearchName(name);
if (isDefinedAndNotEmpty(name)) {
umami("[Wiki] Change search term");
} else {
umami("[Wiki] Clear search term");
}
}}
/>
<WithLabel label={langui.group_by}>
@ -92,14 +103,29 @@ const Wiki = ({ pages, ...otherProps }: Props): JSX.Element => {
className="w-full"
options={[langui.category ?? "Category"]}
value={groupingMethod}
onChange={setGroupingMethod}
onChange={(value) => {
setGroupingMethod(value);
umami(
`[Wiki] Change grouping method (${
["none", "category"][value + 1]
})`
);
}}
allowEmpty
/>
</WithLabel>
{hoverable && (
<WithLabel label={langui.always_show_info}>
<Switch value={keepInfoVisible} onClick={toggleKeepInfoVisible} />
<Switch
value={keepInfoVisible}
onClick={() => {
toggleKeepInfoVisible();
umami(
`[Wiki] Always ${keepInfoVisible ? "hide" : "show"} info`
);
}}
/>
</WithLabel>
)}
@ -109,7 +135,9 @@ const Wiki = ({ pages, ...otherProps }: Props): JSX.Element => {
icon={Icon.Replay}
onClick={() => {
setSearchName(DEFAULT_FILTERS_STATE.searchName);
setGroupingMethod(DEFAULT_FILTERS_STATE.groupingMethod);
setKeepInfoVisible(DEFAULT_FILTERS_STATE.keepInfoVisible);
umami("[Wiki] Reset all filters");
}}
/>

View File

@ -164,7 +164,7 @@ input[type="submit"] {
@apply grid cursor-pointer place-content-center place-items-center rounded-full border-[1px]
border-dark px-4 pt-[0.4rem] pb-[0.5rem] text-dark transition-all hover:bg-dark hover:text-light
hover:drop-shadow-shade-lg active:border-black active:bg-black active:text-light
active:drop-shadow-black-lg;
active:drop-shadow-black-lg outline-none;
}
.texture-paper-dots {