From 9d353fe54afad5131a3adb76ac4a4d1899fbebb4 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Sat, 10 Jan 2026 15:32:32 +0100 Subject: [PATCH 1/2] ItemFeatures are now prepended to the description --- .../sheets/api/application-mixin.mjs | 18 ++++++++++-------- module/applications/sheets/api/base-item.mjs | 8 +------- module/data/item/armor.mjs | 16 ++++++++++++++++ module/data/item/base.mjs | 19 ++++++++++++++++++- module/data/item/weapon.mjs | 16 ++++++++++++++++ styles/less/global/inventory-item.less | 12 ++++++++++++ .../less/sheets/items/item-sheet-shared.less | 12 ++++++++++++ templates/sheets/items/armor/description.hbs | 6 ++++++ templates/sheets/items/weapon/description.hbs | 6 ++++++ 9 files changed, 97 insertions(+), 16 deletions(-) create mode 100644 templates/sheets/items/armor/description.hbs create mode 100644 templates/sheets/items/weapon/description.hbs diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs index d25a1a4e..903caa2a 100644 --- a/module/applications/sheets/api/application-mixin.mjs +++ b/module/applications/sheets/api/application-mixin.mjs @@ -211,7 +211,7 @@ export default function DHApplicationMixin(Base) { const step = event.key === 'ArrowUp' ? 1 : event.key === 'ArrowDown' ? -1 : 0; if (step !== 0) { handleUpdate(step); - deltaInput.dispatchEvent(new Event("change", { bubbles: true })); + deltaInput.dispatchEvent(new Event('change', { bubbles: true })); } }); @@ -222,7 +222,7 @@ export default function DHApplicationMixin(Base) { if (deltaInput === document.activeElement) { event.preventDefault(); handleUpdate(Math.sign(-1 * event.deltaY)); - deltaInput.dispatchEvent(new Event("change", { bubbles: true })); + deltaInput.dispatchEvent(new Event('change', { bubbles: true })); } }, { passive: false } @@ -236,7 +236,7 @@ export default function DHApplicationMixin(Base) { // Handle contenteditable for (const input of htmlElement.querySelectorAll('[contenteditable][data-property]')) { const property = input.dataset.property; - input.addEventListener("blur", () => { + input.addEventListener('blur', () => { const selection = document.getSelection(); if (input.contains(selection.anchorNode)) { selection.empty(); @@ -244,12 +244,12 @@ export default function DHApplicationMixin(Base) { this.document.update({ [property]: input.textContent }); }); - input.addEventListener("keydown", event => { - if (event.key === "Enter") input.blur(); + input.addEventListener('keydown', event => { + if (event.key === 'Enter') input.blur(); }); // Chrome sometimes add
, which aren't a problem for the value but are for the placeholder - input.addEventListener("input", () => input.querySelectorAll("br").forEach((i) => i.remove())); + input.addEventListener('input', () => input.querySelectorAll('br').forEach(i => i.remove())); } } @@ -585,7 +585,9 @@ export default function DHApplicationMixin(Base) { if (!doc || !descriptionElement) continue; // localize the description (idk if it's still necessary) - const description = game.i18n.localize(doc.system?.description ?? doc.description); + const description = doc.system?.getEnrichedDescription + ? await doc.system.getEnrichedDescription() + : game.i18n.localize(doc.system?.description ?? doc.description); // Enrich the description and attach it; const isAction = doc.documentName === 'Action'; @@ -736,7 +738,7 @@ export default function DHApplicationMixin(Base) { }; if (inVault) data['system.inVault'] = true; if (disabled) data.disabled = true; - if (type === "domainCard" && parent?.system.domains?.length) { + if (type === 'domainCard' && parent?.system.domains?.length) { data.system.domain = parent.system.domains[0]; } diff --git a/module/applications/sheets/api/base-item.mjs b/module/applications/sheets/api/base-item.mjs index 42ed9426..4ef5f048 100644 --- a/module/applications/sheets/api/base-item.mjs +++ b/module/applications/sheets/api/base-item.mjs @@ -76,16 +76,10 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) { /**@inheritdoc */ async _preparePartContext(partId, context, options) { await super._preparePartContext(partId, context, options); - const { TextEditor } = foundry.applications.ux; switch (partId) { case 'description': - const value = foundry.utils.getProperty(this.document, 'system.description') ?? ''; - context.enrichedDescription = await TextEditor.enrichHTML(value, { - relativeTo: this.item, - rollData: this.item.getRollData(), - secrets: this.item.isOwner - }); + context.enrichedDescription = await this.document.system.getEnrichedDescription(true); break; case 'effects': await this._prepareEffectsContext(context, options); diff --git a/module/data/item/armor.mjs b/module/data/item/armor.mjs index e35fae46..8f8e87ac 100644 --- a/module/data/item/armor.mjs +++ b/module/data/item/armor.mjs @@ -54,6 +54,22 @@ export default class DHArmor extends AttachableItem { ); } + /**@inheritdoc */ + async getDescriptionData(large) { + const baseDescription = await super.getDescriptionData(); + const allFeatures = CONFIG.DH.ITEM.allArmorFeatures(); + const features = this.armorFeatures.map(x => allFeatures[x.value]); + if (!features.length) return baseDescription; + + const prepend = await foundry.applications.handlebars.renderTemplate( + 'systems/daggerheart/templates/sheets/items/armor/description.hbs', + { features, large } + ); + + const mainDescription = baseDescription ? `\n
\n${baseDescription}` : ''; + return `${prepend}${mainDescription}`; + } + /**@inheritdoc */ async _preUpdate(changes, options, user) { const allowed = await super._preUpdate(changes, options, user); diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index 11be0a52..65760be7 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -8,7 +8,7 @@ * @property {boolean} isInventoryItem- Indicates whether items of this type is a Inventory Item */ -import { addLinkedItemsDiff, createScrollText, getScrollTextData, updateLinkedItemApps } from '../../helpers/utils.mjs'; +import { addLinkedItemsDiff, getScrollTextData, updateLinkedItemApps } from '../../helpers/utils.mjs'; import { ActionsField } from '../fields/actionField.mjs'; import FormulaField from '../fields/formulaField.mjs'; @@ -124,6 +124,23 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { return [source, page ? `pg ${page}.` : null].filter(x => x).join('. '); } + /** */ + async getDescriptionData() { + return this.description; + } + + /** */ + async getEnrichedDescription(large) { + if (!this.metadata.hasDescription) return ''; + + const description = await this.getDescriptionData(large); + return await foundry.applications.ux.TextEditor.implementation.enrichHTML(description, { + relativeTo: this, + rollData: this.getRollData(), + secrets: this.isOwner + }); + } + /** * Obtain a data object used to evaluate any dice rolls associated with this Item Type * @param {object} [options] - Options which modify the getRollData method. diff --git a/module/data/item/weapon.mjs b/module/data/item/weapon.mjs index 295cc0c5..205fb02a 100644 --- a/module/data/item/weapon.mjs +++ b/module/data/item/weapon.mjs @@ -110,6 +110,22 @@ export default class DHWeapon extends AttachableItem { ); } + /**@inheritdoc */ + async getDescriptionData(large) { + const baseDescription = await super.getDescriptionData(); + const allFeatures = CONFIG.DH.ITEM.allWeaponFeatures(); + const features = this.weaponFeatures.map(x => allFeatures[x.value]); + if (!features.length) return baseDescription; + + const prepend = await foundry.applications.handlebars.renderTemplate( + 'systems/daggerheart/templates/sheets/items/weapon/description.hbs', + { features, large } + ); + + const mainDescription = baseDescription ? `\n
\n${baseDescription}` : ''; + return `${prepend}${mainDescription}`; + } + prepareDerivedData() { this.attack.roll.trait = this.rules.attack.roll.trait ?? this.attack.roll.trait; } diff --git a/styles/less/global/inventory-item.less b/styles/less/global/inventory-item.less index c8a29795..a17e2b35 100644 --- a/styles/less/global/inventory-item.less +++ b/styles/less/global/inventory-item.less @@ -211,6 +211,18 @@ ul { list-style: disc; } + + .feature-descriptions { + .features-header { + font-size: 14px; + font-weight: bold; + text-decoration: underline; + + &.large { + font-size: 18px; + } + } + } } } .item-resources { diff --git a/styles/less/sheets/items/item-sheet-shared.less b/styles/less/sheets/items/item-sheet-shared.less index d0a8cc48..54b9c8c2 100644 --- a/styles/less/sheets/items/item-sheet-shared.less +++ b/styles/less/sheets/items/item-sheet-shared.less @@ -10,4 +10,16 @@ font-family: @font-body; color: light-dark(@chat-blue-bg, @beige-50); } + + .feature-descriptions { + .features-header { + font-size: 14px; + font-weight: bold; + text-decoration: underline; + + &.large { + font-size: 18px; + } + } + } } diff --git a/templates/sheets/items/armor/description.hbs b/templates/sheets/items/armor/description.hbs new file mode 100644 index 00000000..efd5c1e5 --- /dev/null +++ b/templates/sheets/items/armor/description.hbs @@ -0,0 +1,6 @@ +
+
{{localize "DAGGERHEART.SETTINGS.Homebrew.itemFeatures"}}
+ {{#each features as | feature |}} +
{{localize feature.label}}: {{{localize feature.description}}}
+ {{/each}} +
\ No newline at end of file diff --git a/templates/sheets/items/weapon/description.hbs b/templates/sheets/items/weapon/description.hbs new file mode 100644 index 00000000..efd5c1e5 --- /dev/null +++ b/templates/sheets/items/weapon/description.hbs @@ -0,0 +1,6 @@ +
+
{{localize "DAGGERHEART.SETTINGS.Homebrew.itemFeatures"}}
+ {{#each features as | feature |}} +
{{localize feature.label}}: {{{localize feature.description}}}
+ {{/each}} +
\ No newline at end of file From 4a027e85912892dcf74fc57006b35d53ed902a5b Mon Sep 17 00:00:00 2001 From: WBHarry Date: Sat, 10 Jan 2026 15:48:40 +0100 Subject: [PATCH 2/2] . --- module/applications/sheets/api/base-item.mjs | 4 +++- module/data/item/armor.mjs | 4 ++-- module/data/item/base.mjs | 18 +++++++++++++----- module/data/item/weapon.mjs | 4 ++-- module/documents/tooltipManager.mjs | 8 ++++++-- styles/less/ux/tooltip/tooltip.less | 15 +++++++++++++-- templates/sheets/items/armor/description.hbs | 4 +++- templates/sheets/items/weapon/description.hbs | 4 +++- 8 files changed, 45 insertions(+), 16 deletions(-) diff --git a/module/applications/sheets/api/base-item.mjs b/module/applications/sheets/api/base-item.mjs index 4ef5f048..00448e95 100644 --- a/module/applications/sheets/api/base-item.mjs +++ b/module/applications/sheets/api/base-item.mjs @@ -79,7 +79,9 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) { switch (partId) { case 'description': - context.enrichedDescription = await this.document.system.getEnrichedDescription(true); + context.enrichedDescription = await this.document.system.getEnrichedDescription({ + headerStyle: 'large' + }); break; case 'effects': await this._prepareEffectsContext(context, options); diff --git a/module/data/item/armor.mjs b/module/data/item/armor.mjs index 8f8e87ac..c0de0eeb 100644 --- a/module/data/item/armor.mjs +++ b/module/data/item/armor.mjs @@ -55,7 +55,7 @@ export default class DHArmor extends AttachableItem { } /**@inheritdoc */ - async getDescriptionData(large) { + async getDescriptionData(options = {}) { const baseDescription = await super.getDescriptionData(); const allFeatures = CONFIG.DH.ITEM.allArmorFeatures(); const features = this.armorFeatures.map(x => allFeatures[x.value]); @@ -63,7 +63,7 @@ export default class DHArmor extends AttachableItem { const prepend = await foundry.applications.handlebars.renderTemplate( 'systems/daggerheart/templates/sheets/items/armor/description.hbs', - { features, large } + { features, headerStyle: options.headerStyle } ); const mainDescription = baseDescription ? `\n
\n${baseDescription}` : ''; diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index 65760be7..c98631cb 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -124,16 +124,24 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { return [source, page ? `pg ${page}.` : null].filter(x => x).join('. '); } - /** */ - async getDescriptionData() { + /** + * Augments the description for the item with type specific info to display. Implemented in applicable item subtypes. + * @param {object} [options] - Options that modify the styling of the rendered template. { headerStyle: undefined|'none'|'large' } + * @returns {string} + */ + async getDescriptionData(_options) { return this.description; } - /** */ - async getEnrichedDescription(large) { + /** + * Gets the enriched and augmented description for the item. + * @param {object} [options] - Options that modify the styling of the rendered template. { headerStyle: undefined|'none'|'large' } + * @returns {string} + */ + async getEnrichedDescription(options) { if (!this.metadata.hasDescription) return ''; - const description = await this.getDescriptionData(large); + const description = await this.getDescriptionData(options); return await foundry.applications.ux.TextEditor.implementation.enrichHTML(description, { relativeTo: this, rollData: this.getRollData(), diff --git a/module/data/item/weapon.mjs b/module/data/item/weapon.mjs index 205fb02a..48a53e02 100644 --- a/module/data/item/weapon.mjs +++ b/module/data/item/weapon.mjs @@ -111,7 +111,7 @@ export default class DHWeapon extends AttachableItem { } /**@inheritdoc */ - async getDescriptionData(large) { + async getDescriptionData(options = {}) { const baseDescription = await super.getDescriptionData(); const allFeatures = CONFIG.DH.ITEM.allWeaponFeatures(); const features = this.weaponFeatures.map(x => allFeatures[x.value]); @@ -119,7 +119,7 @@ export default class DHWeapon extends AttachableItem { const prepend = await foundry.applications.handlebars.renderTemplate( 'systems/daggerheart/templates/sheets/items/weapon/description.hbs', - { features, large } + { features, headerStyle: options.headerStyle } ); const mainDescription = baseDescription ? `\n
\n${baseDescription}` : ''; diff --git a/module/documents/tooltipManager.mjs b/module/documents/tooltipManager.mjs index 3ea6703c..b25a4b21 100644 --- a/module/documents/tooltipManager.mjs +++ b/module/documents/tooltipManager.mjs @@ -220,12 +220,16 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti for (const [index, itemValue] of pathValue.entries()) { const itemIsAction = itemValue instanceof game.system.api.models.actions.actionsTypes.base; const value = itemIsAction || !itemValue?.item ? itemValue : itemValue.item; - const enrichedValue = await TextEditor.enrichHTML(value.system?.description ?? value.description); + const enrichedValue = + (await value.system?.getEnrichedDescription?.({ headerStyle: 'none' })) ?? + (await TextEditor.enrichHTML(value.system?.description ?? value.description)); if (itemIsAction) value.enrichedDescription = enrichedValue; else foundry.utils.setProperty(item, `${basePath}.${index}.enrichedDescription`, enrichedValue); } } else { - const enrichedValue = await TextEditor.enrichHTML(pathValue); + const enrichedValue = + (await item.system?.getEnrichedDescription?.({ headerStyle: 'none' })) ?? + (await TextEditor.enrichHTML(pathValue)); foundry.utils.setProperty( item, `${data.path ? `${data.path}.` : ''}enriched${data.name.capitalize()}`, diff --git a/styles/less/ux/tooltip/tooltip.less b/styles/less/ux/tooltip/tooltip.less index bfe0c01f..970c2ca4 100644 --- a/styles/less/ux/tooltip/tooltip.less +++ b/styles/less/ux/tooltip/tooltip.less @@ -11,7 +11,7 @@ aside[role='tooltip']:has(div.daggerheart.dh-style.tooltip.card-style) { width: 18rem; background-image: url('../assets/parchments/dh-parchment-dark.png'); outline: 1px solid light-dark(@dark-80, @beige-80); - box-shadow: 0 0 25px rgba(0, 0, 0, 0.80); + box-shadow: 0 0 25px rgba(0, 0, 0, 0.8); .tooltip-title { font-size: var(--font-size-20); @@ -235,7 +235,6 @@ aside[role='tooltip'].locked-tooltip:has(div.daggerheart.dh-style.tooltip.card-s .theme-light aside[role='tooltip'].locked-tooltip:has(div.daggerheart.dh-style.tooltip) { box-shadow: 0 0 25px @dark-blue-90; outline: 1px solid light-dark(@dark-blue, @golden); - } #tooltip, @@ -283,6 +282,18 @@ aside[role='tooltip'].locked-tooltip:has(div.daggerheart.dh-style.tooltip.card-s .tooltip-description { font-style: italic; text-align: start; + + .feature-descriptions { + .features-header { + font-size: 14px; + font-weight: bold; + text-decoration: underline; + + &.large { + font-size: 18px; + } + } + } } .simple-info { diff --git a/templates/sheets/items/armor/description.hbs b/templates/sheets/items/armor/description.hbs index efd5c1e5..d2c67604 100644 --- a/templates/sheets/items/armor/description.hbs +++ b/templates/sheets/items/armor/description.hbs @@ -1,5 +1,7 @@
-
{{localize "DAGGERHEART.SETTINGS.Homebrew.itemFeatures"}}
+ {{#unless (eq headerStyle 'none')}} +
{{localize "DAGGERHEART.SETTINGS.Homebrew.itemFeatures"}}
+ {{/unless}} {{#each features as | feature |}}
{{localize feature.label}}: {{{localize feature.description}}}
{{/each}} diff --git a/templates/sheets/items/weapon/description.hbs b/templates/sheets/items/weapon/description.hbs index efd5c1e5..d2c67604 100644 --- a/templates/sheets/items/weapon/description.hbs +++ b/templates/sheets/items/weapon/description.hbs @@ -1,5 +1,7 @@
-
{{localize "DAGGERHEART.SETTINGS.Homebrew.itemFeatures"}}
+ {{#unless (eq headerStyle 'none')}} +
{{localize "DAGGERHEART.SETTINGS.Homebrew.itemFeatures"}}
+ {{/unless}} {{#each features as | feature |}}
{{localize feature.label}}: {{{localize feature.description}}}
{{/each}}