# Activity Feed

> Activity Feed for Comment Thread.

A shadcn/ui block from the [@flx](https://ui.flexnative.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/flx/comment-thread-3).

- Page, with a live preview: https://shadcn.exchange/r/flx/comment-thread-3
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/flx/comment-thread-3-light-341f1d02ffb80474.png
- Registry item: https://ui.flexnative.com/r/comment-thread-3.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://ui.flexnative.com/r/comment-thread-3.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `lucide-react`
- Registry items: `avatar`, `button`, `card`, `input`

## Files

### `registry/intents/collaboration/comment-thread/comment-thread-3.tsx`

```tsx
'use client'

import { useState } from 'react'
import {
  GitCommitVertical,
  MessageSquare,
  Share2,
  UserPlus,
} from 'lucide-react'

import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
import {
  Card,
  CardContent,
  CardFooter,
  CardHeader,
  CardTitle,
} from '@/components/ui/card'
import { Input } from '@/components/ui/input'

type CommentEntry = {
  kind: 'comment'
  id: string
  name: string
  avatar: string
  time: string
  text: string
}

type EventEntry = {
  kind: 'event'
  id: string
  icon: typeof Share2
  time: string
  text: string
}

type Entry = CommentEntry | EventEntry

const INITIAL: Entry[] = [
  {
    kind: 'event',
    id: 'e1',
    icon: UserPlus,
    time: '3h',
    text: 'Grace Hopper was added as an editor',
  },
  {
    kind: 'comment',
    id: 'c1',
    name: 'Ada Lovelace',
    avatar:
      'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=128&h=128&fit=crop&crop=faces',
    time: '2h',
    text: 'First draft is ready for review.',
  },
  {
    kind: 'event',
    id: 'e2',
    icon: GitCommitVertical,
    time: '2h',
    text: 'Alan Turing edited the pricing section',
  },
  {
    kind: 'comment',
    id: 'c2',
    name: 'Grace Hopper',
    avatar:
      'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=128&h=128&fit=crop&crop=faces',
    time: '1h',
    text: 'Looks great. Shipping it.',
  },
  {
    kind: 'event',
    id: 'e3',
    icon: Share2,
    time: '40m',
    text: 'Document shared with the design team',
  },
]

export function CommentThread3() {
  const [entries, setEntries] = useState<Entry[]>(INITIAL)
  const [draft, setDraft] = useState('')

  const send = () => {
    const text = draft.trim()
    if (!text) return
    setEntries((prev) => [
      ...prev,
      {
        kind: 'comment',
        id: `me-${prev.length}`,
        name: 'You',
        avatar: '',
        time: 'now',
        text,
      },
    ])
    setDraft('')
  }

  return (
    <Card>
      <CardHeader>
        <CardTitle className="flex items-center gap-2">
          <MessageSquare className="size-4" />
          Activity
        </CardTitle>
      </CardHeader>
      <CardContent className="flex flex-col gap-4">
        {entries.map((entry) =>
          entry.kind === 'comment' ? (
            <div key={entry.id} className="flex gap-3">
              <Avatar className="size-7">
                <AvatarImage src={entry.avatar} alt={entry.name} />
                <AvatarFallback className="bg-muted text-xs">
                  {entry.name
                    .split(' ')
                    .map((n) => n[0])
                    .join('')}
                </AvatarFallback>
              </Avatar>
              <div className="flex flex-1 flex-col gap-0.5">
                <div className="flex items-baseline justify-between gap-2">
                  <span className="text-sm font-medium">{entry.name}</span>
                  <span className="text-muted-foreground text-xs">
                    {entry.time}
                  </span>
                </div>
                <p className="text-sm">{entry.text}</p>
              </div>
            </div>
          ) : (
            <div
              key={entry.id}
              className="text-muted-foreground flex items-center gap-3 text-xs"
            >
              <div className="bg-muted flex size-7 shrink-0 items-center justify-center rounded-full">
                <entry.icon className="size-3.5" />
              </div>
              <span className="flex-1">{entry.text}</span>
              <span>{entry.time}</span>
            </div>
          ),
        )}
      </CardContent>
      <CardFooter>
        <div className="flex w-full gap-2">
          <Input
            placeholder="Write a comment..."
            value={draft}
            onChange={(e) => setDraft(e.target.value)}
            onKeyDown={(e) => e.key === 'Enter' && send()}
          />
          <Button onClick={send} disabled={!draft.trim()}>
            Send
          </Button>
        </div>
      </CardFooter>
    </Card>
  )
}
```
