Compare commits
1 commit
main
...
feature/ta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b72f22380f |
10 changed files with 213 additions and 2 deletions
137
module/Apps/ActorSheets/TabbedHeroSheet.mjs
Normal file
137
module/Apps/ActorSheets/TabbedHeroSheet.mjs
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
import { filePath } from "../../consts.mjs";
|
||||||
|
import { GenericAppMixin } from "../GenericApp.mjs";
|
||||||
|
import { HeroCraftCardV1 } from "./HeroCraftCardV1.mjs";
|
||||||
|
import { HeroSkillsCardV1 } from "./HeroSkillsCardV1.mjs";
|
||||||
|
import { HeroSummaryCardV1 } from "./HeroSummaryCardV1.mjs";
|
||||||
|
import { Logger } from "../../utils/Logger.mjs";
|
||||||
|
|
||||||
|
const { HandlebarsApplicationMixin } = foundry.applications.api;
|
||||||
|
const { ActorSheetV2 } = foundry.applications.sheets;
|
||||||
|
|
||||||
|
export class TabbedHeroSheet extends GenericAppMixin(HandlebarsApplicationMixin(ActorSheetV2)) {
|
||||||
|
|
||||||
|
// #region Options
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: [
|
||||||
|
`ripcrypt--actor`,
|
||||||
|
`ripcrypt--TabbedHeroSheet`,
|
||||||
|
],
|
||||||
|
position: {
|
||||||
|
width: `auto`,
|
||||||
|
height: `auto`,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
resizable: false,
|
||||||
|
},
|
||||||
|
actions: {},
|
||||||
|
form: {
|
||||||
|
submitOnChange: true,
|
||||||
|
closeOnSubmit: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static PARTS = {
|
||||||
|
nav: {
|
||||||
|
template: filePath(`templates/Apps/TabbedHeroSheet/tabs.hbs`),
|
||||||
|
},
|
||||||
|
summary: {
|
||||||
|
template: filePath(`templates/Apps/HeroSummaryCardV1/content.hbs`),
|
||||||
|
},
|
||||||
|
skills: {
|
||||||
|
template: filePath(`templates/Apps/HeroSkillsCardV1/content.hbs`),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Instance Data
|
||||||
|
#tabs = {
|
||||||
|
root: `HeroSummaryCardV1`,
|
||||||
|
};
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Lifecycle
|
||||||
|
async _onRender(context, options) {
|
||||||
|
await super._onRender(context, options);
|
||||||
|
|
||||||
|
const summaryElement = this.element.querySelector(`.HeroSummaryCardV1`);
|
||||||
|
HeroSummaryCardV1._onRender(
|
||||||
|
context,
|
||||||
|
{
|
||||||
|
...options,
|
||||||
|
element: summaryElement,
|
||||||
|
isEditable: this.isEditable,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const skillsElement = this.element.querySelector(`.HeroSkillsCardV1`);
|
||||||
|
HeroSkillsCardV1._onRender.bind(this)(
|
||||||
|
context,
|
||||||
|
{
|
||||||
|
...options,
|
||||||
|
element: skillsElement,
|
||||||
|
isEditable: this.isEditable,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const craftsElement = this.element.querySelector(`.crafts-summary`);
|
||||||
|
HeroCraftCardV1._onRender.bind(this)(
|
||||||
|
context,
|
||||||
|
{
|
||||||
|
...options,
|
||||||
|
element: craftsElement,
|
||||||
|
isEditable: this.isEditable,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
async _preparePartContext(partId, ctx, opts) {
|
||||||
|
ctx = await super._preparePartContext(partId, ctx, opts);
|
||||||
|
ctx.actor = this.document;
|
||||||
|
|
||||||
|
ctx.classes = {
|
||||||
|
tab: true,
|
||||||
|
visible: false,
|
||||||
|
};
|
||||||
|
ctx.attrs = {};
|
||||||
|
|
||||||
|
|
||||||
|
let tabName;
|
||||||
|
switch (partId) {
|
||||||
|
case `summary`: {
|
||||||
|
tabName = `HeroSummaryCardV1`;
|
||||||
|
ctx = await HeroSummaryCardV1.prepareGuts(ctx);
|
||||||
|
ctx = await HeroSummaryCardV1.prepareWeapons(ctx);
|
||||||
|
ctx = await HeroSummaryCardV1.prepareArmor(ctx);
|
||||||
|
ctx = await HeroSummaryCardV1.prepareFatePath(ctx);
|
||||||
|
ctx = await HeroSummaryCardV1.prepareAbilityRow(ctx);
|
||||||
|
ctx = await HeroSummaryCardV1.prepareSpeed(ctx);
|
||||||
|
ctx = await HeroSummaryCardV1.prepareLevelData(ctx);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
case `skills`: {
|
||||||
|
tabName = `HeroSkillsCardV1`;
|
||||||
|
ctx = await HeroSkillsCardV1.prepareGear(ctx);
|
||||||
|
ctx = await HeroSkillsCardV1.prepareAmmo(ctx);
|
||||||
|
ctx = await HeroSkillsCardV1.prepareSkills(ctx);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
case `craft`: {
|
||||||
|
tabName = `HeroCraftCardV1`;
|
||||||
|
ctx = await HeroCraftCardV1.prepareCraft(ctx);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (tabName) {
|
||||||
|
ctx.attrs[`data-tab`] = tabName;
|
||||||
|
ctx.attrs[`data-group`] = `root`;
|
||||||
|
ctx.classes.visible = this.#tabs.root === tabName;
|
||||||
|
};
|
||||||
|
|
||||||
|
Logger.debug(`Context keys:`, Object.keys(ctx));
|
||||||
|
return ctx;
|
||||||
|
};
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Actions
|
||||||
|
// #endregion
|
||||||
|
};
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
import { handlebarsLocalizer, localizer } from "../utils/Localizer.mjs";
|
import { handlebarsLocalizer, localizer } from "../utils/Localizer.mjs";
|
||||||
import { formFields } from "./inputs/formFields.mjs";
|
import { formFields } from "./inputs/formFields.mjs";
|
||||||
import { options } from "./options.mjs";
|
import { options } from "./options.mjs";
|
||||||
|
import { toAttributes } from "./toAttributes.mjs";
|
||||||
|
import { toClasses } from "./toClasses.mjs";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
// #region Complex
|
// #region Complex
|
||||||
"rc-formFields": formFields,
|
"rc-formFields": formFields,
|
||||||
"rc-i18n": handlebarsLocalizer,
|
"rc-i18n": handlebarsLocalizer,
|
||||||
"rc-options": options,
|
"rc-options": options,
|
||||||
|
"rc-toAttributes": toAttributes,
|
||||||
|
"rc-toClasses": toClasses,
|
||||||
|
|
||||||
// #region Simple
|
// #region Simple
|
||||||
"rc-empty-state": (v) => v ?? localizer(`RipCrypt.common.empty`),
|
"rc-empty-state": (v) => v ?? localizer(`RipCrypt.common.empty`),
|
||||||
|
|
|
||||||
13
module/handlebarHelpers/toAttributes.mjs
Normal file
13
module/handlebarHelpers/toAttributes.mjs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
/**
|
||||||
|
* Allows converting an object of <attribute names, value> into HTML
|
||||||
|
* attribute-value pairs that can be inserted into the DOM
|
||||||
|
*
|
||||||
|
* @param {Record<string, any>} obj The object of attributes to their value
|
||||||
|
*/
|
||||||
|
export function toAttributes(obj = {}) {
|
||||||
|
let attributes = [];
|
||||||
|
for (const [ attr, value] of Object.entries(obj)) {
|
||||||
|
attributes.push(`${attr}=${Handlebars.escapeExpression(value)}`);
|
||||||
|
};
|
||||||
|
return new Handlebars.SafeString(attributes.join(` `));
|
||||||
|
};
|
||||||
14
module/handlebarHelpers/toClasses.mjs
Normal file
14
module/handlebarHelpers/toClasses.mjs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
/**
|
||||||
|
* Allows converting an object of <class names, boolean-likes> into an HTML-compatible class list.
|
||||||
|
*
|
||||||
|
* @param {Record<string, any>} obj The object of class names to boolean-like values for if that class should be included.
|
||||||
|
*/
|
||||||
|
export function toClasses(obj = {}) {
|
||||||
|
let classes = [];
|
||||||
|
for (const [ klass, include ] of Object.entries(obj)) {
|
||||||
|
if (include) {
|
||||||
|
classes.push(klass);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return new Handlebars.SafeString(classes.join(` `));
|
||||||
|
};
|
||||||
|
|
@ -4,6 +4,7 @@ import { CombinedHeroSheet } from "../Apps/ActorSheets/CombinedHeroSheet.mjs";
|
||||||
import { DelveTourApp } from "../Apps/DelveTourApp.mjs";
|
import { DelveTourApp } from "../Apps/DelveTourApp.mjs";
|
||||||
import { HeroSkillsCardV1 } from "../Apps/ActorSheets/HeroSkillsCardV1.mjs";
|
import { HeroSkillsCardV1 } from "../Apps/ActorSheets/HeroSkillsCardV1.mjs";
|
||||||
import { HeroSummaryCardV1 } from "../Apps/ActorSheets/HeroSummaryCardV1.mjs";
|
import { HeroSummaryCardV1 } from "../Apps/ActorSheets/HeroSummaryCardV1.mjs";
|
||||||
|
import { TabbedHeroSheet } from "../Apps/ActorSheets/TabbedHeroSheet.mjs";
|
||||||
|
|
||||||
// Data Models
|
// Data Models
|
||||||
import { AmmoData } from "../data/Item/Ammo.mjs";
|
import { AmmoData } from "../data/Item/Ammo.mjs";
|
||||||
|
|
@ -69,6 +70,12 @@ Hooks.once(`init`, () => {
|
||||||
label: `RipCrypt.sheet-names.CombinedHeroSheet`,
|
label: `RipCrypt.sheet-names.CombinedHeroSheet`,
|
||||||
themes: CombinedHeroSheet.themes,
|
themes: CombinedHeroSheet.themes,
|
||||||
});
|
});
|
||||||
|
Actors.registerSheet(game.system.id, TabbedHeroSheet, {
|
||||||
|
makeDefault: false,
|
||||||
|
types: [`hero`],
|
||||||
|
label: `RipCrypt.sheet-names.TabbedHeroSheet`,
|
||||||
|
themes: TabbedHeroSheet.themes,
|
||||||
|
});
|
||||||
Actors.registerSheet(game.system.id, HeroSummaryCardV1, {
|
Actors.registerSheet(game.system.id, HeroSummaryCardV1, {
|
||||||
types: [`hero`],
|
types: [`hero`],
|
||||||
label: `RipCrypt.sheet-names.HeroSummaryCardV1`,
|
label: `RipCrypt.sheet-names.HeroSummaryCardV1`,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="HeroSkillsCardV1">
|
<div class="HeroSkillsCardV1 {{ rc-toClasses classes }}" {{ rc-toAttributes attrs }}>
|
||||||
<div class="label col-header list-header gait-skills-header">
|
<div class="label col-header list-header gait-skills-header">
|
||||||
<span>{{ rc-i18n "RipCrypt.Apps.grit-skills" }}</span>
|
<span>{{ rc-i18n "RipCrypt.Apps.grit-skills" }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="HeroSummaryCardV1">
|
<div class="HeroSummaryCardV1 {{ rc-toClasses classes }}" {{ rc-toAttributes attrs }}>
|
||||||
{{!-- * Header --}}
|
{{!-- * Header --}}
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="image">Logo Image</div>
|
<div class="image">Logo Image</div>
|
||||||
|
|
|
||||||
9
templates/Apps/TabbedHeroSheet/style.css
Normal file
9
templates/Apps/TabbedHeroSheet/style.css
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
.ripcrypt.ripcrypt--TabbedHeroSheet {
|
||||||
|
> .window-content {
|
||||||
|
gap: 4px;
|
||||||
|
background: var(--base-background);
|
||||||
|
> .tab:not(.visible) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
templates/Apps/TabbedHeroSheet/tabs.hbs
Normal file
26
templates/Apps/TabbedHeroSheet/tabs.hbs
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<nav>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
data-action="tab"
|
||||||
|
data-group="root"
|
||||||
|
data-tab="HeroSummaryCardV1"
|
||||||
|
>
|
||||||
|
Stats
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
data-action="tab"
|
||||||
|
data-group="root"
|
||||||
|
data-tab="HeroSkillsCardV1"
|
||||||
|
>
|
||||||
|
Skills
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
data-action="tab"
|
||||||
|
data-group="root"
|
||||||
|
data-tab="HeroCraftCardV1"
|
||||||
|
>
|
||||||
|
Craft
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
|
@ -5,3 +5,4 @@
|
||||||
@import url("./HeroSummaryCardV1/style.css");
|
@import url("./HeroSummaryCardV1/style.css");
|
||||||
@import url("./HeroSkillsCardV1/style.css");
|
@import url("./HeroSkillsCardV1/style.css");
|
||||||
@import url("./RichEditor/style.css");
|
@import url("./RichEditor/style.css");
|
||||||
|
@import url("./TabbedHeroSheet/style.css");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue