diff --git a/package.json b/package.json index 6f9804e..89ab1d6 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@typescript-eslint/eslint-plugin": "^7.1.1", "@typescript-eslint/parser": "^7.1.1", "@typescript-eslint/typescript-estree": "^7.1.1", + "chalk": "^5.3.0", "esbuild": "^0.20.2", "eslint": "^8.57.0", "eslint-plugin-import-alias": "^1.2.0", @@ -39,8 +40,7 @@ "yargs-parser": "^21.1.1" }, "dependencies": { - "chalk": "^5.3.0", - "fuzzysort": "^2.0.4", + "fuzzysort": "^3.0.1", "spitroast": "^1.4.4" }, "pnpm": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8c3124b..9ff9efa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,12 +5,9 @@ settings: excludeLinksFromLockfile: false dependencies: - chalk: - specifier: ^5.3.0 - version: 5.3.0 fuzzysort: - specifier: ^2.0.4 - version: 2.0.4 + specifier: ^3.0.1 + version: 3.0.1 spitroast: specifier: ^1.4.4 version: 1.4.4 @@ -55,6 +52,9 @@ devDependencies: '@typescript-eslint/typescript-estree': specifier: ^7.1.1 version: 7.1.1(typescript@5.4.5) + chalk: + specifier: ^5.3.0 + version: 5.3.0 esbuild: specifier: ^0.20.2 version: 0.20.2 @@ -976,7 +976,7 @@ packages: /chalk@5.3.0: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - dev: false + dev: true /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} @@ -1445,8 +1445,8 @@ packages: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true - /fuzzysort@2.0.4: - resolution: {integrity: sha512-Api1mJL+Ad7W7vnDZnWq5pGaXJjyencT+iKGia2PlHUcSsSzWwIQ3S1isiMpwpavjYtGd2FzhUIhnnhOULZgDw==} + /fuzzysort@3.0.1: + resolution: {integrity: sha512-jpiSrv+j2GwtI13z3vzdBAD5m7iVH23spSZwJrD657dfr6jUV2Jyc5YuSPKirmTp9OqnJbHudPIBGIId1bCWmA==} dev: false /get-intrinsic@1.2.4: diff --git a/src/core/ui/components/AddonCard.tsx b/src/core/ui/components/AddonCard.tsx index c1d0651..47839d4 100644 --- a/src/core/ui/components/AddonCard.tsx +++ b/src/core/ui/components/AddonCard.tsx @@ -71,7 +71,6 @@ interface OverflowAction extends Action { export interface CardWrapper { item: T; - index: number; } interface CardProps { diff --git a/src/core/ui/components/AddonPage.tsx b/src/core/ui/components/AddonPage.tsx index b0c9fa6..fb29313 100644 --- a/src/core/ui/components/AddonPage.tsx +++ b/src/core/ui/components/AddonPage.tsx @@ -4,15 +4,16 @@ import { requireAssetIndex } from "@lib/api/assets"; import { useProxy } from "@lib/api/storage"; import { settings } from "@lib/settings"; import { HTTP_REGEX_MULTI } from "@lib/utils/constants"; +import { findByProps } from "@metro"; import { clipboard } from "@metro/common"; import { FloatingActionButton, HelpMessage } from "@metro/common/components"; import { showInputAlert } from "@ui/alerts"; import { ErrorBoundary, Search } from "@ui/components"; import fuzzysort from "fuzzysort"; -import { createContext } from "react"; -import { FlatList, View } from "react-native"; +import { useMemo } from "react"; +import { View } from "react-native"; -export const RemoveModeContext = createContext(false); +type SearchKeywords = Array string)>; interface AddonPageProps { title: string; @@ -21,51 +22,54 @@ interface AddonPageProps { safeModeMessage: string; safeModeExtras?: JSX.Element | JSX.Element[]; card: React.ComponentType>; - isRemoveMode?: boolean; + searchKeywords: SearchKeywords; onFABPress?: () => void; } -function getItemsByQuery["items"][string]>(items: T[], query: string): T[] { - if (!query) return items; - - return fuzzysort.go(query, items, { - keys: [ - "id", - "name", - "manifest.name", - "manifest.description", - "manifest.authors.0.name", - "manifest.authors.1.name" - ] - }).map(r => r.obj); -} +// TODO: Move to somewhere else +const { FlashList } = findByProps("FlashList"); export default function AddonPage({ card: CardComponent, ...props }: AddonPageProps) { - useProxy(props.items); useProxy(settings); + useProxy(props.items); const [search, setSearch] = React.useState(""); + const items = useMemo(() => { + return Object.values(props.items).filter(i => typeof i === "object"); + }, [props.items]); + + const data = useMemo(() => { + if (!search) return items; + return fuzzysort.go(search, items, { keys: props.searchKeywords }).map(r => r.obj); + }, [items, search]); + + const headerElement = useMemo(() => ( + + {settings.safeMode?.enabled && + {props.safeModeMessage} + {props.safeModeExtras} + } + setSearch(v.toLowerCase())} + placeholder={Strings.SEARCH} + /> + + ), []); + return ( - {/* TODO: Implement better searching than just by ID */} - - {settings.safeMode?.enabled && - {props.safeModeMessage} - {props.safeModeExtras} - } - setSearch(v.toLowerCase())} - placeholder={Strings.SEARCH} - /> - } - style={{ paddingHorizontal: 10, paddingTop: 10 }} - contentContainerStyle={{ paddingBottom: 90, paddingHorizontal: 5, gap: 12 }} - data={getItemsByQuery(Object.values(props.items).filter(i => typeof i === "object"), search)} - renderItem={({ item, index }) => - - } + ( + + + + )} /> title={Strings.FONTS} + searchKeywords={["name", "description"]} fetchFunction={installFont} items={fonts as Record} safeModeMessage={Strings.SAFE_MODE_NOTICE_FONTS} diff --git a/src/core/ui/settings/pages/Plugins/PluginCard.tsx b/src/core/ui/settings/pages/Plugins/PluginCard.tsx index 839ebdc..4747fca 100644 --- a/src/core/ui/settings/pages/Plugins/PluginCard.tsx +++ b/src/core/ui/settings/pages/Plugins/PluginCard.tsx @@ -6,7 +6,7 @@ import { showSheet } from "@lib/ui/sheets"; import { lazyDestructure } from "@lib/utils/lazy"; import { findByProps } from "@metro"; import { NavigationNative, tokens } from "@metro/common"; -import { Card, PressableScale, Stack, TableSwitch, Text } from "@metro/common/components"; +import { Card, IconButton, Stack, TableSwitch, Text } from "@metro/common/components"; import { createContext, useContext } from "react"; import { Image, View } from "react-native"; @@ -41,12 +41,12 @@ function Title() { return {icon && <> + {/* TODO: Image appears invisible for some devices/installs */} {" "} @@ -65,7 +65,7 @@ function Status() { if (!plugin.error) return null; return - + ; } -function ActionIcon(props: { - onPress: () => void; - icon: string; - disabled?: boolean; -}) { - const styles = usePluginCardStyles(); - - return - !props.disabled && props.onPress()}> - - - - - ; -} - export default function PluginCard({ item: plugin }: CardWrapper) { const navigation = NavigationNative.useNavigation(); - const styles = usePluginCardStyles(); useProxy(plugin); @@ -107,24 +87,28 @@ export default function PluginCard({ item: plugin }: CardWrapper) { - - + + <Authors /> - </Stack> - <View style={{ marginLeft: "auto" }}> + </View> + <View> <Stack spacing={12} direction="horizontal"> <View style={{ flexDirection: "row", gap: 6 }}> - <ActionIcon - icon="WrenchIcon" + <IconButton + size="sm" + variant="secondary" + icon={requireAssetIndex("WrenchIcon")} disabled={!getSettings(plugin.id)} onPress={() => navigation.push("VendettaCustomPage", { title: plugin.manifest.name, render: getSettings(plugin.id), })} /> - <ActionIcon - icon="CircleInformationIcon-primary" + <IconButton + size="sm" + variant="secondary" + icon={requireAssetIndex("CircleInformationIcon-primary")} onPress={() => void showSheet( "PluginInfoActionSheet", import("./sheets/PluginInfoActionSheet"), diff --git a/src/core/ui/settings/pages/Plugins/index.tsx b/src/core/ui/settings/pages/Plugins/index.tsx index bdc7538..db9b1ce 100644 --- a/src/core/ui/settings/pages/Plugins/index.tsx +++ b/src/core/ui/settings/pages/Plugins/index.tsx @@ -4,6 +4,7 @@ import PluginCard from "@core/ui/settings/pages/Plugins/PluginCard"; import { useProxy } from "@lib/api/storage"; import { BunnyPlugin, installPlugin, plugins } from "@lib/managers/plugins"; import { settings } from "@lib/settings"; +import { Author } from "@lib/utils/types"; export default function Plugins() { useProxy(settings); @@ -11,6 +12,11 @@ export default function Plugins() { return ( <AddonPage<BunnyPlugin> title={Strings.PLUGINS} + searchKeywords={[ + "manifest.name", + "manifest.description", + p => p.manifest.authors?.map((a: Author) => a.name).join() + ]} fetchFunction={installPlugin} items={plugins} safeModeMessage={Strings.SAFE_MODE_NOTICE_PLUGINS} diff --git a/src/core/ui/settings/pages/Plugins/usePluginCardStyles.ts b/src/core/ui/settings/pages/Plugins/usePluginCardStyles.ts index 592270b..c575fee 100644 --- a/src/core/ui/settings/pages/Plugins/usePluginCardStyles.ts +++ b/src/core/ui/settings/pages/Plugins/usePluginCardStyles.ts @@ -2,22 +2,9 @@ import { createStyles } from "@lib/ui/styles"; import { tokens } from "@metro/common"; export const usePluginCardStyles = createStyles({ - pluginIcon: { + smallIcon: { tintColor: tokens.colors.LOGO_PRIMARY, height: 18, width: 18, - }, - actionIconContainer: { - width: 32, - height: 32, - borderRadius: 20, - backgroundColor: tokens.colors.BACKGROUND_ACCENT, - justifyContent: "center", - alignItems: "center", - }, - actionIcon: { - tintColor: tokens.colors.INTERACTIVE_NORMAL, - width: 18, - height: 18, - }, + } }); diff --git a/src/core/ui/settings/pages/Themes/index.tsx b/src/core/ui/settings/pages/Themes/index.tsx index 627d354..98fcf6e 100644 --- a/src/core/ui/settings/pages/Themes/index.tsx +++ b/src/core/ui/settings/pages/Themes/index.tsx @@ -4,6 +4,7 @@ import ThemeCard from "@core/ui/settings/pages/Themes/ThemeCard"; import { useProxy } from "@lib/api/storage"; import { installTheme, Theme, themes } from "@lib/managers/themes"; import { settings } from "@lib/settings"; +import { Author } from "@lib/utils/types"; import { Button } from "@metro/common/components"; export default function Themes() { @@ -13,6 +14,11 @@ export default function Themes() { return ( <AddonPage<Theme> title={Strings.THEMES} + searchKeywords={[ + "manifest.name", + "manifest.description", + p => p.manifest.authors?.map((a: Author) => a.name).join() + ]} fetchFunction={installTheme} items={themes} safeModeMessage={formatString("SAFE_MODE_NOTICE_THEMES", { enabled: Boolean(settings.safeMode?.currentThemeId) })} diff --git a/src/lib/ui/components/Search.tsx b/src/lib/ui/components/Search.tsx index fb8181c..5f3b75d 100644 --- a/src/lib/ui/components/Search.tsx +++ b/src/lib/ui/components/Search.tsx @@ -25,12 +25,12 @@ export default ({ onChangeText, placeholder, style }: SearchProps) => { return <ErrorBoundary> <View style={style}> <TextInput - grow - isClearable + grow={true} + isClearable={true} leadingIcon={SearchIcon} placeholder={placeholder ?? Strings.SEARCH} onChange={onChange} - returnKeyType={"search"} + returnKeyType="search" size="md" autoCapitalize="none" autoCorrect={false}