Files
arcum42-ComfyUI_SageUtils/js/shared/skeletonLoader.js
T

155 lines
4.6 KiB
JavaScript

/**
* Skeleton Loader Components
* Provides loading placeholder components for gallery thumbnails
*/
/**
* Create a skeleton loader for a thumbnail
* @param {Object} options - Configuration options
* @param {number} options.width - Width of the skeleton (default: 200px)
* @param {number} options.height - Height of the skeleton (default: 150px)
* @param {boolean} options.animated - Whether to show shimmer animation (default: true)
* @returns {HTMLElement} Skeleton loader element
*/
export function createSkeletonThumbnail(options = {}) {
const {
width = 200,
height = 150,
animated = true
} = options;
const skeleton = document.createElement('div');
skeleton.className = 'gallery-skeleton-item';
skeleton.setAttribute('data-skeleton', 'true');
skeleton.style.cssText = `
position: relative;
background: #333;
border-radius: 6px;
overflow: hidden;
min-height: ${height}px;
width: 100%;
border: 2px solid transparent;
`;
// Create shimmer overlay if animated
if (animated) {
const shimmer = document.createElement('div');
shimmer.className = 'skeleton-shimmer';
shimmer.style.cssText = `
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent 0%,
rgba(255, 255, 255, 0.05) 50%,
transparent 100%
);
animation: shimmer 1.5s infinite;
`;
skeleton.appendChild(shimmer);
// Inject shimmer animation if not already present
if (!document.querySelector('#skeleton-shimmer-style')) {
const style = document.createElement('style');
style.id = 'skeleton-shimmer-style';
style.textContent = `
@keyframes shimmer {
0% {
left: -100%;
}
100% {
left: 100%;
}
}
`;
document.head.appendChild(style);
}
}
// Create placeholder icon
const icon = document.createElement('div');
icon.style.cssText = `
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 32px;
opacity: 0.3;
color: #666;
`;
icon.textContent = '🖼️';
skeleton.appendChild(icon);
return skeleton;
}
/**
* Create multiple skeleton loaders
* @param {number} count - Number of skeletons to create
* @param {Object} options - Options passed to createSkeletonThumbnail
* @returns {HTMLElement[]} Array of skeleton elements
*/
export function createSkeletonGrid(count, options = {}) {
const skeletons = [];
for (let i = 0; i < count; i++) {
skeletons.push(createSkeletonThumbnail(options));
}
return skeletons;
}
/**
* Replace a skeleton with actual content
* @param {HTMLElement} skeleton - Skeleton element to replace
* @param {HTMLElement} actualContent - Actual content element
* @param {boolean} fadeTransition - Whether to fade in the content (default: true)
*/
export function replaceSkeletonWithContent(skeleton, actualContent, fadeTransition = true) {
if (!skeleton || !skeleton.parentNode) {
return;
}
if (fadeTransition) {
// Fade in the actual content
actualContent.style.opacity = '0';
actualContent.style.transition = 'opacity 0.2s ease-in';
skeleton.parentNode.replaceChild(actualContent, skeleton);
// Trigger fade-in after a small delay
requestAnimationFrame(() => {
actualContent.style.opacity = '1';
});
} else {
skeleton.parentNode.replaceChild(actualContent, skeleton);
}
}
/**
* Remove all skeleton loaders from a container
* @param {HTMLElement} container - Container element
*/
export function removeAllSkeletons(container) {
if (!container) return;
const skeletons = container.querySelectorAll('[data-skeleton="true"]');
skeletons.forEach(skeleton => {
if (skeleton.parentNode) {
skeleton.remove();
}
});
}
/**
* Get count of remaining skeleton loaders in a container
* @param {HTMLElement} container - Container element
* @returns {number} Number of skeleton loaders
*/
export function getSkeletonCount(container) {
if (!container) return 0;
return container.querySelectorAll('[data-skeleton="true"]').length;
}