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.
Last updated
---
/**
* 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>
Show codeHide 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.