From b96adb2f18ca34736f48bcb7d45c082ab35e230a Mon Sep 17 00:00:00 2001 From: Innei Date: Wed, 17 Jul 2024 15:54:35 +0800 Subject: [PATCH] feat: add local records in search panel Signed-off-by: Innei --- .../src/components/common/ExPromise.tsx | 22 +++++ src/renderer/src/hono.ts | 45 ++++++---- src/renderer/src/modules/search/cmdk.tsx | 82 +++++++++++++------ src/renderer/src/store/search/index.ts | 8 +- src/renderer/src/store/search/types.ts | 6 ++ 5 files changed, 119 insertions(+), 44 deletions(-) create mode 100644 src/renderer/src/components/common/ExPromise.tsx diff --git a/src/renderer/src/components/common/ExPromise.tsx b/src/renderer/src/components/common/ExPromise.tsx new file mode 100644 index 0000000000..430bb0fc53 --- /dev/null +++ b/src/renderer/src/components/common/ExPromise.tsx @@ -0,0 +1,22 @@ +import { + useLayoutEffect, + useState, +} from "react" + +const NOT_RESOLVED = Symbol("NOT_RESOLVED") +export const ExPromise = ({ + children, + promise, +}: { + promise: Promise + children: (value: T) => JSX.Element +}) => { + // use() is a hook that returns the value of the promise, but in react 19 + + const [value, setValue] = useState(NOT_RESOLVED) + useLayoutEffect(() => { + promise.then(setValue) + }, [promise]) + + return value === NOT_RESOLVED ? null : children(value as T) +} diff --git a/src/renderer/src/hono.ts b/src/renderer/src/hono.ts index e1198b3018..50322fad82 100644 --- a/src/renderer/src/hono.ts +++ b/src/renderer/src/hono.ts @@ -2398,7 +2398,6 @@ declare const _routes: hono_hono_base.HonoBase}`]: { + input: Partial; + output: any; + outputFormat: string; + status: hono_utils_http_status.StatusCode; + }; + }; } & { "/entries": { $post: { @@ -3247,7 +3256,6 @@ declare const _routes: hono_hono_base.HonoBase { return (
- {icon && ( - - )} - - {title} - + {icon && } + {title} {subtitle} @@ -292,26 +293,57 @@ const SearchGroupHeading: FC<{ icon: string, title: string }> = ({ const SearchResultCount: FC<{ count?: number }> = ({ count }) => { + const searchInstance = React.useContext(SearchCmdKContext) const hasKeyword = useSearchStore((s) => !!s.keyword) - if (!count) return null + const searchType = useSearchStore((s) => s.searchType) + const recordCountPromise = useMemo(async () => { + let count = 0 + const counts = await searchInstance?.then((s) => s.counts) + if (!counts) return 0 + if (searchType & SearchType.Entry) { + count += counts.entries || 0 + } + if (searchType & SearchType.Feed) { + count += counts.feeds || 0 + } + if (searchType & SearchType.Subscription) { + count += counts.subscriptions || 0 + } + return count + }, [searchInstance, searchType]) + return ( - hasKeyword && ( - - - - {count} - {" "} - {pluralize("result", count)} - {" "} - (Local mode) - - - - - This search run on local database, the result may not be up-to-date. - - - ) + + + + {hasKeyword ? ( + + {count} + {" "} + {pluralize("result", count || 0)} + + ) : ( + + {(count) => ( + <> + {count} + {" "} + local + {" "} + {pluralize("record", count)} + + )} + + )} + {" "} + (Local mode) + + + + + This search run on local database, the result may not be up-to-date. + + ) } const SearchOptions: Component = memo(({ children }) => { diff --git a/src/renderer/src/store/search/index.ts b/src/renderer/src/store/search/index.ts index 9581e19ea5..089f64d99a 100644 --- a/src/renderer/src/store/search/index.ts +++ b/src/renderer/src/store/search/index.ts @@ -52,14 +52,20 @@ class SearchActions { "title", "content", "description", + "id", ]) - const feedsFuse = this.createFuse(feeds, ["title", "description"]) + const feedsFuse = this.createFuse(feeds, ["title", "description", "id"]) const subscriptionsFuse = this.createFuse(subscriptions, [ "title", "category", ]) return defineSearchInstance({ + counts: { + entries: entries.length, + feeds: feeds.length, + subscriptions: subscriptions.length, + }, search(keyword: string) { const type = get().searchType const entries = diff --git a/src/renderer/src/store/search/types.ts b/src/renderer/src/store/search/types.ts index 04fc4b63e0..e5bf6bd5e1 100644 --- a/src/renderer/src/store/search/types.ts +++ b/src/renderer/src/store/search/types.ts @@ -19,4 +19,10 @@ export interface SearchState { } export interface SearchInstance { search: (keyword: string) => SearchState + + counts: { + feeds: number + entries: number + subscriptions: number + } }