From 0fc8c69d516b799b8c3f5873402811b36179fb3a Mon Sep 17 00:00:00 2001 From: amsyarasyiq <82711525+amsyarasyiq@users.noreply.github.com> Date: Wed, 28 Aug 2024 15:45:50 +0800 Subject: [PATCH] feat: highlight search keywords --- src/core/ui/components/AddonCard.tsx | 1 + src/core/ui/components/AddonPage.tsx | 15 +- .../pages/Plugins/components/PluginCard.tsx | 129 ++++++++++-------- src/core/ui/settings/pages/Themes/index.tsx | 2 +- 4 files changed, 77 insertions(+), 70 deletions(-) diff --git a/src/core/ui/components/AddonCard.tsx b/src/core/ui/components/AddonCard.tsx index c6a4da6..7bab546 100644 --- a/src/core/ui/components/AddonCard.tsx +++ b/src/core/ui/components/AddonCard.tsx @@ -71,6 +71,7 @@ interface OverflowAction extends Action { export interface CardWrapper { item: T; + result: Fuzzysort.KeysResult; } interface CardProps { diff --git a/src/core/ui/components/AddonPage.tsx b/src/core/ui/components/AddonPage.tsx index f6c3c45..ac524c4 100644 --- a/src/core/ui/components/AddonPage.tsx +++ b/src/core/ui/components/AddonPage.tsx @@ -33,16 +33,13 @@ export default function AddonPage({ card: CardComponent, ...pr const [search, setSearch] = React.useState(""); - const items = useMemo(() => { + const results = useMemo(() => { let values = props.items; if (props.resolveItem) values = values.map(props.resolveItem); - return values.filter(i => i && typeof i === "object"); - }, [props.items]); + const items = values.filter(i => i && typeof i === "object"); - const data = useMemo(() => { - if (!search) return items; - return fuzzysort.go(search, items, { keys: props.searchKeywords }).map(r => r.obj); - }, [items, search]); + return fuzzysort.go(search, items, { keys: props.searchKeywords, all: true }); + }, [props.items, search]); const headerElement = ( @@ -58,14 +55,14 @@ export default function AddonPage({ card: CardComponent, ...pr return ( } ListFooterComponent={props.ListFooterComponent} - renderItem={({ item }: any) => } + renderItem={({ item }: any) => } /> {(props.fetchFunction ?? props.onFabPress) && (null!); -const usePlugin = () => useContext(PluginContext); +const CardContext = createContext<{ plugin: UnifiedPluginModel, result: Fuzzysort.KeysResult }>(null!); +const useCardContext = () => useContext(CardContext); + +function getHighlightColor(): import("react-native").ColorValue { + return chroma(tokens.unsafe_rawColors.YELLOW_300).alpha(0.3).hex(); +} + +function Title() { + const styles = usePluginCardStyles(); + const { plugin, result } = useCardContext(); + + // could be empty if the plugin name is irrelevant! + const highlightedNode = result[0].highlight((m, i) => + + {m} + + ); + + const icon = plugin.icon && findAssetId(plugin.icon); + + const textNode = ( + + {highlightedNode.length ? highlightedNode : plugin.name} + + ); + + return + {icon && } + {textNode} + ; +} function Authors() { - const plugin = usePlugin(); + const { plugin, result } = useCardContext(); if (!plugin.authors) return null; + // could be empty if the author(s) are irrelevant with the search! + const highlightedNode = result[2].highlight((m, i) => + + {m} + + ); + + if (highlightedNode.length > 0) return ( + + by {highlightedNode} + + ); + const children = ["by "]; for (const author of plugin.authors) { @@ -30,60 +79,21 @@ function Authors() { ; } -function Title() { - const styles = usePluginCardStyles(); - const plugin = usePlugin(); +function Description() { + const { plugin, result } = useCardContext(); - const icon = plugin.icon && findAssetId(plugin.icon); - - const textElement = ( - - {plugin.name} - + // could be empty if the description is irrelevant with the search! + const highlightedNode = result[1].highlight((m, i) => + {m} ); - return !icon ? textElement : - - {textElement} - ; + return + {highlightedNode.length ? highlightedNode : plugin.description} + ; } -// TODO: Wrap in a Card-ish component with red bg -// TODO: Allow glacing at the error's stack -// function Status() { -// const plugin = usePlugin(); -// const styles = usePluginCardStyles(); -// const INTERACTIVE_NORMAL = useToken(tokens.colors.INTERACTIVE_NORMAL); - -// if (!plugin.error) return null; - -// return -// -// -// -// -// There was an error while attempting to start this plugin. -// -// ; -// } - const Actions = memo(() => { - const plugin = usePlugin(); + const { plugin } = useCardContext(); const navigation = NavigationNative.useNavigation(); return @@ -110,14 +120,15 @@ const Actions = memo(() => { ; }); -export default function PluginCard({ item: plugin }: CardWrapper) { +export default function PluginCard({ result, item: plugin }: CardWrapper) { plugin.usePluginState(); + const cardContextValue = useMemo(() => ({ plugin, result }), [plugin, result]); + return ( - + - {/* */} @@ -135,11 +146,9 @@ export default function PluginCard({ item: plugin }: CardWrapper<UnifiedPluginMo </Stack> </View> </View> - <Text variant="text-md/medium"> - {plugin.description} - </Text> + <Description /> </Stack> </Card> - </PluginContext.Provider> + </CardContext.Provider> ); } diff --git a/src/core/ui/settings/pages/Themes/index.tsx b/src/core/ui/settings/pages/Themes/index.tsx index 6441df9..f3e14f4 100644 --- a/src/core/ui/settings/pages/Themes/index.tsx +++ b/src/core/ui/settings/pages/Themes/index.tsx @@ -17,7 +17,7 @@ export default function Themes() { searchKeywords={[ "manifest.name", "manifest.description", - p => p.manifest.authors?.map((a: Author) => a.name).join() + p => p.manifest.authors?.map((a: Author) => a.name).join(", ") ]} fetchFunction={installTheme} items={Object.values(themes)}