+ return (
+
setColorVisible(!colorVisible)} style={{backgroundColor: color}}/>
{colorVisible &&
-
+
}
-
- )
+ )
}
diff --git a/src/renderer/components/shared/bsm-button.component.tsx b/src/renderer/components/shared/bsm-button.component.tsx
index 29de51a4..80d78356 100644
--- a/src/renderer/components/shared/bsm-button.component.tsx
+++ b/src/renderer/components/shared/bsm-button.component.tsx
@@ -1,16 +1,16 @@
import { BsmIcon, BsmIconType } from "../svgs/bsm-icon.component"
-import OutsideClickHandler from 'react-outside-click-handler';
-import React, { MutableRefObject, Ref } from "react";
+import { useEffect, useRef, CSSProperties } from "react";
import { BsmImage } from "./bsm-image.component";
import { useTranslation } from "renderer/hooks/use-translation.hook";
+import { useClickOutside } from "renderer/hooks/use-click-outside.hook";
import { useThemeColor } from "renderer/hooks/use-theme-color.hook";
import { getCorrectTextColor } from "renderer/helpers/correct-text-color";
type BsmButtonType = "primary"|"success"|"cancel"|"error";
-type propsType = {
+type Props = {
className?: string,
- style?: React.CSSProperties,
+ style?: CSSProperties,
imgClassName?: string,
iconClassName?: string,
icon?: BsmIconType,
@@ -26,43 +26,43 @@ type propsType = {
color?: string,
title?: string,
iconColor?: string,
+ textClassName?: string
}
-export function BsmButton({className, style, imgClassName, iconClassName, icon, image, text, type, active, withBar = true, disabled, onClickOutside, onClick, typeColor, color, title, iconColor}: propsType) {
+export function BsmButton({className, style, imgClassName, iconClassName, icon, image, text, type, active, withBar = true, disabled, onClickOutside, onClick, typeColor, color, title, iconColor, textClassName}: Props) {
- const t = useTranslation();
- const secondColor = useThemeColor("second-color");
+ const t = useTranslation();
+ const secondColor = useThemeColor("second-color");
+ const ref = useRef(null);
+ useClickOutside(ref, onClickOutside);
- const primaryColor = typeColor === "primary" && useThemeColor("first-color");
+ const primaryColor = typeColor === "primary" && useThemeColor("first-color");
- const textColor = (() => {
- if(primaryColor){ return getCorrectTextColor(primaryColor); }
- return typeColor ? "white" : undefined;
- })();
+ const textColor = (() => {
+ if(primaryColor){ return getCorrectTextColor(primaryColor); }
+ return typeColor ? "white" : undefined;
+ })();
- const renderTypeColor = (() => {
- if(typeColor === "primary"){ return ""; }
- if(!typeColor){ return `bg-light-main-color-2 dark:bg-main-color-2 ${!withBar && "hover:bg-light-main-color-3 dark:hover:bg-main-color-3"}`; }
- if(typeColor === "cancel"){ return "bg-gray-500"; }
- if(typeColor === "error"){ return "bg-red-500"; }
- if(typeColor === "success"){ return "bg-green-500"; }
- return "";
- })()
+ const renderTypeColor = (() => {
+ if(typeColor === "primary"){ return ""; }
+ if(!typeColor){ return `bg-light-main-color-2 dark:bg-main-color-2 ${!withBar && "hover:bg-light-main-color-3 dark:hover:bg-main-color-3"}`; }
+ if(typeColor === "cancel"){ return "bg-gray-500"; }
+ if(typeColor === "error"){ return "bg-red-500"; }
+ if(typeColor === "success"){ return "bg-green-500"; }
+ return "";
+ })();
- return (
-
onClickOutside && onClickOutside(e)}>
-
- { image &&
}
- { icon && }
- {text && (type === "submit" ? : {t(text)})}
- { withBar && (
-
- )}
-
-
-
- )
+ return (
+
+ { image &&
}
+ { icon && }
+ {text && (type === "submit" ? : {t(text)})}
+ { withBar && (
+
+ )}
+
+ )
}
diff --git a/src/renderer/components/shared/bsm-dropdown-button.component.tsx b/src/renderer/components/shared/bsm-dropdown-button.component.tsx
index 9f809e51..ac10e717 100644
--- a/src/renderer/components/shared/bsm-dropdown-button.component.tsx
+++ b/src/renderer/components/shared/bsm-dropdown-button.component.tsx
@@ -1,31 +1,58 @@
-import { useState } from "react"
-import { BsmIconType } from "../svgs/bsm-icon.component"
+import { useRef, useState } from "react"
+import { BsmIconType, BsmIcon } from "../svgs/bsm-icon.component"
import { BsmButton } from "./bsm-button.component"
-import { BsmIcon } from "../svgs/bsm-icon.component"
import { useTranslation } from "renderer/hooks/use-translation.hook"
+import { AnimatePresence } from "framer-motion"
+import { v4 as uuidv4 } from 'uuid';
+import { useClickOutside } from "renderer/hooks/use-click-outside.hook"
export interface DropDownItem {text: string, icon?: BsmIconType, onClick?: () => void}
-type Props = {className?: string, items?: DropDownItem[], align?: "left"|"right", withBar?: boolean, icon?: BsmIconType, buttonClassName?: string, menuTranslationY?: string|number}
+type Props = {
+ className?: string,
+ items?: DropDownItem[],
+ align?: "left"|"right",
+ withBar?: boolean,
+ icon?: BsmIconType,
+ buttonClassName?: string,
+ menuTranslationY?: string|number
+ children?: JSX.Element,
+ text?: string,
+ textClassName?: string
+}
-export function BsmDropdownButton({className, items, align, withBar = true, icon = "settings", buttonClassName, menuTranslationY}: Props) {
+export function BsmDropdownButton({className, items, align, withBar = true, icon = "settings", buttonClassName, menuTranslationY, children, text, textClassName}: Props) {
const [expanded, setExpanded] = useState(false)
const t = useTranslation();
+ const ref = useRef(null)
+ useClickOutside(ref, () => setExpanded(false));
const defaultButtonClassName = "relative z-[1] p-1 rounded-md text-inherit w-full h-full shadow-md shadow-black"
+ const handleClickOutside = () => {
+ if(children){ return; }
+ setExpanded(false);
+ }
+
return (
-
-
setExpanded(!expanded)} className={buttonClassName ?? defaultButtonClassName} icon={icon} active={expanded} onClickOutside={() => {setExpanded(false)}} withBar={withBar}/>
+
+
setExpanded(!expanded)} className={buttonClassName ?? defaultButtonClassName} icon={icon} active={expanded} onClickOutside={handleClickOutside} withBar={withBar} text={text}/>
- { items?.map((i, index) => !!i &&(
-
- {i.icon &&
}
+ { items?.map((i) => (
+
i.onClick?.()} className="flex w-full px-3 py-2 hover:backdrop-brightness-150">
+ {i.icon && }
{t(i.text)}
))}
+ {!!children && (
+
+ {expanded && (
+ children
+ )}
+
+ )}
)
}
diff --git a/src/renderer/hooks/use-click-outside.hook.ts b/src/renderer/hooks/use-click-outside.hook.ts
new file mode 100644
index 00000000..36165fd2
--- /dev/null
+++ b/src/renderer/hooks/use-click-outside.hook.ts
@@ -0,0 +1,22 @@
+import { MutableRefObject, useEffect } from "react";
+
+export function useClickOutside(ref: MutableRefObject, handler: (e: MouseEvent) => void) {
+
+ useEffect(() => {
+
+ if(!handler){ return () => {}; }
+
+ const handleClickOutside = (event: MouseEvent) => {
+ if (ref.current && !ref.current.contains(event.target)) {
+ handler?.(event);
+ }
+ }
+
+ document.addEventListener("click", handleClickOutside);
+ return () => {
+ document.removeEventListener("click", handleClickOutside);
+ };
+
+ }, [ref]);
+
+}
\ No newline at end of file
diff --git a/src/renderer/pages/version-viewer.component.tsx b/src/renderer/pages/version-viewer.component.tsx
index c1c9a524..520878ee 100644
--- a/src/renderer/pages/version-viewer.component.tsx
+++ b/src/renderer/pages/version-viewer.component.tsx
@@ -73,7 +73,7 @@ export function VersionViewer() {
diff --git a/src/renderer/partials/map-tags/map-styles.ts b/src/renderer/partials/map-tags/map-styles.ts
new file mode 100644
index 00000000..8a62707c
--- /dev/null
+++ b/src/renderer/partials/map-tags/map-styles.ts
@@ -0,0 +1,40 @@
+import { MapStyle } from "shared/models/maps/beat-saver.model";
+
+export const MAP_STYLES: MapStyle[] = [
+ "DanceStyle",
+ "Swing",
+ "Nightcore",
+ "Folk",
+ "Family",
+ "Ambient",
+ "Funk",
+ "Jazz",
+ "Classical",
+ "Soul",
+ "Speedcore",
+ "Punk",
+ "RB",
+ "Holiday",
+ "Vocaloid",
+ "JRock",
+ "Trance",
+ "DrumBass",
+ "Comedy",
+ "Instrumental",
+ "Hardcore",
+ "KPop",
+ "Indie",
+ "Techno",
+ "House",
+ "Game",
+ "Film",
+ "Alt",
+ "Dubstep",
+ "Metal",
+ "Anime",
+ "HipHop",
+ "JPop",
+ "Rock",
+ "Pop",
+ "Electronic"
+];
\ No newline at end of file
diff --git a/src/renderer/partials/map-tags/map-types.ts b/src/renderer/partials/map-tags/map-types.ts
new file mode 100644
index 00000000..a19d8b23
--- /dev/null
+++ b/src/renderer/partials/map-tags/map-types.ts
@@ -0,0 +1,11 @@
+import { MapType } from "shared/models/maps/beat-saver.model";
+
+export const MAP_TYPES: MapType[] = [
+ "Accuracy",
+ "Balanced",
+ "Challenge",
+ "Dance",
+ "Fitness",
+ "Speed",
+ "Tech"
+];
\ No newline at end of file
diff --git a/src/renderer/services/beat-saver/beat-saver.service.ts b/src/renderer/services/beat-saver/beat-saver.service.ts
index 482f8e5a..39bcca9b 100644
--- a/src/renderer/services/beat-saver/beat-saver.service.ts
+++ b/src/renderer/services/beat-saver/beat-saver.service.ts
@@ -14,6 +14,7 @@ export class BeatSaverService {
private readonly bsaverApi: BeatSaverApiService;
+
private constructor(){
this.bsaverApi = BeatSaverApiService.getInstance();
}
diff --git a/src/shared/models/maps/beat-saver.model.ts b/src/shared/models/maps/beat-saver.model.ts
index 7d4bfbda..2c7d4049 100644
--- a/src/shared/models/maps/beat-saver.model.ts
+++ b/src/shared/models/maps/beat-saver.model.ts
@@ -12,7 +12,7 @@ export interface BsvMapDetail {
qualified: boolean,
ranked: boolean,
stats: BsvMapStats,
- tags: string[],
+ tags: MapTag[],
updatedAt: BsvInstant,
uploaded: BsvInstant,
uploader: BsvUserDetail,
@@ -141,4 +141,27 @@ export interface BsvMapParitySummary {
}
export type BsvMapCharacteristic = ("Standard" | "OneSaber" | "NoArrows" | "90Degree" | "360Degree" | "Lightshow" | "Lawless")
-export type BsvMapDifficultyType = ("Easy" | "Normal" | "Hard" | "Expert" | "ExpertPlus")
\ No newline at end of file
+export type BsvMapDifficultyType = ("Easy" | "Normal" | "Hard" | "Expert" | "ExpertPlus")
+
+export type MapStyle = ("DanceStyle" | "Swing" | "Nightcore" | "Folk" | "Family" | "Ambient" | "Funk" | "Jazz" | "Classical" | "Soul" | "Speedcore" | "Punk" | "RB" | "Holiday" | "Vocaloid" | "JRock" | "Trance" | "DrumBass" | "Comedy" | "Instrumental" | "Hardcore" | "KPop" | "Indie" | "Techno" | "House" | "Game" | "Film" | "Alt" | "Dubstep" | "Metal" | "Anime" | "HipHop" | "JPop" | "Rock" | "Pop" | "Electronic")
+export type MapType = ("Accuracy" | "Balanced" | "Challenge" | "Dance" | "Fitness" | "Speed" | "Tech")
+export type MapTag = MapStyle | MapType
+
+export interface MapFilter {
+ automapper?: boolean,
+ chroma?: boolean,
+ cinema?: boolean,
+ noodle?: boolean,
+ curated?: boolean,
+ verified?: boolean,
+ from?: number,
+ to?: number,
+ fullSpread?: boolean,
+ ranked?: boolean,
+ minDuration?: number,
+ maxDuration?: number,
+ minNps?: number,
+ maxNps?: number,
+ enabledTags?: MapTag[],
+ excludedTags?: MapTag[]
+}
\ No newline at end of file
From f9edf33097d30e2c98dcf2ca009df0acaa20d210 Mon Sep 17 00:00:00 2001
From: MathieuG-P <40181755+Zagrios@users.noreply.github.com>
Date: Mon, 21 Nov 2022 00:05:20 +0100
Subject: [PATCH 039/162] progress on filter panel
---
package-lock.json | 33 +--
package.json | 1 +
.../filter-panel.component.tsx | 207 ++++++++++++++++--
.../map-item.component.tsx | 2 +-
.../maps-playlists-panel.component.tsx | 21 +-
src/renderer/helpers/time-utils.ts | 14 ++
src/shared/models/maps/beat-saver.model.ts | 1 +
7 files changed, 248 insertions(+), 31 deletions(-)
create mode 100644 src/renderer/helpers/time-utils.ts
diff --git a/package-lock.json b/package-lock.json
index 5c1ab1ce..4202eb0a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1876,7 +1876,7 @@
},
"@types/archiver": {
"version": "5.3.1",
- "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-5.3.1.tgz",
+ "resolved": "https://npm.zone51.tf/@types%2farchiver/-/archiver-5.3.1.tgz",
"integrity": "sha512-wKYZaSXaDvTZuInAWjCeGG7BEAgTWG2zZW0/f7IYFcoHB2X2d9lkVFnrOlXl3W6NrvO6Ml3FLLu8Uksyymcpnw==",
"dev": true,
"requires": {
@@ -2396,7 +2396,7 @@
},
"@types/yargs": {
"version": "17.0.13",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz",
+ "resolved": "https://registry.npmjs.org/@types%2fyargs/-/yargs-17.0.13.tgz",
"integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==",
"dev": true,
"requires": {
@@ -2998,7 +2998,7 @@
},
"archiver": {
"version": "5.3.1",
- "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz",
+ "resolved": "https://npm.zone51.tf/archiver/-/archiver-5.3.1.tgz",
"integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==",
"requires": {
"archiver-utils": "^2.1.0",
@@ -3012,7 +3012,7 @@
},
"archiver-utils": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz",
+ "resolved": "https://npm.zone51.tf/archiver-utils/-/archiver-utils-2.1.0.tgz",
"integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==",
"requires": {
"glob": "^7.1.4",
@@ -4053,7 +4053,7 @@
},
"compress-commons": {
"version": "4.1.1",
- "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz",
+ "resolved": "https://npm.zone51.tf/compress-commons/-/compress-commons-4.1.1.tgz",
"integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==",
"requires": {
"buffer-crc32": "^0.2.13",
@@ -4281,12 +4281,12 @@
},
"crc-32": {
"version": "1.2.2",
- "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
+ "resolved": "https://npm.zone51.tf/crc-32/-/crc-32-1.2.2.tgz",
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ=="
},
"crc32-stream": {
"version": "4.0.2",
- "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz",
+ "resolved": "https://npm.zone51.tf/crc32-stream/-/crc32-stream-4.0.2.tgz",
"integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==",
"requires": {
"crc-32": "^1.2.0",
@@ -6895,7 +6895,7 @@
},
"fs-constants": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "resolved": "https://npm.zone51.tf/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
},
"fs-extra": {
@@ -9447,7 +9447,7 @@
},
"lazystream": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
+ "resolved": "https://npm.zone51.tf/lazystream/-/lazystream-1.0.1.tgz",
"integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
"requires": {
"readable-stream": "^2.0.5"
@@ -11650,6 +11650,11 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
+ "react-range": {
+ "version": "1.8.14",
+ "resolved": "https://registry.npmjs.org/react-range/-/react-range-1.8.14.tgz",
+ "integrity": "sha512-v2nyD5106rHf9dwHzq+WRlhCes83h1wJRHIMFjbZsYYsO6LF4mG/mR3cH7Cf+dkeHq65DItuqIbLn/3jjYjsHg=="
+ },
"react-refresh": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.12.0.tgz",
@@ -11758,7 +11763,7 @@
},
"readdir-glob": {
"version": "1.1.2",
- "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.2.tgz",
+ "resolved": "https://npm.zone51.tf/readdir-glob/-/readdir-glob-1.1.2.tgz",
"integrity": "sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==",
"requires": {
"minimatch": "^5.1.0"
@@ -11766,7 +11771,7 @@
"dependencies": {
"brace-expansion": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "resolved": "https://npm.zone51.tf/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"requires": {
"balanced-match": "^1.0.0"
@@ -11774,7 +11779,7 @@
},
"minimatch": {
"version": "5.1.0",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
+ "resolved": "https://npm.zone51.tf/minimatch/-/minimatch-5.1.0.tgz",
"integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
"requires": {
"brace-expansion": "^2.0.1"
@@ -12940,7 +12945,7 @@
},
"tar-stream": {
"version": "2.2.0",
- "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "resolved": "https://npm.zone51.tf/tar-stream/-/tar-stream-2.2.0.tgz",
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"requires": {
"bl": "^4.0.3",
@@ -14130,7 +14135,7 @@
},
"zip-stream": {
"version": "4.1.0",
- "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz",
+ "resolved": "https://npm.zone51.tf/zip-stream/-/zip-stream-4.1.0.tgz",
"integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==",
"requires": {
"archiver-utils": "^2.1.0",
diff --git a/package.json b/package.json
index 40e40386..ed308e56 100644
--- a/package.json
+++ b/package.json
@@ -240,6 +240,7 @@
"react-colorful": "^5.6.1",
"react-dom": "^18.2.0",
"react-fitty": "^1.0.1",
+ "react-range": "^1.8.14",
"react-router-dom": "^6.3.0",
"react-visibility-sensor": "^5.1.1",
"regedit": "^5.1.1",
diff --git a/src/renderer/components/maps-mangement-components/filter-panel.component.tsx b/src/renderer/components/maps-mangement-components/filter-panel.component.tsx
index ac53c47c..e64b4b75 100644
--- a/src/renderer/components/maps-mangement-components/filter-panel.component.tsx
+++ b/src/renderer/components/maps-mangement-components/filter-panel.component.tsx
@@ -1,30 +1,211 @@
import { MapFilter, MapTag } from "shared/models/maps/beat-saver.model"
import {motion} from "framer-motion"
-import { MutableRefObject, useRef } from "react"
+import { MutableRefObject, useRef, useState } from "react"
import { MAP_TYPES } from "renderer/partials/map-tags/map-types"
import { MAP_STYLES } from "renderer/partials/map-tags/map-styles"
+import { BsmCheckbox } from "../shared/bsm-checkbox.component"
+import { diffColors } from "./map-item.component"
+import { getTrackBackground, Range } from 'react-range';
+import { useThemeColor } from "renderer/hooks/use-theme-color.hook"
+import { getCorrectTextColor } from "renderer/helpers/correct-text-color"
+import { hour_to_s, min_to_s } from "renderer/helpers/time-utils"
+import dateFormat from "dateformat"
export type Props = {
className?: string,
ref?: MutableRefObject
playlist?: boolean,
filter?: MapFilter
- onChange?: () => void
+ onChange?: (filter: MapFilter) => void
}
export function FilterPanel({className, ref, playlist = false, filter, onChange}: Props) {
- return !playlist ? (
-
-
-
- {[...MAP_TYPES, ...MAP_STYLES].map(tag => (
-
{tag}
- ))}
+ const MIN_NPS = 0;
+ const MAX_NPS = 17;
+
+ const MIN_DURATION = 0;
+ const MAX_DURATION = min_to_s(30);
+
+ const [npss, setNpss] = useState
([filter?.minNps || MIN_NPS, filter?.maxNps || MAX_NPS]);
+ const [durations, setDurations] = useState([filter?.minDuration || MIN_DURATION, filter?.maxDuration || MAX_DURATION]);
+ const firstColor = useThemeColor("first-color");
+ const thumbTextColor = getCorrectTextColor(firstColor);
+
+ const isTagEnabled = (tag: MapTag): boolean => {
+ return filter?.enabledTags?.some(t => t === tag) || filter?.excludedTags?.some(t => t === tag);
+ }
+
+ const isTagExcluded = (tag: MapTag): boolean => {
+ return filter?.excludedTags?.some(t => t === tag);
+ }
+
+ const secToTimer = (sec: number): string => {
+ const date = new Date(0);
+ date.setSeconds(sec);
+ return sec > 3600 ? dateFormat(date, "h:MM:ss") : dateFormat(date, "MM:ss");
+ }
+
+ const handleRangeChange = ([min, max]: number[]) => {
+ setNpss(() => [min, max]);
+ onChange?.({...filter, minNps: min, maxNps: max});
+ }
+
+ const handleRangeDurationChange = ([min, max]: number[]) => {
+ setDurations([min, max]);
+ onChange?.({...filter, minDuration: min, maxDuration: max});
+ }
+
+ console.log(hour_to_s(2));
+
+ return !playlist ? (
+
+
+
+
(
+
+ {children}
+
+ )}
+ renderThumb={({ index, props }) => (
+
+ {
+ npss[index] === MAX_NPS ? "∞" : npss[index] === MIN_NPS ? "NPS" : npss[index].toFixed(1)
+ }
+
+ )}
+ />
+
+
+
(
+
+ {children}
+
+ )}
+ renderThumb={({ index, props }) => (
+
+ {
+ durations[index] === MAX_DURATION ? "∞" : durations[index] === MIN_DURATION ? "Durée" : secToTimer(durations[index])
+ }
+
+ )}
+ />
+
-
-
- ) : (
+
+
+ general
+
+
+ AI
+
+
+
+ Rancked
+
+
+
+ Curated
+
+
+
+ Verified Mapper
+
+
+
+ Full Spread
+
+ requirements
+
+
+ Chroma
+
+
+
+ Noodle
+
+
+
+ Mapping Extensions
+
+
+
+ Cinema
+
+
+
+
+ TAGS
+
+ {MAP_TYPES.map(tag => (
+ {tag}
+ ))}
+
+
+ {MAP_STYLES.map(tag => (
+ {tag}
+ ))}
+
+
+
+
+
+
+ ) : (
<>>
- )
+ )
}
diff --git a/src/renderer/components/maps-mangement-components/map-item.component.tsx b/src/renderer/components/maps-mangement-components/map-item.component.tsx
index 71505564..cfaa1f31 100644
--- a/src/renderer/components/maps-mangement-components/map-item.component.tsx
+++ b/src/renderer/components/maps-mangement-components/map-item.component.tsx
@@ -214,7 +214,7 @@ export function MapItem({hash, title, autor, songAutor, coverUrl, songUrl, autor
)
}
-const diffColors: Record
= {
+export const diffColors: Record = {
Easy: "#00FF9E",
Normal: "#00FFFF",
Hard: "#FFA700",
diff --git a/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx b/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx
index cee6481a..e8654302 100644
--- a/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx
+++ b/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx
@@ -5,6 +5,7 @@ import { LocalMapsListPanel } from "./local-maps-list-panel.component"
import {AnimatePresence, motion} from "framer-motion"
import { BsmDropdownButton } from "../shared/bsm-dropdown-button.component"
import { FilterPanel } from "./filter-panel.component"
+import { MapFilter } from "shared/models/maps/beat-saver.model"
type Props = {
oneBlock?: boolean,
@@ -14,6 +15,20 @@ type Props = {
export function MapsPlaylistsPanel({version, oneBlock = false}: Props) {
const [tabIndex, setTabIndex] = useState(0);
+ const [filter, setFilter] = useState({
+ automapper: false,
+ chroma: false,
+ cinema: false,
+ curated: false,
+ enabledTags: [],
+ excludedTags: [],
+ fullSpread: false,
+ me: false,
+ noodle: false,
+ ranked: false,
+ verified: false,
+
+ })
return (
<>
@@ -23,10 +38,10 @@ export function MapsPlaylistsPanel({version, oneBlock = false}: Props) {
-
-
+
+
-
+
<>>
diff --git a/src/renderer/helpers/time-utils.ts b/src/renderer/helpers/time-utils.ts
new file mode 100644
index 00000000..6118e6d2
--- /dev/null
+++ b/src/renderer/helpers/time-utils.ts
@@ -0,0 +1,14 @@
+const SECONDS_IN_MINUTE = 60;
+const MINUTES_IN_HOUR = 60;
+
+export function min_to_s(minutes: number): number{
+ return minutes * SECONDS_IN_MINUTE;
+}
+
+export function hour_to_min(hours: number): number{
+ return hours * MINUTES_IN_HOUR;
+}
+
+export function hour_to_s(hours: number): number{
+ return hours * min_to_s(MINUTES_IN_HOUR);
+}
\ No newline at end of file
diff --git a/src/shared/models/maps/beat-saver.model.ts b/src/shared/models/maps/beat-saver.model.ts
index 2c7d4049..16f34ea9 100644
--- a/src/shared/models/maps/beat-saver.model.ts
+++ b/src/shared/models/maps/beat-saver.model.ts
@@ -152,6 +152,7 @@ export interface MapFilter {
chroma?: boolean,
cinema?: boolean,
noodle?: boolean,
+ me?: boolean,
curated?: boolean,
verified?: boolean,
from?: number,
From 46f5f9486c90daa119853e2ad153bf36731a24a9 Mon Sep 17 00:00:00 2001
From: MathieuG-P <40181755+Zagrios@users.noreply.github.com>
Date: Tue, 22 Nov 2022 00:21:22 +0100
Subject: [PATCH 040/162] map filter and search works
---
.../filter-panel.component.tsx | 259 ++++++++----------
.../local-maps-list-panel.component.tsx | 115 +++++++-
.../map-item.component.tsx | 4 +-
.../maps-playlists-panel.component.tsx | 36 ++-
.../components/shared/bsm-range.component.tsx | 63 +++++
src/renderer/hooks/use-theme-color.hook.ts | 8 +-
src/renderer/partials/map-tags/map-styles.ts | 73 ++---
src/renderer/partials/map-tags/map-types.ts | 14 +-
src/shared/models/maps/beat-saver.model.ts | 8 +-
9 files changed, 361 insertions(+), 219 deletions(-)
create mode 100644 src/renderer/components/shared/bsm-range.component.tsx
diff --git a/src/renderer/components/maps-mangement-components/filter-panel.component.tsx b/src/renderer/components/maps-mangement-components/filter-panel.component.tsx
index e64b4b75..c9e901c8 100644
--- a/src/renderer/components/maps-mangement-components/filter-panel.component.tsx
+++ b/src/renderer/components/maps-mangement-components/filter-panel.component.tsx
@@ -1,15 +1,13 @@
import { MapFilter, MapTag } from "shared/models/maps/beat-saver.model"
import {motion} from "framer-motion"
-import { MutableRefObject, useRef, useState } from "react"
+import { MutableRefObject} from "react"
import { MAP_TYPES } from "renderer/partials/map-tags/map-types"
import { MAP_STYLES } from "renderer/partials/map-tags/map-styles"
import { BsmCheckbox } from "../shared/bsm-checkbox.component"
import { diffColors } from "./map-item.component"
-import { getTrackBackground, Range } from 'react-range';
-import { useThemeColor } from "renderer/hooks/use-theme-color.hook"
-import { getCorrectTextColor } from "renderer/helpers/correct-text-color"
-import { hour_to_s, min_to_s } from "renderer/helpers/time-utils"
+import { min_to_s } from "renderer/helpers/time-utils"
import dateFormat from "dateformat"
+import { BsmRange } from "../shared/bsm-range.component"
export type Props = {
className?: string,
@@ -27,177 +25,158 @@ export function FilterPanel({className, ref, playlist = false, filter, onChange}
const MIN_DURATION = 0;
const MAX_DURATION = min_to_s(30);
- const [npss, setNpss] = useState([filter?.minNps || MIN_NPS, filter?.maxNps || MAX_NPS]);
- const [durations, setDurations] = useState([filter?.minDuration || MIN_DURATION, filter?.maxDuration || MAX_DURATION]);
- const firstColor = useThemeColor("first-color");
- const thumbTextColor = getCorrectTextColor(firstColor);
+ const npss = [filter?.minNps || MIN_NPS, filter?.maxNps || MAX_NPS];
+ const durations = [filter?.minDuration || MIN_DURATION, filter?.maxDuration || MAX_DURATION];
- const isTagEnabled = (tag: MapTag): boolean => {
- return filter?.enabledTags?.some(t => t === tag) || filter?.excludedTags?.some(t => t === tag);
+ const isTagActivated = (tag: MapTag): boolean => filter?.enabledTags?.has(tag) || filter?.excludedTags?.has(tag);
+ const isTagExcluded = (tag: MapTag): boolean => filter?.excludedTags?.has(tag);
+
+ const renderDurationLabel = (sec: number): JSX.Element => {
+
+ const textValue = (() => {
+ if(sec === MIN_DURATION){ return "Durée"; } //TODO TRADUIRE
+ if(sec === MAX_DURATION){ return "∞"; }
+ const date = new Date(0);
+ date.setSeconds(sec);
+ return sec > 3600 ? dateFormat(date, "h:MM:ss") : dateFormat(date, "MM:ss");
+ })();
+
+ return renderLabel(textValue, sec === MAX_DURATION);
}
- const isTagExcluded = (tag: MapTag): boolean => {
- return filter?.excludedTags?.some(t => t === tag);
+ const renderNpsLabel = (nps: number): JSX.Element => {
+
+ const textValue = (() => {
+ if(nps === MIN_NPS){ return "NPS"; }
+ if(nps === MAX_NPS){ return "∞"; }
+ return nps;
+ })();
+
+ return renderLabel(textValue, nps === MAX_NPS);
+
+ }
+
+ const renderLabel = (text: unknown, isMax: boolean): JSX.Element => {
+ return (
+
+ {text}
+
+ )
}
- const secToTimer = (sec: number): string => {
- const date = new Date(0);
- date.setSeconds(sec);
- return sec > 3600 ? dateFormat(date, "h:MM:ss") : dateFormat(date, "MM:ss");
+ const onNpssChange = ([min, max]: number[]) => {
+ const newFilter: MapFilter = {...(filter ?? {}), minNps: min, maxNps: max};
+ if(max === MAX_NPS){
+ delete newFilter["maxNps"];
+ }
+ onChange(newFilter);
}
- const handleRangeChange = ([min, max]: number[]) => {
- setNpss(() => [min, max]);
- onChange?.({...filter, minNps: min, maxNps: max});
+ const onDurationsChange = ([min, max]: number[]) => {
+ const newFilter: MapFilter = {...(filter ?? {}), minDuration: min, maxDuration: max};
+ if(max === MAX_DURATION){
+ delete newFilter["maxDuration"];
+ }
+ onChange(newFilter);
}
- const handleRangeDurationChange = ([min, max]: number[]) => {
- setDurations([min, max]);
- onChange?.({...filter, minDuration: min, maxDuration: max});
+ const handleTagClick = (tag: MapTag) => {
+ if(filter.enabledTags.has(tag)){
+ filter.enabledTags.delete(tag);
+ filter.excludedTags.add(tag);
+ return onChange({
+ ...filter,
+ enabledTags: filter.enabledTags,
+ excludedTags: filter.excludedTags
+ })
+ }
+ if(filter.excludedTags.has(tag)){
+ filter.excludedTags.delete(tag);
+ return onChange({
+ ...filter,
+ excludedTags: filter.excludedTags
+ })
+ }
+
+ filter.enabledTags.add(tag);
+ onChange({
+ ...filter,
+ enabledTags: filter.enabledTags
+ })
+
}
- console.log(hour_to_s(2));
+ type BooleanKeys = { [k in keyof T]: T[k] extends boolean ? k : never }[keyof T];
+
+ const handleCheckbox = (key: BooleanKeys) => {
+ const newFilter = {...(filter ?? {})};
+ if(newFilter[key] === true){
+ delete newFilter[key];
+ }
+ else{
+ newFilter[key] = true;
+ }
+ onChange(newFilter);
+ }
return !playlist ? (
-
-
-
(
-
- {children}
-
- )}
- renderThumb={({ index, props }) => (
-
- {
- npss[index] === MAX_NPS ? "∞" : npss[index] === MIN_NPS ? "NPS" : npss[index].toFixed(1)
- }
-
- )}
- />
-
-
-
(
-
- {children}
-
- )}
- renderThumb={({ index, props }) => (
-
- {
- durations[index] === MAX_DURATION ? "∞" : durations[index] === MIN_DURATION ? "Durée" : secToTimer(durations[index])
- }
-
- )}
- />
-
+
+
+
-
+
{/* TODO TRADUIRE */}
general
-
-
- AI
+ handleCheckbox("automapper")}>
+ handleCheckbox("automapper")}/>
+ AI
-
-
- Rancked
+ handleCheckbox("ranked")}>
+ handleCheckbox("ranked")}/>
+ Rancked
-
-
- Curated
+ handleCheckbox("curated")}>
+ handleCheckbox("curated")}/>
+ Curated
-
-
- Verified Mapper
+ handleCheckbox("verified")}>
+ handleCheckbox("verified")}/>
+ Verified Mapper
-
-
- Full Spread
+ handleCheckbox("fullSpread")}>
+ handleCheckbox("fullSpread")}/>
+ Full Spread
requirements
-
-
- Chroma
+ handleCheckbox("chroma")}>
+ handleCheckbox("chroma")}/>
+ Chroma
-
-
- Noodle
+ handleCheckbox("noodle")}>
+ handleCheckbox("noodle")}/>
+ Noodle
-
-
- Mapping Extensions
+ handleCheckbox("me")}>
+ handleCheckbox("me")}/>
+ Me
-
-
- Cinema
+ handleCheckbox("cinema")}>
+ handleCheckbox("cinema")}/>
+ Cinema
-
+
TAGS
{MAP_TYPES.map(tag => (
- {tag}
+ handleTagClick(tag)} className={`text-sm text-black rounded-md px-1 font-bold cursor-pointer ${(!isTagActivated(tag)) && "opacity-40 hover:opacity-100"}`} style={{backgroundColor: isTagExcluded(tag) ? diffColors.Expert : diffColors.Normal}}>{tag}
))}
{MAP_STYLES.map(tag => (
- {tag}
+ handleTagClick(tag)} className={`text-sm text-black rounded-md px-1 font-bold cursor-pointer ${(!isTagActivated(tag)) && "opacity-40 hover:opacity-100"}`} style={{backgroundColor: isTagExcluded(tag) ? diffColors.Expert : diffColors.Easy}}>{tag}
))}
diff --git a/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx b/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx
index d611b835..234c381b 100644
--- a/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx
+++ b/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx
@@ -1,20 +1,20 @@
import { MapsManagerService } from "renderer/services/maps-manager.service"
import { BSVersion } from "shared/bs-version.interface"
-import VisibilitySensor from "react-visibility-sensor"
import { useEffect, useRef, useState } from "react"
import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface"
import { Subscription } from "rxjs"
-import { MapItem, MapItemProps, ParsedMapDiff } from "./map-item.component"
-import { BsvMapCharacteristic, BsvMapDifficultyType } from "shared/models/maps/beat-saver.model"
+import { MapItem, ParsedMapDiff } from "./map-item.component"
+import { BsvMapCharacteristic, MapFilter } from "shared/models/maps/beat-saver.model"
import { useInView } from "framer-motion"
-import { MapsToolbar } from "./maps-toolbar.component"
type Props = {
version: BSVersion,
- className?: string
+ className?: string,
+ filter?: MapFilter
+ search?: string,
}
-export function LocalMapsListPanel({version, className} : Props) {
+export function LocalMapsListPanel({version, className, filter, search} : Props) {
const mapsManager = MapsManagerService.getInstance();
@@ -33,7 +33,6 @@ export function LocalMapsListPanel({version, className} : Props) {
return () => {
setMaps(() => []);
- console.log("DESTORYED");
subs.forEach(s => s.unsubscribe());
}
}, [isVisible, version])
@@ -73,6 +72,106 @@ export function LocalMapsListPanel({version, className} : Props) {
setSelectedMaps(() => hashs);
}
+ const isMapFitFilter = (map: BsmLocalMap): boolean => {
+
+ const fitEnabledTags = (() => {
+ if(!filter?.enabledTags || filter.enabledTags.size === 0){ return true; }
+ if(!map?.bsaverInfo?.tags){ return false; }
+ return Array.from(filter.enabledTags.values()).every(tag => map.bsaverInfo.tags.some(mapTag => mapTag === tag));
+ })();
+
+ const fitExcluedTags = (() => {
+ if(!filter?.excludedTags || filter.excludedTags.size === 0){ return true; }
+ if(!map?.bsaverInfo?.tags){ return true; }
+ return !map.bsaverInfo.tags.some(tag => filter.excludedTags.has(tag));
+ })();
+
+ const fitMinNps = (() => {
+ if(!filter?.minNps){ return true; }
+ if(!map?.bsaverInfo?.versions?.at(0)){ return false; }
+ return !map.bsaverInfo.versions.some(version => {
+ return version.diffs.some(diff => diff.nps < filter.minNps);
+ });
+ })();
+
+ const fitMaxNps = (() => {
+ if(!filter?.maxNps){ return true; }
+ if(!map?.bsaverInfo?.versions?.at(0)){ return false; }
+ return !map.bsaverInfo.versions.some(version => {
+ return version.diffs.some(diff => diff.nps > filter.maxNps);
+ });
+ })();
+
+ const fitMinDuration = (() => {
+ if(!filter?.minDuration){ return true; }
+
+ if(!map?.bsaverInfo?.metadata?.duration){ return false; }
+ return map.bsaverInfo.metadata.duration >= filter.minDuration;
+ })();
+
+ const fitMaxDuration = (() => {
+ if(!filter?.maxDuration){ return true; }
+ if(!map?.bsaverInfo?.metadata?.duration){ return false; }
+ return map.bsaverInfo.metadata.duration <= filter.maxDuration;
+ })();
+
+ const fitNoodle = (() => {
+ if(!filter?.noodle){ return true; }
+ if(!map?.bsaverInfo?.versions?.at(0)){ return false; }
+ return map.bsaverInfo.versions.some(version => version.diffs.some(diff => !!diff.ne));
+ })();
+
+ const fitMe = (() => {
+ if(!filter?.me){ return true; }
+ if(!map?.bsaverInfo?.versions?.at(0)){ return false; }
+ return map.bsaverInfo.versions.some(version => version.diffs.some(diff => !!diff.me));
+ })();
+
+ const fitCinema = (() => {
+ if(!filter?.cinema){ return true; }
+ if(!map?.bsaverInfo?.versions?.at(0)){ return false; }
+ return map.bsaverInfo.versions.some(version => version.diffs.some(diff => !!diff.cinema));
+ })();
+
+ const fitChroma =(() => {
+ if(!filter?.chroma){ return true; }
+ if(!map?.bsaverInfo?.versions?.at(0)){ return false; }
+ return map.bsaverInfo.versions.some(version => version.diffs.some(diff => !!diff.chroma));
+ })();
+
+ const fitFullSpread = (() => {
+ if(!filter?.fullSpread){ return true; }
+ if(!map?.bsaverInfo?.versions?.at(0)){ return false; }
+ return map.bsaverInfo.versions.some(version => version?.diffs?.length >= 5);
+ })();
+
+ const fitAutoMapper = filter?.automapper ? map.bsaverInfo?.automapper === filter.automapper : true;
+ const fitRanked = filter?.ranked ? map.bsaverInfo?.ranked === filter.ranked : true;
+ const fitCurated = filter?.curated ? !!map.bsaverInfo?.curatedAt : true;
+ const fitVerified = filter?.verified ? !!map.bsaverInfo?.uploader?.verifiedMapper : true;
+
+ const filterCheck = fitEnabledTags && fitExcluedTags && fitMinNps && fitMaxNps && fitMinDuration && fitMaxDuration && fitNoodle && fitMe && fitCinema && fitChroma && fitFullSpread && fitAutoMapper && fitRanked && fitCurated && fitVerified;
+
+ const searchCheck = (() => {
+ return (
+ ((map.rawInfo?._songName ?? map.bsaverInfo?.name) || "")?.toLowerCase().includes(search.toLowerCase()) ||
+ ((map.rawInfo?._songAuthorName ?? map.bsaverInfo?.metadata?.songAuthorName) || "")?.toLowerCase().includes(search.toLowerCase()) ||
+ ((map.rawInfo?._levelAuthorName ?? map.bsaverInfo?.metadata?.levelAuthorName) || "")?.toLowerCase().includes(search.toLowerCase()));
+ })();
+
+ return filterCheck && searchCheck;
+
+ }
+
+ const renderMaps = (): JSX.Element[] => {
+ return maps.reduce((acc, current) => {
+ if(isMapFitFilter(current)){
+ acc.push(renderMapItem(current));
+ }
+ return acc
+ }, []);
+ }
+
const renderMapItem = (map: BsmLocalMap) => {
return
- {maps.map(map => renderMapItem(map))}
+ {renderMaps()}
)
diff --git a/src/renderer/components/maps-mangement-components/map-item.component.tsx b/src/renderer/components/maps-mangement-components/map-item.component.tsx
index cfaa1f31..196d059c 100644
--- a/src/renderer/components/maps-mangement-components/map-item.component.tsx
+++ b/src/renderer/components/maps-mangement-components/map-item.component.tsx
@@ -5,7 +5,7 @@ import { BsmLink } from "../shared/bsm-link.component";
import { BsmIcon } from "../svgs/bsm-icon.component";
import { BsmButton } from "../shared/bsm-button.component";
import { AnimatePresence, motion } from "framer-motion";
-import { useState, Fragment } from "react";
+import { useState, Fragment, memo } from "react";
import { LinkOpenerService } from "renderer/services/link-opener.service";
import dateFormat from "dateformat";
import { AudioPlayerService } from "renderer/services/audio-player.service";
@@ -127,7 +127,7 @@ export function MapItem({hash, title, autor, songAutor, coverUrl, songUrl, autor
}
return (
- setHovered(true)} onHoverEnd={() => setHovered(false)} style={{zIndex: hovered && 5, transform: "translateZ(0) scale(1.0, 1.0)", backfaceVisibility: "hidden"}} onClick={e => {e.stopPropagation(); onSelected(hash)}}>
+ setHovered(true)} onHoverEnd={() => setHovered(false)} style={{zIndex: hovered && 5, transform: "translateZ(0) scale(1.0, 1.0)", backfaceVisibility: "hidden"}} onClick={e => {onSelected(hash)}}>
{(hovered || selected) && }
{(diffsPanelHovered || bottomBarHovered) && (
diff --git a/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx b/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx
index e8654302..dfc10a3e 100644
--- a/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx
+++ b/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx
@@ -2,10 +2,9 @@ import { useState } from "react"
import { BSVersion } from "shared/bs-version.interface"
import { TabNavBar } from "../shared/tab-nav-bar.component"
import { LocalMapsListPanel } from "./local-maps-list-panel.component"
-import {AnimatePresence, motion} from "framer-motion"
import { BsmDropdownButton } from "../shared/bsm-dropdown-button.component"
import { FilterPanel } from "./filter-panel.component"
-import { MapFilter } from "shared/models/maps/beat-saver.model"
+import { MapFilter, MapTag } from "shared/models/maps/beat-saver.model"
type Props = {
oneBlock?: boolean,
@@ -15,20 +14,19 @@ type Props = {
export function MapsPlaylistsPanel({version, oneBlock = false}: Props) {
const [tabIndex, setTabIndex] = useState(0);
- const [filter, setFilter] = useState({
- automapper: false,
- chroma: false,
- cinema: false,
- curated: false,
- enabledTags: [],
- excludedTags: [],
- fullSpread: false,
- me: false,
- noodle: false,
- ranked: false,
- verified: false,
-
- })
+ const [mapFilter, setMapFilter] = useState({
+ enabledTags: new Set(),
+ excludedTags: new Set()
+ });
+ const [mapSearch, setMapSearch] = useState("");
+ const [playlistSearch, setPlaylistSearch] = useState("");
+
+ const handleSearch = (value: string) => {
+ if(tabIndex === 0){
+ return setMapSearch(() => value);
+ }
+ return setPlaylistSearch(() => value);
+ }
return (
<>
@@ -36,10 +34,10 @@ export function MapsPlaylistsPanel({version, oneBlock = false}: Props) {