ph/components

Page header

Grid band with a date and a pixel title.

Commit overflow

ada grace

Code

Copy into src/components/ph/ .

dates.ts
const asDate = (d: Date | string) => (typeof d === "string" ? new Date(d) : d);

export function dateBlock(d: Date | string) {
  const date = asDate(d);
  return {
    month: date.toLocaleDateString("en-US", { month: "short", timeZone: "UTC" }).toUpperCase(),
    dayYear: `${date.getUTCDate()}, ${date.getUTCFullYear()}`,
    iso: date.toISOString(),
  };
}

export function longDate(d: Date | string) {
  const date = asDate(d);
  return {
    label: date.toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric", timeZone: "UTC" }),
    iso: date.toISOString(),
  };
}
PageHeader.astro
---
import { longDate } from "./dates";

type Props = {
  title: string;
  date?: Date | string;
  updated?: Date | string;
  align?: "start"| "center";
  class?: string;
};

const { title, date, updated, align = "start", class: className } = Astro.props;
const published = date ? longDate(date) : null;
const edited = updated ? longDate(updated) : null;
---

<header
  class:list={[
    "grid-bg-animated border-b border-border [--grid-size:26px]",
    className,
  ]}
>
  <div
    class:list={[
      "mx-auto flex max-w-5xl flex-col gap-5 px-4 pt-20 pb-12 sm:px-8 md:px-14 md:pt-28 md:pb-16",
      align === "center"? "items-center text-center": "items-start",
    ]}
  >
    {
      published && (
        <div class="border border-foreground bg-card font-pixel text-xs text-card-foreground uppercase sm:text-sm">
          <time datetime={published.iso} class="block px-2 py-0.5">{published.label}</time>
          {edited && (
            <div class="border-t border-foreground/30 px-2 py-0.5">
              Updated <time datetime={edited.iso}>{edited.label}</time>
            </div>
          )}
        </div>
      )
    }
    <h1 class="font-pixel text-4xl leading-[1.05] uppercase sm:text-6xl md:text-7xl dark:text-ph-yellow">{title}</h1>
    {Astro.slots.has("default") && <div class="flex flex-wrap gap-4 md:gap-x-5"><slot /></div>}
  </div>
</header>