Compare commits

...
23 Commits
Author SHA1 Message Date
bruno cc007dfa04 Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 0s
CI / test (pull_request) Failing after 0s
2026-10-28 22:59:13 -04:00
bruno f0ca8b9ec6 Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Successful in 4m24s
2026-10-28 22:59:11 -04:00
bruno 6a938cf778 Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 0s
2026-10-28 22:59:09 -04:00
bruno c60694bf23 Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 0s
2026-10-28 22:59:07 -04:00
bruno a08fa53bab Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 0s
2026-10-28 22:59:05 -04:00
bruno 1c81259e0d Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 0s
2026-10-28 22:59:03 -04:00
bruno 5749b1c718 Merge pull request 'Thème du site : look agent-dev / barre Fusion, fin du bleu/mauve (#49)' (#50) from theme-agent-49 into main
CI / test (push) Successful in 4m50s
2026-10-28 22:48:45 -04:00
bruno c35aafd2e2 Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 0s
CI / test (pull_request) Successful in 4m32s
2026-10-28 22:47:12 -04:00
bruno 219c614216 Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 1s
2026-10-28 22:47:09 -04:00
bruno 0d6499ed1a Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 0s
2026-10-28 22:47:07 -04:00
bruno a09ae26d78 Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 1s
2026-10-28 22:47:04 -04:00
bruno 56f39c0959 Merge pull request 'Page Projets : versionner style.css et dashboard.js (#47)' (#48) from fix-dashboard-cache-47 into main
CI / test (push) Successful in 4m18s
2026-10-28 22:38:19 -04:00
bruno 99a7ebd504 Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 0s
CI / test (pull_request) Failing after 0s
2026-10-28 22:35:55 -04:00
bruno e8f48d3009 Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 0s
2026-10-28 22:35:53 -04:00
bruno dd6a4dd82c Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 0s
2026-10-28 22:35:51 -04:00
bruno a2f3564cc8 Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Successful in 4m17s
2026-10-28 22:35:49 -04:00
bruno ea39916db5 Merge pull request 'Page Projets : copie d'URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)' (#46) from menu-copie-url-44-45 into main
CI / test (push) Successful in 4m2s
2026-10-28 22:27:21 -04:00
bruno 724d7a7799 Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 2s
CI / test (pull_request) Failing after 1s
2026-10-28 22:12:12 -04:00
bruno 5ff51d8e2d Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 1s
2026-10-28 22:12:09 -04:00
bruno 436084aebd Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 2s
2026-10-28 22:12:07 -04:00
bruno 8ab30d25ef Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 1s
2026-10-28 22:12:04 -04:00
bruno 6cac4e71f5 Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Failing after 1s
2026-10-28 22:12:01 -04:00
bruno 210f4f8983 Page Projets : copie URL dans le menu ⋯ + refonte thème barre Fusion/Spark (#44, #45)
CI / test (push) Successful in 4m9s
2026-10-28 22:11:58 -04:00
11 changed files with 423 additions and 140 deletions
+20
View File
@@ -1,3 +1,23 @@
## 0.40.0 — 2026-10-28 — Navigation : section Administration + bouton Dark/Light (#51, #52)
- **Accordéon (#51)** : la section Administration ne fermait jamais — le JS posait `nav-closed-admin`, mais `style.css` ne définissait les règles de fermeture que pour les 4 autres sections. Les règles admin sont ajoutées (fermeture et rotation du chevron) : l'accordéon redevient exclusif.
- **Bouton Dark/Light (#52)** : bouton « ☀️ Mode clair / 🌙 Mode sombre » dans l'en-tête applicatif, qui bascule `data-theme` sur `<html>` et mémorise le choix (localStorage, appliqué avant le rendu par l'amorce de `_header.html`). Thème clair sur les jetons draco (fond #f2f2f0, surfaces blanches/grises, accent rose conservé, second ton assombri pour les liens), barre Fusion et panneau Spark qui suivent. Défaut inchangé : sombre. `nav.js` est désormais versionné (`?v=`), comme dashboard.js depuis la 0.38.1.
## 0.39.0 — 2026-10-28 — Thème du site : look agent-dev / barre Fusion (#49)
- **Re-thème complet** : `style.css` passe sur les jetons draco-barre (Console v7.2) — fond #101211, surfaces #1a1c1a / #242624 / #20221f, bordure #2e302c, textes #eceee9 / #a6aba2 / #8b9089, accent rose Spark #c2437e (second ton #e078a8). Fond plat, plus de halos ni de dégradés violet→bleu, y compris les valeurs de repli et l'écran de connexion.
- **Inchangé** : couleurs sémantiques (vert/jaune/rouge) et couleurs de colonnes choisies par l'utilisateur. Pas de mode clair : l'app force le sombre, comme la console de référence.
## 0.38.1 — 2026-10-28 — Page Projets : le correctif 0.38.0 atteint enfin le navigateur (#47)
- **Cache-busting (#47)** : `dashboard.html` charge désormais `style.css?v={{ version }}` et `dashboard.js?v={{ version }}`, comme les autres pages (admin, board, project) et la barre Fusion. Sans ça, le navigateur gardait l'ancien CSS (menu transparent, bouton de copie non stylé) et l'ancien JS (aucun gestionnaire de copie) alors que le HTML était déjà neuf — c'est pourquoi la 0.38.0 semblait ne rien changer, bouton présent mais inerte. Le code 0.38.0 lui-même (jetons `--menu-bg` opaques, gestionnaire `data-copy-url`) était correct dans le dépôt.
## 0.38.0 — 2026-10-28 — Page Projets : copie d'URL et refonte du menu ⋯
- **Copie d'URL (#44)** : chaque tuile projet (grille, y compris Épinglés) propose désormais « 🔗 Copier l'URL du projet » dans son menu ⋯ — l'URL Gitea du dépôt est copiée dans le presse-papiers, avec confirmation « URL du projet copiée » et repli (textarea + execCommand) quand l'API Clipboard n'est pas disponible.
- **Menu ⋯ (#45)** : refonte sur les jetons de la barre d'apps commune (draco-barre.css, prototype Console v7.2 / console Spark) — fond opaque, bordure, rayon 14 px, ombre portée, survol/focus visibles, séparateur avant l'action de copie. Corrige la cause du menu transparent : il utilisait `var(--surface-1)`, variable jamais définie.
- **Thèmes sombre et clair** : jetons clairs par défaut, variante sombre via `[data-theme="dark"]` sur `<html>` et repli `prefers-color-scheme`, comme la barre Fusion.
## 0.37.6 — 2026-10-28 — Corrections console/recherche : CORS console Spark
- **CORS recherche (PR #43)** : la recherche Kanbante autorise désormais la console Spark (agent prod+dev) en inter-origines — les pages console peuvent appeler la recherche de l'hôte sans erreur CORS/réseau.
+1 -1
View File
@@ -177,7 +177,7 @@ from urllib.parse import urlparse
BASE_DIR = Path(__file__).resolve().parent.parent
APP_VERSION = "0.37.6"
APP_VERSION = "0.40.0"
def _env_bool(name: str, default: bool) -> bool:
+14 -1
View File
@@ -1,3 +1,15 @@
<script>
/* Thème (#52) : appliqué avant le rendu de la barre, pour
éviter le flash sombre quand l'utilisateur a choisi le
clair. Défaut = sombre (les gabarits portent
data-theme="dark") ; seul un choix mémorisé bascule. */
try {
var _t = localStorage.getItem('kanbante-theme');
if (_t === 'light' || _t === 'dark') {
document.documentElement.setAttribute('data-theme', _t);
}
} catch (e) { /* mode privé : le thème ne survit qu'à la page */ }
</script>
{% include "_draco_bar.html" %}
{# ── Cadre applicatif partagé (issue #16, refonte 0.16.0) ─────────
Barre latérale unique pour TOUTES les pages applicatives :
@@ -141,6 +153,7 @@
<a href="{{ repo_info.html_url }}" target="_blank" rel="noopener" class="nav-pill" title="Ouvrir ce dépôt dans Gitea">🔗 Gitea ↗</a>
{% endif %}
<button type="button" class="nav-pill palette-trigger topbar-search" title="Recherche et commandes (Ctrl+K)">🔍</button>
<button type="button" class="nav-pill" id="theme-toggle" title="Basculer entre thème sombre et clair" aria-label="Basculer entre thème sombre et clair">☀️ Mode clair</button>
</div>
<script src="/static/js/nav.js" defer></script>
<script src="/static/js/nav.js?v={{ version }}" defer></script>
</header>
+4 -2
View File
@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kanbante — Dashboard</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📋</text></svg>">
<link rel="stylesheet" href="/static/css/style.css">
<link rel="stylesheet" href="/static/css/style.css?v={{ version }}">
<script defer src="/static/vendor/alpine.min.js"></script>
</head>
<body>
@@ -109,6 +109,8 @@
<a href="/sprint/{{ full }}">📖 Récit de sprint</a>
{% if repo.html_url %}
<a href="{{ repo.html_url }}" target="_blank" rel="noopener">🔗 Gitea ↗</a>
<div class="card-menu-sep" role="separator"></div>
<button type="button" class="card-menu-item" data-copy-url="{{ repo.html_url }}" title="Copier l'URL Gitea de {{ repo.name }}" aria-label="Copier l'URL du projet {{ repo.name }}">🔗 Copier l'URL du projet</button>
{% endif %}
</div>
</div>
@@ -259,7 +261,7 @@
<script src="/static/js/live.js" defer></script>
<script>window.KANBANTE_CSRF = "{{ csrf_token }}";</script>
<script src="/static/js/stars.js" defer></script>
<script src="/static/js/dashboard.js" defer></script>
<script src="/static/js/dashboard.js?v={{ version }}" defer></script>
<script src="/static/js/tablesort.js" defer></script>
<script>
document.addEventListener('keydown', function (e) {
+212 -136
View File
@@ -1,23 +1,24 @@
/* ═══════════════════════════════════════════════
Kanbante — design system 0.4
Dark, calm, modern. One accent gradient, generous
radii, soft depth, visible focus, quiet motion.
Thème agent (draco-barre, Console v7.2) : charbon neutre,
surfaces grises chaudes, accent rose Spark — plus de
dominante bleu/mauve (issue #49).
═══════════════════════════════════════════════ */
:root {
--bg: #0b0e14;
--bg-glow-1: rgba(124, 92, 252, 0.13);
--bg-glow-2: rgba(91, 138, 247, 0.10);
--surface: #141822;
--surface-2: #1b202e;
--surface-3: #232939;
--border: rgba(148, 152, 164, 0.16);
--border-strong: rgba(148, 152, 164, 0.30);
--text: #eceef3;
--text-2: #9aa0ae;
--text-3: #6d7280;
--accent: #7c5cfc;
--accent-2: #5b8af7;
--bg: #101211;
--bg-glow-1: transparent;
--bg-glow-2: transparent;
--surface: #1a1c1a;
--surface-2: #242624;
--surface-3: #20221f;
--border: #2e302c;
--border-strong: #3f4340;
--text: #eceee9;
--text-2: #a6aba2;
--text-3: #8b9089;
--accent: #c2437e;
--accent-2: #e078a8;
--green: #10b981;
--yellow: #f59e0b;
--red: #ef4444;
@@ -25,7 +26,7 @@
--radius-sm: 10px;
--shadow: 0 8px 28px rgba(0, 0, 0, 0.38);
--shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.25);
--ring: 0 0 0 3px rgba(124, 92, 252, 0.35);
--ring: 0 0 0 3px rgba(194, 67, 126, 0.35);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
@@ -47,7 +48,7 @@ body {
line-height: 1.45;
}
::selection { background: rgba(124, 92, 252, 0.45); }
::selection { background: rgba(194, 67, 126, 0.45); }
a { color: var(--accent-2); text-decoration: none; }
a:hover { text-decoration: underline; }
@@ -78,7 +79,7 @@ button, input, select, textarea { font: inherit; }
padding: 8px 10px;
}
:where(input, textarea, select):focus-visible {
outline: 2px solid rgba(124, 92, 252, 0.55);
outline: 2px solid rgba(194, 67, 126, 0.55);
outline-offset: 0;
}
@@ -92,7 +93,7 @@ button, input, select, textarea { font: inherit; }
align-items: center;
gap: 16px;
padding: 12px 24px;
background: rgba(16, 19, 28, 0.82);
background: rgba(26, 28, 26, 0.82);
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
border-bottom: 1px solid var(--border);
@@ -120,7 +121,7 @@ button, input, select, textarea { font: inherit; }
font-size: 1rem;
}
.gradient-text {
background: linear-gradient(120deg, #a78bfa, #7dd3fc);
background: linear-gradient(120deg, #c2437e, #e078a8);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
@@ -144,7 +145,7 @@ header h1 { font-size: 1.2rem; font-weight: 600; }
.nav-pill:hover { color: var(--text); background: var(--surface-2); text-decoration: none; }
.nav-pill.active {
color: #fff;
background: linear-gradient(135deg, rgba(124,92,252,.85), rgba(91,138,247,.85));
background: linear-gradient(135deg, rgba(194,67,126,.85), rgba(224,120,168,.85));
border-color: rgba(255,255,255,0.12);
}
@@ -154,7 +155,7 @@ header h1 { font-size: 1.2rem; font-weight: 600; }
font-size: 0.78rem;
font-weight: 600;
background: color-mix(in srgb, var(--accent) 18%, transparent);
color: #c4b5fd;
color: #d99ab5;
}
.badge.secondary { background: var(--surface-2); color: var(--text-2); }
@@ -280,13 +281,13 @@ a.kpi:hover { background: var(--surface-2); text-decoration: none; }
font-size: 0.68rem;
text-transform: uppercase;
letter-spacing: 0.6px;
color: #c4b5fd;
color: #d99ab5;
font-weight: 700;
}
.date { font-size: 0.75rem; color: var(--text-3); }
.project-card h3 { font-size: 1.08rem; margin-bottom: 6px; letter-spacing: -0.01em; }
.project-card h3 a { color: var(--text); }
.project-card h3 a:hover { color: #a5c4fd; text-decoration: none; }
.project-card h3 a:hover { color: #e078a8; text-decoration: none; }
.desc {
font-size: 0.85rem;
color: var(--text-2);
@@ -362,7 +363,7 @@ a.kpi:hover { background: var(--surface-2); text-decoration: none; }
.milestone-chip:hover { color: var(--text); text-decoration: none; border-color: var(--border-strong); }
.milestone-chip.active {
color: #fff;
background: linear-gradient(135deg, rgba(124,92,252,.9), rgba(91,138,247,.9));
background: linear-gradient(135deg, rgba(194,67,126,.9), rgba(224,120,168,.9));
border-color: transparent;
}
.milestone-banner {
@@ -371,8 +372,8 @@ a.kpi:hover { background: var(--surface-2); text-decoration: none; }
gap: 16px;
margin: 14px 24px 0;
padding: 14px 18px;
background: linear-gradient(120deg, rgba(124,92,252,.14), rgba(91,138,247,.10));
border: 1px solid rgba(124,92,252,.35);
background: linear-gradient(120deg, rgba(194,67,126,.14), rgba(224,120,168,.10));
border: 1px solid rgba(194,67,126,.35);
border-radius: var(--radius);
flex-wrap: wrap;
}
@@ -489,7 +490,7 @@ a.kpi:hover { background: var(--surface-2); text-decoration: none; }
.kanban-card.dragging { opacity: 0.55; transform: rotate(2deg) scale(1.02); box-shadow: var(--shadow); }
.card-id {
font-size: 0.7rem;
color: #c4b5fd;
color: #d99ab5;
font-weight: 700;
margin-bottom: 4px;
display: flex;
@@ -640,7 +641,7 @@ footer {
.focus-group { margin-bottom: 30px; }
.focus-group h2 { font-size: 1.06rem; margin-bottom: 12px; display: flex; gap: 10px; align-items: center; }
.focus-group h2 a { color: var(--text); }
.focus-group h2 a:hover { color: #a5c4fd; text-decoration: none; }
.focus-group h2 a:hover { color: #e078a8; text-decoration: none; }
.focus-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
.focus-card { margin-bottom: 0; cursor: default; }
@@ -771,7 +772,7 @@ footer {
}
.issue-row:hover { border-color: var(--border-strong); }
.issue-main { color: var(--text); flex: 1; min-width: 220px; }
.issue-main:hover { color: #a5c4fd; text-decoration: none; }
.issue-main:hover { color: #e078a8; text-decoration: none; }
.col-chip {
padding: 2px 10px;
border-radius: 999px;
@@ -817,7 +818,7 @@ footer {
cursor: col-resize;
z-index: 5;
}
.notes-resize:hover { background: rgba(124, 92, 252, 0.35); }
.notes-resize:hover { background: rgba(194, 67, 126, 0.35); }
.notes-foot { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-top: 10px; }
.notes-foot .btn-save { margin-top: 0; }
.notes-status { font-size: 0.76rem; color: var(--text-3); }
@@ -925,8 +926,8 @@ footer {
/* ── Wallboard (0.6.0) : affichage plein écran, lisible à 3 mètres ── */
.wall-body {
background: #0b1220;
color: #e5ecf5;
background: #101211;
color: #eceee9;
margin: 0;
font-family: inherit;
height: 100vh;
@@ -950,12 +951,12 @@ footer {
.wall-head {
display: flex; justify-content: space-between; align-items: flex-start; gap: 24px;
}
.wall-kicker { font-size: 1rem; letter-spacing: 0.22em; text-transform: uppercase; color: #8fa3bf; }
.wall-kicker { font-size: 1rem; letter-spacing: 0.22em; text-transform: uppercase; color: #a6aba2; }
.wall-project { font-size: clamp(2.2rem, 5.2vw, 4.2rem); margin: 0.4rem 0 0; line-height: 1.05; }
.wall-clock { text-align: right; }
.wall-time { font-size: clamp(2rem, 4.5vw, 3.6rem); font-weight: 800; line-height: 1; }
.wall-date { color: #8fa3bf; font-size: 1.15rem; margin-top: 0.35rem; text-transform: capitalize; }
.wall-rotation { color: #5b6b84; margin-top: 0.4rem; font-size: 1rem; }
.wall-date { color: #a6aba2; font-size: 1.15rem; margin-top: 0.35rem; text-transform: capitalize; }
.wall-rotation { color: #8b9089; margin-top: 0.4rem; font-size: 1rem; }
.wall-counts {
display: grid; grid-template-columns: repeat(6, 1fr); gap: 14px;
}
@@ -968,7 +969,7 @@ footer {
background: rgba(255, 255, 255, 0.03);
}
.wall-count-n { display: block; font-size: clamp(1.9rem, 3.6vw, 3rem); font-weight: 800; }
.wall-count-l { display: block; color: #aebdd2; font-size: clamp(0.78rem, 1.25vw, 1.02rem); margin-top: 2px; }
.wall-count-l { display: block; color: #a6aba2; font-size: clamp(0.78rem, 1.25vw, 1.02rem); margin-top: 2px; }
.wall-cards {
list-style: none; margin: 0; padding: 0;
display: flex; flex-direction: column; gap: 12px;
@@ -976,7 +977,7 @@ footer {
-webkit-mask-image: linear-gradient(to bottom, #000 88%, transparent);
mask-image: linear-gradient(to bottom, #000 88%, transparent);
}
.wall-more { justify-content: center; color: #8fa3bf; font-size: 1.1rem; background: transparent; }
.wall-more { justify-content: center; color: #a6aba2; font-size: 1.1rem; background: transparent; }
.wall-card {
display: flex; align-items: center; gap: 18px;
background: rgba(255, 255, 255, 0.045);
@@ -992,13 +993,13 @@ footer {
.wall-card-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wall-card-age { color: #fbbf24; font-weight: 700; white-space: nowrap; }
.wall-card-age.hot { color: #f87171; }
.wall-idle { font-size: 1.5rem; color: #8fa3bf; }
.wall-idle { font-size: 1.5rem; color: #a6aba2; }
.wall-foot {
margin-top: auto;
display: flex; gap: 36px; flex-wrap: wrap;
justify-content: space-between; align-items: center;
width: 100%; box-sizing: border-box;
font-size: clamp(1rem, 1.7vw, 1.35rem); color: #aebdd2;
font-size: clamp(1rem, 1.7vw, 1.35rem); color: #a6aba2;
}
@media (max-height: 760px) {
.wall-slide { gap: 1.6vh; padding-top: 2.5vh; }
@@ -1011,9 +1012,9 @@ footer {
.wall-empty {
min-height: 100vh; display: flex; flex-direction: column;
align-items: center; justify-content: center; gap: 10px; text-align: center;
color: #aebdd2; padding: 24px;
color: #a6aba2; padding: 24px;
}
.wall-empty h1 { color: #e5ecf5; font-size: 2.6rem; margin: 0; }
.wall-empty h1 { color: #eceee9; font-size: 2.6rem; margin: 0; }
.wall-empty code { background: rgba(255,255,255,0.08); padding: 2px 8px; border-radius: 6px; }
@media (max-width: 900px) {
.wall-counts { grid-template-columns: repeat(3, 1fr); }
@@ -1043,8 +1044,8 @@ footer {
.palette-overlay[hidden] { display: none; }
.palette {
width: min(640px, 100%);
background: var(--surface-1, #131a29);
border: 1px solid var(--border-strong, #2c3a52);
background: var(--surface-1, #1a1c1a);
border: 1px solid var(--border-strong, #3f4340);
border-radius: 16px;
box-shadow: 0 24px 70px rgba(0, 0, 0, 0.55);
overflow: hidden;
@@ -1052,14 +1053,14 @@ footer {
}
.palette-input-row {
display: flex; align-items: center; gap: 12px;
padding: 14px 16px; border-bottom: 1px solid var(--border, #22304a);
padding: 14px 16px; border-bottom: 1px solid var(--border, #2e302c);
}
.palette-input-row input {
flex: 1; background: transparent; border: none; outline: none;
color: var(--text-1); font: inherit; font-size: 1.05rem;
}
.palette-input-row kbd {
background: var(--surface-3, #1d2942); border: 1px solid var(--border, #22304a);
background: var(--surface-3, #20221f); border: 1px solid var(--border, #2e302c);
border-radius: 6px; padding: 2px 8px; font-size: 0.75rem; color: var(--text-3);
}
.palette-results { list-style: none; margin: 0; padding: 8px; max-height: 46vh; overflow-y: auto; }
@@ -1067,13 +1068,13 @@ footer {
display: flex; align-items: center; gap: 12px;
padding: 10px 12px; border-radius: 10px; cursor: pointer;
}
.palette-item.active { background: var(--surface-3, #1d2942); }
.palette-item.active { background: var(--surface-3, #20221f); }
.palette-item-icon { font-size: 1.05rem; width: 24px; text-align: center; }
.palette-item-main { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.palette-item-sub { color: var(--text-3); font-size: 0.8rem; white-space: nowrap; }
.palette-empty { padding: 18px 14px; color: var(--text-3); text-align: center; }
.palette-hint {
padding: 9px 16px; border-top: 1px solid var(--border, #22304a);
padding: 9px 16px; border-top: 1px solid var(--border, #2e302c);
color: var(--text-3); font-size: 0.78rem; text-align: right;
}
.palette-trigger { cursor: pointer; font: inherit; }
@@ -1082,54 +1083,54 @@ footer {
.triage-main { max-width: 860px; margin: 0 auto; padding: 24px 16px 40px; }
.triage-head h1 { margin: 0 0 12px; font-size: 1.4rem; }
.triage-progress-wrap { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }
.triage-progress { flex: 1; height: 10px; border-radius: 99px; background: var(--surface-3, #1d2942); overflow: hidden; }
.triage-progress { flex: 1; height: 10px; border-radius: 99px; background: var(--surface-3, #20221f); overflow: hidden; }
.triage-progress-bar { height: 100%; width: 0; background: var(--good, #3fb950); border-radius: 99px; transition: width 0.25s ease; }
.triage-progress-label { color: var(--text-3); font-size: 0.85rem; white-space: nowrap; }
.triage-card {
background: var(--surface-1, #131a29);
border: 1px solid var(--border-strong, #2c3a52);
background: var(--surface-1, #1a1c1a);
border: 1px solid var(--border-strong, #3f4340);
border-radius: 16px; padding: 26px 28px; min-height: 220px;
}
.triage-card-top { display: flex; gap: 14px; align-items: baseline; color: var(--text-3); font-size: 0.88rem; }
.triage-card-num { font-weight: 700; color: var(--accent, #58a6ff); }
.triage-card-num { font-weight: 700; color: var(--accent, #c2437e); }
.triage-card-link { margin-left: auto; color: var(--text-3); text-decoration: none; }
.triage-card-title { margin: 10px 0 8px; font-size: 1.5rem; line-height: 1.3; }
.triage-card-labels { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
.triage-card-excerpt { color: var(--text-2, #b6c2d2); line-height: 1.55; white-space: pre-wrap; }
.triage-card-excerpt { color: var(--text-2, #a6aba2); line-height: 1.55; white-space: pre-wrap; }
.triage-card-assign { color: var(--text-3); }
.triage-keys { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; }
.triage-keys button {
background: var(--surface-2, #182236); color: var(--text-1);
border: 1px solid var(--border, #22304a); border-radius: 10px;
border: 1px solid var(--border, #2e302c); border-radius: 10px;
padding: 9px 13px; font: inherit; font-size: 0.9rem; cursor: pointer;
}
.triage-keys button:hover { border-color: var(--accent, #58a6ff); }
.triage-keys button:hover { border-color: var(--accent, #c2437e); }
.triage-keys kbd {
background: var(--surface-3, #1d2942); border: 1px solid var(--border-strong, #2c3a52);
background: var(--surface-3, #20221f); border: 1px solid var(--border-strong, #3f4340);
border-radius: 5px; padding: 1px 6px; font-size: 0.78rem; margin-right: 4px;
}
.triage-status { min-height: 22px; margin-top: 12px; color: var(--good, #3fb950); }
.triage-labels {
margin-top: 14px; background: var(--surface-1, #131a29);
border: 1px solid var(--border-strong, #2c3a52); border-radius: 14px; padding: 16px 18px;
margin-top: 14px; background: var(--surface-1, #1a1c1a);
border: 1px solid var(--border-strong, #3f4340); border-radius: 14px; padding: 16px 18px;
}
.triage-labels-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
.triage-labels-list { display: flex; gap: 8px; flex-wrap: wrap; }
.triage-label-chip {
background: var(--surface-3, #1d2942); color: var(--text-1);
border: 1px solid var(--border, #22304a); border-radius: 99px;
background: var(--surface-3, #20221f); color: var(--text-1);
border: 1px solid var(--border, #2e302c); border-radius: 99px;
padding: 5px 12px; font: inherit; font-size: 0.85rem; cursor: pointer;
}
.triage-label-chip.on { border-color: var(--good, #3fb950); color: var(--good, #3fb950); }
.triage-done { background: var(--surface-1, #131a29); border: 1px solid var(--border-strong, #2c3a52); border-radius: 16px; padding: 26px 28px; }
.triage-done { background: var(--surface-1, #1a1c1a); border: 1px solid var(--border-strong, #3f4340); border-radius: 16px; padding: 26px 28px; }
.triage-summary { line-height: 1.9; }
.triage-projects { display: grid; gap: 10px; }
.triage-project {
display: flex; justify-content: space-between; align-items: center;
background: var(--surface-1, #131a29); border: 1px solid var(--border, #22304a);
background: var(--surface-1, #1a1c1a); border: 1px solid var(--border, #2e302c);
border-radius: 12px; padding: 16px 20px; color: var(--text-1); text-decoration: none;
}
.triage-project:hover { border-color: var(--accent, #58a6ff); }
.triage-project:hover { border-color: var(--accent, #c2437e); }
.triage-project-count { color: var(--text-3); }
/* ── Wallboard : navigation manuelle (0.11.0) ── */
@@ -1143,14 +1144,14 @@ footer {
border: 1px solid rgba(143, 163, 191, 0.45);
font-size: 1.15rem; cursor: pointer; backdrop-filter: blur(4px);
}
.wall-nav-btn:hover { border-color: #58a6ff; color: #fff; }
.wall-nav-btn:hover { border-color: #c2437e; color: #fff; }
.wall-dots { display: flex; gap: 8px; }
.wall-dot {
width: 13px; height: 13px; border-radius: 50%; padding: 0;
background: rgba(143, 163, 191, 0.35); border: 1px solid rgba(143, 163, 191, 0.5);
cursor: pointer;
}
.wall-dot.on { background: #58a6ff; border-color: #58a6ff; }
.wall-dot.on { background: #c2437e; border-color: #c2437e; }
.wall-paused {
position: fixed; top: 18px; left: 50%; transform: translateX(-50%);
background: rgba(19, 26, 41, 0.85); color: #f0b429;
@@ -1169,14 +1170,14 @@ footer {
.today-sub { color: var(--text-3); margin: 0 0 22px; }
.today-picks { display: grid; gap: 14px; margin-bottom: 20px; }
.today-card {
background: var(--surface-1, #131a29); border: 1px solid var(--border-strong, #2c3a52);
border-left: 5px solid var(--accent, #58a6ff); border-radius: 14px; padding: 20px 24px;
background: var(--surface-1, #1a1c1a); border: 1px solid var(--border-strong, #3f4340);
border-left: 5px solid var(--accent, #c2437e); border-radius: 14px; padding: 20px 24px;
}
.today-card.done { border-left-color: var(--good, #3fb950); opacity: 0.85; }
.today-card-top { display: flex; justify-content: space-between; color: var(--text-3); font-size: 0.85rem; }
.today-card h2 { margin: 8px 0 12px; font-size: 1.3rem; line-height: 1.35; }
.today-card-actions { display: flex; gap: 16px; align-items: center; }
.today-card-actions a { color: var(--accent, #58a6ff); text-decoration: none; font-size: 0.9rem; }
.today-card-actions a { color: var(--accent, #c2437e); text-decoration: none; font-size: 0.9rem; }
.today-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 10px; }
.today-list li { display: flex; justify-content: space-between; gap: 12px; align-items: center; }
.today-list em { color: var(--text-3); font-style: normal; font-size: 0.85rem; }
@@ -1184,35 +1185,35 @@ footer {
/* ── Prévisions + Récit (0.12.0, #7 #4) ── */
.forecast-flex { display: flex; gap: 22px; align-items: center; flex-wrap: wrap; }
.sparkline { width: 168px; height: 48px; }
.sparkline rect { fill: var(--accent, #58a6ff); opacity: 0.85; }
.sparkline rect { fill: var(--accent, #c2437e); opacity: 0.85; }
.forecast-nums p { margin: 4px 0; }
.forecast-milestones { margin: 12px 0 0; padding-left: 18px; line-height: 1.8; }
.forecast-line { color: var(--accent, #58a6ff); }
.milestone-forecast { color: var(--accent, #58a6ff); font-weight: 600; }
.milestone-sprint { color: var(--text-1); text-decoration: none; border: 1px solid var(--border, #22304a); border-radius: 8px; padding: 2px 10px; }
.milestone-sprint:hover { border-color: var(--accent, #58a6ff); }
.forecast-line { color: var(--accent, #c2437e); }
.milestone-forecast { color: var(--accent, #c2437e); font-weight: 600; }
.milestone-sprint { color: var(--text-1); text-decoration: none; border: 1px solid var(--border, #2e302c); border-radius: 8px; padding: 2px 10px; }
.milestone-sprint:hover { border-color: var(--accent, #c2437e); }
.sprint-render { line-height: 1.65; }
.sprint-render h1 { font-size: 1.5rem; }
.sprint-render h2 { font-size: 1.15rem; margin-top: 22px; }
.sprint-render a { color: var(--accent, #58a6ff); }
.sprint-render a { color: var(--accent, #c2437e); }
/* ── Code lié (0.13.0, #1) ── */
.card-code { font-size: 0.78rem; color: var(--accent, #58a6ff); margin-top: 5px; }
.card-code { font-size: 0.78rem; color: var(--accent, #c2437e); margin-top: 5px; }
.detail-code { margin: 10px 0; }
.code-line { padding: 3px 0; font-size: 0.9rem; color: var(--text-2, #b6c2d2); }
.code-line a { color: var(--accent, #58a6ff); text-decoration: none; }
.code-line code { background: var(--surface-3, #1d2942); border-radius: 4px; padding: 0 5px; }
.code-line { padding: 3px 0; font-size: 0.9rem; color: var(--text-2, #a6aba2); }
.code-line a { color: var(--accent, #c2437e); text-decoration: none; }
.code-line code { background: var(--surface-3, #20221f); border-radius: 4px; padding: 0 5px; }
/* ── Branche depuis la carte (0.14.0, #3) ── */
.branch-input {
background: var(--surface-3, #1d2942); color: var(--text-1);
border: 1px solid var(--border, #22304a); border-radius: 6px;
background: var(--surface-3, #20221f); color: var(--text-1);
border: 1px solid var(--border, #2e302c); border-radius: 6px;
padding: 3px 8px; font-family: monospace; font-size: 0.85rem;
}
/* ── Santé du flux (0.14.0, #9) ── */
.health-table { width: 100%; border-collapse: collapse; margin: 10px 0; }
.health-table th, .health-table td { text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border, #22304a); }
.health-table th, .health-table td { text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border, #2e302c); }
.health-slowest td { color: var(--warn, #e8a33d); font-weight: 600; }
.zombie-actions { display: flex; gap: 6px; flex-shrink: 0; }
@@ -1266,7 +1267,7 @@ body.sidebar-collapsed .sidebar { width: 68px; }
transition: border-color 0.15s, color 0.15s, transform 0.15s;
}
.side-search:hover {
color: var(--text); border-color: var(--accent, #58a6ff);
color: var(--text); border-color: var(--accent, #c2437e);
transform: translateY(-1px);
}
body.sidebar-collapsed .side-head { flex-direction: column; padding-left: 0; padding-right: 0; }
@@ -1297,11 +1298,13 @@ body.sidebar-collapsed .side-search { margin-left: 0; }
body.nav-closed-principal [data-group="principal"] .side-acc,
body.nav-closed-rituels [data-group="rituels"] .side-acc,
body.nav-closed-pilotage [data-group="pilotage"] .side-acc,
body.nav-closed-outils [data-group="outils"] .side-acc { grid-template-rows: 0fr; }
body.nav-closed-outils [data-group="outils"] .side-acc,
body.nav-closed-admin [data-group="admin"] .side-acc { grid-template-rows: 0fr; }
body.nav-closed-principal [data-group="principal"] .side-chevron,
body.nav-closed-rituels [data-group="rituels"] .side-chevron,
body.nav-closed-pilotage [data-group="pilotage"] .side-chevron,
body.nav-closed-outils [data-group="outils"] .side-chevron { transform: rotate(-90deg); }
body.nav-closed-outils [data-group="outils"] .side-chevron,
body.nav-closed-admin [data-group="admin"] .side-chevron { transform: rotate(-90deg); }
@media (min-width: 901px) {
/* Rail replié : pas d'accordéon, toutes les icônes visibles. */
body.sidebar-collapsed .side-acc { grid-template-rows: 1fr !important; }
@@ -1316,8 +1319,8 @@ body.nav-closed-outils [data-group="outils"] .side-chevron { transform: rotate(-
}
.side-link:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.side-link.active {
color: #fff; border-left-color: #a78bfa;
background: linear-gradient(90deg, rgba(124,92,252,.32), rgba(91,138,247,.14));
color: #fff; border-left-color: #c2437e;
background: linear-gradient(90deg, rgba(194,67,126,.32), rgba(224,120,168,.14));
}
.side-ico { font-size: 1.05rem; width: 22px; text-align: center; flex-shrink: 0; }
.side-foot {
@@ -1335,7 +1338,7 @@ body.nav-closed-outils [data-group="outils"] .side-chevron { transform: rotate(-
transition: border-color 0.15s, color 0.15s, transform 0.15s;
}
.side-collapse:hover {
color: var(--text); border-color: var(--accent, #58a6ff);
color: var(--text); border-color: var(--accent, #c2437e);
transform: translateY(-1px);
}
.side-fresh { color: var(--text-3); font-size: 0.76rem; white-space: nowrap; }
@@ -1401,10 +1404,10 @@ body.sidebar-collapsed .side-foot { justify-content: center; }
padding: 7px 14px; color: var(--text); background: var(--surface-1);
font-size: 0.88rem; font-weight: 600;
}
.health-chip:hover { text-decoration: none; border-color: var(--accent, #58a6ff); }
.health-chip:hover { text-decoration: none; border-color: var(--accent, #c2437e); }
.proj-actions { display: flex; gap: 8px; flex-wrap: wrap; margin: 18px 0 22px; }
.proj-actions .nav-pill { border: 1px solid var(--border); }
.proj-primary { background: linear-gradient(135deg, rgba(124,92,252,.85), rgba(91,138,247,.85)); color: #fff !important; }
.proj-primary { background: linear-gradient(135deg, rgba(194,67,126,.85), rgba(224,120,168,.85)); color: #fff !important; }
.proj-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px; }
.proj-panel {
background: var(--surface-1); border: 1px solid var(--border);
@@ -1451,7 +1454,7 @@ body.sidebar-collapsed .side-foot { justify-content: center; }
background: rgba(255, 255, 255, 0.08); color: var(--text-2);
border-radius: 999px; padding: 1px 7px;
}
.seg-tabs button.active .seg-count { background: rgba(124, 92, 252, 0.22); color: var(--text); }
.seg-tabs button.active .seg-count { background: rgba(194, 67, 126, 0.22); color: var(--text); }
.dash-toolbar .toolbar-search { padding: 0; flex: 1 1 200px; }
.dash-toolbar .toolbar-search input { max-width: none; background: var(--surface-2); }
.dash-tool { display: inline-flex; align-items: center; gap: 8px; font-size: 0.88rem; color: var(--text-2); white-space: nowrap; }
@@ -1460,13 +1463,13 @@ body.sidebar-collapsed .side-foot { justify-content: center; }
border: 1px solid var(--border); border-radius: 8px; padding: 6px 8px;
min-height: 36px;
}
.dash-tool-check input { width: 17px; height: 17px; accent-color: #7c5cfc; }
.dash-tool-check input { width: 17px; height: 17px; accent-color: #c2437e; }
.dash-view-toggle { margin-left: auto; display: inline-flex; border: 1px solid var(--border); border-radius: 9px; overflow: hidden; }
.dash-view-toggle button {
background: var(--surface-1); color: var(--text-2); border: none;
padding: 7px 14px; cursor: pointer; font-size: 0.88rem; min-height: 36px;
}
.dash-view-toggle button.active { background: var(--surface-3, #1d2942); color: var(--text); font-weight: 700; }
.dash-view-toggle button.active { background: var(--surface-3, #20221f); color: var(--text); font-weight: 700; }
.owner-group { grid-column: 1 / -1; }
.owner-head {
display: flex; justify-content: space-between; align-items: center;
@@ -1475,7 +1478,7 @@ body.sidebar-collapsed .side-foot { justify-content: center; }
border: 1px solid var(--border); border-radius: 10px;
font-size: 0.95rem; font-weight: 700;
}
.owner-head:hover { border-color: var(--accent, #58a6ff); }
.owner-head:hover { border-color: var(--accent, #c2437e); }
.owner-head .owner-chevron { transition: transform 0.2s ease; font-size: 0.7rem; }
.owner-head[aria-expanded="false"] .owner-chevron { transform: rotate(-90deg); }
.owner-grid { padding: 0 !important; }
@@ -1486,20 +1489,60 @@ body.sidebar-collapsed .side-foot { justify-content: center; }
padding: 2px 7px; border-radius: 8px; line-height: 1;
}
.card-menu-btn:hover { background: var(--surface-2); color: var(--text); }
.card-menu-btn[aria-expanded="true"] { background: var(--surface-2); color: var(--text); }
/* Menu ⋯ des tuiles projets — refonte issues #44/#45.
Jetons repris de la barre d'apps commune (draco-barre.css,
prototype validé Console v7.2, aussi utilisé par la console
Spark) : clair par défaut, sombre via [data-theme="dark"]
ou prefers-color-scheme. Correctif du bug d'origine : le
menu utilisait var(--surface-1), variable jamais définie,
donc aucun fond — le menu était transparent et illisible. */
.card-menu {
--menu-bg: #ffffff; --menu-bg-2: #e9eae6; --menu-ink: #1b1d1a;
--menu-ink-2: #5c615a; --menu-line: #dedfd9; --menu-agent: #c2437e;
position: absolute; right: 0; top: calc(100% + 6px); z-index: 60;
min-width: 210px; display: flex; flex-direction: column; gap: 2px;
background: var(--surface-1); border: 1px solid var(--border);
border-radius: 12px; padding: 6px;
box-shadow: 0 14px 34px rgba(0, 0, 0, 0.45);
min-width: 248px; display: flex; flex-direction: column; gap: 2px;
background: var(--menu-bg); border: 1px solid var(--menu-line);
border-radius: 14px; padding: 6px; color: var(--menu-ink);
box-shadow: 0 16px 44px rgb(0 0 0 / .28);
}
@media (prefers-color-scheme: dark) {
.card-menu {
--menu-bg: #1a1c1a; --menu-bg-2: #242624; --menu-ink: #eceee9;
--menu-ink-2: #a6aba2; --menu-line: #2e302c;
}
}
[data-theme="dark"] .card-menu {
--menu-bg: #1a1c1a; --menu-bg-2: #242624; --menu-ink: #eceee9;
--menu-ink-2: #a6aba2; --menu-line: #2e302c;
}
.card-menu[hidden] { display: none !important; }
.card-menu a {
.card-menu a, .card-menu-item {
display: flex; align-items: center; min-height: 32px;
padding: 8px 10px; border-radius: 8px;
color: var(--text-2); font-size: 0.92rem;
padding: 8px 10px; border-radius: 10px;
color: var(--menu-ink-2); font-size: 0.92rem;
}
.card-menu-item {
width: 100%; box-sizing: border-box; border: 0;
background: transparent; font: inherit; text-align: left; cursor: pointer;
}
.card-menu a:hover, .card-menu a:focus-visible,
.card-menu-item:hover, .card-menu-item:focus-visible {
background: var(--menu-bg-2); color: var(--menu-ink); text-decoration: none;
}
.card-menu a:focus-visible, .card-menu-item:focus-visible {
outline: 2px solid var(--menu-agent); outline-offset: 1px;
}
.card-menu-sep { height: 1px; margin: 6px 10px; background: var(--menu-line); }
/* Confirmation de copie — pastille fixe, lisible sur fond
clair comme sombre, même patron que la barre (draco). */
.kanbante-toast {
position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%);
z-index: 3000; background: #1f1f1f; color: #eee;
padding: 10px 16px; border-radius: 10px;
font: 500 13.5px system-ui, "Segoe UI", sans-serif;
box-shadow: 0 6px 24px rgb(0 0 0 / .35);
}
.card-menu a:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.proj-table {
width: calc(100% - 48px); margin: 0 24px 18px;
border-collapse: collapse; font-size: 0.93rem;
@@ -1528,7 +1571,7 @@ body.sidebar-collapsed .side-foot { justify-content: center; }
.forecast-summary { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0 4px; }
.forecast-summary .chip {
font-size: 12.5px; padding: 3px 10px; border-radius: 999px;
background: rgba(255, 255, 255, .07); border: 1px solid var(--border, #333);
background: rgba(255, 255, 255, .07); border: 1px solid var(--border, #2e302c);
}
.forecast-summary .chip-late { background: rgba(248, 81, 73, .15); }
.forecast-summary .chip-ok { background: rgba(63, 185, 80, .15); }
@@ -1548,8 +1591,8 @@ a.ms-title:hover { text-decoration: underline; }
}
.health-switch-bar select {
padding: 8px 10px; border-radius: 8px; font-size: 14px; min-height: 38px;
background: var(--panel-2, #1c2330); color: inherit;
border: 1px solid var(--border, #333);
background: var(--panel-2, #242624); color: inherit;
border: 1px solid var(--border, #2e302c);
}
.health-back { font-size: 13.5px; }
@@ -1570,11 +1613,11 @@ a.ms-title:hover { text-decoration: underline; }
padding: 8px 10px; border-radius: 8px; cursor: pointer;
font-weight: 400; font-size: 0.94rem;
}
.repo-item.active { background: var(--surface-2, #1c2330); }
.repo-item.active { background: var(--surface-2, #242624); }
.repo-item-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.repo-item-meta { color: var(--text-3, #8b94a5); font-size: 0.78rem; white-space: nowrap; }
.repo-item-meta { color: var(--text-3, #8b9089); font-size: 0.78rem; white-space: nowrap; }
.repo-hint { font-weight: 400; font-size: 0.85rem; color: #f0a35e; }
.repo-tip { font-weight: 400; font-size: 0.82rem; color: var(--text-3, #8b94a5); }
.repo-tip { font-weight: 400; font-size: 0.82rem; color: var(--text-3, #8b9089); }
.repo-tip kbd {
font-size: 0.72rem; border: 1px solid var(--border); border-bottom-width: 2px;
border-radius: 5px; padding: 0 5px; background: var(--surface);
@@ -1586,14 +1629,14 @@ a.ms-title:hover { text-decoration: underline; }
min-height: 100dvh; margin: 0;
display: flex; align-items: center; justify-content: center;
background:
radial-gradient(640px 420px at 18% 12%, rgba(124, 92, 252, 0.20), transparent 62%),
radial-gradient(560px 380px at 84% 88%, rgba(91, 138, 247, 0.16), transparent 60%),
var(--bg, #0a0f16);
radial-gradient(640px 420px at 18% 12%, rgba(194, 67, 126, 0.20), transparent 62%),
radial-gradient(560px 380px at 84% 88%, rgba(224, 120, 168, 0.16), transparent 60%),
var(--bg, #101211);
padding: 24px 16px;
}
.login-wrap { width: 100%; max-width: 400px; }
.login-card {
background: var(--surface, #10151f);
background: var(--surface, #1a1c1a);
border: 1px solid var(--border);
border-radius: 18px;
padding: 34px 32px 26px;
@@ -1603,16 +1646,16 @@ a.ms-title:hover { text-decoration: underline; }
.login-mark {
display: inline-flex; align-items: center; justify-content: center;
width: 56px; height: 56px; border-radius: 16px; font-size: 1.7rem;
background: linear-gradient(135deg, rgba(124,92,252,.35), rgba(91,138,247,.25));
background: linear-gradient(135deg, rgba(194,67,126,.35), rgba(224,120,168,.25));
border: 1px solid var(--border);
}
.login-brand h1 {
margin: 12px 0 4px; font-size: 1.55rem; font-weight: 700;
background: linear-gradient(120deg, #a78bfa, #7dd3fc);
background: linear-gradient(120deg, #c2437e, #e078a8);
-webkit-background-clip: text; background-clip: text;
-webkit-text-fill-color: transparent;
}
.login-sub { margin: 0; color: var(--text-3, #8b94a5); font-size: 0.9rem; }
.login-sub { margin: 0; color: var(--text-3, #8b9089); font-size: 0.9rem; }
.login-error {
margin: 0 0 14px; padding: 10px 12px; border-radius: 10px;
background: rgba(240, 120, 90, 0.12); border: 1px solid rgba(240, 120, 90, 0.45);
@@ -1622,13 +1665,13 @@ a.ms-title:hover { text-decoration: underline; }
.login-form label { display: flex; flex-direction: column; gap: 6px; font-weight: 600; font-size: 0.92rem; }
.login-form input {
padding: 11px 13px; border: 1px solid var(--border); border-radius: 10px;
background: var(--bg-2, #0d1220); color: var(--text-1, #e6ebf2);
background: var(--bg-2, #101211); color: var(--text-1, #eceee9);
font: inherit; font-weight: 400;
}
.login-form input:focus { outline: 2px solid rgba(124, 92, 252, 0.55); outline-offset: 0; border-color: transparent; }
.login-form input:focus { outline: 2px solid rgba(194, 67, 126, 0.55); outline-offset: 0; border-color: transparent; }
.login-submit {
margin-top: 4px; padding: 12px 18px; cursor: pointer;
background: linear-gradient(135deg, var(--accent, #7c5cfc), var(--accent-2, #5b8af7));
background: linear-gradient(135deg, var(--accent, #c2437e), var(--accent-2, #e078a8));
color: #fff; border: none; border-radius: 10px;
font: inherit; font-weight: 600; font-size: 1rem;
transition: filter 0.15s, transform 0.1s;
@@ -1637,14 +1680,14 @@ a.ms-title:hover { text-decoration: underline; }
.login-submit:active { transform: scale(0.98); }
.login-sso {
display: block; margin-top: 12px; padding: 11px 18px; text-align: center;
color: var(--text-1, #e6ebf2); text-decoration: none;
color: var(--text-1, #eceee9); text-decoration: none;
border: 1px solid var(--border); border-radius: 10px;
font: inherit; font-weight: 500; font-size: 0.95rem;
transition: filter 0.15s, transform 0.1s;
}
.login-sso:hover { filter: brightness(1.35); }
.login-sso:active { transform: scale(0.98); }
.login-foot { margin: 18px 0 0; text-align: center; color: var(--text-3, #8b94a5); font-size: 0.8rem; }
.login-foot { margin: 18px 0 0; text-align: center; color: var(--text-3, #8b9089); font-size: 0.8rem; }
/* ── Fusion ACC-1 (kanbante#28) : cohabitation avec la barre commune ──
La barre d'apps est FIXE et pleine largeur (0.23.1 — en flux, le
@@ -1662,26 +1705,26 @@ body.has-draco-bar .sidebar { top: 60px; }
/* ── Espaces, admin, profils (0.24.0) ─────────────────── */
.ws-switch { display: flex; align-items: center; gap: 8px; padding: 10px 14px 2px; }
.ws-dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; flex: none; }
.ws-select { flex: 1; min-width: 0; background: var(--surface-2, #1c1c22); color: inherit;
border: 1px solid var(--border, #333); border-radius: 8px; padding: 6px 8px; font: inherit; }
.ws-select { flex: 1; min-width: 0; background: var(--surface-2, #242624); color: inherit;
border: 1px solid var(--border, #2e302c); border-radius: 8px; padding: 6px 8px; font: inherit; }
body.sidebar-collapsed .ws-switch { display: none; }
.admin-form { display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: end; margin: 10px 0; }
.admin-form label { display: flex; flex-direction: column; gap: 4px; font-size: 0.85em; }
.admin-form input[type="text"], .admin-form input[type="password"], .admin-form select {
background: var(--surface-2, #1c1c22); color: inherit;
border: 1px solid var(--border, #333); border-radius: 8px; padding: 7px 9px; font: inherit; }
background: var(--surface-2, #242624); color: inherit;
border: 1px solid var(--border, #2e302c); border-radius: 8px; padding: 7px 9px; font: inherit; }
.inline-form { display: inline-flex; gap: 6px; align-items: center; }
.btn-mini { padding: 4px 10px; font-size: 0.85em; border-radius: 8px;
border: 1px solid var(--border, #333); background: var(--surface-2, #1c1c22);
border: 1px solid var(--border, #2e302c); background: var(--surface-2, #242624);
color: inherit; cursor: pointer; }
.btn-mini:hover { border-color: var(--accent, #7c5cfc); }
.btn-mini:hover { border-color: var(--accent, #c2437e); }
.btn-mini:disabled { opacity: 0.45; cursor: not-allowed; }
.btn-danger:hover { border-color: #e5534b; color: #e5534b; }
.chip-ok { display: inline-block; padding: 4px 10px; border-radius: 999px;
background: rgba(16, 185, 129, 0.15); border: 1px solid rgba(16, 185, 129, 0.5); }
.admin-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.conn-badge { font-size: 0.78em; padding: 1px 7px; border-radius: 999px;
border: 1px solid var(--border, #333); white-space: nowrap; }
border: 1px solid var(--border, #2e302c); white-space: nowrap; }
.seg-link { align-self: center; margin-left: 8px; font-size: 0.85em; text-decoration: none; }
/* ── Tiroir de détail : édition et pièces jointes (0.31.0) ── */
@@ -1689,7 +1732,7 @@ body.sidebar-collapsed .ws-switch { display: none; }
.detail-actions { margin: 10px 0; }
#detail-edit-form input[type="text"] { width: 100%; margin-bottom: 8px; }
#detail-edit-form textarea { width: 100%; }
.asset-row { display: flex; align-items: center; gap: 10px; padding: 6px 0; border-bottom: 1px solid var(--border, #333); }
.asset-row { display: flex; align-items: center; gap: 10px; padding: 6px 0; border-bottom: 1px solid var(--border, #2e302c); }
.asset-row a { text-decoration: none; font-weight: 600; }
.asset-meta { color: var(--muted, #999); font-size: 0.85em; margin-right: auto; }
.asset-form { display: flex; gap: 8px; align-items: center; margin: 8px 0 4px; flex-wrap: wrap; }
@@ -1701,10 +1744,10 @@ body.sidebar-collapsed .ws-switch { display: none; }
.composer { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 12px 14px; margin: 6px 0 10px; }
.composer-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 10px; }
.composer-title { font-weight: 700; font-size: 0.95rem; }
.composer-target { color: var(--muted, #9aa3b5); font-size: 0.82rem; }
.composer-target { color: var(--muted, #a6aba2); font-size: 0.82rem; }
.composer-main { display: flex; gap: 8px; }
.composer-main input[type="text"] { flex: 1; background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; padding: 9px 12px; color: inherit; font-size: 0.95rem; }
.composer-main input[type="text"]:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(124, 92, 252, 0.25); }
.composer-main input[type="text"]:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(194, 67, 126, 0.25); }
.composer-desc { margin-top: 10px; }
.composer-desc summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; font-size: 0.88rem; color: var(--accent-2); padding: 4px 2px; user-select: none; }
.composer-desc summary::-webkit-details-marker { display: none; }
@@ -1712,8 +1755,8 @@ body.sidebar-collapsed .ws-switch { display: none; }
.composer-chevron { transition: transform 0.15s ease; font-size: 0.75rem; }
.composer-desc[open ] .composer-chevron { transform: rotate(180deg); }
.composer-desc textarea { width: 100%; margin-top: 8px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; color: inherit; font-family: inherit; resize: vertical; }
.composer-desc textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(124, 92, 252, 0.25); }
.composer-hint { color: var(--muted, #9aa3b5); font-size: 0.78rem; margin: 6px 0 0; }
.composer-desc textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(194, 67, 126, 0.25); }
.composer-hint { color: var(--muted, #a6aba2); font-size: 0.78rem; margin: 6px 0 0; }
/* ── Mes issues : barre de filtres (0.33.0) ── */
.my-filters { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 12px 14px; margin: 12px 0 18px; }
@@ -1722,22 +1765,22 @@ body.sidebar-collapsed .ws-switch { display: none; }
.my-search-wrap { position: relative; flex: 1 1 280px; }
.my-search-icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); opacity: 0.65; pointer-events: none; }
.my-search-wrap input[type="search"] { width: 100%; background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px; padding: 9px 14px 9px 38px; color: inherit; font-size: 0.92rem; }
.my-search-wrap input[type="search"]:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(124, 92, 252, 0.25); }
.my-search-wrap input[type="search"]:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(194, 67, 126, 0.25); }
.my-filters select { background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; padding: 9px 10px; color: inherit; font-size: 0.9rem; }
.my-filters select:focus { outline: none; border-color: var(--accent); }
.my-col-chips { display: flex; gap: 6px; flex-wrap: wrap; margin-right: auto; }
.filter-chip { display: inline-flex; align-items: center; gap: 6px; background: var(--surface-2); border: 1px solid var(--border); color: inherit; border-radius: 999px; padding: 5px 12px; font-size: 0.85rem; cursor: pointer; transition: border-color 0.15s, background 0.15s; }
.filter-chip:hover { border-color: var(--border-strong); }
.filter-chip.on { background: rgba(124, 92, 252, 0.18); border-color: var(--accent); font-weight: 600; }
.filter-chip.on { background: rgba(194, 67, 126, 0.18); border-color: var(--accent); font-weight: 600; }
.filter-chip-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.filter-chip-count { opacity: 0.7; font-size: 0.78rem; }
.my-count { color: var(--muted, #9aa3b5); font-size: 0.88rem; white-space: nowrap; }
.my-count { color: var(--muted, #a6aba2); font-size: 0.88rem; white-space: nowrap; }
/* ── En vol partout (0.34.0, issue #24) ── */
.inflight-summary { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 10px 0 18px; }
.inflight-total { font-weight: 700; margin-right: 4px; }
.inflight-repo { color: var(--accent-2); font-weight: 600; font-size: 0.85rem; }
.inflight-wip { color: var(--muted, #9aa3b5); font-size: 0.8rem; font-weight: 400; margin-left: 8px; }
.inflight-wip { color: var(--muted, #a6aba2); font-size: 0.8rem; font-weight: 400; margin-left: 8px; }
/* ── Page Projet : gestion des jalons (0.35.0, #26) ── */
.ms-edit { margin-top: 8px; }
@@ -1748,5 +1791,38 @@ body.sidebar-collapsed .ws-switch { display: none; }
.ms-form label { display: flex; flex-direction: column; gap: 4px; font-size: 0.85rem; }
.ms-form input[type="text"], .ms-form input[type="date"], .ms-form textarea { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; color: inherit; font-family: inherit; }
.ms-form input:focus, .ms-form textarea:focus { outline: none; border-color: var(--accent); }
.ms-hint { color: var(--muted, #9aa3b5); font-size: 0.78rem; }
.ms-hint { color: var(--muted, #a6aba2); font-size: 0.78rem; }
.ms-form-actions { display: flex; gap: 8px; }
/* ── Thème clair (#52) : jetons draco-barre (clair par défaut).
html[data-theme="light"] prime sur le :root sombre et sur le
prefers-color-scheme de la barre Fusion. Le sombre reste le
défaut (les gabarits portent data-theme="dark", le JS du
thème ne bascule que sur choix mémorisé). */
html[data-theme="light"] {
--bg: #f2f2f0; --surface: #ffffff; --surface-2: #e9eae6; --surface-3: #f6f6f3;
--border: #dedfd9; --border-strong: #c9cbc2;
--text: #1b1d1a; --text-2: #5c615a; --text-3: #787d75;
--accent: #c2437e; --accent-2: #a92e63;
--shadow: 0 8px 28px rgba(0, 0, 0, 0.12);
--shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.08);
color-scheme: light;
}
html[data-theme="light"] .sidebar { background: rgba(255, 255, 255, 0.96); }
html[data-theme="light"] .app-header { background: rgba(255, 255, 255, 0.85); }
/* Lien actif de la barre latérale : fond rose translucide sur
fond clair — le texte blanc du thème sombre y serait illisible. */
html[data-theme="light"] .side-link.active { color: #1b1d1a; }
/* Menu ⋯ des tuiles : jetons clairs explicites, pour primer sur
le prefers-color-scheme sombre du système. */
html[data-theme="light"] .card-menu {
--menu-bg: #ffffff; --menu-bg-2: #e9eae6; --menu-ink: #1b1d1a;
--menu-ink-2: #5c615a; --menu-line: #dedfd9;
}
/* Barre Fusion : jetons clairs explicites, pour primer sur son
@media (prefers-color-scheme: dark). Le panneau Spark suit
via son MutationObserver sur data-theme (draco-panneau.js). */
html[data-theme="light"] .draco-bar {
--bg: #f2f2f0; --surface: #ffffff; --surface-2: #e9eae6; --surface-3: #f6f6f3;
--ink: #1b1d1a; --ink-2: #5c615a; --ink-3: #787d75; --line: #dedfd9;
}
+41
View File
@@ -176,6 +176,47 @@
if (e.key === 'Escape') closeMenus();
});
/* ── Copier l'URL du projet (#44) ─────────────────────── */
function showCopyToast(message) {
var toast = document.createElement('div');
toast.className = 'kanbante-toast';
toast.setAttribute('role', 'status');
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(function () { toast.remove(); }, 2600);
}
function copyTextFallback(text) {
var area = document.createElement('textarea');
area.value = text;
area.style.cssText = 'position:fixed;opacity:0;pointer-events:none;';
document.body.appendChild(area);
area.select();
var ok = false;
try { ok = document.execCommand('copy'); } catch (e) { ok = false; }
area.remove();
return ok;
}
function copyText(text) {
if (navigator.clipboard && window.isSecureContext) {
return navigator.clipboard.writeText(text).then(
function () { return true; },
function () { return copyTextFallback(text); }
);
}
return Promise.resolve(copyTextFallback(text));
}
document.querySelectorAll('[data-copy-url]').forEach(function (btn) {
btn.addEventListener('click', function (e) {
e.stopPropagation();
var url = btn.getAttribute('data-copy-url') || '';
if (!url) return;
copyText(url).then(function (ok) {
closeMenus();
showCopyToast(ok ? 'URL du projet copiée' : 'La copie a échoué');
});
});
});
/* Le tri des tableaux denses (#22) vit dans tablesort.js,
partagé avec /forecast et /health (0.19.0). */
})();
+20
View File
@@ -34,6 +34,26 @@
if (window.innerWidth > 900) closeDrawer();
});
/* Bascule Dark/Light (#52) : le choix est mémorisé et
l'amorce de _header.html l'a déjà appliqué avant le rendu.
Ici, on ne fait que synchroniser le libellé et le clic. */
var themeBtn = document.getElementById('theme-toggle');
function syncThemeBtn(theme) {
if (!themeBtn) return;
var light = theme === 'light';
themeBtn.textContent = light ? '🌙 Mode sombre' : '☀️ Mode clair';
themeBtn.setAttribute('aria-pressed', light ? 'true' : 'false');
}
if (themeBtn) {
syncThemeBtn(document.documentElement.getAttribute('data-theme') || 'dark');
themeBtn.addEventListener('click', function () {
var next = document.documentElement.getAttribute('data-theme') === 'light' ? 'dark' : 'light';
document.documentElement.setAttribute('data-theme', next);
try { localStorage.setItem('kanbante-theme', next); } catch (e) { /* non-fatal */ }
syncThemeBtn(next);
});
}
if (collapseBtn) {
collapseBtn.addEventListener('click', function () {
var collapsed = document.body.classList.toggle('sidebar-collapsed');
+34
View File
@@ -0,0 +1,34 @@
"""Menu ⋯ des tuiles projets : copie d'URL (#44) et thème
opaque barre Fusion / Spark, sombre et clair (#45).
Le menu était transparent parce que son fond utilisait
var(--surface-1), variable jamais définie dans :root.
"""
def test_card_menu_offers_copy_url(client, fake_gitea):
page = client.get("/")
assert "Copier l'URL du projet" in page.text
assert 'data-copy-url="http://gitea.test/Projets/demo"' in page.text
def test_card_menu_theme_is_opaque_and_dual(client, fake_gitea):
css = client.get("/static/css/style.css").text
# Le menu ne repose plus sur la variable indéfinie.
menu = css.split(".card-menu {", 1)[1].split("}", 1)[0]
assert "var(--surface-1)" not in menu
assert "var(--menu-bg)" in menu
# Jetons barre Fusion / Console v7.2, clair par défaut…
assert "--menu-bg: #ffffff" in css
# …et variante sombre explicite, comme draco-barre.css.
assert '[data-theme="dark"] .card-menu' in css
assert "--menu-bg: #1a1c1a" in css
assert "prefers-color-scheme: dark" in css
def test_dashboard_js_copy_contract(client, fake_gitea):
js = client.get("/static/js/dashboard.js").text
assert "data-copy-url" in js
assert "navigator.clipboard" in js
assert "execCommand('copy')" in js
assert "URL du projet copiée" in js
+12
View File
@@ -0,0 +1,12 @@
"""Page Projets (#47) : les fichiers qui portent le menu ⋯ et la
copie d'URL doivent être versionnés, sinon le navigateur garde
l'ancien CSS/JS après une release alors que le HTML est neuf —
c'est exactement ce qui a fait paraître la 0.38.0 inefficace
(menu toujours transparent, bouton de copie présent mais inerte).
"""
def test_dashboard_static_assets_are_versioned(client, fake_gitea):
page = client.get("/")
assert "/static/css/style.css?v=" in page.text
assert "/static/js/dashboard.js?v=" in page.text
+37
View File
@@ -0,0 +1,37 @@
"""Navigation (#51) et bascule Dark/Light (#52).
L'accordéon de la barre latérale omettait la section admin :
le JS posait nav-closed-admin, mais aucun style ne la suivait.
Le thème clair, lui, doit être atteignable par un bouton et
mémorisé, avec les jetons draco clairs.
"""
def test_admin_accordion_closes(client, fake_gitea):
css = client.get("/static/css/style.css").text
assert 'body.nav-closed-admin [data-group="admin"] .side-acc' in css
assert 'body.nav-closed-admin [data-group="admin"] .side-chevron' in css
def test_theme_toggle_present_and_versioned(client, fake_gitea):
page = client.get("/")
assert 'id="theme-toggle"' in page.text
assert "Mode clair" in page.text
assert "/static/js/nav.js?v=" in page.text
def test_theme_js_contract(client, fake_gitea):
js = client.get("/static/js/nav.js").text
assert "kanbante-theme" in js
assert "theme-toggle" in js
assert "data-theme" in js
def test_light_theme_tokens(client, fake_gitea):
css = client.get("/static/css/style.css").text
assert 'html[data-theme="light"]' in css
assert "--bg: #f2f2f0;" in css
assert "--surface: #ffffff;" in css
assert "--accent-2: #a92e63;" in css
assert 'html[data-theme="light"] .draco-bar' in css
assert 'html[data-theme="light"] .card-menu' in css
+28
View File
@@ -0,0 +1,28 @@
"""Thème du site (#49) : Kanbante doit ressembler à la console
agent / barre Fusion (draco-barre, Console v7.2), pas au bleu/mauve
historique. Le test fige les jetons et interdit le retour des
littéraux violet/bleu de thème dans style.css.
"""
def test_theme_agent_tokens(client, fake_gitea):
css = client.get("/static/css/style.css").text
assert "--bg: #101211;" in css
assert "--surface: #1a1c1a;" in css
assert "--surface-2: #242624;" in css
assert "--surface-3: #20221f;" in css
assert "--border: #2e302c;" in css
assert "--text: #eceee9;" in css
assert "--accent: #c2437e;" in css
assert "--accent-2: #e078a8;" in css
def test_no_blue_purple_theme_literals(client, fake_gitea):
css = client.get("/static/css/style.css").text
for banned in (
"#7c5cfc", "#5b8af7", "#58a6ff", "#a78bfa", "#7dd3fc",
"#c4b5fd", "#a5c4fd", "#0b0e14", "#141822", "#1b202e",
"#232939", "124, 92, 252", "124,92,252",
"91, 138, 247", "91,138,247",
):
assert banned not in css, banned