Files
notytex/templates/components/class/trimester_nav.html

280 lines
12 KiB
HTML

{#
Macro : trimester_nav(class_id, base_url, selected_trimester=None, badges={})
COULEURS THÉMATIQUES :
- T1 : from-blue-500 to-blue-600 (Hiver)
- T2 : from-green-500 to-green-600 (Printemps)
- T3 : from-orange-500 to-orange-600 (Été)
- Global : from-purple-500 to-purple-600 (Synthétique)
BADGES : dict optionnel avec le nombre d'évaluations par trimestre
Exemple: badges = {1: 4, 2: 3, 3: 2, 'global': 9}
#}
{% macro trimester_nav(class_id, base_url, selected_trimester=None, badges={}) %}
{# Configuration des trimestres avec couleurs thématiques #}
{% set trimesters = [
{
'key': 'global',
'label': 'Global',
'short': 'Global',
'gradient': 'from-purple-500 to-purple-600',
'hover_gradient': 'from-purple-600 to-purple-700',
'text_color': 'text-purple-600',
'bg_color': 'bg-purple-50',
'border_color': 'border-purple-200',
'icon': '<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20"><path d="M2 10a8 8 0 018-8v8h8a8 8 0 11-16 0z"/><path d="M12 2.252A8.014 8.014 0 0117.748 8H12V2.252z"/></svg>',
'description': 'Vue d\'ensemble de l\'année scolaire'
},
{
'key': 1,
'label': 'Trimestre 1',
'short': 'T1',
'gradient': 'from-blue-500 to-blue-600',
'hover_gradient': 'from-blue-600 to-blue-700',
'text_color': 'text-blue-600',
'bg_color': 'bg-blue-50',
'border_color': 'border-blue-200',
'icon': '<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20"><path d="M6 2a2 2 0 00-2 2v12a2 2 0 002 2h8a2 2 0 002-2V4a2 2 0 00-2-2h-8zM6 4h8v4l-4-2-4 2V4z"/></svg>',
'description': 'Septembre - Décembre'
},
{
'key': 2,
'label': 'Trimestre 2',
'short': 'T2',
'gradient': 'from-green-500 to-green-600',
'hover_gradient': 'from-green-600 to-green-700',
'text_color': 'text-green-600',
'bg_color': 'bg-green-50',
'border_color': 'border-green-200',
'icon': '<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clip-rule="evenodd"/></svg>',
'description': 'Janvier - Mars'
},
{
'key': 3,
'label': 'Trimestre 3',
'short': 'T3',
'gradient': 'from-orange-500 to-orange-600',
'hover_gradient': 'from-orange-600 to-orange-700',
'text_color': 'text-orange-600',
'bg_color': 'bg-orange-50',
'border_color': 'border-orange-200',
'icon': '<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20"><path d="M10 2L3 7v11a2 2 0 002 2h4v-6a1 1 0 011-1h2a1 1 0 011 1v6h4a2 2 0 002-2V7l-7-5zM8 15v2H6v-2h2z"/></svg>',
'description': 'Avril - Juillet'
}
] %}
<div class="trimester-nav bg-white rounded-xl shadow-lg p-6 mb-6" data-class-id="{{ class_id }}">
<!-- En-tête avec titre -->
<div class="flex items-center justify-between mb-4">
<div>
<h2 class="text-lg font-semibold text-gray-900">Navigation par trimestre</h2>
<p class="text-sm text-gray-500">Sélectionnez une période pour filtrer les données</p>
</div>
<!-- Indicateur de sélection actuelle -->
<div class="hidden md:block">
{% set current_trimester = trimesters|selectattr('key', 'equalto', selected_trimester)|first %}
{% if current_trimester %}
<div class="flex items-center text-sm text-gray-600">
<span class="mr-2">Période active :</span>
<div class="flex items-center px-3 py-1 bg-gradient-to-r {{ current_trimester.gradient }} text-white rounded-lg">
{{ current_trimester.icon|safe }}
<span class="ml-2 font-medium">{{ current_trimester.label }}</span>
</div>
</div>
{% endif %}
</div>
</div>
<!-- Tabs de navigation - Version desktop -->
<div class="hidden md:flex space-x-2 overflow-x-auto">
{% for trimester in trimesters %}
{% set is_active = selected_trimester == trimester.key or (selected_trimester is none and trimester.key == 'global') %}
{% set badge_count = badges.get(trimester.key, 0) %}
<button type="button"
class="tab-btn flex-shrink-0 group relative px-6 py-3 rounded-xl font-medium transition-all duration-300 transform hover:scale-105
{% if is_active %}
bg-gradient-to-r {{ trimester.gradient }} text-white shadow-lg
{% else %}
bg-gray-50 text-gray-600 hover:bg-gray-100 border border-gray-200
{% endif %}"
data-trimester="{{ trimester.key }}"
data-base-url="{{ base_url }}"
data-class-id="{{ class_id }}"
onclick="navigateToTrimester(this)">
<!-- Icône -->
<div class="flex items-center">
<div class="mr-3 {% if not is_active %}{{ trimester.text_color }}{% endif %}">
{{ trimester.icon|safe }}
</div>
<!-- Label et badge -->
<div class="flex items-center">
<span>{{ trimester.label }}</span>
{% if badge_count > 0 %}
<span class="ml-2 px-2 py-0.5 text-xs font-bold rounded-full
{% if is_active %}
bg-white/20 text-white
{% else %}
bg-{{ trimester.text_color.replace('text-', '').replace('-600', '') }}-100 {{ trimester.text_color }}
{% endif %}">
{{ badge_count }}
</span>
{% endif %}
</div>
</div>
<!-- Tooltip -->
<div class="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-2 py-1 text-xs bg-gray-900 text-white rounded opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none">
{{ trimester.description }}
<div class="absolute top-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-l-4 border-r-4 border-t-4 border-transparent border-t-gray-900"></div>
</div>
</button>
{% endfor %}
</div>
<!-- Tabs de navigation - Version mobile (scroll horizontal) -->
<div class="md:hidden overflow-x-auto">
<div class="flex space-x-2 pb-2">
{% for trimester in trimesters %}
{% set is_active = selected_trimester == trimester.key or (selected_trimester is none and trimester.key == 'global') %}
{% set badge_count = badges.get(trimester.key, 0) %}
<button type="button"
class="tab-btn flex-shrink-0 px-4 py-2 rounded-lg font-medium text-sm transition-all duration-300
{% if is_active %}
bg-gradient-to-r {{ trimester.gradient }} text-white shadow-md
{% else %}
bg-gray-50 text-gray-600 hover:bg-gray-100 border border-gray-200
{% endif %}"
data-trimester="{{ trimester.key }}"
data-base-url="{{ base_url }}"
data-class-id="{{ class_id }}"
onclick="navigateToTrimester(this)">
<div class="flex items-center">
<div class="mr-2 {% if not is_active %}{{ trimester.text_color }}{% endif %}">
{{ trimester.icon|safe }}
</div>
<span>{{ trimester.short }}</span>
{% if badge_count > 0 %}
<span class="ml-1 px-1.5 py-0.5 text-xs font-bold rounded-full
{% if is_active %}
bg-white/20 text-white
{% else %}
bg-{{ trimester.text_color.replace('text-', '').replace('-600', '') }}-100 {{ trimester.text_color }}
{% endif %}">
{{ badge_count }}
</span>
{% endif %}
</div>
</button>
{% endfor %}
</div>
</div>
<!-- Informations contextuelles -->
<div class="mt-4 p-3 bg-gray-50 rounded-lg border border-gray-200">
{% set current_trimester = trimesters|selectattr('key', 'equalto', selected_trimester)|first %}
{% if not current_trimester %}
{% set current_trimester = trimesters|selectattr('key', 'equalto', 'global')|first %}
{% endif %}
<div class="flex items-center justify-between">
<div class="flex items-center">
<div class="w-8 h-8 {{ current_trimester.bg_color }} rounded-lg flex items-center justify-center mr-3 {{ current_trimester.text_color }}">
{{ current_trimester.icon|safe }}
</div>
<div>
<p class="text-sm font-medium text-gray-900">{{ current_trimester.label }}</p>
<p class="text-xs text-gray-500">{{ current_trimester.description }}</p>
</div>
</div>
<!-- Statistiques rapides -->
{% set current_badge = badges.get(selected_trimester or 'global', 0) %}
{% if current_badge > 0 %}
<div class="text-right">
<p class="text-sm font-semibold {{ current_trimester.text_color }}">{{ current_badge }}</p>
<p class="text-xs text-gray-500">évaluation{{ 's' if current_badge > 1 else '' }}</p>
</div>
{% endif %}
</div>
</div>
</div>
{# JavaScript pour la navigation - À inclure dans la page qui utilise le composant #}
<script>
function navigateToTrimester(button) {
const trimester = button.dataset.trimester;
const baseUrl = button.dataset.baseUrl;
const classId = button.dataset.classId;
// Construire l'URL avec le paramètre trimestre
let url = baseUrl;
if (url.includes('?')) {
url += '&';
} else {
url += '?';
}
// Ajouter le paramètre trimestre (sauf pour 'global')
if (trimester !== 'global') {
url += `trimestre=${trimester}`;
} else {
// Pour global, on ne met pas de paramètre trimestre
url = baseUrl;
}
// Animation de transition
button.style.transform = 'scale(0.95)';
setTimeout(() => {
button.style.transform = '';
window.location.href = url;
}, 150);
}
// Gestion du scroll horizontal sur mobile
document.addEventListener('DOMContentLoaded', function() {
const mobileNav = document.querySelector('.trimester-nav .md\\:hidden .flex');
const activeButton = mobileNav?.querySelector('.bg-gradient-to-r');
// Scroller automatiquement vers le bouton actif sur mobile
if (activeButton && mobileNav) {
activeButton.scrollIntoView({
behavior: 'smooth',
inline: 'center',
block: 'nearest'
});
}
});
// Animation au hover pour les tooltips desktop
document.addEventListener('DOMContentLoaded', function() {
const buttons = document.querySelectorAll('.trimester-nav .tab-btn');
buttons.forEach(button => {
let timeout;
button.addEventListener('mouseenter', function() {
timeout = setTimeout(() => {
const tooltip = this.querySelector('.absolute.bottom-full');
if (tooltip) {
tooltip.style.transform = 'translateX(-50%) translateY(-2px)';
}
}, 300);
});
button.addEventListener('mouseleave', function() {
clearTimeout(timeout);
const tooltip = this.querySelector('.absolute.bottom-full');
if (tooltip) {
tooltip.style.transform = 'translateX(-50%) translateY(0)';
}
});
});
});
</script>
{% endmacro %}