Mooshie's picture
increase professionalism and interactivity
ec87762 verified
class CustomSkills extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
padding: 6rem 1rem;
max-width: 1200px;
margin: 0 auto;
}
.section-header {
text-align: center;
margin-bottom: 4rem;
}
h2 {
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 1rem;
color: white;
}
h2 span {
color: #EAB308;
}
.subtitle {
color: #9ca3af;
font-family: 'Fira Code', monospace;
}
.skills-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
.skill-card {
background: #171717;
border: 1px solid #262626;
padding: 2rem;
border-radius: 0.75rem;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.skill-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: #EAB308;
transform: scaleX(0);
transform-origin: left;
transition: transform 0.3s ease;
}
.skill-card:hover {
transform: translateY(-5px);
border-color: #404040;
box-shadow: 0 10px 30px -10px rgba(0,0,0,0.5);
}
.skill-card:hover::before {
transform: scaleX(1);
}
.card-icon {
margin-bottom: 1.5rem;
color: #EAB308;
}
h3 {
font-size: 1.25rem;
color: white;
margin-bottom: 1rem;
font-weight: 600;
}
.tech-list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
}
.tech-item {
background: rgba(255, 255, 255, 0.05);
padding: 0.35rem 0.75rem;
border-radius: 4px;
font-size: 0.875rem;
color: #d4d4d8;
transition: all 0.2s;
}
.tech-item:hover {
background: #EAB308;
color: black;
font-weight: 500;
transform: translateY(-2px);
}
.filter-buttons {
display: flex;
justify-content: center;
gap: 1rem;
margin-bottom: 3rem;
flex-wrap: wrap;
}
.filter-btn {
padding: 0.5rem 1.5rem;
background: transparent;
border: 1px solid #262626;
color: #9ca3af;
border-radius: 9999px;
cursor: pointer;
font-size: 0.9rem;
font-family: 'Fira Code', monospace;
transition: all 0.3s ease;
}
.filter-btn:hover, .filter-btn.active {
border-color: #EAB308;
color: #EAB308;
background: rgba(234, 179, 8, 0.1);
}
.skill-card.hidden {
display: none;
}
</style>
<section id="skills">
<div class="section-header">
<h2>Skills & <span>Expertise</span></h2>
<p class="subtitle">Technologies I work with</p>
</div>
<div class="filter-buttons">
<button class="filter-btn active" data-filter="all">All</button>
<button class="filter-btn" data-filter="frontend">Frontend</button>
<button class="filter-btn" data-filter="backend">Backend</button>
<button class="filter-btn" data-filter="devops">DevOps</button>
</div>
<div class="skills-grid">
<!-- Frontend -->
<div class="skill-card" data-category="frontend">
<div class="card-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect><line x1="8" y1="21" x2="16" y2="21"></line><line x1="12" y1="17" x2="12" y2="21"></line></svg>
</div>
<h3>Frontend</h3>
<ul class="tech-list">
<li class="tech-item">React</li>
<li class="tech-item">Vue.js</li>
<li class="tech-item">Svelte</li>
<li class="tech-item">Next.js</li>
<li class="tech-item">Nuxt.js</li>
<li class="tech-item">TypeScript</li>
<li class="tech-item">Tailwind</li>
<li class="tech-item">SCSS</li>
</ul>
</div>
<!-- Backend -->
<div class="skill-card" data-category="backend">
<div class="card-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg>
</div>
<h3>Backend</h3>
<ul class="tech-list">
<li class="tech-item">Node.js</li>
<li class="tech-item">Express</li>
<li class="tech-item">Python</li>
<li class="tech-item">Django</li>
<li class="tech-item">PostgreSQL</li>
<li class="tech-item">MongoDB</li>
<li class="tech-item">REST APIs</li>
<li class="tech-item">GraphQL</li>
</ul>
</div>
<!-- DevOps -->
<div class="skill-card" data-category="devops">
<div class="card-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"></path></svg>
</div>
<h3>DevOps & Cloud</h3>
<ul class="tech-list">
<li class="tech-item">AWS</li>
<li class="tech-item">Azure</li>
<li class="tech-item">GCP</li>
<li class="tech-item">Docker</li>
<li class="tech-item">Kubernetes</li>
<li class="tech-item">CI/CD</li>
<li class="tech-item">GitHub Actions</li>
<li class="tech-item">Terraform</li>
</ul>
</div>
</div>
</section>
`;
}
initFilter() {
const filterBtns = this.shadowRoot.querySelectorAll('.filter-btn');
const skillCards = this.shadowRoot.querySelectorAll('.skill-card');
filterBtns.forEach(btn => {
btn.addEventListener('click', () => {
const filter = btn.dataset.filter;
// Update active button
filterBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
// Filter cards
skillCards.forEach(card => {
if (filter === 'all' || card.dataset.category === filter) {
card.classList.remove('hidden');
card.style.animation = 'fadeIn 0.5s ease forwards';
} else {
card.classList.add('hidden');
}
});
});
});
}
}
customElements.define('custom-skills', CustomSkills);