A heading and actions beside a collage of five team photos.

Last updated

Open block
Show code
---
/**
 * Image collage 02: A heading and actions beside a collage of five team photos.
 *
 * @block team
 * @order 10
 */
import Section from '@/components/apogee/Section/Section.astro'
import SectionHeader from '@/components/apogee/SectionHeader/SectionHeader.astro'
import Image from '@/components/apogee/Image/Image.astro'
import Button from '@/components/apogee/Button/Button.astro'
import { plain, type Media } from '@/components/apogee/sections/_shared/spine.ts'
import type { TeamContent } from '@/components/apogee/sections/_shared/team.ts'

/** @composable */
interface Props extends TeamContent {
  /** Five team photos for the collage (decorative, hidden from screen readers). @category content */
  images?: Media[] | null
}

const {
  eyebrow = 'Join our team',
  heading = "We're just getting started",
  description = 'We hire diverse, passionate people and build a culture that lets everyone do their best work.',
  primaryAction = { label: "We're hiring!", href: '#' },
  secondaryAction = { label: 'Read our principles', href: '#' },
  images = [
    { src: 'https://picsum.photos/id/1027/600/600', alt: '', width: 600, height: 600 },
    { src: 'https://picsum.photos/id/856/600/600', alt: '', width: 600, height: 600 },
    { src: 'https://picsum.photos/id/832/600/600', alt: '', width: 600, height: 600 },
    { src: 'https://picsum.photos/id/91/600/600', alt: '', width: 600, height: 600 },
    { src: 'https://picsum.photos/id/64/600/600', alt: '', width: 600, height: 600 },
  ],
} = Astro.props
// ponytail: five fixed collage slots; photos past the fifth are ignored.
const slots = ['row-start-7 col-start-5 row-end-13 col-end-9', 'row-start-1 col-start-7 row-end-7 col-end-11', 'row-start-3 col-start-3 row-end-7 col-end-7', 'row-start-7 col-start-9 row-end-11 col-end-13', 'row-start-7 col-start-1 row-end-12 col-end-5']
---

<Section spacing="large" class="overflow-hidden">
  <div class="grid items-center gap-12 lg:grid-cols-2 lg:gap-16">
    <div class="flex flex-col gap-8">
      <SectionHeader eyebrow={eyebrow ?? undefined} heading={plain(heading)} description={description ?? undefined} size="large" />
      {(primaryAction || secondaryAction) && (
        <div class="flex flex-col gap-3 sm:flex-row-reverse sm:justify-end">
          {primaryAction && <Button href={primaryAction.href} size="large">{primaryAction.label}</Button>}
          {secondaryAction && <Button href={secondaryAction.href} size="large" variant="outline" color="neutral">{secondaryAction.label}</Button>}
        </div>
      )}
    </div>
    {images && (
    <div class="-mx-[25%] overflow-hidden sm:-mx-[10%] md:mx-0">
      <div class="grid h-122 grid-cols-12 grid-rows-12 gap-2 sm:h-124 md:gap-4" aria-hidden="true">
        {images.slice(0, slots.length).map((m, i) => <Image src={m.src} alt={m.alt} width={m.width ?? 600} height={m.height ?? 600} fit="cover" class:list={['size-full', slots[i]]} />)}
      </div>
    </div>
    )}
  </div>
</Section>

Add

npx @ava-ui/apogee add team/image-collage-02

This copies the block to src/components/apogee/blocks/team/ with everything it uses: Button, Image, Section, SectionHeader. Every piece of copy is a prop, with the sample copy as its default. Pass yours, or null to hide a part; see copy is props.

Accessibility

  • The heading is an h2 by default, so the block slots into a page under its h1; item titles are one level down.
  • Photos that only decorate have an empty alt; give yours one when it carries meaning.