+
Chapitre 1
1.1 - Un montage simple
Tout commence par des fils, une source d'energie et un appareil.
diff --git a/scripts/chapter-progress.js b/scripts/chapter-progress.js
new file mode 100644
index 0000000..cd84945
--- /dev/null
+++ b/scripts/chapter-progress.js
@@ -0,0 +1,73 @@
+function progress_tracker(){
+ const sections = Array.from(document.querySelectorAll('section[chapter]'));
+ const fill = document.getElementById('progressFill');
+ const titleEl = document.getElementById('sectionTitle');
+ const countEl = document.getElementById('sectionCount');
+
+ let ticking = false;
+ let currentIndex = -1;
+
+ function updateProgress() {
+ const viewportH = window.innerHeight;
+ const scrollY = window.scrollY;
+
+ // 1. Trouver la section active : celle dont le haut est le plus proche
+ // au-dessus (ou sur) le haut du viewport, mais qui n'est pas encore
+ // entièrement passée.
+ let activeIndex = 0;
+ for (let i = 0; i < sections.length; i++) {
+ const rect = sections[i].getBoundingClientRect();
+ // Une section devient "active" dès que son haut passe sous ~35% du viewport
+ if (rect.top <= viewportH * 0.35) {
+ activeIndex = i;
+ }
+ }
+
+ // 2. Calculer la progression DANS cette section (0 à 100%)
+ const activeSection = sections[activeIndex];
+ const rect = activeSection.getBoundingClientRect();
+ const sectionHeight = activeSection.offsetHeight;
+
+ // distance défilée depuis le haut de la section
+ const scrolledIntoSection = -rect.top;
+ // on borne entre 0 et la hauteur totale de la section moins le viewport
+ // (pour atteindre 100% quand le bas de la section touche le bas de l'écran)
+ const scrollableDistance = Math.max(sectionHeight - viewportH, 1);
+ let progress = scrolledIntoSection / scrollableDistance;
+ progress = Math.min(Math.max(progress, 0), 1);
+
+ // Cas particulier : si la section est plus petite que le viewport,
+ // on considère 100% dès qu'elle est visible en haut.
+ if (sectionHeight <= viewportH) {
+ progress = scrolledIntoSection > 0 ? 1 : 0;
+ }
+
+ fill.style.width = (progress * 100).toFixed(1) + '%';
+
+ // 3. Mettre à jour le titre uniquement si la section a changé
+ // (évite de re-déclencher la transition CSS à chaque pixel)
+ if (activeIndex !== currentIndex) {
+ currentIndex = activeIndex;
+ titleEl.style.opacity = 0;
+ setTimeout(() => {
+ titleEl.textContent = activeSection.dataset.title;
+ countEl.textContent = (activeIndex + 1) + ' / ' + sections.length;
+ titleEl.style.opacity = 1;
+ }, 120);
+ }
+ }
+
+ function onScroll() {
+ if (!ticking) {
+ requestAnimationFrame(() => {
+ updateProgress();
+ ticking = false;
+ });
+ ticking = true;
+ }
+ }
+
+ window.addEventListener('scroll', onScroll, { passive: true });
+ window.addEventListener('resize', onScroll);
+ updateProgress(); // init au chargement
+})();
diff --git a/styles/mood-style.css b/styles/mood-style.css
new file mode 100644
index 0000000..0b3bbc1
--- /dev/null
+++ b/styles/mood-style.css
@@ -0,0 +1,19 @@
+html{
+ scroll-behavior: smooth;
+ background-color: #0f2150;
+ color: #dddddd;
+}
+
+main{
+ display:flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 20px;
+}
+
+img{
+ width: 30vw;
+ height: auto;
+ border-radius: 100%;
+}
diff --git a/styles/style.css b/styles/style.css
index e76aa4a..40ab41a 100644
--- a/styles/style.css
+++ b/styles/style.css
@@ -1,10 +1,12 @@
-html { scroll-behavior: smooth; }
-
-body {
+html {
+ scroll-behavior: smooth;
background-color: #ffffff;
background-image: radial-gradient(circle, #d0d0d5 1.5px, transparent 1px);
background-size: 50px 50px;
- background-repeat: repeat;
+ background-repeat: repeat;
+}
+
+body {
}
header {