From 02958f9574981609ba9a4480ff538c4f5d5b3bcc Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Wed, 6 Aug 2025 13:58:17 +0200 Subject: [PATCH] [Feature] Homebrew Domains (#639) * Split into tabs * Finished homebrew settings * . * Improved domainremoval cleanup --- lang/en.json | 18 +- .../dialogs/multiclassChoiceDialog.mjs | 2 +- .../applications/levelup/characterLevelup.mjs | 10 +- module/applications/levelup/levelup.mjs | 10 +- .../settings/homebrewSettings.mjs | 155 +++++++++++++++++- module/applications/sheets/items/class.mjs | 2 +- .../applications/sheets/items/domainCard.mjs | 8 + module/applications/ux/filter-menu.mjs | 2 +- module/config/domainConfig.mjs | 13 +- module/data/item/domainCard.mjs | 2 +- module/data/settings/Homebrew.mjs | 16 +- module/helpers/utils.mjs | 15 +- styles/less/global/elements.less | 33 ++-- styles/less/global/item-header.less | 4 +- styles/less/ui/index.less | 4 +- .../settings/homebrew-settings/domains.less | 155 ++++++++++++++++++ styles/less/ui/settings/settings.less | 1 + styles/less/utils/colors.less | 7 + .../settings/homebrew-settings/domains.hbs | 45 +++++ .../settings/homebrew-settings/downtime.hbs | 51 ++++++ .../settings/homebrew-settings/footer.hbs | 10 ++ .../settings/homebrew-settings/settings.hbs | 38 +++++ templates/sheets/items/domainCard/header.hbs | 6 +- .../sheets/items/domainCard/settings.hbs | 2 +- 24 files changed, 560 insertions(+), 49 deletions(-) create mode 100644 styles/less/ui/settings/homebrew-settings/domains.less create mode 100644 templates/settings/homebrew-settings/domains.hbs create mode 100644 templates/settings/homebrew-settings/downtime.hbs create mode 100644 templates/settings/homebrew-settings/footer.hbs create mode 100644 templates/settings/homebrew-settings/settings.hbs diff --git a/lang/en.json b/lang/en.json index 81778a4a..b080fcc8 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 cb88e5dd..172b7e40 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'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -253,7 +252,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 } @@ -357,10 +359,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/styles/less/global/elements.less b/styles/less/global/elements.less index 067b4c86..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,23 +652,25 @@ } } -.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); + } } } } 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/ui/index.less b/styles/less/ui/index.less index c2ad2b3b..52c400f9 100644 --- a/styles/less/ui/index.less +++ b/styles/less/ui/index.less @@ -17,4 +17,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/settings/homebrew-settings/domains.hbs b/templates/settings/homebrew-settings/domains.hbs new file mode 100644 index 00000000..0946f211 --- /dev/null +++ b/templates/settings/homebrew-settings/domains.hbs @@ -0,0 +1,45 @@ +
+
+ +

{{localize "DAGGERHEART.SETTINGS.Homebrew.domains.domainsTitle"}}

+ +
+
+ {{#each configDomains as | domain |}} +
+
{{localize domain.label}}
+ +
+ {{/each}} +
+ +
+ +

+ {{localize "DAGGERHEART.SETTINGS.Homebrew.domains.homebrewDomains"}} + +

+ +
+
+ {{#each homebrewDomains as | domain id |}} + + {{/each}} +
+ +
+
+ {{localize "DAGGERHEART.SETTINGS.Homebrew.domains.editDomain"}} + +
{{formGroup settingFields.schema.fields.domains.element.fields.src value=selectedDomain.src name=(concat "domains." selectedDomain.id ".src") localize=true}}
+ +
+
+
\ No newline at end of file diff --git a/templates/settings/homebrew-settings/downtime.hbs b/templates/settings/homebrew-settings/downtime.hbs new file mode 100644 index 00000000..890afddc --- /dev/null +++ b/templates/settings/homebrew-settings/downtime.hbs @@ -0,0 +1,51 @@ +
+
+ {{localize "DAGGERHEART.SETTINGS.Homebrew.downtimeMoves"}} + +
+ + {{localize "DAGGERHEART.APPLICATIONS.Downtime.longRest.title"}} + + + + +
+ +
+ +
+
+ +
+ {{#each settingFields._source.restMoves.longRest.moves as |move id|}} + {{> "systems/daggerheart/templates/settings/components/settings-item-line.hbs" this type="longRest" id=id }} + {{/each}} +
+
+ +
+ + {{localize "DAGGERHEART.APPLICATIONS.Downtime.shortRest.title"}} + + + + +
+ +
+ +
+
+ +
+ {{#each settingFields._source.restMoves.shortRest.moves as |move id|}} + {{> "systems/daggerheart/templates/settings/components/settings-item-line.hbs" this type="shortRest" id=id }} + {{/each}} +
+
+
+
\ No newline at end of file diff --git a/templates/settings/homebrew-settings/footer.hbs b/templates/settings/homebrew-settings/footer.hbs new file mode 100644 index 00000000..954572de --- /dev/null +++ b/templates/settings/homebrew-settings/footer.hbs @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/templates/settings/homebrew-settings/settings.hbs b/templates/settings/homebrew-settings/settings.hbs new file mode 100644 index 00000000..be408353 --- /dev/null +++ b/templates/settings/homebrew-settings/settings.hbs @@ -0,0 +1,38 @@ +
+
+
+

{{localize 'DAGGERHEART.SETTINGS.Menu.homebrew.name'}}

+
+ {{formGroup settingFields.schema.fields.maxFear value=settingFields._source.maxFear localize=true}} + {{formGroup settingFields.schema.fields.maxDomains value=settingFields._source.maxDomains localize=true}} + {{formGroup settingFields.schema.fields.maxLoadout value=settingFields._source.maxLoadout localize=true}} +
+ +

{{localize "DAGGERHEART.SETTINGS.Homebrew.FIELDS.traitArray.label"}}

+
+ {{#each settingFields._source.traitArray as |trait index|}} +
+ + +
+ {{/each}} +
+ +
+ + {{localize "DAGGERHEART.SETTINGS.Homebrew.currency.title"}} + + {{formGroup settingFields.schema.fields.currency.fields.enabled value=settingFields._source.currency.enabled localize=true}} + {{formGroup settingFields.schema.fields.currency.fields.title value=settingFields._source.currency.title localize=true}} + {{formGroup settingFields.schema.fields.currency.fields.coins value=settingFields._source.currency.coins localize=true}} + {{formGroup settingFields.schema.fields.currency.fields.handfulls value=settingFields._source.currency.handfulls localize=true}} + {{formGroup settingFields.schema.fields.currency.fields.bags value=settingFields._source.currency.bags localize=true}} + {{formGroup settingFields.schema.fields.currency.fields.chests value=settingFields._source.currency.chests localize=true}} + +
+
+
\ No newline at end of file diff --git a/templates/sheets/items/domainCard/header.hbs b/templates/sheets/items/domainCard/header.hbs index dd048236..7d3b73e2 100644 --- a/templates/sheets/items/domainCard/header.hbs +++ b/templates/sheets/items/domainCard/header.hbs @@ -7,8 +7,8 @@ - {{localize (concat 'DAGGERHEART.GENERAL.Domain.' source.system.domain '.label')}} - + {{localize @root.domain.label}} +
@@ -18,7 +18,7 @@

{{localize (concat 'DAGGERHEART.CONFIG.DomainCardTypes.' source.system.type)}} - - {{localize (concat 'DAGGERHEART.GENERAL.Domain.' source.system.domain '.label')}} + {{localize @root.domain.label}} - {{localize "DAGGERHEART.GENERAL.level"}}: {{source.system.level}} diff --git a/templates/sheets/items/domainCard/settings.hbs b/templates/sheets/items/domainCard/settings.hbs index 5518b4c3..ae20624d 100644 --- a/templates/sheets/items/domainCard/settings.hbs +++ b/templates/sheets/items/domainCard/settings.hbs @@ -9,7 +9,7 @@ {{localize "DAGGERHEART.GENERAL.type"}} {{formField systemFields.type value=source.system.type localize=true}} {{localize "DAGGERHEART.GENERAL.Domain.single"}} - {{formField systemFields.domain value=source.system.domain localize=true}} + {{formField systemFields.domain value=source.system.domain choices=domainChoices valueAttr="id" labelAttr="label" localize=true}} {{localize "DAGGERHEART.GENERAL.level"}} {{formField systemFields.level value=source.system.level data-dtype="Number"}} {{localize "DAGGERHEART.ITEMS.DomainCard.recallCost"}}