personnalisation des pop-up de confirmation/avertissement
This commit is contained in:
parent
5dc3416009
commit
f9a00576dc
@ -186,5 +186,7 @@ $stories = Stories::getAll();
|
|||||||
margin-bottom: var(--spacing-md);
|
margin-bottom: var(--spacing-md);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<link rel="stylesheet" href="../assets/css/dialog.css">
|
||||||
|
<script src="../assets/js/dialog.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -68,5 +68,7 @@ $stories = Stories::getAll();
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script src="../assets/js/admin.js"></script>
|
<script src="../assets/js/admin.js"></script>
|
||||||
|
<link rel="stylesheet" href="../assets/css/dialog.css">
|
||||||
|
<script src="../assets/js/dialog.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -155,5 +155,7 @@ $config = Config::load();
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<link rel="stylesheet" href="../assets/css/dialog.css">
|
||||||
|
<script src="../assets/js/dialog.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -138,5 +138,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
<button type="submit" class="button">Enregistrer les modifications</button>
|
<button type="submit" class="button">Enregistrer les modifications</button>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
|
<link rel="stylesheet" href="../assets/css/dialog.css">
|
||||||
|
<script src="../assets/js/dialog.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -253,5 +253,7 @@ function generateSlug($title) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<link rel="stylesheet" href="../assets/css/dialog.css">
|
||||||
|
<script src="../assets/js/dialog.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
107
assets/css/dialog.css
Normal file
107
assets/css/dialog.css
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/* dialog.css */
|
||||||
|
.confirm-dialog {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 9999;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog.show {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog-content {
|
||||||
|
background-color: var(--bg-tertiary);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
padding: var(--spacing-xl);
|
||||||
|
max-width: 90%;
|
||||||
|
width: 400px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||||
|
transform: translate(-50%, -60%);
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transition: transform 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog.show .confirm-dialog-content {
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog h3 {
|
||||||
|
margin: 0 0 var(--spacing-md);
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog p {
|
||||||
|
margin: 0 0 var(--spacing-xl);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog-buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: var(--spacing-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog .button {
|
||||||
|
padding: var(--spacing-sm) var(--spacing-lg);
|
||||||
|
border: none;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1rem;
|
||||||
|
transition: all var(--transition-fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog .button.confirm {
|
||||||
|
background-color: var(--accent-primary);
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog .button.confirm:hover {
|
||||||
|
background-color: var(--accent-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog .button.danger {
|
||||||
|
background-color: var(--error-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog .button.danger:hover {
|
||||||
|
background-color: #a33;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog .button.cancel {
|
||||||
|
background-color: var(--bg-secondary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog .button.cancel:hover {
|
||||||
|
background-color: var(--bg-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.confirm-dialog-content {
|
||||||
|
width: calc(100% - 32px);
|
||||||
|
padding: var(--spacing-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog-buttons {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog .button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
function confirmDeletion(storyId) {
|
function confirmDeletion(storyId) {
|
||||||
const storyCard = document.querySelector(`[data-id="${storyId}"]`).closest('.story-item');
|
const storyCard = document.querySelector(`[data-id="${storyId}"]`).closest('.story-item');
|
||||||
const title = storyCard.querySelector('h2').textContent;
|
const title = storyCard.querySelector('h2').textContent;
|
||||||
return confirm(`Voulez-vous vraiment supprimer le roman "${title}" ? Cette action est irréversible.`);
|
|
||||||
|
confirmDialog.show({
|
||||||
|
title: 'Suppression du roman',
|
||||||
|
message: `Voulez-vous vraiment supprimer le roman "${title}" ? Cette action est irréversible.`,
|
||||||
|
confirmText: 'Supprimer',
|
||||||
|
confirmClass: 'danger',
|
||||||
|
onConfirm: async () => {
|
||||||
|
await deleteStory(storyId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false; // Pour empêcher l'exécution immédiate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Suppression d'un roman via l'API
|
// Suppression d'un roman via l'API
|
||||||
@ -78,10 +88,16 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
const logoutForm = document.querySelector('.logout-form');
|
const logoutForm = document.querySelector('.logout-form');
|
||||||
if (logoutForm) {
|
if (logoutForm) {
|
||||||
logoutForm.addEventListener('submit', (e) => {
|
logoutForm.addEventListener('submit', (e) => {
|
||||||
if (!confirm('Voulez-vous vraiment vous déconnecter ?')) {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
confirmDialog.show({
|
||||||
|
title: 'Confirmation de déconnexion',
|
||||||
|
message: 'Voulez-vous vraiment vous déconnecter ?',
|
||||||
|
confirmText: 'Se déconnecter',
|
||||||
|
onConfirm: () => {
|
||||||
|
logoutForm.submit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fonction utilitaire pour détecter les changements non sauvegardés
|
// Fonction utilitaire pour détecter les changements non sauvegardés
|
||||||
|
145
assets/js/dialog.js
Normal file
145
assets/js/dialog.js
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
class ConfirmDialog {
|
||||||
|
constructor() {
|
||||||
|
this.createDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
createDialog() {
|
||||||
|
// Création du conteneur principal
|
||||||
|
this.dialog = document.createElement('div');
|
||||||
|
this.dialog.className = 'confirm-dialog';
|
||||||
|
this.dialog.style.display = 'none';
|
||||||
|
|
||||||
|
// Création du contenu
|
||||||
|
const content = document.createElement('div');
|
||||||
|
content.className = 'confirm-dialog-content';
|
||||||
|
|
||||||
|
// En-tête avec titre
|
||||||
|
this.title = document.createElement('h3');
|
||||||
|
content.appendChild(this.title);
|
||||||
|
|
||||||
|
// Message
|
||||||
|
this.message = document.createElement('p');
|
||||||
|
content.appendChild(this.message);
|
||||||
|
|
||||||
|
// Conteneur des boutons
|
||||||
|
const buttons = document.createElement('div');
|
||||||
|
buttons.className = 'confirm-dialog-buttons';
|
||||||
|
|
||||||
|
// Bouton Confirmer
|
||||||
|
this.confirmButton = document.createElement('button');
|
||||||
|
this.confirmButton.className = 'button confirm';
|
||||||
|
buttons.appendChild(this.confirmButton);
|
||||||
|
|
||||||
|
// Bouton Annuler
|
||||||
|
this.cancelButton = document.createElement('button');
|
||||||
|
this.cancelButton.className = 'button cancel';
|
||||||
|
this.cancelButton.textContent = 'Annuler';
|
||||||
|
buttons.appendChild(this.cancelButton);
|
||||||
|
|
||||||
|
content.appendChild(buttons);
|
||||||
|
this.dialog.appendChild(content);
|
||||||
|
document.body.appendChild(this.dialog);
|
||||||
|
|
||||||
|
// Fermeture au clic en dehors
|
||||||
|
this.dialog.addEventListener('click', (e) => {
|
||||||
|
if (e.target === this.dialog) {
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fermeture avec Echap
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Escape' && this.dialog.style.display === 'block') {
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
show(options) {
|
||||||
|
const defaults = {
|
||||||
|
title: 'Confirmation',
|
||||||
|
message: 'Êtes-vous sûr ?',
|
||||||
|
confirmText: 'Confirmer',
|
||||||
|
confirmClass: 'confirm',
|
||||||
|
cancelText: 'Annuler',
|
||||||
|
onConfirm: () => {},
|
||||||
|
onCancel: () => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const settings = { ...defaults, ...options };
|
||||||
|
|
||||||
|
this.title.textContent = settings.title;
|
||||||
|
this.message.textContent = settings.message;
|
||||||
|
this.confirmButton.textContent = settings.confirmText;
|
||||||
|
this.confirmButton.className = `button ${settings.confirmClass}`;
|
||||||
|
|
||||||
|
// Réinitialisation des événements
|
||||||
|
const newConfirmBtn = this.confirmButton.cloneNode(true);
|
||||||
|
const newCancelBtn = this.cancelButton.cloneNode(true);
|
||||||
|
this.confirmButton.parentNode.replaceChild(newConfirmBtn, this.confirmButton);
|
||||||
|
this.cancelButton.parentNode.replaceChild(newCancelBtn, this.cancelButton);
|
||||||
|
this.confirmButton = newConfirmBtn;
|
||||||
|
this.cancelButton = newCancelBtn;
|
||||||
|
|
||||||
|
// Nouveaux gestionnaires d'événements
|
||||||
|
this.confirmButton.addEventListener('click', () => {
|
||||||
|
settings.onConfirm();
|
||||||
|
this.hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.cancelButton.addEventListener('click', () => {
|
||||||
|
settings.onCancel();
|
||||||
|
this.hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Affichage avec animation
|
||||||
|
this.dialog.style.display = 'block';
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.dialog.classList.add('show');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.dialog.classList.remove('show');
|
||||||
|
setTimeout(() => {
|
||||||
|
this.dialog.style.display = 'none';
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Création d'une instance globale
|
||||||
|
const confirmDialog = new ConfirmDialog();
|
||||||
|
|
||||||
|
// Exemple d'utilisation pour la suppression d'un chapitre
|
||||||
|
document.querySelectorAll('.delete-chapter').forEach(button => {
|
||||||
|
button.addEventListener('click', (e) => {
|
||||||
|
const chapterTitle = e.target.closest('.chapter-item').querySelector('.chapter-title').textContent;
|
||||||
|
|
||||||
|
confirmDialog.show({
|
||||||
|
title: 'Supprimer le chapitre',
|
||||||
|
message: `Voulez-vous vraiment supprimer le chapitre "${chapterTitle}" ? Cette action est irréversible.`,
|
||||||
|
confirmText: 'Supprimer',
|
||||||
|
confirmClass: 'danger',
|
||||||
|
onConfirm: () => {
|
||||||
|
// Code de suppression existant
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Exemple d'utilisation pour la suppression d'un roman
|
||||||
|
document.querySelectorAll('.delete-story').forEach(button => {
|
||||||
|
button.addEventListener('click', (e) => {
|
||||||
|
const storyTitle = e.target.closest('.story-item').querySelector('h2').textContent;
|
||||||
|
|
||||||
|
confirmDialog.show({
|
||||||
|
title: 'Supprimer le roman',
|
||||||
|
message: `Voulez-vous vraiment supprimer le roman "${storyTitle}" ? Cette action est irréversible.`,
|
||||||
|
confirmText: 'Supprimer',
|
||||||
|
confirmClass: 'danger',
|
||||||
|
onConfirm: () => {
|
||||||
|
// Code de suppression existant
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -183,11 +183,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
if (cancelEditBtn) {
|
if (cancelEditBtn) {
|
||||||
cancelEditBtn.addEventListener('click', () => {
|
cancelEditBtn.addEventListener('click', () => {
|
||||||
if (hasUnsavedChanges()) {
|
if (hasUnsavedChanges()) {
|
||||||
if (!confirm('Des modifications non sauvegardées seront perdues. Voulez-vous vraiment fermer ?')) {
|
confirmDialog.show({
|
||||||
return;
|
title: 'Modifications non sauvegardées',
|
||||||
}
|
message: 'Des modifications non sauvegardées seront perdues. Voulez-vous vraiment fermer ?',
|
||||||
}
|
confirmText: 'Fermer sans sauvegarder',
|
||||||
|
onConfirm: () => {
|
||||||
modal.style.display = 'none';
|
modal.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
modal.style.display = 'none';
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +248,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
const chapterId = chapterItem.dataset.id;
|
const chapterId = chapterItem.dataset.id;
|
||||||
const chapterTitle = chapterItem.querySelector('.chapter-title').textContent;
|
const chapterTitle = chapterItem.querySelector('.chapter-title').textContent;
|
||||||
|
|
||||||
if (confirm(`Voulez-vous vraiment supprimer le chapitre "${chapterTitle}" ? Cette action est irréversible.`)) {
|
confirmDialog.show({
|
||||||
|
title: 'Suppression du chapitre',
|
||||||
|
message: `Voulez-vous vraiment supprimer le chapitre "${chapterTitle}" ? Cette action est irréversible.`,
|
||||||
|
confirmText: 'Supprimer',
|
||||||
|
confirmClass: 'danger',
|
||||||
|
onConfirm: async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('api/delete-chapter.php', {
|
const response = await fetch('api/delete-chapter.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -255,13 +266,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) throw new Error('Erreur réseau');
|
||||||
throw new Error('Erreur réseau');
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
// Animation de suppression
|
|
||||||
chapterItem.style.opacity = '0';
|
chapterItem.style.opacity = '0';
|
||||||
chapterItem.style.transform = 'translateX(-100%)';
|
chapterItem.style.transform = 'translateX(-100%)';
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -276,6 +284,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
showNotification(error.message, 'error');
|
showNotification(error.message, 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user