Begin working on the QueryStatus application for the requestor to monitor user responses

This commit is contained in:
Oliver 2025-11-09 00:31:04 -07:00
parent 47b68621c1
commit a242101b5b
6 changed files with 154 additions and 0 deletions

View file

@ -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,

View file

@ -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
};

View file

@ -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,
{

44
styles/elements/span.css Normal file
View file

@ -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 */
}
}
}

View file

@ -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 */

View file

@ -0,0 +1,21 @@
<ul>
{{#each users as | user |}}
<li>
{{ user.name }}
{{#if user.answers}}
<div class="chip-list">
{{#each user.answers as | answer |}}
<span class="chip">
{{ @key }}
<span class="value">
{{ answer }}
</span>
</span>
{{/each}}
</div>
{{else}}
<span class="loader"></span>
{{/if}}
</li>
{{/each}}
</ul>