[Feature] In setting sheets, split by feature type and include descriptions (#2026)

This commit is contained in:
Carlos Fernandez 2026-06-21 17:53:41 -04:00 committed by GitHub
parent 0d59e37a80
commit cc16a726bf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 143 additions and 110 deletions

View file

@ -10,11 +10,7 @@ export default class DHAdversarySettings extends DHBaseActorSettings {
actions: { actions: {
addExperience: DHAdversarySettings.#addExperience, addExperience: DHAdversarySettings.#addExperience,
removeExperience: DHAdversarySettings.#removeExperience removeExperience: DHAdversarySettings.#removeExperience
}, }
dragDrop: [
{ dragSelector: null, dropSelector: '.tab.features' },
{ dragSelector: '.feature-item', dropSelector: null }
]
}; };
/**@override */ /**@override */
@ -38,7 +34,8 @@ export default class DHAdversarySettings extends DHBaseActorSettings {
}, },
features: { features: {
id: 'features', id: 'features',
template: 'systems/daggerheart/templates/sheets-settings/adversary-settings/features.hbs' template: 'systems/daggerheart/templates/sheets-settings/adversary-settings/features.hbs',
scrollable: ['']
} }
}; };
@ -54,12 +51,16 @@ export default class DHAdversarySettings extends DHBaseActorSettings {
async _prepareContext(options) { async _prepareContext(options) {
const context = await super._prepareContext(options); const context = await super._prepareContext(options);
const featureForms = Object.keys(CONFIG.DH.ITEM.featureForm); // Get feature groups. Uncategorized go to actions
context.features = context.document.system.features.sort((a, b) => const featureFormsTypes = ['passive', 'action', 'reaction'];
a.system.featureForm !== b.system.featureForm const features = this.document.system.features.sort((a, b) => a.sort - b.sort);
? featureForms.indexOf(a.system.featureForm) - featureForms.indexOf(b.system.featureForm) const featureGroups = featureFormsTypes.map(t => ({
: a.sort - b.sort featureForm: t,
); label: _loc(CONFIG.DH.ITEM.featureForm[t]),
features: features.filter(f => f.system.featureForm === t)
}));
featureGroups[1].features.push(...features.filter(f => !featureFormsTypes.includes(f.system.featureForm)));
context.featureGroups = featureGroups;
return context; return context;
} }

View file

@ -32,11 +32,13 @@ export default class DHEnvironmentSettings extends DHBaseActorSettings {
}, },
features: { features: {
id: 'features', id: 'features',
template: 'systems/daggerheart/templates/sheets-settings/environment-settings/features.hbs' template: 'systems/daggerheart/templates/sheets-settings/environment-settings/features.hbs',
scrollable: ['']
}, },
adversaries: { adversaries: {
id: 'adversaries', id: 'adversaries',
template: 'systems/daggerheart/templates/sheets-settings/environment-settings/adversaries.hbs' template: 'systems/daggerheart/templates/sheets-settings/environment-settings/adversaries.hbs',
scrollable: ['']
} }
}; };
@ -52,12 +54,16 @@ export default class DHEnvironmentSettings extends DHBaseActorSettings {
async _prepareContext(options) { async _prepareContext(options) {
const context = await super._prepareContext(options); const context = await super._prepareContext(options);
const featureForms = ['passive', 'action', 'reaction']; // Get feature groups. Uncategorized go to actions
context.features = context.document.system.features.sort((a, b) => const featureFormsTypes = ['passive', 'action', 'reaction'];
a.system.featureForm !== b.system.featureForm const features = this.document.system.features.sort((a, b) => a.sort - b.sort);
? featureForms.indexOf(a.system.featureForm) - featureForms.indexOf(b.system.featureForm) const featureGroups = featureFormsTypes.map(t => ({
: a.sort - b.sort featureForm: t,
); label: _loc(CONFIG.DH.ITEM.featureForm[t]),
features: features.filter(f => f.system.featureForm === t)
}));
featureGroups[1].features.push(...features.filter(f => !featureFormsTypes.includes(f.system.featureForm)));
context.featureGroups = featureGroups;
return context; return context;
} }

View file

@ -27,7 +27,8 @@ export default class DHNPCSettings extends DHBaseActorSettings {
}, },
features: { features: {
id: 'features', id: 'features',
template: 'systems/daggerheart/templates/sheets-settings/npc-settings/features.hbs' template: 'systems/daggerheart/templates/sheets-settings/npc-settings/features.hbs',
scrollable: ['']
} }
}; };
@ -43,12 +44,16 @@ export default class DHNPCSettings extends DHBaseActorSettings {
async _prepareContext(options) { async _prepareContext(options) {
const context = await super._prepareContext(options); const context = await super._prepareContext(options);
const featureForms = ['passive', 'action', 'reaction']; // Get feature groups. Uncategorized go to actions
context.features = context.document.system.features.sort((a, b) => const featureFormsTypes = ['passive', 'action', 'reaction'];
a.system.featureForm !== b.system.featureForm const features = this.document.system.features.sort((a, b) => a.sort - b.sort);
? featureForms.indexOf(a.system.featureForm) - featureForms.indexOf(b.system.featureForm) const featureGroups = featureFormsTypes.map(t => ({
: a.sort - b.sort featureForm: t,
); label: _loc(CONFIG.DH.ITEM.featureForm[t]),
features: features.filter(f => f.system.featureForm === t)
}));
featureGroups[1].features.push(...features.filter(f => !featureFormsTypes.includes(f.system.featureForm)));
context.featureGroups = featureGroups;
return context; return context;
} }

View file

@ -25,7 +25,7 @@ export default class DHBaseActorSettings extends DHApplicationMixin(ActorSheetV2
}, },
dragDrop: [ dragDrop: [
{ dragSelector: null, dropSelector: '.tab.features' }, { dragSelector: null, dropSelector: '.tab.features' },
{ dragSelector: '.feature-item', dropSelector: null } { dragSelector: '.feature-item, .inventory-item[data-type="feature"]', dropSelector: null }
] ]
}; };
@ -77,7 +77,7 @@ export default class DHBaseActorSettings extends DHApplicationMixin(ActorSheetV2
} }
async _onDragStart(event) { async _onDragStart(event) {
const featureItemEl = event.currentTarget.closest('.feature-item'); const featureItemEl = event.currentTarget.closest('.feature-item, .inventory-item[data-type="feature"]');
const feature = this.actor.items.get(featureItemEl?.dataset.itemId); const feature = this.actor.items.get(featureItemEl?.dataset.itemId);
if (feature && event.target.closest('.tab.features')) { if (feature && event.target.closest('.tab.features')) {
const featureData = { ...feature.toDragData(), fromInternal: true }; const featureData = { ...feature.toDragData(), fromInternal: true };
@ -100,4 +100,7 @@ export default class DHBaseActorSettings extends DHApplicationMixin(ActorSheetV2
await this.actor.createEmbeddedDocuments('Item', [itemData]); await this.actor.createEmbeddedDocuments('Item', [itemData]);
} }
} }
/** Setting sheets do not auto extend */
async _autoExpandDescriptions() {}
} }

View file

@ -4,6 +4,7 @@ import { getDocFromElement, getDocFromElementSync, tagifyElement } from '../../.
const typeSettingsMap = { const typeSettingsMap = {
character: 'extendCharacterDescriptions', character: 'extendCharacterDescriptions',
adversary: 'extendAdversaryDescriptions', adversary: 'extendAdversaryDescriptions',
npc: 'extendAdversaryDescriptions',
environment: 'extendEnvironmentDescriptions', environment: 'extendEnvironmentDescriptions',
ancestry: 'extendItemDescriptions', ancestry: 'extendItemDescriptions',
community: 'extendItemDescriptions', community: 'extendItemDescriptions',
@ -262,7 +263,7 @@ export default function DHApplicationMixin(Base) {
if (!!this.options.contextMenus.length) this._createContextMenus(); if (!!this.options.contextMenus.length) this._createContextMenus();
this.#autoExtendDescriptions(context); this._autoExpandDescriptions(context);
} }
/** @inheritDoc */ /** @inheritDoc */
@ -630,8 +631,9 @@ export default function DHApplicationMixin(Base) {
/** /**
* Extend inventory description when enabled in settings. * Extend inventory description when enabled in settings.
* @returns {Promise<void>} * @returns {Promise<void>}
* @protected
*/ */
async #autoExtendDescriptions(context) { async _autoExpandDescriptions(context) {
const inventoryItems = this.element.querySelectorAll('.inventory-item[data-item-uuid]'); const inventoryItems = this.element.querySelectorAll('.inventory-item[data-item-uuid]');
for (const el of inventoryItems) { for (const el of inventoryItems) {
// Get the doc uuid from the element // Get the doc uuid from the element
@ -734,7 +736,7 @@ export default function DHApplicationMixin(Base) {
* @type {ApplicationClickAction} * @type {ApplicationClickAction}
*/ */
static async #onCreateDoc(event, target) { static async #onCreateDoc(event, target) {
const { documentClass, type, inVault, disabled } = target.dataset; const { documentClass, type, inVault, disabled, featureForm } = target.dataset;
const parentIsItem = this.document.documentName === 'Item'; const parentIsItem = this.document.documentName === 'Item';
const featureOnCharacter = this.document.parent?.type === 'character' && type === 'feature'; const featureOnCharacter = this.document.parent?.type === 'character' && type === 'feature';
const parent = featureOnCharacter const parent = featureOnCharacter
@ -752,6 +754,7 @@ export default function DHApplicationMixin(Base) {
identifier: this.document.system.isMulticlass ? 'multiclass' : null identifier: this.document.system.isMulticlass ? 'multiclass' : null
}; };
} }
if (featureForm) systemData.featureForm = featureForm;
const cls = const cls =
type === 'action' ? game.system.api.models.actions.actionsTypes.base : getDocumentClass(documentClass); type === 'action' ? game.system.api.models.actions.actionsTypes.base : getDocumentClass(documentClass);

View file

@ -3,27 +3,31 @@
data-tab='{{tabs.features.id}}' data-tab='{{tabs.features.id}}'
data-group='{{tabs.features.group}}' data-group='{{tabs.features.group}}'
> >
<button type="button" class="add-feature-btn" data-action="createDoc" data-document-class="Item" data-type="feature"> {{#each featureGroups as |group|}}
{{localize "DOCUMENT.New" type=(localize "TYPES.Item.feature")}} <fieldset>
</button> <legend>
<fieldset> {{group.label}}
<legend>{{localize tabs.features.label}}</legend> <a data-action="createDoc" data-document-class="Item" data-type="feature" data-tooltip="{{localize 'DOCUMENT.Create' type=(localize "TYPES.Item.feature")}}" data-feature-form="{{group.featureForm}}">
<ul class="feature-list"> <i class="fa-solid fa-plus icon-button"></i>
{{#each @root.features as |feature|}} </a>
<li class="feature-item" data-item-id="{{feature.id}}" draggable="true"> </legend>
<img src="{{feature.img}}" alt=""> <ul class="feature-list">
<div class="label"> {{#each group.features as |feature|}}
<span>{{feature.name}}</span> {{> 'daggerheart.inventory-item'
</div> item=feature
<div class="controls"> type='feature'
<a data-action="editDoc" data-item-uuid="{{feature.uuid}}" data-tooltip="{{localize 'CONTROLS.CommonEdit'}}"><i class="fa-solid fa-pen-to-square"></i></a> actorType=@root.document.type
<a data-action="deleteDoc" data-item-uuid="{{feature.uuid}}" data-tooltip="{{localize 'CONTROLS.CommonDelete'}}"><i class="fa-solid fa-trash"></i></a> hideTags=true
</div> hideContextMenu=true
</li> hideResources=true
{{/each}} showActions=false
</ul> hideTooltip=true
<div class="features-dragger"> }}
<span>{{localize "DAGGERHEART.GENERAL.dropFeaturesHere"}}</span> {{/each}}
</div> </ul>
</fieldset> </fieldset>
{{/each}}
<div class="features-dragger">
<span>{{localize "DAGGERHEART.GENERAL.dropFeaturesHere"}}</span>
</div>
</section> </section>

View file

@ -3,24 +3,31 @@
data-tab='{{tabs.features.id}}' data-tab='{{tabs.features.id}}'
data-group='{{tabs.features.group}}' data-group='{{tabs.features.group}}'
> >
<button type="button" class="add-feature-btn" data-action="createDoc" data-document-class="Item" data-type="feature"> {{#each featureGroups as |group|}}
{{localize "DOCUMENT.New" type=(localize "TYPES.Item.feature")}} <fieldset>
</button> <legend>
<fieldset> {{group.label}}
<legend>{{localize tabs.features.label}}</legend> <a data-action="createDoc" data-document-class="Item" data-type="feature" data-tooltip="{{localize 'DOCUMENT.Create' type=(localize "TYPES.Item.feature")}}" data-feature-form="{{group.featureForm}}">
<ul class="feature-list"> <i class="fa-solid fa-plus icon-button"></i>
{{#each @root.features as |feature|}} </a>
<li class="feature-item" data-item-id="{{feature.id}}"> </legend>
<img src="{{feature.img}}" alt=""> <ul class="feature-list">
<div class="label"> {{#each group.features as |feature|}}
<span>{{feature.name}}</span> {{> 'daggerheart.inventory-item'
</div> item=feature
<div class="controls"> type='feature'
<a data-action="editDoc" data-item-uuid="{{feature.uuid}}" data-tooltip="{{localize 'CONTROLS.CommonEdit'}}"><i class="fa-solid fa-pen-to-square"></i></a> actorType=@root.document.type
<a data-action="deleteDoc" data-item-uuid="{{feature.uuid}}" data-tooltip="{{localize 'CONTROLS.CommonDelete'}}"><i class="fa-solid fa-trash"></i></a> hideTags=true
</div> hideContextMenu=true
</li> hideResources=true
{{/each}} showActions=false
</ul> hideTooltip=true
</fieldset> }}
{{/each}}
</ul>
</fieldset>
{{/each}}
<div class="features-dragger">
<span>{{localize "DAGGERHEART.GENERAL.dropFeaturesHere"}}</span>
</div>
</section> </section>

View file

@ -3,27 +3,31 @@
data-tab='{{tabs.features.id}}' data-tab='{{tabs.features.id}}'
data-group='{{tabs.features.group}}' data-group='{{tabs.features.group}}'
> >
<button type="button" class="add-feature-btn" data-action="createDoc" data-document-class="Item" data-type="feature"> {{#each featureGroups as |group|}}
{{localize "DOCUMENT.New" type=(localize "TYPES.Item.feature")}} <fieldset>
</button> <legend>
<fieldset> {{group.label}}
<legend>{{localize tabs.features.label}}</legend> <a data-action="createDoc" data-document-class="Item" data-type="feature" data-tooltip="{{localize 'DOCUMENT.Create' type=(localize "TYPES.Item.feature")}}" data-feature-form="{{group.featureForm}}">
<ul class="feature-list"> <i class="fa-solid fa-plus icon-button"></i>
{{#each @root.features as |feature|}} </a>
<li class="feature-item" data-item-id="{{feature.id}}" draggable="true"> </legend>
<img src="{{feature.img}}" alt=""> <ul class="feature-list">
<div class="label"> {{#each group.features as |feature|}}
<span>{{feature.name}}</span> {{> 'daggerheart.inventory-item'
</div> item=feature
<div class="controls"> type='feature'
<a data-action="editDoc" data-item-uuid="{{feature.uuid}}" data-tooltip="{{localize 'CONTROLS.CommonEdit'}}"><i class="fa-solid fa-pen-to-square"></i></a> actorType=@root.document.type
<a data-action="deleteDoc" data-item-uuid="{{feature.uuid}}" data-tooltip="{{localize 'CONTROLS.CommonDelete'}}"><i class="fa-solid fa-trash"></i></a> hideTags=true
</div> hideContextMenu=true
</li> hideResources=true
{{/each}} showActions=false
</ul> hideTooltip=true
<div class="features-dragger"> }}
<span>{{localize "DAGGERHEART.GENERAL.dropFeaturesHere"}}</span> {{/each}}
</div> </ul>
</fieldset> </fieldset>
{{/each}}
<div class="features-dragger">
<span>{{localize "DAGGERHEART.GENERAL.dropFeaturesHere"}}</span>
</div>
</section> </section>

View file

@ -27,17 +27,17 @@ Parameters:
> >
<div class="inventory-item-header {{#if hideContextMenu}}padded{{/if}}" {{#unless noExtensible}}data-action="toggleExtended" {{/unless}}> <div class="inventory-item-header {{#if hideContextMenu}}padded{{/if}}" {{#unless noExtensible}}data-action="toggleExtended" {{/unless}}>
{{!-- Image --}} {{!-- Image --}}
<div class="img-portait" data-action='{{ifThen item.usable "useItem" (ifThen <div class="img-portait" draggable="true"
(hasProperty item "toChat" ) "toChat" "editDoc" ) }}' {{#unless hideTooltip}} {{#if (eq type 'attack' )}} {{#unless (eq showActions false)}}data-action='{{ifThen item.usable "useItem" (ifThen (hasProperty item "toChat" ) "toChat" "editDoc" ) }}'{{/unless}}
data-tooltip="#attack#{{item.actor.uuid}}" {{else}} data-tooltip="#item#{{item.uuid}}" {{/if}} {{/unless}} draggable="true"> {{#unless hideTooltip}} {{#if (eq type 'attack' )}} data-tooltip="#attack#{{item.actor.uuid}}" {{else}} data-tooltip="#item#{{item.uuid}}" {{/if}} {{/unless}}>
<img src="{{item.img}}" class="item-img {{#if isActor}}actor-img{{/if}}" /> <img src="{{item.img}}" class="item-img {{#if isActor}}actor-img{{/if}}" />
{{#if item.usable}} {{#if (and item.usable (ne showActions false))}}
{{#if @root.isNPC}} {{#if @root.isNPC}}
<img class="roll-img d20" src="systems/daggerheart/assets/icons/dice/default/d20.svg" alt="d20"> <img class="roll-img d20" src="systems/daggerheart/assets/icons/dice/default/d20.svg" alt="d20">
{{else}} {{else}}
<img class="roll-img duality" src="systems/daggerheart/assets/icons/dice/duality/DualityBW.svg" alt="2d12"> <img class="roll-img duality" src="systems/daggerheart/assets/icons/dice/duality/DualityBW.svg" alt="2d12">
{{/if}}
{{/if}} {{/if}}
{{/if}}
</div> </div>
{{!-- Name & Tags --}} {{!-- Name & Tags --}}
@ -46,10 +46,10 @@ Parameters:
<span class="item-name">{{localize item.name}} {{#unless (or noExtensible (not item.system.description))}}<span class="expanded-icon"><i class="fa-solid fa-expand"></i></span>{{/unless}}</span> <span class="item-name">{{localize item.name}} {{#unless (or noExtensible (not item.system.description))}}<span class="expanded-icon"><i class="fa-solid fa-expand"></i></span>{{/unless}}</span>
{{!-- Tags Start --}} {{!-- Tags Start --}}
{{#if (not ../hideTags)}} {{#if (not hideTags)}}
{{#> "systems/daggerheart/templates/sheets/global/partials/item-tags.hbs" item}} {{#> "systems/daggerheart/templates/sheets/global/partials/item-tags.hbs" item}}
{{#if (eq ../type 'feature')}} {{#if (eq ../type 'feature')}}
{{#if (and system.featureForm (or (eq @root.document.type "adversary") (eq @root.document.type "environment")))}} {{#if (and system.featureForm (ne @root.document.type "character"))}}
<div class="tag feature-form"> <div class="tag feature-form">
<span class="recall-value">{{localize (concat "DAGGERHEART.CONFIG.FeatureForm." system.featureForm)}}</span> <span class="recall-value">{{localize (concat "DAGGERHEART.CONFIG.FeatureForm." system.featureForm)}}</span>
</div> </div>