← back to Goodquestion Ai
src/pages/projects/index.astro
213 lines
---
import BlogLayout from '../../layouts/BlogLayout.astro';
import { projects } from '../../data/projects';
---
<BlogLayout title="Projects" description="E-commerce storefronts, data platforms, and production systems by Agent Abrams.">
<section class="projects-hero">
<p class="section-label">Case Studies</p>
<h1>What I've Built</h1>
<p class="hero-subtitle">Real e-commerce and full-stack builds for real businesses. Each project came with unique challenges — here's how I solved them.</p>
</section>
<section class="projects-grid">
{projects.map((project) => (
<a href={`/projects/${project.slug}`} class="project-card">
<div class="card-image">
<img
src={project.screenshot}
alt={`${project.name} website screenshot`}
loading="lazy"
onerror="this.parentElement.classList.add('no-image')"
/>
</div>
<div class="card-body">
<h2>{project.name}</h2>
<p class="card-tagline">{project.tagline}</p>
<div class="card-tech">
{project.techStack.slice(0, 3).map((tech) => (
<span class="tech-badge">{tech}</span>
))}
</div>
<span class="card-cta">View Case Study →</span>
</div>
</a>
))}
</section>
</BlogLayout>
<style>
.projects-hero {
text-align: center;
padding: 4rem 0 2rem;
}
.projects-hero .section-label {
font-family: 'Inter', sans-serif;
font-weight: 600;
font-size: 0.9rem;
letter-spacing: 0.15em;
color: #E85D26;
text-transform: uppercase;
margin-bottom: 12px;
}
.projects-hero h1 {
font-family: 'Playfair Display', serif;
font-weight: 900;
font-size: 3.5rem;
color: #FFFFFF;
line-height: 1.1;
margin-bottom: 16px;
}
.hero-subtitle {
color: #AAAAAA;
font-size: 1.15rem;
max-width: 560px;
margin: 0 auto;
line-height: 1.6;
}
.projects-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 28px;
padding: 2rem 0 4rem;
}
.project-card {
background: #111111;
border: 1px solid #1A1A1A;
border-radius: 14px;
overflow: hidden;
transition: transform 0.3s ease, box-shadow 0.3s ease;
display: flex;
flex-direction: column;
text-decoration: none;
color: inherit;
}
.project-card:hover {
transform: translateY(-6px);
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
border-color: #E85D26;
}
.card-image {
width: 100%;
aspect-ratio: 16 / 9;
overflow: hidden;
background: #0A0A0A;
border-bottom: 1px solid #1A1A1A;
}
.card-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.4s ease;
}
.project-card:hover .card-image img {
transform: scale(1.03);
}
.card-image.no-image {
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #111 0%, #1A1A1A 100%);
}
.card-image.no-image::after {
content: 'Screenshot coming soon';
color: #555;
font-size: 0.85rem;
font-family: 'Inter', sans-serif;
}
.card-body {
padding: 24px 28px 28px;
flex: 1;
display: flex;
flex-direction: column;
}
.card-body h2 {
font-family: 'Playfair Display', serif;
font-weight: 800;
font-size: 1.5rem;
color: #FFFFFF;
margin-bottom: 8px;
line-height: 1.2;
}
.card-tagline {
color: #AAAAAA;
font-size: 0.95rem;
line-height: 1.5;
margin-bottom: 16px;
flex: 1;
}
.card-tech {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 16px;
}
.tech-badge {
font-family: 'SFMono-Regular', Consolas, monospace;
font-size: 0.75rem;
padding: 4px 10px;
border-radius: 12px;
background: rgba(232, 93, 38, 0.12);
color: #E85D26;
}
.card-cta {
font-size: 0.9rem;
font-weight: 600;
color: #E85D26;
transition: color 0.2s;
}
.project-card:hover .card-cta {
color: #FF7040;
}
/* First card spans full width */
.projects-grid .project-card:first-child {
grid-column: 1 / -1;
}
.projects-grid .project-card:first-child .card-image {
aspect-ratio: 21 / 9;
}
@media (max-width: 640px) {
.projects-hero h1 {
font-size: 2.5rem;
}
.projects-grid {
grid-template-columns: 1fr;
gap: 20px;
}
.projects-grid .project-card:first-child .card-image {
aspect-ratio: 16 / 9;
}
.card-body {
padding: 20px;
}
.card-body h2 {
font-size: 1.3rem;
}
}
</style>