From 8af4f62492b34e9397f056ba5183f2c4bb7b5ac0 Mon Sep 17 00:00:00 2001 From: Dmytro Kondakov Date: Mon, 14 Apr 2025 08:47:57 +0200 Subject: [PATCH] feat(app): restructure routing and implement Search component - Refactored the App component to streamline routing using the Router and Route components. - Introduced a new Search component to handle search functionality, including input handling and result display. - Removed inline search logic from the App component for better separation of concerns. - Updated index.tsx to render the App component directly, simplifying the routing structure. --- frontend/src/App.tsx | 174 ++++---------------------------------- frontend/src/Search.tsx | 182 ++++++++++++++++++++++++++++++++++++++++ frontend/src/index.tsx | 18 +--- 3 files changed, 198 insertions(+), 176 deletions(-) create mode 100644 frontend/src/Search.tsx diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 9a796da..c6553d4 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,101 +1,16 @@ -import { Button } from "@kobalte/core/button"; -import { A } from "@solidjs/router"; -import { IconSearch, IconSettings } from "@tabler/icons-solidjs"; +import { Route, Router } from "@solidjs/router"; import { listen } from "@tauri-apps/api/event"; -import clsx from "clsx"; -import Fuse from "fuse.js"; -import { - For, - createEffect, - createResource, - createSignal, - onCleanup, -} from "solid-js"; -import { ImageViewer } from "./components/ImageViewer"; -import { SearchCard } from "./components/search-card/SearchCard"; -import { SearchCardContact } from "./components/search-card/SearchCardContact"; -import { SearchCardEvent } from "./components/search-card/SearchCardEvent"; -import { SearchCardLocation } from "./components/search-card/SearchCardLocation"; -import { SearchCardNote } from "./components/search-card/SearchCardNote"; -import { type UserImage, getUserImages } from "./network"; -import { getCardSize } from "./utils/getCardSize"; - -// How wonderfully functional -const getAllValues = (object: object): Array => { - const loop = (acc: Array, next: object): Array => { - for (const _value of Object.values(next)) { - const value: unknown = _value; - switch (typeof value) { - case "object": - if (value != null) { - acc.push(...loop(acc, value)); - } - break; - case "string": - case "number": - case "boolean": - acc.push(value.toString()); - break; - default: - break; - } - } - - return acc; - }; - - return loop([], object); -}; +import { createEffect, onCleanup } from "solid-js"; +import { Login } from "./Login"; +import { ProtectedRoute } from "./ProtectedRoute"; +import { Search } from "./Search"; +import { Settings } from "./Settings"; export const App = () => { - const [searchResults, setSearchResults] = createSignal([]); - const [searchQuery, setSearchQuery] = createSignal(""); - const [selectedItem, setSelectedItem] = createSignal( - null, - ); - - const [data] = createResource(() => - getUserImages().then((data) => - data.map((d) => ({ - ...d, - rawData: getAllValues(d), - })), - ), - ); - - let fuze = new Fuse(data() ?? [], { - keys: [ - { name: "rawData", weight: 1 }, - { name: "title", weight: 1 }, - ], - threshold: 0.4, - }); - createEffect(() => { - setSearchResults(data() ?? []); - fuze = new Fuse(data() ?? [], { - keys: [ - { name: "data.Name", weight: 2 }, - { name: "rawData", weight: 1 }, - ], - threshold: 0.4, - }); - }); - - const onInputChange = (event: InputEvent) => { - const query = (event.target as HTMLInputElement).value; - setSearchQuery(query); - setSearchResults(fuze.search(query).map((s) => s.item)); - }; - - let searchInputRef: HTMLInputElement | undefined; - - createEffect(() => { - // Listen for the focus-search event from Tauri + // TODO: Don't use window.location.href const unlisten = listen("focus-search", () => { - if (searchInputRef) { - searchInputRef.focus(); - } + window.location.href = "/"; }); onCleanup(() => { @@ -104,72 +19,13 @@ export const App = () => { }); return ( - <> -
-
-
-
- -
- -
- -
+ + -
-
- {searchResults().length > 0 ? ( -
- - {(item) => ( -
- setSelectedItem(item) - } - onKeyDown={(e) => { - if (e.key === "Enter") { - setSelectedItem(item); - } - }} - class="h-[144px] border relative col-span-3 border-neutral-200 cursor-pointer overflow-hidden rounded-xl" - > - - {item.data.Name} - - -
- )} -
-
- ) : ( -
- No results found -
- )} -
-
- -
- footer -
-
- + + + + + ); }; diff --git a/frontend/src/Search.tsx b/frontend/src/Search.tsx new file mode 100644 index 0000000..9962600 --- /dev/null +++ b/frontend/src/Search.tsx @@ -0,0 +1,182 @@ +import { Button } from "@kobalte/core/button"; +import { A } from "@solidjs/router"; +import { IconSearch, IconSettings } from "@tabler/icons-solidjs"; +import { listen } from "@tauri-apps/api/event"; +import clsx from "clsx"; +import Fuse from "fuse.js"; +import { + For, + createEffect, + createResource, + createSignal, + onCleanup, + onMount, +} from "solid-js"; +import { ImageViewer } from "./components/ImageViewer"; +import { SearchCard } from "./components/search-card/SearchCard"; +import { SearchCardContact } from "./components/search-card/SearchCardContact"; +import { SearchCardEvent } from "./components/search-card/SearchCardEvent"; +import { SearchCardLocation } from "./components/search-card/SearchCardLocation"; +import { SearchCardNote } from "./components/search-card/SearchCardNote"; +import { type UserImage, getUserImages } from "./network"; +import { getCardSize } from "./utils/getCardSize"; + +// How wonderfully functional +const getAllValues = (object: object): Array => { + const loop = (acc: Array, next: object): Array => { + for (const _value of Object.values(next)) { + const value: unknown = _value; + switch (typeof value) { + case "object": + if (value != null) { + acc.push(...loop(acc, value)); + } + break; + case "string": + case "number": + case "boolean": + acc.push(value.toString()); + break; + default: + break; + } + } + + return acc; + }; + + return loop([], object); +}; + +export const Search = () => { + const [searchResults, setSearchResults] = createSignal([]); + const [searchQuery, setSearchQuery] = createSignal(""); + const [selectedItem, setSelectedItem] = createSignal( + null, + ); + + const [data] = createResource(() => + getUserImages().then((data) => + data.map((d) => ({ + ...d, + rawData: getAllValues(d), + })), + ), + ); + + let fuze = new Fuse(data() ?? [], { + keys: [ + { name: "rawData", weight: 1 }, + { name: "title", weight: 1 }, + ], + threshold: 0.4, + }); + + createEffect(() => { + setSearchResults(data() ?? []); + fuze = new Fuse(data() ?? [], { + keys: [ + { name: "data.Name", weight: 2 }, + { name: "rawData", weight: 1 }, + ], + threshold: 0.4, + }); + }); + + const onInputChange = (event: InputEvent) => { + const query = (event.target as HTMLInputElement).value; + setSearchQuery(query); + setSearchResults(fuze.search(query).map((s) => s.item)); + }; + + let searchInputRef: HTMLInputElement | undefined; + + onMount(() => { + if (searchInputRef) { + searchInputRef.focus(); + } + }); + + createEffect(() => { + // Listen for the focus-search event from Tauri + const unlisten = listen("focus-search", () => { + if (searchInputRef) { + searchInputRef.focus(); + } + }); + + onCleanup(() => { + unlisten.then((fn) => fn()); + }); + }); + + return ( + <> +
+
+
+
+ +
+ +
+ +
+ +
+
+ {searchResults().length > 0 ? ( +
+ + {(item) => ( +
+ setSelectedItem(item) + } + onKeyDown={(e) => { + if (e.key === "Enter") { + setSelectedItem(item); + } + }} + class="h-[144px] border relative col-span-3 border-neutral-200 cursor-pointer overflow-hidden rounded-xl" + > + + {item.data.Name} + + +
+ )} +
+
+ ) : ( +
+ No results found +
+ )} +
+
+ +
+ footer +
+
+ + ); +}; diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index f5fb4fa..0e0c8ca 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -2,23 +2,7 @@ import { render } from "solid-js/web"; import "./index.css"; -import { Route, Router } from "@solidjs/router"; import { App } from "./App"; -import { Login } from "./Login"; -import { ProtectedRoute } from "./ProtectedRoute"; -import { Settings } from "./Settings"; -render( - () => ( - - - - - - - - - ), - document.getElementById("root") as HTMLElement, -); +render(() => , document.getElementById("root") as HTMLElement);