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
CI / test (push) Successful in 4m2s
This commit was merged in pull request #46.
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
## 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
@@ -177,7 +177,7 @@ from urllib.parse import urlparse
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
APP_VERSION = "0.37.6"
|
||||
APP_VERSION = "0.38.0"
|
||||
|
||||
|
||||
def _env_bool(name: str, default: bool) -> bool:
|
||||
|
||||
@@ -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>
|
||||
|
||||
+48
-8
@@ -1486,20 +1486,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;
|
||||
|
||||
@@ -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). */
|
||||
})();
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user