ajout de stats à la page "à propos"
This commit is contained in:
parent
dced7ae0db
commit
a15d2260d1
75
about.php
75
about.php
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
require_once 'includes/config.php';
|
||||
require_once 'includes/DeltaConverter.php';
|
||||
require_once 'includes/Stats.php';
|
||||
|
||||
$config = Config::load();
|
||||
$about = $config['about'] ?? [
|
||||
@ -9,6 +10,10 @@ $about = $config['about'] ?? [
|
||||
'background' => ''
|
||||
];
|
||||
|
||||
// Charger les statistiques
|
||||
$stats = new Stats();
|
||||
$siteStats = $stats->getStats();
|
||||
|
||||
// Fonction pour convertir le contenu Delta en HTML
|
||||
function deltaToHtml($content) {
|
||||
return DeltaConverter::toHtml($content);
|
||||
@ -38,10 +43,78 @@ function deltaToHtml($content) {
|
||||
</header>
|
||||
|
||||
<!-- Contenu principal -->
|
||||
<div class="novel-content single-column">
|
||||
<div class="novel-content">
|
||||
<div class="novel-description">
|
||||
<?= deltaToHtml($about['content']) ?>
|
||||
</div>
|
||||
|
||||
<aside class="stats-menu">
|
||||
<h2>Statistiques</h2>
|
||||
<ul class="stats-list">
|
||||
<!-- Nombre total de romans -->
|
||||
<li class="stats-item">
|
||||
<div class="stats-label">Romans publiés</div>
|
||||
<div class="stats-value"><?= Stats::formatNumber($siteStats['total_stories']) ?></div>
|
||||
</li>
|
||||
|
||||
<!-- Nombre total de chapitres -->
|
||||
<li class="stats-item">
|
||||
<div class="stats-label">Chapitres écrits</div>
|
||||
<div class="stats-value"><?= Stats::formatNumber($siteStats['total_chapters']) ?></div>
|
||||
<div class="stats-detail">
|
||||
Moyenne de <?= $siteStats['avg_chapters_per_story'] ?> chapitres par roman
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Nombre total de mots -->
|
||||
<li class="stats-item">
|
||||
<div class="stats-label">Mots écrits</div>
|
||||
<div class="stats-value"><?= Stats::formatNumber($siteStats['total_words']) ?></div>
|
||||
<div class="stats-detail">
|
||||
Moyenne de <?= Stats::formatNumber($siteStats['avg_words_per_chapter']) ?> mots par chapitre
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Roman avec le plus de chapitres -->
|
||||
<?php if ($siteStats['most_chapters']['story']): ?>
|
||||
<li class="stats-item">
|
||||
<div class="stats-label">Plus long roman</div>
|
||||
<div class="stats-value"><?= Stats::formatNumber($siteStats['most_chapters']['count']) ?> chapitres</div>
|
||||
<div class="stats-detail">
|
||||
<a href="roman.php?id=<?= htmlspecialchars($siteStats['most_chapters']['story']['id']) ?>">
|
||||
<?= htmlspecialchars($siteStats['most_chapters']['story']['title']) ?>
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Plus long chapitre -->
|
||||
<?php if ($siteStats['longest_chapter']['story']): ?>
|
||||
<li class="stats-item">
|
||||
<div class="stats-label">Plus long chapitre</div>
|
||||
<div class="stats-value"><?= Stats::formatNumber($siteStats['longest_chapter']['words']) ?> mots</div>
|
||||
<div class="stats-detail">
|
||||
<a href="roman.php?id=<?= htmlspecialchars($siteStats['longest_chapter']['story']['id']) ?>">
|
||||
<?= htmlspecialchars($siteStats['longest_chapter']['story']['title']) ?>
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Dernière mise à jour -->
|
||||
<?php if ($siteStats['latest_update']['story']): ?>
|
||||
<li class="stats-item">
|
||||
<div class="stats-label">Dernière mise à jour</div>
|
||||
<div class="stats-value"><?= Stats::formatDate($siteStats['latest_update']['date']) ?></div>
|
||||
<div class="stats-detail">
|
||||
<a href="roman.php?id=<?= htmlspecialchars($siteStats['latest_update']['story']['id']) ?>">
|
||||
<?= htmlspecialchars($siteStats['latest_update']['story']['title']) ?>
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<div class="back-to-home">
|
||||
|
@ -1,3 +1,6 @@
|
||||
/* Import d'autres fichiers CSS */
|
||||
@import 'stats.css';
|
||||
|
||||
/* Import Google Fonts */
|
||||
@import url('https://fonts.googleapis.com/css2?family=Parisienne&display=swap');
|
||||
|
||||
|
73
assets/css/stats.css
Normal file
73
assets/css/stats.css
Normal file
@ -0,0 +1,73 @@
|
||||
.stats-menu {
|
||||
background: var(--bg-tertiary);
|
||||
padding: var(--spacing-lg);
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--border-color);
|
||||
position: sticky;
|
||||
top: var(--spacing-lg);
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.stats-menu h2 {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: var(--spacing-md);
|
||||
color: var(--text-primary);
|
||||
padding-bottom: var(--spacing-sm);
|
||||
border-bottom: 2px solid var(--accent-primary);
|
||||
}
|
||||
|
||||
.stats-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.stats-item {
|
||||
margin-bottom: var(--spacing-md);
|
||||
padding-bottom: var(--spacing-md);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.stats-item:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.stats-label {
|
||||
font-size: 0.9rem;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.stats-value {
|
||||
font-size: 1.2rem;
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.stats-detail {
|
||||
font-size: 0.85rem;
|
||||
color: var(--accent-primary);
|
||||
margin-top: var(--spacing-xs);
|
||||
}
|
||||
|
||||
/* Style pour les liens dans les stats */
|
||||
.stats-detail a {
|
||||
color: var(--accent-primary);
|
||||
text-decoration: none;
|
||||
transition: color var(--transition-fast);
|
||||
}
|
||||
|
||||
.stats-detail a:hover {
|
||||
color: var(--accent-secondary);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Media queries */
|
||||
@media (max-width: 900px) {
|
||||
.stats-menu {
|
||||
position: static;
|
||||
margin-top: var(--spacing-xl);
|
||||
}
|
||||
}
|
118
includes/Stats.php
Normal file
118
includes/Stats.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
class Stats {
|
||||
private static $storiesDir = __DIR__ . '/../stories/';
|
||||
private $stories = [];
|
||||
private $stats = [];
|
||||
|
||||
public function __construct() {
|
||||
$this->loadStories();
|
||||
$this->calculateStats();
|
||||
}
|
||||
|
||||
private function loadStories() {
|
||||
foreach (glob(self::$storiesDir . '*.json') as $file) {
|
||||
$this->stories[] = json_decode(file_get_contents($file), true);
|
||||
}
|
||||
}
|
||||
|
||||
private function calculateStats() {
|
||||
$totalChapters = 0;
|
||||
$totalWords = 0;
|
||||
$maxChapters = 0;
|
||||
$storyWithMostChapters = null;
|
||||
$lastUpdate = null;
|
||||
$mostRecentStory = null;
|
||||
$longestChapter = [
|
||||
'words' => 0,
|
||||
'story' => null,
|
||||
'chapter' => null
|
||||
];
|
||||
|
||||
foreach ($this->stories as $story) {
|
||||
// Compter les chapitres
|
||||
$chapterCount = count($story['chapters'] ?? []);
|
||||
$totalChapters += $chapterCount;
|
||||
|
||||
// Trouver le roman avec le plus de chapitres
|
||||
if ($chapterCount > $maxChapters) {
|
||||
$maxChapters = $chapterCount;
|
||||
$storyWithMostChapters = $story;
|
||||
}
|
||||
|
||||
// Trouver la dernière mise à jour
|
||||
$storyUpdate = strtotime($story['updated']);
|
||||
if (!$lastUpdate || $storyUpdate > $lastUpdate) {
|
||||
$lastUpdate = $storyUpdate;
|
||||
$mostRecentStory = $story;
|
||||
}
|
||||
|
||||
// Compter les mots et trouver le plus long chapitre
|
||||
foreach ($story['chapters'] ?? [] as $chapter) {
|
||||
$content = $chapter['content'];
|
||||
|
||||
// Si le contenu est au format JSON (Delta)
|
||||
if (is_string($content) && $this->isJson($content)) {
|
||||
$content = json_decode($content, true);
|
||||
$text = '';
|
||||
if (isset($content['ops'])) {
|
||||
foreach ($content['ops'] as $op) {
|
||||
if (is_string($op['insert'])) {
|
||||
$text .= $op['insert'];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Si le contenu est en HTML
|
||||
$text = strip_tags($content);
|
||||
}
|
||||
|
||||
$wordCount = str_word_count(strip_tags($text));
|
||||
$totalWords += $wordCount;
|
||||
|
||||
if ($wordCount > $longestChapter['words']) {
|
||||
$longestChapter = [
|
||||
'words' => $wordCount,
|
||||
'story' => $story,
|
||||
'chapter' => $chapter
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->stats = [
|
||||
'total_stories' => count($this->stories),
|
||||
'total_chapters' => $totalChapters,
|
||||
'total_words' => $totalWords,
|
||||
'avg_chapters_per_story' => $this->stories ? round($totalChapters / count($this->stories), 1) : 0,
|
||||
'avg_words_per_chapter' => $totalChapters ? round($totalWords / $totalChapters) : 0,
|
||||
'most_chapters' => [
|
||||
'story' => $storyWithMostChapters,
|
||||
'count' => $maxChapters
|
||||
],
|
||||
'longest_chapter' => $longestChapter,
|
||||
'latest_update' => [
|
||||
'story' => $mostRecentStory,
|
||||
'date' => $lastUpdate
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function getStats() {
|
||||
return $this->stats;
|
||||
}
|
||||
|
||||
private function isJson($string) {
|
||||
json_decode($string);
|
||||
return json_last_error() === JSON_ERROR_NONE;
|
||||
}
|
||||
|
||||
// Méthodes utilitaires pour le formatage
|
||||
public static function formatNumber($number) {
|
||||
return number_format($number, 0, ',', ' ');
|
||||
}
|
||||
|
||||
public static function formatDate($timestamp) {
|
||||
if (!$timestamp) return 'Jamais';
|
||||
return date('d/m/Y', $timestamp);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user