(function() {
document.documentElement.classList.add('menu-loading');
const criticalStyle = document.createElement('style');
criticalStyle.textContent = `
html.menu-loading .bf-expandable-menu {
display: none !important;
visibility: hidden !important;
opacity: 0 !important;
max-height: 0 !important;
overflow: hidden !important;
transition: none !important;
pointer-events: none !important;
}
`;
document.head.appendChild(criticalStyle);
})();
document.addEventListener('DOMContentLoaded', function() {
const style = document.createElement('style');
style.textContent = `
html.menu-loading * .bf-expandable-menu {
transition: none !important;
}
.bf-expandable-menu {
opacity: 0;
max-height: 0;
margin-bottom: 0;
overflow: hidden;
pointer-events: none;
transform-origin: top center;
transform: translateY(-20px);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
will-change: transform, opacity, max-height;
visibility: hidden;
}
.bf-expandable-menu.active {
opacity: 1;
max-height: 520px;
margin-bottom: 16px;
pointer-events: auto;
transform: translateY(0);
visibility: visible;
}
.bf-expandable-menu > * {
opacity: 0;
transform: translateY(-10px);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
will-change: transform, opacity;
}
.bf-expandable-menu.active > * {
opacity: 1;
transform: translateY(0);
}
[data-menu-trigger].active-trigger {
background-color: rgba(169, 169, 169, 0.2);
border-radius: 6px;
padding: 6px 12px;
transition: all 0.2s ease;
position: relative;
}
[data-menu-trigger].active-trigger:hover {
background-color: rgba(169, 169, 169, 0.25);
}
.bf-expandable-menu.instant-close,
.bf-expandable-menu.instant-close > * {
transition: none !important;
}
.bf-expandable-menu.no-animation,
.bf-expandable-menu.no-animation > * {
transition: none !important;
}
.bf-blur-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.4));
backdrop-filter: blur(8px);
opacity: 0;
visibility: hidden;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
z-index: 999;
}
.bf-blur-overlay.active {
opacity: 1;
visibility: visible;
}
.Blur {
position: relative;
z-index: 1000;
}
`;
document.head.appendChild(style);
const overlay = document.createElement('div');
overlay.className = 'bf-blur-overlay';
document.body.appendChild(overlay);
const menuTriggers = document.querySelectorAll('[data-menu-trigger]');
const menus = document.querySelectorAll('.bf-expandable-menu');
menus.forEach(menu => {
menu.style.opacity = '0';
menu.style.visibility = 'hidden';
menu.style.maxHeight = '0';
menu.style.overflow = 'hidden';
menu.style.pointerEvents = 'none';
});
function updateTriggerState(targetId, isActive) {
menuTriggers.forEach(trigger => {
const triggerId = trigger.getAttribute('data-menu-trigger');
if (triggerId === targetId) {
isActive
? trigger.classList.add('active-trigger')
: trigger.classList.remove('active-trigger');
}
});
}
function handleMenuTransition(menu, isClosing, instantClose = false) {
return new Promise((resolve) => {
const menuId = menu.id;
if (instantClose) {
menu.classList.add('instant-close');
menu.classList.remove('active');
menu.style.visibility = 'hidden';
overlay.classList.remove('active');
updateTriggerState(menuId, false);
setTimeout(() => {
menu.classList.remove('instant-close');
resolve();
}, 50);
return;
}
if (isClosing) {
menu.classList.remove('active');
overlay.classList.remove('active');
updateTriggerState(menuId, false);
setTimeout(() => {
menu.style.visibility = 'hidden';
resolve();
}, 400);
} else {
menu.style.visibility = 'visible';
requestAnimationFrame(() => {
menu.classList.add('active');
overlay.classList.add('active');
updateTriggerState(menuId, true);
setTimeout(resolve, 50);
});
}
});
}
async function closeAllMenus(exceptMenuId = null) {
const closingPromises = Array.from(menus).map(menu => {
if (menu.id !== exceptMenuId && menu.classList.contains('active')) {
return handleMenuTransition(menu, true, !!exceptMenuId);
}
return Promise.resolve();
});
await Promise.all(closingPromises);
}
menuTriggers.forEach(trigger => {
trigger.addEventListener('click', async function(e) {
e.preventDefault();
e.stopPropagation();
const targetId = this.getAttribute('data-menu-trigger');
const targetMenu = document.getElementById(targetId);
if (!targetMenu) return;
if (targetMenu.classList.contains('active')) {
await handleMenuTransition(targetMenu, true);
return;
}
await closeAllMenus(targetId);
await handleMenuTransition(targetMenu, false);
});
});
document.addEventListener('click', function(e) {
const isClickInsideMenu = Array.from(menus).some(menu => menu.contains(e.target));
const isClickOnTrigger = Array.from(menuTriggers).some(trigger => trigger.contains(e.target));
if (!isClickInsideMenu && !isClickOnTrigger) {
closeAllMenus();
}
});
window.addEventListener('load', function() {
setTimeout(() => {
document.documentElement.classList.remove('menu-loading');
setTimeout(() => {
menus.forEach(menu => {
menu.removeAttribute('style');
});
}, 100);
}, 50);
});
});
v2.0
Transform your static text into dynamic, eye-catching content with smooth word rotation animations.
Enter words to rotate through in your animation
How long each word is displayed before rotating
Speed of the transition between words
Choose how words transition
Color of the rotating words