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

sampleshown inside <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

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

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

NameTypeRequiredDefaultDescription
titlestringyesthe card heading
kickerstringa short mono label beside the icon, e.g. a version or a code
descriptionstring | string[]one paragraph, or several as an array; *emphasis* is painted in the brand colour
imagestringfile name in images/, shown whole above the text
Iconanya Heroicon component imported in the article, e.g. Icon={BoltIcon}
bulletsstring[][]short points listed under the description
codestringa code sample rendered in a dark block
filestringfile 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.