mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-09 07:03:25 +00:00
feat: add search modal filter with persistence
This commit is contained in:
@@ -28,7 +28,6 @@ export default function SearchListItem({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selected && !isHover) {
|
if (selected && !isHover) {
|
||||||
console.log(selected, ref.current);
|
|
||||||
ref.current?.scrollIntoView({ behavior: "smooth", block: "center" });
|
ref.current?.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||||
}
|
}
|
||||||
}, [isHover, selected]);
|
}, [isHover, selected]);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import SearchList from "./SearchList";
|
|||||||
import * as Keys from "constants/keys";
|
import * as Keys from "constants/keys";
|
||||||
import { GOOGLE_SEARCH_URL } from "constants/search-urls";
|
import { GOOGLE_SEARCH_URL } from "constants/search-urls";
|
||||||
import { Category, SearchItem } from "types";
|
import { Category, SearchItem } from "types";
|
||||||
|
import { useLocalStorage } from "hooks/useLocalStorage";
|
||||||
|
|
||||||
import styles from "./search.module.scss";
|
import styles from "./search.module.scss";
|
||||||
|
|
||||||
@@ -28,9 +29,14 @@ export default function SearchModal({
|
|||||||
}) {
|
}) {
|
||||||
const autoFocusRef = useAutoFocus();
|
const autoFocusRef = useAutoFocus();
|
||||||
|
|
||||||
// TODO: peristance
|
const [canSearchLink, setCanSearchLink] = useLocalStorage(
|
||||||
const [canSearchLink, setCanSearchLink] = useState<boolean>(true);
|
"search-link",
|
||||||
const [canSearchCategory, setCanSearchCategory] = useState<boolean>(true);
|
true
|
||||||
|
);
|
||||||
|
const [canSearchCategory, setCanSearchCategory] = useLocalStorage(
|
||||||
|
"search-category",
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
const [search, setSearch] = useState<string>("");
|
const [search, setSearch] = useState<string>("");
|
||||||
const [cursor, setCursor] = useState<number>(0);
|
const [cursor, setCursor] = useState<number>(0);
|
||||||
@@ -41,12 +47,15 @@ export default function SearchModal({
|
|||||||
() =>
|
() =>
|
||||||
search.length === 0
|
search.length === 0
|
||||||
? []
|
? []
|
||||||
: items.filter((item) =>
|
: items.filter(
|
||||||
item.name
|
(item) =>
|
||||||
.toLocaleLowerCase()
|
((item.type === "category" && canSearchCategory) ||
|
||||||
.includes(search.toLocaleLowerCase().trim())
|
(item.type === "link" && canSearchLink)) &&
|
||||||
|
item.name
|
||||||
|
.toLocaleLowerCase()
|
||||||
|
.includes(search.toLocaleLowerCase().trim())
|
||||||
),
|
),
|
||||||
[items, search]
|
[canSearchCategory, canSearchLink, items, search]
|
||||||
);
|
);
|
||||||
|
|
||||||
useHotkeys(Keys.ARROW_UP, () => setCursor((cursor) => (cursor -= 1)), {
|
useHotkeys(Keys.ARROW_UP, () => setCursor((cursor) => (cursor -= 1)), {
|
||||||
@@ -65,6 +74,14 @@ export default function SearchModal({
|
|||||||
setSearch(value);
|
setSearch(value);
|
||||||
setCursor(0);
|
setCursor(0);
|
||||||
}, []);
|
}, []);
|
||||||
|
const handleCanSearchLink = (checked: boolean) => {
|
||||||
|
setCanSearchLink(checked);
|
||||||
|
setCursor(0);
|
||||||
|
};
|
||||||
|
const handleCanSearchCategory = (checked: boolean) => {
|
||||||
|
setCanSearchCategory(checked);
|
||||||
|
setCursor(0);
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = useCallback(
|
const handleSubmit = useCallback(
|
||||||
(event: FormEvent<HTMLFormElement>) => {
|
(event: FormEvent<HTMLFormElement>) => {
|
||||||
@@ -108,18 +125,13 @@ export default function SearchModal({
|
|||||||
</div>
|
</div>
|
||||||
<SearchFilter
|
<SearchFilter
|
||||||
canSearchLink={canSearchLink}
|
canSearchLink={canSearchLink}
|
||||||
setCanSearchLink={setCanSearchLink}
|
setCanSearchLink={handleCanSearchLink}
|
||||||
canSearchCategory={canSearchCategory}
|
canSearchCategory={canSearchCategory}
|
||||||
setCanSearchCategory={setCanSearchCategory}
|
setCanSearchCategory={handleCanSearchCategory}
|
||||||
/>
|
/>
|
||||||
{search.length > 0 && (
|
{search.length > 0 && (
|
||||||
<SearchList
|
<SearchList
|
||||||
items={itemsCompletion.map((item) => ({
|
items={itemsCompletion}
|
||||||
id: item.id,
|
|
||||||
name: item.name,
|
|
||||||
url: item.url,
|
|
||||||
type: item.type,
|
|
||||||
}))}
|
|
||||||
noItem={<LabelSearchWithGoogle />}
|
noItem={<LabelSearchWithGoogle />}
|
||||||
cursor={cursor}
|
cursor={cursor}
|
||||||
setCursor={setCursor}
|
setCursor={setCursor}
|
||||||
|
|||||||
30
src/hooks/useLocalStorage.tsx
Normal file
30
src/hooks/useLocalStorage.tsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export function useLocalStorage(key: string, initialValue: any) {
|
||||||
|
const [storedValue, setStoredValue] = useState(() => {
|
||||||
|
if (typeof window === "undefined") {
|
||||||
|
return initialValue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const item = window.localStorage.getItem(key);
|
||||||
|
return item ? JSON.parse(item) : initialValue;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return initialValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const setValue = (value: any) => {
|
||||||
|
try {
|
||||||
|
const valueToStore =
|
||||||
|
value instanceof Function ? value(storedValue) : value;
|
||||||
|
setStoredValue(valueToStore);
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return [storedValue, setValue];
|
||||||
|
}
|
||||||
17
src/utils/array.ts
Normal file
17
src/utils/array.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
export function groupItemBy(array: any[], property: string) {
|
||||||
|
const hash = {};
|
||||||
|
const props = property.split(".");
|
||||||
|
|
||||||
|
for (const item of array) {
|
||||||
|
const key = props.reduce((acc, prop) => acc && acc[prop], item);
|
||||||
|
const hashKey = key !== undefined ? key : "catégories";
|
||||||
|
|
||||||
|
if (!hash[hashKey]) {
|
||||||
|
hash[hashKey] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
hash[hashKey].push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user