{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "agency-journal",
  "title": "Agency: Journal",
  "description": "The journal index as a ruled list with drawn covers, and a post page with its author, a wide cover, the text in one reading column and more posts.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "https://eased.dev/r/eased-tokens.json",
    "https://eased.dev/r/eased-motion.json",
    "https://eased.dev/r/agency-core.json",
    "https://eased.dev/r/avatar.json",
    "https://eased.dev/r/badge.json"
  ],
  "files": [
    {
      "path": "src/registry/eased/templates/agency/journal.tsx",
      "content": "\"use client\";\n\nimport { Avatar } from \"../../avatar/avatar\";\nimport { Badge } from \"../../badge/badge\";\nimport { journal, posts, type Post, type PostBlock } from \"./content-journal\";\nimport { NoteCover } from \"./covers\";\nimport { COLUMN, LABEL, PageHead, Reveal, Section, formatDay, useHref } from \"./kit\";\n\n/**\n * The journal index, /journal: every post as a row of one ruled grid, a small drawn cover beside\n * the kind and date, the title and its line, so the titles all start on one x (rule 103).\n */\nexport function JournalIndex() {\n  const to = useHref();\n  return (\n    <section aria-labelledby=\"page-title\" className={`${COLUMN} pt-section-sm pb-group`}>\n      <PageHead title={journal.title} lead={journal.lead} />\n      <ol className=\"mt-group border-t border-line-subtle\">\n        {posts.map((post, i) => (\n          <li key={post.slug}>\n            <Reveal\n              index={i}\n              className=\"group relative grid grid-cols-[6rem_minmax(0,1fr)] gap-x-pad-md border-b border-line-subtle py-pad-md sm:grid-cols-[10rem_minmax(0,1fr)] lg:grid-cols-[14rem_minmax(0,1fr)] lg:gap-x-pad-lg\"\n            >\n              <div aria-hidden className=\"image-ring relative aspect-square overflow-hidden rounded-panel bg-surface-sunken text-text lg:aspect-[3/2]\">\n                <NoteCover art={post.art} />\n              </div>\n              <div className=\"flex min-w-0 flex-col gap-1.5 lg:gap-in\">\n                <Meta post={post} />\n                <h2 className=\"text-display-xl font-medium text-pretty text-text sm:text-display-2xl\">\n                  <a\n                    href={to(`/journal/${post.slug}`)}\n                    className=\"focus-ring rounded-control-xs transition-colors duration-(--eased-duration-fast) ease-standard group-hover-fine:text-text-secondary after:absolute after:inset-0\"\n                  >\n                    {post.title}\n                  </a>\n                </h2>\n                <p className=\"max-w-2xl text-ui-md text-pretty text-text-secondary max-sm:hidden\">{post.dek}</p>\n              </div>\n            </Reveal>\n          </li>\n        ))}\n      </ol>\n    </section>\n  );\n}\n\n/** The kind as a badge and the date, as the latest strip shows them. */\nfunction Meta({ post, minutes = false }: { post: Post; minutes?: boolean }) {\n  return (\n    <p className=\"flex flex-wrap items-center gap-2 text-ui-sm text-text-muted\">\n      <Badge tone={post.kind === \"Press\" ? \"brand\" : \"neutral\"}>{post.kind}</Badge>\n      <time dateTime={post.date} className=\"tabular-nums\">\n        {formatDay(post.date)}\n      </time>\n      {minutes && (\n        <span className=\"tabular-nums\">\n          · {post.minutes} {journal.read}\n        </span>\n      )}\n    </p>\n  );\n}\n\n/**\n * A post, /journal/<slug>: its kind, date and title over a line and the author, a wide drawn\n * cover, then the text in one reading column, and the other posts under it.\n */\nexport function JournalPost({ slug }: { slug: string }) {\n  const post = posts.find((p) => p.slug === slug) ?? posts[0];\n  const others = posts.filter((p) => p.slug !== post.slug).slice(0, 3);\n\n  return (\n    <>\n      <article aria-labelledby=\"page-title\" className={`${COLUMN} pt-section-sm pb-group`}>\n        <PageHead back={journal.back} title={post.title} lead={post.dek} size=\"md\">\n          <Meta post={post} minutes />\n          <p className=\"flex items-center gap-2 text-ui text-text-secondary\">\n            <Avatar name={post.author} size=\"sm\" />\n            {journal.by} {post.author}\n          </p>\n        </PageHead>\n        <Reveal index={1} className=\"mt-group\">\n          <div aria-hidden className=\"image-ring relative aspect-[2/1] overflow-hidden rounded-surface bg-surface-sunken text-text sm:aspect-[3/1]\">\n            <NoteCover art={post.art} />\n          </div>\n        </Reveal>\n        <Reveal index={2} className=\"mx-auto mt-group flex max-w-[40rem] flex-col gap-pad-base\">\n          {post.body.map((block, i) => (\n            <Block key={i} block={block} />\n          ))}\n        </Reveal>\n      </article>\n\n      <Section id=\"more\" label={journal.more}>\n        <ul className=\"grid gap-x-tiles gap-y-pad-lg sm:grid-cols-3\">\n          {others.map((p, i) => (\n            <li key={p.slug}>\n              <Reveal index={i}>\n                <PostCard post={p} />\n              </Reveal>\n            </li>\n          ))}\n        </ul>\n      </Section>\n    </>\n  );\n}\n\n/** One block of a post's text. */\nfunction Block({ block }: { block: PostBlock }) {\n  if (block.type === \"h2\") return <h2 className=\"mt-pad-md text-display-xl font-medium text-balance text-text\">{block.text}</h2>;\n  if (block.type === \"quote\")\n    return (\n      <figure className=\"my-pad-md flex flex-col gap-in border-l-2 border-(--tessera-tile) pl-pad-md\">\n        <blockquote className=\"font-serif text-display-2xl text-pretty text-text\">{block.text}</blockquote>\n        {block.by && <figcaption className=\"text-ui text-text-muted\">{block.by}</figcaption>}\n      </figure>\n    );\n  if (block.type === \"list\")\n    return (\n      <ul className=\"flex flex-col gap-2.5\">\n        {block.items.map((item) => (\n          <li key={item} className=\"grid grid-cols-[1rem_minmax(0,1fr)] items-baseline gap-2 text-ui-md text-pretty text-text-secondary sm:text-ui-lg\">\n            <span aria-hidden className=\"h-px w-2.5 translate-y-[-0.3em] bg-text-muted\" />\n            {item}\n          </li>\n        ))}\n      </ul>\n    );\n  return <p className=\"text-ui-md text-pretty text-text-secondary sm:text-ui-lg\">{block.text}</p>;\n}\n\n/** A small card for another post: cover, date and title, the whole card one link (rule 59). */\nfunction PostCard({ post }: { post: Post }) {\n  const to = useHref();\n  return (\n    <article className=\"group relative flex flex-col gap-in\">\n      <div aria-hidden className=\"image-ring relative aspect-[3/2] overflow-hidden rounded-panel bg-surface-sunken text-text\">\n        <NoteCover art={post.art} />\n      </div>\n      <div className=\"flex flex-col gap-1.5\">\n        <time dateTime={post.date} className={`${LABEL} tabular-nums`}>\n          {formatDay(post.date)}\n        </time>\n        <h3 className=\"text-ui-md font-medium text-pretty text-text\">\n          <a href={to(`/journal/${post.slug}`)} className=\"focus-ring rounded-control-xs after:absolute after:inset-0 after:rounded-panel\">\n            {post.title}\n          </a>\n        </h3>\n      </div>\n    </article>\n  );\n}\n",
      "type": "registry:component",
      "target": "@components/eased/templates/agency/journal.tsx"
    }
  ],
  "meta": {
    "template": "agency",
    "kind": "template-section",
    "industries": [
      "media"
    ]
  },
  "type": "registry:block"
}