A rounded photo card with a stacked heading, a line and a round button, a giant wordmark across the bottom and a scrolling strip of claims under it.

Last updated

Open block
Show code
---
/**
 * Wordmark photo 01: A rounded photo card with a stacked heading, a line and a round button, a giant wordmark across the bottom and a scrolling strip of claims under it.
 *
 * @block hero
 * @order 61
 */
import Section from '@/components/apogee/Section/Section.astro'
import Heading from '@/components/apogee/Heading/Heading.astro'
import Button from '@/components/apogee/Button/Button.astro'
import Image from '@/components/apogee/Image/Image.astro'
import Marquee from '@/components/apogee/Marquee/Marquee.astro'
import { plain, type HeroContent } from '@/components/apogee/sections/_shared/spine.ts'

/** @composable */
interface Props extends HeroContent {
  /** The giant word across the bottom. @category content */
  wordmark?: string | null
  /** The scrolling strip under the card. @category content */
  claims?: string[] | null
}

// `heading` is three stacked lines; separate them with \n.
const {
  heading = 'Real food.\nMade for dogs.\nBetter every day.',
  description = 'Fresh, gently cooked meals with the extras dogs need for good digestion, strong joints and a shiny coat.',
  primaryAction = { label: 'Shop meals', href: '#' },
  media = { src: 'https://picsum.photos/id/237/2000/1400', alt: '', width: 2000, height: 1400 },
  wordmark = 'woofly',
  claims = ['Real ingredients', 'Vet approved', 'Small batches', 'No fillers', 'Taste tested', 'Made fresh'],
} = Astro.props
---

<Section spacing="small" containerWidth="full">
  <!-- Always dark: the text sits on a photo. -->
  <div data-theme="dark" class="relative isolate flex min-h-[44rem] flex-col justify-between overflow-hidden rounded-2xl text-neutral md:min-h-[52rem]">
    {media && <Image src={media.src} alt={media.alt} width={media.width} height={media.height} fit="cover" loading="eager" class="absolute inset-0 -z-10 size-full" />}
    <div class="absolute inset-0 -z-10 bg-[color-mix(in_oklab,var(--background-page)_55%,transparent)]" aria-hidden="true"></div>

    <div class="grid gap-8 px-6 pt-16 md:grid-cols-2 md:gap-16 md:px-12 md:pt-28">
      <Heading as="h1" size="h1" class="flex flex-col md:items-end md:text-end">{plain(heading).split('\n').map((line) => <span>{line}</span>)}</Heading>
      <div class="flex max-w-md flex-col items-start gap-6">
        {description && <p class="text-lg">{description}</p>}
        {primaryAction && <Button href={primaryAction.href} size="large" rounded>{primaryAction.label}</Button>}
      </div>
    </div>

    {wordmark && <p class="px-4 pb-[0.2em] text-center text-[clamp(5rem,0rem+22vw,22rem)] font-black leading-none tracking-tighter" aria-hidden="true">{wordmark}</p>}
  </div>

  {claims && (
    <div class="mt-2 rounded-full bg-neutral-faded py-2">
      <Marquee label="What goes into every meal">
        {claims.map((c, i) => <span class:list={['px-4 text-sm', i % 2 === 0 ? 'font-semibold' : 'text-neutral-faded']}>{c}</span>)}
      </Marquee>
    </div>
  )}
</Section>

Add

npx @ava-ui/apogee add hero/wordmark-photo-01

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.