{% extends 'layout/frontEndLayout.html.twig' %}
{% block name %}
Welcome to LiveEdu
{% endblock %}
{% block stylesheets %}
{{ parent() }}
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700;900&family=DM+Sans:wght@300;400;500;600&display=swap" rel="stylesheet">
<style>
:root {
--gold: #C9A84C;
--gold-light: #E8D5A3;
--navy: #0A1628;
--navy-mid: #112244;
--white: #FAFAF8;
--cream: #F5F0E8;
--text-muted: #8A8A8A;
--accent: #2C6BAD;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'DM Sans', sans-serif;
background: var(--white);
color: var(--navy);
}
/* ─── HERO SLIDER ─────────────────────────────────────── */
.hero-slider {
position: relative;
height: 100vh;
min-height: 600px;
overflow: hidden;
}
.carousel-item-custom {
position: absolute;
inset: 0;
opacity: 0;
transition: opacity 1s ease;
background-size: cover;
background-position: center;
}
.carousel-item-custom.active { opacity: 1; }
.hero-overlay {
position: absolute;
inset: 0;
background: linear-gradient(
135deg,
rgba(10,22,40,0.85) 0%,
rgba(17,34,68,0.60) 60%,
rgba(201,168,76,0.15) 100%
);
}
.hero-content {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
justify-content: center;
padding: 0 8vw;
max-width: 900px;
}
.hero-label {
font-family: 'DM Sans', sans-serif;
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.35em;
text-transform: uppercase;
color: var(--gold);
margin-bottom: 1.5rem;
opacity: 0;
transform: translateY(20px);
animation: fadeUp 0.8s ease 0.3s forwards;
}
.hero-title {
font-family: 'Playfair Display', serif;
font-size: clamp(2.5rem, 6vw, 5rem);
font-weight: 900;
line-height: 1.1;
color: var(--white);
margin-bottom: 1.5rem;
opacity: 0;
transform: translateY(30px);
animation: fadeUp 0.9s ease 0.5s forwards;
}
.hero-title em {
font-style: italic;
color: var(--gold);
}
.hero-sub {
font-size: 1.1rem;
font-weight: 300;
color: rgba(255,255,255,0.75);
max-width: 480px;
line-height: 1.7;
opacity: 0;
transform: translateY(20px);
animation: fadeUp 0.9s ease 0.7s forwards;
}
.hero-cta {
margin-top: 2.5rem;
display: flex;
gap: 1rem;
opacity: 0;
animation: fadeUp 0.9s ease 0.9s forwards;
}
.btn-gold {
padding: 0.85rem 2rem;
background: var(--gold);
color: var(--navy);
font-weight: 600;
font-size: 0.9rem;
letter-spacing: 0.05em;
border: none;
cursor: pointer;
text-decoration: none;
transition: all 0.3s ease;
}
.btn-gold:hover { background: var(--gold-light); transform: translateY(-2px); }
.btn-outline-white {
padding: 0.85rem 2rem;
background: transparent;
color: var(--white);
font-weight: 500;
font-size: 0.9rem;
letter-spacing: 0.05em;
border: 1px solid rgba(255,255,255,0.4);
cursor: pointer;
text-decoration: none;
transition: all 0.3s ease;
}
.btn-outline-white:hover { border-color: var(--gold); color: var(--gold); }
/* Slider decorative bar */
.hero-bar {
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 6px;
background: var(--gold);
}
/* Slide counter */
.slide-counter {
position: absolute;
bottom: 2.5rem;
right: 3rem;
color: rgba(255,255,255,0.5);
font-size: 0.8rem;
letter-spacing: 0.2em;
font-weight: 500;
}
.slide-counter span { color: var(--gold); font-size: 1.1rem; }
/* Carousel indicators */
.hero-indicators {
position: absolute;
bottom: 2.5rem;
left: 8vw;
display: flex;
gap: 0.6rem;
list-style: none;
}
.hero-indicators li {
width: 28px;
height: 2px;
background: rgba(255,255,255,0.3);
cursor: pointer;
transition: all 0.3s;
}
.hero-indicators li.active {
width: 52px;
background: var(--gold);
}
/* Carousel controls */
.hero-prev, .hero-next {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 52px;
height: 52px;
border: 1px solid rgba(255,255,255,0.25);
background: rgba(10,22,40,0.4);
backdrop-filter: blur(8px);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.1rem;
cursor: pointer;
transition: all 0.3s;
text-decoration: none;
z-index: 10;
}
.hero-prev { left: 2rem; }
.hero-next { right: 2rem; }
.hero-prev:hover, .hero-next:hover {
background: var(--gold);
border-color: var(--gold);
color: var(--navy);
}
@keyframes fadeUp {
to { opacity: 1; transform: translateY(0); }
}
/* ─── STATS BAR ──────────────────────────────────────── */
.stats-bar {
background: var(--navy);
padding: 0;
display: grid;
grid-template-columns: repeat(4, 1fr);
}
.stat-item {
padding: 2rem 1.5rem;
text-align: center;
border-right: 1px solid rgba(255,255,255,0.06);
transition: background 0.3s;
}
.stat-item:last-child { border-right: none; }
.stat-item:hover { background: rgba(201,168,76,0.08); }
.stat-num {
font-family: 'Playfair Display', serif;
font-size: 2rem;
font-weight: 700;
color: var(--gold);
display: block;
}
.stat-label {
font-size: 0.75rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: rgba(255,255,255,0.45);
margin-top: 0.3rem;
}
/* ─── SECTION HEADING ────────────────────────────────── */
.section-header {
text-align: center;
padding: 5rem 2rem 3rem;
}
.section-tag {
display: inline-block;
font-size: 0.7rem;
font-weight: 600;
letter-spacing: 0.35em;
text-transform: uppercase;
color: var(--gold);
margin-bottom: 1rem;
padding: 0.35rem 1rem;
border: 1px solid var(--gold-light);
background: rgba(201,168,76,0.06);
}
.section-title {
font-family: 'Playfair Display', serif;
font-size: clamp(1.8rem, 4vw, 2.8rem);
font-weight: 700;
color: var(--navy);
line-height: 1.2;
}
.section-title em {
font-style: italic;
color: var(--accent);
}
.section-divider {
width: 60px;
height: 3px;
background: var(--gold);
margin: 1.5rem auto 0;
}
.section-sub {
max-width: 520px;
margin: 1.2rem auto 0;
color: var(--text-muted);
font-size: 0.95rem;
line-height: 1.7;
}
/* ─── CHARTS SECTION ─────────────────────────────────── */
.charts-section {
background: var(--cream);
padding-bottom: 5rem;
}
.charts-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 1.5rem;
padding: 0 4vw 2rem;
max-width: 1400px;
margin: 0 auto;
}
.chart-card {
background: var(--white);
border: 1px solid rgba(0,0,0,0.06);
padding: 1.5rem 1rem 1.25rem;
text-align: center;
transition: all 0.35s ease;
position: relative;
overflow: hidden;
}
.chart-card::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0;
height: 3px;
background: linear-gradient(90deg, var(--gold), var(--accent));
transform: scaleX(0);
transition: transform 0.35s ease;
}
.chart-card:hover {
transform: translateY(-6px);
box-shadow: 0 20px 48px rgba(10,22,40,0.10);
}
.chart-card:hover::before { transform: scaleX(1); }
.chart-card canvas {
max-width: 180px;
margin: 0 auto;
display: block;
}
/* ─── FOOTER ACCENT ──────────────────────────────────── */
.page-footer-accent {
background: var(--navy);
text-align: center;
padding: 2rem;
color: rgba(255,255,255,0.35);
font-size: 0.8rem;
letter-spacing: 0.1em;
}
.page-footer-accent span { color: var(--gold); }
/* ─── RESPONSIVE ─────────────────────────────────────── */
@media (max-width: 768px) {
.stats-bar { grid-template-columns: repeat(2, 1fr); }
.hero-content { padding: 0 5vw; }
.hero-prev { left: 0.75rem; }
.hero-next { right: 0.75rem; }
}
@media (max-width: 480px) {
.stats-bar { grid-template-columns: 1fr 1fr; }
.charts-grid { grid-template-columns: 1fr 1fr; gap: 1rem; }
}
</style>
{% endblock %}
{% block body %}
{# ── HERO CAROUSEL ────────────────────────────────────────── #}
<div id="heroCarousel" class="hero-slider">
{# Slide 1 #}
<div class="carousel-item-custom active"
style="background-image:url({{ asset('assets/images/slider-01.jpg') }});">
<div class="hero-overlay"></div>
<div class="hero-content">
<p class="hero-label">Excellence · Innovation · Bilingual Education</p>
<h1 class="hero-title">
{{ french_school_name }}<br>
<em>{{ english_school_name }}</em>
</h1>
<p class="hero-sub">{{ french_slogan }} · {{ english_slogan }}</p>
<div class="hero-cta">
<a href="#officialExams" class="btn-gold">Voir les résultats</a>
<a href="#" class="btn-outline-white">En savoir plus</a>
</div>
</div>
</div>
{# Slide 2 #}
<div class="carousel-item-custom"
style="background-image:url({{ asset('assets/images/slider-02.jpg') }});">
<div class="hero-overlay"></div>
<div class="hero-content">
<p class="hero-label">Digital · Connected · Modern</p>
<h1 class="hero-title">
<em>LiveEdu</em><br>
Software Online Services
</h1>
<p class="hero-sub">A complete digital ecosystem built for educators, students, and administrators.</p>
<div class="hero-cta">
<a href="#" class="btn-gold">Découvrir la plateforme</a>
</div>
</div>
</div>
{# Slide 3 #}
<div class="carousel-item-custom"
style="background-image:url({{ asset('assets/images/slide_04.PNG') }});">
<div class="hero-overlay"></div>
<div class="hero-content">
<p class="hero-label">Transparency · Quality · Trust</p>
<h1 class="hero-title">
<em>{{ english_school_name }}</em><br>
{{ english_slogan }}
</h1>
<p class="hero-sub">Real-time data, open reporting and trusted results — for every student, every year.</p>
<div class="hero-cta">
<a href="#officialExams" class="btn-gold">Voir les statistiques</a>
</div>
</div>
</div>
{# Decorative bar #}
<div class="hero-bar"></div>
{# Indicators #}
<ol class="hero-indicators" id="heroIndicators">
<li class="active" data-slide="0"></li>
<li data-slide="1"></li>
<li data-slide="2"></li>
</ol>
{# Slide counter #}
<div class="slide-counter">
<span id="slideNum">01</span> / 03
</div>
{# Controls #}
<a class="hero-prev" id="heroPrev" href="#">
<i class="fa fa-angle-left"></i>
</a>
<a class="hero-next" id="heroNext" href="#">
<i class="fa fa-angle-right"></i>
</a>
</div>
{# ── STATS BAR ─────────────────────────────────────────────── #}
<div class="stats-bar">
<div class="stat-item">
<span class="stat-num">98%</span>
<span class="stat-label">Taux d'admission</span>
</div>
<div class="stat-item">
<span class="stat-num">400+</span>
<span class="stat-label">Élèves inscrits</span>
</div>
<div class="stat-item">
<span class="stat-num">50+</span>
<span class="stat-label">Enseignants qualifiés</span>
</div>
<div class="stat-item">
<span class="stat-num">{{ year.code }}</span>
<span class="stat-label">Année académique</span>
</div>
</div>
{# ── EXAM RESULTS SECTION ─────────────────────────────────── #}
<section class="charts-section" id="officialExams">
<div class="section-header">
<span class="section-tag">Résultats officiels</span>
<h2 class="section-title">
Taux de réussite aux examens<br>
session <em>{{ year.code }}</em>
</h2>
<div class="section-divider"></div>
<p class="section-sub">
Statistiques détaillées par série et par niveau pour la session officielle en cours.
</p>
</div>
<div class="charts-grid">
{% for key in results|keys %}
<div class="chart-card">
<canvas id="{{ key }}" height="160"
data-exam-objects="{{ results[key] }}"></canvas>
</div>
{% endfor %}
</div>
</section>
{# ── FOOTER ACCENT ─────────────────────────────────────────── #}
<div class="page-footer-accent">
Propulsé par <span>LiveEdu</span> · Tous droits réservés {{ "now"|date("Y") }}
</div>
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script>
/* ── Custom Carousel ───────────────────────────────────────── */
(function () {
const slides = document.querySelectorAll('.carousel-item-custom');
const indicators = document.querySelectorAll('#heroIndicators li');
const slideNum = document.getElementById('slideNum');
let current = 0, timer;
function goTo(n) {
slides[current].classList.remove('active');
indicators[current].classList.remove('active');
current = (n + slides.length) % slides.length;
slides[current].classList.add('active');
indicators[current].classList.add('active');
slideNum.textContent = String(current + 1).padStart(2, '0');
}
function autoPlay() { timer = setInterval(() => goTo(current + 1), 5500); }
function resetTimer() { clearInterval(timer); autoPlay(); }
document.getElementById('heroPrev').addEventListener('click', e => {
e.preventDefault(); goTo(current - 1); resetTimer();
});
document.getElementById('heroNext').addEventListener('click', e => {
e.preventDefault(); goTo(current + 1); resetTimer();
});
indicators.forEach(li => {
li.addEventListener('click', () => { goTo(+li.dataset.slide); resetTimer(); });
});
autoPlay();
})();
/* ── Charts ─────────────────────────────────────────────────── */
const palette = [
'#C9A84C','#2C6BAD','#1D8A6E','#D9534F',
'#7B5EA7','#F0A500','#2E86AB','#A23B72'
];
const randomColor = (type, idx) =>
type === 'ECHEC' ? '#D9534F' : palette[idx % palette.length];
const drawCanvas = (examData, canvasId, name) => {
const el = document.getElementById(canvasId);
if (!el || !examData) return;
const parsed = JSON.parse(examData);
const values = parsed.mentionCountCategories.map(Number);
const colors = parsed.mentionCategories.map((cat, i) => randomColor(cat, i));
new Chart(el, {
type: 'doughnut',
data: {
labels: parsed.mentionCategories,
datasets: [{ data: values, backgroundColor: colors, borderWidth: 0 }]
},
options: {
cutout: '68%',
animation: { animateRotate: true, duration: 1000 },
plugins: {
legend: { display: false },
title: {
display: true,
text: name,
color: '#0A1628',
font: { size: 13, family: "'DM Sans', sans-serif", weight: '600' },
position: 'bottom',
padding: { top: 14 }
}
}
}
});
};
{% for key in results|keys %}
drawCanvas(
document.getElementById('{{ key }}')?.dataset?.examObjects,
'{{ key }}',
'{{ key|replace({'_': ' '})|title }}'
);
{% endfor %}
</script>
{% endblock javascripts %}