diff --git a/langs/en-ca.2.json b/langs/en-ca.2.json index 82a260e..c1d67b1 100644 --- a/langs/en-ca.2.json +++ b/langs/en-ca.2.json @@ -81,10 +81,18 @@ "send-to-chat": "Send to Chat", "edit": "Edit", "delete": "Delete", - "empty": "---" + "empty": "---", + "help": "Help", + "gm": "Server" }, "sheet-names": { "*DataSheet": "Data Sheet" + }, + "help-tooltips": { + "calculated-capacity": { + "title": "What is Calculated Capacity?", + "content": "

The calculated capacity is how much space in your inventory that the item will take up, the way it is calculated is determined by the item. Usually the main thing that affects the capacity is the item's quantity, but this can be turned off by the @dotdungeon.common.gm, which means that no matter the quantity it will only use up one capacity. The @dotdungeon.common.gm can also entirely disable capacity usage which will make the used capacity always be zero.

" + } } }, "TYPES": { diff --git a/module/sheets/Items/GenericItemSheet.mjs b/module/sheets/Items/GenericItemSheet.mjs index 0776648..883050e 100644 --- a/module/sheets/Items/GenericItemSheet.mjs +++ b/module/sheets/Items/GenericItemSheet.mjs @@ -1,3 +1,4 @@ +import { DialogManager } from "../../utils/DialogManager.mjs"; import DOTDUNGEON from "../../config.mjs"; export class GenericItemSheet extends ItemSheet { @@ -45,6 +46,10 @@ export class GenericItemSheet extends ItemSheet { .on(`click`, this._incrementValue.bind(this)); html.find(`button[data-decrement]`) .on(`click`, this._decrementValue.bind(this)); + + + html.find(`[data-help-id]`) + .on(`click`, this._helpPopup.bind(this)); }; async _incrementValue($e) { @@ -66,4 +71,15 @@ export class GenericItemSheet extends ItemSheet { }; this.actor.update({ [data.decrement]: value - 1 }); }; + + async _helpPopup($e) { + const target = $e.currentTarget; + const data = target.dataset; + if (!data.helpId) return; + DialogManager.helpDialog( + data.helpId, + data.helpContent, + data.helpTitle + ); + }; }; diff --git a/module/utils/DialogManager.mjs b/module/utils/DialogManager.mjs new file mode 100644 index 0000000..da28478 --- /dev/null +++ b/module/utils/DialogManager.mjs @@ -0,0 +1,85 @@ +import { localizer } from "./localizer.mjs"; + +/** + * A utility class that allows managing Dialogs that are created for various + * purposes such as deleting items, help popups, etc. This is a singleton class + * that upon instantiating after the first time will just return the first instance + */ +export class DialogManager { + + /** @type {Map} */ + static #dialogs = new Map(); + + /** + * Focuses a dialog if it already exists, or creates a new one and renders it. + * + * @param {string} dialogId The ID to associate with the dialog, should be unique + * @param {object} data The data to pass to the Dialog constructor + * @param {DialogOptions} opts The options to pass to the Dialog constructor + * @returns {Dialog} The Dialog instance + */ + static async createOrFocus(dialogId, data, opts = {}) { + if (DialogManager.#dialogs.has(dialogId)) { + const dialog = DialogManager.#dialogs.get(dialogId); + dialog.bringToTop(); + return dialog; + }; + + /* + This makes sure that if I provide a close function as a part of the data, + that the dialog still gets removed from the set once it's closed, otherwise + it could lead to dangling references that I don't care to keep. Or if I don't + provide the close function, it just sets the function as there isn't anything + extra that's needed to be called. + */ + if (data?.close) { + const provided = data.close; + data.close = () => { + DialogManager.#dialogs.delete(dialogId); + provided(); + }; + } + else { + data.close = () => DialogManager.#dialogs.delete(dialogId); + }; + + // Create the Dialog with the modified data + const dialog = new Dialog(data, opts); + DialogManager.#dialogs.set(dialogId, dialog); + dialog.render(true); + return dialog; + }; + + /** + * Closes a dialog if it is rendered + * + * @param {string} dialogId The ID of the dialog to close + */ + static async close(dialogId) { + const dialog = DialogManager.#dialogs.get(dialogId); + dialog?.close(); + }; + + static async helpDialog( + helpId, + helpContent, + helpTitle = `dotdungeon.common.help`, + localizationData = {}, + ) { + DialogManager.createOrFocus( + helpId, + { + title: localizer(helpTitle, localizationData), + content: localizer(helpContent, localizationData), + buttons: {}, + }, + { resizable: true, } + ); + }; + + static get size() { + return DialogManager.#dialogs.size; + } +}; + +globalThis.DialogManager = DialogManager; \ No newline at end of file diff --git a/styles/v3/layouts/items/untyped/v2.scss b/styles/v3/layouts/items/untyped/v2.scss index 8c18cd3..b3dc3a2 100644 --- a/styles/v3/layouts/items/untyped/v2.scss +++ b/styles/v3/layouts/items/untyped/v2.scss @@ -58,5 +58,14 @@ @include utils.tab("settings") { @extend %flex-col; + + .capacity { + &--calculated { + display: flex; + flex-direction: row; + align-items: center; + gap: 8px; + } + } } } diff --git a/templates/items/untyped/v2/tabs/settings.v2.untyped.hbs b/templates/items/untyped/v2/tabs/settings.v2.untyped.hbs index e9fd907..c69757f 100644 --- a/templates/items/untyped/v2/tabs/settings.v2.untyped.hbs +++ b/templates/items/untyped/v2/tabs/settings.v2.untyped.hbs @@ -16,7 +16,17 @@ (GM Only) {{/if}} -
- Total Capacity Used: +
+ Capacity Used: + +
+ 5