A pill, heading, line and two buttons beside a fading stack of activity cards, over a video card and an ask-anything bar.

Last updated

Open block
Show code
---
/**
 * Activity stack 01: A pill, heading, line and two buttons beside a fading stack of activity cards, over a video card and an ask-anything bar.
 *
 * @block hero
 * @order 84
 */
import { ArrowUp, Bell, Clock, FileText, Mic, Phone, Play, Sparkles } from '@lucide/astro'
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 { plain, type HeroContent } from '@/components/apogee/sections/_shared/spine.ts'

/** @composable */
interface Props extends HeroContent {
  /** The video card under the hero: a title, a short line under it and where it links. @category content */
  videoLink?: { label: string; caption: string; href: string } | null
}

const {
  eyebrow = 'Late quotes still convert',
  heading = 'New customers don’t leave a message.',
  description = 'Someone who wants a quote after dinner won’t wait until office hours. We answer, take down the details and book the visit that used to die in voicemail.',
  primaryAction = { label: 'Get started', href: '#' },
  secondaryAction = { label: 'Try it live', href: '#' },
  videoLink = { label: 'How the phone line works for small teams', caption: 'Watch it in action', href: '#' },
} = Astro.props

const cards = [
  { icon: Sparkles, title: 'Contact enriched', body: 'Found a profile and an email address' },
  { icon: Bell, title: 'Reminder set', body: 'Follow up with Angela on Monday at 9 AM' },
  { icon: FileText, title: 'Quote for Marcus Hale', body: 'Full kitchen refit, oak worktop and two new taps' },
]
---

<Section spacing="large">
  <div class="grid items-center gap-12 lg:grid-cols-2">
    <div class="flex flex-col items-start gap-6">
      {eyebrow && <span class="inline-flex items-center gap-1.5 rounded-full border border-neutral-faded px-3 py-1 text-sm"><Clock class="size-4" aria-hidden="true" />{eyebrow}</span>}
      <Heading as="h1" size="display" class="font-normal text-balance">{plain(heading)}</Heading>
      {description && <p class="max-w-xl text-lg text-neutral-faded">{description}</p>}
      {(primaryAction || secondaryAction) && (
        <div class="flex flex-wrap gap-3">
          {primaryAction && <Button href={primaryAction.href} size="large" rounded>{primaryAction.label}</Button>}
          {secondaryAction && <Button href={secondaryAction.href} size="large" rounded variant="outline" color="neutral"><Phone slot="start" aria-hidden="true" />{secondaryAction.label}</Button>}
        </div>
      )}
    </div>

    <ul class="flex flex-col gap-3 mask-y-from-80%" aria-label="What happened after one call">
      <li class="px-4 text-sm text-neutral-faded" aria-hidden="true">Angela · (561) 300 8821</li>
      {cards.map((c, i) => (
        <li class:list={['flex flex-col overflow-hidden rounded-2xl border border-neutral-faded bg-page shadow-sm', i % 2 === 0 ? 'lg:ms-6' : 'lg:me-6']}>
          <span class="flex items-center gap-2 border-b border-neutral-faded px-4 py-3 font-medium"><c.icon class="size-4" aria-hidden="true" />{c.title}</span>
          <span class="px-4 py-3">{c.body}</span>
        </li>
      ))}
    </ul>
  </div>

  <div class="mt-16 flex flex-col items-center gap-16">
    {videoLink && (
      <a href={videoLink.href} class="flex w-full max-w-lg items-center gap-4 rounded-2xl border border-neutral-faded p-2 pe-4">
        <span class="grid size-16 shrink-0 place-items-center rounded-xl bg-neutral-faded"><Play class="size-5" aria-hidden="true" /></span>
        <span class="flex flex-col"><span class="font-medium">{videoLink.label}</span><span class="text-sm text-neutral-faded">{videoLink.caption}</span></span>
      </a>
    )}
    <form class="flex w-full max-w-md items-center gap-2 rounded-full border border-neutral-faded bg-page p-1.5 shadow-lg" onsubmit="return false">
      <label for="activity-stack-ask" class="sr-only">Ask a question</label>
      <input id="activity-stack-ask" type="text" placeholder="Ask anything about us" class="min-w-0 flex-1 bg-transparent px-3 outline-none placeholder:text-neutral-faded" />
      <button type="button" class="grid size-9 place-items-center rounded-full bg-neutral-faded" aria-label="Speak"><Mic class="size-4" /></button>
      <button type="submit" class="grid size-9 place-items-center rounded-full bg-(--foreground-neutral) text-(--background-page)" aria-label="Send"><ArrowUp class="size-4" /></button>
    </form>
  </div>
</Section>

Add

npx @ava-ui/apogee add hero/activity-stack-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.