Files
kanbante/app/templates/board.html
T
Spark 9bf24da04e feat(frontend): panneau détail de carte, badges d'âge, limites WIP
- drawer de détail: corps markdown rendu (marked + DOMPurify
  vendorés), commentaires, formulaire de commentaire vers Gitea;
  clic distingué du drag par la distance du pointeur
- badges ⏳ N j au-delà du seuil d'âge (rouge au double)
- en-têtes de colonnes: n/limite, classe .over en rouge, toast
  d'avertissement au dépôt dans une colonne saturée
- page activity.html, liens Activité dans dashboard et board
2026-10-11 10:05:51 -04:00

152 lines
7.1 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="fr" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="csrf-token" content="{{ csrf_token }}">
<title>{{ repo }} — Kanbante</title>
<link rel="stylesheet" href="/static/css/style.css">
<script src="/static/vendor/htmx.min.js"></script>
<script src="/static/vendor/sortable.min.js"></script>
<script src="/static/vendor/marked.min.js"></script>
<script src="/static/vendor/purify.min.js"></script>
<script src="/static/js/board.js" defer></script>
</head>
<body>
<header>
<h1>
<a href="/">📋 Kanbante</a>
<span class="sep">/</span>
<span>{{ owner }}/</span><strong>{{ repo }}</strong>
</h1>
<nav>
<a href="/focus" class="btn-sm">🎯 Focus</a>
<a href="/activity" class="btn-sm">📰 Activité</a>
{% if repo_info.html_url %}
<a href="{{ repo_info.html_url }}" target="_blank" class="btn-sm">🔗 Gitea</a>
{% endif %}
</nav>
</header>
<!-- Toolbar: text + label filters, and issue creation (Gitea-backed) -->
<div class="board-toolbar">
<input type="text" id="card-filter" placeholder="🔍 Filtrer les cartes...">
<select id="label-filter">
<option value="">Toutes les étiquettes</option>
{% for label in labels %}
<option value="{{ label.name }}">{{ label.name }}</option>
{% endfor %}
</select>
<form id="create-issue-form">
<input type="text" id="new-issue-title" maxlength="255"
placeholder="➕ Nouvelle issue (titre)..." required>
<button type="submit" class="btn-save btn-inline">Créer</button>
</form>
</div>
<main class="board-container">
<div class="kanban-board">
{% for col in ['backlog','todo','in_progress','review','done'] %}
<div class="kanban-column"
data-column="{{ col }}">
<div class="column-header" style="border-top: 3px solid {{ column_colors[col] }}">
<span class="column-title">{{ column_labels[col] }}</span>
{% set limit = wip_limits.get(col) %}
<span class="column-count{% if limit and columns[col]|length > limit %} over{% endif %}"
{% if limit %}data-limit="{{ limit }}" title="Limite WIP : {{ limit }}"{% endif %}>{% if limit %}{{ columns[col]|length }}/{{ limit }}{% else %}{{ columns[col]|length }}{% endif %}</span>
</div>
<div class="column-cards" data-column="{{ col }}">
{% for issue in columns[col] %}
<div class="kanban-card"
data-issue="{{ issue.number }}"
data-repo="{{ full_name }}"
data-title="{{ issue.title|lower }}"
data-labels="{{ issue.labels|map(attribute='name')|join(',')|lower }}">
<div class="card-id">
#{{ issue.number }}
{% if issue.html_url %}
<a href="{{ issue.html_url }}" target="_blank" title="Ouvrir dans Gitea">↗</a>
{% endif %}
</div>
<div class="card-title">{{ issue.title }}</div>
{% if issue.labels %}
<div class="card-labels">
{% for label in issue.labels %}
<span class="label-tag" style="background: #{{ label.color }}30; color: #{{ label.color }}">
{{ label.name }}
</span>
{% endfor %}
</div>
{% endif %}
<div class="card-meta">
{% if issue.assignee %}
<img src="{{ issue.assignee.avatar_url }}" class="avatar" alt="{{ issue.assignee.login }}">
{% endif %}
<span class="card-date">{{ issue.created_at[:10] }}</span>
{% set age = ages.get(issue.number) %}
{% if age and age.days >= aging_days %}
<span class="age-badge{% if age.days >= aging_days * 2 %} stale{% endif %}"
title="Dans cette colonne depuis le {{ age.since[:10] }}">⏳ {{ age.days }} j</span>
{% endif %}
</div>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
<!-- Notes panel -->
<aside class="notes-panel">
<h3>📝 Notes du projet</h3>
<form hx-post="/api/notes" hx-swap="none"
hx-on::after-request="if(event.detail.successful) showNotesSaved()">
<input type="hidden" name="repo_full_name" value="{{ full_name }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<textarea name="note" rows="10"
placeholder="Notes, idées, liens...">{{ notes }}</textarea>
<button type="submit" class="btn-save">💾 Sauvegarder</button>
</form>
</aside>
</main>
<!-- Card detail drawer: issue body, comments, comment form -->
<div id="detail-overlay" class="detail-overlay" hidden></div>
<aside id="card-detail" class="card-detail" hidden>
<div class="detail-head">
<span id="detail-number" class="card-id"></span>
<span id="detail-state" class="chip"></span>
<button id="detail-close" class="btn-sm" type="button">✕</button>
</div>
<h2 id="detail-title"></h2>
<div id="detail-meta" class="detail-meta"></div>
<div id="detail-labels" class="card-labels"></div>
<div id="detail-body" class="detail-body"></div>
<h3 class="detail-comments-title">💬 Commentaires</h3>
<div id="detail-comments"></div>
<form id="comment-form">
<textarea id="comment-body" rows="3" maxlength="10000"
placeholder="Écrire un commentaire (markdown)..."></textarea>
<button type="submit" class="btn-save">💬 Commenter dans Gitea</button>
</form>
<p class="detail-foot"><a id="detail-gitea-link" href="#" target="_blank">Ouvrir dans Gitea ↗</a></p>
</aside>
<footer>
<span>{{ full_name }}</span>
{% if repo_info.updated_at %}
<span>Mis à jour {{ repo_info.updated_at[:10] }}</span>
{% endif %}
</footer>
<script>
function showNotesSaved() {
const toast = document.createElement('div');
toast.className = 'toast';
toast.textContent = '✅ Notes sauvegardées';
document.body.appendChild(toast);
setTimeout(() => toast.remove(), 2000);
}
</script>
</body>
</html>