diff --git a/lang/en.json b/lang/en.json index 2204f14a..756c6d17 100755 --- a/lang/en.json +++ b/lang/en.json @@ -1854,7 +1854,9 @@ "tier1": "Tier 1", "tier2": "Tier 2", "tier3": "Tier 3", - "tier4": "tier 4" + "tier4": "tier 4", + "domains": "Domains", + "downtime": "Downtime" }, "Tiers": { "singular": "Tier", @@ -1887,6 +1889,7 @@ "damageType": "Damage Type", "description": "Description", "difficulty": "Difficulty", + "downtime": "Downtime", "dropActorsHere": "Drop Actors here", "duality": "Duality", "dualityRoll": "Duality Roll", @@ -1919,6 +1922,7 @@ "inactiveEffects": "Inactive Effects", "inventory": "Inventory", "itemResource": "Item Resource", + "label": "Label", "level": "Level", "levelUp": "Level Up", "loadout": "Loadout", @@ -2137,6 +2141,18 @@ "handfullName": "Handfull Name", "bagName": "Bag Name", "chestName": "Chest Name" + }, + "domains": { + "domainsTitle": "Base Domains", + "homebrewDomains": "Homebrew Domains", + "newDomain": "New Domain", + "newDomainInputTitle": "Create Homebrew Domain", + "newDomainInputLabel": "New Domain Name", + "newDomainInputHint": "This cannot be altered later", + "editDomain": "Active Domain", + "deleteDomain": "Delete Domain", + "deleteDomainText": "Are you sure you want to delete the {name} domain? It will be immediately removed from all Actors in this world where it's currently used. Compendiums are not cleared.", + "duplicateDomain": "There is already a domain with this identification." } }, "Menu": { diff --git a/module/applications/dialogs/multiclassChoiceDialog.mjs b/module/applications/dialogs/multiclassChoiceDialog.mjs index 12f2629b..6d3fcf74 100644 --- a/module/applications/dialogs/multiclassChoiceDialog.mjs +++ b/module/applications/dialogs/multiclassChoiceDialog.mjs @@ -34,7 +34,7 @@ export default class MulticlassChoiceDialog extends HandlebarsApplicationMixin(A const context = await super._prepareContext(_options); context.multiclass = this.multiclass; context.domainChoices = this.multiclass.domains.map(value => { - const domain = CONFIG.DH.DOMAIN.domains[value]; + const domain = CONFIG.DH.DOMAIN.allDomains()[value]; return { value: value, label: game.i18n.localize(domain.label), diff --git a/module/applications/levelup/characterLevelup.mjs b/module/applications/levelup/characterLevelup.mjs index 8e17a907..1ce2bceb 100644 --- a/module/applications/levelup/characterLevelup.mjs +++ b/module/applications/levelup/characterLevelup.mjs @@ -1,6 +1,5 @@ import LevelUpBase from './levelup.mjs'; import { DhLevelup } from '../../data/levelup.mjs'; -import { domains } from '../../config/domainConfig.mjs'; import { abilities, subclassFeatureLabels } from '../../config/actorConfig.mjs'; export default class DhCharacterLevelUp extends LevelUpBase { @@ -113,7 +112,7 @@ export default class DhCharacterLevelUp extends LevelUpBase { : levelBase; return game.i18n.format('DAGGERHEART.APPLICATIONS.Levelup.selections.emptyDomainCardHint', { - domain: game.i18n.localize(domains[domain.domain].label), + domain: game.i18n.localize(CONFIG.DH.DOMAIN.allDomains()[domain.domain].label), level: levelMax }); }), @@ -170,7 +169,7 @@ export default class DhCharacterLevelUp extends LevelUpBase { uuid: multiclass.uuid, domains: multiclass?.system?.domains.map(key => { - const domain = domains[key]; + const domain = CONFIG.DH.DOMAIN.allDomains()[key]; const alreadySelected = this.actor.system.class.value.system.domains.includes(key); return { @@ -315,7 +314,10 @@ export default class DhCharacterLevelUp extends LevelUpBase { ? { ...multiclassItem.toObject(), domain: checkbox.secondaryData.domain - ? game.i18n.localize(domains[checkbox.secondaryData.domain].label) + ? game.i18n.localize( + CONFIG.DH.DOMAIN.allDomains()[checkbox.secondaryData.domain] + .label + ) : null, subclass: subclass ? subclass.name : null } diff --git a/module/applications/levelup/levelup.mjs b/module/applications/levelup/levelup.mjs index 4ec690e4..f1f4226c 100644 --- a/module/applications/levelup/levelup.mjs +++ b/module/applications/levelup/levelup.mjs @@ -1,5 +1,4 @@ import { abilities, subclassFeatureLabels } from '../../config/actorConfig.mjs'; -import { domains } from '../../config/domainConfig.mjs'; import { getDeleteKeys, tagifyElement } from '../../helpers/utils.mjs'; import { ItemBrowser } from '../ui/itemBrowser.mjs'; @@ -23,10 +22,11 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) static DEFAULT_OPTIONS = { tag: 'form', - classes: ['daggerheart', 'levelup'], + classes: ['daggerheart', 'dialog', 'dh-style', 'levelup'], position: { width: 1000, height: 'auto' }, window: { - resizable: true + resizable: true, + icon: 'fa-solid fa-arrow-turn-up' }, actions: { save: this.save, @@ -48,7 +48,10 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) static PARTS = { tabs: { template: 'systems/daggerheart/templates/levelup/tabs/tab-navigation.hbs' }, advancements: { template: 'systems/daggerheart/templates/levelup/tabs/advancements.hbs' }, - selections: { template: 'systems/daggerheart/templates/levelup/tabs/selections.hbs' }, + selections: { + template: 'systems/daggerheart/templates/levelup/tabs/selections.hbs', + scrollable: ['.selections'] + }, summary: { template: 'systems/daggerheart/templates/levelup/tabs/summary.hbs' }, footer: { template: 'systems/daggerheart/templates/levelup/tabs/footer.hbs' } }; @@ -252,7 +255,10 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) ? { ...multiclassItem.toObject(), domain: checkbox.secondaryData.domain - ? game.i18n.localize(domains[checkbox.secondaryData.domain].label) + ? game.i18n.localize( + CONFIG.DH.DOMAIN.allDomains()[checkbox.secondaryData.domain] + .label + ) : null, subclass: subclass ? subclass.name : null } @@ -356,10 +362,10 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) experienceIncreaseTagify, Object.keys(this.actor.system.experiences).reduce((acc, id) => { const experience = this.actor.system.experiences[id]; - acc[id] = { label: experience.name }; + acc.push({ id: id, label: experience.name }); return acc; - }, {}), + }, []), this.tagifyUpdate('experience').bind(this) ); } diff --git a/module/applications/settings/homebrewSettings.mjs b/module/applications/settings/homebrewSettings.mjs index 1b73747c..3fa42afd 100644 --- a/module/applications/settings/homebrewSettings.mjs +++ b/module/applications/settings/homebrewSettings.mjs @@ -1,4 +1,5 @@ import { DhHomebrew } from '../../data/settings/_module.mjs'; +import { slugify } from '../../helpers/utils.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; export default class DhHomebrewSettings extends HandlebarsApplicationMixin(ApplicationV2) { @@ -8,6 +9,10 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli this.settings = new DhHomebrew( game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).toObject() ); + + this.selected = { + domain: null + }; } get title() { @@ -17,7 +22,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli static DEFAULT_OPTIONS = { tag: 'form', id: 'daggerheart-homebrew-settings', - classes: ['daggerheart', 'dh-style', 'dialog', 'setting'], + classes: ['daggerheart', 'dh-style', 'dialog', 'setting', 'homebrew-settings'], position: { width: '600', height: 'auto' }, window: { icon: 'fa-solid fa-gears' @@ -27,6 +32,9 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli editItem: this.editItem, removeItem: this.removeItem, resetMoves: this.resetMoves, + addDomain: this.addDomain, + toggleSelectedDomain: this.toggleSelectedDomain, + deleteDomain: this.deleteDomain, save: this.save, reset: this.reset }, @@ -34,9 +42,19 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli }; static PARTS = { + tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }, + settings: { template: 'systems/daggerheart/templates/settings/homebrew-settings/settings.hbs' }, + domains: { template: 'systems/daggerheart/templates/settings/homebrew-settings/domains.hbs' }, + downtime: { template: 'systems/daggerheart/templates/settings/homebrew-settings/downtime.hbs' }, + footer: { template: 'systems/daggerheart/templates/settings/homebrew-settings/footer.hbs' } + }; + + /** @inheritdoc */ + static TABS = { main: { - template: 'systems/daggerheart/templates/settings/homebrew-settings.hbs', - scrollable: [''] + tabs: [{ id: 'settings' }, { id: 'domains' }, { id: 'downtime' }], + initial: 'settings', + labelPrefix: 'DAGGERHEART.GENERAL.Tabs' } }; @@ -47,7 +65,26 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli return context; } - static async updateData(event, element, formData) { + async _preparePartContext(partId, context) { + await super._preparePartContext(partId, context); + + switch (partId) { + case 'domains': + const selectedDomain = this.selected.domain ? this.settings.domains[this.selected.domain] : null; + const enrichedDescription = selectedDomain + ? await foundry.applications.ux.TextEditor.implementation.enrichHTML(selectedDomain.description) + : null; + + if (enrichedDescription !== null) context.selectedDomain = { ...selectedDomain, enrichedDescription }; + context.configDomains = CONFIG.DH.DOMAIN.domains; + context.homebrewDomains = this.settings.domains; + break; + } + + return context; + } + + static async updateData(_event, _element, formData) { const updatedSettings = foundry.utils.expandObject(formData.object); await this.settings.updateSource({ @@ -163,6 +200,107 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli this.render(); } + static async addDomain(event) { + event.preventDefault(); + const content = new foundry.data.fields.StringField({ + label: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.domains.newDomainInputLabel'), + hint: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.domains.newDomainInputHint'), + required: true + }).toFormGroup({}, { name: 'domainName', localize: true }).outerHTML; + + async function callback(_, button) { + const domainName = button.form.elements.domainName.value; + if (!domainName) return; + + const newSlug = slugify(domainName); + const existingDomains = [ + ...Object.values(this.settings.domains), + ...Object.values(CONFIG.DH.DOMAIN.domains) + ]; + if (existingDomains.find(x => slugify(game.i18n.localize(x.label)) === newSlug)) { + ui.notifications.warn(game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.domains.duplicateDomain')); + return; + } + + this.settings.updateSource({ + [`domains.${newSlug}`]: { + id: newSlug, + label: domainName, + src: 'icons/svg/portal.svg' + } + }); + + this.selected.domain = newSlug; + this.render(); + } + + foundry.applications.api.DialogV2.prompt({ + content: content, + rejectClose: false, + modal: true, + ok: { callback: callback.bind(this) }, + window: { + title: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.domains.newDomainInputTitle') + }, + position: { width: 400 } + }); + } + + static toggleSelectedDomain(_, target) { + this.selected.domain = this.selected.domain === target.id ? null : target.id; + this.render(); + } + + static async deleteDomain() { + const confirmed = await foundry.applications.api.DialogV2.confirm({ + window: { + title: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.domains.deleteDomain') + }, + content: game.i18n.format('DAGGERHEART.SETTINGS.Homebrew.domains.deleteDomainText', { + name: this.settings.domains[this.selected.domain].label + }) + }); + + if (!confirmed) return; + + await this.settings.updateSource({ + [`domains.-=${this.selected.domain}`]: null + }); + + const currentSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew); + if (currentSettings.domains[this.selected.domain]) { + await currentSettings.updateSource({ [`domains.-=${this.selected.domain}`]: null }); + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, currentSettings); + } + + const updateClasses = game.items.filter(x => x.type === 'class'); + for (let actor of game.actors) { + updateClasses.push(...actor.items.filter(x => x.type === 'class')); + } + + for (let c of updateClasses) { + if (c.system.domains.includes(this.selected.domain)) { + const newDomains = + c.system.domains.length === 1 + ? [CONFIG.DH.DOMAIN.domains.arcana.id] + : c.system.domains.filter(x => x !== this.selected.domain); + await c.update({ 'system.domains': newDomains }); + } + c.sheet.render(); + } + + const updateDomainCards = game.items.filter( + x => x.type === 'domainCard' && x.system.domain === this.selected.domain + ); + for (let d of updateDomainCards) { + await d.update({ 'system.domain': CONFIG.DH.DOMAIN.domains.arcana.id }); + d.sheet.render(); + } + + this.selected.domain = null; + this.render(); + } + static async save() { await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, this.settings.toObject()); this.close(); @@ -200,4 +338,13 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli } return obj; } + + _getTabs(tabs) { + for (const v of Object.values(tabs)) { + v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; + v.cssClass = v.active ? 'active' : ''; + } + + return tabs; + } } diff --git a/module/applications/sheets/items/class.mjs b/module/applications/sheets/items/class.mjs index f858b2c5..79a689d8 100644 --- a/module/applications/sheets/items/class.mjs +++ b/module/applications/sheets/items/class.mjs @@ -14,7 +14,7 @@ export default class ClassSheet extends DHBaseItemSheet { tagifyConfigs: [ { selector: '.domain-input', - options: () => CONFIG.DH.DOMAIN.domains, + options: () => CONFIG.DH.DOMAIN.orderedDomains(), callback: ClassSheet.#onDomainSelect, tagifyOptions: { maxTags: () => game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxDomains diff --git a/module/applications/sheets/items/domainCard.mjs b/module/applications/sheets/items/domainCard.mjs index 7820fa0e..ce2d305c 100644 --- a/module/applications/sheets/items/domainCard.mjs +++ b/module/applications/sheets/items/domainCard.mjs @@ -34,4 +34,12 @@ export default class DomainCardSheet extends DHBaseItemSheet { scrollable: ['.effects'] } }; + + async _prepareContext(options) { + const context = await super._prepareContext(options); + context.domain = CONFIG.DH.DOMAIN.allDomains()[this.document.system.domain]; + context.domainChoices = CONFIG.DH.DOMAIN.orderedDomains(); + + return context; + } } diff --git a/module/applications/ux/filter-menu.mjs b/module/applications/ux/filter-menu.mjs index b62e884b..065d08f9 100644 --- a/module/applications/ux/filter-menu.mjs +++ b/module/applications/ux/filter-menu.mjs @@ -219,7 +219,7 @@ export default class FilterMenu extends foundry.applications.ux.ContextMenu { } })); - const domainFilter = Object.values(CONFIG.DH.DOMAIN.domains).map(({ id, label }) => ({ + const domainFilter = Object.values(CONFIG.DH.DOMAIN.allDomains()).map(({ id, label }) => ({ group: game.i18n.localize('DAGGERHEART.GENERAL.Domain.single'), name: game.i18n.localize(label), filter: { diff --git a/module/config/domainConfig.mjs b/module/config/domainConfig.mjs index 2387e00f..9574fd50 100644 --- a/module/config/domainConfig.mjs +++ b/module/config/domainConfig.mjs @@ -55,8 +55,17 @@ export const domains = { } }; -export const classDomainMap = { - rogue: [domains.midnight, domains.grace] +export const allDomains = () => ({ + ...domains, + ...game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).domains +}); + +export const orderedDomains = () => { + const all = { + ...domains, + ...game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).domains + }; + return Object.values(all).sort((a, b) => game.i18n.localize(a.label).localeCompare(game.i18n.localize(b.label))); }; export const subclassMap = { diff --git a/module/data/item/domainCard.mjs b/module/data/item/domainCard.mjs index 67c3ab04..34754a41 100644 --- a/module/data/item/domainCard.mjs +++ b/module/data/item/domainCard.mjs @@ -18,7 +18,7 @@ export default class DHDomainCard extends BaseDataItem { return { ...super.defineSchema(), domain: new fields.StringField({ - choices: CONFIG.DH.DOMAIN.domains, + choices: CONFIG.DH.DOMAIN.allDomains, required: true, initial: CONFIG.DH.DOMAIN.domains.arcana.id }), diff --git a/module/data/settings/Homebrew.mjs b/module/data/settings/Homebrew.mjs index 0251dd54..d2296dc6 100644 --- a/module/data/settings/Homebrew.mjs +++ b/module/data/settings/Homebrew.mjs @@ -2,8 +2,6 @@ import { defaultRestOptions } from '../../config/generalConfig.mjs'; import { ActionsField } from '../fields/actionField.mjs'; export default class DhHomebrew extends foundry.abstract.DataModel { - static LOCALIZATION_PREFIXES = ['DAGGERHEART.SETTINGS.Homebrew']; // Doesn't work for some reason - static defineSchema() { const fields = foundry.data.fields; return { @@ -98,7 +96,19 @@ export default class DhHomebrew extends foundry.abstract.DataModel { { initial: defaultRestOptions.shortRest() } ) }) - }) + }), + domains: new fields.TypedObjectField( + new fields.SchemaField({ + id: new fields.StringField({ required: true }), + label: new fields.StringField({ required: true, initial: '', label: 'DAGGERHEART.GENERAL.label' }), + src: new fields.FilePathField({ + categories: ['IMAGE'], + base64: false, + label: 'Image' + }), + description: new fields.HTMLField() + }) + ) }; } } diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 83935356..f1df4723 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -83,15 +83,16 @@ export const chunkify = (array, chunkSize, mappingFunc) => { return chunkifiedArray; }; -export const tagifyElement = (element, options, onChange, tagifyOptions = {}) => { +export const tagifyElement = (element, baseOptions, onChange, tagifyOptions = {}) => { const { maxTags } = tagifyOptions; + const options = typeof baseOptions === 'object' ? Object.values(baseOptions) : baseOptions; + const tagifyElement = new Tagify(element, { tagTextProp: 'name', enforceWhitelist: true, - whitelist: Object.keys(options).map(key => { - const option = options[key]; + whitelist: options.map(option => { return { - value: key, + value: option.id, name: game.i18n.localize(option.label), src: option.src, description: option.description @@ -100,7 +101,7 @@ export const tagifyElement = (element, options, onChange, tagifyOptions = {}) => maxTags: typeof maxTags === 'function' ? maxTags() : maxTags, dropdown: { mapValueTo: 'name', - searchKeys: ['name'], + searchKeys: ['value'], enabled: 0, maxItems: 100, closeOnSelect: true, @@ -369,3 +370,7 @@ export async function createEmbeddedItemWithEffects(actor, baseData, update) { return doc; } + +export const slugify = name => { + return name.toLowerCase().replaceAll(' ', '-').replaceAll('.', ''); +}; diff --git a/src/packs/adversaries/adversary_Minor_Chaos_Elemental_sRn4bqerfARvhgSV.json b/src/packs/adversaries/adversary_Minor_Chaos_Elemental_sRn4bqerfARvhgSV.json index 571c0942..075e47dc 100644 --- a/src/packs/adversaries/adversary_Minor_Chaos_Elemental_sRn4bqerfARvhgSV.json +++ b/src/packs/adversaries/adversary_Minor_Chaos_Elemental_sRn4bqerfARvhgSV.json @@ -68,6 +68,7 @@ "description": "
A coruscating mass of uncontrollable magic.
", "attack": { "name": "Warp Blast", + "img": "icons/magic/light/beam-rays-magenta.webp", "roll": { "bonus": 3, "type": "attack" diff --git a/src/packs/domains/domainCard_Rage_Up_GRL0cvs96vrTDckZ.json b/src/packs/domains/domainCard_Rage_Up_GRL0cvs96vrTDckZ.json index c79bd98a..b11bd6f9 100644 --- a/src/packs/domains/domainCard_Rage_Up_GRL0cvs96vrTDckZ.json +++ b/src/packs/domains/domainCard_Rage_Up_GRL0cvs96vrTDckZ.json @@ -19,7 +19,7 @@ "actionType": "action", "cost": [ { - "scalable": true, + "scalable": false, "key": "stress", "value": 1, "step": 1, @@ -95,8 +95,8 @@ "systemId": "daggerheart", "systemVersion": "0.0.1", "createdTime": 1753922784496, - "modifiedTime": 1754304556054, - "lastModifiedBy": "MQSznptE5yLT7kj8" + "modifiedTime": 1754445106667, + "lastModifiedBy": "Q9NoTaEarn3VMS6Z" }, "_id": "GRL0cvs96vrTDckZ", "sort": 3400000, @@ -105,7 +105,7 @@ "name": "Rage Up (1)", "img": "systems/daggerheart/assets/icons/domains/domain-card/blade.png", "origin": "Compendium.daggerheart.domains.Item.GRL0cvs96vrTDckZ", - "transfer": true, + "transfer": false, "_id": "bq1MhcmoP6Wo5CXF", "type": "base", "system": { @@ -118,13 +118,19 @@ }, "changes": [ { - "key": "system.bonuses.roll.attack.bonus", + "key": "system.bonuses.damage.magical.bonus", + "mode": 2, + "value": "2*@system.traits.strength.value", + "priority": null + }, + { + "key": "system.bonuses.damage.physical.bonus", "mode": 2, "value": "2*@system.traits.strength.value", "priority": null } ], - "disabled": true, + "disabled": false, "duration": { "startTime": null, "combat": null, @@ -147,8 +153,8 @@ "systemId": "daggerheart", "systemVersion": "0.0.1", "createdTime": 1754246159246, - "modifiedTime": 1754304575352, - "lastModifiedBy": "MQSznptE5yLT7kj8" + "modifiedTime": 1754446417671, + "lastModifiedBy": "Q9NoTaEarn3VMS6Z" }, "_key": "!items.effects!GRL0cvs96vrTDckZ.bq1MhcmoP6Wo5CXF" }, @@ -156,7 +162,7 @@ "name": "Rage Up (2)", "img": "systems/daggerheart/assets/icons/domains/domain-card/blade.png", "origin": "Compendium.daggerheart.domains.Item.GRL0cvs96vrTDckZ", - "transfer": true, + "transfer": false, "_id": "t6SIjQxB6UBUJ98f", "type": "base", "system": { @@ -169,13 +175,19 @@ }, "changes": [ { - "key": "system.bonuses.roll.attack.bonus", + "key": "system.bonuses.damage.magical.bonus", + "mode": 2, + "value": "4*@system.traits.strength.value", + "priority": null + }, + { + "key": "system.bonuses.damage.physical.bonus", "mode": 2, "value": "4*@system.traits.strength.value", "priority": null } ], - "disabled": true, + "disabled": false, "duration": { "startTime": null, "combat": null, @@ -198,8 +210,8 @@ "systemId": "daggerheart", "systemVersion": "0.0.1", "createdTime": 1754246675511, - "modifiedTime": 1754304583724, - "lastModifiedBy": "MQSznptE5yLT7kj8" + "modifiedTime": 1754446412834, + "lastModifiedBy": "Q9NoTaEarn3VMS6Z" }, "_key": "!items.effects!GRL0cvs96vrTDckZ.t6SIjQxB6UBUJ98f" } diff --git a/styles/less/dialog/index.less b/styles/less/dialog/index.less index c6a16527..942016e0 100644 --- a/styles/less/dialog/index.less +++ b/styles/less/dialog/index.less @@ -3,6 +3,7 @@ @import './level-up/sheet.less'; @import './level-up/summary-container.less'; @import './level-up/tiers-container.less'; +@import './level-up/footer.less'; @import './resource-dice/sheet.less'; diff --git a/styles/less/dialog/level-up/footer.less b/styles/less/dialog/level-up/footer.less new file mode 100644 index 00000000..daf25b60 --- /dev/null +++ b/styles/less/dialog/level-up/footer.less @@ -0,0 +1,19 @@ +@import '../../utils/fonts.less'; + +.daggerheart.levelup { + .tab-footer { + margin-top: 10px; + .levelup-navigation-actions, + .levelup-footer { + display: flex; + justify-content: end; + gap: 10px; + + button { + font-family: @font-body; + font-weight: bold; + height: 40px; + } + } + } +} diff --git a/styles/less/dialog/level-up/navigation-container.less b/styles/less/dialog/level-up/navigation-container.less index 142cf089..d8872931 100644 --- a/styles/less/dialog/level-up/navigation-container.less +++ b/styles/less/dialog/level-up/navigation-container.less @@ -1,3 +1,6 @@ +@import '../../utils/colors.less'; +@import '../../utils/fonts.less'; + .daggerheart.levelup { .levelup-navigation-container { display: flex; @@ -7,23 +10,18 @@ nav { flex: 1; + border: none; .levelup-tab-container { display: flex; align-items: center; gap: 4px; - } - } - .levelup-navigation-actions { - width: 306px; - display: flex; - justify-content: end; - gap: 16px; - margin-right: 4px; - - * { - width: calc(50% - 8px); + a, + span { + font-family: @font-body; + color: light-dark(@dark-blue, @golden); + } } } } diff --git a/styles/less/dialog/level-up/selections-container.less b/styles/less/dialog/level-up/selections-container.less index 552f7c86..843fead0 100644 --- a/styles/less/dialog/level-up/selections-container.less +++ b/styles/less/dialog/level-up/selections-container.less @@ -1,18 +1,38 @@ +@import '../../utils/fonts.less'; +@import '../../utils/colors.less'; + .daggerheart.levelup { .levelup-selections-container { + overflow: auto; + padding: 10px 0; + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; + max-height: 500px; + mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%); + .achievement-experience-cards { display: flex; gap: 8px; .achievement-experience-card { - border: 1px solid; - border-radius: 4px; - padding-right: 4px; - font-size: 18px; display: flex; justify-content: space-between; align-items: center; + background: light-dark(@dark-blue-40, @golden-40); + border-radius: 3px; + padding: 5px; + font-size: 16px; gap: 4px; + width: 100%; + + input { + background: light-dark(@soft-shadow, @semi-transparent-dark-blue); + width: 80%; + } + + span { + font-family: @font-body; + } .achievement-experience-marker { border: 1px solid; @@ -30,10 +50,13 @@ .levelup-card-selection { display: flex; flex-wrap: wrap; + justify-content: center; gap: 40px; + height: 190px; .card-preview-container { - width: calc(100% * (1 / 5)); + height: 100%; + max-width: 200px; } .levelup-domains-selection-container { @@ -89,10 +112,30 @@ } } + .card-section { + flex: 1 1 100%; + + .card-section-header { + display: flex; + align-items: center; + gap: 20px; + margin-bottom: 10px; + + h3 { + font-family: @font-subtitle; + color: light-dark(@dark, @beige); + margin: 0; + white-space: nowrap; + } + } + } + .levelup-selections-title { - display: flex; - align-items: center; - gap: 4px; + margin-left: auto; + margin-right: auto; + font-size: 22px; + font-weight: bold; + padding: 0 12px; } .levelup-radio-choices { diff --git a/styles/less/dialog/level-up/sheet.less b/styles/less/dialog/level-up/sheet.less index 2f89034c..ade7c8a9 100644 --- a/styles/less/dialog/level-up/sheet.less +++ b/styles/less/dialog/level-up/sheet.less @@ -25,9 +25,11 @@ section { .section-container { display: flex; - flex-direction: column; - gap: 8px; + flex-direction: row; + justify-content: center; + gap: 20px 8px; margin-top: 8px; + flex-wrap: wrap; } } diff --git a/styles/less/dialog/level-up/summary-container.less b/styles/less/dialog/level-up/summary-container.less index fbaa783e..eb760cde 100644 --- a/styles/less/dialog/level-up/summary-container.less +++ b/styles/less/dialog/level-up/summary-container.less @@ -1,5 +1,28 @@ +@import '../../utils/colors.less'; +@import '../../utils/fonts.less'; + .daggerheart.levelup { + .summary-header { + display: flex; + align-items: center; + gap: 20px; + margin-bottom: 10px; + + h3 { + font-family: @font-subtitle; + color: light-dark(@dark, @beige); + margin: 0; + white-space: nowrap; + } + } .levelup-summary-container { + overflow: auto; + padding: 10px 0; + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; + max-height: 700px; + mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%); + .level-achievements-container, .level-advancements-container { display: flex; @@ -11,7 +34,7 @@ h4, h5 { margin: 0; - color: var(--color-text-secondary); + color: light-dark(@dark, @beige); } } @@ -19,7 +42,19 @@ display: flex; align-items: center; gap: 4px; - font-size: 20px; + font-size: 14px; + font-family: @font-body; + color: light-dark(@dark, @beige); + } + + h5.summary-section { + display: flex; + align-items: center; + gap: 4px; + font-size: 16px; + font-family: @font-subtitle; + color: light-dark(@dark, @beige); + margin-bottom: 5px; } .summary-selection-container { @@ -28,9 +63,11 @@ .summary-selection { border: 2px solid; - border-radius: 6px; + border-radius: 3px; padding: 0 4px; - font-size: 18px; + font-size: 14px; + font-family: @font-body; + color: light-dark(@dark, @beige); } } } diff --git a/styles/less/dialog/level-up/tiers-container.less b/styles/less/dialog/level-up/tiers-container.less index bf270fe9..1149ede3 100644 --- a/styles/less/dialog/level-up/tiers-container.less +++ b/styles/less/dialog/level-up/tiers-container.less @@ -1,3 +1,6 @@ +@import '../../utils/colors.less'; +@import '../../utils/fonts.less'; + .daggerheart.levelup { .tiers-container { display: flex; @@ -38,7 +41,7 @@ height: min-content; &.multi { - border: 2px solid grey; + border: 2px solid light-dark(@dark-blue-40, @golden-40); padding: 2.4px 2.5px 0; border-radius: 4px; gap: 2px; @@ -56,7 +59,8 @@ } .checkbox-group-label { - font-size: 14px; + font-family: @font-body; + font-size: 12px; font-style: italic; } } diff --git a/styles/less/global/elements.less b/styles/less/global/elements.less index 4b638748..35262b3b 100755 --- a/styles/less/global/elements.less +++ b/styles/less/global/elements.less @@ -619,6 +619,7 @@ margin-left: 8px; height: 20px; width: 20px; + filter: @dark-filter; } } } @@ -651,31 +652,33 @@ } } -.theme-light .application { - &.sheet.dh-style { - button.glow { - animation: glow-dark 0.75s infinite alternate; - } - } - - .component.dh-style.card-preview-container { - background-image: url('../assets/parchments/dh-parchment-light.png'); - - .preview-text-container { - background-image: url(../assets/parchments/dh-parchment-dark.png); +.theme-light { + .application { + &.sheet.dh-style { + button.glow { + animation: glow-dark 0.75s infinite alternate; + } } - .preview-selected-icon-container { - background-image: url(../assets/parchments/dh-parchment-dark.png); - color: var(--color-light-5); + .component.dh-style.card-preview-container { + background-image: url('../assets/parchments/dh-parchment-light.png'); + + .preview-text-container { + background-image: url(../assets/parchments/dh-parchment-dark.png); + } + + .preview-selected-icon-container { + background-image: url(../assets/parchments/dh-parchment-dark.png); + color: var(--color-light-5); + } } } } .application .component.dh-style.card-preview-container { position: relative; - border-radius: 6px; - border: 2px solid var(--color-tabs-border); + border: 2px solid transparent; + display: flex; flex-direction: column; aspect-ratio: 0.75; @@ -697,31 +700,41 @@ justify-content: center; } - .preview-image-container { - flex: 1; - border-radius: 4px 4px 0 0; - } - - .preview-text-container { - flex: 1; - border-radius: 0 0 4px 4px; + .preview-selected-container { display: flex; flex-direction: column; - align-items: center; - justify-content: center; - font-size: 18px; - text-align: center; - color: var(--color-text-selection-bg); - background-image: url(../assets/parchments/dh-parchment-light.png); + border: 2px solid light-dark(@dark-blue-50, @beige-50); + border-radius: 6px; + max-width: 200px; + height: 100%; + + .preview-image-container { + width: 100%; + flex-grow: 1; + object-fit: cover; + border-radius: 4px 4px 0 0; + } + + .preview-text-container { + font-family: @font-body; + padding: 10px 0; + text-align: center; + font-size: 16px; + color: light-dark(@beige, @dark); + background-image: url(../assets/parchments/dh-parchment-light.png); + border-radius: 0 0 4px 4px; + } } .preview-empty-container { + border-radius: 6px; pointer-events: none; position: relative; display: flex; align-items: center; justify-content: center; flex: 1; + border: 2px dashed light-dark(@dark-blue-50, @beige-50); .preview-empty-inner-container { width: 100%; @@ -729,15 +742,19 @@ justify-content: center; .preview-add-icon { - font-size: 48px; + font-size: 40px; + color: light-dark(@dark-blue-50, @beige-50); } .preview-empty-subtext { position: absolute; - top: 10%; - font-size: 18px; + bottom: 5%; + font-size: 10px; font-variant: small-caps; text-align: center; + font-family: @font-body; + font-style: italic; + color: light-dark(@dark-blue-60, @beige-80); } } } diff --git a/styles/less/global/inventory-item.less b/styles/less/global/inventory-item.less index 5ab4759c..0ca383d5 100644 --- a/styles/less/global/inventory-item.less +++ b/styles/less/global/inventory-item.less @@ -55,6 +55,10 @@ width: 40px; object-fit: cover; border-radius: 3px; + + &.actor-img { + border-radius: 50%; + } } .roll-img { diff --git a/styles/less/global/item-header.less b/styles/less/global/item-header.less index 1fb27325..7b2c907f 100755 --- a/styles/less/global/item-header.less +++ b/styles/less/global/item-header.less @@ -3,11 +3,11 @@ .appTheme({ .item-card-header .item-icons-list .item-icon img { - filter: invert(88%) sepia(98%) saturate(1784%) hue-rotate(311deg) brightness(104%) contrast(91%); + filter: @golden-filter; } }, { .item-card-header .item-icons-list .item-icon img { - filter: invert(87%) sepia(15%) saturate(343%) hue-rotate(333deg) brightness(110%) contrast(87%); + filter: @bright-beige-filter; } }); diff --git a/styles/less/sheets/actors/companion/details.less b/styles/less/sheets/actors/companion/details.less index 2e76cf44..47b5873d 100644 --- a/styles/less/sheets/actors/companion/details.less +++ b/styles/less/sheets/actors/companion/details.less @@ -24,6 +24,9 @@ flex-direction: column; gap: 10px; align-items: center; + width: 100%; + padding: 0 10px; + margin-bottom: 5px; } } @@ -33,6 +36,7 @@ text-align: center; font-style: italic; justify-content: center; + padding: 10px 0; } .experience-list { @@ -40,7 +44,6 @@ flex-direction: column; gap: 5px; width: 100%; - margin-top: 10px; align-items: center; .experience-row { @@ -49,6 +52,8 @@ width: 250px; align-items: center; justify-content: space-between; + width: 100%; + padding: 0 10px; .experience-name { width: 180px; diff --git a/styles/less/ui/index.less b/styles/less/ui/index.less index e9865a2d..4a93feb6 100644 --- a/styles/less/ui/index.less +++ b/styles/less/ui/index.less @@ -18,4 +18,6 @@ @import './resources/resources.less'; -@import './settings/settings.less'; \ No newline at end of file +@import './settings/settings.less'; + +@import './settings/homebrew-settings/domains.less'; diff --git a/styles/less/ui/settings/homebrew-settings/domains.less b/styles/less/ui/settings/homebrew-settings/domains.less new file mode 100644 index 00000000..e0e0dcd7 --- /dev/null +++ b/styles/less/ui/settings/homebrew-settings/domains.less @@ -0,0 +1,155 @@ +.theme-light .daggerheart.dh-style.setting.homebrew-settings .domains.tab { + .domains-container .domain-container { + .domain-label { + background-image: url('../assets/parchments/dh-parchment-light.png'); + } + + img { + filter: @dark-filter; + } + } +} + +.daggerheart.dh-style.setting.homebrew-settings { + .domains.tab { + .title-wrapper { + width: 100%; + display: flex; + align-items: center; + justify-content: center; + gap: 12px; + + &:first-child { + h2 { + margin-top: 0; + } + } + + .top-lines { + position: relative; + bottom: 8px; + } + + h2 { + display: flex; + align-items: center; + font-family: @font-subtitle; + position: relative; + width: auto; + white-space: nowrap; + margin-top: 16px; + gap: 8px; + color: light-dark(@dark, @beige); + + .add-button { + border-radius: 50%; + width: 24px; + height: 24px; + font-size: 12px; + } + } + } + + .domains-container { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; + gap: 8px; + + .domain-container { + position: relative; + display: flex; + justify-content: center; + border: 1px solid light-dark(@dark-blue, @golden); + border-radius: 6px; + + &.selectable { + height: 100%; + background: inherit; + padding: 0; + } + + &.inactive { + opacity: 0.5; + } + + .domain-label { + position: absolute; + top: 4px; + border: 1px solid light-dark(@dark-blue, @golden); + border-radius: 6px; + padding: 0 2px; + color: light-dark(@dark, @beige); + background-image: url('../assets/parchments/dh-parchment-dark.png'); + white-space: nowrap; + text-wrap: auto; + text-align: center; + z-index: 2; + } + + img { + border-radius: 6px; + filter: @beige-filter; + } + } + } + + .domain-edit-container { + display: grid; + grid-template-rows: 0fr; + transition: grid-template-rows 0.3s ease-in-out; + overflow: hidden; + + &.extended { + grid-template-rows: 1fr; + + fieldset { + opacity: 1; + } + } + + fieldset { + overflow: hidden; + opacity: 0; + transition: opacity 0.3s ease-in-out; + + legend { + display: flex; + align-items: center; + gap: 4px; + + button { + border-radius: 50%; + font-size: 12px; + height: 24px; + width: 24px; + margin-right: 4px; + } + } + + .domain-filepicker-row { + width: 100%; + + .form-group { + flex: 1; + gap: 8px; + + .form-fields { + flex: 1; + display: flex; + + file-picker { + flex: 1; + } + } + } + } + + textarea { + width: 100%; + height: 120px; + margin-top: 4px; + } + } + } + } +} diff --git a/styles/less/ui/settings/settings.less b/styles/less/ui/settings/settings.less index 3033b4e7..8062ff73 100644 --- a/styles/less/ui/settings/settings.less +++ b/styles/less/ui/settings/settings.less @@ -119,6 +119,7 @@ top: -7px; font-size: 12px; font-variant: petite-caps; + z-index: 2; } input { diff --git a/styles/less/utils/colors.less b/styles/less/utils/colors.less index 0b87e18c..aed3b7dc 100755 --- a/styles/less/utils/colors.less +++ b/styles/less/utils/colors.less @@ -5,6 +5,8 @@ @golden-10: #f3c26710; @golden-40: #f3c26740; @golden-bg: #f3c2671a; +@golden-filter: brightness(0) saturate(100%) invert(89%) sepia(13%) saturate(2008%) hue-rotate(332deg) brightness(99%) + contrast(92%); @chat-blue: #8f87ee; @chat-blue-10: #8f87ee10; @@ -49,6 +51,7 @@ @dark: #222; @dark-15: #22222215; @dark-40: #22222240; +@dark-filter: brightness(0) saturate(100%); @deep-black: #0e0d15; @@ -56,6 +59,10 @@ @beige-15: #efe6d815; @beige-50: #efe6d850; @beige-80: #efe6d880; +@beige-filter: brightness(0) saturate(100%) invert(87%) sepia(25%) saturate(164%) hue-rotate(339deg) brightness(106%) + contrast(87%); +@bright-beige-filter: brightness(0) saturate(100%) invert(87%) sepia(15%) saturate(343%) hue-rotate(333deg) + brightness(110%) contrast(87%); @soft-white-shadow: rgba(255, 255, 255, 0.05); diff --git a/templates/components/card-preview.hbs b/templates/components/card-preview.hbs index 08d4ca01..67388b6d 100644 --- a/templates/components/card-preview.hbs +++ b/templates/components/card-preview.hbs @@ -3,13 +3,15 @@ {{#if (not disabled)}}data-action="viewCompendium"{{/if}} data-compendium="{{this.compendium}}" data-path="{{this.path}}" data-limit="{{this.limit}}" > {{#if this.img}} -