Skip to content

Hero

The Hero component is what gets used on pages with the splash template, like the index page.

Hero.astro
---
import { Image } from 'astro:assets';
import CallToAction from './CallToAction.astro';
import type { Props } from '@astrojs/starlight/props';
import { PAGE_TITLE_ID } from 'starlight-ion-theme/constants';
const { data } = Astro.props.entry;
const { title = data.title, tagline, image, actions = [] } = data.hero || {};
const imageAttrs = {
loading: 'eager' as const,
decoding: 'async' as const,
width: 400,
height: 400,
alt: image?.alt || '',
};
let darkImage: ImageMetadata | undefined;
let lightImage: ImageMetadata | undefined;
let rawHtml: string | undefined;
if (image) {
if ('file' in image) {
darkImage = image.file;
} else if ('dark' in image) {
darkImage = image.dark;
lightImage = image.light;
} else {
rawHtml = image.html;
}
}
const titleHTML = title.split(" ").map((titlePart: string) => {
return `<span>${titlePart}</span>`
});
---
<div class="hero">
<div class="sl-flex copy">
<h1 id={PAGE_TITLE_ID} data-page-title set:html={titleHTML} />
{tagline && <div class="tagline" set:html={tagline} />}
{actions.length > 0 && (
<div class="sl-flex actions">
{actions.map(({ text, ...attrs }: any) => (
<CallToAction {...attrs} set:html={text} />
))}
</div>
)}
</div>
{darkImage && (
<Image
src={darkImage}
{...imageAttrs}
class:list={{ 'light:sl-hidden': Boolean(lightImage) }}
/>
)}
{lightImage && <Image src={lightImage} {...imageAttrs} class="dark:sl-hidden" />}
{rawHtml && <div class="hero-html sl-flex" set:html={rawHtml} />}
</div>
<style>
.hero {
display: flex;
flex-direction: row;
align-items: center;
gap: 1rem;
border-bottom: 1px solid var(--sl-color-gray-6);
padding: 1rem;
}
.hero > img,
.hero > .hero-html {
object-fit: contain;
width: min(70%, 20rem);
height: auto;
margin-inline: auto;
}
.stack {
flex-direction: column;
gap: clamp(1.5rem, calc(1.5rem + 1vw), 2rem);
text-align: center;
}
.copy {
flex-direction: column;
gap: 1rem;
align-items: center;
}
.copy > * {
width: 100%;
}
h1 {
font-size: clamp(var(--sl-text-3xl), calc(0.25rem + 5vw), var(--sl-text-5xl));
line-height: var(--sl-line-height-headings);
font-weight: 600;
color: var(--sl-color-white);
display: flex;
flex-direction: row;
align-items: center;
gap: 1rem;
flex-wrap: wrap;
}
.tagline {
font-size: clamp(var(--sl-text-base), calc(0.0625rem + 2vw), var(--sl-text-lg));
color: var(--sl-color-gray-2);
}
.actions {
gap: 1rem 2rem;
flex-wrap: wrap;
justify-content: center;
margin-top: 1rem;
}
@media screen and (max-width: 1250px) {
.hero {
flex-direction: column-reverse;
text-align: center
}
h1 {
gap: 0.75rem;
text-align: center;
justify-content: center;
}
.hero > img,
.hero > .hero-html {
order: 2;
width: min(100%, 25rem);
}
}
@media (min-width: 50rem) {
.hero {
gap: 2rem;
padding: 2rem;
}
.hero > img,
.hero > .hero-html {
order: 2;
width: min(100%, 25rem);
}
.stack {
text-align: start;
}
.copy {
align-items: flex-start;
}
.actions {
justify-content: flex-start;
}
}
</style>