This commit is contained in:
TheGiddyLimit
2024-06-23 22:13:57 +01:00
parent ed9833eefc
commit e5844f8a3f
279 changed files with 38254 additions and 7675 deletions

View File

@@ -0,0 +1,10 @@
export class UtilConfigHelpers {
static packSettingId (groupId, configId) {
return `${groupId}.${configId}`;
}
static unpackSettingId (settingId) {
const [groupId, configId] = settingId.split(".");
return {groupId, configId};
}
}

View File

@@ -0,0 +1,38 @@
export class ConfigSettingsGroup {
constructor (
{
groupId,
name,
configSettings,
},
) {
this._groupId = groupId;
this._name = name;
this._configSettings = configSettings;
this._configSettings
.forEach(configSetting => configSetting.setGroupId(this._groupId));
}
get groupId () { return this._groupId; }
render (rdState, {isLast = false} = {}) {
const wrpRows = ee`<div></div>`;
ee`<div class="w-100">
<h4>${this._name}</h4>
${wrpRows}
${isLast ? null : `<hr class="hr-3 mb-1">`}
</div>`
.appendTo(rdState.wrp);
this._configSettings
.forEach(configSetting => configSetting.render(rdState, wrpRows));
}
mutDefaults (config) {
const group = config[this._groupId] ||= {};
this._configSettings
.forEach(configSetting => configSetting.mutDefaults(group));
}
}

View File

@@ -0,0 +1,66 @@
import {SETTINGS_GROUPS} from "./utils-config-registry.js";
import {UtilConfigHelpers} from "./util-config-helpers.js";
export class VetoolsConfig {
static _STORAGE_KEY = "config";
static _CONFIG = null;
static _init () {
if (this._CONFIG) return;
this._CONFIG = StorageUtil.syncGet(this._STORAGE_KEY) || {};
SETTINGS_GROUPS
.forEach(settingsGroup => settingsGroup.mutDefaults(this._CONFIG));
}
/* -------------------------------------------- */
static get (groupId, configId) {
this._init();
return MiscUtil.get(this._CONFIG, groupId, configId);
}
static set (groupId, configId, val) {
this._init();
MiscUtil.set(this._CONFIG, groupId, configId, val);
this._save();
}
/* -------------------------------------------- */
static _save () {
StorageUtil.syncSet(this._STORAGE_KEY, this._CONFIG);
}
static _saveThrottled = MiscUtil.throttle(this._save.bind(this), 50);
/* -------------------------------------------- */
static getConfigComp () {
this._init();
const state = {};
Object.entries(this._CONFIG)
.forEach(([groupId, groupTo]) => {
Object.entries(groupTo)
.forEach(([configId, val]) => {
state[UtilConfigHelpers.packSettingId(groupId, configId)] = MiscUtil.copyFast(val);
});
});
const comp = BaseComponent.fromObject(state, "*");
comp._addHookAllBase(() => {
Object.entries(comp._state)
.forEach(([settingId, v]) => {
const {groupId, configId} = UtilConfigHelpers.unpackSettingId(settingId);
MiscUtil.set(this._CONFIG, groupId, configId, v);
});
this._saveThrottled();
});
return comp;
}
}

View File

@@ -0,0 +1,74 @@
import {ConfigSettingsGroup} from "./util-config-settings-group.js";
import {ConfigSettingBoolean, ConfigSettingEnum, ConfigSettingExternal} from "./utils-config-setting-base.js";
const settingsGroupStyleSwitcher = new ConfigSettingsGroup({
groupId: "styleSwitcher",
name: "Appearance",
configSettings: [
new (
class extends ConfigSettingExternal {
_configId = "theme";
_name = "Theme";
_help = "The color theme to be applied.";
_isRowLabel = true;
_getEleExternal () { return StyleSwitcher.getSelStyle(); }
}
)(),
new (
class extends ConfigSettingExternal {
_configId = "isWideMode";
_name = "Wide Mode (Experimental)";
_help = "This feature is unsupported. Expect bugs.";
_isRowLabel = true;
_getEleExternal () { return StyleSwitcher.getCbWide(); }
}
)(),
],
});
const _MARKDOWN_TAG_RENDER_MODES = {
"convertMarkdown": "Convert to Markdown",
"ignore": "Leave As-Is",
"convertText": "Convert to Text",
};
const settingsGroupMarkdown = new ConfigSettingsGroup({
groupId: "markdown",
name: "Markdown",
configSettings: [
new ConfigSettingEnum({
configId: "tagRenderMode",
name: `Tag Handling (<code>@tag</code>)`,
help: `THe output to produce when rendering a 5etools "@tag".`,
isRowLabel: true,
default: "convertMarkdown",
values: [
"convertMarkdown",
"ignore",
"convertText",
],
fnDisplay: it => _MARKDOWN_TAG_RENDER_MODES[it] || it,
}),
new ConfigSettingBoolean({
configId: "isAddColumnBreaks",
name: `Add GM Binder Column Breaks (<code>\\\\columnbreak</code>)`,
help: `If "\\\\columnbreak"s should be added to exported Markdown, at an approximate column breakpoint.`,
isRowLabel: true,
default: false,
}),
new ConfigSettingBoolean({
configId: "isAddPageBreaks",
name: `Add GM Binder Page Breaks (<code>\\\\pagebreak</code>)`,
help: `If "\\\\pagebreak"s should be added to exported Markdown, at an approximate page breakpoint.`,
isRowLabel: true,
default: false,
}),
],
});
export const SETTINGS_GROUPS = [
settingsGroupStyleSwitcher,
settingsGroupMarkdown,
];

View File

@@ -0,0 +1,118 @@
import {UtilConfigHelpers} from "./util-config-helpers.js";
// TODO rename this file
/** @abstract */
class _ConfigSettingBase {
_groupId;
_configId;
_name;
_help;
_isRowLabel = false;
constructor (
{
configId,
name,
help,
isRowLabel,
} = {},
) {
this._configId = configId;
this._name = name;
this._help = help;
this._isRowLabel = isRowLabel;
}
setGroupId (groupId) { this._groupId = groupId; }
/* -------------------------------------------- */
render (rdState, wrpRows) {
const tag = this._isRowLabel ? "label" : "div";
ee`<${tag} class="py-1 w-100 split-v-center" title="${this._help.qq()}">
${this._renderLabel(rdState)}
${this._renderUi(rdState)}
</${tag}>`
.appendTo(wrpRows);
}
_renderLabel (rdState) {
return `<div class="w-66 no-shrink mr-2">${this._name}</div>`;
}
/**
* @abstract
* @return {HTMLElementModified}
*/
_renderUi (rdState) { throw new Error("Unimplemented!"); }
/* -------------------------------------------- */
/** @abstract */
mutDefaults (group) {
throw new Error("Unimplemented!");
}
}
/** @abstract */
export class ConfigSettingExternal extends _ConfigSettingBase {
_renderUi (rdState) { return this._getEleExternal(); }
/**
* @abstract
* @return {HTMLElementModified}
*/
_getEleExternal () { throw new Error("Unimplemented!"); }
mutDefaults (group) { /* No-op */ }
}
/** @abstract */
class _ConfigSettingStandardBase extends _ConfigSettingBase {
_default;
constructor (opts) {
super(opts);
this._default = opts.default;
}
mutDefaults (group) {
if (group[this._configId] !== undefined) return;
group[this._configId] = this._default;
}
}
export class ConfigSettingBoolean extends _ConfigSettingStandardBase {
_renderUi (rdState) {
const prop = UtilConfigHelpers.packSettingId(this._groupId, this._configId);
return ComponentUiUtil.getCbBool(rdState.comp, prop);
}
}
export class ConfigSettingEnum extends _ConfigSettingStandardBase {
_values;
_fnDisplay;
constructor ({values, fnDisplay, ...rest}) {
super(rest);
this._values = values;
this._fnDisplay = fnDisplay;
}
_renderUi (rdState) {
const prop = UtilConfigHelpers.packSettingId(this._groupId, this._configId);
return ComponentUiUtil.getSelEnum(
rdState.comp,
prop,
{
values: this._values,
fnDisplay: this._fnDisplay,
},
);
}
}

View File

@@ -0,0 +1,79 @@
import {VetoolsConfig} from "./utils-config-config.js";
import {SETTINGS_GROUPS} from "./utils-config-registry.js";
class _ConfigRenderState {
wrp;
comp;
constructor (
{
wrp,
comp,
},
) {
this.wrp = wrp;
this.comp = comp;
}
}
export class ConfigUi {
constructor (
{
settingsGroups,
},
) {
this._settingsGroups = settingsGroups;
}
render (wrp) {
const rdState = new _ConfigRenderState({
wrp,
comp: VetoolsConfig.getConfigComp(),
});
this._settingsGroups
.forEach((configSection, i, arr) => {
configSection.render(rdState, {isLast: i === arr.length - 1});
});
}
/* -------------------------------------------- */
/**
* @param {?string[]} settingsGroupIds Subset of group IDs to display
*/
static show (
{
settingsGroupIds = null,
} = {},
) {
const settingsGroups = settingsGroupIds
? SETTINGS_GROUPS
.filter(group => settingsGroupIds.includes(group.groupId))
: SETTINGS_GROUPS;
const ui = new this({
settingsGroups,
});
const {$modalInner, $modalFooter, doClose} = UiUtil.getShowModal({
isUncappedWidth: true,
isUncappedHeight: true,
title: "Preferences",
headerType: 3,
isHeaderBorder: true,
overlayColor: "transparent",
hasFooter: true,
});
ui.render($modalInner[0]);
const btnClose = ee`<button class="btn btn-default btn-sm ml-auto">Close</button>`
.onn("click", () => doClose());
ee`<div class="py-1 w-100 ve-flex-v-center">
${btnClose}
</div>`
.appendTo($modalFooter[0]);
}
}