alejandro-ao's picture
alejandro-ao HF Staff
**Prompt: Fake Analytics Dashboard App (Full-Stack)**
744bca2 verified
class MetricsCard extends HTMLElement {
static get observedAttributes() {
return ['title', 'icon', 'value', 'change', 'color'];
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
}
attributeChangedCallback(name, oldValue, newValue) {
if (oldValue !== newValue) {
this.render();
}
}
render() {
const title = this.getAttribute('title') || '';
const icon = this.getAttribute('icon') || 'activity';
const value = this.getAttribute('value') || '0';
const change = parseFloat(this.getAttribute('change') || '0');
const color = this.getAttribute('color') || 'primary';
const changeClass = change > 0 ? 'change-positive' : change < 0 ? 'change-negative' : 'change-neutral';
const changeIcon = change > 0 ? 'trending-up' : change < 0 ? 'trending-down' : 'minus';
const changeText = change > 0 ? `+${change}` : change;
this.shadowRoot.innerHTML = `
<style>
.card {
transition: all 0.3s ease;
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
</style>
<div class="card bg-white dark:bg-gray-800 rounded-xl shadow p-6 hover:shadow-md transition-all duration-300">
<div class="flex justify-between items-start">
<div>
<p class="text-gray-500 dark:text-gray-400 text-sm font-medium">${title}</p>
<h3 class="text-2xl font-bold mt-1">${value}</h3>
</div>
<div class="w-10 h-10 rounded-lg flex items-center justify-center bg-${color}-100 dark:bg-${color}-900/30">
<i data-feather="${icon}" class="text-${color}-600 dark:text-${color}-400"></i>
</div>
</div>
<div class="mt-4 flex items-center ${changeClass}">
<i data-feather="${changeIcon}" class="w-4 h-4 mr-1"></i>
<span class="text-sm font-medium">${changeText}%</span>
<span class="text-xs ml-1 opacity-70">vs last update</span>
</div>
</div>
`;
feather.replace();
}
}
customElements.define('metrics-card', MetricsCard);