UNPKG

apple-intelligence-glow

Version:

A JavaScript and CSS implementation of the Apple Intelligence border glow effect

199 lines (166 loc) 7.61 kB
/** * Apple Intelligence Border Glow Effect * A JavaScript implementation of a glowing border effect similar to Apple Intelligence UI * With continuous color coverage around the entire border */ class BorderGlowEffect { constructor(options = {}) { this.options = { containerId: options.containerId || null, colorScheme: options.colorScheme || 'default', animated: options.animated !== undefined ? options.animated : true, ...options }; this.containers = []; this.init(); } init() { // Initialize all containers if no specific ID is provided if (!this.options.containerId) { const allContainers = document.querySelectorAll('.border-glow-container'); allContainers.forEach(container => { this.containers.push(container); }); } else { const container = document.getElementById(this.options.containerId); if (container) { this.containers.push(container); } else { console.error(`Container with ID "${this.options.containerId}" not found.`); return; } } // Initialize each container this.containers.forEach(container => { this.initContainer(container); }); // Set up global controls this.initControls(); } initContainer(container) { // Clear existing glow layers const existingLayers = container.querySelectorAll('.glow-layer'); existingLayers.forEach(layer => layer.remove()); // Use document fragment for better performance const layersFragment = document.createDocumentFragment(); // Create glow layers - adding a 4th layer for better coverage for (let i = 1; i <= 4; i++) { const layer = document.createElement('div'); layer.className = `glow-layer glow-layer-${i}`; layersFragment.appendChild(layer); } // Add all layers at once to minimize reflows container.prepend(layersFragment); // No pulsing glows - only animated border const contentArea = container.querySelector('.content-area'); if (contentArea) { // Remove existing pulsing glows if any const existingPulsingGlows = contentArea.querySelectorAll('.pulsing-glow, .pulsing-glow-container'); existingPulsingGlows.forEach(glow => glow.remove()); } // Set initial color scheme this.setColorScheme(container, this.options.colorScheme); // Set animation state if (this.options.animated) { container.classList.add('animated'); } else { container.classList.remove('animated'); } } setColorScheme(container, scheme) { // Remove all color scheme classes container.classList.remove('color-scheme-default', 'color-scheme-blue', 'color-scheme-green'); // Add the selected color scheme class container.classList.add(`color-scheme-${scheme}`); // Update app content colors if they exist const appLogo = container.querySelector('.app-logo'); const appButton = container.querySelector('.app-button'); if (appLogo) { let gradientColors; switch (scheme) { case 'blue': gradientColors = ['#0033ff', '#ff00cc']; break; case 'green': gradientColors = ['#00ff33', '#ffcc00']; break; default: // default/purple gradientColors = ['#6600ff', '#ff6600']; break; } appLogo.style.background = `linear-gradient(to right, ${gradientColors[0]}, ${gradientColors[1]})`; appLogo.style.webkitBackgroundClip = 'text'; appLogo.style.backgroundClip = 'text'; if (appButton) { appButton.style.background = `linear-gradient(to right, ${gradientColors[0]}, ${gradientColors[1]})`; } } } toggleAnimation(paused) { this.containers.forEach(container => { if (paused) { container.classList.add('paused'); } else { container.classList.remove('paused'); } }); } initControls() { // Animation controls const pauseButton = document.getElementById('pauseButton'); if (pauseButton) { let isPaused = false; // Use passive event listener for better performance pauseButton.addEventListener('click', () => { isPaused = !isPaused; this.toggleAnimation(isPaused); pauseButton.textContent = isPaused ? 'Resume Animation' : 'Pause Animation'; }, { passive: true }); } // Color scheme controls - use event delegation for better performance const colorOptionsContainer = document.querySelector('.color-options'); if (colorOptionsContainer) { // Single event listener instead of multiple colorOptionsContainer.addEventListener('click', (event) => { const option = event.target.closest('.color-option'); if (!option) return; // Not a color option // Remove active class from all options const colorOptions = document.querySelectorAll('.color-option'); colorOptions.forEach(opt => opt.classList.remove('active')); // Add active class to clicked option option.classList.add('active'); // Get color scheme from data attribute const scheme = option.getAttribute('data-scheme'); // Apply color scheme to all containers this.containers.forEach(container => { this.setColorScheme(container, scheme); }); }, { passive: true }); } else { // Fallback to direct listeners if container doesn't exist const colorOptions = document.querySelectorAll('.color-option'); if (colorOptions.length > 0) { colorOptions.forEach(option => { option.addEventListener('click', () => { // Remove active class from all options colorOptions.forEach(opt => opt.classList.remove('active')); // Add active class to clicked option option.classList.add('active'); // Get color scheme from data attribute const scheme = option.getAttribute('data-scheme'); // Apply color scheme to all containers this.containers.forEach(container => { this.setColorScheme(container, scheme); }); }, { passive: true }); }); } } } } /** * Apple Intelligence Border Glow Effect * Main entry point for the NPM package */ export { BorderGlowEffect as default }; //# sourceMappingURL=index.js.map