Split layout 02
A heading and View all posts button beside two stacked posts with large images.
Last updated
---
/**
* Split layout 02: A heading and View all posts button beside two stacked posts with large images.
*
* @block blog
* @order 21
*/
import Section from '@/components/apogee/Section/Section.astro'
import SectionHeader from '@/components/apogee/SectionHeader/SectionHeader.astro'
import PostCard from '@/components/apogee/PostCard/PostCard.astro'
import { plain } from '@/components/apogee/sections/_shared/spine.ts'
import { toCard, type BlogContent, type Post } from '@/components/apogee/sections/_shared/blog.ts'
import Button from '@/components/apogee/Button/Button.astro'
const demoPosts: Post[] = [
{
title: 'Designing review sessions people look forward to',
href: '#',
excerpt: 'How to run critiques that sharpen the work instead of draining the room.',
date: '2026-01-20',
readingTime: '8 min read',
image: { src: 'https://picsum.photos/seed/apogee-blog-1/960/640', alt: '', width: 960, height: 640 },
category: { name: 'Design', href: '#' },
author: { name: 'Ada Lovelace', href: '#' },
tags: [{ name: 'Design', href: '#', color: 'primary' }, { name: 'Research', href: '#', color: 'neutral' }, { name: 'Process', href: '#', color: 'positive' }],
},
{
title: 'Migrating to a typed component library',
href: '#',
excerpt: 'What changed when we moved two hundred screens onto one set of typed parts.',
date: '2026-01-19',
readingTime: '6 min read',
image: { src: 'https://picsum.photos/seed/apogee-blog-2/960/640', alt: '', width: 960, height: 640 },
category: { name: 'Engineering', href: '#' },
author: { name: 'Alan Turing', href: '#' },
tags: [{ name: 'Engineering', href: '#', color: 'primary' }, { name: 'Tooling', href: '#', color: 'neutral' }],
},
]
/** @composable */
interface Props extends BlogContent {}
const {
eyebrow = 'Our blog',
heading = 'From the blog',
description = 'Interviews, tips, guides, industry best practices, and news.',
items = demoPosts,
locale = Astro.currentLocale ?? 'en',
primaryAction = { label: 'View all posts', href: '#' },
} = Astro.props
---
<Section spacing="large">
<div class="grid gap-12 lg:grid-cols-[minmax(0,1fr)_minmax(0,2fr)] lg:gap-16">
<div class="flex flex-col items-start gap-8">
<SectionHeader eyebrow={eyebrow ?? undefined} heading={plain(heading)} description={description ?? undefined} />
{primaryAction && <Button href={primaryAction.href} size="large" class="max-sm:hidden">{primaryAction.label}</Button>}
</div>
<ul class="flex list-none flex-col gap-12 p-0">
{items.map((post) => <li><PostCard post={toCard(post)} locale={locale} orientation="horizontal" size="large" headingLevel={3} /></li>)}
</ul>
</div>
{primaryAction && <Button href={primaryAction.href} size="large" fullWidth class="mt-8 sm:hidden">{primaryAction.label}</Button>}
</Section>
Show codeHide code
---
/**
* Split layout 02: A heading and View all posts button beside two stacked posts with large images.
*
* @block blog
* @order 21
*/
import Section from '@/components/apogee/Section/Section.astro'
import SectionHeader from '@/components/apogee/SectionHeader/SectionHeader.astro'
import PostCard from '@/components/apogee/PostCard/PostCard.astro'
import { plain } from '@/components/apogee/sections/_shared/spine.ts'
import { toCard, type BlogContent, type Post } from '@/components/apogee/sections/_shared/blog.ts'
import Button from '@/components/apogee/Button/Button.astro'
const demoPosts: Post[] = [
{
title: 'Designing review sessions people look forward to',
href: '#',
excerpt: 'How to run critiques that sharpen the work instead of draining the room.',
date: '2026-01-20',
readingTime: '8 min read',
image: { src: 'https://picsum.photos/seed/apogee-blog-1/960/640', alt: '', width: 960, height: 640 },
category: { name: 'Design', href: '#' },
author: { name: 'Ada Lovelace', href: '#' },
tags: [{ name: 'Design', href: '#', color: 'primary' }, { name: 'Research', href: '#', color: 'neutral' }, { name: 'Process', href: '#', color: 'positive' }],
},
{
title: 'Migrating to a typed component library',
href: '#',
excerpt: 'What changed when we moved two hundred screens onto one set of typed parts.',
date: '2026-01-19',
readingTime: '6 min read',
image: { src: 'https://picsum.photos/seed/apogee-blog-2/960/640', alt: '', width: 960, height: 640 },
category: { name: 'Engineering', href: '#' },
author: { name: 'Alan Turing', href: '#' },
tags: [{ name: 'Engineering', href: '#', color: 'primary' }, { name: 'Tooling', href: '#', color: 'neutral' }],
},
]
/** @composable */
interface Props extends BlogContent {}
const {
eyebrow = 'Our blog',
heading = 'From the blog',
description = 'Interviews, tips, guides, industry best practices, and news.',
items = demoPosts,
locale = Astro.currentLocale ?? 'en',
primaryAction = { label: 'View all posts', href: '#' },
} = Astro.props
---
<Section spacing="large">
<div class="grid gap-12 lg:grid-cols-[minmax(0,1fr)_minmax(0,2fr)] lg:gap-16">
<div class="flex flex-col items-start gap-8">
<SectionHeader eyebrow={eyebrow ?? undefined} heading={plain(heading)} description={description ?? undefined} />
{primaryAction && <Button href={primaryAction.href} size="large" class="max-sm:hidden">{primaryAction.label}</Button>}
</div>
<ul class="flex list-none flex-col gap-12 p-0">
{items.map((post) => <li><PostCard post={toCard(post)} locale={locale} orientation="horizontal" size="large" headingLevel={3} /></li>)}
</ul>
</div>
{primaryAction && <Button href={primaryAction.href} size="large" fullWidth class="mt-8 sm:hidden">{primaryAction.label}</Button>}
</Section>Add
npx @ava-ui/apogee add blog/split-layout-02
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.
This copies the block to src/components/apogee/blocks/blog/ with everything it uses: Button, PostCard, Section, SectionHeader. It slots into any page, such as a home page or a product page. Swap the posts array for your content collection. Use Copy code above to paste it instead.
Accessibility
- Each post is one link: the title stretches over the card, and the author, category and tag links sit above it and stay clickable.
- The decorative arrow and the images are hidden from screen readers (their alt is empty because the title already names the post).