apple-intelligence-glow
Version:
A JavaScript and CSS implementation of the Apple Intelligence border glow effect
199 lines (166 loc) • 7.61 kB
JavaScript
/**
* 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