Comments

A threaded comment section with avatars, timestamps, and a reply form.

Preview

Comments (3)
AJ
Alice Johnson2 hours ago

This component library looks fantastic! The signal-first approach is exactly what I've been waiting for.


BS
Bob Smith5 hours ago

How does theming work with SSR? Would love to know more about dark-mode.

CL
Carol Lee3 hours ago

It uses CSS custom properties on :root — works great with SSR since there's no flash.


html
<div class="card max-w-lg">
  <header><strong>Comments (3)</strong></header>
  <div class="vstack gap-4">
    <div class="hstack gap-3 items-start">
      <ng-oat-avatar initials="AJ" />
      <div class="vstack gap-1 flex-1">
        <div class="hstack gap-2">
          <strong>Alice Johnson</strong>
          <small class="text-light">2 hours ago</small>
        </div>
        <p class="mb-0">Great component library!</p>
        <button class="btn ghost small">Reply</button>
      </div>
    </div>
    <hr />
    <div class="vstack gap-2">
      <textarea rows="3" placeholder="Write a comment..."></textarea>
      <div class="flex justify-end">
        <button class="btn">Post Comment</button>
      </div>
    </div>
  </div>
</div>

SFC Source

typescript
import { Component } from '@angular/core';
import { NgOatAvatar } from '@letsprogram/ng-oat';

@Component({
  selector: 'app-comments',
  imports: [NgOatAvatar],
  template: `
    <div class="card max-w-lg">
      <header><strong>Comments ({{ comments.length }})</strong></header>
      <div class="vstack gap-4">
        @for (comment of comments; track comment.name) {
          <div class="hstack gap-3 items-start">
            <ng-oat-avatar [initials]="comment.initials" />
            <div class="vstack gap-1 flex-1">
              <div class="hstack gap-2">
                <strong>{{ comment.name }}</strong>
                <small class="text-light">{{ comment.time }}</small>
              </div>
              <p class="mb-0">{{ comment.text }}</p>
              <button class="btn ghost small">Reply</button>
            </div>
          </div>
          <hr />
        }
        <div class="vstack gap-2">
          <textarea rows="3" placeholder="Write a comment..."></textarea>
          <div class="flex justify-end">
            <button class="btn">Post Comment</button>
          </div>
        </div>
      </div>
    </div>
  `,
})
export class CommentsComponent {
  comments = [
    { initials: 'AJ', name: 'Alice Johnson', time: '2 hours ago', text: 'Great article!' },
    { initials: 'BS', name: 'Bob Smith', time: '5 hours ago', text: 'Very helpful, thanks!' },
  ];
}