CompareItempopular
apps/www/src/sections/CompareItem.astro · 71 lines · group Compare
CompareItem — one column of <Compare>: a white card with an optional picture on top, an icon or a mono label, a title, paragraphs, bullets, a code sample and markdown. Parent: <Compare> only. Text: `description` is one paragraph or an array of paragraphs; words between *asterisks* inside it are painted in the brand colour. Code: `code` renders a dark code block at the bottom of the card, `file` its file-name caption — for comparing two configurations or snippets. Children: markdown between the tags is rendered at the end of the card. Picture: `image` (file name in images/) is shown whole in a fixed-height box above the text — a product shot or a logo, not a wide photo.
In the fleet
Used on 3 sites built with this engine.
Samples 1
<Compare>TWO WAYS TO RUN IT
Cloud or your own server
The stations do not care; the data can live where your policy says it should.

Nordvind Cloud
We keep the servers, the backups and the forecasts up to date.
- Nothing to install
- Forecasts included
- Updates on the day they ship

On your own server
The same software inside your network, on your hardware.
- Data never leaves the farm
- Your backup policy
- Yearly licence
MDX of this sample
<Compare columns={2} kicker="TWO WAYS TO RUN IT" title="Cloud or your own server" description="The stations do not care; the data can live where your policy says it should.">
<CompareItem title="Nordvind Cloud" description="We keep the servers, the backups and the forecasts up to date." bullets={['Nothing to install', 'Forecasts included', 'Updates on the day they ship']} image="screen-01.png" />
<CompareItem title="On your own server" description="The same software inside your network, on your hardware." bullets={['Data never leaves the farm', 'Your backup policy', 'Yearly licence']} image="screen-02.png" />
</Compare>Props
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| title | string | yes | the card heading | |
| kicker | string | a short mono label beside the icon, e.g. a version or a code | ||
| description | string | string[] | one paragraph, or several as an array; *emphasis* is painted in the brand colour | ||
| image | string | file name in images/, shown whole above the text | ||
| Icon | any | a Heroicon component imported in the article, e.g. Icon={BoltIcon} | ||
| bullets | string[] | [] | short points listed under the description | |
| code | string | a code sample rendered in a dark block | ||
| file | string | file name shown as the caption of the code block |
Source apps/www/src/sections/CompareItem.astro @ gitt.one
---
/**
* CompareItem — one column of <Compare>: a white card with an optional picture
* on top, an icon or a mono label, a title, paragraphs, bullets, a code
* sample and markdown.
*
* Parent: <Compare> only.
* Text: `description` is one paragraph or an array of paragraphs; words
* between *asterisks* inside it are painted in the brand colour.
* Code: `code` renders a dark code block at the bottom of the card, `file` its
* file-name caption — for comparing two configurations or snippets.
* Children: markdown between the tags is rendered at the end of the card.
* Picture: `image` (file name in images/) is shown whole in a fixed-height box
* above the text — a product shot or a logo, not a wide photo.
*/
import { Image } from 'astro:assets';
import { resolveImage } from '../lib/images';
interface Props {
/** the card heading */
title: string;
/** a short mono label beside the icon, e.g. a version or a code */
kicker?: string;
/** one paragraph, or several as an array; *emphasis* is painted in the brand colour */
description?: string | string[];
/** file name in images/, shown whole above the text */
image?: string;
/** a Heroicon component imported in the article, e.g. Icon={BoltIcon} */
Icon?: any;
/** short points listed under the description */
bullets?: string[];
/** a code sample rendered in a dark block */
code?: string;
/** file name shown as the caption of the code block */
file?: string;
}
const { title, kicker, description, image, Icon, bullets = [], code, file } = Astro.props;
const img = image ? await resolveImage(image) : undefined;
const paragraphs = description === undefined ? [] : Array.isArray(description) ? description : [description];
---
<div class="flex flex-col overflow-hidden rounded-lg bg-white text-gray-900 shadow-lg">
{img && <Image src={img} alt={title} widths={[400, 840]} class="h-48 w-full max-w-full flex-shrink-0 object-contain" />}
<div class="flex flex-1 flex-col p-6">
<div class="flex items-center gap-3">
{Icon && <span class="flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md bg-gradient-to-r from-primary-500 to-primary-alt-600"><Icon class="h-5 w-5 text-white" aria-hidden="true" /></span>}
{kicker && <code class="rounded bg-gray-50 px-2 py-1 font-mono text-sm text-primary-700 ring-1 ring-inset ring-primary-100">{kicker}</code>}
</div>
<h3 class:list={['text-xl font-semibold', (Icon || kicker) && 'mt-4']}>{title}</h3>
{paragraphs.length > 0 && (
<div class="mt-3 text-base text-gray-500">
{paragraphs.map((p) => (
<p class="my-2">{p.split('*').map((chunk, i) => <span class:list={[i % 2 === 1 && 'text-primary-600']}>{chunk}</span>)}</p>
))}
</div>
)}
{bullets.length > 0 && (
<ul class="mt-4 list-none space-y-3 text-base text-gray-500">
{bullets.map((b) => <li class="flex"><span aria-hidden="true" class="mr-3 mt-2 h-1.5 w-1.5 flex-none rounded-full bg-gradient-to-r from-primary-500 to-primary-alt-600" /><span>{b}</span></li>)}
</ul>
)}
{code !== undefined && (
<div class="mt-4 flex flex-grow flex-col overflow-hidden rounded-xl bg-gray-900 shadow-lg">
{file && <div class="border-b border-white/10 px-4 py-2 font-mono text-xs uppercase tracking-wide text-gray-400">{file}</div>}
<pre class="flex-grow overflow-x-auto px-4 py-4 text-sm leading-relaxed text-gray-100"><code>{code}</code></pre>
</div>
)}
<div class="text-base text-gray-500 [&>p]:mt-2"><slot /></div>
</div>
</div>Source links point to engine-astro@7b686388. Samples are demo content: the components are the real ones, the copy and the pictures are made up.