Fix Layout
This commit is contained in:
parent
db75a89401
commit
4a03a992d0
@ -86,5 +86,9 @@
|
||||
"CONFIGURABLE_REACTIONS.Builder.DropSpellOnTrigger": "Zauber auf diesen Auslöser ziehen, um nach Zaubername zu filtern.",
|
||||
"CONFIGURABLE_REACTIONS.Builder.DropSpellOnAction": "Zauber hier ablegen, um ihn für diese Aktion zu speichern.",
|
||||
"CONFIGURABLE_REACTIONS.Builder.DropSpellCreatesAction": "Ein Zauber kann direkt in den Effekt-Bereich gezogen werden und erzeugt eine passende Zauber-Aktion.",
|
||||
"CONFIGURABLE_REACTIONS.Triggers.SpellFilter": "Zauberfilter: {name}"
|
||||
"CONFIGURABLE_REACTIONS.Triggers.SpellFilter": "Zauberfilter: {name}",
|
||||
"CONFIGURABLE_REACTIONS.Conditions.Damage.SelectedTypes": "Gewählte Schadenstypen",
|
||||
"CONFIGURABLE_REACTIONS.Conditions.Damage.NoTypes": "Keine Schadenstypen ausgewählt",
|
||||
"CONFIGURABLE_REACTIONS.Conditions.Damage.SelectPlaceholder": "Schadenstyp auswählen",
|
||||
"CONFIGURABLE_REACTIONS.Conditions.Damage.RemoveType": "Schadenstyp entfernen: {type}"
|
||||
}
|
||||
|
||||
@ -86,5 +86,9 @@
|
||||
"CONFIGURABLE_REACTIONS.Builder.DropSpellOnTrigger": "Drop a spell on this trigger to filter by spell name.",
|
||||
"CONFIGURABLE_REACTIONS.Builder.DropSpellOnAction": "Drop a spell here to store it for this action.",
|
||||
"CONFIGURABLE_REACTIONS.Builder.DropSpellCreatesAction": "A spell can be dropped directly into the effect area to create a configured spell action.",
|
||||
"CONFIGURABLE_REACTIONS.Triggers.SpellFilter": "Spell filter: {name}"
|
||||
"CONFIGURABLE_REACTIONS.Triggers.SpellFilter": "Spell filter: {name}",
|
||||
"CONFIGURABLE_REACTIONS.Conditions.Damage.SelectedTypes": "Selected damage types",
|
||||
"CONFIGURABLE_REACTIONS.Conditions.Damage.NoTypes": "No damage types selected",
|
||||
"CONFIGURABLE_REACTIONS.Conditions.Damage.SelectPlaceholder": "Select damage type",
|
||||
"CONFIGURABLE_REACTIONS.Conditions.Damage.RemoveType": "Remove damage type: {type}"
|
||||
}
|
||||
|
||||
@ -18,7 +18,8 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
classes: ["configurable-reactions", "standard-form"],
|
||||
window: {
|
||||
title: "CONFIGURABLE_REACTIONS.App.Title",
|
||||
icon: "fa-solid fa-bolt"
|
||||
icon: "fa-solid fa-bolt",
|
||||
resizable: true
|
||||
},
|
||||
position: {
|
||||
width: 1040,
|
||||
@ -33,6 +34,7 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
removeAction: ConfigurableReactionsConfigApp.#onRemoveAction,
|
||||
saveReactionBasics: ConfigurableReactionsConfigApp.#onSaveReactionBasics,
|
||||
clearTriggerSpell: ConfigurableReactionsConfigApp.#onClearTriggerSpell,
|
||||
removeDamageType: ConfigurableReactionsConfigApp.#onRemoveDamageType,
|
||||
clearActionSpell: ConfigurableReactionsConfigApp.#onClearActionSpell,
|
||||
removeActionStatus: ConfigurableReactionsConfigApp.#onRemoveActionStatus
|
||||
}
|
||||
@ -67,7 +69,12 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
const activeTrigger = triggerPalette.find(t => t.type === selectedReaction?.trigger?.type) ?? null;
|
||||
const triggerSpellName = selectedReaction?.trigger?.spell?.itemName || selectedReaction?.trigger?.spell?.itemUuid || "";
|
||||
const activeTriggerAcceptsSpell = isSpellTrigger(selectedReaction?.trigger?.type);
|
||||
const activeTriggerIsDamage = selectedReaction?.trigger?.type === TRIGGER_TYPES.DAMAGE_RECEIVED;
|
||||
const statusEffects = getStatusEffectOptions();
|
||||
const damageTypes = getDamageTypeOptions();
|
||||
const selectedDamageTypeIds = Array.from(new Set(selectedReaction?.conditions?.damage?.types ?? []));
|
||||
const selectedDamageTypes = selectedDamageTypeIds.map(typeId => resolveDamageType(typeId, damageTypes));
|
||||
const availableDamageTypes = damageTypes.filter(type => !selectedDamageTypeIds.includes(type.id));
|
||||
const visualActions = (selectedReaction?.actions ?? []).map((action, index) => {
|
||||
const paletteEntry = actionPalette.find(p => p.type === action.type);
|
||||
const selectedStatusIds = Array.from(new Set(action.statuses ?? []));
|
||||
@ -101,9 +108,12 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
actionPalette,
|
||||
activeTrigger,
|
||||
activeTriggerAcceptsSpell,
|
||||
activeTriggerIsDamage,
|
||||
triggerSpellName,
|
||||
visualActions,
|
||||
statusEffects
|
||||
statusEffects,
|
||||
selectedDamageTypes,
|
||||
availableDamageTypes
|
||||
};
|
||||
}
|
||||
|
||||
@ -115,7 +125,10 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
this.render({ force: true });
|
||||
});
|
||||
|
||||
this.#activateJsonEditor();
|
||||
this.#activateBasicsSync();
|
||||
this.#activateStatusSelectors();
|
||||
this.#activateDamageTypeSelector();
|
||||
this.#activateDragAndDrop();
|
||||
}
|
||||
|
||||
@ -130,6 +143,41 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
});
|
||||
}
|
||||
}
|
||||
#activateJsonEditor() {
|
||||
const textarea = this.element.querySelector("[name='reactionJson']");
|
||||
if (!textarea) return;
|
||||
|
||||
textarea.addEventListener("blur", async () => {
|
||||
if (document.activeElement === textarea) return;
|
||||
await this.#saveReactionJsonFromTextarea({ render: true });
|
||||
});
|
||||
}
|
||||
|
||||
#activateBasicsSync() {
|
||||
const nameInput = this.element.querySelector("[name='reactionName']");
|
||||
const enabledInput = this.element.querySelector("[name='reactionEnabled']");
|
||||
|
||||
nameInput?.addEventListener("input", () => this.#syncJsonFromDesignerForm());
|
||||
nameInput?.addEventListener("change", async () => this.#saveBasicsFromDesignerForm());
|
||||
nameInput?.addEventListener("blur", async () => this.#saveBasicsFromDesignerForm());
|
||||
|
||||
enabledInput?.addEventListener("change", async () => {
|
||||
this.#syncJsonFromDesignerForm();
|
||||
await this.#saveBasicsFromDesignerForm();
|
||||
});
|
||||
}
|
||||
|
||||
#activateDamageTypeSelector() {
|
||||
const select = this.element.querySelector("[data-cr-damage-type-select]");
|
||||
if (!select) return;
|
||||
|
||||
select.addEventListener("change", async event => {
|
||||
const damageType = event.currentTarget.value;
|
||||
if (!damageType) return;
|
||||
await this.#addDamageType(damageType);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
#activateDragAndDrop() {
|
||||
for (const draggable of this.element.querySelectorAll("[data-cr-drag]")) {
|
||||
@ -208,29 +256,7 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
}
|
||||
|
||||
static async #onSaveReactionJson(event, target) {
|
||||
const textarea = this.element.querySelector("[name='reactionJson']");
|
||||
if (!textarea) return;
|
||||
|
||||
let reaction;
|
||||
try {
|
||||
reaction = JSON.parse(textarea.value);
|
||||
} catch (error) {
|
||||
ui.notifications.error(game.i18n.localize("CONFIGURABLE_REACTIONS.Errors.InvalidJson"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!reaction.id) reaction.id = foundry.utils.randomID();
|
||||
if (!reaction.name) reaction.name = game.i18n.localize("CONFIGURABLE_REACTIONS.Reactions.NewReaction");
|
||||
reaction.actions ??= [];
|
||||
|
||||
const reactions = foundry.utils.deepClone(game.settings.get(MODULE_ID, SETTINGS.REACTIONS) ?? []);
|
||||
const index = reactions.findIndex(r => r.id === reaction.id);
|
||||
if (index >= 0) reactions[index] = reaction;
|
||||
else reactions.push(reaction);
|
||||
|
||||
await game.settings.set(MODULE_ID, SETTINGS.REACTIONS, reactions);
|
||||
this._selectedReactionId = reaction.id;
|
||||
this.render({ force: true });
|
||||
await this.#saveReactionJsonFromTextarea({ render: true });
|
||||
}
|
||||
|
||||
static async #onDeleteReaction(event, target) {
|
||||
@ -308,16 +334,21 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
});
|
||||
}
|
||||
|
||||
static async #onSaveReactionBasics(event, target) {
|
||||
const name = this.element.querySelector("[name='reactionName']")?.value?.trim();
|
||||
const enabled = this.element.querySelector("[name='reactionEnabled']")?.checked === true;
|
||||
static async #onRemoveDamageType(event, target) {
|
||||
const damageType = target.dataset.damageType;
|
||||
if (!damageType) return;
|
||||
|
||||
await this.#mutateSelectedReaction(reaction => {
|
||||
if (name) reaction.name = name;
|
||||
reaction.enabled = enabled;
|
||||
reaction.conditions ??= {};
|
||||
reaction.conditions.damage ??= {};
|
||||
reaction.conditions.damage.types = (reaction.conditions.damage.types ?? []).filter(type => type !== damageType);
|
||||
});
|
||||
}
|
||||
|
||||
static async #onSaveReactionBasics(event, target) {
|
||||
await this.#saveBasicsFromDesignerForm();
|
||||
}
|
||||
|
||||
async #setTrigger(triggerType) {
|
||||
await this.#mutateSelectedReaction(reaction => {
|
||||
reaction.trigger ??= {};
|
||||
@ -361,12 +392,77 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
});
|
||||
}
|
||||
|
||||
async #addDamageType(damageType) {
|
||||
await this.#mutateSelectedReaction(reaction => {
|
||||
reaction.conditions ??= {};
|
||||
reaction.conditions.damage ??= { enabled: true, amountMode: "damageOnly", types: [], typeMode: "any", minAmount: 1 };
|
||||
reaction.conditions.damage.types ??= [];
|
||||
if (!reaction.conditions.damage.types.includes(damageType)) reaction.conditions.damage.types.push(damageType);
|
||||
});
|
||||
}
|
||||
|
||||
async #saveReactionJsonFromTextarea({ render = true } = {}) {
|
||||
const textarea = this.element.querySelector("[name='reactionJson']");
|
||||
if (!textarea) return false;
|
||||
|
||||
let reaction;
|
||||
try {
|
||||
reaction = JSON.parse(textarea.value);
|
||||
} catch (error) {
|
||||
ui.notifications.error(game.i18n.localize("CONFIGURABLE_REACTIONS.Errors.InvalidJson"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reaction.id) reaction.id = foundry.utils.randomID();
|
||||
if (!reaction.name) reaction.name = game.i18n.localize("CONFIGURABLE_REACTIONS.Reactions.NewReaction");
|
||||
reaction.actions ??= [];
|
||||
|
||||
const reactions = foundry.utils.deepClone(game.settings.get(MODULE_ID, SETTINGS.REACTIONS) ?? []);
|
||||
const index = reactions.findIndex(r => r.id === reaction.id);
|
||||
if (index >= 0) reactions[index] = reaction;
|
||||
else reactions.push(reaction);
|
||||
|
||||
await game.settings.set(MODULE_ID, SETTINGS.REACTIONS, reactions);
|
||||
this._selectedReactionId = reaction.id;
|
||||
if (render) this.render({ force: true });
|
||||
return true;
|
||||
}
|
||||
|
||||
async #saveBasicsFromDesignerForm() {
|
||||
const name = this.element.querySelector("[name='reactionName']")?.value?.trim();
|
||||
const enabled = this.element.querySelector("[name='reactionEnabled']")?.checked === true;
|
||||
|
||||
await this.#mutateSelectedReaction(reaction => {
|
||||
if (name) reaction.name = name;
|
||||
reaction.enabled = enabled;
|
||||
});
|
||||
}
|
||||
|
||||
#syncJsonFromDesignerForm() {
|
||||
const reactions = foundry.utils.deepClone(game.settings.get(MODULE_ID, SETTINGS.REACTIONS) ?? []);
|
||||
const reaction = reactions.find(r => r.id === this._selectedReactionId);
|
||||
if (!reaction) return;
|
||||
|
||||
const name = this.element.querySelector("[name='reactionName']")?.value?.trim();
|
||||
const enabled = this.element.querySelector("[name='reactionEnabled']")?.checked === true;
|
||||
if (name) reaction.name = name;
|
||||
reaction.enabled = enabled;
|
||||
this.#updateJsonTextarea(reaction);
|
||||
}
|
||||
|
||||
#updateJsonTextarea(reaction) {
|
||||
const textarea = this.element.querySelector("[name='reactionJson']");
|
||||
if (!textarea || document.activeElement === textarea) return;
|
||||
textarea.value = JSON.stringify(reaction, null, 2);
|
||||
}
|
||||
|
||||
async #mutateSelectedReaction(mutator) {
|
||||
const reactions = foundry.utils.deepClone(game.settings.get(MODULE_ID, SETTINGS.REACTIONS) ?? []);
|
||||
const reaction = reactions.find(r => r.id === this._selectedReactionId);
|
||||
if (!reaction) return;
|
||||
|
||||
mutator(reaction);
|
||||
this.#updateJsonTextarea(reaction);
|
||||
await game.settings.set(MODULE_ID, SETTINGS.REACTIONS, reactions);
|
||||
this.render({ force: true });
|
||||
}
|
||||
@ -495,6 +591,25 @@ function resolveStatusEffect(statusId, statusEffects = getStatusEffectOptions())
|
||||
};
|
||||
}
|
||||
|
||||
function getDamageTypeOptions() {
|
||||
const damageTypes = CONFIG.DND5E?.damageTypes ?? {};
|
||||
const entries = damageTypes instanceof Map
|
||||
? Array.from(damageTypes.entries())
|
||||
: Object.entries(damageTypes);
|
||||
|
||||
return entries.map(([id, value]) => ({
|
||||
id,
|
||||
label: game.i18n.localize(value?.label ?? value ?? id)
|
||||
})).sort((a, b) => a.label.localeCompare(b.label, game.i18n.lang));
|
||||
}
|
||||
|
||||
function resolveDamageType(typeId, damageTypes = getDamageTypeOptions()) {
|
||||
return damageTypes.find(type => type.id === typeId) ?? {
|
||||
id: typeId,
|
||||
label: typeId
|
||||
};
|
||||
}
|
||||
|
||||
function summarizeAction(action, statusEffects = getStatusEffectOptions()) {
|
||||
switch (action.type) {
|
||||
case ACTION_TYPES.TELEPORT:
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
.configurable-reactions .cr-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 310px 1fr;
|
||||
grid-template-columns: 33% 67%;
|
||||
gap: 1rem;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
@ -27,6 +27,12 @@
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.configurable-reactions .cr-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.configurable-reactions .cr-button-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -86,7 +92,9 @@
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1.35fr;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
flex: 0 0 40%;
|
||||
min-height: 220px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.configurable-reactions .cr-card,
|
||||
@ -100,7 +108,7 @@
|
||||
|
||||
.configurable-reactions .cr-basics {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
grid-template-columns: 1fr auto;
|
||||
align-items: end;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
@ -157,15 +165,17 @@
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.configurable-reactions .cr-main textarea[name="reactionJson"] {
|
||||
width: 100%;
|
||||
min-height: 340px;
|
||||
font-family: var(--font-monospace, monospace);
|
||||
resize: vertical;
|
||||
.configurable-reactions .cr-json-editor {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.configurable-reactions .cr-reaction-summary {
|
||||
margin-bottom: 0.75rem;
|
||||
.configurable-reactions .cr-main textarea[name="reactionJson"] {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 180px;
|
||||
font-family: var(--font-monospace, monospace);
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.configurable-reactions .form-group.stacked {
|
||||
@ -198,21 +208,23 @@
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
.configurable-reactions .cr-status-builder {
|
||||
.configurable-reactions .cr-status-builder,
|
||||
.configurable-reactions .cr-damage-builder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.configurable-reactions .cr-status-label {
|
||||
.configurable-reactions .cr-chip-label {
|
||||
opacity: 0.85;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.configurable-reactions .cr-status-chip-list {
|
||||
.configurable-reactions .cr-chip-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
gap: 0.25rem;
|
||||
min-height: 1.6rem;
|
||||
padding: 0.25rem;
|
||||
@ -221,38 +233,45 @@
|
||||
background: rgb(0 0 0 / 0.08);
|
||||
}
|
||||
|
||||
.configurable-reactions .cr-status-chip {
|
||||
.configurable-reactions .cr-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
max-width: 100%;
|
||||
padding: 0.15rem 0.25rem 0.15rem 0.35rem;
|
||||
padding: 0.12rem 0.2rem 0.12rem 0.35rem;
|
||||
border: 1px solid var(--color-border-light-secondary, #777);
|
||||
border-radius: 999px;
|
||||
background: rgb(0 0 0 / 0.16);
|
||||
font-size: 0.8rem;
|
||||
font-size: 70%;
|
||||
}
|
||||
|
||||
.configurable-reactions .cr-status-chip img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
.configurable-reactions .cr-chip img {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border: none;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.configurable-reactions .cr-status-chip span {
|
||||
.configurable-reactions .cr-chip span {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.configurable-reactions .cr-status-chip button {
|
||||
width: 1.35rem;
|
||||
min-height: 1.35rem;
|
||||
.configurable-reactions .cr-chip button {
|
||||
width: 1rem;
|
||||
min-height: 1rem;
|
||||
height: 1rem;
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
background: transparent;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
.configurable-reactions .cr-status-builder select {
|
||||
.configurable-reactions .cr-status-builder select,
|
||||
.configurable-reactions .cr-damage-builder select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
@ -78,9 +78,6 @@
|
||||
<label>{{localize "CONFIGURABLE_REACTIONS.Reactions.Enabled"}}</label>
|
||||
<input type="checkbox" name="reactionEnabled" {{#if selectedReaction.enabled}}checked{{/if}}>
|
||||
</div>
|
||||
<button type="button" data-action="saveReactionBasics">
|
||||
<i class="fa-solid fa-floppy-disk"></i> {{localize "CONFIGURABLE_REACTIONS.Common.Apply"}}
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<section class="cr-builder-grid">
|
||||
@ -99,6 +96,32 @@
|
||||
<small class="cr-inline-drop">{{localize "CONFIGURABLE_REACTIONS.Builder.DropSpellOnTrigger"}}</small>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if activeTriggerIsDamage}}
|
||||
<div class="cr-damage-builder">
|
||||
<small class="cr-chip-label">{{localize "CONFIGURABLE_REACTIONS.Conditions.Damage.SelectedTypes"}}</small>
|
||||
<div class="cr-chip-list cr-damage-chip-list">
|
||||
{{#if selectedDamageTypes.length}}
|
||||
{{#each selectedDamageTypes}}
|
||||
<span class="cr-chip cr-damage-chip" title="{{this.label}}">
|
||||
<span>{{this.label}}</span>
|
||||
<button type="button" data-action="removeDamageType" data-damage-type="{{this.id}}" title="{{localize 'CONFIGURABLE_REACTIONS.Conditions.Damage.RemoveType' type=this.label}}">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</button>
|
||||
</span>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<small class="cr-inline-drop">{{localize "CONFIGURABLE_REACTIONS.Conditions.Damage.NoTypes"}}</small>
|
||||
{{/if}}
|
||||
</div>
|
||||
<select data-cr-damage-type-select>
|
||||
<option value="">{{localize "CONFIGURABLE_REACTIONS.Conditions.Damage.SelectPlaceholder"}}</option>
|
||||
{{#each availableDamageTypes}}
|
||||
<option value="{{this.id}}">{{this.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if triggerSpellName}}
|
||||
<button type="button" data-action="clearTriggerSpell" title="{{localize 'CONFIGURABLE_REACTIONS.Common.Remove'}}">
|
||||
@ -132,11 +155,11 @@
|
||||
{{/if}}
|
||||
{{#if this.isStatusAction}}
|
||||
<div class="cr-status-builder">
|
||||
<small class="cr-status-label">{{localize "CONFIGURABLE_REACTIONS.Actions.ApplyStatus.SelectedStatuses"}}</small>
|
||||
<div class="cr-status-chip-list">
|
||||
<small class="cr-chip-label">{{localize "CONFIGURABLE_REACTIONS.Actions.ApplyStatus.SelectedStatuses"}}</small>
|
||||
<div class="cr-chip-list cr-status-chip-list">
|
||||
{{#if this.selectedStatuses.length}}
|
||||
{{#each this.selectedStatuses}}
|
||||
<span class="cr-status-chip" title="{{this.label}}">
|
||||
<span class="cr-chip cr-status-chip" title="{{this.label}}">
|
||||
<img src="{{this.icon}}" alt="">
|
||||
<span>{{this.label}}</span>
|
||||
<button type="button" data-action="removeActionStatus" data-action-index="{{../index}}" data-status-id="{{this.id}}" title="{{localize 'CONFIGURABLE_REACTIONS.Actions.ApplyStatus.RemoveStatus' status=this.label}}">
|
||||
@ -176,23 +199,10 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="cr-reaction-summary">
|
||||
<h3>{{localize "CONFIGURABLE_REACTIONS.Reactions.JsonPreview"}}</h3>
|
||||
<p><strong>ID:</strong> <code>{{selectedReaction.id}}</code></p>
|
||||
<p><strong>{{localize "CONFIGURABLE_REACTIONS.Trigger.Label"}}:</strong> {{selectedReaction.trigger.type}}</p>
|
||||
<p><strong>{{localize "CONFIGURABLE_REACTIONS.Actions.Title"}}:</strong> {{selectedReaction.actions.length}}</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group stacked">
|
||||
<div class="form-group stacked cr-json-editor">
|
||||
<label>{{localize "CONFIGURABLE_REACTIONS.Reactions.JsonEditor"}}</label>
|
||||
<textarea name="reactionJson" spellcheck="false">{{selectedReactionJson}}</textarea>
|
||||
</div>
|
||||
|
||||
<footer class="cr-footer">
|
||||
<button type="button" data-action="saveReactionJson">
|
||||
<i class="fa-solid fa-floppy-disk"></i> {{localize "CONFIGURABLE_REACTIONS.Common.Save"}}
|
||||
</button>
|
||||
</footer>
|
||||
{{else}}
|
||||
<p>{{localize "CONFIGURABLE_REACTIONS.Reactions.None"}}</p>
|
||||
{{/if}}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user