/** * Skeleton Card Component * Shows a loading placeholder for listing cards */ class SkeletonCard extends HTMLElement { connectedCallback() { this.render() } render() { this.innerHTML = /* html */`
` } } customElements.define('skeleton-card', SkeletonCard) const style = document.createElement('style') style.textContent = /* css */` skeleton-card { display: block; background: var(--color-bg-secondary); border: 1px solid var(--color-border); border-radius: var(--radius-md); overflow: hidden; } skeleton-card .skeleton-image { aspect-ratio: 1; background: var(--color-bg-tertiary); animation: skeleton-pulse 1.5s ease-in-out infinite; } skeleton-card .skeleton-info { padding: var(--space-sm); } skeleton-card .skeleton-title, skeleton-card .skeleton-price, skeleton-card .skeleton-location { background: var(--color-bg-tertiary); border-radius: var(--radius-sm); animation: skeleton-pulse 1.5s ease-in-out infinite; } skeleton-card .skeleton-title { height: 1rem; width: 80%; margin-bottom: var(--space-xs); } skeleton-card .skeleton-price { height: 1rem; width: 50%; margin-bottom: var(--space-xs); } skeleton-card .skeleton-location { height: 0.75rem; width: 60%; } @keyframes skeleton-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } ` document.head.appendChild(style)