feat: improve focus mode

This commit is contained in:
2025-08-12 07:25:26 +02:00
parent 11bfc5c5cb
commit c3ef5287b3
2 changed files with 627 additions and 347 deletions

View File

@@ -538,25 +538,8 @@ class AutoSaveManager {
}
bindManualSaveButtons() {
const saveButtons = document.querySelectorAll('[data-save-manual]');
const finalizeButtons = document.querySelectorAll('[data-finalize]');
saveButtons.forEach(button => {
const studentId = button.dataset.saveManual;
button.addEventListener('click', () => {
const textarea = document.querySelector(`[data-appreciation-textarea][data-student-id="${studentId}"]`);
if (textarea) {
this.queueSave(studentId, textarea.value, true);
}
});
});
finalizeButtons.forEach(button => {
const studentId = button.dataset.finalize;
button.addEventListener('click', () => {
this.finalizeAppreciation(studentId);
});
});
// Boutons supprimés de l'interface - auto-sauvegarde uniquement
console.log('📝 Auto-sauvegarde activée - Pas de boutons manuels');
}
setupCharacterCounter(textarea, studentId) {
@@ -1077,6 +1060,18 @@ class FocusManager {
detailsSection.classList.remove('hidden');
detailsSection.style.height = 'auto';
detailsSection.style.opacity = '1';
detailsSection.style.flex = '1';
detailsSection.style.display = 'block';
detailsSection.style.overflowY = 'auto';
// S'assurer que le contenu interne utilise Flexbox
const innerContent = detailsSection.querySelector('.px-6.py-6.space-y-6');
if (innerContent) {
innerContent.style.display = 'flex';
innerContent.style.flexDirection = 'column';
innerContent.style.height = '100%';
innerContent.style.gap = '1.5rem';
}
}
// Ajouter une classe spéciale pour le mode focus
@@ -1094,6 +1089,9 @@ class FocusManager {
// Réattacher TOUS les événements pour le nouvel élément focus
this.bindFocusStudentEvents(clonedStudent, studentId);
// Assurer que toutes les sections sont visibles
this.ensureAllSectionsVisible(clonedStudent);
// Focus automatique sur le textarea de l'appréciation
this.focusAppreciationTextarea(clonedStudent);
@@ -1133,36 +1131,49 @@ class FocusManager {
this.parent.autoSaveManager.setupCharacterCounter(textarea, studentId);
}
// 2. Boutons de sauvegarde manuelle
const saveButton = clonedStudent.querySelector(`[data-save-manual="${studentId}"]`);
if (saveButton) {
saveButton.addEventListener('click', () => {
const textareaValue = clonedStudent.querySelector(`[data-appreciation-textarea][data-student-id="${studentId}"]`)?.value || '';
console.log(`💾 Sauvegarde manuelle en focus pour élève ${studentId}`);
this.saveFocusAppreciation(studentId, textareaValue, true);
});
}
// 3. Bouton de finalisation
const finalizeButton = clonedStudent.querySelector(`[data-finalize="${studentId}"]`);
if (finalizeButton) {
finalizeButton.addEventListener('click', () => {
const textareaValue = clonedStudent.querySelector(`[data-appreciation-textarea][data-student-id="${studentId}"]`)?.value || '';
if (!textareaValue.trim()) {
this.parent.showToast('Veuillez saisir une appréciation avant de finaliser', 'warning');
return;
}
if (confirm('Finaliser cette appréciation ? Elle ne pourra plus être modifiée.')) {
console.log(`✅ Finalisation en focus pour élève ${studentId}`);
this.saveFocusAppreciation(studentId, textareaValue, true);
}
});
}
// 2. Boutons supprimés - auto-sauvegarde uniquement
console.log(`🔧 Mode focus: Auto-sauvegarde configurée pour élève ${studentId}`);
// 4. Gestion des barres de progression
this.setupProgressBars(clonedStudent);
}
ensureAllSectionsVisible(clonedStudent) {
console.log('🔍 Vérification de la visibilité de toutes les sections en mode focus');
// S'assurer que les sections compétences/domaines sont visibles
const competenceSection = clonedStudent.querySelector('.competence-domain-section');
if (competenceSection) {
competenceSection.style.display = 'block';
competenceSection.style.minHeight = '200px';
competenceSection.style.flexShrink = '0';
console.log('✅ Section compétences/domaines visible');
}
// S'assurer que les barres de progression sont configurées
const progressBars = clonedStudent.querySelectorAll('.progress-bar-container');
progressBars.forEach(bar => {
bar.style.display = 'block';
});
// Section info supprimée - maintenant intégrée dans la zone d'appréciation
console.log('✅ Informations intégrées dans la zone d\'appréciation');
// S'assurer que les résultats d'évaluation sont visibles
const evaluationResults = clonedStudent.querySelector('.evaluation-results');
if (evaluationResults) {
evaluationResults.style.display = 'block';
console.log('✅ Section résultats d\'évaluation visible');
}
// S'assurer que la section progress-bars est visible
const progressBarsSection = clonedStudent.querySelector('.progress-bars');
if (progressBarsSection) {
progressBarsSection.style.display = 'block';
console.log('✅ Section barres de progression visible');
}
}
setupProgressBars(clonedStudent) {
// Configure les interactions avec les barres de progression des compétences et domaines
@@ -1746,16 +1757,41 @@ class FocusManager {
const student = focusContainer.querySelector('.focus-mode-student');
if (!student) return;
// Calculer la hauteur disponible
const windowHeight = window.innerHeight;
const headerHeight = 200; // Approximation header + navigation + contrôles
const maxHeight = windowHeight - headerHeight;
// Ajuster la hauteur de la carte
student.style.maxHeight = `${maxHeight}px`;
// Forcer explicitement la hauteur complète
student.style.height = '100%';
student.style.minHeight = '100%';
student.style.maxHeight = 'none';
student.style.display = 'flex';
student.style.flexDirection = 'column';
student.style.overflow = 'hidden';
// S'assurer que le header garde sa taille et ne grandit pas
const headerContainer = student.querySelector('.px-6.py-4');
if (headerContainer) {
headerContainer.style.flexShrink = '0';
headerContainer.style.flex = 'none';
}
// S'assurer que la section détails utilise tout l'espace restant
const detailsSection = student.querySelector('[data-student-details]');
if (detailsSection) {
detailsSection.style.flex = '1 1 0';
detailsSection.style.height = '0'; // Force flexbox
detailsSection.style.display = 'block';
detailsSection.style.overflowY = 'auto';
detailsSection.style.minHeight = '0';
}
// Scroll vers le haut si nécessaire
window.scrollTo(0, 0);
// Debug des hauteurs
const containerHeight = focusContainer.offsetHeight;
const studentHeight = student.offsetHeight;
console.log(`🎯 Mode focus optimisé:`);
console.log(` Container height: ${containerHeight}px`);
console.log(` Student height: ${studentHeight}px`);
console.log(` Window height: ${window.innerHeight}px`);
}
preserveJsonDataBeforeCloning(originalStudent) {

View File

@@ -233,122 +233,97 @@
data-performance-status="{{ summary.performance_status }}"
data-has-appreciation="{{ 'true' if summary.has_appreciation else 'false' }}">
{# Header cliquable #}
<div class="px-6 py-4 cursor-pointer flex items-center justify-between"
data-toggle-student="{{ summary.student.id }}">
<div class="flex items-center space-x-4">
{# Avatar avec initiales #}
<div class="w-12 h-12 rounded-full flex items-center justify-center text-white font-bold text-sm
{% if summary.performance_status == 'excellent' %}bg-gradient-to-r from-green-500 to-green-600{% endif %}
{% if summary.performance_status == 'good' %}bg-gradient-to-r from-blue-500 to-blue-600{% endif %}
{% if summary.performance_status == 'average' %}bg-gradient-to-r from-yellow-500 to-yellow-600{% endif %}
{% if summary.performance_status == 'struggling' %}bg-gradient-to-r from-red-500 to-red-600{% endif %}
{% if summary.performance_status == 'no_data' %}bg-gradient-to-r from-gray-500 to-gray-600{% endif %}">
{{ summary.student.first_name[0] }}{{ summary.student.last_name[0] }}
</div>
{# Informations élève #}
<div class="flex-1 min-w-0">
<h3 class="font-semibold text-gray-900 text-lg">{{ summary.student.last_name }}, {{ summary.student.first_name }}</h3>
{# Ligne 1: Info de base #}
<div class="flex items-center space-x-4 text-sm text-gray-600 mb-2">
<span class="flex items-center">
<svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 20 20">
<path d="M2 11a1 1 0 011-1h2a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1v-5zM8 7a1 1 0 011-1h2a1 1 0 011 1v9a1 1 0 01-1 1H9a1 1 0 01-1-1V7zM14 4a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1h-2a1 1 0 01-1-1V4z"/>
</svg>
{{ summary.assessment_count }} évaluation(s)
</span>
{% if summary.performance_status == 'struggling' %}
<span class="inline-flex items-center px-2 py-1 rounded-full text-xs bg-red-100 text-red-800 font-medium">
⚠️ Attention requise
</span>
{% endif %}
{# Header avec layout en deux colonnes principales #}
<div class="px-6 py-4">
{# Layout principal : Informations élève + Appréciation + Moyenne #}
<div class="flex items-start space-x-6">
{# Colonne 1: Informations élève avec avatar #}
<div class="flex items-center space-x-4 cursor-pointer" data-toggle-student="{{ summary.student.id }}">
{# Avatar avec initiales #}
<div class="w-12 h-12 rounded-full flex items-center justify-center text-white font-bold text-sm
{% if summary.performance_status == 'excellent' %}bg-gradient-to-r from-green-500 to-green-600{% endif %}
{% if summary.performance_status == 'good' %}bg-gradient-to-r from-blue-500 to-blue-600{% endif %}
{% if summary.performance_status == 'average' %}bg-gradient-to-r from-yellow-500 to-yellow-600{% endif %}
{% if summary.performance_status == 'struggling' %}bg-gradient-to-r from-red-500 to-red-600{% endif %}
{% if summary.performance_status == 'no_data' %}bg-gradient-to-r from-gray-500 to-gray-600{% endif %}">
{{ summary.student.first_name[0] }}{{ summary.student.last_name[0] }}
</div>
{# NOUVEAU - Ligne 2: Aperçu rapide des dernières évaluations #}
{% if summary.grades_by_assessment %}
<div class="assessment-preview-mobile-hide">
<div class="flex items-center space-x-1 text-xs text-gray-500 mb-1">Dernières évaluations :</div>
<div class="flex items-center space-x-2">
{% set recent_assessments = summary.grades_by_assessment.items() | list | sort(attribute='1.date', reverse=True) %}
{% for assessment_id, assessment_data in recent_assessments[:4] %}
<div class="assessment-preview-pills flex items-center space-x-1 bg-gray-50 px-2 py-1 rounded text-xs cursor-help
{% if assessment_data.score / assessment_data.max >= 0.8 %}text-green-700 bg-green-50{% endif %}
{% if assessment_data.score / assessment_data.max < 0.5 %}text-red-700 bg-red-50{% endif %}"
title="{{ assessment_data.title }} - {{ assessment_data.date.strftime('%d/%m') if assessment_data.date else 'Date inconnue' }}">
<span class="font-medium">{{ "%.1f"|format(assessment_data.score) }}</span>
<span class="text-gray-400">/</span>
<span>{{ assessment_data.max }}</span>
</div>
{% endfor %}
{% if summary.grades_by_assessment | length > 4 %}
<span class="text-xs text-gray-400 cursor-help" title="Cliquez pour voir toutes les évaluations">+{{ summary.grades_by_assessment | length - 4 }}</span>
{# Informations de base élève #}
<div class="min-w-0">
<h3 class="font-semibold text-gray-900 text-lg">{{ summary.student.last_name }}, {{ summary.student.first_name }}</h3>
{# Info de base avec chevron #}
<div class="flex items-center space-x-4 text-sm text-gray-600">
<span class="flex items-center">
<svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 20 20">
<path d="M2 11a1 1 0 011-1h2a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1v-5zM8 7a1 1 0 011-1h2a1 1 0 011 1v9a1 1 0 01-1 1H9a1 1 0 01-1-1V7zM14 4a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1h-2a1 1 0 01-1-1V4z"/>
</svg>
{{ summary.assessment_count }} évaluation(s)
</span>
{% if summary.performance_status == 'struggling' %}
<span class="inline-flex items-center px-2 py-1 rounded-full text-xs bg-red-100 text-red-800 font-medium">
⚠️ Attention requise
</span>
{% endif %}
{# Chevron d'expansion #}
<svg class="w-4 h-4 text-gray-400 transform transition-transform duration-300"
data-toggle-icon fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
</svg>
</div>
</div>
{% endif %}
</div>
</div>
{# Moyenne et statut - REORGANISÉ pour plus de clarté #}
<div class="flex flex-col items-end space-y-2 text-right">
{# Ligne 1: Moyenne principale #}
<div class="flex items-center space-x-3">
{% if summary.overall_average %}
<span class="text-xl font-bold px-4 py-2 rounded-lg
{% if summary.performance_status == 'excellent' %}bg-green-100 text-green-800{% endif %}
{% if summary.performance_status == 'good' %}bg-blue-100 text-blue-800{% endif %}
{% if summary.performance_status == 'average' %}bg-yellow-100 text-yellow-800{% endif %}
{% if summary.performance_status == 'struggling' %}bg-red-100 text-red-800{% endif %}">
{{ "%.1f"|format(summary.overall_average) }}/20
</span>
{% else %}
<span class="text-sm text-gray-500 px-3 py-1 bg-gray-100 rounded-lg">
Pas de données
</span>
{% endif %}
{# Chevron d'expansion #}
<svg class="w-5 h-5 text-gray-400 transform transition-transform duration-300"
data-toggle-icon fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
</svg>
</div>
{# Ligne 2: Indicateurs de statut #}
<div class="flex items-center space-x-2">
{# NOUVEAU - Indicateur de tendance #}
{% if summary.overall_average and summary.grades_by_assessment | length > 1 %}
{% set recent_assessments = summary.grades_by_assessment.values() | list | sort(attribute='date') %}
{% set trend_recent = (recent_assessments[-1].score / recent_assessments[-1].max * 20) if recent_assessments | length > 0 else 0 %}
{% set trend_previous = (recent_assessments[-2].score / recent_assessments[-2].max * 20) if recent_assessments | length > 1 else trend_recent %}
{% if trend_recent > trend_previous + 1 %}
<span class="inline-flex items-center text-xs text-green-600" title="Tendance positive">
<svg class="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M3.293 9.707a1 1 0 010-1.414l6-6a1 1 0 011.414 0l6 6a1 1 0 01-1.414 1.414L10 4.414 4.707 9.707a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
</svg>
+{{ "%.1f"|format(trend_recent - trend_previous) }}
</span>
{% elif trend_recent < trend_previous - 1 %}
<span class="inline-flex items-center text-xs text-red-600" title="Tendance négative">
<svg class="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M16.707 10.293a1 1 0 010 1.414l-6 6a1 1 0 01-1.414 0l-6-6a1 1 0 111.414-1.414L10 15.586l5.293-5.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
</svg>
{{ "%.1f"|format(trend_recent - trend_previous) }}
{# Colonne 2: Zone d'appréciation intégrée #}
<div class="flex-1 min-w-0">
<label class="block text-sm font-medium text-gray-700 mb-2 flex items-center">
<svg class="w-4 h-4 text-purple-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
</svg>
Appréciation du conseil de classe
</label>
<textarea
data-appreciation-textarea
data-student-id="{{ summary.student.id }}"
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-purple-500 focus:border-purple-500 resize-none transition-colors"
rows="2"
placeholder="Saisir l'appréciation générale pour le bulletin...">{% if summary.appreciation and summary.appreciation.general_appreciation %}{{ summary.appreciation.general_appreciation }}{% endif %}</textarea>
<div class="mt-1 flex justify-between items-center text-xs text-gray-500">
<div class="flex items-center space-x-3">
<span>Sauvegarde automatique</span>
<div class="hidden" data-save-indicator="{{ summary.student.id }}"></div>
{% if summary.appreciation %}
<span class="text-gray-400"></span>
<span data-last-modified="{{ summary.student.id }}">{{ summary.appreciation.last_modified.strftime('%d/%m à %H:%M') }}</span>
{% endif %}
</div>
<span data-char-counter>0 caractères</span>
</div>
</div>
{# Colonne 3: Moyenne et statuts #}
<div class="flex flex-col items-end space-y-2 text-right min-w-max">
{# Moyenne principale #}
<div class="flex items-center space-x-2">
{% if summary.overall_average %}
<span class="text-xl font-bold px-4 py-2 rounded-lg
{% if summary.performance_status == 'excellent' %}bg-green-100 text-green-800{% endif %}
{% if summary.performance_status == 'good' %}bg-blue-100 text-blue-800{% endif %}
{% if summary.performance_status == 'average' %}bg-yellow-100 text-yellow-800{% endif %}
{% if summary.performance_status == 'struggling' %}bg-red-100 text-red-800{% endif %}">
{{ "%.1f"|format(summary.overall_average) }}/20
</span>
{% else %}
<span class="inline-flex items-center text-xs text-gray-500" title="Stable">
<svg class="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M5 10a1 1 0 011-1h8a1 1 0 110 2H6a1 1 0 01-1-1z" clip-rule="evenodd"/>
</svg>
Stable
<span class="text-sm text-gray-500 px-3 py-1 bg-gray-100 rounded-lg">
Pas de données
</span>
{% endif %}
{% endif %}
</div>
{# Indicateur d'appréciation #}
<div class="flex items-center">
{# Indicateurs de statut compacts #}
<div class="flex items-center space-x-2">
{# Indicateur d'appréciation #}
{% if summary.has_appreciation %}
<span class="inline-flex items-center px-2 py-1 rounded-full text-xs bg-green-100 text-green-800">
<span class="w-2 h-2 bg-green-400 rounded-full mr-1"></span>
@@ -360,10 +335,27 @@
À rédiger
</span>
{% endif %}
{# Indicateur de tendance condensé #}
{% if summary.overall_average and summary.grades_by_assessment | length > 1 %}
{% set recent_assessments = summary.grades_by_assessment.values() | list | sort(attribute='date') %}
{% set trend_recent = (recent_assessments[-1].score / recent_assessments[-1].max * 20) if recent_assessments | length > 0 else 0 %}
{% set trend_previous = (recent_assessments[-2].score / recent_assessments[-2].max * 20) if recent_assessments | length > 1 else trend_recent %}
{% if trend_recent > trend_previous + 1 %}
<span class="inline-flex items-center text-xs text-green-600" title="Tendance positive: +{{ '%.1f'|format(trend_recent - trend_previous) }}">
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M3.293 9.707a1 1 0 010-1.414l6-6a1 1 0 011.414 0l6 6a1 1 0 01-1.414 1.414L10 4.414 4.707 9.707a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
</svg>
</span>
{% elif trend_recent < trend_previous - 1 %}
<span class="inline-flex items-center text-xs text-red-600" title="Tendance négative: {{ '%.1f'|format(trend_recent - trend_previous) }}">
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M16.707 10.293a1 1 0 010 1.414l-6 6a1 1 0 01-1.414 0l-6-6a1 1 0 111.414-1.414L10 15.586l5.293-5.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
</svg>
</span>
{% endif %}
{% endif %}
</div>
{# Indicateur de sauvegarde #}
<div class="hidden" data-save-indicator="{{ summary.student.id }}"></div>
</div>
</div>
</div>
@@ -372,199 +364,155 @@
<div class="hidden border-t border-gray-200" data-student-details="{{ summary.student.id }}">
<div class="px-6 py-6 space-y-6">
{# Détail des évaluations #}
{% if summary.grades_by_assessment %}
<div>
<h4 class="font-medium text-gray-700 mb-3 flex items-center">
<svg class="w-4 h-4 text-blue-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path d="M2 11a1 1 0 011-1h2a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1v-5zM8 7a1 1 0 011-1h2a1 1 0 011 1v9a1 1 0 01-1 1H9a1 1 0 01-1-1V7zM14 4a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1h-2a1 1 0 01-1-1V4z"/>
</svg>
Résultats par évaluation
</h4>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
{% for assessment_id, assessment_data in summary.grades_by_assessment.items() %}
<div class="bg-blue-50 px-4 py-3 rounded-lg border border-blue-100">
<div class="font-medium text-blue-900 text-sm mb-1">{{ assessment_data.title }}</div>
<div class="flex items-center justify-between">
<span class="text-blue-700 font-bold">{{ "%.1f"|format(assessment_data.score) }}/{{ assessment_data.max }}</span>
<span class="text-xs text-blue-600">Coeff. {{ assessment_data.coefficient }}</span>
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{# Section Compétences et Domaines #}
{# Section Compétences et Domaines - Layout horizontal #}
{% if summary.competence_domain_breakdown and (summary.competence_domain_breakdown.competences or summary.competence_domain_breakdown.domains) %}
<div class="competence-domain-section">
<h4 class="font-medium text-gray-700 mb-3 flex items-center">
<svg class="w-4 h-4 text-indigo-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
Progression par compétence et domaine
</h4>
{# Barres de compétences #}
{% if summary.competence_domain_breakdown.competences %}
<div class="mb-4">
<h5 class="text-sm font-medium text-purple-700 mb-3 flex items-center">
<svg class="w-3 h-3 text-purple-500 mr-1" fill="currentColor" viewBox="0 0 20 20">
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/>
</svg>
Compétences
</h5>
<div class="space-y-2">
{% for competence in summary.competence_domain_breakdown.competences %}
<div class="competence-progress-bar">
<div class="flex items-center justify-between mb-1">
<span class="text-sm font-medium text-gray-700">{{ competence.name }}</span>
<span class="text-sm font-bold" style="color: {{ competence.color }}">
{{ competence.percentage }}% ({{ competence.earned_points }}/{{ competence.total_points }})
</span>
</div>
<div class="progress-bar-container segmented-progress"
data-competence-name="{{ competence.name }}"
data-assessments="{{ competence.assessments | tojson | e }}"
role="progressbar"
aria-valuenow="{{ competence.percentage }}"
aria-valuemin="0"
aria-valuemax="100"
aria-label="Progression de la compétence {{ competence.name }}: {{ competence.percentage }}%"
tabindex="0">
<div class="segmented-progress-bar" data-expanded="true">
<!-- Segments pour chaque évaluation -->
{% for assessment in competence.assessments %}
<div class="progress-segment"
style="width: {{ assessment.percentage_contribution }}%; background-color: {{ assessment.color }};"
data-assessment-id="{{ assessment.id }}"
data-assessment-title="{{ assessment.title }}"
data-assessment-performance="{{ assessment.performance }}"
data-earned-this="{{ assessment.earned_this }}"
data-max-this="{{ assessment.max_this }}"
data-earned-cumulative="{{ assessment.earned_cumulative }}"
data-max-cumulative="{{ assessment.max_cumulative }}"
data-contribution-percentage="{{ assessment.percentage_contribution }}"
title="{{ assessment.title }}: {{ assessment.earned_this }} pts ({{ assessment.performance }}%)"
role="button"
tabindex="0"
aria-label="Évaluation {{ assessment.title }}: {{ assessment.earned_this }} points sur {{ assessment.max_this }}">
<span class="segment-label">{{ assessment.title }}</span>
</div>
{% endfor %}
{# Layout horizontal: Résultats + Barres #}
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
{# Colonne gauche: Résultats par évaluation (si disponibles) #}
{% if summary.grades_by_assessment %}
<div class="evaluation-results">
<h5 class="text-sm font-medium text-blue-700 mb-3 flex items-center">
<svg class="w-4 h-4 text-blue-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path d="M2 11a1 1 0 011-1h2a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1v-5zM8 7a1 1 0 011-1h2a1 1 0 011 1v9a1 1 0 01-1 1H9a1 1 0 01-1-1V7zM14 4a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1h-2a1 1 0 01-1-1V4z"/>
</svg>
Résultats par évaluation
</h5>
<div class="space-y-1.5">
{% for assessment_id, assessment_data in summary.grades_by_assessment.items() %}
<div class="flex items-center justify-between p-2 bg-blue-50 rounded-lg border border-blue-100">
<span class="text-sm font-medium text-blue-900 truncate">{{ assessment_data.title }}</span>
<div class="flex items-center space-x-2">
<span class="text-sm font-bold text-blue-700">{{ "%.1f"|format(assessment_data.score) }}/{{ assessment_data.max }}</span>
{% if assessment_data.coefficient != 1 %}
<span class="text-xs text-blue-600 bg-blue-200 px-1 rounded">×{{ assessment_data.coefficient }}</span>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
{% endif %}
{# Barres de domaines #}
{% if summary.competence_domain_breakdown.domains %}
<div>
<h5 class="text-sm font-medium text-orange-700 mb-3 flex items-center">
<svg class="w-3 h-3 text-orange-500 mr-1" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M3 4a1 1 0 011-1h4a1 1 0 010 2H6.414l2.293 2.293a1 1 0 01-1.414 1.414L5 6.414V8a1 1 0 01-2 0V4zm9 1a1 1 0 010-2h4a1 1 0 011 1v4a1 1 0 01-2 0V6.414l-2.293 2.293a1 1 0 11-1.414-1.414L13.586 5H12zm-9 7a1 1 0 012 0v1.586l2.293-2.293a1 1 0 111.414 1.414L6.414 15H8a1 1 0 010 2H4a1 1 0 01-1-1v-4zm13-1a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 010-2h1.586l-2.293-2.293a1 1 0 111.414-1.414L15 13.586V12a1 1 0 011-1z" clip-rule="evenodd"/>
</svg>
Domaines
</h5>
<div class="space-y-2">
{% for domain in summary.competence_domain_breakdown.domains %}
<div class="domain-progress-bar">
<div class="flex items-center justify-between mb-1">
<span class="text-sm font-medium text-gray-700">{{ domain.name }}</span>
<span class="text-sm font-bold" style="color: {{ domain.color }}">
{{ domain.percentage }}% ({{ domain.earned_points }}/{{ domain.total_points }})
</span>
</div>
<div class="progress-bar-container segmented-progress"
data-domain-name="{{ domain.name }}"
data-assessments="{{ domain.assessments | tojson | e }}"
role="progressbar"
aria-valuenow="{{ domain.percentage }}"
aria-valuemin="0"
aria-valuemax="100"
aria-label="Progression du domaine {{ domain.name }}: {{ domain.percentage }}%"
tabindex="0">
<div class="segmented-progress-bar" data-expanded="true">
<!-- Segments pour chaque évaluation -->
{% for assessment in domain.assessments %}
<div class="progress-segment"
style="width: {{ assessment.percentage_contribution }}%; background-color: {{ assessment.color }};"
data-assessment-id="{{ assessment.id }}"
data-assessment-title="{{ assessment.title }}"
data-assessment-performance="{{ assessment.performance }}"
data-earned-this="{{ assessment.earned_this }}"
data-max-this="{{ assessment.max_this }}"
data-earned-cumulative="{{ assessment.earned_cumulative }}"
data-max-cumulative="{{ assessment.max_cumulative }}"
data-contribution-percentage="{{ assessment.percentage_contribution }}"
title="{{ assessment.title }}: {{ assessment.earned_this }} pts ({{ assessment.performance }}%)"
role="button"
tabindex="0"
aria-label="Évaluation {{ assessment.title }}: {{ assessment.earned_this }} points sur {{ assessment.max_this }}">
<span class="segment-label">{{ assessment.title }}</span>
{% endif %}
{# Colonne droite: Barres de progression #}
<div class="progress-bars">
{# Compétences #}
{% if summary.competence_domain_breakdown.competences %}
<div class="mb-4">
<h5 class="text-sm font-medium text-purple-700 mb-3 flex items-center">
<svg class="w-3 h-3 text-purple-500 mr-1" fill="currentColor" viewBox="0 0 20 20">
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/>
</svg>
Compétences
</h5>
<div class="space-y-3">
{% for competence in summary.competence_domain_breakdown.competences %}
<div class="competence-progress-horizontal">
{# Nom et score à côté de la barre #}
<div class="flex items-center justify-between mb-1">
<span class="text-xs font-medium text-gray-700 truncate flex-1 mr-2">{{ competence.name }}</span>
<span class="text-xs font-bold whitespace-nowrap" style="color: {{ competence.color }}">
{{ competence.percentage }}%
</span>
</div>
{# Barre de progression compacte #}
<div class="progress-bar-container segmented-progress compact"
data-competence-name="{{ competence.name }}"
data-assessments="{{ competence.assessments | tojson | e }}"
role="progressbar"
aria-valuenow="{{ competence.percentage }}"
aria-valuemin="0"
aria-valuemax="100"
aria-label="Progression de la compétence {{ competence.name }}: {{ competence.percentage }}%"
tabindex="0">
<div class="segmented-progress-bar compact" data-expanded="true">
{% for assessment in competence.assessments %}
<div class="progress-segment"
style="width: {{ assessment.percentage_contribution }}%; background-color: {{ assessment.color }};"
data-assessment-id="{{ assessment.id }}"
data-assessment-title="{{ assessment.title }}"
data-assessment-performance="{{ assessment.performance }}"
data-earned-this="{{ assessment.earned_this }}"
data-max-this="{{ assessment.max_this }}"
data-earned-cumulative="{{ assessment.earned_cumulative }}"
data-max-cumulative="{{ assessment.max_cumulative }}"
data-contribution-percentage="{{ assessment.percentage_contribution }}"
title="{{ assessment.title }}: {{ assessment.earned_this }} pts ({{ assessment.performance }}%)"
role="button"
tabindex="0"
aria-label="Évaluation {{ assessment.title }}: {{ assessment.earned_this }} points sur {{ assessment.max_this }}">
<span class="segment-label">{{ assessment.title|truncate(6, true) }}</span>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
{% endfor %}
{% endif %}
{# Domaines #}
{% if summary.competence_domain_breakdown.domains %}
<div>
<h5 class="text-sm font-medium text-orange-700 mb-3 flex items-center">
<svg class="w-3 h-3 text-orange-500 mr-1" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M3 4a1 1 0 011-1h4a1 1 0 010 2H6.414l2.293 2.293a1 1 0 01-1.414 1.414L5 6.414V8a1 1 0 01-2 0V4zm9 1a1 1 0 010-2h4a1 1 0 011 1v4a1 1 0 01-2 0V6.414l-2.293 2.293a1 1 0 11-1.414-1.414L13.586 5H12zm-9 7a1 1 0 012 0v1.586l2.293-2.293a1 1 0 111.414 1.414L6.414 15H8a1 1 0 010 2H4a1 1 0 01-1-1v-4zm13-1a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 010-2h1.586l-2.293-2.293a1 1 0 111.414-1.414L15 13.586V12a1 1 0 011-1z" clip-rule="evenodd"/>
</svg>
Domaines
</h5>
<div class="space-y-3">
{% for domain in summary.competence_domain_breakdown.domains %}
<div class="domain-progress-horizontal">
{# Nom et score à côté de la barre #}
<div class="flex items-center justify-between mb-1">
<span class="text-xs font-medium text-gray-700 truncate flex-1 mr-2">{{ domain.name }}</span>
<span class="text-xs font-bold whitespace-nowrap" style="color: {{ domain.color }}">
{{ domain.percentage }}%
</span>
</div>
{# Barre de progression compacte #}
<div class="progress-bar-container segmented-progress compact"
data-domain-name="{{ domain.name }}"
data-assessments="{{ domain.assessments | tojson | e }}"
role="progressbar"
aria-valuenow="{{ domain.percentage }}"
aria-valuemin="0"
aria-valuemax="100"
aria-label="Progression du domaine {{ domain.name }}: {{ domain.percentage }}%"
tabindex="0">
<div class="segmented-progress-bar compact" data-expanded="true">
{% for assessment in domain.assessments %}
<div class="progress-segment"
style="width: {{ assessment.percentage_contribution }}%; background-color: {{ assessment.color }};"
data-assessment-id="{{ assessment.id }}"
data-assessment-title="{{ assessment.title }}"
data-assessment-performance="{{ assessment.performance }}"
data-earned-this="{{ assessment.earned_this }}"
data-max-this="{{ assessment.max_this }}"
data-earned-cumulative="{{ assessment.earned_cumulative }}"
data-max-cumulative="{{ assessment.max_cumulative }}"
data-contribution-percentage="{{ assessment.percentage_contribution }}"
title="{{ assessment.title }}: {{ assessment.earned_this }} pts ({{ assessment.performance }}%)"
role="button"
tabindex="0"
aria-label="Évaluation {{ assessment.title }}: {{ assessment.earned_this }} points sur {{ assessment.max_this }}">
<span class="segment-label">{{ assessment.title|truncate(6, true) }}</span>
</div>
{% endfor %}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
</div>
</div>
{% endif %}
</div>
{% endif %}
{# Zone d'appréciation #}
<div>
<label class="block font-medium text-gray-700 mb-3 flex items-center">
<svg class="w-4 h-4 text-purple-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
</svg>
Appréciation du conseil de classe
</label>
<textarea
data-appreciation-textarea
data-student-id="{{ summary.student.id }}"
class="w-full border border-gray-300 rounded-lg px-4 py-3 text-sm focus:ring-2 focus:ring-purple-500 focus:border-purple-500 resize-none transition-colors"
rows="4"
placeholder="Saisir l'appréciation générale pour le bulletin...">{% if summary.appreciation and summary.appreciation.general_appreciation %}{{ summary.appreciation.general_appreciation }}{% endif %}</textarea>
<div class="mt-2 flex justify-between items-center text-xs text-gray-500">
<span>L'appréciation est sauvegardée automatiquement</span>
<span data-char-counter>0 caractères</span>
</div>
</div>
{# Actions #}
<div class="flex items-center justify-between pt-4 border-t border-gray-200">
<div class="flex items-center space-x-3">
<button data-save-manual="{{ summary.student.id }}"
class="inline-flex items-center px-4 py-2 bg-gradient-to-r from-green-500 to-green-600 text-white rounded-lg hover:from-green-600 hover:to-green-700 transition-all duration-300 text-sm font-medium transform hover:scale-[1.02] shadow-lg hover:shadow-xl">
<svg class="w-4 h-4 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
</svg>
Sauvegarder
</button>
<button data-finalize="{{ summary.student.id }}"
class="inline-flex items-center px-4 py-2 bg-gradient-to-r from-purple-500 to-purple-600 text-white rounded-lg hover:from-purple-600 hover:to-purple-700 transition-all duration-300 text-sm font-medium transform hover:scale-[1.02] shadow-lg hover:shadow-xl">
<svg class="w-4 h-4 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M6.267 3.455a3.066 3.066 0 001.745-.723 3.066 3.066 0 013.976 0 3.066 3.066 0 001.745.723 3.066 3.066 0 012.812 2.812c.051.643.304 1.254.723 1.745a3.066 3.066 0 010 3.976 3.066 3.066 0 00-.723 1.745 3.066 3.066 0 01-2.812 2.812 3.066 3.066 0 00-1.745.723 3.066 3.066 0 01-3.976 0 3.066 3.066 0 00-1.745-.723 3.066 3.066 0 01-2.812-2.812 3.066 3.066 0 00-.723-1.745 3.066 3.066 0 010-3.976 3.066 3.066 0 00.723-1.745 3.066 3.066 0 012.812-2.812zm7.44 5.252a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
</svg>
Finaliser
</button>
</div>
<div class="text-xs text-gray-500">
{% if summary.appreciation %}
Dernière modification : <span data-last-modified="{{ summary.student.id }}">{{ summary.appreciation.last_modified.strftime('%d/%m à %H:%M') }}</span>
{% else %}
Pas encore d'appréciation
{% endif %}
</div>
</div>
</div>
</div>
</div>
@@ -726,38 +674,112 @@ body.focus-mode {
left: 0;
right: 0;
bottom: 0;
overflow-y: auto;
overflow: hidden;
background: #f9fafb;
padding: 1rem;
display: flex;
flex-direction: column;
}
/* Mode focus - Optimisation pour éviter le scroll */
/* Mode focus - Utilisation complète de la hauteur */
.focus-mode-student {
max-height: calc(100vh - 80px); /* Header compact + padding */
overflow-y: auto;
height: 100%;
min-height: 100%;
max-height: none;
overflow: hidden;
background: white;
border-radius: 0.5rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
display: flex;
flex-direction: column;
}
/* Mode focus - Améliorer la lisibilité */
.focus-mode-student textarea {
min-height: 100px;
max-height: 200px;
min-height: 150px;
max-height: 50vh;
font-size: 14px;
line-height: 1.5;
resize: vertical;
flex: 1;
}
/* Mode focus - Compactage de la carte */
/* Mode focus - Conteneur de la carte élève s'étend sur toute la hauteur */
.focus-mode-student .px-6 {
padding-left: 1rem;
padding-right: 1rem;
/* Retirer flex: 1 car ce n'est que le header */
flex-shrink: 0;
}
.focus-mode-student .py-4 {
padding-top: 1rem;
padding-bottom: 1rem;
/* Mode focus - Section détails s'étend pour utiliser l'espace disponible */
.focus-mode-student [data-student-details] {
flex: 1;
display: flex;
flex-direction: column;
}
/* Mode focus - Zone d'appréciation garde sa structure */
.focus-mode-student .flex-1.min-w-0 {
/* Garder la structure originale */
flex: 1;
min-width: 0;
}
/* Mode focus - Garder le layout horizontal du header */
.focus-mode-student .flex.items-start.space-x-6 {
/* Conserver le layout horizontal original */
flex-direction: row;
gap: 1.5rem;
align-items: flex-start;
flex-shrink: 0;
}
/* Mode focus - Appréciation garde sa taille originale */
.focus-mode-student .flex-1.min-w-0 textarea {
/* Garder les propriétés originales, juste ajuster légèrement */
min-height: 80px;
max-height: 200px;
height: auto;
}
/* Mode focus - Assurer que les sections s'étendent correctement */
.focus-mode-student .space-y-6 {
display: flex;
flex-direction: column;
flex: 1;
gap: 1.5rem;
}
/* Mode focus - Section détails visible et prend tout l'espace restant */
.focus-mode-student [data-student-details] {
display: block !important;
opacity: 1 !important;
flex: 1 1 0;
overflow-y: auto;
min-height: 0;
height: 0; /* Force flexbox à utiliser flex: 1 */
}
/* Mode focus - Organisation du contenu des détails */
.focus-mode-student [data-student-details] > .px-6.py-6.space-y-6 {
display: flex;
flex-direction: column;
height: 100%;
gap: 1.5rem;
}
/* Mode focus - Section compétences/domaines compacte mais visible */
.focus-mode-student .competence-domain-section {
flex-shrink: 0;
min-height: 200px;
}
/* Mode focus - Header garde son padding normal */
.focus-mode-student .px-6.py-4 {
padding: 1rem;
flex-shrink: 0;
}
/* Mode focus - Réduction des espacements */
@@ -1301,5 +1323,227 @@ button:disabled {
text-align: center;
}
}
/* ========== STYLES POUR LE NOUVEAU LAYOUT HORIZONTAL ========== */
/* Header à trois colonnes */
[data-student-card] .flex.items-start.space-x-6 {
gap: 1.5rem;
}
/* Responsive du header : passage en vertical sur tablette */
@media (max-width: 1024px) {
[data-student-card] .flex.items-start.space-x-6 {
flex-direction: column;
gap: 1rem;
align-items: stretch;
}
/* Appréciation en pleine largeur sur tablette */
[data-student-card] .flex-1.min-w-0 textarea {
min-height: 60px;
}
/* Moyenne et statuts alignés à droite même en vertical */
[data-student-card] .flex.flex-col.items-end.space-y-2.text-right {
flex-direction: row;
justify-content: space-between;
align-items: center;
text-align: left;
}
}
/* Mobile : layout complètement vertical */
@media (max-width: 640px) {
[data-student-card] .flex.items-start.space-x-6 {
gap: 0.75rem;
}
/* Info élève en ligne sur mobile */
[data-student-card] .flex.items-center.space-x-4[data-toggle-student] {
flex-direction: row;
align-items: center;
}
/* Appréciation compacte sur mobile */
[data-student-card] .flex-1.min-w-0 textarea {
rows: 2;
font-size: 0.875rem;
}
/* Statuts empilés sur mobile */
[data-student-card] .flex.flex-col.items-end.space-y-2.text-right {
flex-direction: column;
align-items: stretch;
gap: 0.5rem;
}
}
/* ========== STYLES POUR LES BARRES DE PROGRESSION COMPACTES ========== */
/* Version compacte des barres de progression */
.segmented-progress.compact {
padding: 3px;
min-height: 24px;
border-radius: 6px;
}
.segmented-progress-bar.compact {
height: 18px;
gap: 1px;
padding: 1px;
}
.segmented-progress.compact .progress-segment {
height: 16px;
border-radius: 3px;
border: 1px solid rgba(255, 255, 255, 0.3);
min-width: 4px;
}
/* Labels plus petits en mode compact */
.segmented-progress.compact .segment-label {
font-size: 0.6rem;
font-weight: 500;
}
/* Hover effects compacts */
.segmented-progress.compact .progress-segment:hover {
transform: translateY(-1px);
filter: brightness(1.1);
}
/* ========== SECTION RÉSULTATS PAR ÉVALUATION ========== */
.evaluation-results {
background: rgba(239, 246, 255, 0.3);
border-radius: 8px;
padding: 1rem;
border: 1px solid rgba(59, 130, 246, 0.1);
}
.evaluation-results .space-y-1\.5 > * + * {
margin-top: 0.375rem;
}
/* Cards d'évaluation avec couleurs des évaluations */
.evaluation-results .flex.items-center.justify-between {
transition: all 0.2s ease;
}
.evaluation-results .flex.items-center.justify-between:hover {
transform: translateX(2px);
box-shadow: 0 2px 4px rgba(59, 130, 246, 0.1);
}
/* ========== BARRES DE PROGRESSION HORIZONTALES ========== */
.competence-progress-horizontal,
.domain-progress-horizontal {
background: rgba(255, 255, 255, 0.5);
border-radius: 6px;
padding: 0.5rem;
border: 1px solid rgba(0, 0, 0, 0.05);
transition: all 0.2s ease;
}
.competence-progress-horizontal:hover,
.domain-progress-horizontal:hover {
background: rgba(255, 255, 255, 0.8);
border-color: rgba(0, 0, 0, 0.1);
transform: translateY(-1px);
}
/* ========== RESPONSIVE POUR LE NOUVEAU LAYOUT ========== */
/* Sur grands écrans : layout côte à côte */
@media (min-width: 1024px) {
.grid.grid-cols-1.lg\\:grid-cols-2.gap-6 {
grid-template-columns: 1fr 1fr;
}
}
/* Sur moyens écrans : layout adaptatif */
@media (max-width: 1023px) {
.grid.grid-cols-1.lg\\:grid-cols-2.gap-6 {
grid-template-columns: 1fr;
gap: 1rem;
}
/* Barres plus visibles sur tablette */
.segmented-progress.compact {
min-height: 28px;
padding: 4px;
}
.segmented-progress-bar.compact {
height: 20px;
}
.segmented-progress.compact .progress-segment {
height: 18px;
min-width: 6px;
}
}
/* Sur petits écrans : layout ultra-compact */
@media (max-width: 640px) {
.competence-domain-section .grid.grid-cols-1.lg\\:grid-cols-2.gap-6 {
gap: 0.75rem;
}
/* Textes plus petits */
.evaluation-results h5,
.progress-bars h5 {
font-size: 0.8rem;
}
/* Espacement réduit */
.competence-progress-horizontal,
.domain-progress-horizontal {
padding: 0.375rem;
margin-bottom: 0.5rem;
}
/* Noms tronqués plus agressivement */
.competence-progress-horizontal .text-xs.font-medium.text-gray-700,
.domain-progress-horizontal .text-xs.font-medium.text-gray-700 {
max-width: 100px;
}
}
/* ========== MODE FOCUS ADAPTATIONS ========== */
/* Mode focus : maintenir le layout 2 colonnes */
.focus-mode-student .competence-domain-section .grid.grid-cols-1.lg\\:grid-cols-2 {
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
/* Mode focus sur tablette : revenir à une colonne */
@media (max-width: 1023px) {
.focus-mode-student .competence-domain-section .grid.grid-cols-1.lg\\:grid-cols-2 {
grid-template-columns: 1fr;
gap: 0.75rem;
}
}
.focus-mode-student .evaluation-results,
.focus-mode-student .progress-bars {
padding: 0.75rem;
}
.focus-mode-student .segmented-progress.compact {
min-height: 20px;
padding: 2px;
}
.focus-mode-student .segmented-progress-bar.compact {
height: 16px;
}
.focus-mode-student .segmented-progress.compact .progress-segment {
height: 14px;
}
</style>
{% endblock %}
{% endblock %}