From a242101b5b4609680e38b726e19c23573f2ef70a Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 9 Nov 2025 00:31:04 -0700 Subject: [PATCH] Begin working on the QueryStatus application for the requestor to monitor user responses --- module/api.mjs | 2 + module/apps/QueryStatus.mjs | 75 +++++++++++++++++++++++++++++++++ module/utils/QueryManager.mjs | 11 +++++ styles/elements/span.css | 44 +++++++++++++++++++ styles/main.css | 1 + templates/QueryStatus/users.hbs | 21 +++++++++ 6 files changed, 154 insertions(+) create mode 100644 module/apps/QueryStatus.mjs create mode 100644 styles/elements/span.css create mode 100644 templates/QueryStatus/users.hbs diff --git a/module/api.mjs b/module/api.mjs index 8655eb3..dc38c3d 100644 --- a/module/api.mjs +++ b/module/api.mjs @@ -2,6 +2,7 @@ import { Ask } from "./apps/Ask.mjs"; import { AttributeManager } from "./apps/AttributeManager.mjs"; import { PlayerSheet } from "./apps/PlayerSheet.mjs"; +import { QueryStatus } from "./apps/QueryStatus.mjs"; // Utils import { attributeSorter } from "./utils/attributeSort.mjs"; @@ -22,6 +23,7 @@ Object.defineProperty( Ask, AttributeManager, PlayerSheet, + QueryStatus, }, utils: { attributeSorter, diff --git a/module/apps/QueryStatus.mjs b/module/apps/QueryStatus.mjs new file mode 100644 index 0000000..bcae4ce --- /dev/null +++ b/module/apps/QueryStatus.mjs @@ -0,0 +1,75 @@ +import { __ID__, filePath } from "../consts.mjs"; +import { QueryManager } from "../utils/QueryManager.mjs"; + +const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; + +export class QueryStatus extends HandlebarsApplicationMixin(ApplicationV2) { + // #region Options + static DEFAULT_OPTIONS = { + classes: [ + __ID__, + `QueryStatus`, + ], + }; + + static PARTS = { + users: { + template: filePath(`templates/QueryStatus/users.hbs`), + }, + // controls: { + // template: filePath(`templates/QueryStatus/controls.hbs`), + // }, + }; + // #endregion Options + + // #region Instance + constructor({ + requestID, + ...opts + }) { + super(opts); + this.requestID = requestID; + }; + // #endregion Instance + + // #region Lifecycle + async _preparePartContext(partID) { + const ctx = {}; + + switch (partID) { + case `users`: { + this._prepareUsers(ctx); + break; + }; + case `controls`: { + this._prepareControls(ctx); + break; + }; + }; + + return ctx; + }; + + async _prepareUsers(ctx) { + const query = QueryManager.get(this.requestID); + if (!query) { return }; + + const users = []; + for (const userID of query.users) { + const user = game.users.get(userID); + users.push({ + id: userID, + name: user.name, + colour: user.color, + answers: query.responses[userID] ?? null, + }); + }; + ctx.users = users; + }; + + async _prepareControls(ctx) {}; + // #endregion Lifecycle + + // #region Actions + // #endregion Actions +}; diff --git a/module/utils/QueryManager.mjs b/module/utils/QueryManager.mjs index b56b813..35ece0a 100644 --- a/module/utils/QueryManager.mjs +++ b/module/utils/QueryManager.mjs @@ -26,6 +26,17 @@ export class QueryManager { return this.#queries.has(requestID); }; + static get(requestID) { + if (!this.#queries.has(requestID)) { return null }; + const query = this.#queries.get(requestID); + const cloned = foundry.utils.deepClone(query); + + delete cloned.onSubmit; + delete cloned.resolve; + + return cloned; + }; + static async query( request, { diff --git a/styles/elements/span.css b/styles/elements/span.css new file mode 100644 index 0000000..da5c58a --- /dev/null +++ b/styles/elements/span.css @@ -0,0 +1,44 @@ +@keyframes rotate { + 0% { transform: rotate(0deg); } + 50% { transform: rotate(360deg); } + 100% { transform: rotate(720deg); } +} + +@keyframes prixClipFix { + 0%, 100% { + clip-path: polygon(50% 50%,0 0,0 0,0 0,0 0,0 0); + } + 25%, 63% { + clip-path: polygon(50% 50%,0 0,100% 0,100% 0,100% 0,100% 0); + } + 37%, 50% { + clip-path: polygon(50% 50%,0 0,100% 0,100% 100%,100% 100%,100% 100%); + } +} + +.taf > .window-content span { + &.loader { + width: 48px; + height: 48px; + border-radius: 50%; + position: relative; + animation: rotate 2s linear infinite; + display: block; + + &::before, &::after { + content: ""; + box-sizing: border-box; + position: absolute; + inset: 0px; + border-radius: 50%; + border: 5px solid #FFF; + animation: prixClipFix 4s linear infinite; + } + + &::after{ + inset: 8px; + transform: rotate3d(90, 90, 0, 180deg ); + border-color: #FF3D00; /* This can be the user colour */ + } + } +} diff --git a/styles/main.css b/styles/main.css index 40f4ed2..28a27a4 100644 --- a/styles/main.css +++ b/styles/main.css @@ -14,6 +14,7 @@ @import url("./elements/input.css") layer(elements); @import url("./elements/p.css") layer(elements); @import url("./elements/prose-mirror.css") layer(elements); +@import url("./elements/span.css") layer(elements); @import url("./elements/table.css") layer(elements); /* Apps */ diff --git a/templates/QueryStatus/users.hbs b/templates/QueryStatus/users.hbs new file mode 100644 index 0000000..ca9049f --- /dev/null +++ b/templates/QueryStatus/users.hbs @@ -0,0 +1,21 @@ +