feat: gestion de l'expérience (XP)

- Schéma xp dans CelestopolCharacter : actuel (éditable), log[] ({montant, raison, date}), depense (calculé dans prepareDerivedData)
- Bouton 'Dépenser XP' → DialogV2 (montant + raison) : décrémente actuel, logge l'entrée
- Suppression d'entrée de log avec remboursement des points (mode édition)
- Section XP en haut de l'onglet Biographie : compteurs, tableau du log, référentiel des coûts
- i18n : section CELESTOPOL.XP.* complète
- CSS : .xp-section avec compteurs, tableau de log et accordéon de référence

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-03-31 00:33:59 +02:00
parent 79a68ee9ab
commit 9dbd614c5a
40 changed files with 849 additions and 529 deletions

View File

@@ -131,39 +131,27 @@
text-align: center;
}
// Track de niveau (cases à cocher Art Déco)
// Points de niveau Art Déco (remplacent les cases à cocher)
.skill-checkboxes-container {
.skill-checkboxes {
display: flex;
gap: 3px;
align-items: center;
}
.skill-checkbox-wrapper {
line-height: 0;
cursor: pointer;
.skill-level-checkbox {
appearance: none;
-webkit-appearance: none;
display: inline-block;
width: 13px;
height: 13px;
border: 1px solid var(--cel-border);
border-radius: 1px;
background: rgba(255,255,255,0.3);
cursor: pointer;
vertical-align: middle;
transition: background 0.1s, border-color 0.1s;
&:checked {
background: var(--cel-orange);
border-color: var(--cel-border);
}
&:disabled { cursor: default; }
&:disabled:checked {
background: var(--cel-orange);
border-color: var(--cel-border);
opacity: 1;
}
.skill-level-dot {
display: inline-block;
width: 13px;
height: 13px;
border: 1px solid var(--cel-border);
border-radius: 1px;
background: rgba(255,255,255,0.3);
vertical-align: middle;
transition: background 0.1s, border-color 0.1s;
&.filled {
background: var(--cel-orange);
border-color: var(--cel-border);
}
&[data-action] { cursor: pointer; }
}
}
}
@@ -215,6 +203,11 @@
text-transform: uppercase;
font-size: 0.9em;
}
.track-title-destin {
cursor: help;
border-bottom: 1px dashed currentColor;
text-decoration: none;
}
}
.track-boxes {
@@ -228,17 +221,29 @@
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
width: 22px;
min-height: 22px;
border: 2px solid var(--cel-border);
border-radius: 2px;
background: rgba(255,255,255,0.45);
transition: background 0.1s, border-color 0.1s;
&.filled {
background: var(--cel-orange);
border-color: var(--cel-orange);
}
&[data-action] { cursor: pointer; }
input[type="checkbox"] { .cel-box(); accent-color: var(--cel-orange); }
.box-label {
font-size: 0.65em;
font-size: 0.6em;
color: var(--cel-border);
line-height: 1;
}
&.checked input[type="checkbox"] {
accent-color: var(--cel-orange);
}
&.filled .box-label { color: rgba(30,10,0,0.65); }
}
}
@@ -274,6 +279,38 @@
td { padding: 4px 8px; border-bottom: 1px solid rgba(122,92,32,0.2); }
&.custom td { font-style: italic; color: #666; }
.faction-checkboxes-container {
display: flex;
align-items: center;
gap: 8px;
}
.faction-checkboxes {
display: flex;
gap: 3px;
align-items: center;
}
.faction-dot {
display: inline-block;
width: 12px;
height: 12px;
border: 1px solid var(--cel-border);
border-radius: 1px;
background: rgba(255,255,255,0.3);
transition: background 0.1s;
&.filled { background: var(--cel-orange); border-color: var(--cel-orange); }
&[data-action] { cursor: pointer; }
}
.faction-count {
font-size: 0.85em;
font-weight: bold;
color: var(--cel-orange);
min-width: 16px;
text-align: center;
}
.faction-value input[type="number"] {
width: 50px;
.cel-input-std();
@@ -335,6 +372,156 @@
.enriched-html { font-size: 0.9em; line-height: 1.6; }
}
// ── Section Expérience (onglet Biographie) ──────────────────────────────
.xp-section {
margin-bottom: 14px;
.section-header { .cel-section-header(); }
.xp-counters {
display: flex;
align-items: center;
gap: 12px;
padding: 6px 0 8px;
flex-wrap: wrap;
.xp-counter {
display: flex;
flex-direction: column;
align-items: center;
background: rgba(0,0,0,0.18);
border: 1px solid var(--cel-orange);
border-radius: 4px;
padding: 4px 12px;
min-width: 80px;
label {
font-size: 0.6em;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--cel-orange-light);
white-space: nowrap;
}
input[type="number"] {
width: 52px;
text-align: center;
.cel-input-std();
font-family: var(--cel-font-title);
font-size: 1.1em;
font-weight: bold;
color: var(--cel-orange);
}
}
.xp-depense-counter {
border-color: rgba(196,154,26,0.4);
.xp-depense-value {
font-family: var(--cel-font-title);
font-size: 1.1em;
font-weight: bold;
color: rgba(196,154,26,0.7);
}
}
.xp-btn-depenser {
background: var(--cel-green);
border: 1px solid var(--cel-orange);
color: var(--cel-orange);
font-size: 0.78em;
padding: 5px 12px;
cursor: pointer;
font-family: var(--cel-font-title);
text-transform: uppercase;
letter-spacing: 0.04em;
border-radius: 2px;
transition: background 0.15s;
margin-left: auto;
&:hover { background: var(--cel-green-light); }
i { margin-right: 4px; }
}
}
.xp-log-table {
width: 100%;
border-collapse: collapse;
font-size: 0.82em;
margin-bottom: 8px;
thead tr {
background: rgba(12,76,12,0.35);
th {
color: var(--cel-orange-light);
font-size: 0.75em;
text-transform: uppercase;
letter-spacing: 0.04em;
padding: 3px 6px;
text-align: left;
border-bottom: 1px solid rgba(196,154,26,0.3);
}
}
tbody tr {
border-bottom: 1px solid rgba(196,154,26,0.12);
&:nth-child(even) { background: rgba(0,0,0,0.08); }
td { padding: 3px 6px; color: var(--cel-text-dark, #3a2a0a); }
.xp-date { white-space: nowrap; color: var(--cel-border); font-size: 0.9em; }
.xp-montant { font-weight: bold; color: #c04040; white-space: nowrap; }
.xp-suppr-cell {
text-align: center;
.xp-btn-suppr {
background: none;
border: none;
color: rgba(180,60,60,0.6);
cursor: pointer;
font-size: 0.9em;
padding: 1px 4px;
&:hover { color: #c04040; }
}
}
}
}
// Référentiel de coûts (accordéon)
.xp-ref {
margin-top: 6px;
summary {
font-size: 0.78em;
color: var(--cel-orange-light);
cursor: pointer;
letter-spacing: 0.03em;
text-transform: uppercase;
user-select: none;
&:hover { color: var(--cel-orange); }
}
.xp-ref-table {
width: 100%;
border-collapse: collapse;
font-size: 0.78em;
margin-top: 5px;
opacity: 0.75;
th {
color: var(--cel-orange-light);
text-transform: uppercase;
font-size: 0.85em;
letter-spacing: 0.03em;
padding: 2px 6px;
border-bottom: 1px solid rgba(196,154,26,0.25);
text-align: left;
}
td {
padding: 2px 6px;
border-bottom: 1px solid rgba(196,154,26,0.1);
color: var(--cel-text-dark, #3a2a0a);
}
}
}
}
// ── Bloc Anomalie sur l'onglet Domaines ──────────────────────────────────
.anomaly-block {
border: 1px solid rgba(196,154,26,0.5);

View File

@@ -277,18 +277,63 @@
&:disabled { cursor: default; opacity: 0.7; }
}
.faction-count {
margin-left: 8px;
font-weight: bold;
color: var(--cel-orange);
min-width: 20px;
text-align: right;
// ── Badge d'état de blessure intégré dans header-stats-row ─────────────────
.wound-status-badge {
// Supprime le fond/bord générique du .header-stat
background: transparent;
border-color: currentColor;
label {
text-transform: uppercase;
white-space: nowrap;
}
.wound-value {
font-family: var(--cel-font-title);
font-size: 0.95em;
font-weight: bold;
white-space: nowrap;
line-height: 1.2;
}
.wound-duration { font-weight: normal; opacity: 0.85; }
.wound-malus { opacity: 0.9; }
// Niveaux 1-2 : aucun malus → vert doux
&.wound-level-1, &.wound-level-2 {
color: #6abf5e;
background: rgba(106,191,94,0.10);
label { color: #6abf5e; }
}
// Niveaux 3-4 : malus -1 → ambre
&.wound-level-3, &.wound-level-4 {
color: #e8a020;
background: rgba(232,160,32,0.13);
label { color: #e8a020; }
}
// Niveaux 5-6 : malus -2 → orange vif
&.wound-level-5, &.wound-level-6 {
color: #e06020;
background: rgba(224,96,32,0.13);
label { color: #e06020; }
}
// Niveau 7 : malus -3 → rouge
&.wound-level-7 {
color: #d43030;
background: rgba(212,48,48,0.13);
label { color: #d43030; }
}
// Niveau 8 : hors combat → rouge sombre + pulsation
&.wound-level-8 {
color: #c00;
background: rgba(192,0,0,0.18);
label { color: #c00; }
animation: wound-pulse 1.4s ease-in-out infinite;
}
}
.faction-value-input { width: 40px; margin-left: 8px; }
.faction-row {
pointer-events: auto !important;
td { pointer-events: auto !important; }
@keyframes wound-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.55; }
}
}