diff --git a/lang/en.json b/lang/en.json index 6060a141..06ababf5 100755 --- a/lang/en.json +++ b/lang/en.json @@ -2135,6 +2135,10 @@ "plural": "Experiences" }, "failure": "Failure", + "favorite": { + "single": "Favorite", + "plural": "Favorites" + }, "fear": "Fear", "features": "Features", "formula": "Formula", diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index 594269be..e7733826 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -33,7 +33,7 @@ export default class CharacterSheet extends DHBaseActorSheet { advanceResourceDie: CharacterSheet.#advanceResourceDie, cancelBeastform: CharacterSheet.#cancelBeastform, useDowntime: this.useDowntime, - viewParty: CharacterSheet.#viewParty, + viewParty: CharacterSheet.#viewParty }, window: { resizable: true, @@ -49,6 +49,10 @@ export default class CharacterSheet extends DHBaseActorSheet { { dragSelector: '[data-item-id][draggable="true"], [data-item-id] [draggable="true"]', dropSelector: null + }, + { + dragSelector: null, + dropSelector: '.character-sidebar-sheet' } ], contextMenus: [ @@ -261,6 +265,24 @@ export default class CharacterSheet extends DHBaseActorSheet { */ async _prepareSidebarContext(context, _options) { context.isDeath = this.document.system.deathMoveViable; + context.sidebarFavoritesEmpty = this.document.system.sidebarFavorites.length === 0; + + const initialFavorites = this.document.system.usedUnarmed + ? { + equipment: { + label: 'DAGGERHEART.GENERAL.equipment', + items: [{ type: 'attack', value: this.document.system.usedUnarmed }] + } + } + : {}; + context.sidebarFavorites = this.document.system.sidebarFavorites.reduce((acc, item) => { + const type = item.type === 'domainCard' ? item.type : 'equipment'; + const label = type === 'domainCard' ? 'DAGGERHEART.GENERAL.loadout' : 'DAGGERHEART.GENERAL.equipment'; + if (!acc[type]) acc[type] = { label, items: [] }; + acc[type].items.push({ type: item.type, value: item }); + + return acc; + }, initialFavorites); } /** @@ -310,7 +332,9 @@ export default class CharacterSheet extends DHBaseActorSheet { icon: 'fa-solid fa-arrow-up', condition: target => { const doc = getDocFromElementSync(target); - return doc && doc.system.inVault; + const inCharacterSidebar = + this.document.type === 'character' && target.closest('.items-sidebar-list'); + return doc && doc.system.inVault && !inCharacterSidebar; }, callback: async target => { const doc = await getDocFromElement(target); @@ -324,7 +348,9 @@ export default class CharacterSheet extends DHBaseActorSheet { icon: 'fa-solid fa-bolt-lightning', condition: target => { const doc = getDocFromElementSync(target); - return doc && doc.system.inVault; + const inCharacterSidebar = + this.document.type === 'character' && target.closest('.items-sidebar-list'); + return doc && doc.system.inVault && !inCharacterSidebar; }, callback: async (target, event) => { const doc = await getDocFromElement(target); @@ -338,15 +364,20 @@ export default class CharacterSheet extends DHBaseActorSheet { } const type = 'effect'; const cls = game.system.api.models.actions.actionsTypes[type]; - const action = new cls({ - ...cls.getSourceConfig(doc.system), - type: type, - chatDisplay: false, - cost: [{ - key: 'stress', - value: doc.system.recallCost - }] - }, { parent: doc.system }); + const action = new cls( + { + ...cls.getSourceConfig(doc.system), + type: type, + chatDisplay: false, + cost: [ + { + key: 'stress', + value: doc.system.recallCost + } + ] + }, + { parent: doc.system } + ); const config = await action.use(event); if (config) { return doc.update({ 'system.inVault': false }); @@ -358,7 +389,9 @@ export default class CharacterSheet extends DHBaseActorSheet { icon: 'fa-solid fa-arrow-down', condition: target => { const doc = getDocFromElementSync(target); - return doc && !doc.system.inVault; + const inCharacterSidebar = + this.document.type === 'character' && target.closest('.items-sidebar-list'); + return doc && !doc.system.inVault && !inCharacterSidebar; }, callback: async target => (await getDocFromElement(target)).update({ 'system.inVault': true }) } @@ -900,32 +933,32 @@ export default class CharacterSheet extends DHBaseActorSheet { return; } - const buttons = parties.map((p) => { - const button = document.createElement("button"); - button.type = "button"; - button.classList.add("plain"); - const img = document.createElement("img"); + const buttons = parties.map(p => { + const button = document.createElement('button'); + button.type = 'button'; + button.classList.add('plain'); + const img = document.createElement('img'); img.src = p.img; button.append(img); - const name = document.createElement("span"); + const name = document.createElement('span'); name.textContent = p.name; button.append(name); - button.addEventListener("click", () => { + button.addEventListener('click', () => { p.sheet?.render({ force: true }); game.tooltip.dismissLockedTooltips(); }); return button; }); - const html = document.createElement("div"); - html.classList.add("party-list"); + const html = document.createElement('div'); + html.classList.add('party-list'); html.append(...buttons); - + game.tooltip.dismissLockedTooltips(); game.tooltip.activate(target, { html, - locked: true, - }) + locked: true + }); } /** @@ -948,6 +981,11 @@ export default class CharacterSheet extends DHBaseActorSheet { } async _onDropItem(event, item) { + const sidebarDrop = event.target.closest('.character-sidebar-sheet'); + if (sidebarDrop) { + return this._onSidebarDrop(event, item); + } + if (this.document.uuid === item.parent?.uuid) { return super._onDropItem(event, item); } @@ -986,4 +1024,18 @@ export default class CharacterSheet extends DHBaseActorSheet { itemData = itemData instanceof Array ? itemData : [itemData]; return this.document.createEmbeddedDocuments('Item', itemData); } + + async _onSidebarDrop(event, item) { + if (!item.testUserPermission(game.user, 'OWNER')) return; + + if (!(item instanceof game.system.api.documents.DHItem)) return; + if (!this.document.items.get(item.id)) return; + + const allowedItemTypes = ['domainCard', 'feature', 'weapon', 'armor', 'loot', 'consumable']; + if (!allowedItemTypes.includes(item.type)) return; + + if (this.document.system.sidebarFavorites.some(x => x.id === item.id)) return; + + this.document.update({ 'system.sidebarFavorites': [...this.document.system.sidebarFavorites, item] }); + } } diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs index 903caa2a..2d83b54b 100644 --- a/module/applications/sheets/api/application-mixin.mjs +++ b/module/applications/sheets/api/application-mixin.mjs @@ -539,6 +539,39 @@ export default function DHApplicationMixin(Base) { } }); + options.push({ + name: 'Unfavorite', + icon: 'fa-regular fa-star', + condition: target => { + return this.document.type === 'character' && target.closest('.items-sidebar-list'); + }, + callback: async (target, _event) => { + const doc = await getDocFromElement(target); + this.document.update({ + 'system.sidebarFavorites': this.document.system.sidebarFavorites.filter(x => x.id !== doc.id) + }); + } + }); + + options.push({ + name: 'Favorite', + icon: 'fa-solid fa-star', + condition: target => { + const doc = getDocFromElementSync(target); + return ( + !(doc instanceof game.system.api.documents.DhActiveEffect) && + this.document.type === 'character' && + !target.closest('.items-sidebar-list') + ); + }, + callback: async (target, _event) => { + const doc = await getDocFromElement(target); + this.document.update({ + 'system.sidebarFavorites': [...this.document.system.sidebarFavorites, doc] + }); + } + }); + return options.map(option => ({ ...option, icon: `` diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index eba46f10..4bb47ebc 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -5,6 +5,7 @@ import BaseDataActor, { commonActorRules } from './base.mjs'; import { attributeField, resourceField, stressDamageReductionRule, bonusField } from '../fields/actorField.mjs'; import { ActionField } from '../fields/actionField.mjs'; import DHCharacterSettings from '../../applications/sheets-configs/character-settings.mjs'; +import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs'; export default class DhCharacter extends BaseDataActor { /**@override */ @@ -284,7 +285,8 @@ export default class DhCharacter extends BaseDataActor { burden: new fields.SchemaField({ ignore: new fields.BooleanField() }) - }) + }), + sidebarFavorites: new ForeignDocumentUUIDArrayField({ type: 'Item' }) }; } diff --git a/styles/less/sheets/actors/character/sidebar.less b/styles/less/sheets/actors/character/sidebar.less index 04baf2b9..976dffcd 100644 --- a/styles/less/sheets/actors/character/sidebar.less +++ b/styles/less/sheets/actors/character/sidebar.less @@ -561,6 +561,25 @@ overflow-y: auto; scrollbar-color: light-dark(@dark-blue, @golden) transparent; } + + .empty-favorites { + width: 100%; + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + height: 40px; + border: 1px dashed light-dark(@dark-blue-50, @beige-50); + border-radius: 3px; + color: light-dark(@dark-blue-50, @beige-50); + text-align: center; + margin-bottom: 10px; + margin-left: 4px; + + span { + width: 250px; + } + } } .equipment-section, diff --git a/templates/sheets/actors/character/sidebar.hbs b/templates/sheets/actors/character/sidebar.hbs index 0db2bf42..58827518 100644 --- a/templates/sheets/actors/character/sidebar.hbs +++ b/templates/sheets/actors/character/sidebar.hbs @@ -96,45 +96,27 @@
-
-
- -

{{localize "DAGGERHEART.GENERAL.equipment"}}

- -
- -
-
-
- -

{{localize "DAGGERHEART.GENERAL.loadout"}}

- -
- -
+ {{#if sidebarFavoritesEmpty}} +
{{localize "DAGGERHEART.GENERAL.favorite.plural"}}
+ {{else}} + {{#each sidebarFavorites as |category|}} +
+
+ +

{{localize category.label}}

+ +
+ +
+ {{/each}} + {{/if}}
diff --git a/templates/sheets/global/partials/inventory-item-compact.hbs b/templates/sheets/global/partials/inventory-item-compact.hbs index bbdf9116..6f7205fa 100644 --- a/templates/sheets/global/partials/inventory-item-compact.hbs +++ b/templates/sheets/global/partials/inventory-item-compact.hbs @@ -58,11 +58,6 @@ data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.equipped 'unequip' 'equip' }}"> - {{else if (eq type 'domainCard')}} - - - {{else if (eq type 'effect')}}