FEATURE + REFACTOR Handling sommaire chapter progression + refactoring footnote hebaviour
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
36bad45e67
commit
53e280383e
|
|
@ -1,9 +1,84 @@
|
||||||
import {
|
import { toggleActiveTabPanel } from './index-panel';
|
||||||
scrollToFootnoteInIndexPanel,
|
|
||||||
toggleActiveTabPanel,
|
|
||||||
toggleActiveFootnoteLinkInIndexPanel,
|
|
||||||
} from './index-panel';
|
|
||||||
|
|
||||||
|
/* ********************************************************
|
||||||
|
* ************* SCROLLING FUNCTIONS *********************
|
||||||
|
* ********************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function scrollToFootnoteInIndexPanel(footnoteId: string): void {
|
||||||
|
const footnotesIndex = document.querySelector('#footnotes-index') as HTMLElement;
|
||||||
|
const footnotesIndexContainer = document.querySelector('ul#footnotes-index');
|
||||||
|
const indexPanelContent = document.querySelector('.index-panel__content') as HTMLElement;
|
||||||
|
const currentFootnote = footnotesIndexContainer?.querySelector(
|
||||||
|
`a[href="#${footnoteId}"]`
|
||||||
|
) as HTMLElement;
|
||||||
|
|
||||||
|
if (currentFootnote && footnotesIndexContainer) {
|
||||||
|
const containerRect = footnotesIndexContainer.getBoundingClientRect();
|
||||||
|
const elementRect = currentFootnote.getBoundingClientRect();
|
||||||
|
|
||||||
|
const relativeTop = elementRect.top - containerRect.top;
|
||||||
|
const scrollTop = footnotesIndexContainer.scrollTop + relativeTop - 20;
|
||||||
|
|
||||||
|
footnotesIndexContainer.scrollTo({
|
||||||
|
top: scrollTop,
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function scrollToFootnote(footnoteId: string): void {
|
||||||
|
const footnote = document.querySelector(`a.footnote-reference#${footnoteId}`);
|
||||||
|
if (!footnote) return;
|
||||||
|
|
||||||
|
footnote.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ********************************************************
|
||||||
|
* ************* TOGGLE ACTIVE ***************************
|
||||||
|
* ********************************************************
|
||||||
|
*/
|
||||||
|
export function toggleActiveFootnoteLinkInIndexPanel(footnoteId: string): void {
|
||||||
|
const footnotesIndexLinks = document.querySelectorAll('.footnote-reference-item');
|
||||||
|
const indexPanel = document.querySelector('.index-panel') as HTMLElement;
|
||||||
|
const currentFootnote = indexPanel.querySelector(`a[href="#${footnoteId}"]`) as HTMLElement;
|
||||||
|
|
||||||
|
footnotesIndexLinks.forEach((footnoteLink) => {
|
||||||
|
footnoteLink.setAttribute('active', 'false');
|
||||||
|
});
|
||||||
|
|
||||||
|
currentFootnote?.setAttribute('active', 'true');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ********************************************************
|
||||||
|
* ************* OBSERVE LINKS ***************************
|
||||||
|
* ********************************************************
|
||||||
|
*/
|
||||||
|
export function observeFootnotesLinks(): void {
|
||||||
|
const footnotesLinks = document.querySelectorAll('.footnotes-index a');
|
||||||
|
|
||||||
|
footnotesLinks.forEach((footnoteLink) => {
|
||||||
|
footnoteLink.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
const href = target.getAttribute('href');
|
||||||
|
if (!href) return;
|
||||||
|
|
||||||
|
const targetId = href.startsWith('#') ? href.substring(1) : href;
|
||||||
|
if (!targetId) return;
|
||||||
|
scrollToFootnote(targetId);
|
||||||
|
// document.querySelector(`#${targetId}`)?.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
|
||||||
|
toggleActiveFootnoteLinkInIndexPanel(targetId);
|
||||||
|
scrollToFootnoteInIndexPanel(targetId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ********************************************************
|
||||||
|
* ************* MAIN — HANDLE GENERAL BEHAVIOUR *********
|
||||||
|
* ********************************************************
|
||||||
|
*/
|
||||||
export default function handleFootnoteFormat(): void {
|
export default function handleFootnoteFormat(): void {
|
||||||
const footnotes = document.querySelectorAll('.content-area .footnote-reference');
|
const footnotes = document.querySelectorAll('.content-area .footnote-reference');
|
||||||
|
|
||||||
|
|
@ -18,10 +93,3 @@ export default function handleFootnoteFormat(): void {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function scrollToFootnote(footnoteId: string): void {
|
|
||||||
const footnote = document.querySelector(`a.footnote-reference#${footnoteId}`);
|
|
||||||
if (!footnote) return;
|
|
||||||
|
|
||||||
footnote.scrollIntoView({ behavior: 'smooth' });
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,19 @@
|
||||||
import { scrollToFootnote } from './footnote-format';
|
import handleChapterProgression, { observeSommaireLinks } from './sommaire';
|
||||||
import { handleSmoothScrollToTitle } from './sommaire';
|
import { observeFootnotesLinks } from './footnote-format';
|
||||||
|
|
||||||
export default function handleIndexPanel(): void {
|
export default function handleIndexPanel(): void {
|
||||||
const indexPanel = document.querySelector('.index-panel');
|
const indexPanel = document.querySelector('.index-panel');
|
||||||
if (!indexPanel) return;
|
if (!indexPanel) return;
|
||||||
|
|
||||||
|
// TABS
|
||||||
observeTabsButtons();
|
observeTabsButtons();
|
||||||
|
// FOOTNOTES
|
||||||
observeFootnotesLinks();
|
observeFootnotesLinks();
|
||||||
|
// INDEX PANEL MOBILE
|
||||||
|
handleMobileOpenToggle();
|
||||||
|
// CHAPITRES
|
||||||
observeSommaireLinks();
|
observeSommaireLinks();
|
||||||
|
handleChapterProgression();
|
||||||
handleMobileOpenToggle();
|
handleMobileOpenToggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -19,7 +25,7 @@ function handleMobileOpenToggle(): void {
|
||||||
|
|
||||||
mobileOpenToggle.addEventListener('click', () => {
|
mobileOpenToggle.addEventListener('click', () => {
|
||||||
const isMobileOpen = indexPanel.getAttribute('data-mobile-open');
|
const isMobileOpen = indexPanel.getAttribute('data-mobile-open');
|
||||||
console.log(isMobileOpen);
|
|
||||||
if (isMobileOpen === 'true') {
|
if (isMobileOpen === 'true') {
|
||||||
indexPanel.setAttribute('data-mobile-open', 'false');
|
indexPanel.setAttribute('data-mobile-open', 'false');
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -63,99 +69,3 @@ export function toggleActiveTabPanel(dataIndex: string): void {
|
||||||
activeButton.setAttribute('aria-selected', 'true');
|
activeButton.setAttribute('aria-selected', 'true');
|
||||||
activePanel.setAttribute('aria-hidden', 'false');
|
activePanel.setAttribute('aria-hidden', 'false');
|
||||||
}
|
}
|
||||||
|
|
||||||
// ********************************************************
|
|
||||||
// ************* SOMMAIRE *********************************
|
|
||||||
// ********************************************************
|
|
||||||
|
|
||||||
function observeSommaireLinks(): void {
|
|
||||||
const sommaireTitles: NodeListOf<Element> = document.querySelectorAll('.sommaire-index li a');
|
|
||||||
for (const title of sommaireTitles) {
|
|
||||||
title.addEventListener('click', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const href = title.getAttribute('href');
|
|
||||||
if (!href) return;
|
|
||||||
|
|
||||||
const targetId = href.startsWith('#') ? href.substring(1) : href;
|
|
||||||
if (!targetId) return;
|
|
||||||
|
|
||||||
handleSmoothScrollToTitle(targetId);
|
|
||||||
toggleActiveChapterLinkInIndexPanel(targetId);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleActiveChapterLinkInIndexPanel(targetId: string): void {
|
|
||||||
const sommaireLinks: NodeListOf<Element> = document.querySelectorAll('.sommaire-index li a');
|
|
||||||
|
|
||||||
const indexPanel = document.querySelector('.index-panel') as HTMLElement;
|
|
||||||
const currentLink = indexPanel.querySelector(`a[href="#${targetId}"]`) as HTMLElement;
|
|
||||||
|
|
||||||
if (!currentLink) return;
|
|
||||||
|
|
||||||
for (const link of sommaireLinks) {
|
|
||||||
link.setAttribute('active', 'false');
|
|
||||||
}
|
|
||||||
|
|
||||||
currentLink?.setAttribute('active', 'true');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ********************************************************
|
|
||||||
// ************* FOOTNOTES *********************************
|
|
||||||
// ********************************************************
|
|
||||||
|
|
||||||
function observeFootnotesLinks(): void {
|
|
||||||
const footnotesLinks = document.querySelectorAll('.footnotes-index a');
|
|
||||||
|
|
||||||
footnotesLinks.forEach((footnoteLink) => {
|
|
||||||
footnoteLink.addEventListener('click', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const target = e.target as HTMLElement;
|
|
||||||
const href = target.getAttribute('href');
|
|
||||||
if (!href) return;
|
|
||||||
|
|
||||||
const targetId = href.startsWith('#') ? href.substring(1) : href;
|
|
||||||
if (!targetId) return;
|
|
||||||
scrollToFootnote(targetId);
|
|
||||||
// document.querySelector(`#${targetId}`)?.scrollIntoView({ behavior: 'smooth' });
|
|
||||||
|
|
||||||
toggleActiveFootnoteLinkInIndexPanel(targetId);
|
|
||||||
scrollToFootnoteInIndexPanel(targetId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toggleActiveFootnoteLinkInIndexPanel(footnoteId: string): void {
|
|
||||||
const footnotesIndexLinks = document.querySelectorAll('.footnote-reference-item');
|
|
||||||
const indexPanel = document.querySelector('.index-panel') as HTMLElement;
|
|
||||||
const currentFootnote = indexPanel.querySelector(`a[href="#${footnoteId}"]`) as HTMLElement;
|
|
||||||
|
|
||||||
footnotesIndexLinks.forEach((footnoteLink) => {
|
|
||||||
footnoteLink.setAttribute('active', 'false');
|
|
||||||
});
|
|
||||||
|
|
||||||
currentFootnote?.setAttribute('active', 'true');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function scrollToFootnoteInIndexPanel(footnoteId: string): void {
|
|
||||||
const footnotesIndex = document.querySelector('#footnotes-index') as HTMLElement;
|
|
||||||
const footnotesIndexContainer = document.querySelector('ul#footnotes-index');
|
|
||||||
const indexPanelContent = document.querySelector('.index-panel__content') as HTMLElement;
|
|
||||||
const currentFootnote = footnotesIndexContainer?.querySelector(
|
|
||||||
`a[href="#${footnoteId}"]`
|
|
||||||
) as HTMLElement;
|
|
||||||
|
|
||||||
if (currentFootnote && footnotesIndexContainer) {
|
|
||||||
const containerRect = footnotesIndexContainer.getBoundingClientRect();
|
|
||||||
const elementRect = currentFootnote.getBoundingClientRect();
|
|
||||||
|
|
||||||
const relativeTop = elementRect.top - containerRect.top;
|
|
||||||
const scrollTop = footnotesIndexContainer.scrollTop + relativeTop - 20;
|
|
||||||
|
|
||||||
footnotesIndexContainer.scrollTo({
|
|
||||||
top: scrollTop,
|
|
||||||
behavior: 'smooth',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import handleFootnoteFormat from './footnote-format';
|
||||||
import handleCiteButton from './cite-button';
|
import handleCiteButton from './cite-button';
|
||||||
import handleLikeButton from './like-button.ts';
|
import handleLikeButton from './like-button.ts';
|
||||||
import handleShareButton from './share-button.ts';
|
import handleShareButton from './share-button.ts';
|
||||||
|
|
||||||
import { handleArticleToolbar } from './article-toolbar.ts';
|
import { handleArticleToolbar } from './article-toolbar.ts';
|
||||||
import { handleRevueToolbar } from './revue-toolbar.ts';
|
import { handleRevueToolbar } from './revue-toolbar.ts';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,228 @@
|
||||||
|
/* ********************************************************
|
||||||
|
* ************* SCROLLING FUNCTIONS *********************
|
||||||
|
* ********************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Effectue un scroll fluide vers un élément ciblé avec un offset personnalisé.
|
||||||
|
* @param targetId - ID de l'élément cible (sans le #)
|
||||||
|
*/
|
||||||
export function handleSmoothScrollToTitle(targetId: string): void {
|
export function handleSmoothScrollToTitle(targetId: string): void {
|
||||||
const targetElement = document.querySelector(`#${targetId}`);
|
const targetElement = document.querySelector(`#${targetId}`);
|
||||||
if (!targetElement) return;
|
if (!targetElement) return;
|
||||||
|
|
||||||
const elementRect = targetElement.getBoundingClientRect();
|
const elementRect = targetElement.getBoundingClientRect();
|
||||||
const offset = 30; // 10px offset from top
|
const offset = 30; // 30px offset from top
|
||||||
|
|
||||||
window.scrollTo({
|
window.scrollTo({
|
||||||
top: window.pageYOffset + elementRect.top - offset,
|
top: window.pageYOffset + elementRect.top - offset,
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fait défiler l'indicateur de position vers le chapitre actif dans l'index panel.
|
||||||
|
* @param targetId - ID du chapitre cible
|
||||||
|
*/
|
||||||
|
export function scrollToActiveChapterInIndexPanel(targetId: string): void {
|
||||||
|
// const activeLink = document.querySelector(`a[active="true"]`) as HTMLElement;
|
||||||
|
// const targetPosition = activeLink.offsetTop;
|
||||||
|
// const targetHeight = activeLink.offsetHeight;
|
||||||
|
// let chapterIndicator = document.querySelector('.chapter_index__position-indicator');
|
||||||
|
// chapterIndicator.style.top = targetPosition + 'px';
|
||||||
|
// chapterIndicator.style.height = targetHeight + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ********************************************************
|
||||||
|
// ************* TOGGLE ACTIVE **************************
|
||||||
|
// ********************************************************
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Désactive tous les liens de chapitre précédemment actifs.
|
||||||
|
*/
|
||||||
|
function removePreviousActiveLink() {
|
||||||
|
const activeLinks = document.querySelectorAll(
|
||||||
|
'.index-panel__content .sommaire-index li a[active="true"]'
|
||||||
|
);
|
||||||
|
activeLinks.forEach((link) => {
|
||||||
|
link.setAttribute('active', 'false');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Active le lien de chapitre correspondant à l'ID cible dans l'index panel.
|
||||||
|
* @param targetId - ID du chapitre à activer
|
||||||
|
*/
|
||||||
|
export function toggleActiveChapterLinkInIndexPanel(targetId: string): void {
|
||||||
|
const sommaireLinks: NodeListOf<Element> = document.querySelectorAll('.sommaire-index li a');
|
||||||
|
|
||||||
|
const indexPanel = document.querySelector('.index-panel') as HTMLElement;
|
||||||
|
const currentLink = indexPanel.querySelector(`a[href="#${targetId}"]`) as HTMLElement;
|
||||||
|
|
||||||
|
if (!currentLink) return;
|
||||||
|
|
||||||
|
for (const link of sommaireLinks) {
|
||||||
|
link.setAttribute('active', 'false');
|
||||||
|
}
|
||||||
|
|
||||||
|
currentLink?.setAttribute('active', 'true');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ********************************************************
|
||||||
|
// ************* CHAPTER OBSERVER STATE MANAGEMENT *******
|
||||||
|
// ********************************************************
|
||||||
|
|
||||||
|
// Variable globale pour contrôler l'état de pause de l'intersection observer
|
||||||
|
let isChapterObserverPaused = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Met en pause ou réactive l'intersection observer des chapitres.
|
||||||
|
* @param paused - État de pause à définir
|
||||||
|
*/
|
||||||
|
export function setChapterObserverPaused(paused: boolean): void {
|
||||||
|
isChapterObserverPaused = paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne l'état actuel de pause de l'intersection observer.
|
||||||
|
* @returns État de pause de l'observer
|
||||||
|
*/
|
||||||
|
export function getChapterObserverPausedState(): boolean {
|
||||||
|
return isChapterObserverPaused;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ajoute des écouteurs d'événements aux liens de chapitre pour la navigation.
|
||||||
|
*/
|
||||||
|
function observeChapterLinks(): void {
|
||||||
|
let chapterLinks = document.querySelectorAll('.chapter_index__link');
|
||||||
|
if (!chapterLinks) return;
|
||||||
|
|
||||||
|
chapterLinks.forEach((link) => {
|
||||||
|
link.addEventListener('click', (e) => {
|
||||||
|
handleLinkScrollToTarget(e);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intersection Observer qui détecte automatiquement les chapitres visibles
|
||||||
|
* et met à jour l'état actif dans l'index panel.
|
||||||
|
*/
|
||||||
|
const chapterProgressionObserver = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
// Ne pas traiter les entrées si l'observer est en pause (pendant un clic)
|
||||||
|
const isIntersetionObserverPaused = getChapterObserverPausedState();
|
||||||
|
if (isIntersetionObserverPaused) return;
|
||||||
|
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
const blockId = entry.target.getAttribute('id');
|
||||||
|
const relatedChapterLink = document.querySelector(`a[href="#${blockId}"]`);
|
||||||
|
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
removePreviousActiveLink();
|
||||||
|
|
||||||
|
entry.target.setAttribute('active', 'true');
|
||||||
|
relatedChapterLink?.setAttribute('active', 'true');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rootMargin: '-10% 0px -50% 0px',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gère le scroll vers un élément cible lors du clic sur un lien.
|
||||||
|
* @param e - Événement du clic
|
||||||
|
*/
|
||||||
|
function handleLinkScrollToTarget(e: Event) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let target = (e.target as HTMLElement).getAttribute('href');
|
||||||
|
if (!target) return;
|
||||||
|
|
||||||
|
let targetBlock = document.querySelector(target);
|
||||||
|
if (!targetBlock) return;
|
||||||
|
|
||||||
|
targetBlock.setAttribute('tabindex', '-1');
|
||||||
|
targetBlock.scrollIntoView({
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
(targetBlock as HTMLElement).focus({ preventScroll: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// ********************************************************
|
||||||
|
// ************* MAIN FUNCTION ****************************
|
||||||
|
// ********************************************************
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise le système de progression des chapitres avec l'intersection observer.
|
||||||
|
* Active la détection automatique des chapitres visibles lors du scroll.
|
||||||
|
*/
|
||||||
|
export default function handleChapterProgression() {
|
||||||
|
const hasChapterIndex = document.querySelector('.index-panel__content .sommaire-index');
|
||||||
|
if (!hasChapterIndex) return;
|
||||||
|
|
||||||
|
// Debug function to visualize rootMargin
|
||||||
|
// function createDebugOverlay() {
|
||||||
|
// const overlay = document.createElement('div');
|
||||||
|
// overlay.style.position = 'fixed';
|
||||||
|
// overlay.style.top = '10%';
|
||||||
|
// overlay.style.bottom = '50%';
|
||||||
|
// overlay.style.left = '0';
|
||||||
|
// overlay.style.right = '0';
|
||||||
|
// overlay.style.border = '2px solid red';
|
||||||
|
// overlay.style.pointerEvents = 'none';
|
||||||
|
// overlay.style.zIndex = '9999';
|
||||||
|
// overlay.style.opacity = '0.3';
|
||||||
|
// overlay.style.backgroundColor = 'rgba(255, 0, 0, 0.1)';
|
||||||
|
// document.body.appendChild(overlay);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Uncomment the line below to see the detection zone
|
||||||
|
// createDebugOverlay();
|
||||||
|
|
||||||
|
// Initialiser les écouteurs de liens
|
||||||
|
observeChapterLinks();
|
||||||
|
|
||||||
|
// Observer tous les titres h2 de l'article
|
||||||
|
const titlesBlocks = document.querySelectorAll('.article-content h2');
|
||||||
|
titlesBlocks.forEach((block) => {
|
||||||
|
chapterProgressionObserver.observe(block);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ********************************************************
|
||||||
|
// ************* SOMMAIRE NAVIGATION **********************
|
||||||
|
// ********************************************************
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ajoute des écouteurs d'événements aux liens du sommaire pour la navigation manuelle.
|
||||||
|
* Gère le conflit avec l'intersection observer en le pausant temporairement.
|
||||||
|
*/
|
||||||
|
export function observeSommaireLinks(): void {
|
||||||
|
const sommaireTitles: NodeListOf<Element> = document.querySelectorAll('.sommaire-index li a');
|
||||||
|
for (const title of sommaireTitles) {
|
||||||
|
title.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const href = title.getAttribute('href');
|
||||||
|
if (!href) return;
|
||||||
|
|
||||||
|
const targetId = href.startsWith('#') ? href.substring(1) : href;
|
||||||
|
if (!targetId) return;
|
||||||
|
|
||||||
|
// Désactiver temporairement l'intersection observer pour éviter les conflits
|
||||||
|
setChapterObserverPaused(true);
|
||||||
|
|
||||||
|
handleSmoothScrollToTitle(targetId);
|
||||||
|
toggleActiveChapterLinkInIndexPanel(targetId);
|
||||||
|
|
||||||
|
// Réactiver l'intersection observer après le smooth scroll
|
||||||
|
setTimeout(() => {
|
||||||
|
setChapterObserverPaused(false);
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user