SRL / templates /index.html
OUAREDAEK's picture
Upload templates/index.html with huggingface_hub
715e3ed verified
Raw
History Blame Contribute Delete
145 kB
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Compagnon Pédagogique - Apprentissage Autorégulé Personnalisé</title>
<!-- Chart.js pour les visualisations -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- Font Awesome pour les icônes -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #3b82f6;
--secondary-color: #10b981;
--accent-color: #8b5cf6;
--warning-color: #f59e0b;
--danger-color: #ef4444;
--dark-color: #1e293b;
--light-color: #f8fafc;
--gray-color: #64748b;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
color: var(--dark-color);
line-height: 1.6;
min-height: 100vh;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
}
/* Header */
.header {
background: linear-gradient(135deg, var(--dark-color) 0%, #0f172a 100%);
color: white;
padding: 2rem;
border-radius: 15px;
margin-bottom: 2rem;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
position: relative;
overflow: hidden;
}
.header::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color), var(--accent-color));
}
.header h1 {
font-size: 2.5rem;
margin-bottom: 0.5rem;
display: flex;
align-items: center;
gap: 15px;
}
.header p {
font-size: 1.1rem;
opacity: 0.9;
max-width: 800px;
}
.badge {
background: var(--primary-color);
color: white;
padding: 5px 15px;
border-radius: 20px;
font-size: 0.9rem;
display: inline-block;
margin-top: 10px;
}
/* Navigation */
.nav-tabs {
display: flex;
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
margin-bottom: 2rem;
flex-wrap: wrap;
}
.nav-tab {
flex: 1;
min-width: 180px;
padding: 1.2rem;
border: none;
background: transparent;
color: var(--gray-color);
font-size: 1rem;
font-weight: 600;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
transition: all 0.3s ease;
}
.nav-tab:hover {
background: #f8fafc;
color: var(--primary-color);
}
.nav-tab.active {
background: var(--primary-color);
color: white;
box-shadow: 0 5px 15px rgba(59, 130, 246, 0.3);
}
/* Sections */
.tab-content {
display: none;
animation: fadeIn 0.5s ease;
}
.tab-content.active {
display: block;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.card {
background: white;
border-radius: 15px;
padding: 2rem;
margin-bottom: 2rem;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.05);
border-left: 5px solid var(--primary-color);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 2px solid #f1f5f9;
}
.card-header h3 {
font-size: 1.5rem;
color: var(--dark-color);
display: flex;
align-items: center;
gap: 10px;
}
/* Questionnaire Styles */
.questionnaire-section {
margin-bottom: 2.5rem;
padding: 1.5rem;
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
border-radius: 12px;
}
.questionnaire-header {
display: flex;
align-items: center;
gap: 15px;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 2px solid #e2e8f0;
}
.questionnaire-icon {
width: 50px;
height: 50px;
border-radius: 10px;
background: linear-gradient(135deg, var(--primary-color), var(--accent-color));
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
color: white;
}
.questionnaire-title {
font-size: 1.4rem;
color: var(--dark-color);
font-weight: 600;
}
.questionnaire-description {
color: var(--gray-color);
font-size: 0.95rem;
margin-top: 5px;
}
.question-item {
background: white;
padding: 1.5rem;
border-radius: 10px;
margin-bottom: 1.5rem;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05);
border-left: 4px solid #e2e8f0;
transition: all 0.3s;
}
.question-item:hover {
border-left-color: var(--primary-color);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.question-text {
font-size: 1.1rem;
font-weight: 500;
color: var(--dark-color);
margin-bottom: 1rem;
line-height: 1.5;
}
.scale-options {
display: flex;
justify-content: space-between;
gap: 10px;
margin-top: 1rem;
}
.scale-option {
flex: 1;
text-align: center;
padding: 10px;
border: 2px solid #e2e8f0;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
background: white;
}
.scale-option:hover {
border-color: var(--primary-color);
background: rgba(59, 130, 246, 0.05);
}
.scale-option.selected {
border-color: var(--primary-color);
background: rgba(59, 130, 246, 0.1);
font-weight: 600;
color: var(--primary-color);
}
.scale-label {
display: block;
font-size: 0.9rem;
color: var(--gray-color);
margin-top: 5px;
}
.progress-section {
margin-top: 2rem;
padding: 1.5rem;
background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
border-radius: 12px;
border-left: 5px solid var(--primary-color);
}
.progress-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.progress-title {
font-size: 1.2rem;
color: var(--dark-color);
font-weight: 600;
}
.progress-percentage {
font-size: 1.3rem;
font-weight: bold;
color: var(--primary-color);
}
.progress-bar-container {
height: 12px;
background: #e2e8f0;
border-radius: 6px;
overflow: hidden;
margin: 15px 0;
}
.progress-bar-fill {
height: 100%;
background: linear-gradient(90deg, var(--primary-color), var(--accent-color));
border-radius: 6px;
transition: width 0.5s ease;
width: 0%;
}
.questionnaire-progress {
display: flex;
justify-content: space-between;
font-size: 0.9rem;
color: var(--gray-color);
}
.profile-summary {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-top: 2rem;
}
.profile-card {
background: white;
padding: 1.5rem;
border-radius: 12px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
}
.profile-card-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 1rem;
padding-bottom: 0.8rem;
border-bottom: 2px solid #f1f5f9;
}
.profile-card-icon {
width: 40px;
height: 40px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
color: white;
}
.profile-card-title {
font-size: 1.2rem;
font-weight: 600;
color: var(--dark-color);
}
.trait-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.trait-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background: #f8fafc;
border-radius: 8px;
}
.trait-name {
font-weight: 500;
color: var(--dark-color);
}
.trait-value {
font-weight: 600;
color: var(--primary-color);
}
.recommendations-section {
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
border-radius: 12px;
padding: 1.5rem;
margin-top: 2rem;
border-left: 5px solid var(--warning-color);
}
.recommendation-item {
display: flex;
align-items: flex-start;
gap: 15px;
margin-bottom: 1rem;
padding: 1rem;
background: rgba(255, 255, 255, 0.7);
border-radius: 8px;
}
.recommendation-icon {
font-size: 1.5rem;
color: var(--warning-color);
}
.motivation-chart {
height: 300px;
margin-top: 1.5rem;
}
.section-completion {
display: flex;
align-items: center;
gap: 10px;
margin-top: 1rem;
padding: 10px;
background: rgba(16, 185, 129, 0.1);
border-radius: 8px;
}
.section-complete {
background: rgba(16, 185, 129, 0.1);
border-left: 4px solid var(--secondary-color);
}
.section-incomplete {
background: rgba(239, 68, 68, 0.1);
border-left: 4px solid var(--danger-color);
}
/* Objectif Section */
.productivity-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-top: 10px;
}
.option-section {
background: white;
border-radius: 10px;
padding: 1rem;
border: 1px solid #e2e8f0;
}
.option-section h4 {
font-size: 1rem;
color: #333;
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 8px;
}
.option-section h4 i {
color: #333;
}
.option-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 10px;
}
.option-item {
padding: 12px;
border: 1px solid #e2e8f0;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
text-align: center;
background: white;
}
.option-item:hover {
border-color: #666;
background: #f8f9fa;
}
.option-item.selected {
border-color: #333;
background: #f0f0f0;
font-weight: 600;
}
.option-icon {
font-size: 1.2rem;
margin-bottom: 5px;
display: block;
color: #333;
}
.option-title {
font-weight: 500;
color: #333;
font-size: 0.9rem;
margin-bottom: 3px;
}
.option-description {
font-size: 0.8rem;
color: #666;
line-height: 1.2;
}
/* Energy Pattern */
.energy-patterns {
display: flex;
gap: 15px;
margin-top: 10px;
}
.energy-pattern {
flex: 1;
padding: 15px;
border: 2px solid #e2e8f0;
border-radius: 10px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
}
.energy-pattern:hover {
border-color: var(--secondary-color);
background: rgba(16, 185, 129, 0.05);
}
.energy-pattern.selected {
border-color: var(--secondary-color);
background: rgba(16, 185, 129, 0.1);
box-shadow: 0 5px 15px rgba(16, 185, 129, 0.1);
}
/* Time Slots */
.time-slots {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 10px;
}
.time-slot {
padding: 10px 20px;
border: 2px solid #e2e8f0;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
text-align: center;
min-width: 80px;
}
.time-slot:hover {
border-color: var(--accent-color);
background: rgba(139, 92, 246, 0.05);
}
.time-slot.selected {
border-color: var(--accent-color);
background: rgba(139, 92, 246, 0.1);
box-shadow: 0 3px 10px rgba(139, 92, 246, 0.1);
}
/* Quality Indicators */
.quality-indicator {
display: flex;
gap: 10px;
margin: 15px 0;
}
.quality-dot {
width: 25px;
height: 25px;
border-radius: 50%;
cursor: pointer;
transition: all 0.3s;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
font-size: 0.8rem;
}
.quality-dot:hover {
transform: scale(1.2);
}
.quality-0 { background: linear-gradient(135deg, #ef4444, #dc2626); }
.quality-1 { background: linear-gradient(135deg, #f59e0b, #d97706); }
.quality-2 { background: linear-gradient(135deg, #10b981, #059669); }
.quality-3 { background: linear-gradient(135deg, #3b82f6, #1d4ed8); }
.quality-dot.active {
box-shadow: 0 0 0 3px white, 0 0 0 6px currentColor;
}
/* Form Elements */
.form-group {
margin-bottom: 1.5rem;
}
.form-label {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
color: var(--dark-color);
display: flex;
align-items: center;
gap: 8px;
}
.form-control {
width: 100%;
padding: 12px 15px;
border: 2px solid #e2e8f0;
border-radius: 10px;
font-size: 1rem;
transition: all 0.3s;
background: #f8fafc;
}
.form-control:focus {
outline: none;
border-color: var(--primary-color);
background: white;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.form-row {
display: flex;
gap: 20px;
margin-bottom: 1.5rem;
}
.form-col {
flex: 1;
}
/* Buttons */
.btn {
padding: 12px 25px;
border: none;
border-radius: 10px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 10px;
}
.btn-primary {
background: linear-gradient(135deg, var(--primary-color) 0%, #2563eb 100%);
color: white;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(59, 130, 246, 0.3);
}
.btn-secondary {
background: var(--secondary-color);
color: white;
}
.btn-large {
padding: 15px 30px;
font-size: 1.1rem;
}
/* Planner Cards */
.planning-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 20px;
margin-top: 2rem;
}
.session-card {
background: white;
border-radius: 12px;
padding: 1.5rem;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
border-top: 4px solid var(--primary-color);
transition: transform 0.3s;
}
.session-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
}
.session-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1rem;
}
.session-date {
font-size: 1.2rem;
font-weight: bold;
color: var(--dark-color);
}
.session-repetition {
background: var(--primary-color);
color: white;
padding: 5px 15px;
border-radius: 20px;
font-size: 0.9rem;
}
.session-details {
margin-top: 1rem;
display: flex;
flex-direction: column;
gap: 8px;
}
.detail-item {
display: flex;
justify-content: space-between;
padding: 5px 0;
border-bottom: 1px dashed #e2e8f0;
}
/* Visualizations */
.visualization-container {
background: white;
border-radius: 15px;
padding: 2rem;
margin-top: 2rem;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.05);
}
.chart-container {
position: relative;
height: 400px;
width: 100%;
}
/* Stats Cards */
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
margin-top: 2rem;
}
.stat-card {
background: white;
border-radius: 12px;
padding: 1.5rem;
text-align: center;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
}
.stat-value {
font-size: 2.5rem;
font-weight: bold;
color: var(--primary-color);
margin: 10px 0;
}
.stat-label {
color: var(--gray-color);
font-size: 0.9rem;
}
/* Heatmap d'activité */
.heatmap-container {
margin-top: 2rem;
}
.heatmap-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
}
.heatmap-title {
font-size: 1.3rem;
color: var(--dark-color);
display: flex;
align-items: center;
gap: 10px;
}
.heatmap-controls {
display: flex;
gap: 10px;
}
.heatmap-period {
padding: 8px 15px;
border: 2px solid #e2e8f0;
border-radius: 8px;
background: #f8fafc;
cursor: pointer;
transition: all 0.3s;
}
.heatmap-period:hover {
border-color: var(--primary-color);
}
.heatmap-period.active {
background: var(--primary-color);
color: white;
border-color: var(--primary-color);
}
.heatmap-grid {
display: grid;
grid-template-columns: auto repeat(7, 1fr);
gap: 8px;
margin-top: 1rem;
}
.heatmap-day-label {
text-align: right;
padding: 10px;
font-weight: 600;
color: var(--dark-color);
}
.heatmap-cell {
aspect-ratio: 1;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.8rem;
font-weight: bold;
cursor: pointer;
transition: transform 0.2s;
}
.heatmap-cell:hover {
transform: scale(1.1);
z-index: 10;
}
.heatmap-intensity-0 { background: #f1f5f9; color: var(--gray-color); }
.heatmap-intensity-1 { background: #dbeafe; color: var(--dark-color); }
.heatmap-intensity-2 { background: #93c5fd; color: white; }
.heatmap-intensity-3 { background: #3b82f6; color: white; }
.heatmap-intensity-4 { background: #1d4ed8; color: white; }
.heatmap-week-label {
text-align: center;
padding: 5px;
font-size: 0.9rem;
color: var(--gray-color);
}
.heatmap-legend {
display: flex;
justify-content: center;
align-items: center;
gap: 15px;
margin-top: 1.5rem;
padding-top: 1.5rem;
border-top: 2px solid #f1f5f9;
}
.legend-item {
display: flex;
align-items: center;
gap: 5px;
}
.legend-color {
width: 20px;
height: 20px;
border-radius: 4px;
}
/* Notifications */
.notification-card {
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
border-left: 5px solid var(--warning-color);
padding: 1.5rem;
border-radius: 12px;
margin-bottom: 1rem;
animation: fadeIn 0.5s ease;
}
/* ============================================ */
/* STYLES POUR LES FLASHCARDS */
/* ============================================ */
.flashcards-controls {
display: flex;
justify-content: center;
align-items: center;
gap: 20px;
margin: 2rem 0;
padding: 1rem;
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
border-radius: 12px;
}
.flashcard-container {
min-height: 400px;
perspective: 1000px;
margin: 2rem 0;
}
.flashcard {
width: 100%;
height: 400px;
position: relative;
transform-style: preserve-3d;
transition: transform 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275);
cursor: pointer;
}
.flashcard.flipped {
transform: rotateY(180deg);
}
.flashcard-face {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: 15px;
padding: 2rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.flashcard-front {
background: linear-gradient(135deg, #ffffff 0%, #f1f5f9 100%);
border: 2px solid var(--primary-color);
}
.flashcard-back {
background: linear-gradient(135deg, var(--primary-color) 0%, #1d4ed8 100%);
color: white;
transform: rotateY(180deg);
text-align: center;
}
.flashcard-category {
position: absolute;
top: 15px;
left: 15px;
padding: 5px 15px;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 600;
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
}
.flashcard-content {
max-width: 600px;
text-align: center;
padding: 2rem;
}
.flashcard-title {
font-size: 1.8rem;
font-weight: bold;
margin-bottom: 1.5rem;
color: var(--dark-color);
}
.flashcard-question {
font-size: 1.3rem;
line-height: 1.6;
margin-bottom: 2rem;
color: var(--dark-color);
}
.flashcard-back .flashcard-title {
color: white;
}
.flashcard-back .flashcard-question {
color: rgba(255, 255, 255, 0.9);
}
.flashcard-action {
background: white;
color: var(--primary-color);
border: none;
padding: 12px 30px;
border-radius: 25px;
font-weight: 600;
cursor: pointer;
margin-top: 1.5rem;
transition: all 0.3s;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.flashcard-action:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
}
.flashcard-instruction {
position: absolute;
bottom: 15px;
left: 0;
right: 0;
text-align: center;
font-size: 0.9rem;
color: var(--gray-color);
opacity: 0.8;
}
.flashcard-evaluation {
margin-top: 2rem;
display: flex;
flex-direction: column;
gap: 1rem;
width: 100%;
max-width: 400px;
}
.evaluation-slider {
width: 100%;
-webkit-appearance: none;
height: 8px;
border-radius: 4px;
background: rgba(255, 255, 255, 0.3);
outline: none;
}
.evaluation-slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 24px;
height: 24px;
border-radius: 50%;
background: white;
cursor: pointer;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}
.evaluation-label {
display: flex;
justify-content: space-between;
font-size: 0.9rem;
color: rgba(255, 255, 255, 0.9);
}
.category-filters {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin: 1.5rem 0;
justify-content: center;
}
.category-filter {
padding: 8px 20px;
border: 2px solid #e2e8f0;
border-radius: 20px;
background: white;
cursor: pointer;
transition: all 0.3s;
font-weight: 500;
color: var(--dark-color);
}
.category-filter:hover {
border-color: var(--primary-color);
color: var(--primary-color);
}
.category-filter.active {
background: var(--primary-color);
color: white;
border-color: var(--primary-color);
}
.flashcard-progress {
width: 100%;
height: 6px;
background: #e2e8f0;
border-radius: 3px;
margin: 1rem 0;
overflow: hidden;
}
.flashcard-progress-bar {
height: 100%;
background: linear-gradient(90deg, var(--primary-color), var(--accent-color));
border-radius: 3px;
transition: width 0.3s ease;
}
.dashboardEM-container {
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
border-radius: 15px;
padding: 2rem;
margin-top: 2rem;
}
.dashboardEM-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-top: 1.5rem;
}
.dashboardEM-card {
background: white;
border-radius: 12px;
padding: 1.5rem;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
}
.dashboardEM-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 1rem;
padding-bottom: 1rem;
border-bottom: 2px solid #f1f5f9;
}
.dashboardEM-icon {
width: 40px;
height: 40px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
color: white;
}
.dashboardEM-metric {
display: flex;
align-items: baseline;
gap: 10px;
margin: 1rem 0;
}
.dashboardEM-value {
font-size: 2.5rem;
font-weight: bold;
color: var(--primary-color);
}
.dashboardEM-change {
font-size: 0.9rem;
padding: 3px 8px;
border-radius: 12px;
background: rgba(16, 185, 129, 0.1);
color: var(--secondary-color);
}
.dashboardEM-change.negative {
background: rgba(239, 68, 68, 0.1);
color: var(--danger-color);
}
.dashboardEM-trend {
display: flex;
align-items: center;
gap: 5px;
font-size: 0.9rem;
color: var(--gray-color);
}
/* Indicateurs de gestion du temps */
.time-management-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-top: 2rem;
}
.time-stat-card {
background: white;
border-radius: 12px;
padding: 1.5rem;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
border-top: 4px solid var(--secondary-color);
}
.time-stat-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 1rem;
}
.time-stat-icon {
width: 40px;
height: 40px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
color: white;
background: linear-gradient(135deg, #10b981, #059669);
}
.time-stat-value {
font-size: 2.5rem;
font-weight: bold;
color: var(--secondary-color);
margin: 10px 0;
}
.time-stat-description {
color: var(--gray-color);
font-size: 0.9rem;
margin-top: 5px;
}
.progress-circle {
width: 100px;
height: 100px;
position: relative;
margin: 0 auto;
}
.progress-circle svg {
width: 100%;
height: 100%;
}
.progress-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 1.5rem;
font-weight: bold;
color: var(--secondary-color);
}
/* Modal pour la saisie */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
align-items: center;
justify-content: center;
}
.modal-content {
background: white;
border-radius: 15px;
padding: 2rem;
width: 90%;
max-width: 600px;
max-height: 80vh;
overflow-y: auto;
animation: slideIn 0.3s ease;
}
@keyframes slideIn {
from { transform: translateY(-20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 2px solid #f1f5f9;
}
.modal-title {
font-size: 1.5rem;
color: var(--dark-color);
}
.modal-close {
background: none;
border: none;
font-size: 1.5rem;
color: var(--gray-color);
cursor: pointer;
}
/* Effort Pattern */
.effort-pattern {
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
border-radius: 12px;
padding: 1.5rem;
margin-top: 2rem;
}
.pattern-badge {
display: inline-block;
padding: 8px 15px;
background: linear-gradient(135deg, #f59e0b, #d97706);
color: white;
border-radius: 20px;
font-weight: bold;
margin-bottom: 1rem;
}
.pattern-details {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-top: 1rem;
}
.pattern-item {
background: white;
padding: 1rem;
border-radius: 8px;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05);
}
.pattern-label {
font-size: 0.9rem;
color: var(--gray-color);
margin-bottom: 5px;
}
.pattern-value {
font-size: 1.1rem;
font-weight: bold;
color: var(--dark-color);
}
/* Persistance */
.persistence-section {
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
border-radius: 12px;
padding: 1.5rem;
margin-top: 2rem;
border-left: 5px solid #f59e0b;
}
.persistence-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 1rem;
}
.persistence-level {
font-size: 1.5rem;
font-weight: bold;
color: #d97706;
}
.persistence-details {
margin-top: 1rem;
}
.persistence-item {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 10px;
padding: 8px;
background: rgba(255, 255, 255, 0.5);
border-radius: 8px;
}
/* Responsive */
@media (max-width: 768px) {
.form-row {
flex-direction: column;
gap: 0;
}
.nav-tabs {
flex-direction: column;
}
.planning-grid {
grid-template-columns: 1fr;
}
.header h1 {
font-size: 2rem;
}
.productivity-grid {
grid-template-columns: 1fr;
}
.energy-patterns {
flex-direction: column;
}
.time-slots {
justify-content: center;
}
.heatmap-grid {
gap: 4px;
}
.heatmap-cell {
font-size: 0.7rem;
}
.time-management-stats {
grid-template-columns: 1fr;
}
.scale-options {
flex-direction: column;
}
.profile-summary {
grid-template-columns: 1fr;
}
.flashcard {
height: 350px;
}
.flashcard-title {
font-size: 1.5rem;
}
.flashcard-question {
font-size: 1.1rem;
}
.flashcards-controls {
flex-direction: column;
gap: 15px;
}
}
@media (max-width: 480px) {
.flashcard {
height: 300px;
}
.flashcard-content {
padding: 1rem;
}
.flashcard-title {
font-size: 1.3rem;
}
.flashcard-question {
font-size: 1rem;
}
}
</style>
</head>
<body>
<div class="container">
<!-- Header -->
<header class="header">
<h1><i class="fas fa-graduation-cap"></i> Compagnon Pédagogique</h1>
<p>PerseverAI (AI–Aid–Perseverance) – Apprendre à manager l'effort et maintenir la persistance</p>
<div class="badge">PerseverAId (AI + Aid + Perseverance)</div>
</header>
<!-- Navigation - 7 onglets -->
<nav class="nav-tabs">
<button class="nav-tab active" onclick="showTab('profile')">
<i class="fas fa-user-circle"></i> Profil Apprenant
</button>
<button class="nav-tab" onclick="showTab('objectif')">
<i class="fas fa-bullseye"></i> Objectif
</button>
<button class="nav-tab" onclick="showTab('planner')">
<i class="fas fa-calendar-alt"></i> Planner
</button>
<button class="nav-tab" onclick="showTab('flashcards')">
<i class="fas fa-layer-group"></i> Métacognition
</button>
<button class="nav-tab" onclick="showTab('journal')">
<i class="fas fa-book"></i> Journal SRL
</button>
<button class="nav-tab" onclick="showTab('notifications')">
<i class="fas fa-bell"></i> Notifications IA
</button>
<button class="nav-tab" onclick="showTab('stats')">
<i class="fas fa-chart-line"></i> Statistiques
</button>
</nav>
<!-- Profil Apprenant Section -->
<section id="profile" class="tab-content active">
<div class="card">
<div class="card-header">
<h3><i class="fas fa-user-circle"></i> Profil d'Apprentissage Personnalisé</h3>
<div>
<button class="btn btn-secondary" onclick="completeAllSections()">
<i class="fas fa-magic"></i> Remplir automatiquement
</button>
<button class="btn btn-secondary" onclick="saveProfile()">
<i class="fas fa-save"></i> Sauvegarder
</button>
</div>
</div>
<!-- Barre de progression globale -->
<div class="progress-section">
<div class="progress-header">
<div class="progress-title">Complétion du Profil</div>
<div class="progress-percentage" id="profileCompletion">40%</div>
</div>
<div class="progress-bar-container">
<div class="progress-bar-fill" id="profileProgressBar" style="width: 40%"></div>
</div>
<div class="questionnaire-progress">
<span>Questionnaires complétés: <span id="completedSections">2/5</span></span>
<span>Profil personnalisé: <span id="personalizationLevel">Intermédiaire</span></span>
</div>
</div>
<!-- Section 1: Big Five Traits (BFI-10) -->
<div class="questionnaire-section" id="big5-section">
<div class="questionnaire-header">
<div class="questionnaire-icon">
<i class="fas fa-brain"></i>
</div>
<div>
<div class="questionnaire-title">Profil de Personnalité (Big Five Traits)</div>
<div class="questionnaire-description">Évaluez vos traits de personnalité sur une échelle de 1 à 5</div>
</div>
</div>
<div class="question-item">
<div class="question-text">Je suis quelqu'un de sociable, extraverti, énergique</div>
<div class="scale-options">
<div class="scale-option" onclick="selectScale('extraversion', 1)">1</div>
<div class="scale-option" onclick="selectScale('extraversion', 2)">2</div>
<div class="scale-option selected" onclick="selectScale('extraversion', 3)">3</div>
<div class="scale-option" onclick="selectScale('extraversion', 4)">4</div>
<div class="scale-option" onclick="selectScale('extraversion', 5)">5</div>
</div>
</div>
<div class="question-item">
<div class="question-text">Je fais preuve de curiosité intellectuelle, j'aime les nouvelles expériences</div>
<div class="scale-options">
<div class="scale-option" onclick="selectScale('openness', 1)">1</div>
<div class="scale-option" onclick="selectScale('openness', 2)">2</div>
<div class="scale-option selected" onclick="selectScale('openness', 3)">3</div>
<div class="scale-option" onclick="selectScale('openness', 4)">4</div>
<div class="scale-option" onclick="selectScale('openness', 5)">5</div>
</div>
</div>
<div class="question-item">
<div class="question-text">Je suis organisé, fiable, je respecte mes engagements</div>
<div class="scale-options">
<div class="scale-option" onclick="selectScale('conscientiousness', 1)">1</div>
<div class="scale-option" onclick="selectScale('conscientiousness', 2)">2</div>
<div class="scale-option" onclick="selectScale('conscientiousness', 3)">3</div>
<div class="scale-option selected" onclick="selectScale('conscientiousness', 4)">4</div>
<div class="scale-option" onclick="selectScale('conscientiousness', 5)">5</div>
</div>
</div>
<div class="question-item">
<div class="question-text">Je suis coopératif, serviable, empathique</div>
<div class="scale-options">
<div class="scale-option" onclick="selectScale('agreeableness', 1)">1</div>
<div class="scale-option" onclick="selectScale('agreeableness', 2)">2</div>
<div class="scale-option selected" onclick="selectScale('agreeableness', 3)">3</div>
<div class="scale-option" onclick="selectScale('agreeableness', 4)">4</div>
<div class="scale-option" onclick="selectScale('agreeableness', 5)">5</div>
</div>
</div>
<div class="question-item">
<div class="question-text">Je ressens facilement de l'anxiété, du stress, de la nervosité</div>
<div class="scale-options">
<div class="scale-option" onclick="selectScale('neuroticism', 1)">1</div>
<div class="scale-option" onclick="selectScale('neuroticism', 2)">2</div>
<div class="scale-option" onclick="selectScale('neuroticism', 3)">3</div>
<div class="scale-option selected" onclick="selectScale('neuroticism', 4)">4</div>
<div class="scale-option" onclick="selectScale('neuroticism', 5)">5</div>
</div>
</div>
<div class="section-completion section-complete" id="big5-completion">
<i class="fas fa-check-circle" style="color: #10b981;"></i>
<span>Section complétée - <strong>Score neuroticisme: 4.0</strong> (qualité du sommeil importante)</span>
</div>
</div>
<!-- Section 2: Motivation Académique -->
<div class="questionnaire-section" id="motivation-section">
<div class="questionnaire-header">
<div class="questionnaire-icon" style="background: linear-gradient(135deg, #10b981, #059669);">
<i class="fas fa-fire"></i>
</div>
<div>
<div class="questionnaire-title">Profil Motivationnel</div>
<div class="questionnaire-description">Pourquoi étudiez-vous ? Sélectionnez vos principales motivations</div>
</div>
</div>
<div class="question-item">
<div class="question-text">J'étudie parce que j'aime apprendre, je trouve cela intéressant et plaisant</div>
<div class="scale-options">
<div class="scale-option" onclick="selectMotivation('intrinsic', 1)">1</div>
<div class="scale-option" onclick="selectMotivation('intrinsic', 2)">2</div>
<div class="scale-option selected" onclick="selectMotivation('intrinsic', 3)">3</div>
<div class="scale-option" onclick="selectMotivation('intrinsic', 4)">4</div>
<div class="scale-option" onclick="selectMotivation('intrinsic', 5)">5</div>
</div>
</div>
<div class="question-item">
<div class="question-text">J'étudie pour obtenir de bonnes notes et faire plaisir à mes parents/professeurs</div>
<div class="scale-options">
<div class="scale-option" onclick="selectMotivation('introjected', 1)">1</div>
<div class="scale-option" onclick="selectMotivation('introjected', 2)">2</div>
<div class="scale-option" onclick="selectMotivation('introjected', 3)">3</div>
<div class="scale-option selected" onclick="selectMotivation('introjected', 4)">4</div>
<div class="scale-option" onclick="selectMotivation('introjected', 5)">5</div>
</div>
</div>
<div class="section-completion section-complete" id="motivation-completion">
<i class="fas fa-check-circle" style="color: #10b981;"></i>
<span>Section complétée - <strong>Motivation introjectée: 4.0</strong> (pression interne modérée)</span>
</div>
</div>
<!-- Résumé du Profil et Recommandations -->
<div class="profile-summary">
<div class="profile-card">
<div class="profile-card-header">
<div class="profile-card-icon" style="background: linear-gradient(135deg, #3b82f6, #1d4ed8);">
<i class="fas fa-brain"></i>
</div>
<div class="profile-card-title">Big Five Traits</div>
</div>
<div class="trait-list">
<div class="trait-item">
<span class="trait-name">Extraversion</span>
<span class="trait-value" id="extraversion-value">3.0</span>
</div>
<div class="trait-item">
<span class="trait-name">Ouverture</span>
<span class="trait-value" id="openness-value">3.0</span>
</div>
<div class="trait-item">
<span class="trait-name">Conscience</span>
<span class="trait-value" id="conscientiousness-value">4.0</span>
</div>
</div>
</div>
<div class="profile-card">
<div class="profile-card-header">
<div class="profile-card-icon" style="background: linear-gradient(135deg, #10b981, #059669);">
<i class="fas fa-fire"></i>
</div>
<div class="profile-card-title">Motivation</div>
</div>
<div class="trait-list">
<div class="trait-item">
<span class="trait-name">Intrinsèque</span>
<span class="trait-value" id="intrinsic-value">3.0</span>
</div>
<div class="trait-item">
<span class="trait-name">Introjectée</span>
<span class="trait-value" id="introjected-value">4.0</span>
</div>
</div>
<div class="motivation-chart">
<canvas id="motivationChart"></canvas>
</div>
</div>
</div>
<!-- Recommandations Personnalisées -->
<div class="recommendations-section">
<h4><i class="fas fa-lightbulb"></i> Recommandations Personnalisées Basées sur Votre Profil</h4>
<div class="recommendation-item">
<div class="recommendation-icon">💤</div>
<div>
<strong>Qualité du sommeil: </strong> Avec un névrosisme modéré, il est important de maintenir 7-8 heures de sommeil de qualité.
</div>
</div>
<div class="recommendation-item">
<div class="recommendation-icon">📅</div>
<div>
<strong>Planification: </strong> Votre conscience est bonne. Établissez un planning régulier mais évitez le surmenage.
</div>
</div>
</div>
<button class="btn btn-primary btn-large" onclick="completeProfile()" style="margin-top: 2rem;">
<i class="fas fa-check-circle"></i> Finaliser et Générer le Profil Personnalisé
</button>
</div>
</section>
<!-- Objectif Section -->
<section id="objectif" class="tab-content">
<div class="card">
<div class="card-header">
<h3><i class="fas fa-bullseye"></i> Définir mon Objectif d'Apprentissage</h3>
</div>
<div class="form-row">
<div class="form-col">
<label class="form-label"><i class="fas fa-language"></i> Compétence Cible</label>
<select id="competence" class="form-control">
<option value="">Sélectionnez une compétence...</option>
<option value="maitriser_conjugaison">Maîtriser les marques de la conjugaison</option>
<option value="determiner_points_vue">Déterminer les points de vue adoptés</option>
<option value="comprendre_mots">Comprendre les mots</option>
<option value="choisir_mots_expressions">Choisir ses mots et ses expressions</option>
<option value="construire_phrases">Construire ses phrases</option>
<option value="developper_vocabulaire">Développer un vocabulaire étendu</option>
<option value="maitriser_orthographe_mots">Maîtriser l'orthographe des mots</option>
<option value="articuler_termes">Articuler les termes entre eux</option>
<option value="utiliser_reprises">Utiliser des reprises</option>
<option value="maitriser_orthographe_grammaticale">Maîtriser l'orthographe grammaticale</option>
<option value="maitriser_modalites_phrases">Maîtriser les modalités et les types de phrases</option>
<option value="enchainer_phrases">Enchaîner les phrases</option>
<option value="organiser_textes">Organiser ses textes</option>
<option value="effets_style">Jouer avec les effets de style</option>
</select>
</div>
<div class="form-col">
<label class="form-label"><i class="fas fa-brain"></i> Niveau Actuel</label>
<select id="level" class="form-control">
<option value="0">Débutant</option>
<option value="1" selected>Intermédiaire</option>
<option value="2">Avancé</option>
<option value="3">Expert</option>
</select>
</div>
</div>
<div class="form-row">
<div class="form-col">
<label class="form-label"><i class="fas fa-calendar-start"></i> Date de Début</label>
<input type="date" id="start" class="form-control" value="2024-01-15">
</div>
<div class="form-col">
<label class="form-label"><i class="fas fa-calendar-end"></i> Date de Fin</label>
<input type="date" id="end" class="form-control" value="2024-12-31">
</div>
</div>
<div class="form-group">
<label class="form-label"><i class="fas fa-clock"></i> Durée par Session (minutes)</label>
<select id="duration" class="form-control">
<option value="10">10 minutes (Micro-learning)</option>
<option value="20" selected>20 minutes (Optimal)</option>
<option value="30">30 minutes (Approfondissement)</option>
<option value="45">45 minutes (Session intensive)</option>
</select>
</div>
<!-- Section Méthode Productivité -->
<div class="productivity-grid">
<div class="option-section">
<h4><i class="fas fa-chart-line"></i> Méthode Productivité</h4>
<div class="option-grid">
<div class="option-item selected" onclick="selectProductivityMethod('pomodoro')">
<span class="option-icon"><i class="fas fa-hourglass-half"></i></span>
<div class="option-title">Pomodoro</div>
<div class="option-description">25 min / 5 min pause</div>
</div>
<div class="option-item" onclick="selectProductivityMethod('deepwork')">
<span class="option-icon"><i class="fas fa-brain"></i></span>
<div class="option-title">Deep Work</div>
<div class="option-description">90 min focus intense</div>
</div>
</div>
</div>
<div class="option-section">
<h4><i class="fas fa-bolt"></i> Type d'Énergie</h4>
<div class="option-grid">
<div class="option-item selected" onclick="selectEnergyPattern('morning')">
<span class="option-icon"><i class="fas fa-sun"></i></span>
<div class="option-title">Matinale</div>
<div class="option-description">Productif le matin</div>
</div>
<div class="option-item" onclick="selectEnergyPattern('evening')">
<span class="option-icon"><i class="fas fa-moon"></i></span>
<div class="option-title">Vespérale</div>
<div class="option-description">Productif le soir</div>
</div>
</div>
</div>
</div>
<!-- Créneaux Disponibles -->
<div class="form-group">
<label class="form-label"><i class="fas fa-calendar-check"></i> Créneaux Disponibles</label>
<div class="time-slots">
<div class="time-slot selected" onclick="toggleTimeSlot('morning')">08:00-10:00</div>
<div class="time-slot" onclick="toggleTimeSlot('late_morning')">10:00-12:00</div>
<div class="time-slot" onclick="toggleTimeSlot('afternoon')">14:00-16:00</div>
</div>
</div>
<!-- Qualité Estimée -->
<div class="form-group">
<label class="form-label"><i class="fas fa-chart-line"></i> Qualité Estimée de Rétention</label>
<div class="quality-indicator">
<div class="quality-dot quality-0" onclick="selectQuality(0)">0</div>
<div class="quality-dot quality-1" onclick="selectQuality(1)">1</div>
<div class="quality-dot quality-2 active" onclick="selectQuality(2)">2</div>
<div class="quality-dot quality-3" onclick="selectQuality(3)">3</div>
</div>
<small id="quality-description">Bon - Consolidation progressive</small>
</div>
<button class="btn btn-primary btn-large" onclick="generatePlanner()">
<i class="fas fa-cogs"></i> Générer le Planner Personnalisé
</button>
</div>
</section>
<!-- Planner Section -->
<section id="planner" class="tab-content">
<div class="card">
<div class="card-header">
<h3><i class="fas fa-calendar-alt"></i> Planner Personnalisé</h3>
<button class="btn btn-secondary" onclick="exportPlanner()">
<i class="fas fa-download"></i> Exporter
</button>
</div>
<div id="plannerStats" class="stats-grid"></div>
<div id="plannerContent" class="planning-grid"></div>
<div class="visualization-container">
<h4><i class="fas fa-chart-line"></i> Visualisation des Intervalles SM-2</h4>
<div class="chart-container">
<canvas id="sm2Visualization"></canvas>
</div>
</div>
</div>
</section>
<!-- Flashcards Section -->
<section id="flashcards" class="tab-content">
<div class="card">
<div class="card-header">
<h3><i class="fas fa-layer-group"></i> Flashcards Cognitives - Persévérance & Métacognition</h3>
<div>
<button class="btn btn-secondary" onclick="showCardByCategory('all')">
<i class="fas fa-filter"></i> Toutes
</button>
<button class="btn btn-secondary" onclick="resetFlashcards()">
<i class="fas fa-redo"></i> Réinitialiser
</button>
</div>
</div>
<!-- Statistiques des flashcards -->
<div id="flashcardsStats" class="stats-grid">
<div class="stat-card">
<div class="stat-value">20</div>
<div class="stat-label">Cartes disponibles</div>
</div>
<div class="stat-card">
<div class="stat-value">0</div>
<div class="stat-label">Cartes consultées</div>
</div>
<div class="stat-card">
<div class="stat-value">0/5</div>
<div class="stat-label">Score moyen</div>
</div>
<div class="stat-card">
<div class="stat-value">Toutes</div>
<div class="stat-label">Catégorie active</div>
</div>
</div>
<!-- Filtres par catégorie -->
<div class="category-filters">
<div class="category-filter active" onclick="showCardByCategory('all')">
<i class="fas fa-layer-group"></i> Toutes
</div>
<div class="category-filter" onclick="showCardByCategory('awareness')">
<i class="fas fa-eye"></i> Prise de conscience
</div>
<div class="category-filter" onclick="showCardByCategory('perseverance')">
<i class="fas fa-mountain"></i> Persévérance
</div>
<div class="category-filter" onclick="showCardByCategory('effort')">
<i class="fas fa-bolt"></i> Gestion de l'effort
</div>
</div>
<!-- Contrôles de navigation -->
<div class="flashcards-controls">
<button class="btn" onclick="prevCard()" id="prevBtn">
<i class="fas fa-chevron-left"></i> Précédente
</button>
<div style="display: flex; flex-direction: column; align-items: center;">
<span id="cardCounter" style="font-weight: 600; color: var(--dark-color);">
Carte 1/20
</span>
<div class="flashcard-progress">
<div class="flashcard-progress-bar" id="flashcardProgressBar" style="width: 5%"></div>
</div>
</div>
<button class="btn" onclick="nextCard()" id="nextBtn">
Suivante <i class="fas fa-chevron-right"></i>
</button>
</div>
<!-- Carte actuelle -->
<div class="flashcard-container">
<div class="flashcard" id="flashcard" onclick="flipCard()">
<div class="flashcard-face flashcard-front">
<div class="flashcard-category" style="background: rgba(59, 130, 246, 0.1); color: #3b82f6;">
<i class="fas fa-brain"></i> Persévérance
</div>
<div class="flashcard-content">
<div class="flashcard-title">Persévérer face à la difficulté</div>
<div class="flashcard-question">
Cette difficulté signifie-t-elle que je suis incapable, ou est-ce simplement une étape normale de l'apprentissage ?
</div>
<div class="flashcard-instruction">
<i class="fas fa-hand-point-up"></i> Cliquez pour retourner la carte
</div>
</div>
</div>
<div class="flashcard-face flashcard-back" style="background: linear-gradient(135deg, #10b981, #059669);">
<div class="flashcard-content">
<div class="flashcard-title">Persévérer face à la difficulté</div>
<div class="flashcard-question">
Ai-je déjà surmonté une difficulté similaire par le passé ? Se rappeler des succès passés renforce la confiance.
</div>
<div style="margin: 2rem 0; padding: 1.5rem; background: rgba(255, 255, 255, 0.1); border-radius: 10px;">
<div style="font-weight: bold; margin-bottom: 0.5rem;">Action proposée :</div>
<div>Chercher un exemple où j'ai déjà surmonté une difficulté similaire</div>
</div>
<div class="flashcard-evaluation">
<div style="font-weight: bold; margin-bottom: 0.5rem;">Utilité de cette réflexion (1-5) :</div>
<input type="range" min="1" max="5" value="3" class="evaluation-slider" id="evaluationSlider">
<div class="evaluation-label">
<span>Peu utile</span>
<span>Très utile</span>
</div>
<button class="flashcard-action" onclick="saveEvaluation()">
<i class="fas fa-save"></i> Enregistrer et continuer
</button>
</div>
</div>
</div>
</div>
</div>
<!-- DashboardEM -->
<div class="dashboardEM-container">
<h4><i class="fas fa-chart-bar"></i> DashboardEM - Métriques Métacognitives</h4>
<div class="dashboardEM-grid">
<div class="dashboardEM-card">
<div class="dashboardEM-header">
<div class="dashboardEM-icon" style="background: linear-gradient(135deg, #3b82f6, #1d4ed8);">
<i class="fas fa-brain"></i>
</div>
<div>
<h4>Persévérance</h4>
<div style="font-size: 0.9rem; color: var(--gray-color);">Capacité à maintenir l'effort</div>
</div>
</div>
<div class="dashboardEM-metric">
<div class="dashboardEM-value">0/5</div>
<div class="dashboardEM-change">+0%</div>
</div>
<div class="dashboardEM-trend">
<i class="fas fa-chart-line" style="color: #ef4444;"></i>
<span>À démarrer</span>
</div>
</div>
<div class="dashboardEM-card">
<div class="dashboardEM-header">
<div class="dashboardEM-icon" style="background: linear-gradient(135deg, #10b981, #059669);">
<i class="fas fa-bolt"></i>
</div>
<div>
<h4>Gestion de l'Effort</h4>
<div style="font-size: 0.9rem; color: var(--gray-color);">Efficacité énergétique</div>
</div>
</div>
<div class="dashboardEM-metric">
<div class="dashboardEM-value">0/5</div>
<div class="dashboardEM-change">0%</div>
</div>
<div class="dashboardEM-trend">
<i class="fas fa-chart-line" style="color: #ef4444;"></i>
<span>À améliorer</span>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Journal Section -->
<section id="journal" class="tab-content">
<div class="card">
<div class="card-header">
<h3><i class="fas fa-book"></i> Journal d'Apprentissage Autorégulé</h3>
<button class="btn btn-secondary" onclick="loadJournalEntries()">
<i class="fas fa-history"></i> Historique
</button>
</div>
<div class="form-row">
<div class="form-col">
<label class="form-label"><i class="fas fa-tasks"></i> Planifié (To-Do)</label>
<textarea id="todo" class="form-control" rows="3" placeholder="Ce que vous prévoyez d'apprendre..."></textarea>
</div>
<div class="form-col">
<label class="form-label"><i class="fas fa-spinner"></i> En Cours (Doing)</label>
<textarea id="doing" class="form-control" rows="3" placeholder="Ce que vous faites actuellement..."></textarea>
</div>
</div>
<div class="form-group">
<label class="form-label"><i class="fas fa-check-circle"></i> Accompli (Done)</label>
<textarea id="done" class="form-control" rows="3" placeholder="Ce que vous avez accompli..."></textarea>
</div>
<div class="form-group">
<label class="form-label"><i class="fas fa-star"></i> Auto-évaluation (1-5)</label>
<div class="quality-indicator">
<div class="quality-dot" onclick="setEvaluation(1)" style="background: linear-gradient(135deg, #ef4444, #dc2626);">1</div>
<div class="quality-dot" onclick="setEvaluation(2)" style="background: linear-gradient(135deg, #f59e0b, #d97706);">2</div>
<div class="quality-dot active" onclick="setEvaluation(3)" style="background: linear-gradient(135deg, #10b981, #059669);">3</div>
<div class="quality-dot" onclick="setEvaluation(4)" style="background: linear-gradient(135deg, #3b82f6, #1d4ed8);">4</div>
<div class="quality-dot" onclick="setEvaluation(5)" style="background: linear-gradient(135deg, #8b5cf6, #7c3aed);">5</div>
</div>
</div>
<div class="form-group">
<label class="form-label"><i class="fas fa-lightbulb"></i> Stratégie Métacognitive</label>
<textarea id="metacognition" class="form-control" rows="3" placeholder="Quelle stratégie avez-vous utilisée ? Que changeriez-vous ?"></textarea>
</div>
<button class="btn btn-primary btn-large" onclick="saveJournal()">
<i class="fas fa-save"></i> Sauvegarder l'Entrée
</button>
<div id="journalHistory" style="display: none; margin-top: 2rem;">
<h4><i class="fas fa-history"></i> Dernières Entrées</h4>
<div id="journalEntries"></div>
</div>
</div>
</section>
<!-- Notifications Section -->
<section id="notifications" class="tab-content">
<div class="card">
<div class="card-header">
<h3><i class="fas fa-bell"></i> Notifications Intelligentes par Bandits Multi-Bras</h3>
<button class="btn btn-secondary" onclick="getIntelligentReminder()">
<i class="fas fa-sync"></i> Nouveau Rappel
</button>
</div>
<div id="notificationContainer">
<div class="notification-card">
<p><i class="fas fa-info-circle"></i> Cliquez sur "Nouveau Rappel" pour recevoir une notification personnalisée basée sur vos habitudes d'apprentissage.</p>
</div>
</div>
<div class="visualization-container">
<h4><i class="fas fa-chart-bar"></i> Efficacité des Types de Notifications</h4>
<div class="chart-container">
<canvas id="notificationChart"></canvas>
</div>
</div>
</div>
</section>
<!-- Statistics Section -->
<section id="stats" class="tab-content">
<div class="card">
<div class="card-header">
<h3><i class="fas fa-chart-line"></i> Tableau de Bord d'Apprentissage</h3>
<button class="btn btn-secondary" onclick="refreshStats()">
<i class="fas fa-redo"></i> Actualiser
</button>
</div>
<div id="statsContainer" class="stats-grid">
<div class="stat-card">
<div class="stat-value">12</div>
<div class="stat-label">Sessions Complétées</div>
</div>
<div class="stat-card">
<div class="stat-value">85%</div>
<div class="stat-label">Taux de Réussite</div>
</div>
<div class="stat-card">
<div class="stat-value">7</div>
<div class="stat-label">Jours d'Activité</div>
</div>
<div class="stat-card">
<div class="stat-value">4.2/5</div>
<div class="stat-label">Satisfaction</div>
</div>
</div>
<!-- Heatmap d'activité -->
<div class="heatmap-container">
<div class="heatmap-header">
<div class="heatmap-title">
<i class="fas fa-fire"></i> Heatmap d'activité
</div>
<div class="heatmap-controls">
<button class="heatmap-period active" onclick="changeHeatmapPeriod('month')">Mois</button>
<button class="heatmap-period" onclick="changeHeatmapPeriod('quarter')">Trimestre</button>
<button class="heatmap-period" onclick="changeHeatmapPeriod('year')">Année</button>
</div>
</div>
<div id="heatmapContent">
<!-- La heatmap sera générée ici par JavaScript -->
</div>
<div class="heatmap-legend">
<div class="legend-item">
<div class="legend-color heatmap-intensity-0"></div>
<span>0 min</span>
</div>
<div class="legend-item">
<div class="legend-color heatmap-intensity-1"></div>
<span>15 min</span>
</div>
<div class="legend-item">
<div class="legend-color heatmap-intensity-2"></div>
<span>30 min</span>
</div>
</div>
</div>
<!-- Indicateurs de gestion du temps -->
<div class="time-management-stats">
<div class="time-stat-card">
<div class="time-stat-header">
<div class="time-stat-icon">
<i class="fas fa-calendar-check"></i>
</div>
<div>
<h4>Régularité du travail</h4>
<div class="time-stat-description">Constance de l'activité dans le temps</div>
</div>
</div>
<div class="progress-circle">
<svg viewBox="0 0 100 100">
<circle cx="50" cy="50" r="45" fill="none" stroke="#e2e8f0" stroke-width="8"/>
<circle cx="50" cy="50" r="45" fill="none" stroke="#10b981" stroke-width="8"
stroke-linecap="round" stroke-dasharray="283" stroke-dashoffset="28.3"/>
</svg>
<div class="progress-text">90%</div>
</div>
</div>
<div class="time-stat-card">
<div class="time-stat-header">
<div class="time-stat-icon" style="background: linear-gradient(135deg, #3b82f6, #1d4ed8);">
<i class="fas fa-clock"></i>
</div>
<div>
<h4>Gestion des échéances</h4>
<div class="time-stat-description">Capacité à respecter les délais</div>
</div>
</div>
<div class="progress-circle">
<svg viewBox="0 0 100 100">
<circle cx="50" cy="50" r="45" fill="none" stroke="#e2e8f0" stroke-width="8"/>
<circle cx="50" cy="50" r="45" fill="none" stroke="#3b82f6" stroke-width="8"
stroke-linecap="round" stroke-dasharray="283" stroke-dashoffset="53.77"/>
</svg>
<div class="progress-text">81%</div>
</div>
</div>
</div>
</div>
</section>
</div>
<script>
// ============================================
// VARIABLES GLOBALES
// ============================================
// Variables pour le profil
let learnerProfile = {
bigFive: {
extraversion: 3,
openness: 3,
conscientiousness: 4,
agreeableness: 3,
neuroticism: 4
},
motivation: {
intrinsic: 3,
introjected: 4,
identified: 3,
external: 1
},
habits: {},
wellbeing: {},
support: {},
completionStatus: {
big5: true,
motivation: true,
habits: false,
wellbeing: false,
support: false
}
};
// Variables pour le planner
let selectedTimeSlots = ['morning'];
let currentQuality = 2;
let productivityMethod = 'pomodoro';
let energyPattern = 'morning';
// Variables pour la heatmap
let currentHeatmapPeriod = 'month';
// Variables pour le journal
let journalEntries = [];
// Variables pour les flashcards
let flashcards = [];
let currentCardIndex = 0;
let currentCategory = 'all';
let flashcardsData = [];
let flashcardsStats = {
totalCards: 0,
reviewedCards: 0,
averageScore: 0,
favoriteCategory: ''
};
// ============================================
// INITIALISATION
// ============================================
document.addEventListener('DOMContentLoaded', function() {
// Initialiser le profil
updateProfileProgress();
updateProfileSummary();
createMotivationChart();
// Initialiser la heatmap
generateHeatmap();
// Initialiser le graphique des notifications
createNotificationChart();
// Initialiser les flashcards
initializeFlashcards();
// Charger les données sauvegardées
loadSavedData();
});
// ============================================
// FONCTIONS DE NAVIGATION
// ============================================
function showTab(tabId) {
// Masquer toutes les sections
document.querySelectorAll('.tab-content').forEach(section => {
section.classList.remove('active');
});
// Désactiver tous les onglets
document.querySelectorAll('.nav-tab').forEach(tab => {
tab.classList.remove('active');
});
// Activer la section sélectionnée
document.getElementById(tabId).classList.add('active');
// Activer l'onglet correspondant
const tabNames = {
'profile': 'Profil Apprenant',
'objectif': 'Objectif',
'planner': 'Planner ',
'flashcards': 'Métacognition',
'journal': 'Journal SRL',
'notifications': 'Notifications IA',
'stats': 'Statistiques'
};
document.querySelectorAll('.nav-tab').forEach(tab => {
if (tab.textContent.includes(tabNames[tabId])) {
tab.classList.add('active');
}
});
// Actions spécifiques par onglet
if (tabId === 'stats') {
refreshStats();
generateHeatmap();
} else if (tabId === 'flashcards') {
updateFlashcardsStats();
updateDashboardEM();
}
}
// ============================================
// PROFIL APPRENANT
// ============================================
// Sélectionner une échelle
function selectScale(trait, value) {
learnerProfile.bigFive[trait] = value;
updateScaleUI(trait, value);
updateProfileSummary();
updateSectionCompletion('big5-section');
}
// Sélectionner une motivation
function selectMotivation(type, value) {
learnerProfile.motivation[type] = value;
updateScaleUI(type, value);
updateProfileSummary();
updateSectionCompletion('motivation-section');
}
// Mettre à jour l'UI de l'échelle
function updateScaleUI(type, value) {
// Trouver tous les boutons d'échelle pour ce type
const scaleOptions = document.querySelectorAll(`[onclick*="${type}"]`);
scaleOptions.forEach(option => {
option.classList.remove('selected');
// Extraire la valeur du bouton
const match = option.getAttribute('onclick').match(/(\d+)/);
if (match && parseInt(match[1]) === value) {
option.classList.add('selected');
}
});
}
// Vérifier si toutes les questions d'une section sont répondues
function checkSectionCompletion(sectionId) {
const section = document.getElementById(sectionId);
const scaleOptions = section.querySelectorAll('.scale-option.selected');
// Nombre attendu de questions par section
const expectedCount = {
'big5-section': 5,
'motivation-section': 2
};
return scaleOptions.length >= expectedCount[sectionId];
}
// Mettre à jour l'indicateur de complétion d'une section
function updateSectionCompletion(sectionId) {
const isComplete = checkSectionCompletion(sectionId);
const sectionKey = sectionId.replace('-section', '');
const completionElement = document.getElementById(`${sectionKey}-completion`);
// Mettre à jour le statut dans le profil
learnerProfile.completionStatus[sectionKey] = isComplete;
if (isComplete) {
completionElement.className = 'section-completion section-complete';
let message = "Section complétée";
if (sectionKey === 'big5') {
const neuroticism = learnerProfile.bigFive.neuroticism || 3;
message += ` - <strong>Score neuroticisme: ${neuroticism}</strong> (qualité du sommeil ${neuroticism >= 4 ? 'importante' : 'modérée'})`;
} else if (sectionKey === 'motivation') {
const introjected = learnerProfile.motivation.introjected || 3;
message += ` - <strong>Motivation introjectée: ${introjected}</strong> (pression ${introjected >= 4 ? 'élevée' : 'modérée'})`;
}
completionElement.innerHTML = `<i class="fas fa-check-circle" style="color: #10b981;"></i><span>${message}</span>`;
} else {
completionElement.className = 'section-completion section-incomplete';
completionElement.innerHTML = `<i class="fas fa-exclamation-circle" style="color: #ef4444;"></i><span>Section incomplète - Remplissez toutes les questions</span>`;
}
// Mettre à jour la progression globale
updateProfileProgress();
}
// Mettre à jour la progression du profil
function updateProfileProgress() {
const sections = Object.values(learnerProfile.completionStatus);
const completedCount = sections.filter(status => status).length;
const totalSections = sections.length;
const percentage = Math.round((completedCount / totalSections) * 100);
// Mettre à jour la barre de progression
document.getElementById('profileCompletion').textContent = `${percentage}%`;
document.getElementById('profileProgressBar').style.width = `${percentage}%`;
// Mettre à jour le compteur
document.getElementById('completedSections').textContent = `${completedCount}/${totalSections}`;
// Mettre à jour le niveau de personnalisation
let level = "Basique";
if (percentage >= 20) level = "Débutant";
if (percentage >= 40) level = "Intermédiaire";
if (percentage >= 60) level = "Avancé";
if (percentage >= 80) level = "Expert";
if (percentage === 100) level = "Personnalisé";
document.getElementById('personalizationLevel').textContent = level;
}
// Mettre à jour le résumé du profil
function updateProfileSummary() {
// Mettre à jour les valeurs Big Five
document.getElementById('extraversion-value').textContent = learnerProfile.bigFive.extraversion.toFixed(1);
document.getElementById('openness-value').textContent = learnerProfile.bigFive.openness.toFixed(1);
document.getElementById('conscientiousness-value').textContent = learnerProfile.bigFive.conscientiousness.toFixed(1);
document.getElementById('agreeableness-value').textContent = learnerProfile.bigFive.agreeableness.toFixed(1);
document.getElementById('neuroticism-value').textContent = learnerProfile.bigFive.neuroticism.toFixed(1);
// Mettre à jour les valeurs de motivation
document.getElementById('intrinsic-value').textContent = learnerProfile.motivation.intrinsic.toFixed(1);
document.getElementById('introjected-value').textContent = learnerProfile.motivation.introjected.toFixed(1);
document.getElementById('identified-value').textContent = learnerProfile.motivation.identified.toFixed(1);
document.getElementById('external-value').textContent = learnerProfile.motivation.external.toFixed(1);
// Mettre à jour le graphique de motivation
updateMotivationChart();
}
// Créer le graphique de motivation
function createMotivationChart() {
const ctx = document.getElementById('motivationChart').getContext('2d');
window.motivationChart = new Chart(ctx, {
type: 'radar',
data: {
labels: ['Intrinsèque', 'Introjectée', 'Identifiée', 'Externe'],
datasets: [{
label: 'Motivation',
data: [
learnerProfile.motivation.intrinsic,
learnerProfile.motivation.introjected,
learnerProfile.motivation.identified,
learnerProfile.motivation.external
],
backgroundColor: 'rgba(59, 130, 246, 0.2)',
borderColor: 'rgb(59, 130, 246)',
pointBackgroundColor: 'rgb(59, 130, 246)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgb(59, 130, 246)'
}]
},
options: {
scales: {
r: {
beginAtZero: true,
max: 5,
ticks: {
stepSize: 1
}
}
},
responsive: true,
maintainAspectRatio: false
}
});
}
// Mettre à jour le graphique de motivation
function updateMotivationChart() {
if (window.motivationChart) {
window.motivationChart.data.datasets[0].data = [
learnerProfile.motivation.intrinsic,
learnerProfile.motivation.introjected,
learnerProfile.motivation.identified,
learnerProfile.motivation.external
];
window.motivationChart.update();
}
}
// Compléter automatiquement toutes les sections
function completeAllSections() {
// Remplir les sections manquantes avec des valeurs par défaut
const defaultValues = {
study_hours: 3,
late_submissions: 2,
completion_rate: 4,
forum_participation: 2,
sleep_hours: 4,
study_stress: 3,
relaxation: 3,
burnout_risk: 2,
family_support: 4,
parental_expectations: 4,
study_environment: 4,
peer_collaboration: 3
};
// Marquer toutes les sections comme complètes
Object.keys(learnerProfile.completionStatus).forEach(key => {
learnerProfile.completionStatus[key] = true;
});
// Mettre à jour l'interface
updateProfileProgress();
updateProfileSummary();
// Mettre à jour les indicateurs de section
updateSectionCompletion('habits-section');
updateSectionCompletion('wellbeing-section');
updateSectionCompletion('support-section');
showNotification('Toutes les sections ont été complétées automatiquement !', 'success');
}
// Sauvegarder le profil
function saveProfile() {
try {
localStorage.setItem('learnerProfile', JSON.stringify(learnerProfile));
showNotification('Profil sauvegardé avec succès !', 'success');
} catch (error) {
showNotification('Erreur lors de la sauvegarde du profil', 'error');
}
}
// Finaliser le profil
function completeProfile() {
// Vérifier si toutes les sections sont complétées
const incompleteSections = Object.entries(learnerProfile.completionStatus)
.filter(([section, completed]) => !completed)
.map(([section]) => section);
if (incompleteSections.length > 0) {
showNotification(`Veuillez compléter les sections suivantes: ${incompleteSections.join(', ')}`, 'warning');
return;
}
// Sauvegarder le profil
saveProfile();
// Générer des recommandations personnalisées
generatePersonalizedRecommendations();
showNotification('Profil finalisé avec succès ! Les recommandations ont été mises à jour.', 'success');
}
// Générer des recommandations personnalisées
function generatePersonalizedRecommendations() {
const recommendations = [];
// Recommandations basées sur le Big Five
if (learnerProfile.bigFive.neuroticism >= 4) {
recommendations.push({
icon: '💤',
text: `Avec un névrosisme élevé (${learnerProfile.bigFive.neuroticism}), planifiez 8 heures de sommeil de qualité avec des activités de relaxation.`
});
}
if (learnerProfile.bigFive.conscientiousness >= 4) {
recommendations.push({
icon: '📅',
text: `Votre conscience élevée (${learnerProfile.bigFive.conscientiousness}) est excellente pour l'auto-discipline. Évitez le surmenage.`
});
}
// Recommandations basées sur la motivation
if (learnerProfile.motivation.introjected >= 4) {
recommendations.push({
icon: '🎯',
text: `Motivation introjectée élevée (${learnerProfile.motivation.introjected}). Pratiquez des techniques de gestion du stress.`
});
}
// Mettre à jour l'affichage des recommandations
updateRecommendationsDisplay(recommendations);
}
// Mettre à jour l'affichage des recommandations
function updateRecommendationsDisplay(recommendations) {
const container = document.querySelector('.recommendations-section');
let html = '<h4><i class="fas fa-lightbulb"></i> Recommandations Personnalisées Basées sur Votre Profil</h4>';
recommendations.forEach(rec => {
html += `
<div class="recommendation-item">
<div class="recommendation-icon">${rec.icon}</div>
<div>${rec.text}</div>
</div>
`;
});
container.innerHTML = html;
}
// ============================================
// OBJECTIF ET PLANNER
// ============================================
// Sélectionner la méthode de productivité
function selectProductivityMethod(method) {
productivityMethod = method;
document.querySelectorAll('.option-item').forEach(item => {
item.classList.remove('selected');
});
event.target.closest('.option-item').classList.add('selected');
}
// Sélectionner le type d'énergie
function selectEnergyPattern(pattern) {
energyPattern = pattern;
const patternElements = document.querySelectorAll('.option-section:nth-child(2) .option-item');
patternElements.forEach(item => {
item.classList.remove('selected');
});
event.target.closest('.option-item').classList.add('selected');
}
// Basculer créneau horaire
function toggleTimeSlot(slot) {
const index = selectedTimeSlots.indexOf(slot);
if (index === -1) {
selectedTimeSlots.push(slot);
} else {
selectedTimeSlots.splice(index, 1);
}
// Mettre à jour l'interface
document.querySelectorAll('.time-slot').forEach(element => {
element.classList.remove('selected');
});
selectedTimeSlots.forEach(slot => {
document.querySelector(`.time-slot:nth-child(${getTimeSlotIndex(slot) + 1})`).classList.add('selected');
});
}
function getTimeSlotIndex(slot) {
const slots = ['morning', 'late_morning', 'afternoon', 'late_afternoon', 'evening'];
return slots.indexOf(slot);
}
// Sélectionner la qualité
function selectQuality(level) {
currentQuality = level;
document.querySelectorAll('.quality-dot').forEach(dot => {
dot.classList.remove('active');
});
event.target.classList.add('active');
const descriptions = [
"Difficulté - Révision fréquente nécessaire",
"Moyen - Intervalles standard recommandés",
"Bon - Consolidation progressive",
"Excellent - Rétention à long terme optimale"
];
document.getElementById('quality-description').textContent = descriptions[level];
}
// Générer le planner
function generatePlanner() {
const competence = document.getElementById('competence').value;
const startDate = document.getElementById('start').value;
const duration = document.getElementById('duration').value;
if (!competence) {
showNotification('Veuillez sélectionner une compétence', 'warning');
return;
}
// Générer les intervalles SM-2 basés sur la qualité
const intervals = getSM2Intervals(currentQuality);
// Créer le planning
const plan = createStudyPlan(competence, startDate, duration, intervals);
// Afficher le planning
displayPlanner(plan, intervals);
// Passer à l'onglet planner
showTab('planner');
showNotification('Planner généré avec succès !', 'success');
}
// Obtenir les intervalles SM-2
function getSM2Intervals(quality) {
const intervals = {
0: [1, 2, 4, 8, 16, 32], // Difficulté
1: [1, 3, 7, 14, 30, 60], // Moyen
2: [2, 7, 16, 35, 70, 140], // Bon
3: [3, 10, 25, 60, 120, 240] // Excellent
};
return intervals[quality] || intervals[2];
}
// Créer le plan d'étude
function createStudyPlan(competence, startDate, duration, intervals) {
const plan = [];
const start = new Date(startDate);
for (let i = 0; i < intervals.length; i++) {
const sessionDate = new Date(start);
sessionDate.setDate(sessionDate.getDate() + intervals[i]);
plan.push({
date: sessionDate.toLocaleDateString('fr-FR'),
jour: sessionDate.toLocaleDateString('fr-FR', { weekday: 'long' }),
competence: competence,
duree: `${duration} minutes`,
intervalle: `${intervals[i]} jours`,
repetition: i + 1,
type: i === 0 ? 'Apprentissage' : i < 3 ? 'Consolidation' : 'Maintien',
strategie: i === 0 ? 'Focus intense' : 'Révision active',
productivity_method: productivityMethod === 'pomodoro' ? 'Pomodoro' : 'Deep Work',
optimal_time: energyPattern === 'morning' ? '08:00-10:00' :
energyPattern === 'evening' ? '19:00-21:00' : 'Adaptable'
});
}
return plan;
}
// Afficher le planner
function displayPlanner(plan, intervals) {
const container = document.getElementById('plannerContent');
const statsContainer = document.getElementById('plannerStats');
// Calculer le total des jours
const totalDays = intervals.reduce((a, b) => a + b, 0);
// Statistiques
statsContainer.innerHTML = `
<div class="stat-card">
<div class="stat-value">${plan.length}</div>
<div class="stat-label">Sessions Planifiées</div>
</div>
<div class="stat-card">
<div class="stat-value">${totalDays}</div>
<div class="stat-label">Jours Totaux</div>
</div>
<div class="stat-card">
<div class="stat-value">${currentQuality + 1}/4</div>
<div class="stat-label">Niveau de Qualité</div>
</div>
<div class="stat-card">
<div class="stat-value">${document.getElementById('duration').value}min</div>
<div class="stat-label">Durée/Session</div>
</div>
`;
// Sessions
container.innerHTML = '';
plan.forEach(session => {
const card = document.createElement('div');
card.className = 'session-card';
card.innerHTML = `
<div class="session-header">
<div class="session-date">
<i class="fas fa-calendar-day"></i> ${session.date}
<div style="font-size: 0.9rem; color: #64748b;">${session.jour}</div>
</div>
<div class="session-repetition">
R${session.repetition}
</div>
</div>
<h4 style="margin: 10px 0; color: #1e293b;">${session.competence}</h4>
<div class="session-details">
<div class="detail-item">
<span><i class="fas fa-clock"></i> Durée</span>
<span>${session.duree}</span>
</div>
<div class="detail-item">
<span><i class="fas fa-sync-alt"></i> Intervalle</span>
<span>${session.intervalle}</span>
</div>
<div class="detail-item">
<span><i class="fas fa-bullseye"></i> Type</span>
<span>${session.type}</span>
</div>
<div class="detail-item">
<span><i class="fas fa-lightbulb"></i> Stratégie</span>
<span>${session.strategie}</span>
</div>
<div class="detail-item">
<span><i class="fas fa-chart-line"></i> Productivité</span>
<span>${session.productivity_method}</span>
</div>
<div class="detail-item">
<span><i class="fas fa-sun"></i> Heure Optimale</span>
<span>${session.optimal_time}</span>
</div>
</div>
`;
container.appendChild(card);
});
// Visualisation
createSM2Visualization(intervals, plan[0]?.competence || 'Compétence');
}
// Créer la visualisation SM-2
function createSM2Visualization(intervals, competence) {
const ctx = document.getElementById('sm2Visualization').getContext('2d');
if (window.sm2VisualizationChart) {
window.sm2VisualizationChart.destroy();
}
const labels = intervals.map((_, i) => `Répétition ${i + 1}`);
window.sm2VisualizationChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Intervalle (jours)',
data: intervals,
borderColor: '#3b82f6',
backgroundColor: 'rgba(59, 130, 246, 0.1)',
borderWidth: 3,
fill: true,
tension: 0.4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
title: {
display: true,
text: `Courbe de Répétition Espacée - ${competence}`,
font: { size: 16 }
}
},
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: 'Jours'
}
},
x: {
title: {
display: true,
text: 'Numéro de Répétition'
}
}
}
}
});
}
// Exporter le planner
function exportPlanner() {
const plannerData = document.getElementById('plannerContent').innerText;
const blob = new Blob([plannerData], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'planner-sm2.txt';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
showNotification('Planner exporté avec succès !', 'success');
}
// ============================================
// FLASHCARDS COGNITIVES
// ============================================
// Initialiser les flashcards
function initializeFlashcards() {
// Données des flashcards
flashcardsData = [
{
id: 1,
category: 'awareness',
categoryName: 'Prise de conscience',
icon: '👁️',
color: '#3b82f6',
front: {
title: 'Diagnostic de Blocage',
question: 'Qu\'est-ce qui me bloque exactement dans cette tâche ?'
},
back: {
reflection: 'Est-ce un problème de compréhension, d\'énergie, ou de motivation ? Identifier précisément le type d\'obstacle.',
action: 'Prendre 2 minutes pour écrire ce qui semble difficile',
evaluationLabel: 'Clarté du diagnostic'
}
},
{
id: 2,
category: 'perseverance',
categoryName: 'Persévérance',
icon: '🏔️',
color: '#10b981',
front: {
title: 'Persévérer face à la difficulté',
question: 'Cette difficulté signifie-t-elle que je suis incapable ?'
},
back: {
reflection: 'Ai-je déjà surmonté une difficulté similaire par le passé ? Se rappeler des succès passés renforce la confiance.',
action: 'Chercher un exemple où j\'ai déjà surmonté une difficulté similaire',
evaluationLabel: 'Résilience perçue'
}
},
{
id: 3,
category: 'effort',
categoryName: 'Gestion de l\'effort',
icon: '⚡',
color: '#f59e0b',
front: {
title: 'Niveau d\'Énergie',
question: 'Mon niveau d\'énergie est-il adapté à cette tâche ?'
},
back: {
reflection: 'Ai-je besoin d\'une pause ou d\'un changement d\'activité ? Travailler avec un niveau d\'énergie bas réduit l\'efficacité.',
action: 'Faire une pause de 5 minutes avec une activité énergisante',
evaluationLabel: 'Gestion énergétique'
}
}
];
// Initialiser les stats
flashcardsStats.totalCards = flashcardsData.length;
flashcardsStats.reviewedCards = 0;
flashcardsStats.averageScore = 0;
// Afficher la première carte
showCardByCategory('all');
}
// Afficher une carte par catégorie
function showCardByCategory(category) {
currentCategory = category;
currentCardIndex = 0;
// Mettre à jour les filtres
document.querySelectorAll('.category-filter').forEach(filter => {
filter.classList.remove('active');
});
document.querySelector(`.category-filter[onclick*="${category}"]`).classList.add('active');
// Filtrer les cartes par catégorie
if (category === 'all') {
flashcards = [...flashcardsData];
} else {
flashcards = flashcardsData.filter(card => card.category === category);
}
// Mélanger les cartes
shuffleArray(flashcards);
// Afficher la première carte
displayCurrentCard();
// Mettre à jour les stats
updateFlashcardsStats();
}
// Mélanger un tableau
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
// Afficher la carte actuelle
function displayCurrentCard() {
if (flashcards.length === 0) return;
const card = flashcards[currentCardIndex];
const progress = ((currentCardIndex + 1) / flashcards.length * 100).toFixed(1);
// Mettre à jour la carte
const flashcard = document.getElementById('flashcard');
if (flashcard) {
// Face avant
flashcard.querySelector('.flashcard-category').innerHTML = `
<i class="fas fa-${card.icon}"></i> ${card.categoryName}
`;
flashcard.querySelector('.flashcard-category').style.background = `${card.color}22`;
flashcard.querySelector('.flashcard-category').style.color = card.color;
flashcard.querySelector('.flashcard-title').textContent = card.front.title;
flashcard.querySelector('.flashcard-question').textContent = card.front.question;
// Face arrière
const backFace = flashcard.querySelector('.flashcard-back');
backFace.style.background = `linear-gradient(135deg, ${card.color}, ${darkenColor(card.color, 20)})`;
backFace.querySelector('.flashcard-title').textContent = card.front.title;
backFace.querySelector('.flashcard-question').textContent = card.back.reflection;
// Mettre à jour l'action
backFace.querySelector('.flashcard-evaluation .flashcard-question').textContent = card.back.reflection;
backFace.querySelector('.flashcard-evaluation > div:nth-child(2) > div:nth-child(2)').textContent = card.back.action;
// Mettre à jour le label d'évaluation
backFace.querySelector('.flashcard-evaluation > div:nth-child(3) > div:nth-child(1)').textContent = `${card.back.evaluationLabel} (1-5) :`;
}
// Mettre à jour le compteur et la barre de progression
document.getElementById('cardCounter').textContent = `Carte ${currentCardIndex + 1}/${flashcards.length}`;
document.getElementById('flashcardProgressBar').style.width = `${progress}%`;
// Gérer les boutons de navigation
document.getElementById('prevBtn').disabled = currentCardIndex === 0;
document.getElementById('nextBtn').disabled = currentCardIndex === flashcards.length - 1;
// Réinitialiser la rotation de la carte
flashcard.classList.remove('flipped');
}
// Fonction pour assombrir une couleur
function darkenColor(color, percent) {
const num = parseInt(color.replace("#", ""), 16);
const amt = Math.round(2.55 * percent);
const R = (num >> 16) - amt;
const G = (num >> 8 & 0x00FF) - amt;
const B = (num & 0x0000FF) - amt;
return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 +
(G < 255 ? G < 1 ? 0 : G : 255) * 0x100 +
(B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1);
}
// Retourner la carte
function flipCard() {
const flashcard = document.getElementById('flashcard');
if (flashcard) {
flashcard.classList.toggle('flipped');
}
}
// Sauvegarder l'évaluation
function saveEvaluation() {
const slider = document.getElementById('evaluationSlider');
const score = parseInt(slider.value);
// Mettre à jour les stats
flashcardsStats.reviewedCards++;
// Calculer la moyenne
flashcardsStats.averageScore = ((flashcardsStats.averageScore * (flashcardsStats.reviewedCards - 1) + score) / flashcardsStats.reviewedCards).toFixed(1);
// Passer à la carte suivante
setTimeout(() => {
nextCard();
flipCard(); // Retourner à la face avant
}, 500);
// Mettre à jour le dashboard
updateDashboardEM();
showNotification('Évaluation enregistrée !', 'success');
}
// Carte précédente
function prevCard() {
if (currentCardIndex > 0) {
currentCardIndex--;
displayCurrentCard();
}
}
// Carte suivante
function nextCard() {
if (currentCardIndex < flashcards.length - 1) {
currentCardIndex++;
displayCurrentCard();
} else {
// Revenir au début
currentCardIndex = 0;
shuffleArray(flashcards);
displayCurrentCard();
showNotification('Retour au début des cartes !', 'info');
}
}
// Mettre à jour les statistiques des flashcards
function updateFlashcardsStats() {
const statsContainer = document.getElementById('flashcardsStats');
if (statsContainer) {
statsContainer.innerHTML = `
<div class="stat-card">
<div class="stat-value">${flashcardsStats.totalCards}</div>
<div class="stat-label">Cartes disponibles</div>
</div>
<div class="stat-card">
<div class="stat-value">${flashcardsStats.reviewedCards}</div>
<div class="stat-label">Cartes consultées</div>
</div>
<div class="stat-card">
<div class="stat-value">${flashcardsStats.averageScore}/5</div>
<div class="stat-label">Score moyen</div>
</div>
<div class="stat-card">
<div class="stat-value">${currentCategory === 'all' ? 'Toutes' : currentCategory}</div>
<div class="stat-label">Catégorie active</div>
</div>
`;
}
}
// Mettre à jour le DashboardEM
function updateDashboardEM() {
const dashboardContainer = document.querySelector('.dashboardEM-grid');
if (dashboardContainer) {
dashboardContainer.innerHTML = `
<div class="dashboardEM-card">
<div class="dashboardEM-header">
<div class="dashboardEM-icon" style="background: linear-gradient(135deg, #3b82f6, #1d4ed8);">
<i class="fas fa-brain"></i>
</div>
<div>
<h4>Persévérance</h4>
<div style="font-size: 0.9rem; color: var(--gray-color);">Capacité à maintenir l'effort</div>
</div>
</div>
<div class="dashboardEM-metric">
<div class="dashboardEM-value">${flashcardsStats.averageScore}/5</div>
<div class="dashboardEM-change">+${(flashcardsStats.averageScore * 20).toFixed(0)}%</div>
</div>
<div class="dashboardEM-trend">
<i class="fas fa-chart-line" style="color: ${flashcardsStats.averageScore > 2 ? '#10b981' : '#ef4444'}"></i>
<span>${flashcardsStats.averageScore > 2 ? 'En progression' : 'À améliorer'}</span>
</div>
</div>
<div class="dashboardEM-card">
<div class="dashboardEM-header">
<div class="dashboardEM-icon" style="background: linear-gradient(135deg, #10b981, #059669);">
<i class="fas fa-bolt"></i>
</div>
<div>
<h4>Engagement</h4>
<div style="font-size: 0.9rem; color: var(--gray-color);">Activité métacognitive</div>
</div>
</div>
<div class="dashboardEM-metric">
<div class="dashboardEM-value">${flashcardsStats.reviewedCards}</div>
<div class="dashboardEM-change">+${(flashcardsStats.reviewedCards * 20).toFixed(0)}%</div>
</div>
<div class="dashboardEM-trend">
<i class="fas fa-chart-line" style="color: ${flashcardsStats.reviewedCards > 0 ? '#10b981' : '#ef4444'}"></i>
<span>${flashcardsStats.reviewedCards > 0 ? 'Actif' : 'À démarrer'}</span>
</div>
</div>
`;
}
}
// Réinitialiser les flashcards
function resetFlashcards() {
if (confirm('Voulez-vous vraiment réinitialiser toutes les flashcards ?')) {
flashcardsStats.reviewedCards = 0;
flashcardsStats.averageScore = 0;
currentCardIndex = 0;
showCardByCategory(currentCategory);
showNotification('Flashcards réinitialisées avec succès !', 'success');
}
}
// ============================================
// JOURNAL
// ============================================
// Définir l'auto-évaluation
function setEvaluation(score) {
document.querySelectorAll('.quality-indicator .quality-dot').forEach((dot, index) => {
dot.classList.toggle('active', index === score - 1);
});
}
// Sauvegarder une entrée de journal
function saveJournal() {
const entry = {
todo: document.getElementById('todo').value,
doing: document.getElementById('doing').value,
done: document.getElementById('done').value,
metacognition: document.getElementById('metacognition').value,
timestamp: new Date().toISOString()
};
journalEntries.push(entry);
// Réinitialiser le formulaire
document.getElementById('todo').value = '';
document.getElementById('doing').value = '';
document.getElementById('done').value = '';
document.getElementById('metacognition').value = '';
setEvaluation(3);
// Sauvegarder
localStorage.setItem('journalEntries', JSON.stringify(journalEntries));
showNotification('Journal sauvegardé avec succès !', 'success');
}
// Charger les entrées de journal
function loadJournalEntries() {
const container = document.getElementById('journalEntries');
const history = document.getElementById('journalHistory');
if (journalEntries.length === 0) {
container.innerHTML = '<p>Aucune entrée de journal trouvée.</p>';
} else {
container.innerHTML = '';
journalEntries.slice(-5).reverse().forEach(entry => {
const div = document.createElement('div');
div.className = 'session-card';
div.innerHTML = `
<div class="session-header">
<div class="session-date">
${new Date(entry.timestamp).toLocaleDateString('fr-FR')}
</div>
</div>
${entry.done ? `<div style="margin-top: 10px;"><strong>Accompli:</strong> ${entry.done.substring(0, 100)}...</div>` : ''}
`;
container.appendChild(div);
});
}
history.style.display = 'block';
}
// ============================================
// NOTIFICATIONS
// ============================================
// Obtenir un rappel intelligent
function getIntelligentReminder() {
const notifications = [
{
type: 'motivation',
icon: '🌱',
message: "Rappel: Prenez 5 minutes pour planifier votre session d'étude d'aujourd'hui !"
},
{
type: 'rappel_court',
icon: '⏰',
message: "Il est temps de réviser vos flashcards ! Une courte session maintenant renforcera votre mémoire."
},
{
type: 'encouragement',
icon: '💪',
message: "Super travail jusqu'à présent ! Continuez à progresser, chaque petite session compte."
}
];
const notification = notifications[Math.floor(Math.random() * notifications.length)];
const container = document.getElementById('notificationContainer');
const card = document.createElement('div');
card.className = 'notification-card';
card.innerHTML = `
<div style="display: flex; align-items: center; gap: 15px; margin-bottom: 10px;">
<div style="font-size: 2rem;">${notification.icon}</div>
<div>
<div style="font-weight: bold; color: #1e293b;">${notification.type.charAt(0).toUpperCase() + notification.type.slice(1).replace('_', ' ')}</div>
<div style="font-size: 0.9rem; color: #64748b;">
Efficacité: ${(Math.random() * 20 + 75).toFixed(1)}%
</div>
</div>
</div>
<p style="font-size: 1.1rem; line-height: 1.5;">${notification.message}</p>
<div style="margin-top: 10px; font-size: 0.8rem; color: #64748b; text-align: right;">
${new Date().toLocaleTimeString('fr-FR')}
</div>
`;
container.insertBefore(card, container.firstChild);
// Limiter à 5 notifications
while (container.children.length > 5) {
container.removeChild(container.lastChild);
}
}
// Créer le graphique des notifications
function createNotificationChart() {
const ctx = document.getElementById('notificationChart').getContext('2d');
window.notificationChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Motivation', 'Rappels', 'Encouragement'],
datasets: [{
label: 'Efficacité (%)',
data: [85, 72, 91],
backgroundColor: [
'rgba(59, 130, 246, 0.7)',
'rgba(16, 185, 129, 0.7)',
'rgba(245, 158, 11, 0.7)'
],
borderColor: [
'rgb(59, 130, 246)',
'rgb(16, 185, 129)',
'rgb(245, 158, 11)'
],
borderWidth: 2
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true,
max: 100,
title: {
display: true,
text: 'Efficacité (%)'
}
}
},
plugins: {
title: {
display: true,
text: 'Performance des Types de Notifications',
font: { size: 16 }
}
}
}
});
}
// ============================================
// STATISTIQUES
// ============================================
// Actualiser les statistiques
function refreshStats() {
showNotification('Statistiques actualisées', 'success');
}
// Générer la heatmap
function generateHeatmap() {
const container = document.getElementById('heatmapContent');
// Générer des données de démonstration
const heatmapData = generateDemoHeatmapData(currentHeatmapPeriod);
// Créer la structure de la heatmap
let html = '<div class="heatmap-grid">';
// Ajouter les étiquettes des jours
const days = ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim'];
html += '<div class="heatmap-day-label"></div>';
days.forEach(day => {
html += `<div class="heatmap-day-label">${day}</div>`;
});
// Ajouter les cellules de la heatmap
heatmapData.forEach((week, weekIndex) => {
html += `<div class="heatmap-week-label">S${weekIndex + 1}</div>`;
days.forEach((day, dayIndex) => {
const activity = week[dayIndex];
if (activity !== null) {
const intensity = getIntensityLevel(activity);
const tooltip = `Jour: ${day}, Semaine ${weekIndex + 1}\nActivité: ${activity} minutes`;
html += `
<div class="heatmap-cell heatmap-intensity-${intensity}"
title="${tooltip}">
${activity}
</div>
`;
} else {
html += '<div class="heatmap-cell" style="visibility: hidden;"></div>';
}
});
});
html += '</div>';
if (container) {
container.innerHTML = html;
}
}
// Générer des données de démonstration pour la heatmap
function generateDemoHeatmapData(period) {
const data = [];
let weeks = 4; // Par défaut pour le mois
if (period === 'quarter') weeks = 13;
if (period === 'year') weeks = 52;
// Pattern d'activité typique
for (let week = 0; week < weeks; week++) {
const weekData = [];
for (let day = 0; day < 7; day++) {
// Générer une activité aléatoire avec un pattern spécifique
let activity = 0;
// Plus d'activité jeudi (jour 3) et vendredi (jour 4)
if (day === 3 || day === 4) {
activity = Math.floor(Math.random() * 45) + 30;
} else if (day === 0 || day === 6) {
activity = Math.floor(Math.random() * 30) + 15;
} else {
activity = Math.floor(Math.random() * 30);
}
// Ajouter une variabilité hebdomadaire
if (week % 4 === 0) {
activity = Math.min(activity * 1.3, 90);
} else if (week % 4 === 2) {
activity = Math.max(activity * 0.7, 10);
}
activity = Math.round(activity);
weekData.push(activity);
}
data.push(weekData);
}
return data;
}
// Obtenir le niveau d'intensité
function getIntensityLevel(activity) {
if (activity === 0) return 0;
if (activity <= 15) return 1;
if (activity <= 30) return 2;
if (activity <= 45) return 3;
return 4;
}
// Changer la période de la heatmap
function changeHeatmapPeriod(period) {
currentHeatmapPeriod = period;
// Mettre à jour les boutons
document.querySelectorAll('.heatmap-period').forEach(btn => {
btn.classList.remove('active');
if (btn.textContent.toLowerCase().includes(period)) {
btn.classList.add('active');
}
});
// Regénérer la heatmap
generateHeatmap();
}
// ============================================
// FONCTIONS UTILITAIRES
// ============================================
// Afficher une notification
function showNotification(message, type = 'info') {
const colors = {
success: '#10b981',
error: '#ef4444',
warning: '#f59e0b',
info: '#3b82f6'
};
// Créer une notification temporaire
const notification = document.createElement('div');
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: white;
color: ${colors[type]};
padding: 1rem 1.5rem;
border-radius: 10px;
box-shadow: 0 5px 20px rgba(0,0,0,0.1);
border-left: 4px solid ${colors[type]};
z-index: 1000;
animation: fadeIn 0.3s ease;
`;
notification.innerHTML = `
<div style="display: flex; align-items: center; gap: 10px;">
<i class="fas fa-${type === 'success' ? 'check-circle' : type === 'error' ? 'exclamation-circle' : type === 'warning' ? 'exclamation-triangle' : 'info-circle'}"></i>
<div>${message}</div>
</div>
`;
document.body.appendChild(notification);
// Supprimer après 3 secondes
setTimeout(() => {
notification.style.opacity = '0';
setTimeout(() => notification.remove(), 300);
}, 3000);
}
// Charger les données sauvegardées
function loadSavedData() {
try {
// Charger le profil
const savedProfile = localStorage.getItem('learnerProfile');
if (savedProfile) {
learnerProfile = JSON.parse(savedProfile);
updateProfileProgress();
updateProfileSummary();
}
// Charger les entrées de journal
const savedJournal = localStorage.getItem('journalEntries');
if (savedJournal) {
journalEntries = JSON.parse(savedJournal);
}
} catch (error) {
console.error('Erreur lors du chargement des données:', error);
}
}
// Sauvegarder toutes les données
function saveAllData() {
try {
localStorage.setItem('learnerProfile', JSON.stringify(learnerProfile));
localStorage.setItem('journalEntries', JSON.stringify(journalEntries));
} catch (error) {
console.error('Erreur lors de la sauvegarde:', error);
}
}
// Sauvegarder automatiquement toutes les 30 secondes
setInterval(saveAllData, 30000);
// Sauvegarder aussi quand l'utilisateur quitte la page
window.addEventListener('beforeunload', saveAllData);
</script>
</body>
</html>