Compare commits
No commits in common. "main" and "v1.1.6" have entirely different histories.
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidienne",
|
"name": "obsidienne",
|
||||||
"version": "1.1.7",
|
"version": "1.1.6",
|
||||||
"description": "Obsidienne — Minuteur d'élevage Dragodinde pour Dofus 3",
|
"description": "Obsidienne — Minuteur d'élevage Dragodinde pour Dofus 3",
|
||||||
"main": "dist-electron/main.js",
|
"main": "dist-electron/main.js",
|
||||||
"author": "Mickael",
|
"author": "Mickael",
|
||||||
|
|||||||
@ -88,15 +88,6 @@ function toISO(d: Date): string {
|
|||||||
return d.toISOString().slice(0, 10);
|
return d.toISOString().slice(0, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Normalise une date (string ISO, timestamp number, Date object) en string "YYYY-MM-DD". */
|
|
||||||
function normalizeDate(raw: unknown): string {
|
|
||||||
if (!raw) return '';
|
|
||||||
if (typeof raw === 'string') return raw.slice(0, 10);
|
|
||||||
if (typeof raw === 'number') return new Date(raw).toISOString().slice(0, 10);
|
|
||||||
if (raw instanceof Date) return raw.toISOString().slice(0, 10);
|
|
||||||
return String(raw).slice(0, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
function aggregate(entries: AccEntry[]) {
|
function aggregate(entries: AccEntry[]) {
|
||||||
let couples = 0, babies = 0;
|
let couples = 0, babies = 0;
|
||||||
const races = new Set<string>();
|
const races = new Set<string>();
|
||||||
@ -111,61 +102,37 @@ function aggregate(entries: AccEntry[]) {
|
|||||||
|
|
||||||
const WEEKDAY_NAMES = ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'];
|
const WEEKDAY_NAMES = ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'];
|
||||||
|
|
||||||
function emptyResult(days: number): StatisticsResult {
|
|
||||||
const kpi0: KpiDelta = { value: 0, delta: null };
|
|
||||||
const missingRaces: MissingRace[] = Object.entries(RACE_GEN)
|
|
||||||
.filter(([, gen]) => gen !== 1)
|
|
||||||
.map(([name, gen]) => ({ name, gen }))
|
|
||||||
.sort((a, b) => a.gen - b.gen || a.name.localeCompare(b.name));
|
|
||||||
return {
|
|
||||||
totalBabies: kpi0, totalCouples: kpi0, successRate: kpi0, racesCount: kpi0,
|
|
||||||
dailyBirths: [], raceShares: [], raceSuccessRates: [], bestCouples: [],
|
|
||||||
genBreakdown: [], missingRaces, weekdayActivity: [], days,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createGetStatisticsHandler(state: AppState) {
|
export function createGetStatisticsHandler(state: AppState) {
|
||||||
return (query: GetStatisticsQuery): StatisticsResult => {
|
return (query: GetStatisticsQuery): StatisticsResult => {
|
||||||
const days = query.days ?? 30;
|
const days = query.days ?? 30;
|
||||||
try {
|
|
||||||
return computeStatistics(state, days);
|
|
||||||
} catch (e) {
|
|
||||||
console.error('GetStatistics handler error:', e);
|
|
||||||
return emptyResult(days);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function computeStatistics(state: AppState, days: number): StatisticsResult {
|
|
||||||
// Collecter toutes les entrées normalisées (exclure Gen 1 : non créables, seulement capturables)
|
// Collecter toutes les entrées normalisées (exclure Gen 1 : non créables, seulement capturables)
|
||||||
const all: AccEntry[] = [];
|
const all: AccEntry[] = [];
|
||||||
const accouplements = Array.isArray(state.accouplements) ? state.accouplements : [];
|
for (const acc of state.accouplements) {
|
||||||
for (const acc of accouplements) {
|
|
||||||
if (!acc || !acc.baby) continue;
|
|
||||||
if (acc.gen === 1 || (RACE_GEN[acc.baby] ?? 0) === 1) continue;
|
if (acc.gen === 1 || (RACE_GEN[acc.baby] ?? 0) === 1) continue;
|
||||||
all.push({
|
all.push({
|
||||||
parentA: acc.parentA ?? '', parentB: acc.parentB ?? '',
|
parentA: acc.parentA, parentB: acc.parentB,
|
||||||
baby: acc.baby, gen: acc.gen ?? (RACE_GEN[acc.baby] ?? 0),
|
baby: acc.baby, gen: acc.gen,
|
||||||
couples: Number(acc.couples) || 0, babiesObtained: Number(acc.babiesObtained) || 0,
|
couples: acc.couples, babiesObtained: acc.babiesObtained,
|
||||||
date: normalizeDate(acc.date),
|
date: acc.date,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const archivedStats = Array.isArray(state.archivedStats) ? state.archivedStats : [];
|
for (const arch of state.archivedStats as Array<{
|
||||||
for (const arch of archivedStats as Array<{
|
|
||||||
parentA?: string; parentB?: string; baby?: string; gen?: number;
|
parentA?: string; parentB?: string; baby?: string; gen?: number;
|
||||||
couples?: number; babiesObtained?: number; date?: string;
|
couples?: number; babiesObtained?: number; date?: string;
|
||||||
}>) {
|
}>) {
|
||||||
if (!arch || !arch.baby) continue;
|
if (arch.baby) {
|
||||||
const gen = arch.gen ?? (RACE_GEN[arch.baby] ?? 0);
|
const gen = arch.gen ?? (RACE_GEN[arch.baby] ?? 0);
|
||||||
if (gen === 1) continue;
|
if (gen === 1) continue;
|
||||||
all.push({
|
all.push({
|
||||||
parentA: arch.parentA ?? '', parentB: arch.parentB ?? '',
|
parentA: arch.parentA ?? '', parentB: arch.parentB ?? '',
|
||||||
baby: arch.baby, gen,
|
baby: arch.baby, gen,
|
||||||
couples: Number(arch.couples) || 0,
|
couples: arch.couples ?? 0,
|
||||||
babiesObtained: Number(arch.babiesObtained) || 0,
|
babiesObtained: arch.babiesObtained ?? 0,
|
||||||
date: normalizeDate(arch.date),
|
date: arch.date ?? '',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const todayISO = toISO(now);
|
const todayISO = toISO(now);
|
||||||
@ -317,4 +284,5 @@ function computeStatistics(state: AppState, days: number): StatisticsResult {
|
|||||||
weekdayActivity,
|
weekdayActivity,
|
||||||
days,
|
days,
|
||||||
};
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,17 +34,7 @@ if (process.env.ELECTRON_USER_DATA_DIR) {
|
|||||||
if (app.isPackaged) {
|
if (app.isPackaged) {
|
||||||
const oldDataFile = path.join(app.getPath('appData'), 'Minuteur Dragodinde', 'dd-timer-data.json');
|
const oldDataFile = path.join(app.getPath('appData'), 'Minuteur Dragodinde', 'dd-timer-data.json');
|
||||||
const newDataFile = path.join(app.getPath('userData'), 'dd-timer-data.json');
|
const newDataFile = path.join(app.getPath('userData'), 'dd-timer-data.json');
|
||||||
const shouldMigrate = (() => {
|
if (!fs.existsSync(newDataFile) && fs.existsSync(oldDataFile)) {
|
||||||
if (!fs.existsSync(oldDataFile)) return false;
|
|
||||||
if (!fs.existsSync(newDataFile)) return true;
|
|
||||||
// Si le nouveau fichier est quasi-vide (<200 octets = état par défaut), on remigre
|
|
||||||
try {
|
|
||||||
const newSize = fs.statSync(newDataFile).size;
|
|
||||||
const oldSize = fs.statSync(oldDataFile).size;
|
|
||||||
return newSize < 200 && oldSize > newSize;
|
|
||||||
} catch { return false; }
|
|
||||||
})();
|
|
||||||
if (shouldMigrate) {
|
|
||||||
try {
|
try {
|
||||||
fs.mkdirSync(path.dirname(newDataFile), { recursive: true });
|
fs.mkdirSync(path.dirname(newDataFile), { recursive: true });
|
||||||
fs.copyFileSync(oldDataFile, newDataFile);
|
fs.copyFileSync(oldDataFile, newDataFile);
|
||||||
|
|||||||
@ -324,18 +324,8 @@ export class App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Live update loop ──────────────────────────────────────────
|
// ── Live update loop ──────────────────────────────────────────
|
||||||
private lastRafTime = 0;
|
|
||||||
|
|
||||||
private startAnimationLoop(): void {
|
private startAnimationLoop(): void {
|
||||||
const loop = (now: number) => {
|
const loop = () => {
|
||||||
// Throttle à ~4fps quand aucun timer ne tourne (idle)
|
|
||||||
const data = this.getDashboardData();
|
|
||||||
const anyRunning = data.enclosSummaries.some(e => e.running);
|
|
||||||
if (!anyRunning && now - this.lastRafTime < 250) {
|
|
||||||
this.rafId = requestAnimationFrame(loop);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.lastRafTime = now;
|
|
||||||
this.updateTabDots();
|
this.updateTabDots();
|
||||||
if (this.activeChild) this.activeChild.update();
|
if (this.activeChild) this.activeChild.update();
|
||||||
this.rafId = requestAnimationFrame(loop);
|
this.rafId = requestAnimationFrame(loop);
|
||||||
|
|||||||
@ -15,28 +15,10 @@ import { UndoManager } from '@presentation/services/UndoManager';
|
|||||||
|
|
||||||
const ALL_GAUGES: GaugeType[] = ['baffeur', 'caresseur', 'foudroyeur', 'abreuvoir', 'dragofesse', 'mangeoire'];
|
const ALL_GAUGES: GaugeType[] = ['baffeur', 'caresseur', 'foudroyeur', 'abreuvoir', 'dragofesse', 'mangeoire'];
|
||||||
|
|
||||||
interface CachedGaugeEls {
|
|
||||||
tier: Element | null;
|
|
||||||
bar: HTMLElement | null;
|
|
||||||
empty: Element | null;
|
|
||||||
inp: HTMLInputElement | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class EnclosView {
|
export class EnclosView {
|
||||||
private el: HTMLElement | null = null;
|
private el: HTMLElement | null = null;
|
||||||
private enclosId = 0;
|
private enclosId = 0;
|
||||||
private ddCards: Map<number, DragodindeCard> = new Map();
|
private ddCards: Map<number, DragodindeCard> = new Map();
|
||||||
private cachedEls: {
|
|
||||||
elapsed: Element | null;
|
|
||||||
gcd: Element | null;
|
|
||||||
tbtn: HTMLButtonElement | null;
|
|
||||||
resetBtn: HTMLElement | null;
|
|
||||||
doneBanner: HTMLElement | null;
|
|
||||||
doneResetBtn: HTMLElement | null;
|
|
||||||
ddCount: Element | null;
|
|
||||||
addBtn: HTMLButtonElement | null;
|
|
||||||
gauges: Map<string, CachedGaugeEls>;
|
|
||||||
} | null = null;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private commandBus: CommandBus,
|
private commandBus: CommandBus,
|
||||||
@ -197,35 +179,9 @@ export class EnclosView {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
this.bindEvents(enc);
|
this.bindEvents(enc);
|
||||||
this.cacheElements(enc);
|
|
||||||
this.renderDdCards(enc);
|
this.renderDdCards(enc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private cacheElements(enc: Enclos): void {
|
|
||||||
if (!this.el) return;
|
|
||||||
const eId = this.enclosId;
|
|
||||||
const gauges = new Map<string, CachedGaugeEls>();
|
|
||||||
enc.activeGauges.forEach(gid => {
|
|
||||||
gauges.set(gid, {
|
|
||||||
tier: this.el!.querySelector(`#gtier-${eId}-${gid}`),
|
|
||||||
bar: this.el!.querySelector<HTMLElement>(`#gbar-${eId}-${gid}`),
|
|
||||||
empty: this.el!.querySelector(`#gempty-${eId}-${gid}`),
|
|
||||||
inp: this.el!.querySelector<HTMLInputElement>(`#glvl-${eId}-${gid}`),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.cachedEls = {
|
|
||||||
elapsed: this.el.querySelector(`#elapsed-${eId}`),
|
|
||||||
gcd: this.el.querySelector(`#gcd-${eId}`),
|
|
||||||
tbtn: this.el.querySelector<HTMLButtonElement>(`#tbtn-${eId}`),
|
|
||||||
resetBtn: this.el.querySelector<HTMLElement>(`#treset-${eId}`),
|
|
||||||
doneBanner: this.el.querySelector<HTMLElement>(`#done-banner-${eId}`),
|
|
||||||
doneResetBtn: this.el.querySelector<HTMLElement>(`#done-reset-${eId}`),
|
|
||||||
ddCount: this.el.querySelector(`#ddcount-${eId}`),
|
|
||||||
addBtn: this.el.querySelector<HTMLButtonElement>(`#adddd-${eId}`),
|
|
||||||
gauges,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private bindEvents(enc: Enclos): void {
|
private bindEvents(enc: Enclos): void {
|
||||||
if (!this.el) return;
|
if (!this.el) return;
|
||||||
const eId = this.enclosId;
|
const eId = this.enclosId;
|
||||||
@ -351,52 +307,54 @@ export class EnclosView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update(): void {
|
update(): void {
|
||||||
if (!this.el || !this.cachedEls) return;
|
if (!this.el) return;
|
||||||
const enc = this.getEnc();
|
const enc = this.getEnc();
|
||||||
const c = this.cachedEls;
|
const eId = this.enclosId;
|
||||||
const { globalMax, allDone, started, el: elSec } = enclosGlobalState(enc);
|
const { globalMax, allDone, started, el: elSec, ddDone } = enclosGlobalState(enc);
|
||||||
const running = enc.timer.running;
|
const running = enc.timer.running;
|
||||||
|
|
||||||
/* Complétion automatique : toutes les cibles atteintes → une seule alarme */
|
/* Complétion automatique : toutes les cibles atteintes → une seule alarme */
|
||||||
if (allDone && running && enc.dragodindes.length > 0 && enc.activeGauges.length > 0) {
|
if (allDone && running && enc.dragodindes.length > 0 && enc.activeGauges.length > 0) {
|
||||||
this.commandBus.execute({ type: 'complete-timer', enclosId: this.enclosId });
|
this.commandBus.execute({ type: 'complete-timer', enclosId: eId });
|
||||||
this.renderInner();
|
this.renderInner();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Elapsed clock */
|
/* Elapsed clock */
|
||||||
if (c.elapsed) c.elapsed.textContent = fmtClock(elSec);
|
const elapsedEl = this.el.querySelector(`#elapsed-${eId}`);
|
||||||
|
if (elapsedEl) elapsedEl.textContent = fmtClock(elSec);
|
||||||
|
|
||||||
/* Global countdown */
|
/* Global countdown */
|
||||||
if (c.gcd) {
|
const gcdEl = this.el.querySelector(`#gcd-${eId}`);
|
||||||
|
if (gcdEl) {
|
||||||
if (enc.activeGauges.length > 0 && enc.dragodindes.length > 0) {
|
if (enc.activeGauges.length > 0 && enc.dragodindes.length > 0) {
|
||||||
if (allDone) {
|
if (allDone) {
|
||||||
c.gcd.textContent = '✅';
|
gcdEl.textContent = '✅';
|
||||||
} else if (!isFinite(globalMax)) {
|
} else if (!isFinite(globalMax)) {
|
||||||
c.gcd.textContent = '∞';
|
gcdEl.textContent = '∞';
|
||||||
} else {
|
} else {
|
||||||
c.gcd.textContent = fmtClock(globalMax);
|
gcdEl.textContent = fmtClock(globalMax);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.gcd.textContent = '--:--:--';
|
gcdEl.textContent = '--:--:--';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Timer button state */
|
/* Timer button state */
|
||||||
if (c.tbtn) {
|
const tbtn = this.el.querySelector<HTMLButtonElement>(`#tbtn-${eId}`);
|
||||||
|
if (tbtn) {
|
||||||
const timerIcon = running ? 'pause' : 'play_arrow';
|
const timerIcon = running ? 'pause' : 'play_arrow';
|
||||||
const timerText = running ? 'PAUSE' : (enc.timer.pausedAt && !enc.alerted['__done__'] ? 'REPRENDRE' : 'DÉMARRER');
|
const timerText = running ? 'PAUSE' : (enc.timer.pausedAt && !enc.alerted['__done__'] ? 'REPRENDRE' : 'DÉMARRER');
|
||||||
c.tbtn.className = running ? 'enc-start-btn enc-btn-pause' : 'enc-start-btn';
|
tbtn.className = running ? 'enc-start-btn enc-btn-pause' : 'enc-start-btn';
|
||||||
c.tbtn.innerHTML = `<span class="material-symbols-outlined">${timerIcon}</span>${timerText}`;
|
tbtn.innerHTML = `<span class="material-symbols-outlined">${timerIcon}</span>${timerText}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset button visibility */
|
/* Reset button visibility */
|
||||||
if (c.resetBtn) c.resetBtn.style.display = started ? '' : 'none';
|
const resetBtn = this.el.querySelector<HTMLElement>(`#treset-${eId}`);
|
||||||
|
if (resetBtn) resetBtn.style.display = started ? '' : 'none';
|
||||||
|
|
||||||
/* Gauge config live updates (cached — no querySelector per frame) */
|
/* Gauge config live updates (tier badges and bars decay over time) */
|
||||||
enc.activeGauges.forEach(gid => {
|
enc.activeGauges.forEach(gid => {
|
||||||
const g = c.gauges.get(gid);
|
|
||||||
if (!g) return;
|
|
||||||
const startGl = started ? (enc.timer.snapGauges[gid] ?? enc.gaugeLevels[gid]) : enc.gaugeLevels[gid];
|
const startGl = started ? (enc.timer.snapGauges[gid] ?? enc.gaugeLevels[gid]) : enc.gaugeLevels[gid];
|
||||||
const curGl = started ? enclosGaugeCurGl(enc, gid) : startGl;
|
const curGl = started ? enclosGaugeCurGl(enc, gid) : startGl;
|
||||||
const tn = tierNum(curGl);
|
const tn = tierNum(curGl);
|
||||||
@ -405,48 +363,62 @@ export class EnclosView {
|
|||||||
const emptyTime = curGl > 0 ? timeToGain(curGl, curGl) : 0;
|
const emptyTime = curGl > 0 ? timeToGain(curGl, curGl) : 0;
|
||||||
const emptyStr = emptyTime === Infinity ? '∞' : fmt(emptyTime);
|
const emptyStr = emptyTime === Infinity ? '∞' : fmt(emptyTime);
|
||||||
|
|
||||||
if (g.tier) {
|
const tierEl = this.el!.querySelector(`#gtier-${eId}-${gid}`);
|
||||||
g.tier.textContent = curGl > 0 ? `Tier ${tn} · ±${tr}/tick` : 'Jauge vide';
|
if (tierEl) {
|
||||||
|
tierEl.textContent = curGl > 0 ? `Tier ${tn} · ±${tr}/tick` : 'Jauge vide';
|
||||||
}
|
}
|
||||||
if (g.bar) g.bar.style.width = `${pct.toFixed(1)}%`;
|
|
||||||
if (g.empty) {
|
const barEl = this.el!.querySelector<HTMLElement>(`#gbar-${eId}-${gid}`);
|
||||||
|
if (barEl) barEl.style.width = `${pct.toFixed(1)}%`;
|
||||||
|
|
||||||
|
const emptyEl = this.el!.querySelector(`#gempty-${eId}-${gid}`);
|
||||||
|
if (emptyEl) {
|
||||||
if (curGl > 0) {
|
if (curGl > 0) {
|
||||||
g.empty.textContent = `Vide en ${emptyStr}`;
|
emptyEl.textContent = `Vide en ${emptyStr}`;
|
||||||
g.empty.classList.remove('enc-gauge-alert');
|
emptyEl.classList.remove('enc-gauge-alert');
|
||||||
} else if (started && running) {
|
} else if (started && running) {
|
||||||
g.empty.textContent = '⚠ Rechargez la jauge';
|
emptyEl.textContent = '⚠ Rechargez la jauge';
|
||||||
g.empty.classList.add('enc-gauge-alert');
|
emptyEl.classList.add('enc-gauge-alert');
|
||||||
} else {
|
} else {
|
||||||
g.empty.textContent = 'Vide';
|
emptyEl.textContent = 'Vide';
|
||||||
g.empty.classList.remove('enc-gauge-alert');
|
emptyEl.classList.remove('enc-gauge-alert');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (g.inp) {
|
|
||||||
g.inp.dataset.running = started ? '1' : '0';
|
/* Mettre à jour la valeur affichée de l'input et son état en temps réel */
|
||||||
if (document.activeElement !== g.inp) {
|
const inp = this.el!.querySelector<HTMLInputElement>(`#glvl-${eId}-${gid}`);
|
||||||
g.inp.value = String(Math.round(started ? curGl : (enc.gaugeLevels[gid] ?? 0)));
|
if (inp) {
|
||||||
|
// Synchroniser data-running avec l'état réel du timer
|
||||||
|
inp.dataset.running = started ? '1' : '0';
|
||||||
|
// Mettre à jour la valeur affichée (sauf si l'utilisateur est en train de taper)
|
||||||
|
if (document.activeElement !== inp) {
|
||||||
|
inp.value = String(Math.round(started ? curGl : (enc.gaugeLevels[gid] ?? 0)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Done banner */
|
/* Done banner */
|
||||||
if (c.doneBanner) {
|
const doneBanner = this.el.querySelector<HTMLElement>(`#done-banner-${eId}`);
|
||||||
c.doneBanner.style.display = (allDone && started && enc.dragodindes.length > 0 && enc.activeGauges.length > 0) ? '' : 'none';
|
if (doneBanner) {
|
||||||
|
doneBanner.style.display = (allDone && started && enc.dragodindes.length > 0 && enc.activeGauges.length > 0) ? '' : 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bouton "Nouvelle fournée" */
|
/* Bouton "Nouvelle fournée" — visible uniquement si toutes les DD ont 20000 en maturité, endurance et amour */
|
||||||
if (c.doneResetBtn) {
|
const doneResetBtn = this.el.querySelector<HTMLElement>(`#done-reset-${eId}`);
|
||||||
|
if (doneResetBtn) {
|
||||||
const allMaxed = enc.dragodindes.length > 0 && enc.dragodindes.every(dd =>
|
const allMaxed = enc.dragodindes.length > 0 && enc.dragodindes.every(dd =>
|
||||||
dd.stats.maturite >= 20000 && dd.stats.endurance >= 20000 && dd.stats.amour >= 20000
|
dd.stats.maturite >= 20000 && dd.stats.endurance >= 20000 && dd.stats.amour >= 20000
|
||||||
);
|
);
|
||||||
c.doneResetBtn.style.display = allMaxed ? '' : 'none';
|
doneResetBtn.style.display = allMaxed ? '' : 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DD count */
|
/* DD count */
|
||||||
if (c.ddCount) c.ddCount.textContent = `${enc.dragodindes.length}/10`;
|
const ddCountEl = this.el.querySelector(`#ddcount-${eId}`);
|
||||||
|
if (ddCountEl) ddCountEl.textContent = `${enc.dragodindes.length}/10`;
|
||||||
|
|
||||||
/* Add button state */
|
/* Add button state */
|
||||||
if (c.addBtn) c.addBtn.disabled = enc.dragodindes.length >= 10;
|
const addBtn = this.el.querySelector<HTMLButtonElement>(`#adddd-${eId}`);
|
||||||
|
if (addBtn) addBtn.disabled = enc.dragodindes.length >= 10;
|
||||||
|
|
||||||
/* Update each DD card */
|
/* Update each DD card */
|
||||||
enc.dragodindes.forEach(dd => {
|
enc.dragodindes.forEach(dd => {
|
||||||
@ -467,7 +439,6 @@ export class EnclosView {
|
|||||||
destroy(): void {
|
destroy(): void {
|
||||||
this.ddCards.forEach(card => card.destroy());
|
this.ddCards.forEach(card => card.destroy());
|
||||||
this.ddCards.clear();
|
this.ddCards.clear();
|
||||||
this.cachedEls = null;
|
|
||||||
this.el?.remove();
|
this.el?.remove();
|
||||||
this.el = null;
|
this.el = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import { esc } from '@presentation/helpers/format';
|
|||||||
|
|
||||||
export class Sidebar {
|
export class Sidebar {
|
||||||
private el: HTMLElement | null = null;
|
private el: HTMLElement | null = null;
|
||||||
private cachedVersion: string | null = null;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private uiState: UIState,
|
private uiState: UIState,
|
||||||
@ -33,7 +32,7 @@ export class Sidebar {
|
|||||||
html += `
|
html += `
|
||||||
<div class="sb-header">
|
<div class="sb-header">
|
||||||
<div class="sb-logo-wrap">
|
<div class="sb-logo-wrap">
|
||||||
<img src="icone_sidebar.png" alt="logo" class="sb-logo-img" />
|
<img src="/icone_sidebar.png" alt="logo" class="sb-logo-img" />
|
||||||
</div>
|
</div>
|
||||||
<div class="sb-brand">
|
<div class="sb-brand">
|
||||||
<span class="sb-brand-name">Obsidienne</span>
|
<span class="sb-brand-name">Obsidienne</span>
|
||||||
@ -112,15 +111,9 @@ export class Sidebar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fetchAndInjectVersion(): void {
|
private fetchAndInjectVersion(): void {
|
||||||
if (this.cachedVersion) {
|
|
||||||
const verEl = this.el?.querySelector('#sb-ver');
|
|
||||||
if (verEl) verEl.textContent = `v${this.cachedVersion}`;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const api = (window as any).electronAPI;
|
const api = (window as any).electronAPI;
|
||||||
if (!api?.getVersion) return;
|
if (!api?.getVersion) return;
|
||||||
api.getVersion().then((v: string) => {
|
api.getVersion().then((v: string) => {
|
||||||
this.cachedVersion = v;
|
|
||||||
const verEl = this.el?.querySelector('#sb-ver');
|
const verEl = this.el?.querySelector('#sb-ver');
|
||||||
if (verEl) verEl.textContent = `v${v}`;
|
if (verEl) verEl.textContent = `v${v}`;
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
|
|||||||
@ -43,25 +43,6 @@ export class StatistiquesView {
|
|||||||
|
|
||||||
private renderAll(): void {
|
private renderAll(): void {
|
||||||
if (!this.el) return;
|
if (!this.el) return;
|
||||||
|
|
||||||
try {
|
|
||||||
this.renderAllInner();
|
|
||||||
} catch (e) {
|
|
||||||
const msg = e instanceof Error ? e.message : String(e);
|
|
||||||
const stack = e instanceof Error ? e.stack ?? '' : '';
|
|
||||||
console.error('Erreur statistiques:', e);
|
|
||||||
this.el.innerHTML = `<div class="stats-hero">
|
|
||||||
<div>
|
|
||||||
<h2 class="stats-hero-title">Statistiques d'\u00c9levage</h2>
|
|
||||||
<p class="stats-hero-sub" style="color:#f87171">Erreur : ${esc(msg)}</p>
|
|
||||||
<pre style="color:#f87171;font-size:11px;white-space:pre-wrap;max-height:200px;overflow:auto;margin-top:8px">${esc(stack)}</pre>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderAllInner(): void {
|
|
||||||
if (!this.el) return;
|
|
||||||
const data = this.getData();
|
const data = this.getData();
|
||||||
|
|
||||||
let html = '';
|
let html = '';
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 438 KiB |
Loading…
Reference in New Issue
Block a user