Mooshie's picture
increase professionalism and interactivity
ec87762 verified
class CustomProjects 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;
color: white;
margin-bottom: 0.5rem;
}
.subtitle {
color: #9ca3af;
font-family: 'Fira Code', monospace;
}
.projects-wrapper {
position: relative;
}
.projects-scroll {
display: flex;
gap: 2rem;
overflow-x: auto;
scroll-snap-type: x mandatory;
padding: 1rem;
scroll-behavior: smooth;
-ms-overflow-style: none;
scrollbar-width: none;
}
.projects-scroll::-webkit-scrollbar {
display: none;
}
.project-container {
background: #171717;
border: 1px solid #262626;
border-radius: 1rem;
overflow: hidden;
display: grid;
grid-template-columns: 1fr;
min-width: 100%;
transition: border-color 0.3s ease;
scroll-snap-align: center;
}
@media (min-width: 768px) {
.project-container {
grid-template-columns: 1.2fr 0.8fr;
min-width: calc(50% - 1rem);
}
}
.project-container {
transform-style: preserve-3d;
transition: all 0.5s ease;
}
.project-container:hover {
border-color: #EAB308;
transform: translateY(-10px) rotateX(5deg);
}
.project-image {
width: 100%;
height: 300px;
object-fit: cover;
border-bottom: 1px solid #262626;
}
@media (min-width: 768px) {
.project-image {
height: 100%;
border-bottom: none;
border-right: 1px solid #262626;
}
}
.project-content {
padding: 2.5rem;
display: flex;
flex-direction: column;
justify-content: center;
}
.folder-icon {
color: #EAB308;
margin-bottom: 1rem;
}
h3 {
font-size: 1.75rem;
color: white;
margin-bottom: 1rem;
font-weight: 700;
}
p {
color: #a1a1aa;
margin-bottom: 2rem;
line-height: 1.6;
}
.tech-stack {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
margin-bottom: 2rem;
font-family: 'Fira Code', monospace;
font-size: 0.8rem;
}
.tech-item {
color: #EAB308;
}
.project-links {
display: flex;
gap: 1.5rem;
}
.link-item {
display: flex;
align-items: center;
gap: 0.5rem;
color: #e5e7eb;
text-decoration: none;
font-size: 0.9rem;
transition: color 0.3s;
}
.link-item:hover {
color: #EAB308;
}
.link-item svg {
width: 18px;
height: 18px;
transition: transform 0.3s ease;
}
.link-item:hover svg {
transform: translateX(5px);
}
.project-tags {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
}
.tag {
background: rgba(234, 179, 8, 0.1);
color: #EAB308;
padding: 0.25rem 0.75rem;
border-radius: 9999px;
font-size: 0.75rem;
font-family: 'Fira Code', monospace;
}
.nav-btn {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 50px;
height: 50px;
background: #171717;
border: 1px solid #262626;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: #EAB308;
transition: all 0.3s ease;
z-index: 10;
}
.nav-btn:hover {
background: #EAB308;
color: black;
border-color: #EAB308;
}
.nav-btn.prev {
left: -25px;
}
.nav-btn.next {
right: -25px;
}
.nav-btn svg {
width: 24px;
height: 24px;
}
@media (max-width: 768px) {
.nav-btn {
width: 40px;
height: 40px;
}
.nav-btn.prev {
left: 10px;
}
.nav-btn.next {
right: 10px;
}
}
.dots-container {
display: flex;
justify-content: center;
gap: 0.5rem;
margin-top: 2rem;
}
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: #262626;
cursor: pointer;
transition: all 0.3s ease;
}
.dot.active {
background: #EAB308;
width: 30px;
border-radius: 5px;
}
.dot:hover {
background: #404040;
}
.dot.active:hover {
background: #EAB308;
}
</style>
<section id="projects">
<div class="section-header">
<h2>Featured Projects</h2>
<p class="subtitle">Some of my recent work</p>
</div>
<div class="projects-wrapper">
<button class="nav-btn prev" id="prev-btn">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"></polyline></svg>
</button>
<div class="projects-scroll" id="projects-scroll">
<!-- Project 1 -->
<div class="project-container">
<img src="http://static.photos/technology/640x360/42" alt="Mooshieblob.com Project" class="project-image">
<div class="project-content">
<div class="project-tags">
<span class="tag">Featured</span>
</div>
<div class="folder-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
</div>
<h3>mooshieblob.com</h3>
<p>
My fun alias profile showcasing my AI projects and online persona, featuring interactive demos, creative experiments, and real-time AI integrations.
</p>
<div class="tech-stack">
<span class="tech-item">Nuxt.js</span>
<span class="tech-item">Tailwind CSS</span>
<span class="tech-item">Cloudflare AI</span>
<span class="tech-item">Vercel</span>
</div>
<div class="project-links">
<a href="https://github.com/Mooshieblob1/mooshieblob1.github.io" target="_blank" class="link-item">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
Code
</a>
<a href="https://mooshieblob.com/" target="_blank" class="link-item">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>
Visit Live
</a>
</div>
</div>
</div>
<!-- Project 2 -->
<div class="project-container">
<img src="http://static.photos/office/640x360/123" alt="Cloud Dashboard Project" class="project-image">
<div class="project-content">
<div class="folder-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
</div>
<div class="project-tags">
<span class="tag">Enterprise</span>
</div>
<div class="folder-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
</div>
<h3>Cloud Dashboard</h3>
<p>
A comprehensive cloud infrastructure monitoring dashboard with real-time metrics, intelligent alerts, automated scaling controls, and predictive analytics.
</p>
<div class="tech-stack">
<span class="tech-item">React</span>
<span class="tech-item">TypeScript</span>
<span class="tech-item">AWS</span>
<span class="tech-item">Terraform</span>
<span class="tech-item">Grafana</span>
<span class="tech-item">Prometheus</span>
</div>
<div class="project-links">
<a href="#" target="_blank" class="link-item">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
Code
</a>
<a href="#" target="_blank" class="link-item">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>
Visit Live
</a>
</div>
</div>
</div>
<!-- Project 3 -->
<div class="project-container">
<img src="http://static.photos/nature/640x360/456" alt="E-Commerce Platform Project" class="project-image">
<div class="project-content">
<div class="folder-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
</div>
<div class="project-tags">
<span class="tag">SaaS</span>
</div>
<div class="folder-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
</div>
<h3>E-Commerce Platform</h3>
<p>
A full-stack e-commerce solution with headless CMS, seamless payment integration, real-time inventory management, and global multi-region deployment.
</p>
<div class="tech-stack">
<span class="tech-item">Next.js</span>
<span class="tech-item">Stripe</span>
<span class="tech-item">PostgreSQL</span>
<span class="tech-item">Redis</span>
<span class="tech-item">Docker</span>
<span class="tech-item">GraphQL</span>
</div>
<div class="project-links">
<a href="#" target="_blank" class="link-item">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
Code
</a>
<a href="#" target="_blank" class="link-item">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>
Visit Live
</a>
</div>
</div>
</div>
<!-- Project 4 -->
<div class="project-container">
<img src="http://static.photos/abstract/640x360/789" alt="DevOps Pipeline Project" class="project-image">
<div class="project-content">
<div class="folder-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
</div>
<div class="project-tags">
<span class="tag">Infrastructure</span>
</div>
<div class="folder-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
</div>
<h3>DevOps Pipeline</h3>
<p>
Automated CI/CD pipeline solution with self-hosted runners, comprehensive security scanning, automated testing, and multi-environment deployments.
</p>
<div class="tech-stack">
<span class="tech-item">GitHub Actions</span>
<span class="tech-item">Kubernetes</span>
<span class="tech-item">Helm</span>
<span class="tech-item">ArgoCD</span>
<span class="tech-item">SonarQube</span>
</div>
<div class="project-links">
<a href="#" target="_blank" class="link-item">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
Code
</a>
<a href="#" target="_blank" class="link-item">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>
Visit Live
</a>
</div>
</div>
</div>
</div>
<button class="nav-btn next" id="next-btn">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>
</button>
<div class="dots-container" id="dots-container"></div>
</div>
</section>
`;
}
initScrollNavigation() {
const scrollContainer = this.shadowRoot.getElementById('projects-scroll');
const prevBtn = this.shadowRoot.getElementById('prev-btn');
const nextBtn = this.shadowRoot.getElementById('next-btn');
const dotsContainer = this.shadowRoot.getElementById('dots-container');
const projects = scrollContainer.querySelectorAll('.project-container');
// Create dots
projects.forEach((_, index) => {
const dot = document.createElement('div');
dot.classList.add('dot');
if (index === 0) dot.classList.add('active');
dot.addEventListener('click', () => {
projects[index].scrollIntoView({ behavior: 'smooth', inline: 'center' });
});
dotsContainer.appendChild(dot);
});
// Update active dot on scroll
const updateDots = () => {
const scrollLeft = scrollContainer.scrollLeft;
const containerWidth = scrollContainer.offsetWidth;
projects.forEach((project, index) => {
const projectLeft = project.offsetLeft;
const projectWidth = project.offsetWidth;
if (scrollLeft >= projectLeft - containerWidth / 2 &&
scrollLeft < projectLeft + projectWidth - containerWidth / 2) {
dotsContainer.querySelectorAll('.dot').forEach(dot => dot.classList.remove('active'));
dotsContainer.querySelectorAll('.dot')[index]?.classList.add('active');
}
});
};
scrollContainer.addEventListener('scroll', updateDots);
// Navigation buttons
prevBtn.addEventListener('click', () => {
const scrollAmount = scrollContainer.offsetWidth * 0.9;
scrollContainer.scrollBy({ left: -scrollAmount, behavior: 'smooth' });
});
nextBtn.addEventListener('click', () => {
const scrollAmount = scrollContainer.offsetWidth * 0.9;
scrollContainer.scrollBy({ left: scrollAmount, behavior: 'smooth' });
});
// Touch/drag support for mobile
let isDown = false;
let startX;
let scrollLeft;
scrollContainer.addEventListener('mousedown', (e) => {
isDown = true;
startX = e.pageX - scrollContainer.offsetLeft;
scrollLeft = scrollContainer.scrollLeft;
});
scrollContainer.addEventListener('mouseleave', () => isDown = false);
scrollContainer.addEventListener('mouseup', () => isDown = false);
scrollContainer.addEventListener('mousemove', (e) => {
if (!isDown) return;
e.preventDefault();
const x = e.pageX - scrollContainer.offsetLeft;
const walk = (x - startX) * 2;
scrollContainer.scrollLeft = scrollLeft - walk;
});
}
}
customElements.define('custom-projects', CustomProjects);