First row of tests and fixes

This commit is contained in:
2026-03-05 23:43:45 +01:00
parent f28df2ae76
commit 95b19c8f02
9 changed files with 430 additions and 86 deletions
+2
View File
@@ -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",
@@ -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"
},
+48 -1
View File
@@ -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
}
}
+4 -2
View File
@@ -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 })
})
+292 -6
View File
@@ -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%);
+14
View File
@@ -0,0 +1,14 @@
<section class="tab creature-description {{tab.cssClass}}" data-group="sheet" data-tab="description">
<fieldset>
<legend>{{localize "AWEMMY.Character.Description"}}</legend>
{{formInput
systemFields.description
enriched=enrichedDescription
value=system.description
name="system.description"
toggled=true
}}
</fieldset>
</section>
+33
View File
@@ -0,0 +1,33 @@
<section class="tab creature-eureka {{tab.cssClass}}" data-group="sheet" data-tab="eureka">
<div class="eureka-rubric">
<div class="eureka-field">
<label>{{localize "AWEMMY.Creature.Claims"}}</label>
<textarea name="system.eurekaClaims" rows="4" placeholder="{{localize 'AWEMMY.Creature.Claims'}}…">{{system.eurekaClaims}}</textarea>
</div>
<div class="eureka-field">
<label>{{localize "AWEMMY.Creature.Evidence"}}</label>
<textarea name="system.eurekaEvidence" rows="4" placeholder="{{localize 'AWEMMY.Creature.Evidence'}}…">{{system.eurekaEvidence}}</textarea>
</div>
<div class="eureka-columns">
<div class="eureka-field">
<label>{{localize "AWEMMY.Creature.Threshold1"}}</label>
<textarea name="system.eurekaThreshold1" rows="3" placeholder="{{localize 'AWEMMY.Creature.Threshold1'}}…">{{system.eurekaThreshold1}}</textarea>
</div>
<div class="eureka-field">
<label>{{localize "AWEMMY.Creature.Threshold2"}}</label>
<textarea name="system.eurekaThreshold2" rows="3" placeholder="{{localize 'AWEMMY.Creature.Threshold2'}}…">{{system.eurekaThreshold2}}</textarea>
</div>
</div>
<div class="eureka-field">
<label>{{localize "AWEMMY.Creature.Hints"}}</label>
<textarea name="system.eurekaHints" rows="4" placeholder="{{localize 'AWEMMY.Creature.Hints'}}…">{{system.eurekaHints}}</textarea>
</div>
</div>
</section>
+27
View File
@@ -0,0 +1,27 @@
<div class="actor-header">
<img class="actor-img" src="{{actor.img}}" data-edit="img" data-action="editImage" data-tooltip="{{actor.name}}" />
<div class="actor-identity">
{{formInput fields.name value=source.name classes="actor-name"}}
<div class="actor-details">
<div class="detail-item">
<label>{{localize "AWEMMY.Character.Level"}}</label>
{{formInput systemFields.level value=system.level}}
</div>
<div class="detail-item">
<label>{{localize "AWEMMY.Character.Stride"}}</label>
{{formInput systemFields.stride value=system.stride}}
</div>
<div class="detail-item">
<label>{{localize "AWEMMY.Character.HP"}}</label>
{{formInput systemFields.hp.fields.value value=system.hp.value}}
<span>/</span>
{{formInput systemFields.hp.fields.max value=system.hp.max}}
</div>
</div>
</div>
<div class="sheet-controls">
<button type="button" data-action="toggleSheet" data-tooltip="{{#if isPlayMode}}{{localize 'AWEMMY.Sheet.EditMode'}}{{else}}{{localize 'AWEMMY.Sheet.PlayMode'}}{{/if}}">
{{#if isPlayMode}}<i class="fa-solid fa-lock"></i>{{else}}<i class="fa-solid fa-unlock"></i>{{/if}}
</button>
</div>
</div>
+7 -74
View File
@@ -1,62 +1,34 @@
<section class="creature-main">
<div class="actor-header">
<img class="actor-img" src="{{actor.img}}" data-edit="img" data-action="editImage" data-tooltip="{{actor.name}}" />
<div class="actor-identity">
{{formInput fields.name value=source.name classes="actor-name"}}
<div class="actor-details">
<div class="detail-item">
<label>{{localize "AWEMMY.Character.Level"}}</label>
{{formInput systemFields.level value=system.level}}
</div>
<div class="detail-item">
<label>{{localize "AWEMMY.Character.Stride"}}</label>
{{formInput systemFields.stride value=system.stride}}
</div>
<div class="detail-item">
<label>{{localize "AWEMMY.Character.HP"}}</label>
{{formInput systemFields.hp.fields.value value=system.hp.value}}
<span>/</span>
{{formInput systemFields.hp.fields.max value=system.hp.max}}
</div>
</div>
</div>
<div class="sheet-controls">
<button type="button" data-action="toggleSheet">
{{#if isPlayMode}}<i class="fa-solid fa-lock"></i>{{else}}<i class="fa-solid fa-unlock"></i>{{/if}}
</button>
</div>
</div>
<section class="tab creature-main {{tab.cssClass}}" data-group="sheet" data-tab="main">
{{!-- Attributes --}}
<fieldset>
<legend>Attributes</legend>
<legend>{{localize "AWEMMY.Character.Attributes"}}</legend>
<table class="attributes-table">
<thead>
<tr>
<th>Attribute</th>
<th>{{localize "AWEMMY.Character.Attribute"}}</th>
<th>{{localize "AWEMMY.Character.Mod"}}</th>
<th>{{localize "AWEMMY.Character.DC"}}</th>
</tr>
</thead>
<tbody>
<tr>
<td class="attr-label">{{localize "AWEMMY.Attribute.Agility"}}</td>
<td class="attr-label rollable" data-attribute-id="agility">{{localize "AWEMMY.Attribute.Agility"}} <i class="fa-solid fa-dice-d20"></i></td>
<td>{{formInput systemFields.attributes.fields.agility.fields.mod value=system.attributes.agility.mod}}</td>
<td>{{formInput systemFields.attributes.fields.agility.fields.dc value=system.attributes.agility.dc}}</td>
</tr>
<tr>
<td class="attr-label">{{localize "AWEMMY.Attribute.Fitness"}}</td>
<td class="attr-label rollable" data-attribute-id="fitness">{{localize "AWEMMY.Attribute.Fitness"}} <i class="fa-solid fa-dice-d20"></i></td>
<td>{{formInput systemFields.attributes.fields.fitness.fields.mod value=system.attributes.fitness.mod}}</td>
<td>{{formInput systemFields.attributes.fields.fitness.fields.dc value=system.attributes.fitness.dc}}</td>
</tr>
<tr>
<td class="attr-label">{{localize "AWEMMY.Attribute.Awareness"}}</td>
<td class="attr-label rollable" data-attribute-id="awareness">{{localize "AWEMMY.Attribute.Awareness"}} <i class="fa-solid fa-dice-d20"></i></td>
<td>{{formInput systemFields.attributes.fields.awareness.fields.mod value=system.attributes.awareness.mod}}</td>
<td>{{formInput systemFields.attributes.fields.awareness.fields.dc value=system.attributes.awareness.dc}}</td>
</tr>
<tr>
<td class="attr-label">{{localize "AWEMMY.Attribute.Influence"}}</td>
<td class="attr-label rollable" data-attribute-id="influence">{{localize "AWEMMY.Attribute.Influence"}} <i class="fa-solid fa-dice-d20"></i></td>
<td>{{formInput systemFields.attributes.fields.influence.fields.mod value=system.attributes.influence.mod}}</td>
<td>{{formInput systemFields.attributes.fields.influence.fields.dc value=system.attributes.influence.dc}}</td>
</tr>
@@ -64,43 +36,4 @@
</table>
</fieldset>
{{!-- Description --}}
<fieldset>
<legend>Description</legend>
{{formInput
systemFields.description
enriched=enrichedDescription
value=system.description
name="system.description"
toggled=true
}}
</fieldset>
{{!-- Eureka Rubric --}}
<fieldset>
<legend>{{localize "AWEMMY.Creature.EurekaRubric"}}</legend>
<div class="eureka-rubric">
<div class="eureka-row">
<label>{{localize "AWEMMY.Creature.Claims"}}</label>
{{formInput systemFields.eurekaClaims value=system.eurekaClaims}}
</div>
<div class="eureka-row">
<label>{{localize "AWEMMY.Creature.Evidence"}}</label>
{{formInput systemFields.eurekaEvidence value=system.eurekaEvidence}}
</div>
<div class="eureka-row">
<label>{{localize "AWEMMY.Creature.Threshold1"}}</label>
{{formInput systemFields.eurekaThreshold1 value=system.eurekaThreshold1}}
</div>
<div class="eureka-row">
<label>{{localize "AWEMMY.Creature.Threshold2"}}</label>
{{formInput systemFields.eurekaThreshold2 value=system.eurekaThreshold2}}
</div>
<div class="eureka-row">
<label>{{localize "AWEMMY.Creature.Hints"}}</label>
{{formInput systemFields.eurekaHints value=system.eurekaHints}}
</div>
</div>
</fieldset>
</section>