feat(lib/discord): add initial impl of discord/ui/settings

This commit is contained in:
PalmDevs 2025-05-01 18:21:10 +07:00
parent c379d815a6
commit ca94e6122b
No known key found for this signature in database
GPG key ID: 6FAE8F8677ACA8BA
7 changed files with 128 additions and 0 deletions

View file

@ -15,8 +15,17 @@
"./preinit": {
"default": "./src/preinit.ts"
},
"./ui": {
"default": "./src/ui/index.ts"
},
"./ui/settings": {
"default": "./src/ui/settings/index.ts"
},
"./types": {
"types": "./types/index.ts"
},
"./_/ui/settings": {
"default": "./src/ui/settings/_internal.ts"
}
}
}

View file

@ -7,6 +7,7 @@ export * from './preinit'
export * as flux from './flux'
export * as native from './native'
export * as ui from './ui'
// ../discord_common/js/shared/Logger.tsx
export const Logger = lookupModule(byName<DiscordModules.Logger>('Logger'))!

View file

@ -0,0 +1 @@
export * as settings from './settings'

View file

@ -0,0 +1,11 @@
import type { SettingsRowConfig, SettingsSection } from './api'
export const _suiData = {
// Settings that are in the Overview screen
sections: {},
// Settings that are not in the Overview screen (submenus, hidden, etc.)
settings: {},
} as {
sections: Record<string, SettingsSection>
settings: Record<string, SettingsRowConfig>
}

View file

@ -0,0 +1,53 @@
import { _suiData } from './_internal'
import type { ComponentType, ReactNode } from 'react'
export function addSettingsSection(key: string, section: SettingsSection) {
_suiData.sections[key] = section
return () => delete _suiData.sections[key]
}
export function addSettingsRow(key: string, row: SettingsRowConfig) {
_suiData.settings[key] = row
return () => delete _suiData.settings[key]
}
export function addSettingsRowToSection(sectionKey: string, rowKey: string, row: SettingsRowConfig) {
if (!_suiData.sections[sectionKey]) throw new Error(`Section "${sectionKey}" does not exist`)
_suiData.sections[sectionKey].settings[rowKey] = row
return () => delete _suiData.sections[sectionKey].settings[rowKey]
}
export interface SettingsSection {
label: string
settings: Record<string, SettingsRowConfig>
}
interface BaseSettingsRowConfig {
title: () => string
parent: string | null
unsearchable?: boolean
IconComponent?: () => ReactNode
usePredicate?: () => boolean
useTrailing?: () => ReactNode
useDescription?: () => string
useIsDisabled?: () => boolean
}
export interface PressableSettingsRowConfig extends BaseSettingsRowConfig {
type: 'pressable'
onPress?: () => void
}
export interface ToggleSettingsRowConfig extends BaseSettingsRowConfig {
type: 'toggle'
useValue?: () => boolean
onValueChange?: (value: boolean) => void
}
export interface RouteSettingsRowConfig extends BaseSettingsRowConfig {
type: 'route'
screen: { route: string; getComponent(): ComponentType }
}
export type SettingsRowConfig = PressableSettingsRowConfig | ToggleSettingsRowConfig | RouteSettingsRowConfig

View file

@ -0,0 +1,49 @@
import { lookupModule } from '@revenge-mod/modules/finders'
import { byDependencies, byProps, looseDeps, moduleStateAware, relativeDep } from '@revenge-mod/modules/finders/filters'
import { ReactJsxRuntimeModuleId, ReactModuleId, ReactNativeModuleId } from '@revenge-mod/react'
import { proxify } from '@revenge-mod/utils/proxy'
import type { ComponentType, ReactNode } from 'react'
export let SettingListRenderer: SettingListRenderer = proxify(
() => {
const module = lookupModule(
moduleStateAware(
byProps('SettingsList'),
byDependencies(
// biome-ignore lint/suspicious/noSparseArray: don't care
looseDeps([
ReactModuleId,
ReactNativeModuleId,
relativeDep(1),
relativeDep(2),
,
ReactJsxRuntimeModuleId,
]),
),
),
{
includeUninitialized: true,
},
) as SettingListRenderer | undefined
if (module) {
// This allows the Proxy instance to be garbage collected
// after the module is initialized.
SettingListRenderer = module
gc()
return module
}
},
{
cache: true,
hint: 'object',
},
)!
export interface SettingListRenderer {
SettingsList: ComponentType<{
ListHeaderComponent: ComponentType
sections: Array<{ label: string | ReactNode; settings: string[] }>
}>
}

View file

@ -0,0 +1,4 @@
import { _suiData } from './_internal'
export * from './api'
export * from './common'