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"}}
+
+
+ {{localize "DAGGERHEART.SETTINGS.Homebrew.domains.homebrewDomains"}}
+
+
+ {{localize 'DAGGERHEART.SETTINGS.Menu.homebrew.name'}}
+ {{localize "DAGGERHEART.SETTINGS.Homebrew.FIELDS.traitArray.label"}}
+