← back to Goodquestion Ai
src/pages/index.astro
567 lines
---
import BlogLayout from '../layouts/BlogLayout.astro';
import { getCollection } from 'astro:content';
const posts = (await getCollection('posts', ({ data }) => !data.draft))
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
/** Extract the first YouTube video ID from a post's markdown body */
function extractYouTubeId(body: string | undefined): string | null {
if (!body) return null;
const match = body.match(/(?:youtu\.be\/|youtube\.com\/(?:embed\/|watch\?v=))([a-zA-Z0-9_-]{11})/);
return match ? match[1] : null;
}
/** Extract native video path from a post's markdown body */
function extractNativeVideo(body: string | undefined): string | null {
if (!body) return null;
const match = body.match(/src="(\/videos\/[^"]+\.mp4)"/);
return match ? match[1] : null;
}
---
<BlogLayout>
<!-- ── Hero ─────────────────────────────────────────────────── -->
<section class="hero-banner" aria-label="Introduction">
<div class="hero-left">
<p class="hero-eyebrow">Build in public</p>
<h1 class="hero-title">Agent<br/>Abrams</h1>
<p class="hero-tagline">A solo developer shipping real software with Claude Code and AI agents — documenting every bug, breakthrough, and late-night decision along the way.</p>
<div class="hero-cta" role="list">
<a
href="https://x.com/agentabrams"
target="_blank"
rel="noopener noreferrer"
class="btn btn-primary"
role="listitem"
aria-label="Follow Agent Abrams on X (Twitter)"
>
<svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
@agentabrams
</a>
<a
href="https://bsky.app/profile/agentabrams.bsky.social"
target="_blank"
rel="noopener noreferrer"
class="btn btn-ghost"
role="listitem"
aria-label="Follow Agent Abrams on Bluesky"
>
<svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.596 6.449.764 2.81 3.495 3.508 5.98 3.27-4.34.422-8.141 1.822-3.6 6.445 4.946 4.667 6.766-1.2 7.024-2.5.258 1.3 2.078 7.167 7.024 2.5 4.541-4.623.74-6.023-3.6-6.445 2.485.238 5.216-.46 5.98-3.27C19.622 9.418 20 4.458 20 3.768c0-.688-.139-1.86-.902-2.203-.659-.299-1.664-.621-4.3 1.24C12.046 4.747 9.087 8.686 8 10.8z" transform="translate(2 2)"/></svg>
Bluesky
</a>
<a
href="https://youtube.com/@agentabrams"
target="_blank"
rel="noopener noreferrer"
class="btn btn-ghost"
role="listitem"
aria-label="Watch Agent Abrams on YouTube"
>
<svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/></svg>
YouTube
</a>
</div>
</div>
<div class="hero-right" aria-hidden="true">
<div class="hero-image-frame">
<img src="/images/launch-meme.png" alt="Agent Abrams Launch Day" class="hero-image" width="220" height="220" />
</div>
</div>
</section>
<!-- ── Latest Posts ─────────────────────────────────────────── -->
<section aria-labelledby="posts-heading">
<h2 class="section-heading" id="posts-heading">Latest Posts</h2>
{posts.length === 0 && (
<p class="empty-state">Posts coming soon.</p>
)}
<ul class="post-list" role="list">
{posts.map((post) => {
const formattedDate = post.data.date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
});
const slug = post.id.replace(/^\d{4}-\d{2}-\d{2}-/, '');
const heroImage = `/images/heroes/${slug}.png`;
const videoId = extractYouTubeId(post.body);
const nativeVideo = extractNativeVideo(post.body);
return (
<li role="listitem">
<a href={`/posts/${slug}/`} class="post-card" aria-label={`Read: ${post.data.title}`}>
<div class="post-card-thumb" aria-hidden="true">
<img src={heroImage} alt="" loading="lazy" decoding="async" onerror="this.parentElement.style.display='none'" />
</div>
<div class="post-card-content">
<div class="post-card-meta">
<time>{formattedDate}</time>
</div>
<div class="post-card-title">{post.data.title}</div>
<div class="post-card-description">{post.data.description}</div>
{post.data.tags.length > 0 && (
<div class="post-card-tags" aria-label="Tags">
{post.data.tags.map(tag => <span class="tag">{tag}</span>)}
</div>
)}
</div>
<div class="post-card-arrow" aria-hidden="true">→</div>
</a>
</li>
);
})}
</ul>
</section>
<!-- ── Contact CTA ──────────────────────────────────────────── -->
<section class="contact-section" aria-label="Get in touch">
<div class="contact-section-header">
<h2 class="contact-heading">Get In Touch</h2>
<p class="contact-sub">No gatekeeping. No paywalls. Just a developer sharing the journey.</p>
</div>
<div class="contact-grid" role="list">
<a href="https://x.com/agentabrams" target="_blank" rel="noopener noreferrer" class="contact-card" role="listitem" aria-label="Follow Agent Abrams on X">
<div class="contact-icon">
<svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
</div>
<div class="contact-label">@agentabrams</div>
<div class="contact-desc">Daily updates on X</div>
</a>
<a href="https://bsky.app/profile/agentabrams.bsky.social" target="_blank" rel="noopener noreferrer" class="contact-card" role="listitem" aria-label="Follow Agent Abrams on Bluesky">
<div class="contact-icon">
<svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.596 6.449.764 2.81 3.495 3.508 5.98 3.27-4.34.422-8.141 1.822-3.6 6.445 4.946 4.667 6.766-1.2 7.024-2.5.258 1.3 2.078 7.167 7.024 2.5 4.541-4.623.74-6.023-3.6-6.445 2.485.238 5.216-.46 5.98-3.27C19.622 9.418 20 4.458 20 3.768c0-.688-.139-1.86-.902-2.203-.659-.299-1.664-.621-4.3 1.24C12.046 4.747 9.087 8.686 8 10.8z" transform="translate(2 2)"/></svg>
</div>
<div class="contact-label">@agentabrams</div>
<div class="contact-desc">Follow on Bluesky</div>
</a>
<a href="https://youtube.com/@agentabrams" target="_blank" rel="noopener noreferrer" class="contact-card" role="listitem" aria-label="Watch Agent Abrams on YouTube">
<div class="contact-icon">
<svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/></svg>
</div>
<div class="contact-label">YouTube</div>
<div class="contact-desc">Walkthroughs & demos</div>
</a>
<a href="mailto:agent@goodquestion.ai" class="contact-card" role="listitem" aria-label="Email Agent Abrams">
<div class="contact-icon">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
</div>
<div class="contact-label">Email</div>
<div class="contact-desc">agent@goodquestion.ai</div>
</a>
</div>
</section>
</BlogLayout>
<style>
/* ── Hero ─────────────────────────────────────────────────── */
.hero-banner {
display: flex;
align-items: center;
gap: 3rem;
padding: 3.5rem 0 3rem;
margin-bottom: 0;
}
.hero-left {
flex: 1;
min-width: 0;
}
.hero-right {
flex-shrink: 0;
}
/* "Build in public" eyebrow */
.hero-eyebrow {
display: inline-block;
font-family: var(--font-mono);
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--accent);
background: var(--accent-subtle);
border: 1px solid rgba(232, 93, 38, 0.2);
padding: 0.25em 0.75em;
border-radius: 999px;
margin-bottom: 1.1rem;
}
.hero-title {
font-family: var(--font-display);
font-size: clamp(3rem, 8vw, 5rem);
font-weight: 900;
line-height: 0.95;
letter-spacing: -0.04em;
margin: 0 0 1rem;
color: var(--text-primary);
/* Subtle gradient shimmer on the name */
background: linear-gradient(135deg, var(--text-primary) 60%, var(--accent) 130%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-tagline {
font-family: var(--font-body);
color: var(--text-secondary);
font-size: clamp(0.97rem, 2vw, 1.08rem);
line-height: 1.7;
margin-bottom: 2rem;
max-width: 46ch;
}
/* Hero image */
.hero-image-frame {
position: relative;
display: inline-block;
}
.hero-image-frame::before {
content: '';
position: absolute;
inset: -3px;
border-radius: calc(var(--radius-lg) + 3px);
background: linear-gradient(135deg, var(--accent) 0%, transparent 60%);
opacity: 0.4;
z-index: 0;
}
.hero-image {
position: relative;
z-index: 1;
width: 200px;
height: 200px;
border-radius: var(--radius-lg);
border: 1px solid var(--border-strong);
object-fit: cover;
box-shadow: var(--shadow-lg);
display: block;
}
/* CTA Buttons */
.hero-cta {
display: flex;
gap: 0.6rem;
flex-wrap: wrap;
align-items: center;
}
.btn {
display: inline-flex;
align-items: center;
gap: 0.45rem;
padding: 0.55rem 1.1rem;
border-radius: var(--radius-md);
font-size: 0.88rem;
font-weight: 600;
text-decoration: none;
transition: background var(--duration-fast) var(--ease-out),
color var(--duration-fast) var(--ease-out),
border-color var(--duration-fast) var(--ease-out),
box-shadow var(--duration-fast) var(--ease-out),
transform var(--duration-fast) var(--ease-out);
border: 1px solid transparent;
white-space: nowrap;
}
.btn:hover {
transform: translateY(-1px);
text-decoration: none;
}
.btn-primary {
background: var(--text-primary);
color: var(--bg-primary);
border-color: var(--text-primary);
}
.btn-primary:hover {
background: var(--accent);
border-color: var(--accent);
color: #fff;
box-shadow: 0 4px 14px rgba(232, 93, 38, 0.35);
}
.btn-ghost {
background: transparent;
color: var(--text-secondary);
border-color: var(--border-strong);
}
.btn-ghost:hover {
border-color: var(--accent);
color: var(--accent);
background: var(--accent-subtle);
}
/* ── Section heading override for posts ─────────────────── */
.section-heading {
font-size: 0.72rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--text-muted);
font-weight: 600;
font-family: var(--font-mono);
margin: 3rem 0 1rem;
padding: 0;
border: none;
border-bottom: 1px solid var(--border);
padding-bottom: 0.75rem;
}
/* ── Post Cards ──────────────────────────────────────────── */
.post-list {
gap: 0.5rem;
}
/* Layout override — thumbnail left, content right, arrow right */
.post-card {
display: flex;
gap: 1.25rem;
align-items: flex-start;
padding: 1.1rem 1.25rem;
border-radius: var(--radius-md);
}
.post-card-thumb {
flex-shrink: 0;
width: 180px;
height: 101px;
border-radius: var(--radius-sm);
overflow: hidden;
border: 1px solid var(--border);
background: var(--bg-tertiary);
}
.post-card-thumb img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform var(--duration-base) var(--ease-out);
display: block;
}
.post-card:hover .post-card-thumb img {
transform: scale(1.04);
}
.post-card-content {
flex: 1;
min-width: 0;
}
.post-card-meta time {
font-family: var(--font-mono);
font-size: 0.78rem;
color: var(--text-muted);
letter-spacing: 0.03em;
}
.post-card-title {
font-size: 1.05rem;
margin-bottom: 0.3rem;
margin-top: 0.25rem;
}
.post-card-description {
font-size: 0.9rem;
color: var(--text-secondary);
line-height: 1.55;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* Trailing arrow — visual affordance */
.post-card-arrow {
flex-shrink: 0;
align-self: center;
color: var(--text-muted);
font-size: 1.1rem;
transition: color var(--duration-fast) var(--ease-out),
transform var(--duration-fast) var(--ease-out);
margin-left: 0.25rem;
}
.post-card:hover .post-card-arrow {
color: var(--accent);
transform: translateX(3px);
}
/* ── Empty state ─────────────────────────────────────────── */
.empty-state {
color: var(--text-muted);
text-align: center;
padding: 3.5rem 0;
font-size: 0.95rem;
}
/* ── Contact Section ─────────────────────────────────────── */
.contact-section {
margin-top: 4rem;
padding: 2.25rem 2rem;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: var(--radius-xl);
position: relative;
overflow: hidden;
}
/* Subtle accent glow behind the section */
.contact-section::before {
content: '';
position: absolute;
top: -40px;
right: -40px;
width: 200px;
height: 200px;
background: radial-gradient(circle, rgba(232, 93, 38, 0.08) 0%, transparent 70%);
pointer-events: none;
}
.contact-section-header {
margin-bottom: 1.5rem;
}
.contact-heading {
font-family: var(--font-display);
font-weight: 900;
font-size: clamp(1.3rem, 3vw, 1.6rem);
margin: 0 0 0.35rem;
border: none;
padding: 0;
letter-spacing: -0.03em;
}
.contact-sub {
color: var(--text-secondary);
font-size: 0.95rem;
margin: 0;
line-height: 1.6;
}
.contact-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0.75rem;
}
.contact-card {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: 1.25rem 0.75rem 1rem;
border-radius: var(--radius-md);
border: 1px solid var(--border);
background: var(--bg-primary);
text-decoration: none;
transition: border-color var(--duration-base) var(--ease-out),
background var(--duration-base) var(--ease-out),
box-shadow var(--duration-base) var(--ease-out),
transform var(--duration-base) var(--ease-out);
}
.contact-card:hover {
border-color: var(--accent);
background: var(--accent-subtle);
box-shadow: var(--shadow-sm);
transform: translateY(-2px);
text-decoration: none;
}
.contact-icon {
width: 44px;
height: 44px;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 0.65rem;
background: var(--accent-subtle);
color: var(--accent);
transition: background var(--duration-fast), transform var(--duration-fast);
}
.contact-card:hover .contact-icon {
background: rgba(232, 93, 38, 0.2);
transform: scale(1.05);
}
.contact-label {
font-weight: 600;
font-size: 0.85rem;
color: var(--text-primary);
margin-bottom: 0.2rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
.contact-desc {
font-size: 0.78rem;
color: var(--text-muted);
line-height: 1.4;
}
/* ── Responsive ──────────────────────────────────────────── */
@media (max-width: 640px) {
.hero-banner {
flex-direction: column-reverse;
text-align: center;
gap: 1.75rem;
padding: 2rem 0 2rem;
}
.hero-title {
font-size: clamp(2.8rem, 14vw, 3.5rem);
}
.hero-tagline {
max-width: 100%;
}
.hero-image {
width: 150px;
height: 150px;
}
.hero-cta {
justify-content: center;
}
.post-card {
flex-direction: column;
gap: 0.85rem;
}
.post-card-thumb {
width: 100%;
height: 160px;
}
.post-card-arrow {
display: none;
}
.contact-grid {
grid-template-columns: repeat(2, 1fr);
}
.contact-section {
padding: 1.5rem 1.25rem;
}
}
@media (max-width: 400px) {
.hero-title {
font-size: 2.5rem;
}
}
</style>