Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/3.3.x' into publish-wiki
Browse files Browse the repository at this point in the history
  • Loading branch information
Fyorl committed Jul 22, 2024
2 parents 3bff255 + b6ca06a commit 84ce71a
Show file tree
Hide file tree
Showing 29 changed files with 298 additions and 104 deletions.
9 changes: 9 additions & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,7 @@
"DND5E.ExperiencePoints": "Experience Points",
"DND5E.ExperiencePointsAbbr": "XP",
"DND5E.ExperiencePointsCurrent": "Current XP",
"DND5E.ExperiencePointsFormat": "{value} XP",
"DND5E.ExperiencePointsLabel": "Progress to next level",
"DND5E.ExperiencePointsMax": "XP for Next Level",
"DND5E.ExperiencePointsMin": "Minimum XP for This Level",
Expand Down Expand Up @@ -1028,6 +1029,7 @@
"DND5E.HitPointsMin": "Minimum Hit Points",
"DND5E.HitPointsOverride": "Maximum Hit Points Override",
"DND5E.HitPointsTemp": "Temporary Hit Points",
"DND5E.HitPointsTempShort": "Temporary HP",
"DND5E.HitPointsTempMax": "Temporary Maximum Hit Points",
"DND5E.HitPointsTempMaxShort": "Temp Max HP",
"DND5E.HP": "HP",
Expand Down Expand Up @@ -2117,6 +2119,13 @@
"SETTINGS.5eAutoCollapseCardN": "Collapse Item Cards in Chat",
"SETTINGS.5eAutoSpellTemplateL": "When a spell is cast, defaults to begin the process to create the corresponding Measured Template if any (requires TRUSTED or higher player role)",
"SETTINGS.5eAutoSpellTemplateN": "Always place Spell Template",
"SETTINGS.5eAttackRollVisibility": {
"Name": "Attack Result Visibility",
"Hint": "Control visibility of attack roll results in chat cards for players.",
"All": "Show results & target ACs",
"HideAC": "Show only results",
"None": "Hide all"
},
"SETTINGS.5eChallengeVisibility": {
"Name": "Challenge Visibility",
"Hint": "Control what roll DCs are visible to the players and whether successes/failures are highlighted.",
Expand Down
36 changes: 36 additions & 0 deletions less/v2/actors.less
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,42 @@

form:is(.tab-inventory, .tab-features, .tab-spells, .tab-effects) .create-child { display: block; }

/* ---------------------------------- */
/* Warnings */
/* ---------------------------------- */

dialog.warnings:is(#tooltip, .locked-tooltip) { /* :is used here to override specificity of base tooltip styles */
position: fixed;
width: 300px;
max-width: unset;
max-height: unset;
margin: 0;
outline: none;
padding: 4px 8px;
font-family: var(--dnd5e-font-roboto-condensed);

li {
padding: 6px 8px;
border-bottom: 1px dotted var(--dnd5e-color-gold);
&:last-child { border: none; }

a:hover {
text-shadow: none;
text-decoration: underline dotted;
}

&.warning::before, &.error::before {
font-family: var(--font-awesome);
font-weight: bold;
color: var(--color-text-dark-5);
margin-right: 2px;
}

&.warning::before { content: "\f071"; }
&.error::before { content: "\f06a"; }
}
}

/* ---------------------------------- */
/* Minimized */
/* ---------------------------------- */
Expand Down
2 changes: 1 addition & 1 deletion less/v2/apps.less
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
height: 18px;
aspect-ratio: 1;
line-height: unset;
display: grid;
place-content: center;

&:not([hidden]) { display: grid; }
> i { margin: 0 }
}

Expand Down
14 changes: 12 additions & 2 deletions less/v2/npc.less
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

&.minimized {
box-shadow: 0 0 20px var(--color-shadow-dark);
.window-header .source-book { display: none; }
.window-header .header-elements { display: none; }
}

/* ---------------------------------- */
Expand All @@ -20,7 +20,7 @@

> header slide-toggle { --slide-toggle-track-color-unchecked: var(--dnd5e-background-25); }

.window-header .source-book {
.window-header .header-elements {
flex: none;
color: var(--color-text-dark-primary);
font-family: var(--dnd5e-font-roboto-condensed);
Expand All @@ -30,6 +30,14 @@
margin-top: 7px;
gap: 4px;

> div:has(> span:not(:empty)) + div::before { content: ""; }

.source-book {
display: flex;
align-items: center;
gap: 4px;
}

a {
margin: 0;
display: grid;
Expand All @@ -40,6 +48,7 @@
i {
font-size: var(--font-size-11);
color: var(--color-text-light-6);
margin: 0;
}
}

Expand Down Expand Up @@ -80,6 +89,7 @@
object-fit: cover;
object-position: top;
margin: 0;
display: block;
}

&.token > img {
Expand Down
11 changes: 10 additions & 1 deletion module/applications/actor/character-sheet-2.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import CharacterData from "../../data/actor/character.mjs";
import * as Trait from "../../documents/actor/trait.mjs";
import { simplifyBonus, staticID } from "../../utils.mjs";
import { simplifyBonus } from "../../utils.mjs";
import CompendiumBrowser from "../compendium-browser.mjs";
import ContextMenu5e from "../context-menu.mjs";
import SheetConfig5e from "../sheet-config.mjs";
Expand Down Expand Up @@ -717,4 +717,13 @@ export default class ActorSheet5eCharacter2 extends ActorSheetV2Mixin(ActorSheet
return { img, title, subtitle, modifier: total, passive, reference };
}
}

/* -------------------------------------------- */
/* Helpers */
/* -------------------------------------------- */

/** @inheritDoc */
canExpand(item) {
return !["background", "race"].includes(item.type) && super.canExpand(item);
}
}
40 changes: 25 additions & 15 deletions module/applications/actor/npc-sheet-2.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,20 @@ export default class ActorSheet5eNPC2 extends ActorSheetV2Mixin(ActorSheet5eNPC)
/** @inheritDoc */
async _renderOuter() {
const html = await super._renderOuter();
const source = document.createElement("div");
source.classList.add("source-book");
source.innerHTML = `
<span></span>
<a class="config-button" data-action="source" data-tooltip="DND5E.SourceConfig"
aria-label="${game.i18n.localize("DND5E.SourceConfig")}">
<i class="fas fa-cog"></i>
</a>
const elements = document.createElement("div");
elements.classList.add("header-elements");
elements.innerHTML = `
<div class="source-book">
<a class="config-button" data-action="source" data-tooltip="DND5E.SourceConfig"
aria-label="${game.i18n.localize("DND5E.SourceConfig")}">
<i class="fas fa-cog"></i>
</a>
<span></span>
</div>
<div class="cr-xp"></div>
`;
html[0].querySelector(".window-title")?.insertAdjacentElement("afterend", source);
source.querySelector(".config-button").addEventListener("click", this._onConfigMenu.bind(this));
html[0].querySelector(".window-title")?.insertAdjacentElement("afterend", elements);
elements.querySelector(".config-button").addEventListener("click", this._onConfigMenu.bind(this));
return html;
}

Expand All @@ -66,11 +69,18 @@ export default class ActorSheet5eNPC2 extends ActorSheetV2Mixin(ActorSheet5eNPC)
/** @inheritDoc */
async _render(force=false, options={}) {
await super._render(force, options);
const [source] = this.element.find(".source-book");
if ( !source ) return;
const sourceEditable = this.isEditable && (this._mode === this.constructor.MODES.EDIT);
source.querySelector(".config-button")?.toggleAttribute("hidden", !sourceEditable);
source.querySelector(":scope > span").innerText = this.actor.system.details.source.label;
const [elements] = this.element.find(".header-elements");
if ( !elements ) return;
const { details } = this.actor.system;
const editable = this.isEditable && (this._mode === this.constructor.MODES.EDIT);
const sourceLabel = details.source.label;
elements.querySelector(".config-button")?.toggleAttribute("hidden", !editable);
elements.querySelector(".source-book > span").innerText = editable
? (sourceLabel || game.i18n.localize("DND5E.Source"))
: sourceLabel;
elements.querySelector(".cr-xp").innerText = game.i18n.format("DND5E.ExperiencePointsFormat", {
value: new Intl.NumberFormat(game.i18n.lang).format(details.xp.value)
});
}

/* -------------------------------------------- */
Expand Down
7 changes: 2 additions & 5 deletions module/applications/actor/npc-sheet.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export default class ActorSheet5eNPC extends ActorSheet5e {

// Start by classifying items into groups for rendering
const maxLevelDelta = CONFIG.DND5E.maxLevel - (this.actor.system.details.level ?? 0);
let [spells, other] = context.items.reduce((arr, item) => {
const [spells, other] = context.items.reduce((arr, item) => {
const {quantity, uses, target} = item.system;
const ctx = context.itemContext[item.id] ??= {};
ctx.isStack = Number.isNumeric(quantity) && (quantity !== 1);
Expand All @@ -79,10 +79,6 @@ export default class ActorSheet5eNPC extends ActorSheet5e {
return arr;
}, [[], []]);

// Apply item filters
spells = this._filterItems(spells, this._filters.spellbook.properties);
other = this._filterItems(other, this._filters.features.properties);

// Organize Spellbook
const spellbook = this._prepareSpellbook(context, spells);

Expand Down Expand Up @@ -172,6 +168,7 @@ export default class ActorSheet5eNPC extends ActorSheet5e {
return this.actor.rollDeathSave({ event });

case "rollInitiative":
event.stopPropagation();
return this.actor.rollInitiativeDialog({ event });
}
}
Expand Down
63 changes: 62 additions & 1 deletion module/applications/actor/sheet-v2-mixin.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,24 @@ export default function ActorSheetV2Mixin(Base) {
header.insertAdjacentElement("afterbegin", toggle);
}

// Document UUID link.
const firstButton = header.querySelector(".header-button");
const idLink = header.querySelector(".document-id-link");
if ( idLink ) {
const firstButton = header.querySelector(".header-button");
firstButton?.insertAdjacentElement("beforebegin", idLink);
idLink.classList.add("header-button");
idLink.dataset.tooltipDirection = "DOWN";
}

// Preparation warnings.
const warnings = document.createElement("a");
warnings.classList.add("header-button", "preparation-warnings");
warnings.dataset.tooltip = "Warnings";
warnings.setAttribute("aria-label", game.i18n.localize("Warnings"));
warnings.innerHTML = '<i class="fas fa-triangle-exclamation"></i>';
warnings.addEventListener("click", this._onOpenWarnings.bind(this));
firstButton?.insertAdjacentElement("beforebegin", warnings);

// Render tabs.
const nav = document.createElement("nav");
nav.classList.add("tabs", "tabs-right");
Expand Down Expand Up @@ -123,6 +133,15 @@ export default function ActorSheetV2Mixin(Base) {

/* -------------------------------------------- */

/** @inheritDoc */
async _render(force=false, options={}) {
await super._render(force, options);
const [warnings] = this.element.find(".header-button.preparation-warnings");
warnings?.toggleAttribute("hidden", !this.actor._preparationWarnings?.length);
}

/* -------------------------------------------- */

/** @inheritDoc */
async getData(options) {
this._concentration = this.actor.concentration; // Cache concentration so it's not called for every item.
Expand Down Expand Up @@ -430,6 +449,7 @@ export default function ActorSheetV2Mixin(Base) {
html.find(".sidebar-collapser").on("click", this._onToggleSidebar.bind(this));
html.find("[data-item-id][data-action]").on("click", this._onItemAction.bind(this));
html.find("[data-toggle-description]").on("click", this._onToggleDescription.bind(this));
html.find("dialog.warnings").on("click", this._onCloseWarnings.bind(this));
this.form.querySelectorAll(".item-tooltip").forEach(this._applyItemTooltips.bind(this));
this.form.querySelectorAll("[data-reference-tooltip]").forEach(this._applyReferenceTooltips.bind(this));

Expand Down Expand Up @@ -488,6 +508,18 @@ export default function ActorSheetV2Mixin(Base) {

/* -------------------------------------------- */

/**
* Handle closing the warnings dialog.
* @param {PointerEvent} event The triggering event.
* @protected
*/
_onCloseWarnings(event) {
if ( event.target instanceof HTMLDialogElement ) event.target.close();
if ( event.target instanceof HTMLAnchorElement ) event.target.closest("dialog")?.close();
}

/* -------------------------------------------- */

/**
* Handle creating a new embedded child.
* @returns {ActiveEffect5e|Item5e|void}
Expand Down Expand Up @@ -548,6 +580,22 @@ export default function ActorSheetV2Mixin(Base) {

/* -------------------------------------------- */

/**
* Handle opening the warnings dialog.
* @param {PointerEvent} event The triggering event.
* @protected
*/
_onOpenWarnings(event) {
event.stopImmediatePropagation();
const { top, left, height } = event.target.getBoundingClientRect();
const { clientWidth } = document.documentElement;
const dialog = this.form.querySelector("dialog.warnings");
Object.assign(dialog.style, { top: `${top + height}px`, left: `${Math.min(left - 16, clientWidth - 300)}px` });
dialog.showModal();
}

/* -------------------------------------------- */

/**
* Toggle editing hit points.
* @param {PointerEvent} event The triggering event.
Expand Down Expand Up @@ -726,5 +774,18 @@ export default function ActorSheetV2Mixin(Base) {
<section class="loading" data-uuid="${uuid}"><i class="fas fa-spinner fa-spin-pulse"></i></section>
`;
}

/* -------------------------------------------- */
/* Helpers */
/* -------------------------------------------- */

/**
* Can an item be expanded on the sheet?
* @param {Item5e} item Item on the sheet.
* @returns {boolean}
*/
canExpand(item) {
return !["class", "subclass"].includes(item.type);
}
};
}
7 changes: 5 additions & 2 deletions module/applications/compendium-browser.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,7 @@ export default class CompendiumBrowser extends HandlebarsApplicationMixin(Applic
try {
const { type } = foundry.utils.parseUuid(uuid);
event.dataTransfer.setData("text/plain", JSON.stringify({ type, uuid }));
} catch (e) {
} catch(e) {
console.error(e);
}
}
Expand Down Expand Up @@ -966,8 +966,11 @@ export default class CompendiumBrowser extends HandlebarsApplicationMixin(Applic
static #onToggleMode(event, target) {
// TODO: Consider persisting this choice in a client setting.
this._mode = target.checked ? this.constructor.MODES.ADVANCED : this.constructor.MODES.BASIC;
const types = target.checked ? [] : ["class"];
const tabs = foundry.utils.deepClone(this.constructor.TABS.filter(t => !!t.advanced === target.checked));
const activeTab = tabs.find(t => t.tab === this.tabGroups.primary) ?? tabs[0];
const types = target.checked ? [] : (activeTab?.types ?? ["class"]);
this._applyModeFilters(this._mode);
this._applyTabFilters(activeTab?.tab);
this.render({ parts: ["results", "filters", "types", "tabs"], dnd5e: { browser: { types } } });
}

Expand Down
Loading

0 comments on commit 84ce71a

Please sign in to comment.