DocBlocks
All blocks

Comment Thread

Inline comment thread with avatars and a composer. Local state, drop-in.

Free · Collaboration

This Pro block's preview & source unlock with the library.

Unlock — ₹2,499

Install

terminal
npx shadcn@latest add https://blocks.aiskillhub.info/api/registry/comment-thread

Source

components/docblocks/comment-thread.tsx
"use client";
import { useState } from "react";

type Comment = { id: string; author: string; initials: string; body: string; time: string };

export function CommentThread({ initial = [] }: { initial?: Comment[] }) {
  const [comments, setComments] = useState<Comment[]>(initial);
  const [draft, setDraft] = useState("");
  return (
    <div className="w-80 space-y-3 rounded-xl border border-border bg-surface p-4">
      {comments.map((c) => (
        <div key={c.id} className="flex gap-3">
          <span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-primary text-[11px] font-semibold text-primary-fg">{c.initials}</span>
          <div className="space-y-0.5">
            <p className="text-xs"><span className="font-medium">{c.author}</span> <span className="text-muted">{c.time}</span></p>
            <p className="text-sm">{c.body}</p>
          </div>
        </div>
      ))}
      <form
        onSubmit={(e) => { e.preventDefault(); if (!draft.trim()) return;
          setComments((p) => [...p, { id: crypto.randomUUID(), author: "You", initials: "Y", body: draft, time: "now" }]); setDraft(""); }}
        className="flex gap-2"
      >
        <input value={draft} onChange={(e) => setDraft(e.target.value)} placeholder="Add a comment…"
          className="flex-1 rounded-lg border border-border bg-background px-3 py-1.5 text-sm outline-none focus:ring-2 focus:ring-ring" />
        <button className="rounded-lg bg-primary px-3 text-sm font-medium text-primary-fg">Send</button>
      </form>
    </div>
  );
}