96 lines
15 KiB
PHP
96 lines
15 KiB
PHP
@extends('layouts.vitrine')
|
||
|
||
@section('titre', 'Bibliothèque')
|
||
|
||
@section('contenu')
|
||
<section class="border-b-4 border-black bg-white">
|
||
<div class="mx-auto max-w-7xl px-5 pb-12 pt-12 lg:px-10">
|
||
<p class="inline-block -rotate-2 border-2 border-black bg-[#C4B5FD] px-3 py-1 text-sm font-extrabold uppercase tracking-wider shadow-[4px_4px_0px_#000000]">Bibliothèque du prof</p>
|
||
<h1 class="mt-6 max-w-5xl text-6xl font-black leading-[0.9] tracking-tighter sm:text-7xl">Tout le référentiel, fiche par fiche.</h1>
|
||
<p class="mt-6 max-w-3xl text-xl font-medium leading-relaxed">Du SNT au master, en passant par l’école d’ingénieurs. Chaque fiche regroupe cours, quiz, TD, labs et examens. Un même chapitre sert plusieurs formations : OSPF compte pour la NSI, le BTS SIO, le BTS CIEL, le BUT R&T et les titres pro.</p>
|
||
<dl id="stats" class="mt-10 grid max-w-4xl grid-cols-2 border-4 border-black sm:grid-cols-5"></dl>
|
||
<div class="mt-6 max-w-4xl border-4 border-black bg-[#7CF2C0] p-4 text-sm font-bold shadow-[4px_4px_0px_#000000]"><p>Construit à partir des programmes officiels. Vérifié le 29 septembre 2026 :</p><ul class="mt-2 flex flex-wrap gap-x-5 gap-y-1 underline underline-offset-4"><li><a href="https://www.legifrance.gouv.fr/jorf/id/JORFTEXT000049926463" target="_blank" rel="noopener">BTS SIO · arrêté du 8 juillet 2024 (épreuves E5, E6, E7)</a></li><li><a href="https://www.francecompetences.fr/recherche/rncp/37391/" target="_blank" rel="noopener">BTS CIEL · RNCP37391, arrêté du 25 janvier 2023</a></li><li><a href="https://www.onisep.fr/ressources/univers-formation/formations/post-bac/but-reseaux-et-telecommunications-parcours-cybersecurite" target="_blank" rel="noopener">BUT R&T · 5 parcours (Onisep)</a></li></ul></div>
|
||
</div>
|
||
</section>
|
||
<div class="sticky top-0 z-20 border-b-4 border-black bg-white">
|
||
<div class="mx-auto flex max-w-7xl flex-wrap items-center gap-3 px-5 py-3 lg:px-10">
|
||
<div class="flex border-4 border-black font-extrabold" role="tablist">
|
||
<button type="button" data-vue="themes" aria-selected="true" class="px-4 py-2 aria-selected:bg-black aria-selected:text-white">Par thème</button>
|
||
<button type="button" data-vue="formations" aria-selected="false" class="border-l-4 border-black px-4 py-2 aria-selected:bg-black aria-selected:text-white">Par formation</button>
|
||
<button type="button" data-vue="examens" aria-selected="false" class="border-l-4 border-black px-4 py-2 aria-selected:bg-black aria-selected:text-white">Examens</button>
|
||
</div>
|
||
<input id="b-recherche" class="min-w-[200px] flex-1 border-4 border-black px-3 py-2 font-semibold focus:bg-[#FFFBEA] focus:outline-none" placeholder="Rechercher : OSPF, chmod, RSA…" aria-label="Rechercher">
|
||
<select id="b-theme" class="border-4 border-black px-3 py-2 font-bold" aria-label="Thème"><option value="">Tous les thèmes</option></select>
|
||
<label class="flex items-center gap-2 font-bold"><input id="b-vm" type="checkbox" class="h-5 w-5 accent-black"> Masquer hors VM</label>
|
||
<p class="ml-auto border-4 border-black bg-[#7CF2C0] px-3 py-2 font-extrabold">Ma séquence : <span id="b-seq">0</span></p>
|
||
</div>
|
||
<div class="mx-auto flex max-w-7xl flex-wrap gap-2 px-5 pb-3 lg:px-10" role="group" aria-label="Activités">
|
||
<button type="button" data-tag="C" aria-pressed="false" class="border-2 border-black bg-white px-2 py-0.5 font-mono text-xs font-semibold aria-pressed:outline aria-pressed:outline-4 aria-pressed:outline-offset-1 aria-pressed:outline-black">C · Cours</button>
|
||
<button type="button" data-tag="Q" aria-pressed="false" class="border-2 border-black bg-[#FFD23F] px-2 py-0.5 font-mono text-xs font-semibold aria-pressed:outline aria-pressed:outline-4 aria-pressed:outline-offset-1 aria-pressed:outline-black">Q · Quiz</button>
|
||
<button type="button" data-tag="TD" aria-pressed="false" class="border-2 border-black bg-[#C4B5FD] px-2 py-0.5 font-mono text-xs font-semibold aria-pressed:outline aria-pressed:outline-4 aria-pressed:outline-offset-1 aria-pressed:outline-black">TD · TD</button>
|
||
<button type="button" data-tag="LAB" aria-pressed="false" class="border-2 border-black bg-[#7CF2C0] px-2 py-0.5 font-mono text-xs font-semibold aria-pressed:outline aria-pressed:outline-4 aria-pressed:outline-offset-1 aria-pressed:outline-black">LAB · TP sur VM</button>
|
||
<button type="button" data-tag="LAB+" aria-pressed="false" class="border-2 border-black bg-[#7CF2C0] px-2 py-0.5 font-mono text-xs font-semibold aria-pressed:outline aria-pressed:outline-4 aria-pressed:outline-offset-1 aria-pressed:outline-black">LAB+ · Lab multi-VM</button>
|
||
<button type="button" data-tag="IDE" aria-pressed="false" class="border-2 border-black bg-[#13233A] text-white px-2 py-0.5 font-mono text-xs font-semibold aria-pressed:outline aria-pressed:outline-4 aria-pressed:outline-offset-1 aria-pressed:outline-black">IDE · IDE</button>
|
||
<button type="button" data-tag="GEN" aria-pressed="false" class="border-2 border-black bg-[#FF6FB5] px-2 py-0.5 font-mono text-xs font-semibold aria-pressed:outline aria-pressed:outline-4 aria-pressed:outline-offset-1 aria-pressed:outline-black">GEN · Générateur</button>
|
||
<button type="button" data-tag="EXAM" aria-pressed="false" class="border-2 border-black bg-[#ec3013] text-white px-2 py-0.5 font-mono text-xs font-semibold aria-pressed:outline aria-pressed:outline-4 aria-pressed:outline-offset-1 aria-pressed:outline-black">EXAM · Examen</button>
|
||
<button type="button" data-tag="PROJ" aria-pressed="false" class="border-2 border-black bg-white px-2 py-0.5 font-mono text-xs font-semibold aria-pressed:outline aria-pressed:outline-4 aria-pressed:outline-offset-1 aria-pressed:outline-black">PROJ · Projet</button>
|
||
<button type="button" data-tag="CTF" aria-pressed="false" class="border-2 border-black bg-black text-white px-2 py-0.5 font-mono text-xs font-semibold aria-pressed:outline aria-pressed:outline-4 aria-pressed:outline-offset-1 aria-pressed:outline-black">CTF · CTF</button>
|
||
</div>
|
||
</div>
|
||
<div id="b-contenu" class="mx-auto max-w-7xl px-5 py-12 lg:px-10" data-url-cours="{{ route('cours.show') }}" data-url-ide="{{ route('ide') }}" data-url-lab="{{ route('labs.essai') }}" data-url-gen="{{ route('generateur') }}" data-url-exam="{{ route('examen') }}" data-url-banque="{{ route('banque') }}"></div>
|
||
<script src="{{ asset('js/referentiel.js') }}"></script>
|
||
<script>
|
||
(function () {
|
||
var R = window.REFERENTIEL, box = document.getElementById('b-contenu'), vue = 'themes', seq = 0, actifs = [];
|
||
var BG = {"C":"bg-white","Q":"bg-[#FFD23F]","TD":"bg-[#C4B5FD]","LAB":"bg-[#7CF2C0]","LAB+":"bg-[#7CF2C0]","IDE":"bg-[#13233A] text-white","GEN":"bg-[#FF6FB5]","EXAM":"bg-[#ec3013] text-white","PROJ":"bg-white","CTF":"bg-black text-white"}; BG.HV = 'bg-white border-dashed';
|
||
var U = box.dataset;
|
||
var esc = function (s) { return String(s).replace(/&/g, '&').replace(/</g, '<'); };
|
||
var badges = function (tags) { return tags.split(' ').map(function (t) { return '<span class="border-2 border-black ' + (BG[t] || 'bg-white') + ' px-1.5 font-mono text-[11px] font-semibold">' + (t === 'HV' ? 'hors VM' : t) + '</span>'; }).join(''); };
|
||
var lien = function (tags) { var t = tags.split(' '); return t.indexOf('IDE') > -1 ? U.urlIde : t.indexOf('GEN') > -1 ? U.urlGen : (t.indexOf('LAB') > -1 || t.indexOf('LAB+') > -1) ? U.urlLab : t.indexOf('EXAM') > -1 ? U.urlExam : U.urlCours; };
|
||
var tous = []; R.themes.forEach(function (th) { th.items.forEach(function (it, i) { tous.push({ code: th.code + '-' + (i + 1), theme: th.code, t: it[0], tags: it[1] }); }); });
|
||
var nb = function (tag) { return tous.filter(function (f) { return f.tags.split(' ').indexOf(tag) > -1; }).length; };
|
||
document.getElementById('stats').innerHTML = [['Fiches', tous.length, 'bg-white'], ['Quiz', nb('Q'), 'bg-[#FFD23F]'], ['Labs', nb('LAB') + nb('LAB+'), 'bg-[#7CF2C0]'], ['Formations', R.formations.length, 'bg-[#C4B5FD]'], ['Examens', R.examens.length + nb('EXAM'), 'bg-[#FF6FB5]']].map(function (s, i) { return '<div class="' + (i ? 'border-l-4 ' : '') + 'border-black ' + s[2] + ' p-4"><dt class="font-mono text-sm font-semibold">' + s[0] + '</dt><dd class="text-4xl font-black">' + s[1] + '</dd></div>'; }).join('');
|
||
var sel = document.getElementById('b-theme'); R.themes.forEach(function (th) { var o = document.createElement('option'); o.value = th.code; o.textContent = th.code + ' · ' + th.nom; sel.appendChild(o); });
|
||
function garde(t, tags) {
|
||
var q = document.getElementById('b-recherche').value.toLowerCase(), tg = tags.split(' ');
|
||
if (q && t.toLowerCase().indexOf(q) === -1) return false;
|
||
if (document.getElementById('b-vm').checked && tg.indexOf('HV') > -1) return false;
|
||
return actifs.every(function (a) { return tg.indexOf(a) > -1; });
|
||
}
|
||
function carte(code, t, tags, sous) {
|
||
return '<li class="flex flex-col gap-3 border-4 border-black bg-white p-4 shadow-[5px_5px_0px_#000000]"><div class="flex items-start justify-between gap-2"><span class="border-2 border-black bg-black px-1.5 font-mono text-xs font-semibold text-white">' + code + '</span>' + (sous ? '<span class="text-right text-xs font-bold">' + sous + '</span>' : '') + '</div><p class="flex-1 font-extrabold leading-snug">' + esc(t) + '</p><div class="flex flex-wrap gap-1">' + badges(tags) + '</div><div class="flex flex-wrap gap-2 border-t-2 border-black pt-3"><a href="' + lien(tags) + '" class="border-2 border-black bg-[#FFD23F] px-2 py-0.5 text-sm font-extrabold hover:bg-black hover:text-white">Ouvrir</a><button type="button" data-ajout class="border-2 border-black bg-white px-2 py-0.5 text-sm font-extrabold hover:bg-[#7CF2C0]">+ Séquence</button></div></li>';
|
||
}
|
||
function rendre() {
|
||
var h = '', th = sel.value;
|
||
if (vue === 'themes') {
|
||
R.themes.filter(function (x) { return !th || x.code === th; }).forEach(function (x) {
|
||
var its = x.items.map(function (it, i) { return [x.code + '-' + (i + 1), it[0], it[1]]; }).filter(function (it) { return garde(it[1], it[2]); });
|
||
if (!its.length) return;
|
||
h += '<section class="mb-14"><h2 class="flex flex-wrap items-baseline gap-3 text-3xl font-black tracking-tight"><span class="border-4 border-black bg-[#C4B5FD] px-2 font-mono text-2xl shadow-[4px_4px_0px_#000000]">' + x.code + '</span>' + esc(x.nom) + '<span class="font-mono text-base font-semibold">' + its.length + ' fiche(s)</span></h2><ul class="mt-6 grid gap-5 sm:grid-cols-2 lg:grid-cols-4">' + its.map(function (it) { return carte(it[0], it[1], it[2]); }).join('') + '</ul></section>';
|
||
});
|
||
} else if (vue === 'formations') {
|
||
var gr = {}; R.formations.forEach(function (f) { (gr[f.groupe] = gr[f.groupe] || []).push(f); });
|
||
Object.keys(gr).forEach(function (g) {
|
||
var bloc = gr[g].map(function (f) {
|
||
var ch = f.chapitres.filter(function (c) { return garde(c[0], c[1]); });
|
||
if (!ch.length) return '';
|
||
return '<details class="border-4 border-black bg-white shadow-[5px_5px_0px_#000000]" open><summary class="cursor-pointer border-b-4 border-black bg-[#7CF2C0] px-5 py-3 text-xl font-black">' + esc(f.nom) + ' <span class="font-mono text-sm font-semibold">· ' + ch.length + ' chapitre(s)</span></summary><ul class="divide-y-2 divide-black">' + ch.map(function (c, i) { return '<li class="flex flex-wrap items-center gap-3 px-5 py-3"><span class="font-mono text-sm font-semibold">' + (i + 1) + '</span><a href="' + lien(c[1]) + '" class="min-w-0 flex-1 font-bold hover:underline">' + esc(c[0]) + '</a><span class="flex flex-wrap gap-1">' + badges(c[1]) + '</span><button type="button" data-ajout class="border-2 border-black px-2 text-xs font-extrabold hover:bg-[#7CF2C0]">+ Séquence</button></li>'; }).join('') + '</ul></details>';
|
||
}).join('');
|
||
if (bloc) h += '<section class="mb-12"><h2 class="text-3xl font-black tracking-tight">' + esc(g) + '</h2><div class="mt-5 grid gap-6">' + bloc + '</div></section>';
|
||
});
|
||
} else {
|
||
var ex = R.examens.filter(function (e) { return garde(e[0] + ' ' + e[1], 'EXAM'); });
|
||
var ext = tous.filter(function (f) { return f.tags.split(' ').indexOf('EXAM') > -1 && garde(f.t, f.tags); });
|
||
h += '<section class="mb-12"><h2 class="text-3xl font-black tracking-tight">Épreuves et examens blancs</h2><ul class="mt-6 grid gap-5 sm:grid-cols-2 lg:grid-cols-3">' + ex.map(function (e) { return '<li class="border-4 border-black bg-white p-5 shadow-[5px_5px_0px_#000000]"><p class="font-mono text-sm font-semibold">⏱ ' + e[2] + '</p><p class="mt-2 text-xl font-black">' + esc(e[0]) + '</p><p class="mt-1 font-semibold">' + esc(e[1]) + '</p><div class="mt-4 flex gap-2"><a href="' + U.urlExam + '" class="border-2 border-black bg-[#ec3013] px-2 py-0.5 text-sm font-extrabold text-white">Aperçu</a><a href="' + U.urlBanque + '" class="border-2 border-black bg-white px-2 py-0.5 text-sm font-extrabold hover:bg-[#FFD23F]">Personnaliser</a></div></li>'; }).join('') + '</ul></section>';
|
||
h += '<section><h2 class="text-3xl font-black tracking-tight">Fiches avec mode examen</h2><ul class="mt-6 grid gap-5 sm:grid-cols-2 lg:grid-cols-4">' + ext.map(function (f) { return carte(f.code, f.t, f.tags); }).join('') + '</ul></section>';
|
||
}
|
||
box.innerHTML = h || '<p class="border-4 border-black bg-white p-6 text-xl font-black">Aucune fiche ne correspond à ces filtres.</p>';
|
||
}
|
||
box.addEventListener('click', function (e) { var b = e.target.closest('[data-ajout]'); if (!b || b.disabled) return; seq++; document.getElementById('b-seq').textContent = seq; b.textContent = 'Ajoutée ✓'; b.disabled = true; b.classList.add('bg-[#7CF2C0]'); });
|
||
document.querySelectorAll('[data-vue]').forEach(function (b) { b.addEventListener('click', function () { vue = b.dataset.vue; document.querySelectorAll('[data-vue]').forEach(function (x) { x.setAttribute('aria-selected', x === b); }); rendre(); }); });
|
||
document.querySelectorAll('[data-tag]').forEach(function (b) { b.addEventListener('click', function () { var on = b.getAttribute('aria-pressed') !== 'true'; b.setAttribute('aria-pressed', on); actifs = Array.prototype.filter.call(document.querySelectorAll('[data-tag]'), function (x) { return x.getAttribute('aria-pressed') === 'true'; }).map(function (x) { return x.dataset.tag; }); rendre(); }); });
|
||
['b-recherche', 'b-theme', 'b-vm'].forEach(function (id) { document.getElementById(id).addEventListener('input', rendre); document.getElementById(id).addEventListener('change', rendre); });
|
||
rendre();
|
||
})();
|
||
</script>
|
||
@endsection
|