Spaces:
Running
Running
File size: 4,765 Bytes
ca7232a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
/**
* Image Optimizer Web Component
* Automatically optimizes image loading with lazy loading, placeholders, and responsive images
*/
class ImageOptimizer extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
const src = this.getAttribute('src') || '';
const alt = this.getAttribute('alt') || '';
const width = this.getAttribute('width') || '100%';
const height = this.getAttribute('height') || 'auto';
const lazy = this.hasAttribute('lazy');
const placeholder = this.getAttribute('placeholder') || 'https://static.photos/abstract/100x100';
const category = this.getAttribute('category') || 'general';
// Generate optimized image URL based on static.photos API
const optimizeURL = (url) => {
// If it's already a static.photos URL, keep it
if (url.includes('static.photos')) return url;
// For other URLs, we could add resize parameters if needed
// For now, just return the original
return url;
};
// Create responsive image sets for different screen sizes
const generateSrcSet = (baseUrl) => {
if (!baseUrl.includes('static.photos')) return '';
// Extract dimensions if present
const dimMatch = baseUrl.match(/\/(\d+)x(\d+)\//);
if (!dimMatch) return '';
const [_, width, height] = dimMatch;
const base = baseUrl.replace(`/${width}x${height}/`, '');
// Generate srcset for common breakpoints
const sizes = [
{ width: 320, height: Math.round(320 * height / width) },
{ width: 640, height: Math.round(640 * height / width) },
{ width: 768, height: Math.round(768 * height / width) },
{ width: 1024, height: Math.round(1024 * height / width) },
{ width: 1280, height: Math.round(1280 * height / width) }
];
return sizes.map(size =>
`${base.replace(/\/\d+x\d+\//, `/${size.width}x${size.height}/`)} ${size.width}w`
).join(', ');
};
const optimizedSrc = optimizeURL(src);
const srcset = generateSrcSet(optimizedSrc);
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
position: relative;
width: ${width};
height: ${height};
overflow: hidden;
}
.image-container {
position: relative;
width: 100%;
height: 100%;
}
.optimized-image {
width: 100%;
height: 100%;
object-fit: cover;
transition: opacity 0.3s ease;
opacity: 0;
}
.optimized-image.loaded {
opacity: 1;
}
.placeholder {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: loading 1.5s infinite;
border-radius: inherit;
}
@keyframes loading {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
.error-fallback {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #f8f9fa;
display: flex;
align-items: center;
justify-content: center;
color: #6c757d;
font-size: 14px;
border-radius: inherit;
}
.error-fallback i {
font-size: 24px;
margin-bottom: 8px;
}
</style>
<div class="image-container">
<div class="placeholder"></div>
<img
class="optimized-image"
src="${optimizedSrc}"
${srcset ? `srcset="${srcset}"` : ''}
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
alt="${alt}"
${lazy ? 'loading="lazy"' : ''}
onload="this.classList.add('loaded')"
onerror="this.style.display='none'; this.parentNode.querySelector('.error-fallback').style.display='flex';"
>
<div class="error-fallback" style="display: none;">
<div style="text-align: center;">
<i class="fas fa-image"></i>
<div>${alt || 'Image'}</div>
</div>
</div>
</div>
`;
}
static get observedAttributes() {
return ['src', 'alt', 'width', 'height'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (oldValue !== newValue) {
this.connectedCallback();
}
}
}
customElements.define('optimized-image', ImageOptimizer); |