import { property, state, html, customElement, css, cssManager, type TemplateResult, type CSSResult, } from '@design.estate/dees-element'; import { DeesTileBase } from '../dees-tile-shared/DeesTileBase.js'; import { tileBaseStyles } from '../dees-tile-shared/styles.js'; import { demo } from './demo.js'; declare global { interface HTMLElementTagNameMap { 'dees-tile-image': DeesTileImage; } } @customElement('dees-tile-image') export class DeesTileImage extends DeesTileBase { public static demo = demo; public static demoGroups = ['Media']; public static styles = [ ...tileBaseStyles, css` .image-wrapper { position: relative; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; overflow: hidden; background: ${cssManager.bdTheme( 'repeating-conic-gradient(#e8e8e8 0% 25%, white 0% 50%) 50% / 16px 16px', 'repeating-conic-gradient(hsl(215 20% 18%) 0% 25%, hsl(215 20% 14%) 0% 50%) 50% / 16px 16px' )}; } .image-wrapper img { width: 100%; height: 100%; object-fit: cover; display: block; transition: opacity 0.3s ease; } .image-wrapper img.loaded { opacity: 1; } .image-wrapper img.loading { opacity: 0; } .tile-badge-topright.dimension-badge { opacity: 0; transition: opacity 0.2s ease; } .tile-container.clickable:hover .tile-badge-topright.dimension-badge { opacity: 1; } `, ] as any; @property({ type: String }) accessor src: string = ''; @property({ type: String }) accessor alt: string = ''; @state() accessor imageLoaded: boolean = false; @state() accessor imageWidth: number = 0; @state() accessor imageHeight: number = 0; private hasStartedLoading: boolean = false; protected renderTileContent(): TemplateResult { return html`
${this.hasStartedLoading ? html` ${this.alt} ` : ''}
${this.imageWidth > 0 && this.imageHeight > 0 ? html`
${this.imageWidth} × ${this.imageHeight}
` : ''} ${this.imageLoaded ? html`
${this.imageWidth} × ${this.imageHeight}
` : ''} ${this.clickable ? html`
View Image
` : ''} `; } protected getTileClickDetail(): Record { return { src: this.src, alt: this.alt, width: this.imageWidth, height: this.imageHeight, }; } protected onBecameVisible(): void { if (!this.hasStartedLoading && this.src) { this.hasStartedLoading = true; this.loading = true; this.requestUpdate(); } } private handleImageLoad(e: Event): void { const img = e.target as HTMLImageElement; this.imageWidth = img.naturalWidth; this.imageHeight = img.naturalHeight; this.imageLoaded = true; this.loading = false; } private handleImageError(): void { this.error = true; this.loading = false; } public async updated(changedProperties: Map): Promise { super.updated(changedProperties); if (changedProperties.has('src') && this.src && this.isVisible) { this.hasStartedLoading = true; this.imageLoaded = false; this.loading = true; } } }