From 3e83730c342f1981c9165cf24aadcdcbf897c49d Mon Sep 17 00:00:00 2001 From: Chris Ryan <73275196+chrisryan10@users.noreply.github.com> Date: Sat, 9 Aug 2025 21:39:19 +1000 Subject: [PATCH 1/3] Implementation of Dice So Nice settings preview #710 (#732) * Fix for #695 * Implements DiceSoNice preview in config settings #710 * Remove incorrect class * Fix Preview button position * Remove extra line * Fix formatting --------- Co-authored-by: Chris Ryan --- .../settings/appearanceSettings.mjs | 20 ++++++++++++++++++- module/config/generalConfig.mjs | 15 +++++++------- styles/less/global/elements.less | 10 ++++++++++ templates/settings/appearance-settings.hbs | 8 +++++++- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/module/applications/settings/appearanceSettings.mjs b/module/applications/settings/appearanceSettings.mjs index 491c9799..f0310477 100644 --- a/module/applications/settings/appearanceSettings.mjs +++ b/module/applications/settings/appearanceSettings.mjs @@ -1,4 +1,5 @@ import DhAppearance from '../../data/settings/Appearance.mjs'; +import { getDiceSoNicePreset } from '../../config/generalConfig.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -25,7 +26,8 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App }, actions: { reset: this.reset, - save: this.save + save: this.save, + preview: this.preview }, form: { handler: this.updateData, submitOnChange: true } }; @@ -89,6 +91,22 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App this.render(); } + static async preview() { + const source = this.settings._source.diceSoNice[this.tabGroups.diceSoNice]; + let faces = 'd12'; + switch (this.tabGroups.diceSoNice) { + case 'advantage': + case 'disadvantage': + faces = 'd6'; + } + const preset = await getDiceSoNicePreset(source, faces); + const diceSoNiceRoll = await new Roll(`1${faces}`).evaluate(); + diceSoNiceRoll.dice[0].options.appearance = preset.appearance; + diceSoNiceRoll.dice[0].options.modelFile = preset.modelFile; + + await game.dice3d.showForRoll(diceSoNiceRoll, game.user, false); + } + static async reset() { this.settings = new DhAppearance(); this.render(); diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index 7785b6a6..bd6ef44e 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -494,9 +494,7 @@ export const diceSetNumbers = { flat: 'Flat' }; -export const getDiceSoNicePresets = async (hopeFaces, fearFaces, advantageFaces = 'd6', disadvantageFaces = 'd6') => { - const { diceSoNice } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance); - const getPreset = async (type, faces) => { +export const getDiceSoNicePreset = async (type, faces) => { const system = game.dice3d.DiceFactory.systems.get(type.system).dice.get(faces); if (!system) { ui.notifications.error( @@ -523,11 +521,14 @@ export const getDiceSoNicePresets = async (hopeFaces, fearFaces, advantageFaces }; }; +export const getDiceSoNicePresets = async (hopeFaces, fearFaces, advantageFaces = 'd6', disadvantageFaces = 'd6') => { + const { diceSoNice } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance); + return { - hope: await getPreset(diceSoNice.hope, hopeFaces), - fear: await getPreset(diceSoNice.fear, fearFaces), - advantage: await getPreset(diceSoNice.advantage, advantageFaces), - disadvantage: await getPreset(diceSoNice.disadvantage, disadvantageFaces) + hope: await getDiceSoNicePreset(diceSoNice.hope, hopeFaces), + fear: await getDiceSoNicePreset(diceSoNice.fear, fearFaces), + advantage: await getDiceSoNicePreset(diceSoNice.advantage, advantageFaces), + disadvantage: await getDiceSoNicePreset(diceSoNice.disadvantage, disadvantageFaces) }; }; diff --git a/styles/less/global/elements.less b/styles/less/global/elements.less index 7f8cdd94..688df165 100755 --- a/styles/less/global/elements.less +++ b/styles/less/global/elements.less @@ -571,6 +571,16 @@ white-space: nowrap; } } + + .button-container { + display: grid; + grid-template-columns: 1fr; + gap: 10px; + text-align: center; + display: flex; + justify-content: center; + width: 100% + } } footer { diff --git a/templates/settings/appearance-settings.hbs b/templates/settings/appearance-settings.hbs index e7c1d757..ab30eefd 100644 --- a/templates/settings/appearance-settings.hbs +++ b/templates/settings/appearance-settings.hbs @@ -69,7 +69,13 @@ {{selectOptions diceSoNiceMaterials selected=diceTab.source.material valueAttr="key" labelAttr="name" localize=true}} - +
+ +
+ {{/if}} From 7f3a83564b96a191a9deb563e93de1637c6a7655 Mon Sep 17 00:00:00 2001 From: Murilo Brito <91566541+moliloo@users.noreply.github.com> Date: Sat, 9 Aug 2025 08:39:56 -0300 Subject: [PATCH 2/3] remove very far field from variant rules range section (#730) --- templates/settings/variant-rules.hbs | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/settings/variant-rules.hbs b/templates/settings/variant-rules.hbs index 03027f69..5cc5c90c 100644 --- a/templates/settings/variant-rules.hbs +++ b/templates/settings/variant-rules.hbs @@ -11,7 +11,6 @@ {{formGroup settingFields.schema.fields.rangeMeasurement.fields.veryClose value=settingFields._source.rangeMeasurement.veryClose localize=true}} {{formGroup settingFields.schema.fields.rangeMeasurement.fields.close value=settingFields._source.rangeMeasurement.close localize=true}} {{formGroup settingFields.schema.fields.rangeMeasurement.fields.far value=settingFields._source.rangeMeasurement.far localize=true}} - {{formGroup settingFields.schema.fields.rangeMeasurement.fields.veryFar value=settingFields._source.rangeMeasurement.veryFar localize=true}}
From 1c000c7cfe912c8b30dcdbc42d120eb8b564d137 Mon Sep 17 00:00:00 2001 From: Murilo Brito <91566541+moliloo@users.noreply.github.com> Date: Sat, 9 Aug 2025 08:40:20 -0300 Subject: [PATCH 3/3] fix item list columns and pretier itemBrowser.mjs (#729) --- module/applications/ui/itemBrowser.mjs | 82 +++++++++---------- styles/less/ui/item-browser/item-browser.less | 6 +- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/module/applications/ui/itemBrowser.mjs b/module/applications/ui/itemBrowser.mjs index 69de5249..3763bd36 100644 --- a/module/applications/ui/itemBrowser.mjs +++ b/module/applications/ui/itemBrowser.mjs @@ -17,7 +17,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { this.config = CONFIG.DH.ITEMBROWSER.compendiumConfig; this.presets = options.presets; - if(this.presets?.compendium && this.presets?.folder) + if (this.presets?.compendium && this.presets?.folder) ItemBrowser.selectFolder.call(this, null, null, this.presets.compendium, this.presets.folder); } @@ -26,7 +26,6 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { id: 'itemBrowser', classes: ['daggerheart', 'dh-style', 'dialog', 'compendium-browser'], tag: 'div', - // title: 'Item Browser', window: { frame: true, title: 'Compendium Browser', @@ -41,9 +40,8 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { sortList: this.sortList }, position: { - top: 330, - left: 120, - width: 800, + left: 100, + width: 850, height: 600 } }; @@ -88,16 +86,14 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { /** @inheritDoc */ async _preFirstRender(context, options) { - if(context.presets?.render?.noFolder || context.presets?.render?.lite) - options.position.width = 600; - + if (context.presets?.render?.noFolder || context.presets?.render?.lite) options.position.width = 600; + await super._preFirstRender(context, options); } /** @inheritDoc */ async _preRender(context, options) { - - if(context.presets?.render?.noFolder || context.presets?.render?.lite) + if (context.presets?.render?.noFolder || context.presets?.render?.lite) options.parts.splice(options.parts.indexOf('sidebar'), 1); await super._preRender(context, options); @@ -110,18 +106,17 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { this._createSearchFilter(); this._createFilterInputs(); this._createDragProcess(); - - if(context.presets?.render?.lite) - this.element.classList.add('lite'); - - if(context.presets?.render?.noFolder) - this.element.classList.add('no-folder'); - - if(context.presets?.render?.noFilter) - this.element.classList.add('no-filter'); - if(this.presets?.filter) { - Object.entries(this.presets.filter).forEach(([k,v]) => this.fieldFilter.find(c => c.name === k).value = v.value); + if (context.presets?.render?.lite) this.element.classList.add('lite'); + + if (context.presets?.render?.noFolder) this.element.classList.add('no-folder'); + + if (context.presets?.render?.noFilter) this.element.classList.add('no-filter'); + + if (this.presets?.filter) { + Object.entries(this.presets.filter).forEach( + ([k, v]) => (this.fieldFilter.find(c => c.name === k).value = v.value) + ); await this._onInputFilterBrowser(); } } @@ -198,6 +193,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { formatLabel(item, field) { const property = foundry.utils.getProperty(item, field.key); + if (Array.isArray(property)) property.join(', '); if (typeof field.format !== 'function') return property ?? '-'; return field.format(property); } @@ -315,19 +311,18 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { async _onInputFilterBrowser(event) { this.#filteredItems.browser.input.clear(); - if(event) this.fieldFilter.find(f => f.name === event.target.name).value = event.target.value; + if (event) this.fieldFilter.find(f => f.name === event.target.name).value = event.target.value; for (const li of this.element.querySelectorAll('.item-container')) { const itemUUID = li.dataset.itemUuid, item = this.items.find(i => i.uuid === itemUUID); - - if(!item) continue; + + if (!item) continue; const matchesMenu = this.fieldFilter.length === 0 || - this.fieldFilter.every(f => ( - !f.value && f.value !== false) || - ItemBrowser.evaluateFilter(item, this.createFilterData(f)) + this.fieldFilter.every( + f => (!f.value && f.value !== false) || ItemBrowser.evaluateFilter(item, this.createFilterData(f)) ); if (matchesMenu) this.#filteredItems.browser.input.add(item.id); @@ -335,21 +330,21 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { li.hidden = !(search.has(item.id) && matchesMenu); } } - + /** * Foundry evaluateFilter doesn't allow you to match if filter values are included into item data - * @param {*} obj - * @param {*} filter + * @param {*} obj + * @param {*} filter */ static evaluateFilter(obj, filter) { let docValue = foundry.utils.getProperty(obj, filter.field); let filterValue = filter.value; switch (filter.operator) { - case "contains2": + case 'contains2': filterValue = Array.isArray(filterValue) ? filterValue : [filterValue]; docValue = Array.isArray(docValue) ? docValue : [docValue]; return docValue.some(dv => filterValue.includes(dv)); - case "contains3": + case 'contains3': return docValue.some(f => f.value === filterValue); default: return foundry.applications.ux.SearchFilter.evaluateFilter(obj, filter); @@ -373,30 +368,33 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { this.render({ force: true }); } - static getFolderConfig(folder, property = "columns") { - if(!folder) return []; + static getFolderConfig(folder, property = 'columns') { + if (!folder) return []; return folder[property] ?? CONFIG.DH.ITEMBROWSER.typeConfig[folder.listType]?.[property] ?? []; } static sortList(_, target) { const key = target.dataset.sortKey, - type = !target.dataset.sortType || target.dataset.sortType === "DESC" ? "ASC" : "DESC", - itemListContainer = target.closest(".compendium-results").querySelector(".item-list"), - itemList = itemListContainer.querySelectorAll(".item-container"); + type = !target.dataset.sortType || target.dataset.sortType === 'DESC' ? 'ASC' : 'DESC', + itemListContainer = target.closest('.compendium-results').querySelector('.item-list'), + itemList = itemListContainer.querySelectorAll('.item-container'); - target.closest(".item-list-header").querySelectorAll('[data-sort-key]').forEach(b => b.dataset.sortType = ""); + target + .closest('.item-list-header') + .querySelectorAll('[data-sort-key]') + .forEach(b => (b.dataset.sortType = '')); target.dataset.sortType = type; - + const newOrder = [...itemList].reverse().sort((a, b) => { const aProp = a.querySelector(`[data-item-key="${key}"]`), - bProp = b.querySelector(`[data-item-key="${key}"]`) - if(type === "DESC") { + bProp = b.querySelector(`[data-item-key="${key}"]`); + if (type === 'DESC') { return aProp.innerText < bProp.innerText ? 1 : -1; } else { return aProp.innerText > bProp.innerText ? 1 : -1; } }); - + itemListContainer.replaceChildren(...newOrder); } diff --git a/styles/less/ui/item-browser/item-browser.less b/styles/less/ui/item-browser/item-browser.less index 3b13056b..e7ff3b12 100644 --- a/styles/less/ui/item-browser/item-browser.less +++ b/styles/less/ui/item-browser/item-browser.less @@ -227,14 +227,16 @@ display: flex; > * { - flex: 1; + flex: 2.5; + text-align: center; } .item-list-img { width: 40px; flex: unset; } .item-list-name { - flex-grow: 3 !important; + flex-grow: 3; + text-align: start; } }