Get items appearing on the sheet, still a lot to do but this is a strong step in the right direction
This commit is contained in:
parent
6b03d62234
commit
23a402f11a
9 changed files with 254 additions and 10 deletions
|
|
@ -9,6 +9,11 @@
|
|||
},
|
||||
"taf": {
|
||||
"settings": {
|
||||
"actorDefaultAttributes": {
|
||||
"name": "Remove Default Attributes",
|
||||
"hint": "This removes the default attributes that are applied when a new actor is created, making it so that no attributes get created alongside the actor.",
|
||||
"label": "Remove Attributes"
|
||||
},
|
||||
"canPlayersManageAttributes": {
|
||||
"name": "Players Can Manage Attributes",
|
||||
"hint": "This allows players who have edit access to a document to be able to edit what attributes those characters have via the attribute editor"
|
||||
|
|
@ -34,10 +39,9 @@
|
|||
"true": "Resizable"
|
||||
}
|
||||
},
|
||||
"actorDefaultAttributes": {
|
||||
"name": "Remove Default Attributes",
|
||||
"hint": "This removes the default attributes that are applied when a new actor is created, making it so that no attributes get created alongside the actor.",
|
||||
"label": "Remove Attributes"
|
||||
"weightUnit": {
|
||||
"name": "Weight Unit",
|
||||
"hint": "This unit is used to display the units for the weights of items and carrying capacity of actors. This does NOTHING beyond adding the unit into the displays, it will not automatically convert between any units."
|
||||
}
|
||||
},
|
||||
"sheet-names": {
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ import { __ID__, filePath } from "../consts.mjs";
|
|||
import { AttributeManager } from "./AttributeManager.mjs";
|
||||
import { attributeSorter } from "../utils/attributeSort.mjs";
|
||||
import { TAFDocumentSheetConfig } from "./TAFDocumentSheetConfig.mjs";
|
||||
import { toPrecision } from "../utils/roundToPrecision.mjs";
|
||||
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api;
|
||||
const { ActorSheetV2 } = foundry.applications.sheets;
|
||||
const { getProperty, hasProperty } = foundry.utils;
|
||||
const { TextEditor } = foundry.applications.ux;
|
||||
|
||||
const propertyToParts = {
|
||||
"name": [`header`],
|
||||
|
|
@ -39,6 +41,7 @@ export class PlayerSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
|
|||
actions: {
|
||||
manageAttributes: this.#manageAttributes,
|
||||
configureSheet: this.#configureSheet,
|
||||
toggleExpand: this.#toggleExpand,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -68,6 +71,15 @@ export class PlayerSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
|
|||
};
|
||||
// #endregion Options
|
||||
|
||||
// #region Instance Data
|
||||
/**
|
||||
* This Set is used to keep track of which items have had their full
|
||||
* details expanded so that it can be persisted across rerenders as
|
||||
* they occur.
|
||||
*/
|
||||
#expandedItems = new Set();
|
||||
// #endregion Instance Data
|
||||
|
||||
// #region Lifecycle
|
||||
_initializeApplicationOptions(options) {
|
||||
const sizing = getProperty(options.document, `flags.${__ID__}.PlayerSheet.size`) ?? {};
|
||||
|
|
@ -203,24 +215,73 @@ export class PlayerSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
|
|||
ctx.toggled = true;
|
||||
ctx.tabActive = this.tabGroups.primary === `content` || this.actor.items.size === 0;
|
||||
|
||||
const TextEditor = foundry.applications.ux.TextEditor.implementation;
|
||||
ctx.enriched = {
|
||||
system: {
|
||||
content: await TextEditor.enrichHTML(this.actor.system.content),
|
||||
content: await TextEditor.implementation.enrichHTML(this.actor.system.content),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
async _prepareItems(ctx) {
|
||||
ctx.tabActive = this.tabGroups.primary === `items`;
|
||||
|
||||
const weightUnit = game.settings.get(__ID__, `weightUnit`);
|
||||
let totalWeight = 0;
|
||||
|
||||
ctx.itemGroups = [];
|
||||
for (const [groupName, items] of Object.entries(this.actor.itemTypes)) {
|
||||
const preparedItems = [];
|
||||
|
||||
let summedWeight = 0;
|
||||
for (const item of items) {
|
||||
summedWeight += item.system.quantifiedWeight;
|
||||
preparedItems.push(await this._prepareItem(item));
|
||||
};
|
||||
totalWeight += summedWeight;
|
||||
|
||||
ctx.itemGroups.push({
|
||||
name: groupName.titleCase(),
|
||||
items: preparedItems,
|
||||
weight: toPrecision(summedWeight, 2) + weightUnit,
|
||||
});
|
||||
};
|
||||
|
||||
ctx.totalWeight = toPrecision(totalWeight, 2) + weightUnit;
|
||||
};
|
||||
|
||||
async _prepareItem(item) {};
|
||||
async _prepareItem(item) {
|
||||
const weightUnit = game.settings.get(__ID__, `weightUnit`)
|
||||
const ctx = {
|
||||
uuid: item.uuid,
|
||||
img: item.img,
|
||||
name: item.name,
|
||||
equipped: item.system.equipped,
|
||||
quantity: item.system.quantity,
|
||||
weight: item.system.quantifiedWeight + weightUnit,
|
||||
isExpanded: this.#expandedItems.has(item.uuid),
|
||||
canExpand: item.system.description.length > 0,
|
||||
};
|
||||
|
||||
ctx.description = ``;
|
||||
if (item.system.description.length > 0) {
|
||||
ctx.description = await TextEditor.implementation.enrichHTML(item.system.description);
|
||||
};
|
||||
|
||||
return ctx;
|
||||
};
|
||||
// #endregion Data Prep
|
||||
|
||||
// #region Actions
|
||||
#attributeManager = null;
|
||||
/** @this {PlayerSheet} */
|
||||
|
||||
/**
|
||||
* This action opens an instance of the AttributeManager application
|
||||
* so that the user can edit and update all of the attributes for the
|
||||
* actor. This persists the application instance for the duration of
|
||||
* the ActorSheet's lifespan.
|
||||
*
|
||||
* @this {PlayerSheet}
|
||||
*/
|
||||
static async #manageAttributes() {
|
||||
this.#attributeManager ??= new AttributeManager({ document: this.actor });
|
||||
if (this.#attributeManager.rendered) {
|
||||
|
|
@ -233,6 +294,13 @@ export class PlayerSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
|
|||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* This action overrides the default Foundry action in order to tell
|
||||
* it to open my custom DocumentSheetConfig application instead of
|
||||
* opening the non-customized sheet config app.
|
||||
*
|
||||
* @this {PlayerSheet}
|
||||
*/
|
||||
static async #configureSheet(event) {
|
||||
event.stopPropagation();
|
||||
if ( event.detail > 1 ) { return }
|
||||
|
|
@ -248,5 +316,27 @@ export class PlayerSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
|
|||
window: { windowId: this.window.windowId },
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* This action is used by the item lists in order to expand/collapse
|
||||
* the descriptions while maintaining that state across renders.
|
||||
*
|
||||
* @this {PlayerSheet}
|
||||
*/
|
||||
static async #toggleExpand(event, target) {
|
||||
if (event.srcElement instanceof HTMLInputElement) { return };
|
||||
|
||||
const { itemUuid } = target.closest(`[data-item-uuid]`)?.dataset ?? {};
|
||||
if (!itemUuid) { return };
|
||||
|
||||
const expanded = this.#expandedItems.has(itemUuid);
|
||||
if (expanded) {
|
||||
this.#expandedItems.delete(itemUuid);
|
||||
target.nextElementSibling.dataset.expanded = false;
|
||||
} else {
|
||||
this.#expandedItems.add(itemUuid);
|
||||
target.nextElementSibling.dataset.expanded = true;
|
||||
}
|
||||
};
|
||||
// #endregion Actions
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { toPrecision } from "../../utils/roundToPrecision.mjs";
|
||||
|
||||
export class GenericItemData extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
|
|
@ -28,4 +30,12 @@ export class GenericItemData extends foundry.abstract.TypeDataModel {
|
|||
}),
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the total weight of the item based on the quantity of it, this
|
||||
* rounds the number to the nearest 2 decimal places.
|
||||
*/
|
||||
get quantifiedWeight() {
|
||||
return toPrecision(this.weight * this.quantity, 2);
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,6 +13,15 @@ export function registerWorldSettings() {
|
|||
scope: `world`,
|
||||
});
|
||||
|
||||
game.settings.register(__ID__, `weightUnit`, {
|
||||
name: `taf.settings.weightUnit.name`,
|
||||
hint: `taf.settings.weightUnit.hint`,
|
||||
config: true,
|
||||
type: String,
|
||||
default: ``,
|
||||
scope: `world`,
|
||||
});
|
||||
|
||||
game.settings.register(__ID__, `canPlayersManageAttributes`, {
|
||||
name: `taf.settings.canPlayersManageAttributes.name`,
|
||||
hint: `taf.settings.canPlayersManageAttributes.hint`,
|
||||
|
|
|
|||
20
module/utils/roundToPrecision.mjs
Normal file
20
module/utils/roundToPrecision.mjs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* Takes a possibly-decimal value and rounds after a certain precision, keeping
|
||||
* only the specified amount of decimals.
|
||||
*
|
||||
* @param {number} value The value that is to be rounded.
|
||||
* @param {number} precision The number of decimal places to round to. Must be a
|
||||
* positive integer.
|
||||
* @returns The rounded number
|
||||
*/
|
||||
export function toPrecision(value, precision = 1) {
|
||||
if (!Number.isInteger(precision)) {
|
||||
throw `Precision must be an integer`;
|
||||
};
|
||||
if (precision < 0) {
|
||||
throw `Precision must be greater than or equal to 0`;
|
||||
};
|
||||
|
||||
const m = 10 ** precision;
|
||||
return Math.round(value * m) / m;
|
||||
};
|
||||
|
|
@ -37,6 +37,64 @@
|
|||
}
|
||||
}
|
||||
|
||||
.item-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.item {
|
||||
background: var(--item-card-background);
|
||||
color: var(--item-card-color);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
|
||||
.summary {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr 50px auto;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background: var(--item-card-header-background);
|
||||
color: var(--item-card-header-color);
|
||||
padding: 4px;
|
||||
|
||||
img {
|
||||
--size: 35px;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
.subtitle {
|
||||
font-size: 0.7rem;
|
||||
opacity: 90%;
|
||||
}
|
||||
|
||||
input {
|
||||
background: var(--item-card-header-input-background);
|
||||
color: var(--item-card-header-input-color);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.full-details {
|
||||
padding: 4px;
|
||||
|
||||
&[data-expanded="false"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,13 @@
|
|||
--tab-button-active-border: rebeccapurple;
|
||||
--tab-button-hover-bg: var(--color-cool-3);
|
||||
|
||||
--item-card-background: #1d262f;
|
||||
--item-card-color: white;
|
||||
--item-card-header-background: #242d38;
|
||||
--item-card-header-color: white;
|
||||
--item-card-header-input-background: #2b3642;
|
||||
--item-card-header-input-color: white;
|
||||
|
||||
/* Chip Variables */
|
||||
--chip-color: #fff7ed;
|
||||
--chip-background: #2b3642;
|
||||
|
|
|
|||
|
|
@ -3,5 +3,23 @@
|
|||
data-group="primary"
|
||||
data-tab="items"
|
||||
>
|
||||
Item Tab Content Here
|
||||
Total Weight: {{totalWeight}}
|
||||
<hr>
|
||||
{{#each itemGroups as | group |}}
|
||||
<section>
|
||||
<div class="header">
|
||||
<span class="name">
|
||||
{{ group.name }}
|
||||
</span>
|
||||
<span class="weight">
|
||||
{{ group.weight }}
|
||||
</span>
|
||||
</div>
|
||||
<ul class="item-list">
|
||||
{{#each group.items as |item|}}
|
||||
{{> (systemFilePath "templates/PlayerSheet/item.hbs") item }}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</section>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1 +1,29 @@
|
|||
<div></div>
|
||||
<li
|
||||
class="item"
|
||||
data-item-uuid="{{uuid}}"
|
||||
>
|
||||
<div
|
||||
class="summary"
|
||||
{{#if canExpand}}
|
||||
data-action="toggleExpand"
|
||||
{{/if}}
|
||||
>
|
||||
<img
|
||||
src="{{img}}"
|
||||
alt=""
|
||||
>
|
||||
<div class="title">
|
||||
<span class="name">{{ name }}</span>
|
||||
<span class="subtitle">{{ weight }}</span>
|
||||
</div>
|
||||
<input
|
||||
type="number"
|
||||
value="{{quantity}}"
|
||||
>
|
||||
</div>
|
||||
{{#if canExpand}}
|
||||
<div class="full-details" data-expanded="{{isExpanded}}">
|
||||
{{{ description }}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</li>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue