← 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>