Gear for the long way round.
Tents, packs and layers cut in small batches, repaired for life and shipped from one warehouse in Duluth.
Centred headline and actions above a wide media panel.
HeroSection1 dependency Original, MIT
Tents, packs and layers cut in small batches, repaired for life and shipped from one warehouse in Duluth.
Using Claude Code? Give it the agent prompt and skip these steps.
foundation.css holds the tokens every component reads.
---
// src/layouts/Layout.astro
import "../styles/foundation.css";
--- ---
import HeroStatement from "../components/viewership/hero-statement/HeroStatement.astro";
---
<HeroStatement /> | Prop | Type | Default | Description |
|---|---|---|---|
title | string | · | Headline. |
accent | string | · | Closing words of the headline, drawn in the theme's accent style (<em>). |
body | string | · | Supporting paragraph. |
primary | { label: string; href: string } | · | Main call to action. |
secondary | { label: string; href: string } | · | Quieter second action. |
as | "h1" | "h2" | "h1" | Heading element. |
slot: media | slot | · | Image, video or rendered visual, cropped to 16:7. |
---
/**
* HeroStatement: centred headline and actions over a wide media panel.
*
* Media goes in the `media` slot (image, video, rendered visual). The section
* responds to its own width, and its look follows the --vs-* tokens or a
* theme preset.
*
* @example
* <HeroStatement title="Gear for the" accent="long way round." primary={{ label: "Shop", href: "/shop" }}>
* <img slot="media" src="/hero.webp" alt="" />
* </HeroStatement>
*/
import Button from "../button/Button.astro";
interface Cta {
label: string;
href: string;
}
interface Props {
title: string;
/** Closing words of the headline, drawn in the theme's accent style. */
accent?: string;
body?: string;
primary?: Cta;
secondary?: Cta;
/** Heading element. Use "h2" when the page already has an h1. */
as?: "h1" | "h2";
class?: string;
}
const { title, accent, body, primary, secondary, as: Heading = "h1", class: className } = Astro.props;
---
<section class:list={["vs-hero-statement", className]}>
<div class="vs-hero-statement__inner">
<Heading class="vs-display vs-hero-statement__title">{title}{accent && <> <em>{accent}</em></>}</Heading>
{body && <p class="vs-hero-statement__body">{body}</p>}
{
(primary || secondary) && (
<div class="vs-hero-statement__actions">
{primary && <Button href={primary.href} variant="primary">{primary.label}</Button>}
{secondary && <Button href={secondary.href} variant="secondary">{secondary.label}</Button>}
</div>
)
}
{
Astro.slots.has("media") && (
<div class="vs-hero-statement__media">
<slot name="media" />
</div>
)
}
</div>
</section>
<style>
.vs-hero-statement {
container-type: inline-size;
background: var(--vs-page);
color: var(--vs-ink);
font-family: var(--vs-font-sans);
font-stretch: var(--vs-font-stretch);
text-align: center;
}
.vs-hero-statement__inner {
max-width: var(--vs-container);
margin-inline: auto;
padding: var(--vs-section-y) var(--vs-gutter);
}
.vs-hero-statement__title {
font-size: clamp(2.5rem, 10cqi, 6.75rem);
}
.vs-hero-statement__body {
max-width: 34rem;
margin: 1.5rem auto 0;
font-size: 1.0625rem;
line-height: 1.55;
color: var(--vs-ink-2);
}
.vs-hero-statement__actions {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 12px;
margin-top: 2rem;
}
.vs-hero-statement__media {
margin-top: clamp(40px, 7cqi, 72px);
aspect-ratio: 16 / 7;
overflow: hidden;
border: var(--vs-border-w) solid var(--vs-line);
border-radius: var(--vs-radius-window);
background: var(--vs-canvas);
box-shadow: var(--vs-pop-shadow, none);
}
.vs-hero-statement__media :global(:is(img, video)) {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
</style> Original, MIT.