diff --git a/module/apps/AttributeItemSheet.mjs b/module/apps/AttributeItemSheet.mjs
new file mode 100644
index 0000000..d39b3f0
--- /dev/null
+++ b/module/apps/AttributeItemSheet.mjs
@@ -0,0 +1,75 @@
+import { __ID__, filePath } from "../consts.mjs";
+import { TAFDocumentSheetMixin } from "./mixins/TAFDocumentSheetMixin.mjs";
+
+const { HandlebarsApplicationMixin } = foundry.applications.api;
+const { ItemSheetV2 } = foundry.applications.sheets;
+const { setProperty } = foundry.utils;
+
+export class AttributeItemSheet extends
+ TAFDocumentSheetMixin(
+ HandlebarsApplicationMixin(
+ ItemSheetV2,
+)) {
+ // #region Options
+ static DEFAULT_OPTIONS = {
+ classes: [
+ __ID__,
+ `AttributeItemSheet`,
+ ],
+ position: {
+ width: 350,
+ height: `auto`,
+ },
+ window: {
+ resizable: true,
+ },
+ form: {
+ submitOnChange: true,
+ closeOnSubmit: false,
+ },
+ actions: {},
+ };
+
+ static PARTS = {
+ header: { template: filePath(`templates/AttributeItemSheet/header.hbs`) },
+ value: { template: filePath(`templates/AttributeItemSheet/value.hbs`) },
+ settings: { template: filePath(`templates/AttributeItemSheet/settings.hbs`) },
+ };
+
+ /**
+ * This tells the Application's TAFDocumentSheetMixin how to rerender
+ * this app when specific properties get changed on the actor, so that
+ * it doesn't need to full-app rendering if we can do a partial
+ * rerender instead.
+ */
+ static PROPERTY_TO_PARTIAL = {
+ "name": [`header`],
+ "system.value": [`value`],
+ "system.min": [`value`],
+ "system.max": [`value`],
+ "system.aboveTheFold": [`settings`],
+ "system.group": [`settings`],
+ "system.key": [`settings`],
+ };
+ // #endregion Options
+
+ // #region Instance Data
+ // #endregion Instance Data
+
+ // #region Lifecycle
+ async _prepareContext() {
+ return {
+ meta: {
+ idp: this.id,
+ editable: this.isEditable,
+ limited: this.isLimited,
+ },
+ item: this.item,
+ system: this.item.system,
+ };
+ };
+ // #endregion Lifecycle
+
+ // #region Actions
+ // #endregion Actions
+};
diff --git a/module/hooks/init.mjs b/module/hooks/init.mjs
index 995b6fb..54190fc 100644
--- a/module/hooks/init.mjs
+++ b/module/hooks/init.mjs
@@ -1,4 +1,5 @@
// Apps
+import { AttributeItemSheet } from "../apps/AttributeItemSheet.mjs";
import { AttributeOnlyPlayerSheet } from "../apps/AttributeOnlyPlayerSheet.mjs";
import { GenericItemSheet } from "../apps/GenericItemSheet.mjs";
import { PlayerSheet } from "../apps/PlayerSheet.mjs";
@@ -68,6 +69,15 @@ Hooks.on(`init`, () => {
label: `taf.sheet-names.GenericItemSheet`,
},
);
+ foundry.documents.collections.Items.registerSheet(
+ __ID__,
+ AttributeItemSheet,
+ {
+ types: [`attribute`],
+ makeDefault: true,
+ label: `taf.sheet-names.AttributeItemSheet`,
+ },
+ );
// #endregion Sheets
registerWorldSettings();
diff --git a/styles/Apps/AttributeItemSheet.css b/styles/Apps/AttributeItemSheet.css
new file mode 100644
index 0000000..6253b6a
--- /dev/null
+++ b/styles/Apps/AttributeItemSheet.css
@@ -0,0 +1,56 @@
+.taf.AttributeItemSheet {
+ min-width: 300px;
+
+ > .window-content {
+ padding: 0;
+ color: var(--attribute-sheet-colour);
+ background: var(--attribute-sheet-background);
+ }
+
+ .sheet-header {
+ padding: 0.5rem;
+ border-bottom: 1px solid var(--attribute-sheet-divider-colour);
+ }
+
+ .value-controls {
+ display: grid;
+ align-items: center;
+ grid-auto-flow: column;
+ grid-template-columns: repeat(3, 1fr);
+ grid-template-rows: repeat(2, auto);
+ gap: 2px 4px;
+ padding: 0 8px;
+ }
+
+ .property {
+ display: grid;
+ align-items: center;
+ justify-items: left;
+ grid-template-columns: 2fr 1fr;
+ gap: 2px 8px;
+ margin: 0 8px 8px;
+
+ .hint {
+ grid-column: 1 / -1;
+ margin: 0;
+ color: var(--attribute-sheet-hint-colour);
+ }
+ }
+
+ input {
+ color: var(--attribute-sheet-input-colour);
+ background: var(--attribute-sheet-input-background);
+
+ &:disabled {
+ color: var(--attribute-sheet-disabled-input-colour);
+ cursor: not-allowed;
+ }
+ }
+
+ taf-toggle {
+ --toggle-background: var(--attribute-sheet-input-background);
+ --slider-checked-colour: var(--attribute-sheet-toggle-slider-enabled-colour);
+ --slider-unchecked-colour: var(--attribute-sheet-toggle-slider-disabled-colour);
+ justify-self: right;
+ }
+}
diff --git a/styles/main.css b/styles/main.css
index 49e4763..be8ba70 100644
--- a/styles/main.css
+++ b/styles/main.css
@@ -26,6 +26,7 @@
/* Apps */
@import url("./Apps/common.css") layer(apps);
@import url("./Apps/Ask.css") layer(apps);
+@import url("./Apps/AttributeItemSheet.css") layer(apps);
@import url("./Apps/AttributeManager.css") layer(apps);
@import url("./Apps/GenericItemSheet.css") layer(apps);
@import url("./Apps/PlayerSheet.css") layer(apps);
diff --git a/styles/themes/dark.css b/styles/themes/dark.css
index cba92a8..3d008e2 100644
--- a/styles/themes/dark.css
+++ b/styles/themes/dark.css
@@ -50,6 +50,17 @@
--item-sheet-description-menu-background: var(--steel-700);
--item-sheet-description-content-background: var(--steel-650);
+ /* Attribute Sheet Variables */
+ --attribute-sheet-colour: var(--item-sheet-colour);
+ --attribute-sheet-background: var(--item-sheet-background);
+ --attribute-sheet-divider-colour: var(--item-sheet-divider);
+ --attribute-sheet-hint-colour: var(--steel-250);
+ --attribute-sheet-input-colour: var(--item-sheet-input-colour);
+ --attribute-sheet-input-background: var(--item-sheet-input-background);
+ --attribute-sheet-disabled-input-colour: var(--steel-350);
+ --attribute-sheet-toggle-slider-enabled-colour: var(--item-sheet-toggle-slider-enabled-colour);
+ --attribute-sheet-toggle-slider-disabled-colour: var(--item-sheet-toggle-slider-disabled-colour);
+
/* Chip Variables */
--chip-colour: #fff7ed;
--chip-background: #2b3642;
diff --git a/templates/AttributeItemSheet/header.hbs b/templates/AttributeItemSheet/header.hbs
new file mode 100644
index 0000000..1e540e9
--- /dev/null
+++ b/templates/AttributeItemSheet/header.hbs
@@ -0,0 +1,11 @@
+
+ This is the computer-friendly identifier for the attribute. + When accessing the attribute in rolls, this is the name you will + need to use. Changing this WILL break any existing macros you have. +
+