1import { ChangeDetectionStrategy, Component } from "@angular/core";
2
3import { FeatureHeaderComponent } from "../feature-header.component";
4import { HeadlessChatController } from "./headless-chat";
5import { messageText } from "./headless-message-utils";
6
7@Component({
8  selector: "showcase-headless-simple-feature",
9  imports: [FeatureHeaderComponent],
10  changeDetection: ChangeDetectionStrategy.OnPush,
11  host: { class: "feature-page" },
12  template: `
13    <showcase-feature-header />
14    <main class="headless-page" aria-label="Simple headless chat">
15      <section class="headless-panel">
16        <h2>Headless Chat (Simple)</h2>
17        <div class="headless-messages" aria-live="polite">
18          @if (messages().length === 0) {
19            <p class="headless-empty">No messages yet. Say hi!</p>
20          }
21          @for (message of messages(); track message.id) {
22            @if (message.role === "user") {
23              <div
24                class="headless-user-message"
25                data-testid="headless-message-user"
26                data-message-role="user"
27              >
28                {{ messageText(message) }}
29              </div>
30            } @else if (message.role === "assistant") {
31              <div
32                class="headless-assistant-message"
33                data-testid="headless-message-assistant"
34                data-message-role="assistant"
35              >
36                {{ messageText(message) }}
37              </div>
38            }
39          }
40          @if (isRunning()) {
41            <p class="headless-status">Agent is thinking…</p>
42          }
43        </div>
44        <div class="headless-suggestions" data-testid="headless-suggestions">
45          @for (suggestion of suggestions; track suggestion) {
46            <button
47              type="button"
48              [disabled]="isRunning()"
49              (click)="send(suggestion)"
50            >
51              {{ suggestion }}
52            </button>
53          }
54        </div>
55        @if (error()) {
56          <p
57            class="headless-error"
58            data-testid="headless-simple-error"
59            role="alert"
60          >
61            {{ error() }}
62          </p>
63        }
64        <div class="headless-composer" data-testid="headless-composer">
65          <textarea
66            rows="2"
67            aria-label="Message"
68            placeholder="Type a message"
69            [value]="inputValue()"
70            (input)="updateInput($event)"
71            (keydown)="handleComposerKeydown($event)"
72          ></textarea>
73          <button
74            type="button"
75            [disabled]="isRunning() || !inputValue().trim()"
76            (click)="send()"
77          >
78            Send
79          </button>
80        </div>
81      </section>
82    </main>
83  `,
84})
85export class HeadlessSimpleFeatureComponent extends HeadlessChatController {
86  protected readonly messageText = messageText;
87  protected readonly suggestions = [
88    "Say hello in one short sentence.",
89    "Tell me a one-line joke.",
90    "Give me a fun fact.",
91  ] as const;
92
93  constructor() {
94    super("headless-simple");
95  }
96}
97
4a65196ee
CopilotKit Showcase