Compare commits

...

4 Commits

19 changed files with 1132 additions and 93 deletions

@ -34,6 +34,11 @@ $siteStats = $stats->getStats();
<div class="novel-header-background" style="background-image: url('<?= htmlspecialchars($about['background']) ?>');"></div>
<?php endif; ?>
<h1><?= htmlspecialchars($about['title']) ?></h1>
<div class="header-actions">
<a href="index.php" class="about-button">
<i class="fas fa-home"></i> Accueil
</a>
</div>
</header>
<!-- Contenu principal -->
@ -131,11 +136,9 @@ $siteStats = $stats->getStats();
</aside>
</div>
<div class="back-to-home">
<a href="index.php">&larr; Retour à l'accueil</a>
</div>
<button class="scroll-top" aria-label="Retour en haut de page"></button>
<button class="scroll-top" aria-label="Retour en haut de page">
<i class="fas fa-arrow-up"></i>
</button>
<script>
document.addEventListener('DOMContentLoaded', function() {

@ -49,7 +49,9 @@ $stories = Stories::getAll();
<span>Administration</span>
</div>
<div class="nav-menu">
<a href="index.php" class="button">Retour</a>
<a href="index.php" class="button tooltip" data-tooltip="Retour">
<i class="fas fa-arrow-left"></i>
</a>
</div>
</nav>
@ -80,8 +82,14 @@ $stories = Stories::getAll();
</div>
<div class="form-actions">
<button type="button" class="button select-all">Tout sélectionner</button>
<button type="submit" class="button">Exporter la sélection</button>
<button type="button" class="button tooltip select-all" data-tooltip="Tout sélectionner">
<i class="fas fa-check-square"></i>
<span class="tooltip-text">Tout sélectionner</span>
</button>
<button type="submit" class="button tooltip" data-tooltip="Exporter">
<i class="fas fa-upload"></i>
<span class="tooltip-text">Exporter</span>
</button>
</div>
</form>
</section>
@ -102,7 +110,10 @@ $stories = Stories::getAll();
</label>
</div>
<button type="submit" class="button">Importer</button>
<button type="submit" class="button tooltip" data-tooltip="Importer">
<i class="fas fa-download"></i>
<span class="tooltip-text">Importer</span>
</button>
</form>
</section>
</main>
@ -114,10 +125,17 @@ $stories = Stories::getAll();
const checkboxes = document.querySelectorAll('input[name="stories[]"]');
selectAllBtn.addEventListener('click', function() {
const allChecked = Array.from(checkboxes).every(cb => cb.checked);
checkboxes.forEach(cb => cb.checked = !allChecked);
this.textContent = allChecked ? 'Tout sélectionner' : 'Tout désélectionner';
});
const allChecked = Array.from(checkboxes).every(cb => cb.checked);
checkboxes.forEach(cb => cb.checked = !allChecked);
// Mise à jour du texte de la tooltip et non du contenu du bouton
const tooltipText = this.querySelector('.tooltip-text');
if (tooltipText) {
tooltipText.textContent = allChecked ? 'Tout sélectionner' : 'Tout désélectionner';
}
// Mise à jour de l'attribut data-tooltip pour que le survol affiche le bon texte
this.setAttribute('data-tooltip', allChecked ? 'Tout sélectionner' : 'Tout désélectionner');
});
// Validation du formulaire d'export
document.getElementById('exportForm').addEventListener('submit', function(e) {

@ -58,18 +58,31 @@ $users = Auth::getAllUsers(false);
<?php endif; ?>
<span>Administration</span>
</div>
<!-- Le bouton hamburger sera inséré par JS -->
<div class="nav-menu">
<a href="../index.php" target="_blank" class="button">Visiter le site</a>
<a href="profile.php" class="button">Profil</a>
<a href="../index.php" target="_blank" class="button tooltip" data-tooltip="Visiter le site">
<i class="fa-solid fa-house"></i>
</a>
<a href="profile.php" class="button tooltip" data-tooltip="Profil">
<i class="fas fa-user"></i>
</a>
<?php if (Auth::isAdmin() || Auth::hasAdminRole()): ?>
<a href="users.php" class="button">Utilisateurs</a>
<a href="users.php" class="button tooltip" data-tooltip="Utilisateurs">
<i class="fas fa-users"></i>
</a>
<?php endif; ?>
<a href="story-edit.php" class="button">Nouveau roman</a>
<a href="options.php" class="button">Options</a>
<a href="export-import.php" class="button">Import/Export</a>
<a href="story-edit.php" class="button tooltip" data-tooltip="Nouveau roman">
<i class="fa-solid fa-book"></i>
</a>
<a href="options.php" class="button tooltip" data-tooltip="Options">
<i class="fas fa-cog"></i>
</a>
<a href="export-import.php" class="button tooltip" data-tooltip="Import/Export">
<i class="fa-solid fa-upload"></i>
</a>
<form method="POST" action="logout.php" class="logout-form">
<button type="submit">Déconnexion</button>
<button type="submit" class="tooltip" data-tooltip="Déconnexion">
<i class="fas fa-sign-out-alt"></i>
</button>
</form>
</div>
</nav>
@ -92,11 +105,17 @@ $users = Auth::getAllUsers(false);
</p>
</div>
<div class="story-actions">
<a href="story-edit.php?id=<?= htmlspecialchars($story['id']) ?>" class="button">Modifier</a>
<a href="story-edit.php?id=<?= htmlspecialchars($story['id']) ?>" class="button tooltip" data-tooltip="Modifier">
<i class="fas fa-edit"></i>
</a>
<?php if (Auth::isAdmin() || Auth::hasAdminRole()): ?>
<button type="button" class="button manage-access" data-id="<?= htmlspecialchars($story['id']) ?>">Accès</button>
<button type="button" class="button tooltip manage-access" data-tooltip="Accès" data-id="<?= htmlspecialchars($story['id']) ?>">
<i class="fas fa-users-cog"></i>
</button>
<?php endif; ?>
<button type="button" class="button delete-story" data-id="<?= htmlspecialchars($story['id']) ?>">Supprimer</button>
<button type="button" class="button tooltip delete-story" data-tooltip="Supprimer" data-id="<?= htmlspecialchars($story['id']) ?>">
<i class="fas fa-trash-alt"></i>
</button>
</div>
</div>
<?php endforeach; ?>
@ -131,8 +150,14 @@ $users = Auth::getAllUsers(false);
</div>
</div>
<div class="modal-footer">
<button type="button" class="button dark" id="cancelAccess">Annuler</button>
<button type="button" class="button" id="saveAccess">Enregistrer</button>
<button type="button" class="button dark" id="cancelAccess">
<i class="fas fa-times"></i>
<span class="button-text">Annuler</span>
</button>
<button type="button" class="button" id="saveAccess">
<i class="fas fa-save"></i>
<span class="button-text">Enregistrer</span>
</button>
</div>
</div>
</div>

@ -90,7 +90,9 @@ $config = Config::load();
<span>Administration</span>
</div>
<div class="nav-menu">
<a href="index.php" class="button">Retour</a>
<a href="index.php" class="button tooltip" data-tooltip="Retour">
<i class="fas fa-arrow-left"></i>
</a>
</div>
</nav>
@ -204,20 +206,30 @@ $config = Config::load();
Ouvrir dans un nouvel onglet
</label>
</div>
<button type="button" class="button delete-story">Supprimer ce lien</button>
<button type="button" class="button dark tooltip remove-link" data-tooltip="Supprimer ce lien">
<i class="fas fa-trash-alt"></i>
</button>
</div>
<?php
}
}
?>
</div>
<button type="button" id="addLink" class="button">Ajouter un lien</button>
<button type="button" id="addLink" class="button tooltip" data-tooltip="Ajouter un lien">
<i class="fas fa-plus"></i>
</button>
<br />
<button type="submit" class="button submit-button">Enregistrer les modifications</button>
<button type="submit" class="button tooltip submit-button" data-tooltip="Enregistrer">
<i class="fas fa-save"></i>
<span class="tooltip-text">Enregistrer les modifications</span>
</button>
<!-- Section Nettoyage des médias -->
<h2>Maintenance</h2>
<div class="maintenance-actions">
<button type="button" id="cleanMedia" class="button">Nettoyer les médias inutilisés</button>
<button type="button" id="cleanMedia" class="button tooltip" data-tooltip="Nettoyer">
<i class="fas fa-broom"></i>
<span class="tooltip-text">Nettoyer les médias inutilisés</span>
</button>
<small>Supprime les images qui ne sont plus utilisées dans les romans et chapitres.</small>
</div>
</form>

@ -96,7 +96,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<span>Administration</span>
</div>
<div class="nav-menu">
<a href="index.php" class="button">Retour</a>
<a href="index.php" class="button tooltip" data-tooltip="Retour">
<i class="fas fa-arrow-left"></i>
</a>
</div>
</nav>
@ -135,7 +137,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<input type="password" id="confirm_password" name="confirm_password">
</div>
<button type="submit" class="button">Enregistrer les modifications</button>
<button type="submit" class="button tooltip" data-tooltip="Enregistrer">
<i class="fas fa-save"></i>
<span class="tooltip-text">Enregistrer</span>
</button>
</form>
</main>
<link rel="stylesheet" href="../assets/css/dialog.css">

@ -102,7 +102,9 @@ function generateSlug($title) {
<span>Administration</span>
</div>
<div class="nav-menu">
<a href="index.php" class="button">Retour</a>
<a href="index.php" class="button tooltip" data-tooltip="Retour">
<i class="fas fa-arrow-left"></i>
</a>
</div>
</nav>
@ -143,13 +145,19 @@ function generateSlug($title) {
<input type="file" id="cover" name="cover" accept="image/*">
</div>
<button type="submit" class="button">Enregistrer</button>
<button type="submit" class="button tooltip" data-tooltip="Enregistrer">
<i class="fas fa-save"></i>
<span class="tooltip-text">Enregistrer</span>
</button>
</form>
<?php if ($story): ?>
<section class="chapters-section">
<h2>Chapitres</h2>
<button type="button" id="addChapter" class="button">Ajouter un chapitre</button>
<button type="button" id="addChapter" class="button">
<i class="fas fa-plus"></i>
<span class="button-text">Ajouter un chapitre</span>
</button>
<div id="chaptersList" class="chapters-list">
<?php foreach ($story['chapters'] ?? [] as $index => $chapter): ?>
@ -157,9 +165,18 @@ function generateSlug($title) {
<span class="chapter-number"><?= $index + 1 ?></span>
<h3 class="chapter-title"><?= htmlspecialchars($chapter['title']) ?></h3>
<div class="chapter-actions">
<button type="button" class="button edit-chapter">Éditer</button>
<button type="button" class="button edit-cover">Couverture</button>
<button type="button" class="button delete-chapter">Supprimer</button>
<button type="button" class="edit-chapter">
<i class="fas fa-edit"></i>
<span class="button-text">Éditer</span>
</button>
<button type="button" class="edit-cover">
<i class="fas fa-image"></i>
<span class="button-text">Couverture</span>
</button>
<button type="button" class="delete-chapter">
<i class="fas fa-trash-alt"></i>
<span class="button-text">Supprimer</span>
</button>
</div>
</div>
<?php endforeach; ?>
@ -182,8 +199,14 @@ function generateSlug($title) {
</div>
<div class="modal-footer">
<button type="button" id="cancelEdit" class="button dark">Annuler</button>
<button type="button" id="saveChapter" class="button">Enregistrer</button>
<button type="button" id="cancelEdit" class="button dark">
<i class="fas fa-times"></i>
<span class="button-text">Annuler</span>
</button>
<button type="button" id="saveChapter" class="button">
<i class="fas fa-save"></i>
<span class="button-text">Enregistrer</span>
</button>
</div>
</div>
</div>
@ -207,9 +230,18 @@ function generateSlug($title) {
</div>
<div class="modal-footer">
<button type="button" id="cancelCoverEdit" class="button dark">Annuler</button>
<button type="button" id="deleteCover" class="button delete-story" style="display: none;">Supprimer</button>
<button type="button" id="saveCover" class="button">Enregistrer</button>
<button type="button" id="cancelCoverEdit" class="button dark">
<i class="fas fa-times"></i>
<span class="button-text">Annuler</span>
</button>
<button type="button" id="deleteCover" class="button delete-story" style="display: none;">
<i class="fas fa-trash-alt"></i>
<span class="button-text">Supprimer</span>
</button>
<button type="button" id="saveCover" class="button">
<i class="fas fa-save"></i>
<span class="button-text">Enregistrer</span>
</button>
</div>
</div>
</div>

@ -175,7 +175,9 @@ $config = Config::load();
<span>Administration</span>
</div>
<div class="nav-menu">
<a href="index.php" class="button">Retour</a>
<a href="index.php" class="button tooltip" data-tooltip="Retour">
<i class="fas fa-arrow-left"></i>
</a>
</div>
</nav>
@ -206,16 +208,23 @@ $config = Config::load();
<?php endif; ?>
</div>
<div class="user-actions">
<button type="button" class="button edit-user" data-user-id="<?= htmlspecialchars($user['id']) ?>" data-user-comment="<?= htmlspecialchars($user['comment'] ?? '') ?>" data-user-role="<?= htmlspecialchars($user['role'] ?? 'editor') ?>">Modifier</button>
<button type="button" class="button tooltip edit-user" data-tooltip="Modifier" data-user-id="<?= htmlspecialchars($user['id']) ?>" data-user-comment="<?= htmlspecialchars($user['comment'] ?? '') ?>" data-user-role="<?= htmlspecialchars($user['role'] ?? 'editor') ?>">
<i class="fas fa-edit"></i>
</button>
<?php if ($index !== 0): ?>
<button type="button" class="button delete-user" data-user-id="<?= htmlspecialchars($user['id']) ?>">Supprimer</button>
<button type="button" class="button tooltip delete-user" data-tooltip="Supprimer" data-user-id="<?= htmlspecialchars($user['id']) ?>">
<i class="fas fa-trash-alt"></i>
</button>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
<button type="button" id="addUserBtn" class="button">Ajouter un utilisateur</button>
<button type="button" id="addUserBtn" class="button tooltip" data-tooltip="Ajouter un utilisateur">
<i class="fas fa-user-plus"></i>
<span class="tooltip-text">Ajouter un utilisateur</span>
</button>
</section>
<!-- Formulaire d'ajout d'utilisateur (modal) -->
@ -297,8 +306,14 @@ $config = Config::load();
</div>
<div class="modal-footer">
<button type="button" class="button dark cancel-btn">Annuler</button>
<button type="submit" class="button">Enregistrer</button>
<button type="button" class="button dark cancel-btn">
<i class="fas fa-times"></i>
<span class="button-text">Annuler</span>
</button>
<button type="submit" class="button">
<i class="fas fa-save"></i>
<span class="button-text">Enregistrer</span>
</button>
</div>
</form>
</div>

377
assets/css/buttons.css Normal file

@ -0,0 +1,377 @@
@import "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css";
/* buttons.css - Styles pour les boutons, tooltips et menu */
/* Styles pour les boutons avec icônes */
.button.tooltip,
.tooltip {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
padding: 0;
border-radius: var(--radius-sm);
transition: var(--transition-fast);
}
.button.tooltip i,
.tooltip i {
font-size: 1.2rem;
}
/* Style pour le bouton de déconnexion */
.logout-form button {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-sm);
padding: 0;
border: 1px solid var(--border-color);
background-color: var(--bg-tertiary);
color: var(--text-primary);
position: relative;
}
.logout-form button:hover {
background-color: var(--error-color);
}
.logout-form button i {
font-size: 1.2rem;
}
/* Tooltip styles */
.tooltip::after {
content: attr(data-tooltip);
position: absolute;
bottom: -35px;
left: 50%;
transform: translateX(-50%);
background-color: var(--bg-primary);
color: var(--text-primary);
padding: 5px 10px;
border-radius: var(--radius-sm);
font-size: 0.8rem;
white-space: nowrap;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s, visibility 0.3s;
z-index: 100;
pointer-events: none;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
border: 1px solid var(--border-color);
}
.tooltip:hover::after {
opacity: 1;
visibility: visible;
}
/* Styles pour le texte à côté des icônes (mobile) */
.tooltip-text {
display: none;
margin-left: var(--spacing-md);
}
/* Menu toggle button */
.menu-toggle {
display: none;
background: none;
border: none;
color: var(--text-primary);
font-size: 1.5rem;
cursor: pointer;
padding: var(--spacing-sm);
}
/* Styles pour la barre de navigation */
.admin-nav {
position: relative;
}
.nav-menu {
display: flex;
gap: var(--spacing-md);
justify-content: flex-end;
}
/* Styles pour les boutons d'action des romans */
.story-actions {
display: flex;
gap: var(--spacing-sm);
}
/* Style spécifique pour le bouton d'édition */
.story-actions a.button {
background-color: var(--accent-primary);
color: var(--text-tertiary);
}
.story-actions a.button:hover {
background-color: var(--accent-secondary);
}
/* Style spécifique pour le bouton d'accès */
.story-actions .manage-access {
background-color: var(--bg-secondary);
color: var(--text-primary);
}
.story-actions .manage-access:hover {
background-color: var(--accent-primary);
color: var(--text-tertiary);
}
/* Style spécifique pour le bouton de suppression */
.story-actions .delete-story {
background-color: var(--bg-secondary);
color: var(--text-primary);
}
.story-actions .delete-story:hover {
background-color: var(--error-color);
color: var(--text-tertiary);
}
/* Styles pour les boutons modaux */
.modal-footer .button {
width: auto;
padding: var(--spacing-sm) var(--spacing-md);
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.modal-footer .button i,
.modal-footer .button .button-text {
pointer-events: none; /* Solution au problème de clic */
}
/* Styles pour afficher du texte dans les boutons */
.button-text {
margin-left: var(--spacing-sm);
}
/* Styles pour les boutons avec texte intégré */
.button.with-text {
width: auto;
padding: var(--spacing-sm) var(--spacing-md);
justify-content: flex-start;
}
.button.with-text i {
margin-right: var(--spacing-sm);
}
/* Styles pour les boutons de formulaire */
.submit-button,
#cleanMedia,
#addUserBtn {
width: auto;
padding: var(--spacing-sm) var(--spacing-md);
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
/* Solution globale pour les problèmes de clic sur les boutons */
button i,
button span,
.button i,
.button span {
pointer-events: none;
}
/* Styles pour les boutons d'action de chapitre */
.chapter-actions .button {
padding: 0;
width: 40px;
height: 40px;
}
.chapter-actions .edit-chapter {
background-color: var(--accent-primary);
}
.chapter-actions .edit-cover {
background-color: var(--bg-secondary);
}
.chapter-actions .delete-chapter {
background-color: var(--bg-secondary);
}
.chapter-actions .delete-chapter:hover {
background-color: var(--error-color);
}
/* Styles pour les boutons de formulaire */
.form-actions .button {
display: flex;
align-items: center;
justify-content: center;
gap: var(--spacing-sm);
}
.form-actions .button i {
font-size: 1.2rem;
}
/* Bouton d'ajout */
.button.add-button {
background-color: var(--accent-primary);
color: var(--text-tertiary);
}
.button.add-button:hover {
background-color: var(--accent-secondary);
}
.chapter-actions .edit-chapter,
.chapter-actions .edit-cover,
.chapter-actions .delete-chapter {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
padding: 0;
border-radius: var(--radius-sm);
transition: var(--transition-fast);
position: relative;
border: none;
cursor: pointer;
}
.chapter-actions .edit-chapter i,
.chapter-actions .edit-cover i,
.chapter-actions .delete-chapter i {
font-size: 1.2rem;
}
.chapter-actions .button-text {
display: none;
}
.chapter-actions .edit-chapter {
background-color: var(--accent-primary);
color: var(--text-tertiary);
}
.chapter-actions .edit-cover,
.chapter-actions .delete-chapter {
background-color: var(--bg-secondary);
color: var(--text-primary);
}
.chapter-actions .delete-chapter:hover {
background-color: var(--error-color);
}
.chapter-actions .edit-chapter i,
.chapter-actions .edit-cover i,
.chapter-actions .delete-chapter i,
.chapter-actions .button-text {
pointer-events: none;
}
/* Media queries pour le menu mobile */
@media (max-width: 768px) {
.menu-toggle {
display: block;
position: absolute;
right: var(--spacing-md);
top: 50%;
transform: translateY(-50%);
z-index: 101;
}
.nav-menu {
flex-direction: column;
position: absolute;
top: 100%;
right: 0;
background-color: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
padding: var(--spacing-md);
z-index: 100;
width: 200px;
gap: var(--spacing-sm);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
/* État caché par défaut */
opacity: 0;
visibility: hidden;
transform: translateY(-10px);
transition: all var(--transition-fast);
}
.nav-menu.active {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
/* Style des boutons en mode mobile */
.nav-menu.active .button,
.nav-menu.active .logout-form button {
width: 100%;
justify-content: flex-start;
padding: var(--spacing-sm) var(--spacing-md);
gap: var(--spacing-md);
}
/* Afficher le texte des tooltips en mode mobile */
.nav-menu.active .tooltip-text {
display: inline-block;
}
/* Cacher les tooltips standards sur mobile */
.tooltip::after {
display: none;
}
.logout-form {
width: 100%;
}
/* Afficher le texte des tooltips en mode mobile pour les actions des romans */
.story-actions.active .tooltip-text {
display: inline-block;
margin-left: var(--spacing-sm);
}
.story-actions.active .button {
width: auto;
padding: var(--spacing-xs) var(--spacing-sm);
}
.chapter-actions.active .edit-chapter,
.chapter-actions.active .edit-cover,
.chapter-actions.active .delete-chapter {
width: 100%;
justify-content: flex-start;
padding: var(--spacing-sm) var(--spacing-md);
}
.chapter-actions.active .button-text {
display: inline-block;
margin-left: var(--spacing-sm);
}
}
/* Pour les très petits écrans */
@media (max-width: 480px) {
.story-actions {
justify-content: space-between;
}
.story-actions .button {
flex: 1;
}
}

@ -5,9 +5,10 @@
border-radius: var(--radius-md);
border: 1px solid var(--border-color);
display: flex;
align-items: center;
align-items: flex-start;
gap: var(--spacing-lg);
transition: transform var(--transition-fast), box-shadow var(--transition-fast);
position: relative;
}
.story-item:hover {
@ -16,7 +17,7 @@
}
.story-cover {
width: 200px;
width: 180px;
height: 120px;
object-fit: cover;
border-radius: var(--radius-sm);
@ -35,6 +36,10 @@
.story-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
height: 120px;
}
.story-info p {
@ -88,7 +93,7 @@
.chapter-number {
background: var(--accent-primary);
color: var(--text-primary);
color: var(--text-tertiary);
width: 40px;
height: 40px;
display: flex;

182
assets/css/fixes.css Normal file

@ -0,0 +1,182 @@
/* Correctifs pour les problèmes d'affichage des champs de texte */
/* 1. Règles globales pour tous les conteneurs de formulaire */
.form-group {
margin-bottom: var(--spacing-lg);
width: 100%;
position: relative;
overflow: visible;
}
/* 2. Correction pour les champs de texte */
.form-group input[type="text"],
.form-group input[type="password"],
.form-group textarea,
.form-group input[type="file"],
.form-group select {
width: 100%;
box-sizing: border-box;
max-width: 100%;
padding: var(--spacing-sm);
background-color: var(--input-bg);
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
color: var(--text-primary);
font-size: 1rem;
}
/* 3. Correction pour les modales et leurs contenus */
.modal-content {
max-width: 90vw;
max-height: 90vh;
overflow-y: auto;
padding: var(--spacing-md);
width: auto;
box-sizing: border-box;
}
.modal-header,
.modal-body,
.modal-footer {
width: 100%;
box-sizing: border-box;
padding: var(--spacing-md);
}
/* 4. Correction pour l'éditeur Quill */
.ql-container {
overflow: auto;
max-width: 100%;
}
.ql-editor {
min-height: 200px;
max-width: 100%;
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-word;
}
/* 5. Gestion spécifique pour les grilles et les flex containers */
.story-item,
.chapter-item,
.user-item {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-md);
width: 100%;
box-sizing: border-box;
}
.story-info,
.chapter-info {
flex: 1;
min-width: 0; /* Empêche le dépassement */
overflow: hidden;
}
/* 6. Meilleures media queries pour la responsivité */
@media (max-width: 768px) {
.story-item,
.chapter-item,
.user-item {
flex-direction: column;
}
.story-actions,
.chapter-actions,
.user-actions {
width: 100%;
flex-wrap: wrap;
justify-content: flex-start;
}
.form-group input[type="text"],
.form-group input[type="password"],
.form-group textarea {
font-size: 16px; /* Pour éviter le zoom sur mobile */
}
#chapterTitle {
width: 100%;
}
}
/* 7. Correction pour les boutons qui peuvent déborder */
.button,
button {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
/* 8. Meilleure gestion des tables et des listes */
table {
width: 100%;
max-width: 100%;
table-layout: fixed;
border-collapse: collapse;
}
td, th {
word-break: break-word;
overflow-wrap: break-word;
padding: var(--spacing-sm);
}
/* 9. Amélioration du contenu affichable */
.novel-description,
.chapter-content,
.about-description {
width: 100%;
max-width: 100%;
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-word;
}
/* 10. Flexibilité des images dans l'éditeur et le contenu */
img {
max-width: 100%;
height: auto;
}
/* 11. Correction pour les éléments de navigation */
.chapters-list a {
display: block;
width: 100%;
box-sizing: border-box;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 12. Correction pour la page options.php */
.options-section {
width: 100%;
box-sizing: border-box;
overflow: hidden;
}
#aboutEditor {
max-width: 100%;
}
.cover-preview-container {
max-width: 100%;
overflow: hidden;
}
.link-item {
width: 100%;
box-sizing: border-box;
}
/* 13. Empêcher les textes de déborder */
h1, h2, h3, h4, h5, h6, p {
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-word;
max-width: 100%;
}

@ -204,6 +204,69 @@
color: var(--text-secondary);
}
/* Style pour les sélecteurs (dropdowns) */
select {
width: 100%;
padding: var(--spacing-sm);
background-color: var(--input-bg);
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
color: var(--text-primary);
font-size: 1rem;
transition: border-color var(--transition-fast);
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='6'%3E%3Cpath d='M0 0h12L6 6 0 0z' fill='%23d2a679'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right var(--spacing-sm) center;
background-size: 12px;
padding-right: 30px;
}
select:focus {
border-color: var(--accent-primary);
outline: none;
box-shadow: 0 0 0 2px rgba(210, 166, 121, 0.2);
}
select option {
background-color: var(--bg-secondary);
color: var(--text-primary);
padding: var(--spacing-sm);
}
/* Style pour les sélecteurs dans les formulaires modaux */
.modal-content select {
max-width: 100%;
margin-bottom: var(--spacing-md);
}
/* Style pour le sélecteur désactivé (pour le premier utilisateur admin) */
select:disabled {
opacity: 0.7;
cursor: not-allowed;
background-color: var(--bg-secondary);
}
/* Styles spécifiques pour les sélecteurs dans users.php */
#role, #edit_role {
width: auto;
min-width: 180px;
background-color: var(--input-bg);
}
/* Style visuel différent pour les options */
#role option[value="admin"],
#edit_role option[value="admin"] {
font-weight: bold;
color: var(--accent-primary);
}
#role option[value="editor"],
#edit_role option[value="editor"] {
font-weight: normal;
color: var(--text-secondary);
}
/* Responsive */
@media (max-width: 768px) {
.options-section {
@ -213,4 +276,9 @@
.link-item {
padding: var(--spacing-md);
}
select {
width: 100%;
max-width: none;
}
}

@ -3,4 +3,6 @@
@import 'layout.css';
@import 'components.css';
@import 'forms.css';
@import 'editor.css';
@import 'editor.css';
@import 'buttons.css';
@import 'fixes.css';

@ -4,6 +4,9 @@
/* Import Google Fonts */
@import url('https://fonts.googleapis.com/css2?family=Parisienne&display=swap');
/* Import Font Awesome */
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css');
/* Variables globales */
:root {
/* Couleurs de fond */
@ -759,4 +762,183 @@ body {
.stats-value {
font-size: 1.1rem;
}
}
/* Styles pour les boutons avec icônes */
.about-button {
display: inline-flex;
align-items: center;
gap: var(--spacing-sm);
padding: var(--spacing-sm) var(--spacing-md);
background-color: var(--accent-primary);
color: var(--text-tertiary);
text-decoration: none;
border-radius: var(--radius-sm);
transition: var(--transition);
font-weight: normal;
}
.about-button i {
font-size: 1.1rem;
}
.about-button:hover {
background-color: var(--accent-secondary);
}
/* Navigation entre chapitres */
.chapter-nav {
display: inline-flex;
align-items: center;
gap: var(--spacing-sm);
color: var(--text-secondary);
text-decoration: none;
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--radius-sm);
transition: var(--transition);
}
.chapter-nav:hover {
background-color: var(--bg-secondary);
color: var(--accent-primary);
}
/* Bouton retour en haut */
.scroll-top {
position: fixed;
bottom: 2rem;
right: 2rem;
background-color: var(--bg-tertiary);
color: var(--text-primary);
width: 3rem;
height: 3rem;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
border: 1px solid var(--border-color);
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
cursor: pointer;
z-index: 100;
}
.scroll-top i {
font-size: 1.2rem;
}
.scroll-top.visible {
opacity: 1;
visibility: visible;
}
.scroll-top:hover {
background-color: var(--accent-primary);
color: var(--text-tertiary);
}
/* Lien de retour */
.back-to-home a {
display: inline-flex;
align-items: center;
gap: var(--spacing-sm);
color: var(--text-secondary);
text-decoration: none;
transition: var(--transition);
padding: var(--spacing-sm) 0;
}
.back-to-home a:hover {
color: var(--accent-primary);
}
/* Icônes dans la liste des chapitres */
.chapters-list a {
position: relative;
padding-left: calc(var(--spacing-md) + 1.2rem);
}
.chapters-list a::before {
content: "\f15c"; /* Icône de document */
font-family: "Font Awesome 6 Free";
font-weight: 900;
position: absolute;
left: var(--spacing-sm);
color: var(--accent-primary);
}
.chapters-list .current-chapter::before {
content: "\f02e"; /* Icône de marque-page */
color: var(--text-tertiary);
}
/* Pour les petits écrans */
@media (max-width: 768px) {
.header-actions {
display: flex;
gap: var(--spacing-sm);
}
.about-button {
padding: var(--spacing-xs) var(--spacing-sm);
font-size: 0.9rem;
}
}
/* Modification des styles pour les chapitres en brouillon */
.chapters-list .draft-chapter {
opacity: 0.7;
border-left: 3px solid var(--accent-primary);
padding-left: calc(var(--spacing-sm) + 1.5rem) !important;
}
.chapters-list .draft-chapter::before {
content: "\f249";
left: calc(var(--spacing-sm) + 0.3rem);
}
.draft-label {
font-size: 0.8em;
background-color: var(--accent-primary);
color: var(--text-tertiary);
padding: 2px 6px;
border-radius: 10px;
margin-left: 8px;
display: inline-block;
vertical-align: middle;
position: relative;
z-index: 1;
}
/* S'assurer que l'étiquette de brouillon ne chevauche pas l'icône */
.chapters-list a {
display: flex;
align-items: center;
flex-wrap: wrap;
padding: var(--spacing-sm);
padding-left: calc(var(--spacing-md) + 1.2rem);
gap: var(--spacing-xs);
line-height: 1.4;
}
/* Pour conserver l'espace correct en cas de texte long */
.chapter-title-text {
flex: 1;
min-width: 0;
white-space: normal;
word-break: break-word;
}
@media (max-width: 768px) {
.chapters-list a {
padding-right: var(--spacing-xs);
}
.draft-label {
font-size: 0.7em;
padding: 1px 4px;
margin-left: 4px;
}
}

@ -133,33 +133,126 @@ document.addEventListener('DOMContentLoaded', function() {
}
});
// Gestion du menu mobile
const navMenu = document.querySelector('.nav-menu');
const navBrand = document.querySelector('.nav-brand');
// Gestion du menu mobile
const navMenu = document.querySelector('.nav-menu');
function initializeTooltips() {
// Ajouter le texte des tooltips à côté des icônes pour mobile
document.querySelectorAll('.tooltip:not(.tooltip-initialized)').forEach(button => {
if (!button.querySelector('.tooltip-text')) {
const tooltip = button.getAttribute('data-tooltip');
if (tooltip) {
const tooltipSpan = document.createElement('span');
tooltipSpan.className = 'tooltip-text';
tooltipSpan.textContent = tooltip;
button.appendChild(tooltipSpan);
button.classList.add('tooltip-initialized');
}
}
});
}
// Observer les changements du DOM pour initialiser les nouveaux tooltips
const tooltipObserver = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
initializeTooltips();
}
});
});
// Initialiser les tooltips existants et commencer l'observation
document.addEventListener('DOMContentLoaded', function() {
initializeTooltips();
tooltipObserver.observe(document.body, { childList: true, subtree: true });
// Créer le bouton hamburger s'il n'existe pas déjà
if (!document.querySelector('.menu-toggle')) {
const menuToggle = document.createElement('button');
menuToggle.className = 'menu-toggle';
menuToggle.innerHTML = '☰';
menuToggle.setAttribute('aria-label', 'Menu');
// Vérifier le mode mobile au chargement et au redimensionnement
function checkMobileMode() {
const isMobile = window.innerWidth <= 768;
// Insérer le bouton avant le menu
navMenu.parentNode.insertBefore(menuToggle, navMenu);
// Gérer les clics sur le bouton
menuToggle.addEventListener('click', function() {
navMenu.classList.toggle('active');
});
// Fermer le menu au clic en dehors
document.addEventListener('click', function(e) {
if (!navMenu.contains(e.target) && !menuToggle.contains(e.target)) {
navMenu.classList.remove('active');
// Gestion des conteneurs d'actions
const actionContainers = document.querySelectorAll('.story-actions, .chapter-actions, .user-actions');
actionContainers.forEach(container => {
if (isMobile) {
container.classList.add('active');
} else {
container.classList.remove('active');
}
});
}
checkMobileMode();
window.addEventListener('resize', checkMobileMode);
});
// Créer le bouton hamburger s'il n'existe pas déjà
if (!document.querySelector('.menu-toggle')) {
const menuToggle = document.createElement('button');
menuToggle.className = 'menu-toggle';
menuToggle.innerHTML = '☰';
menuToggle.setAttribute('aria-label', 'Menu');
// Insérer le bouton avant le menu
navMenu.parentNode.insertBefore(menuToggle, navMenu);
// Ajouter le texte des tooltips à côté des icônes pour mobile
document.querySelectorAll('.nav-menu .tooltip').forEach(button => {
const tooltip = button.getAttribute('data-tooltip');
const tooltipSpan = document.createElement('span');
tooltipSpan.className = 'tooltip-text';
tooltipSpan.textContent = tooltip;
button.appendChild(tooltipSpan);
});
// Gérer les clics sur le bouton
menuToggle.addEventListener('click', function() {
navMenu.classList.toggle('active');
});
// Fermer le menu au clic en dehors
document.addEventListener('click', function(e) {
if (!navMenu.contains(e.target) && !menuToggle.contains(e.target)) {
navMenu.classList.remove('active');
}
});
}
// Ajouter le texte des tooltips à côté des icônes pour mobile - pour tous les tooltips
function addTooltipText() {
document.querySelectorAll('.tooltip').forEach(button => {
// Vérifier si le tooltip-text n'existe pas déjà
if (!button.querySelector('.tooltip-text')) {
const tooltip = button.getAttribute('data-tooltip');
const tooltipSpan = document.createElement('span');
tooltipSpan.className = 'tooltip-text';
tooltipSpan.textContent = tooltip;
button.appendChild(tooltipSpan);
}
});
}
// Appliquer à tous les tooltips du site
addTooltipText();
// Détection de la taille d'écran pour activer le mode mobile
function checkMobileMode() {
const isMobile = window.innerWidth <= 768;
// Gestion des actions pour les romans
const storyActions = document.querySelectorAll('.story-actions');
storyActions.forEach(action => {
if (isMobile) {
action.classList.add('active');
} else {
action.classList.remove('active');
}
});
}
// Vérifier au chargement et au redimensionnement
checkMobileMode();
window.addEventListener('resize', checkMobileMode);
// Gestion de la suppression des romans
const storyList = document.querySelector('.stories-list');
if (storyList) {

@ -480,4 +480,11 @@ document.addEventListener('DOMContentLoaded', function() {
// Initialisation
detectUnsavedChanges();
});
document.addEventListener('DOMContentLoaded', function() {
// S'assurer que les clics sur les icônes se propagent correctement
document.querySelectorAll('.chapter-actions button i, .chapter-actions button .button-text').forEach(element => {
element.style.pointerEvents = 'none';
});
});

@ -79,8 +79,12 @@ $config = Config::load();
<div class="novel-header-background" style="background-image: url('<?= htmlspecialchars($currentChapter['cover']) ?>');"></div>
<?php endif; ?>
<div class="header-actions">
<a href="index.php" class="about-button">Accueil</a>
<a href="roman.php?id=<?= urlencode($storyId) ?>" class="about-button">Roman</a>
<a href="index.php" class="about-button">
<i class="fas fa-home"></i> Accueil
</a>
<a href="roman.php?id=<?= urlencode($storyId) ?>" class="about-button">
<i class="fas fa-book"></i> Roman
</a>
</div>
<h1>
<?= htmlspecialchars($currentChapter['title']) ?>
@ -99,15 +103,15 @@ $config = Config::load();
<div class="chapter-navigation">
<?php if ($prevChapter): ?>
<a href="?story=<?= urlencode($storyId) ?>&chapter=<?= urlencode($prevChapter['id']) ?>"
class="chapter-nav prev-chapter">
&larr; <?= htmlspecialchars($prevChapter['title']) ?>
class="chapter-nav prev-chapter">
<i class="fas fa-chevron-left"></i> <?= htmlspecialchars($prevChapter['title']) ?>
</a>
<?php endif; ?>
<?php if ($nextChapter): ?>
<a href="?story=<?= urlencode($storyId) ?>&chapter=<?= urlencode($nextChapter['id']) ?>"
class="chapter-nav next-chapter">
<?= htmlspecialchars($nextChapter['title']) ?> &rarr;
class="chapter-nav next-chapter">
<?= htmlspecialchars($nextChapter['title']) ?> <i class="fas fa-chevron-right"></i>
</a>
<?php endif; ?>
</div>
@ -122,10 +126,10 @@ $config = Config::load();
?>
<li>
<a href="?story=<?= urlencode($storyId) ?>&chapter=<?= urlencode($chapter['id']) ?>"
class="<?= $chapter['id'] === $chapterId ? 'current-chapter' : '' ?> <?= $isDraft ? 'draft-chapter' : '' ?>">
<?= htmlspecialchars($chapter['title']) ?>
class="<?= $chapter['id'] === $chapterId ? 'current-chapter' : '' ?> <?= $isDraft ? 'draft-chapter' : '' ?>">
<span class="chapter-title-text"><?= htmlspecialchars($chapter['title']) ?></span>
<?php if ($isDraft && $canViewDrafts): ?>
<span class="draft-label">(Brouillon)</span>
<span class="draft-label">Brouillon</span>
<?php endif; ?>
</a>
</li>
@ -134,7 +138,9 @@ $config = Config::load();
</aside>
</div>
<button class="scroll-top" aria-label="Retour en haut de page"></button>
<button class="scroll-top" aria-label="Retour en haut de page">
<i class="fas fa-arrow-up"></i>
</button>
<style>
.draft-header::after {

@ -64,7 +64,9 @@ function formatDate($date) {
</div>
<div class="header-actions">
<a href="about.php" class="about-button">À propos</a>
<a href="about.php" class="about-button">
<i class="fas fa-info-circle"></i> À propos
</a>
</div>
</header>
</div>

@ -45,7 +45,9 @@ $canViewDrafts = Auth::check() && Auth::canAccessStory($storyId);
<div class="novel-header-background" style="background-image: url('<?= htmlspecialchars($story['cover']) ?>');"></div>
<?php endif; ?>
<div class="header-actions">
<a href="index.php" class="about-button">Accueil</a>
<a href="index.php" class="about-button">
<i class="fas fa-home"></i> Accueil
</a>
</div>
<h1><?= htmlspecialchars($story['title']) ?></h1>
</header>
@ -71,13 +73,14 @@ $canViewDrafts = Auth::check() && Auth::canAccessStory($storyId);
<p>Aucun chapitre publié disponible pour le moment.</p>
<?php else:
foreach ($visibleChapters as $chapter):
$isDraft = $chapter['draft'] ?? false;
?>
<li>
<a href="chapitre.php?story=<?= urlencode($story['id']) ?>&chapter=<?= urlencode($chapter['id']) ?>"
class="<?= ($chapter['draft'] ?? false) ? 'draft-chapter' : '' ?>">
<?= htmlspecialchars($chapter['title']) ?>
<?php if (($chapter['draft'] ?? false) && $canViewDrafts): ?>
<span class="draft-label">(Brouillon)</span>
class="<?= $isDraft ? 'draft-chapter' : '' ?>">
<span class="chapter-title-text"><?= htmlspecialchars($chapter['title']) ?></span>
<?php if ($isDraft && $canViewDrafts): ?>
<span class="draft-label">Brouillon</span>
<?php endif; ?>
</a>
</li>
@ -92,7 +95,9 @@ $canViewDrafts = Auth::check() && Auth::canAccessStory($storyId);
</aside>
</div>
<button class="scroll-top" aria-label="Retour en haut de page"></button>
<button class="scroll-top" aria-label="Retour en haut de page">
<i class="fas fa-arrow-up"></i>
</button>
<style>
.draft-chapter {

@ -1 +1 @@
1.3.0
1.3.1