From 461fa28d9494497b22202c5d3901b4e7e110d6cb Mon Sep 17 00:00:00 2001 From: grimsace Date: Thu, 7 May 2026 14:11:48 -0500 Subject: [PATCH] added aura tab --- README.md | 2 +- languages/en.json | 21 +++++++++++++ module.json | 27 +++++++++++++--- scripts/module.js | 79 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 languages/en.json create mode 100644 scripts/module.js diff --git a/README.md b/README.md index bfa4963..f781bf6 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # Basic Aura Highlighting -A small, FoundryVTT system agnostic module that places a highlight around tokens in another token's aura. \ No newline at end of file +A small, FoundryVTT Pathfinder 2e/Starfinder 2e module that places a highlight around tokens in another token's aura. diff --git a/languages/en.json b/languages/en.json new file mode 100644 index 0000000..ec74df7 --- /dev/null +++ b/languages/en.json @@ -0,0 +1,21 @@ +{ + "BASIC_AURA_HIGHLIGHTING": { + "tabs": { + "aura": "Aura", + "auraHint": "Aura controls will be added here." + }, + "settings": { + "enabled": { + "name": "Enable Aura Highlight", + "hint": "Whether this token should highlight others within its aura." + }, + "radius": { + "name": "Aura Radius", + "hint": "The radius of the aura in grid units." + }, + "color": { + "name": "Highlight Color" + } + } + } +} diff --git a/module.json b/module.json index ef768c3..8d89fad 100644 --- a/module.json +++ b/module.json @@ -1,5 +1,5 @@ { - "id": "basicaurahighlighting", + "id": "basic_aura_highlighting", "title": "Basic Aura Highlighting", "version": "0.1.0", "compatibility": { @@ -7,9 +7,28 @@ "verified": "13", "maximum": "14" }, - "description": "

A small, system agnostic module that places a highlight around tokens in another token's aura. This aura can be measured from the center of the tokens or edge to edge. See the token or prototype token menus for configuration. This module also includes integration with pathfidner 2e, to make the auras toggleable in the actions tab of a character sheet.

", + "description": "

A module specifically for Pathfinder 2e that places a highlight around tokens in another token's aura. This aura can be measured from the center of the tokens or edge to edge. See the token or prototype token menus for configuration.

", + "relationships": { + "systems": [ + { + "id": "pf2e", + "manifest": "https://github.com/foundryvtt/pf2e/releases/latest/download/system.json", + "compatibility": { + "minimum": "6.0.0" + } + } + ] + }, "flags": { "canUpload": true }, - "url": "https://codeberg.org/Grimsace/basic_aura_highlighting" -} \ No newline at end of file + "url": "https://codeberg.org/Grimsace/basic_aura_highlighting", + "esmodules": ["scripts/module.js"], + "languages": [ + { + "lang": "en", + "name": "English", + "path": "languages/en.json" + } + ] +} diff --git a/scripts/module.js b/scripts/module.js new file mode 100644 index 0000000..5e88a34 --- /dev/null +++ b/scripts/module.js @@ -0,0 +1,79 @@ +const MODULE_ID = "basic_aura_highlighting"; +const AURA_TAB = "basic-aura-highlighting-aura"; + +Hooks.on("renderTokenConfig", injectAuraTab); +Hooks.on("renderPrototypeTokenConfig", injectAuraTab); + +function injectAuraTab(app, element) { + const root = getRootElement(element); + if (!root || root.querySelector(`[data-tab="${AURA_TAB}"]`)) return; + + const tabsNav = findTabsNav(root); + const existingTab = findExistingTab(root, tabsNav); + if (!tabsNav || !existingTab) { + console.warn(`${MODULE_ID} | Could not find token config tabs to add Aura tab.`); + return; + } + + const group = tabsNav.dataset.group || existingTab.dataset.group || "sheet"; + const auraTabButton = createAuraTabButton(group); + tabsNav.append(auraTabButton); + + const auraPanel = createAuraTabPanel(group); + existingTab.after(auraPanel); + + auraTabButton.addEventListener("click", (event) => { + event.preventDefault(); + event.stopPropagation(); + activateAuraTab(root, group); + }); +} + +function getRootElement(element) { + if (element instanceof HTMLElement) return element; + if (element?.[0] instanceof HTMLElement) return element[0]; + return null; +} + +function findTabsNav(root) { + return root.querySelector(`nav.tabs[data-group], .tabs[data-group], nav.tabs, .tabs`); +} + +function findExistingTab(root, tabsNav) { + const group = tabsNav?.dataset.group; + const selector = group ? `.tab[data-group="${group}"][data-tab]` : `.tab[data-tab]`; + return root.querySelector(selector) || root.querySelector(`.tab[data-tab]`); +} + +function createAuraTabButton(group) { + const button = document.createElement("a"); + button.classList.add("item"); + button.dataset.tab = AURA_TAB; + button.dataset.group = group; + button.dataset.action = "tab"; + button.innerHTML = ` ${game.i18n.localize("BASIC_AURA_HIGHLIGHTING.tabs.aura")}`; + return button; +} + +function createAuraTabPanel(group) { + const panel = document.createElement("section"); + panel.classList.add("tab"); + panel.dataset.tab = AURA_TAB; + panel.dataset.group = group; + panel.innerHTML = ` +
+

${game.i18n.localize("BASIC_AURA_HIGHLIGHTING.tabs.auraHint")}

+
+ `; + return panel; +} + +function activateAuraTab(root, group) { + for (const tab of root.querySelectorAll(`.tab[data-group="${group}"], .tab[data-tab]`)) { + tab.classList.toggle("active", tab.dataset.tab === AURA_TAB); + } + + for (const item of root.querySelectorAll(`[data-group="${group}"][data-tab], .tabs [data-tab]`)) { + item.classList.toggle("active", item.dataset.tab === AURA_TAB); + } +}