export enum SettingType { String = "string", Boolean = "boolean", Enum = "enum", Float = "float", Integer = "integer", Code = "code", } export type Setting = { title: string; description: string; notImplemented?: boolean; type: SettingType; value: unknown; page: SettingPages; }; export type StringSetting = Setting & { type: SettingType.String; value: string; }; export type BooleanSetting = Setting & { type: SettingType.Boolean; value: boolean; }; export type EnumSetting = Setting & { type: SettingType.Enum; value: string; options: string[]; }; export type FloatSetting = Setting & { type: SettingType.Float; value: number; min: number; max: number; step: number; }; export type IntegerSetting = Setting & { type: SettingType.Integer; value: number; min: number; max: number; step: number; }; export type CodeSetting = Setting & { type: SettingType.Code; value: string; language: string; }; export enum SettingPages { Account = "account", Behaviour = "behaviour", Advanced = "advanced", Appearance = "appearance", } export enum SettingIds { Mfm = "mfm", CustomCSS = "custom-css", Theme = "theme", CustomEmojis = "custom-emojis", ShowContentWarning = "show-content-warning", PopupAvatarHover = "popup-avatar-hover", InfiniteScroll = "infinite-scroll", ConfirmDelete = "confirm-delete", ConfirmFollow = "confirm-follow", ConfirmReblog = "confirm-reblog", ConfirmFavourite = "confirm-favourite", } export const settings: Record = { [SettingIds.Mfm]: { title: "Render MFM", description: "Render Misskey-Flavoured Markdown", type: SettingType.Boolean, value: false, page: SettingPages.Behaviour, notImplemented: true, } as BooleanSetting, [SettingIds.CustomCSS]: { title: "Custom CSS", description: "Custom CSS for the UI", type: SettingType.Code, value: "", language: "css", page: SettingPages.Appearance, } as CodeSetting, [SettingIds.Theme]: { title: "Theme", description: "UI theme", type: SettingType.Enum, value: "dark", options: ["light", "dark"], page: SettingPages.Appearance, } as EnumSetting, [SettingIds.CustomEmojis]: { title: "Render Custom Emojis", description: "Render custom emojis", type: SettingType.Boolean, value: true, page: SettingPages.Behaviour, } as BooleanSetting, [SettingIds.ShowContentWarning]: { title: "Show Content Warning", description: "Show content warnings on notes marked sensitive/spoiler", type: SettingType.Boolean, value: true, page: SettingPages.Behaviour, } as BooleanSetting, [SettingIds.PopupAvatarHover]: { title: "Popup Profile Hover", description: "Show profile popup when hovering over a user's avatar", type: SettingType.Boolean, value: true, page: SettingPages.Behaviour, } as BooleanSetting, [SettingIds.InfiniteScroll]: { title: "Infinite Scroll", description: "Automatically load more notes when reaching the bottom of the page", type: SettingType.Boolean, value: true, page: SettingPages.Behaviour, } as BooleanSetting, [SettingIds.ConfirmDelete]: { title: "Confirm Delete", description: "Confirm before deleting a note", type: SettingType.Boolean, value: false, page: SettingPages.Behaviour, notImplemented: true, } as BooleanSetting, [SettingIds.ConfirmFollow]: { title: "Confirm Follow", description: "Confirm before following/unfollowing a user", type: SettingType.Boolean, value: false, page: SettingPages.Behaviour, notImplemented: true, } as BooleanSetting, [SettingIds.ConfirmReblog]: { title: "Confirm Reblog", description: "Confirm before reblogging a note", type: SettingType.Boolean, value: false, page: SettingPages.Behaviour, notImplemented: true, } as BooleanSetting, [SettingIds.ConfirmFavourite]: { title: "Confirm Favourite", description: "Confirm before favouriting a note", type: SettingType.Boolean, value: false, page: SettingPages.Behaviour, notImplemented: true, } as BooleanSetting, }; export const getSettingsForPage = (page: SettingPages): Partial => { return Object.fromEntries( Object.entries(settings).filter(([, setting]) => setting.page === page), ); }; /** * Merge a partly defined Settings object with the default settings * Useful when there is an update to the settings in the backend */ export const mergeSettings = ( settingsToMerge: Record, ): Settings => { const finalSettings = structuredClone(settings); for (const [key, value] of Object.entries(settingsToMerge)) { if (key in settings) { finalSettings[key as SettingIds].value = value; } } return finalSettings; }; export type Settings = typeof settings;