I’ll shape this as a production-ready standalone chunk file for RX Theme: safe vanilla JavaScript, no dependency, WordPress-friendly, accessibility-ready, and easy to connect with PHP/localized settings.
Dear friend, for this file:
assets/static-js/static-chunks-js/chunk-036-notification.js
use this advanced RX Theme notification chunk. It includes toast notifications, alert bars, modal notices, browser notification permission handling, localStorage history, AJAX-ready hooks, accessibility, reduced-motion support, auto-dismiss, sound option, event API, and WordPress-friendly global settings.
/*!
* RX Theme - Notification Chunk
* File: assets/static-js/static-chunks-js/chunk-036-notification.js
* Version: 1.0.0
* Author: RxHarun
*
* Purpose:
* - Toast notifications
* - Site alert bars
* - Modal notices
* - Browser notification permission helper
* - LocalStorage notification history
* - WordPress-friendly global API
*
* Global API:
* window.RXThemeNotification.success('Message')
* window.RXThemeNotification.error('Message')
* window.RXThemeNotification.warning('Message')
* window.RXThemeNotification.info('Message')
* window.RXThemeNotification.show({...})
* window.RXThemeNotification.alertBar({...})
* window.RXThemeNotification.modal({...})
*/
(function RXNotificationChunk(window, document) {
'use strict';
if (!window || !document) return;
var RX = window.RXThemeNotification || {};
var docEl = document.documentElement;
var body = document.body;
var DEFAULTS = {
containerId: 'rx-notification-container',
alertBarId: 'rx-site-alert-bar',
modalId: 'rx-notification-modal',
position: 'top-right',
maxVisible: 5,
duration: 6000,
animationDuration: 250,
closeOnClick: false,
pauseOnHover: true,
newestOnTop: true,
saveHistory: true,
historyLimit: 30,
storageKey: 'rx_theme_notification_history',
sound: false,
soundUrl: '',
enableBrowserNotification: false,
browserNotificationIcon: '',
debug: false
};
var config = mergeObjects(DEFAULTS, window.rxNotificationConfig || {});
var queue = [];
var activeToasts = [];
var initialized = false;
var uniqueCounter = 0;
var TYPE_MAP = {
success: {
label: 'Success',
icon: '✓',
className: 'rx-notification--success'
},
error: {
label: 'Error',
icon: '!',
className: 'rx-notification--error'
},
warning: {
label: 'Warning',
icon: '⚠',
className: 'rx-notification--warning'
},
info: {
label: 'Information',
icon: 'i',
className: 'rx-notification--info'
},
loading: {
label: 'Loading',
icon: '…',
className: 'rx-notification--loading'
},
medical: {
label: 'Medical Notice',
icon: '+',
className: 'rx-notification--medical'
}
};
function init(customConfig) {
if (initialized) return RX;
if (customConfig && typeof customConfig === 'object') {
config = mergeObjects(config, customConfig);
}
injectBaseStyles();
createContainer();
bindGlobalListeners();
initialized = true;
log('RX Theme Notification initialized');
return RX;
}
function mergeObjects(target, source) {
var output = {};
var key;
target = target || {};
source = source || {};
for (key in target) {
if (Object.prototype.hasOwnProperty.call(target, key)) {
output[key] = target[key];
}
}
for (key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
output[key] = source[key];
}
}
return output;
}
function createContainer() {
var container = document.getElementById(config.containerId);
if (!container) {
container = document.createElement('div');
container.id = config.containerId;
container.className = 'rx-notification-container rx-notification-container--' + sanitizeClass(config.position);
container.setAttribute('aria-live', 'polite');
container.setAttribute('aria-atomic', 'false');
container.setAttribute('role', 'region');
container.setAttribute('aria-label', 'Website notifications');
body.appendChild(container);
}
return container;
}
function getContainer() {
return document.getElementById(config.containerId) || createContainer();
}
function show(options) {
init();
if (typeof options === 'string') {
options = {
message: options
};
}
options = mergeObjects({
id: '',
type: 'info',
title: '',
message: '',
duration: config.duration,
dismissible: true,
closeOnClick: config.closeOnClick,
pauseOnHover: config.pauseOnHover,
actionText: '',
actionUrl: '',
actionCallback: null,
html: false,
persistent: false,
sound: config.sound,
browserNotification: false,
data: {}
}, options || {});
options.type = TYPE_MAP[options.type] ? options.type : 'info';
options.id = options.id || generateId('rx-toast');
if (!options.title && TYPE_MAP[options.type]) {
options.title = TYPE_MAP[options.type].label;
}
if (!options.message && !options.title) {
return null;
}
if (activeToasts.length >= config.maxVisible) {
queue.push(options);
return options.id;
}
return renderToast(options);
}
function renderToast(options) {
var container = getContainer();
var toast = document.createElement('div');
var type = TYPE_MAP[options.type] || TYPE_MAP.info;
var closeBtn;
var timer = null;
var remaining = options.duration;
var startedAt = Date.now();
toast.id = options.id;
toast.className = [
'rx-notification',
type.className,
'rx-notification--enter'
].join(' ');
toast.setAttribute('role', options.type === 'error' ? 'alert' : 'status');
toast.setAttribute('aria-live', options.type === 'error' ? 'assertive' : 'polite');
toast.setAttribute('data-rx-notification-id', options.id);
toast.setAttribute('data-rx-notification-type', options.type);
toast.innerHTML = buildToastMarkup(options, type);
closeBtn = toast.querySelector('[data-rx-notification-close]');
if (closeBtn) {
closeBtn.addEventListener('click', function onCloseClick(event) {
event.preventDefault();
dismiss(options.id, 'button');
});
}
if (options.closeOnClick) {
toast.addEventListener('click', function onToastClick(event) {
if (event.target.closest('a, button')) return;
dismiss(options.id, 'click');
});
}
var actionBtn = toast.querySelector('[data-rx-notification-action]');
if (actionBtn) {
actionBtn.addEventListener('click', function onActionClick(event) {
if (typeof options.actionCallback === 'function') {
event.preventDefault();
options.actionCallback.call(toast, event, options);
}
emit('rx:notification:action', {
id: options.id,
type: options.type,
options: options
});
});
}
if (options.pauseOnHover && !options.persistent && options.duration > 0) {
toast.addEventListener('mouseenter', function onMouseEnter() {
if (timer) {
clearTimeout(timer);
timer = null;
remaining -= Date.now() - startedAt;
}
});
toast.addEventListener('mouseleave', function onMouseLeave() {
startedAt = Date.now();
timer = window.setTimeout(function autoDismissAfterHover() {
dismiss(options.id, 'timeout');
}, Math.max(100, remaining));
});
}
if (config.newestOnTop) {
container.insertBefore(toast, container.firstChild);
} else {
container.appendChild(toast);
}
activeToasts.push({
id: options.id,
element: toast,
options: options
});
requestAnimationFrame(function animateIn() {
toast.classList.remove('rx-notification--enter');
toast.classList.add('rx-notification--visible');
});
if (!options.persistent && options.duration > 0) {
startedAt = Date.now();
timer = window.setTimeout(function autoDismiss() {
dismiss(options.id, 'timeout');
}, options.duration);
}
toast._rxTimer = timer;
if (options.sound) {
playSound(options.soundUrl || config.soundUrl);
}
if (options.browserNotification || config.enableBrowserNotification) {
sendBrowserNotification(options.title, stripHTML(options.message), {
icon: config.browserNotificationIcon
});
}
if (config.saveHistory) {
saveHistoryItem(options);
}
emit('rx:notification:show', {
id: options.id,
type: options.type,
options: options
});
return options.id;
}
function buildToastMarkup(options, type) {
var title = escapeHTML(options.title || type.label);
var message = options.html ? String(options.message || '') : escapeHTML(options.message || '');
var icon = escapeHTML(options.icon || type.icon || '');
var actionHtml = '';
var closeHtml = '';
if (options.actionText) {
if (options.actionUrl) {
actionHtml =
'<a class="rx-notification__action" data-rx-notification-action href="' +
escapeAttr(options.actionUrl) +
'">' +
escapeHTML(options.actionText) +
'</a>';
} else {
actionHtml =
'<button class="rx-notification__action" data-rx-notification-action type="button">' +
escapeHTML(options.actionText) +
'</button>';
}
}
if (options.dismissible) {
closeHtml =
'<button class="rx-notification__close" data-rx-notification-close type="button" aria-label="Close notification">' +
'<span aria-hidden="true">×</span>' +
'</button>';
}
return (
'<div class="rx-notification__inner">' +
'<div class="rx-notification__icon" aria-hidden="true">' + icon + '</div>' +
'<div class="rx-notification__content">' +
'<strong class="rx-notification__title">' + title + '</strong>' +
'<div class="rx-notification__message">' + message + '</div>' +
actionHtml +
'</div>' +
closeHtml +
'</div>'
);
}
function dismiss(id, reason) {
var index = findToastIndex(id);
if (index === -1) return false;
var item = activeToasts[index];
var toast = item.element;
if (toast._rxTimer) {
clearTimeout(toast._rxTimer);
toast._rxTimer = null;
}
toast.classList.remove('rx-notification--visible');
toast.classList.add('rx-notification--exit');
window.setTimeout(function removeToast() {
if (toast && toast.parentNode) {
toast.parentNode.removeChild(toast);
}
activeToasts.splice(index, 1);
emit('rx:notification:dismiss', {
id: id,
reason: reason || 'manual',
options: item.options
});
processQueue();
}, config.animationDuration + 50);
return true;
}
function dismissAll(reason) {
var ids = activeToasts.map(function mapToast(item) {
return item.id;
});
ids.forEach(function eachToast(id) {
dismiss(id, reason || 'dismiss-all');
});
return ids.length;
}
function processQueue() {
if (!queue.length) return;
if (activeToasts.length >= config.maxVisible) return;
var next = queue.shift();
if (next) {
renderToast(next);
}
}
function findToastIndex(id) {
for (var i = 0; i < activeToasts.length; i++) {
if (activeToasts[i].id === id) return i;
}
return -1;
}
function success(message, options) {
return show(mergeObjects(options || {}, {
type: 'success',
message: message
}));
}
function error(message, options) {
return show(mergeObjects(options || {}, {
type: 'error',
message: message,
duration: options && options.duration ? options.duration : 8000
}));
}
function warning(message, options) {
return show(mergeObjects(options || {}, {
type: 'warning',
message: message,
duration: options && options.duration ? options.duration : 7000
}));
}
function info(message, options) {
return show(mergeObjects(options || {}, {
type: 'info',
message: message
}));
}
function loading(message, options) {
return show(mergeObjects(options || {}, {
type: 'loading',
message: message || 'Loading...',
persistent: true,
dismissible: false
}));
}
function update(id, options) {
var index = findToastIndex(id);
if (index === -1) return false;
var item = activeToasts[index];
var oldOptions = item.options;
var newOptions = mergeObjects(oldOptions, options || {});
var type = TYPE_MAP[newOptions.type] || TYPE_MAP.info;
item.options = newOptions;
item.element.className = [
'rx-notification',
type.className,
'rx-notification--visible'
].join(' ');
item.element.innerHTML = buildToastMarkup(newOptions, type);
emit('rx:notification:update', {
id: id,
options: newOptions
});
return true;
}
function alertBar(options) {
init();
options = mergeObjects({
id: config.alertBarId,
type: 'info',
message: '',
html: false,
dismissible: true,
position: 'top',
sticky: true,
rememberDismiss: true,
storageKey: 'rx_theme_alert_bar_dismissed',
actionText: '',
actionUrl: ''
}, options || {});
if (!options.message) return null;
if (options.rememberDismiss && localStorageGet(options.storageKey) === '1') {
return null;
}
var existing = document.getElementById(options.id);
if (existing) {
existing.parentNode.removeChild(existing);
}
var bar = document.createElement('div');
var type = TYPE_MAP[options.type] || TYPE_MAP.info;
bar.id = options.id;
bar.className = [
'rx-alert-bar',
'rx-alert-bar--' + sanitizeClass(options.position),
type.className,
options.sticky ? 'rx-alert-bar--sticky' : ''
].join(' ');
bar.setAttribute('role', options.type === 'error' ? 'alert' : 'status');
bar.setAttribute('aria-live', options.type === 'error' ? 'assertive' : 'polite');
var message = options.html ? String(options.message) : escapeHTML(options.message);
var action = '';
if (options.actionText && options.actionUrl) {
action =
'<a class="rx-alert-bar__action" href="' +
escapeAttr(options.actionUrl) +
'">' +
escapeHTML(options.actionText) +
'</a>';
}
bar.innerHTML =
'<div class="rx-alert-bar__inner">' +
'<div class="rx-alert-bar__message">' + message + '</div>' +
action +
(
options.dismissible
? '<button class="rx-alert-bar__close" type="button" data-rx-alert-close aria-label="Close alert">×</button>'
: ''
) +
'</div>';
var close = bar.querySelector('[data-rx-alert-close]');
if (close) {
close.addEventListener('click', function closeAlert() {
if (options.rememberDismiss) {
localStorageSet(options.storageKey, '1');
}
bar.classList.add('rx-alert-bar--hidden');
window.setTimeout(function removeAlert() {
if (bar.parentNode) {
bar.parentNode.removeChild(bar);
}
}, config.animationDuration);
});
}
if (options.position === 'bottom') {
body.appendChild(bar);
} else {
body.insertBefore(bar, body.firstChild);
}
emit('rx:notification:alertbar', options);
return bar;
}
function clearAlertBar(id) {
var bar = document.getElementById(id || config.alertBarId);
if (!bar) return false;
bar.parentNode.removeChild(bar);
return true;
}
function modal(options) {
init();
options = mergeObjects({
id: config.modalId,
type: 'info',
title: '',
message: '',
html: false,
closeText: 'Close',
confirmText: '',
cancelText: '',
onConfirm: null,
onCancel: null,
closeOnOverlay: true,
closeOnEsc: true
}, options || {});
var existing = document.getElementById(options.id);
if (existing) {
existing.parentNode.removeChild(existing);
}
var modalEl = document.createElement('div');
var type = TYPE_MAP[options.type] || TYPE_MAP.info;
var message = options.html ? String(options.message) : escapeHTML(options.message);
var title = escapeHTML(options.title || type.label);
modalEl.id = options.id;
modalEl.className = 'rx-notification-modal ' + type.className;
modalEl.setAttribute('role', 'dialog');
modalEl.setAttribute('aria-modal', 'true');
modalEl.setAttribute('aria-labelledby', options.id + '-title');
modalEl.innerHTML =
'<div class="rx-notification-modal__overlay" data-rx-modal-overlay></div>' +
'<div class="rx-notification-modal__panel" role="document">' +
'<button class="rx-notification-modal__x" type="button" data-rx-modal-close aria-label="Close">×</button>' +
'<div class="rx-notification-modal__icon" aria-hidden="true">' + escapeHTML(type.icon) + '</div>' +
'<h2 class="rx-notification-modal__title" id="' + escapeAttr(options.id) + '-title">' + title + '</h2>' +
'<div class="rx-notification-modal__message">' + message + '</div>' +
'<div class="rx-notification-modal__actions">' +
(
options.cancelText
? '<button type="button" class="rx-notification-modal__cancel" data-rx-modal-cancel>' + escapeHTML(options.cancelText) + '</button>'
: ''
) +
(
options.confirmText
? '<button type="button" class="rx-notification-modal__confirm" data-rx-modal-confirm>' + escapeHTML(options.confirmText) + '</button>'
: '<button type="button" class="rx-notification-modal__close" data-rx-modal-close>' + escapeHTML(options.closeText) + '</button>'
) +
'</div>' +
'</div>';
body.appendChild(modalEl);
body.classList.add('rx-modal-open');
var previousFocus = document.activeElement;
var closeButtons = modalEl.querySelectorAll('[data-rx-modal-close]');
var overlay = modalEl.querySelector('[data-rx-modal-overlay]');
var confirmBtn = modalEl.querySelector('[data-rx-modal-confirm]');
var cancelBtn = modalEl.querySelector('[data-rx-modal-cancel]');
function closeModal(reason) {
modalEl.classList.add('rx-notification-modal--closing');
body.classList.remove('rx-modal-open');
window.setTimeout(function removeModal() {
if (modalEl.parentNode) {
modalEl.parentNode.removeChild(modalEl);
}
if (previousFocus && typeof previousFocus.focus === 'function') {
previousFocus.focus();
}
document.removeEventListener('keydown', escListener);
emit('rx:notification:modalclose', {
reason: reason || 'close',
options: options
});
}, config.animationDuration);
}
function escListener(event) {
if (event.key === 'Escape' && options.closeOnEsc) {
closeModal('escape');
}
if (event.key === 'Tab') {
trapFocus(event, modalEl);
}
}
closeButtons.forEach(function bindClose(btn) {
btn.addEventListener('click', function closeByButton() {
closeModal('button');
});
});
if (overlay && options.closeOnOverlay) {
overlay.addEventListener('click', function closeByOverlay() {
closeModal('overlay');
});
}
if (confirmBtn) {
confirmBtn.addEventListener('click', function confirmModal(event) {
if (typeof options.onConfirm === 'function') {
options.onConfirm.call(modalEl, event, options);
}
closeModal('confirm');
});
}
if (cancelBtn) {
cancelBtn.addEventListener('click', function cancelModal(event) {
if (typeof options.onCancel === 'function') {
options.onCancel.call(modalEl, event, options);
}
closeModal('cancel');
});
}
document.addEventListener('keydown', escListener);
requestAnimationFrame(function modalEnter() {
modalEl.classList.add('rx-notification-modal--visible');
var firstButton = modalEl.querySelector('button, a, input, select, textarea, [tabindex]:not([tabindex="-1"])');
if (firstButton) {
firstButton.focus();
}
});
emit('rx:notification:modal', options);
return {
element: modalEl,
close: closeModal
};
}
function trapFocus(event, wrapper) {
var focusable = wrapper.querySelectorAll(
'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])'
);
if (!focusable.length) return;
var first = focusable[0];
var last = focusable[focusable.length - 1];
if (event.shiftKey && document.activeElement === first) {
event.preventDefault();
last.focus();
} else if (!event.shiftKey && document.activeElement === last) {
event.preventDefault();
first.focus();
}
}
function requestBrowserPermission() {
if (!('Notification' in window)) {
return Promise.resolve('unsupported');
}
if (Notification.permission === 'granted') {
return Promise.resolve('granted');
}
if (Notification.permission === 'denied') {
return Promise.resolve('denied');
}
return Notification.requestPermission();
}
function sendBrowserNotification(title, message, options) {
options = options || {};
if (!('Notification' in window)) return false;
if (Notification.permission !== 'granted') return false;
try {
var notification = new Notification(title || 'RX Theme Notification', {
body: message || '',
icon: options.icon || config.browserNotificationIcon || '',
tag: options.tag || 'rx-theme-notification',
silent: !!options.silent
});
if (options.url) {
notification.onclick = function onNotificationClick() {
window.focus();
window.location.href = options.url;
};
}
return notification;
} catch (error) {
log('Browser notification failed', error);
return false;
}
}
function playSound(url) {
if (!url) return;
try {
var audio = new Audio(url);
audio.volume = 0.35;
var promise = audio.play();
if (promise && typeof promise.catch === 'function') {
promise.catch(function ignoreAutoplayError() {});
}
} catch (error) {
log('Notification sound failed', error);
}
}
function saveHistoryItem(options) {
var history = getHistory();
history.unshift({
id: options.id,
type: options.type,
title: options.title,
message: stripHTML(String(options.message || '')),
createdAt: new Date().toISOString(),
data: options.data || {}
});
if (history.length > config.historyLimit) {
history = history.slice(0, config.historyLimit);
}
localStorageSet(config.storageKey, JSON.stringify(history));
}
function getHistory() {
var raw = localStorageGet(config.storageKey);
if (!raw) return [];
try {
var parsed = JSON.parse(raw);
return Array.isArray(parsed) ? parsed : [];
} catch (error) {
return [];
}
}
function clearHistory() {
localStorageRemove(config.storageKey);
return true;
}
function localStorageGet(key) {
try {
return window.localStorage.getItem(key);
} catch (error) {
return null;
}
}
function localStorageSet(key, value) {
try {
window.localStorage.setItem(key, value);
return true;
} catch (error) {
return false;
}
}
function localStorageRemove(key) {
try {
window.localStorage.removeItem(key);
return true;
} catch (error) {
return false;
}
}
function emit(name, detail) {
try {
var event = new CustomEvent(name, {
bubbles: true,
cancelable: false,
detail: detail || {}
});
document.dispatchEvent(event);
} catch (error) {
log('Event emit failed', name, error);
}
}
function on(name, callback) {
if (typeof callback !== 'function') return RX;
document.addEventListener(name, callback);
return RX;
}
function off(name, callback) {
if (typeof callback !== 'function') return RX;
document.removeEventListener(name, callback);
return RX;
}
function bindGlobalListeners() {
document.addEventListener('click', function handleDataNotification(event) {
var trigger = event.target.closest('[data-rx-notify]');
if (!trigger) return;
var message = trigger.getAttribute('data-rx-notify') || '';
var type = trigger.getAttribute('data-rx-notify-type') || 'info';
var title = trigger.getAttribute('data-rx-notify-title') || '';
var duration = parseInt(trigger.getAttribute('data-rx-notify-duration'), 10);
if (!message) return;
show({
type: type,
title: title,
message: message,
duration: Number.isFinite(duration) ? duration : config.duration
});
});
document.addEventListener('rx:ajax:success', function ajaxSuccess(event) {
var detail = event.detail || {};
if (detail.message) {
success(detail.message);
}
});
document.addEventListener('rx:ajax:error', function ajaxError(event) {
var detail = event.detail || {};
if (detail.message) {
error(detail.message);
}
});
}
function generateId(prefix) {
uniqueCounter += 1;
return prefix + '-' + Date.now().toString(36) + '-' + uniqueCounter;
}
function sanitizeClass(value) {
return String(value || '')
.toLowerCase()
.replace(/[^a-z0-9_-]/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '');
}
function escapeHTML(value) {
return String(value || '')
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function escapeAttr(value) {
return escapeHTML(value).replace(/`/g, '`');
}
function stripHTML(value) {
var temp = document.createElement('div');
temp.innerHTML = value;
return temp.textContent || temp.innerText || '';
}
function log() {
if (!config.debug || !window.console) return;
var args = Array.prototype.slice.call(arguments);
args.unshift('[RX Notification]');
window.console.log.apply(window.console, args);
}
function injectBaseStyles() {
if (document.getElementById('rx-notification-inline-style')) return;
var style = document.createElement('style');
style.id = 'rx-notification-inline-style';
style.textContent = `
:root {
--rx-notification-z: 99999;
--rx-notification-bg: #ffffff;
--rx-notification-text: #101828;
--rx-notification-muted: #667085;
--rx-notification-border: rgba(16, 24, 40, 0.12);
--rx-notification-shadow: 0 16px 40px rgba(16, 24, 40, 0.16);
--rx-notification-radius: 14px;
--rx-notification-gap: 12px;
--rx-notification-success: #108a43;
--rx-notification-error: #d92d20;
--rx-notification-warning: #dc6803;
--rx-notification-info: #2563eb;
--rx-notification-medical: #047857;
}
.rx-notification-container {
position: fixed;
z-index: var(--rx-notification-z);
display: flex;
flex-direction: column;
gap: var(--rx-notification-gap);
width: min(420px, calc(100vw - 24px));
pointer-events: none;
}
.rx-notification-container--top-right {
top: 18px;
right: 18px;
}
.rx-notification-container--top-left {
top: 18px;
left: 18px;
}
.rx-notification-container--bottom-right {
right: 18px;
bottom: 18px;
}
.rx-notification-container--bottom-left {
left: 18px;
bottom: 18px;
}
.rx-notification-container--top-center {
top: 18px;
left: 50%;
transform: translateX(-50%);
}
.rx-notification-container--bottom-center {
bottom: 18px;
left: 50%;
transform: translateX(-50%);
}
.rx-notification {
pointer-events: auto;
overflow: hidden;
background: var(--rx-notification-bg);
color: var(--rx-notification-text);
border: 1px solid var(--rx-notification-border);
border-left: 5px solid var(--rx-notification-info);
border-radius: var(--rx-notification-radius);
box-shadow: var(--rx-notification-shadow);
opacity: 0;
transform: translateY(-8px) scale(0.98);
transition: opacity 250ms ease, transform 250ms ease;
}
.rx-notification--visible {
opacity: 1;
transform: translateY(0) scale(1);
}
.rx-notification--exit {
opacity: 0;
transform: translateY(-8px) scale(0.98);
}
.rx-notification__inner {
display: grid;
grid-template-columns: 36px 1fr auto;
gap: 12px;
padding: 14px;
align-items: start;
}
.rx-notification__icon {
width: 36px;
height: 36px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 999px;
font-weight: 700;
background: rgba(37, 99, 235, 0.1);
color: var(--rx-notification-info);
}
.rx-notification__title {
display: block;
margin: 0 0 4px;
font-size: 15px;
line-height: 1.3;
font-weight: 700;
}
.rx-notification__message {
font-size: 14px;
line-height: 1.55;
color: var(--rx-notification-muted);
}
.rx-notification__close {
appearance: none;
border: 0;
background: transparent;
color: var(--rx-notification-muted);
cursor: pointer;
font-size: 22px;
line-height: 1;
padding: 0 2px;
}
.rx-notification__close:hover,
.rx-notification__close:focus {
color: var(--rx-notification-text);
}
.rx-notification__action {
display: inline-flex;
margin-top: 10px;
font-weight: 700;
font-size: 13px;
text-decoration: none;
border: 0;
background: transparent;
color: var(--rx-notification-info);
cursor: pointer;
padding: 0;
}
.rx-notification--success {
border-left-color: var(--rx-notification-success);
}
.rx-notification--success .rx-notification__icon,
.rx-notification--success .rx-notification__action {
color: var(--rx-notification-success);
}
.rx-notification--success .rx-notification__icon {
background: rgba(16, 138, 67, 0.1);
}
.rx-notification--error {
border-left-color: var(--rx-notification-error);
}
.rx-notification--error .rx-notification__icon,
.rx-notification--error .rx-notification__action {
color: var(--rx-notification-error);
}
.rx-notification--error .rx-notification__icon {
background: rgba(217, 45, 32, 0.1);
}
.rx-notification--warning {
border-left-color: var(--rx-notification-warning);
}
.rx-notification--warning .rx-notification__icon,
.rx-notification--warning .rx-notification__action {
color: var(--rx-notification-warning);
}
.rx-notification--warning .rx-notification__icon {
background: rgba(220, 104, 3, 0.1);
}
.rx-notification--medical {
border-left-color: var(--rx-notification-medical);
}
.rx-notification--medical .rx-notification__icon,
.rx-notification--medical .rx-notification__action {
color: var(--rx-notification-medical);
}
.rx-notification--medical .rx-notification__icon {
background: rgba(4, 120, 87, 0.1);
}
.rx-notification--loading .rx-notification__icon {
animation: rxNotificationPulse 1s infinite ease-in-out;
}
@keyframes rxNotificationPulse {
0%, 100% {
opacity: 0.45;
}
50% {
opacity: 1;
}
}
.rx-alert-bar {
z-index: var(--rx-notification-z);
width: 100%;
background: var(--rx-notification-bg);
color: var(--rx-notification-text);
border-bottom: 1px solid var(--rx-notification-border);
box-shadow: 0 8px 24px rgba(16, 24, 40, 0.08);
transition: opacity 250ms ease, transform 250ms ease;
}
.rx-alert-bar--sticky {
position: sticky;
top: 0;
}
.rx-alert-bar--bottom.rx-alert-bar--sticky {
top: auto;
bottom: 0;
}
.rx-alert-bar__inner {
max-width: 1200px;
margin: 0 auto;
padding: 12px 18px;
display: flex;
align-items: center;
justify-content: center;
gap: 14px;
}
.rx-alert-bar__message {
font-size: 14px;
line-height: 1.5;
}
.rx-alert-bar__action {
font-weight: 700;
text-decoration: none;
}
.rx-alert-bar__close {
margin-left: auto;
border: 0;
background: transparent;
cursor: pointer;
font-size: 22px;
line-height: 1;
}
.rx-alert-bar--hidden {
opacity: 0;
transform: translateY(-100%);
}
.rx-notification-modal {
position: fixed;
inset: 0;
z-index: calc(var(--rx-notification-z) + 1);
display: grid;
place-items: center;
opacity: 0;
pointer-events: none;
transition: opacity 250ms ease;
}
.rx-notification-modal--visible {
opacity: 1;
pointer-events: auto;
}
.rx-notification-modal--closing {
opacity: 0;
}
.rx-notification-modal__overlay {
position: absolute;
inset: 0;
background: rgba(15, 23, 42, 0.58);
}
.rx-notification-modal__panel {
position: relative;
width: min(560px, calc(100vw - 28px));
background: var(--rx-notification-bg);
color: var(--rx-notification-text);
border-radius: 18px;
box-shadow: var(--rx-notification-shadow);
padding: 28px;
transform: translateY(10px) scale(0.98);
transition: transform 250ms ease;
}
.rx-notification-modal--visible .rx-notification-modal__panel {
transform: translateY(0) scale(1);
}
.rx-notification-modal__x {
position: absolute;
top: 12px;
right: 14px;
border: 0;
background: transparent;
cursor: pointer;
font-size: 24px;
line-height: 1;
}
.rx-notification-modal__icon {
width: 44px;
height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 999px;
background: rgba(37, 99, 235, 0.1);
color: var(--rx-notification-info);
font-weight: 800;
margin-bottom: 12px;
}
.rx-notification-modal__title {
margin: 0 0 10px;
font-size: 22px;
line-height: 1.25;
}
.rx-notification-modal__message {
color: var(--rx-notification-muted);
line-height: 1.7;
}
.rx-notification-modal__actions {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 22px;
}
.rx-notification-modal__confirm,
.rx-notification-modal__close,
.rx-notification-modal__cancel {
border: 1px solid var(--rx-notification-border);
border-radius: 10px;
padding: 10px 16px;
font-weight: 700;
cursor: pointer;
}
.rx-notification-modal__confirm,
.rx-notification-modal__close {
background: var(--rx-notification-info);
color: #ffffff;
border-color: var(--rx-notification-info);
}
.rx-modal-open {
overflow: hidden;
}
@media (prefers-reduced-motion: reduce) {
.rx-notification,
.rx-alert-bar,
.rx-notification-modal,
.rx-notification-modal__panel {
transition: none !important;
animation: none !important;
}
}
@media (max-width: 600px) {
.rx-notification-container {
top: 12px;
right: 12px;
left: 12px;
bottom: auto;
width: auto;
transform: none;
}
.rx-notification__inner {
grid-template-columns: 32px 1fr auto;
padding: 12px;
}
.rx-alert-bar__inner {
align-items: flex-start;
flex-direction: column;
}
.rx-alert-bar__close {
position: absolute;
right: 14px;
}
.rx-notification-modal__panel {
padding: 22px;
}
}
`;
document.head.appendChild(style);
}
RX.init = init;
RX.show = show;
RX.success = success;
RX.error = error;
RX.warning = warning;
RX.info = info;
RX.loading = loading;
RX.update = update;
RX.dismiss = dismiss;
RX.dismissAll = dismissAll;
RX.alertBar = alertBar;
RX.clearAlertBar = clearAlertBar;
RX.modal = modal;
RX.getHistory = getHistory;
RX.clearHistory = clearHistory;
RX.requestBrowserPermission = requestBrowserPermission;
RX.sendBrowserNotification = sendBrowserNotification;
RX.on = on;
RX.off = off;
RX.config = config;
window.RXThemeNotification = RX;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function onReady() {
init();
});
} else {
init();
}
})(window, document);
How to use it inside RX Theme
Example success notification:
window.RXThemeNotification.success('Your settings have been saved successfully.');
Example error notification:
window.RXThemeNotification.error('Something went wrong. Please try again.');
Example medical notice:
window.RXThemeNotification.show({
type: 'medical',
title: 'Medical Reminder',
message: 'This article is for education only. Please consult a qualified doctor for diagnosis and treatment.',
duration: 9000
});
Example alert bar:
window.RXThemeNotification.alertBar({
type: 'info',
message: 'Welcome to RX Harun Medical Knowledge Platform.',
actionText: 'Read More',
actionUrl: '/about/',
rememberDismiss: true
});
Example modal:
window.RXThemeNotification.modal({
type: 'warning',
title: 'Important Notice',
message: 'This website content does not replace professional medical advice.',
confirmText: 'I Understand'
});
WordPress enqueue example
In your RX Theme functions.php or enqueue file:
function rx_theme_enqueue_notification_chunk() {
wp_enqueue_script(
'rx-theme-notification-chunk',
get_template_directory_uri() . '/assets/static-js/static-chunks-js/chunk-036-notification.js',
array(),
'1.0.0',
true
);
wp_localize_script(
'rx-theme-notification-chunk',
'rxNotificationConfig',
array(
'position' => 'top-right',
'duration' => 6000,
'maxVisible' => 5,
'saveHistory' => true,
'enableBrowserNotification' => false,
'debug' => false,
)
);
}
add_action( 'wp_enqueue_scripts', 'rx_theme_enqueue_notification_chunk' );
Best use: keep this file for notification behavior only. Later you can connect it with login forms, comment forms, AJAX search, appointment forms, medical disclaimer popups, cookie notices, and admin setting success messages.