1e41ef207e
- Carte visiteurs uniques non-bot : 7 / 14 / 30 jours en tête de /admin/stats - Bouton ✕ par AS pour l'exclure des stats ; section AS exclus avec ↺ - Alerte IPs sans résolution AS dans la carte pays - Parser : fenêtre 30 jours, calcul visiteurs uniques toutes IPs non-bot - Graphiques adaptés à 30 jours (labels x/3) - Réactions articles : 👍 uniquement (suppression 🔥 et 🤔) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
144 lines
7.0 KiB
PHP
144 lines
7.0 KiB
PHP
<?php
|
|
// Variables attendues (injectées depuis index.php) :
|
|
// $article — tableau article courant (uuid, slug, title)
|
|
// $reactionStats — array<string, int>
|
|
// $visitorReactions — string[] (types déjà cliqués par ce visiteur)
|
|
// $comments — array de commentaires publiés
|
|
// $commentFlash — bool|null (commentaire soumis, email envoyé)
|
|
// $commentVerified — bool|null (commentaire vérifié et publié)
|
|
// $commentError — string|null (message d'erreur)
|
|
|
|
$_reactionDefs = [
|
|
'useful' => ['👍', 'Utile'],
|
|
];
|
|
|
|
$_csrfToken = bin2hex(random_bytes(16));
|
|
setcookie('_csrf_c', $_csrfToken, [
|
|
'expires' => 0,
|
|
'path' => '/',
|
|
'secure' => !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off',
|
|
'httponly' => true,
|
|
'samesite' => 'Strict',
|
|
]);
|
|
?>
|
|
|
|
<?php if (!empty($alsoReadArticles ?? [])): ?>
|
|
<!-- ── À lire aussi ──────────────────────────────────────────────── -->
|
|
<div class="also-read mb-4" id="also-read">
|
|
<h6 class="also-read-title">À lire aussi</h6>
|
|
<div class="also-read-grid">
|
|
<?php foreach ($alsoReadArticles as $_also):
|
|
$_alsoCover = $_also['cover'] ?? '';
|
|
$_alsoCat = trim($_also['category'] ?? '');
|
|
$_alsoGradient = coverGradient($_alsoCat !== '' ? $_alsoCat : $_also['uuid'], $allCats ?? []);
|
|
$_alsoDate = date('d/m/Y', strtotime((string)($_also['published_at'] ?? $_also['created_at'] ?? '')));
|
|
?>
|
|
<a href="/post/<?= rawurlencode($_also['slug'] ?? '') ?>" class="related-card">
|
|
<div class="related-card-thumb" style="<?= $_alsoCover !== ''
|
|
? 'background-image:url(/file?uuid=' . rawurlencode($_also['uuid']) . '&name=' . rawurlencode($_alsoCover) . ');background-size:cover;background-position:center'
|
|
: 'background:' . htmlspecialchars($_alsoGradient) ?>"></div>
|
|
<div class="related-card-body">
|
|
<div class="related-card-title"><?= htmlspecialchars($_also['title']) ?></div>
|
|
<div class="related-card-date"><?= $_alsoDate ?></div>
|
|
</div>
|
|
</a>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- ── Commentaires ───────────────────────────────────────────────── -->
|
|
<div id="comments" class="mb-4">
|
|
|
|
<h5 class="mb-3">
|
|
Commentaires
|
|
<?php if (!empty($comments)): ?>
|
|
<span class="badge bg-secondary ms-1"><?= count($comments) ?></span>
|
|
<?php endif; ?>
|
|
</h5>
|
|
|
|
<?php if ($commentFlash ?? false): ?>
|
|
<div class="alert alert-info">
|
|
Un code de confirmation vous a été envoyé par email.
|
|
Cliquez sur le lien reçu, puis saisissez le code à 6 chiffres pour publier votre commentaire.
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($commentVerified ?? false): ?>
|
|
<div class="alert alert-success">Votre commentaire a été publié. Merci !</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if (!empty($commentError ?? null)): ?>
|
|
<div class="alert alert-danger"><?= htmlspecialchars($commentError) ?></div>
|
|
<?php endif; ?>
|
|
|
|
<?php foreach ($comments as $c): ?>
|
|
<div class="card mb-3 comment-card" id="comment-<?= (int)$c['id'] ?>">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between align-items-start mb-2">
|
|
<strong class="comment-author"><?= htmlspecialchars($c['author_name']) ?></strong>
|
|
<small class="text-muted">
|
|
<?= htmlspecialchars(date('d/m/Y à H\hi', strtotime((string)$c['created_at']))) ?>
|
|
</small>
|
|
</div>
|
|
<div class="comment-content"><?= nl2br(htmlspecialchars((string)$c['content'])) ?></div>
|
|
<?php if (function_exists('isAdmin') && isAdmin()): ?>
|
|
<div class="mt-2">
|
|
<form method="post" action="/comment-moderate" class="d-inline">
|
|
<input type="hidden" name="id" value="<?= (int)$c['id'] ?>">
|
|
<input type="hidden" name="pub" value="0">
|
|
<button type="submit" class="btn btn-sm btn-outline-danger">Masquer</button>
|
|
</form>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
|
|
<?php if (empty($comments) && !($commentFlash ?? false) && !($commentVerified ?? false)): ?>
|
|
<p class="text-muted mb-4">Aucun commentaire pour l'instant. Soyez le premier !</p>
|
|
<?php endif; ?>
|
|
|
|
<!-- Formulaire -->
|
|
<div class="card mt-3" id="comment-form-card">
|
|
<div class="card-body">
|
|
<h6 class="card-title mb-3">Laisser un commentaire</h6>
|
|
<form method="post" action="/comment" id="comment-form">
|
|
<input type="hidden" name="_token" value="<?= htmlspecialchars($_csrfToken) ?>">
|
|
<input type="hidden" name="uuid" value="<?= htmlspecialchars($article['uuid']) ?>">
|
|
<!-- honeypot -->
|
|
<div class="d-none" aria-hidden="true">
|
|
<input type="text" name="website" tabindex="-1" autocomplete="off">
|
|
</div>
|
|
<div class="row g-3">
|
|
<div class="col-sm-6">
|
|
<label class="form-label" for="comment-name">Nom <span class="text-danger">*</span></label>
|
|
<input type="text" class="form-control" id="comment-name" name="author_name"
|
|
maxlength="100" required placeholder="Votre nom">
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<label class="form-label" for="comment-email">
|
|
Email <span class="text-danger">*</span>
|
|
<span class="text-muted fw-normal">(non publié)</span>
|
|
</label>
|
|
<input type="email" class="form-control" id="comment-email" name="author_email"
|
|
maxlength="254" required placeholder="votre@email.fr">
|
|
</div>
|
|
<div class="col-12">
|
|
<label class="form-label" for="comment-content">Commentaire <span class="text-danger">*</span></label>
|
|
<textarea class="form-control" id="comment-content" name="content"
|
|
rows="4" maxlength="2000" required
|
|
placeholder="Votre commentaire (2000 caractères max)"></textarea>
|
|
</div>
|
|
<div class="col-12 d-flex align-items-center gap-3">
|
|
<button type="submit" class="btn btn-primary">Envoyer</button>
|
|
<small class="text-muted">Un code de vérification sera envoyé à votre adresse email.</small>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<script src="/assets/js/comments.js" defer></script>
|