From 95b19c8f02b37c462945977db012b796c2b0bdf1 Mon Sep 17 00:00:00 2001 From: LeRatierBretonnier Date: Thu, 5 Mar 2026 23:43:45 +0100 Subject: [PATCH] First row of tests and fixes --- lang/en.json | 2 + .../applications/sheets/character-sheet.mjs | 6 +- module/applications/sheets/creature-sheet.mjs | 49 ++- module/models/character.mjs | 6 +- styles/adventures-with-emmy.less | 298 +++++++++++++++++- templates/creature-description.hbs | 14 + templates/creature-eureka.hbs | 33 ++ templates/creature-header.hbs | 27 ++ templates/creature-main.hbs | 81 +---- 9 files changed, 430 insertions(+), 86 deletions(-) create mode 100644 templates/creature-description.hbs create mode 100644 templates/creature-eureka.hbs create mode 100644 templates/creature-header.hbs diff --git a/lang/en.json b/lang/en.json index beeaf2a..fe23530 100644 --- a/lang/en.json +++ b/lang/en.json @@ -55,6 +55,8 @@ "AWEMMY.Sheet.Tab.Main": "Main", "AWEMMY.Sheet.Tab.Biography": "Biography", "AWEMMY.Sheet.Tab.Equipment": "Equipment", + "AWEMMY.Sheet.Tab.Description": "Description", + "AWEMMY.Sheet.Tab.Eureka": "Eureka", "AWEMMY.Sheet.EditMode": "Edit", "AWEMMY.Sheet.PlayMode": "Play", "AWEMMY.Character.Level": "Level", diff --git a/module/applications/sheets/character-sheet.mjs b/module/applications/sheets/character-sheet.mjs index f3ec0e0..cb98965 100644 --- a/module/applications/sheets/character-sheet.mjs +++ b/module/applications/sheets/character-sheet.mjs @@ -27,12 +27,12 @@ export default class AwECharacterSheet extends AwEActorSheet { header: { template: "systems/fvtt-adventures-with-emmy/templates/character-header.hbs" }, - main: { - template: "systems/fvtt-adventures-with-emmy/templates/character-main.hbs" - }, tabs: { template: "templates/generic/tab-navigation.hbs" }, + main: { + template: "systems/fvtt-adventures-with-emmy/templates/character-main.hbs" + }, biography: { template: "systems/fvtt-adventures-with-emmy/templates/character-biography.hbs" }, diff --git a/module/applications/sheets/creature-sheet.mjs b/module/applications/sheets/creature-sheet.mjs index ed29619..b2897d9 100644 --- a/module/applications/sheets/creature-sheet.mjs +++ b/module/applications/sheets/creature-sheet.mjs @@ -6,7 +6,7 @@ export default class AwECreatureSheet extends AwEActorSheet { classes: ["creature"], position: { width: 700, - height: "auto" + height: 700 }, window: { contentClasses: ["creature-content"] @@ -15,17 +15,64 @@ export default class AwECreatureSheet extends AwEActorSheet { /** @override */ static PARTS = { + header: { + template: "systems/fvtt-adventures-with-emmy/templates/creature-header.hbs" + }, + tabs: { + template: "templates/generic/tab-navigation.hbs" + }, main: { template: "systems/fvtt-adventures-with-emmy/templates/creature-main.hbs" + }, + description: { + template: "systems/fvtt-adventures-with-emmy/templates/creature-description.hbs" + }, + eureka: { + template: "systems/fvtt-adventures-with-emmy/templates/creature-eureka.hbs" } } + /** @override */ + tabGroups = { + sheet: "main" + } + + #getTabs() { + const tabs = { + main: { id: "main", group: "sheet", icon: "fa-solid fa-dragon", label: "AWEMMY.Sheet.Tab.Main" }, + description: { id: "description", group: "sheet", icon: "fa-solid fa-scroll", label: "AWEMMY.Sheet.Tab.Description" }, + eureka: { id: "eureka", group: "sheet", icon: "fa-solid fa-lightbulb", label: "AWEMMY.Sheet.Tab.Eureka" } + } + for (const v of Object.values(tabs)) { + v.active = this.tabGroups[v.group] === v.id + v.cssClass = v.active ? "active" : "" + } + return tabs + } + /** @override */ async _prepareContext() { const context = await super._prepareContext() + context.tabs = this.#getTabs() context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML( this.document.system.description, { async: true } ) return context } + + /** @override */ + async _preparePartContext(partId, context) { + switch (partId) { + case "main": + context.tab = context.tabs.main + break + case "description": + context.tab = context.tabs.description + break + case "eureka": + context.tab = context.tabs.eureka + break + } + return context + } } diff --git a/module/models/character.mjs b/module/models/character.mjs index 0182b6e..4884a38 100644 --- a/module/models/character.mjs +++ b/module/models/character.mjs @@ -17,7 +17,8 @@ export default class AwECharacter extends foundry.abstract.TypeDataModel { schema.backgroundName = new fields.StringField({ initial: "", required: false, nullable: true }) // Core stats - schema.level = new fields.NumberField({ ...requiredInteger, initial: 1, min: 1, max: 10 }) + schema.level = new fields.NumberField({ ...requiredInteger, initial: 1, min: 1, max: 10, + choices: Object.fromEntries([1,2,3,4,5,6,7,8,9,10].map(v => [v, String(v)])) }) schema.stride = new fields.NumberField({ ...requiredInteger, initial: 5, min: 0 }) // Hit Points @@ -39,7 +40,8 @@ export default class AwECharacter extends foundry.abstract.TypeDataModel { // dc = 10 + mod (computed) // bonus: manual +/- bonus const attributeField = () => new fields.SchemaField({ - boostLevel: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 4 }), + boostLevel: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 4, + choices: {0:"0", 1:"1", 2:"2", 3:"3", 4:"4"} }), bonus: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 0 }) }) diff --git a/styles/adventures-with-emmy.less b/styles/adventures-with-emmy.less index 56f3145..59a1ff3 100644 --- a/styles/adventures-with-emmy.less +++ b/styles/adventures-with-emmy.less @@ -28,6 +28,34 @@ color: @color-text; background: @color-bg; + // -------------------------------------------------------- + // Global form field overrides (light theme) + // -------------------------------------------------------- + input[type="text"], + input[type="number"], + input[type="search"], + input:not([type]), + select, + textarea { + background: white; + color: @color-text; + border: 1px solid @color-border; + border-radius: 3px; + + &:focus { + border-color: @color-primary; + outline: none; + box-shadow: 0 0 0 2px fade(@color-primary, 20%); + } + + &:disabled, + &[disabled] { + background: lighten(@color-border, 15%); + color: @color-text-light; + cursor: default; + } + } + .window-header { background: @color-primary; color: white; @@ -98,16 +126,24 @@ .attributes-table { width: 100%; border-collapse: collapse; - margin: 0.5rem 0; + margin: 0.3rem 0; + font-size: 0.85rem; + + // Col widths: name | boost | mod | dc | bonus + th:nth-child(1), td:nth-child(1) { width: 30%; } + th:nth-child(2), td:nth-child(2) { width: 20%; } + th:nth-child(3), td:nth-child(3) { width: 15%; } + th:nth-child(4), td:nth-child(4) { width: 15%; } + th:nth-child(5), td:nth-child(5) { width: 20%; } thead tr { background: @color-primary; color: white; th { - padding: 0.4rem 0.5rem; + padding: 0.25rem 0.4rem; text-align: center; - font-size: 0.8rem; + font-size: 0.75rem; text-transform: uppercase; } } @@ -118,19 +154,37 @@ } td { - padding: 0.35rem 0.5rem; + padding: 0.2rem 0.4rem; text-align: center; border-bottom: 1px solid @color-border; + select { + width: auto; + min-width: 55px; + padding: 0.1rem 0.25rem; + font-size: 0.82rem; + background: white; + color: @color-text; + border: 1px solid @color-border; + border-radius: 3px; + } + input { - width: 50px; + width: 48px; text-align: center; + padding: 0.1rem 0.2rem; + font-size: 0.82rem; + background: white; + color: @color-text; + border: 1px solid @color-border; + border-radius: 3px; } } .attr-label { text-align: left; font-weight: bold; + white-space: nowrap; } .rollable { @@ -313,8 +367,240 @@ } } + // -------------------------------------------------------- - // Creature Sheet - Eureka Rubric + // Character Sheet Header + // -------------------------------------------------------- + .character-content { + .actor-header { + display: grid; + grid-template-columns: 80px 1fr auto auto; + gap: 0.5rem 0.75rem; + align-items: center; + padding: 0.5rem 0.75rem; + + .actor-img { + grid-row: 1 / 3; + align-self: start; + width: 80px; + height: 80px; + } + + .actor-identity { + grid-column: 2; + grid-row: 1 / 3; + display: flex; + flex-direction: column; + gap: 0.3rem; + justify-content: center; + + .actor-name { + font-size: 1.3rem; + width: 100%; + } + + .actor-details { + display: flex; + flex-wrap: wrap; + gap: 0.3rem 1rem; + align-items: center; + + .detail-item { + display: flex; + align-items: center; + gap: 0.3rem; + + label { + font-size: 0.72rem; + text-transform: uppercase; + color: @color-text-light; + white-space: nowrap; + font-weight: 600; + } + + select, input[type="number"] { + width: 64px; + padding: 0.15rem 0.25rem; + font-size: 0.9rem; + text-align: center; + } + } + } + } + + .actor-stats { + grid-column: 3; + grid-row: 1 / 3; + display: flex; + flex-direction: column; + gap: 0.3rem; + justify-content: center; + + .resource-block { + display: flex; + align-items: center; + gap: 0.4rem; + flex-wrap: nowrap; + + > label { + font-size: 0.7rem; + text-transform: uppercase; + color: @color-text-light; + font-weight: 600; + min-width: 70px; + white-space: nowrap; + } + + .resource-values { + display: flex; + align-items: center; + gap: 0.2rem; + + input { + width: 42px; + text-align: center; + font-size: 0.9rem; + } + } + + .resource-temp { + display: flex; + align-items: center; + gap: 0.3rem; + + label { + font-size: 0.65rem; + text-transform: uppercase; + color: @color-text-light; + white-space: nowrap; + } + + input { + width: 38px; + text-align: center; + font-size: 0.85rem; + } + } + + .resource-stepper { + margin-left: 0.2rem; + } + } + } + + .sheet-controls { + grid-column: 4; + grid-row: 1 / 3; + align-self: center; + } + } + } + + + // -------------------------------------------------------- + // Creature Sheet Header (compact) + // -------------------------------------------------------- + .creature-content { + .actor-header { + align-items: center; + flex-wrap: wrap; + + .actor-img { + width: 56px; + height: 56px; + } + + .actor-identity { + flex: 1; + display: flex; + flex-direction: column; + gap: 0.25rem; + } + + .actor-details { + display: flex; + flex-wrap: wrap; + gap: 0.5rem 1rem; + align-items: center; + + .detail-item { + display: flex; + align-items: center; + gap: 0.25rem; + + label { + font-size: 0.75rem; + text-transform: uppercase; + color: @color-text-light; + white-space: nowrap; + } + + input { + width: 42px; + text-align: center; + } + + span { + color: @color-text-light; + } + } + } + } + + // Eureka tab — large textareas + .eureka-rubric { + display: flex; + flex-direction: column; + gap: 0.75rem; + padding: 0.25rem 0; + + .eureka-field { + display: flex; + flex-direction: column; + gap: 0.25rem; + + label { + font-weight: bold; + font-size: 0.85rem; + color: darken(@color-accent, 20%); + text-transform: uppercase; + } + + textarea { + width: 100%; + resize: vertical; + border: 1px solid @color-border; + border-radius: 4px; + padding: 0.4rem 0.5rem; + font-family: @font-body; + font-size: 0.9rem; + background: white; + color: @color-text; + line-height: 1.4; + + &:focus { + border-color: @color-primary; + outline: none; + box-shadow: 0 0 0 2px fadeout(@color-primary, 75%); + } + + &::placeholder { + color: @color-text-light; + font-style: italic; + } + } + } + + .eureka-columns { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0.75rem; + } + } + } + + // -------------------------------------------------------- + // Creature Sheet - Eureka Rubric (legacy / fieldset version) // -------------------------------------------------------- .eureka-rubric { background: lighten(@color-accent, 45%); diff --git a/templates/creature-description.hbs b/templates/creature-description.hbs new file mode 100644 index 0000000..4d84b5c --- /dev/null +++ b/templates/creature-description.hbs @@ -0,0 +1,14 @@ +
+ +
+ {{localize "AWEMMY.Character.Description"}} + {{formInput + systemFields.description + enriched=enrichedDescription + value=system.description + name="system.description" + toggled=true + }} +
+ +
diff --git a/templates/creature-eureka.hbs b/templates/creature-eureka.hbs new file mode 100644 index 0000000..71acbcd --- /dev/null +++ b/templates/creature-eureka.hbs @@ -0,0 +1,33 @@ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ +
diff --git a/templates/creature-header.hbs b/templates/creature-header.hbs new file mode 100644 index 0000000..e829de7 --- /dev/null +++ b/templates/creature-header.hbs @@ -0,0 +1,27 @@ +
+ +
+ {{formInput fields.name value=source.name classes="actor-name"}} +
+
+ + {{formInput systemFields.level value=system.level}} +
+
+ + {{formInput systemFields.stride value=system.stride}} +
+
+ + {{formInput systemFields.hp.fields.value value=system.hp.value}} + / + {{formInput systemFields.hp.fields.max value=system.hp.max}} +
+
+
+
+ +
+
diff --git a/templates/creature-main.hbs b/templates/creature-main.hbs index 99ac54d..c183cbe 100644 --- a/templates/creature-main.hbs +++ b/templates/creature-main.hbs @@ -1,62 +1,34 @@ -
- -
- -
- {{formInput fields.name value=source.name classes="actor-name"}} -
-
- - {{formInput systemFields.level value=system.level}} -
-
- - {{formInput systemFields.stride value=system.stride}} -
-
- - {{formInput systemFields.hp.fields.value value=system.hp.value}} - / - {{formInput systemFields.hp.fields.max value=system.hp.max}} -
-
-
-
- -
-
+
{{!-- Attributes --}}
- Attributes + {{localize "AWEMMY.Character.Attributes"}} - + - + - + - + - + @@ -64,43 +36,4 @@
Attribute{{localize "AWEMMY.Character.Attribute"}} {{localize "AWEMMY.Character.Mod"}} {{localize "AWEMMY.Character.DC"}}
{{localize "AWEMMY.Attribute.Agility"}}{{localize "AWEMMY.Attribute.Agility"}} {{formInput systemFields.attributes.fields.agility.fields.mod value=system.attributes.agility.mod}} {{formInput systemFields.attributes.fields.agility.fields.dc value=system.attributes.agility.dc}}
{{localize "AWEMMY.Attribute.Fitness"}}{{localize "AWEMMY.Attribute.Fitness"}} {{formInput systemFields.attributes.fields.fitness.fields.mod value=system.attributes.fitness.mod}} {{formInput systemFields.attributes.fields.fitness.fields.dc value=system.attributes.fitness.dc}}
{{localize "AWEMMY.Attribute.Awareness"}}{{localize "AWEMMY.Attribute.Awareness"}} {{formInput systemFields.attributes.fields.awareness.fields.mod value=system.attributes.awareness.mod}} {{formInput systemFields.attributes.fields.awareness.fields.dc value=system.attributes.awareness.dc}}
{{localize "AWEMMY.Attribute.Influence"}}{{localize "AWEMMY.Attribute.Influence"}} {{formInput systemFields.attributes.fields.influence.fields.mod value=system.attributes.influence.mod}} {{formInput systemFields.attributes.fields.influence.fields.dc value=system.attributes.influence.dc}}
- {{!-- Description --}} -
- Description - {{formInput - systemFields.description - enriched=enrichedDescription - value=system.description - name="system.description" - toggled=true - }} -
- - {{!-- Eureka Rubric --}} -
- {{localize "AWEMMY.Creature.EurekaRubric"}} -
-
- - {{formInput systemFields.eurekaClaims value=system.eurekaClaims}} -
-
- - {{formInput systemFields.eurekaEvidence value=system.eurekaEvidence}} -
-
- - {{formInput systemFields.eurekaThreshold1 value=system.eurekaThreshold1}} -
-
- - {{formInput systemFields.eurekaThreshold2 value=system.eurekaThreshold2}} -
-
- - {{formInput systemFields.eurekaHints value=system.eurekaHints}} -
-
-
-