feat: Loksyu & TinJi standalone AppV2 apps with chat buttons and dice automation

- CDELoksyuApp: standalone HandlebarsApplicationMixin(ApplicationV2) app
  - 5-element Wu Xing grid with yin/yang inputs per element
  - Per-element reset buttons + global reset-all
  - Auto-refresh via updateActor hook

- CDETinjiApp: standalone AppV2 for the collective Tin Ji dice pool
  - Large neon counter with +/- buttons and direct input
  - Spend button sends a chat message with remaining count

- singletons.js: shared utilities
  - getSingletonActor: find or auto-create singleton actor
  - updateLoksyuFromRoll: compute lokAspect from Wu Xing cycle, update yin/yang
  - updateTinjiFromRoll: add tinji face count to value

- rolling.js: auto-update both singletons after every dice roll
  (weapon path + main roll path)

- system.js: renderChatLog hook injects Loksyu/TinJi footer buttons
  in the chat sidebar

- loksyu.js / tinji.js: actor sheets redirect to standalone apps
  when opened via the sidebar

- CSS: .cde-loksyu-standalone, .cde-tinji-standalone, .cde-chat-app-buttons,
  .cde-tinji-spend-msg styles added

- i18n: new keys in fr-cde.json and en-cde.json for all new UI strings
  (LoksyuNotFound, TinjiNotFound, Reset, ResetAll, SpendTinji, etc.)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-03-30 09:51:39 +02:00
parent 6fda4b9246
commit 0689fae792
41 changed files with 1558 additions and 13 deletions

View File

@@ -11,6 +11,8 @@ import { registerHandlebarsHelpers } from "./ui/helpers.js"
import { preloadPartials } from "./ui/templates.js"
import { CDELoksyuSheet, CDECharacterSheet, CDENpcSheet, CDETinjiSheet } from "./ui/sheets/actors/index.js"
import { CDEItemSheet, CDEKungfuSheet, CDESpellSheet, CDESupernaturalSheet, CDEWeaponSheet, CDEArmorSheet, CDESanheiSheet, CDEIngredientSheet } from "./ui/sheets/items/index.js"
import { CDELoksyuApp } from "./ui/apps/loksyu-app.js"
import { CDETinjiApp } from "./ui/apps/tinji-app.js"
import { migrateIfNeeded, registerSettings } from "./migration.js"
Hooks.once("i18nInit", preLocalizeConfig)
@@ -122,6 +124,28 @@ Hooks.once("ready", async () => {
await migrateIfNeeded()
})
/** Add Loksyu + Tin Ji quick-access buttons to the chat footer */
Hooks.on("renderChatLog", (_app, html) => {
const el = html instanceof HTMLElement ? html : html[0]
const controls = el?.querySelector?.(".chat-controls")
if (!controls) return
const wrapper = document.createElement("div")
wrapper.classList.add("cde-chat-app-buttons")
wrapper.innerHTML = `
<button class="cde-chat-btn cde-chat-btn--loksyu" title="${game.i18n.localize("CDE.Loksyu")}">
<i class="fas fa-yin-yang"></i> ${game.i18n.localize("CDE.Loksyu")}
</button>
<button class="cde-chat-btn cde-chat-btn--tinji" title="${game.i18n.localize("CDE.TinJi2")}">
<i class="fas fa-star"></i> ${game.i18n.localize("CDE.TinJi2")}
</button>
`
controls.appendChild(wrapper)
wrapper.querySelector(".cde-chat-btn--loksyu")?.addEventListener("click", () => CDELoksyuApp.open())
wrapper.querySelector(".cde-chat-btn--tinji")?.addEventListener("click", () => CDETinjiApp.open())
})
function injectCompendiumLink(html) {
const header = html[0]?.querySelector?.("h4.divider")
if (!header) return