Merge branch 'main' into feature/total-reroll

This commit is contained in:
WBHarry 2026-05-26 15:46:39 +02:00
commit 06c70b7e58
26 changed files with 270 additions and 176 deletions

View file

@ -175,14 +175,14 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
this.disadvantage = advantage === -1; this.disadvantage = advantage === -1;
this.config.roll.advantage = this.config.roll.advantage === advantage ? 0 : advantage; this.config.roll.advantage = this.config.roll.advantage === advantage ? 0 : advantage;
if (this.config.roll.advantage === 0) return this.render();
if (this.config.roll.advantage === 1 && this.config.data.rules.roll.defaultAdvantageDice) { const defaultFaces =
const faces = Number.parseInt(this.config.data.rules.roll.defaultAdvantageDice); this.config.roll.advantage === 1
this.roll.advantageFaces = Number.isNaN(faces) ? this.roll.advantageFaces : faces; ? this.config.data.rules.roll.defaultAdvantageDice
} else if (this.config.roll.advantage === -1 && this.config.data.rules.roll.defaultDisadvantageDice) { : this.config.data.rules.roll.defaultDisadvantageDice;
const faces = Number.parseInt(this.config.data.rules.roll.defaultDisadvantageDice); const faces = Number.parseInt(defaultFaces);
this.roll.advantageFaces = Number.isNaN(faces) ? this.roll.advantageFaces : faces; this.roll.advantageFaces = Number.isNaN(faces) ? this.roll.advantageFaces : faces;
}
this.render(); this.render();
} }

View file

@ -204,7 +204,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
}; };
} }
if (this.action.parent.metadata?.isQuantifiable) { if (this.action.parent.metadata.isInventoryItem) {
options.quantity = { options.quantity = {
label: 'DAGGERHEART.GENERAL.itemQuantity', label: 'DAGGERHEART.GENERAL.itemQuantity',
group: 'Global' group: 'Global'

View file

@ -175,6 +175,7 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac
const partContext = await super._preparePartContext(partId, context); const partContext = await super._preparePartContext(partId, context);
switch (partId) { switch (partId) {
case 'details': case 'details':
partContext.isItemEffect = partContext.isItemEffect || this.options.isSetting;
const useGeneric = game.settings.get( const useGeneric = game.settings.get(
CONFIG.DH.id, CONFIG.DH.id,
CONFIG.DH.SETTINGS.gameSettings.appearance CONFIG.DH.SETTINGS.gameSettings.appearance

View file

@ -184,6 +184,9 @@ export default class CharacterSheet extends DHBaseActorSheet {
for (const input of form.querySelectorAll('input:not([type=search]), .editor.prosemirror')) { for (const input of form.querySelectorAll('input:not([type=search]), .editor.prosemirror')) {
input.disabled = disabled; input.disabled = disabled;
} }
for (const element of form.querySelectorAll('.input[contenteditable]')) {
element.classList.toggle('disabled', disabled);
}
} }
/** @inheritDoc */ /** @inheritDoc */
@ -368,7 +371,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
const doc = getDocFromElementSync(target); const doc = getDocFromElementSync(target);
return doc?.isOwner && !isItemWizardManaged(doc); return doc?.isOwner && !isItemWizardManaged(doc);
}, },
callback: async (target, event) => { onClick: async (event, target) => {
const doc = await getDocFromElement(target); const doc = await getDocFromElement(target);
if (event.shiftKey) return doc.delete(); if (event.shiftKey) return doc.delete();
else return doc.deleteDialog(); else return doc.deleteDialog();
@ -393,7 +396,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
const doc = getDocFromElementSync(target); const doc = getDocFromElementSync(target);
return doc?.isOwner && doc.system.inVault; return doc?.isOwner && doc.system.inVault;
}, },
callback: async target => { onClick: async (_, target) => {
const doc = await getDocFromElement(target); const doc = await getDocFromElement(target);
const actorLoadout = doc.actor.system.loadoutSlot; const actorLoadout = doc.actor.system.loadoutSlot;
if (actorLoadout.available) return doc.update({ 'system.inVault': false }); if (actorLoadout.available) return doc.update({ 'system.inVault': false });
@ -407,7 +410,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
const doc = getDocFromElementSync(target); const doc = getDocFromElementSync(target);
return doc?.isOwner && doc.system.inVault; return doc?.isOwner && doc.system.inVault;
}, },
callback: async (target, event) => { onClick: async (event, target) => {
const doc = await getDocFromElement(target); const doc = await getDocFromElement(target);
const actorLoadout = doc.actor.system.loadoutSlot; const actorLoadout = doc.actor.system.loadoutSlot;
if (!actorLoadout.available) { if (!actorLoadout.available) {
@ -446,7 +449,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
const doc = getDocFromElementSync(target); const doc = getDocFromElementSync(target);
return doc?.isOwner && !doc.system.inVault; return doc?.isOwner && !doc.system.inVault;
}, },
callback: async target => (await getDocFromElement(target)).update({ 'system.inVault': true }) onClick: async (_, target) => (await getDocFromElement(target)).update({ 'system.inVault': true })
} }
].map(option => ({ ].map(option => ({
...option, ...option,
@ -472,7 +475,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
const doc = getDocFromElementSync(target); const doc = getDocFromElementSync(target);
return doc.isOwner && doc && !doc.system.equipped; return doc.isOwner && doc && !doc.system.equipped;
}, },
callback: (target, event) => CharacterSheet.#toggleEquipItem.call(this, event, target) onClick: (event, target) => CharacterSheet.#toggleEquipItem.call(this, event, target)
}, },
{ {
label: 'unequip', label: 'unequip',
@ -481,7 +484,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
const doc = getDocFromElementSync(target); const doc = getDocFromElementSync(target);
return doc.isOwner && doc && doc.system.equipped; return doc.isOwner && doc && doc.system.equipped;
}, },
callback: (target, event) => CharacterSheet.#toggleEquipItem.call(this, event, target) onClick: (event, target) => CharacterSheet.#toggleEquipItem.call(this, event, target)
} }
].map(option => ({ ].map(option => ({
...option, ...option,

View file

@ -424,7 +424,7 @@ export default function DHApplicationMixin(Base) {
const target = element.closest('[data-item-uuid]'); const target = element.closest('[data-item-uuid]');
return !target.dataset.disabled && target.dataset.itemType !== 'beastform'; return !target.dataset.disabled && target.dataset.itemType !== 'beastform';
}, },
callback: async target => (await getDocFromElement(target)).update({ disabled: true }) onClick: async (_, target) => (await getDocFromElement(target)).update({ disabled: true })
}, },
{ {
label: 'enableEffect', label: 'enableEffect',
@ -433,7 +433,7 @@ export default function DHApplicationMixin(Base) {
const target = element.closest('[data-item-uuid]'); const target = element.closest('[data-item-uuid]');
return target.dataset.disabled && target.dataset.itemType !== 'beastform'; return target.dataset.disabled && target.dataset.itemType !== 'beastform';
}, },
callback: async target => (await getDocFromElement(target)).update({ disabled: false }) onClick: async (_, target) => (await getDocFromElement(target)).update({ disabled: false })
} }
].map(option => ({ ].map(option => ({
...option, ...option,
@ -478,7 +478,9 @@ export default function DHApplicationMixin(Base) {
(doc?.isOwner && (!doc?.hasOwnProperty('systemPath') || doc?.inCollection)) (doc?.isOwner && (!doc?.hasOwnProperty('systemPath') || doc?.inCollection))
); );
}, },
callback: async target => (await getDocFromElement(target)).sheet.render({ force: true }) onClick: async (_, target) => {
return (await getDocFromElement(target)).sheet.render({ force: true });
}
} }
]; ];
@ -493,7 +495,7 @@ export default function DHApplicationMixin(Base) {
!foundry.utils.isEmpty(doc?.damage?.parts); !foundry.utils.isEmpty(doc?.damage?.parts);
return doc?.isOwner && hasDamage; return doc?.isOwner && hasDamage;
}, },
callback: async (target, event) => { onClick: async (event, target) => {
const doc = await getDocFromElement(target), const doc = await getDocFromElement(target),
action = doc?.system?.attack ?? doc; action = doc?.system?.attack ?? doc;
const config = action.prepareConfig(event); const config = action.prepareConfig(event);
@ -513,7 +515,7 @@ export default function DHApplicationMixin(Base) {
const doc = getDocFromElementSync(target); const doc = getDocFromElementSync(target);
return doc?.isOwner && !(doc.type === 'domainCard' && doc.system.inVault); return doc?.isOwner && !(doc.type === 'domainCard' && doc.system.inVault);
}, },
callback: async (target, event) => (await getDocFromElement(target)).use(event) onClick: async (event, target) => (await getDocFromElement(target)).use(event)
}); });
} }
@ -521,7 +523,7 @@ export default function DHApplicationMixin(Base) {
options.push({ options.push({
label: 'DAGGERHEART.APPLICATIONS.ContextMenu.sendToChat', label: 'DAGGERHEART.APPLICATIONS.ContextMenu.sendToChat',
icon: 'fa-solid fa-message', icon: 'fa-solid fa-message',
callback: async target => (await getDocFromElement(target)).toChat(this.document.uuid) onClick: async (_, target) => (await getDocFromElement(target)).toChat(this.document.uuid)
}); });
if (deletable) if (deletable)
@ -533,7 +535,7 @@ export default function DHApplicationMixin(Base) {
const doc = getDocFromElementSync(target); const doc = getDocFromElementSync(target);
return doc?.isOwner !== false && target.dataset.itemType !== 'beastform'; return doc?.isOwner !== false && target.dataset.itemType !== 'beastform';
}, },
callback: async (target, event) => { onClick: async (event, target) => {
const doc = await getDocFromElement(target); const doc = await getDocFromElement(target);
if (event.shiftKey) return doc.delete(); if (event.shiftKey) return doc.delete();
else return doc.deleteDialog(); else return doc.deleteDialog();

View file

@ -166,6 +166,15 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
} }
} }
/** Add support for input content editables */
_toggleDisabled(disabled) {
super._toggleDisabled(disabled);
const form = this.form;
for (const element of form.querySelectorAll('.input[contenteditable]')) {
element.classList.toggle('disabled', disabled);
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Context Menu */ /* Context Menu */
/* -------------------------------------------- */ /* -------------------------------------------- */

View file

@ -126,7 +126,7 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
options.push({ options.push({
name: 'CONTROLS.CommonDelete', name: 'CONTROLS.CommonDelete',
icon: '<i class="fa-solid fa-trash"></i>', icon: '<i class="fa-solid fa-trash"></i>',
callback: async target => { onClick: async (_, target) => {
const feature = await getDocFromElement(target); const feature = await getDocFromElement(target);
if (!feature) return; if (!feature) return;
const confirmed = await foundry.applications.api.DialogV2.confirm({ const confirmed = await foundry.applications.api.DialogV2.confirm({

View file

@ -1,3 +1,4 @@
import { getDocFromElement } from '../../helpers/utils.mjs';
import { RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; import { RefreshType, socketEvent } from '../../systemRegistration/socket.mjs';
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
@ -47,7 +48,8 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
expandContent: this.expandContent, expandContent: this.expandContent,
resetFilters: this.resetFilters, resetFilters: this.resetFilters,
sortList: this.sortList, sortList: this.sortList,
openSettings: this.openSettings openSettings: this.openSettings,
viewSheet: this.#onViewSheet
}, },
position: { position: {
left: 100, left: 100,
@ -306,7 +308,8 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
{ {
items: this.items, items: this.items,
menu: this.selectedMenu, menu: this.selectedMenu,
formatLabel: this.formatLabel formatLabel: this.formatLabel,
viewSheet: this.items[0] instanceof Actor
} }
); );
@ -568,6 +571,11 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
} }
} }
static async #onViewSheet(_, target) {
const document = await getDocFromElement(target);
document?.sheet?.render(true);
}
_createDragProcess() { _createDragProcess() {
new foundry.applications.ux.DragDrop.implementation({ new foundry.applications.ux.DragDrop.implementation({
dragSelector: '.item-container', dragSelector: '.item-container',
@ -606,7 +614,16 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
items: { items: {
folder: 'equipments', folder: 'equipments',
render: { render: {
noFolder: true folders: [
'equipments',
'ancestries',
'classes',
'subclasses',
'domains',
'communities',
'beastforms'
// excluded: features
]
} }
}, },
compendium: {} compendium: {}

View file

@ -148,10 +148,14 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
: null; : null;
} }
/** Returns true if the action is usable */ /**
* Returns true if the action is usable.
* An action is usable on any actor type. For example, an adversary might have a base attack action.
*/
get usable() { get usable() {
const actor = this.actor; const actor = this.actor;
return this.isOwner && actor?.type === 'character'; const pack = actor?.pack ? game.packs.get(actor.pack) : null;
return !pack?.locked && this.isOwner;
} }
static getRollType(parent) { static getRollType(parent) {

View file

@ -103,7 +103,7 @@ export default class CostField extends fields.ArrayField {
static calcCosts(costs) { static calcCosts(costs) {
const resources = CostField.getResources.call(this, costs); const resources = CostField.getResources.call(this, costs);
let filteredCosts = costs; let filteredCosts = costs;
if (this.parent?.metadata.isQuantifiable && this.parent.consumeOnUse === false) { if (this.parent?.isInventoryItem && this.parent.consumeOnUse === false) {
filteredCosts = filteredCosts.filter(c => c.key !== 'quantity'); filteredCosts = filteredCosts.filter(c => c.key !== 'quantity');
} }

View file

@ -150,14 +150,22 @@ export default class DualityRoll extends D20Roll {
} }
applyAdvantage() { applyAdvantage() {
if (this.hasAdvantage || this.hasDisadvantage) { const advDieClass = this.hasAdvantage
const dieFaces = this.advantageFaces, ? game.system.api.dice.diceTypes.AdvantageDie
advDie = new foundry.dice.terms.Die({ faces: dieFaces, number: this.advantageNumber }); : this.hasDisadvantage
if (this.advantageNumber > 1) advDie.modifiers = ['kh']; ? game.system.api.dice.diceTypes.DisadvantageDie
this.terms.push( : null;
new foundry.dice.terms.OperatorTerm({ operator: this.hasDisadvantage ? '-' : '+' }), if (advDieClass) {
advDie const advDie = new advDieClass({ faces: this.advantageFaces, number: this.advantageNumber });
); if (this.terms.length < 4) {
if (this.advantageNumber > 1) advDie.modifiers = ['kh'];
this.terms.push(
new foundry.dice.terms.OperatorTerm({ operator: this.hasDisadvantage ? '-' : '+' }),
advDie
);
} else {
this.terms[4] = advDie;
}
} }
if (this.rallyFaces) if (this.rallyFaces)
this.terms.push( this.terms.push(

View file

@ -73,8 +73,10 @@ export default class DHItem extends foundry.documents.Item {
/** Returns true if the item can be used */ /** Returns true if the item can be used */
get usable() { get usable() {
const actor = this.actor; const actor = this.actor;
const actionsList = this.system.actionsList; const pack = actor?.pack ? game.packs.get(actor.pack) : null;
return this.isOwner && actor?.type === 'character' && (actionsList?.size || actionsList?.length); const hasActions = this.system.actionsList?.size || this.system.actionsList?.length;
const isValidType = actor?.type === 'character' || this.type === 'feature';
return !pack?.locked && this.isOwner && isValidType && hasActions;
} }
/** @inheritdoc */ /** @inheritdoc */

View file

@ -1,3 +1,5 @@
@import '../../utils/mixin.less';
.theme-light .daggerheart.dialog.dh-style.views.tag-team-dialog { .theme-light .daggerheart.dialog.dh-style.views.tag-team-dialog {
.initialization-container .members-container .member-container { .initialization-container .members-container .member-container {
.member-name { .member-name {
@ -62,17 +64,7 @@
color: var(--color-text-primary); color: var(--color-text-primary);
text-shadow: 1px 1px 2px var(--shadow-color), 0 0 10px var(--shadow-color); text-shadow: 1px 1px 2px var(--shadow-color), 0 0 10px var(--shadow-color);
.smooth-gradient-ease-in-out(background-image, to bottom, var(--shadow-color), 100%);
// Basic "scrim" gradient
background-image: linear-gradient(
to top,
var(--shadow-color),
rgba(from var(--shadow-color) r g b / 0.834) 10.6%,
rgba(from var(--shadow-color) r g b / 0.541) 34%,
rgba(from var(--shadow-color) r g b / 0.382) 47%,
rgba(from var(--shadow-color) r g b / 0.194) 65%,
transparent 100%
);
} }
img { img {

View file

@ -34,7 +34,7 @@
.attribution-header-label { .attribution-header-label {
font-style: italic; font-style: italic;
font-family: @font-body; font-family: @font-body;
color: light-dark(@chat-blue-bg, @beige-50); color: @color-text-subtle;
} }
.tab.inventory { .tab.inventory {

View file

@ -11,7 +11,7 @@
.profile { .profile {
height: 235px; height: 235px;
cursor: pointer; cursor: pointer;
mask-image: linear-gradient(0deg, transparent 0%, black 10%); .smooth-gradient-ease-in-out(mask-image, to top, black, 2.25rem);
} }
.actor-name { .actor-name {
@ -24,11 +24,16 @@
margin-bottom: -30px; margin-bottom: -30px;
input[type='text'] { input[type='text'] {
backdrop-filter: none;
border: none;
font-family: @font-title;
font-size: var(--font-size-24); font-size: var(--font-size-24);
height: 32px;
text-align: center;
border: 1px solid transparent;
outline: 2px solid transparent; outline: 2px solid transparent;
box-shadow: unset;
text-shadow: 0 0 4px light-dark(white, @dark-80), 0 0 8px light-dark(white, @dark-80), 0 0 14px light-dark(white, @dark-80);
height: 2rem;
text-align: center;
transition: all 0.3s ease; transition: all 0.3s ease;
&:hover { &:hover {
@ -243,7 +248,7 @@
.companion-navigation { .companion-navigation {
display: flex; display: flex;
gap: 8px; gap: 8px;
align-items: center; align-items: baseline;
width: 100%; width: 100%;
} }
} }

View file

@ -1,5 +1,6 @@
@import '../../../utils/colors.less'; @import '../../../utils/colors.less';
@import '../../../utils/fonts.less'; @import '../../../utils/fonts.less';
@import '../../../utils/mixin.less';
.application.sheet.daggerheart.actor.dh-style.environment { .application.sheet.daggerheart.actor.dh-style.environment {
.environment-header-sheet { .environment-header-sheet {
@ -10,60 +11,83 @@
.profile { .profile {
height: 235px; height: 235px;
mask-image: linear-gradient(0deg, transparent 0%, black 10%);
cursor: pointer; cursor: pointer;
.smooth-gradient-ease-in-out(mask-image, to top, black, 3.5rem);
} }
.item-container { .item-container {
display: flex; display: grid;
grid-auto-flow: row;
grid-template-columns: 1fr min-content;
align-items: center; align-items: center;
position: relative; position: relative;
top: -45px; top: -36px;
gap: 20px; gap: 0 var(--spacer-12);
padding: 0 20px; padding: 0 20px;
margin-bottom: -30px; margin-bottom: -26px;
.item-info { .item-name input[type='text'] {
backdrop-filter: none;
border: none;
font-family: @font-title;
font-size: var(--font-size-32);
text-align: start;
transition: all 0.3s ease;
outline: 2px solid transparent;
box-shadow: none;
text-shadow: 0 0 4px light-dark(white, @dark-80), 0 0 8px light-dark(white, @dark-80), 0 0 14px light-dark(white, @dark-80);
padding-left: 0;
height: 2.625rem;
&:hover[type='text'],
&:focus[type='text'] {
box-shadow: none;
outline: 2px solid light-dark(@dark-blue, @golden);
}
}
.flexrow {
align-items: baseline;
grid-column: span 2;
}
.tags {
display: flex; display: flex;
flex-direction: column; gap: 10px;
gap: 8px; padding-bottom: 0;
flex: 0;
.tags { .tag {
display: flex; display: flex;
gap: 10px; flex-direction: row;
padding-bottom: 0; justify-content: center;
align-items: center;
padding: 3px 5px;
font-size: var(--font-size-12);
font: @font-body;
white-space: nowrap;
.tag { background: light-dark(@dark-15, @beige-15);
display: flex; border: 1px solid light-dark(@dark, @beige);
flex-direction: row; border-radius: 3px;
justify-content: center;
align-items: center;
padding: 3px 5px;
font-size: var(--font-size-12);
font: @font-body;
background: light-dark(@dark-15, @beige-15);
border: 1px solid light-dark(@dark, @beige);
border-radius: 3px;
}
.label {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: var(--font-size-12);
}
} }
.attribution-header-label { .label {
text-align: left; display: flex;
position: relative; flex-direction: row;
top: 4px; justify-content: center;
margin-bottom: -6px; align-items: center;
font-size: var(--font-size-12);
} }
} }
.attribution-header-label {
text-align: right;
position: relative;
}
.status-number { .status-number {
display: flex; display: flex;
align-items: center; align-items: center;
@ -81,7 +105,7 @@
font-size: 1.2rem; font-size: 1.2rem;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background: light-dark(transparent, @dark-blue); background: light-dark(#e8e6e3, @dark-blue);
z-index: 2; z-index: 2;
&.armor-slots { &.armor-slots {
@ -93,7 +117,7 @@
.status-label { .status-label {
padding: 2px 10px; padding: 2px 10px;
width: 100%; width: 100%;
border-radius: 3px; border-radius: 0 0 3px 3px;
background: light-dark(@dark-blue, @golden); background: light-dark(@dark-blue, @golden);
h4 { h4 {
@ -105,37 +129,23 @@
} }
} }
} }
.item-name {
input[type='text'] {
font-size: var(--font-size-32);
height: 42px;
text-align: start;
transition: all 0.3s ease;
outline: 2px solid transparent;
border: 1px solid transparent;
&:hover[type='text'],
&:focus[type='text'] {
box-shadow: none;
outline: 2px solid light-dark(@dark-blue, @golden);
}
}
}
} }
.environment-info { .environment-info {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: var(--spacer-8);
padding: 10px 20px; padding: 10px 20px;
} }
.environment-navigation { .environment-navigation {
display: flex; display: flex;
gap: 20px; gap: 20px;
align-items: center; align-items: baseline;
padding: 0 20px; padding: 0 20px;
.tab-navigation {
margin-top: 0;
}
} }
} }
} }

View file

@ -5,10 +5,6 @@
.appTheme({ .appTheme({
&.environment { &.environment {
background-image: url('../assets/parchments/dh-parchment-dark.png'); background-image: url('../assets/parchments/dh-parchment-dark.png');
.attribution-header-label {
background-image: url('../assets/parchments/dh-parchment-dark.png');
}
} }
}, { }, {
&.environment { &.environment {

View file

@ -1,5 +1,6 @@
@import '../../../utils/colors.less'; @import '../../../utils/colors.less';
@import '../../../utils/fonts.less'; @import '../../../utils/fonts.less';
@import '../../../utils/mixin.less';
.party-header-sheet { .party-header-sheet {
display: flex; display: flex;
@ -9,26 +10,30 @@
.profile { .profile {
height: 235px; height: 235px;
mask-image: linear-gradient(0deg, transparent 0%, black 10%);
cursor: pointer; cursor: pointer;
.smooth-gradient-ease-in-out(mask-image, to top, black, 3.5rem);
} }
.item-container { .item-container {
.item-name { margin-top: -2rem;
padding: 0 20px; z-index: 1;
input[type='text'] { input.item-name[type='text'] {
font-size: 32px; backdrop-filter: none;
height: 42px; border: none;
text-align: center; font-family: @font-title;
transition: all 0.3s ease; font-size: var(--font-size-32);
outline: 2px solid transparent; outline: 2px solid transparent;
border: 1px solid transparent; box-shadow: unset;
text-shadow: 0 0 4px light-dark(white, @dark-80), 0 0 8px light-dark(white, @dark-80), 0 0 14px light-dark(white, @dark-80);
&:hover[type='text'], text-align: center;
&:focus[type='text'] { transition: all 0.3s ease;
box-shadow: none; width: calc(100% - 40px);
outline: 2px solid light-dark(@dark-blue, @golden); height: 2.625rem;
}
&:hover[type='text'],
&:focus[type='text'] {
outline: 2px solid light-dark(@dark-blue, @golden);
} }
} }

View file

@ -245,7 +245,7 @@
} }
.item-list-header, .item-list-header,
.item-list [data-action='expandContent'] { .item-list .item-info[data-action] {
display: flex; display: flex;
> * { > * {

View file

@ -83,6 +83,8 @@
--gradient-stress: linear-gradient(15deg, rgb(130, 59, 1) 0%, rgb(252, 142, 69) 65%, rgb(190, 0, 0) 100%); --gradient-stress: linear-gradient(15deg, rgb(130, 59, 1) 0%, rgb(252, 142, 69) 65%, rgb(190, 0, 0) 100%);
--primary-color-fear: rgba(9, 71, 179, 0.75); --primary-color-fear: rgba(9, 71, 179, 0.75);
--dh-color-text-subtle: light-dark(#555, #a29086);
} }
@primary-blue: var(--primary-blue, #1488cc); @primary-blue: var(--primary-blue, #1488cc);
@ -190,3 +192,5 @@
box-shadow: 0 0 2px 2px @dark-blue; box-shadow: 0 0 2px 2px @dark-blue;
} }
} }
@color-text-subtle: var(--dh-color-text-subtle);

View file

@ -114,3 +114,48 @@
font-family: @font-body; font-family: @font-body;
} }
} }
// A simple ease-out mask
.smooth-gradient-ease-out(@param, @to, @destination, @length) {
@{param}+: linear-gradient(
@to,
transparent 0%,
rgb(from @destination r g b / ~"calc(alpha * 0.013)") calc(0.008 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.049)") calc(0.029 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.104)") calc(0.064 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.259)") calc(0.166 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.45)") calc(0.304 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.741)") calc(0.554 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.825)") calc(0.644 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.896)") calc(0.735 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.951)") calc(0.825 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.987)") calc(0.914 * @length),
@destination @length
);
}
/**
* A simple ease in and out mask.
* @param - the parameter to add to
* @param - direction, such as "to top"
* @destination - the color at the destination. The origin is always transparent
* @length - the value at the destination
*/
.smooth-gradient-ease-in-out(@param, @to, @destination, @length: 100%) {
@{param}+: linear-gradient(
@to,
transparent 0%,
rgb(from @destination r g b / ~"calc(alpha * 0.013)") calc(0.081 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.049)") calc(0.155 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.104)") calc(0.225 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.259)") calc(0.353 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.45)") calc(0.471 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.741)") calc(0.647 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.825)") calc(0.71 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.896)") calc(0.775 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.951)") calc(0.845 * @length),
rgb(from @destination r g b / ~"calc(alpha * 0.987)") calc(0.914 * @length),
@destination @length
);
}

View file

@ -5,16 +5,9 @@
{{formGroup systemFields.targetDispositions value=source.system.targetDispositions name=(concat "system.targetDispositions") localize=true}} {{formGroup systemFields.targetDispositions value=source.system.targetDispositions name=(concat "system.targetDispositions") localize=true}}
{{#if isActorEffect}} {{#if isActorEffect}}
<div class="form-group"> {{formGroup fields.origin value=source.origin rootId=rootId disabled=true}}
<label>{{localize "EFFECT.FIELDS.origin.label"}}</label> {{else if isItemEffect}}
<div class="form-fields"> {{formGroup fields.transfer value=source.transfer rootId=rootId}}
<input type="text" value="{{source.origin}}" disabled />
</div>
</div>
{{/if}}
{{#if isItemEffect}}
{{formGroup fields.transfer value=source.transfer rootId=rootId label=legacyTransfer.label hint=(localize "DAGGERHEART.EFFECTS.Attachments.transferHint")}}
{{/if}} {{/if}}
{{formGroup fields.statuses value=source.statuses options=statuses rootId=rootId classes="statuses"}} {{formGroup fields.statuses value=source.statuses options=statuses rootId=rootId classes="statuses"}}

View file

@ -1,28 +1,7 @@
<header class='environment-header-sheet'> <header class='environment-header-sheet'>
<img class='profile' src='{{source.img}}' data-action='editImage' data-edit='img' /> <img class='profile' src='{{source.img}}' data-action='editImage' data-edit='img' />
<div class='item-container'> <div class='item-container'>
<div class="item-info"> <h1 class='item-name'><input type='text' name='name' value='{{source.name}}' /></h1>
<h1 class='item-name'><input type='text' name='name' value='{{source.name}}' /></h1>
<div class="flexcol">
<div class="tags">
<div class="tag">
<span>
{{localize (concat 'DAGGERHEART.GENERAL.Tiers.' source.system.tier)}}
</span>
</div>
{{#if source.system.type}}
<div class="tag">
<span>
{{localize (concat 'DAGGERHEART.CONFIG.EnvironmentType.' source.system.type '.label')}}
</span>
</div>
{{/if}}
</div>
{{#if (and showAttribution document.system.attributionLabel)}}
<label class="attribution-header-label">{{document.system.attributionLabel}}</label>
{{/if}}
</div>
</div>
<div class="status-number"> <div class="status-number">
<div class='status-value armor-slots'> <div class='status-value armor-slots'>
{{#if source.system.difficulty}} {{#if source.system.difficulty}}
@ -35,6 +14,25 @@
<h4>{{localize "DAGGERHEART.GENERAL.difficulty"}}</h4> <h4>{{localize "DAGGERHEART.GENERAL.difficulty"}}</h4>
</div> </div>
</div> </div>
<div class="flexrow">
<div class="tags">
<div class="tag">
<span>
{{localize (concat 'DAGGERHEART.GENERAL.Tiers.' source.system.tier)}}
</span>
</div>
{{#if source.system.type}}
<div class="tag">
<span>
{{localize (concat 'DAGGERHEART.CONFIG.EnvironmentType.' source.system.type '.label')}}
</span>
</div>
{{/if}}
</div>
{{#if (and showAttribution document.system.attributionLabel)}}
<label class="attribution-header-label">{{document.system.attributionLabel}}</label>
{{/if}}
</div>
</div> </div>
<line-div></line-div> <line-div></line-div>
<div class="environment-info"> <div class="environment-info">

View file

@ -2,9 +2,7 @@
<img class='profile' src='{{source.img}}' data-action='editImage' data-edit='img' /> <img class='profile' src='{{source.img}}' data-action='editImage' data-edit='img' />
<div class='item-container'> <div class='item-container'>
<div class="item-info"> <div class="item-info">
<h1 class='item-name'> <input class="item-name" type='text' name='name' value='{{source.name}}' autocomplete="off" spellcheck="false"/>
<input type='text' name='name' value='{{source.name}}' autocomplete="off" spellcheck="false"/>
</h1>
</div> </div>
</div> </div>
</header> </header>

View file

@ -5,7 +5,7 @@
(hasProperty item "toChat" ) "toChat" "editDoc" ) }}' {{#unless hideTooltip}} {{#if (eq type 'attack' )}} (hasProperty item "toChat" ) "toChat" "editDoc" ) }}' {{#unless hideTooltip}} {{#if (eq type 'attack' )}}
data-tooltip="#attack#{{item.actor.uuid}}" {{else}} data-tooltip="#item#{{item.uuid}}" {{/if}} {{/unless}}> 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 (or item.system.actionsList.size item.system.actionsList.length item.actionType)}} {{#if item.usable}}
{{#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}}

View file

@ -1,7 +1,7 @@
{{#each items}} {{#each items}}
<div class="item-container" data-item-uuid="{{uuid}}" draggable="true"> <div class="item-container" data-item-uuid="{{uuid}}" draggable="true">
<div class="item-header"> <div class="item-header">
<div class="item-info" data-action="expandContent"> <div class="item-info" {{#if @root.viewSheet}}data-action="viewSheet"{{else}}data-action="expandContent"{{/if}}>
<img src="{{img}}" data-item-key="img" class="item-list-img"> <img src="{{img}}" data-item-key="img" class="item-list-img">
<span data-item-key="name" class="item-list-name">{{name}}</span> <span data-item-key="name" class="item-list-name">{{name}}</span>
{{#each ../menu.data.columns}} {{#each ../menu.data.columns}}
@ -9,11 +9,13 @@
{{/each}} {{/each}}
</div> </div>
</div> </div>
<div class="item-desc extensible"> {{#unless viewSheet}}
<span class="wrapper"> <div class="item-desc extensible">
{{{system.enrichedTags}}} <span class="wrapper">
{{{system.enrichedDescription}}} {{{system.enrichedTags}}}
</span> {{{system.enrichedDescription}}}
</div> </span>
</div>
{{/unless}}
</div> </div>
{{/each}} {{/each}}