Compare commits

...

13 commits
v1.0.0 ... main

29 changed files with 479 additions and 60 deletions

2
dev/dev.mjs Normal file
View file

@ -0,0 +1,2 @@
// Hooks
import "./hooks/ready.mjs";

5
dev/hooks/ready.mjs Normal file
View file

@ -0,0 +1,5 @@
import { __ID__ } from "../../module/consts.mjs";
Hooks.on(`ready`, () => {
console.table(game.modules.get(__ID__).api.settings);
});

View file

@ -9,6 +9,10 @@
"name": "Auto Unpause On Load",
"hint": "(v13+, GM-Only) Automatically unpauses the game when you load into the world. This will happen EVERY time you load into the world, including if you reload the website."
},
"chatImageLinks": {
"name": "Image Shortcuts",
"hint": "(v13+) When attempting to send an image/gif in chat, this allows you to easily embed the actual image in the text by changing \"http\"/\"https\" into \"image\", automatically displaying the image after sending the message."
},
"chatSidebarBackground": {
"name": "Chat Background",
"hint": "(v13+) Adds a background to the chat tab of the right-hand sidebar."
@ -21,9 +25,17 @@
"name": "Hotbar Button Size",
"hint": "(v13+) Changes the size of the hotbar buttons to a size you prefer."
},
"preventMovementHistory": {
"name": "Prevent Movement History",
"hint": "(v13+, GM-Only) This prevents Foundry from recording movement history of a token, but not disabling the movement ruler."
},
"preventTokenRotation": {
"name": "Prevent Token Auto-Rotation",
"hint": "(v13+, GM-Only) This prevents tokens from rotating while you are moving them allowing you to more easily use POG-style tokens without them being rotated automatically by Foundry."
},
"preventUserConfigOpen": {
"name": "Prevent Auto User Config",
"hint": "(v13+) Prevents Foundry from opening the User Configuration when a player loads into the world."
"hint": "(v13+, Non-GMs) Prevents Foundry from opening the User Configuration when a player loads into the world."
},
"repositionHotbar": {
"name": "Reposition Hotbar",
@ -46,11 +58,25 @@
"name": "Developer Settings",
"hint": "Tweaks that are relevant if you are developing something within Foundry, but are rarely useful outside of that context.",
"label": "Configure Dev Settings"
},
"hotbarSettings": {
"name": "Hotbar Settings",
"hint": "Tweaks that modify Foundry's hotbar",
"label": "Configure Hotbar"
}
},
"apps": {
"no-settings-to-display": "No settings to display",
"make-global-reference": "Make Global Reference"
},
"dialogs": {
"chatImageLinks": {
"didYouKnowImageLink": "",
"convertAndDontShowAgain": "",
"justConvert": "",
"ignoreAndDontShowAgain": "",
"disableEntirely": ""
}
}
}
}

View file

@ -1,7 +1,7 @@
{
"id": "oft",
"title": "Oliver's Foundry Tweaks",
"version": "1.0.0",
"version": "1.1.0",
"authors": [
{ "name": "Oliver" }
],
@ -14,7 +14,8 @@
"maximum": 13
},
"esmodules": [
"module/oft.mjs"
"module/oft.mjs",
"dev/dev.mjs"
],
"styles": [
{

View file

@ -1,4 +1,4 @@
import { devSettings } from "../utils/DevSettings.mjs";
import { categories } from "../utils/SubMenuSettings.mjs";
import { OFTSettingsMenu } from "./OFTSettingsMenu.mjs";
export class DevSettingsMenu extends OFTSettingsMenu {
@ -9,6 +9,7 @@ export class DevSettingsMenu extends OFTSettingsMenu {
};
static get _SETTINGS() {
const devSettings = categories.get(`dev`);
const settingIDs = [];
for (const [settingID, shown] of devSettings.entries()) {
if (shown) {

View file

@ -0,0 +1,21 @@
import { categories } from "../utils/SubMenuSettings.mjs";
import { OFTSettingsMenu } from "./OFTSettingsMenu.mjs";
export class HotbarSettingsMenu extends OFTSettingsMenu {
static DEFAULT_OPTIONS = {
window: {
title: `OFT.menu.hotbarSettings.name`,
},
};
static get _SETTINGS() {
const settings = categories.get(`hotbar`);
const settingIDs = [];
for (const [settingID, shown] of settings.entries()) {
if (shown) {
settingIDs.push(settingID);
};
};
return settingIDs;
};
};

View file

@ -1,4 +1,4 @@
import { filePath } from "../consts.mjs";
import { __ID__, filePath } from "../consts.mjs";
const { HandlebarsApplicationMixin: HAM, ApplicationV2 } = foundry.applications.api;
@ -7,6 +7,7 @@ export class OFTSettingsMenu extends HAM(ApplicationV2) {
// #region Options
static DEFAULT_OPTIONS = {
tag: `form`,
classes: [ __ID__ ],
window: {
icon: `fa-solid fa-gears`,
resizable: true,

17
module/hooks/init.mjs Normal file
View file

@ -0,0 +1,17 @@
// Settings
import { preventMovementHistory } from "../settings/preventMovementHistory.mjs";
// Utils
import { Logger } from "../utils/Logger.mjs";
/*
This is only here for setting that **require** being registered during
initialization due to documentClass changes. If there is any way that
these settings can be implemented to work during the setup hook, that is
where they ideally should be implemented.
*/
Hooks.on(`init`, () => {
Logger.log(`Initializing`);
preventMovementHistory();
});

View file

@ -5,7 +5,8 @@ of incompatabilities for whatever reason. This can also be used
internally within this module if we discover incompatabilites with
systems and want to disable it on our side.
This file is more as documentation than anything at this point in time.
This file is meant more documentation than anything at this point in
time.
Call Signature: (settingKey: string) => {}
Call Signature: (settingKey: string) => (void | boolean)
*/

View file

@ -0,0 +1,13 @@
/*
This hook is used to enable any modules that attempt to disable settings
or just want to investigate what settings are enabled to be able to get
a ping with information about which settings where registered entirely
and which weren't. The object that is passed to this is frozen and is
not meant to be edited as you cannot de-register nor prevent setting
registration from this hook. For that see the "oft.preventSetting" hook.
This file is meant more documentation than anything at this point in
time.
Call Signature: (settings: Record<string, boolean>) => void
*/

58
module/hooks/setup.mjs Normal file
View file

@ -0,0 +1,58 @@
// Settings
import { addGlobalDocReferrer } from "../settings/addGlobalDocReferrer.mjs";
import { autoUnpauseOnLoad } from "../settings/autoUnpauseOnLoad.mjs";
import { chatImageLinks } from "../settings/chatImageLinks.mjs";
import { chatSidebarBackground } from "../settings/chatSidebarBackground.mjs";
import { hotbarButtonGap } from "../settings/hotbarButtonGap.mjs";
import { hotbarButtonSize } from "../settings/hotbarButtonSize.mjs";
import { preventTokenRotation } from "../settings/preventTokenRotation.mjs";
import { preventUserConfigOpen } from "../settings/preventUserConfigOpen.mjs";
import { repositionHotbar } from "../settings/repositionHotbar.mjs";
import { startingSidebarTab } from "../settings/startingSidebarTab.mjs";
import { startSidebarExpanded } from "../settings/startSidebarExpanded.mjs";
// Apps
import { DevSettingsMenu } from "../apps/DevSettingsMenu.mjs";
import { HotbarSettingsMenu } from "../apps/HotbarSettingsMenu.mjs";
// Misc
import { __ID__ } from "../consts.mjs";
import { status } from "../utils/SettingStatus.mjs";
const { deepFreeze } = foundry.utils;
Hooks.on(`setup`, () => {
game.settings.registerMenu(__ID__, `devSettings`, {
name: `OFT.menu.devSettings.name`,
hint: `OFT.menu.devSettings.hint`,
label: `OFT.menu.devSettings.label`,
restricted: false,
type: DevSettingsMenu,
});
addGlobalDocReferrer();
autoUnpauseOnLoad();
game.settings.registerMenu(__ID__, `hotbarSettings`, {
name: `OFT.menu.hotbarSettings.name`,
hint: `OFT.menu.hotbarSettings.hint`,
label: `OFT.menu.hotbarSettings.label`,
restricted: false,
type: HotbarSettingsMenu,
});
hotbarButtonSize();
hotbarButtonGap();
repositionHotbar();
chatImageLinks();
chatSidebarBackground();
startSidebarExpanded();
startingSidebarTab();
preventTokenRotation();
preventUserConfigOpen();
Hooks.callAll(`oft.settingStatuses`, deepFreeze(status));
game.modules.get(__ID__).api = deepFreeze({
settings: status,
});
});

View file

@ -1,40 +1,4 @@
// Hooks
import "./hooks/init.mjs";
import "./hooks/setup.mjs";
import "./hooks/renderSettingsConfig.mjs";
// Settings
import { addGlobalDocReferrer } from "./settings/addGlobalDocReferrer.mjs";
import { autoUnpauseOnLoad } from "./settings/autoUnpauseOnLoad.mjs";
import { chatSidebarBackground } from "./settings/chatSidebarBackground.mjs";
import { hotbarButtonGap } from "./settings/hotbarButtonGap.mjs";
import { hotbarButtonSize } from "./settings/hotbarButtonSize.mjs";
import { preventUserConfigOpen } from "./settings/preventUserConfigOpen.mjs";
import { repositionHotbar } from "./settings/repositionHotbar.mjs";
import { startingSidebarTab } from "./settings/startingSidebarTab.mjs";
import { startSidebarExpanded } from "./settings/startSidebarExpanded.mjs";
// Apps
import { DevSettingsMenu } from "./apps/DevSettingsMenu.mjs";
// Misc
import { __ID__ } from "./consts.mjs";
Hooks.on(`setup`, () => {
game.settings.registerMenu(__ID__, `devSettings`, {
name: `OFT.menu.devSettings.name`,
hint: `OFT.menu.devSettings.hint`,
label: `OFT.menu.devSettings.label`,
restricted: false,
type: DevSettingsMenu,
});
addGlobalDocReferrer();
autoUnpauseOnLoad();
chatSidebarBackground();
startSidebarExpanded();
startingSidebarTab();
hotbarButtonSize();
hotbarButtonGap();
repositionHotbar();
preventUserConfigOpen();
});

View file

@ -1,10 +1,12 @@
import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs";
import { __ID__ } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
import { registerDevSetting } from "../utils/DevSettings.mjs";
import { registerDevSetting } from "../utils/SubMenuSettings.mjs";
const key = `addGlobalDocReferrer`;
export function addGlobalDocReferrer() {
status[key] = SettingStatusEnum.Unknown;
// #region Registration
Logger.log(`Registering setting: ${key}`);
@ -33,4 +35,5 @@ export function addGlobalDocReferrer() {
});
// #endregion Implementation
status[key] = SettingStatusEnum.Registered;
};

View file

@ -1,14 +1,17 @@
import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs";
import { __ID__ } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
import { registerDevSetting } from "../utils/DevSettings.mjs";
import { registerDevSetting } from "../utils/SubMenuSettings.mjs";
const key = `autoUnpauseOnLoad`;
export function autoUnpauseOnLoad() {
status[key] = SettingStatusEnum.Unknown;
const prevented = Hooks.call(`${__ID__}.preventSetting`, key);
if (!prevented) {
Logger.log(`Preventing setting "${key}" from being registered`);
status[key] = SettingStatusEnum.Blocked;
return;
};
@ -34,4 +37,6 @@ export function autoUnpauseOnLoad() {
};
});
// #endregion Implementation
status[key] = SettingStatusEnum.Registered;
};

View file

@ -0,0 +1,130 @@
import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs";
import { __ID__ } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
const { DialogV2 } = foundry.applications.api;
const key = `chatImageLinks`;
const IMAGE_TYPES = [
`png`,
`jpg`,
`jpeg`,
`webp`,
`svg`,
];
export function chatImageLinks() {
status[key] = SettingStatusEnum.Unknown;
const prevented = Hooks.call(`${__ID__}.preventSetting`, key);
if (!prevented) {
Logger.log(`Preventing setting "${key}" from being registered`);
status[key] = SettingStatusEnum.Blocked;
return;
};
// #region Registration
Logger.log(`Registering setting: ${key}`);
game.settings.register(__ID__, key, {
name: `OFT.setting.${key}.name`,
hint: `OFT.setting.${key}.hint`,
scope: `user`,
type: Boolean,
default: true,
config: true,
requiresReload: true,
});
game.settings.register(__ID__, key + `-showPromptAgain`, {
scope: `user`,
type: Boolean,
default: true,
config: false,
});
// #endregion Registration
// #region Implementation
if (game.settings.get(__ID__, key)) {
Logger.log(`setting:${key} | Adding text enricher`);
// MARK: Enricher
const pattern = new RegExp(
`(?<!=|")(image:\\/\\/.*\\.(?:${IMAGE_TYPES.join(`|`)}))`,
`gi`,
);
CONFIG.TextEditor.enrichers.push({
pattern,
replaceParent: true,
enricher: async (url) => {
Logger.debug(url);
url = url[0].replace(/^image:\/\//, ``);
const secure = `https://${url}`;
const insecure = `http://${url}`;
if (await isAcceptableImage(secure)) {
const img = document.createElement(`img`);
img.src = secure;
img.alt = secure;
return img;
};
if (await isAcceptableImage(insecure)) {
const img = document.createElement(`img`);
img.src = insecure;
img.alt = insecure;
return img;
};
return null;
},
});
// MARK: Chat Input
// Hooks.on(`chatMessage`, (chatLog, message, options) => {
// if (!game.settings.get(__ID__, key)) { return };
// const match = message.match(pattern);
// if (!match) { return };
// DialogV2.wait({
// rejectClose: false,
// content: game.i18n.localize(`OFT.dialogs.chatImageLinks.didYouKnowImageLink`),
// buttons: [
// { action: ``, label: `OFT.dialogs.chatImageLinks.convertAndDontShowAgain` },
// { action: ``, label: `OFT.dialogs.chatImageLinks.justConvert` },
// { action: ``, label: `OFT.dialogs.chatImageLinks.ignoreAndDontShowAgain` },
// { action: ``, label: `OFT.dialogs.chatImageLinks.disableEntirely` },
// ],
// })
// .then((selected) => {
// chatLog.processMessage(message, options);
// });
// return false;
// });
}
// #endregion Implementation
status[key] = SettingStatusEnum.Registered;
};
// #region Helpers
async function isAcceptableImage(url) {
try {
const response = await fetch(url, { method: `HEAD` });
const contentType = response.headers.get(`Content-Type`);
Logger.debug(`Image data:`, { url, contentType });
let [ superType, subtype ] = contentType.split(`/`);
if (superType !== `image`) {
return false;
};
if (subtype.includes(`+`)) {
subtype = subtype.split(`+`, 2).at(0);
};
return IMAGE_TYPES.includes(subtype);
} catch {
return false;
};
};
// #endregion Helpers

View file

@ -1,9 +1,11 @@
import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs";
import { __ID__ } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
const key = `chatSidebarBackground`;
export function chatSidebarBackground() {
status[key] = SettingStatusEnum.Unknown;
// #region Registration
Logger.log(`Registering setting: ${key}`);
@ -28,4 +30,6 @@ export function chatSidebarBackground() {
document.body.classList.add(`${__ID__}-${key}`);
};
// #endregion Implementation
status[key] = SettingStatusEnum.Registered;
};

View file

@ -1,20 +1,24 @@
import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs";
import { __ID__ } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
import { registerCategorySetting } from "../utils/SubMenuSettings.mjs";
const key = `hotbarButtonGap`;
export function hotbarButtonGap() {
status[key] = SettingStatusEnum.Unknown;
const prevented = Hooks.call(`${__ID__}.preventSetting`, key);
if (!prevented) {
Logger.log(`Preventing setting "${key}" from being registered`);
status[key] = SettingStatusEnum.Blocked;
return;
};
// #region Registration
Logger.log(`Registering setting: ${key}`);
document.body.classList.add(`${__ID__}-${key}`);
game.settings.register(__ID__, key, {
registerCategorySetting(`hotbar`, __ID__, key, {
name: `OFT.setting.${key}.name`,
hint: `OFT.setting.${key}.hint`,
scope: `user`,
@ -36,4 +40,6 @@ export function hotbarButtonGap() {
const buttonGap = game.settings.get(__ID__, key);
document.body.style.setProperty(`--hotbar-button-gap`, `${buttonGap}px`);
// #endregion Implementation
status[key] = SettingStatusEnum.Registered;
};

View file

@ -1,20 +1,24 @@
import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs";
import { __ID__ } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
import { registerCategorySetting } from "../utils/SubMenuSettings.mjs";
const key = `hotbarButtonSize`;
export function hotbarButtonSize() {
status[key] = SettingStatusEnum.Unknown;
const prevented = Hooks.call(`${__ID__}.preventSetting`, key);
if (!prevented) {
Logger.log(`Preventing setting "${key}" from being registered`);
status[key] = SettingStatusEnum.Blocked;
return;
};
// #region Registration
Logger.log(`Registering setting: ${key}`);
document.body.classList.add(`${__ID__}-${key}`);
game.settings.register(__ID__, key, {
registerCategorySetting(`hotbar`, __ID__, key, {
name: `OFT.setting.${key}.name`,
hint: `OFT.setting.${key}.hint`,
scope: `user`,
@ -36,4 +40,6 @@ export function hotbarButtonSize() {
const hotbarSize = game.settings.get(__ID__, key);
document.body.style.setProperty(`--hotbar-size`, `${hotbarSize}px`);
// #endregion Implementation
status[key] = SettingStatusEnum.Registered;
};

View file

@ -0,0 +1,42 @@
import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs";
import { __ID__ } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
const key = `preventMovementHistory`;
export function preventMovementHistory() {
status[key] = SettingStatusEnum.Unknown;
const prevented = Hooks.call(`${__ID__}.preventSetting`, key);
if (!prevented) {
Logger.log(`Preventing setting "${key}" from being registered`);
status[key] = SettingStatusEnum.Blocked;
return;
};
// #region Registration
Logger.log(`Registering setting: ${key}`);
game.settings.register(__ID__, key, {
name: `OFT.setting.${key}.name`,
hint: `OFT.setting.${key}.hint`,
scope: `world`,
type: Boolean,
default: false,
config: true,
reloadRequired: true,
});
// #endregion Registration
// #region Implementation
if (game.settings.get(__ID__, key)) {
class OFTTokenDocument extends CONFIG.Token.documentClass {
_shouldRecordMovementHistory() {
return false;
};
};
CONFIG.Token.documentClass = OFTTokenDocument;
};
// #endregion Implementation
status[key] = SettingStatusEnum.Registered;
};

View file

@ -0,0 +1,53 @@
import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs";
import { __ID__ } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
const key = `preventTokenRotation`;
export function preventTokenRotation() {
status[key] = SettingStatusEnum.Unknown;
const prevented = Hooks.call(`${__ID__}.preventSetting`, key);
if (!prevented) {
Logger.log(`Preventing setting "${key}" from being registered`);
status[key] = SettingStatusEnum.Blocked;
return;
};
/** @type {number|null} */
let hookID = null;
// #region Registration
Logger.log(`Registering setting: ${key}`);
game.settings.register(__ID__, key, {
name: `OFT.setting.${key}.name`,
hint: `OFT.setting.${key}.hint`,
scope: `world`,
type: Boolean,
default: true,
config: true,
requiresReload: false,
onChange: (newValue) => {
if (newValue) {
hookID = Hooks.on(`preMoveToken`, preMoveTokenHandler);
} else if (hookID != null) {
Hooks.off(`preMoveToken`, hookID);
};
},
});
// #endregion Registration
// #region Implementation
if (game.settings.get(__ID__, key)) {
hookID = Hooks.on(`preMoveToken`, preMoveTokenHandler);
};
// #endregion Implementation
status[key] = SettingStatusEnum.Registered;
};
// #region Helpers
function preMoveTokenHandler(_token, update) {
update.autoRotate = false;
};
// #endregion Helpers

View file

@ -1,13 +1,16 @@
import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs";
import { __ID__ } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
const key = `preventUserConfigOpen`;
export function preventUserConfigOpen() {
status[key] = SettingStatusEnum.Unknown;
const prevented = Hooks.call(`${__ID__}.preventSetting`, key);
if (!prevented) {
Logger.log(`Preventing setting "${key}" from being registered`);
status[key] = SettingStatusEnum.Blocked;
return;
};
@ -19,7 +22,7 @@ export function preventUserConfigOpen() {
scope: `user`,
type: Boolean,
default: false,
config: true,
config: !game.user.isGM,
requiresReload: false,
});
// #endregion Registration
@ -32,4 +35,6 @@ export function preventUserConfigOpen() {
};
});
// #endregion Implementation
status[key] = SettingStatusEnum.Registered;
};

View file

@ -1,19 +1,23 @@
import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs";
import { __ID__ } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
import { registerCategorySetting } from "../utils/SubMenuSettings.mjs";
const key = `repositionHotbar`;
export function repositionHotbar() {
status[key] = SettingStatusEnum.Unknown;
const prevented = Hooks.call(`${__ID__}.preventSetting`, key);
if (!prevented) {
Logger.log(`Preventing setting "${key}" from being registered`);
status[key] = SettingStatusEnum.Blocked;
return;
};
// #region Registration
Logger.log(`Registering setting: ${key}`);
game.settings.register(__ID__, key, {
registerCategorySetting(`hotbar`, __ID__, key, {
name: `OFT.setting.${key}.name`,
hint: `OFT.setting.${key}.hint`,
scope: `user`,
@ -42,4 +46,6 @@ export function repositionHotbar() {
uiPosition.insertAdjacentElement(`beforeend`, container);
};
// #endregion Implementation
status[key] = SettingStatusEnum.Registered;
};

View file

@ -1,9 +1,11 @@
import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs";
import { __ID__ } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
const key = `startSidebarExpanded`;
export function startSidebarExpanded() {
status[key] = SettingStatusEnum.Unknown;
// #region Registration
Logger.log(`Registering setting: ${key}`);
@ -26,4 +28,6 @@ export function startSidebarExpanded() {
};
});
// #endregion Implementation
status[key] = SettingStatusEnum.Registered;
};

View file

@ -1,9 +1,11 @@
import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs";
import { __ID__ } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
const key = `startingSidebarTab`;
export function startingSidebarTab() {
status[key] = SettingStatusEnum.Unknown;
// #region Registration
Logger.log(`Registering setting: ${key}`);
@ -42,10 +44,19 @@ export function startingSidebarTab() {
// #region Implementation
Hooks.once(`ready`, () => {
const defaultTab = game.settings.get(__ID__, key);
if (defaultTab === ``) { return };
if (!(defaultTab in CONFIG.ui.sidebar.TABS)) {
Logger.error(`Failed to find starting tab with ID "${defaultTab}", skipping`);
return;
};
if (defaultTab) {
Logger.debug(`Changing tab to:`, defaultTab);
ui.sidebar.changeTab(defaultTab, `primary`);
};
});
// #endregion Implementation
status[key] = SettingStatusEnum.Registered;
};

View file

@ -1,9 +0,0 @@
/** @type {Map<string, boolean>} */
export const devSettings = new Map();
export function registerDevSetting(namespace, key, config) {
const visible = config.config;
config.config = false;
game.settings.register(namespace, key, config);
devSettings.set(`${namespace}.${key}`, visible);
};

View file

@ -0,0 +1,11 @@
/** @typedef {typeof SettingStatusEnum[keyof typeof SettingStatusEnum]} SettingStatus */
export const SettingStatusEnum = foundry.utils.deepFreeze({
Registered: `registered`,
Blocked: `blocked`,
Incompatible: `incompatible`,
Unknown: `unknown`,
});
/** @type {Record<string, SettingStatus>} */
export const status = {};

View file

@ -0,0 +1,22 @@
/** @type {Map<string, Map<string, boolean>>} */
export const categories = new Map();
export function registerCategorySetting(category, namespace, key, config) {
let cat = categories.get(category);
if (!cat) {
cat = new Map();
categories.set(category, cat);
};
const visible = config.config;
config.config = false;
game.settings.register(namespace, key, config);
cat.set(`${namespace}.${key}`, visible);
};
/**
* A helper function that registers the setting to the "dev"
* category
*/
export function registerDevSetting(namespace, key, config) {
registerCategorySetting(`dev`, namespace, key, config);
};

8
styles/apps.css Normal file
View file

@ -0,0 +1,8 @@
.application.oft {
> .window-content.standard-form .setting-list {
flex-grow: 1;
display: flex;
flex-direction: column;
gap: 1rem;
}
}

View file

@ -3,5 +3,7 @@
@import url("./hotbarButtonSize.css");
@import url("./repositionHotbar.css");
@import url("./apps.css");
/* Make the chat sidebar the same width as all the other tabs */
.chat-sidebar:not(.sidebar-popout) { width: unset; }