Create PlayerSheet
This commit is contained in:
parent
e0578d425d
commit
e224f819a3
11 changed files with 252 additions and 0 deletions
86
module/apps/PlayerSheet.mjs
Normal file
86
module/apps/PlayerSheet.mjs
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
import { __ID__, filePath } from "../consts.mjs";
|
||||||
|
|
||||||
|
const { HandlebarsApplicationMixin } = foundry.applications.api;
|
||||||
|
const { ActorSheetV2 } = foundry.applications.sheets;
|
||||||
|
|
||||||
|
export class PlayerSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
|
||||||
|
|
||||||
|
// #region Options
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: [
|
||||||
|
__ID__,
|
||||||
|
`PlayerSheet`,
|
||||||
|
],
|
||||||
|
position: {
|
||||||
|
width: 400,
|
||||||
|
height: 500,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
submitOnChange: true,
|
||||||
|
closeOnSubmit: false,
|
||||||
|
},
|
||||||
|
actions: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
static PARTS = {
|
||||||
|
header: { template: filePath(`templates/PlayerSheet/header.hbs`) },
|
||||||
|
attributes: { template: filePath(`templates/PlayerSheet/attributes.hbs`) },
|
||||||
|
content: { template: filePath(`templates/PlayerSheet/content.hbs`) },
|
||||||
|
};
|
||||||
|
// #endregion Options
|
||||||
|
|
||||||
|
// #region Lifecycle
|
||||||
|
// #endregion Lifecycle
|
||||||
|
|
||||||
|
// #region Data Prep
|
||||||
|
async _preparePartContext(partID) {
|
||||||
|
let ctx = {
|
||||||
|
actor: this.actor,
|
||||||
|
system: this.actor.system,
|
||||||
|
editable: this.isEditable,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (partID) {
|
||||||
|
case `attributes`: {
|
||||||
|
await this._prepareAttributes(ctx);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
case `content`: {
|
||||||
|
await this._prepareContent(ctx);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
async _prepareAttributes(ctx) {
|
||||||
|
ctx.hasAttributes = this.actor.system.hasAttributes;
|
||||||
|
|
||||||
|
const attrs = [];
|
||||||
|
for (const [id, data] of Object.entries(this.actor.system.attr)) {
|
||||||
|
attrs.push({
|
||||||
|
...data,
|
||||||
|
id,
|
||||||
|
path: `system.attr.${id}`,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
ctx.attrs = attrs.toSorted((a, b) => a.name.localeCompare(b.name));
|
||||||
|
};
|
||||||
|
|
||||||
|
async _prepareContent(ctx) {
|
||||||
|
const TextEditor = foundry.applications.ux.TextEditor.implementation;
|
||||||
|
ctx.enriched = {
|
||||||
|
system: {
|
||||||
|
content: await TextEditor.enrichHTML(this.actor.system.content),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// #endregion Data Prep
|
||||||
|
|
||||||
|
// #region Actions
|
||||||
|
// #endregion Actions
|
||||||
|
};
|
||||||
60
styles/Apps/PlayerSheet.css
Normal file
60
styles/Apps/PlayerSheet.css
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
.taf.PlayerSheet {
|
||||||
|
> .window-content {
|
||||||
|
padding: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sheet-header, fieldset, .content {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid rebeccapurple;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-content > header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attributes {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-around;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attr-range {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
width: 100px;
|
||||||
|
|
||||||
|
> input {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&:not(:has(> prose-mirror)) {
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prose-mirror {
|
||||||
|
height: 100%;
|
||||||
|
background: var(--color-cool-5);
|
||||||
|
|
||||||
|
menu {
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
styles/elements/headers.css
Normal file
5
styles/elements/headers.css
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
.taf > .window-content {
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
6
styles/elements/input.css
Normal file
6
styles/elements/input.css
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
.taf > .window-content input {
|
||||||
|
&.large {
|
||||||
|
--input-height: 2.5rem;
|
||||||
|
font-size: 1.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
styles/elements/p.css
Normal file
9
styles/elements/p.css
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
.taf > .window-content p {
|
||||||
|
&:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
5
styles/elements/prose-mirror.css
Normal file
5
styles/elements/prose-mirror.css
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
.taf > .window-content prose-mirror {
|
||||||
|
.editor-content {
|
||||||
|
padding: 0 8px 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
@layer resets, elements, components, partials, apps, exceptions;
|
||||||
|
|
||||||
|
/* Resets */
|
||||||
|
|
||||||
|
/* Elements */
|
||||||
|
@import url("./elements/headers.css") layer(elements);
|
||||||
|
@import url("./elements/input.css") layer(elements);
|
||||||
|
@import url("./elements/p.css") layer(elements);
|
||||||
|
@import url("./elements/prose-mirror.css") layer(elements);
|
||||||
|
|
||||||
|
/* Apps */
|
||||||
|
@import url("./Apps/PlayerSheet.css") layer(apps);
|
||||||
5
styles/resets/inputs.css
Normal file
5
styles/resets/inputs.css
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
.taf > .window-content {
|
||||||
|
button, input {
|
||||||
|
all: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
templates/PlayerSheet/attributes.hbs
Normal file
32
templates/PlayerSheet/attributes.hbs
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
{{#if hasAttributes}}
|
||||||
|
<div class="attributes">
|
||||||
|
{{#each attrs as | attr |}}
|
||||||
|
<fieldset>
|
||||||
|
<legend>
|
||||||
|
{{ attr.name }}
|
||||||
|
</legend>
|
||||||
|
<div class="attr-range">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="attr-range__value"
|
||||||
|
name="{{attr.path}}.value"
|
||||||
|
value="{{attr.value}}"
|
||||||
|
aria-label="Current value"
|
||||||
|
>
|
||||||
|
{{#if attr.isRange}}
|
||||||
|
<span aria-hidden="true">/</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="attr-range__max"
|
||||||
|
name="{{attr.path}}.max"
|
||||||
|
value="{{attr.max}}"
|
||||||
|
aria-label="Maximum value"
|
||||||
|
>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<template />
|
||||||
|
{{/if}}
|
||||||
16
templates/PlayerSheet/content.hbs
Normal file
16
templates/PlayerSheet/content.hbs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<div class="content">
|
||||||
|
{{log this}}
|
||||||
|
{{#if editable}}
|
||||||
|
<prose-mirror
|
||||||
|
class="actor-text"
|
||||||
|
name="system.content"
|
||||||
|
value="{{system.content}}"
|
||||||
|
collaborate="true"
|
||||||
|
data-document-uuid="{{actor.uuid}}"
|
||||||
|
>
|
||||||
|
{{{ enriched.system.content }}}
|
||||||
|
</prose-mirror>
|
||||||
|
{{else}}
|
||||||
|
{{{ enriched.system.content }}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
16
templates/PlayerSheet/header.hbs
Normal file
16
templates/PlayerSheet/header.hbs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<header class="sheet-header">
|
||||||
|
<img
|
||||||
|
src="{{actor.img}}"
|
||||||
|
data-action="editImage"
|
||||||
|
title="{{actor.name}}"
|
||||||
|
height="64"
|
||||||
|
width="64"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
class="large"
|
||||||
|
value="{{actor.name}}"
|
||||||
|
placeholder="{{ localize 'Name' }}"
|
||||||
|
/>
|
||||||
|
</header>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue