diff --git a/module/applications/ui/countdowns.mjs b/module/applications/ui/countdowns.mjs index e9804b6a..b825d66e 100644 --- a/module/applications/ui/countdowns.mjs +++ b/module/applications/ui/countdowns.mjs @@ -12,6 +12,7 @@ const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; export default class DhCountdowns extends HandlebarsApplicationMixin(ApplicationV2) { previusCountdownData = null; + changedCountdownsForAnimation = new Set(); countdownChangeAnimationTimeout = null; constructor(options = {}) { @@ -58,7 +59,6 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application } }; - /**@inheritdoc */ async _renderFrame(options) { const frame = await super._renderFrame(options); @@ -71,6 +71,52 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application return frame; } + + async _onRender(context, options) { + await super._onRender(context, options); + + /**/ + this.element.hidden = !game.user.isGM && this.#getCountdowns().length === 0; + if (options?.force) { + document.getElementById('ui-right-column-1')?.appendChild(this.element); + } + + /**/ + if (this.changedCountdownsForAnimation.size) { + if (this.countdownChangeAnimationTimeout) + clearTimeout(this.countdownChangeAnimationTimeout); + + for (const countdownKey of this.changedCountdownsForAnimation) { + this.element.querySelector(`.countdown-container[data-countdown="${countdownKey}"]`) + .classList.add('change-glow'); + + /* If the countdown is not currently visible, add a glow to the CountdownType pill */ + const visibleTypes = game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownTypeModes) ?? [] + const countdown = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns) + .countdowns[countdownKey]; + if (!visibleTypes.includes(countdown?.type)) { + this.element.querySelector(`.header-type-toggles .header-type[data-type="${countdown.type}"]`) + .classList.add('change-glow'); + } + } + + this.countdownChangeAnimationTimeout = setTimeout(() => { + this.changedCountdownsForAnimation.clear(); + for (const element of this.element.querySelectorAll('.countdown-container')) { + element.classList.remove('change-glow'); + } + + for (const element of this.element.querySelectorAll('.header-type-toggles .header-type')) { + element.classList.remove('change-glow'); + } + + }, 3000); + } + + this.previusCountdownData = + game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns).countdowns; + } + /** Returns countdown data filtered by ownership */ #getCountdowns() { const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns); @@ -84,12 +130,8 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application _getCountdownData() { const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns); - const typeModes = game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownTypeModes) ?? []; return this.#getCountdowns().reduce((acc, { key, countdown, ownership }) => { - if (!typeModes.includes(countdown.type)) - return acc; - const playersWithAccess = game.users.reduce((acc, user) => { const ownership = DhCountdowns.#getPlayerOwnership(user, setting, countdown); if (!user.isGM && ownership && ownership !== CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE) { @@ -112,7 +154,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application !countdownEditable || (isLooping && (countdown.progress.current > 0 || countdown.progress.start === '0')); - acc[key] = { + acc[countdown.type][key] = { ...countdown, editable: countdownEditable, noPlayerAccess: nonGmPlayers.length && playersWithAccess.length === 0, @@ -121,25 +163,27 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application loopTooltip: isLooping && game.i18n.localize(loopTooltip) }; return acc; - }, {}); + }, Object.keys(CONFIG.DH.GENERAL.countdownType).reduce((acc, key) => { + acc[key] = {}; + return acc; + }, {})); } /** @override */ async _prepareContext(options) { const context = await super._prepareContext(options); context.isGM = game.user.isGM; - this.previusCountdownData = - game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns).countdowns; context.iconOnly = - game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownMode) === - CONFIG.DH.GENERAL.countdownAppMode.iconOnly; + game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownMode) + === CONFIG.DH.GENERAL.countdownAppMode.iconOnly; - const userCountdownTypes = game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownTypeModes) ?? []; + context.userCountdownTypes = + game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownTypeModes) ?? []; context.typeToggles = Object.values(CONFIG.DH.GENERAL.countdownType).map(type => ({ type: type.id, label: game.i18n.localize(type.label), - active: userCountdownTypes.includes(type.id) + active: context.userCountdownTypes.includes(type.id) })); context.countdowns = this._getCountdownData(); @@ -191,26 +235,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application currentTypes.includes(type) ? currentTypes.filter(x => x !== type) : [...currentTypes, type]; await game.user.setFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownTypeModes, newTypes); - for (const type of Object.keys(CONFIG.DH.GENERAL.countdownType)) { - const toggleElement = this.element.querySelector(`.header-type-toggles .header-type[data-type="${type}"]`); - if (newTypes.includes(type)) - toggleElement.classList.remove('inactive'); - - else - toggleElement.classList.add('inactive'); - } - - const updatedCountdownsElement = await foundry.applications.handlebars.renderTemplate( - 'systems/daggerheart/templates/ui/countdowns/parts/countdowns.hbs', - { - countdowns: this._getCountdownData(), - iconOnly: game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownMode) === - CONFIG.DH.GENERAL.countdownAppMode.iconOnly, - isGM: game.user.isGM - } - ); - - this.element.querySelector('#countdowns .countdowns-container').innerHTML = updatedCountdownsElement; + this.render(); } static async #onEditCountdowns() { @@ -267,10 +292,6 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application } static async gmSetSetting(data) { - // if(Object.keys(data).some(x => x.includes('countdowns'))) { - // this.previusCountdownData = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns).countdowns; - // } - await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, data); game.socket.emit(`system.${CONFIG.DH.id}`, { action: socketEvent.Refresh, @@ -328,26 +349,4 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application refreshType: RefreshType.Countdown }); } - - /** - * - * @param {*} context - * @param {*} options - */ - async performChangeAnimations(changedCountdowns) { - if (this.countdownChangeAnimationTimeout) - clearTimeout(this.countdownChangeAnimationTimeout); - - this.countdownChangeAnimationTimeout = setTimeout(() => { - - }, 3000); - } - - async _onRender(context, options) { - await super._onRender(context, options); - this.element.hidden = !game.user.isGM && this.#getCountdowns().length === 0; - if (options?.force) { - document.getElementById('ui-right-column-1')?.appendChild(this.element); - } - } } diff --git a/module/data/countdowns.mjs b/module/data/countdowns.mjs index ab71ca28..f9cad1de 100644 --- a/module/data/countdowns.mjs +++ b/module/data/countdowns.mjs @@ -16,16 +16,16 @@ export default class DhCountdowns extends foundry.abstract.DataModel { handleChange() { const previousCountdowns = foundry.ui.countdowns.previusCountdownData; - const changedCountdowns = Object.values(this.countdowns).reduce((acc, [key, countdown]) => { + const changedCountdowns = Object.entries(this.countdowns).reduce((acc, [key, countdown]) => { const previousCountdown = previousCountdowns[key]; - if (!previousCountdown || (previousCountdown.current !== countdown.current)) { + if (!previousCountdown || (previousCountdown.progress.current !== countdown.progress.current)) { acc.push(key); } return acc; }, []); - foundry.ui.performChangeAnimations(changedCountdowns); + foundry.ui.countdowns.changedCountdownsForAnimation.add(...changedCountdowns); } migrateData(source) { diff --git a/module/helpers/handlebarsHelper.mjs b/module/helpers/handlebarsHelper.mjs index 7f30d970..d6e8417e 100644 --- a/module/helpers/handlebarsHelper.mjs +++ b/module/helpers/handlebarsHelper.mjs @@ -16,7 +16,8 @@ export default class RegisterHandlebarsHelpers { empty: this.empty, pluralize: this.pluralize, positive: this.positive, - isNullish: this.isNullish + isNullish: this.isNullish, + debug: this.debug }); } static add(a, b) { @@ -92,4 +93,8 @@ export default class RegisterHandlebarsHelpers { static isNullish(a) { return a === null || a === undefined; } + + static debug(a) { + return a; + } } diff --git a/styles/less/ui/countdown/countdown.less b/styles/less/ui/countdown/countdown.less index 307af858..0fee6516 100644 --- a/styles/less/ui/countdown/countdown.less +++ b/styles/less/ui/countdown/countdown.less @@ -89,6 +89,10 @@ &.inactive { opacity: 0.4; } + + &.change-glow { + animation: change-glow 1s ease-in-out infinite; + } } } } @@ -101,10 +105,20 @@ overflow: auto; max-height: 312px; + .countdown-category-container { + &.hidden { + display: none; + } + } + .countdown-container { display: flex; width: 100%; + &.change-glow { + animation: change-glow 1s ease-in-out infinite; + } + &.icon-only { gap: 8px; @@ -203,4 +217,14 @@ // } } } + + @keyframes change-glow { + 0% { + box-shadow: 0 0 1px 1px @golden; + } + + 100% { + box-shadow: 0 0 2px 2px @golden; + } + } } diff --git a/templates/ui/countdowns/parts/countdowns.hbs b/templates/ui/countdowns/parts/countdowns.hbs index f919d3fc..df766113 100644 --- a/templates/ui/countdowns/parts/countdowns.hbs +++ b/templates/ui/countdowns/parts/countdowns.hbs @@ -1,40 +1,44 @@ -{{#each countdowns as | countdown id |}} -
-
- -
- {{#unless ../iconOnly}} -
{{countdown.name}}
- {{/unless}} -
-
- {{#if countdown.editable}}{{/if}} -
- {{countdown.progress.current}}/{{countdown.progress.start}} +{{#each countdowns as | category key |}} +
+ {{#each category as |countdown id|}} +
+
+ +
+ {{#unless ../iconOnly}} +
{{countdown.name}}
+ {{/unless}} +
+
+ {{#if countdown.editable}}{{/if}} +
+ {{countdown.progress.current}}/{{countdown.progress.start}} +
+ {{#if countdown.editable}}{{/if}} +
+
+ {{#if (not ../iconOnly)}} + {{#if (and countdown.noPlayerAccess @root.isGM)}} + + {{/if}} + {{#unless (eq countdown.progress.looping "noLooping")}} + + + + {{#if (eq countdown.progress.looping "increasing")}} + + {{else if (eq countdown.progress.looping "decreasing")}} + + {{/if}} + + + {{/unless}} + {{/if}} +
- {{#if countdown.editable}}{{/if}} -
-
- {{#if (not ../iconOnly)}} - {{#if (and countdown.noPlayerAccess @root.isGM)}} - - {{/if}} - {{#unless (eq countdown.progress.looping "noLooping")}} - - - - {{#if (eq countdown.progress.looping "increasing")}} - - {{else if (eq countdown.progress.looping "decreasing")}} - - {{/if}} - - - {{/unless}} - {{/if}}
-
+ {{/each}}
{{/each}} \ No newline at end of file