Search

Jump to any page.

Marketing

Research List

Index of articles with cover, topic and localised date.

pnpm dlx shadcn@latest add @paragon/research-list
Brings in@base-ui/reactcn
registry/paragon/components/research-list.tsx
import * as React from "react"
import { mergeProps } from "@base-ui/react/merge-props"
import { useRender } from "@base-ui/react/use-render"
import { cn } from "cn"

function ResearchList({ className, ...props }: React.ComponentProps<"ul">) {
  return (
    <ul
      data-slot="research-list"
      className={cn("flex flex-col border-b", className)}
      {...props}
    />
  )
}

/**
 * One row of the research index: cover, title, topic and date.
 * `date` takes a Date or ISO string and is formatted in `locale`.
 */
function ResearchItem({
  title,
  topic,
  date,
  locale = "en-GB",
  cover,
  className,
  render,
  ...props
}: Omit<useRender.ComponentProps<"a">, "title" | "children"> & {
  title: React.ReactNode
  topic?: React.ReactNode
  date?: Date | string
  locale?: string
  /** Artwork for the 4:3 cover. A sand swatch is shown when omitted. */
  cover?: React.ReactNode
}) {
  const when = date ? new Date(date) : undefined

  const row = useRender({
    defaultTagName: "a",
    props: mergeProps<"a">(
      {
        className: cn(
          "group/research grid grid-cols-[6rem_1fr] items-center gap-x-5 gap-y-1 border-t py-[1.125rem] outline-none focus-visible:ring-3 focus-visible:ring-ring/40 sm:grid-cols-[9rem_1fr_auto] sm:gap-x-6",
          className
        ),
        children: (
          <>
            <span className="row-span-2 aspect-[4/3] overflow-hidden rounded-[0.625rem] bg-sand sm:row-span-1 [&>*]:size-full [&>img]:object-cover [&>img]:transition-transform [&>img]:duration-700 [&>img]:ease-paragon group-hover/research:[&>img]:scale-[1.04]">
              {cover}
            </span>
            <span className="flex min-w-0 flex-col gap-1">
              <span className="text-lg leading-snug font-medium tracking-[-0.01em] text-balance decoration-1 underline-offset-4 group-hover/research:underline">
                {title}
              </span>
              {topic ? <span className="text-[0.90625rem] text-muted-foreground">{topic}</span> : null}
            </span>
            {when ? (
              <time
                dateTime={when.toISOString().slice(0, 10)}
                className="col-start-2 text-[0.90625rem] text-muted-foreground tabular-nums sm:col-start-auto"
              >
                {new Intl.DateTimeFormat(locale, { day: "numeric", month: "short", year: "numeric", timeZone: "UTC" }).format(when)}
              </time>
            ) : null}
          </>
        ),
      },
      props
    ),
    render,
    state: { slot: "research-item" },
  })

  return <li>{row}</li>
}

export { ResearchList, ResearchItem }