gentelella
Version:
Gentelella Admin is a free to use Bootstrap admin template
237 lines (207 loc) • 7.69 kB
JavaScript
/**
* UI Components Module
* Handles panel toolbox, progress bars, and toast notifications
* Modernized from jQuery to vanilla JavaScript
*/
// Modern DOM utilities (jQuery replacement)
const DOM = {
select: (selector) => document.querySelector(selector),
selectAll: (selector) => [...document.querySelectorAll(selector)],
on: (element, event, handler) => element.addEventListener(event, handler),
find: (element, selector) => element.querySelector(selector),
closest: (element, selector) => element.closest(selector),
addClass: (element, className) => element.classList.add(className),
removeClass: (element, className) => element.classList.remove(className),
toggle: (element, className) => element.classList.toggle(className),
slideUp: (element, duration = 300) => {
element.style.transition = `height ${duration}ms ease`;
element.style.overflow = 'hidden';
element.style.height = element.offsetHeight + 'px';
element.offsetHeight; // Force reflow
element.style.height = '0px';
setTimeout(() => {
element.style.display = 'none';
}, duration);
},
slideDown: (element, duration = 300) => {
element.style.display = 'block';
const height = element.scrollHeight;
element.style.height = '0px';
element.style.transition = `height ${duration}ms ease`;
element.style.overflow = 'hidden';
element.offsetHeight; // Force reflow
element.style.height = height + 'px';
setTimeout(() => {
element.style.height = '';
element.style.overflow = '';
element.style.transition = '';
}, duration);
}
};
/**
* Panel Toolbox Functionality
* Modernized from jQuery event handlers
*/
export function initializePanelToolbox() {
// Close panel functionality - MODERNIZED
DOM.selectAll('.close-link').forEach(link => {
DOM.on(link, 'click', function(e) {
e.preventDefault();
const panel = DOM.closest(this, '.x_panel');
if (panel) {
DOM.slideUp(panel);
}
});
});
// Collapse panel functionality - MODERNIZED
DOM.selectAll('.collapse-link').forEach(link => {
DOM.on(link, 'click', function(e) {
e.preventDefault();
const panel = DOM.closest(this, '.x_panel');
const content = DOM.find(panel, '.x_content');
const icon = DOM.find(this, 'i');
if (content && icon) {
if (content.style.display === 'none') {
DOM.slideDown(content);
DOM.removeClass(icon, 'fa-chevron-down');
DOM.addClass(icon, 'fa-chevron-up');
} else {
DOM.slideUp(content);
DOM.removeClass(icon, 'fa-chevron-up');
DOM.addClass(icon, 'fa-chevron-down');
}
}
});
});
console.log('✅ Panel toolbox initialized (jQuery-free)');
}
/**
* Progress Bar Animations
* Already modern - moved from init.js
*/
export function initializeProgressBars() {
// Animate all progress bars with data-transitiongoal
const progressBars = DOM.selectAll('.progress-bar[data-transitiongoal]');
progressBars.forEach(bar => {
const targetPercent = parseInt(bar.getAttribute('data-transitiongoal'), 10);
const displayText = bar.getAttribute('data-display-text') !== 'false';
// Remove any inline width styles to allow animation
bar.style.removeProperty('width');
// Set initial state with !important to override any CSS
bar.style.setProperty('width', '0%', 'important');
bar.setAttribute('aria-valuenow', '0');
// Animate to target value
setTimeout(() => {
bar.style.setProperty('transition', 'width 1s ease-in-out', 'important');
bar.style.setProperty('width', targetPercent + '%', 'important');
bar.setAttribute('aria-valuenow', targetPercent);
if (displayText) {
bar.textContent = targetPercent + '%';
}
}, 100);
});
// Handle App Versions progress bars (widget_summary containers)
const appVersionBars = DOM.selectAll('.widget_summary .progress-bar');
appVersionBars.forEach(bar => {
// Skip if already processed with data-transitiongoal
if (bar.getAttribute('data-transitiongoal')) {
return;
}
// Extract target percentage from inline style
const inlineWidth = bar.style.width;
if (inlineWidth && inlineWidth.includes('%')) {
const targetPercent = parseInt(inlineWidth.replace('%', ''), 10);
// Remove inline width and animate
bar.style.removeProperty('width');
bar.style.setProperty('width', '0%', 'important');
bar.setAttribute('aria-valuenow', '0');
// Animate to target value with delay for staggered effect
const delay = Array.from(appVersionBars).indexOf(bar) * 100 + 200;
setTimeout(() => {
bar.style.setProperty('transition', 'width 1s ease-in-out', 'important');
bar.style.setProperty('width', targetPercent + '%', 'important');
bar.setAttribute('aria-valuenow', targetPercent);
}, delay);
}
});
// For other progress bars without data-transitiongoal, just show them immediately
const staticProgressBars = DOM.selectAll('.progress-bar:not([data-transitiongoal])');
staticProgressBars.forEach(bar => {
// Skip App Versions bars as they're handled above
if (DOM.closest(bar, '.widget_summary')) {
return;
}
const currentPercent = bar.style.width || bar.getAttribute('aria-valuenow') + '%' || '0%';
bar.style.width = currentPercent;
});
console.log('✅ Progress bars initialized (jQuery-free)');
}
/**
* Toast Notifications
* Bootstrap 5 native implementation - MODERNIZED
*/
export function initializeToasts() {
// Initialize all toast elements
const toastElements = DOM.selectAll('.toast');
toastElements.forEach(toastEl => {
// Use Bootstrap 5 native Toast API instead of jQuery plugin
if (typeof bootstrap !== 'undefined' && bootstrap.Toast) {
const toast = new bootstrap.Toast(toastEl);
// Auto-show toasts marked with data-show
if (toastEl.getAttribute('data-show') === 'true') {
toast.show();
}
}
});
console.log('✅ Toasts initialized (jQuery-free)');
}
/**
* Bootstrap Component Initialization
* Using Bootstrap 5 native APIs - MODERNIZED
*/
export function initializeBootstrapComponents() {
// Initialize tooltips - MODERNIZED from jQuery
if (typeof bootstrap !== 'undefined' && bootstrap.Tooltip) {
DOM.selectAll('[data-bs-toggle="tooltip"]').forEach(element => {
new bootstrap.Tooltip(element);
});
}
// Initialize popovers - MODERNIZED from jQuery
if (typeof bootstrap !== 'undefined' && bootstrap.Popover) {
DOM.selectAll('[data-bs-toggle="popover"]').forEach(element => {
new bootstrap.Popover(element);
});
}
console.log('✅ Bootstrap components initialized (jQuery-free)');
}
/**
* Switchery Toggle Switches
* Modern implementation - ALREADY MODERN
*/
export function initializeSwitchery() {
if (typeof Switchery === 'undefined') {
console.warn('⚠️ Switchery library not available');
return;
}
DOM.selectAll('.js-switch').forEach(element => {
if (!element.switchery) { // Avoid double initialization
new Switchery(element, {
color: '#26B99A',
size: 'small'
});
}
});
console.log('✅ Switchery initialized (jQuery-free)');
}
// Export DOM utilities for other modules
export { DOM };
// Auto-initialize when module loads
if (typeof document !== 'undefined') {
document.addEventListener('DOMContentLoaded', () => {
initializePanelToolbox();
initializeProgressBars();
initializeToasts();
initializeBootstrapComponents();
initializeSwitchery();
});
}