mirror of
https://github.com/modrinth/code.git
synced 2026-08-26 17:44:50 +00:00
feat: moderation settings (#6895)
* feat: moderation settings * chore: move moderation specific feature flag to settings * feat: force open collapsed regions if opened in new tab * chore: remove unused field * chore: run prepr
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import {
|
||||
type KeybindDefinition,
|
||||
type KeybindListener,
|
||||
matchesKeybind,
|
||||
type ModerationContext,
|
||||
normalizeKeybind,
|
||||
} from '../types/keybinds.ts'
|
||||
import keybinds from '../data/keybinds.ts'
|
||||
|
||||
function normalizeKeybinds(
|
||||
keybind: KeybindDefinition | KeybindDefinition[] | string | string[],
|
||||
): KeybindDefinition[] {
|
||||
return Array.isArray(keybind) ? keybind.map(normalizeKeybind) : [normalizeKeybind(keybind)]
|
||||
}
|
||||
|
||||
export type KeybindListenerWithDefault = KeybindListener & {
|
||||
keybind: KeybindDefinition[]
|
||||
defaultKeybind: KeybindDefinition[]
|
||||
}
|
||||
|
||||
export class Keybinds {
|
||||
private readonly configured: { [id: string]: KeybindDefinition[] } = {}
|
||||
|
||||
constructor(keybinds: { [id: string]: KeybindDefinition[] }) {
|
||||
this.configured = keybinds
|
||||
}
|
||||
|
||||
*[Symbol.iterator](): IterableIterator<[string, KeybindListenerWithDefault]> {
|
||||
for (const [id, keybind] of Object.entries(keybinds)) {
|
||||
yield [
|
||||
id,
|
||||
{
|
||||
...keybind,
|
||||
keybind: this.configured[id] ?? normalizeKeybinds(keybind.keybind),
|
||||
defaultKeybind: normalizeKeybinds(keybind.keybind),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
set(id: string, keybind: KeybindDefinition | KeybindDefinition[] | string | string[]): void {
|
||||
this.configured[id] = normalizeKeybinds(keybind)
|
||||
}
|
||||
|
||||
handle(event: KeyboardEvent, ctx: ModerationContext): boolean {
|
||||
if (
|
||||
event.target instanceof HTMLInputElement ||
|
||||
event.target instanceof HTMLTextAreaElement ||
|
||||
(event.target as HTMLElement)?.closest('.cm-editor') ||
|
||||
(event.target as HTMLElement)?.classList?.contains('cm-content') ||
|
||||
(event.target as HTMLElement)?.classList?.contains('cm-line')
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
for (const [id, keybind] of Object.entries(keybinds)) {
|
||||
if (ctx.scope !== keybind.scope) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (keybind.enabled && !keybind.enabled(ctx as any)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const definitions = this.configured[id] ?? normalizeKeybinds(keybind.keybind)
|
||||
const matches = definitions.some((def) => matchesKeybind(event, def))
|
||||
|
||||
if (matches) {
|
||||
keybind.action(ctx as any)
|
||||
|
||||
const shouldPrevent = definitions.some((def) => def.preventDefault !== false)
|
||||
if (shouldPrevent) {
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { SettingDefinitionBase } from '../types/settings.ts'
|
||||
|
||||
export class Settings {
|
||||
private readonly settings: { [id: string]: any }
|
||||
private readonly onChange: () => void
|
||||
|
||||
constructor(
|
||||
settings: { [id: string]: any } | undefined = undefined,
|
||||
onChange: () => void = () => {},
|
||||
) {
|
||||
this.settings = settings || {}
|
||||
this.onChange = onChange
|
||||
}
|
||||
|
||||
get<T>(definition: SettingDefinitionBase<T>): T {
|
||||
return this.settings[definition.id] ?? definition.default
|
||||
}
|
||||
|
||||
set<T>(definition: SettingDefinitionBase<T>, value?: T): void {
|
||||
const previous = this.settings[definition.id] ?? definition.default
|
||||
this.settings[definition.id] = value
|
||||
definition.onChange?.(previous, value ?? definition.default)
|
||||
this.onChange()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user