@m6d/cortex-angular 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -51,20 +51,23 @@ No root-level providers needed — each widget instance is fully self-contained.
51
51
 
52
52
  `transport.getHeaders` can return any request headers needed by the host app. WebSocket auth continues to derive the `token` query param from a bearer `Authorization` header when present.
53
53
 
54
- ## Custom header
54
+ ## Custom parts
55
55
 
56
- Put an `ng-template` marked `cortexHeader` inside the widget to replace its
57
- header. It replaces the default on both screens, the chat and the history, and
58
- receives one context with the widget's state and actions:
56
+ Put an `ng-template` marked `cortexSlot` inside the widget to draw one of its
57
+ parts yourself: `header`, `landing` (the blank chat) or `threadList` (the
58
+ history's list). Each replaces the widget's default and receives the same
59
+ context the default is drawn from, typed by the slot name. Use only the slots
60
+ you need:
59
61
 
60
62
  ```ts
61
- import { CortexChatWidgetComponent, CortexHeaderDirective } from '@m6d/cortex-angular';
63
+ import { NgTemplateOutlet } from '@angular/common';
64
+ import { CortexChatWidgetComponent, CortexSlotDirective } from '@m6d/cortex-angular';
62
65
 
63
66
  @Component({
64
- imports: [CortexChatWidgetComponent, CortexHeaderDirective],
67
+ imports: [CortexChatWidgetComponent, CortexSlotDirective, NgTemplateOutlet],
65
68
  template: `
66
69
  <cortex-chat-widget [config]="config">
67
- <ng-template cortexHeader let-chat>
70
+ <ng-template cortexSlot="header" let-chat>
68
71
  <div class="cortex-widget__chat-header">
69
72
  @if (chat.screen === 'threads') {
70
73
  <button class="cortex-widget__header-btn" (click)="chat.closeHistory()">←</button>
@@ -77,17 +80,49 @@ import { CortexChatWidgetComponent, CortexHeaderDirective } from '@m6d/cortex-an
77
80
  <button class="cortex-widget__header-btn" (click)="chat.newChat()">+</button>
78
81
  </div>
79
82
  </ng-template>
83
+
84
+ <ng-template cortexSlot="landing" let-landing>
85
+ <div class="cortex-widget__landing">
86
+ <h1>{{ landing.greeting }}</h1>
87
+ @for (suggestion of landing.suggestions; track $index) {
88
+ <button (click)="landing.send(suggestion.prompt)">{{ suggestion.title }}</button>
89
+ }
90
+ <ng-container *ngTemplateOutlet="landing.composer" />
91
+ </div>
92
+ </ng-template>
93
+
94
+ <ng-template cortexSlot="threadList" let-list>
95
+ <div class="cortex-widget__threads-list">
96
+ @for (thread of list.threads; track thread.id) {
97
+ <button (click)="list.openThread(thread)">{{ thread.title }}</button>
98
+ }
99
+ </div>
100
+ </ng-template>
80
101
  </cortex-chat-widget>
81
102
  `,
82
103
  })
83
104
  ```
84
105
 
106
+ A slot replaces the whole part, so its root sits where the default's did: in
107
+ the chat or history screen's column, under the header. The defaults' classes
108
+ are there to reuse: `cortex-widget__chat-header`, `cortex-widget__chat-title`
109
+ and `cortex-widget__header-btn` for a header, `cortex-widget__landing` for a
110
+ centered landing, `cortex-widget__threads-list` for a scrolling list. Utility
111
+ classes such as Tailwind's apply inside the widget; its own reset sits in
112
+ `@layer base.cortex`, below them. `ThreadSummary` and `Suggestion` are exported
113
+ for typing your own rows and chips.
114
+
115
+ ### `header`
116
+
117
+ One header serves both screens; `screen` says which is showing.
118
+
85
119
  | Field | Type | Description |
86
120
  | -------------- | --------------------- | -------------------------------------------------------------- |
87
121
  | `screen` | `'chat' \| 'threads'` | Which screen the header is on |
88
122
  | `viewMode` | `'helper' \| 'full'` | The configured view mode |
89
123
  | `title` | `string \| null` | The open thread's title; `null` on a new chat |
90
124
  | `agentName` | `string \| undefined` | `agentName` in the widget's locale |
125
+ | `threadCount` | `number` | How many conversations the history lists; 0 while it loads |
91
126
  | `isWorking` | `boolean` | The agent is answering |
92
127
  | `debug` | `{ shown, on }` | Whether `showDebugButton` is set, and whether debug mode is on |
93
128
  | `newChat` | `() => void` | Starts a new chat |
@@ -95,9 +130,31 @@ import { CortexChatWidgetComponent, CortexHeaderDirective } from '@m6d/cortex-an
95
130
  | `closeHistory` | `() => void` | Returns to the open chat |
96
131
  | `toggleDebug` | `() => void` | Switches debug mode |
97
132
 
98
- The default header's classes are there to reuse: `cortex-widget__chat-header`
99
- for the bar, `cortex-widget__chat-title` for the title, and
100
- `cortex-widget__header-btn` for its quiet icon buttons.
133
+ ### `landing`
134
+
135
+ Shown while no thread is open. The first send opens a thread and swaps the
136
+ landing for it.
137
+
138
+ | Field | Type | Description |
139
+ | ------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------- |
140
+ | `greeting` | `string` | The agent's greeting in the widget's locale, or the built-in one |
141
+ | `suggestions` | `{ title, prompt }[]` | Empty until the handshake answers, and for an agent that takes no messages |
142
+ | `threads` | `ThreadSummary[] \| undefined` | Newest first; `undefined` while the first load is out |
143
+ | `composer` | `TemplateRef` | The widget's composer, or its "messages disabled" notice; place it with `ngTemplateOutlet` |
144
+ | `send` | `(prompt: string) => void` | Sends a first message; does nothing until the handshake answers, or for an agent that takes no messages |
145
+ | `openThread` | `(thread: ThreadSummary) => void` | Opens a thread |
146
+
147
+ ### `threadList`
148
+
149
+ The history's list. Its header is the `header` slot.
150
+
151
+ | Field | Type | Description |
152
+ | ------------------ | --------------------------------- | ----------------------------------------------------- |
153
+ | `threads` | `ThreadSummary[] \| undefined` | Newest first; `undefined` while the first load is out |
154
+ | `selectedThreadId` | `string \| undefined` | The open thread's id; `undefined` on a new chat |
155
+ | `openThread` | `(thread: ThreadSummary) => void` | Opens a thread |
156
+ | `deleteThread` | `(threadId: string) => void` | Deletes a thread |
157
+ | `newChat` | `() => void` | Starts a new chat |
101
158
 
102
159
  ## Theming
103
160