From f1ab04bf32e9b4c02886a3c24fa89f4eb650f076 Mon Sep 17 00:00:00 2001 From: LeRatierBretonnier Date: Wed, 25 Feb 2026 15:49:55 +0100 Subject: [PATCH] Migration vers datamodels --- gulpfile.js | 46 +- lang/en.json | 15 +- lang/fr.json | 15 +- modules/actors/ecryme-actor.js | 6 +- modules/actors/sheets/_module.js | 2 + modules/actors/sheets/annency-sheet.js | 127 + modules/actors/sheets/base-actor-sheet.js | 81 + modules/actors/sheets/pc-npc-sheet.js | 255 ++ modules/common/ecryme-utility.js | 5 + modules/dialogs/ecryme-confront-dialog.js | 399 +-- .../dialogs/ecryme-confront-start-dialog.js | 111 +- modules/dialogs/ecryme-roll-dialog.js | 130 +- modules/ecryme-main.js | 23 +- modules/items/sheets/_module.js | 6 + modules/items/sheets/base-item-sheet.js | 131 + modules/items/sheets/equipment-sheet.js | 24 + modules/items/sheets/maneuver-sheet.js | 24 + modules/items/sheets/specialization-sheet.js | 24 + modules/items/sheets/trait-sheet.js | 24 + modules/items/sheets/weapon-sheet.js | 24 + package-lock.json | 2167 +++++++++++++++++ package.json | 22 + packs/equipment/{000276.log => 000280.log} | 0 packs/equipment/CURRENT | 2 +- packs/equipment/LOG | 6 +- packs/equipment/LOG.old | 10 +- .../{MANIFEST-000275 => MANIFEST-000279} | Bin 160 -> 160 bytes packs/help/{000213.log => 000217.log} | 0 packs/help/CURRENT | 2 +- packs/help/LOG | 6 +- packs/help/LOG.old | 11 +- .../help/{MANIFEST-000212 => MANIFEST-000216} | Bin 208 -> 208 bytes packs/maneuvers/{000276.log => 000280.log} | 0 packs/maneuvers/CURRENT | 2 +- packs/maneuvers/LOG | 6 +- packs/maneuvers/LOG.old | 10 +- .../{MANIFEST-000275 => MANIFEST-000279} | Bin 156 -> 156 bytes packs/scenes/{000162.log => 000166.log} | 0 packs/scenes/CURRENT | 2 +- packs/scenes/LOG | 6 +- packs/scenes/LOG.old | 11 +- .../{MANIFEST-000161 => MANIFEST-000165} | Bin 193 -> 193 bytes .../specialisation/{000276.log => 000280.log} | 0 packs/specialisation/CURRENT | 2 +- packs/specialisation/LOG | 6 +- packs/specialisation/LOG.old | 10 +- .../{MANIFEST-000275 => MANIFEST-000279} | Bin 160 -> 160 bytes packs/traits/{000276.log => 000280.log} | 0 packs/traits/CURRENT | 2 +- packs/traits/LOG | 6 +- packs/traits/LOG.old | 10 +- .../{MANIFEST-000275 => MANIFEST-000279} | Bin 159 -> 159 bytes styles/_variables.less | 51 + styles/actor-sheet-steampunk.less | 430 ++++ styles/actor-sheet-v2.less | 71 + styles/actor-sheet.less | 154 ++ styles/chat-steampunk.less | 689 ++++++ styles/chat.less | 251 ++ styles/dialog-steampunk.less | 264 ++ styles/ecryme.css | 95 +- styles/ecryme.less | 20 + styles/fonts.less | 8 + styles/global.less | 179 ++ styles/hud.less | 75 + styles/item-sheet-steampunk.less | 258 ++ styles/item-sheet.less | 59 + styles/sheet.less | 189 ++ styles/sidebar.less | 156 ++ styles/ui.less | 359 +++ system.json | 2 +- templates/actors/actor-biodata.hbs | 57 + templates/actors/actor-cephaly.hbs | 42 + templates/actors/actor-combat.hbs | 68 + templates/actors/actor-equipements.hbs | 40 + templates/actors/actor-skills.hbs | 70 + templates/actors/actor-traits.hbs | 30 + templates/actors/annency-annency.hbs | 50 + templates/actors/annency-boheme.hbs | 23 + templates/actors/partial-impacts.hbs | 4 +- templates/actors/partials/actor-header.hbs | 51 + templates/chat/chat-cephaly-result.hbs | 37 +- templates/chat/chat-confrontation-pending.hbs | 43 +- templates/chat/chat-confrontation-result.hbs | 57 +- templates/chat/chat-generic-result.hbs | 90 +- templates/dialogs/confront-dialog.hbs | 47 +- templates/dialogs/confront-start-dialog.hbs | 28 +- templates/dialogs/roll-dialog-generic.hbs | 20 +- templates/items/item-equipment-details.hbs | 19 + templates/items/item-maneuver-details.hbs | 5 + .../items/item-specialization-details.hbs | 14 + templates/items/item-trait-details.hbs | 16 + templates/items/item-weapon-details.hbs | 25 + templates/items/partials/item-description.hbs | 5 + templates/items/partials/item-header.hbs | 6 + welcome-message-ecryme.html | 83 +- 95 files changed, 7418 insertions(+), 593 deletions(-) create mode 100644 modules/actors/sheets/_module.js create mode 100644 modules/actors/sheets/annency-sheet.js create mode 100644 modules/actors/sheets/base-actor-sheet.js create mode 100644 modules/actors/sheets/pc-npc-sheet.js create mode 100644 modules/items/sheets/_module.js create mode 100644 modules/items/sheets/base-item-sheet.js create mode 100644 modules/items/sheets/equipment-sheet.js create mode 100644 modules/items/sheets/maneuver-sheet.js create mode 100644 modules/items/sheets/specialization-sheet.js create mode 100644 modules/items/sheets/trait-sheet.js create mode 100644 modules/items/sheets/weapon-sheet.js create mode 100644 package-lock.json create mode 100644 package.json rename packs/equipment/{000276.log => 000280.log} (100%) rename packs/equipment/{MANIFEST-000275 => MANIFEST-000279} (80%) rename packs/help/{000213.log => 000217.log} (100%) rename packs/help/{MANIFEST-000212 => MANIFEST-000216} (61%) rename packs/maneuvers/{000276.log => 000280.log} (100%) rename packs/maneuvers/{MANIFEST-000275 => MANIFEST-000279} (82%) rename packs/scenes/{000162.log => 000166.log} (100%) rename packs/scenes/{MANIFEST-000161 => MANIFEST-000165} (66%) rename packs/specialisation/{000276.log => 000280.log} (100%) rename packs/specialisation/{MANIFEST-000275 => MANIFEST-000279} (80%) rename packs/traits/{000276.log => 000280.log} (100%) rename packs/traits/{MANIFEST-000275 => MANIFEST-000279} (80%) create mode 100644 styles/_variables.less create mode 100644 styles/actor-sheet-steampunk.less create mode 100644 styles/actor-sheet-v2.less create mode 100644 styles/actor-sheet.less create mode 100644 styles/chat-steampunk.less create mode 100644 styles/chat.less create mode 100644 styles/dialog-steampunk.less create mode 100644 styles/ecryme.less create mode 100644 styles/fonts.less create mode 100644 styles/global.less create mode 100644 styles/hud.less create mode 100644 styles/item-sheet-steampunk.less create mode 100644 styles/item-sheet.less create mode 100644 styles/sheet.less create mode 100644 styles/sidebar.less create mode 100644 styles/ui.less create mode 100644 templates/actors/actor-biodata.hbs create mode 100644 templates/actors/actor-cephaly.hbs create mode 100644 templates/actors/actor-combat.hbs create mode 100644 templates/actors/actor-equipements.hbs create mode 100644 templates/actors/actor-skills.hbs create mode 100644 templates/actors/actor-traits.hbs create mode 100644 templates/actors/annency-annency.hbs create mode 100644 templates/actors/annency-boheme.hbs create mode 100644 templates/actors/partials/actor-header.hbs create mode 100644 templates/items/item-equipment-details.hbs create mode 100644 templates/items/item-maneuver-details.hbs create mode 100644 templates/items/item-specialization-details.hbs create mode 100644 templates/items/item-trait-details.hbs create mode 100644 templates/items/item-weapon-details.hbs create mode 100644 templates/items/partials/item-description.hbs create mode 100644 templates/items/partials/item-header.hbs diff --git a/gulpfile.js b/gulpfile.js index 4c748fd..3a2fe0e 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,25 +1,31 @@ -var gulp = require('gulp'); +const gulp = require('gulp'); +const less = require('gulp-less'); -var postcss = require('gulp-postcss'); - -var autoprefixer = require('autoprefixer'); -var cssnext = require('cssnext'); -var precss = require('precss'); - -gulp.task('css', function () { - - var processors = [ - autoprefixer, - cssnext, - precss - ]; - - return gulp.src('./postcss/*.css') - .pipe(postcss(processors)) - .pipe(gulp.dest('./styles')); -}); +/* ----------------------------------------- */ +/* Compile LESS +/* ----------------------------------------- */ +function compileLESS() { + return gulp.src("styles/ecryme.less") + .pipe(less()).on('error', console.log.bind(console)) + .pipe(gulp.dest("./css")); +} +const css = gulp.series(compileLESS); +/* ----------------------------------------- */ +/* Watch Updates +/* ----------------------------------------- */ +const LESS_FILES = ["styles/**/*.less"]; function watchUpdates() { - gulp.watch('./postcss/*.css', css); + gulp.watch(LESS_FILES, css); } + +/* ----------------------------------------- */ +/* Export Tasks +/* ----------------------------------------- */ +exports.default = gulp.series( + gulp.parallel(css), + watchUpdates +); +exports.css = css; +exports.watchUpdates = watchUpdates; diff --git a/lang/en.json b/lang/en.json index a6448a0..aec63c5 100644 --- a/lang/en.json +++ b/lang/en.json @@ -112,6 +112,7 @@ "applyspleen": "Apply spleen", "skilltranscendence": "Self Transcendence", "confrontation": "Confrontation", + "confrontresult": "Confrontation Result", "rollnormal": "Normal (4d6)", "rollspleen": "With Spleen (5d6, worst 4 are kept)", "rollideal": "With Ideal (5d6, best 4 are kept)", @@ -168,7 +169,19 @@ "residence": "Residence", "origin": "Origin", "childhood": "Childhood", - "bonus": "Bonus" + "bonus": "Bonus", + "details": "Details", + "quantity": "Quantity", + "background": "Background", + "gmnotes": "GM Notes", + "age": "Age", + "profession": "Profession", + "level": "Level", + "create": "Create", + "delete": "Delete", + "edit": "Edit", + "spleen": "Spleen", + "ideal": "Ideal" } } } \ No newline at end of file diff --git a/lang/fr.json b/lang/fr.json index 9691f70..21568df 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -113,6 +113,7 @@ "applyspleen": "Utiliser le spleen", "skilltranscendence": "Dépassement de soi", "confrontation": "Confrontation", + "confrontresult": "Résultat de Confrontation", "rollnormal": "Normal (4d6)", "rollspleen": "Avec le Spleen (5d6, 4 plus bas conservés)", "rollideal": "Avec l'Idéal (5d6, 4 plus haut conservés)", @@ -169,7 +170,19 @@ "residence": "Résidence", "origin": "Origine", "childhood": "Enfance", - "bonus": "Bonus" + "bonus": "Bonus", + "details": "Détails", + "quantity": "Quantité", + "background": "Background", + "gmnotes": "Notes GM", + "age": "Âge", + "profession": "Profession", + "level": "Niveau", + "create": "Créer", + "delete": "Supprimer", + "edit": "Éditer", + "spleen": "Spleen", + "ideal": "Idéal" } } } \ No newline at end of file diff --git a/modules/actors/ecryme-actor.js b/modules/actors/ecryme-actor.js index c57697c..4db6b0d 100644 --- a/modules/actors/ecryme-actor.js +++ b/modules/actors/ecryme-actor.js @@ -379,9 +379,9 @@ export class EcrymeActor extends Actor { rollData.img = this.img rollData.isReroll = false rollData.config = game.system.ecryme.config - rollData.traits = foundry.utils.duplicate(this.getRollTraits()) - rollData.spleen = foundry.utils.duplicate(this.getSpleen() || {}) - rollData.ideal = foundry.utils.duplicate(this.getIdeal() || {}) + rollData.traits = this.getRollTraits().map(t => ({ _id: t.id, name: t.name, img: t.img, system: { level: t.system.level, traitype: t.system.traitype } })) + rollData.spleen = this.getSpleen() ? foundry.utils.duplicate(this.getSpleen()) : null + rollData.ideal = this.getIdeal() ? foundry.utils.duplicate(this.getIdeal()) : null rollData.confrontBonus = this.getBonusList() return rollData diff --git a/modules/actors/sheets/_module.js b/modules/actors/sheets/_module.js new file mode 100644 index 0000000..8c0042d --- /dev/null +++ b/modules/actors/sheets/_module.js @@ -0,0 +1,2 @@ +export { default as EcrymeActorSheet } from "./pc-npc-sheet.js" +export { default as EcrymeAnnencySheet } from "./annency-sheet.js" diff --git a/modules/actors/sheets/annency-sheet.js b/modules/actors/sheets/annency-sheet.js new file mode 100644 index 0000000..6599aff --- /dev/null +++ b/modules/actors/sheets/annency-sheet.js @@ -0,0 +1,127 @@ +import EcrymeBaseActorSheet from "./base-actor-sheet.js" +import { EcrymeUtility } from "../../common/ecryme-utility.js" + +/** + * Actor sheet for the Annency type using Application V2. + */ +export default class EcrymeAnnencySheet extends EcrymeBaseActorSheet { + + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["annency"], + position: { width: 640, height: 600 }, + actions: { + actorEdit: EcrymeAnnencySheet.#onActorEdit, + actorDelete: EcrymeAnnencySheet.#onActorDelete, + itemEdit: EcrymeAnnencySheet.#onItemEdit, + itemDelete: EcrymeAnnencySheet.#onItemDelete, + itemCreate: EcrymeAnnencySheet.#onItemCreate, + }, + } + + /** @override */ + static PARTS = { + header: { template: "systems/fvtt-ecryme/templates/actors/partials/actor-header.hbs" }, + tabs: { template: "templates/generic/tab-navigation.hbs" }, + annency: { template: "systems/fvtt-ecryme/templates/actors/annency-annency.hbs" }, + boheme: { template: "systems/fvtt-ecryme/templates/actors/annency-boheme.hbs" }, + } + + /** @override */ + tabGroups = { primary: "annency" } + + /** Build tabs conditionally based on active modules */ + _getTabs() { + const tabs = {} + if (EcrymeUtility.hasCephaly()) { + tabs.annency = { id: "annency", group: "primary", label: "ECRY.ui.annency" } + } + if (EcrymeUtility.hasBoheme()) { + tabs.boheme = { id: "boheme", group: "primary", label: "ECRY.ui.boheme" } + } + // Ensure initial tab is valid + if (!tabs[this.tabGroups.primary]) { + this.tabGroups.primary = Object.keys(tabs)[0] ?? "annency" + } + for (const tab of Object.values(tabs)) { + tab.active = this.tabGroups[tab.group] === tab.id + tab.cssClass = tab.active ? "active" : "" + } + return tabs + } + + /** @override */ + async _prepareContext() { + const actor = this.document + return { + actor, + system: actor.system, + source: actor.toObject(), + fields: actor.schema.fields, + systemFields: actor.system.schema.fields, + type: actor.type, + img: actor.img, + name: actor.name, + isEditable: this.isEditable, + config: game.system.ecryme.config, + hasCephaly: EcrymeUtility.hasCephaly(), + hasBoheme: EcrymeUtility.hasBoheme(), + characters: actor.buildAnnencyActorList(), + owner: this.document.isOwner, + isGM: game.user.isGM, + tabs: this._getTabs(), + } + } + + /** @override */ + async _preparePartContext(partId, context) { + context = await super._preparePartContext(partId, context) + if (partId === "annency" || partId === "boheme") { + context.tab = context.tabs[partId] + } + return context + } + + /** @override */ + async _onDrop(event) { + const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event) + if (data.type === "Actor") { + const actor = await fromUuid(data.uuid) + if (actor) { + this.actor.addAnnencyActor(actor.id) + } else { + ui.notifications.warn("Actor not found") + } + } + } + + // #region Static Action Handlers + + static #onActorEdit(event, target) { + const li = target.closest("[data-actor-id]") + game.actors.get(li?.dataset.actorId)?.sheet.render(true) + } + + static async #onActorDelete(event, target) { + const li = target.closest("[data-actor-id]") + this.actor.removeAnnencyActor(li?.dataset.actorId) + } + + static #onItemEdit(event, target) { + const li = target.closest("[data-item-id]") + const itemId = li?.dataset.itemId ?? target.dataset.itemId + this.document.items.get(itemId)?.sheet.render(true) + } + + static async #onItemDelete(event, target) { + const li = target.closest("[data-item-id]") + EcrymeUtility.confirmDelete(this, $(li)).catch(() => {}) + } + + static #onItemCreate(event, target) { + const dataType = target.dataset.type + this.document.createEmbeddedDocuments("Item", [{ name: "NewItem", type: dataType }], { renderSheet: true }) + } + + // #endregion +} diff --git a/modules/actors/sheets/base-actor-sheet.js b/modules/actors/sheets/base-actor-sheet.js new file mode 100644 index 0000000..7576d22 --- /dev/null +++ b/modules/actors/sheets/base-actor-sheet.js @@ -0,0 +1,81 @@ +const { HandlebarsApplicationMixin } = foundry.applications.api + +/** + * Base actor sheet for Ecryme using Application V2. + * Provides common drag-drop, image editing, and shared structure. + */ +export default class EcrymeBaseActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) { + + constructor(options = {}) { + super(options) + this.#dragDrop = this.#createDragDropHandlers() + } + + #dragDrop + + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["fvtt-ecryme", "sheet", "actor"], + position: { + width: 860, + height: 680, + }, + form: { + submitOnChange: true, + }, + window: { + resizable: true, + }, + dragDrop: [{ dragSelector: ".item-list .item[data-item-id]", dropSelector: null }], + actions: { + editImage: EcrymeBaseActorSheet.#onEditImage, + }, + } + + /** @override */ + _onRender(context, options) { + this.#dragDrop.forEach((d) => d.bind(this.element)) + } + + // #region Drag-and-Drop + #createDragDropHandlers() { + return this.options.dragDrop.map((d) => { + d.permissions = { + dragstart: this._canDragStart.bind(this), + drop: this._canDragDrop.bind(this), + } + d.callbacks = { + dragstart: this._onDragStart.bind(this), + dragover: this._onDragOver.bind(this), + drop: this._onDrop.bind(this), + } + return new foundry.applications.ux.DragDrop.implementation(d) + }) + } + + _canDragStart(selector) { return this.isEditable } + _canDragDrop(selector) { return this.isEditable && this.document.isOwner } + _onDragStart(event) {} + _onDragOver(event) {} + async _onDrop(event) {} + // #endregion + + // #region Actions + static async #onEditImage(event, target) { + const attr = target.dataset.edit + const current = foundry.utils.getProperty(this.document, attr) + const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {} + const fp = new FilePicker({ + current, + type: "image", + redirectToRoot: img ? [img] : [], + callback: (path) => { + this.document.update({ [attr]: path }) + }, + top: this.position.top + 40, + left: this.position.left + 10, + }) + return fp.browse() + } + // #endregion +} diff --git a/modules/actors/sheets/pc-npc-sheet.js b/modules/actors/sheets/pc-npc-sheet.js new file mode 100644 index 0000000..342aa79 --- /dev/null +++ b/modules/actors/sheets/pc-npc-sheet.js @@ -0,0 +1,255 @@ +import EcrymeBaseActorSheet from "./base-actor-sheet.js" +import { EcrymeUtility } from "../../common/ecryme-utility.js" + +/** + * Actor sheet for PC and NPC types using Application V2. + */ +export default class EcrymeActorSheet extends EcrymeBaseActorSheet { + + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["pc-npc"], + position: { width: 860, height: 680 }, + actions: { + openAnnency: EcrymeActorSheet.#onOpenAnnency, + itemEdit: EcrymeActorSheet.#onItemEdit, + itemDelete: EcrymeActorSheet.#onItemDelete, + itemCreate: EcrymeActorSheet.#onItemCreate, + subactorEdit: EcrymeActorSheet.#onSubactorEdit, + subactorDelete: EcrymeActorSheet.#onSubactorDelete, + rollSkill: EcrymeActorSheet.#onRollSkill, + rollSpec: EcrymeActorSheet.#onRollSpec, + rollSkillConfront: EcrymeActorSheet.#onRollSkillConfront, + rollCephaly: EcrymeActorSheet.#onRollCephaly, + rollWeaponConfront:EcrymeActorSheet.#onRollWeaponConfront, + impactModify: EcrymeActorSheet.#onImpactModify, + rollWeapon: EcrymeActorSheet.#onRollWeapon, + lockUnlock: EcrymeActorSheet.#onLockUnlock, + equipItem: EcrymeActorSheet.#onEquipItem, + quantityMinus: EcrymeActorSheet.#onQuantityMinus, + quantityPlus: EcrymeActorSheet.#onQuantityPlus, + }, + } + + /** @override */ + static PARTS = { + header: { template: "systems/fvtt-ecryme/templates/actors/partials/actor-header.hbs" }, + tabs: { template: "templates/generic/tab-navigation.hbs" }, + skills: { template: "systems/fvtt-ecryme/templates/actors/actor-skills.hbs" }, + traits: { template: "systems/fvtt-ecryme/templates/actors/actor-traits.hbs" }, + combat: { template: "systems/fvtt-ecryme/templates/actors/actor-combat.hbs" }, + cephaly: { template: "systems/fvtt-ecryme/templates/actors/actor-cephaly.hbs" }, + equipements:{ template: "systems/fvtt-ecryme/templates/actors/actor-equipements.hbs" }, + biodata: { template: "systems/fvtt-ecryme/templates/actors/actor-biodata.hbs" }, + } + + /** @override */ + tabGroups = { primary: "skills" } + + /** Build tabs, conditionally adding cephaly if the module is active */ + _getTabs() { + const hasCephaly = EcrymeUtility.hasCephaly() + const tabs = { + skills: { id: "skills", group: "primary", label: "ECRY.ui.skills" }, + traits: { id: "traits", group: "primary", label: "ECRY.ui.traits" }, + combat: { id: "combat", group: "primary", label: "ECRY.ui.healthcombat" }, + equipements:{ id: "equipements", group: "primary", label: "ECRY.ui.equipment" }, + biodata: { id: "biodata", group: "primary", label: "ECRY.ui.bionotes" }, + } + if (hasCephaly) { + // Insert cephaly after combat, rebuilding the object to preserve insertion order + const ordered = {} + for (const [k, v] of Object.entries(tabs)) { + ordered[k] = v + if (k === "combat") ordered.cephaly = { id: "cephaly", group: "primary", label: "ECRY.ui.cephaly" } + } + for (const tab of Object.values(ordered)) { + tab.active = this.tabGroups[tab.group] === tab.id + tab.cssClass = tab.active ? "active" : "" + } + return ordered + } + for (const tab of Object.values(tabs)) { + tab.active = this.tabGroups[tab.group] === tab.id + tab.cssClass = tab.active ? "active" : "" + } + return tabs + } + + /** @override */ + async _prepareContext() { + const actor = this.document + return { + actor, + system: actor.system, + source: actor.toObject(), + fields: actor.schema.fields, + systemFields: actor.system.schema.fields, + type: actor.type, + img: actor.img, + name: actor.name, + isEditable: this.isEditable, + config: game.system.ecryme.config, + hasCephaly: EcrymeUtility.hasCephaly(), + hasBoheme: EcrymeUtility.hasBoheme(), + hasAmertume: EcrymeUtility.hasAmertume(), + skills: actor.prepareSkills(), + traits: actor.getRollTraits(), + ideal: actor.getIdeal(), + spleen: actor.getSpleen(), + weapons: actor.getWeapons(), + maneuvers: actor.getManeuvers(), + impactsMalus: actor.getImpactsMalus(), + equipments: actor.getEquipments(), + cephalySkills:actor.getCephalySkills(), + confrontations: actor.getConfrontations(), + subActors: actor.getSubActors(), + annency: actor.getAnnency(), + owner: this.document.isOwner, + isGM: game.user.isGM, + editScore: this.options.editScore ?? true, + tabs: this._getTabs(), + } + } + + /** @override */ + async _preparePartContext(partId, context) { + context = await super._preparePartContext(partId, context) + switch (partId) { + case "skills": + case "traits": + case "combat": + case "cephaly": + case "equipements": + context.tab = context.tabs[partId] ?? { cssClass: "" } + break + case "biodata": + context.tab = context.tabs.biodata + context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML( + this.document.system.biodata.description, { async: true } + ) + context.enrichedGmnotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML( + this.document.system.biodata.gmnotes, { async: true } + ) + break + } + return context + } + + // #region Drag and Drop + + /** Handle incoming drops: Items from sidebar/compendium, Actors as subactors */ + async _onDrop(event) { + const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event) + if (!data?.type) return + + if (data.type === "Item") { + const item = await fromUuid(data.uuid) + if (!item) return + await this.document.createEmbeddedDocuments("Item", [item.toObject()]) + } else if (data.type === "Actor") { + const actor = fromUuidSync(data.uuid) + if (actor) await this.actor.addSubActor(actor.id) + } + } + + /** Handle outgoing drag from embedded item rows */ + _onDragStart(event) { + const li = event.currentTarget.closest("[data-item-id]") + if (!li) return + const item = this.document.items.get(li.dataset.itemId) + if (!item) return + event.dataTransfer.setData("text/plain", JSON.stringify(item.toDragData())) + } + + // #endregion + + // #region Static Action Handlers + + static #onOpenAnnency(event, target) { + const actorId = target.dataset.annencyId + game.actors.get(actorId)?.sheet.render(true) + } + + static #onItemEdit(event, target) { + const li = target.closest("[data-item-id]") + const itemId = li?.dataset.itemId ?? target.dataset.itemId + this.document.items.get(itemId)?.sheet.render(true) + } + + static async #onItemDelete(event, target) { + const li = target.closest("[data-item-id]") + EcrymeUtility.confirmDelete(this, $(li)).catch(() => {}) + } + + static #onItemCreate(event, target) { + const dataType = target.dataset.type + this.document.createEmbeddedDocuments("Item", [{ name: "NewItem", type: dataType }], { renderSheet: true }) + } + + static #onSubactorEdit(event, target) { + const li = target.closest("[data-actor-id]") + game.actors.get(li?.dataset.actorId)?.sheet.render(true) + } + + static #onSubactorDelete(event, target) { + const li = target.closest("[data-actor-id]") + this.actor.delSubActor(li?.dataset.actorId) + } + + static #onRollSkill(event, target) { + this.actor.rollSkill(target.dataset.categoryKey, target.dataset.skillKey) + } + + static #onRollSpec(event, target) { + this.actor.rollSpec(target.dataset.categoryKey, target.dataset.skillKey, target.dataset.specId) + } + + static #onRollSkillConfront(event, target) { + this.actor.rollSkillConfront(target.dataset.categoryKey, target.dataset.skillKey) + } + + static #onRollCephaly(event, target) { + this.actor.rollCephalySkillConfront(target.dataset.skillKey) + } + + static #onRollWeaponConfront(event, target) { + const li = target.closest("[data-item-id]") + this.actor.rollWeaponConfront(li?.dataset.itemId) + } + + static #onImpactModify(event, target) { + this.actor.modifyImpact( + target.dataset.impactType, + target.dataset.impactLevel, + Number(target.dataset.impactModifier) + ) + } + + static #onRollWeapon(event, target) { + this.actor.rollArme(target.dataset.armeId) + } + + static #onLockUnlock(event, target) { + this.options.editScore = !this.options.editScore + this.render(true) + } + + static #onEquipItem(event, target) { + const li = target.closest("[data-item-id]") + this.actor.equipItem(li?.dataset.itemId) + this.render(true) + } + + static #onQuantityMinus(event, target) { + const li = target.closest("[data-item-id]") + this.actor.incDecQuantity(li?.dataset.itemId, -1) + } + + static #onQuantityPlus(event, target) { + const li = target.closest("[data-item-id]") + this.actor.incDecQuantity(li?.dataset.itemId, +1) + } + + // #endregion +} diff --git a/modules/common/ecryme-utility.js b/modules/common/ecryme-utility.js index 1aae5f1..428442d 100644 --- a/modules/common/ecryme-utility.js +++ b/modules/common/ecryme-utility.js @@ -211,6 +211,8 @@ export class EcrymeUtility { type: "confront-data", rollData1: this.confrontData1, rollData2: this.confrontData2, + alias: this.confrontData1.alias, + actorImg: this.confrontData1.actorImg, } // Compute margin confront.marginExecution = this.confrontData1.executionTotal - this.confrontData2.preservationTotal @@ -378,6 +380,9 @@ export class EcrymeUtility { 'systems/fvtt-ecryme/templates/dialogs/partial-confront-dice-area.hbs', 'systems/fvtt-ecryme/templates/dialogs/partial-confront-bonus-area.hbs', 'systems/fvtt-ecryme/templates/actors/partial-impacts.hbs', + 'systems/fvtt-ecryme/templates/actors/partials/actor-header.hbs', + 'systems/fvtt-ecryme/templates/items/partials/item-header.hbs', + 'systems/fvtt-ecryme/templates/items/partials/item-description.hbs', ] return foundry.applications.handlebars.loadTemplates(templatePaths); } diff --git a/modules/dialogs/ecryme-confront-dialog.js b/modules/dialogs/ecryme-confront-dialog.js index bdeb338..c6ad6ba 100644 --- a/modules/dialogs/ecryme-confront-dialog.js +++ b/modules/dialogs/ecryme-confront-dialog.js @@ -1,169 +1,192 @@ import { EcrymeUtility } from "../common/ecryme-utility.js"; -import { EcrymeRollDialog } from "./ecryme-roll-dialog.js"; -export class EcrymeConfrontDialog extends Dialog { +const { HandlebarsApplicationMixin } = foundry.applications.api + +/** + * Main confrontation dialog — Application V2 version. + * Features drag-and-drop of dice from the pool to execution/preservation slots. + * All event listeners (change + drag-drop) are bound once via _listenersAdded guard. + */ +export class EcrymeConfrontDialog extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) { + + #dragDrop + _listenersAdded = false + + /* -------------------------------------------- */ + constructor(actor, rollData, options = {}) { + super(options) + this.actor = actor + this.rollData = rollData + this.buttonDisabled = true + this.#dragDrop = this.#createDragDropHandlers() + } + + /* -------------------------------------------- */ + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["fvtt-ecryme", "ecryme-confrontation-dialog"], + position: { width: 640 }, + window: { title: "ECRY.ui.confront" }, + dragDrop: [{ dragSelector: ".confront-dice-container", dropSelector: null }], + actions: { + launchConfront: EcrymeConfrontDialog.#onLaunchConfront, + cancel: EcrymeConfrontDialog.#onCancel, + }, + } + + /** @override */ + static PARTS = { + content: { template: "systems/fvtt-ecryme/templates/dialogs/confront-dialog.hbs" }, + } /* -------------------------------------------- */ static async create(actor, rollData) { - - let options = foundry.utils.mergeObject(super.defaultOptions, { - classes: ["fvtt-ecryme ecryme-confrontation-dialog"], - dragDrop: [{ dragSelector: ".confront-dice-container", dropSelector: null }], - width: 620, height: 'fit-content', 'z-index': 99999 - }); - - let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-ecryme/templates/dialogs/confront-dialog.hbs', rollData); - return new EcrymeConfrontDialog(actor, rollData, html, options); + return new EcrymeConfrontDialog(actor, rollData) } /* -------------------------------------------- */ - constructor(actor, rollData, html, options, close = undefined) { - let conf = { - title: game.i18n.localize("ECRY.ui.confront"), - content: html, - buttons: { - launchConfront: { - icon: '', - label: game.i18n.localize("ECRY.ui.launchconfront"), - callback: () => { this.launchConfront().catch("Error when launching Confrontation") } - }, - cancel: { - icon: '', - label: game.i18n.localize("ECRY.ui.cancel"), - callback: () => { this.close() } - } - }, - close: close + async _prepareContext() { + return { + ...this.rollData, + config: game.system.ecryme.config, + buttonDisabled: this.buttonDisabled, } - - super(conf, options); - - this.actor = actor; - this.rollData = rollData; - - // Ensure button is disabled - setTimeout(function () { $(".launchConfront").attr("disabled", true) }, 180) } /* -------------------------------------------- */ - async launchConfront() { - let msg = await EcrymeUtility.createChatMessage(this.rollData.alias, "blindroll", { - content: await renderTemplate(`systems/fvtt-ecryme/templates/chat/chat-confrontation-pending.hbs`, this.rollData) + /** Bind drag-drop and form-change listeners once; re-bind DragDrop on each render. */ + _onRender(context, options) { + // DragDrop must be re-bound each render because the DOM is replaced + this.#dragDrop.forEach(d => d.bind(this.element)) + + // Form-change listener is bound once (event delegation survives DOM re-renders) + if (!this._listenersAdded) { + this._listenersAdded = true + this.element.addEventListener('change', this.#onFormChange.bind(this)) + } + } + + /* -------------------------------------------- */ + #onFormChange(event) { + const target = event.target + switch (target.id) { + case 'bonusMalusPerso': + this.rollData.bonusMalusPerso = Number(target.value) + this.computeTotals() + break + case 'roll-specialization': + this.rollData.selectedSpecs = Array.from(target.selectedOptions).map(o => o.value) + this.computeTotals() + break + case 'roll-trait-bonus': + this.rollData.traitsBonusSelected = Array.from(target.selectedOptions).map(o => o.value) + this.computeTotals() + break + case 'roll-trait-malus': + this.rollData.traitsMalusSelected = Array.from(target.selectedOptions).map(o => o.value) + this.computeTotals() + break + case 'roll-select-transcendence': + this.rollData.skillTranscendence = Number(target.value) + this.computeTotals() + break + case 'roll-apply-transcendence': + this.rollData.applyTranscendence = target.value + this.computeTotals() + break + case 'annency-bonus': + this.rollData.annencyBonus = Number(target.value) + break + } + } + + // #region Drag-and-Drop + + #createDragDropHandlers() { + return this.options.dragDrop.map(d => { + d.permissions = { + dragstart: () => true, + drop: () => true, + } + d.callbacks = { + dragstart: this._onDragStart.bind(this), + dragover: this._onDragOver.bind(this), + drop: this._onDrop.bind(this), + } + return new foundry.applications.ux.DragDrop.implementation(d) }) - EcrymeUtility.blindMessageToGM( { rollData: this.rollData, template: "systems/fvtt-ecryme/templates/chat/chat-confrontation-pending.hbs" }) - console.log("MSG", this.rollData) - msg.setFlag("world", "ecryme-rolldata", this.rollData) } /* -------------------------------------------- */ - async refreshDice() { - this.rollData.filter = "execution" - let content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-dice-area.hbs", this.rollData ) - content += await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-bonus-area.hbs", this.rollData ) - $("#confront-execution").html(content) - - this.rollData.filter = "preservation" - content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-dice-area.hbs", this.rollData ) - content += await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-bonus-area.hbs", this.rollData ) - $("#confront-preservation").html(content) - - this.rollData.filter = "mainpool" - content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-dice-area.hbs", this.rollData ) - $("#confront-dice-pool").html(content) - content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-bonus-area.hbs", this.rollData ) - $("#confront-bonus-pool").html(content) - - } - /* -------------------------------------------- */ - async refreshDialog() { - const content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/confront-dialog.hbs", this.rollData) - this.data.content = content - this.render(true) - - let button = this.buttonDisabled - setTimeout(function () { $(".launchConfront").attr("disabled", button) }, 180) - } - - /* ------------------ -------------------------- */ - _canDragStart(selector) { - console.log("CAN DRAG START", selector, super._canDragStart(selector) ) - return true - } - _canDragDrop(selector) { - console.log("CAN DRAG DROP", selector, super._canDragDrop(selector) ) - return true - } - - /* ------------------ -------------------------- */ _onDragStart(event) { - console.log("DRAGSTART::::", event) - super._onDragStart(event) - let dragType = $(event.srcElement).data("drag-type") - let diceData = {} - console.log("DRAGTYPE", dragType) - if (dragType == "dice") { + const target = event.target + const dragType = target.dataset.dragType + let diceData + + if (dragType === "dice") { diceData = { - dragType: "dice", - diceIndex: $(event.srcElement).data("dice-idx"), - diceValue: $(event.srcElement).data("dice-value"), + dragType: "dice", + diceIndex: target.dataset.diceIdx, + diceValue: target.dataset.diceValue, } } else { diceData = { - dragType: "bonus", - bonusIndex: $(event.srcElement).data("bonus-idx"), - bonusValue: 1 + dragType: "bonus", + bonusIndex: target.dataset.bonusIdx, + bonusValue: 1, } } - event.dataTransfer.setData("text/plain", JSON.stringify(diceData)); + event.dataTransfer.setData("text/plain", JSON.stringify(diceData)) + } + + /* -------------------------------------------- */ + _onDragOver(event) { + event.preventDefault() } /* -------------------------------------------- */ _onDrop(event) { - let dataJSON = event.dataTransfer.getData('text/plain') - let data = JSON.parse(dataJSON) - if ( data.dragType == "dice") { - let idx = Number(data.diceIndex) - console.log("DATA", data, event, event.srcElement.className) - if (event.srcElement.className.includes("execution") && - this.rollData.availableDices.filter(d => d.location == "execution").length < 2) { + let data + try { data = JSON.parse(event.dataTransfer.getData("text/plain")) } + catch (e) { return } + + // Walk up the DOM to find a meaningful drop area + const executionArea = event.target.closest('.confront-execution-area') + const preservationArea = event.target.closest('.confront-preservation-area') + const diceList = event.target.closest('.confrontation-dice-list') + const bonusList = event.target.closest('.confrontation-bonus-list') + + if (data.dragType === "dice") { + const idx = Number(data.diceIndex) + if (executionArea && this.rollData.availableDices.filter(d => d.location === "execution").length < 2) { this.rollData.availableDices[idx].location = "execution" - } - if (event.srcElement.className.includes("preservation") && - this.rollData.availableDices.filter(d => d.location == "preservation").length < 2) { + } else if (preservationArea && this.rollData.availableDices.filter(d => d.location === "preservation").length < 2) { this.rollData.availableDices[idx].location = "preservation" - } - if (event.srcElement.className.includes("dice-list")) { + } else if (diceList) { this.rollData.availableDices[idx].location = "mainpool" } - if (this.rollData.availableDices.filter(d => d.location == "execution").length == 2 && this.rollData.availableDices.filter(d => d.location == "preservation").length == 2) { - this.buttonDisabled = false - } else { - this.buttonDisabled = true - } - } else { - let idx = Number(data.bonusIndex) - if (event.srcElement.className.includes("execution")) { - this.rollData.confrontBonus[idx].location = "execution" - } - if (event.srcElement.className.includes("preservation")) { - this.rollData.confrontBonus[idx].location = "preservation" - } - if (event.srcElement.className.includes("bonus-list")) { - this.rollData.confrontBonus[idx].location = "mainpool" - } + const execCount = this.rollData.availableDices.filter(d => d.location === "execution").length + const presCount = this.rollData.availableDices.filter(d => d.location === "preservation").length + this.buttonDisabled = !(execCount === 2 && presCount === 2) + + } else if (data.dragType === "bonus") { + const idx = Number(data.bonusIndex) + if (executionArea) this.rollData.confrontBonus[idx].location = "execution" + else if (preservationArea) this.rollData.confrontBonus[idx].location = "preservation" + else if (bonusList) this.rollData.confrontBonus[idx].location = "mainpool" } - // Manage total values this.computeTotals() - } + + // #endregion + /* -------------------------------------------- */ processTranscendence() { - // Apply Transcend if needed if (this.rollData.skillTranscendence > 0) { - if (this.rollData.applyTranscendence == "execution") { - this.rollData.executionTotal += Number(this.rollData.skillTranscendence) + if (this.rollData.applyTranscendence === "execution") { + this.rollData.executionTotal += Number(this.rollData.skillTranscendence) } else { this.rollData.preservationTotal += Number(this.rollData.skillTranscendence) } @@ -172,94 +195,78 @@ export class EcrymeConfrontDialog extends Dialog { /* -------------------------------------------- */ computeTotals() { - let rollData = this.rollData - let actor = game.actors.get(rollData.actorId) + const rollData = this.rollData + const actor = game.actors.get(rollData.actorId) - rollData.executionTotal = rollData.availableDices.filter(d => d.location == "execution").reduce((previous, current) => { - return previous + current.result - }, rollData.skill.value) - rollData.executionTotal = rollData.confrontBonus.filter(d => d.location == "execution").reduce((previous, current) => { - return previous + 1 - }, rollData.executionTotal) + rollData.executionTotal = rollData.availableDices + .filter(d => d.location === "execution") + .reduce((acc, d) => acc + d.result, rollData.skill.value) + rollData.executionTotal = rollData.confrontBonus + .filter(d => d.location === "execution") + .reduce((acc) => acc + 1, rollData.executionTotal) - rollData.preservationTotal = rollData.availableDices.filter(d => d.location == "preservation").reduce((previous, current) => { - return previous + current.result - }, rollData.skill.value) - rollData.preservationTotal = rollData.confrontBonus.filter(d => d.location == "preservation").reduce((previous, current) => { - return previous + 1 - }, rollData.preservationTotal) + rollData.preservationTotal = rollData.availableDices + .filter(d => d.location === "preservation") + .reduce((acc, d) => acc + d.result, rollData.skill.value) + rollData.preservationTotal = rollData.confrontBonus + .filter(d => d.location === "preservation") + .reduce((acc) => acc + 1, rollData.preservationTotal) this.processTranscendence() - if (rollData.selectedSpecs && rollData.selectedSpecs.length > 0) { - rollData.spec = foundry.utils.duplicate(actor.getSpecialization(rollData.selectedSpecs[0])) + // Specialization + if (rollData.selectedSpecs?.length > 0) { + rollData.spec = foundry.utils.duplicate(actor.getSpecialization(rollData.selectedSpecs[0])) rollData.specApplied = true - rollData.executionTotal += 2 + rollData.executionTotal += 2 rollData.preservationTotal += 2 } - if ( rollData.specApplied && rollData.selectedSpecs.length == 0) { - rollData.spec = undefined + if (rollData.specApplied && rollData.selectedSpecs?.length === 0) { + rollData.spec = undefined rollData.specApplied = false } + + // Traits bonus/malus rollData.bonusMalusTraits = 0 - for (let t of rollData.traitsBonus) { - t.activated = false + for (const t of rollData.traitsBonus) t.activated = false + for (const t of rollData.traitsMalus) t.activated = false + + for (const id of (rollData.traitsBonusSelected ?? [])) { + const trait = rollData.traitsBonus.find(t => t._id === id) + if (trait) { trait.activated = true; rollData.bonusMalusTraits += Number(trait.system.level) } } - for (let t of rollData.traitsMalus) { - t.activated = false - } - if (rollData.traitsBonusSelected && rollData.traitsBonusSelected.length > 0) { - for (let id of rollData.traitsBonusSelected) { - let trait = rollData.traitsBonus.find(t => t._id == id) - trait.activated = true - rollData.bonusMalusTraits += Number(trait.system.level) - } - } - if (rollData.traitsMalusSelected && rollData.traitsMalusSelected.length > 0) { - for (let id of rollData.traitsMalusSelected) { - let trait = rollData.traitsMalus.find(t => t._id == id) - trait.activated = true - rollData.bonusMalusTraits -= Number(trait.system.level) - } + for (const id of (rollData.traitsMalusSelected ?? [])) { + const trait = rollData.traitsMalus.find(t => t._id === id) + if (trait) { trait.activated = true; rollData.bonusMalusTraits -= Number(trait.system.level) } } - rollData.executionTotal += Number(rollData.bonusMalusTraits) + Number(rollData.bonusMalusPerso) + rollData.executionTotal += Number(rollData.bonusMalusTraits) + Number(rollData.bonusMalusPerso) rollData.preservationTotal += Number(rollData.bonusMalusTraits) + Number(rollData.bonusMalusPerso) - this.refreshDialog() + this.render() } /* -------------------------------------------- */ - activateListeners(html) { - super.activateListeners(html); - - html.find('#bonusMalusPerso').change((event) => { - this.rollData.bonusMalusPerso = event.currentTarget.value - this.computeTotals() + async launchConfront() { + const msg = await EcrymeUtility.createChatMessage(this.rollData.alias, "blindroll", { + content: await foundry.applications.handlebars.renderTemplate( + `systems/fvtt-ecryme/templates/chat/chat-confrontation-pending.hbs`, this.rollData + ), }) - html.find('#roll-specialization').change((event) => { - this.rollData.selectedSpecs = $('#roll-specialization').val() - this.computeTotals() + EcrymeUtility.blindMessageToGM({ + rollData: this.rollData, + template: "systems/fvtt-ecryme/templates/chat/chat-confrontation-pending.hbs", }) - html.find('#roll-trait-bonus').change((event) => { - this.rollData.traitsBonusSelected = $('#roll-trait-bonus').val() - this.computeTotals() - }) - html.find('#roll-trait-malus').change((event) => { - this.rollData.traitsMalusSelected = $('#roll-trait-malus').val() - this.computeTotals() - }) - html.find('#roll-select-transcendence').change((event) => { - this.rollData.skillTranscendence = Number($('#roll-select-transcendence').val()) - this.computeTotals() - }) - html.find('#roll-apply-transcendence').change((event) => { - this.rollData.applyTranscendence = $('#roll-apply-transcendence').val() - this.computeTotals() - }) - html.find('#annency-bonus').change((event) => { - this.rollData.annencyBonus = Number(event.currentTarget.value) - }) - + msg.setFlag("world", "ecryme-rolldata", this.rollData) } -} \ No newline at end of file + + /* -------------------------------------------- */ + static async #onLaunchConfront(event, target) { + await this.launchConfront() + this.close() + } + + static #onCancel(event, target) { + this.close() + } +} diff --git a/modules/dialogs/ecryme-confront-start-dialog.js b/modules/dialogs/ecryme-confront-start-dialog.js index 6a20f63..1b53ccb 100644 --- a/modules/dialogs/ecryme-confront-start-dialog.js +++ b/modules/dialogs/ecryme-confront-start-dialog.js @@ -1,77 +1,80 @@ import { EcrymeUtility } from "../common/ecryme-utility.js"; import { EcrymeConfrontDialog } from "./ecryme-confront-dialog.js"; -export class EcrymeConfrontStartDialog extends Dialog { +const { HandlebarsApplicationMixin } = foundry.applications.api + +/** + * Confrontation start dialog — Application V2 version. + * Player picks which dice formula to roll (normal / spleen / ideal), + * the dice are rolled and the main EcrymeConfrontDialog is opened. + */ +export class EcrymeConfrontStartDialog extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) { + + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["fvtt-ecryme", "ecryme-confront-start-dialog"], + position: { width: 540 }, + window: { title: "ECRY.ui.confront" }, + actions: { + rollNormal: EcrymeConfrontStartDialog.#onRollNormal, + rollSpleen: EcrymeConfrontStartDialog.#onRollSpleen, + rollIdeal: EcrymeConfrontStartDialog.#onRollIdeal, + cancel: EcrymeConfrontStartDialog.#onCancel, + }, + } + + /** @override */ + static PARTS = { + content: { template: "systems/fvtt-ecryme/templates/dialogs/confront-start-dialog.hbs" }, + } + + /* -------------------------------------------- */ + constructor(actor, rollData, options = {}) { + super(options) + this.actor = actor?.token?.actor ?? actor + this.rollData = rollData + } /* -------------------------------------------- */ static async create(actor, rollData) { - if (!actor) throw new Error("Ecryme | No actor provided for confront dialog"); - if (!rollData) throw new Error("Ecryme | No roll data provided for confront dialog"); - - if (actor?.token) rollData.tokenId = actor.token.id; - let options = { classes: ["fvtt-ecryme ecryme-confront-dialog"], width: 540, height: 'fit-content', 'z-index': 99999 } - let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-ecryme/templates/dialogs/confront-start-dialog.hbs', rollData); - return new EcrymeConfrontStartDialog(actor, rollData, html, options); + if (!actor) throw new Error("Ecryme | No actor provided for confront dialog") + if (!rollData) throw new Error("Ecryme | No roll data provided for confront dialog") + if (actor?.token) rollData.tokenId = actor.token.id + return new EcrymeConfrontStartDialog(actor, rollData) } /* -------------------------------------------- */ - constructor(actor, rollData, html, options, close = undefined) { - let conf = { - title: game.i18n.localize("ECRY.ui.confront"), - content: html, - buttons: { - rollNormal: { - icon: '', - label: game.i18n.localize("ECRY.ui.rollnormal"), - callback: () => { this.rollConfront("4d6") } - }, - rollSpleen: { - icon: '', - label: game.i18n.localize("ECRY.ui.rollspleen"), - callback: () => { this.rollConfront("5d6kl4") } - }, - rollIdeal: { - icon: '', - label: game.i18n.localize("ECRY.ui.rollideal"), - callback: () => { this.rollConfront("5d6kh4") } - }, - cancel: { - icon: '', - label: game.i18n.localize("ECRY.ui.cancel"), - callback: () => { this.close() } - } - }, - close: close + async _prepareContext() { + return { + ...this.rollData, + config: game.system.ecryme.config, } - - super(conf, options); - - this.actor = actor?.token?.actor || actor; - this.rollData = rollData; } /* -------------------------------------------- */ - async rollConfront(diceFormula) { - // Do the initial roll - let myRoll = await new Roll(diceFormula).roll() + async #rollConfront(diceFormula) { + const myRoll = await new Roll(diceFormula).roll() await EcrymeUtility.showDiceSoNice(myRoll, game.settings.get("core", "rollMode")) - // Fill the available dice table - let rollData = this.rollData + + const rollData = this.rollData rollData.roll = foundry.utils.duplicate(myRoll) rollData.availableDices = [] - for (let result of myRoll.terms[0].results) { + for (const result of myRoll.terms[0].results) { if (!result.discarded) { - let resultDup = foundry.utils.duplicate(result) - resultDup.location = "mainpool" - rollData.availableDices.push(resultDup) + const dup = foundry.utils.duplicate(result) + dup.location = "mainpool" + rollData.availableDices.push(dup) } } - let confrontDialog = await EcrymeConfrontDialog.create(this.actor, rollData) + + const confrontDialog = await EcrymeConfrontDialog.create(this.actor, rollData) confrontDialog.render(true) + this.close() } /* -------------------------------------------- */ - activateListeners(html) { - super.activateListeners(html); - } -} \ No newline at end of file + static async #onRollNormal(event, target) { await this.#rollConfront("4d6") } + static async #onRollSpleen(event, target) { await this.#rollConfront("5d6kl4") } + static async #onRollIdeal(event, target) { await this.#rollConfront("5d6kh4") } + static #onCancel(event, target) { this.close() } +} diff --git a/modules/dialogs/ecryme-roll-dialog.js b/modules/dialogs/ecryme-roll-dialog.js index 793b9f9..83f9dd6 100644 --- a/modules/dialogs/ecryme-roll-dialog.js +++ b/modules/dialogs/ecryme-roll-dialog.js @@ -1,86 +1,78 @@ import { EcrymeUtility } from "../common/ecryme-utility.js"; -export class EcrymeRollDialog extends Dialog { +const { HandlebarsApplicationMixin } = foundry.applications.api + +/** + * Roll dialog — Application V2 version. + * Reads all form values at roll time (no live tracking needed). + */ +export class EcrymeRollDialog extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) { + + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["fvtt-ecryme", "ecryme-roll-dialog"], + position: { width: 540 }, + window: { title: "ECRY.ui.rolltitle" }, + actions: { + roll: EcrymeRollDialog.#onRoll, + cancel: EcrymeRollDialog.#onCancel, + }, + } + + /** @override */ + static PARTS = { + content: { template: "systems/fvtt-ecryme/templates/dialogs/roll-dialog-generic.hbs" }, + } + + /* -------------------------------------------- */ + constructor(actor, rollData, options = {}) { + super(options) + this.actor = actor + this.rollData = rollData + } /* -------------------------------------------- */ static async create(actor, rollData) { - - let options = { classes: ["ecryme-roll-dialog"], width: 540, height: 'fit-content', 'z-index': 99999 } - let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-ecryme/templates/dialogs/roll-dialog-generic.hbs', rollData); - return new EcrymeRollDialog(actor, rollData, html, options); + return new EcrymeRollDialog(actor, rollData) } /* -------------------------------------------- */ - constructor(actor, rollData, html, options, close = undefined) { - let conf = { - title: game.i18n.localize("ECRY.ui.rolltitle"), - content: html, - buttons: { - roll: { - icon: '', - label: game.i18n.localize("ECRY.ui.roll"), - callback: () => { this.roll() } - }, - cancel: { - icon: '', - label: game.i18n.localize("ECRY.ui.cancel"), - callback: () => { this.close() } - } - }, - close: close + async _prepareContext() { + return { + ...this.rollData, + config: game.system.ecryme.config, } - - super(conf, options); - - this.actor = actor; - this.rollData = rollData; } /* -------------------------------------------- */ - roll() { + /** Read all form values at roll time, then execute. */ + static #onRoll(event, target) { + const el = this.element + + const bonusEl = el.querySelector('#bonusMalusPerso') + const diffEl = el.querySelector('#roll-difficulty') + const specEl = el.querySelector('#roll-specialization') + const traitBonusEl = el.querySelector('#roll-trait-bonus') + const traitMalusEl = el.querySelector('#roll-trait-malus') + const transcEl = el.querySelector('#roll-select-transcendence') + const spleenEl = el.querySelector('#roll-use-spleen') + const idealEl = el.querySelector('#roll-use-ideal') + + if (bonusEl) this.rollData.bonusMalusPerso = Number(bonusEl.value) + if (diffEl) this.rollData.difficulty = Number(diffEl.value) || 0 + if (specEl) this.rollData.selectedSpecs = Array.from(specEl.selectedOptions).map(o => o.value) + if (traitBonusEl) this.rollData.traitsBonus = Array.from(traitBonusEl.selectedOptions).map(o => o.value) + if (traitMalusEl) this.rollData.traitsMalus = Array.from(traitMalusEl.selectedOptions).map(o => o.value) + if (transcEl) this.rollData.skillTranscendence = Number(transcEl.value) + if (spleenEl) this.rollData.useSpleen = spleenEl.checked + if (idealEl) this.rollData.useIdeal = idealEl.checked + EcrymeUtility.rollEcryme(this.rollData) + this.close() } /* -------------------------------------------- */ - async refreshDialog() { - const content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/roll-dialog-generic.hbs", this.rollData) - this.data.content = content - this.render(true) + static #onCancel(event, target) { + this.close() } - - /* -------------------------------------------- */ - activateListeners(html) { - super.activateListeners(html); - - function onLoad() { - } - $(function () { onLoad(); }); - - html.find('#bonusMalusPerso').change((event) => { - console.log("DIFF", event.currentTarget.value) - this.rollData.bonusMalusPerso = Number(event.currentTarget.value) - }) - html.find('#roll-difficulty').change((event) => { - this.rollData.difficulty = Number(event.currentTarget.value) || 0 - }) - html.find('#roll-specialization').change((event) => { - this.rollData.selectedSpecs = $('#roll-specialization').val() - }) - html.find('#roll-trait-bonus').change((event) => { - this.rollData.traitsBonus = $('#roll-trait-bonus').val() - }) - html.find('#roll-trait-malus').change((event) => { - this.rollData.traitsMalus = $('#roll-trait-malus').val() - }) - html.find('#roll-select-transcendence').change((event) => { - this.rollData.skillTranscendence = Number($('#roll-select-transcendence').val()) - }) - html.find('#roll-use-spleen').change((event) => { - this.rollData.useSpleen = event.currentTarget.checked - }) - html.find('#roll-use-ideal').change((event) => { - this.rollData.useIdeal = event.currentTarget.checked - }) - - } -} \ No newline at end of file +} diff --git a/modules/ecryme-main.js b/modules/ecryme-main.js index a7c019a..b39a1e9 100644 --- a/modules/ecryme-main.js +++ b/modules/ecryme-main.js @@ -11,8 +11,17 @@ const ECRYME_WELCOME_MESSAGE_URL = "https://www.uberwald.me/gitea/public/fvtt-ec // Import Modules import { EcrymeActor } from "./actors/ecryme-actor.js"; import { EcrymeItemSheet } from "./items/ecryme-item-sheet.js"; -import { EcrymeActorSheet } from "./actors/ecryme-actor-sheet.js"; -import { EcrymeAnnencySheet } from "./actors/ecryme-annency-sheet.js"; +import { + EcrymeEquipmentSheet, + EcrymeWeaponSheet, + EcrymeTraitSheet, + EcrymeSpecializationSheet, + EcrymeManeuverSheet +} from "./items/sheets/_module.js"; +import { + EcrymeActorSheet, + EcrymeAnnencySheet +} from "./actors/sheets/_module.js"; import { EcrymeUtility } from "./common/ecryme-utility.js"; import { EcrymeCombat } from "./app/ecryme-combat.js"; import { EcrymeItem } from "./items/ecryme-item.js"; @@ -76,12 +85,16 @@ Hooks.once("init", async function () { /* -------------------------------------------- */ // Register sheet application classes foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet); - foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeActorSheet, { types: ["pc"], makeDefault: true }); + foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeActorSheet, { types: ["pc"], makeDefault: true }); foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeActorSheet, { types: ["npc"], makeDefault: true }); - foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeAnnencySheet, { types: ["annency"], makeDefault: false }); + foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeAnnencySheet, { types: ["annency"], makeDefault: true }); foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet); - foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeItemSheet, { makeDefault: true }); + foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeEquipmentSheet, { types: ["equipment"], makeDefault: true }); + foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeWeaponSheet, { types: ["weapon"], makeDefault: true }); + foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeTraitSheet, { types: ["trait"], makeDefault: true }); + foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeSpecializationSheet, { types: ["specialization"], makeDefault: true }); + foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeManeuverSheet, { types: ["maneuver"], makeDefault: true }); EcrymeUtility.init() diff --git a/modules/items/sheets/_module.js b/modules/items/sheets/_module.js new file mode 100644 index 0000000..3d62441 --- /dev/null +++ b/modules/items/sheets/_module.js @@ -0,0 +1,6 @@ +export { default as EcrymeBaseItemSheet } from "./base-item-sheet.js" +export { default as EcrymeEquipmentSheet } from "./equipment-sheet.js" +export { default as EcrymeWeaponSheet } from "./weapon-sheet.js" +export { default as EcrymeTraitSheet } from "./trait-sheet.js" +export { default as EcrymeSpecializationSheet } from "./specialization-sheet.js" +export { default as EcrymeManeuverSheet } from "./maneuver-sheet.js" diff --git a/modules/items/sheets/base-item-sheet.js b/modules/items/sheets/base-item-sheet.js new file mode 100644 index 0000000..329c596 --- /dev/null +++ b/modules/items/sheets/base-item-sheet.js @@ -0,0 +1,131 @@ +const { HandlebarsApplicationMixin } = foundry.applications.api + +/** + * Base item sheet for Ecryme using Application V2. + * Subclasses must define static PARTS including header, tabs, description, and optionally details. + */ +export default class EcrymeBaseItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) { + + constructor(options = {}) { + super(options) + this.#dragDrop = this.#createDragDropHandlers() + } + + #dragDrop + + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["fvtt-ecryme", "item"], + position: { + width: 520, + height: "auto", + }, + form: { + submitOnChange: true, + }, + window: { + resizable: true, + }, + dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }], + actions: { + editImage: EcrymeBaseItemSheet.#onEditImage, + }, + } + + /** Active tab group tracking */ + tabGroups = { + primary: "description", + } + + /** + * Build the tabs definition, adding a "details" tab only if the subclass has a "details" PART. + * @returns {Record} + */ + _getTabs() { + const tabs = { + description: { id: "description", group: "primary", label: "ECRY.ui.description" }, + } + if (this.constructor.PARTS?.details) { + tabs.details = { id: "details", group: "primary", label: "ECRY.ui.details" } + } + for (const tab of Object.values(tabs)) { + tab.active = this.tabGroups[tab.group] === tab.id + tab.cssClass = tab.active ? "active" : "" + } + return tabs + } + + /** @override */ + async _prepareContext() { + const context = { + fields: this.document.schema.fields, + systemFields: this.document.system.schema.fields, + item: this.document, + system: this.document.system, + source: this.document.toObject(), + config: game.system.ecryme.config, + isEditable: this.isEditable, + tabs: this._getTabs(), + } + return context + } + + /** @override */ + async _preparePartContext(partId, context) { + context = await super._preparePartContext(partId, context) + if (partId === "description") { + context.tab = context.tabs.description + context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML( + this.document.system.description, { async: true } + ) + } + return context + } + + /** @override */ + _onRender(context, options) { + this.#dragDrop.forEach((d) => d.bind(this.element)) + } + + // #region Drag-and-Drop + #createDragDropHandlers() { + return this.options.dragDrop.map((d) => { + d.permissions = { + dragstart: this._canDragStart.bind(this), + drop: this._canDragDrop.bind(this), + } + d.callbacks = { + dragstart: this._onDragStart.bind(this), + dragover: this._onDragOver.bind(this), + drop: this._onDrop.bind(this), + } + return new foundry.applications.ux.DragDrop.implementation(d) + }) + } + + _canDragStart(selector) { return this.isEditable } + _canDragDrop(selector) { return this.isEditable && this.document.isOwner } + _onDragStart(event) {} + _onDragOver(event) {} + async _onDrop(event) {} + // #endregion + + // #region Actions + static async #onEditImage(event, target) { + const attr = target.dataset.edit + const current = foundry.utils.getProperty(this.document, attr) + const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {} + const fp = new FilePicker({ + current, + type: "image", + redirectToRoot: img ? [img] : [], + callback: (path) => { + this.document.update({ [attr]: path }) + }, + top: this.position.top + 40, + left: this.position.left + 10, + }) + return fp.browse() + } + // #endregion +} diff --git a/modules/items/sheets/equipment-sheet.js b/modules/items/sheets/equipment-sheet.js new file mode 100644 index 0000000..b43daab --- /dev/null +++ b/modules/items/sheets/equipment-sheet.js @@ -0,0 +1,24 @@ +import EcrymeBaseItemSheet from "./base-item-sheet.js" + +export default class EcrymeEquipmentSheet extends EcrymeBaseItemSheet { + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["equipment"], + position: { width: 520 }, + } + + /** @override */ + static PARTS = { + header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" }, + tabs: { template: "templates/generic/tab-navigation.hbs" }, + description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" }, + details: { template: "systems/fvtt-ecryme/templates/items/item-equipment-details.hbs" }, + } + + /** @override */ + async _preparePartContext(partId, context) { + context = await super._preparePartContext(partId, context) + if (partId === "details") context.tab = context.tabs.details + return context + } +} diff --git a/modules/items/sheets/maneuver-sheet.js b/modules/items/sheets/maneuver-sheet.js new file mode 100644 index 0000000..6b3fac6 --- /dev/null +++ b/modules/items/sheets/maneuver-sheet.js @@ -0,0 +1,24 @@ +import EcrymeBaseItemSheet from "./base-item-sheet.js" + +export default class EcrymeManeuverSheet extends EcrymeBaseItemSheet { + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["maneuver"], + position: { width: 520 }, + } + + /** @override */ + static PARTS = { + header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" }, + tabs: { template: "templates/generic/tab-navigation.hbs" }, + description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" }, + details: { template: "systems/fvtt-ecryme/templates/items/item-maneuver-details.hbs" }, + } + + /** @override */ + async _preparePartContext(partId, context) { + context = await super._preparePartContext(partId, context) + if (partId === "details") context.tab = context.tabs.details + return context + } +} diff --git a/modules/items/sheets/specialization-sheet.js b/modules/items/sheets/specialization-sheet.js new file mode 100644 index 0000000..714f452 --- /dev/null +++ b/modules/items/sheets/specialization-sheet.js @@ -0,0 +1,24 @@ +import EcrymeBaseItemSheet from "./base-item-sheet.js" + +export default class EcrymeSpecializationSheet extends EcrymeBaseItemSheet { + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["specialization"], + position: { width: 520 }, + } + + /** @override */ + static PARTS = { + header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" }, + tabs: { template: "templates/generic/tab-navigation.hbs" }, + description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" }, + details: { template: "systems/fvtt-ecryme/templates/items/item-specialization-details.hbs" }, + } + + /** @override */ + async _preparePartContext(partId, context) { + context = await super._preparePartContext(partId, context) + if (partId === "details") context.tab = context.tabs.details + return context + } +} diff --git a/modules/items/sheets/trait-sheet.js b/modules/items/sheets/trait-sheet.js new file mode 100644 index 0000000..a164db3 --- /dev/null +++ b/modules/items/sheets/trait-sheet.js @@ -0,0 +1,24 @@ +import EcrymeBaseItemSheet from "./base-item-sheet.js" + +export default class EcrymeTraitSheet extends EcrymeBaseItemSheet { + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["trait"], + position: { width: 520 }, + } + + /** @override */ + static PARTS = { + header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" }, + tabs: { template: "templates/generic/tab-navigation.hbs" }, + description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" }, + details: { template: "systems/fvtt-ecryme/templates/items/item-trait-details.hbs" }, + } + + /** @override */ + async _preparePartContext(partId, context) { + context = await super._preparePartContext(partId, context) + if (partId === "details") context.tab = context.tabs.details + return context + } +} diff --git a/modules/items/sheets/weapon-sheet.js b/modules/items/sheets/weapon-sheet.js new file mode 100644 index 0000000..efd245a --- /dev/null +++ b/modules/items/sheets/weapon-sheet.js @@ -0,0 +1,24 @@ +import EcrymeBaseItemSheet from "./base-item-sheet.js" + +export default class EcrymeWeaponSheet extends EcrymeBaseItemSheet { + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["weapon"], + position: { width: 540 }, + } + + /** @override */ + static PARTS = { + header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" }, + tabs: { template: "templates/generic/tab-navigation.hbs" }, + description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" }, + details: { template: "systems/fvtt-ecryme/templates/items/item-weapon-details.hbs" }, + } + + /** @override */ + async _preparePartContext(partId, context) { + context = await super._preparePartContext(partId, context) + if (partId === "details") context.tab = context.tabs.details + return context + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..c520f95 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2167 @@ +{ + "name": "fvtt-ecryme", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "fvtt-ecryme", + "version": "1.0.0", + "license": "UNLICENSED", + "devDependencies": { + "gulp": "^5.0.0", + "gulp-less": "^5.0.0", + "less": "^4.1.3" + } + }, + "node_modules/@gulpjs/messages": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@gulpjs/messages/-/messages-1.1.0.tgz", + "integrity": "sha512-Ys9sazDatyTgZVb4xPlDufLweJ/Os2uHWOv+Caxvy2O85JcnT4M3vc73bi8pdLWlv3fdWQz3pdI9tVwo8rQQSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@gulpjs/to-absolute-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@gulpjs/to-absolute-glob/-/to-absolute-glob-4.0.0.tgz", + "integrity": "sha512-kjotm7XJrJ6v+7knhPaRgaT6q8F8K2jiafwYdNHLzmV0uGLuZY43FK6smNSHUPrhq5kX2slCUy+RGG/xGqmIKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async-done": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-2.0.0.tgz", + "integrity": "sha512-j0s3bzYq9yKIVLKGE/tWlCpa3PfFLcrDZLTSVdnnCTGagXuXBJO4SsY9Xdk/fQBirCkH4evW5xOeJXqlAQFdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.4.4", + "once": "^1.4.0", + "stream-exhaust": "^1.0.2" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/async-settle": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-2.0.0.tgz", + "integrity": "sha512-Obu/KE8FurfQRN6ODdHN9LuXqwC+JFIM9NRyZqJJ4ZfLJmIYN9Rg0/kb+wF70VV5+fJusTMQlJ1t5rF7J/ETdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-done": "^2.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/b4a": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", + "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/bach": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bach/-/bach-2.0.1.tgz", + "integrity": "sha512-A7bvGMGiTOxGMpNupYl9HQTf0FFDNF4VCmks4PJpFyN1AX2pdKuxuwdvUz2Hu388wcgp+OvGFNsumBfFNkR7eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-done": "^2.0.0", + "async-settle": "^2.0.0", + "now-and-later": "^3.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/bare-events": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", + "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-props": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-4.0.0.tgz", + "integrity": "sha512-bVWtw1wQLzzKiYROtvNlbJgxgBYt2bMJpkCbKmXM3xyijvcjjWXEk5nyrrT3bgJ7ODb19ZohE2T0Y3FgNPyoTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "each-props": "^3.0.0", + "is-plain-object": "^5.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/each-props": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-3.0.0.tgz", + "integrity": "sha512-IYf1hpuWrdzse/s/YJOrFmU15lyhSzxelNVAHTEG3DtP4QsLTWZUzcUL3HMXmKQxXpa4EIrBPpwRgj0aehdvAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^5.0.0", + "object.defaults": "^1.1.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz", + "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fastest-levenshtein": "^1.0.7" + } + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/findup-sync": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", + "integrity": "sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.3", + "micromatch": "^4.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/fined": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-2.0.0.tgz", + "integrity": "sha512-OFRzsL6ZMHz5s0JrsEr+TpdGNCtrVtnuG3x1yzGNiQHT0yaDnXAj8V/lWcpJVrnoDpcwXcASxAZYbuXda2Y82A==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^5.0.0", + "object.defaults": "^1.1.0", + "object.pick": "^1.3.0", + "parse-filepath": "^1.0.2" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/flagged-respawn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-2.0.0.tgz", + "integrity": "sha512-Gq/a6YCi8zexmGHMuJwahTGzXlAZAOsbCVKduWXC6TlLCjjFRlExMJc4GC2NYPYZ0r/brw9P7CpRgQmlPVeOoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dev": true, + "license": "MIT", + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fs-mkdirp-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-2.0.1.tgz", + "integrity": "sha512-UTOY+59K6IA94tec8Wjqm0FSh5OVudGNB0NL/P6fB3HiE3bYOY3VYBGijsnOHNkQSwC1FKkU77pmq7xp9CskLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.8", + "streamx": "^2.12.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-stream": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-8.0.3.tgz", + "integrity": "sha512-fqZVj22LtFJkHODT+M4N1RJQ3TjnnQhfE9GwZI8qXscYarnhpip70poMldRnP8ipQ/w0B621kOhfc53/J9bd/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@gulpjs/to-absolute-glob": "^4.0.0", + "anymatch": "^3.1.3", + "fastq": "^1.13.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "is-negated-glob": "^1.0.0", + "normalize-path": "^3.0.0", + "streamx": "^2.12.5" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-stream/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-watcher": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-6.0.0.tgz", + "integrity": "sha512-wGM28Ehmcnk2NqRORXFOTOR064L4imSw3EeOqU5bIwUf62eXGwg89WivH6VMahL8zlQHeodzvHpXplrqzrz3Nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-done": "^2.0.0", + "chokidar": "^3.5.3" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glogg": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-2.2.0.tgz", + "integrity": "sha512-eWv1ds/zAlz+M1ioHsyKJomfY7jbDDPpwSkv14KQj89bycx1nvK5/2Cj/T9g7kzJcX5Bc7Yv22FjfBZS/jl94A==", + "dev": true, + "license": "MIT", + "dependencies": { + "sparkles": "^2.1.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/gulp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-5.0.1.tgz", + "integrity": "sha512-PErok3DZSA5WGMd6XXV3IRNO0mlB+wW3OzhFJLEec1jSERg2j1bxJ6e5Fh6N6fn3FH2T9AP4UYNb/pYlADB9sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-watcher": "^6.0.0", + "gulp-cli": "^3.1.0", + "undertaker": "^2.0.0", + "vinyl-fs": "^4.0.2" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-cli": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-3.1.0.tgz", + "integrity": "sha512-zZzwlmEsTfXcxRKiCHsdyjZZnFvXWM4v1NqBJSYbuApkvVKivjcmOS2qruAJ+PkEHLFavcDKH40DPc1+t12a9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@gulpjs/messages": "^1.1.0", + "chalk": "^4.1.2", + "copy-props": "^4.0.0", + "gulplog": "^2.2.0", + "interpret": "^3.1.1", + "liftoff": "^5.0.1", + "mute-stdout": "^2.0.0", + "replace-homedir": "^2.0.0", + "semver-greatest-satisfied-range": "^2.0.0", + "string-width": "^4.2.3", + "v8flags": "^4.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-less": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gulp-less/-/gulp-less-5.0.0.tgz", + "integrity": "sha512-W2I3TewO/By6UZsM/wJG3pyK5M6J0NYmJAAhwYXQHR+38S0iDtZasmUgFCH3CQj+pQYw/PAIzxvFvwtEXz1HhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "less": "^3.7.1 || ^4.0.0", + "object-assign": "^4.0.1", + "plugin-error": "^1.0.0", + "replace-ext": "^2.0.0", + "through2": "^4.0.0", + "vinyl-sourcemaps-apply": "^0.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/gulplog": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-2.2.0.tgz", + "integrity": "sha512-V2FaKiOhpR3DRXZuYdRLn/qiY0yI5XmqbTKrYbdemJ+xOh2d2MOweI/XFgMzd/9+1twdvMwllnZbWZNJ+BOm4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "glogg": "^2.2.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/last-run": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-2.0.0.tgz", + "integrity": "sha512-j+y6WhTLN4Itnf9j5ZQos1BGPCS8DAwmgMroR3OzfxAsBxam0hMw7J8M3KqZl0pLQJ1jNnwIexg5DYpC/ctwEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/lead": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-4.0.0.tgz", + "integrity": "sha512-DpMa59o5uGUWWjruMp71e6knmwKU3jRBBn1kjuLWN9EeIOxNeSAwvHf03WIl8g/ZMR2oSQC9ej3yeLBwdDc/pg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/less": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/less/-/less-4.5.1.tgz", + "integrity": "sha512-UKgI3/KON4u6ngSsnDADsUERqhZknsVZbnuzlRZXLQCmfC/MDld42fTydUE9B+Mla1AL6SJ/Pp6SlEFi/AVGfw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/liftoff": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-5.0.1.tgz", + "integrity": "sha512-wwLXMbuxSF8gMvubFcFRp56lkFV69twvbU5vDPbaw+Q+/rF8j0HKjGbIdlSi+LuJm9jf7k9PB+nTxnsLMPcv2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "extend": "^3.0.2", + "findup-sync": "^5.0.0", + "fined": "^2.0.0", + "flagged-respawn": "^2.0.0", + "is-plain-object": "^5.0.0", + "rechoir": "^0.8.0", + "resolve": "^1.20.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mute-stdout": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-2.0.0.tgz", + "integrity": "sha512-32GSKM3Wyc8dg/p39lWPKYu8zci9mJFzV1Np9Of0ZEpe6Fhssn/FbI7ywAMd40uX+p3ZKh3T5EeCFv81qS3HmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/now-and-later": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-3.0.0.tgz", + "integrity": "sha512-pGO4pzSdaxhWTGkfSfHx3hVzJVslFPwBp2Myq9MYN/ChfJZF87ochMAXnvz6/58RJSf5ik2q9tXprBBrk2cpcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true, + "license": "ISC" + }, + "node_modules/replace-ext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", + "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/replace-homedir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-2.0.0.tgz", + "integrity": "sha512-bgEuQQ/BHW0XkkJtawzrfzHFSN70f/3cNOiHa2QsYxqrjaC30X1k74FJ6xswVBP0sr0SpGIdVFuPwfrYziVeyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-options": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-2.0.0.tgz", + "integrity": "sha512-/FopbmmFOQCfsCx77BRFdKOniglTiHumLgwvd6IDPihy1GKkadZbgQJBcTb2lMzSR1pndzd96b1nZrreZ7+9/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "value-or-function": "^4.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", + "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", + "dev": true, + "license": "BlueOak-1.0.0", + "optional": true, + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-greatest-satisfied-range": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-2.0.0.tgz", + "integrity": "sha512-lH3f6kMbwyANB7HuOWRMlLCa2itaCrZJ+SAqqkSZrZKO/cAsk2EOyaKHUtNkVLFyFW9pct22SFesFp3Z7zpA0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "sver": "^1.8.3" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sparkles": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-2.1.0.tgz", + "integrity": "sha512-r7iW1bDw8R/cFifrD3JnQJX0K1jqT0kprL48BiBpLZLJPmAm34zsVBsK5lc7HirZYZqMW65dOXZgbAGt/I6frg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/stream-composer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-composer/-/stream-composer-1.0.2.tgz", + "integrity": "sha512-bnBselmwfX5K10AH6L4c8+S5lgZMWI7ZYrz2rvYjCPB2DIMC4Ig8OpxGpNJSxRZ58oti7y1IcNvjBAz9vW5m4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "streamx": "^2.13.2" + } + }, + "node_modules/stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "dev": true, + "license": "MIT" + }, + "node_modules/streamx": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", + "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sver": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/sver/-/sver-1.8.4.tgz", + "integrity": "sha512-71o1zfzyawLfIWBOmw8brleKyvnbn73oVHNCsu51uPMz/HWiKkkXsI31JjHW5zqXEqnPYkIiHd8ZmL7FCimLEA==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "semver": "^6.3.0" + } + }, + "node_modules/sver/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/to-through": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-3.0.0.tgz", + "integrity": "sha512-y8MN937s/HVhEoBU1SxfHC+wxCHkV1a9gW8eAdTadYh/bGyesZIVcbjI+mSpFbSVwQici/XjBjuUyri1dnXwBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/undertaker": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-2.0.0.tgz", + "integrity": "sha512-tO/bf30wBbTsJ7go80j0RzA2rcwX6o7XPBpeFcb+jzoeb4pfMM2zUeSDIkY1AWqeZabWxaQZ/h8N9t35QKDLPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bach": "^2.0.1", + "fast-levenshtein": "^3.0.0", + "last-run": "^2.0.0", + "undertaker-registry": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/undertaker-registry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-2.0.0.tgz", + "integrity": "sha512-+hhVICbnp+rlzZMgxXenpvTxpuvA67Bfgtt+O9WOE5jo7w/dyiF1VmoZVIHvP2EkUjsyKyTwYKlLhA+j47m1Ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8flags": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-4.0.1.tgz", + "integrity": "sha512-fcRLaS4H/hrZk9hYwbdRM35D0U8IYMfEClhXxCivOojl+yTRAZH3Zy2sSy6qVCiGbV9YAtPssP6jaChqC9vPCg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/value-or-function": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-4.0.0.tgz", + "integrity": "sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/vinyl": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.1.tgz", + "integrity": "sha512-0QwqXteBNXgnLCdWdvPQBX6FXRHtIH3VhJPTd5Lwn28tJXc34YqSCWUmkOvtJHBmB3gGoPtrOKk3Ts8/kEZ9aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^2.1.2", + "remove-trailing-separator": "^1.1.0", + "replace-ext": "^2.0.0", + "teex": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/vinyl-contents": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-contents/-/vinyl-contents-2.0.0.tgz", + "integrity": "sha512-cHq6NnGyi2pZ7xwdHSW1v4Jfnho4TEGtxZHw01cmnc8+i7jgR6bRnED/LbrKan/Q7CvVLbnvA5OepnhbpjBZ5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^5.0.0", + "vinyl": "^3.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/vinyl-fs": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-4.0.2.tgz", + "integrity": "sha512-XRFwBLLTl8lRAOYiBqxY279wY46tVxLaRhSwo3GzKEuLz1giffsOquWWboD/haGf5lx+JyTigCFfe7DWHoARIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fs-mkdirp-stream": "^2.0.1", + "glob-stream": "^8.0.3", + "graceful-fs": "^4.2.11", + "iconv-lite": "^0.6.3", + "is-valid-glob": "^1.0.0", + "lead": "^4.0.0", + "normalize-path": "3.0.0", + "resolve-options": "^2.0.0", + "stream-composer": "^1.0.2", + "streamx": "^2.14.0", + "to-through": "^3.0.0", + "value-or-function": "^4.0.0", + "vinyl": "^3.0.1", + "vinyl-sourcemap": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/vinyl-sourcemap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-2.0.0.tgz", + "integrity": "sha512-BAEvWxbBUXvlNoFQVFVHpybBbjW1r03WhohJzJDSfgrrK5xVYIDTan6xN14DlyImShgDRv2gl9qhM6irVMsV0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "convert-source-map": "^2.0.0", + "graceful-fs": "^4.2.10", + "now-and-later": "^3.0.0", + "streamx": "^2.12.5", + "vinyl": "^3.0.0", + "vinyl-contents": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/vinyl-sourcemaps-apply": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", + "integrity": "sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==", + "dev": true, + "license": "ISC", + "dependencies": { + "source-map": "^0.5.1" + } + }, + "node_modules/vinyl-sourcemaps-apply/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..824ac2a --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "fvtt-ecryme", + "private": true, + "version": "1.0.0", + "description": "Ecryme RPG system for Foundry Virtual TableTop", + "author": "LeRatierBretonnien", + "license": "UNLICENSED", + "main": "gulpfile.js", + "devDependencies": { + "gulp": "^5.0.0", + "gulp-less": "^5.0.0", + "less": "^4.1.3" + }, + "scripts": { + "build": "gulp css", + "watch": "gulp" + }, + "repository": { + "type": "git", + "url": "https://www.uberwald.me/gitea/uberwald/fvtt-ecryme.git" + } +} diff --git a/packs/equipment/000276.log b/packs/equipment/000280.log similarity index 100% rename from packs/equipment/000276.log rename to packs/equipment/000280.log diff --git a/packs/equipment/CURRENT b/packs/equipment/CURRENT index 1df8f35..f248351 100644 --- a/packs/equipment/CURRENT +++ b/packs/equipment/CURRENT @@ -1 +1 @@ -MANIFEST-000275 +MANIFEST-000279 diff --git a/packs/equipment/LOG b/packs/equipment/LOG index 10f5feb..5c02d66 100644 --- a/packs/equipment/LOG +++ b/packs/equipment/LOG @@ -1,3 +1,3 @@ -2026/02/24-18:28:52.374972 7f821e7fc6c0 Recovering log #274 -2026/02/24-18:28:52.385656 7f821e7fc6c0 Delete type=0 #274 -2026/02/24-18:28:52.385721 7f821e7fc6c0 Delete type=3 #273 +2026/02/25-11:33:37.234178 7f821ffff6c0 Recovering log #277 +2026/02/25-11:33:37.244778 7f821ffff6c0 Delete type=3 #275 +2026/02/25-11:33:37.244834 7f821ffff6c0 Delete type=0 #277 diff --git a/packs/equipment/LOG.old b/packs/equipment/LOG.old index 125100d..1171be6 100644 --- a/packs/equipment/LOG.old +++ b/packs/equipment/LOG.old @@ -1,3 +1,7 @@ -2026/02/18-11:45:24.449013 7f1e213fc6c0 Recovering log #271 -2026/02/18-11:45:24.459087 7f1e213fc6c0 Delete type=3 #269 -2026/02/18-11:45:24.459153 7f1e213fc6c0 Delete type=0 #271 +2026/02/24-18:28:52.374972 7f821e7fc6c0 Recovering log #274 +2026/02/24-18:28:52.385656 7f821e7fc6c0 Delete type=0 #274 +2026/02/24-18:28:52.385721 7f821e7fc6c0 Delete type=3 #273 +2026/02/25-09:35:17.826867 7f821d8d46c0 Level-0 table #278: started +2026/02/25-09:35:17.826905 7f821d8d46c0 Level-0 table #278: 0 bytes OK +2026/02/25-09:35:17.833281 7f821d8d46c0 Delete type=0 #276 +2026/02/25-09:35:17.840522 7f821d8d46c0 Manual compaction at level-0 from '!folders!1GrTlI1xWvaxdKRI' @ 72057594037927935 : 1 .. '!items!zs7krgXhDRndtqbl' @ 0 : 0; will stop at (end) diff --git a/packs/equipment/MANIFEST-000275 b/packs/equipment/MANIFEST-000279 similarity index 80% rename from packs/equipment/MANIFEST-000275 rename to packs/equipment/MANIFEST-000279 index 00036402e9c3ce675586f32660fc81eb58940973..f6222ea4e6c5b332fee69d00d9697be96dce2e99 100644 GIT binary patch delta 25 hcmZ3$xPWm&pOBGB?p$sLMy44|oD9q}nOJ7A0svUz1=Rom delta 25 hcmZ3$xPWm&pOD99+W>9`My4rDoD9rUnOJ7A0svbc1?2z$ diff --git a/packs/help/000213.log b/packs/help/000217.log similarity index 100% rename from packs/help/000213.log rename to packs/help/000217.log diff --git a/packs/help/CURRENT b/packs/help/CURRENT index 7d5a51c..2cccabd 100644 --- a/packs/help/CURRENT +++ b/packs/help/CURRENT @@ -1 +1 @@ -MANIFEST-000212 +MANIFEST-000216 diff --git a/packs/help/LOG b/packs/help/LOG index 89bd101..17099c0 100644 --- a/packs/help/LOG +++ b/packs/help/LOG @@ -1,3 +1,3 @@ -2026/02/24-18:28:52.429828 7f821ffff6c0 Recovering log #211 -2026/02/24-18:28:52.439806 7f821ffff6c0 Delete type=0 #211 -2026/02/24-18:28:52.439868 7f821ffff6c0 Delete type=3 #210 +2026/02/25-11:33:37.286335 7f821effd6c0 Recovering log #214 +2026/02/25-11:33:37.295774 7f821effd6c0 Delete type=3 #212 +2026/02/25-11:33:37.295826 7f821effd6c0 Delete type=0 #214 diff --git a/packs/help/LOG.old b/packs/help/LOG.old index 60364a8..97c7826 100644 --- a/packs/help/LOG.old +++ b/packs/help/LOG.old @@ -1,3 +1,8 @@ -2026/02/18-11:45:24.501020 7f1e22bff6c0 Recovering log #208 -2026/02/18-11:45:24.512291 7f1e22bff6c0 Delete type=3 #206 -2026/02/18-11:45:24.512365 7f1e22bff6c0 Delete type=0 #208 +2026/02/24-18:28:52.429828 7f821ffff6c0 Recovering log #211 +2026/02/24-18:28:52.439806 7f821ffff6c0 Delete type=0 #211 +2026/02/24-18:28:52.439868 7f821ffff6c0 Delete type=3 #210 +2026/02/25-09:35:17.846770 7f821d8d46c0 Level-0 table #215: started +2026/02/25-09:35:17.846804 7f821d8d46c0 Level-0 table #215: 0 bytes OK +2026/02/25-09:35:17.852623 7f821d8d46c0 Delete type=0 #213 +2026/02/25-09:35:17.869656 7f821d8d46c0 Manual compaction at level-0 from '!journal!wooTFYjEwh83FwgT' @ 72057594037927935 : 1 .. '!journal.pages!wooTFYjEwh83FwgT.xhc7hqoL8kdW6lrD' @ 0 : 0; will stop at (end) +2026/02/25-09:35:17.869687 7f821d8d46c0 Manual compaction at level-1 from '!journal!wooTFYjEwh83FwgT' @ 72057594037927935 : 1 .. '!journal.pages!wooTFYjEwh83FwgT.xhc7hqoL8kdW6lrD' @ 0 : 0; will stop at (end) diff --git a/packs/help/MANIFEST-000212 b/packs/help/MANIFEST-000216 similarity index 61% rename from packs/help/MANIFEST-000212 rename to packs/help/MANIFEST-000216 index 4fb20c1ac0dde1ce00ac2597c870590471968109..004a597a0bb9d33903bb30ee2d13965cd7294262 100644 GIT binary patch delta 24 gcmcb>c!6=kenE+occQo$7@2M|axyUAVq}p30Bl|d1ONa4 delta 24 gcmcb>c!6=ke!(+e_Q-QFFfv_bgT80CltnfB*mh diff --git a/packs/maneuvers/000276.log b/packs/maneuvers/000280.log similarity index 100% rename from packs/maneuvers/000276.log rename to packs/maneuvers/000280.log diff --git a/packs/maneuvers/CURRENT b/packs/maneuvers/CURRENT index 1df8f35..f248351 100644 --- a/packs/maneuvers/CURRENT +++ b/packs/maneuvers/CURRENT @@ -1 +1 @@ -MANIFEST-000275 +MANIFEST-000279 diff --git a/packs/maneuvers/LOG b/packs/maneuvers/LOG index b596174..ad69742 100644 --- a/packs/maneuvers/LOG +++ b/packs/maneuvers/LOG @@ -1,3 +1,3 @@ -2026/02/24-18:28:52.415329 7f821effd6c0 Recovering log #274 -2026/02/24-18:28:52.426422 7f821effd6c0 Delete type=0 #274 -2026/02/24-18:28:52.426510 7f821effd6c0 Delete type=3 #273 +2026/02/25-11:33:37.273602 7f821f7fe6c0 Recovering log #277 +2026/02/25-11:33:37.284454 7f821f7fe6c0 Delete type=3 #275 +2026/02/25-11:33:37.284519 7f821f7fe6c0 Delete type=0 #277 diff --git a/packs/maneuvers/LOG.old b/packs/maneuvers/LOG.old index 26d7cc4..ee7124a 100644 --- a/packs/maneuvers/LOG.old +++ b/packs/maneuvers/LOG.old @@ -1,3 +1,7 @@ -2026/02/18-11:45:24.488266 7f1e213fc6c0 Recovering log #271 -2026/02/18-11:45:24.498651 7f1e213fc6c0 Delete type=3 #269 -2026/02/18-11:45:24.498723 7f1e213fc6c0 Delete type=0 #271 +2026/02/24-18:28:52.415329 7f821effd6c0 Recovering log #274 +2026/02/24-18:28:52.426422 7f821effd6c0 Delete type=0 #274 +2026/02/24-18:28:52.426510 7f821effd6c0 Delete type=3 #273 +2026/02/25-09:35:17.840651 7f821d8d46c0 Level-0 table #278: started +2026/02/25-09:35:17.840692 7f821d8d46c0 Level-0 table #278: 0 bytes OK +2026/02/25-09:35:17.846652 7f821d8d46c0 Delete type=0 #276 +2026/02/25-09:35:17.869637 7f821d8d46c0 Manual compaction at level-0 from '!items!13IYF6BPUTivFZzB' @ 72057594037927935 : 1 .. '!items!oSutlbe9wyBZccmf' @ 0 : 0; will stop at (end) diff --git a/packs/maneuvers/MANIFEST-000275 b/packs/maneuvers/MANIFEST-000279 similarity index 82% rename from packs/maneuvers/MANIFEST-000275 rename to packs/maneuvers/MANIFEST-000279 index 879488002c57c894dcb1232e54863504d8f96692..7521a712f4a39ba952797df42fd6860259cd70ad 100644 GIT binary patch delta 24 gcmbQkIEQgUw_w`o={vX>7@1};aWXK^WMc6K0Ahj$ga7~l delta 24 fcmbQkIEQgUx1f;HuTm}sMy4rDoD9rUnOM95R80k+ diff --git a/packs/scenes/000162.log b/packs/scenes/000166.log similarity index 100% rename from packs/scenes/000162.log rename to packs/scenes/000166.log diff --git a/packs/scenes/CURRENT b/packs/scenes/CURRENT index c1ddd5c..6da0b2c 100644 --- a/packs/scenes/CURRENT +++ b/packs/scenes/CURRENT @@ -1 +1 @@ -MANIFEST-000161 +MANIFEST-000165 diff --git a/packs/scenes/LOG b/packs/scenes/LOG index c0257e5..9212f8f 100644 --- a/packs/scenes/LOG +++ b/packs/scenes/LOG @@ -1,3 +1,3 @@ -2026/02/24-18:28:52.402010 7f821ffff6c0 Recovering log #160 -2026/02/24-18:28:52.411649 7f821ffff6c0 Delete type=0 #160 -2026/02/24-18:28:52.411699 7f821ffff6c0 Delete type=3 #159 +2026/02/25-11:33:37.259598 7f821effd6c0 Recovering log #163 +2026/02/25-11:33:37.270700 7f821effd6c0 Delete type=3 #161 +2026/02/25-11:33:37.270746 7f821effd6c0 Delete type=0 #163 diff --git a/packs/scenes/LOG.old b/packs/scenes/LOG.old index 71d5f90..ae2763b 100644 --- a/packs/scenes/LOG.old +++ b/packs/scenes/LOG.old @@ -1,3 +1,8 @@ -2026/02/18-11:45:24.475762 7f1e22bff6c0 Recovering log #157 -2026/02/18-11:45:24.485161 7f1e22bff6c0 Delete type=3 #155 -2026/02/18-11:45:24.485216 7f1e22bff6c0 Delete type=0 #157 +2026/02/24-18:28:52.402010 7f821ffff6c0 Recovering log #160 +2026/02/24-18:28:52.411649 7f821ffff6c0 Delete type=0 #160 +2026/02/24-18:28:52.411699 7f821ffff6c0 Delete type=3 #159 +2026/02/25-09:35:17.833446 7f821d8d46c0 Level-0 table #164: started +2026/02/25-09:35:17.833494 7f821d8d46c0 Level-0 table #164: 0 bytes OK +2026/02/25-09:35:17.840352 7f821d8d46c0 Delete type=0 #162 +2026/02/25-09:35:17.840534 7f821d8d46c0 Manual compaction at level-0 from '!scenes!DDibQQLAvyIq9y09' @ 72057594037927935 : 1 .. '!scenes!zvY1RwBhTfwdZIBa' @ 0 : 0; will stop at (end) +2026/02/25-09:35:17.840570 7f821d8d46c0 Manual compaction at level-1 from '!scenes!DDibQQLAvyIq9y09' @ 72057594037927935 : 1 .. '!scenes!zvY1RwBhTfwdZIBa' @ 0 : 0; will stop at (end) diff --git a/packs/scenes/MANIFEST-000161 b/packs/scenes/MANIFEST-000165 similarity index 66% rename from packs/scenes/MANIFEST-000161 rename to packs/scenes/MANIFEST-000165 index 431f8d00db12e3253633f4eda131f6c2f35625a6..cdf37b067498340d81a49a1b560f181fd66d9b4b 100644 GIT binary patch delta 24 gcmX@ec#v_z2EqI@Qw_No7@3waaxyS4XJioq0A+#(RR910 delta 24 gcmX@ec#v_z20@jnV%%H|j7*CdIT@H2GqMN)08?HCCIA2c diff --git a/packs/specialisation/000276.log b/packs/specialisation/000280.log similarity index 100% rename from packs/specialisation/000276.log rename to packs/specialisation/000280.log diff --git a/packs/specialisation/CURRENT b/packs/specialisation/CURRENT index 1df8f35..f248351 100644 --- a/packs/specialisation/CURRENT +++ b/packs/specialisation/CURRENT @@ -1 +1 @@ -MANIFEST-000275 +MANIFEST-000279 diff --git a/packs/specialisation/LOG b/packs/specialisation/LOG index 25ab51c..1016888 100644 --- a/packs/specialisation/LOG +++ b/packs/specialisation/LOG @@ -1,3 +1,3 @@ -2026/02/24-18:28:52.362517 7f821ffff6c0 Recovering log #274 -2026/02/24-18:28:52.372026 7f821ffff6c0 Delete type=0 #274 -2026/02/24-18:28:52.372073 7f821ffff6c0 Delete type=3 #273 +2026/02/25-11:33:37.221392 7f821e7fc6c0 Recovering log #277 +2026/02/25-11:33:37.232248 7f821e7fc6c0 Delete type=3 #275 +2026/02/25-11:33:37.232321 7f821e7fc6c0 Delete type=0 #277 diff --git a/packs/specialisation/LOG.old b/packs/specialisation/LOG.old index 4f61e7c..cf8620a 100644 --- a/packs/specialisation/LOG.old +++ b/packs/specialisation/LOG.old @@ -1,3 +1,7 @@ -2026/02/18-11:45:24.436705 7f1e22bff6c0 Recovering log #271 -2026/02/18-11:45:24.446559 7f1e22bff6c0 Delete type=3 #269 -2026/02/18-11:45:24.446634 7f1e22bff6c0 Delete type=0 #271 +2026/02/24-18:28:52.362517 7f821ffff6c0 Recovering log #274 +2026/02/24-18:28:52.372026 7f821ffff6c0 Delete type=0 #274 +2026/02/24-18:28:52.372073 7f821ffff6c0 Delete type=3 #273 +2026/02/25-09:35:17.814535 7f821d8d46c0 Level-0 table #278: started +2026/02/25-09:35:17.814622 7f821d8d46c0 Level-0 table #278: 0 bytes OK +2026/02/25-09:35:17.820646 7f821d8d46c0 Delete type=0 #276 +2026/02/25-09:35:17.840492 7f821d8d46c0 Manual compaction at level-0 from '!folders!00Hn2nNarlL7b0DR' @ 72057594037927935 : 1 .. '!items!yozTUjNuc2rEGjFK' @ 0 : 0; will stop at (end) diff --git a/packs/specialisation/MANIFEST-000275 b/packs/specialisation/MANIFEST-000279 similarity index 80% rename from packs/specialisation/MANIFEST-000275 rename to packs/specialisation/MANIFEST-000279 index 336c99b3dc82e751109a5d625f0ec896799bd3b3..678135a317d32f4dd95400360cd6079c8a8a8fc7 100644 GIT binary patch delta 25 hcmZ3$xPWm&pHSRI<{jJ&j7&3_I2o8{GO_eA0{~${20;J- delta 25 gcmZ3$xPWm&pHNFs@KbIEMy4rDoD9rUnOORm0b=F`T>t<8 diff --git a/packs/traits/000276.log b/packs/traits/000280.log similarity index 100% rename from packs/traits/000276.log rename to packs/traits/000280.log diff --git a/packs/traits/CURRENT b/packs/traits/CURRENT index 1df8f35..f248351 100644 --- a/packs/traits/CURRENT +++ b/packs/traits/CURRENT @@ -1 +1 @@ -MANIFEST-000275 +MANIFEST-000279 diff --git a/packs/traits/LOG b/packs/traits/LOG index f8c6ab8..2486135 100644 --- a/packs/traits/LOG +++ b/packs/traits/LOG @@ -1,3 +1,3 @@ -2026/02/24-18:28:52.388644 7f821effd6c0 Recovering log #274 -2026/02/24-18:28:52.398773 7f821effd6c0 Delete type=0 #274 -2026/02/24-18:28:52.398821 7f821effd6c0 Delete type=3 #273 +2026/02/25-11:33:37.247436 7f821f7fe6c0 Recovering log #277 +2026/02/25-11:33:37.257397 7f821f7fe6c0 Delete type=3 #275 +2026/02/25-11:33:37.257468 7f821f7fe6c0 Delete type=0 #277 diff --git a/packs/traits/LOG.old b/packs/traits/LOG.old index 447f602..e1e26e4 100644 --- a/packs/traits/LOG.old +++ b/packs/traits/LOG.old @@ -1,3 +1,7 @@ -2026/02/18-11:45:24.461683 7f1e223fe6c0 Recovering log #271 -2026/02/18-11:45:24.472892 7f1e223fe6c0 Delete type=3 #269 -2026/02/18-11:45:24.472965 7f1e223fe6c0 Delete type=0 #271 +2026/02/24-18:28:52.388644 7f821effd6c0 Recovering log #274 +2026/02/24-18:28:52.398773 7f821effd6c0 Delete type=0 #274 +2026/02/24-18:28:52.398821 7f821effd6c0 Delete type=3 #273 +2026/02/25-09:35:17.820786 7f821d8d46c0 Level-0 table #278: started +2026/02/25-09:35:17.820832 7f821d8d46c0 Level-0 table #278: 0 bytes OK +2026/02/25-09:35:17.826739 7f821d8d46c0 Delete type=0 #276 +2026/02/25-09:35:17.840510 7f821d8d46c0 Manual compaction at level-0 from '!folders!DiwHbtGAkTYxtshX' @ 72057594037927935 : 1 .. '!items!zgNI2haxhBxBDBdl' @ 0 : 0; will stop at (end) diff --git a/packs/traits/MANIFEST-000275 b/packs/traits/MANIFEST-000279 similarity index 80% rename from packs/traits/MANIFEST-000275 rename to packs/traits/MANIFEST-000279 index bd5992e950ef5a1d3dc64730cc48878599e2e835..4d30a9bef873c4e80752321a2b75e986b7767d5b 100644 GIT binary patch delta 25 hcmbQwIG=GsuaMkx^>5q^j7&3_I2o8{GO .folder-header h3 { + color: @color-text-dark; +} + +.editor { + border: 2; + height: 100%; + padding: 0 3px; +} + +.medium-editor { + border: 2; + height: 240px; + padding: 0 3px; +} + +.small-editor { + border: 2; + height: 120px; + padding: 0 3px; +} diff --git a/styles/chat-steampunk.less b/styles/chat-steampunk.less new file mode 100644 index 0000000..2625bf8 --- /dev/null +++ b/styles/chat-steampunk.less @@ -0,0 +1,689 @@ +// ============================================================ +// Chat — Steampunk theme for Ecryme +// Uses .ecryme-chat-body (custom class) so Foundry CSS never interferes. +// Header = brass plate. Body = aged parchment + dark ink. +// ============================================================ + +// ---- Mixin: rivet ornament (corner box-shadow bolts) ---- +.riveted-border() { + box-shadow: + inset 4px 4px 0 1px @steam-rivet, + inset -4px 4px 0 1px @steam-rivet, + inset 4px -4px 0 1px @steam-rivet, + inset -4px -4px 0 1px @steam-rivet, + 0 3px 10px rgba(0, 0, 0, 0.55); +} + +// ---- Mixin: brass gradient ---- +.brass-gradient() { + background: linear-gradient( + 135deg, + @steam-brass-dark 0%, + @steam-brass 30%, + @steam-brass-light 50%, + @steam-brass 70%, + @steam-brass-dark 100% + ); +} + +// ============================================================ +// Chat message outer frame — brass border + rivets +// ============================================================ +#chat-log .chat-message, +.chat-popout .chat-message { + border: 2px solid @steam-brass-dark; + border-radius: 3px; + .riveted-border(); + margin-bottom: 6px; + overflow: hidden; + + // Whisper: acid-tinted border + &.whisper { + border-color: @steam-acid-dark; + box-shadow: + inset 4px 4px 0 1px @steam-acid-dark, + inset -4px 4px 0 1px @steam-acid-dark, + inset 4px -4px 0 1px @steam-acid-dark, + inset -4px -4px 0 1px @steam-acid-dark, + 0 3px 10px rgba(0, 0, 0, 0.4); + + .ecryme-chat-body { + background: mix(@steam-parchment, @steam-acid, 82%); + } + } +} + +// ============================================================ +// Message header — brass plate +// ============================================================ +.chat-message-header { + .brass-gradient(); + border-bottom: 2px solid @steam-brass-dark; + font-size: 1rem; + height: 48px; + display: flex; + align-items: center; + padding: 0 8px; + gap: 8px; + + img.actor-icon, + .actor-icon { + border: 2px solid @steam-brass-dark; + border-radius: 2px; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.4); + width: 38px; + height: 38px; + padding: 1px; + background: @steam-parchment-dk; + flex-shrink: 0; + } +} + +.chat-actor-name { + font-family: @font-primary; + font-size: 1.1rem; + font-weight: bold; + color: @steam-dark; + text-shadow: 0 1px 1px rgba(255, 210, 60, 0.5); + letter-spacing: 0.04em; + margin: 0; + padding: 0; +} + +.chat-actor-subtitle { + font-family: @font-primary; + font-size: 0.78rem; + font-weight: normal; + color: @steam-dark; + opacity: 0.75; + letter-spacing: 0.05em; + text-transform: uppercase; + margin: 0; + padding: 0; +} + +// ============================================================ +// Body — aged parchment panel (our class = Foundry never overrides) +// ============================================================ +.ecryme-chat-body { + background: @steam-parchment; + color: @steam-dark; + padding: 6px 8px 8px; + font-size: 0.88rem; + + // Skill / ability icon + .ecryme-chat-icon-row { + overflow: hidden; + margin-bottom: 4px; + + img.chat-icon { + border: 2px solid @steam-brass-dark; + border-radius: 3px; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.25); + background: @steam-parchment-dk; + width: 52px; + height: 52px; + padding: 2px; + float: left; + margin: 0 8px 4px 0; + } + } + + // Brass wire separator + hr { + border: none; + height: 2px; + background: linear-gradient( + 90deg, + transparent 0%, + @steam-brass-dark 10%, + @steam-brass 50%, + @steam-brass-dark 90%, + transparent 100% + ); + margin: 6px 4px; + position: relative; + + &::after { + content: "⚙"; + position: absolute; + top: -0.6em; + left: 50%; + transform: translateX(-50%); + color: @steam-brass-dark; + font-size: 0.8rem; + background: @steam-parchment; + padding: 0 4px; + line-height: 1.2; + } + } + + // Detail list — dark sepia ink on parchment + ul { + list-style: none; + margin: 0; + padding: 0; + + li { + color: @steam-rust; + font-size: 0.87rem; + padding: 3px 2px 3px 20px; + border-bottom: 1px solid rgba(@steam-brass-dark, 0.2); + position: relative; + line-height: 1.4; + + &:last-child { border-bottom: none; } + + // Brass arrow bullet + &::before { + content: "▸"; + position: absolute; + left: 4px; + top: 4px; + color: @steam-brass-dark; + font-size: 0.75rem; + } + + strong { + color: @steam-brass-dark; + font-weight: bold; + } + } + + // Result line (success/failure) — no bullet, centered + li.ecryme-result-line { + padding-left: 4px; + text-align: center; + border-bottom: none; + margin-top: 2px; + + &::before { content: none; } + } + } + + // GM row with difficulty select + .ecryme-chat-gm-row { + display: flex; + align-items: center; + gap: 8px; + margin: 6px 0 4px; + color: @steam-dark; + font-size: 0.85rem; + + select { + background: @steam-parchment-dk; + color: @steam-dark; + border: 1px solid @steam-brass-dark; + border-radius: 2px; + padding: 2px 4px; + font-size: 0.85rem; + } + } + + // "Sent to GM" italic note + p.ecryme-chat-sent-gm { + color: @steam-brass-dark; + font-style: italic; + font-size: 0.82rem; + margin: 4px 0 0; + text-align: center; + } +} + +// ============================================================ +// Success / Failure labels +// ============================================================ +.chat-result-success { + color: @steam-success; + font-family: @font-primary; + font-size: 1.1rem; + font-weight: bold; + letter-spacing: 0.05em; +} + +.chat-result-failure { + color: @steam-failure; + font-family: @font-primary; + font-size: 1.1rem; + font-weight: bold; + letter-spacing: 0.05em; +} + +.chat-result-text { + font-family: @font-primary; + font-size: 1.15rem; +} + +// ============================================================ +// Action buttons — brass mechanical style +// ============================================================ +.chat-card-button, +.button-apply-impact, +.button-apply-bonus, +.button-select-confront, +.button-apply-cephaly-difficulty { + display: block; + width: calc(100% - 8px); + margin: 4px 4px 2px; + padding: 5px 10px; + cursor: pointer; + font-size: 0.8rem; + font-family: @font-primary; + letter-spacing: 0.05em; + text-align: center; + border-radius: 2px; + border: 1px solid @steam-brass-dark; + color: @steam-parchment; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8); + position: relative; + background: linear-gradient(180deg, + mix(@steam-brass, @steam-dark, 50%) 0%, + mix(@steam-brass-dark, @steam-dark, 65%) 100% + ); + box-shadow: + inset 0 1px 0 rgba(255, 215, 80, 0.2), + 0 2px 4px rgba(0, 0, 0, 0.35); + transition: background 0.15s; + + &:hover { + background: linear-gradient(180deg, + mix(@steam-brass-light, @steam-dark, 60%) 0%, + mix(@steam-brass, @steam-dark, 50%) 100% + ); + color: @steam-cream; + } + &:active { top: 1px; } +} + +.plus-minus-button { + background: linear-gradient(180deg, + mix(@steam-brass, @steam-dark, 40%) 0%, + mix(@steam-brass-dark, @steam-dark, 55%) 100% + ); + border: 1px solid @steam-brass-dark; + border-radius: 2px; + color: @steam-parchment; + padding: 2px 5px; + cursor: pointer; + font-size: 0.9rem; + font-weight: bold; + + &:hover { color: @steam-cream; } + &:active { position: relative; top: 1px; } +} + +// ============================================================ +// Dice images +// ============================================================ +.dice-image { + border: 1px solid @steam-brass-dark; + border-radius: 2px; + box-shadow: 0 0 3px rgba(0, 0, 0, 0.25); +} + +.dice-image-reroll { + border: 2px solid @steam-acid; + border-radius: 2px; + background-color: rgba(@steam-acid-dark, 0.15); + box-shadow: 0 0 5px rgba(@steam-acid, 0.5); +} + + +// ---- Mixin: rivet ornament (corner box-shadow bolts) ---- +.riveted-border() { + box-shadow: + inset 4px 4px 0 1px @steam-rivet, + inset -4px 4px 0 1px @steam-rivet, + inset 4px -4px 0 1px @steam-rivet, + inset -4px -4px 0 1px @steam-rivet, + 0 3px 10px rgba(0, 0, 0, 0.55); +} + +// ---- Mixin: brass gradient ---- +.brass-gradient() { + background: linear-gradient( + 135deg, + @steam-brass-dark 0%, + @steam-brass 30%, + @steam-brass-light 50%, + @steam-brass 70%, + @steam-brass-dark 100% + ); +} + +// ============================================================ +// Chat message container — parchment panel + brass frame +// ============================================================ +#chat-log .chat-message, +.chat-popout .chat-message { + border: 2px solid @steam-brass-dark; + border-radius: 3px; + .riveted-border(); + // Parchment background applied at all levels + background: @steam-parchment !important; + background-color: @steam-parchment !important; + color: @steam-dark; + margin-bottom: 6px; + + // Cover Foundry's inner wrappers + .message-content { + background: @steam-parchment !important; + background-color: @steam-parchment !important; + color: @steam-dark; + padding: 4px 6px; + } + + // All text descendants default to dark ink + p, span, div, label, li, ul, h1, h2, h3, h4, h5 { + color: @steam-dark; + } + + // Whisper: acid-tinted parchment + &.whisper { + border-color: @steam-acid-dark; + background: mix(@steam-parchment, @steam-acid, 85%) !important; + background-color: mix(@steam-parchment, @steam-acid, 85%) !important; + box-shadow: + inset 4px 4px 0 1px @steam-acid-dark, + inset -4px 4px 0 1px @steam-acid-dark, + inset 4px -4px 0 1px @steam-acid-dark, + inset -4px -4px 0 1px @steam-acid-dark, + 0 3px 10px rgba(0, 0, 0, 0.4); + + .message-content { + background: mix(@steam-parchment, @steam-acid, 85%) !important; + background-color: mix(@steam-parchment, @steam-acid, 85%) !important; + } + } +} + +// ============================================================ +// Message header — brass plate with dark name +// ============================================================ +.chat-message-header { + .brass-gradient(); + border-bottom: 2px solid @steam-brass-dark; + border-radius: 2px 2px 0 0; + font-size: 1rem; + height: 48px; + display: flex; + align-items: center; + padding: 0 6px; + gap: 6px; + + // Force brass bg even inside message-content parchment + background: linear-gradient(135deg, @steam-brass-dark 0%, @steam-brass 30%, @steam-brass-light 50%, @steam-brass 70%, @steam-brass-dark 100%) !important; + background-color: @steam-brass !important; + + img.actor-icon, + .actor-icon { + border: 2px solid @steam-brass-dark; + border-radius: 2px; + box-shadow: 0 0 4px rgba(0,0,0,0.4); + width: 40px; + height: 40px; + padding: 1px; + background: @steam-parchment; + flex-shrink: 0; + } +} + +.chat-actor-name { + font-family: @font-primary; + font-size: 1.1rem; + font-weight: bold; + color: @steam-dark !important; + text-shadow: 0 1px 1px rgba(255, 220, 80, 0.4); + letter-spacing: 0.04em; + margin: 0; + padding: 0; +} + +// ============================================================ +// Separator — brass wire with central gear +// ============================================================ +#chat-log .chat-message hr, +.chat-popout .chat-message hr { + border: none; + height: 2px; + background: linear-gradient( + 90deg, + transparent 0%, + @steam-brass-dark 10%, + @steam-brass 50%, + @steam-brass-dark 90%, + transparent 100% + ); + margin: 5px 4px; + position: relative; + + &::after { + content: "⚙"; + position: absolute; + top: -0.6em; + left: 50%; + transform: translateX(-50%); + color: @steam-brass; + font-size: 0.8rem; + background: @steam-parchment; + padding: 0 4px; + line-height: 1.2; + } +} + +// ============================================================ +// Detail list — dark ink on parchment +// ============================================================ +#chat-log .chat-message ul, +.chat-popout .chat-message ul { + list-style: none; + margin: 4px 0; + padding: 0 4px; + + li { + color: @steam-rust !important; // dark sepia/brown ink — readable on parchment + font-size: 0.88rem; + padding: 2px 0 2px 18px; + border-bottom: 1px solid rgba(@steam-brass-dark, 0.2); + position: relative; + line-height: 1.4; + + &:last-child { border-bottom: none; } + + // Arrow bullet in brass + &::before { + content: "▸"; + position: absolute; + left: 2px; + color: @steam-brass-dark; + font-size: 0.75rem; + top: 3px; + } + + strong { color: @steam-brass-dark !important; } + } +} + +// ============================================================ +// Skill / ability icon +// ============================================================ +.chat-icon { + border: 2px solid @steam-brass-dark; + border-radius: 3px; + box-shadow: 0 0 5px rgba(0,0,0,0.3); + background: @steam-parchment-dk; + width: 52px; + height: 52px; + padding: 2px; + margin: 4px 6px 4px 4px; + float: left; +} + +// ============================================================ +// Result labels (success / failure) +// ============================================================ +.chat-result-success { + color: @steam-success !important; + font-family: @font-primary; + font-size: 1.1rem; + font-weight: bold; + letter-spacing: 0.05em; +} + +.chat-result-failure { + color: @steam-failure !important; + font-family: @font-primary; + font-size: 1.1rem; + font-weight: bold; + letter-spacing: 0.05em; +} + +.chat-result-text { + font-family: @font-primary; + font-size: 1.1rem; + color: @steam-dark !important; +} + +// ============================================================ +// Action buttons — brass mechanical style +// ============================================================ +.chat-card-button, +.button-apply-impact, +.button-apply-bonus, +.button-select-confront, +.button-apply-cephaly-difficulty { + display: block; + width: calc(100% - 8px); + margin: 4px; + padding: 5px 10px; + cursor: pointer; + font-size: 0.8rem; + font-family: @font-primary; + letter-spacing: 0.05em; + text-align: center; + border-radius: 2px; + border: 1px solid @steam-brass-dark; + color: @steam-parchment !important; + text-shadow: 0 1px 2px rgba(0,0,0,0.8); + position: relative; + background: linear-gradient(180deg, + mix(@steam-brass, @steam-dark, 50%) 0%, + mix(@steam-brass-dark, @steam-dark, 65%) 100% + ); + box-shadow: + inset 0 1px 0 rgba(255, 215, 80, 0.2), + 0 2px 4px rgba(0,0,0,0.4); + transition: background 0.15s; + + &:hover { + background: linear-gradient(180deg, + mix(@steam-brass-light, @steam-dark, 60%) 0%, + mix(@steam-brass, @steam-dark, 50%) 100% + ); + color: @steam-cream !important; + } + &:active { top: 1px; } +} + +.plus-minus-button { + background: linear-gradient(180deg, + mix(@steam-brass, @steam-dark, 40%) 0%, + mix(@steam-brass-dark, @steam-dark, 55%) 100% + ); + border: 1px solid @steam-brass-dark; + border-radius: 2px; + color: @steam-parchment !important; + padding: 2px 5px; + cursor: pointer; + font-size: 0.9rem; + font-weight: bold; + + &:hover { color: @steam-cream !important; } + &:active { position: relative; top: 1px; } +} + +// ============================================================ +// Dice images — brass frame +// ============================================================ +.dice-image { + border: 1px solid @steam-brass-dark; + border-radius: 2px; + box-shadow: 0 0 3px rgba(0,0,0,0.3); +} + +.dice-image-reroll { + border: 2px solid @steam-acid; + border-radius: 2px; + background-color: rgba(@steam-acid-dark, 0.15); + box-shadow: 0 0 5px rgba(@steam-acid, 0.5); +} + +// ============================================================ +// GM difficulty select +// ============================================================ +#chat-log .chat-message, +.chat-popout .chat-message { + select[name="cephaly-difficulty"] { + background: @steam-parchment-dk; + color: @steam-dark; + border: 1px solid @steam-brass-dark; + border-radius: 2px; + padding: 2px 4px; + font-size: 0.85rem; + } +} + + +// ============================================================ +// Welcome message — sections & footer +// ============================================================ +.ecryme-chat-body { + + // Title + .welcome-message-h3 { + font-family: @font-primary; + font-size: 1.1rem; + font-weight: bold; + color: @steam-brass-dark; + text-align: center; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); + letter-spacing: 0.06em; + margin: 0 0 8px; + padding-bottom: 4px; + border-bottom: 1px solid rgba(@steam-brass-dark, 0.35); + } + + // Content sections + .welcome-section { + color: @steam-dark; + font-size: 0.86rem; + line-height: 1.5; + margin-bottom: 8px; + padding: 5px 6px; + background: rgba(@steam-parchment-dk, 0.55); + border-left: 3px solid @steam-brass; + border-radius: 0 2px 2px 0; + + strong { color: @steam-rust; } + + a { + color: @steam-brass-dark; + font-weight: bold; + text-decoration: underline; + &:hover { color: @steam-brass; } + } + } + + // Footer signature + .welcome-footer { + font-family: @font-primary; + font-size: 0.82rem; + color: @steam-rust; + text-align: center; + font-style: italic; + margin-top: 8px; + padding-top: 6px; + border-top: 1px solid rgba(@steam-brass-dark, 0.3); + letter-spacing: 0.03em; + } +} diff --git a/styles/chat.less b/styles/chat.less new file mode 100644 index 0000000..ed9a8fc --- /dev/null +++ b/styles/chat.less @@ -0,0 +1,251 @@ +// ============================================================ +// Chat, dice, roll dialogs, buttons +// ============================================================ + +.chat-message-header { + background: rgba(220, 220, 210, 0.5); + font-size: 1.1rem; + height: 48px; + text-align: center; + vertical-align: middle; + display: flex; + align-items: center; +} + +.message-chat-center { + text-align: center; +} + +.welcome-message-h3 { + font-size: 1.2rem; + text-align: center; + margin-bottom: 0.5rem; + color: darkred; +} + +.chat-message { + background: rgba(220, 220, 210, 0.5); + font-size: 0.9rem; + + &.whisper { + background: rgba(220, 220, 210, 0.75); + border: 2px solid #545469; + } + + .message-header { + .flavor-text, + .whisper-to { + font-size: 0.9rem; + } + } + + .chat-icon { + border: 0; + padding: 2px 6px 2px 2px; + float: left; + width: 64px; + height: 64px; + } +} + +.chat-result-text, +.chat-actor-name { + font-weight: bold; + font-family: @font-primary; + font-size: 1.2rem; + padding: 4px; +} + +.chat-result-success { color: darkgreen; } +.chat-result-failure { color: darkred; } + +.chat-img { + width: 64px; + height: 64px; +} + +// Roll dialog +.roll-dialog-header { + height: 52px; + align-items: center; + gap: 8px; + overflow: hidden; +} + +.roll-dialog-actor-title { + font-size: 1rem; + font-weight: bold; + line-height: 1.3; + overflow: hidden; + text-overflow: ellipsis; +} + +.ecryme-roll-dialog, +.ecryme-confront-start-dialog, +.ecryme-confrontation-dialog { + .window-header { border-radius: 10px 10px 0% 0%; } + .window-content { border-radius: 0% 0% 10px 10px; } + + .sheet-footer { + margin-top: 8px; + padding: 4px 0; + border-top: 1px solid var(--color-border-light-tertiary, #999); + gap: 6px; + button { + flex: 1; + } + } +} + +.ecryme-confront-start-dialog { + .sheet-footer { + gap: 4px; + button { font-size: 0.85rem; } + } +} + +.skill-roll-dialog div { + margin-top: 4px; + margin-bottom: 4px; +} + +// Actor icon in chat +.actor-icon { + float: left; + width: 48px; + height: 48px; + padding: 2px 6px 2px 2px; +} + +// Dice +.padding-dice { + padding-top: .2rem; + padding-bottom: .2rem; +} + +.dice-image { + box-sizing: border-box; + border: none; + border-radius: 0; + max-width: 100%; +} + +.dice-image-reroll { + background-color: rgba(115, 224, 115, 0.25); + border-color: #011d33; + box-sizing: border-box; + border: 1px; + border-radius: 0%; + max-width: 100%; +} + +.chat-dice { + width: 15%; + height: 15%; + font-size: 15px; + padding: 10px; + padding-top: .2rem; + padding-bottom: .2rem; +} + +.div-center { align-self: center; } + +.ability-icon { + border: 0; + padding: 2px; + max-width: 32px; + max-height: 32px; + width: auto; + height: auto; +} + +.small-ability-icon { + border: 0; + padding: 2px; + max-width: 16px; + max-height: 16px; + width: auto; + height: auto; +} + +.combat-icon { + border: 0; + padding: 2px; + max-width: 24px; + max-height: 24px; + width: auto; + height: auto; +} + +// Dice cell / formula / total +.dice-cell { + padding-left: 12px; + padding-right: 12px; + width: 60px; + text-align: center; +} + +.dice-formula, +.dice-total { + height: 54px; + position: relative; +} + +// Buttons +.chat-card-button { + box-shadow: inset 0px 1px 0px 0px #a6827e; + background: linear-gradient(to bottom, rgba(33, 55, 74, 0.98824) 5%, rgba(21, 40, 51, 0.67059) 100%); + background-color: rgba(125, 93, 59, 0); + border-radius: 3px; + border: 2px ridge #846109; + display: inline-block; + cursor: pointer; + color: #ffffff; + font-size: 0.8rem; + padding: 4px 12px 0px 12px; + text-decoration: none; + text-shadow: 0px 1px 0px #4d3534; + position: relative; + margin: 2px; + + &:hover { + background: linear-gradient(to bottom, #800000 5%, #3e0101 100%); + background-color: red; + } + + &:active { + position: relative; + top: 1px; + } +} + +.plus-minus-button { + box-shadow: inset 0px 1px 0px 0px #a6827e; + background: linear-gradient(to bottom, rgba(33, 55, 74, 0.98824) 5%, rgba(21, 40, 51, 0.67059) 100%); + background-color: rgba(125, 93, 59, 0); + border-radius: 2px; + border: 1px ridge #846109; + display: inline-block; + cursor: pointer; + color: #ffffff; + padding: 2px; + text-decoration: none; + text-shadow: 0px 1px 0px #4d3534; + position: relative; + margin: 0px; + + &:hover { + background: linear-gradient(to bottom, #800000 5%, #3e0101 100%); + background-color: red; + } + + &:active { + position: relative; + top: 1px; + } +} + +.plus-minus { + font-size: 0.9rem; + font-weight: bold; +} diff --git a/styles/dialog-steampunk.less b/styles/dialog-steampunk.less new file mode 100644 index 0000000..a62f828 --- /dev/null +++ b/styles/dialog-steampunk.less @@ -0,0 +1,264 @@ +// ============================================================ +// Roll & Confrontation dialogs — Steampunk theme +// Targets .ecryme-roll-dialog, .ecryme-confront-start-dialog, +// .ecryme-confrontation-dialog (AppV2 root classes) +// ============================================================ + +// Common container mixin +.steam-dialog-window() { + // Title bar — brass plate + .window-header { + .brass-gradient(); + border-bottom: 2px solid @steam-brass-dark; + color: @steam-dark; + text-shadow: 0 1px 1px rgba(255, 220, 80, 0.4); + + .window-title { + font-family: @font-primary; + font-size: 1rem; + font-weight: bold; + color: @steam-dark; + letter-spacing: 0.04em; + } + + // Close button — rivet look + .header-button, + button[data-action="close"] { + color: @steam-dark; + background: none; + border: none; + font-size: 1rem; + opacity: 0.7; + &:hover { opacity: 1; color: @steam-rust; } + } + } + + // Content area — aged parchment + .window-content { + background: @steam-parchment; + color: @steam-rust; + } +} + +// ============================================================ +// Apply to all three dialog app containers +// ============================================================ +.ecryme-roll-dialog, +.ecryme-confront-start-dialog, +.ecryme-confrontation-dialog { + .steam-dialog-window(); + + // Outer window frame + border: 2px solid @steam-brass-dark; + box-shadow: + inset 4px 4px 0 1px @steam-rivet, + inset -4px 4px 0 1px @steam-rivet, + inset 4px -4px 0 1px @steam-rivet, + inset -4px -4px 0 1px @steam-rivet, + 0 4px 14px rgba(0, 0, 0, 0.6); + + // ---- Actor header row ---- + .roll-dialog-header { + background: linear-gradient( + 90deg, + @steam-parchment-dk 0%, + @steam-parchment 60% + ); + border-bottom: 1px solid @steam-brass-dark; + border-radius: 0; + padding: 6px 8px; + margin-bottom: 6px; + display: flex; + align-items: center; + gap: 8px; + + .actor-icon { + border: 2px solid @steam-brass-dark; + border-radius: 2px; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.35); + background: @steam-parchment-dk; + width: 44px; + height: 44px; + padding: 1px; + flex-shrink: 0; + } + + .roll-dialog-actor-title { + font-family: @font-primary; + font-size: 1rem; + font-weight: bold; + color: @steam-dark; + letter-spacing: 0.03em; + } + } + + // ---- Form labels ---- + .roll-dialog-label { + color: @steam-rust; + font-size: 0.88rem; + font-weight: 600; + } + + // ---- Row separator ---- + .flexrow { + border-bottom: 1px solid rgba(@steam-brass-dark, 0.15); + padding: 3px 0; + &:last-child { border-bottom: none; } + } + + // ---- Selects & inputs ---- + select, + input[type="text"], + input[type="number"] { + background: @steam-cream; + color: @steam-dark; + border: 1px solid @steam-brass-dark; + border-radius: 2px; + padding: 2px 5px; + font-size: 0.85rem; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.12); + + &:focus { + outline: none; + border-color: @steam-brass; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.12), + 0 0 4px rgba(@steam-brass, 0.5); + } + } + + select[multiple] { + min-height: 60px; + } + + // ---- Headings inside content ---- + h3, h4 { + font-family: @font-primary; + color: @steam-brass-dark; + font-size: 0.9rem; + margin: 6px 0 3px; + border-bottom: 1px solid rgba(@steam-brass-dark, 0.3); + padding-bottom: 2px; + } + + // ---- Footer ---- + .sheet-footer { + border-top: 2px solid @steam-brass-dark; + background: @steam-parchment-dk; + padding: 6px 4px; + margin-top: 6px; + + button { + background: linear-gradient(180deg, + mix(@steam-brass, @steam-dark, 50%) 0%, + mix(@steam-brass-dark, @steam-dark, 65%) 100% + ); + border: 1px solid @steam-brass-dark; + border-radius: 2px; + color: @steam-parchment; + font-family: @font-primary; + font-size: 0.85rem; + letter-spacing: 0.04em; + padding: 5px 10px; + cursor: pointer; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7); + box-shadow: + inset 0 1px 0 rgba(255, 215, 80, 0.2), + 0 2px 4px rgba(0, 0, 0, 0.35); + transition: background 0.15s; + + &:hover { + background: linear-gradient(180deg, + mix(@steam-brass-light, @steam-dark, 60%) 0%, + mix(@steam-brass, @steam-dark, 50%) 100% + ); + color: @steam-cream; + } + &:active { position: relative; top: 1px; } + + &[disabled] { + opacity: 0.5; + cursor: default; + box-shadow: none; + &:hover { background: none; } + } + } + } +} + +// ============================================================ +// Confrontation dialog — dice / bonus pool areas +// ============================================================ +.ecryme-confrontation-dialog { + + // Area containers (execution, preservation, pool) + .confront-area { + background: @steam-parchment-dk; + border: 1px solid @steam-brass-dark; + border-radius: 3px; + min-height: 60px; + padding: 4px; + flex-wrap: wrap; + gap: 4px; + margin-bottom: 4px; + } + + // Execution area — slight warm tint + .confront-execution-area { + border-left: 3px solid @steam-brass; + } + + // Preservation area — slight cool tint + .confront-preservation-area { + border-left: 3px solid @steam-copper; + } + + // Pool list area + .pool-list { + border-left: 3px solid @steam-metal-mid; + min-height: 50px; + } + + // Individual dice container + .confront-dice-container { + display: flex; + flex-direction: column; + align-items: center; + gap: 2px; + cursor: grab; + padding: 3px; + border-radius: 2px; + transition: background 0.1s; + + &:hover { + background: rgba(@steam-brass, 0.18); + } + + // Dice image + .confront-dice { + border: 1px solid @steam-brass-dark; + border-radius: 2px; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.3); + background: @steam-parchment-dk; + width: 38px; + height: 38px; + } + + // Dice value label + .confront-dice-centered, + .confront-bonus-centered { + font-family: @font-primary; + font-size: 0.85rem; + font-weight: bold; + color: @steam-brass-dark; + text-align: center; + margin: 0; + } + } + + // Bonus spec — acid tint + .bonus-spec .confront-dice { + border-color: @steam-acid; + background-color: mix(@steam-parchment, @steam-acid, 88%); + box-shadow: 0 0 4px rgba(@steam-acid, 0.3); + } +} diff --git a/styles/ecryme.css b/styles/ecryme.css index 02a5db1..8277133 100644 --- a/styles/ecryme.css +++ b/styles/ecryme.css @@ -60,6 +60,7 @@ /* For nav and title */ .window-app input, + .application input, .fvtt-ecryme .item-form, .sheet header.sheet-header .flex-group-center.flex-compteurs, .sheet header.sheet-header .flex-group-center.flex-fatigue, @@ -76,9 +77,11 @@ background: rgba(0, 0, 0, 0.75); } - .window-app.sheet .window-content { + .window-app.sheet .window-content, + .application.sheet .window-content { margin: 0; padding: 0; + overflow: hidden auto; } .strong-text { @@ -396,13 +399,15 @@ /* ======================================== */ /* Sheet */ - .window-app.sheet .window-content .sheet-header { + .window-app.sheet .window-content .sheet-header, + .application.sheet .window-content .sheet-header { color: rgba(19, 18, 18, 0.95); background: url("../images/ui/fond_carnet_01.webp"); /*background: #494e6b;*/ } input[type="text"], + input[type="number"], select[type="text"] { background: white; color: #494e6b; @@ -420,14 +425,23 @@ .window-app.sheet .window-content .sheet-header input[type="number"], .window-app.sheet .window-content .sheet-body input[type="text"], .window-app.sheet .window-content .sheet-body input[type="number"], - .window-app.sheet .window-content .sheet-body select[type="text"] { + .window-app.sheet .window-content .sheet-body select[type="text"], + .application.sheet .window-content .sheet-header select[type="text"], + .application.sheet .window-content .sheet-header input[type="text"], + .application.sheet .window-content .sheet-header input[type="number"], + .application.sheet .window-content .sheet-body input[type="text"], + .application.sheet .window-content .sheet-body input[type="number"], + .application.sheet .window-content .sheet-body select[type="text"] { color: rgba(19, 18, 18, 0.95); /*color: #494e6b;*/ } .window-app.sheet .window-content .sheet-header input[type="password"], .window-app.sheet .window-content .sheet-header input[type="date"], - .window-app.sheet .window-content .sheet-header input[type="time"] { + .window-app.sheet .window-content .sheet-header input[type="time"], + .application.sheet .window-content .sheet-header input[type="password"], + .application.sheet .window-content .sheet-header input[type="date"], + .application.sheet .window-content .sheet-header input[type="time"] { color: rgba(19, 18, 18, 0.95); background: url("../images/ui/fond_carnet_01.webp"); border: 1 none; @@ -437,7 +451,10 @@ .window-app.sheet .window-content .sheet-body input[type="password"], .window-app.sheet .window-content .sheet-body input[type="date"], - .window-app.sheet .window-content .sheet-body input[type="time"] { + .window-app.sheet .window-content .sheet-body input[type="time"], + .application.sheet .window-content .sheet-body input[type="password"], + .application.sheet .window-content .sheet-body input[type="date"], + .application.sheet .window-content .sheet-body input[type="time"] { color: rgba(19, 18, 18, 0.95); background: url("../images/ui/fond_carnet_01.webp"); border: 1 none; @@ -446,7 +463,9 @@ } .window-app.sheet .window-content .sheet-body select, - .window-app.sheet .window-content .sheet-header select { + .window-app.sheet .window-content .sheet-header select, + .application.sheet .window-content .sheet-body select, + .application.sheet .window-content .sheet-header select { color: rgba(19, 18, 18, 0.95); background: #fff; border: 1 none; @@ -455,7 +474,9 @@ } .window-app .window-content, - .window-app.sheet .window-content .sheet-body { + .window-app.sheet .window-content .sheet-body, + .application .window-content, + .application.sheet .window-content .sheet-body { font-size: 0.8rem; /*background: url("../images/ui/pc_sheet_bg.webp") repeat left top;*/ background: url("../images/ui/fond_carnet_01.webp"); @@ -1565,4 +1586,62 @@ border: 2px ridge #443307; align-items: center; justify-content: center; - } \ No newline at end of file + } + +/* ============================== + Application V2 Item Sheets + ============================== */ + + /* Compact header for item sheets (smaller than actor sheets) */ + .fvtt-ecryme.item .sheet-header { + flex: 0 0 auto; + min-height: 70px; + padding: 4px 6px; + align-items: center; + } + + .fvtt-ecryme.item .sheet-header .item-sheet-img { + width: 64px; + height: 64px; + object-fit: contain; + border: 1px solid #7a7971; + cursor: pointer; + flex: 0 0 64px; + margin-right: 8px; + } + + .fvtt-ecryme.item .sheet-header .header-fields { + flex: 1; + } + + .fvtt-ecryme.item .sheet-header h1.charname { + height: auto; + margin: 0; + border-bottom: 0; + } + + .fvtt-ecryme.item .sheet-header h1.charname input { + font-family: MailartRubberstamp; + font-size: 1.8rem; + width: 100%; + height: auto; + margin: 0; + } + + /* Active tab styling for AppV2 (uses without .item class) */ + .fvtt-ecryme.item nav.sheet-tabs a.active { + text-decoration: underline; + } + + /* Details tab content */ + .fvtt-ecryme.item .sheet-body ul { + list-style: none; + margin: 0; + padding: 4px 2px; + } + + .fvtt-ecryme.item .sheet-body ul li.flexrow { + align-items: center; + margin-bottom: 4px; + gap: 4px; + } diff --git a/styles/ecryme.less b/styles/ecryme.less new file mode 100644 index 0000000..5f9a332 --- /dev/null +++ b/styles/ecryme.less @@ -0,0 +1,20 @@ +// ============================================================ +// Ecryme — Main LESS entry point +// Compiled output: css/ecryme.css +// ============================================================ + +@import "_variables.less"; +@import "fonts.less"; +@import "global.less"; +@import "sheet.less"; +@import "actor-sheet.less"; +@import "actor-sheet-v2.less"; +@import "item-sheet.less"; +@import "ui.less"; +@import "sidebar.less"; +@import "chat.less"; +@import "chat-steampunk.less"; +@import "dialog-steampunk.less"; +@import "actor-sheet-steampunk.less"; +@import "item-sheet-steampunk.less"; +@import "hud.less"; diff --git a/styles/fonts.less b/styles/fonts.less new file mode 100644 index 0000000..870ce90 --- /dev/null +++ b/styles/fonts.less @@ -0,0 +1,8 @@ +// ============================================================ +// Fonts +// ============================================================ + +@font-face { + font-family: "MailartRubberstamp"; + src: url('../fonts/MailartRubberstamp-Regular.woff') format("woff"); +} diff --git a/styles/global.less b/styles/global.less new file mode 100644 index 0000000..80afe92 --- /dev/null +++ b/styles/global.less @@ -0,0 +1,179 @@ +// ============================================================ +// Global base styles +// ============================================================ + +:root { + // Actor sheet font styles + --window-header-title-font-size: 1.3rem; + --window-header-title-font-weight: normal; + --window-header-title-color: #f5f5f5; + + --major-button-font-size: 1.05rem; + --major-button-font-weight: normal; + --major-button-color: #dadada; + + --tab-header-font-size: 1.0rem; + --tab-header-font-weight: 700; + --tab-header-color: #403f3e; + --tab-header-color-active: #4a0404; + + --actor-input-font-size: 0.8rem; + --actor-input-font-weight: 500; + --actor-input-color: black; + + --actor-label-font-size: 0.8rem; + --actor-label-font-weight: 700; + --actor-label-color: rgba(70, 67, 49, 0.76863); + + // Debugging highlighters + --debug-background-color-red: rgba(255, 0, 0, 0.32941); + --debug-background-color-blue: rgba(29, 0, 255, 0.32941); + --debug-background-color-green: rgba(84, 255, 0, 0.32941); + + --debug-box-shadow-red: inset 0 0 2px red; + --debug-box-shadow-blue: inset 0 0 2px blue; + --debug-box-shadow-green: inset 0 0 2px green; +} + +.window-app { + text-align: justify; + font-size: 16px; + letter-spacing: 1px; +} + +// Fonts: title, sidebar, scene nav +.sheet header.sheet-header h1 input, +.window-app .window-header, +#actors .directory-list, +#navigation #scene-list .scene.nav-item { + font-size: 1.0rem; +} + +// Nav and title +.sheet nav.sheet-tabs { + font-size: 0.8rem; +} + +// Inputs, buttons, sidebar, navigation +.window-app input, +.application input, +.fvtt-ecryme .item-form, +.sheet header.sheet-header .flex-group-center.flex-compteurs, +.sheet header.sheet-header .flex-group-center.flex-fatigue, +select, +button, +.item-checkbox, +#sidebar, +#players, +#navigation #nav-toggle { + font-size: 0.8rem; +} + +.window-header { + background: rgba(0, 0, 0, 0.75); +} + +.window-app.sheet .window-content, +.application.sheet .window-content { + margin: 0; + padding: 0; + overflow: hidden auto; +} + +.strong-text { + font-weight: bold; +} + +.tabs .item.active, +.blessures-list li ul li:first-child:hover, +a:hover { + text-shadow: 1px 0px 0px @color-accent; +} + +.rollable { + &:hover, + &:focus { + color: #000; + text-shadow: 0 0 10px red; + cursor: pointer; + } +} + +input { + &:hover { + border-width: 4px; + border-color: rgba(37, 124, 37, 0.7); + } + &:disabled { + color: @color-text-disabled; + } +} + +select:disabled { + color: @color-text-disabled; +} + +table { + border: 1px solid #7a7971; +} + +// Grid utilities +.grid, +.grid-2col { + display: grid; + grid-column: span 2 / span 2; + grid-template-columns: repeat(2, minmax(0, 1fr)); + grid-gap: 10px; + gap: 10px; + margin: 10px 0; + padding: 0; +} + +.grid-3col { grid-column: span 3 / span 3; grid-template-columns: repeat(3, minmax(0, 1fr)); } +.grid-4col { grid-column: span 4 / span 4; grid-template-columns: repeat(4, minmax(0, 1fr)); } +.grid-5col { grid-column: span 5 / span 5; grid-template-columns: repeat(5, minmax(0, 1fr)); } +.grid-6col { grid-column: span 5 / span 5; grid-template-columns: repeat(5, minmax(0, 1fr)); } +.grid-7col { grid-column: span 7 / span 7; grid-template-columns: repeat(7, minmax(0, 1fr)); } +.grid-8col { grid-column: span 8 / span 8; grid-template-columns: repeat(8, minmax(0, 1fr)); } +.grid-9col { grid-column: span 9 / span 9; grid-template-columns: repeat(9, minmax(0, 1fr)); } +.grid-10col { grid-column: span 10 / span 10; grid-template-columns: repeat(10, minmax(0, 1fr)); } +.grid-11col { grid-column: span 11 / span 11; grid-template-columns: repeat(11, minmax(0, 1fr)); } +.grid-12col { grid-column: span 12 / span 12; grid-template-columns: repeat(12, minmax(0, 1fr)); } + +// Flex utilities +.flex-group-center, +.flex-group-left, +.flex-group-right { + justify-content: center; + align-items: center; + text-align: center; + padding: 5px; +} + +.flex-group-left { + justify-content: flex-start; + text-align: left; +} + +.flex-group-right { + justify-content: flex-end; + text-align: right; +} + +.flex-center { + align-items: center; + justify-content: center; + text-align: center; +} + +.table-create-actor { + font-size: 0.8rem; +} + +.flex-between { + justify-content: space-between; +} + +.flex-shrink { + flex: 'flex-shrink'; +} diff --git a/styles/hud.less b/styles/hud.less new file mode 100644 index 0000000..1ad0437 --- /dev/null +++ b/styles/hud.less @@ -0,0 +1,75 @@ +// ============================================================ +// HUD, token, pause, logo +// ============================================================ + +// Token HUD extension +.tokenhudext { + display: flex; + flex: 0 !important; + font-weight: 600; + + &.left { + justify-content: flex-start; + flex-direction: column; + position: absolute; + top: 2.75rem; + right: 4rem; + } + + &.right { + justify-content: flex-start; + flex-direction: column; + position: absolute; + top: 2.75rem; + left: 4rem; + } +} + +.control-icon.tokenhudicon { + width: fit-content; + height: fit-content; + min-width: 6rem; + flex-basis: auto; + padding: 0; + line-height: 1rem; + margin: 0.25rem; + + &.right { + margin-left: 8px; + } +} + +#token-hud .status-effects.active { + z-index: 2; +} + +.token-sheet .window-content .flexcol .sheet-tabs { + font-size: 0.8rem; +} + +// Pause screen +#pause { + font-size: 2rem; + + > h3 { color: #CCC; } + + > img { + content: @logo-image; + height: 200px; + width: 200px; + top: -200px; + left: calc(50% - 132px); + } +} + +// Logo +#logo { + content: @logo-image; + width: 100px; + height: 60px; +} + +// Confront dice +.confront-dice { + border-width: 0px; +} diff --git a/styles/item-sheet-steampunk.less b/styles/item-sheet-steampunk.less new file mode 100644 index 0000000..adf9d2d --- /dev/null +++ b/styles/item-sheet-steampunk.less @@ -0,0 +1,258 @@ +// ============================================================ +// Item sheets — Steampunk theme +// Scoped to .fvtt-ecryme.item +// Same visual language as actor-sheet-steampunk.less +// ============================================================ + +.fvtt-ecryme.item { + + // ---------------------------------------------------------- + // AppV2 window title bar — brass plate + // ---------------------------------------------------------- + .window-header { + .brass-gradient(); + border-bottom: 2px solid @steam-brass-dark; + color: @steam-dark; + + .window-title { + font-family: @font-primary; + font-size: 1rem; + font-weight: bold; + color: @steam-dark; + letter-spacing: 0.04em; + } + + .header-button, + button[data-action="close"] { + color: @steam-dark; + opacity: 0.75; + &:hover { opacity: 1; color: @steam-rust; } + } + } + + // Window outer frame — rivets + border: 2px solid @steam-brass-dark; + box-shadow: + inset 4px 4px 0 1px @steam-rivet, + inset -4px 4px 0 1px @steam-rivet, + inset 4px -4px 0 1px @steam-rivet, + inset -4px -4px 0 1px @steam-rivet, + 0 4px 16px rgba(0, 0, 0, 0.55); + + // ---------------------------------------------------------- + // Window content area — parchment background + // ---------------------------------------------------------- + .window-content { + background: @steam-parchment; + color: @steam-rust; + } + + // ---------------------------------------------------------- + // Sheet header — item image + name + // ---------------------------------------------------------- + .sheet-header { + background: linear-gradient(180deg, @steam-parchment-dk 0%, @steam-parchment 100%); + border-bottom: 2px solid @steam-brass-dark; + padding: 8px 10px; + align-items: center; + + .item-sheet-img { + border: 3px solid @steam-brass-dark; + border-radius: 3px; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.45); + background: @steam-parchment-dk; + object-fit: contain; + } + + h1.charname input { + font-family: @font-primary; + color: @steam-dark; + background: transparent; + border: none; + border-bottom: 2px solid rgba(@steam-brass-dark, 0.4); + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.12); + padding-bottom: 2px; + + &:focus { + outline: none; + border-bottom-color: @steam-brass; + background: rgba(@steam-cream, 0.4); + } + } + } + + // ---------------------------------------------------------- + // Tab navigation — industrial metal bar + // ---------------------------------------------------------- + nav.sheet-tabs { + background: linear-gradient(180deg, @steam-metal 0%, @steam-metal-mid 100%); + border-top: 1px solid @steam-brass-dark; + border-bottom: 2px solid @steam-brass-dark; + padding: 0 8px; + gap: 4px; + + a { + font-family: @font-primary; + font-size: 1.1rem; + color: @steam-parchment-dk; + padding: 4px 10px; + letter-spacing: 0.04em; + border-bottom: 3px solid transparent; + transition: color 0.15s, border-color 0.15s; + text-decoration: none; + + &:hover { + color: @steam-brass-light; + border-bottom-color: rgba(@steam-brass, 0.5); + } + + &.active { + color: @steam-brass-light; + border-bottom-color: @steam-brass; + text-shadow: 0 0 6px rgba(@steam-brass-light, 0.5); + text-decoration: none; + } + } + } + + // ---------------------------------------------------------- + // Sheet body (tab content) + // ---------------------------------------------------------- + .sheet-body { + background: transparent; + color: @steam-rust; + padding: 0 8px; + + // ---- Field rows ---- + ul { + list-style: none; + margin: 4px 0; + padding: 0; + } + + ul li.flexrow { + align-items: center; + padding: 4px 2px; + border-bottom: 1px solid rgba(@steam-brass-dark, 0.18); + color: @steam-rust; + font-size: 0.85rem; + gap: 6px; + + &:last-child { border-bottom: none; } + } + + // ---- Labels ---- + label, + .item-name-label-short, + .item-name-label-medium, + .item-name-label-long, + .item-name-label-long2, + .item-name-label-free, + .item-field-label-short, + .item-field-label-medium { + color: @steam-rust; + } + + // ---- Selects & inputs ---- + select, + input[type="text"], + input[type="number"] { + background: @steam-cream; + color: @steam-dark; + border: 1px solid @steam-brass-dark; + border-radius: 2px; + padding: 2px 5px; + font-size: 0.85rem; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + + &:focus { + outline: none; + border-color: @steam-brass; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), + 0 0 4px rgba(@steam-brass, 0.45); + } + } + + // ---- Description editor area ---- + .tab.description { + .editor, + .editor-content, + .prosemirror, + [data-edit] { + background: @steam-cream; + color: @steam-dark; + border: 1px solid @steam-brass-dark; + border-radius: 2px; + padding: 6px 8px; + font-size: 0.86rem; + min-height: 80px; + } + } + + // ---- Section title rows ---- + .items-title-bg { + .brass-gradient(); + border: 1px solid @steam-brass-dark; + border-radius: 2px; + padding: 3px 6px; + margin-bottom: 2px; + + h3, label, .items-title-text { + font-family: @font-primary; + font-size: 0.92rem; + font-weight: bold; + color: @steam-dark; + text-shadow: 0 1px 1px rgba(255, 220, 60, 0.4); + letter-spacing: 0.04em; + margin: 0; + } + } + + // ---- h3/h4 outside section titles ---- + h3, h4 { + font-family: @font-primary; + color: @steam-brass-dark; + margin: 6px 0 3px; + font-size: 0.9rem; + } + + // ---- HR separator — brass wire + gear ---- + hr { + border: none; + height: 2px; + background: linear-gradient( + 90deg, + transparent 0%, + @steam-brass-dark 10%, + @steam-brass 50%, + @steam-brass-dark 90%, + transparent 100% + ); + margin: 10px 4px; + position: relative; + + &::after { + content: "⚙"; + position: absolute; + top: -0.6em; + left: 50%; + transform: translateX(-50%); + color: @steam-brass-dark; + font-size: 0.85rem; + background: @steam-parchment; + padding: 0 4px; + line-height: 1.2; + } + } + + // ---- Item icon (competence img) ---- + img.sheet-competence-img { + border: 1px solid @steam-brass-dark; + border-radius: 2px; + background: @steam-parchment-dk; + width: 24px; + height: 24px; + padding: 1px; + } + } +} diff --git a/styles/item-sheet.less b/styles/item-sheet.less new file mode 100644 index 0000000..97e9f65 --- /dev/null +++ b/styles/item-sheet.less @@ -0,0 +1,59 @@ +// ============================================================ +// AppV2 Item Sheet styles (.fvtt-ecryme.item) +// ============================================================ + +.fvtt-ecryme.item { + .sheet-header { + flex: 0 0 auto; + min-height: 70px; + padding: 4px 6px; + align-items: center; + + .item-sheet-img { + width: 64px; + height: 64px; + object-fit: contain; + border: 1px solid #7a7971; + cursor: pointer; + flex: 0 0 64px; + margin-right: 8px; + } + + .header-fields { + flex: 1; + } + + h1.charname { + height: auto; + margin: 0; + border-bottom: 0; + + input { + font-family: @font-primary; + font-size: 1.8rem; + width: 100%; + height: auto; + margin: 0; + } + } + } + + // Active tab styling (AppV2 uses without .item class) + nav.sheet-tabs a.active { + text-decoration: underline; + } + + .sheet-body { + ul { + list-style: none; + margin: 0; + padding: 4px 2px; + } + + ul li.flexrow { + align-items: center; + margin-bottom: 4px; + gap: 4px; + } + } +} diff --git a/styles/sheet.less b/styles/sheet.less new file mode 100644 index 0000000..a0d503a --- /dev/null +++ b/styles/sheet.less @@ -0,0 +1,189 @@ +// ============================================================ +// Sheet styles (actor + item, AppV1 + AppV2) +// ============================================================ + +// Sheet header background +.window-app.sheet .window-content .sheet-header, +.application.sheet .window-content .sheet-header { + color: @color-text-dark; + background: @background-image; +} + +// Input / select base (light background) +input[type="text"], +input[type="number"], +select[type="text"] { + background: @color-input-bg; + color: @color-input-text; +} + +select { + background: @color-input-bg; + color: @color-input-text; +} + +// Sheet content inputs & selects — dark text +.window-app.sheet .window-content, +.application.sheet .window-content { + .sheet-header, + .sheet-body { + select[type="text"], + input[type="text"], + input[type="number"] { + color: @color-text-dark; + } + + input[type="password"], + input[type="date"], + input[type="time"] { + color: @color-text-dark; + background: @background-image; + border: 1 none; + margin-bottom: 0.25rem; + margin-left: 2px; + } + + select { + color: @color-text-dark; + background: #fff; + border: 1 none; + margin-bottom: 0.25rem; + margin-left: 2px; + } + } +} + +// Sheet body + window-content background +.window-app .window-content, +.window-app.sheet .window-content .sheet-body, +.application .window-content, +.application.sheet .window-content .sheet-body { + font-size: 0.8rem; + background: @background-image; + color: @color-text-dark; +} + +section.sheet-body { + padding: 0.25rem 0.5rem; + + &:after { + content: ""; + display: block; + clear: both; + } +} + +.sheet { + header.sheet-header { + .profile-img { + object-fit: cover; + object-position: 50% 0; + margin: 0.5rem 0 0.5rem 0.5rem; + padding: 0; + } + + .flex-compteurs { + text-align: right; + } + + .resource-content { + width: 2rem; + } + } + + nav.sheet-tabs { + font-size: 1.2rem; + font-weight: bold; + height: 3rem; + flex: 0 0 3rem; + margin: 0; + padding: 0 0 0 0.25rem; + text-align: center; + line-height: 1.5rem; + border-top: 0 none; + border-bottom: 0 none; + background-color: @color-nav-bg; + color: @color-nav-text; + } + + .tab[data-tab] { + padding: 0; + } + + li { + margin: 0.010rem; + padding: 0.25rem; + } +} + +nav.sheet-tabs { + a, + .item { + position: relative; + padding: 0 0.25rem; + color: @color-nav-text; + + &:after { + content: ""; + position: absolute; + top: 0; + right: 0; + height: 2rem; + width: 1px; + border-right: 1px dashed rgba(52, 52, 52, 0.25); + } + } +} + +// Tooltip +.window-app.sheet .window-content { + .tooltip:hover .tooltiptext { + top: 2rem; + left: 2rem; + margin: 0; + padding: 0.25rem; + } + + .carac-value, + .competence-xp { + margin: 0.05rem; + flex-basis: 3rem; + text-align: center; + } +} + +// Tooltip widget +.tooltip { + position: relative; + display: inline-block; + + .tooltiptext { + text-align: left; + background: rgba(231, 229, 226, 0.9); + width: 150px; + padding: 3px 0; + font-size: 0.9rem; + top: 1px; + position: absolute; + z-index: 1; + visibility: hidden; + opacity: 0; + transition: opacity 0.3s; + } + + &:hover .tooltiptext { + visibility: visible; + opacity: 1; + } +} + +.tooltip-nobottom { + border-bottom: unset; +} + +// Select diff helper +.select-diff { + display: inline-block; + text-align: left; + width: 50px; +} diff --git a/styles/sidebar.less b/styles/sidebar.less new file mode 100644 index 0000000..a55ae29 --- /dev/null +++ b/styles/sidebar.less @@ -0,0 +1,156 @@ +// ============================================================ +// Sidebar, controls, hotbar, navigation +// ============================================================ + +#sidebar { + font-size: 1rem; + background-color: #f5f5f5; + background-position: 0px 35px; + background-repeat: no-repeat; + background-image: @background-image; + color: @color-text-dark; + + &.collapsed { + height: 470px !important; + } + + #sidebar-tabs i { + display: inline-block; + background-position: center; + background-size: cover; + text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.75); + } +} + +#sidebar-tabs { + flex: 0 0 32px; + box-sizing: border-box; + margin: 0 0 5px; + border-bottom: 1px solid rgba(0, 0, 0, 0); + box-shadow: inset 0 0 2rem rgba(0, 0, 0, 0.5); + + > .collapsed, + ~ .chat-control-icon { + color: @color-text-dark; + text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.75); + } + + > .item.active { + border: 1px solid rgba(114, 98, 72, 1); + background: rgba(30, 25, 20, 0.75); + box-shadow: 0 0 6px inset rgba(114, 98, 72, 1); + } +} + +// Sidebar tabs chat control icon +#sidebar-tabs > .collapsed, +#chat-controls .chat-control-icon { + color: @color-text-dark; + text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.75); +} + +.sidebar-tab .directory-list .entity { + border-top: 1px dashed rgba(0, 0, 0, 0.25); + border-bottom: 0 none; + padding: 0.25rem 0; + + &:hover { + background: rgba(0, 0, 0, 0.05); + cursor: pointer; + } +} + +// Controls & tools +#controls { + .scene-control, + .control-tool { + box-shadow: 0 0 3px #000; + margin: 0 0 8px; + border-radius: 0; + background: @color-control-dark; + background-origin: padding-box; + -o-border-image: url(img/ui/footer-button.png) 10 repeat; + border-image: url(img/ui/footer-button.png) 10 repeat; + border-image-width: 4px; + border-image-outset: 0px; + } + + .scene-control.active, + .control-tool.active, + .scene-control:hover, + .control-tool:hover { + background: @color-control-warm; + background-origin: padding-box; + -o-border-image: url(img/ui/footer-button.png) 10 repeat; + border-image: url(img/ui/footer-button.png) 10 repeat; + border-image-width: 4px; + border-image-outset: 0px; + box-shadow: 0 0 3px #ff6400; + } +} + +// Hotbar +#hotbar { + #action-bar #macro-list { + border: 1px solid @color-control-warm; + box-shadow: 2px 2px 5px #000000; + } + + #action-bar .macro { + -o-border-image: url(img/ui/bg_control.jpg) 21 repeat; + border-image: url(img/ui/bg_control.jpg) 21 repeat; + border-image-slice: 6 6 6 6 fill; + border-image-width: 6px 6px 6px 6px; + border-image-outset: 0px 0px 0px 0px; + border-radius: 0px; + } + + .bar-controls { + background: @color-control-dark; + border: 1px solid @color-control-warm; + } +} + +// Players & navigation +#players { + -o-border-image: url(img/ui/footer-button.png) 10 repeat; + border-image: url(img/ui/footer-button.png) 10 repeat; + border-image-width: 4px; + border-image-outset: 0px; + background: @color-control-dark; +} + +#navigation #scene-list { + .scene.nav-item { + background: @color-control-dark; + background-origin: padding-box; + -o-border-image: url(img/ui/footer-button.png) 10 repeat; + border-image: url(img/ui/footer-button.png) 10 repeat; + border-image-width: 4px; + border-image-outset: 0px; + + &.active { + background: @color-control-warm; + } + } + + .scene.view, + .scene.context { + background: @color-control-warm; + background-origin: padding-box; + -o-border-image: url(img/ui/footer-button.png) 10 repeat; + border-image: url(img/ui/footer-button.png) 10 repeat; + border-image-width: 4px; + border-image-outset: 0px; + box-shadow: 0 0 3px #ff6400; + } +} + +#navigation #nav-toggle { + background: @color-control-dark; + background-origin: padding-box; + -o-border-image: url(img/ui/footer-button.png) 10 repeat; + border-image: url(img/ui/footer-button.png) 10 repeat; + border-image-width: 4px; + border-image-outset: 0px; +} diff --git a/styles/ui.less b/styles/ui.less new file mode 100644 index 0000000..4248253 --- /dev/null +++ b/styles/ui.less @@ -0,0 +1,359 @@ +// ============================================================ +// Generic UI utilities and layout helpers +// ============================================================ + +h1, h2, h3, h4 { + font-weight: bold; +} + +ul, ol { + margin: 0; + padding: 0; +} + +ul, li { + list-style-type: none; +} + +.header-fields li { + margin: 0; + padding: 0; +} + +// Alternate list rows +.alterne-list { + > .list-item:hover { + background: rgba(100, 100, 50, 0.25); + } + > .list-item:nth-child(even) { + background: rgba(80, 60, 0, 0.10); + } + > .list-item:nth-child(odd) { + background: rgb(160, 130, 100, 0.05); + } +} + +.specialisation-label { + font-size: 0.8rem; +} + +.carac-label, +.attr-label { + font-weight: bold; +} + +.list-item { + flex: 1 1 5rem; + display: flex !important; + color: @color-text-dark; +} + +.list-item-shadow { + background: rgba(87, 60, 32, 0.35); + flex-grow: 0; + flex-wrap: nowrap; + justify-content: flex-start; +} + +.list-item-shadow2 { + background: rgba(87, 60, 32, 0.25); + flex-grow: 0; + flex-wrap: nowrap; + justify-content: flex-start; +} + +.item-display-show { display: block; } +.item-display-hide { display: none; } + +.item-quantite { + margin-left: 0.5rem; +} + +.list-item-margin1 { margin-left: 1rem; } +.list-item-margin2 { margin-left: 2rem; } +.list-item-margin3 { margin-left: 3rem; } +.list-item-margin4 { margin-left: 4rem; } + +.sheet-competence-img { + width: 24px; + max-width: 24px; + height: 24px; + max-height: 24px; + flex-grow: 0; + margin-right: 0.25rem; +} + +.competence-column { + flex-direction: column; + align-content: flex-start; + justify-content: flex-start; + flex-grow: 0; + flex-basis: 1; +} + +.competence-header { + align-content: flex-start; + justify-content: flex-start; + font-weight: bold; + flex-grow: 0; +} + +.description-label { + flex-grow: 2; + margin-left: 4px; +} + +.status-header-label { margin-left: 2px; } +.roll-dialog-label { margin: 4px 0; min-width: 96px; } + +// Select[multiple] in roll dialogs needs explicit height so options are visible +.skill-roll-dialog, +.confrontation-roll-dialog, +.confrontation-start-dialog { + select[multiple] { + min-height: 60px; + height: auto; + flex: 1; + } +} +.short-label { flex-grow: 1; } +.keyword-label { font-size: 0.85rem; } +.item-sheet-label { flex-grow: 1; } +.item-text-long-line { flex-grow: 3; } + +.score-label { + flex-grow: 2; + align-content: center; +} + +.attribut-value, +.carac-value { + flex-grow: 0; + flex-basis: 64px; + margin-right: 4px; + margin-left: 4px; +} + +.sante-value, +.competence-value { + flex-grow: 0; + flex-basis: 2rem; + margin-right: 0.25rem; + margin-left: 0.25rem; +} + +.description-value { + flex-grow: 0; + flex-basis: 4rem; + margin-right: 0.25rem; + margin-left: 0.25rem; +} + +.small-label { margin-top: 5px; } +.padd-right { margin-right: 8px; } +.padd-left { margin-left: 8px; } + +.stack-left { + align-items: center; + flex-shrink: 1; + flex-grow: 0; +} + +.packed-left { + white-space: nowrap; + flex-grow: 0; +} + +.input-numeric-short { + width: 40px; + max-width: 40px; + flex-grow: 0; + flex-shrink: 0; + flex-basis: 40px; + margin-right: 0.25rem; + margin-left: 0.25rem; +} + +.abilities-table { + align-content: flex-start; +} + +// Image helpers +.button-img { + vertical-align: baseline; + width: 8%; + height: 8%; + max-height: 48px; + border-width: 0px; + border: 1px solid rgba(0, 0, 0, 0); + + &:hover { + color: rgba(255, 255, 128, 0.7); + border: 1px solid rgba(255, 128, 0, 0.8); + cursor: pointer; + } +} + +.button-effect-img { + vertical-align: baseline; + width: 16px; + max-height: 16px; + height: 16; + border-width: 0; +} + +.small-button-container { + height: 16px; + width: 16px; + border: 0; + vertical-align: bottom; +} + +.item-checkbox { + height: 25px; + border: 1px solid rgba(115, 105, 83, 0.65098); + border-left: none; + font-weight: 500; + font-size: 1rem; + color: black; + padding-top: 5px; + margin-right: 0px; + width: 45px; + position: relative; + left: 0px; + text-align: center; +} + +.skill-label { font-size: 0.7rem; } +.skill-good-checkbox { max-height: 10px; max-width: 10px; } + +.flex-actions-bar { flex-grow: 2; } + +// Item name / field labels +.item-sheet-img { + width: 64px; + height: auto; + border: 0; +} + +.item-name-img { flex-grow: 1; max-width: 2rem; min-width: 2rem; } +.item-name-label-header { flex-grow: 2; max-width: 12rem; min-width: 12rem; } +.item-name-label-header-long { flex-grow: 2; max-width: 14rem; min-width: 14rem; } +.item-name-label-header-long2 { flex-grow: 2; max-width: 24rem; min-width: 24rem; } +.item-name-label { flex-grow: 2; max-width: 10rem; min-width: 10rem; } +.item-name-label-long { margin-top: 4px; flex-grow: 2; max-width: 12rem; min-width: 12rem; } +.item-name-label-short { margin-top: 4px; flex-grow: 1; max-width: 4rem; min-width: 4rem; } +.item-name-label-medium { margin-top: 4px; flex-grow: 2; max-width: 6rem; min-width: 6rem; } +.item-name-label-medium2 { margin-top: 4px; flex-grow: 0; max-width: 10rem; min-width: 10rem; } +.item-name-label-free { margin-top: 4px; align-self: flex-start; } +.item-name-label-long2 { margin-top: 4px; flex-grow: 2; max-width: 22rem; min-width: 22rem; } +.item-name-label-level2 { flex-grow: 2; max-width: 9rem; min-width: 9rem; } + +.item-field-label-short { margin-top: 4px; flex-grow: 1; max-width: 4rem; min-width: 4rem; } +.item-field-label-short-header { margin-top: 4px; flex-grow: 1; max-width: 2.2rem; min-width: 2.2rem; } +.item-field-label-medium { flex-grow: 1; max-width: 6rem; min-width: 6rem; } +.item-field-skill { flex-grow: 1; max-width: 6.8rem; min-width: 6.8rem; } +.item-field-label-long { flex-grow: 1; max-width: 10rem; min-width: 10rem; } + +.item-control-end { align-self: flex-end; } +.alternate-list { margin-top: 4px; flex-wrap: nowrap; } +.item-filler { flex-grow: 6; flex-shrink: 7; } +.item-controls-fixed { min-width: 2rem; max-width: 2rem; } +.item-controls-fixed-full { min-width: 3rem; max-width: 3rem; } +.attribute-label { font-weight: bold; } +.flexrow-no-expand { flex-grow: 0; } +.flexrow-start { justify-content: flex-start; align-content: flex-start; align-self: flex-start; } +.item-input-small { max-width: 16px; max-height: 12px; } +.character-summary-rollable { text-decoration: underline; } +.ul-level1 { padding-left: 2rem; } + +// Impact / confrontation +.impact-box { + border-width: 2px; + border-color: #000000; + border-radius: 6px; + border: 2px ridge #443307; + margin: 4px; + padding: 4px; +} + +.impact-title { + font-size: bold; + display: flex; + align-items: center; + justify-content: center; + margin-left: auto; + margin-right: auto; + text-align: center; +} + +.items-title-bg { + margin-top: 6px; + color: @color-text-dark; +} + +.items-title-text { + text-align: center; + font-family: @font-primary; + margin-left: 4px; +} + +.lock-icon { width: 16px; height: 16px; } +.img-no-border { max-width: 48px; max-height: 48px; border: 0px; } +.no-grow { flex-grow: 1; max-width: 32px; } +.status-col-name { max-width: 72px; } +.status-small-label { font-size: 0.65rem; } + +.confront-bonus-container { + position: relative; + flex-grow: 1; + text-align: center; + color: black; +} + +.confront-bonus-centered { + position: absolute; + top: 50%; + left: 50%; + font-size: 1.6rem; + color: darkgreen; + font-family: @font-primary; + transform: translate(-50%, -55%); +} + +.dice-spec { max-width: 64px; } +.bonus-spec { max-width: 48px; } + +.confront-dice-container { + position: relative; + flex-grow: 1; + text-align: center; + color: black; +} + +.confront-dice-centered { + position: absolute; + top: 50%; + left: 50%; + font-size: 2rem; + color: darkgreen; + font-family: @font-primary; + transform: translate(-50%, -55%); +} + +.confront-area { + margin: 2px; + padding: 4px; + min-height: 64px; + border-width: 2px; + border-color: #000000; + border-radius: 6px; + border: 2px ridge #443307; + align-items: center; + justify-content: center; +} + +.pool-list { + align-items: center; + justify-content: center; +} diff --git a/system.json b/system.json index ef55228..c493e6b 100644 --- a/system.json +++ b/system.json @@ -108,7 +108,7 @@ "secondaryTokenAttribute": "secondary.delirium", "socket": true, "styles": [ - "styles/ecryme.css" + "css/ecryme.css" ], "relationships": { "requires": [ diff --git a/templates/actors/actor-biodata.hbs b/templates/actors/actor-biodata.hbs new file mode 100644 index 0000000..ea4facb --- /dev/null +++ b/templates/actors/actor-biodata.hbs @@ -0,0 +1,57 @@ +
+ +
+
+
    +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
+
+
+
    +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
+
+
+ +
+ +

+
+
+ {{formInput systemFields.biodata.fields.description enriched=enrichedDescription + value=system.biodata.description name="system.biodata.description" toggled=true}} +
+ +
+ +

+
+
+ {{formInput systemFields.biodata.fields.gmnotes enriched=enrichedGmnotes + value=system.biodata.gmnotes name="system.biodata.gmnotes" toggled=true}} +
+
+ +
diff --git a/templates/actors/actor-cephaly.hbs b/templates/actors/actor-cephaly.hbs new file mode 100644 index 0000000..b266501 --- /dev/null +++ b/templates/actors/actor-cephaly.hbs @@ -0,0 +1,42 @@ +
+ +
+ +
+

{{localize "ECRY.ui.cephaly"}}

+
+
+ +
+ {{#if annency.id}} +

{{localize "ECRY.ui.annency"}} : + + {{annency.name}} + +

+
    +
  • + {{annency.system.base.description}} +
  • +
+ {{/if}} +
+ +
+ +
diff --git a/templates/actors/actor-combat.hbs b/templates/actors/actor-combat.hbs new file mode 100644 index 0000000..92cbd31 --- /dev/null +++ b/templates/actors/actor-combat.hbs @@ -0,0 +1,68 @@ +
+ + {{!-- Impacts --}} +
+ {{> systems/fvtt-ecryme/templates/actors/partial-impacts.hbs + impacts=system.impacts.physical impacttype="physical" impactMalus=impactsMalus.physical}} + {{> systems/fvtt-ecryme/templates/actors/partial-impacts.hbs + impacts=system.impacts.mental impacttype="mental" impactMalus=impactsMalus.mental}} + {{> systems/fvtt-ecryme/templates/actors/partial-impacts.hbs + impacts=system.impacts.social impacttype="social" impactMalus=impactsMalus.social}} +
+ + {{!-- Weapons --}} +
    +
  • + +

    +
    + + + + + + +
  • + {{#each weapons as |weapon key|}} +
  • + + + + + + + {{weapon.name}} + + + {{localize (concat "ECRY.ui." weapon.system.weapontype)}} + {{weapon.system.effect}} +
     
    +
    + +
    +
  • + {{/each}} +
+ + {{!-- Maneuvers --}} +
    +
  • + +

    +
    +
  • + {{#each maneuvers as |maneuver key|}} +
  • + + + + {{maneuver.name}} +
     
    +
    + +
    +
  • + {{/each}} +
+ +
diff --git a/templates/actors/actor-equipements.hbs b/templates/actors/actor-equipements.hbs new file mode 100644 index 0000000..c2d93ee --- /dev/null +++ b/templates/actors/actor-equipements.hbs @@ -0,0 +1,40 @@ +
+ + {{!-- Free equipment (plain text area) --}} + +

+
+
+ +
+ + {{!-- Equipment list --}} +
    +
  • + +

    +
    + + + +
     
    +
    + +
    +
  • + {{#each equipments as |equip key|}} +
  • + + + + {{equip.name}} + {{equip.system.weight}} +
     
    +
    + +
    +
  • + {{/each}} +
+ +
diff --git a/templates/actors/actor-skills.hbs b/templates/actors/actor-skills.hbs new file mode 100644 index 0000000..4e7cb63 --- /dev/null +++ b/templates/actors/actor-skills.hbs @@ -0,0 +1,70 @@ +
+ +
+ + {{#each skills as |category categkey|}} +
+ +
+ {{/each}} + +
+ +
diff --git a/templates/actors/actor-traits.hbs b/templates/actors/actor-traits.hbs new file mode 100644 index 0000000..cd295ed --- /dev/null +++ b/templates/actors/actor-traits.hbs @@ -0,0 +1,30 @@ +
+ +
    +
  • + +

    +
    + + + +
    + +
    +
  • + {{#each traits as |trait key|}} +
  • + + + + {{trait.name}} + +
     
    +
    + +
    +
  • + {{/each}} +
+ +
diff --git a/templates/actors/annency-annency.hbs b/templates/actors/annency-annency.hbs new file mode 100644 index 0000000..ec649d6 --- /dev/null +++ b/templates/actors/annency-annency.hbs @@ -0,0 +1,50 @@ +
+ +
+ +
+

{{localize "ECRY.ui.annency"}}

+
    +
  • + {{localize "ECRY.ui.iscollective"}} + + {{localize "ECRY.ui.ismultiple"}} + +
  • +
+ +

{{localize "ECRY.ui.characters"}}

+
    + {{#each characters as |character id|}} +
  • + + {{character.name}} +
     
    +
    + + +
    +
  • + {{/each}} +
+
+ +
+

{{localize "ECRY.ui.location"}}

+
    + {{#each system.base.location as |location index|}} +
  • + {{localize "ECRY.ui.location"}} {{index}} + +
  • + {{/each}} +
  • + {{localize "ECRY.ui.enhancements"}} + +
  • +
+
+ +
+ +
diff --git a/templates/actors/annency-boheme.hbs b/templates/actors/annency-boheme.hbs new file mode 100644 index 0000000..5daca0b --- /dev/null +++ b/templates/actors/annency-boheme.hbs @@ -0,0 +1,23 @@ +
+ +

{{localize "ECRY.ui.oniricform"}}

+
    +
  • + {{localize "ECRY.ui.name"}} + +
  • +
  • + {{localize "ECRY.ui.ideals"}} + +
  • +
  • + {{localize "ECRY.ui.politic"}} + +
  • +
  • + {{localize "ECRY.ui.description"}} + +
  • +
+ +
diff --git a/templates/actors/partial-impacts.hbs b/templates/actors/partial-impacts.hbs index 0da3375..c791d6f 100644 --- a/templates/actors/partial-impacts.hbs +++ b/templates/actors/partial-impacts.hbs @@ -8,9 +8,9 @@ {{#each impacts as |value key|}}
  • - + {{value}} - +
  • {{/each}} diff --git a/templates/actors/partials/actor-header.hbs b/templates/actors/partials/actor-header.hbs new file mode 100644 index 0000000..851f769 --- /dev/null +++ b/templates/actors/partials/actor-header.hbs @@ -0,0 +1,51 @@ +
    + +
    +

    + +

    + {{#if (eq type "annency")}} + {{!-- Annency header: description --}} +
    + + +
    + {{else}} + {{!-- PC/NPC header: spleen, ideal, traits (rows always visible, controls conditional on item existence) --}} +
    +
      +
    • + + +
       
      + {{#if spleen}} +
      + + +
      + {{/if}} +
    • +
    • + + +
       
      + {{#if ideal}} +
      + + +
      + {{/if}} +
    • +
    • + + {{#each traits as |trait key|}} + + {{/each}} +
    • +
    +
    + {{/if}} +
    +
    diff --git a/templates/chat/chat-cephaly-result.hbs b/templates/chat/chat-cephaly-result.hbs index 3d9d9f6..b8c53d1 100644 --- a/templates/chat/chat-cephaly-result.hbs +++ b/templates/chat/chat-cephaly-result.hbs @@ -5,33 +5,30 @@

    {{alias}}

    -
    +
    -{{#if img}} -
    - {{alias}} -
    -{{/if}} + {{#if img}} +
    + {{alias}} +
    + {{/if}} -
      -
    • {{localize "ECRY.ui.cephaly"}} : {{localize skill.name}}
    • - +
    • {{localize "ECRY.ui.cephaly"}} : {{localize skill.name}}
    • + {{#if annency}} -
    • {{localize "ECRY.ui.annencybonus"}} {{annency.name}}: {{annencyBonus}}
    • +
    • {{localize "ECRY.ui.annencybonus"}} {{annency.name}}: {{annencyBonus}}
    • {{/if}} - - {{#if (gt marginExecution 0)}} -
    • {{localize "ECRY.ui.execution"}} {{executionTotal}} vs {{difficulty}} : {{marginExecution}}
    • -
    • {{localize cephalySuccess}}
    • + + {{#if (gt marginExecution 0)}} +
    • {{localize "ECRY.ui.execution"}} {{executionTotal}} vs {{difficulty}} : {{marginExecution}}
    • +
    • {{/if}} - - {{#if (gt marginPreservation 0)}} -
    • {{localize "ECRY.ui.preservation"}} {{preservationTotal}} vs {{difficulty}} : {{marginPreservation}}
    • -
    • {{localize cephalyFailure}}
    • + + {{#if (gt marginPreservation 0)}} +
    • {{localize "ECRY.ui.preservation"}} {{preservationTotal}} vs {{difficulty}} : {{marginPreservation}}
    • +
    • {{/if}} -
    -
    \ No newline at end of file diff --git a/templates/chat/chat-confrontation-pending.hbs b/templates/chat/chat-confrontation-pending.hbs index 76530b3..e6da16b 100644 --- a/templates/chat/chat-confrontation-pending.hbs +++ b/templates/chat/chat-confrontation-pending.hbs @@ -5,52 +5,50 @@

    {{alias}}

    -
    +
    -{{#if img}} -
    - {{alias}} -
    -{{/if}} + {{#if img}} +
    + {{alias}} +
    + {{/if}} -
      {{#if (eq mode "cephaly")}} -
    • {{localize "ECRY.ui.cephaly"}} : {{localize skill.name}}
    • +
    • {{localize "ECRY.ui.cephaly"}} : {{localize skill.name}}
    • {{else}} -
    • Confrontation : {{alias}}
    • +
    • Confrontation : {{alias}}
    • {{/if}} -
    • {{localize skill.name}}: {{skill.value}}
    • +
    • {{localize skill.name}}: {{skill.value}}
    • {{#if spec}} -
    • {{localize "ECRY.chat.specialization"}} {{spec.name}} (+{{spec.system.bonus}})
    • +
    • {{localize "ECRY.chat.specialization"}} {{spec.name}} (+{{spec.system.bonus}})
    • {{/if}} {{#each traitsBonus as |trait idx|}} {{#if trait.activated}} -
    • {{localize "ECRY.chat.traitbonus"}}: {{trait.name}} ({{trait.system.level}})
    • +
    • {{localize "ECRY.chat.traitbonus"}}: {{trait.name}} ({{trait.system.level}})
    • {{/if}} {{/each}} {{#each traitsMalus as |trait idx|}} {{#if trait.activated}} -
    • {{localize "ECRY.chat.traitmalus"}}: {{trait.name}} ({{trait.system.level}})
    • +
    • {{localize "ECRY.chat.traitmalus"}}: {{trait.name}} ({{trait.system.level}})
    • {{/if}} {{/each}} {{#if bonusMalusTraits}} -
    • {{localize "ECRY.chat.bonusmalustraits"}}: {{bonusMalusTraits}}
    • +
    • {{localize "ECRY.chat.bonusmalustraits"}}: {{bonusMalusTraits}}
    • {{/if}} {{#if (isGM)}} {{else}} -
    • {{localize "ECRY.ui.execution"}} : {{executionTotal}}
    • -
    • {{localize "ECRY.ui.preservation"}} : {{preservationTotal}}
    • +
    • {{localize "ECRY.ui.execution"}} : {{executionTotal}}
    • +
    • {{localize "ECRY.ui.preservation"}} : {{preservationTotal}}
    • {{/if}} -
    {{#if (isGM)}} {{#if (eq mode "cephaly")}} -
    +
    {{localize "ECRY.chat.difficulty"}}
    - + {{else}} - + {{/if}} {{else}} -
    - {{localize "ECRY.chat.sentogm"}} -
    +

    {{localize "ECRY.chat.sentogm"}}

    {{/if}} -
    \ No newline at end of file diff --git a/templates/chat/chat-confrontation-result.hbs b/templates/chat/chat-confrontation-result.hbs index a55258e..a01edcb 100644 --- a/templates/chat/chat-confrontation-result.hbs +++ b/templates/chat/chat-confrontation-result.hbs @@ -2,53 +2,60 @@ {{#if actorImg}} {{alias}} {{/if}} -

    {{alias}}

    +
    +

    {{alias}}

    + {{localize "ECRY.ui.confrontresult"}} +
    -
    +
    -{{#if img}} -
    - {{alias}} -
    -{{/if}} - -
    • Confrontation : {{rollData1.alias}} vs {{rollData2.alias}}
    • -
    • {{localize rollData1.skill.name}} ({{rollData1.skill.value}}) vs {{localize rollData2.skill.name}} ({{rollData2.skill.value}})
    • -
    • {{rollData1.executionTotal}} vs {{rollData2.preservationTotal}} : {{marginExecution}}
    • -
    • {{rollData1.preservationTotal}} vs {{rollData2.executionTotal}} : {{marginPreservation}}
    • +
    • {{localize rollData1.skill.name}} ({{rollData1.skill.value}}) vs {{localize rollData2.skill.name}} ({{rollData2.skill.value}})
    • +
    • {{localize "ECRY.ui.execution"}} : {{rollData1.executionTotal}} vs {{rollData2.preservationTotal}} → {{marginExecution}}
    • +
    • {{localize "ECRY.ui.preservation"}} : {{rollData1.preservationTotal}} vs {{rollData2.executionTotal}} → {{marginPreservation}}
    • {{#if rollData1.weapon}} -
    • {{rollData1.alias}} {{rollData1.weapon.name}} ({{rollData1.weapon.system.effect}}) -
    • +
    • {{rollData1.alias}} — {{rollData1.weapon.name}} ({{rollData1.weapon.system.effect}})
    • {{/if}} - {{#if rollData2.weapon}} -
    • {{rollData2.alias}} {{rollData2.weapon.name}} ({{rollData2.weapon.system.effect}})
    • +
    • {{rollData2.alias}} — {{rollData2.weapon.name}} ({{rollData2.weapon.system.effect}})
    • {{/if}} -
    • {{localize "ECRY.ui.effect"}} {{localize "ECRY.ui.execution"}} : {{effectExecution}}
    • +
    • {{localize "ECRY.ui.effect"}} {{localize "ECRY.ui.execution"}} : {{effectExecution}}
    • {{#if impactExecution}}
    • Impact {{rollData2.alias}} : 1 {{localize (concat "ECRY.ui." impactExecution)}}
    • - + {{/if}} {{#if bonus2}} -
    • Bonus {{rollData2.alias}} : {{bonus2}}
    • - +
    • Bonus {{rollData2.alias}} : {{bonus2}}
    • + {{/if}} -
    • {{localize "ECRY.ui.effect"}} {{localize "ECRY.ui.preservation"}} : {{effectPreservation}}
    • +
    • {{localize "ECRY.ui.effect"}} {{localize "ECRY.ui.preservation"}} : {{effectPreservation}}
    • {{#if impactPreservation}}
    • Impact {{rollData1.alias}} : 1 {{localize (concat "ECRY.ui." impactPreservation)}}
    • - + {{/if}} {{#if bonus1}} -
    • Bonus {{rollData1.alias}} : {{bonus1}}
    • - +
    • Bonus {{rollData1.alias}} : {{bonus1}}
    • + {{/if}}
    -
    \ No newline at end of file diff --git a/templates/chat/chat-generic-result.hbs b/templates/chat/chat-generic-result.hbs index 41d2a08..7d34474 100644 --- a/templates/chat/chat-generic-result.hbs +++ b/templates/chat/chat-generic-result.hbs @@ -5,61 +5,55 @@

    {{alias}}

    -
    - +
    + {{#if img}} -
    +
    {{name}}
    {{/if}} -
    -
    +
      + {{#if skill}} +
    • {{localize skill.name}}: {{skill.value}}
    • + {{#if spec}} +
    • {{localize "ECRY.chat.specialization"}} {{spec.name}} (+{{spec.system.bonus}})
    • + {{/if}} + {{/if}} -
      -
        - {{#if skill}} -
      • {{localize skill.name}}: {{skill.value}}
      • - {{#if spec}} -
      • {{localize "ECRY.chat.specialization"}} {{spec.name}} (+{{spec.system.bonus}})
      • - {{/if}} - {{/if}} + {{#if impactMalus}} +
      • {{localize "ECRY.ui.impactmalus"}}: {{impactMalus}}
      • + {{/if}} - {{#if impactMalus}} -
      • {{localize "ECRY.ui.impactmalus"}}: {{impactMalus}}
      • - {{/if}} + {{#if skillTranscendence}} +
      • {{localize "ECRY.ui.skilltranscendence"}}: {{skillTranscendence}}
      • + {{/if}} - {{#if skillTranscendence}} -
      • {{localize "ECRY.ui.skilltranscendence"}}: {{skillTranscendence}}
      • - {{/if}} + {{#if traitsBonusList}} + {{#each traitsBonusList as |trait idx|}} +
      • {{localize "ECRY.chat.traitbonus"}}: {{trait.name}} ({{trait.system.level}})
      • + {{/each}} + {{/if}} + {{#if traitsMalusList}} + {{#each traitsMalusList as |trait idx|}} +
      • {{localize "ECRY.chat.traitmalus"}}: {{trait.name}} ({{trait.system.level}})
      • + {{/each}} + {{/if}} + {{#if bonusMalusTraits}} +
      • {{localize "ECRY.chat.bonusmalustraits"}}: {{bonusMalusTraits}}
      • + {{/if}} - {{#if traitsBonusList}} - {{#each traitsBonusList as |trait idx|}} -
      • {{localize "ECRY.chat.traitbonus"}}: {{trait.name}} ({{trait.system.level}})
      • - {{/each}} - {{/if}} - {{#if traitsMalusList}} - {{#each traitsMalusList as |trait idx|}} -
      • {{localize "ECRY.chat.traitmalus"}}: {{trait.name}} ({{trait.system.level}})
      • - {{/each}} - {{/if}} - {{#if bonusMalusTraits}} -
      • {{localize "ECRY.chat.bonusmalustraits"}}: {{bonusMalusTraits}}
      • - {{/if}} +
      • {{localize "ECRY.chat.formula"}}: {{diceFormula}}
      • +
      • {{localize "ECRY.chat.dicesum"}}: {{diceSum}}
      • +
      • {{localize "ECRY.chat.result"}}: {{total}}
      • + {{#if difficulty}} +
      • {{localize "ECRY.chat.difficulty"}}: {{difficulty}} — {{localize "ECRY.chat.margin"}}: {{margin}}
      • + {{#if isSuccess}} +
      • + {{else}} +
      • + {{/if}} + {{/if}} +
      -
    • {{localize "ECRY.chat.formula"}}: {{diceFormula}}
    • -
    • {{localize "ECRY.chat.dicesum"}}: {{diceSum}}
    • -
    • {{localize "ECRY.chat.result"}}: {{total}}
    • - {{#if difficulty}} -
    • {{localize "ECRY.chat.difficulty"}}: {{difficulty}} - {{localize "ECRY.chat.margin"}}: {{margin}}
    • - {{#if isSuccess}} -
    • - {{else}} -
    • - {{/if}} - {{/if}} - -
    -
    - -
    + diff --git a/templates/dialogs/confront-dialog.hbs b/templates/dialogs/confront-dialog.hbs index bcf699f..10b58a4 100644 --- a/templates/dialogs/confront-dialog.hbs +++ b/templates/dialogs/confront-dialog.hbs @@ -1,7 +1,7 @@ -
    +
    {{#if img}} - + {{/if}}

    {{title}} ({{skill.value}})

    @@ -11,7 +11,7 @@
    -

    {{localize "ECRY.ui.execution"}} : {{executionTotal}}

    +

    {{localize "ECRY.ui.execution"}} : {{executionTotal}}

    {{> systems/fvtt-ecryme/templates/dialogs/partial-confront-dice-area.hbs filter="execution"}} {{> systems/fvtt-ecryme/templates/dialogs/partial-confront-bonus-area.hbs filter="execution"}} @@ -54,13 +54,13 @@
    {{localize "ECRY.ui.skilltranscendence"}} : - {{selectOptions config.skillLevel selected=skillTranscendence}}
    {{localize "ECRY.ui.transcendapply"}} : - {{selectOptions config.transcendanceOptions selected=applyTranscendence localize=true}}
    @@ -68,9 +68,9 @@ {{#if skill.spec}}
    {{localize "ECRY.ui.spec"}} : - {{#each skill.spec as |spec idx|}} - + {{/each}}
    @@ -78,7 +78,7 @@
    {{localize "ECRY.ui.traitbonus"}} : - {{#each traitsBonus as |trait idx|}} {{/each}} @@ -87,13 +87,13 @@
    {{localize "ECRY.ui.traitmalus"}} : - {{#each traitsMalus as |trait idx|}} {{/each}}
    - + {{#if annency}}
    {{localize "ECRY.ui.annency"}} : {{annency.name}} @@ -101,25 +101,32 @@
    {{localize "ECRY.ui.annencybonus"}} - + + + + + +
    {{/if}}
    Bonus/Malus : - {{selectOptions config.bonusMalusPersoOptions selected=bonusMalusPerso labelAttr="label"}}
    -
    - \ No newline at end of file +
    + + +
    +
    diff --git a/templates/dialogs/confront-start-dialog.hbs b/templates/dialogs/confront-start-dialog.hbs index 93d861f..45b6fa2 100644 --- a/templates/dialogs/confront-start-dialog.hbs +++ b/templates/dialogs/confront-start-dialog.hbs @@ -1,13 +1,23 @@ -
    -
    +
    +
    {{#if img}} - + {{/if}} -

    {{title}}

    -
    - -
    - + {{title}}
    -
    \ No newline at end of file +
    + + + + +
    +
    diff --git a/templates/dialogs/roll-dialog-generic.hbs b/templates/dialogs/roll-dialog-generic.hbs index 4cdd9a0..a010671 100644 --- a/templates/dialogs/roll-dialog-generic.hbs +++ b/templates/dialogs/roll-dialog-generic.hbs @@ -1,9 +1,9 @@ -
    +
    {{#if img}} - + {{/if}} -

    {{title}}

    + {{title}}
    @@ -11,12 +11,20 @@ {{> systems/fvtt-ecryme/templates/dialogs/partial-common-roll-dialog.hbs}}
    - Difficulté : - {{selectOptions config.difficulty selected=difficulty localize=true labelAttr="difficulty"}}
    - \ No newline at end of file +
    + + +
    +
    diff --git a/templates/items/item-equipment-details.hbs b/templates/items/item-equipment-details.hbs new file mode 100644 index 0000000..421da6e --- /dev/null +++ b/templates/items/item-equipment-details.hbs @@ -0,0 +1,19 @@ +
    +
      +
    • + + +
    • +
    • + + +
    • +
    • + + + +
    • +
    +
    diff --git a/templates/items/item-maneuver-details.hbs b/templates/items/item-maneuver-details.hbs new file mode 100644 index 0000000..acb4c2f --- /dev/null +++ b/templates/items/item-maneuver-details.hbs @@ -0,0 +1,5 @@ +
    +
      + {{!-- Maneuver has no additional details --}} +
    +
    diff --git a/templates/items/item-specialization-details.hbs b/templates/items/item-specialization-details.hbs new file mode 100644 index 0000000..768235e --- /dev/null +++ b/templates/items/item-specialization-details.hbs @@ -0,0 +1,14 @@ +
    +
      +
    • + + +
    • +
    • + + +
    • +
    +
    diff --git a/templates/items/item-trait-details.hbs b/templates/items/item-trait-details.hbs new file mode 100644 index 0000000..97e20fe --- /dev/null +++ b/templates/items/item-trait-details.hbs @@ -0,0 +1,16 @@ +
    +
      +
    • + + +
    • +
    • + + +
    • +
    +
    diff --git a/templates/items/item-weapon-details.hbs b/templates/items/item-weapon-details.hbs new file mode 100644 index 0000000..d98866b --- /dev/null +++ b/templates/items/item-weapon-details.hbs @@ -0,0 +1,25 @@ +
    +
      +
    • + + +
    • +
    • + + +
    • +
    • + + +
    • +
    • + + + +
    • +
    +
    diff --git a/templates/items/partials/item-description.hbs b/templates/items/partials/item-description.hbs new file mode 100644 index 0000000..efacee0 --- /dev/null +++ b/templates/items/partials/item-description.hbs @@ -0,0 +1,5 @@ +
    +
    + {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}} +
    +
    diff --git a/templates/items/partials/item-header.hbs b/templates/items/partials/item-header.hbs new file mode 100644 index 0000000..ad7da5f --- /dev/null +++ b/templates/items/partials/item-header.hbs @@ -0,0 +1,6 @@ +
    + +
    +

    {{formInput fields.name value=source.name}}

    +
    +
    diff --git a/welcome-message-ecryme.html b/welcome-message-ecryme.html index 25c27d6..cbf5e4a 100644 --- a/welcome-message-ecryme.html +++ b/welcome-message-ecryme.html @@ -1,42 +1,47 @@ -

    Bonjour à tous !

    - -
    - 👋 Juste un petit message pour vous informer que : -
    - ⚠️ Le nouveau financement participatif pour la prochaine extension - d'Écryme, LES SECRETS DE L'ÉCRYME ouvre le 21 octobre ! +
    + Écryme +

    Écryme RPG

    -
    - ⚠️ Suivez la page de pré-lancement ici pour être sûr de ne pas manquer le - lancement :
    https://shorturl.at/qDjg7 -
    - -
    - Nous avons aussi un nouveau Discord pour ceux ou celles qui souhaiteraient - participer plus activement à la communauté des jeux d'Open Sesame Games, avec - un espace dédié aux écrymiens !
    - Nouveaux joueurs comme vétérans sont les bienvenus, n'hésitez pas à passer - pour papoter, profiter de nos ressources, ou suivre les nouvelles d'OSG plus - directement. Cliquez ici :
    - https://discord.gg/dUPhNfJdaD
    -
    - -
    - Ce système vous est proposé par Open Sesame Games.
    - Vous trouverez de l'aide dans - @UUID[Compendium.fvtt-ecryme.help.JournalEntry.wooTFYjEwh83FwgT]{Aide pour - Ecryme}
    - ainsi que sur le Discord de Foundry FR :
    - https://discord.gg/pPSDNJk -
    - -
    - Merci pour votre attention et à très bientôt pour la suite ! L'équipe Open - Sesame Games +
    + +

    ⚙ Bonjour à tous !

    + +
    + 👋 Juste un petit message pour vous informer que : +
    + ⚠️ Le nouveau financement participatif pour la prochaine extension + d'Écryme, LES SECRETS DE L'ÉCRYME ouvre le 21 octobre ! +
    + +
    + ⚠️ Suivez la page de pré-lancement ici pour être sûr de ne pas manquer le + lancement :
    + https://shorturl.at/qDjg7 +
    + +
    + +
    + Nous avons aussi un nouveau Discord pour ceux ou celles qui souhaiteraient + participer plus activement à la communauté des jeux d'Open Sesame Games, avec + un espace dédié aux écrymiens !
    + Nouveaux joueurs comme vétérans sont les bienvenus, n'hésitez pas à passer + pour papoter, profiter de nos ressources, ou suivre les nouvelles d'OSG plus + directement.
    + Discord Open Sesame Games +
    + +
    + Ce système vous est proposé par Open Sesame Games.
    + Vous trouverez de l'aide dans + @UUID[Compendium.fvtt-ecryme.help.JournalEntry.wooTFYjEwh83FwgT]{Aide pour Écryme}
    + ainsi que sur le Discord de Foundry FR :
    + Discord Foundry FR +
    + + +