Zoeken...  ⌘K GitHub

TeamAlternating Sections

Uitgebreide alternerende team-layout — grote foto + bio, feiten, quote overlay.

/team-alternating
src/components/sections/TeamAlternating.astro
---
/**
 * TeamAlternating
 * Grote alternerende team member layout — foto + uitgebreide bio.
 */
interface TeamMember {
  name: string;
  role: string;
  bio: string;
  image: string;
  imageAlt?: string;
  facts?: { label: string; value: string; }[];
  linkedin?: string;
  quote?: string;
}

interface Props {
  eyebrow?: string;
  headline?: string;
  members: TeamMember[];
}

const { eyebrow, headline, members = [] } = Astro.props;
---

<section class="ta" data-component="team-alternating">
  <div class="ta__inner">
    {(eyebrow || headline) && (
      <div class="ta__header">
        {eyebrow && <p class="ta__eyebrow">{eyebrow}</p>}
        {headline && <h2 class="ta__title" set:html={headline} />}
      </div>
    )}

    {members.map((m, i) => (
      <div class:list={['ta__row', { 'ta__row--reversed': i % 2 !== 0 }]}>
        <div class="ta__photo">
          <img src={m.image} alt={m.imageAlt ?? m.name} loading="lazy" />
          {m.quote && (
            <div class="ta__quote-card">
              <p class="ta__quote-text">"{m.quote}"</p>
            </div>
          )}
        </div>
        <div class="ta__content">
          <p class="ta__member-role">{m.role}</p>
          <h3 class="ta__member-name">{m.name}</h3>
          <p class="ta__bio">{m.bio}</p>

          {m.facts && m.facts.length > 0 && (
            <div class="ta__facts">
              {m.facts.map(fact => (
                <div class="ta__fact">
                  <div class="ta__fact-value">{fact.value}</div>
                  <div class="ta__fact-label">{fact.label}</div>
                </div>
              ))}
            </div>
          )}

          {m.linkedin && (
            <a href={m.linkedin} class="ta__linkedin" target="_blank" rel="noopener">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
                <path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
              </svg>
              Verbinden op LinkedIn
            </a>
          )}
        </div>
      </div>
    ))}
  </div>
</section>

<style>
  .ta {
    background: var(--color-bg, #fff);
    padding: 5rem 1.5rem;
  }

  .ta__inner { max-width: 1100px; margin: 0 auto; }

  .ta__header {
    text-align: center;
    margin-bottom: 4rem;
  }

  .ta__eyebrow {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-accent, #6366f1);
    margin-bottom: 0.75rem;
  }

  .ta__title {
    font-size: clamp(1.875rem, 3vw, 2.75rem);
    font-weight: 800;
    letter-spacing: -0.03em;
    color: var(--color-primary, #0a0a0a);
  }

  .ta__title :global(em) { font-style: normal; color: var(--color-accent, #6366f1); }

  .ta__row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 4rem;
    align-items: center;
    padding: 4rem 0;
    border-top: 1px solid rgba(0,0,0,0.07);
  }

  .ta__row--reversed { direction: rtl; }
  .ta__row--reversed > * { direction: ltr; }

  /* Photo */
  .ta__photo {
    position: relative;
  }

  .ta__photo img {
    width: 100%;
    height: 480px;
    object-fit: cover;
    object-position: top;
    border-radius: calc(var(--radius, 0.5rem) * 2);
    display: block;
  }

  .ta__quote-card {
    position: absolute;
    bottom: -1.5rem;
    right: -1.5rem;
    background: #fff;
    border: 1px solid rgba(0,0,0,0.07);
    border-radius: calc(var(--radius, 0.5rem) * 1.5);
    padding: 1.25rem;
    max-width: 240px;
    box-shadow: 0 12px 32px rgba(0,0,0,0.08);
  }

  .ta__row--reversed .ta__quote-card {
    right: auto;
    left: -1.5rem;
  }

  .ta__quote-text {
    font-size: 0.875rem;
    line-height: 1.6;
    color: var(--color-primary, #0a0a0a);
    font-style: italic;
  }

  /* Content */
  .ta__member-role {
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-accent, #6366f1);
    margin-bottom: 0.5rem;
  }

  .ta__member-name {
    font-size: clamp(1.5rem, 2.5vw, 2.25rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--color-primary, #0a0a0a);
    margin-bottom: 1rem;
  }

  .ta__bio {
    font-size: 1rem;
    line-height: 1.75;
    color: var(--color-muted, #6b7280);
    margin-bottom: 2rem;
  }

  .ta__facts {
    display: flex;
    gap: 2rem;
    padding: 1.5rem 0;
    border-top: 1px solid rgba(0,0,0,0.07);
    border-bottom: 1px solid rgba(0,0,0,0.07);
    margin-bottom: 1.5rem;
  }

  .ta__fact-value {
    font-size: 1.75rem;
    font-weight: 800;
    letter-spacing: -0.03em;
    color: var(--color-primary, #0a0a0a);
  }

  .ta__fact-label {
    font-size: 0.8125rem;
    color: var(--color-muted, #6b7280);
    margin-top: 0.125rem;
  }

  .ta__linkedin {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--color-accent, #6366f1);
    font-size: 0.9rem;
    font-weight: 600;
    text-decoration: none;
  }

  .ta__linkedin:hover { opacity: 0.7; }

  @media (max-width: 768px) {
    .ta__row { grid-template-columns: 1fr; gap: 2rem; }
    .ta__row--reversed { direction: ltr; }
    .ta__photo img { height: 300px; }
    .ta__quote-card { display: none; }
  }
</style>

Props

Prop Type Default Beschrijving
members * TeamMember[] Team leden met bio, feiten en optionele quote.
eyebrow string Label boven sectie
headline string Sectie headline

* = verplicht