Dolie - KOPHI'S MUSIC
Aller au contenu
Dolie URBAN GOSPEL - WORSHIP - R&B GOSPEL
Iris Dosso, connue sous le nom de Dolie, est une chanteuse ivoirienne de 21 ans, figure montante de l’Urban Gospel francophone africain. Depuis le 9 mars 2026, est officiellement chez KOPHI’S MUSIC, devenant la première artiste féminine du label.
Dolie URBAN GOSPEL - WORSHIP - R&B GOSPEL
Dolie , de son vrai nom Iris Dosso , est une artiste chantre ivoirienne de 21 ans et figure montante de l’Urban Gospel africain francophone . Issue d’une famille baignée dans la foi et la musique, elle a construit sa voix entre un groupe familial animé par son oncle beatmaker et les scènes de son église. En 2025, elle sort son premier projet solo « Le Dieu de mon temps » . Le 09 mars 2026 , elle signe officiellement chez KOPHI’S MUSIC , devenant la toute première artiste féminine du label .
Identité & Profil Dolie est le nom de scène d’Iris Dosso , jeune artiste chantre ivoirienne née en 2004. À seulement 21 ans , elle incarne une nouvelle vague de l’Urban Gospel africain francophone — un genre qui marie les codes de la musique urbaine contemporaine (R&B, Soul, Afrobeats) à un message profondément ancré dans la foi chrétienne. Étudiante, elle mène de front ses études et une carrière artistique déjà remarquable.
Nom d’artiste : DolieNom civil : Iris DossoÂge : 21 ansNationalité : Ivoirienne (Côte d’Ivoire)Genre musical : Urban Gospel · Worship · R&B GospelLabel : KOPHI’S MUSIC (division musicale de KOPHI’S GROUP SAS)Signature label : 09 Mars 2026Statut : Étudiante & Artiste
Les Racines : Une Vocation Née en Famille Tout commence comme un jeu d’enfance. Dolie fait ses premiers pas dans la musique au sein d’un petit groupe créé par l’un de ses oncles, réunissant frères, sœurs et cousins pour animer les vacances familiales. Ce qui n’était au départ qu’une parenthèse joyeuse se révèle rapidement être bien plus : une passion, un don, un appel.
Son oncle — aujourd’hui reconnu comme beatmaker actif sur la scène musicale ivoirienne , ayant collaboré sur plusieurs grands projets en Côte d’Ivoire — perçoit très tôt le talent exceptionnel de sa nièce. Ensemble, ils posent les premières fondations d’une relation artistique aussi rare que précieuse : celle d’une famille qui se construit dans la musique.
Lorsque l’aventure du groupe familial prend fin quelques années plus tard, la flamme, elle, ne s’éteint pas .
L’Appel du Saint-Esprit : La Scène de l’Église Répondant à ce qu’elle décrit comme un appel du Saint-Esprit , Dolie intègre le ministère de louange et d’adoration de son église. C’est là, derrière un micro d’église, que sa voix trouve sa pleine dimension : puissante, sincère, habitée.
Depuis ce jour, elle n’a plus jamais cessé de chanter. Le service de Dieu avec sa voix n’est pas pour elle une étape de sa carrière — c’est le fondement même de son identité d’artiste. Cette fidélité au ministère spirituel, combinée à un travail vocal constant, forge une artiste complète, ancrée et authentique.
« Elle sert le Seigneur avec sa voix depuis ce temps et ne s’est plus jamais arrêtée jusqu’à ce jour. »
2023 – 2024 : L’Éveil d’une Carrière Professionnelle En 2023 , des rencontres décisives changent la trajectoire de Dolie. Des amis proches, convaincus par son talent, l’encouragent à franchir le cap de la professionnalisation. Elle s’y engage avec sérieux : plusieurs titres sont enregistrés cette année-là, témoignant d’une artiste déjà mature dans son propos, mais qui attendent encore le bon moment pour être révélés au grand public.
En 2024 , elle fait une première apparition remarquée en contribuant à la chanson d’un ami — un featuring qui marque ses débuts dans la sphère musicale professionnelle ivoirienne et confirme la singularité de sa voix sur la scène de la nouvelle génération gospel.
2025 : Premiers Projets Officiels & Révélation L’année 2025 marque l’entrée officielle de Dolie sur la scène musicale ivoirienne. Deux œuvres majeures jalonnent cette étape fondatrice.
« Par Amour » — Feat. Emmanuel King Son tout premier featuring officiel sort en 2025 aux côtés de l’artiste Emmanuel King . Intitulé « Par Amour » , ce titre est une déclaration gospel à la fois intime et universelle, portée par deux voix complémentaires. Il positionne Dolie comme une voix féminine à part entière dans l’écosystème Urban Gospel ivoirien.
« Le Dieu de mon temps » — Premier Projet Solo (03 Juin 2025) Le 03 juin 2025 , Dolie franchit une étape symbolique avec la sortie de son tout premier projet solo , « Le Dieu de mon temps » , disponible sur YouTube. Ce titre est bien plus qu’une simple chanson : il est le manifeste d’une artiste qui assume pleinement sa mission, témoigne de sa foi avec maturité et s’adresse à une génération en quête de sens.
09 Mars 2026 : Signature chez KOPHI’S MUSIC — Une Date Symbolique Le 09 mars 2026 , au lendemain de la Journée Internationale des Droits de la Femme, Dolie signe officiellement un contrat avec KOPHI’S MUSIC , la division musicale de KOPHI’S GROUP SAS . Une date hautement symbolique, choisie juste après le 08 Mars — comme un message fort adressé aux femmes artistes de la scène gospel ivoirienne.
Elle devient ainsi la toute première artiste féminine du label , rejoignant une maison qui abrite déjà des artistes reconnus de l’Urban Gospel ivoirien :
KOPHI’S MUSIC est un label indépendant basé à Abidjan, Côte d’Ivoire , fondé et porté par Monsieur Kophi, artiste-rappeur-chanteur et auteur-compositeur ivoirien. La structure s’inscrit pleinement dans la dynamique de l’Urban Gospel ivoirien, un mouvement musical en pleine expansion sur le continent africain et dans les diasporas francophones.
Positionnement Artistique : La Voix du Renouveau Gospel Ivoirien Dans un paysage gospel ivoirien riche et compétitif, Dolie s’inscrit avec une proposition musicale singulière. L’Urban Gospel qu’elle pratique est l’un des genres les plus dynamiques de la scène chrétienne africaine francophone, à la croisée du R&B, de l’Afrobeats et du Worship contemporain.
Ce qui distingue Dolie :
🎯 Une voix puissante et émotionnelle forgée dans des années de ministère de louange 🎯 Une authenticité spirituelle rare : la foi n’est pas un concept, c’est son quotidien 🎯 Une maîtrise croissante des codes de la musique urbaine au service du message évangélique 🎯 Un profil de jeune artiste étudiante, accessible et fédératrice pour la jeunesse africaine francophone 🎯 Le soutien structurant d’un label professionnel (KOPHI’S MUSIC) pour développer sa carrière
Une Nouvelle Aventure Commence Dolie est bien plus qu’une artiste en devenir : elle est le symbole d’une génération gospel ivoirienne qui n’a pas peur de mêler excellence artistique , ancrage spirituel et ambition créative . Avec KOPHI’S MUSIC comme cadre de développement et une voix que l’Afrique francophone commence à peine à découvrir, la trajectoire de cette pépite prometteuse de l’Urban Gospel ivoirien et africain francophone ne fait que commencer.
Restez attentifs — Dolie a beaucoup à dire, et sa voix n’attend que d’être entendue.
)
* ============================================================
*
* SPEC TIMING (synchronisé avec le CSS) :
* DISPLAY_MS = 5000ms — durée totale d'affichage par slide
* TRANSITION_MS = 1200ms — durée du crossfade CSS ease-in-out
* OVERLAP_MS = 3800ms — délai avant déclenchement du crossfade
* (DISPLAY − TRANSITION = 3800ms)
*
* FONCTIONNEMENT :
* t = 0 → slide N devient is-active
* Ken Burns scale(1.0 → 1.08) démarre
* t = 3800ms → crossfadeTo() déclenché :
* slide N → is-leaving (opacity 1→0 / 1200ms)
* slide N+1 → is-active (opacity 0→1 / 1200ms)
* Ken Burns de N+1 démarre
* t = 5000ms → crossfade terminé, slide N+1 pleinement visible
* t = 5000ms → prochain cycle démarre (boucle)
*
* RÈGLES :
* • Pas de pause au survol de la souris
* • Couleur accent propagée via CSS var(--accent) par slide
* • Labels en français (SUIVANT, Mettre en pause, etc.)
* ============================================================
*/(function () {
'use strict';/* ─────────────────────────────────────────────────────────
CONSTANTES DE TIMING — synchronisées avec le CSS
───────────────────────────────────────────────────────── */
const DISPLAY_MS = 5000; // Affichage total par slide
const TRANSITION_MS = 1200; // Durée du crossfade CSS
const OVERLAP_MS = DISPLAY_MS - TRANSITION_MS; // 3800ms : déclenchement anticipé/* ─────────────────────────────────────────────────────────
INIT D'UN SLIDER
───────────────────────────────────────────────────────── */
function initKMSlider(wrapper) {/* ── Config ── */
const id = wrapper.id;
const slidesData = (window.kmSliderData && window.kmSliderData[id]) || [];
const auto = wrapper.dataset.auto !== 'false';
const total = parseInt(wrapper.dataset.total) || 0;if (total < 1) return;/* ── Éléments DOM ── */
const slides = wrapper.querySelectorAll('.km-slide');
const dots = wrapper.querySelectorAll('.km-dot');
const counter = wrapper.querySelector('.km-counter__current');
const progressFill = wrapper.querySelector('.km-progress-fill');
const nextTitle = wrapper.querySelector(`#${id}-next-title`);
const btnPrev = wrapper.querySelector('.km-nav--prev');
const btnNext = wrapper.querySelector('.km-nav--next');
const btnPlay = wrapper.querySelector('.km-play-pause');if (!slides.length) return;/* ── État ── */
let current = 0;
let isPlaying = auto;
let overlapTimer = null; // Timer OVERLAP_MS → déclenche le crossfade
let cleanTimer = null; // Timer TRANSITION_MS → nettoie is-leaving/* ── Utilitaires ── */
const pad = n => String(n).padStart(2, '0');
const mod = (n, m) => ((n % m) + m) % m;
const getData = i => slidesData[i] || {};/* ───────────────────────────────────────────────────────
MISE À JOUR UI
Compteur · Dots · Titre SUIVANT · Couleur accent
─────────────────────────────────────────────────────── */
function updateUI(index) {// Compteur numérique
if (counter) counter.textContent = pad(index + 1);// Dots : classe active + aria
dots.forEach((d, i) => {
d.classList.toggle('is-active', i === index);
d.setAttribute('aria-selected', i === index ? 'true' : 'false');
});// Titre SUIVANT : micro fade-out → mise à jour → fade-in
const nextIdx = mod(index + 1, total);
if (nextTitle) {
nextTitle.classList.add('is-updating');
setTimeout(() => {
nextTitle.textContent = getData(nextIdx).titre || '';
nextTitle.classList.remove('is-updating');
}, 300);
}// Couleur accent : propagée à tous les éléments via var(--accent)
const accent = getData(index).couleur || '#E63946';
wrapper.style.setProperty('--accent', accent);
}/* ───────────────────────────────────────────────────────
BARRE DE PROGRESSION
Se remplit sur DISPLAY_MS (5000ms) en continu.
─────────────────────────────────────────────────────── */
function startProgress() {
if (!progressFill) return;
progressFill.style.transition = 'none';
progressFill.style.width = '0%';
void progressFill.offsetWidth; // Force reflow
progressFill.style.transition = `width ${DISPLAY_MS}ms linear`;
progressFill.style.width = '100%';
}function stopProgress() {
if (!progressFill) return;
const computed = parseFloat(getComputedStyle(progressFill).width);
const parent = progressFill.parentElement;
const pct = parent ? (computed / parent.offsetWidth) * 100 : 0;
progressFill.style.transition = 'none';
progressFill.style.width = pct + '%';
}function resetProgress() {
if (!progressFill) return;
progressFill.style.transition = 'none';
progressFill.style.width = '0%';
}/* ───────────────────────────────────────────────────────
CROSSFADE — cœur de la transition
───────────────────────────────────────────────────────
Appelé à t = OVERLAP_MS (3800ms) après le début d'affichage.
• Slide sortant → is-leaving : opacity 1→0 sur 1200ms
• Slide entrant → is-active : opacity 0→1 sur 1200ms
Ken Burns scale(1→1.08) sur 5000ms
─────────────────────────────────────────────────────── */
function crossfadeTo(nextIndex) {
const prev = current;
current = mod(nextIndex, total);const slideOut = slides[prev];
const slideIn = slides[current];// Slide sortant : amorce le fondu sortant CSS
slideOut.classList.remove('is-active');
slideOut.classList.add('is-leaving');
slideOut.setAttribute('aria-hidden', 'true');// Slide entrant : amorce le fondu entrant + Ken Burns CSS
slideIn.classList.add('is-active');
slideIn.setAttribute('aria-hidden', 'false');// Mise à jour interface
updateUI(current);// Nettoyage du slide sortant après fin du crossfade
clearTimeout(cleanTimer);
cleanTimer = setTimeout(() => {
slideOut.classList.remove('is-leaving');
}, TRANSITION_MS + 50); // +50ms de marge de sécurité// Planifier le prochain crossfade si autoplay actif
if (isPlaying) scheduleNext();
}/* ───────────────────────────────────────────────────────
AUTOPLAY — timer précis OVERLAP
───────────────────────────────────────────────────────
Le crossfade est déclenché à OVERLAP_MS (3800ms) pour que
la transition se termine exactement à DISPLAY_MS (5000ms).
─────────────────────────────────────────────────────── */
function scheduleNext() {
clearTimeout(overlapTimer);
if (!isPlaying) return;
overlapTimer = setTimeout(() => {
crossfadeTo(current + 1);
}, OVERLAP_MS);
}function cancelAutoplay() {
clearTimeout(overlapTimer);
}/* ───────────────────────────────────────────────────────
NAVIGATION MANUELLE
Déclenche le crossfade immédiatement, repart sur un
cycle complet de DISPLAY_MS.
─────────────────────────────────────────────────────── */
function goTo(index) {
const target = mod(index, total);
if (target === current) return;cancelAutoplay();
resetProgress();
crossfadeTo(target);if (isPlaying) startProgress();
}const nextSlide = () => goTo(current + 1);
const prevSlide = () => goTo(current - 1);/* ───────────────────────────────────────────────────────
LECTURE / PAUSE
─────────────────────────────────────────────────────── */
function play() {
isPlaying = true;
if (btnPlay) {
btnPlay.classList.remove('is-paused');
btnPlay.setAttribute('aria-label', 'Mettre en pause');
}
scheduleNext();
startProgress();
}function pause() {
isPlaying = false;
cancelAutoplay();
if (btnPlay) {
btnPlay.classList.add('is-paused');
btnPlay.setAttribute('aria-label', 'Reprendre la lecture');
}
stopProgress();
}/* ───────────────────────────────────────────────────────
ÉVÉNEMENTS
─────────────────────────────────────────────────────── */// Flèches
if (btnPrev) btnPrev.addEventListener('click', prevSlide);
if (btnNext) btnNext.addEventListener('click', nextSlide);// Lecture / Pause
if (btnPlay) {
btnPlay.addEventListener('click', () => isPlaying ? pause() : play());
}// Points de navigation
dots.forEach(dot => {
dot.addEventListener('click', () => {
const i = parseInt(dot.dataset.goto, 10);
if (!isNaN(i) && i !== current) goTo(i);
});
});// PAS de pause au survol — comportement intentionnel// Swipe tactile
let txStart = 0, tyStart = 0;
wrapper.addEventListener('touchstart', e => {
txStart = e.touches[0].clientX;
tyStart = e.touches[0].clientY;
}, { passive: true });wrapper.addEventListener('touchend', e => {
const dx = txStart - e.changedTouches[0].clientX;
const dy = tyStart - e.changedTouches[0].clientY;
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) {
dx > 0 ? nextSlide() : prevSlide();
}
}, { passive: true });// Navigation clavier
wrapper.setAttribute('tabindex', '0');
wrapper.addEventListener('keydown', e => {
switch (e.key) {
case 'ArrowRight': nextSlide(); break;
case 'ArrowLeft': prevSlide(); break;
case ' ':
e.preventDefault();
isPlaying ? pause() : play();
break;
}
});/* ───────────────────────────────────────────────────────
INITIALISATION
─────────────────────────────────────────────────────── */
(function init() {// Le slide 0 est déjà is-active dans le HTML (via PHP)
if (counter) counter.textContent = pad(1);dots.forEach((d, i) => {
d.classList.toggle('is-active', i === 0);
d.setAttribute('aria-selected', i === 0 ? 'true' : 'false');
});// Titre SUIVANT : slide index 1
if (nextTitle) {
nextTitle.textContent = getData(mod(1, total)).titre || '';
}// Couleur accent initiale
wrapper.style.setProperty('--accent', getData(0).couleur || '#E63946');// prefers-reduced-motion → pas d'autoplay
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
return;
}// Démarrage de l'autoplay
if (isPlaying) {
scheduleNext(); // Premier crossfade à OVERLAP_MS (3800ms)
startProgress(); // Barre de progression sur DISPLAY_MS (5000ms)
}
})();
}/* ─────────────────────────────────────────────────────────
BOOTSTRAP — Initialise tous les sliders de la page
───────────────────────────────────────────────────────── */
function boot() {
document.querySelectorAll('.km-hero-slider').forEach(initKMSlider);
}if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', boot);
} else {
boot();
}})();)
*
* CORRECTIONS v11 vs v10 :
* 1. Throbber : exclut explicitement #kpm-cta-artiste du listener
* (sécurité supplémentaire, target="_blank" suffit déjà).
* 2. Aucune autre logique modifiée (rétrocompatible v10).
* ════════════════════════════════════════════════════════════════
*/
(function () {
'use strict';document.readyState === 'loading'
? document.addEventListener('DOMContentLoaded', init)
: init();function init() {
injectPageLoader();
initCompactOnScroll();
initProgressBar();
initDynamicColors();
initMegaMenu();
initArtistePageActive();
initActualitesPageActive();
initBurgerMenu();
initThrobberLoader();
}/* ══════════════════════════════════════════════════════════════
UTILITAIRES COULEUR
══════════════════════════════════════════════════════════════ */
function hexToRgb(hex) {
var c = (hex || '').replace('#', '');
if (c.length === 3) c = c[0]+c[0]+c[1]+c[1]+c[2]+c[2];
var m = /^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(c);
return m ? { r:parseInt(m[1],16), g:parseInt(m[2],16), b:parseInt(m[3],16) } : null;
}function tintLogoImage(img, hexColor) {
if (!img || img.tagName !== 'IMG') return;
var rgb = hexToRgb(hexColor); if (!rgb) return;
if (!img.dataset.originalSrc) img.dataset.originalSrc = img.src;
var t = new Image(); t.crossOrigin = 'anonymous';
t.onload = function() {
try {
var cv = document.createElement('canvas');
cv.width = t.naturalWidth || 100; cv.height = t.naturalHeight || 100;
var ctx = cv.getContext('2d'); ctx.drawImage(t,0,0);
var id = ctx.getImageData(0,0,cv.width,cv.height), d = id.data;
for (var i=0; i10) {
var l=(d[i]*.299+d[i+1]*.587+d[i+2]*.114)/255;
d[i]=Math.round(rgb.r*l); d[i+1]=Math.round(rgb.g*l); d[i+2]=Math.round(rgb.b*l);
}
}
ctx.putImageData(id,0,0);
img.src = cv.toDataURL('image/png'); img.style.filter='none';
} catch(e) { applyLogoFilterFallback(img, hexColor); }
};
t.onerror = function() { applyLogoFilterFallback(img, hexColor); };
t.src = img.dataset.originalSrc;
}function applyLogoFilterFallback(img, hex) {
var rgb = hexToRgb(hex);
if (!rgb) { img.style.filter='brightness(0) invert(1)'; return; }
var r=rgb.r/255,g=rgb.g/255,b=rgb.b/255,
mx=Math.max(r,g,b),mn=Math.min(r,g,b),h=0,s=0,l=(mx+mn)/2;
if (mx!==mn){var d=mx-mn; s=l>.5?d/(2-mx-mn):d/(mx+mn);
if(mx===r) h=((g-b)/d+(g THRESHOLD; if (sc===isCompact) return;
isCompact=sc; header.classList.toggle('kpm-compact',isCompact); applyState(isCompact);
}, {passive:true});window.addEventListener('resize', function() {
H_NORMAL = window.matchMedia('(max-width:600px)').matches ? 56
: window.matchMedia('(max-width:868px)').matches ? 60
: window.matchMedia('(max-width:1024px)').matches ? 64 : 72;
if (!isCompact) applyState(false);
}, {passive:true});applyState(false);
}/* ══════════════════════════════════════════════════════════════
2. BARRE DE PROGRESSION
══════════════════════════════════════════════════════════════ */
function initProgressBar() {
var bar = document.getElementById('kpm-progress')||document.querySelector('.kpm-progress-bar');
if (!bar) return;
window.addEventListener('scroll', function() {
var s=document.documentElement.scrollTop||document.body.scrollTop;
var t=document.documentElement.scrollHeight-document.documentElement.clientHeight;
bar.style.width = t>0 ? (s/t*100)+'%' : '0%';
}, {passive:true});
}/* ══════════════════════════════════════════════════════════════
3. COULEURS DYNAMIQUES
══════════════════════════════════════════════════════════════ */
function initDynamicColors() {
var menuLinks = document.querySelectorAll('.kpm-menu > li > a[data-color]');
var logo = document.getElementById('kpm-logo-svg')||document.getElementById('kpm-logo-text');
var bar = document.getElementById('kpm-progress')||document.querySelector('.kpm-progress-bar');
if (!menuLinks.length) return;var activeLink = null;
var initItem = document.querySelector('.kpm-menu > li.current-menu-item > a[data-color]');
if (initItem && !document.body.classList.contains('single-nos-artistes')
&& !document.body.classList.contains('kpm-is-actualites')) {
activeLink = initItem;
colorItem(initItem, initItem.getAttribute('data-color')||'#6621c3');
applyLogoColor(logo, initItem.getAttribute('data-logo-color')||initItem.getAttribute('data-color')||'#6621c3');
if (bar) bar.style.background = initItem.getAttribute('data-color')||'#6621c3';
}menuLinks.forEach(function(link) {
var mc = link.getAttribute('data-color')||'#6621c3';
var lc = link.getAttribute('data-logo-color')||mc;
var li = link.closest('li');link.addEventListener('mouseenter', function() { colorItem(link,mc); });
link.addEventListener('mouseleave', function() {
var act = (link===activeLink)||(li&&(li.classList.contains('current-menu-item')||li.classList.contains('nos-artistes-actif')));
act ? colorItem(link,mc) : resetItem(link);
});
link.addEventListener('click', function() {
if (link.classList.contains('kpm-menu-trigger')) return;
menuLinks.forEach(function(l2){
var l2li=l2.closest('li'); if(l2li) l2li.classList.remove('current-menu-item');
if(l2!==link) resetItem(l2);
});
li&&li.classList.add('current-menu-item');
activeLink=link; colorItem(link,mc); applyLogoColor(logo,lc);
if (bar) bar.style.background=mc;
});
});
}/* ══════════════════════════════════════════════════════════════
4. PAGES ARTISTE — item "Nos Artistes" actif
══════════════════════════════════════════════════════════════ */
function initArtistePageActive() {
if (!document.body.classList.contains('single-nos-artistes')) return;
var trigger = document.querySelector('.kpm-menu-trigger');
var logo = document.getElementById('kpm-logo-svg')||document.getElementById('kpm-logo-text');
var bar = document.getElementById('kpm-progress')||document.querySelector('.kpm-progress-bar');
if (!trigger) return;
var mc=trigger.getAttribute('data-color')||'#c0392b';
var lc=trigger.getAttribute('data-logo-color')||mc;
var li=trigger.closest('li');
if (li) { li.classList.add('nos-artistes-actif','current-menu-item'); }
colorItem(trigger,mc); applyLogoColor(logo,lc);
if (bar) bar.style.background=mc;
}/* ══════════════════════════════════════════════════════════════
5. PAGES ACTUALITÉS — item "Actualités" actif
══════════════════════════════════════════════════════════════ */
function initActualitesPageActive() {
if (!document.body.classList.contains('kpm-is-actualites')) return;var logo = document.getElementById('kpm-logo-svg')||document.getElementById('kpm-logo-text');
var bar = document.getElementById('kpm-progress')||document.querySelector('.kpm-progress-bar');var actuLink = null;
var menuLinks = document.querySelectorAll('.kpm-menu > li > a[data-color]');
menuLinks.forEach(function(link) {
var label = (link.querySelector('.menu-label')||link).textContent.toLowerCase().trim();
if (label.indexOf('actu') !== -1 || label.indexOf('news') !== -1 || label.indexOf('blog') !== -1) {
actuLink = link;
}
});if (!actuLink) return;var mc = actuLink.getAttribute('data-color') || '#6621c3';
var lc = actuLink.getAttribute('data-logo-color') || mc;
var li = actuLink.closest('li');if (li) li.classList.add('current-menu-item', 'kpm-actualites-actif');
colorItem(actuLink, mc);
applyLogoColor(logo, lc);
if (bar) bar.style.background = mc;
}/* ══════════════════════════════════════════════════════════════
6. MÉGA MENU
══════════════════════════════════════════════════════════════ */
function initMegaMenu() {
var trigger = document.querySelector('.kpm-menu-trigger');
var dropdown = document.querySelector('.has-megamenu .aa-dropdown');
var btnBack = dropdown ? dropdown.querySelector('.aa-dropdown-back') : null;
var logo = document.getElementById('kpm-logo-svg')||document.getElementById('kpm-logo-text');
var bar = document.getElementById('kpm-progress')||document.querySelector('.kpm-progress-bar');
if (!trigger || !dropdown) return;var isOpen = false;
var mc = trigger.getAttribute('data-color') || '#6621c3';
var lc = trigger.getAttribute('data-logo-color') || mc;
var li = trigger.closest('li');function open() {
isOpen = true;
dropdown.classList.add('is-open');
dropdown.setAttribute('aria-hidden','false');
trigger.setAttribute('aria-expanded','true');
colorItem(trigger,mc); applyLogoColor(logo,lc);
if (bar) bar.style.background = mc;
if (!isMobileNav()) {
dropdown.querySelectorAll('.aa-drop-card').forEach(function(c,i){
c.style.animationDelay = (i*.04)+'s';
});
}
}function close() {
isOpen = false;
dropdown.classList.remove('is-open');
dropdown.setAttribute('aria-hidden','true');
trigger.setAttribute('aria-expanded','false');
if (!document.body.classList.contains('single-nos-artistes')
&& li && !li.classList.contains('current-menu-item')) {
resetItem(trigger);
}
}trigger.addEventListener('click', function(e) {
e.preventDefault(); e.stopPropagation();
isOpen ? close() : open();
});if (btnBack) {
btnBack.addEventListener('click', function(e) {
e.stopPropagation();
close();
trigger.focus();
});
}document.addEventListener('click', function(e) {
if (!isOpen || isMobileNav()) return;
if (!dropdown.contains(e.target) && !trigger.contains(e.target)) close();
});document.addEventListener('keydown', function(e) {
if (e.key==='Escape' && isOpen) close();
});dropdown.addEventListener('wheel', function(e) {
if (isMobileNav()) return;
var grid = dropdown.querySelector('.aa-dropdown-grid');
if (grid && !dropdown.classList.contains('aa-dropdown-grid--wrap')) {
e.preventDefault(); grid.scrollLeft += e.deltaY;
}
}, {passive:false});
}/* ══════════════════════════════════════════════════════════════
7. BURGER MENU
══════════════════════════════════════════════════════════════ */
function initBurgerMenu() {
var burger = document.getElementById('kpm-burger');
var nav = document.getElementById('kpm-nav');
var overlay = document.getElementById('kpm-overlay');
var dropdown = document.querySelector('.has-megamenu .aa-dropdown');
if (!burger || !nav || !overlay) return;
var isOpen = false;function openNav() {
isOpen = true;
burger.classList.add('is-active');
burger.setAttribute('aria-expanded','true');
nav.classList.add('is-active');
overlay.classList.add('is-active');
overlay.setAttribute('aria-hidden','false');
document.body.style.overflow = 'hidden';
}function closeNav() {
isOpen = false;
if (dropdown && dropdown.classList.contains('is-open')) {
dropdown.classList.remove('is-open');
dropdown.setAttribute('aria-hidden','true');
var trig = document.querySelector('.kpm-menu-trigger');
if (trig) trig.setAttribute('aria-expanded','false');
}
burger.classList.remove('is-active');
burger.setAttribute('aria-expanded','false');
nav.classList.remove('is-active');
overlay.classList.remove('is-active');
overlay.setAttribute('aria-hidden','true');
document.body.style.overflow = '';
}burger.addEventListener('click', function() { isOpen ? closeNav() : openNav(); });
overlay.addEventListener('click', closeNav);nav.querySelectorAll('.kpm-menu a').forEach(function(l) {
l.addEventListener('click', function() {
if (l.classList.contains('kpm-menu-trigger')) return;
if (isOpen) setTimeout(closeNav, 250);
});
});document.addEventListener('keydown', function(e) {
if (e.key==='Escape' && isOpen) closeNav();
});
}/* ══════════════════════════════════════════════════════════════
8. THROBBER LOADER
══════════════════════════════════════════════════════════════
v11 : exclut #kpm-cta-artiste (target="_blank" suffit déjà,
mais on sécurise avec un check explicite sur l'id).
══════════════════════════════════════════════════════════════ */
function initThrobberLoader() {
var logo = document.getElementById('kpm-logo-svg')||document.getElementById('kpm-logo-text');
var overlay = document.getElementById('kpm-page-loader');
var iconEl = document.getElementById('kpm-loader-icon');if (logo && logo.tagName==='IMG' && iconEl && iconEl.tagName==='IMG') {
iconEl.src = logo.dataset.originalSrc || logo.src;
}var isLoading=false, kickT=null, stopT=null, safeT=null;function clearClasses(el) {
if (!el) return;
el.classList.remove('kpm-throbber-kick','kpm-throbbing','kpm-throbber-stop');
}function startThrobber() {
if (isLoading) return; isLoading=true;
clearTimeout(kickT); clearTimeout(stopT); clearTimeout(safeT);
overlay && overlay.classList.add('kpm-loader-active');
overlay && overlay.classList.remove('kpm-loader-exit');
[logo, iconEl].forEach(function(el){ clearClasses(el); el&&el.classList.add('kpm-throbber-kick'); });
kickT = setTimeout(function() {
if (!isLoading) return;
[logo, iconEl].forEach(function(el){ clearClasses(el); el&&el.classList.add('kpm-throbbing'); });
}, 600);
safeT = setTimeout(stopThrobber, 8000);
}function stopThrobber() {
if (!isLoading) return; isLoading=false;
clearTimeout(kickT); clearTimeout(safeT);
[logo, iconEl].forEach(function(el){ clearClasses(el); el&&el.classList.add('kpm-throbber-stop'); });
if (overlay) { overlay.classList.remove('kpm-loader-active'); overlay.classList.add('kpm-loader-exit'); }
stopT = setTimeout(function() {
[logo, iconEl].forEach(function(el){ clearClasses(el); });
overlay&&overlay.classList.remove('kpm-loader-exit');
}, 600);
}document.querySelectorAll('.kpm-menu a').forEach(function(link) {
link.addEventListener('click', function() {
if (link.classList.contains('kpm-menu-trigger')) return;
if (link.target==='_blank') return;
/* v11 : sécurité supplémentaire — ne jamais throbber sur le CTA artiste */
if (link.id === 'kpm-cta-artiste') return;
startThrobber();
window.addEventListener('beforeunload', stopThrobber, {once:true});
});
});window.addEventListener('load', function() { if (isLoading) stopThrobber(); });
window.addEventListener('pageshow', function() { if (isLoading) stopThrobber(); });
window.addEventListener('popstate', function() { if (isLoading) stopThrobber(); });
}})();)
*
* Comportement style Reach Records :
* → Clic "Nos Artistes" = dropdown s'ouvre SOUS le header
* → La page en dessous reste visible
* → L'URL passe à /nos-artistes/ via pushState
* → Clic en dehors / Échap / ✕ = ferme
* → Clic sur une image = navigue vers l'artiste
* ================================================================
*/
(function () {
'use strict';document.readyState === 'loading'
? document.addEventListener('DOMContentLoaded', init)
: init();function init() {
var trigger = document.querySelector('.rr-menu-trigger, .aa-nav-trigger');
var dropdown = document.getElementById('aa-dropdown');if (!trigger || !dropdown) return;var btnClose = dropdown.querySelector('.aa-dropdown-close');
var archiveUrl = trigger.getAttribute('href') || '/nos-artistes/';
var urlOrigin = window.location.href;
var isOpen = false;
var histPushed = false;/* ── Hauteur du header → positionne le dropdown ── */
function updateHeaderHeight() {
var header = document.querySelector(
'#masthead, .main-header-bar, .ast-primary-header-bar, .site-header, header'
);
if (header) {
var h = Math.round(header.getBoundingClientRect().height);
document.documentElement.style.setProperty('--rr-header-h', h + 'px');
dropdown.style.top = h + 'px';
}
}
updateHeaderHeight();
window.addEventListener('resize', updateHeaderHeight, { passive: true });/* ── OUVRIR ── */
function open() {
if (isOpen) return;
isOpen = true;dropdown.classList.add('is-open');
dropdown.setAttribute('aria-hidden', 'false');
trigger.classList.add('is-active');
trigger.setAttribute('aria-expanded', 'true');/* URL → /nos-artistes/ sans rechargement */
if (window.history && window.history.pushState) {
urlOrigin = window.location.href;
window.history.pushState({ aaMenu: true }, 'Nos Artistes', archiveUrl);
histPushed = true;
}/* Animation cascade des cartes */
var cartes = dropdown.querySelectorAll('.aa-drop-card');
cartes.forEach(function (c, i) {
c.classList.remove('rr-animate');
c.style.animationDelay = (i * 0.04) + 's';
void c.offsetWidth; // force reflow
c.classList.add('rr-animate');
});/* Focus accessibilité */
var first = dropdown.querySelector('.aa-drop-card');
if (first) setTimeout(function () { first.focus(); }, 60);
}/* ── FERMER ── */
function close(opts) {
opts = opts || {};
if (!isOpen) return;
isOpen = false;dropdown.classList.remove('is-open');
dropdown.setAttribute('aria-hidden', 'true');
trigger.classList.remove('is-active');
trigger.setAttribute('aria-expanded', 'false');/* Remet l'URL d'origine */
if (!opts.noHistory && histPushed && window.history && window.history.pushState) {
window.history.pushState({ aaMenu: false }, document.title, urlOrigin);
histPushed = false;
}/* Reset animations */
dropdown.querySelectorAll('.aa-drop-card').forEach(function (c) {
c.classList.remove('rr-animate');
c.style.animationDelay = '';
});trigger.focus();
}/* ── Clic sur le trigger ── */
trigger.addEventListener('click', function (e) {
e.preventDefault();
e.stopPropagation();if (isOpen) {
/* 2e clic → naviguer vers la page archive */
close({ noHistory: true });
window.location.href = archiveUrl;
} else {
open();
}
});/* ── Bouton ✕ ── */
if (btnClose) {
btnClose.addEventListener('click', function (e) {
e.stopPropagation();
close();
});
}/* ── Clic en dehors ── */
document.addEventListener('click', function (e) {
if (!isOpen) return;
if (!dropdown.contains(e.target) && !trigger.contains(e.target)) close();
});/* ── Touche Échap ── */
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape' && isOpen) close();
});/* ── Navigation clavier dans le dropdown ── */
dropdown.addEventListener('keydown', function (e) {
var liens = Array.from(dropdown.querySelectorAll('.aa-drop-card'));
var idx = liens.indexOf(document.activeElement);
if (idx === -1) return;
var next;
switch (e.key) {
case 'ArrowRight': case 'ArrowDown': next = liens[(idx + 1) % liens.length]; break;
case 'ArrowLeft': case 'ArrowUp': next = liens[(idx - 1 + liens.length) % liens.length]; break;
case 'Home': next = liens[0]; break;
case 'End': next = liens[liens.length - 1]; break;
default: return;
}
if (next) { e.preventDefault(); next.focus(); }
});/* ── Bouton Précédent du navigateur ── */
window.addEventListener('popstate', function () {
if (isOpen) {
isOpen = false;
dropdown.classList.remove('is-open');
dropdown.setAttribute('aria-hidden', 'true');
trigger.classList.remove('is-active');
trigger.setAttribute('aria-expanded', 'false');
histPushed = false;
dropdown.querySelectorAll('.aa-drop-card').forEach(function (c) {
c.classList.remove('rr-animate');
});
}
});/* ── Scroll horizontal dans le dropdown (tactile) ── */
dropdown.addEventListener('wheel', function (e) {
var grid = dropdown.querySelector('.aa-dropdown-grid');
if (grid && !dropdown.classList.contains('aa-dropdown-grid--wrap')) {
e.preventDefault();
grid.scrollLeft += e.deltaY;
}
}, { passive: false });
}})();