Files
dees-catalog/ts_web/elements/00group-media/dees-tile-image/component.ts

161 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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`
<div class="image-wrapper">
${this.hasStartedLoading ? html`
<img
class="${this.imageLoaded ? 'loaded' : 'loading'}"
src="${this.src}"
alt="${this.alt}"
@load=${this.handleImageLoad}
@error=${this.handleImageError}
/>
` : ''}
</div>
${this.imageWidth > 0 && this.imageHeight > 0 ? html`
<div class="tile-badge-topright dimension-badge">
${this.imageWidth} × ${this.imageHeight}
</div>
` : ''}
${this.imageLoaded ? html`
<div class="tile-info">
<dees-icon icon="lucide:Image"></dees-icon>
<span class="tile-info-text">${this.imageWidth} × ${this.imageHeight}</span>
</div>
` : ''}
${this.clickable ? html`
<div class="tile-overlay">
<dees-icon icon="lucide:Eye"></dees-icon>
<span>View Image</span>
</div>
` : ''}
`;
}
protected getTileClickDetail(): Record<string, unknown> {
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<PropertyKey, unknown>): Promise<void> {
super.updated(changedProperties);
if (changedProperties.has('src') && this.src && this.isVisible) {
this.hasStartedLoading = true;
this.imageLoaded = false;
this.loading = true;
}
}
}