Improve relations sheet style and behavior

This commit is contained in:
PalmDevs 2026-08-13 01:45:38 +07:00
parent 0178bedd12
commit 9959ff7513
No known key found for this signature in database
GPG key ID: 6FAE8F8677ACA8BA
3 changed files with 123 additions and 6 deletions

View file

@ -8,8 +8,10 @@ const PuzzlePieceIcon = getAssetIdByName('PuzzlePieceIcon', 'png')!
export function PluginIcon({ export function PluginIcon({
icon, icon,
size = 20, size = 20,
danger = false,
}: { }: {
icon?: string icon?: string
danger?: boolean
size?: number size?: number
}) { }) {
const styles = usePluginIconStyles() const styles = usePluginIconStyles()
@ -26,7 +28,11 @@ export function PluginIcon({
? (getAssetIdByName(icon) ?? PuzzlePieceIcon) ? (getAssetIdByName(icon) ?? PuzzlePieceIcon)
: PuzzlePieceIcon : PuzzlePieceIcon
} }
style={[!dataUrl && styles.icon, { width: size, height: size }]} style={[
!dataUrl && styles.icon,
danger && styles.danger,
{ width: size, height: size },
]}
/> />
) )
} }
@ -35,4 +41,7 @@ const usePluginIconStyles = Design.createStyles({
icon: { icon: {
tintColor: Tokens.default.colors.TEXT_DEFAULT, tintColor: Tokens.default.colors.TEXT_DEFAULT,
}, },
danger: {
tintColor: Tokens.default.colors.TEXT_FEEDBACK_CRITICAL,
},
}) })

View file

@ -19,6 +19,7 @@ import {
isPluginPendingUpdate, isPluginPendingUpdate,
isPluginStartable, isPluginStartable,
PluginFlags, PluginFlags,
pList,
runPluginLate, runPluginLate,
stopPlugin, stopPlugin,
} from '@revenge-mod/plugins/_' } from '@revenge-mod/plugins/_'
@ -197,8 +198,15 @@ function AdvancedSection({ plugin }: { plugin: AnyPlugin }) {
`plugin-deps-${id}`, `plugin-deps-${id}`,
{ {
title: `Dependencies of ${name}`, title: `Dependencies of ${name}`,
unsatisfiedTitle: `Unsatisfied dependencies of ${name}`,
unsatisfiedPlugins:
meta.unsatisfiedOptionalDependencies.map(
id => pList.get(id) ?? id,
),
plugins: dependencies, plugins: dependencies,
dependencyMap: plugin.manifest.dependencies!,
}, },
'stack',
) )
}} }}
/> />
@ -216,6 +224,7 @@ function AdvancedSection({ plugin }: { plugin: AnyPlugin }) {
title: `Dependents of ${name}`, title: `Dependents of ${name}`,
plugins: dependents, plugins: dependents,
}, },
'stack',
) )
}} }}
/> />

View file

@ -1,31 +1,130 @@
import { TableRowAssetIcon } from '@revenge-mod/components'
import { Design } from '@revenge-mod/discord/design' import { Design } from '@revenge-mod/discord/design'
import { Clipboard } from '@revenge-mod/externals/react-native-clipboard'
import { formatVersion } from '@revenge-mod/plugins/utils'
import { PluginIcon } from './PluginIcon'
import type { DiscordModules } from '@revenge-mod/discord/types'
import type { AnyPlugin } from '@revenge-mod/plugins/_' import type { AnyPlugin } from '@revenge-mod/plugins/_'
import type {
PluginDependency,
PluginManifest,
} from '@revenge-mod/plugins/types'
const { ActionSheet, Stack, TableRow, TableRowGroup } = Design const { ActionSheet, Stack, TableRow, TableRowGroup } = Design
export interface PluginRelationsListActionSheetProps { export interface PluginRelationsListActionSheetProps {
title: string title: string
unsatisfiedTitle?: string
dependencyMap?: NonNullable<PluginManifest['dependencies']>
plugins: AnyPlugin[] plugins: AnyPlugin[]
unsatisfiedPlugins?: Array<string | AnyPlugin>
}
interface PluginRowProps {
plugin: AnyPlugin
variant?: DiscordModules.Components.TableRowProps['variant']
dependency?: PluginDependency
showInstalledVersion?: boolean
}
const formatDependencyRequirement = (dependency: PluginDependency) =>
`(${dependency.version ?? '*'} ${dependency.optional ? 'optional' : 'required'})`
function PluginRow({
plugin,
dependency,
variant,
showInstalledVersion = false,
}: PluginRowProps) {
const { id, name, version, icon } = plugin.manifest
const installedVersion = showInstalledVersion
? `@${formatVersion(version)}`
: ''
const depRequirement = dependency
? ` ${formatDependencyRequirement(dependency)}`
: ''
const subLabel = `${id}${installedVersion}${depRequirement}`
return (
<TableRow
icon={
<PluginIcon
danger={variant === 'danger'}
icon={icon ?? undefined}
size={24}
/>
}
label={name}
subLabel={subLabel}
variant={variant}
onPress={() => Clipboard.setString(subLabel)}
/>
)
} }
export default function PluginRelationsListActionSheet({ export default function PluginRelationsListActionSheet({
title, title,
unsatisfiedTitle,
dependencyMap,
plugins, plugins,
unsatisfiedPlugins,
}: PluginRelationsListActionSheetProps) { }: PluginRelationsListActionSheetProps) {
return ( return (
<ActionSheet> <ActionSheet>
<Stack spacing={24} style={{ paddingTop: 8 }}> <Stack spacing={24} style={{ paddingTop: 8 }}>
<TableRowGroup title={title}> <TableRowGroup title={title}>
{plugins.map(plugin => ( {plugins.map(plugin => (
<TableRow <PluginRow
key={plugin.manifest.id} key={plugin.manifest.id}
icon={<TableRowAssetIcon name="ListBulletsIcon" />} plugin={plugin}
label={plugin.manifest.name} // biome-ignore lint/suspicious/noNonNullAssertedOptionalChain: Can't be undefined
subLabel={plugin.manifest.id} dependency={dependencyMap?.[plugin.manifest.id]!}
showInstalledVersion
/> />
))} ))}
</TableRowGroup> </TableRowGroup>
{Boolean(unsatisfiedPlugins?.length) && (
<TableRowGroup title={unsatisfiedTitle}>
{unsatisfiedPlugins?.map(plugin => {
if (typeof plugin === 'string') {
// biome-ignore lint/suspicious/noNonNullAssertedOptionalChain: Can't be undefined
const dep = dependencyMap?.[plugin]!
return (
<TableRow
key={plugin}
icon={
<PluginIcon
icon="CircleQuestionIcon"
danger
size={24}
/>
}
label={plugin}
subLabel={`${plugin} (not installed) ${formatDependencyRequirement(dep)}`}
variant="danger"
onPress={() =>
Clipboard.setString(plugin)
}
/>
)
}
return (
<PluginRow
key={plugin.manifest.id}
plugin={plugin}
variant="danger"
dependency={
// biome-ignore lint/suspicious/noNonNullAssertedOptionalChain: Can't be undefined
dependencyMap?.[plugin.manifest.id]!
}
/>
)
})}
</TableRowGroup>
)}
</Stack> </Stack>
</ActionSheet> </ActionSheet>
) )