{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "post-row",
  "title": "Post Row",
  "description": "One writing entry as a single link: a title, a date that stays on its calendar day and quiet tags, for blogs, changelogs and archives.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/miseui/ui/post-row.tsx",
      "content": "import type * as React from \"react\"\nimport { ArrowUpRight } from \"lucide-react\"\nimport { cn } from \"@/registry/miseui/lib/utils\"\n\ntype PostRowVariant = \"line\" | \"stacked\" | \"ledger\"\ntype PostRowEffect = \"nudge\"\n\nconst DATE_ONLY = /^\\d{4}-\\d{2}-\\d{2}$/\n\n/**\n * \"2026-11-03\" means that calendar day, but new Date reads it as UTC midnight, which is still the 2nd in the Americas.\n * Date-only strings therefore format in UTC, so nobody sees yesterday's date.\n */\nfunction formatPostDate(date: string | Date, locale?: string) {\n  const dateOnly = typeof date === \"string\" && DATE_ONLY.test(date)\n  const parsed = new Date(dateOnly ? `${date}T00:00:00Z` : date)\n  if (Number.isNaN(parsed.getTime())) return { label: String(date), dateTime: undefined }\n  const label = new Intl.DateTimeFormat(locale, { dateStyle: \"medium\", timeZone: dateOnly ? \"UTC\" : undefined }).format(parsed)\n  return { label, dateTime: dateOnly ? (date as string) : parsed.toISOString() }\n}\n\nconst ROOT_CLASS: Record<PostRowVariant, string> = {\n  line: \"grid grid-cols-[minmax(0,1fr)_auto] items-baseline gap-x-4 gap-y-1 py-3\",\n  stacked: \"grid grid-cols-[minmax(0,1fr)] gap-1 py-4\",\n  // Wide enough for a medium date in the common locales, and it may still wrap rather than push the title out.\n  ledger: \"grid grid-cols-[minmax(0,5.5rem)_minmax(0,1fr)] items-baseline gap-x-4 gap-y-1 py-3\",\n}\n\nconst TITLE_CLASS: Record<PostRowVariant, string> = {\n  line: \"text-sm font-medium\",\n  stacked: \"text-[15px] font-medium\",\n  ledger: \"text-sm font-medium\",\n}\n\nconst NUDGE_CLASS =\n  \"transition-transform duration-(--duration-base) ease-(--ease-mise) group-hover/post:translate-x-1 rtl:group-hover/post:-translate-x-1 motion-reduce:transition-none motion-reduce:group-hover/post:translate-x-0\"\n\nfunction PostTitle({ variant, effect, kicker, children }: { variant: PostRowVariant; effect?: PostRowEffect; kicker?: React.ReactNode; children: React.ReactNode }) {\n  return (\n    <span data-slot=\"post-row-title\" className={cn(\"block min-w-0 leading-5 wrap-break-word text-foreground\", TITLE_CLASS[variant], effect === \"nudge\" && NUDGE_CLASS)}>\n      {kicker ? <span className=\"me-2 text-xs font-normal text-muted-foreground\">{kicker}</span> : null}\n      <span className=\"decoration-border underline-offset-4 group-hover/post:underline\">{children}</span>\n      {effect === \"nudge\" ? (\n        // Takes its room at rest, so the line never reflows when it fades in.\n        <ArrowUpRight aria-hidden=\"true\" data-slot=\"post-row-arrow\" className=\"ms-1 inline-block size-3.5 align-[-2px] text-muted-foreground opacity-0 transition-opacity duration-(--duration-fast) ease-(--ease-mise) group-hover/post:opacity-100\" />\n      ) : null}\n    </span>\n  )\n}\n\nfunction PostTags({ tags }: { tags?: readonly string[] }) {\n  if (!tags || tags.length === 0) return null\n  return (\n    <span data-slot=\"post-row-tags\" className=\"flex min-w-0 flex-wrap gap-1\">\n      {tags.map((tag) => (\n        <span key={tag} className=\"rounded-sm bg-muted px-1 text-xs leading-5 text-muted-foreground\">\n          {tag}\n        </span>\n      ))}\n    </span>\n  )\n}\n\ntype PostRowProps = Omit<React.ComponentProps<\"a\">, \"title\"> & {\n  title: React.ReactNode\n  /** A Date or an ISO string. A date-only string is shown as that calendar day in every time zone. */\n  date: string | Date\n  tags?: readonly string[]\n  /** A short type label in front of the title, such as \"Note\". */\n  kicker?: React.ReactNode\n  /** A sentence or two under the title. Only `stacked` has room for it. */\n  excerpt?: React.ReactNode\n  /** A few words beside the date, such as \"6 min read\". */\n  meta?: React.ReactNode\n  locale?: string\n  /** `line` title and date on one baseline, `stacked` a title with a summary, `ledger` a date column for archives. */\n  variant?: PostRowVariant\n  /** `nudge` moves the title a little towards where the link goes, and shows an arrow. */\n  effect?: PostRowEffect\n  /** Your router's link. It receives `href` and the rest. */\n  as?: React.ElementType\n}\n\ninterface LayoutProps {\n  variant: PostRowVariant\n  heading: React.ReactNode\n  time: React.ReactNode\n  tags: React.ReactNode\n  excerpt: React.ReactNode\n  extra: React.ReactNode\n}\n\nfunction PostLayout({ variant, heading, time, tags, excerpt, extra }: LayoutProps) {\n  const titled = (\n    <span className=\"grid min-w-0 gap-1\">\n      {heading}\n      {tags}\n    </span>\n  )\n  if (variant === \"ledger\") {\n    return (\n      <>\n        {time}\n        {titled}\n      </>\n    )\n  }\n  if (variant === \"line\") {\n    return (\n      <>\n        {titled}\n        <span className=\"flex shrink-0 items-baseline gap-2 whitespace-nowrap\">\n          {extra ? <span className=\"max-sm:hidden\">{extra}</span> : null}\n          {time}\n        </span>\n      </>\n    )\n  }\n  return (\n    <>\n      {heading}\n      {excerpt ? <span data-slot=\"post-row-excerpt\" className=\"text-[13px] leading-5 text-pretty text-muted-foreground\">{excerpt}</span> : null}\n      <span className=\"mt-1 flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1\">\n        {time}\n        {extra}\n        {tags}\n      </span>\n    </>\n  )\n}\n\nfunction PostRow({ title, date, tags, kicker, excerpt, meta, locale, variant = \"line\", effect, as: Root = \"a\", className, ...props }: PostRowProps) {\n  const { label, dateTime } = formatPostDate(date, locale)\n  return (\n    <Root\n      data-slot=\"post-row\"\n      data-variant={variant}\n      data-effect={effect}\n      className={cn(\n        \"group/post min-w-0 border-b text-start outline-none [li:last-child>&]:border-b-0\",\n        \"transition-opacity duration-(--duration-fast) ease-(--ease-mise) active:opacity-70 active:duration-0\",\n        \"focus-visible:rounded-sm focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:ring-inset\",\n        ROOT_CLASS[variant],\n        className,\n      )}\n      {...props}\n    >\n      <PostLayout\n        variant={variant}\n        heading={<PostTitle variant={variant} effect={effect} kicker={kicker}>{title}</PostTitle>}\n        time={\n          <time data-slot=\"post-row-date\" dateTime={dateTime} className=\"text-[13px] leading-5 text-muted-foreground tabular-nums\">\n            {label}\n          </time>\n        }\n        tags={<PostTags tags={tags} />}\n        excerpt={excerpt}\n        extra={meta ? <span className=\"text-[13px] leading-5 text-muted-foreground\">{meta}</span> : null}\n      />\n    </Root>\n  )\n}\n\nexport { PostRow, formatPostDate, type PostRowProps, type PostRowVariant, type PostRowEffect }\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "display"
  ],
  "type": "registry:ui"
}