|
<!DOCTYPE html> |
|
<html lang="fr"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<title>Gestion des Données</title> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> |
|
<style> |
|
@keyframes slideIn { |
|
from { |
|
transform: translateY(-20px); |
|
opacity: 0; |
|
} |
|
to { |
|
transform: translateY(0); |
|
opacity: 1; |
|
} |
|
} |
|
|
|
@keyframes fadeIn { |
|
from { opacity: 0; } |
|
to { opacity: 1; } |
|
} |
|
|
|
@keyframes scaleIn { |
|
from { |
|
transform: scale(0.95); |
|
opacity: 0; |
|
} |
|
to { |
|
transform: scale(1); |
|
opacity: 1; |
|
} |
|
} |
|
|
|
@keyframes shimmer { |
|
0% { |
|
background-position: -1000px 0; |
|
} |
|
100% { |
|
background-position: 1000px 0; |
|
} |
|
} |
|
|
|
.animate-slideIn { |
|
animation: slideIn 0.5s ease-out; |
|
} |
|
|
|
.animate-fadeIn { |
|
animation: fadeIn 0.5s ease-out; |
|
} |
|
|
|
.animate-scaleIn { |
|
animation: scaleIn 0.3s ease-out; |
|
} |
|
|
|
.card-hover { |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.card-hover:hover { |
|
transform: translateY(-5px); |
|
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1); |
|
} |
|
|
|
.shimmer { |
|
background: linear-gradient(90deg, #f6f7f8 0%, #edeef1 50%, #f6f7f8 100%); |
|
background-size: 1000px 100%; |
|
animation: shimmer 2s infinite linear; |
|
} |
|
|
|
.tab-active { |
|
position: relative; |
|
} |
|
|
|
.tab-active::after { |
|
content: ''; |
|
position: absolute; |
|
bottom: -2px; |
|
left: 0; |
|
width: 100%; |
|
height: 2px; |
|
background: #3b82f6; |
|
transform: scaleX(0); |
|
transition: transform 0.3s ease; |
|
} |
|
|
|
.tab-active:hover::after, |
|
.tab-active.active::after { |
|
transform: scaleX(1); |
|
} |
|
|
|
.btn-primary { |
|
@apply bg-blue-500 hover:bg-blue-600 text-white font-semibold py-2 px-4 rounded-lg transition-all duration-300 transform hover:scale-105 hover:shadow-lg; |
|
} |
|
|
|
.btn-warning { |
|
@apply bg-yellow-500 hover:bg-yellow-600 text-white font-semibold py-2 px-4 rounded-lg transition-all duration-300 transform hover:scale-105 hover:shadow-lg; |
|
} |
|
|
|
.btn-danger { |
|
@apply bg-red-500 hover:bg-red-600 text-white font-semibold py-2 px-4 rounded-lg transition-all duration-300 transform hover:scale-105 hover:shadow-lg; |
|
} |
|
|
|
.form-input { |
|
@apply w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-300; |
|
} |
|
|
|
.alert { |
|
@apply p-4 mb-4 rounded-lg shadow-lg animate-slideIn; |
|
} |
|
|
|
.alert-success { |
|
@apply bg-green-100 border-l-4 border-green-500 text-green-700; |
|
} |
|
|
|
.alert-danger { |
|
@apply bg-red-100 border-l-4 border-red-500 text-red-700; |
|
} |
|
</style> |
|
</head> |
|
<body class="bg-gray-50 min-h-screen"> |
|
<div class="container mx-auto px-4 py-8 animate-fadeIn"> |
|
<h1 class="text-4xl font-bold text-gray-800 mb-8 animate-slideIn"> |
|
Gestion des Données |
|
</h1> |
|
|
|
{% with messages = get_flashed_messages(with_categories=true) %} |
|
{% if messages %} |
|
{% for category, message in messages %} |
|
<div class="alert alert-{{ category }} animate-scaleIn"> |
|
{{ message }} |
|
</div> |
|
{% endfor %} |
|
{% endif %} |
|
{% endwith %} |
|
|
|
|
|
<div class="mb-6 border-b border-gray-200"> |
|
<nav class="flex space-x-8" aria-label="Tabs"> |
|
<button class="tab-active px-4 py-2 text-gray-600 hover:text-blue-600 active"> |
|
<i class="fas fa-book mr-2"></i>Matières |
|
</button> |
|
<button class="tab-active px-4 py-2 text-gray-600 hover:text-blue-600"> |
|
<i class="fas fa-list mr-2"></i>Sous-Catégories |
|
</button> |
|
<button class="tab-active px-4 py-2 text-gray-600 hover:text-blue-600"> |
|
<i class="fas fa-file-alt mr-2"></i>Textes |
|
</button> |
|
<button class="tab-active px-4 py-2 text-gray-600 hover:text-blue-600"> |
|
<i class="fas fa-plus-circle mr-2"></i>Ajouter |
|
</button> |
|
</nav> |
|
</div> |
|
|
|
|
|
<div class="grid gap-6"> |
|
|
|
<div class="animate-scaleIn"> |
|
{% for matiere in matieres %} |
|
<div class="card-hover bg-white rounded-lg shadow-md p-6 mb-4"> |
|
<div class="flex justify-between items-center"> |
|
<h3 class="text-lg font-semibold text-gray-800">{{ matiere.nom }}</h3> |
|
<div class="flex space-x-2"> |
|
<button class="btn-warning edit-button"> |
|
<i class="fas fa-edit mr-2"></i>Modifier |
|
</button> |
|
<form method="post" class="inline"> |
|
<input type="hidden" name="action" value="delete_matiere_{{ matiere.id }}"> |
|
<button type="submit" class="btn-danger"> |
|
<i class="fas fa-trash mr-2"></i>Supprimer |
|
</button> |
|
</form> |
|
</div> |
|
</div> |
|
|
|
|
|
<form method="post" class="hidden editable mt-4"> |
|
<input type="hidden" name="action" value="edit_matiere_{{ matiere.id }}"> |
|
<div class="flex space-x-4"> |
|
<input type="text" name="edit_nom_matiere_{{ matiere.id }}" |
|
value="{{ matiere.nom }}" |
|
class="form-input flex-grow" |
|
placeholder="Nom de la matière"> |
|
<button type="submit" class="btn-primary"> |
|
<i class="fas fa-check mr-2"></i>Sauvegarder |
|
</button> |
|
<button type="button" class="btn-danger cancel-edit"> |
|
<i class="fas fa-times mr-2"></i>Annuler |
|
</button> |
|
</div> |
|
</form> |
|
</div> |
|
{% endfor %} |
|
</div> |
|
|
|
|
|
<div class="bg-white rounded-lg shadow-lg p-6 animate-scaleIn"> |
|
<h2 class="text-xl font-bold text-gray-800 mb-4"> |
|
<i class="fas fa-plus-circle mr-2"></i>Ajouter une nouvelle matière |
|
</h2> |
|
<form method="post" class="space-y-4"> |
|
<input type="hidden" name="action" value="add_matiere"> |
|
<div> |
|
<label class="block text-sm font-medium text-gray-700 mb-2"> |
|
Nom de la matière |
|
</label> |
|
<input type="text" name="nom_matiere" |
|
class="form-input" |
|
placeholder="Entrez le nom de la matière" |
|
required> |
|
</div> |
|
<button type="submit" class="btn-primary w-full"> |
|
<i class="fas fa-plus mr-2"></i>Ajouter la matière |
|
</button> |
|
</form> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> |
|
<script> |
|
$(document).ready(function() { |
|
|
|
$('.tab-active').click(function() { |
|
$('.tab-active').removeClass('active'); |
|
$(this).addClass('active'); |
|
|
|
|
|
$('.grid > div').addClass('animate-slideIn'); |
|
setTimeout(() => { |
|
$('.grid > div').removeClass('animate-slideIn'); |
|
}, 500); |
|
}); |
|
|
|
|
|
$(document).on('click', '.edit-button', function(e) { |
|
e.preventDefault(); |
|
const card = $(this).closest('.card-hover'); |
|
const form = card.find('.editable'); |
|
|
|
form.slideDown(300).css('display', 'block'); |
|
card.find('h3').fadeOut(300); |
|
$(this).fadeOut(300); |
|
}); |
|
|
|
|
|
$(document).on('click', '.cancel-edit', function(e) { |
|
e.preventDefault(); |
|
const card = $(this).closest('.card-hover'); |
|
const form = card.find('.editable'); |
|
|
|
form.slideUp(300); |
|
card.find('h3').fadeIn(300); |
|
card.find('.edit-button').fadeIn(300); |
|
}); |
|
|
|
|
|
$('form[method="post"]').submit(function(e) { |
|
if ($(this).find('.btn-danger').length) { |
|
if (!confirm('Êtes-vous sûr de vouloir supprimer cet élément ?')) { |
|
e.preventDefault(); |
|
} else { |
|
$(this).closest('.card-hover').addClass('animate-slideIn').fadeOut(500); |
|
} |
|
} |
|
}); |
|
|
|
|
|
$('.btn-primary').click(function() { |
|
$(this).addClass('shimmer'); |
|
setTimeout(() => { |
|
$(this).removeClass('shimmer'); |
|
}, 1000); |
|
}); |
|
}); |
|
</script> |
|
</body> |
|
</html> |