← ui

telegram-summary

block · paid

a link-summary bot's Telegram conversation, built on telegram-chat

npx shadcn add @ag/telegram-summary

A paid item: its source installs with a licence key, kept in .env.local as AG_LICENCE_KEY and sent from components.json. The source stays in your project and out of any public repository. The licence

components.json
{
  "registries": {
    "@ag": {
      "url": "https://ui.adriangalilea.com/r/{name}.json",
      "headers": { "Authorization": "Bearer ${AG_LICENCE_KEY}" }
    }
  }
}
Already installed? Preview an update
npx shadcn add @ag/telegram-summary --dry-run

Your installed source stays unchanged until you update it. How updates work

Latest changes · 2026-09-30
  • Breaking: from="conversation" is gone with the chat's own clock. summaryClip(script) is the summary's clip and conversationStart(script) now returns where the conversation starts in it (ms): <Playback clip={summaryClip(s)} start={conversationStart(s)}><TelegramSummary script={s} /></Playback>.
Updated 2026-09-30 · release notes

shelf social & links

uses telegram-chat, clip

the demo above, verbatim

telegram-summary.demo.tsx
"use client"

import { Sample } from "@/app/samples"
import {
  conversationStart,
  summaryClip,
  TelegramSummary,
  type TelegramSummaryScript,
} from "@/registry/base-nova/blocks/telegram-summary/telegram-summary"
import { Playback } from "@/registry/base-nova/ui/playback"

// #region script
const SCRIPT: TelegramSummaryScript = {
  kind: "peer",
  chatName: "Adrian",
  chatTag: "online",
  // A real face, and Telegram's animated profile video looping over it. The letter
  // gradient is only the fallback for a peer with no photo, and a demo that shows the
  // fallback is showing the one case the component did not have to be written for.
  avatar: "/adriangalilea.jpg",
  avatarVideo: "/adriangalilea.mp4",
  intro: "you have to read this",
  link: "paulgraham.com/ds.html",
  preview: {
    site: "paulgraham.com",
    title: "Do Things that Don't Scale",
    description:
      "One of the most common types of advice we give at Y Combinator is to do things that don't scale.",
  },
  mention: "@xtldrbot",
  summary: {
    via: "via @xtldrbot",
    sections: [
      {
        emoji: "🌱",
        heading: "Recruit users by hand",
        items: [
          "Startups take off because founders make them",
          "Stripe installed itself on users' laptops",
        ],
      },
      {
        emoji: "🔥",
        heading: "Delight, deliberately",
        items: [
          { text: "Over-engage with early users; it compounds", cite: "¶12" },
        ],
      },
    ],
    quote: {
      text: "The most common unscalable thing founders have to do at the start is to recruit users manually.",
      by: "Paul Graham",
    },
    linkLabel: "🔗 paulgraham.com",
    time: "⏱ 14 min read",
    reactions: [{ emoji: "❤️", count: 1 }],
  },
  alt: "A private chat: a friend sends an essay, the bot summarizes it inline.",
}
// #endregion

export default function Demo() {
  return (
    <div className="space-y-16">
      <Sample name="summary" title="an essay, summarized inline" with="script">
        {/* The phone is as wide as its box. */}
        <div className="mx-auto w-89">
          <Playback
            clip={summaryClip(SCRIPT)}
            start={conversationStart(SCRIPT)}
          >
            <TelegramSummary script={SCRIPT} wallpaper="/tg-pattern.svg" />
          </Playback>
        </div>
      </Sample>
      <Sample
        name="small"
        glance="large"
        title="the same, small"
        description="every size a share of the phone's width"
        with="script"
      >
        <div className="mx-auto w-56">
          <Playback
            clip={summaryClip(SCRIPT)}
            start={conversationStart(SCRIPT)}
          >
            <TelegramSummary script={SCRIPT} wallpaper="/tg-pattern.svg" />
          </Playback>
        </div>
      </Sample>
    </div>
  )
}