(() => {
const loadTailwind = () => {
if (window.tailwind) return;
const tw = document.createElement('script');
tw.src = 'https://cdn.tailwindcss.com';
tw.async = true;
document.head.appendChild(tw);
};
loadTailwind();
const i18n = {
ru: {
siteTitle: '',
nav: { home: 'Главная', catalog: 'Каталог', contact: 'Контакты' },
welcome: {
title: 'Добро пожаловать',
subtitle: 'Подождите 3‑5 секунд, чтобы увидеть демонстрацию адаптивного модального окна.'
},
popup: {
title: 'Рекламные предложения',
timerPrefix: 'Закроется через',
timerSuffix: 'сек.',
closeBtn: 'Закрыть окно',
learnMore: 'Получить бонус',
closeIconAria: 'Close popup'
},
placeholder: 'Контент сайта {n}'
},
en: {
siteTitle: '',
nav: { home: 'Home', catalog: 'Catalog', contact: 'Contact' },
welcome: { title: 'Welcome', subtitle: 'Wait 3‑5 seconds to see the responsive modal demo.' },
popup: {
title: 'Promotional Offers',
timerPrefix: 'Will close in',
timerSuffix: 'seconds',
closeBtn: 'Close window',
learnMore: 'Get a bonus',
closeIconAria: 'Close popup'
},
placeholder: 'Site content {n}'
}
};
let currentLang = (navigator.language || '').startsWith('en') ? 'en' : 'ru';
const t = (path, ...repl) => {
const parts = path.split('.');
let txt = i18n[currentLang];
for (const p of parts) txt = txt?.[p];
if (txt && repl.length) {
repl.forEach((v, i) => { txt = txt.replace(`{${i}}`, v); });
}
return txt ?? '';
};
const createPopup = (offers, autoCloseSec) => {
const backdrop = document.createElement('div');
backdrop.className = 'fixed inset-0 bg-black/60 backdrop-blur-sm transition-opacity';
backdrop.setAttribute('aria-hidden', 'true');
const container = document.createElement('div');
container.className = 'fixed inset-0 z-10 overflow-y-auto';
const wrapper = document.createElement('div');
wrapper.className = 'flex min-h-full items-center justify-center p-4 text-center';
const panel = document.createElement('div');
panel.className = 'relative w-full max-w-5xl transform bg-white text-left rounded-2xl shadow-2xl animate-popup flex flex-col overflow-hidden my-8 transition-all';
const header = document.createElement('div');
header.className = 'flex items-center justify-between px-6 py-4 border-b border-gray-100 bg-gray-50/50 sticky top-0 z-20 backdrop-blur-md';
const h2 = document.createElement('h2');
h2.id = 'popup-title';
h2.className = 'text-xl md:text-2xl font-bold text-gray-800';
h2.textContent = t('popup.title');
const headerRight = document.createElement('div');
headerRight.className = 'flex items-center space-x-4';
const timerBadge = document.createElement('div');
timerBadge.className = 'flex items-center space-x-2 text-gray-500 bg-gray-100 px-3 py-1.5 rounded-full text-sm font-medium whitespace-nowrap';
timerBadge.innerHTML = `
${t('popup.timerPrefix')} ${t('popup.timerSuffix')}
`;
const closeBtn = document.createElement('button');
closeBtn.className = 'group p-2 rounded-full bg-red-50 hover:bg-red-100 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-red-500';
closeBtn.setAttribute('aria-label', t('popup.closeIconAria'));
closeBtn.innerHTML = `
`;
closeBtn.style.display = 'none';
headerRight.append(timerBadge, closeBtn);
header.append(h2, headerRight);
const body = document.createElement('div');
body.className = 'p-6 md:p-8 bg-white';
const grid = document.createElement('div');
grid.className = 'grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6';
offers.forEach(offer => {
const a = document.createElement('a');
a.href = offer.linkUrl;
a.target = '_blank';
a.rel = 'noopener noreferrer';
a.className = 'group flex flex-col h-full bg-white rounded-xl border border-gray-200 overflow-hidden hover:shadow-xl hover:border-blue-200 transition-all duration-300 transform hover:-translate-y-1';
const imgWrap = document.createElement('div');
imgWrap.className = 'relative w-full aspect-video overflow-hidden bg-gray-200 shrink-0';
const img = document.createElement('img');
img.src = offer.imageUrl;
img.alt = offer.title[currentLang] ?? offer.title.en;
img.className = 'w-full h-full object-cover transition-transform duration-500 group-hover:scale-105';
img.loading = 'lazy';
const overlay = document.createElement('div');
overlay.className = 'absolute inset-0 bg-black/0 group-hover:bg-black/5 transition-colors duration-300';
imgWrap.append(img, overlay);
const content = document.createElement('div');
content.className = 'flex flex-col flex-grow p-5';
const h3 = document.createElement('h3');
h3.className = 'text-lg font-bold text-gray-900 mb-2 group-hover:text-blue-600 transition-colors';
h3.textContent = offer.title[currentLang] ?? offer.title.en;
const p = document.createElement('p');
p.className = 'text-gray-600 text-sm mb-4 line-clamp-2 flex-grow';
p.textContent = offer.description[currentLang] ?? offer.description.en;
const linkWrap = document.createElement('div');
linkWrap.className = 'mt-auto';
const linkSpan = document.createElement('span');
linkSpan.className = 'inline-flex items-center text-sm font-semibold text-blue-600 group-hover:text-blue-700 transition-colors';
linkSpan.innerHTML = `
${t('popup.learnMore')}
`;
linkWrap.append(linkSpan);
content.append(h3, p, linkWrap);
a.append(imgWrap, content);
grid.appendChild(a);
});
body.appendChild(grid);
const footer = document.createElement('div');
footer.className = 'md:hidden px-6 pb-6';
const mobileClose = document.createElement('button');
mobileClose.className = 'w-full py-3 bg-gray-100 hover:bg-gray-200 text-gray-800 font-semibold rounded-lg transition-colors';
mobileClose.textContent = t('popup.closeBtn');
mobileClose.style.display = 'none';
footer.appendChild(mobileClose);
panel.append(header, body, footer);
wrapper.appendChild(panel);
container.appendChild(wrapper);
const root = document.createElement('div');
root.className = 'relative z-50';
root.setAttribute('role', 'dialog');
root.setAttribute('aria-modal', 'true');
root.setAttribute('aria-labelledby', 'popup-title');
root.append(backdrop, container);
document.body.appendChild(root);
let timeLeft = autoCloseSec;
const timerEl = document.getElementById('popup-timer');
const tick = () => {
timeLeft--;
if (timerEl) timerEl.textContent = timeLeft;
if (timeLeft <= 0) {
clearInterval(timerId);
timerBadge.style.display = 'none';
closeBtn.style.display = '';
mobileClose.style.display = '';
}
};
const timerId = setInterval(tick, 1000);
const closeAll = () => {
clearInterval(timerId);
root.remove();
};
closeBtn.addEventListener('click', closeAll);
mobileClose.addEventListener('click', closeAll);
backdrop.addEventListener('click', closeAll);
};
const DEFAULT_OFFERS = [
{
id: '1',
title: { ru: '300 % до 3000 $', en: '300% up to 3000$' },
description: { ru: "Не упустите приветственный бонус: 200% + 30FS+100%! Только сегодня!", en: "Don't miss out on the welcome bonus: 200% + 30FS+100%! Only today!" },
imageUrl: 'https://image2url.com/r2/default/images/1773919449944-3a6ade99-c2d4-48f2-9ac1-9c45a0ae2825.png',
linkUrl: 'https://t.nimje.org/zhv8c5'
},
{
id: '2',
title: { ru: '300 % до 3000 $', en: '300% up to 3000$' },
description: { ru: "Не упустите приветственный бонус: 200% + 30FS+100%! Только сегодня!", en: "Don't miss out on the welcome bonus: 200% + 30FS+100%! Only today!" },
imageUrl: 'https://image2url.com/r2/default/images/1773919449944-3a6ade99-c2d4-48f2-9ac1-9c45a0ae2825.png',
linkUrl: 'https://shorturl.fm/czrAS'
}
,
{
id: '3',
title: { ru: '300 % до 3000 $', en: '300% up to 3000$' },
description: { ru: "Не упустите приветственный бонус: 200% + 30FS+100%! Только сегодня!", en: "Don't miss out on the welcome bonus: 200% + 30FS+100%! Only today!" },
imageUrl: 'https://image2url.com/r2/default/images/1773919449944-3a6ade99-c2d4-48f2-9ac1-9c45a0ae2825.png',
linkUrl: 'https://t.nimje.org/zhv8c5'
}
];
const PromoPopup = {
init(cfg = {}) {
if (cfg.lang && (cfg.lang === 'ru' || cfg.lang === 'en')) {
currentLang = cfg.lang;
}
if (cfg.customTexts) {
Object.entries(cfg.customTexts).forEach(([lang, map]) => {
if (i18n[lang]) {
i18n[lang] = { ...i18n[lang], ...map };
}
});
}
const offers = cfg.offers ?? DEFAULT_OFFERS;
const timer = Number.isInteger(cfg.autoCloseTimer) ? cfg.autoCloseTimer : 5;
const delay = Number.isInteger(cfg.delay) ? cfg.delay : 10000;
setTimeout(() => createPopup(offers, timer), delay);
}
};
window.PromoPopup = PromoPopup;
})();