nkjoy's picture
์ „์ฒด ํ•œ๊ตญ์–ด๋กœ
9cbdeca verified
class SoftwareCard extends HTMLElement {
static get observedAttributes() {
return ['name', 'category', 'url', 'version', 'seed'];
}
connectedCallback() {
this.render();
}
attributeChangedCallback() {
this.render();
}
render() {
const name = this.getAttribute('name') || 'Software Name';
const category = this.getAttribute('category') || 'Category';
const url = this.getAttribute('url') || '#';
const version = this.getAttribute('version') || '1.0.0';
const seed = this.getAttribute('seed') || '1';
const categoryColors = {
'์Œ์•… ์ œ์ž‘': 'bg-purple-500/20 text-purple-400',
'๋น„๋””์˜ค ํŽธ์ง‘': 'bg-pink-500/20 text-pink-400',
'AI ๋„๊ตฌ': 'bg-cyan-500/20 text-cyan-400',
'์œ ํ‹ธ๋ฆฌํ‹ฐ': 'bg-blue-500/20 text-blue-400',
'iOS ๋„๊ตฌ': 'bg-gray-500/20 text-gray-400',
'์‹œ์Šคํ…œ ๋„๊ตฌ': 'bg-yellow-500/20 text-yellow-400',
'๋ฐ์ดํ„ฐ ๋ณต๊ตฌ': 'bg-green-500/20 text-green-400',
'๊ฐœ๋ฐœ': 'bg-indigo-500/20 text-indigo-400',
'๋น„๋””์˜ค ๋„๊ตฌ': 'bg-red-500/20 text-red-400',
'์˜ค๋””์˜ค ๋„๊ตฌ': 'bg-orange-500/20 text-orange-400',
'3D ๋””์ž์ธ': 'bg-teal-500/20 text-teal-400',
'๊ฒŒ์ž„ ๊ฐœ๋ฐœ': 'bg-violet-500/20 text-violet-400'
};
const categoryClass = categoryColors[category] || 'bg-primary/20 text-primary';
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.card {
background: linear-gradient(145deg, rgba(30, 41, 59, 0.7), rgba(15, 23, 42, 0.9));
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 20px;
overflow: hidden;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
position: relative;
opacity: 0;
transform: translateY(20px);
animation: slide-in 0.5s ease-out forwards;
animation-delay: calc(var(--order, 0) * 0.05s);
}
@keyframes slide-in {
to {
opacity: 1;
transform: translateY(0);
}
}
.card:hover {
transform: translateY(-10px) scale(1.02);
border-color: rgba(99, 102, 241, 0.5);
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5), 0 0 30px rgba(99, 102, 241, 0.3);
}
.card-image {
width: 100%;
height: 180px;
background: linear-gradient(45deg, #1e293b, #0f172a);
position: relative;
overflow: hidden;
}
.card-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.card:hover .card-image img {
transform: scale(1.1);
}
.card-category {
position: absolute;
top: 1rem;
left: 1rem;
padding: 0.5rem 1rem;
border-radius: 50px;
font-size: 0.75rem;
font-weight: 600;
backdrop-filter: blur(10px);
}
.card-content {
padding: 1.5rem;
}
.card-title {
font-size: 1.25rem;
font-weight: 700;
color: white;
margin-bottom: 0.5rem;
line-height: 1.4;
}
.card-meta {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
}
.card-version {
color: #94a3b8;
font-size: 0.875rem;
display: flex;
align-items: center;
gap: 0.25rem;
}
.card-rating {
color: #fbbf24;
font-size: 0.875rem;
display: flex;
align-items: center;
gap: 0.25rem;
}
.card-description {
color: #94a3b8;
font-size: 0.875rem;
margin-bottom: 1.5rem;
line-height: 1.5;
}
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.card-size {
color: #64748b;
font-size: 0.875rem;
display: flex;
align-items: center;
gap: 0.25rem;
}
.download-btn {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
color: white;
border: none;
padding: 0.75rem 1.5rem;
border-radius: 12px;
font-weight: 600;
font-size: 0.875rem;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
display: flex;
align-items: center;
gap: 0.5rem;
text-decoration: none;
}
.download-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(99, 102, 241, 0.4);
}
.download-btn::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.7s;
}
.download-btn:hover::after {
left: 100%;
}
.pulse-dot {
position: absolute;
top: 0.5rem;
right: 0.5rem;
width: 8px;
height: 8px;
background: #10b981;
border-radius: 50%;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% {
box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7);
}
50% {
box-shadow: 0 0 0 10px rgba(16, 185, 129, 0);
}
}
</style>
<div class="card">
<div class="pulse-dot"></div>
<div class="card-image">
<img src="http://static.photos/technology/640x360/${seed}" alt="${name}" loading="lazy">
<div class="card-category ${categoryClass}">
${category}
</div>
</div>
<div class="card-content">
<h3 class="card-title">${name}</h3>
<div class="card-meta">
<div class="card-version">
<i data-feather="tag"></i>
v${version}
</div>
<div class="card-rating">
<i data-feather="star"></i>
4.8
</div>
</div>
<p class="card-description">
ํ–ฅ์ƒ๋œ ๊ธฐ๋Šฅ๊ณผ ์™„์ „ํ•œ ๊ธฐ๋Šฅ์„ ๊ฐ–์ถ˜ ํ”„๋ฆฌ๋ฏธ์—„ ๋ฒ„์ „์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์—…๋ฐ์ดํŠธ์™€ ํ”„๋ฆฌ๋ฏธ์—„ ์ง€์›์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.
</p>
<div class="card-footer">
<div class="card-size">
<i data-feather="hard-drive"></i>
${Math.floor(Math.random() * 500) + 100} MB
</div>
<a href="${url}" target="_blank" class="download-btn">
<i data-feather="download"></i>
์ง€๊ธˆ ๋‹ค์šด๋กœ๋“œ
</a>
</div>
</div>
</div>
`;
// Initialize feather icons
setTimeout(() => {
if (typeof feather !== 'undefined') {
feather.replace();
}
}, 100);
}
}
customElements.define('software-card', SoftwareCard);