@memberjunction/ng-conversations 6.2.0-edge.4 → 6.2.0-edge.6
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 +29 -0
- package/dist/lib/components/attachment/image-viewer.component.d.ts +3 -1
- package/dist/lib/components/attachment/image-viewer.component.d.ts.map +1 -1
- package/dist/lib/components/attachment/image-viewer.component.js +5 -1
- package/dist/lib/components/attachment/image-viewer.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-agent-picker.component.d.ts +1 -1
- package/dist/lib/components/conversation/conversation-agent-picker.component.js +3 -3
- package/dist/lib/components/conversation/conversation-agent-picker.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +88 -20
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +785 -387
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +60 -20
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +290 -389
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +153 -17
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +1400 -299
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +25 -2
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +79 -40
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.d.ts +19 -0
- package/dist/lib/components/overlay/chat-overlay.component.d.ts.map +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.js +125 -13
- package/dist/lib/components/overlay/chat-overlay.component.js.map +1 -1
- package/dist/lib/components/project/project-form-modal.component.js +2 -2
- package/dist/lib/components/project/project-form-modal.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +6 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.js +110 -82
- package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-call-failure-notice.d.ts +13 -0
- package/dist/lib/components/realtime/realtime-call-failure-notice.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-call-failure-notice.js +21 -0
- package/dist/lib/components/realtime/realtime-call-failure-notice.js.map +1 -0
- package/dist/lib/components/realtime/realtime-composer.component.js +114 -102
- package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +21 -2
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-session-overlay.component.js +113 -76
- package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +7 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -1
- package/dist/lib/components/sidebar/routines-section.component.js +1 -1
- package/dist/lib/components/sidebar/routines-section.component.js.map +1 -1
- package/dist/lib/components/task/tasks-full-view.component.d.ts +152 -31
- package/dist/lib/components/task/tasks-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/task/tasks-full-view.component.js +2227 -214
- package/dist/lib/components/task/tasks-full-view.component.js.map +1 -1
- package/dist/lib/components/tasks/tasks-dropdown.component.js +4 -4
- package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +11 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +25 -28
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/services/agent-state.service.d.ts.map +1 -1
- package/dist/lib/services/agent-state.service.js +8 -8
- package/dist/lib/services/agent-state.service.js.map +1 -1
- package/dist/lib/services/browser-realtime-media-host.d.ts +7 -7
- package/dist/lib/services/browser-realtime-media-host.js +8 -78
- package/dist/lib/services/browser-realtime-media-host.js.map +1 -1
- package/dist/lib/services/conversation-agent.service.d.ts +53 -20
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +108 -54
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-detail-window.store.d.ts +5 -0
- package/dist/lib/services/conversation-detail-window.store.d.ts.map +1 -1
- package/dist/lib/services/conversation-detail-window.store.js +52 -5
- package/dist/lib/services/conversation-detail-window.store.js.map +1 -1
- package/dist/lib/services/conversation-naming.d.ts.map +1 -1
- package/dist/lib/services/conversation-naming.js +9 -2
- package/dist/lib/services/conversation-naming.js.map +1 -1
- package/dist/lib/services/conversation-tasks-filter.d.ts +15 -0
- package/dist/lib/services/conversation-tasks-filter.d.ts.map +1 -0
- package/dist/lib/services/conversation-tasks-filter.js +69 -0
- package/dist/lib/services/conversation-tasks-filter.js.map +1 -0
- package/dist/lib/services/realtime-audio-recorder.d.ts +94 -86
- package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.js +222 -195
- package/dist/lib/services/realtime-audio-recorder.js.map +1 -1
- package/dist/lib/services/realtime-session.service.d.ts +30 -2
- package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
- package/dist/lib/services/realtime-session.service.js +35 -7
- package/dist/lib/services/realtime-session.service.js.map +1 -1
- package/dist/lib/services/recording/libopus-wasm-binary.d.ts +3 -0
- package/dist/lib/services/recording/libopus-wasm-binary.d.ts.map +1 -0
- package/dist/lib/services/recording/libopus-wasm-binary.js +489 -0
- package/dist/lib/services/recording/libopus-wasm-binary.js.map +1 -0
- package/dist/lib/services/recording/libopus-worker-source.d.ts +48 -0
- package/dist/lib/services/recording/libopus-worker-source.d.ts.map +1 -0
- package/dist/lib/services/recording/libopus-worker-source.js +170 -0
- package/dist/lib/services/recording/libopus-worker-source.js.map +1 -0
- package/dist/lib/services/recording/linear-resampler.d.ts +45 -0
- package/dist/lib/services/recording/linear-resampler.d.ts.map +1 -0
- package/dist/lib/services/recording/linear-resampler.js +85 -0
- package/dist/lib/services/recording/linear-resampler.js.map +1 -0
- package/dist/lib/services/recording/opus-packet-encoder.d.ts +50 -0
- package/dist/lib/services/recording/opus-packet-encoder.d.ts.map +1 -0
- package/dist/lib/services/recording/opus-packet-encoder.js +41 -0
- package/dist/lib/services/recording/opus-packet-encoder.js.map +1 -0
- package/dist/lib/services/recording/wasm-opus-encoder.d.ts +86 -0
- package/dist/lib/services/recording/wasm-opus-encoder.d.ts.map +1 -0
- package/dist/lib/services/recording/wasm-opus-encoder.js +232 -0
- package/dist/lib/services/recording/wasm-opus-encoder.js.map +1 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.d.ts +39 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.d.ts.map +1 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.js +101 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.js.map +1 -0
- package/dist/lib/services/search.service.d.ts.map +1 -1
- package/dist/lib/services/search.service.js +3 -16
- package/dist/lib/services/search.service.js.map +1 -1
- package/dist/lib/utils/agent-failure-display.d.ts +14 -0
- package/dist/lib/utils/agent-failure-display.d.ts.map +1 -0
- package/dist/lib/utils/agent-failure-display.js +26 -0
- package/dist/lib/utils/agent-failure-display.js.map +1 -0
- package/dist/lib/utils/distinct-artifacts.d.ts +9 -3
- package/dist/lib/utils/distinct-artifacts.d.ts.map +1 -1
- package/dist/lib/utils/distinct-artifacts.js +24 -5
- package/dist/lib/utils/distinct-artifacts.js.map +1 -1
- package/dist/lib/utils/message-list-order.d.ts +13 -0
- package/dist/lib/utils/message-list-order.d.ts.map +1 -0
- package/dist/lib/utils/message-list-order.js +31 -0
- package/dist/lib/utils/message-list-order.js.map +1 -0
- package/dist/lib/utils/pin-state.d.ts +11 -0
- package/dist/lib/utils/pin-state.d.ts.map +1 -0
- package/dist/lib/utils/pin-state.js +9 -0
- package/dist/lib/utils/pin-state.js.map +1 -0
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +36 -36
- package/dist/lib/services/browser-recording-unload-guard.d.ts +0 -30
- package/dist/lib/services/browser-recording-unload-guard.d.ts.map +0 -1
- package/dist/lib/services/browser-recording-unload-guard.js +0 -43
- package/dist/lib/services/browser-recording-unload-guard.js.map +0 -1
- package/dist/lib/services/realtime-pcm-wav.d.ts +0 -79
- package/dist/lib/services/realtime-pcm-wav.d.ts.map +0 -1
- package/dist/lib/services/realtime-pcm-wav.js +0 -213
- package/dist/lib/services/realtime-pcm-wav.js.map +0 -1
|
@@ -78,19 +78,32 @@ function RealtimeAgentBannerComponent_Conditional_1_Template(rf, ctx) { if (rf &
|
|
|
78
78
|
i0.ɵɵadvance(6);
|
|
79
79
|
i0.ɵɵconditional(ctx_r1.ShowStartLive ? 15 : -1);
|
|
80
80
|
} }
|
|
81
|
-
function
|
|
82
|
-
i0.ɵɵelement(0, "i",
|
|
81
|
+
function RealtimeAgentBannerComponent_Conditional_2_Conditional_5_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
82
|
+
i0.ɵɵelement(0, "i", 25);
|
|
83
83
|
} }
|
|
84
|
-
function
|
|
85
|
-
i0.ɵɵelement(0, "span",
|
|
84
|
+
function RealtimeAgentBannerComponent_Conditional_2_Conditional_5_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
85
|
+
i0.ɵɵelement(0, "span", 26);
|
|
86
86
|
} if (rf & 2) {
|
|
87
|
-
const ctx_r1 = i0.ɵɵnextContext(
|
|
87
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
88
88
|
i0.ɵɵattribute("data-state", ctx_r1.OrbState(ctx_r1.State));
|
|
89
89
|
} }
|
|
90
|
-
function
|
|
90
|
+
function RealtimeAgentBannerComponent_Conditional_2_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
91
|
+
i0.ɵɵelementStart(0, "span", 23);
|
|
92
|
+
i0.ɵɵconditionalCreate(1, RealtimeAgentBannerComponent_Conditional_2_Conditional_5_Conditional_1_Template, 1, 0, "i", 25)(2, RealtimeAgentBannerComponent_Conditional_2_Conditional_5_Conditional_2_Template, 1, 1, "span", 26);
|
|
93
|
+
i0.ɵɵelementStart(3, "span", 27);
|
|
94
|
+
i0.ɵɵtext(4);
|
|
95
|
+
i0.ɵɵelementEnd()();
|
|
96
|
+
} if (rf & 2) {
|
|
97
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
98
|
+
i0.ɵɵadvance();
|
|
99
|
+
i0.ɵɵconditional(ctx_r1.IsBusy(ctx_r1.State) ? 1 : 2);
|
|
100
|
+
i0.ɵɵadvance(3);
|
|
101
|
+
i0.ɵɵtextInterpolate(ctx_r1.StateLabel(ctx_r1.State));
|
|
102
|
+
} }
|
|
103
|
+
function RealtimeAgentBannerComponent_Conditional_2_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
91
104
|
const _r5 = i0.ɵɵgetCurrentView();
|
|
92
105
|
i0.ɵɵelementStart(0, "button", 28);
|
|
93
|
-
i0.ɵɵlistener("click", function
|
|
106
|
+
i0.ɵɵlistener("click", function RealtimeAgentBannerComponent_Conditional_2_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MinimizeRequested.emit()); });
|
|
94
107
|
i0.ɵɵelement(1, "i", 29);
|
|
95
108
|
i0.ɵɵelementEnd();
|
|
96
109
|
} }
|
|
@@ -101,26 +114,32 @@ function RealtimeAgentBannerComponent_Conditional_2_Template(rf, ctx) { if (rf &
|
|
|
101
114
|
i0.ɵɵelementStart(3, "span", 22);
|
|
102
115
|
i0.ɵɵtext(4);
|
|
103
116
|
i0.ɵɵelementEnd();
|
|
104
|
-
i0.ɵɵ
|
|
105
|
-
i0.ɵɵ
|
|
106
|
-
i0.ɵɵ
|
|
107
|
-
i0.ɵɵtext(9);
|
|
108
|
-
i0.ɵɵelementEnd()()();
|
|
109
|
-
i0.ɵɵconditionalCreate(10, RealtimeAgentBannerComponent_Conditional_2_Conditional_10_Template, 2, 0, "button", 27);
|
|
117
|
+
i0.ɵɵconditionalCreate(5, RealtimeAgentBannerComponent_Conditional_2_Conditional_5_Template, 5, 2, "span", 23);
|
|
118
|
+
i0.ɵɵelementEnd();
|
|
119
|
+
i0.ɵɵconditionalCreate(6, RealtimeAgentBannerComponent_Conditional_2_Conditional_6_Template, 2, 0, "button", 24);
|
|
110
120
|
} if (rf & 2) {
|
|
111
121
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
112
122
|
i0.ɵɵadvance(2);
|
|
113
123
|
i0.ɵɵtextInterpolate(ctx_r1.AgentName.charAt(0));
|
|
114
124
|
i0.ɵɵadvance(2);
|
|
115
125
|
i0.ɵɵtextInterpolate(ctx_r1.AgentName);
|
|
116
|
-
i0.ɵɵadvance(2);
|
|
117
|
-
i0.ɵɵconditional(ctx_r1.IsBusy(ctx_r1.State) ? 6 : 7);
|
|
118
|
-
i0.ɵɵadvance(3);
|
|
119
|
-
i0.ɵɵtextInterpolate(ctx_r1.StateLabel(ctx_r1.State));
|
|
120
126
|
i0.ɵɵadvance();
|
|
121
|
-
i0.ɵɵconditional(ctx_r1.
|
|
127
|
+
i0.ɵɵconditional(!ctx_r1.HideState ? 5 : -1);
|
|
128
|
+
i0.ɵɵadvance();
|
|
129
|
+
i0.ɵɵconditional(ctx_r1.ShowMinimize ? 6 : -1);
|
|
122
130
|
} }
|
|
123
|
-
function
|
|
131
|
+
function RealtimeAgentBannerComponent_Conditional_3_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
132
|
+
i0.ɵɵelementStart(0, "span", 33);
|
|
133
|
+
i0.ɵɵtext(1, "speaking as ");
|
|
134
|
+
i0.ɵɵelementStart(2, "b");
|
|
135
|
+
i0.ɵɵtext(3);
|
|
136
|
+
i0.ɵɵelementEnd()();
|
|
137
|
+
} if (rf & 2) {
|
|
138
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
139
|
+
i0.ɵɵadvance(3);
|
|
140
|
+
i0.ɵɵtextInterpolate(ctx_r1.AgentName);
|
|
141
|
+
} }
|
|
142
|
+
function RealtimeAgentBannerComponent_Conditional_3_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
124
143
|
i0.ɵɵelementStart(0, "span", 34);
|
|
125
144
|
i0.ɵɵtext(1);
|
|
126
145
|
i0.ɵɵelementEnd();
|
|
@@ -130,48 +149,62 @@ function RealtimeAgentBannerComponent_Conditional_3_Conditional_11_Template(rf,
|
|
|
130
149
|
i0.ɵɵadvance();
|
|
131
150
|
i0.ɵɵtextInterpolate1("\u00B7 ", ctx_r1.ModelName);
|
|
132
151
|
} }
|
|
133
|
-
function
|
|
152
|
+
function RealtimeAgentBannerComponent_Conditional_3_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
134
153
|
const _r6 = i0.ɵɵgetCurrentView();
|
|
135
154
|
i0.ɵɵelementStart(0, "button", 16);
|
|
136
|
-
i0.ɵɵlistener("click", function
|
|
155
|
+
i0.ɵɵlistener("click", function RealtimeAgentBannerComponent_Conditional_3_Conditional_9_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OpenSession()); });
|
|
137
156
|
i0.ɵɵelement(1, "i", 17);
|
|
138
157
|
i0.ɵɵelementStart(2, "span");
|
|
139
158
|
i0.ɵɵtext(3, "Open session");
|
|
140
159
|
i0.ɵɵelementEnd()();
|
|
141
160
|
} }
|
|
142
|
-
function
|
|
143
|
-
i0.ɵɵelement(0, "i",
|
|
161
|
+
function RealtimeAgentBannerComponent_Conditional_3_Conditional_10_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
162
|
+
i0.ɵɵelement(0, "i", 25);
|
|
144
163
|
} }
|
|
145
|
-
function
|
|
146
|
-
i0.ɵɵelementStart(0, "div",
|
|
164
|
+
function RealtimeAgentBannerComponent_Conditional_3_Conditional_10_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
165
|
+
i0.ɵɵelementStart(0, "div", 42);
|
|
147
166
|
i0.ɵɵelement(1, "span")(2, "span")(3, "span")(4, "span")(5, "span")(6, "span")(7, "span")(8, "span");
|
|
148
167
|
i0.ɵɵelementEnd();
|
|
149
168
|
} if (rf & 2) {
|
|
150
|
-
const ctx_r1 = i0.ɵɵnextContext(
|
|
169
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
151
170
|
i0.ɵɵclassProp("waveform--idle", ctx_r1.State !== "speaking");
|
|
152
171
|
} }
|
|
153
|
-
function
|
|
172
|
+
function RealtimeAgentBannerComponent_Conditional_3_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
173
|
+
i0.ɵɵelementStart(0, "div", 39);
|
|
174
|
+
i0.ɵɵconditionalCreate(1, RealtimeAgentBannerComponent_Conditional_3_Conditional_10_Conditional_1_Template, 1, 0, "i", 25)(2, RealtimeAgentBannerComponent_Conditional_3_Conditional_10_Conditional_2_Template, 9, 2, "div", 40);
|
|
175
|
+
i0.ɵɵelementStart(3, "span", 41);
|
|
176
|
+
i0.ɵɵtext(4);
|
|
177
|
+
i0.ɵɵelementEnd()();
|
|
178
|
+
} if (rf & 2) {
|
|
179
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
180
|
+
i0.ɵɵclassProp("banner__state--busy", ctx_r1.IsBusy(ctx_r1.State));
|
|
181
|
+
i0.ɵɵadvance();
|
|
182
|
+
i0.ɵɵconditional(ctx_r1.IsBusy(ctx_r1.State) ? 1 : 2);
|
|
183
|
+
i0.ɵɵadvance(3);
|
|
184
|
+
i0.ɵɵtextInterpolate(ctx_r1.StateLabel(ctx_r1.State));
|
|
185
|
+
} }
|
|
186
|
+
function RealtimeAgentBannerComponent_Conditional_3_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
154
187
|
const _r7 = i0.ɵɵgetCurrentView();
|
|
155
|
-
i0.ɵɵelementStart(0, "button",
|
|
156
|
-
i0.ɵɵlistener("click", function
|
|
157
|
-
i0.ɵɵelement(1, "i",
|
|
188
|
+
i0.ɵɵelementStart(0, "button", 43);
|
|
189
|
+
i0.ɵɵlistener("click", function RealtimeAgentBannerComponent_Conditional_3_Conditional_12_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ToggleGear($event)); });
|
|
190
|
+
i0.ɵɵelement(1, "i", 44);
|
|
158
191
|
i0.ɵɵelementEnd();
|
|
159
192
|
} if (rf & 2) {
|
|
160
193
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
161
194
|
i0.ɵɵclassProp("iconb--on", ctx_r1.GearOpen || ctx_r1.DevMode);
|
|
162
195
|
i0.ɵɵattribute("aria-expanded", ctx_r1.GearOpen);
|
|
163
196
|
} }
|
|
164
|
-
function
|
|
197
|
+
function RealtimeAgentBannerComponent_Conditional_3_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
165
198
|
const _r8 = i0.ɵɵgetCurrentView();
|
|
166
|
-
i0.ɵɵelementStart(0, "button",
|
|
167
|
-
i0.ɵɵlistener("click", function
|
|
168
|
-
i0.ɵɵelement(1, "i",
|
|
199
|
+
i0.ɵɵelementStart(0, "button", 45);
|
|
200
|
+
i0.ɵɵlistener("click", function RealtimeAgentBannerComponent_Conditional_3_Conditional_13_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MinimizeRequested.emit()); });
|
|
201
|
+
i0.ɵɵelement(1, "i", 46);
|
|
169
202
|
i0.ɵɵelementEnd();
|
|
170
203
|
} }
|
|
171
|
-
function
|
|
204
|
+
function RealtimeAgentBannerComponent_Conditional_3_Conditional_14_Conditional_3_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
172
205
|
const _r10 = i0.ɵɵgetCurrentView();
|
|
173
|
-
i0.ɵɵelementStart(0, "button",
|
|
174
|
-
i0.ɵɵlistener("click", function
|
|
206
|
+
i0.ɵɵelementStart(0, "button", 57);
|
|
207
|
+
i0.ɵɵlistener("click", function RealtimeAgentBannerComponent_Conditional_3_Conditional_14_Conditional_3_For_5_Template_button_click_0_listener() { const d_r11 = i0.ɵɵrestoreView(_r10).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.SelectDensity(d_r11.Key)); });
|
|
175
208
|
i0.ɵɵtext(1);
|
|
176
209
|
i0.ɵɵelementEnd();
|
|
177
210
|
} if (rf & 2) {
|
|
@@ -182,33 +215,33 @@ function RealtimeAgentBannerComponent_Conditional_3_Conditional_21_Conditional_3
|
|
|
182
215
|
i0.ɵɵadvance();
|
|
183
216
|
i0.ɵɵtextInterpolate(d_r11.Label);
|
|
184
217
|
} }
|
|
185
|
-
function
|
|
186
|
-
i0.ɵɵelementStart(0, "div",
|
|
218
|
+
function RealtimeAgentBannerComponent_Conditional_3_Conditional_14_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
219
|
+
i0.ɵɵelementStart(0, "div", 51)(1, "span", 52);
|
|
187
220
|
i0.ɵɵtext(2, "Density");
|
|
188
221
|
i0.ɵɵelementEnd();
|
|
189
|
-
i0.ɵɵelementStart(3, "div",
|
|
190
|
-
i0.ɵɵrepeaterCreate(4,
|
|
222
|
+
i0.ɵɵelementStart(3, "div", 53);
|
|
223
|
+
i0.ɵɵrepeaterCreate(4, RealtimeAgentBannerComponent_Conditional_3_Conditional_14_Conditional_3_For_5_Template, 2, 4, "button", 54, _forTrack0);
|
|
191
224
|
i0.ɵɵelementEnd()();
|
|
192
|
-
i0.ɵɵelementStart(6, "div",
|
|
225
|
+
i0.ɵɵelementStart(6, "div", 55);
|
|
193
226
|
i0.ɵɵtext(7, "Simple returns to the pure-audio surface. Auto grows the console as you use it.");
|
|
194
227
|
i0.ɵɵelementEnd();
|
|
195
|
-
i0.ɵɵelement(8, "div",
|
|
228
|
+
i0.ɵɵelement(8, "div", 56);
|
|
196
229
|
} if (rf & 2) {
|
|
197
230
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
198
231
|
i0.ɵɵadvance(4);
|
|
199
232
|
i0.ɵɵrepeater(ctx_r1.Densities);
|
|
200
233
|
} }
|
|
201
|
-
function
|
|
234
|
+
function RealtimeAgentBannerComponent_Conditional_3_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
202
235
|
const _r9 = i0.ɵɵgetCurrentView();
|
|
203
|
-
i0.ɵɵelementStart(0, "div",
|
|
204
|
-
i0.ɵɵlistener("click", function
|
|
205
|
-
i0.ɵɵelementStart(1, "div",
|
|
236
|
+
i0.ɵɵelementStart(0, "div", 47);
|
|
237
|
+
i0.ɵɵlistener("click", function RealtimeAgentBannerComponent_Conditional_3_Conditional_14_Template_div_click_0_listener($event) { return $event.stopPropagation(); });
|
|
238
|
+
i0.ɵɵelementStart(1, "div", 48);
|
|
206
239
|
i0.ɵɵtext(2, "Interface");
|
|
207
240
|
i0.ɵɵelementEnd();
|
|
208
|
-
i0.ɵɵconditionalCreate(3,
|
|
209
|
-
i0.ɵɵelementStart(4, "button",
|
|
210
|
-
i0.ɵɵlistener("click", function
|
|
211
|
-
i0.ɵɵelement(5, "i",
|
|
241
|
+
i0.ɵɵconditionalCreate(3, RealtimeAgentBannerComponent_Conditional_3_Conditional_14_Conditional_3_Template, 9, 0);
|
|
242
|
+
i0.ɵɵelementStart(4, "button", 49);
|
|
243
|
+
i0.ɵɵlistener("click", function RealtimeAgentBannerComponent_Conditional_3_Conditional_14_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ToggleDev()); });
|
|
244
|
+
i0.ɵɵelement(5, "i", 50);
|
|
212
245
|
i0.ɵɵtext(6);
|
|
213
246
|
i0.ɵɵelementEnd()();
|
|
214
247
|
} if (rf & 2) {
|
|
@@ -231,47 +264,35 @@ function RealtimeAgentBannerComponent_Conditional_3_Template(rf, ctx) { if (rf &
|
|
|
231
264
|
i0.ɵɵelement(5, "i", 32);
|
|
232
265
|
i0.ɵɵtext(6, " Co-Agent");
|
|
233
266
|
i0.ɵɵelementEnd();
|
|
234
|
-
i0.ɵɵ
|
|
235
|
-
i0.ɵɵ
|
|
236
|
-
i0.ɵɵ
|
|
237
|
-
i0.ɵɵtext(10);
|
|
238
|
-
i0.ɵɵelementEnd()();
|
|
239
|
-
i0.ɵɵconditionalCreate(11, RealtimeAgentBannerComponent_Conditional_3_Conditional_11_Template, 2, 2, "span", 34);
|
|
240
|
-
i0.ɵɵconditionalCreate(12, RealtimeAgentBannerComponent_Conditional_3_Conditional_12_Template, 4, 0, "button", 8);
|
|
267
|
+
i0.ɵɵconditionalCreate(7, RealtimeAgentBannerComponent_Conditional_3_Conditional_7_Template, 4, 1, "span", 33);
|
|
268
|
+
i0.ɵɵconditionalCreate(8, RealtimeAgentBannerComponent_Conditional_3_Conditional_8_Template, 2, 2, "span", 34);
|
|
269
|
+
i0.ɵɵconditionalCreate(9, RealtimeAgentBannerComponent_Conditional_3_Conditional_9_Template, 4, 0, "button", 8);
|
|
241
270
|
i0.ɵɵelementEnd();
|
|
242
|
-
i0.ɵɵ
|
|
243
|
-
i0.ɵɵ
|
|
244
|
-
i0.ɵɵ
|
|
245
|
-
i0.ɵɵ
|
|
246
|
-
i0.ɵɵelementEnd()();
|
|
247
|
-
i0.ɵɵelementStart(18, "div", 12);
|
|
248
|
-
i0.ɵɵconditionalCreate(19, RealtimeAgentBannerComponent_Conditional_3_Conditional_19_Template, 2, 3, "button", 38);
|
|
249
|
-
i0.ɵɵconditionalCreate(20, RealtimeAgentBannerComponent_Conditional_3_Conditional_20_Template, 2, 0, "button", 39);
|
|
271
|
+
i0.ɵɵconditionalCreate(10, RealtimeAgentBannerComponent_Conditional_3_Conditional_10_Template, 5, 4, "div", 35);
|
|
272
|
+
i0.ɵɵelementStart(11, "div", 12);
|
|
273
|
+
i0.ɵɵconditionalCreate(12, RealtimeAgentBannerComponent_Conditional_3_Conditional_12_Template, 2, 3, "button", 36);
|
|
274
|
+
i0.ɵɵconditionalCreate(13, RealtimeAgentBannerComponent_Conditional_3_Conditional_13_Template, 2, 0, "button", 37);
|
|
250
275
|
i0.ɵɵelementEnd();
|
|
251
|
-
i0.ɵɵconditionalCreate(
|
|
276
|
+
i0.ɵɵconditionalCreate(14, RealtimeAgentBannerComponent_Conditional_3_Conditional_14_Template, 7, 4, "div", 38);
|
|
252
277
|
} if (rf & 2) {
|
|
253
278
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
254
279
|
i0.ɵɵattribute("data-state", ctx_r1.OrbState(ctx_r1.State));
|
|
255
280
|
i0.ɵɵadvance(3);
|
|
256
281
|
i0.ɵɵtextInterpolate1("Voice for ", ctx_r1.AgentName);
|
|
257
|
-
i0.ɵɵadvance(
|
|
258
|
-
i0.ɵɵ
|
|
259
|
-
i0.ɵɵadvance();
|
|
260
|
-
i0.ɵɵconditional(ctx_r1.ModelName ? 11 : -1);
|
|
282
|
+
i0.ɵɵadvance(4);
|
|
283
|
+
i0.ɵɵconditional(!ctx_r1.HideState ? 7 : -1);
|
|
261
284
|
i0.ɵɵadvance();
|
|
262
|
-
i0.ɵɵconditional(ctx_r1.
|
|
285
|
+
i0.ɵɵconditional(ctx_r1.ModelName ? 8 : -1);
|
|
263
286
|
i0.ɵɵadvance();
|
|
264
|
-
i0.ɵɵ
|
|
287
|
+
i0.ɵɵconditional(ctx_r1.ShowOpenSession ? 9 : -1);
|
|
265
288
|
i0.ɵɵadvance();
|
|
266
|
-
i0.ɵɵconditional(ctx_r1.
|
|
267
|
-
i0.ɵɵadvance(3);
|
|
268
|
-
i0.ɵɵtextInterpolate(ctx_r1.StateLabel(ctx_r1.State));
|
|
289
|
+
i0.ɵɵconditional(!ctx_r1.HideState ? 10 : -1);
|
|
269
290
|
i0.ɵɵadvance(2);
|
|
270
|
-
i0.ɵɵconditional(ctx_r1.ShowGear ?
|
|
291
|
+
i0.ɵɵconditional(ctx_r1.ShowGear ? 12 : -1);
|
|
271
292
|
i0.ɵɵadvance();
|
|
272
|
-
i0.ɵɵconditional(ctx_r1.ShowMinimize ?
|
|
293
|
+
i0.ɵɵconditional(ctx_r1.ShowMinimize ? 13 : -1);
|
|
273
294
|
i0.ɵɵadvance();
|
|
274
|
-
i0.ɵɵconditional(ctx_r1.GearOpen ?
|
|
295
|
+
i0.ɵɵconditional(ctx_r1.GearOpen ? 14 : -1);
|
|
275
296
|
} }
|
|
276
297
|
/**
|
|
277
298
|
* The call overlay's UNIFIED APP-BAR (per Redesign A — `plans/realtime/mockups/redesign-a.html`):
|
|
@@ -304,6 +325,11 @@ export class RealtimeAgentBannerComponent {
|
|
|
304
325
|
* Default `false` (the full console banner is unchanged).
|
|
305
326
|
*/
|
|
306
327
|
Compact = false;
|
|
328
|
+
/**
|
|
329
|
+
* Whether to suppress the turn-state pill and redundant "speaking as" label in the banner
|
|
330
|
+
* because the center hero orb is already displaying the agent's name and live turn state.
|
|
331
|
+
*/
|
|
332
|
+
HideState = false;
|
|
307
333
|
/** Display name of the agent the voice session fronts (e.g. "Sage"). */
|
|
308
334
|
AgentName = 'the agent';
|
|
309
335
|
/**
|
|
@@ -457,9 +483,9 @@ export class RealtimeAgentBannerComponent {
|
|
|
457
483
|
static ɵfac = function RealtimeAgentBannerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RealtimeAgentBannerComponent)(); };
|
|
458
484
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RealtimeAgentBannerComponent, selectors: [["mj-realtime-agent-banner"]], hostBindings: function RealtimeAgentBannerComponent_HostBindings(rf, ctx) { if (rf & 1) {
|
|
459
485
|
i0.ɵɵlistener("click", function RealtimeAgentBannerComponent_click_HostBindingHandler() { return ctx.OnDocumentClick(); }, i0.ɵɵresolveDocument);
|
|
460
|
-
} }, inputs: { State: "State", Compact: "Compact", AgentName: "AgentName", ErrorLabel: "ErrorLabel", ModelName: "ModelName", DevMode: "DevMode", SessionID: "SessionID", ReviewMode: "ReviewMode", ReviewStartedAt: "ReviewStartedAt", ReviewClosedAt: "ReviewClosedAt", ReviewCloseReason: "ReviewCloseReason", ShowGear: "ShowGear", ShowDensityPicker: "ShowDensityPicker", ShowMinimize: "ShowMinimize", ShowStartLive: "ShowStartLive", Density: "Density" }, outputs: { OpenSessionRequested: "OpenSessionRequested", DevModeToggled: "DevModeToggled", DensityChanged: "DensityChanged", MinimizeRequested: "MinimizeRequested", StartLiveRequested: "StartLiveRequested", CloseRequested: "CloseRequested" }, decls: 4, vars: 5, consts: [[1, "banner"], ["aria-hidden", "true", 1, "agent-orb", "agent-orb--review"], [1, "banner__id"], [1, "banner__name"], [1, "pill", "pill--review"], ["aria-hidden", "true", 1, "fa-solid", "fa-clock-rotate-left"], [1, "banner__for", "banner__range"], [1, "pill", "pill--close-reason", 3, "title"], ["type", "button", "title", "Open the agent session record", 1, "dev-link"], [1, "banner__state", "banner__state--review"], ["aria-hidden", "true", 1, "fa-solid", "fa-box-archive"], [1, "banner__state-label", "banner__state-label--review"], [1, "bar-actions"], ["type", "button", "title", "Resume this session as a new live call", 1, "start-live-pill"], ["type", "button", "title", "Close review", "aria-label", "Close session review", 1, "iconb", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-xmark"], ["type", "button", "title", "Open the agent session record", 1, "dev-link", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-arrow-up-right-from-square"], ["type", "button", "title", "Resume this session as a new live call", 1, "start-live-pill", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-phone"], [1, "banner__id", "banner__id--compact"], ["aria-hidden", "true", 1, "banner__avatar"], [1, "banner__name", "banner__name--compact"], [1, "banner__state-chip"], ["
|
|
486
|
+
} }, inputs: { State: "State", Compact: "Compact", HideState: "HideState", AgentName: "AgentName", ErrorLabel: "ErrorLabel", ModelName: "ModelName", DevMode: "DevMode", SessionID: "SessionID", ReviewMode: "ReviewMode", ReviewStartedAt: "ReviewStartedAt", ReviewClosedAt: "ReviewClosedAt", ReviewCloseReason: "ReviewCloseReason", ShowGear: "ShowGear", ShowDensityPicker: "ShowDensityPicker", ShowMinimize: "ShowMinimize", ShowStartLive: "ShowStartLive", Density: "Density" }, outputs: { OpenSessionRequested: "OpenSessionRequested", DevModeToggled: "DevModeToggled", DensityChanged: "DensityChanged", MinimizeRequested: "MinimizeRequested", StartLiveRequested: "StartLiveRequested", CloseRequested: "CloseRequested" }, decls: 4, vars: 5, consts: [[1, "banner"], ["aria-hidden", "true", 1, "agent-orb", "agent-orb--review"], [1, "banner__id"], [1, "banner__name"], [1, "pill", "pill--review"], ["aria-hidden", "true", 1, "fa-solid", "fa-clock-rotate-left"], [1, "banner__for", "banner__range"], [1, "pill", "pill--close-reason", 3, "title"], ["type", "button", "title", "Open the agent session record", 1, "dev-link"], [1, "banner__state", "banner__state--review"], ["aria-hidden", "true", 1, "fa-solid", "fa-box-archive"], [1, "banner__state-label", "banner__state-label--review"], [1, "bar-actions"], ["type", "button", "title", "Resume this session as a new live call", 1, "start-live-pill"], ["type", "button", "title", "Close review", "aria-label", "Close session review", 1, "iconb", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-xmark"], ["type", "button", "title", "Open the agent session record", 1, "dev-link", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-arrow-up-right-from-square"], ["type", "button", "title", "Resume this session as a new live call", 1, "start-live-pill", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-phone"], [1, "banner__id", "banner__id--compact"], ["aria-hidden", "true", 1, "banner__avatar"], [1, "banner__name", "banner__name--compact"], [1, "banner__state-chip"], ["type", "button", "title", "Hide the call view \u2014 the call stays live", "aria-label", "Minimize the call view", 1, "iconb", "banner__minimize--compact"], ["aria-hidden", "true", 1, "fa-solid", "fa-spinner", "fa-spin"], ["aria-hidden", "true", 1, "banner__state-dot"], [1, "banner__state-chip-label"], ["type", "button", "title", "Hide the call view \u2014 the call stays live", "aria-label", "Minimize the call view", 1, "iconb", "banner__minimize--compact", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-minus"], ["aria-hidden", "true", 1, "agent-orb"], [1, "pill", "pill--sage"], ["aria-hidden", "true", 1, "fa-solid", "fa-feather"], [1, "banner__for"], [1, "banner__model", 3, "title"], [1, "banner__state", 3, "banner__state--busy"], ["type", "button", "title", "Interface density & developer links", 1, "iconb", 3, "iconb--on"], ["type", "button", "title", "Hide the call view \u2014 the call stays live", "aria-label", "Minimize the call view", 1, "iconb"], ["role", "menu", "aria-label", "Interface settings", 1, "gear-pop"], [1, "banner__state"], ["aria-hidden", "true", 1, "waveform", 3, "waveform--idle"], [1, "banner__state-label"], ["aria-hidden", "true", 1, "waveform"], ["type", "button", "title", "Interface density & developer links", 1, "iconb", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-gear"], ["type", "button", "title", "Hide the call view \u2014 the call stays live", "aria-label", "Minimize the call view", 1, "iconb", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-down-left-and-up-right-to-center"], ["role", "menu", "aria-label", "Interface settings", 1, "gear-pop", 3, "click"], [1, "gp-h"], ["type", "button", 1, "gp-link", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", 3, "ngClass"], [1, "gp-row"], [1, "gp-l"], ["role", "radiogroup", "aria-label", "Interface density", 1, "gp-seg"], ["type", "button", "role", "radio", 3, "on"], [1, "gp-note"], [1, "gp-div"], ["type", "button", "role", "radio", 3, "click"]], template: function RealtimeAgentBannerComponent_Template(rf, ctx) { if (rf & 1) {
|
|
461
487
|
i0.ɵɵelementStart(0, "div", 0);
|
|
462
|
-
i0.ɵɵconditionalCreate(1, RealtimeAgentBannerComponent_Conditional_1_Template, 18, 5)(2, RealtimeAgentBannerComponent_Conditional_2_Template,
|
|
488
|
+
i0.ɵɵconditionalCreate(1, RealtimeAgentBannerComponent_Conditional_1_Template, 18, 5)(2, RealtimeAgentBannerComponent_Conditional_2_Template, 7, 4)(3, RealtimeAgentBannerComponent_Conditional_3_Template, 15, 9);
|
|
463
489
|
i0.ɵɵelementEnd();
|
|
464
490
|
} if (rf & 2) {
|
|
465
491
|
i0.ɵɵclassProp("banner--review", ctx.ReviewMode)("banner--compact", ctx.Compact && !ctx.ReviewMode);
|
|
@@ -469,12 +495,14 @@ export class RealtimeAgentBannerComponent {
|
|
|
469
495
|
}
|
|
470
496
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RealtimeAgentBannerComponent, [{
|
|
471
497
|
type: Component,
|
|
472
|
-
args: [{ standalone: true, selector: 'mj-realtime-agent-banner', imports: [CommonModule], template: "<div class=\"banner\" [class.banner--review]=\"ReviewMode\" [class.banner--compact]=\"Compact && !ReviewMode\">\n @if (ReviewMode) {\n <!-- SESSION REVIEW: static orb \u00B7 name \u00B7 review badge \u00B7 started\u2192closed \u00B7 close-reason chip,\n with the review's exit actions up here in the header bar (Start live leads, Close trails). -->\n <div class=\"agent-orb agent-orb--review\" aria-hidden=\"true\"></div>\n\n <div class=\"banner__id\">\n <span class=\"banner__name\">Voice for {{ AgentName }}</span>\n <span class=\"pill pill--review\"><i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i> Session review</span>\n @if (ReviewRangeLabel) {\n <span class=\"banner__for banner__range\">{{ ReviewRangeLabel }}</span>\n }\n @if (ReviewCloseReasonLabel) {\n <span class=\"pill pill--close-reason\" [title]=\"'Close reason: ' + ReviewCloseReason\">{{ ReviewCloseReasonLabel }}</span>\n }\n @if (ShowOpenSession) {\n <button type=\"button\" class=\"dev-link\" (click)=\"OpenSession()\"\n title=\"Open the agent session record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Open session</span>\n </button>\n }\n </div>\n\n <div class=\"banner__state banner__state--review\">\n <i class=\"fa-solid fa-box-archive\" aria-hidden=\"true\"></i>\n <span class=\"banner__state-label banner__state-label--review\">Reviewing past session</span>\n </div>\n\n <div class=\"bar-actions\">\n @if (ShowStartLive) {\n <button type=\"button\" class=\"start-live-pill\" (click)=\"StartLiveRequested.emit()\"\n title=\"Resume this session as a new live call\">\n <i class=\"fa-solid fa-phone\" aria-hidden=\"true\"></i>\n <span>Start live session</span>\n </button>\n }\n <button type=\"button\" class=\"iconb\" (click)=\"CloseRequested.emit()\"\n title=\"Close review\" aria-label=\"Close session review\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n </div>\n } @else if (Compact) {\n <!-- COMPACT (Calm Orb \u00B7 overlay): a tiny identity + state row only. No duplicate orb,\n no state pill, no headphones / gear / expand \u2014 the body shows the big orb + name +\n state, and the lean dock owns the actions. Minimize stays reachable here. -->\n <div class=\"banner__id banner__id--compact\">\n <span class=\"banner__avatar\" aria-hidden=\"true\">{{ AgentName.charAt(0) }}</span>\n <span class=\"banner__name banner__name--compact\">{{ AgentName }}</span>\n <span class=\"banner__state-chip\">\n @if (IsBusy(State)) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <span class=\"banner__state-dot\" [attr.data-state]=\"OrbState(State)\" aria-hidden=\"true\"></span>\n }\n <span class=\"banner__state-chip-label\">{{ StateLabel(State) }}</span>\n </span>\n </div>\n\n @if (ShowMinimize) {\n <button type=\"button\" class=\"iconb banner__minimize--compact\" (click)=\"MinimizeRequested.emit()\"\n title=\"Hide the call view \u2014 the call stays live\"\n aria-label=\"Minimize the call view\">\n <i class=\"fa-solid fa-minus\" aria-hidden=\"true\"></i>\n </button>\n }\n } @else {\n <div class=\"agent-orb\" [attr.data-state]=\"OrbState(State)\" aria-hidden=\"true\"></div>\n\n <div class=\"banner__id\">\n <span class=\"banner__name\">Voice for {{ AgentName }}</span>\n <span class=\"pill pill--sage\"><i class=\"fa-solid fa-feather\" aria-hidden=\"true\"></i> Co-Agent</span>\n <span class=\"banner__for\">speaking as <b>{{ AgentName }}</b></span>\n @if (ModelName) {\n <span class=\"banner__model\" [title]=\"'Realtime voice model: ' + ModelName\">\u00B7 {{ ModelName }}</span>\n }\n @if (ShowOpenSession) {\n <button type=\"button\" class=\"dev-link\" (click)=\"OpenSession()\"\n title=\"Open the agent session record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Open session</span>\n </button>\n }\n </div>\n\n <div class=\"banner__state\" [class.banner__state--busy]=\"IsBusy(State)\">\n @if (IsBusy(State)) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <div class=\"waveform\" [class.waveform--idle]=\"State !== 'speaking'\" aria-hidden=\"true\">\n <span></span><span></span><span></span><span></span>\n <span></span><span></span><span></span><span></span>\n </div>\n }\n <span class=\"banner__state-label\">{{ StateLabel(State) }}</span>\n </div>\n\n <!-- Disclosure-gated app-bar action cluster: STATE + WINDOW-CHROME only. Call actions\n (Mute / Captions / Details / Type / End) live in the bottom dock \u2014 the single home for\n each control. Captions & End were removed from here (they were exact duplicates of the\n dock's), and the standalone \"pure audio\" headphones was folded into the gear's Density =\n Simple. What remains up here is non-duplicated chrome: the gear (density + dev links) and\n Minimize. -->\n <div class=\"bar-actions\">\n @if (ShowGear) {\n <button type=\"button\" class=\"iconb\" [class.iconb--on]=\"GearOpen || DevMode\"\n (click)=\"ToggleGear($event)\"\n title=\"Interface density & developer links\"\n [attr.aria-expanded]=\"GearOpen\">\n <i class=\"fa-solid fa-gear\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (ShowMinimize) {\n <button type=\"button\" class=\"iconb\" (click)=\"MinimizeRequested.emit()\"\n title=\"Hide the call view \u2014 the call stays live\"\n aria-label=\"Minimize the call view\">\n <i class=\"fa-solid fa-down-left-and-up-right-to-center\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n\n <!-- Gear popover: interface density (the disclosure escape hatch) + developer links. -->\n @if (GearOpen) {\n <div class=\"gear-pop\" (click)=\"$event.stopPropagation()\" role=\"menu\" aria-label=\"Interface settings\">\n <div class=\"gp-h\">Interface</div>\n @if (ShowDensityPicker) {\n <div class=\"gp-row\">\n <span class=\"gp-l\">Density</span>\n <div class=\"gp-seg\" role=\"radiogroup\" aria-label=\"Interface density\">\n @for (d of Densities; track d.Key) {\n <button type=\"button\" [class.on]=\"Density === d.Key\"\n (click)=\"SelectDensity(d.Key)\"\n [attr.aria-checked]=\"Density === d.Key\" role=\"radio\">{{ d.Label }}</button>\n }\n </div>\n </div>\n <div class=\"gp-note\">Simple returns to the pure-audio surface. Auto grows the console as you use it.</div>\n <div class=\"gp-div\"></div>\n }\n <button type=\"button\" class=\"gp-link\" (click)=\"ToggleDev()\" [attr.aria-pressed]=\"DevMode\">\n <i class=\"fa-solid\" [ngClass]=\"DevMode ? 'fa-toggle-on' : 'fa-toggle-off'\" aria-hidden=\"true\"></i>\n Developer links {{ DevMode ? 'on' : 'off' }}\n </button>\n </div>\n }\n }\n</div>\n", styles: [":host {\n display: block;\n --sage: var(--mj-color-violet-400, #a78bfa);\n --sage-bg: color-mix(in srgb, var(--mj-color-violet-400, #a78bfa) 14%, transparent);\n --sage-border: color-mix(in srgb, var(--mj-color-violet-400, #a78bfa) 45%, transparent);\n}\n\n/* The UNIFIED APP-BAR (Redesign A): orb \u00B7 name \u00B7 Co-Agent pill \u00B7 \"speaking as\" \u00B7\n state pill \u00B7 disclosure-gated action cluster (captions / gear / minimize / End). */\n.banner {\n position: relative; /* anchors the gear popover */\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 16px 10px 22px;\n border-bottom: 1px solid var(--mj-border-default);\n background: linear-gradient(180deg, color-mix(in srgb, var(--mj-brand-primary) 10%, transparent), transparent);\n flex-shrink: 0;\n}\n\n.banner__id {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 8px;\n white-space: nowrap;\n overflow: hidden;\n}\n.banner__name {\n font-size: 14.5px;\n font-weight: 700;\n letter-spacing: -0.01em;\n color: var(--mj-text-primary);\n flex-shrink: 0;\n}\n.banner__for {\n font-size: 11.5px;\n color: var(--mj-text-muted);\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 5; /* gives way before the name/pill, after the model suffix */\n}\n.banner__for b {\n color: var(--mj-text-secondary);\n}\n/* Subtle realtime-model suffix (e.g. \"\u00B7 GPT Realtime 2\") in the identity line. */\n.banner__model {\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n flex-shrink: 10; /* first to give way when the banner narrows */\n min-width: 0;\n}\n\n.banner__state {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 12px;\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n.banner__state--busy {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-status-warning);\n}\n.banner__state--busy .fa-spinner {\n color: var(--mj-status-warning);\n}\n.banner__state-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.banner__state--busy .banner__state-label {\n color: var(--mj-status-warning-text, var(--mj-status-warning));\n}\n\n/* ---------- Glowing agent orb ---------- */\n.agent-orb {\n --orb-size: 34px;\n width: var(--orb-size);\n height: var(--orb-size);\n border-radius: 50%;\n position: relative;\n flex-shrink: 0;\n background: radial-gradient(circle at 35% 30%,\n var(--mj-brand-accent, var(--mj-brand-primary)),\n var(--mj-brand-primary) 60%,\n var(--mj-brand-primary-active, var(--mj-brand-primary)));\n box-shadow:\n 0 0 0 6px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent),\n 0 0 30px color-mix(in srgb, var(--mj-brand-primary) 45%, transparent);\n}\n.agent-orb::after {\n content: \"\";\n position: absolute;\n inset: -4px;\n border-radius: 50%;\n border: 2px solid color-mix(in srgb, var(--mj-brand-accent, var(--mj-brand-primary)) 40%, transparent);\n animation: orb-ring 2.4s ease-out infinite;\n}\n.agent-orb[data-state=\"speaking\"] {\n animation: orb-bob 0.9s ease-in-out infinite;\n}\n.agent-orb[data-state=\"listening\"] {\n box-shadow:\n 0 0 0 6px color-mix(in srgb, var(--mj-status-success) 16%, transparent),\n 0 0 30px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n background: radial-gradient(circle at 35% 30%,\n color-mix(in srgb, var(--mj-status-success) 60%, white), var(--mj-brand-primary) 65%);\n}\n.agent-orb[data-state=\"thinking\"] {\n box-shadow:\n 0 0 0 6px color-mix(in srgb, var(--mj-status-warning) 14%, transparent),\n 0 0 26px color-mix(in srgb, var(--mj-status-warning) 35%, transparent);\n}\n\n@keyframes orb-ring { 0% { transform: scale(1); opacity: .6 } 100% { transform: scale(1.5); opacity: 0 } }\n@keyframes orb-bob { 0%, 100% { transform: translateY(0) } 50% { transform: translateY(-3px) } }\n\n/* ---------- Audio-reactive mode ----------\n The overlay's rAF meter loop writes --voice-out / --voice-in + data attributes on\n .call-overlay; custom properties INHERIT into this component and :host-context()\n reaches the ancestor's attributes \u2014 so the app-bar orb rides the SAME live signal as\n the hero (scaled subtler at app-bar size). Un-metered sessions keep the keyframes. */\n:host-context(.call-overlay[data-audio-live='true']) .agent-orb:not(.agent-orb--review) {\n animation: none;\n transform: scale(calc(1 + var(--voice-out, 0) * 0.14));\n transition: transform 70ms linear;\n}\n:host-context(.call-overlay[data-audio-live='true']) .agent-orb:not(.agent-orb--review)::after {\n animation: none;\n opacity: calc(0.15 + var(--voice-out, 0) * 0.85);\n}\n:host-context(.call-overlay[data-audio-live='true'][data-voice-dir='user']) .agent-orb:not(.agent-orb--review) {\n box-shadow:\n 0 0 0 6px color-mix(in srgb, var(--mj-status-success) 16%, transparent),\n 0 0 30px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n background: radial-gradient(circle at 35% 30%,\n color-mix(in srgb, var(--mj-status-success) 60%, white), var(--mj-brand-primary) 65%);\n}\n\n/* ---------- Voice activity waveform ---------- */\n.waveform {\n display: flex;\n align-items: center;\n gap: 3px;\n height: 18px;\n}\n.waveform span {\n width: 3px;\n border-radius: 3px;\n background: var(--mj-brand-primary);\n animation: wave 1.1s ease-in-out infinite;\n}\n.waveform span:nth-child(1) { height: 30%; animation-delay: 0s }\n.waveform span:nth-child(2) { height: 65%; animation-delay: .1s }\n.waveform span:nth-child(3) { height: 100%; animation-delay: .2s }\n.waveform span:nth-child(4) { height: 55%; animation-delay: .3s }\n.waveform span:nth-child(5) { height: 85%; animation-delay: .15s }\n.waveform span:nth-child(6) { height: 40%; animation-delay: .25s }\n.waveform span:nth-child(7) { height: 70%; animation-delay: .05s }\n.waveform span:nth-child(8) { height: 35%; animation-delay: .35s }\n.waveform--idle span {\n animation: none;\n height: 18% !important;\n background: var(--mj-text-disabled);\n}\n@keyframes wave { 0%, 100% { transform: scaleY(.4) } 50% { transform: scaleY(1) } }\n\n.pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 3px 10px;\n border-radius: var(--mj-radius-full, 9999px);\n font-size: 11.5px;\n font-weight: 600;\n border: 1px solid transparent;\n line-height: 1.4;\n}\n.pill i { font-size: 10px; }\n.pill--sage {\n background: var(--sage-bg);\n color: var(--mj-color-violet-300, var(--mj-text-secondary));\n border-color: var(--sage-border);\n}\n\n/* ---------- Session review variant ---------- */\n.banner--review {\n background: linear-gradient(180deg, color-mix(in srgb, var(--mj-text-muted) 10%, transparent), transparent);\n}\n/* Static orb: no pulse ring, dimmed glow \u2014 the session is history, nothing is live. */\n.agent-orb--review {\n box-shadow: 0 0 0 6px color-mix(in srgb, var(--mj-text-muted) 12%, transparent);\n background: radial-gradient(circle at 35% 30%,\n color-mix(in srgb, var(--mj-text-muted) 55%, var(--mj-bg-surface)),\n var(--mj-text-muted) 65%);\n}\n.agent-orb--review::after {\n animation: none;\n border-color: color-mix(in srgb, var(--mj-text-muted) 30%, transparent);\n}\n.pill--review {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--mj-text-link, var(--mj-brand-primary));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n}\n.pill--close-reason {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-default);\n}\n.banner__range {\n flex-shrink: 3;\n}\n.banner__state--review {\n background: var(--mj-bg-surface-card);\n}\n.banner__state--review i {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n.banner__state-label--review {\n color: var(--mj-text-secondary);\n}\n\n/* Gear-gated developer link to the live agent session record */\n.dev-link {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 3px 9px;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px dashed var(--mj-border-strong);\n background: transparent;\n color: var(--mj-text-muted);\n font-family: inherit;\n font-size: 10.5px;\n font-weight: 700;\n white-space: nowrap;\n cursor: pointer;\n transition: color 140ms ease, border-color 140ms ease, background 140ms ease;\n}\n.dev-link:hover {\n color: var(--mj-text-link, var(--mj-brand-primary));\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n.dev-link i {\n font-size: 9px;\n}\n\n/* ---------- App-bar action cluster (disclosure-gated; Redesign A) ---------- */\n.bar-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n}\n.iconb {\n width: 34px;\n height: 34px;\n border-radius: var(--mj-radius-md, 8px);\n display: grid;\n place-items: center;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n cursor: pointer;\n font-size: 13px;\n transition: all 140ms ease;\n}\n.iconb:hover {\n color: var(--mj-text-primary);\n border-color: var(--mj-border-strong);\n background: var(--mj-bg-surface-hover);\n}\n.iconb--on {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.bar-sep {\n width: 1px;\n height: 26px;\n background: var(--mj-border-default);\n}\n.end-pill {\n display: inline-flex;\n align-items: center;\n gap: 9px;\n padding: 8px 18px;\n font-family: inherit;\n font-size: 13px;\n font-weight: 700;\n white-space: nowrap;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px solid var(--mj-status-error);\n background: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n cursor: pointer;\n box-shadow: 0 4px 16px color-mix(in srgb, var(--mj-status-error) 35%, transparent);\n transition: filter 140ms ease;\n}\n.end-pill:hover {\n filter: brightness(0.92);\n}\n.start-live-pill {\n display: inline-flex;\n align-items: center;\n gap: 9px;\n padding: 8px 18px;\n font-family: inherit;\n font-size: 13px;\n font-weight: 700;\n white-space: nowrap;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px solid var(--mj-brand-primary);\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n cursor: pointer;\n box-shadow: 0 4px 16px color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n transition: filter 140ms ease;\n}\n.start-live-pill:hover {\n filter: brightness(1.05);\n}\n\n/* ---------- Gear popover: density escape hatch + developer links ---------- */\n.gear-pop {\n position: absolute;\n top: calc(100% + 8px);\n right: 14px;\n z-index: 70;\n width: 268px;\n border: 1px solid var(--mj-border-strong);\n border-radius: var(--mj-radius-lg, 12px);\n background: var(--mj-bg-surface-elevated);\n box-shadow: var(--mj-shadow-xl, 0 12px 32px rgba(0, 0, 0, 0.18));\n padding: 12px 14px 10px;\n animation: gear-pop-in 160ms ease;\n}\n@keyframes gear-pop-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.gp-h {\n font-size: 10.5px;\n font-weight: 800;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--mj-text-muted);\n margin-bottom: 9px;\n}\n.gp-row {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.gp-l {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n.gp-seg {\n display: inline-flex;\n flex: 1;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface);\n padding: 2px;\n gap: 2px;\n}\n.gp-seg button {\n flex: 1;\n border: 0;\n background: transparent;\n color: var(--mj-text-muted);\n font-family: inherit;\n font-size: 11px;\n font-weight: 700;\n padding: 4px 0;\n border-radius: 6px;\n cursor: pointer;\n transition: all 120ms ease;\n}\n.gp-seg button.on {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n}\n.gp-note {\n font-size: 10.5px;\n color: var(--mj-text-muted);\n line-height: 1.45;\n margin-top: 8px;\n}\n.gp-div {\n height: 1px;\n background: var(--mj-border-default);\n margin: 10px -14px;\n}\n.gp-link {\n display: flex;\n width: 100%;\n align-items: center;\n gap: 9px;\n padding: 6px 2px;\n border: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n font-family: inherit;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n text-align: left;\n}\n.gp-link:hover {\n color: var(--mj-text-primary);\n}\n.gp-link i {\n width: 16px;\n text-align: center;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n.gp-link:hover i {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n\n/* ============================================================= COMPACT (Calm Orb \u00B7 overlay)\n A tiny identity + state row only \u2014 the body owns the big orb + name + state, and the lean\n dock owns the actions. No duplicate orb / state pill / headphones / gear / expand here. */\n.banner--compact {\n gap: 10px;\n padding: 12px 14px;\n background: transparent;\n border-bottom: none;\n}\n.banner__id--compact {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 9px;\n overflow: hidden;\n}\n.banner__avatar {\n flex-shrink: 0;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n font-size: 11px;\n font-weight: 800;\n color: var(--mj-text-inverse);\n background: radial-gradient(circle at 35% 30%,\n color-mix(in srgb, var(--mj-brand-primary) 60%, white), var(--mj-brand-primary) 65%);\n}\n.banner__name--compact {\n font-size: 13px;\n font-weight: 700;\n letter-spacing: -0.01em;\n color: var(--mj-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.banner__state-chip {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n gap: 7px;\n padding: 4px 10px;\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n font-size: 11.5px;\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n.banner__state-chip-label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 130px;\n}\n.banner__state-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--mj-status-success);\n box-shadow: 0 0 8px color-mix(in srgb, var(--mj-status-success) 70%, transparent);\n}\n.banner__state-dot[data-state=\"speaking\"] {\n background: var(--mj-brand-primary);\n box-shadow: 0 0 8px color-mix(in srgb, var(--mj-brand-primary) 70%, transparent);\n animation: compact-dot-blink 0.9s infinite;\n}\n.banner__state-dot[data-state=\"thinking\"] {\n background: var(--mj-status-warning);\n box-shadow: 0 0 8px color-mix(in srgb, var(--mj-status-warning) 70%, transparent);\n}\n@keyframes compact-dot-blink { 50% { opacity: 0.35; } }\n/* Minimize is the only control left in the compact bar \u2014 render it round + de-emphasized. */\n.banner__minimize--compact {\n flex-shrink: 0;\n width: 30px;\n height: 30px;\n border-radius: 50%;\n background: transparent;\n border-color: transparent;\n color: var(--mj-text-muted);\n}\n.banner__minimize--compact:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-default);\n}\n"] }]
|
|
498
|
+
args: [{ standalone: true, selector: 'mj-realtime-agent-banner', imports: [CommonModule], template: "<div class=\"banner\" [class.banner--review]=\"ReviewMode\" [class.banner--compact]=\"Compact && !ReviewMode\">\n @if (ReviewMode) {\n <!-- SESSION REVIEW: static orb \u00B7 name \u00B7 review badge \u00B7 started\u2192closed \u00B7 close-reason chip,\n with the review's exit actions up here in the header bar (Start live leads, Close trails). -->\n <div class=\"agent-orb agent-orb--review\" aria-hidden=\"true\"></div>\n\n <div class=\"banner__id\">\n <span class=\"banner__name\">Voice for {{ AgentName }}</span>\n <span class=\"pill pill--review\"><i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i> Session review</span>\n @if (ReviewRangeLabel) {\n <span class=\"banner__for banner__range\">{{ ReviewRangeLabel }}</span>\n }\n @if (ReviewCloseReasonLabel) {\n <span class=\"pill pill--close-reason\" [title]=\"'Close reason: ' + ReviewCloseReason\">{{ ReviewCloseReasonLabel }}</span>\n }\n @if (ShowOpenSession) {\n <button type=\"button\" class=\"dev-link\" (click)=\"OpenSession()\"\n title=\"Open the agent session record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Open session</span>\n </button>\n }\n </div>\n\n <div class=\"banner__state banner__state--review\">\n <i class=\"fa-solid fa-box-archive\" aria-hidden=\"true\"></i>\n <span class=\"banner__state-label banner__state-label--review\">Reviewing past session</span>\n </div>\n\n <div class=\"bar-actions\">\n @if (ShowStartLive) {\n <button type=\"button\" class=\"start-live-pill\" (click)=\"StartLiveRequested.emit()\"\n title=\"Resume this session as a new live call\">\n <i class=\"fa-solid fa-phone\" aria-hidden=\"true\"></i>\n <span>Start live session</span>\n </button>\n }\n <button type=\"button\" class=\"iconb\" (click)=\"CloseRequested.emit()\"\n title=\"Close review\" aria-label=\"Close session review\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n </div>\n } @else if (Compact) {\n <!-- COMPACT (Calm Orb \u00B7 overlay): a tiny identity + state row only. No duplicate orb,\n no state pill, no headphones / gear / expand \u2014 the body shows the big orb + name +\n state, and the lean dock owns the actions. Minimize stays reachable here. -->\n <div class=\"banner__id banner__id--compact\">\n <span class=\"banner__avatar\" aria-hidden=\"true\">{{ AgentName.charAt(0) }}</span>\n <span class=\"banner__name banner__name--compact\">{{ AgentName }}</span>\n @if (!HideState) {\n <span class=\"banner__state-chip\">\n @if (IsBusy(State)) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <span class=\"banner__state-dot\" [attr.data-state]=\"OrbState(State)\" aria-hidden=\"true\"></span>\n }\n <span class=\"banner__state-chip-label\">{{ StateLabel(State) }}</span>\n </span>\n }\n </div>\n\n @if (ShowMinimize) {\n <button type=\"button\" class=\"iconb banner__minimize--compact\" (click)=\"MinimizeRequested.emit()\"\n title=\"Hide the call view \u2014 the call stays live\"\n aria-label=\"Minimize the call view\">\n <i class=\"fa-solid fa-minus\" aria-hidden=\"true\"></i>\n </button>\n }\n } @else {\n <div class=\"agent-orb\" [attr.data-state]=\"OrbState(State)\" aria-hidden=\"true\"></div>\n\n <div class=\"banner__id\">\n <span class=\"banner__name\">Voice for {{ AgentName }}</span>\n <span class=\"pill pill--sage\"><i class=\"fa-solid fa-feather\" aria-hidden=\"true\"></i> Co-Agent</span>\n @if (!HideState) {\n <span class=\"banner__for\">speaking as <b>{{ AgentName }}</b></span>\n }\n @if (ModelName) {\n <span class=\"banner__model\" [title]=\"'Realtime voice model: ' + ModelName\">\u00B7 {{ ModelName }}</span>\n }\n @if (ShowOpenSession) {\n <button type=\"button\" class=\"dev-link\" (click)=\"OpenSession()\"\n title=\"Open the agent session record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Open session</span>\n </button>\n }\n </div>\n\n @if (!HideState) {\n <div class=\"banner__state\" [class.banner__state--busy]=\"IsBusy(State)\">\n @if (IsBusy(State)) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <div class=\"waveform\" [class.waveform--idle]=\"State !== 'speaking'\" aria-hidden=\"true\">\n <span></span><span></span><span></span><span></span>\n <span></span><span></span><span></span><span></span>\n </div>\n }\n <span class=\"banner__state-label\">{{ StateLabel(State) }}</span>\n </div>\n }\n\n <!-- Disclosure-gated app-bar action cluster: STATE + WINDOW-CHROME only. Call actions\n (Mute / Captions / Details / Type / End) live in the bottom dock \u2014 the single home for\n each control. Captions & End were removed from here (they were exact duplicates of the\n dock's), and the standalone \"pure audio\" headphones was folded into the gear's Density =\n Simple. What remains up here is non-duplicated chrome: the gear (density + dev links) and\n Minimize. -->\n <div class=\"bar-actions\">\n @if (ShowGear) {\n <button type=\"button\" class=\"iconb\" [class.iconb--on]=\"GearOpen || DevMode\"\n (click)=\"ToggleGear($event)\"\n title=\"Interface density & developer links\"\n [attr.aria-expanded]=\"GearOpen\">\n <i class=\"fa-solid fa-gear\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (ShowMinimize) {\n <button type=\"button\" class=\"iconb\" (click)=\"MinimizeRequested.emit()\"\n title=\"Hide the call view \u2014 the call stays live\"\n aria-label=\"Minimize the call view\">\n <i class=\"fa-solid fa-down-left-and-up-right-to-center\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n\n <!-- Gear popover: interface density (the disclosure escape hatch) + developer links. -->\n @if (GearOpen) {\n <div class=\"gear-pop\" (click)=\"$event.stopPropagation()\" role=\"menu\" aria-label=\"Interface settings\">\n <div class=\"gp-h\">Interface</div>\n @if (ShowDensityPicker) {\n <div class=\"gp-row\">\n <span class=\"gp-l\">Density</span>\n <div class=\"gp-seg\" role=\"radiogroup\" aria-label=\"Interface density\">\n @for (d of Densities; track d.Key) {\n <button type=\"button\" [class.on]=\"Density === d.Key\"\n (click)=\"SelectDensity(d.Key)\"\n [attr.aria-checked]=\"Density === d.Key\" role=\"radio\">{{ d.Label }}</button>\n }\n </div>\n </div>\n <div class=\"gp-note\">Simple returns to the pure-audio surface. Auto grows the console as you use it.</div>\n <div class=\"gp-div\"></div>\n }\n <button type=\"button\" class=\"gp-link\" (click)=\"ToggleDev()\" [attr.aria-pressed]=\"DevMode\">\n <i class=\"fa-solid\" [ngClass]=\"DevMode ? 'fa-toggle-on' : 'fa-toggle-off'\" aria-hidden=\"true\"></i>\n Developer links {{ DevMode ? 'on' : 'off' }}\n </button>\n </div>\n }\n }\n</div>\n", styles: [":host {\n display: block;\n --sage: var(--mj-color-violet-400, #a78bfa);\n --sage-bg: color-mix(in srgb, var(--mj-color-violet-400, #a78bfa) 14%, transparent);\n --sage-border: color-mix(in srgb, var(--mj-color-violet-400, #a78bfa) 45%, transparent);\n}\n\n/* The UNIFIED APP-BAR (Redesign A): orb \u00B7 name \u00B7 Co-Agent pill \u00B7 \"speaking as\" \u00B7\n state pill \u00B7 disclosure-gated action cluster (captions / gear / minimize / End). */\n.banner {\n position: relative; /* anchors the gear popover */\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 16px 10px 22px;\n border-bottom: 1px solid var(--mj-border-default);\n background: linear-gradient(180deg, color-mix(in srgb, var(--mj-brand-primary) 10%, transparent), transparent);\n flex-shrink: 0;\n}\n\n.banner__id {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 8px;\n white-space: nowrap;\n overflow: hidden;\n}\n.banner__name {\n font-size: 14.5px;\n font-weight: 700;\n letter-spacing: -0.01em;\n color: var(--mj-text-primary);\n flex-shrink: 0;\n}\n.banner__for {\n font-size: 11.5px;\n color: var(--mj-text-muted);\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 5; /* gives way before the name/pill, after the model suffix */\n}\n.banner__for b {\n color: var(--mj-text-secondary);\n}\n/* Subtle realtime-model suffix (e.g. \"\u00B7 GPT Realtime 2\") in the identity line. */\n.banner__model {\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n flex-shrink: 10; /* first to give way when the banner narrows */\n min-width: 0;\n}\n\n.banner__state {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 12px;\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n.banner__state--busy {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-status-warning);\n}\n.banner__state--busy .fa-spinner {\n color: var(--mj-status-warning);\n}\n.banner__state-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.banner__state--busy .banner__state-label {\n color: var(--mj-status-warning-text, var(--mj-status-warning));\n}\n\n/* ---------- Glowing agent orb ---------- */\n.agent-orb {\n --orb-size: 34px;\n width: var(--orb-size);\n height: var(--orb-size);\n border-radius: 50%;\n position: relative;\n flex-shrink: 0;\n background: radial-gradient(circle at 35% 30%,\n var(--mj-brand-accent, var(--mj-brand-primary)),\n var(--mj-brand-primary) 60%,\n var(--mj-brand-primary-active, var(--mj-brand-primary)));\n box-shadow:\n 0 0 0 6px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent),\n 0 0 30px color-mix(in srgb, var(--mj-brand-primary) 45%, transparent);\n}\n.agent-orb::after {\n content: \"\";\n position: absolute;\n inset: -4px;\n border-radius: 50%;\n border: 2px solid color-mix(in srgb, var(--mj-brand-accent, var(--mj-brand-primary)) 40%, transparent);\n animation: orb-ring 2.4s ease-out infinite;\n}\n.agent-orb[data-state=\"speaking\"] {\n animation: orb-bob 0.9s ease-in-out infinite;\n}\n.agent-orb[data-state=\"listening\"] {\n box-shadow:\n 0 0 0 6px color-mix(in srgb, var(--mj-status-success) 16%, transparent),\n 0 0 30px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n background: radial-gradient(circle at 35% 30%,\n color-mix(in srgb, var(--mj-status-success) 60%, white), var(--mj-brand-primary) 65%);\n}\n.agent-orb[data-state=\"thinking\"] {\n box-shadow:\n 0 0 0 6px color-mix(in srgb, var(--mj-status-warning) 14%, transparent),\n 0 0 26px color-mix(in srgb, var(--mj-status-warning) 35%, transparent);\n}\n\n@keyframes orb-ring { 0% { transform: scale(1); opacity: .6 } 100% { transform: scale(1.5); opacity: 0 } }\n@keyframes orb-bob { 0%, 100% { transform: translateY(0) } 50% { transform: translateY(-3px) } }\n\n/* ---------- Audio-reactive mode ----------\n The overlay's rAF meter loop writes --voice-out / --voice-in + data attributes on\n .call-overlay; custom properties INHERIT into this component and :host-context()\n reaches the ancestor's attributes \u2014 so the app-bar orb rides the SAME live signal as\n the hero (scaled subtler at app-bar size). Un-metered sessions keep the keyframes. */\n:host-context(.call-overlay[data-audio-live='true']) .agent-orb:not(.agent-orb--review) {\n animation: none;\n transform: scale(calc(1 + var(--voice-out, 0) * 0.14));\n transition: transform 70ms linear;\n}\n:host-context(.call-overlay[data-audio-live='true']) .agent-orb:not(.agent-orb--review)::after {\n animation: none;\n opacity: calc(0.15 + var(--voice-out, 0) * 0.85);\n}\n:host-context(.call-overlay[data-audio-live='true'][data-voice-dir='user']) .agent-orb:not(.agent-orb--review) {\n box-shadow:\n 0 0 0 6px color-mix(in srgb, var(--mj-status-success) 16%, transparent),\n 0 0 30px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n background: radial-gradient(circle at 35% 30%,\n color-mix(in srgb, var(--mj-status-success) 60%, white), var(--mj-brand-primary) 65%);\n}\n\n/* ---------- Voice activity waveform ---------- */\n.waveform {\n display: flex;\n align-items: center;\n gap: 3px;\n height: 18px;\n}\n.waveform span {\n width: 3px;\n border-radius: 3px;\n background: var(--mj-brand-primary);\n animation: wave 1.1s ease-in-out infinite;\n}\n.waveform span:nth-child(1) { height: 30%; animation-delay: 0s }\n.waveform span:nth-child(2) { height: 65%; animation-delay: .1s }\n.waveform span:nth-child(3) { height: 100%; animation-delay: .2s }\n.waveform span:nth-child(4) { height: 55%; animation-delay: .3s }\n.waveform span:nth-child(5) { height: 85%; animation-delay: .15s }\n.waveform span:nth-child(6) { height: 40%; animation-delay: .25s }\n.waveform span:nth-child(7) { height: 70%; animation-delay: .05s }\n.waveform span:nth-child(8) { height: 35%; animation-delay: .35s }\n.waveform--idle span {\n animation: none;\n height: 18% !important;\n background: var(--mj-text-disabled);\n}\n@keyframes wave { 0%, 100% { transform: scaleY(.4) } 50% { transform: scaleY(1) } }\n\n.pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 3px 10px;\n border-radius: var(--mj-radius-full, 9999px);\n font-size: 11.5px;\n font-weight: 600;\n border: 1px solid transparent;\n line-height: 1.4;\n}\n.pill i { font-size: 10px; }\n.pill--sage {\n background: var(--sage-bg);\n color: var(--mj-color-violet-300, var(--mj-text-secondary));\n border-color: var(--sage-border);\n}\n\n/* ---------- Session review variant ---------- */\n.banner--review {\n background: linear-gradient(180deg, color-mix(in srgb, var(--mj-text-muted) 10%, transparent), transparent);\n}\n/* Static orb: no pulse ring, dimmed glow \u2014 the session is history, nothing is live. */\n.agent-orb--review {\n box-shadow: 0 0 0 6px color-mix(in srgb, var(--mj-text-muted) 12%, transparent);\n background: radial-gradient(circle at 35% 30%,\n color-mix(in srgb, var(--mj-text-muted) 55%, var(--mj-bg-surface)),\n var(--mj-text-muted) 65%);\n}\n.agent-orb--review::after {\n animation: none;\n border-color: color-mix(in srgb, var(--mj-text-muted) 30%, transparent);\n}\n.pill--review {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--mj-text-link, var(--mj-brand-primary));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n}\n.pill--close-reason {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-default);\n}\n.banner__range {\n flex-shrink: 3;\n}\n.banner__state--review {\n background: var(--mj-bg-surface-card);\n}\n.banner__state--review i {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n.banner__state-label--review {\n color: var(--mj-text-secondary);\n}\n\n/* Gear-gated developer link to the live agent session record */\n.dev-link {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 3px 9px;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px dashed var(--mj-border-strong);\n background: transparent;\n color: var(--mj-text-muted);\n font-family: inherit;\n font-size: 10.5px;\n font-weight: 700;\n white-space: nowrap;\n cursor: pointer;\n transition: color 140ms ease, border-color 140ms ease, background 140ms ease;\n}\n.dev-link:hover {\n color: var(--mj-text-link, var(--mj-brand-primary));\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n.dev-link i {\n font-size: 9px;\n}\n\n/* ---------- App-bar action cluster (disclosure-gated; Redesign A) ---------- */\n.bar-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n}\n.iconb {\n width: 34px;\n height: 34px;\n border-radius: var(--mj-radius-md, 8px);\n display: grid;\n place-items: center;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n cursor: pointer;\n font-size: 13px;\n transition: all 140ms ease;\n}\n.iconb:hover {\n color: var(--mj-text-primary);\n border-color: var(--mj-border-strong);\n background: var(--mj-bg-surface-hover);\n}\n.iconb--on {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.bar-sep {\n width: 1px;\n height: 26px;\n background: var(--mj-border-default);\n}\n.end-pill {\n display: inline-flex;\n align-items: center;\n gap: 9px;\n padding: 8px 18px;\n font-family: inherit;\n font-size: 13px;\n font-weight: 700;\n white-space: nowrap;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px solid var(--mj-status-error);\n background: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n cursor: pointer;\n box-shadow: 0 4px 16px color-mix(in srgb, var(--mj-status-error) 35%, transparent);\n transition: filter 140ms ease;\n}\n.end-pill:hover {\n filter: brightness(0.92);\n}\n.start-live-pill {\n display: inline-flex;\n align-items: center;\n gap: 9px;\n padding: 8px 18px;\n font-family: inherit;\n font-size: 13px;\n font-weight: 700;\n white-space: nowrap;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px solid var(--mj-brand-primary);\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n cursor: pointer;\n box-shadow: 0 4px 16px color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n transition: filter 140ms ease;\n}\n.start-live-pill:hover {\n filter: brightness(1.05);\n}\n\n/* ---------- Gear popover: density escape hatch + developer links ---------- */\n.gear-pop {\n position: absolute;\n top: calc(100% + 8px);\n right: 14px;\n z-index: 70;\n width: 268px;\n border: 1px solid var(--mj-border-strong);\n border-radius: var(--mj-radius-lg, 12px);\n background: var(--mj-bg-surface-elevated);\n box-shadow: var(--mj-shadow-xl, 0 12px 32px rgba(0, 0, 0, 0.18));\n padding: 12px 14px 10px;\n animation: gear-pop-in 160ms ease;\n}\n@keyframes gear-pop-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.gp-h {\n font-size: 10.5px;\n font-weight: 800;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--mj-text-muted);\n margin-bottom: 9px;\n}\n.gp-row {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.gp-l {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n.gp-seg {\n display: inline-flex;\n flex: 1;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface);\n padding: 2px;\n gap: 2px;\n}\n.gp-seg button {\n flex: 1;\n border: 0;\n background: transparent;\n color: var(--mj-text-muted);\n font-family: inherit;\n font-size: 11px;\n font-weight: 700;\n padding: 4px 0;\n border-radius: 6px;\n cursor: pointer;\n transition: all 120ms ease;\n}\n.gp-seg button.on {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n}\n.gp-note {\n font-size: 10.5px;\n color: var(--mj-text-muted);\n line-height: 1.45;\n margin-top: 8px;\n}\n.gp-div {\n height: 1px;\n background: var(--mj-border-default);\n margin: 10px -14px;\n}\n.gp-link {\n display: flex;\n width: 100%;\n align-items: center;\n gap: 9px;\n padding: 6px 2px;\n border: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n font-family: inherit;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n text-align: left;\n}\n.gp-link:hover {\n color: var(--mj-text-primary);\n}\n.gp-link i {\n width: 16px;\n text-align: center;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n.gp-link:hover i {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n\n/* ============================================================= COMPACT (Calm Orb \u00B7 overlay)\n A tiny identity + state row only \u2014 the body owns the big orb + name + state, and the lean\n dock owns the actions. No duplicate orb / state pill / headphones / gear / expand here. */\n.banner--compact {\n gap: 10px;\n padding: 12px 14px;\n background: transparent;\n border-bottom: none;\n}\n.banner__id--compact {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 9px;\n overflow: hidden;\n}\n.banner__avatar {\n flex-shrink: 0;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n font-size: 11px;\n font-weight: 800;\n color: var(--mj-text-inverse);\n background: radial-gradient(circle at 35% 30%,\n color-mix(in srgb, var(--mj-brand-primary) 60%, white), var(--mj-brand-primary) 65%);\n}\n.banner__name--compact {\n font-size: 13px;\n font-weight: 700;\n letter-spacing: -0.01em;\n color: var(--mj-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.banner__state-chip {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n gap: 7px;\n padding: 4px 10px;\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n font-size: 11.5px;\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n.banner__state-chip-label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 130px;\n}\n.banner__state-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--mj-status-success);\n box-shadow: 0 0 8px color-mix(in srgb, var(--mj-status-success) 70%, transparent);\n}\n.banner__state-dot[data-state=\"speaking\"] {\n background: var(--mj-brand-primary);\n box-shadow: 0 0 8px color-mix(in srgb, var(--mj-brand-primary) 70%, transparent);\n animation: compact-dot-blink 0.9s infinite;\n}\n.banner__state-dot[data-state=\"thinking\"] {\n background: var(--mj-status-warning);\n box-shadow: 0 0 8px color-mix(in srgb, var(--mj-status-warning) 70%, transparent);\n}\n@keyframes compact-dot-blink { 50% { opacity: 0.35; } }\n/* Minimize is the only control left in the compact bar \u2014 render it round + de-emphasized. */\n.banner__minimize--compact {\n flex-shrink: 0;\n width: 30px;\n height: 30px;\n border-radius: 50%;\n background: transparent;\n border-color: transparent;\n color: var(--mj-text-muted);\n}\n.banner__minimize--compact:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-default);\n}\n"] }]
|
|
473
499
|
}], null, { State: [{
|
|
474
500
|
type: Input,
|
|
475
501
|
args: [{ required: true }]
|
|
476
502
|
}], Compact: [{
|
|
477
503
|
type: Input
|
|
504
|
+
}], HideState: [{
|
|
505
|
+
type: Input
|
|
478
506
|
}], AgentName: [{
|
|
479
507
|
type: Input
|
|
480
508
|
}], ErrorLabel: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-agent-banner.component.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-agent-banner.component.ts","../../../../src/lib/components/realtime/realtime-agent-banner.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, HostListener, Input, Output } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { RealtimeConnectionState } from '@memberjunction/realtime-runtime';\nimport { RealtimeUxDensity } from './realtime-disclosure';\n\n/**\n * The call overlay's UNIFIED APP-BAR (per Redesign A — `plans/realtime/mockups/redesign-a.html`):\n * ONE header that owns identity, state, and every session action.\n *\n * - LEFT: the glowing agent orb (motion = turn-state), agent name + \"Co-Agent\" badge,\n * \"speaking as\" subline (+ subtle realtime-model suffix), and the state pill that swaps\n * between a waveform (speaking/listening) and a spinner (connecting/thinking).\n * - RIGHT (live): STATE + WINDOW-CHROME only — the gear (level 2+, opens a popover hosting the\n * Simple/Standard/Pro/Auto INTERFACE DENSITY control — the progressive-disclosure escape hatch,\n * where Simple IS the pure-audio surface — plus the developer-links toggle) and Minimize (hide\n * the call view, call stays live). Call actions (Mute / Captions / Details / Type / End) live in\n * the bottom dock, the single home for each; Captions & End used to duplicate here and were\n * removed, and the standalone pure-audio headphones was folded into the gear's Density = Simple.\n * - RIGHT (review): \"Start live session\" (resume, affirmative leads) + Close — the\n * review session's exit lives up here in the header bar, not floating in the body.\n *\n * Which controls render is decided by the OVERLAY (it owns the disclosure model) and\n * passed down as booleans — this component stays purely presentational.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-agent-banner',\n imports: [CommonModule],\n templateUrl: './realtime-agent-banner.component.html',\n styleUrl: './realtime-agent-banner.component.css'\n})\nexport class RealtimeAgentBannerComponent {\n /** Current connection / turn state — drives the orb animation + state label. */\n @Input({ required: true }) State!: RealtimeConnectionState;\n\n /**\n * COMPACT (orb/overlay) presentation: collapse the app-bar to a minimal identity + state\n * row. The duplicate orb, the redundant state pill, and the headphones / gear / expand\n * controls are dropped — the body already shows the big orb + name + state, and the lean\n * bottom dock (Mute / End / •••) owns the session actions. Minimize stays reachable so the\n * user can hide the call without ending it. Fed from the overlay's resolved `Ui.compact`.\n * Default `false` (the full console banner is unchanged).\n */\n @Input() Compact = false;\n\n /** Display name of the agent the voice session fronts (e.g. \"Sage\"). */\n @Input() AgentName = 'the agent';\n\n /**\n * What the state label says in the `'error'` state when the call said why it ended (`DescribeCallEnd`'s `Label`, such\n * as \"Time limit reached\"); `null` keeps \"Connection error\".\n */\n @Input() ErrorLabel: string | null = null;\n\n /**\n * Display name of the realtime model the live session runs on (e.g. \"GPT Realtime 2\").\n * Rendered as a subtle suffix in the identity line; hidden when null/empty.\n */\n @Input() ModelName: string | null = null;\n\n /** Whether developer affordances (the \"Open session\" link) are revealed (gear-gated). */\n @Input() DevMode = false;\n\n /** ID of the server-side agent session record (`MJ: AI Agent Sessions`), when known. */\n @Input() SessionID: string | null = null;\n\n /**\n * SESSION REVIEW presentation: the banner shows the past session's identity\n * (review badge, started→closed range, close-reason chip) instead of live turn-state,\n * and the action cluster swaps to Start-live + Close.\n */\n @Input() ReviewMode = false;\n\n /** When reviewing: when the past session started (`__mj_CreatedAt`). */\n @Input() ReviewStartedAt: Date | null = null;\n\n /** When reviewing: when the past session closed (null while it is still open). */\n @Input() ReviewClosedAt: Date | null = null;\n\n /** When reviewing: why the past session closed (`Explicit` | `Janitor` | `Shutdown` | `Error`), when known. */\n @Input() ReviewCloseReason: string | null = null;\n\n // ── App-bar action cluster (disclosure-gated by the overlay) ────────────────\n // STATE + WINDOW-CHROME only. Captions & End were removed (they duplicated the bottom dock's\n // controls — one home per control), and \"pure audio\" was folded into the gear's Density = Simple.\n\n /** Whether the gear (density escape hatch + dev toggle) renders (disclosure level 2+). */\n @Input() ShowGear = false;\n\n /**\n * Whether the interface-density segmented control renders inside the gear popover.\n * Default `true` (historical behaviour); a host may hide it via the overlay's\n * `[ShowDensityPicker]` input. The gear itself (and its developer-links toggle) still\n * renders when {@link ShowGear} is true even if the density picker is hidden.\n */\n @Input() ShowDensityPicker = true;\n\n /** Whether the Minimize control renders (live sessions only). */\n @Input() ShowMinimize = false;\n\n /** Review only: whether the \"Start live session\" action renders. */\n @Input() ShowStartLive = true;\n\n /** The user's current interface-density override (selected state in the gear popover). */\n @Input() Density: RealtimeUxDensity = 'auto';\n\n /** Emitted with the session record's ID when the dev \"Open session\" link is clicked. */\n @Output() OpenSessionRequested = new EventEmitter<string>();\n\n /** Emitted when the user toggles developer links from the gear popover. */\n @Output() DevModeToggled = new EventEmitter<boolean>();\n\n /** Emitted when the user picks an interface density in the gear popover. */\n @Output() DensityChanged = new EventEmitter<RealtimeUxDensity>();\n\n /** Emitted when the user minimizes the call view (the call stays live). */\n @Output() MinimizeRequested = new EventEmitter<void>();\n\n /** Review only: the user asked to RESUME the reviewed session as a new live call. */\n @Output() StartLiveRequested = new EventEmitter<void>();\n\n /** Review only: the user asked to close the review and return to the conversation. */\n @Output() CloseRequested = new EventEmitter<void>();\n\n /** Whether the gear popover is open (closed by any outside click). */\n public GearOpen = false;\n\n /** The density choices the gear popover offers, in display order. */\n public readonly Densities: ReadonlyArray<{ Key: RealtimeUxDensity; Label: string }> = [\n { Key: 'simple', Label: 'Simple' },\n { Key: 'standard', Label: 'Standard' },\n { Key: 'pro', Label: 'Pro' },\n { Key: 'auto', Label: 'Auto' }\n ];\n\n /** True when the dev \"Open session\" link should render (gear on + session id known). */\n public get ShowOpenSession(): boolean {\n return this.DevMode && !!this.SessionID;\n }\n\n /** Emits the open-session request for the live agent session record. */\n public OpenSession(): void {\n if (this.SessionID) {\n this.OpenSessionRequested.emit(this.SessionID);\n }\n }\n\n /** Opens/closes the gear popover (stops propagation so the outside-click close skips it). */\n public ToggleGear(event: MouseEvent): void {\n event.stopPropagation();\n this.GearOpen = !this.GearOpen;\n }\n\n /** Any outside click closes the gear popover. */\n @HostListener('document:click')\n public OnDocumentClick(): void {\n if (this.GearOpen) {\n this.GearOpen = false;\n }\n }\n\n /** Gear popover: pick an interface density (the overlay applies + persists it). */\n public SelectDensity(density: RealtimeUxDensity): void {\n this.DensityChanged.emit(density);\n }\n\n /** Gear popover: toggle developer links. */\n public ToggleDev(): void {\n this.DevMode = !this.DevMode;\n this.DevModeToggled.emit(this.DevMode);\n }\n\n /** The review banner's \"started → closed\" time-range label (empty when the start is unknown). */\n public get ReviewRangeLabel(): string {\n if (!this.ReviewStartedAt) {\n return '';\n }\n const start = this.formatStamp(this.ReviewStartedAt);\n if (!this.ReviewClosedAt) {\n return start;\n }\n return `${start} → ${this.formatStamp(this.ReviewClosedAt, this.ReviewStartedAt)}`;\n }\n\n /** Human label for the close-reason chip (empty hides the chip). */\n public get ReviewCloseReasonLabel(): string {\n switch (this.ReviewCloseReason) {\n case 'Explicit': return 'Ended by user';\n case 'Janitor': return 'Closed by janitor';\n case 'Shutdown': return 'Closed at shutdown';\n case 'Error': return 'Ended with error';\n default: return '';\n }\n }\n\n /** Compact date+time stamp; same-day end stamps drop the redundant date part. */\n private formatStamp(date: Date, sameDayAs?: Date | null): string {\n const time = date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }).toLowerCase();\n if (sameDayAs && date.toDateString() === sameDayAs.toDateString()) {\n return time;\n }\n return `${date.toLocaleDateString([], { month: 'short', day: 'numeric' })}, ${time}`;\n }\n\n /** Maps the realtime state to the orb's `data-state` (the orb only models active turn-states). */\n public OrbState(state: RealtimeConnectionState): 'speaking' | 'listening' | 'thinking' {\n switch (state) {\n case 'speaking': return 'speaking';\n case 'thinking': return 'thinking';\n default: return 'listening';\n }\n }\n\n /** Human-readable state label, agent-aware where it reads better. */\n public StateLabel(state: RealtimeConnectionState): string {\n switch (state) {\n case 'connecting': return 'Connecting…';\n case 'listening': return 'Listening';\n case 'speaking': return `${this.AgentName} is speaking…`;\n case 'thinking': return 'Working on it…';\n case 'error': return this.ErrorLabel ?? 'Connection error';\n case 'closed': return 'Call ended';\n default: return '';\n }\n }\n\n /** True while the state pill should show a spinner instead of the waveform. */\n public IsBusy(state: RealtimeConnectionState): boolean {\n return state === 'connecting' || state === 'thinking';\n }\n}\n","<div class=\"banner\" [class.banner--review]=\"ReviewMode\" [class.banner--compact]=\"Compact && !ReviewMode\">\n @if (ReviewMode) {\n <!-- SESSION REVIEW: static orb · name · review badge · started→closed · close-reason chip,\n with the review's exit actions up here in the header bar (Start live leads, Close trails). -->\n <div class=\"agent-orb agent-orb--review\" aria-hidden=\"true\"></div>\n\n <div class=\"banner__id\">\n <span class=\"banner__name\">Voice for {{ AgentName }}</span>\n <span class=\"pill pill--review\"><i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i> Session review</span>\n @if (ReviewRangeLabel) {\n <span class=\"banner__for banner__range\">{{ ReviewRangeLabel }}</span>\n }\n @if (ReviewCloseReasonLabel) {\n <span class=\"pill pill--close-reason\" [title]=\"'Close reason: ' + ReviewCloseReason\">{{ ReviewCloseReasonLabel }}</span>\n }\n @if (ShowOpenSession) {\n <button type=\"button\" class=\"dev-link\" (click)=\"OpenSession()\"\n title=\"Open the agent session record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Open session</span>\n </button>\n }\n </div>\n\n <div class=\"banner__state banner__state--review\">\n <i class=\"fa-solid fa-box-archive\" aria-hidden=\"true\"></i>\n <span class=\"banner__state-label banner__state-label--review\">Reviewing past session</span>\n </div>\n\n <div class=\"bar-actions\">\n @if (ShowStartLive) {\n <button type=\"button\" class=\"start-live-pill\" (click)=\"StartLiveRequested.emit()\"\n title=\"Resume this session as a new live call\">\n <i class=\"fa-solid fa-phone\" aria-hidden=\"true\"></i>\n <span>Start live session</span>\n </button>\n }\n <button type=\"button\" class=\"iconb\" (click)=\"CloseRequested.emit()\"\n title=\"Close review\" aria-label=\"Close session review\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n </div>\n } @else if (Compact) {\n <!-- COMPACT (Calm Orb · overlay): a tiny identity + state row only. No duplicate orb,\n no state pill, no headphones / gear / expand — the body shows the big orb + name +\n state, and the lean dock owns the actions. Minimize stays reachable here. -->\n <div class=\"banner__id banner__id--compact\">\n <span class=\"banner__avatar\" aria-hidden=\"true\">{{ AgentName.charAt(0) }}</span>\n <span class=\"banner__name banner__name--compact\">{{ AgentName }}</span>\n <span class=\"banner__state-chip\">\n @if (IsBusy(State)) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <span class=\"banner__state-dot\" [attr.data-state]=\"OrbState(State)\" aria-hidden=\"true\"></span>\n }\n <span class=\"banner__state-chip-label\">{{ StateLabel(State) }}</span>\n </span>\n </div>\n\n @if (ShowMinimize) {\n <button type=\"button\" class=\"iconb banner__minimize--compact\" (click)=\"MinimizeRequested.emit()\"\n title=\"Hide the call view — the call stays live\"\n aria-label=\"Minimize the call view\">\n <i class=\"fa-solid fa-minus\" aria-hidden=\"true\"></i>\n </button>\n }\n } @else {\n <div class=\"agent-orb\" [attr.data-state]=\"OrbState(State)\" aria-hidden=\"true\"></div>\n\n <div class=\"banner__id\">\n <span class=\"banner__name\">Voice for {{ AgentName }}</span>\n <span class=\"pill pill--sage\"><i class=\"fa-solid fa-feather\" aria-hidden=\"true\"></i> Co-Agent</span>\n <span class=\"banner__for\">speaking as <b>{{ AgentName }}</b></span>\n @if (ModelName) {\n <span class=\"banner__model\" [title]=\"'Realtime voice model: ' + ModelName\">· {{ ModelName }}</span>\n }\n @if (ShowOpenSession) {\n <button type=\"button\" class=\"dev-link\" (click)=\"OpenSession()\"\n title=\"Open the agent session record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Open session</span>\n </button>\n }\n </div>\n\n <div class=\"banner__state\" [class.banner__state--busy]=\"IsBusy(State)\">\n @if (IsBusy(State)) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <div class=\"waveform\" [class.waveform--idle]=\"State !== 'speaking'\" aria-hidden=\"true\">\n <span></span><span></span><span></span><span></span>\n <span></span><span></span><span></span><span></span>\n </div>\n }\n <span class=\"banner__state-label\">{{ StateLabel(State) }}</span>\n </div>\n\n <!-- Disclosure-gated app-bar action cluster: STATE + WINDOW-CHROME only. Call actions\n (Mute / Captions / Details / Type / End) live in the bottom dock — the single home for\n each control. Captions & End were removed from here (they were exact duplicates of the\n dock's), and the standalone \"pure audio\" headphones was folded into the gear's Density =\n Simple. What remains up here is non-duplicated chrome: the gear (density + dev links) and\n Minimize. -->\n <div class=\"bar-actions\">\n @if (ShowGear) {\n <button type=\"button\" class=\"iconb\" [class.iconb--on]=\"GearOpen || DevMode\"\n (click)=\"ToggleGear($event)\"\n title=\"Interface density & developer links\"\n [attr.aria-expanded]=\"GearOpen\">\n <i class=\"fa-solid fa-gear\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (ShowMinimize) {\n <button type=\"button\" class=\"iconb\" (click)=\"MinimizeRequested.emit()\"\n title=\"Hide the call view — the call stays live\"\n aria-label=\"Minimize the call view\">\n <i class=\"fa-solid fa-down-left-and-up-right-to-center\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n\n <!-- Gear popover: interface density (the disclosure escape hatch) + developer links. -->\n @if (GearOpen) {\n <div class=\"gear-pop\" (click)=\"$event.stopPropagation()\" role=\"menu\" aria-label=\"Interface settings\">\n <div class=\"gp-h\">Interface</div>\n @if (ShowDensityPicker) {\n <div class=\"gp-row\">\n <span class=\"gp-l\">Density</span>\n <div class=\"gp-seg\" role=\"radiogroup\" aria-label=\"Interface density\">\n @for (d of Densities; track d.Key) {\n <button type=\"button\" [class.on]=\"Density === d.Key\"\n (click)=\"SelectDensity(d.Key)\"\n [attr.aria-checked]=\"Density === d.Key\" role=\"radio\">{{ d.Label }}</button>\n }\n </div>\n </div>\n <div class=\"gp-note\">Simple returns to the pure-audio surface. Auto grows the console as you use it.</div>\n <div class=\"gp-div\"></div>\n }\n <button type=\"button\" class=\"gp-link\" (click)=\"ToggleDev()\" [attr.aria-pressed]=\"DevMode\">\n <i class=\"fa-solid\" [ngClass]=\"DevMode ? 'fa-toggle-on' : 'fa-toggle-off'\" aria-hidden=\"true\"></i>\n Developer links {{ DevMode ? 'on' : 'off' }}\n </button>\n </div>\n }\n }\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"realtime-agent-banner.component.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-agent-banner.component.ts","../../../../src/lib/components/realtime/realtime-agent-banner.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, HostListener, Input, Output } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { RealtimeConnectionState } from '@memberjunction/realtime-runtime';\nimport { RealtimeUxDensity } from './realtime-disclosure';\n\n/**\n * The call overlay's UNIFIED APP-BAR (per Redesign A — `plans/realtime/mockups/redesign-a.html`):\n * ONE header that owns identity, state, and every session action.\n *\n * - LEFT: the glowing agent orb (motion = turn-state), agent name + \"Co-Agent\" badge,\n * \"speaking as\" subline (+ subtle realtime-model suffix), and the state pill that swaps\n * between a waveform (speaking/listening) and a spinner (connecting/thinking).\n * - RIGHT (live): STATE + WINDOW-CHROME only — the gear (level 2+, opens a popover hosting the\n * Simple/Standard/Pro/Auto INTERFACE DENSITY control — the progressive-disclosure escape hatch,\n * where Simple IS the pure-audio surface — plus the developer-links toggle) and Minimize (hide\n * the call view, call stays live). Call actions (Mute / Captions / Details / Type / End) live in\n * the bottom dock, the single home for each; Captions & End used to duplicate here and were\n * removed, and the standalone pure-audio headphones was folded into the gear's Density = Simple.\n * - RIGHT (review): \"Start live session\" (resume, affirmative leads) + Close — the\n * review session's exit lives up here in the header bar, not floating in the body.\n *\n * Which controls render is decided by the OVERLAY (it owns the disclosure model) and\n * passed down as booleans — this component stays purely presentational.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-agent-banner',\n imports: [CommonModule],\n templateUrl: './realtime-agent-banner.component.html',\n styleUrl: './realtime-agent-banner.component.css'\n})\nexport class RealtimeAgentBannerComponent {\n /** Current connection / turn state — drives the orb animation + state label. */\n @Input({ required: true }) State!: RealtimeConnectionState;\n\n /**\n * COMPACT (orb/overlay) presentation: collapse the app-bar to a minimal identity + state\n * row. The duplicate orb, the redundant state pill, and the headphones / gear / expand\n * controls are dropped — the body already shows the big orb + name + state, and the lean\n * bottom dock (Mute / End / •••) owns the session actions. Minimize stays reachable so the\n * user can hide the call without ending it. Fed from the overlay's resolved `Ui.compact`.\n * Default `false` (the full console banner is unchanged).\n */\n @Input() Compact = false;\n\n /**\n * Whether to suppress the turn-state pill and redundant \"speaking as\" label in the banner\n * because the center hero orb is already displaying the agent's name and live turn state.\n */\n @Input() HideState = false;\n\n /** Display name of the agent the voice session fronts (e.g. \"Sage\"). */\n @Input() AgentName = 'the agent';\n\n /**\n * What the state label says in the `'error'` state when the call said why it ended (`DescribeCallEnd`'s `Label`, such\n * as \"Time limit reached\"); `null` keeps \"Connection error\".\n */\n @Input() ErrorLabel: string | null = null;\n\n /**\n * Display name of the realtime model the live session runs on (e.g. \"GPT Realtime 2\").\n * Rendered as a subtle suffix in the identity line; hidden when null/empty.\n */\n @Input() ModelName: string | null = null;\n\n /** Whether developer affordances (the \"Open session\" link) are revealed (gear-gated). */\n @Input() DevMode = false;\n\n /** ID of the server-side agent session record (`MJ: AI Agent Sessions`), when known. */\n @Input() SessionID: string | null = null;\n\n /**\n * SESSION REVIEW presentation: the banner shows the past session's identity\n * (review badge, started→closed range, close-reason chip) instead of live turn-state,\n * and the action cluster swaps to Start-live + Close.\n */\n @Input() ReviewMode = false;\n\n /** When reviewing: when the past session started (`__mj_CreatedAt`). */\n @Input() ReviewStartedAt: Date | null = null;\n\n /** When reviewing: when the past session closed (null while it is still open). */\n @Input() ReviewClosedAt: Date | null = null;\n\n /** When reviewing: why the past session closed (`Explicit` | `Janitor` | `Shutdown` | `Error`), when known. */\n @Input() ReviewCloseReason: string | null = null;\n\n // ── App-bar action cluster (disclosure-gated by the overlay) ────────────────\n // STATE + WINDOW-CHROME only. Captions & End were removed (they duplicated the bottom dock's\n // controls — one home per control), and \"pure audio\" was folded into the gear's Density = Simple.\n\n /** Whether the gear (density escape hatch + dev toggle) renders (disclosure level 2+). */\n @Input() ShowGear = false;\n\n /**\n * Whether the interface-density segmented control renders inside the gear popover.\n * Default `true` (historical behaviour); a host may hide it via the overlay's\n * `[ShowDensityPicker]` input. The gear itself (and its developer-links toggle) still\n * renders when {@link ShowGear} is true even if the density picker is hidden.\n */\n @Input() ShowDensityPicker = true;\n\n /** Whether the Minimize control renders (live sessions only). */\n @Input() ShowMinimize = false;\n\n /** Review only: whether the \"Start live session\" action renders. */\n @Input() ShowStartLive = true;\n\n /** The user's current interface-density override (selected state in the gear popover). */\n @Input() Density: RealtimeUxDensity = 'auto';\n\n /** Emitted with the session record's ID when the dev \"Open session\" link is clicked. */\n @Output() OpenSessionRequested = new EventEmitter<string>();\n\n /** Emitted when the user toggles developer links from the gear popover. */\n @Output() DevModeToggled = new EventEmitter<boolean>();\n\n /** Emitted when the user picks an interface density in the gear popover. */\n @Output() DensityChanged = new EventEmitter<RealtimeUxDensity>();\n\n /** Emitted when the user minimizes the call view (the call stays live). */\n @Output() MinimizeRequested = new EventEmitter<void>();\n\n /** Review only: the user asked to RESUME the reviewed session as a new live call. */\n @Output() StartLiveRequested = new EventEmitter<void>();\n\n /** Review only: the user asked to close the review and return to the conversation. */\n @Output() CloseRequested = new EventEmitter<void>();\n\n /** Whether the gear popover is open (closed by any outside click). */\n public GearOpen = false;\n\n /** The density choices the gear popover offers, in display order. */\n public readonly Densities: ReadonlyArray<{ Key: RealtimeUxDensity; Label: string }> = [\n { Key: 'simple', Label: 'Simple' },\n { Key: 'standard', Label: 'Standard' },\n { Key: 'pro', Label: 'Pro' },\n { Key: 'auto', Label: 'Auto' }\n ];\n\n /** True when the dev \"Open session\" link should render (gear on + session id known). */\n public get ShowOpenSession(): boolean {\n return this.DevMode && !!this.SessionID;\n }\n\n /** Emits the open-session request for the live agent session record. */\n public OpenSession(): void {\n if (this.SessionID) {\n this.OpenSessionRequested.emit(this.SessionID);\n }\n }\n\n /** Opens/closes the gear popover (stops propagation so the outside-click close skips it). */\n public ToggleGear(event: MouseEvent): void {\n event.stopPropagation();\n this.GearOpen = !this.GearOpen;\n }\n\n /** Any outside click closes the gear popover. */\n @HostListener('document:click')\n public OnDocumentClick(): void {\n if (this.GearOpen) {\n this.GearOpen = false;\n }\n }\n\n /** Gear popover: pick an interface density (the overlay applies + persists it). */\n public SelectDensity(density: RealtimeUxDensity): void {\n this.DensityChanged.emit(density);\n }\n\n /** Gear popover: toggle developer links. */\n public ToggleDev(): void {\n this.DevMode = !this.DevMode;\n this.DevModeToggled.emit(this.DevMode);\n }\n\n /** The review banner's \"started → closed\" time-range label (empty when the start is unknown). */\n public get ReviewRangeLabel(): string {\n if (!this.ReviewStartedAt) {\n return '';\n }\n const start = this.formatStamp(this.ReviewStartedAt);\n if (!this.ReviewClosedAt) {\n return start;\n }\n return `${start} → ${this.formatStamp(this.ReviewClosedAt, this.ReviewStartedAt)}`;\n }\n\n /** Human label for the close-reason chip (empty hides the chip). */\n public get ReviewCloseReasonLabel(): string {\n switch (this.ReviewCloseReason) {\n case 'Explicit': return 'Ended by user';\n case 'Janitor': return 'Closed by janitor';\n case 'Shutdown': return 'Closed at shutdown';\n case 'Error': return 'Ended with error';\n default: return '';\n }\n }\n\n /** Compact date+time stamp; same-day end stamps drop the redundant date part. */\n private formatStamp(date: Date, sameDayAs?: Date | null): string {\n const time = date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }).toLowerCase();\n if (sameDayAs && date.toDateString() === sameDayAs.toDateString()) {\n return time;\n }\n return `${date.toLocaleDateString([], { month: 'short', day: 'numeric' })}, ${time}`;\n }\n\n /** Maps the realtime state to the orb's `data-state` (the orb only models active turn-states). */\n public OrbState(state: RealtimeConnectionState): 'speaking' | 'listening' | 'thinking' {\n switch (state) {\n case 'speaking': return 'speaking';\n case 'thinking': return 'thinking';\n default: return 'listening';\n }\n }\n\n /** Human-readable state label, agent-aware where it reads better. */\n public StateLabel(state: RealtimeConnectionState): string {\n switch (state) {\n case 'connecting': return 'Connecting…';\n case 'listening': return 'Listening';\n case 'speaking': return `${this.AgentName} is speaking…`;\n case 'thinking': return 'Working on it…';\n case 'error': return this.ErrorLabel ?? 'Connection error';\n case 'closed': return 'Call ended';\n default: return '';\n }\n }\n\n /** True while the state pill should show a spinner instead of the waveform. */\n public IsBusy(state: RealtimeConnectionState): boolean {\n return state === 'connecting' || state === 'thinking';\n }\n}\n","<div class=\"banner\" [class.banner--review]=\"ReviewMode\" [class.banner--compact]=\"Compact && !ReviewMode\">\n @if (ReviewMode) {\n <!-- SESSION REVIEW: static orb · name · review badge · started→closed · close-reason chip,\n with the review's exit actions up here in the header bar (Start live leads, Close trails). -->\n <div class=\"agent-orb agent-orb--review\" aria-hidden=\"true\"></div>\n\n <div class=\"banner__id\">\n <span class=\"banner__name\">Voice for {{ AgentName }}</span>\n <span class=\"pill pill--review\"><i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i> Session review</span>\n @if (ReviewRangeLabel) {\n <span class=\"banner__for banner__range\">{{ ReviewRangeLabel }}</span>\n }\n @if (ReviewCloseReasonLabel) {\n <span class=\"pill pill--close-reason\" [title]=\"'Close reason: ' + ReviewCloseReason\">{{ ReviewCloseReasonLabel }}</span>\n }\n @if (ShowOpenSession) {\n <button type=\"button\" class=\"dev-link\" (click)=\"OpenSession()\"\n title=\"Open the agent session record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Open session</span>\n </button>\n }\n </div>\n\n <div class=\"banner__state banner__state--review\">\n <i class=\"fa-solid fa-box-archive\" aria-hidden=\"true\"></i>\n <span class=\"banner__state-label banner__state-label--review\">Reviewing past session</span>\n </div>\n\n <div class=\"bar-actions\">\n @if (ShowStartLive) {\n <button type=\"button\" class=\"start-live-pill\" (click)=\"StartLiveRequested.emit()\"\n title=\"Resume this session as a new live call\">\n <i class=\"fa-solid fa-phone\" aria-hidden=\"true\"></i>\n <span>Start live session</span>\n </button>\n }\n <button type=\"button\" class=\"iconb\" (click)=\"CloseRequested.emit()\"\n title=\"Close review\" aria-label=\"Close session review\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n </div>\n } @else if (Compact) {\n <!-- COMPACT (Calm Orb · overlay): a tiny identity + state row only. No duplicate orb,\n no state pill, no headphones / gear / expand — the body shows the big orb + name +\n state, and the lean dock owns the actions. Minimize stays reachable here. -->\n <div class=\"banner__id banner__id--compact\">\n <span class=\"banner__avatar\" aria-hidden=\"true\">{{ AgentName.charAt(0) }}</span>\n <span class=\"banner__name banner__name--compact\">{{ AgentName }}</span>\n @if (!HideState) {\n <span class=\"banner__state-chip\">\n @if (IsBusy(State)) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <span class=\"banner__state-dot\" [attr.data-state]=\"OrbState(State)\" aria-hidden=\"true\"></span>\n }\n <span class=\"banner__state-chip-label\">{{ StateLabel(State) }}</span>\n </span>\n }\n </div>\n\n @if (ShowMinimize) {\n <button type=\"button\" class=\"iconb banner__minimize--compact\" (click)=\"MinimizeRequested.emit()\"\n title=\"Hide the call view — the call stays live\"\n aria-label=\"Minimize the call view\">\n <i class=\"fa-solid fa-minus\" aria-hidden=\"true\"></i>\n </button>\n }\n } @else {\n <div class=\"agent-orb\" [attr.data-state]=\"OrbState(State)\" aria-hidden=\"true\"></div>\n\n <div class=\"banner__id\">\n <span class=\"banner__name\">Voice for {{ AgentName }}</span>\n <span class=\"pill pill--sage\"><i class=\"fa-solid fa-feather\" aria-hidden=\"true\"></i> Co-Agent</span>\n @if (!HideState) {\n <span class=\"banner__for\">speaking as <b>{{ AgentName }}</b></span>\n }\n @if (ModelName) {\n <span class=\"banner__model\" [title]=\"'Realtime voice model: ' + ModelName\">· {{ ModelName }}</span>\n }\n @if (ShowOpenSession) {\n <button type=\"button\" class=\"dev-link\" (click)=\"OpenSession()\"\n title=\"Open the agent session record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Open session</span>\n </button>\n }\n </div>\n\n @if (!HideState) {\n <div class=\"banner__state\" [class.banner__state--busy]=\"IsBusy(State)\">\n @if (IsBusy(State)) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <div class=\"waveform\" [class.waveform--idle]=\"State !== 'speaking'\" aria-hidden=\"true\">\n <span></span><span></span><span></span><span></span>\n <span></span><span></span><span></span><span></span>\n </div>\n }\n <span class=\"banner__state-label\">{{ StateLabel(State) }}</span>\n </div>\n }\n\n <!-- Disclosure-gated app-bar action cluster: STATE + WINDOW-CHROME only. Call actions\n (Mute / Captions / Details / Type / End) live in the bottom dock — the single home for\n each control. Captions & End were removed from here (they were exact duplicates of the\n dock's), and the standalone \"pure audio\" headphones was folded into the gear's Density =\n Simple. What remains up here is non-duplicated chrome: the gear (density + dev links) and\n Minimize. -->\n <div class=\"bar-actions\">\n @if (ShowGear) {\n <button type=\"button\" class=\"iconb\" [class.iconb--on]=\"GearOpen || DevMode\"\n (click)=\"ToggleGear($event)\"\n title=\"Interface density & developer links\"\n [attr.aria-expanded]=\"GearOpen\">\n <i class=\"fa-solid fa-gear\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (ShowMinimize) {\n <button type=\"button\" class=\"iconb\" (click)=\"MinimizeRequested.emit()\"\n title=\"Hide the call view — the call stays live\"\n aria-label=\"Minimize the call view\">\n <i class=\"fa-solid fa-down-left-and-up-right-to-center\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n\n <!-- Gear popover: interface density (the disclosure escape hatch) + developer links. -->\n @if (GearOpen) {\n <div class=\"gear-pop\" (click)=\"$event.stopPropagation()\" role=\"menu\" aria-label=\"Interface settings\">\n <div class=\"gp-h\">Interface</div>\n @if (ShowDensityPicker) {\n <div class=\"gp-row\">\n <span class=\"gp-l\">Density</span>\n <div class=\"gp-seg\" role=\"radiogroup\" aria-label=\"Interface density\">\n @for (d of Densities; track d.Key) {\n <button type=\"button\" [class.on]=\"Density === d.Key\"\n (click)=\"SelectDensity(d.Key)\"\n [attr.aria-checked]=\"Density === d.Key\" role=\"radio\">{{ d.Label }}</button>\n }\n </div>\n </div>\n <div class=\"gp-note\">Simple returns to the pure-audio surface. Auto grows the console as you use it.</div>\n <div class=\"gp-div\"></div>\n }\n <button type=\"button\" class=\"gp-link\" (click)=\"ToggleDev()\" [attr.aria-pressed]=\"DevMode\">\n <i class=\"fa-solid\" [ngClass]=\"DevMode ? 'fa-toggle-on' : 'fa-toggle-off'\" aria-hidden=\"true\"></i>\n Developer links {{ DevMode ? 'on' : 'off' }}\n </button>\n </div>\n }\n }\n</div>\n"]}
|