templates/school/roomList.html.twig line 1

Open in your IDE?
  1. {% extends 'layout/frontEndLayout.html.twig' %}
  2. {% block name %}Classrooms of Bethesda{% endblock %}
  3. {% block stylesheets %}
  4. {{ parent() }}
  5. <style>
  6. /* ── Hero Banner ──────────────────────────────────────── */
  7. .classrooms-hero {
  8. background:
  9. linear-gradient(135deg, rgba(10,22,40,0.92) 0%, rgba(17,34,68,0.78) 100%),
  10. url("{{ asset('assets/images/slider-02.jpg') }}") center / cover no-repeat;
  11. padding: 5rem 1rem 4rem;
  12. text-align: center;
  13. position: relative;
  14. overflow: hidden;
  15. }
  16. .classrooms-hero::after {
  17. content: '';
  18. position: absolute;
  19. bottom: 0; left: 0; right: 0;
  20. height: 3px;
  21. background: linear-gradient(90deg, var(--gold), var(--accent), var(--gold));
  22. }
  23. .classrooms-hero .hero-tag {
  24. font-size: 0.7rem;
  25. font-weight: 600;
  26. letter-spacing: 0.35em;
  27. text-transform: uppercase;
  28. color: var(--gold);
  29. display: inline-block;
  30. margin-bottom: 1rem;
  31. padding: 0.3rem 0.9rem;
  32. border: 1px solid rgba(201,168,76,0.35);
  33. }
  34. .classrooms-hero h1 {
  35. font-family: var(--font-display);
  36. font-size: clamp(2rem, 5vw, 3.2rem);
  37. font-weight: 900;
  38. color: var(--white);
  39. margin: 0 0 1rem;
  40. line-height: 1.15;
  41. }
  42. .classrooms-hero h1 em { font-style: italic; color: var(--gold); }
  43. .hero-meta {
  44. display: inline-flex;
  45. align-items: center;
  46. gap: 1.5rem;
  47. flex-wrap: wrap;
  48. justify-content: center;
  49. }
  50. .hero-meta-item {
  51. display: flex;
  52. align-items: center;
  53. gap: 0.5rem;
  54. font-size: 0.78rem;
  55. letter-spacing: 0.1em;
  56. text-transform: uppercase;
  57. color: rgba(255,255,255,0.5);
  58. padding: 0.3rem 0.9rem;
  59. border: 1px solid rgba(255,255,255,0.1);
  60. }
  61. .hero-meta-item i { color: var(--gold); }
  62. /* ── Section wrapper ──────────────────────────────────── */
  63. .classrooms-section {
  64. background: var(--cream);
  65. padding: 4rem 0 5rem;
  66. }
  67. /* ── Classroom Card ───────────────────────────────────── */
  68. .classroom-card {
  69. background: var(--white);
  70. border: 1px solid rgba(0,0,0,0.06);
  71. overflow: hidden;
  72. position: relative;
  73. margin-bottom: 1.75rem;
  74. transition: transform 0.32s ease, box-shadow 0.32s ease;
  75. display: flex;
  76. flex-direction: column;
  77. }
  78. .classroom-card::before {
  79. content: '';
  80. position: absolute;
  81. top: 0; left: 0; right: 0;
  82. height: 3px;
  83. background: linear-gradient(90deg, var(--gold), var(--accent));
  84. transform: scaleX(0);
  85. transition: transform 0.32s ease;
  86. }
  87. .classroom-card:hover {
  88. transform: translateY(-6px);
  89. box-shadow: 0 20px 48px rgba(10,22,40,0.11);
  90. }
  91. .classroom-card:hover::before { transform: scaleX(1); }
  92. /* Teacher photo header */
  93. .classroom-img-wrap {
  94. position: relative;
  95. height: 160px;
  96. overflow: hidden;
  97. background: var(--navy);
  98. }
  99. .classroom-img-wrap img {
  100. width: 100%;
  101. height: 100%;
  102. object-fit: cover;
  103. object-position: top;
  104. transition: transform 0.42s ease, filter 0.42s ease;
  105. filter: brightness(0.85);
  106. }
  107. .classroom-card:hover .classroom-img-wrap img {
  108. transform: scale(1.05);
  109. filter: brightness(0.7);
  110. }
  111. /* Class name badge over image */
  112. .classroom-name-badge {
  113. position: absolute;
  114. bottom: 0; left: 0; right: 0;
  115. padding: 1.5rem 1rem 0.85rem;
  116. background: linear-gradient(to top, rgba(10,22,40,0.92), transparent);
  117. }
  118. .classroom-name-badge h2 {
  119. font-family: var(--font-display);
  120. font-size: 1.2rem;
  121. font-weight: 700;
  122. color: var(--white);
  123. margin: 0;
  124. line-height: 1.2;
  125. }
  126. .classroom-name-badge h2 a {
  127. color: inherit;
  128. text-decoration: none;
  129. transition: color 0.25s;
  130. }
  131. .classroom-name-badge h2 a:hover { color: var(--gold); }
  132. /* APC exam results block */
  133. .exam-block {
  134. padding: 0 1rem;
  135. flex: 1;
  136. }
  137. .exam-block-header {
  138. display: flex;
  139. align-items: center;
  140. justify-content: space-between;
  141. padding: 0.9rem 0 0.6rem;
  142. border-bottom: 1px solid rgba(0,0,0,0.06);
  143. margin-bottom: 0.6rem;
  144. }
  145. .exam-block-label {
  146. font-size: 0.68rem;
  147. font-weight: 600;
  148. letter-spacing: 0.18em;
  149. text-transform: uppercase;
  150. color: var(--text-muted);
  151. }
  152. .exam-success-rate {
  153. font-family: var(--font-display);
  154. font-size: 1.4rem;
  155. font-weight: 700;
  156. color: var(--gold);
  157. line-height: 1;
  158. }
  159. /* Student list */
  160. .student-list {
  161. list-style: none;
  162. padding: 0;
  163. margin: 0 0 0.75rem;
  164. max-height: 260px;
  165. overflow-y: auto;
  166. scrollbar-width: thin;
  167. scrollbar-color: var(--gold-light) transparent;
  168. }
  169. .student-list::-webkit-scrollbar { width: 4px; }
  170. .student-list::-webkit-scrollbar-thumb { background: var(--gold-light); }
  171. .student-row {
  172. display: grid;
  173. grid-template-columns: 36px 1fr auto;
  174. align-items: center;
  175. gap: 0.65rem;
  176. padding: 0.55rem 0;
  177. border-bottom: 1px solid rgba(0,0,0,0.04);
  178. }
  179. .student-row:last-child { border-bottom: none; }
  180. .student-avatar {
  181. width: 36px;
  182. height: 36px;
  183. border-radius: 50%;
  184. object-fit: cover;
  185. border: 1px solid rgba(201,168,76,0.25);
  186. }
  187. .student-name {
  188. font-size: 0.82rem;
  189. font-weight: 500;
  190. color: var(--navy);
  191. white-space: nowrap;
  192. overflow: hidden;
  193. text-overflow: ellipsis;
  194. }
  195. .student-result {
  196. font-size: 0.72rem;
  197. font-weight: 600;
  198. padding: 0.2rem 0.55rem;
  199. text-transform: capitalize;
  200. white-space: nowrap;
  201. }
  202. .student-result.success {
  203. background: rgba(29,138,110,0.1);
  204. color: #1D8A6E;
  205. }
  206. .student-result.fail {
  207. background: rgba(217,83,79,0.1);
  208. color: var(--danger);
  209. }
  210. .student-result.pending {
  211. background: rgba(201,168,76,0.1);
  212. color: #9A7A2A;
  213. }
  214. /* Card footer */
  215. .classroom-card-footer {
  216. display: flex;
  217. align-items: center;
  218. justify-content: space-between;
  219. padding: 0.85rem 1rem;
  220. background: rgba(10,22,40,0.03);
  221. border-top: 1px solid rgba(0,0,0,0.05);
  222. margin-top: auto;
  223. }
  224. .classroom-meta-item {
  225. display: flex;
  226. align-items: center;
  227. gap: 0.45rem;
  228. font-size: 0.75rem;
  229. color: var(--text-muted);
  230. font-weight: 500;
  231. }
  232. .classroom-meta-item i { color: var(--gold); font-size: 0.78rem; }
  233. /* ── Pagination ───────────────────────────────────────── */
  234. .pagination-wrap {
  235. display: flex;
  236. justify-content: center;
  237. padding: 2.5rem 0 0;
  238. }
  239. .pagination-wrap .pagination .page-item .page-link {
  240. border: 1px solid rgba(0,0,0,0.1);
  241. color: var(--navy);
  242. font-size: 0.85rem;
  243. padding: 0.55rem 0.95rem;
  244. border-radius: 0 !important;
  245. transition: all 0.25s;
  246. }
  247. .pagination-wrap .pagination .page-item.active .page-link,
  248. .pagination-wrap .pagination .page-item .page-link:hover {
  249. background: var(--gold);
  250. border-color: var(--gold);
  251. color: var(--navy);
  252. font-weight: 700;
  253. }
  254. /* ── Empty state ──────────────────────────────────────── */
  255. .empty-state {
  256. text-align: center;
  257. padding: 5rem 2rem;
  258. }
  259. .empty-icon {
  260. width: 72px;
  261. height: 72px;
  262. border: 2px solid rgba(201,168,76,0.3);
  263. display: inline-flex;
  264. align-items: center;
  265. justify-content: center;
  266. color: var(--gold);
  267. font-size: 1.8rem;
  268. margin-bottom: 1.5rem;
  269. }
  270. .empty-state h2 {
  271. font-family: var(--font-display);
  272. font-size: 1.6rem;
  273. color: var(--navy);
  274. margin-bottom: 0.75rem;
  275. }
  276. .empty-state p {
  277. color: var(--text-muted);
  278. font-size: 0.95rem;
  279. margin-bottom: 1.8rem;
  280. }
  281. </style>
  282. {% endblock %}
  283. {% block body %}
  284. {# ── Hero Banner ──────────────────────────────────────────── #}
  285. <div class="classrooms-hero">
  286. <span class="hero-tag">{{ french_school_name }}</span>
  287. <h1>
  288. Liste des <em>Classes</em><br>
  289. &amp; Résultats aux examens officiels
  290. </h1>
  291. <div class="hero-meta">
  292. <div class="hero-meta-item">
  293. <i class="fa fa-calendar"></i>
  294. Session {{ year.code ?? '2022-2023' }}
  295. </div>
  296. {% if rooms|length > 0 %}
  297. <div class="hero-meta-item">
  298. <i class="fa fa-door-open"></i>
  299. {{ rooms|length }} {{ rooms|length > 1 ? 'classes' : 'classe' }}
  300. </div>
  301. {% endif %}
  302. </div>
  303. </div>
  304. {# ── Classrooms Grid ──────────────────────────────────────── #}
  305. {% if rooms|length > 0 %}
  306. <section class="classrooms-section" id="overviews">
  307. <div class="container">
  308. {# Section header #}
  309. <div class="section-header" style="padding-top:0; padding-bottom:2.5rem;">
  310. <span class="section-tag">Résultats officiels</span>
  311. <h2 class="section-title">
  312. Nos classes &amp; <em>performances</em>
  313. </h2>
  314. <div class="section-divider"></div>
  315. <p class="section-sub">
  316. Résultats détaillés par classe pour la session officielle {{ year.code ?? '2022-2023' }}.
  317. </p>
  318. </div>
  319. {% for row in rooms|batch(3) %}
  320. <div class="row">
  321. {% for room in row %}
  322. {# ── Pre-compute stats ── #}
  323. {% set success = 0 %}
  324. {% set candidats = 0 %}
  325. {% if room.apc %}
  326. {% for sub in subscriptions %}
  327. {% if sub.classRoom.id == room.id %}
  328. {% set candidats = candidats + 1 %}
  329. {% if sub.officialExamResult != "0" %}
  330. {% set success = success + 1 %}
  331. {% endif %}
  332. {% endif %}
  333. {% endfor %}
  334. {% endif %}
  335. <div class="col-lg-4 col-md-6 col-12">
  336. <div class="classroom-card">
  337. {# ── Teacher photo + class name ── #}
  338. <div class="classroom-img-wrap">
  339. {% if room.id in mainTeachersMap|keys %}
  340. <img src="{{ mainTeachersMap[room.id].avatar(300) }}"
  341. alt="{{ room.name }}" loading="lazy">
  342. {% else %}
  343. <img src="{{ asset('assets/images/teacher_default.png') }}"
  344. alt="{{ room.name }}" loading="lazy">
  345. {% endif %}
  346. <div class="classroom-name-badge">
  347. <h2><a href="#">{{ room.name }}</a></h2>
  348. </div>
  349. </div>
  350. {# ── APC exam results ── #}
  351. {% if room.apc and candidats > 0 %}
  352. <div class="exam-block">
  353. <div class="exam-block-header">
  354. <span class="exam-block-label">Résultats examen officiel</span>
  355. <span class="exam-success-rate">
  356. {{ (100 * success / candidats)|round(1, 'floor') }}%
  357. </span>
  358. </div>
  359. <ul class="student-list">
  360. {% for sub in subscriptions %}
  361. {% if sub.classRoom.id == room.id %}
  362. {% set resultLower = sub.verbalOfficialExamResult|lower %}
  363. {% set resultClass = 'pending' %}
  364. {% if sub.officialExamResult != "0" %}
  365. {% set resultClass = 'success' %}
  366. {% elseif sub.officialExamResult == "0" and sub.verbalOfficialExamResult %}
  367. {% set resultClass = 'fail' %}
  368. {% endif %}
  369. <li class="student-row">
  370. <img class="student-avatar"
  371. src="{{ sub.student.imageName
  372. ? asset('assets/images/student/' ~ sub.student.imageName)
  373. : (sub.student.gender
  374. ? asset('assets/images/student/female-default-avatar.jpg')
  375. : asset('assets/images/student/male-default-avatar.jpg'))
  376. }}"
  377. alt="{{ sub.student.lastname }}"
  378. loading="lazy">
  379. <span class="student-name">
  380. {{ sub.student.lastname|title }}
  381. {{ sub.student.firstname|title }}
  382. </span>
  383. <span class="student-result {{ resultClass }}">
  384. {{ resultLower ?: '—' }}
  385. </span>
  386. </li>
  387. {% endif %}
  388. {% endfor %}
  389. </ul>
  390. </div>
  391. {% endif %}
  392. {# ── Card footer ── #}
  393. <div class="classroom-card-footer">
  394. <span class="classroom-meta-item">
  395. <i class="fa fa-book"></i>
  396. {{ room.modules|length }}
  397. {{ room.modules|length > 1 ? 'modules' : 'module' }}
  398. </span>
  399. {% if room.apc and candidats > 0 %}
  400. <span class="classroom-meta-item">
  401. <i class="fa fa-users"></i>
  402. {{ candidats }}
  403. {{ candidats > 1 ? 'candidats' : 'candidat' }}
  404. </span>
  405. <span class="classroom-meta-item">
  406. <i class="fa fa-check-circle"></i>
  407. {{ success }} reçu{{ success > 1 ? 's' : '' }}
  408. </span>
  409. {% endif %}
  410. </div>
  411. </div>{# end classroom-card #}
  412. </div>
  413. {% endfor %}
  414. </div>{# end row #}
  415. {% endfor %}
  416. {# ── Pagination ── #}
  417. <div class="pagination-wrap">
  418. {{ knp_pagination_render(rooms) }}
  419. </div>
  420. </div>{# end container #}
  421. </section>
  422. {% else %}
  423. {# ── Empty state ── #}
  424. <section class="classrooms-section">
  425. <div class="container">
  426. <div class="empty-state">
  427. <div class="empty-icon">
  428. <i class="fa fa-building"></i>
  429. </div>
  430. <h2>Aucune classe pour le moment</h2>
  431. <p>Les salles de classe n'ont pas encore été configurées.</p>
  432. {% if is_granted("IS_AUTHENTICATED_REMEMBERED") %}
  433. <a href="{{ path('admin_classrooms_new') }}" class="btn-gold">
  434. <i class="fa fa-plus"></i>&nbsp; Créer la première classe
  435. </a>
  436. {% endif %}
  437. </div>
  438. </div>
  439. </section>
  440. {% endif %}
  441. {% endblock %}