Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Ability for plugins to have a settings menu #183

Open
2 tasks done
tddebart opened this issue Dec 14, 2024 · 3 comments
Open
2 tasks done

[Feature] Ability for plugins to have a settings menu #183

tddebart opened this issue Dec 14, 2024 · 3 comments
Labels
enhancement New feature or request ongoing This issue is being worked on

Comments

@tddebart
Copy link
Contributor

Before Requesting

  • I found no existing issue matching my feature request
  • This request is related to Millennium, and not a request for a specific theme/addon

Describe the feature you'd like!

It would be nice for plugins to also have a settings menu like themes currently have. It could even have the same json configuration but still allow plugins to render their own settings tabs.
That way you can have an easy way to create settings and also allow people to create their own custom setting tabs for more complex stuff.
Saw there already was a pluginSelf.renderPluginSettings but this seems to only render a broken settings button on the plugin page.
Might try to implement this myself, but no promises.

Anything else?

No response

@tddebart tddebart added the enhancement New feature or request label Dec 14, 2024
@tddebart
Copy link
Contributor Author

tddebart commented Dec 14, 2024

I was personally thinking of making the config something like what is done in celeste modding by using ts decorators. As this makes it quite easy on the plugin side to setup the settings and also looks quite nice.
This does mean that "experimentalDecorators": true, will need to be added to the tsconfig. Otherwise the decorators wont work and it will also add a small piece of boilerplate code to the compiled js file to make the decorators work. But luckily it is quite a small dependency.
I made a small proof of concept:

Code
//SettingTypes.ts
enum SettingType {
    Unknown,
    NumberInput,
    TextInput,
    Dropdown,
    Toggle,
    Slider,
    Color,
}
type SliderOptions = SettingOptions & {
    min: number;
    max: number;
}

type SettingOptions = {
    name: string;
}

type Setting = {
    type: SettingType;
    options: SettingOptions | SliderOptions;
}

interface SettingsData {
    settings: { [key: string]: Setting };
}

export {SettingType, Setting, SettingsData};
// SettingsDecorators.ts
import { SettingsData, SettingType } from "./SettingTypes";

function resolveSettingType(type: any): SettingType {
    switch (type) {
        case Number:
            return SettingType.NumberInput;
        case String:
            return SettingType.TextInput;
        case Boolean:
            return SettingType.Toggle;
        default:
            return SettingType.Unknown;
    }
}

export function DefineSetting<T>(options: {name: string}, type: T) {
    return function (target: SettingsData, propertyKey: string) {
        if (!target.settings) {
            target.settings = {};
        }

        target.settings[propertyKey] = {
            type: resolveSettingType(type),
            options: {...options},
        };
    };
}

export function SettingRange(options: { min: number, max: number }) {
    return function (target: SettingsData, propertyKey: string) {
        const setting = target.settings[propertyKey];
        setting.options = {...setting.options, ...options};
    };
}

// etc for the other setting types

And then the per plugin settings class

//ExampleSettingsData.ts
import { DefineSetting, SettingRange } from "./SettingsDecorators";
import { Setting, SettingsData } from "./SettingTypes";

export class ExampleSettingsData implements SettingsData {
   settings: { [key: string]: Setting; };

   @SettingRange({ min: 0, max: 100 })
   @DefineSetting({ name: "My slider" }, Number)
   public mySlider: number = 0;

   @DefineSetting({ name: "My text input" }, String)
   public textInput: string = "";
}   

And then maybe some function like RenderSettings that would allow you to render the settings page yourself with react.

@shdwmtr
Copy link
Owner

shdwmtr commented Dec 15, 2024

Ah, I saw your PR first, and then this; which all makes more sense now.

Thanks for the POC --- I think its a great idea, I completely forgot decorators existed.

I'll open a development branch for this, and I can assist with implementation!

@shdwmtr shdwmtr added the ongoing This issue is being worked on label Dec 15, 2024
@shdwmtr
Copy link
Owner

shdwmtr commented Dec 15, 2024

Also make sure to use Millenium.exposeObj({ SettingsDataStuff }) instead of pluginSelf (if you ever use it) as it's more idiomatic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request ongoing This issue is being worked on
Projects
None yet
Development

When branches are created from issues, their pull requests are automatically linked.

2 participants