@rtsee/ngx 0.0.120 → 0.0.122

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.
@@ -1,6 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Injectable, Input, Component, ViewChild, EventEmitter, Output, forwardRef, Directive, HostListener, reflectComponentType, DOCUMENT, Inject, ChangeDetectionStrategy, output, CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
3
- import * as i2$1 from '@angular/common';
3
+ import * as i1$3 from '@angular/common';
4
4
  import { NgClass, NgIf, NgForOf, DecimalPipe, DatePipe, NgComponentOutlet, SlicePipe, JsonPipe, DOCUMENT as DOCUMENT$1, CommonModule, NgStyle, NgOptimizedImage } from '@angular/common';
5
5
  import * as i1 from '@angular/forms';
6
6
  import { FormsModule, FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
@@ -14,11 +14,11 @@ import { AuthEndpointsKeys, LS_TOKEN_LABEL, LS_USER_LABEL, DEFAULT_ROUTE_NAMES }
14
14
  import * as i2 from '@angular/router';
15
15
  import { RouterLink, RouterLinkActive, NavigationEnd } from '@angular/router';
16
16
  import * as i1$1 from '@angular/common/http';
17
- import { RTSeeChatMemberRoles, RTSeeIllustratorEvents, RTSeeChatTypes, OzzyTaskStatus, getStoryTranslatorLanguage, STORY_TRANSLATOR_LANGUAGES } from '@rtsee/common';
17
+ import { RTSeeChatMemberRoles, RTSeeIllustratorEvents, RTSeeChatTypes, OzzyTaskStatus, CREATE_STORY_ACTION_NAME, EDIT_STORY_ACTION_NAME, CREATE_SLIDE_ACTION_NAME, EDIT_SLIDE_ACTION_NAME, getStoryTranslatorLanguage, STORY_TRANSLATOR_LANGUAGES } from '@rtsee/common';
18
18
  import { sanitizeImageUrl, ManageAgentForm, RTSeeForm, RTSeeFormFieldRadioGroup, RTSeeFormField, RTSeeFormFieldImageUploader, fetchImageBlob, RTSeeRater } from '@rtsee/utilities-ui';
19
19
  import { InputText } from 'primeng/inputtext';
20
20
  import { InputGroup } from 'primeng/inputgroup';
21
- import * as i2$2 from 'primeng/message';
21
+ import * as i2$1 from 'primeng/message';
22
22
  import { Message, MessageModule } from 'primeng/message';
23
23
  import { Textarea } from 'primeng/textarea';
24
24
  import { Checkbox } from 'primeng/checkbox';
@@ -31,7 +31,7 @@ import { ImageCropperComponent } from 'ngx-image-cropper';
31
31
  import { Tooltip } from 'primeng/tooltip';
32
32
  import { Fieldset } from 'primeng/fieldset';
33
33
  import { DatePicker } from 'primeng/datepicker';
34
- import { RTSeeManageChatInfo, RTSeeChatEvents, OzzyClientTaskEvents, OzzyWorkflowClientEvents, RTSeeMentionAutocomplete, RTSeeWorkflowAutocomplete } from '@rtsee/messenger';
34
+ import { RTSeeManageChatInfo, RTSeeChatEvents, OzzyClientTaskActionEvents, OzzyClientTaskEvents, OzzyWorkflowClientEvents, RTSeeMentionAutocomplete, RTSeeWorkflowAutocomplete } from '@rtsee/messenger';
35
35
  import { InfiniteScrollDirective, InfiniteScrollModule } from 'ngx-infinite-scroll';
36
36
  import dayjs from 'dayjs';
37
37
  import relativeTime from 'dayjs/plugin/relativeTime';
@@ -40,7 +40,7 @@ import { loadStripe } from '@stripe/stripe-js';
40
40
  import { Card } from 'primeng/card';
41
41
  import { CdkCopyToClipboard } from '@angular/cdk/clipboard';
42
42
  import { Toast } from 'primeng/toast';
43
- import * as i1$3 from 'primeng/api';
43
+ import * as i1$4 from 'primeng/api';
44
44
  import { MessageService } from 'primeng/api';
45
45
  import Swiper from 'swiper';
46
46
  import { Virtual, EffectCards } from 'swiper/modules';
@@ -1280,6 +1280,7 @@ class AddChatMemberComponent {
1280
1280
  }
1281
1281
  }
1282
1282
  async copyLink() {
1283
+ this.messenger?.trackChatMemberInviteClicked?.(this.chatInfo?.chat, this.invitationLink);
1283
1284
  try {
1284
1285
  await navigator.clipboard.writeText(this.invitationLink);
1285
1286
  this.linkCopied = true;
@@ -1403,6 +1404,7 @@ class ChatMembersComponent {
1403
1404
  }
1404
1405
  showAddMember() {
1405
1406
  this.view = 'add';
1407
+ this.messenger?.trackChatMemberInviteClicked?.(this.chatInfo?.chat);
1406
1408
  }
1407
1409
  showEditAgent(memberId) {
1408
1410
  this.editingAgentMemberId = memberId;
@@ -1573,6 +1575,9 @@ class ManageChatInfoComponent {
1573
1575
  },
1574
1576
  });
1575
1577
  this.manageChatInfo.on('saved', (savedChat) => {
1578
+ if (!this.isEditMode) {
1579
+ this.messenger?.trackChatCreated?.(savedChat);
1580
+ }
1576
1581
  this.chatSaved.emit(savedChat);
1577
1582
  });
1578
1583
  }
@@ -1598,6 +1603,80 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
1598
1603
  type: Output
1599
1604
  }] } });
1600
1605
 
1606
+ class InviteLinkComponent {
1607
+ constructor() {
1608
+ this.inviteUrl = '';
1609
+ this.disclaimer = '';
1610
+ this.copied = false;
1611
+ this.loading = false;
1612
+ this.RTSeeTextLabelKeys = RTSeeTextLabelKeys;
1613
+ }
1614
+ async ngOnInit() {
1615
+ if (!this.inviteUrl && this.messenger) {
1616
+ await this.loadInviteLink();
1617
+ }
1618
+ }
1619
+ async loadInviteLink() {
1620
+ if (!this.messenger)
1621
+ return;
1622
+ this.loading = true;
1623
+ try {
1624
+ const result = await this.messenger.remoteActions.getChatInvitationLink.send({
1625
+ chatId: this.chatId,
1626
+ });
1627
+ if (result?.invitationLink) {
1628
+ this.inviteUrl = result.invitationLink;
1629
+ }
1630
+ }
1631
+ catch (e) {
1632
+ console.log('Failed to fetch chat invitation link', e);
1633
+ }
1634
+ finally {
1635
+ this.loading = false;
1636
+ }
1637
+ }
1638
+ async copyToClipboard() {
1639
+ const targetChat = this.chatId
1640
+ ? this.messenger?.getChatById?.(this.chatId) || this.messenger?.openedChat
1641
+ : this.messenger?.openedChat;
1642
+ this.messenger?.trackChatMemberInviteClicked?.(targetChat, this.inviteUrl);
1643
+ try {
1644
+ await navigator.clipboard.writeText(this.inviteUrl);
1645
+ this.copied = true;
1646
+ setTimeout(() => {
1647
+ this.copied = false;
1648
+ }, 2000);
1649
+ }
1650
+ catch {
1651
+ // Fallback for older browsers
1652
+ const textArea = document.createElement('textarea');
1653
+ textArea.value = this.inviteUrl;
1654
+ document.body.appendChild(textArea);
1655
+ textArea.select();
1656
+ document.execCommand('copy');
1657
+ document.body.removeChild(textArea);
1658
+ this.copied = true;
1659
+ setTimeout(() => {
1660
+ this.copied = false;
1661
+ }, 2000);
1662
+ }
1663
+ }
1664
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InviteLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1665
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: InviteLinkComponent, isStandalone: true, selector: "rtsee-invite-link", inputs: { inviteUrl: "inviteUrl", chatId: "chatId", messenger: "messenger", disclaimer: "disclaimer" }, ngImport: i0, template: "<div class=\"rts-invite-link\">\n <div class=\"rts-invite-link-info\">\n <span class=\"rts-invite-link-icon material-icons-outlined\">link</span>\n <div class=\"rts-invite-link-info-text\">\n <h4>{{ messenger?.labels?.[RTSeeTextLabelKeys.MESSENGER_INVITE_LINK_TITLE] || 'Invite Link' }}</h4>\n <p>{{ disclaimer || (chatId ? messenger?.labels?.[RTSeeTextLabelKeys.MESSENGER_INVITE_LINK_DISCLAIMER] : messenger?.labels?.[RTSeeTextLabelKeys.MESSENGER_INVITE_USER_DISCLAIMER]) || 'Anyone who opens this link can join the chat.' }}</p>\n </div>\n </div>\n\n @if (loading) {\n <div class=\"rts-invite-link-loading\">\n <span class=\"material-icons-outlined rts-spin-icon\">autorenew</span>\n <span>{{ messenger?.labels?.[RTSeeTextLabelKeys.MESSENGER_INVITE_LINK_GENERATING] || 'Generating invite link...' }}</span>\n </div>\n } @else {\n <div class=\"rts-invite-link-url-container\">\n <p-inputgroup>\n <input pInputText\n [value]=\"inviteUrl\"\n readonly\n class=\"rts-invite-link-url-input\"\n />\n <p-button [icon]=\"copied ? 'pi pi-check' : 'pi pi-copy'\"\n [severity]=\"copied ? 'success' : 'primary'\"\n (click)=\"copyToClipboard()\"\n [label]=\"copied ? (messenger?.labels?.[RTSeeTextLabelKeys.MESSENGER_COPIED_BUTTON] || 'Copied!') : (messenger?.labels?.[RTSeeTextLabelKeys.MESSENGER_COPY_BUTTON] || 'Copy')\"\n />\n </p-inputgroup>\n </div>\n }\n</div>\n", dependencies: [{ kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }] }); }
1666
+ }
1667
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InviteLinkComponent, decorators: [{
1668
+ type: Component,
1669
+ args: [{ selector: 'rtsee-invite-link', standalone: true, imports: [Button, InputText, InputGroup], template: "<div class=\"rts-invite-link\">\n <div class=\"rts-invite-link-info\">\n <span class=\"rts-invite-link-icon material-icons-outlined\">link</span>\n <div class=\"rts-invite-link-info-text\">\n <h4>{{ messenger?.labels?.[RTSeeTextLabelKeys.MESSENGER_INVITE_LINK_TITLE] || 'Invite Link' }}</h4>\n <p>{{ disclaimer || (chatId ? messenger?.labels?.[RTSeeTextLabelKeys.MESSENGER_INVITE_LINK_DISCLAIMER] : messenger?.labels?.[RTSeeTextLabelKeys.MESSENGER_INVITE_USER_DISCLAIMER]) || 'Anyone who opens this link can join the chat.' }}</p>\n </div>\n </div>\n\n @if (loading) {\n <div class=\"rts-invite-link-loading\">\n <span class=\"material-icons-outlined rts-spin-icon\">autorenew</span>\n <span>{{ messenger?.labels?.[RTSeeTextLabelKeys.MESSENGER_INVITE_LINK_GENERATING] || 'Generating invite link...' }}</span>\n </div>\n } @else {\n <div class=\"rts-invite-link-url-container\">\n <p-inputgroup>\n <input pInputText\n [value]=\"inviteUrl\"\n readonly\n class=\"rts-invite-link-url-input\"\n />\n <p-button [icon]=\"copied ? 'pi pi-check' : 'pi pi-copy'\"\n [severity]=\"copied ? 'success' : 'primary'\"\n (click)=\"copyToClipboard()\"\n [label]=\"copied ? (messenger?.labels?.[RTSeeTextLabelKeys.MESSENGER_COPIED_BUTTON] || 'Copied!') : (messenger?.labels?.[RTSeeTextLabelKeys.MESSENGER_COPY_BUTTON] || 'Copy')\"\n />\n </p-inputgroup>\n </div>\n }\n</div>\n" }]
1670
+ }], propDecorators: { inviteUrl: [{
1671
+ type: Input
1672
+ }], chatId: [{
1673
+ type: Input
1674
+ }], messenger: [{
1675
+ type: Input
1676
+ }], disclaimer: [{
1677
+ type: Input
1678
+ }] } });
1679
+
1601
1680
  class DefaultImagesService {
1602
1681
  constructor() {
1603
1682
  this.PROFILE = 'https://werf-assets.s3.amazonaws.com/default-profile-logo.png';
@@ -1641,6 +1720,13 @@ class MessengerHeaderComponent {
1641
1720
  this.isDropdownOpen = false;
1642
1721
  this.messenger.openManageChatInfo();
1643
1722
  }
1723
+ openInviteUserDialog() {
1724
+ this.isDropdownOpen = false;
1725
+ this.messenger.openInviteUser();
1726
+ }
1727
+ closeInviteUserDialog() {
1728
+ this.messenger.closeInviteUser();
1729
+ }
1644
1730
  closeManageChatDialog() {
1645
1731
  this.messenger.closeManageChatInfo();
1646
1732
  }
@@ -1721,11 +1807,11 @@ class MessengerHeaderComponent {
1721
1807
  this.defaultImagesService.PROFILE;
1722
1808
  }
1723
1809
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MessengerHeaderComponent, deps: [{ token: DefaultImagesService }], target: i0.ɵɵFactoryTarget.Component }); }
1724
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MessengerHeaderComponent, isStandalone: true, selector: "rtsee-messenger-header", inputs: { messenger: "messenger" }, ngImport: i0, template: "<div class=\"rts-messenger-header\"\n [ngClass]=\"{\n 'rts-messenger-header-chat-opened': messenger.openedChat && !messenger.manageChatInfo,\n 'rts-chat-header-unread': messenger.openedChat && !messenger.unreadMessagesCount,\n 'rts-messenger-header-expanded': messenger.openedProfile || messenger.openedChatDetails || messenger.manageChatInfo,\n 'rts-messenger-header-create-chat-mode': messenger.manageChatInfo,\n 'rts-messenger-header-my-profile-mode': messenger.ownProfileOpened,\n 'rts-messenger-header-chat-info-mode': (messenger.openedProfile || messenger.openedChatDetails) && !messenger.ownProfileOpened && !messenger.manageChatInfo,\n 'rts-messenger-header-chat-image-expanded': imageExpandedToSquare,\n 'rts-messenger-header-image-square': imageExpandedToSquare\n }\"\n>\n <span class=\"rts-messenger-header-collapse-button\"\n (click)=\"messenger.manageChatInfo ? closeManageChatDialog() : collapseInfo()\"\n >\n <span class=\"pi pi-arrow-left\"></span>\n </span>\n <div class=\"rts-messenger-header-left\">\n @if (!messenger.openedChat && messenger.myPeer) {\n <div class=\"rts-messenger-header-avatar\"\n (click)=\"onMyAvatarClick()\"\n (dblclick)=\"onMyAvatarDblClick()\"\n >\n <div [style.background-image]=\"'url(' + myProfileImageUrl + ')'\"\n class=\"rts-messenger-header-avatar-image\">\n </div>\n </div>\n } @else if (messenger.openedChat) {\n <button class=\"rts-messenger-close-chat\"\n (click)=\"messenger.closeChat()\"\n >\n <span class=\"material-icons-outlined\">arrow_back</span>\n @if (messenger.unreadMessagesCount) {\n <span class=\"unread-count\">{{messenger.unreadMessagesCount}}</span>\n }\n </button>\n }\n </div>\n <div class=\"rts-messenger-header-right\">\n @if (messenger.openedChat) {\n <div class=\"rts-messenger-chat-image-container rts-messenger-header-avatar\"\n (click)=\"onChatImageClick()\"\n (dblclick)=\"onChatImageDblClick()\"\n >\n <div class=\"rts-messenger-chat-image rts-messenger-header-avatar-image\"\n [style.background-image]=\"'url(' + chatImageUrl + ')'\"\n ></div>\n </div>\n } @else {\n <div class=\"rts-messenger-header-actions\">\n <button class=\"rts-messenger-header-add-button\"\n (click)=\"toggleDropdown()\"\n >\n <span class=\"material-icons-outlined\">add</span>\n </button>\n\n @if (isDropdownOpen) {\n <div class=\"rts-messenger-header-dropdown-backdrop\"\n (click)=\"closeDropdown()\"\n ></div>\n <div class=\"rts-messenger-header-dropdown\">\n <button class=\"rts-messenger-header-dropdown-item\"\n (click)=\"openNewChatDialog()\"\n >\n <span class=\"material-icons-outlined rts-messenger-header-dropdown-icon\">chat_bubble_outline</span>\n <span>New Chat</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"rts-messenger-header-center\">\n @if (messenger.manageChatInfo) {\n <div class=\"rts-messenger-header-create-chat-container\">\n <rtsee-manage-chat-info [messenger]=\"messenger\"\n [chat]=\"messenger.manageChatInfo.chat || undefined\"\n (chatSaved)=\"onChatSaved($event)\"\n (cancelled)=\"closeManageChatDialog()\"\n ></rtsee-manage-chat-info>\n </div>\n } @else if (messenger.openedChat) {\n <div [ngClass]=\"{'rts-messenger-header-opened-chat-info-expanded': messenger.openedProfile || messenger.openedChatDetails}\"\n class=\"rts-messenger-header-opened-chat-info\">\n <div class=\"rts-messenger-profile-header-placeholder\">\n <p class=\"rts-messenger-header-chat-title\"\n >{{ headerTitle }}</p>\n </div>\n\n <div class=\"rts-messenger-profile-data-container\">\n @if (messenger.openedChatDetails && isGroupOrChannelChat && messenger.chatInfo) {\n <rtsee-chat-info [messenger]=\"messenger\"\n [chatInfo]=\"messenger.chatInfo\"\n (editChatInfo)=\"messenger.openManageChatInfo(messenger.openedChat)\"\n (chatDeleted)=\"messenger.closeChatInfo()\"\n ></rtsee-chat-info>\n } @else if (messenger.openedChatDetails || messenger.openedProfile) {\n <rtsee-profile [messenger]=\"messenger\"\n ></rtsee-profile>\n }\n </div>\n </div>\n } @else {\n @if (messenger.ownProfileOpened) {\n <div class=\"rts-messenger-header-opened-chat-info rts-messenger-header-opened-chat-info-expanded\">\n <div class=\"rts-messenger-profile-header-placeholder\">\n <p class=\"rts-messenger-header-chat-title\">{{ headerTitle }}</p>\n </div>\n <div class=\"rts-messenger-profile-data-container\">\n <rtsee-profile [messenger]=\"messenger\"\n [peer]=\"messenger.myPeer\"\n ></rtsee-profile>\n </div>\n </div>\n } @else {\n <p class=\"rts-messenger-header-title\"\n >{{messenger.labels[RTSeeTextLabelKeys.MESSANGER_TITLE]}}</p>\n <rtsee-profile [messenger]=\"messenger\"\n [peer]=\"messenger.myPeer\"\n ></rtsee-profile>\n }\n }\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ProfileComponent, selector: "rtsee-profile", inputs: ["messenger", "peer"] }, { kind: "component", type: ChatInfoComponent, selector: "rtsee-chat-info", inputs: ["messenger", "chatInfo"], outputs: ["editChatInfo", "chatDeleted"] }, { kind: "component", type: ManageChatInfoComponent, selector: "rtsee-manage-chat-info", inputs: ["messenger", "chat"], outputs: ["chatSaved", "cancelled"] }] }); }
1810
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MessengerHeaderComponent, isStandalone: true, selector: "rtsee-messenger-header", inputs: { messenger: "messenger" }, ngImport: i0, template: "<div class=\"rts-messenger-header\"\n [ngClass]=\"{\n 'rts-messenger-header-chat-opened': messenger.openedChat && !messenger.manageChatInfo && !messenger.inviteUserOpened,\n 'rts-chat-header-unread': messenger.openedChat && !messenger.unreadMessagesCount,\n 'rts-messenger-header-expanded': messenger.openedProfile || messenger.openedChatDetails || messenger.manageChatInfo || messenger.inviteUserOpened,\n 'rts-messenger-header-create-chat-mode': messenger.manageChatInfo || messenger.inviteUserOpened,\n 'rts-messenger-header-my-profile-mode': messenger.ownProfileOpened,\n 'rts-messenger-header-chat-info-mode': (messenger.openedProfile || messenger.openedChatDetails) && !messenger.ownProfileOpened && !messenger.manageChatInfo && !messenger.inviteUserOpened,\n 'rts-messenger-header-chat-image-expanded': imageExpandedToSquare,\n 'rts-messenger-header-image-square': imageExpandedToSquare\n }\"\n>\n <span class=\"rts-messenger-header-collapse-button\"\n (click)=\"messenger.manageChatInfo ? closeManageChatDialog() : (messenger.inviteUserOpened ? closeInviteUserDialog() : collapseInfo())\"\n >\n <span class=\"pi pi-arrow-left\"></span>\n </span>\n <div class=\"rts-messenger-header-left\">\n @if (!messenger.openedChat && messenger.myPeer) {\n <div class=\"rts-messenger-header-avatar\"\n (click)=\"onMyAvatarClick()\"\n (dblclick)=\"onMyAvatarDblClick()\"\n >\n <div [style.background-image]=\"'url(' + myProfileImageUrl + ')'\"\n class=\"rts-messenger-header-avatar-image\">\n </div>\n </div>\n } @else if (messenger.openedChat) {\n <button class=\"rts-messenger-close-chat\"\n (click)=\"messenger.closeChat()\"\n >\n <span class=\"material-icons-outlined\">arrow_back</span>\n @if (messenger.unreadMessagesCount) {\n <span class=\"unread-count\">{{messenger.unreadMessagesCount}}</span>\n }\n </button>\n }\n </div>\n <div class=\"rts-messenger-header-right\">\n @if (messenger.openedChat) {\n <div class=\"rts-messenger-chat-image-container rts-messenger-header-avatar\"\n (click)=\"onChatImageClick()\"\n (dblclick)=\"onChatImageDblClick()\"\n >\n <div class=\"rts-messenger-chat-image rts-messenger-header-avatar-image\"\n [style.background-image]=\"'url(' + chatImageUrl + ')'\"\n ></div>\n </div>\n } @else {\n <div class=\"rts-messenger-header-actions\">\n <button class=\"rts-messenger-header-add-button\"\n (click)=\"toggleDropdown()\"\n >\n <span class=\"material-icons-outlined\">add</span>\n </button>\n\n @if (isDropdownOpen) {\n <div class=\"rts-messenger-header-dropdown-backdrop\"\n (click)=\"closeDropdown()\"\n ></div>\n <div class=\"rts-messenger-header-dropdown\">\n <button class=\"rts-messenger-header-dropdown-item\"\n (click)=\"openInviteUserDialog()\"\n >\n <span class=\"material-icons-outlined rts-messenger-header-dropdown-icon\">person_add</span>\n <span>{{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_USER_BUTTON] }}</span>\n </button>\n <button class=\"rts-messenger-header-dropdown-item\"\n (click)=\"openNewChatDialog()\"\n >\n <span class=\"material-icons-outlined rts-messenger-header-dropdown-icon\">chat_bubble_outline</span>\n <span>{{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_NEW_CHAT_BUTTON] }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"rts-messenger-header-center\">\n @if (messenger.manageChatInfo) {\n <div class=\"rts-messenger-header-create-chat-container\">\n <rtsee-manage-chat-info [messenger]=\"messenger\"\n [chat]=\"messenger.manageChatInfo.chat || undefined\"\n (chatSaved)=\"onChatSaved($event)\"\n (cancelled)=\"closeManageChatDialog()\"\n ></rtsee-manage-chat-info>\n </div>\n } @else if (messenger.inviteUserOpened) {\n <div class=\"rts-messenger-header-create-chat-container rts-messenger-header-invite-user-container\">\n <div class=\"rts-create-chat\">\n <h3 class=\"rts-create-chat-title\">{{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_USER_BUTTON] }}</h3>\n <rtsee-invite-link [messenger]=\"messenger\"\n [disclaimer]=\"messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_USER_DISCLAIMER]\"\n ></rtsee-invite-link>\n </div>\n </div>\n } @else if (messenger.openedChat) {\n <div [ngClass]=\"{'rts-messenger-header-opened-chat-info-expanded': messenger.openedProfile || messenger.openedChatDetails}\"\n class=\"rts-messenger-header-opened-chat-info\">\n <div class=\"rts-messenger-profile-header-placeholder\">\n <p class=\"rts-messenger-header-chat-title\"\n >{{ headerTitle }}</p>\n </div>\n\n <div class=\"rts-messenger-profile-data-container\">\n @if (messenger.openedChatDetails && isGroupOrChannelChat && messenger.chatInfo) {\n <rtsee-chat-info [messenger]=\"messenger\"\n [chatInfo]=\"messenger.chatInfo\"\n (editChatInfo)=\"messenger.openManageChatInfo(messenger.openedChat)\"\n (chatDeleted)=\"messenger.closeChatInfo()\"\n ></rtsee-chat-info>\n } @else if (messenger.openedChatDetails || messenger.openedProfile) {\n <rtsee-profile [messenger]=\"messenger\"\n ></rtsee-profile>\n }\n </div>\n </div>\n } @else {\n @if (messenger.ownProfileOpened) {\n <div class=\"rts-messenger-header-opened-chat-info rts-messenger-header-opened-chat-info-expanded\">\n <div class=\"rts-messenger-profile-header-placeholder\">\n <p class=\"rts-messenger-header-chat-title\">{{ headerTitle }}</p>\n </div>\n <div class=\"rts-messenger-profile-data-container\">\n <rtsee-profile [messenger]=\"messenger\"\n [peer]=\"messenger.myPeer\"\n ></rtsee-profile>\n </div>\n </div>\n } @else {\n <p class=\"rts-messenger-header-title\"\n >{{messenger.labels[RTSeeTextLabelKeys.MESSANGER_TITLE]}}</p>\n <rtsee-profile [messenger]=\"messenger\"\n [peer]=\"messenger.myPeer\"\n ></rtsee-profile>\n }\n }\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ProfileComponent, selector: "rtsee-profile", inputs: ["messenger", "peer"] }, { kind: "component", type: ChatInfoComponent, selector: "rtsee-chat-info", inputs: ["messenger", "chatInfo"], outputs: ["editChatInfo", "chatDeleted"] }, { kind: "component", type: ManageChatInfoComponent, selector: "rtsee-manage-chat-info", inputs: ["messenger", "chat"], outputs: ["chatSaved", "cancelled"] }, { kind: "component", type: InviteLinkComponent, selector: "rtsee-invite-link", inputs: ["inviteUrl", "chatId", "messenger", "disclaimer"] }] }); }
1725
1811
  }
1726
1812
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MessengerHeaderComponent, decorators: [{
1727
1813
  type: Component,
1728
- args: [{ selector: 'rtsee-messenger-header', imports: [NgClass, ProfileComponent, ChatInfoComponent, ManageChatInfoComponent], standalone: true, template: "<div class=\"rts-messenger-header\"\n [ngClass]=\"{\n 'rts-messenger-header-chat-opened': messenger.openedChat && !messenger.manageChatInfo,\n 'rts-chat-header-unread': messenger.openedChat && !messenger.unreadMessagesCount,\n 'rts-messenger-header-expanded': messenger.openedProfile || messenger.openedChatDetails || messenger.manageChatInfo,\n 'rts-messenger-header-create-chat-mode': messenger.manageChatInfo,\n 'rts-messenger-header-my-profile-mode': messenger.ownProfileOpened,\n 'rts-messenger-header-chat-info-mode': (messenger.openedProfile || messenger.openedChatDetails) && !messenger.ownProfileOpened && !messenger.manageChatInfo,\n 'rts-messenger-header-chat-image-expanded': imageExpandedToSquare,\n 'rts-messenger-header-image-square': imageExpandedToSquare\n }\"\n>\n <span class=\"rts-messenger-header-collapse-button\"\n (click)=\"messenger.manageChatInfo ? closeManageChatDialog() : collapseInfo()\"\n >\n <span class=\"pi pi-arrow-left\"></span>\n </span>\n <div class=\"rts-messenger-header-left\">\n @if (!messenger.openedChat && messenger.myPeer) {\n <div class=\"rts-messenger-header-avatar\"\n (click)=\"onMyAvatarClick()\"\n (dblclick)=\"onMyAvatarDblClick()\"\n >\n <div [style.background-image]=\"'url(' + myProfileImageUrl + ')'\"\n class=\"rts-messenger-header-avatar-image\">\n </div>\n </div>\n } @else if (messenger.openedChat) {\n <button class=\"rts-messenger-close-chat\"\n (click)=\"messenger.closeChat()\"\n >\n <span class=\"material-icons-outlined\">arrow_back</span>\n @if (messenger.unreadMessagesCount) {\n <span class=\"unread-count\">{{messenger.unreadMessagesCount}}</span>\n }\n </button>\n }\n </div>\n <div class=\"rts-messenger-header-right\">\n @if (messenger.openedChat) {\n <div class=\"rts-messenger-chat-image-container rts-messenger-header-avatar\"\n (click)=\"onChatImageClick()\"\n (dblclick)=\"onChatImageDblClick()\"\n >\n <div class=\"rts-messenger-chat-image rts-messenger-header-avatar-image\"\n [style.background-image]=\"'url(' + chatImageUrl + ')'\"\n ></div>\n </div>\n } @else {\n <div class=\"rts-messenger-header-actions\">\n <button class=\"rts-messenger-header-add-button\"\n (click)=\"toggleDropdown()\"\n >\n <span class=\"material-icons-outlined\">add</span>\n </button>\n\n @if (isDropdownOpen) {\n <div class=\"rts-messenger-header-dropdown-backdrop\"\n (click)=\"closeDropdown()\"\n ></div>\n <div class=\"rts-messenger-header-dropdown\">\n <button class=\"rts-messenger-header-dropdown-item\"\n (click)=\"openNewChatDialog()\"\n >\n <span class=\"material-icons-outlined rts-messenger-header-dropdown-icon\">chat_bubble_outline</span>\n <span>New Chat</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"rts-messenger-header-center\">\n @if (messenger.manageChatInfo) {\n <div class=\"rts-messenger-header-create-chat-container\">\n <rtsee-manage-chat-info [messenger]=\"messenger\"\n [chat]=\"messenger.manageChatInfo.chat || undefined\"\n (chatSaved)=\"onChatSaved($event)\"\n (cancelled)=\"closeManageChatDialog()\"\n ></rtsee-manage-chat-info>\n </div>\n } @else if (messenger.openedChat) {\n <div [ngClass]=\"{'rts-messenger-header-opened-chat-info-expanded': messenger.openedProfile || messenger.openedChatDetails}\"\n class=\"rts-messenger-header-opened-chat-info\">\n <div class=\"rts-messenger-profile-header-placeholder\">\n <p class=\"rts-messenger-header-chat-title\"\n >{{ headerTitle }}</p>\n </div>\n\n <div class=\"rts-messenger-profile-data-container\">\n @if (messenger.openedChatDetails && isGroupOrChannelChat && messenger.chatInfo) {\n <rtsee-chat-info [messenger]=\"messenger\"\n [chatInfo]=\"messenger.chatInfo\"\n (editChatInfo)=\"messenger.openManageChatInfo(messenger.openedChat)\"\n (chatDeleted)=\"messenger.closeChatInfo()\"\n ></rtsee-chat-info>\n } @else if (messenger.openedChatDetails || messenger.openedProfile) {\n <rtsee-profile [messenger]=\"messenger\"\n ></rtsee-profile>\n }\n </div>\n </div>\n } @else {\n @if (messenger.ownProfileOpened) {\n <div class=\"rts-messenger-header-opened-chat-info rts-messenger-header-opened-chat-info-expanded\">\n <div class=\"rts-messenger-profile-header-placeholder\">\n <p class=\"rts-messenger-header-chat-title\">{{ headerTitle }}</p>\n </div>\n <div class=\"rts-messenger-profile-data-container\">\n <rtsee-profile [messenger]=\"messenger\"\n [peer]=\"messenger.myPeer\"\n ></rtsee-profile>\n </div>\n </div>\n } @else {\n <p class=\"rts-messenger-header-title\"\n >{{messenger.labels[RTSeeTextLabelKeys.MESSANGER_TITLE]}}</p>\n <rtsee-profile [messenger]=\"messenger\"\n [peer]=\"messenger.myPeer\"\n ></rtsee-profile>\n }\n }\n </div>\n</div>\n" }]
1814
+ args: [{ selector: 'rtsee-messenger-header', imports: [NgClass, ProfileComponent, ChatInfoComponent, ManageChatInfoComponent, InviteLinkComponent], standalone: true, template: "<div class=\"rts-messenger-header\"\n [ngClass]=\"{\n 'rts-messenger-header-chat-opened': messenger.openedChat && !messenger.manageChatInfo && !messenger.inviteUserOpened,\n 'rts-chat-header-unread': messenger.openedChat && !messenger.unreadMessagesCount,\n 'rts-messenger-header-expanded': messenger.openedProfile || messenger.openedChatDetails || messenger.manageChatInfo || messenger.inviteUserOpened,\n 'rts-messenger-header-create-chat-mode': messenger.manageChatInfo || messenger.inviteUserOpened,\n 'rts-messenger-header-my-profile-mode': messenger.ownProfileOpened,\n 'rts-messenger-header-chat-info-mode': (messenger.openedProfile || messenger.openedChatDetails) && !messenger.ownProfileOpened && !messenger.manageChatInfo && !messenger.inviteUserOpened,\n 'rts-messenger-header-chat-image-expanded': imageExpandedToSquare,\n 'rts-messenger-header-image-square': imageExpandedToSquare\n }\"\n>\n <span class=\"rts-messenger-header-collapse-button\"\n (click)=\"messenger.manageChatInfo ? closeManageChatDialog() : (messenger.inviteUserOpened ? closeInviteUserDialog() : collapseInfo())\"\n >\n <span class=\"pi pi-arrow-left\"></span>\n </span>\n <div class=\"rts-messenger-header-left\">\n @if (!messenger.openedChat && messenger.myPeer) {\n <div class=\"rts-messenger-header-avatar\"\n (click)=\"onMyAvatarClick()\"\n (dblclick)=\"onMyAvatarDblClick()\"\n >\n <div [style.background-image]=\"'url(' + myProfileImageUrl + ')'\"\n class=\"rts-messenger-header-avatar-image\">\n </div>\n </div>\n } @else if (messenger.openedChat) {\n <button class=\"rts-messenger-close-chat\"\n (click)=\"messenger.closeChat()\"\n >\n <span class=\"material-icons-outlined\">arrow_back</span>\n @if (messenger.unreadMessagesCount) {\n <span class=\"unread-count\">{{messenger.unreadMessagesCount}}</span>\n }\n </button>\n }\n </div>\n <div class=\"rts-messenger-header-right\">\n @if (messenger.openedChat) {\n <div class=\"rts-messenger-chat-image-container rts-messenger-header-avatar\"\n (click)=\"onChatImageClick()\"\n (dblclick)=\"onChatImageDblClick()\"\n >\n <div class=\"rts-messenger-chat-image rts-messenger-header-avatar-image\"\n [style.background-image]=\"'url(' + chatImageUrl + ')'\"\n ></div>\n </div>\n } @else {\n <div class=\"rts-messenger-header-actions\">\n <button class=\"rts-messenger-header-add-button\"\n (click)=\"toggleDropdown()\"\n >\n <span class=\"material-icons-outlined\">add</span>\n </button>\n\n @if (isDropdownOpen) {\n <div class=\"rts-messenger-header-dropdown-backdrop\"\n (click)=\"closeDropdown()\"\n ></div>\n <div class=\"rts-messenger-header-dropdown\">\n <button class=\"rts-messenger-header-dropdown-item\"\n (click)=\"openInviteUserDialog()\"\n >\n <span class=\"material-icons-outlined rts-messenger-header-dropdown-icon\">person_add</span>\n <span>{{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_USER_BUTTON] }}</span>\n </button>\n <button class=\"rts-messenger-header-dropdown-item\"\n (click)=\"openNewChatDialog()\"\n >\n <span class=\"material-icons-outlined rts-messenger-header-dropdown-icon\">chat_bubble_outline</span>\n <span>{{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_NEW_CHAT_BUTTON] }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"rts-messenger-header-center\">\n @if (messenger.manageChatInfo) {\n <div class=\"rts-messenger-header-create-chat-container\">\n <rtsee-manage-chat-info [messenger]=\"messenger\"\n [chat]=\"messenger.manageChatInfo.chat || undefined\"\n (chatSaved)=\"onChatSaved($event)\"\n (cancelled)=\"closeManageChatDialog()\"\n ></rtsee-manage-chat-info>\n </div>\n } @else if (messenger.inviteUserOpened) {\n <div class=\"rts-messenger-header-create-chat-container rts-messenger-header-invite-user-container\">\n <div class=\"rts-create-chat\">\n <h3 class=\"rts-create-chat-title\">{{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_USER_BUTTON] }}</h3>\n <rtsee-invite-link [messenger]=\"messenger\"\n [disclaimer]=\"messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_USER_DISCLAIMER]\"\n ></rtsee-invite-link>\n </div>\n </div>\n } @else if (messenger.openedChat) {\n <div [ngClass]=\"{'rts-messenger-header-opened-chat-info-expanded': messenger.openedProfile || messenger.openedChatDetails}\"\n class=\"rts-messenger-header-opened-chat-info\">\n <div class=\"rts-messenger-profile-header-placeholder\">\n <p class=\"rts-messenger-header-chat-title\"\n >{{ headerTitle }}</p>\n </div>\n\n <div class=\"rts-messenger-profile-data-container\">\n @if (messenger.openedChatDetails && isGroupOrChannelChat && messenger.chatInfo) {\n <rtsee-chat-info [messenger]=\"messenger\"\n [chatInfo]=\"messenger.chatInfo\"\n (editChatInfo)=\"messenger.openManageChatInfo(messenger.openedChat)\"\n (chatDeleted)=\"messenger.closeChatInfo()\"\n ></rtsee-chat-info>\n } @else if (messenger.openedChatDetails || messenger.openedProfile) {\n <rtsee-profile [messenger]=\"messenger\"\n ></rtsee-profile>\n }\n </div>\n </div>\n } @else {\n @if (messenger.ownProfileOpened) {\n <div class=\"rts-messenger-header-opened-chat-info rts-messenger-header-opened-chat-info-expanded\">\n <div class=\"rts-messenger-profile-header-placeholder\">\n <p class=\"rts-messenger-header-chat-title\">{{ headerTitle }}</p>\n </div>\n <div class=\"rts-messenger-profile-data-container\">\n <rtsee-profile [messenger]=\"messenger\"\n [peer]=\"messenger.myPeer\"\n ></rtsee-profile>\n </div>\n </div>\n } @else {\n <p class=\"rts-messenger-header-title\"\n >{{messenger.labels[RTSeeTextLabelKeys.MESSANGER_TITLE]}}</p>\n <rtsee-profile [messenger]=\"messenger\"\n [peer]=\"messenger.myPeer\"\n ></rtsee-profile>\n }\n }\n </div>\n</div>\n" }]
1729
1815
  }], ctorParameters: () => [{ type: DefaultImagesService }], propDecorators: { messenger: [{
1730
1816
  type: Input
1731
1817
  }] } });
@@ -1885,15 +1971,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
1885
1971
  }] } });
1886
1972
 
1887
1973
  class ChatsListComponent {
1974
+ constructor() {
1975
+ this.RTSeeTextLabelKeys = RTSeeTextLabelKeys;
1976
+ }
1888
1977
  ngOnInit() {
1889
1978
  // console.log(this.chats);
1890
1979
  }
1980
+ onInviteUserClick() {
1981
+ this.messenger.openInviteUser();
1982
+ }
1983
+ onCreateGroupClick() {
1984
+ this.messenger.openManageChatInfo();
1985
+ }
1891
1986
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatsListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1892
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: ChatsListComponent, isStandalone: true, selector: "rtsee-chats-list", inputs: { messenger: "messenger", chats: "chats" }, ngImport: i0, template: "<div class=\"rts-chats-list\">\n <div class=\"rts-chat-thumbnail-container\" *ngFor=\"let chat of chats; let last = last;\">\n <rtsee-chat-thumbnail [chat]=\"chat.thumbnail\" [messenger]=\"messenger\"></rtsee-chat-thumbnail>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ChatThumbnailComponent, selector: "rtsee-chat-thumbnail", inputs: ["chat", "messenger"] }] }); }
1987
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ChatsListComponent, isStandalone: true, selector: "rtsee-chats-list", inputs: { messenger: "messenger", chats: "chats" }, ngImport: i0, template: "<div class=\"rts-chats-list\">\n @if (chats && chats.length) {\n <div class=\"rts-chat-thumbnail-container\" *ngFor=\"let chat of chats; let last = last;\">\n <rtsee-chat-thumbnail [chat]=\"chat.thumbnail\" [messenger]=\"messenger\"></rtsee-chat-thumbnail>\n </div>\n } @else if (!messenger.loadingChatsInProgress) {\n <div class=\"rts-chats-list-empty\">\n <span class=\"material-icons-outlined rts-chats-list-empty-icon\">forum</span>\n <p class=\"rts-chats-list-empty-disclaimer\">\n {{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_NO_CHATS_DISCLAIMER] }}\n </p>\n <div class=\"rts-chats-list-empty-actions\">\n <button type=\"button\"\n class=\"rts-btn rts-btn-primary rts-chats-list-empty-btn\"\n (click)=\"onInviteUserClick()\"\n >\n <span class=\"material-icons-outlined\">person_add</span>\n <span>{{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_USER_BUTTON] }}</span>\n </button>\n <button type=\"button\"\n class=\"rts-btn rts-btn-secondary rts-chats-list-empty-btn\"\n (click)=\"onCreateGroupClick()\"\n >\n <span class=\"material-icons-outlined\">group_add</span>\n <span>{{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_CREATE_GROUP_BUTTON] }}</span>\n </button>\n </div>\n </div>\n }\n</div>\n", dependencies: [{ kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ChatThumbnailComponent, selector: "rtsee-chat-thumbnail", inputs: ["chat", "messenger"] }] }); }
1893
1988
  }
1894
1989
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatsListComponent, decorators: [{
1895
1990
  type: Component,
1896
- args: [{ selector: 'rtsee-chats-list', imports: [NgForOf, ChatThumbnailComponent], standalone: true, template: "<div class=\"rts-chats-list\">\n <div class=\"rts-chat-thumbnail-container\" *ngFor=\"let chat of chats; let last = last;\">\n <rtsee-chat-thumbnail [chat]=\"chat.thumbnail\" [messenger]=\"messenger\"></rtsee-chat-thumbnail>\n </div>\n</div>\n" }]
1991
+ args: [{ selector: 'rtsee-chats-list', imports: [NgForOf, ChatThumbnailComponent], standalone: true, template: "<div class=\"rts-chats-list\">\n @if (chats && chats.length) {\n <div class=\"rts-chat-thumbnail-container\" *ngFor=\"let chat of chats; let last = last;\">\n <rtsee-chat-thumbnail [chat]=\"chat.thumbnail\" [messenger]=\"messenger\"></rtsee-chat-thumbnail>\n </div>\n } @else if (!messenger.loadingChatsInProgress) {\n <div class=\"rts-chats-list-empty\">\n <span class=\"material-icons-outlined rts-chats-list-empty-icon\">forum</span>\n <p class=\"rts-chats-list-empty-disclaimer\">\n {{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_NO_CHATS_DISCLAIMER] }}\n </p>\n <div class=\"rts-chats-list-empty-actions\">\n <button type=\"button\"\n class=\"rts-btn rts-btn-primary rts-chats-list-empty-btn\"\n (click)=\"onInviteUserClick()\"\n >\n <span class=\"material-icons-outlined\">person_add</span>\n <span>{{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_USER_BUTTON] }}</span>\n </button>\n <button type=\"button\"\n class=\"rts-btn rts-btn-secondary rts-chats-list-empty-btn\"\n (click)=\"onCreateGroupClick()\"\n >\n <span class=\"material-icons-outlined\">group_add</span>\n <span>{{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_CREATE_GROUP_BUTTON] }}</span>\n </button>\n </div>\n </div>\n }\n</div>\n" }]
1897
1992
  }], propDecorators: { messenger: [{
1898
1993
  type: Input
1899
1994
  }], chats: [{
@@ -1961,11 +2056,11 @@ class RatingComponent {
1961
2056
  this.init();
1962
2057
  }
1963
2058
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RatingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1964
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RatingComponent, isStandalone: true, selector: "rtsee-rating", inputs: { config: "config", rate: "rate" }, ngImport: i0, template: "<div\n class=\"rtsee-rating\"\n data-ugc=\"true\"\n rel=\"ugc\"\n itemprop=\"reviewRating\"\n itemscope\n itemtype=\"https://schema.org/Rating\"\n>\n <meta itemprop=\"bestRating\" content=\"5\" />\n <meta itemprop=\"worstRating\" content=\"1\" />\n @for (star of stars; track $index) {\n <span class=\"rtsee-rating-star\"\n [ngClass]=\"{\n 'rtsee-rating-star-full': star === 'full',\n 'rtsee-rating-star-half': star === 'half',\n 'rtsee-rating-star-empty': star === 'empty',\n 'rtsee-rating-star-clickable': mutable\n }\"\n (click)=\"onStarClicked($index)\"\n >\u2605</span>\n }\n @if (rateValue) {\n <span class=\"rtsee-rating-number\" itemprop=\"ratingValue\">{{ rateValue | number:'1.1-1' }}</span>\n }\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: DecimalPipe, name: "number" }] }); }
2059
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RatingComponent, isStandalone: true, selector: "rtsee-rating", inputs: { config: "config", rate: "rate" }, ngImport: i0, template: "<div\n class=\"rtsee-rating\"\n data-ugc=\"true\"\n rel=\"ugc\"\n [attr.itemprop]=\"!mutable ? 'reviewRating' : null\"\n [attr.itemscope]=\"!mutable ? '' : null\"\n [attr.itemtype]=\"!mutable ? 'https://schema.org/Rating' : null\"\n>\n @if (!mutable) {\n <meta itemprop=\"bestRating\" content=\"5\" />\n <meta itemprop=\"worstRating\" content=\"1\" />\n }\n @for (star of stars; track $index) {\n <span class=\"rtsee-rating-star\"\n [ngClass]=\"{\n 'rtsee-rating-star-full': star === 'full',\n 'rtsee-rating-star-half': star === 'half',\n 'rtsee-rating-star-empty': star === 'empty',\n 'rtsee-rating-star-clickable': mutable\n }\"\n (click)=\"onStarClicked($index)\"\n >\u2605</span>\n }\n @if (rateValue) {\n <span class=\"rtsee-rating-number\" [attr.itemprop]=\"!mutable ? 'ratingValue' : null\">{{ rateValue | number:'1.1-1' }}</span>\n }\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: DecimalPipe, name: "number" }] }); }
1965
2060
  }
1966
2061
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RatingComponent, decorators: [{
1967
2062
  type: Component,
1968
- args: [{ selector: 'rtsee-rating', imports: [NgClass, DecimalPipe], template: "<div\n class=\"rtsee-rating\"\n data-ugc=\"true\"\n rel=\"ugc\"\n itemprop=\"reviewRating\"\n itemscope\n itemtype=\"https://schema.org/Rating\"\n>\n <meta itemprop=\"bestRating\" content=\"5\" />\n <meta itemprop=\"worstRating\" content=\"1\" />\n @for (star of stars; track $index) {\n <span class=\"rtsee-rating-star\"\n [ngClass]=\"{\n 'rtsee-rating-star-full': star === 'full',\n 'rtsee-rating-star-half': star === 'half',\n 'rtsee-rating-star-empty': star === 'empty',\n 'rtsee-rating-star-clickable': mutable\n }\"\n (click)=\"onStarClicked($index)\"\n >\u2605</span>\n }\n @if (rateValue) {\n <span class=\"rtsee-rating-number\" itemprop=\"ratingValue\">{{ rateValue | number:'1.1-1' }}</span>\n }\n</div>\n" }]
2063
+ args: [{ selector: 'rtsee-rating', imports: [NgClass, DecimalPipe], template: "<div\n class=\"rtsee-rating\"\n data-ugc=\"true\"\n rel=\"ugc\"\n [attr.itemprop]=\"!mutable ? 'reviewRating' : null\"\n [attr.itemscope]=\"!mutable ? '' : null\"\n [attr.itemtype]=\"!mutable ? 'https://schema.org/Rating' : null\"\n>\n @if (!mutable) {\n <meta itemprop=\"bestRating\" content=\"5\" />\n <meta itemprop=\"worstRating\" content=\"1\" />\n }\n @for (star of stars; track $index) {\n <span class=\"rtsee-rating-star\"\n [ngClass]=\"{\n 'rtsee-rating-star-full': star === 'full',\n 'rtsee-rating-star-half': star === 'half',\n 'rtsee-rating-star-empty': star === 'empty',\n 'rtsee-rating-star-clickable': mutable\n }\"\n (click)=\"onStarClicked($index)\"\n >\u2605</span>\n }\n @if (rateValue) {\n <span class=\"rtsee-rating-number\" [attr.itemprop]=\"!mutable ? 'ratingValue' : null\">{{ rateValue | number:'1.1-1' }}</span>\n }\n</div>\n" }]
1969
2064
  }], propDecorators: { config: [{
1970
2065
  type: Input
1971
2066
  }], rate: [{
@@ -2444,6 +2539,808 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
2444
2539
  type: Input
2445
2540
  }] } });
2446
2541
 
2542
+ /**
2543
+ * Full client-side representation of a single OzzyTaskAction.
2544
+ * Displays input, logs, output, and/or errors of the action.
2545
+ */
2546
+ class RTSeeTaskActionComponent {
2547
+ constructor(cdr) {
2548
+ this.cdr = cdr;
2549
+ this.copied = null;
2550
+ this.subscribedAction = null;
2551
+ this.onChangedBound = () => this.onActionChanged();
2552
+ }
2553
+ ngOnInit() {
2554
+ this.subscribe();
2555
+ this.ensureLoaded();
2556
+ }
2557
+ ngOnChanges(changes) {
2558
+ if (changes['action'] && !changes['action'].firstChange) {
2559
+ this.subscribe();
2560
+ this.ensureLoaded();
2561
+ }
2562
+ }
2563
+ ngOnDestroy() {
2564
+ this.unsubscribe();
2565
+ }
2566
+ get statusLabel() {
2567
+ switch (this.action?.status) {
2568
+ case OzzyTaskStatus.IN_PROGRESS:
2569
+ return 'Running';
2570
+ case OzzyTaskStatus.SUCCESS:
2571
+ return 'Completed';
2572
+ case OzzyTaskStatus.FAIL:
2573
+ return 'Failed';
2574
+ default:
2575
+ return 'Ready';
2576
+ }
2577
+ }
2578
+ get statusClass() {
2579
+ switch (this.action?.status) {
2580
+ case OzzyTaskStatus.IN_PROGRESS:
2581
+ return 'rts-task-action-status-running';
2582
+ case OzzyTaskStatus.SUCCESS:
2583
+ return 'rts-task-action-status-success';
2584
+ case OzzyTaskStatus.FAIL:
2585
+ return 'rts-task-action-status-fail';
2586
+ default:
2587
+ return 'rts-task-action-status-ready';
2588
+ }
2589
+ }
2590
+ get inputJson() {
2591
+ return this.toJson(this.action?.input);
2592
+ }
2593
+ get outputJson() {
2594
+ return this.toJson(this.action?.output);
2595
+ }
2596
+ get hasOutput() {
2597
+ return this.action?.output !== undefined && this.action?.output !== null;
2598
+ }
2599
+ get hasLogs() {
2600
+ return !!(this.action?.logs?.length || this.action?.liveText);
2601
+ }
2602
+ async copy(kind) {
2603
+ try {
2604
+ await navigator.clipboard.writeText(kind === 'input' ? this.inputJson : this.outputJson);
2605
+ this.copied = kind;
2606
+ this.cdr.detectChanges();
2607
+ setTimeout(() => {
2608
+ this.copied = null;
2609
+ this.cdr.detectChanges();
2610
+ }, 1500);
2611
+ }
2612
+ catch (e) {
2613
+ console.log('Failed to copy', e);
2614
+ }
2615
+ }
2616
+ trackLog(index, log) {
2617
+ return `${index}-${log.level}`;
2618
+ }
2619
+ ensureLoaded() {
2620
+ if (this.action && !this.action.loaded && !this.action.isRunning) {
2621
+ void this.action.load();
2622
+ }
2623
+ }
2624
+ toJson(value) {
2625
+ if (value === undefined || value === null) {
2626
+ return '';
2627
+ }
2628
+ try {
2629
+ return JSON.stringify(value, null, 2);
2630
+ }
2631
+ catch {
2632
+ return String(value);
2633
+ }
2634
+ }
2635
+ subscribe() {
2636
+ if (this.subscribedAction === this.action) {
2637
+ return;
2638
+ }
2639
+ this.unsubscribe();
2640
+ if (this.action) {
2641
+ this.subscribedAction = this.action;
2642
+ this.action.on(OzzyClientTaskActionEvents.CHANGED, this.onChangedBound);
2643
+ }
2644
+ }
2645
+ unsubscribe() {
2646
+ this.subscribedAction?.off(OzzyClientTaskActionEvents.CHANGED, this.onChangedBound);
2647
+ this.subscribedAction = null;
2648
+ }
2649
+ onActionChanged() {
2650
+ this.cdr.detectChanges();
2651
+ const el = this.logsContainer?.nativeElement;
2652
+ if (el) {
2653
+ el.scrollTop = el.scrollHeight;
2654
+ }
2655
+ }
2656
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RTSeeTaskActionComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2657
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RTSeeTaskActionComponent, isStandalone: true, selector: "rtsee-task-action", inputs: { action: "action" }, viewQueries: [{ propertyName: "logsContainer", first: true, predicate: ["logsContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"rts-task-action\" [ngClass]=\"statusClass\">\n @if (action) {\n <div class=\"rts-task-action-header\">\n <div class=\"rts-task-action-identity\">\n <span class=\"rts-task-action-icon\">\u26A1</span>\n <div class=\"rts-task-action-titles\">\n <span class=\"rts-task-action-name\">{{ action.name || 'Action' }}</span>\n <span class=\"rts-task-action-id\" [title]=\"action.id\">#{{ action.id }}</span>\n </div>\n </div>\n <span class=\"rts-task-action-status\">\n <span class=\"rts-task-action-status-dot\"></span>\n {{ statusLabel }}\n </span>\n </div>\n\n <!-- Input -->\n <div class=\"rts-task-action-section\">\n <div class=\"rts-task-action-section-head\">\n <span class=\"rts-task-action-section-label\">Input</span>\n @if (inputJson) {\n <button type=\"button\" class=\"rts-task-action-copy\" (click)=\"copy('input')\">\n {{ copied === 'input' ? 'Copied' : 'Copy' }}\n </button>\n }\n </div>\n @if (inputJson) {\n <pre class=\"rts-task-action-code\"><code>{{ inputJson }}</code></pre>\n } @else if (action.loading) {\n <div class=\"rts-task-action-placeholder\">Loading\u2026</div>\n } @else {\n <div class=\"rts-task-action-placeholder\">No input</div>\n }\n </div>\n\n <!-- Logs -->\n @if (hasLogs || action.isRunning || action.loading) {\n <div class=\"rts-task-action-section\">\n <div class=\"rts-task-action-section-head\">\n <span class=\"rts-task-action-section-label\">Logs</span>\n @if (action.isRunning) {\n <span class=\"rts-task-action-live\">LIVE</span>\n }\n </div>\n <div #logsContainer class=\"rts-task-action-terminal\">\n @for (log of action.logs; track $index) {\n <div class=\"rts-task-action-log\" [ngClass]=\"'rts-task-action-log-' + log.level\">\n <span class=\"rts-task-action-log-time\">{{ log.createdAt | date: 'HH:mm:ss' }}</span>\n <span class=\"rts-task-action-log-level\">{{ log.level }}</span>\n <span class=\"rts-task-action-log-message\">{{ log.message }}</span>\n </div>\n }\n @if (action.liveText) {\n <div class=\"rts-task-action-live-text\">{{ action.liveText }}@if (action.isRunning) {<span class=\"rts-task-action-cursor\"></span>}</div>\n } @else if (action.isRunning && !action.logs.length) {\n <div class=\"rts-task-action-log rts-task-action-log-info\">\n <span class=\"rts-task-action-log-message\">Waiting for logs\u2026</span>\n </div>\n } @else if (action.loading && !action.logs.length) {\n <div class=\"rts-task-action-log rts-task-action-log-info\">\n <span class=\"rts-task-action-log-message\">Loading logs\u2026</span>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Output -->\n @if (hasOutput) {\n <div class=\"rts-task-action-section rts-task-action-section-output\">\n <div class=\"rts-task-action-section-head\">\n <span class=\"rts-task-action-section-label\">Output</span>\n <button type=\"button\" class=\"rts-task-action-copy\" (click)=\"copy('output')\">\n {{ copied === 'output' ? 'Copied' : 'Copy' }}\n </button>\n </div>\n <pre class=\"rts-task-action-code\"><code>{{ outputJson }}</code></pre>\n </div>\n }\n\n @if (action.errors.length) {\n <div class=\"rts-task-action-errors\">\n @for (error of action.errors; track $index) {\n <div class=\"rts-task-action-error\">{{ error.message }}</div>\n }\n </div>\n }\n\n @if (action.requestError) {\n <div class=\"rts-task-action-errors\">\n <div class=\"rts-task-action-error\">{{ action.requestError }}</div>\n </div>\n }\n } @else {\n <div class=\"rts-task-action-placeholder\">Action is not available yet.</div>\n }\n</div>\n", styles: [":host{display:block;--rts-task-action-accent: #8b5cf6;--rts-task-action-accent-2: #6366f1;--rts-task-action-success: #10b981;--rts-task-action-fail: #f43f5e;--rts-task-action-warn: #f59e0b}.rts-task-action{position:relative;display:flex;flex-direction:column;gap:8px;padding:10px 12px;border-radius:10px;background:var(--rts-bg-secondary, #fff);border:1px solid rgba(139,92,246,.22);font-size:12.5px}.rts-task-action-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.rts-task-action-identity{display:flex;align-items:center;gap:8px;min-width:0}.rts-task-action-icon{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;flex-shrink:0;border-radius:6px;color:#fff;font-size:12px;background:linear-gradient(135deg,var(--rts-task-action-accent-2),var(--rts-task-action-accent))}.rts-task-action-titles{display:flex;flex-direction:column;min-width:0}.rts-task-action-name{font-weight:600;color:var(--rts-text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.rts-task-action-id{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;color:var(--rts-text-secondary, #8a8fa3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:220px}.rts-task-action-status{display:inline-flex;align-items:center;gap:5px;padding:2px 8px;border-radius:999px;font-size:10px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;flex-shrink:0;color:var(--rts-task-action-accent);background:#8b5cf61f}.rts-task-action-status-dot{width:6px;height:6px;border-radius:50%;background:currentColor}.rts-task-action-status-running .rts-task-action-status-dot{animation:rts-task-action-pulse 1s ease-in-out infinite}.rts-task-action-status-success .rts-task-action-status{color:var(--rts-task-action-success);background:#10b9811f}.rts-task-action-status-fail .rts-task-action-status{color:var(--rts-task-action-fail);background:#f43f5e1f}.rts-task-action-section{display:flex;flex-direction:column;gap:4px}.rts-task-action-section-head{display:flex;align-items:center;justify-content:space-between}.rts-task-action-section-label{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--rts-text-secondary, #8a8fa3)}.rts-task-action-copy{border:none;background:transparent;color:var(--rts-task-action-accent);font-size:11px;cursor:pointer;padding:0 2px}.rts-task-action-copy:hover{text-decoration:underline}.rts-task-action-live{font-size:9px;font-weight:700;letter-spacing:.08em;color:var(--rts-task-action-fail);animation:rts-task-action-pulse 1.2s ease-in-out infinite}.rts-task-action-code,.rts-task-action-terminal{margin:0;padding:8px 10px;border-radius:7px;background:#0f1020;color:#e4e4f0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;line-height:1.5;max-height:180px;overflow:auto;white-space:pre-wrap;word-break:break-word;border:1px solid rgba(139,92,246,.18)}.rts-task-action-section-output .rts-task-action-code{border-color:#10b98159}.rts-task-action-log{display:flex;gap:8px;align-items:baseline}.rts-task-action-log-time{color:#6b6f8a;flex-shrink:0}.rts-task-action-log-level{flex-shrink:0;min-width:34px;text-transform:uppercase;font-size:9.5px;font-weight:700;color:#a78bfa}.rts-task-action-log-warn .rts-task-action-log-level{color:var(--rts-task-action-warn)}.rts-task-action-log-error .rts-task-action-log-level,.rts-task-action-log-error .rts-task-action-log-message{color:#fb7185}.rts-task-action-live-text{margin-top:6px;padding-top:6px;border-top:1px dashed rgba(139,92,246,.25);color:#c4b5fd;white-space:pre-wrap}.rts-task-action-cursor{display:inline-block;width:6px;height:12px;margin-left:1px;vertical-align:text-bottom;background:#a78bfa;animation:rts-task-action-blink .8s step-end infinite}.rts-task-action-placeholder{font-size:11.5px;color:var(--rts-text-secondary, #8a8fa3);font-style:italic}.rts-task-action-errors{display:flex;flex-direction:column;gap:4px}.rts-task-action-error{padding:6px 10px;border-radius:6px;font-size:11.5px;color:var(--rts-task-action-fail);background:#f43f5e14;border:1px solid rgba(244,63,94,.25)}@keyframes rts-task-action-pulse{0%,to{opacity:1}50%{opacity:.35}}@keyframes rts-task-action-blink{0%,to{opacity:1}50%{opacity:0}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: DatePipe, name: "date" }] }); }
2658
+ }
2659
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RTSeeTaskActionComponent, decorators: [{
2660
+ type: Component,
2661
+ args: [{ selector: 'rtsee-task-action', standalone: true, imports: [NgClass, DatePipe], template: "<div class=\"rts-task-action\" [ngClass]=\"statusClass\">\n @if (action) {\n <div class=\"rts-task-action-header\">\n <div class=\"rts-task-action-identity\">\n <span class=\"rts-task-action-icon\">\u26A1</span>\n <div class=\"rts-task-action-titles\">\n <span class=\"rts-task-action-name\">{{ action.name || 'Action' }}</span>\n <span class=\"rts-task-action-id\" [title]=\"action.id\">#{{ action.id }}</span>\n </div>\n </div>\n <span class=\"rts-task-action-status\">\n <span class=\"rts-task-action-status-dot\"></span>\n {{ statusLabel }}\n </span>\n </div>\n\n <!-- Input -->\n <div class=\"rts-task-action-section\">\n <div class=\"rts-task-action-section-head\">\n <span class=\"rts-task-action-section-label\">Input</span>\n @if (inputJson) {\n <button type=\"button\" class=\"rts-task-action-copy\" (click)=\"copy('input')\">\n {{ copied === 'input' ? 'Copied' : 'Copy' }}\n </button>\n }\n </div>\n @if (inputJson) {\n <pre class=\"rts-task-action-code\"><code>{{ inputJson }}</code></pre>\n } @else if (action.loading) {\n <div class=\"rts-task-action-placeholder\">Loading\u2026</div>\n } @else {\n <div class=\"rts-task-action-placeholder\">No input</div>\n }\n </div>\n\n <!-- Logs -->\n @if (hasLogs || action.isRunning || action.loading) {\n <div class=\"rts-task-action-section\">\n <div class=\"rts-task-action-section-head\">\n <span class=\"rts-task-action-section-label\">Logs</span>\n @if (action.isRunning) {\n <span class=\"rts-task-action-live\">LIVE</span>\n }\n </div>\n <div #logsContainer class=\"rts-task-action-terminal\">\n @for (log of action.logs; track $index) {\n <div class=\"rts-task-action-log\" [ngClass]=\"'rts-task-action-log-' + log.level\">\n <span class=\"rts-task-action-log-time\">{{ log.createdAt | date: 'HH:mm:ss' }}</span>\n <span class=\"rts-task-action-log-level\">{{ log.level }}</span>\n <span class=\"rts-task-action-log-message\">{{ log.message }}</span>\n </div>\n }\n @if (action.liveText) {\n <div class=\"rts-task-action-live-text\">{{ action.liveText }}@if (action.isRunning) {<span class=\"rts-task-action-cursor\"></span>}</div>\n } @else if (action.isRunning && !action.logs.length) {\n <div class=\"rts-task-action-log rts-task-action-log-info\">\n <span class=\"rts-task-action-log-message\">Waiting for logs\u2026</span>\n </div>\n } @else if (action.loading && !action.logs.length) {\n <div class=\"rts-task-action-log rts-task-action-log-info\">\n <span class=\"rts-task-action-log-message\">Loading logs\u2026</span>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Output -->\n @if (hasOutput) {\n <div class=\"rts-task-action-section rts-task-action-section-output\">\n <div class=\"rts-task-action-section-head\">\n <span class=\"rts-task-action-section-label\">Output</span>\n <button type=\"button\" class=\"rts-task-action-copy\" (click)=\"copy('output')\">\n {{ copied === 'output' ? 'Copied' : 'Copy' }}\n </button>\n </div>\n <pre class=\"rts-task-action-code\"><code>{{ outputJson }}</code></pre>\n </div>\n }\n\n @if (action.errors.length) {\n <div class=\"rts-task-action-errors\">\n @for (error of action.errors; track $index) {\n <div class=\"rts-task-action-error\">{{ error.message }}</div>\n }\n </div>\n }\n\n @if (action.requestError) {\n <div class=\"rts-task-action-errors\">\n <div class=\"rts-task-action-error\">{{ action.requestError }}</div>\n </div>\n }\n } @else {\n <div class=\"rts-task-action-placeholder\">Action is not available yet.</div>\n }\n</div>\n", styles: [":host{display:block;--rts-task-action-accent: #8b5cf6;--rts-task-action-accent-2: #6366f1;--rts-task-action-success: #10b981;--rts-task-action-fail: #f43f5e;--rts-task-action-warn: #f59e0b}.rts-task-action{position:relative;display:flex;flex-direction:column;gap:8px;padding:10px 12px;border-radius:10px;background:var(--rts-bg-secondary, #fff);border:1px solid rgba(139,92,246,.22);font-size:12.5px}.rts-task-action-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.rts-task-action-identity{display:flex;align-items:center;gap:8px;min-width:0}.rts-task-action-icon{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;flex-shrink:0;border-radius:6px;color:#fff;font-size:12px;background:linear-gradient(135deg,var(--rts-task-action-accent-2),var(--rts-task-action-accent))}.rts-task-action-titles{display:flex;flex-direction:column;min-width:0}.rts-task-action-name{font-weight:600;color:var(--rts-text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.rts-task-action-id{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;color:var(--rts-text-secondary, #8a8fa3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:220px}.rts-task-action-status{display:inline-flex;align-items:center;gap:5px;padding:2px 8px;border-radius:999px;font-size:10px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;flex-shrink:0;color:var(--rts-task-action-accent);background:#8b5cf61f}.rts-task-action-status-dot{width:6px;height:6px;border-radius:50%;background:currentColor}.rts-task-action-status-running .rts-task-action-status-dot{animation:rts-task-action-pulse 1s ease-in-out infinite}.rts-task-action-status-success .rts-task-action-status{color:var(--rts-task-action-success);background:#10b9811f}.rts-task-action-status-fail .rts-task-action-status{color:var(--rts-task-action-fail);background:#f43f5e1f}.rts-task-action-section{display:flex;flex-direction:column;gap:4px}.rts-task-action-section-head{display:flex;align-items:center;justify-content:space-between}.rts-task-action-section-label{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--rts-text-secondary, #8a8fa3)}.rts-task-action-copy{border:none;background:transparent;color:var(--rts-task-action-accent);font-size:11px;cursor:pointer;padding:0 2px}.rts-task-action-copy:hover{text-decoration:underline}.rts-task-action-live{font-size:9px;font-weight:700;letter-spacing:.08em;color:var(--rts-task-action-fail);animation:rts-task-action-pulse 1.2s ease-in-out infinite}.rts-task-action-code,.rts-task-action-terminal{margin:0;padding:8px 10px;border-radius:7px;background:#0f1020;color:#e4e4f0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;line-height:1.5;max-height:180px;overflow:auto;white-space:pre-wrap;word-break:break-word;border:1px solid rgba(139,92,246,.18)}.rts-task-action-section-output .rts-task-action-code{border-color:#10b98159}.rts-task-action-log{display:flex;gap:8px;align-items:baseline}.rts-task-action-log-time{color:#6b6f8a;flex-shrink:0}.rts-task-action-log-level{flex-shrink:0;min-width:34px;text-transform:uppercase;font-size:9.5px;font-weight:700;color:#a78bfa}.rts-task-action-log-warn .rts-task-action-log-level{color:var(--rts-task-action-warn)}.rts-task-action-log-error .rts-task-action-log-level,.rts-task-action-log-error .rts-task-action-log-message{color:#fb7185}.rts-task-action-live-text{margin-top:6px;padding-top:6px;border-top:1px dashed rgba(139,92,246,.25);color:#c4b5fd;white-space:pre-wrap}.rts-task-action-cursor{display:inline-block;width:6px;height:12px;margin-left:1px;vertical-align:text-bottom;background:#a78bfa;animation:rts-task-action-blink .8s step-end infinite}.rts-task-action-placeholder{font-size:11.5px;color:var(--rts-text-secondary, #8a8fa3);font-style:italic}.rts-task-action-errors{display:flex;flex-direction:column;gap:4px}.rts-task-action-error{padding:6px 10px;border-radius:6px;font-size:11.5px;color:var(--rts-task-action-fail);background:#f43f5e14;border:1px solid rgba(244,63,94,.25)}@keyframes rts-task-action-pulse{0%,to{opacity:1}50%{opacity:.35}}@keyframes rts-task-action-blink{0%,to{opacity:1}50%{opacity:0}}\n"] }]
2662
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { action: [{
2663
+ type: Input
2664
+ }], logsContainer: [{
2665
+ type: ViewChild,
2666
+ args: ['logsContainer']
2667
+ }] } });
2668
+
2669
+ class DefaultTaskActionThumbnailComponent {
2670
+ constructor() {
2671
+ this.expanded = false;
2672
+ }
2673
+ get statusClass() {
2674
+ switch (this.action?.status) {
2675
+ case OzzyTaskStatus.SUCCESS:
2676
+ return 'rts-action-thumb-status-success';
2677
+ case OzzyTaskStatus.FAIL:
2678
+ return 'rts-action-thumb-status-fail';
2679
+ case OzzyTaskStatus.IN_PROGRESS:
2680
+ return 'rts-action-thumb-status-running';
2681
+ default:
2682
+ return 'rts-action-thumb-status-ready';
2683
+ }
2684
+ }
2685
+ onToggle() {
2686
+ this.toggleExpand?.();
2687
+ }
2688
+ onButtonClick(event) {
2689
+ event.stopPropagation();
2690
+ this.toggleExpand?.();
2691
+ }
2692
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DefaultTaskActionThumbnailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2693
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: DefaultTaskActionThumbnailComponent, isStandalone: true, selector: "rtsee-default-task-action-thumbnail", inputs: { action: "action", task: "task", expanded: "expanded", toggleExpand: "toggleExpand" }, ngImport: i0, template: `
2694
+ <div class="rts-action-thumb-default" [ngClass]="statusClass" (click)="onToggle()">
2695
+ <div class="rts-action-thumb-left">
2696
+ <span class="rts-action-thumb-dot"></span>
2697
+ <span class="rts-action-thumb-name" [title]="action?.name || 'Action'">
2698
+ {{ action?.name || 'Action' }}
2699
+ </span>
2700
+ </div>
2701
+ <button type="button"
2702
+ class="rts-action-thumb-expand"
2703
+ (click)="onButtonClick($event)"
2704
+ [title]="expanded ? 'Collapse action details' : 'Expand action details'"
2705
+ >
2706
+ {{ expanded ? 'Hide' : 'Expand' }}
2707
+ <span class="pi" [ngClass]="expanded ? 'pi-chevron-up' : 'pi-chevron-down'"></span>
2708
+ </button>
2709
+ </div>
2710
+ `, isInline: true, styles: [".rts-action-thumb-default{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:7px 10px;border-radius:8px;background:#8b5cf60f;border:1px solid rgba(139,92,246,.18);cursor:pointer;transition:background .15s ease,border-color .15s ease}.rts-action-thumb-default:hover{background:#8b5cf61c;border-color:#8b5cf652}.rts-action-thumb-left{display:flex;align-items:center;gap:8px;min-width:0}.rts-action-thumb-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;background:#8b5cf6}.rts-action-thumb-status-success .rts-action-thumb-dot{background:#10b981}.rts-action-thumb-status-fail .rts-action-thumb-dot{background:#f43f5e}.rts-action-thumb-status-running .rts-action-thumb-dot{background:#8b5cf6;animation:rts-thumb-pulse 1s ease-in-out infinite}.rts-action-thumb-name{font-size:12px;font-weight:600;color:var(--rts-text-primary, #1f2430);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.rts-action-thumb-expand{display:inline-flex;align-items:center;gap:4px;border:none;background:#8b5cf61f;color:#8b5cf6;font-size:11px;font-weight:600;padding:3px 8px;border-radius:6px;cursor:pointer;flex-shrink:0}.rts-action-thumb-expand:hover{background:#8b5cf638}@keyframes rts-thumb-pulse{0%,to{opacity:1}50%{opacity:.35}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
2711
+ }
2712
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DefaultTaskActionThumbnailComponent, decorators: [{
2713
+ type: Component,
2714
+ args: [{ selector: 'rtsee-default-task-action-thumbnail', standalone: true, imports: [NgClass], template: `
2715
+ <div class="rts-action-thumb-default" [ngClass]="statusClass" (click)="onToggle()">
2716
+ <div class="rts-action-thumb-left">
2717
+ <span class="rts-action-thumb-dot"></span>
2718
+ <span class="rts-action-thumb-name" [title]="action?.name || 'Action'">
2719
+ {{ action?.name || 'Action' }}
2720
+ </span>
2721
+ </div>
2722
+ <button type="button"
2723
+ class="rts-action-thumb-expand"
2724
+ (click)="onButtonClick($event)"
2725
+ [title]="expanded ? 'Collapse action details' : 'Expand action details'"
2726
+ >
2727
+ {{ expanded ? 'Hide' : 'Expand' }}
2728
+ <span class="pi" [ngClass]="expanded ? 'pi-chevron-up' : 'pi-chevron-down'"></span>
2729
+ </button>
2730
+ </div>
2731
+ `, styles: [".rts-action-thumb-default{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:7px 10px;border-radius:8px;background:#8b5cf60f;border:1px solid rgba(139,92,246,.18);cursor:pointer;transition:background .15s ease,border-color .15s ease}.rts-action-thumb-default:hover{background:#8b5cf61c;border-color:#8b5cf652}.rts-action-thumb-left{display:flex;align-items:center;gap:8px;min-width:0}.rts-action-thumb-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;background:#8b5cf6}.rts-action-thumb-status-success .rts-action-thumb-dot{background:#10b981}.rts-action-thumb-status-fail .rts-action-thumb-dot{background:#f43f5e}.rts-action-thumb-status-running .rts-action-thumb-dot{background:#8b5cf6;animation:rts-thumb-pulse 1s ease-in-out infinite}.rts-action-thumb-name{font-size:12px;font-weight:600;color:var(--rts-text-primary, #1f2430);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.rts-action-thumb-expand{display:inline-flex;align-items:center;gap:4px;border:none;background:#8b5cf61f;color:#8b5cf6;font-size:11px;font-weight:600;padding:3px 8px;border-radius:6px;cursor:pointer;flex-shrink:0}.rts-action-thumb-expand:hover{background:#8b5cf638}@keyframes rts-thumb-pulse{0%,to{opacity:1}50%{opacity:.35}}\n"] }]
2732
+ }], propDecorators: { action: [{
2733
+ type: Input
2734
+ }], task: [{
2735
+ type: Input
2736
+ }], expanded: [{
2737
+ type: Input
2738
+ }], toggleExpand: [{
2739
+ type: Input
2740
+ }] } });
2741
+
2742
+ /**
2743
+ * Custom task-action thumbnail widget for Story creation / update actions.
2744
+ * Displays story-name, recommendedAge, friendlyUrl, and 2-line truncated
2745
+ * description, moralMeaning, and history with full text tooltip on hover.
2746
+ */
2747
+ class StoryTaskActionThumbnailComponent {
2748
+ constructor() {
2749
+ this.expanded = false;
2750
+ }
2751
+ get storyData() {
2752
+ return {
2753
+ ...(this.action?.input || {}),
2754
+ ...(this.action?.output || {}),
2755
+ };
2756
+ }
2757
+ get storyName() {
2758
+ return this.storyData.name || this.action?.name || 'Story';
2759
+ }
2760
+ get recommendedAge() {
2761
+ return this.storyData.recommendedAge || '';
2762
+ }
2763
+ get friendlyUrl() {
2764
+ return this.storyData.friendlyUrl || '';
2765
+ }
2766
+ get description() {
2767
+ return this.storyData.description || '';
2768
+ }
2769
+ get moralMeaning() {
2770
+ return this.storyData.moralMeaning || '';
2771
+ }
2772
+ get history() {
2773
+ return this.storyData.history || '';
2774
+ }
2775
+ get statusClass() {
2776
+ switch (this.action?.status) {
2777
+ case OzzyTaskStatus.SUCCESS:
2778
+ return 'rts-story-thumb-status-success';
2779
+ case OzzyTaskStatus.FAIL:
2780
+ return 'rts-story-thumb-status-fail';
2781
+ case OzzyTaskStatus.IN_PROGRESS:
2782
+ return 'rts-story-thumb-status-running';
2783
+ default:
2784
+ return 'rts-story-thumb-status-ready';
2785
+ }
2786
+ }
2787
+ onToggle() {
2788
+ this.toggleExpand?.();
2789
+ }
2790
+ onButtonClick(event) {
2791
+ event.stopPropagation();
2792
+ this.toggleExpand?.();
2793
+ }
2794
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryTaskActionThumbnailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2795
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: StoryTaskActionThumbnailComponent, isStandalone: true, selector: "rtsee-story-task-action-thumbnail", inputs: { action: "action", task: "task", expanded: "expanded", toggleExpand: "toggleExpand" }, ngImport: i0, template: `
2796
+ <div class="rts-story-thumb" [ngClass]="statusClass" (click)="onToggle()">
2797
+ <div class="rts-story-thumb-header">
2798
+ <div class="rts-story-thumb-title-wrap">
2799
+ <span class="rts-story-thumb-dot"></span>
2800
+ <span class="rts-story-thumb-badge">Story</span>
2801
+ <span class="rts-story-thumb-name" [title]="storyName">{{ storyName }}</span>
2802
+ @if (recommendedAge) {
2803
+ <span class="rts-story-thumb-age" [title]="'Recommended age: ' + recommendedAge">
2804
+ {{ recommendedAge }}
2805
+ </span>
2806
+ }
2807
+ @if (friendlyUrl) {
2808
+ <span class="rts-story-thumb-url" [title]="friendlyUrl">/{{ friendlyUrl }}</span>
2809
+ }
2810
+ </div>
2811
+ <button type="button"
2812
+ class="rts-story-thumb-expand"
2813
+ (click)="onButtonClick($event)"
2814
+ [title]="expanded ? 'Collapse action details' : 'Expand action details'"
2815
+ >
2816
+ {{ expanded ? 'Hide' : 'Expand' }}
2817
+ <span class="pi" [ngClass]="expanded ? 'pi-chevron-up' : 'pi-chevron-down'"></span>
2818
+ </button>
2819
+ </div>
2820
+
2821
+ @if (description || moralMeaning || history) {
2822
+ <div class="rts-story-thumb-fields">
2823
+ @if (description) {
2824
+ <div class="rts-story-thumb-field">
2825
+ <span class="rts-story-thumb-field-label">Description</span>
2826
+ <p class="rts-story-thumb-truncated" [title]="description">{{ description }}</p>
2827
+ </div>
2828
+ }
2829
+ @if (moralMeaning) {
2830
+ <div class="rts-story-thumb-field">
2831
+ <span class="rts-story-thumb-field-label">Moral Meaning</span>
2832
+ <p class="rts-story-thumb-truncated" [title]="moralMeaning">{{ moralMeaning }}</p>
2833
+ </div>
2834
+ }
2835
+ @if (history) {
2836
+ <div class="rts-story-thumb-field">
2837
+ <span class="rts-story-thumb-field-label">History</span>
2838
+ <p class="rts-story-thumb-truncated" [title]="history">{{ history }}</p>
2839
+ </div>
2840
+ }
2841
+ </div>
2842
+ }
2843
+ </div>
2844
+ `, isInline: true, styles: [".rts-story-thumb{display:flex;flex-direction:column;gap:6px;padding:9px 11px;border-radius:9px;background:#6366f10f;border:1px solid rgba(99,102,241,.22);cursor:pointer;transition:background .15s ease,border-color .15s ease}.rts-story-thumb:hover{background:#6366f11c;border-color:#6366f15c}.rts-story-thumb-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.rts-story-thumb-title-wrap{display:flex;align-items:center;gap:6px;min-width:0;flex-wrap:wrap}.rts-story-thumb-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;background:#8b5cf6}.rts-story-thumb-status-success .rts-story-thumb-dot{background:#10b981}.rts-story-thumb-status-fail .rts-story-thumb-dot{background:#f43f5e}.rts-story-thumb-badge{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;padding:1px 6px;border-radius:4px;background:#6366f126;color:#6366f1;flex-shrink:0}.rts-story-thumb-name{font-size:12.5px;font-weight:700;color:var(--rts-text-primary, #1f2430);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:220px}.rts-story-thumb-age{font-size:10.5px;font-weight:700;padding:1px 6px;border-radius:999px;background:#10b98124;color:#10b981;flex-shrink:0}.rts-story-thumb-url{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10.5px;color:var(--rts-text-secondary, #8a8fa3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:180px}.rts-story-thumb-expand{display:inline-flex;align-items:center;gap:4px;border:none;background:#8b5cf61f;color:#8b5cf6;font-size:11px;font-weight:600;padding:3px 8px;border-radius:6px;cursor:pointer;flex-shrink:0}.rts-story-thumb-expand:hover{background:#8b5cf638}.rts-story-thumb-fields{display:flex;flex-direction:column;gap:5px;padding-top:2px}.rts-story-thumb-field{display:flex;flex-direction:column;gap:1px}.rts-story-thumb-field-label{font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--rts-text-secondary, #8a8fa3)}.rts-story-thumb-truncated{margin:0;font-size:11.5px;line-height:1.4;color:var(--rts-text-primary, #1f2430);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;word-break:break-word}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
2845
+ }
2846
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryTaskActionThumbnailComponent, decorators: [{
2847
+ type: Component,
2848
+ args: [{ selector: 'rtsee-story-task-action-thumbnail', standalone: true, imports: [NgClass], template: `
2849
+ <div class="rts-story-thumb" [ngClass]="statusClass" (click)="onToggle()">
2850
+ <div class="rts-story-thumb-header">
2851
+ <div class="rts-story-thumb-title-wrap">
2852
+ <span class="rts-story-thumb-dot"></span>
2853
+ <span class="rts-story-thumb-badge">Story</span>
2854
+ <span class="rts-story-thumb-name" [title]="storyName">{{ storyName }}</span>
2855
+ @if (recommendedAge) {
2856
+ <span class="rts-story-thumb-age" [title]="'Recommended age: ' + recommendedAge">
2857
+ {{ recommendedAge }}
2858
+ </span>
2859
+ }
2860
+ @if (friendlyUrl) {
2861
+ <span class="rts-story-thumb-url" [title]="friendlyUrl">/{{ friendlyUrl }}</span>
2862
+ }
2863
+ </div>
2864
+ <button type="button"
2865
+ class="rts-story-thumb-expand"
2866
+ (click)="onButtonClick($event)"
2867
+ [title]="expanded ? 'Collapse action details' : 'Expand action details'"
2868
+ >
2869
+ {{ expanded ? 'Hide' : 'Expand' }}
2870
+ <span class="pi" [ngClass]="expanded ? 'pi-chevron-up' : 'pi-chevron-down'"></span>
2871
+ </button>
2872
+ </div>
2873
+
2874
+ @if (description || moralMeaning || history) {
2875
+ <div class="rts-story-thumb-fields">
2876
+ @if (description) {
2877
+ <div class="rts-story-thumb-field">
2878
+ <span class="rts-story-thumb-field-label">Description</span>
2879
+ <p class="rts-story-thumb-truncated" [title]="description">{{ description }}</p>
2880
+ </div>
2881
+ }
2882
+ @if (moralMeaning) {
2883
+ <div class="rts-story-thumb-field">
2884
+ <span class="rts-story-thumb-field-label">Moral Meaning</span>
2885
+ <p class="rts-story-thumb-truncated" [title]="moralMeaning">{{ moralMeaning }}</p>
2886
+ </div>
2887
+ }
2888
+ @if (history) {
2889
+ <div class="rts-story-thumb-field">
2890
+ <span class="rts-story-thumb-field-label">History</span>
2891
+ <p class="rts-story-thumb-truncated" [title]="history">{{ history }}</p>
2892
+ </div>
2893
+ }
2894
+ </div>
2895
+ }
2896
+ </div>
2897
+ `, styles: [".rts-story-thumb{display:flex;flex-direction:column;gap:6px;padding:9px 11px;border-radius:9px;background:#6366f10f;border:1px solid rgba(99,102,241,.22);cursor:pointer;transition:background .15s ease,border-color .15s ease}.rts-story-thumb:hover{background:#6366f11c;border-color:#6366f15c}.rts-story-thumb-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.rts-story-thumb-title-wrap{display:flex;align-items:center;gap:6px;min-width:0;flex-wrap:wrap}.rts-story-thumb-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;background:#8b5cf6}.rts-story-thumb-status-success .rts-story-thumb-dot{background:#10b981}.rts-story-thumb-status-fail .rts-story-thumb-dot{background:#f43f5e}.rts-story-thumb-badge{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;padding:1px 6px;border-radius:4px;background:#6366f126;color:#6366f1;flex-shrink:0}.rts-story-thumb-name{font-size:12.5px;font-weight:700;color:var(--rts-text-primary, #1f2430);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:220px}.rts-story-thumb-age{font-size:10.5px;font-weight:700;padding:1px 6px;border-radius:999px;background:#10b98124;color:#10b981;flex-shrink:0}.rts-story-thumb-url{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10.5px;color:var(--rts-text-secondary, #8a8fa3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:180px}.rts-story-thumb-expand{display:inline-flex;align-items:center;gap:4px;border:none;background:#8b5cf61f;color:#8b5cf6;font-size:11px;font-weight:600;padding:3px 8px;border-radius:6px;cursor:pointer;flex-shrink:0}.rts-story-thumb-expand:hover{background:#8b5cf638}.rts-story-thumb-fields{display:flex;flex-direction:column;gap:5px;padding-top:2px}.rts-story-thumb-field{display:flex;flex-direction:column;gap:1px}.rts-story-thumb-field-label{font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--rts-text-secondary, #8a8fa3)}.rts-story-thumb-truncated{margin:0;font-size:11.5px;line-height:1.4;color:var(--rts-text-primary, #1f2430);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;word-break:break-word}\n"] }]
2898
+ }], propDecorators: { action: [{
2899
+ type: Input
2900
+ }], task: [{
2901
+ type: Input
2902
+ }], expanded: [{
2903
+ type: Input
2904
+ }], toggleExpand: [{
2905
+ type: Input
2906
+ }] } });
2907
+
2908
+ /**
2909
+ * Custom task-action thumbnail widget for Slide creation / update actions.
2910
+ * Displays slide number and 2 first truncated lines of slide text with full text tooltip on hover.
2911
+ */
2912
+ class SlideTaskActionThumbnailComponent {
2913
+ constructor() {
2914
+ this.expanded = false;
2915
+ }
2916
+ get slideData() {
2917
+ return {
2918
+ ...(this.action?.input || {}),
2919
+ ...(this.action?.output || {}),
2920
+ };
2921
+ }
2922
+ get slideNumber() {
2923
+ return this.slideData.slideNumber ?? '-';
2924
+ }
2925
+ get slideText() {
2926
+ return this.slideData.text || '';
2927
+ }
2928
+ get statusClass() {
2929
+ switch (this.action?.status) {
2930
+ case OzzyTaskStatus.SUCCESS:
2931
+ return 'rts-slide-thumb-status-success';
2932
+ case OzzyTaskStatus.FAIL:
2933
+ return 'rts-slide-thumb-status-fail';
2934
+ case OzzyTaskStatus.IN_PROGRESS:
2935
+ return 'rts-slide-thumb-status-running';
2936
+ default:
2937
+ return 'rts-slide-thumb-status-ready';
2938
+ }
2939
+ }
2940
+ onToggle() {
2941
+ this.toggleExpand?.();
2942
+ }
2943
+ onButtonClick(event) {
2944
+ event.stopPropagation();
2945
+ this.toggleExpand?.();
2946
+ }
2947
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SlideTaskActionThumbnailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2948
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: SlideTaskActionThumbnailComponent, isStandalone: true, selector: "rtsee-slide-task-action-thumbnail", inputs: { action: "action", task: "task", expanded: "expanded", toggleExpand: "toggleExpand" }, ngImport: i0, template: `
2949
+ <div class="rts-slide-thumb" [ngClass]="statusClass" (click)="onToggle()">
2950
+ <div class="rts-slide-thumb-header">
2951
+ <div class="rts-slide-thumb-title-wrap">
2952
+ <span class="rts-slide-thumb-dot"></span>
2953
+ <span class="rts-slide-thumb-number">Slide #{{ slideNumber }}</span>
2954
+ <span class="rts-slide-thumb-action-name">{{ action?.name }}</span>
2955
+ </div>
2956
+ <button type="button"
2957
+ class="rts-slide-thumb-expand"
2958
+ (click)="onButtonClick($event)"
2959
+ [title]="expanded ? 'Collapse action details' : 'Expand action details'"
2960
+ >
2961
+ {{ expanded ? 'Hide' : 'Expand' }}
2962
+ <span class="pi" [ngClass]="expanded ? 'pi-chevron-up' : 'pi-chevron-down'"></span>
2963
+ </button>
2964
+ </div>
2965
+
2966
+ @if (slideText) {
2967
+ <p class="rts-slide-thumb-text" [title]="slideText">{{ slideText }}</p>
2968
+ }
2969
+ </div>
2970
+ `, isInline: true, styles: [".rts-slide-thumb{display:flex;flex-direction:column;gap:5px;padding:8px 11px;border-radius:8px;background:#8b5cf60d;border:1px solid rgba(139,92,246,.18);cursor:pointer;transition:background .15s ease,border-color .15s ease}.rts-slide-thumb:hover{background:#8b5cf61a;border-color:#8b5cf652}.rts-slide-thumb-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.rts-slide-thumb-title-wrap{display:flex;align-items:center;gap:6px;min-width:0}.rts-slide-thumb-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;background:#8b5cf6}.rts-slide-thumb-status-success .rts-slide-thumb-dot{background:#10b981}.rts-slide-thumb-status-fail .rts-slide-thumb-dot{background:#f43f5e}.rts-slide-thumb-number{font-size:11px;font-weight:700;padding:1px 7px;border-radius:999px;background:#8b5cf626;color:#8b5cf6;flex-shrink:0}.rts-slide-thumb-action-name{font-size:11px;color:var(--rts-text-secondary, #8a8fa3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.rts-slide-thumb-expand{display:inline-flex;align-items:center;gap:4px;border:none;background:#8b5cf61f;color:#8b5cf6;font-size:11px;font-weight:600;padding:3px 8px;border-radius:6px;cursor:pointer;flex-shrink:0}.rts-slide-thumb-expand:hover{background:#8b5cf638}.rts-slide-thumb-text{margin:0;font-size:12px;line-height:1.45;color:var(--rts-text-primary, #1f2430);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;word-break:break-word}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
2971
+ }
2972
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: SlideTaskActionThumbnailComponent, decorators: [{
2973
+ type: Component,
2974
+ args: [{ selector: 'rtsee-slide-task-action-thumbnail', standalone: true, imports: [NgClass], template: `
2975
+ <div class="rts-slide-thumb" [ngClass]="statusClass" (click)="onToggle()">
2976
+ <div class="rts-slide-thumb-header">
2977
+ <div class="rts-slide-thumb-title-wrap">
2978
+ <span class="rts-slide-thumb-dot"></span>
2979
+ <span class="rts-slide-thumb-number">Slide #{{ slideNumber }}</span>
2980
+ <span class="rts-slide-thumb-action-name">{{ action?.name }}</span>
2981
+ </div>
2982
+ <button type="button"
2983
+ class="rts-slide-thumb-expand"
2984
+ (click)="onButtonClick($event)"
2985
+ [title]="expanded ? 'Collapse action details' : 'Expand action details'"
2986
+ >
2987
+ {{ expanded ? 'Hide' : 'Expand' }}
2988
+ <span class="pi" [ngClass]="expanded ? 'pi-chevron-up' : 'pi-chevron-down'"></span>
2989
+ </button>
2990
+ </div>
2991
+
2992
+ @if (slideText) {
2993
+ <p class="rts-slide-thumb-text" [title]="slideText">{{ slideText }}</p>
2994
+ }
2995
+ </div>
2996
+ `, styles: [".rts-slide-thumb{display:flex;flex-direction:column;gap:5px;padding:8px 11px;border-radius:8px;background:#8b5cf60d;border:1px solid rgba(139,92,246,.18);cursor:pointer;transition:background .15s ease,border-color .15s ease}.rts-slide-thumb:hover{background:#8b5cf61a;border-color:#8b5cf652}.rts-slide-thumb-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.rts-slide-thumb-title-wrap{display:flex;align-items:center;gap:6px;min-width:0}.rts-slide-thumb-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;background:#8b5cf6}.rts-slide-thumb-status-success .rts-slide-thumb-dot{background:#10b981}.rts-slide-thumb-status-fail .rts-slide-thumb-dot{background:#f43f5e}.rts-slide-thumb-number{font-size:11px;font-weight:700;padding:1px 7px;border-radius:999px;background:#8b5cf626;color:#8b5cf6;flex-shrink:0}.rts-slide-thumb-action-name{font-size:11px;color:var(--rts-text-secondary, #8a8fa3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.rts-slide-thumb-expand{display:inline-flex;align-items:center;gap:4px;border:none;background:#8b5cf61f;color:#8b5cf6;font-size:11px;font-weight:600;padding:3px 8px;border-radius:6px;cursor:pointer;flex-shrink:0}.rts-slide-thumb-expand:hover{background:#8b5cf638}.rts-slide-thumb-text{margin:0;font-size:12px;line-height:1.45;color:var(--rts-text-primary, #1f2430);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;word-break:break-word}\n"] }]
2997
+ }], propDecorators: { action: [{
2998
+ type: Input
2999
+ }], task: [{
3000
+ type: Input
3001
+ }], expanded: [{
3002
+ type: Input
3003
+ }], toggleExpand: [{
3004
+ type: Input
3005
+ }] } });
3006
+
3007
+ class DefaultTaskActionPromptComponent {
3008
+ constructor() {
3009
+ this.expanded = false;
3010
+ this.responseValue = '';
3011
+ this.submitting = false;
3012
+ }
3013
+ get promptDataJson() {
3014
+ if (this.prompt?.data === undefined || this.prompt?.data === null) {
3015
+ return '';
3016
+ }
3017
+ try {
3018
+ return JSON.stringify(this.prompt.data, null, 2);
3019
+ }
3020
+ catch {
3021
+ return String(this.prompt.data);
3022
+ }
3023
+ }
3024
+ onToggle() {
3025
+ this.toggleExpand?.();
3026
+ }
3027
+ onButtonClick(event) {
3028
+ event.stopPropagation();
3029
+ this.toggleExpand?.();
3030
+ }
3031
+ async submit() {
3032
+ if (!this.task || !this.prompt || this.submitting) {
3033
+ return;
3034
+ }
3035
+ this.submitting = true;
3036
+ try {
3037
+ await this.task.respondToPrompt(this.prompt.id, this.responseValue);
3038
+ }
3039
+ finally {
3040
+ this.submitting = false;
3041
+ }
3042
+ }
3043
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DefaultTaskActionPromptComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3044
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: DefaultTaskActionPromptComponent, isStandalone: true, selector: "rtsee-default-task-action-prompt", inputs: { prompt: "prompt", task: "task", expanded: "expanded", toggleExpand: "toggleExpand" }, ngImport: i0, template: `
3045
+ <div class="rts-prompt-default">
3046
+ <div class="rts-prompt-header" (click)="onToggle()">
3047
+ <div class="rts-prompt-left">
3048
+ <span class="rts-prompt-badge">Prompt</span>
3049
+ <span class="rts-prompt-name" [title]="prompt?.name || 'Prompt'">
3050
+ {{ prompt?.name || 'Prompt' }}
3051
+ </span>
3052
+ </div>
3053
+ <button type="button"
3054
+ class="rts-prompt-expand"
3055
+ (click)="onButtonClick($event)"
3056
+ >
3057
+ {{ expanded ? 'Hide' : 'Expand' }}
3058
+ <span class="pi" [ngClass]="expanded ? 'pi-chevron-up' : 'pi-chevron-down'"></span>
3059
+ </button>
3060
+ </div>
3061
+
3062
+ @if (expanded && prompt) {
3063
+ <div class="rts-prompt-body">
3064
+ @if (promptDataJson) {
3065
+ <pre class="rts-prompt-code"><code>{{ promptDataJson }}</code></pre>
3066
+ }
3067
+ @if (!prompt.resolved) {
3068
+ <div class="rts-prompt-Controls">
3069
+ <input type="text"
3070
+ class="rts-prompt-input"
3071
+ [(ngModel)]="responseValue"
3072
+ placeholder="Provide response…"
3073
+ />
3074
+ <button type="button"
3075
+ class="rts-prompt-submit"
3076
+ [disabled]="submitting"
3077
+ (click)="submit()"
3078
+ >
3079
+ Send
3080
+ </button>
3081
+ </div>
3082
+ } @else {
3083
+ <div class="rts-prompt-resolved">Prompt answered.</div>
3084
+ }
3085
+ </div>
3086
+ }
3087
+ </div>
3088
+ `, isInline: true, styles: [".rts-prompt-default{display:flex;flex-direction:column;gap:6px;padding:8px 10px;border-radius:8px;background:#f59e0b14;border:1px solid rgba(245,158,11,.28)}.rts-prompt-header{display:flex;align-items:center;justify-content:space-between;gap:8px;cursor:pointer}.rts-prompt-left{display:flex;align-items:center;gap:6px;min-width:0}.rts-prompt-badge{font-size:10px;font-weight:700;text-transform:uppercase;padding:1px 6px;border-radius:4px;background:#f59e0b33;color:#d97706}.rts-prompt-name{font-size:12px;font-weight:600;color:var(--rts-text-primary, #1f2430);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.rts-prompt-expand{display:inline-flex;align-items:center;gap:4px;border:none;background:#f59e0b29;color:#d97706;font-size:11px;font-weight:600;padding:3px 8px;border-radius:6px;cursor:pointer}.rts-prompt-body{display:flex;flex-direction:column;gap:6px;padding-top:4px}.rts-prompt-code{margin:0;padding:8px 10px;border-radius:6px;background:#0f1020;color:#e4e4f0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;max-height:140px;overflow:auto;white-space:pre-wrap}.rts-prompt-Controls{display:flex;gap:6px}.rts-prompt-input{flex:1;padding:5px 8px;border-radius:6px;border:1px solid rgba(139,92,246,.3);font-size:12px;background:var(--rts-bg-primary, #fff);color:var(--rts-text-primary, #1f2430)}.rts-prompt-submit{padding:5px 12px;border:none;border-radius:6px;background:#8b5cf6;color:#fff;font-size:11.5px;font-weight:600;cursor:pointer}.rts-prompt-resolved{font-size:11px;color:#10b981;font-weight:600}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
3089
+ }
3090
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: DefaultTaskActionPromptComponent, decorators: [{
3091
+ type: Component,
3092
+ args: [{ selector: 'rtsee-default-task-action-prompt', standalone: true, imports: [NgClass, FormsModule], template: `
3093
+ <div class="rts-prompt-default">
3094
+ <div class="rts-prompt-header" (click)="onToggle()">
3095
+ <div class="rts-prompt-left">
3096
+ <span class="rts-prompt-badge">Prompt</span>
3097
+ <span class="rts-prompt-name" [title]="prompt?.name || 'Prompt'">
3098
+ {{ prompt?.name || 'Prompt' }}
3099
+ </span>
3100
+ </div>
3101
+ <button type="button"
3102
+ class="rts-prompt-expand"
3103
+ (click)="onButtonClick($event)"
3104
+ >
3105
+ {{ expanded ? 'Hide' : 'Expand' }}
3106
+ <span class="pi" [ngClass]="expanded ? 'pi-chevron-up' : 'pi-chevron-down'"></span>
3107
+ </button>
3108
+ </div>
3109
+
3110
+ @if (expanded && prompt) {
3111
+ <div class="rts-prompt-body">
3112
+ @if (promptDataJson) {
3113
+ <pre class="rts-prompt-code"><code>{{ promptDataJson }}</code></pre>
3114
+ }
3115
+ @if (!prompt.resolved) {
3116
+ <div class="rts-prompt-Controls">
3117
+ <input type="text"
3118
+ class="rts-prompt-input"
3119
+ [(ngModel)]="responseValue"
3120
+ placeholder="Provide response…"
3121
+ />
3122
+ <button type="button"
3123
+ class="rts-prompt-submit"
3124
+ [disabled]="submitting"
3125
+ (click)="submit()"
3126
+ >
3127
+ Send
3128
+ </button>
3129
+ </div>
3130
+ } @else {
3131
+ <div class="rts-prompt-resolved">Prompt answered.</div>
3132
+ }
3133
+ </div>
3134
+ }
3135
+ </div>
3136
+ `, styles: [".rts-prompt-default{display:flex;flex-direction:column;gap:6px;padding:8px 10px;border-radius:8px;background:#f59e0b14;border:1px solid rgba(245,158,11,.28)}.rts-prompt-header{display:flex;align-items:center;justify-content:space-between;gap:8px;cursor:pointer}.rts-prompt-left{display:flex;align-items:center;gap:6px;min-width:0}.rts-prompt-badge{font-size:10px;font-weight:700;text-transform:uppercase;padding:1px 6px;border-radius:4px;background:#f59e0b33;color:#d97706}.rts-prompt-name{font-size:12px;font-weight:600;color:var(--rts-text-primary, #1f2430);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.rts-prompt-expand{display:inline-flex;align-items:center;gap:4px;border:none;background:#f59e0b29;color:#d97706;font-size:11px;font-weight:600;padding:3px 8px;border-radius:6px;cursor:pointer}.rts-prompt-body{display:flex;flex-direction:column;gap:6px;padding-top:4px}.rts-prompt-code{margin:0;padding:8px 10px;border-radius:6px;background:#0f1020;color:#e4e4f0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;max-height:140px;overflow:auto;white-space:pre-wrap}.rts-prompt-Controls{display:flex;gap:6px}.rts-prompt-input{flex:1;padding:5px 8px;border-radius:6px;border:1px solid rgba(139,92,246,.3);font-size:12px;background:var(--rts-bg-primary, #fff);color:var(--rts-text-primary, #1f2430)}.rts-prompt-submit{padding:5px 12px;border:none;border-radius:6px;background:#8b5cf6;color:#fff;font-size:11.5px;font-weight:600;cursor:pointer}.rts-prompt-resolved{font-size:11px;color:#10b981;font-weight:600}\n"] }]
3137
+ }], propDecorators: { prompt: [{
3138
+ type: Input
3139
+ }], task: [{
3140
+ type: Input
3141
+ }], expanded: [{
3142
+ type: Input
3143
+ }], toggleExpand: [{
3144
+ type: Input
3145
+ }] } });
3146
+
3147
+ /**
3148
+ * Registry of custom client-side widgets for task-action-thumbnails and task-action-prompts.
3149
+ * Falls back to DefaultTaskActionThumbnailComponent / DefaultTaskActionPromptComponent.
3150
+ */
3151
+ class TaskActionWidgetsService {
3152
+ constructor() {
3153
+ this.thumbnailsMap = [
3154
+ { name: CREATE_STORY_ACTION_NAME, component: StoryTaskActionThumbnailComponent },
3155
+ { name: EDIT_STORY_ACTION_NAME, component: StoryTaskActionThumbnailComponent },
3156
+ { name: CREATE_SLIDE_ACTION_NAME, component: SlideTaskActionThumbnailComponent },
3157
+ { name: EDIT_SLIDE_ACTION_NAME, component: SlideTaskActionThumbnailComponent },
3158
+ ];
3159
+ this.promptsMap = [];
3160
+ }
3161
+ registerThumbnail(widget) {
3162
+ this.thumbnailsMap = [
3163
+ ...this.thumbnailsMap.filter((e) => e.name !== widget.name),
3164
+ widget,
3165
+ ];
3166
+ }
3167
+ registerPrompt(widget) {
3168
+ this.promptsMap = [
3169
+ ...this.promptsMap.filter((e) => e.name !== widget.name),
3170
+ widget,
3171
+ ];
3172
+ }
3173
+ getThumbnailComponentByName(name) {
3174
+ if (!name) {
3175
+ return DefaultTaskActionThumbnailComponent;
3176
+ }
3177
+ return (this.thumbnailsMap.find((e) => e.name === name)?.component ||
3178
+ DefaultTaskActionThumbnailComponent);
3179
+ }
3180
+ getPromptComponentByName(name) {
3181
+ if (!name) {
3182
+ return DefaultTaskActionPromptComponent;
3183
+ }
3184
+ return (this.promptsMap.find((e) => e.name === name)?.component ||
3185
+ DefaultTaskActionPromptComponent);
3186
+ }
3187
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TaskActionWidgetsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3188
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TaskActionWidgetsService, providedIn: 'root' }); }
3189
+ }
3190
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TaskActionWidgetsService, decorators: [{
3191
+ type: Injectable,
3192
+ args: [{
3193
+ providedIn: 'root',
3194
+ }]
3195
+ }] });
3196
+
3197
+ /**
3198
+ * Minified thumbnail representation of an OzzyClientTaskAction.
3199
+ * Renders the registered custom thumbnail widget (or DefaultTaskActionThumbnailComponent)
3200
+ * and expands into the full RTSeeTaskActionComponent view on toggle.
3201
+ */
3202
+ class TaskActionThumbnailComponent {
3203
+ constructor(cdr, actionWidgets) {
3204
+ this.cdr = cdr;
3205
+ this.actionWidgets = actionWidgets;
3206
+ this.expanded = false;
3207
+ this.subscribedAction = null;
3208
+ this.onChangedBound = () => this.cdr.detectChanges();
3209
+ this.toggleExpandBound = () => this.toggleExpand();
3210
+ }
3211
+ ngOnInit() {
3212
+ this.subscribe();
3213
+ }
3214
+ ngOnChanges(changes) {
3215
+ if (changes['action'] && !changes['action'].firstChange) {
3216
+ this.subscribe();
3217
+ }
3218
+ }
3219
+ ngOnDestroy() {
3220
+ this.unsubscribe();
3221
+ }
3222
+ get thumbnailComponent() {
3223
+ return this.actionWidgets.getThumbnailComponentByName(this.action?.name);
3224
+ }
3225
+ get thumbnailInputs() {
3226
+ return {
3227
+ action: this.action,
3228
+ task: this.task,
3229
+ expanded: this.expanded,
3230
+ toggleExpand: this.toggleExpandBound,
3231
+ };
3232
+ }
3233
+ toggleExpand() {
3234
+ this.expanded = !this.expanded;
3235
+ if (this.expanded && this.action && !this.action.loaded && !this.action.isRunning) {
3236
+ void this.action.load();
3237
+ }
3238
+ this.cdr.detectChanges();
3239
+ }
3240
+ subscribe() {
3241
+ if (this.subscribedAction === this.action) {
3242
+ return;
3243
+ }
3244
+ this.unsubscribe();
3245
+ if (this.action) {
3246
+ this.subscribedAction = this.action;
3247
+ this.action.on(OzzyClientTaskActionEvents.CHANGED, this.onChangedBound);
3248
+ }
3249
+ }
3250
+ unsubscribe() {
3251
+ this.subscribedAction?.off(OzzyClientTaskActionEvents.CHANGED, this.onChangedBound);
3252
+ this.subscribedAction = null;
3253
+ }
3254
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TaskActionThumbnailComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: TaskActionWidgetsService }], target: i0.ɵɵFactoryTarget.Component }); }
3255
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: TaskActionThumbnailComponent, isStandalone: true, selector: "rtsee-task-action-thumbnail, task-action-thumbnail", inputs: { action: "action", task: "task" }, usesOnChanges: true, ngImport: i0, template: `
3256
+ <div class="rts-action-thumbnail-host">
3257
+ @if (action) {
3258
+ <ng-container
3259
+ *ngComponentOutlet="thumbnailComponent; inputs: thumbnailInputs"
3260
+ ></ng-container>
3261
+
3262
+ @if (expanded) {
3263
+ <div class="rts-action-thumbnail-expanded">
3264
+ <rtsee-task-action [action]="action"></rtsee-task-action>
3265
+ </div>
3266
+ }
3267
+ }
3268
+ </div>
3269
+ `, isInline: true, styles: [":host{display:block}.rts-action-thumbnail-host{display:flex;flex-direction:column;gap:6px}.rts-action-thumbnail-expanded{padding-left:8px;border-left:2px solid rgba(139,92,246,.35)}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: RTSeeTaskActionComponent, selector: "rtsee-task-action", inputs: ["action"] }] }); }
3270
+ }
3271
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TaskActionThumbnailComponent, decorators: [{
3272
+ type: Component,
3273
+ args: [{ selector: 'rtsee-task-action-thumbnail, task-action-thumbnail', standalone: true, imports: [NgComponentOutlet, RTSeeTaskActionComponent], template: `
3274
+ <div class="rts-action-thumbnail-host">
3275
+ @if (action) {
3276
+ <ng-container
3277
+ *ngComponentOutlet="thumbnailComponent; inputs: thumbnailInputs"
3278
+ ></ng-container>
3279
+
3280
+ @if (expanded) {
3281
+ <div class="rts-action-thumbnail-expanded">
3282
+ <rtsee-task-action [action]="action"></rtsee-task-action>
3283
+ </div>
3284
+ }
3285
+ }
3286
+ </div>
3287
+ `, styles: [":host{display:block}.rts-action-thumbnail-host{display:flex;flex-direction:column;gap:6px}.rts-action-thumbnail-expanded{padding-left:8px;border-left:2px solid rgba(139,92,246,.35)}\n"] }]
3288
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: TaskActionWidgetsService }], propDecorators: { action: [{
3289
+ type: Input
3290
+ }], task: [{
3291
+ type: Input
3292
+ }] } });
3293
+
3294
+ /**
3295
+ * Host component for a task action prompt.
3296
+ * Renders the registered custom prompt widget (or DefaultTaskActionPromptComponent).
3297
+ */
3298
+ class TaskActionPromptComponent {
3299
+ constructor(cdr, actionWidgets) {
3300
+ this.cdr = cdr;
3301
+ this.actionWidgets = actionWidgets;
3302
+ this.expanded = false;
3303
+ this.toggleExpandBound = () => this.toggleExpand();
3304
+ }
3305
+ get promptComponent() {
3306
+ return this.actionWidgets.getPromptComponentByName(this.prompt?.name);
3307
+ }
3308
+ get promptInputs() {
3309
+ return {
3310
+ prompt: this.prompt,
3311
+ task: this.task,
3312
+ expanded: this.expanded,
3313
+ toggleExpand: this.toggleExpandBound,
3314
+ };
3315
+ }
3316
+ toggleExpand() {
3317
+ this.expanded = !this.expanded;
3318
+ this.cdr.detectChanges();
3319
+ }
3320
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TaskActionPromptComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: TaskActionWidgetsService }], target: i0.ɵɵFactoryTarget.Component }); }
3321
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: TaskActionPromptComponent, isStandalone: true, selector: "rtsee-task-action-prompt, task-action-prompt", inputs: { prompt: "prompt", task: "task" }, ngImport: i0, template: `
3322
+ @if (prompt) {
3323
+ <ng-container
3324
+ *ngComponentOutlet="promptComponent; inputs: promptInputs"
3325
+ ></ng-container>
3326
+ }
3327
+ `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }] }); }
3328
+ }
3329
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: TaskActionPromptComponent, decorators: [{
3330
+ type: Component,
3331
+ args: [{ selector: 'rtsee-task-action-prompt, task-action-prompt', standalone: true, imports: [NgComponentOutlet], template: `
3332
+ @if (prompt) {
3333
+ <ng-container
3334
+ *ngComponentOutlet="promptComponent; inputs: promptInputs"
3335
+ ></ng-container>
3336
+ }
3337
+ `, styles: [":host{display:block}\n"] }]
3338
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: TaskActionWidgetsService }], propDecorators: { prompt: [{
3339
+ type: Input
3340
+ }], task: [{
3341
+ type: Input
3342
+ }] } });
3343
+
2447
3344
  /**
2448
3345
  * Default client-side representation of a server-side OzzyTask.
2449
3346
  * Can be used directly (`[task]`) or as a message widget (`message.data.taskId`).
@@ -2462,10 +3359,12 @@ class RTSeeTaskComponent {
2462
3359
  this.task = this.messenger.ozzy.getTask(this.message.data.taskId);
2463
3360
  }
2464
3361
  this.subscribe();
3362
+ this.ensureActions();
2465
3363
  }
2466
3364
  ngOnChanges(changes) {
2467
3365
  if (changes['task'] && !changes['task'].firstChange) {
2468
3366
  this.subscribe();
3367
+ this.ensureActions();
2469
3368
  }
2470
3369
  }
2471
3370
  ngOnDestroy() {
@@ -2504,12 +3403,27 @@ class RTSeeTaskComponent {
2504
3403
  get hasOutput() {
2505
3404
  return this.task?.output !== undefined && this.task?.output !== null;
2506
3405
  }
2507
- get hasLogs() {
2508
- return !!(this.task?.logs?.length || this.task?.liveText);
3406
+ get hasActions() {
3407
+ return !!(this.task?.actions?.length || this.task?.actionsLoading);
3408
+ }
3409
+ get hasPrompts() {
3410
+ return !!(this.task?.prompts?.length);
2509
3411
  }
2510
3412
  execute() {
2511
3413
  void this.task?.execute();
2512
3414
  }
3415
+ loadMoreActions() {
3416
+ void this.task?.loadMoreActions();
3417
+ }
3418
+ onActionsScroll(event) {
3419
+ const el = event.target;
3420
+ if (!el || !this.task?.hasMoreActions || this.task.actionsLoading) {
3421
+ return;
3422
+ }
3423
+ if (el.scrollTop + el.clientHeight >= el.scrollHeight - 40) {
3424
+ void this.task.loadMoreActions();
3425
+ }
3426
+ }
2513
3427
  async copy(kind) {
2514
3428
  try {
2515
3429
  await navigator.clipboard.writeText(kind === 'input' ? this.inputJson : this.outputJson);
@@ -2524,8 +3438,19 @@ class RTSeeTaskComponent {
2524
3438
  console.log('Failed to copy', e);
2525
3439
  }
2526
3440
  }
2527
- trackLog(index, log) {
2528
- return `${index}-${log.level}`;
3441
+ trackAction(_index, action) {
3442
+ return action.id;
3443
+ }
3444
+ trackPrompt(_index, prompt) {
3445
+ return prompt.id;
3446
+ }
3447
+ ensureActions() {
3448
+ if (!this.task) {
3449
+ return;
3450
+ }
3451
+ if (this.task.status !== OzzyTaskStatus.CREATED) {
3452
+ this.task.ensureActionsLoaded();
3453
+ }
2529
3454
  }
2530
3455
  toJson(value) {
2531
3456
  if (value === undefined || value === null) {
@@ -2553,18 +3478,21 @@ class RTSeeTaskComponent {
2553
3478
  this.subscribedTask = null;
2554
3479
  }
2555
3480
  onTaskChanged() {
3481
+ this.ensureActions();
2556
3482
  this.cdr.detectChanges();
2557
- const el = this.logsContainer?.nativeElement;
2558
- if (el) {
2559
- el.scrollTop = el.scrollHeight;
3483
+ if (this.task?.isRunning) {
3484
+ const el = this.actionsContainer?.nativeElement;
3485
+ if (el) {
3486
+ el.scrollTop = el.scrollHeight;
3487
+ }
2560
3488
  }
2561
3489
  }
2562
3490
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RTSeeTaskComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2563
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RTSeeTaskComponent, isStandalone: true, selector: "rtsee-task", inputs: { task: "task", message: "message", messenger: "messenger", chat: "chat", allowExecute: "allowExecute" }, viewQueries: [{ propertyName: "logsContainer", first: true, predicate: ["logsContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"rts-task\" [ngClass]=\"statusClass\">\n @if (task) {\n <div class=\"rts-task-header\">\n <div class=\"rts-task-identity\">\n <span class=\"rts-task-icon\">\u2699</span>\n <div class=\"rts-task-titles\">\n <span class=\"rts-task-name\">{{ task.name || 'Task' }}</span>\n <span class=\"rts-task-id\" [title]=\"task.id\">#{{ task.id }}</span>\n </div>\n </div>\n <span class=\"rts-task-status\">\n <span class=\"rts-task-status-dot\"></span>\n {{ statusLabel }}\n </span>\n </div>\n\n <!-- Input -->\n <div class=\"rts-task-section\">\n <div class=\"rts-task-section-head\">\n <span class=\"rts-task-section-label\">Input</span>\n @if (inputJson) {\n <button type=\"button\" class=\"rts-task-copy\" (click)=\"copy('input')\">\n {{ copied === 'input' ? 'Copied' : 'Copy' }}\n </button>\n }\n </div>\n @if (inputJson) {\n <pre class=\"rts-task-code\"><code>{{ inputJson }}</code></pre>\n } @else if (task.loading) {\n <div class=\"rts-task-placeholder\">Loading\u2026</div>\n } @else {\n <div class=\"rts-task-placeholder\">No input</div>\n }\n </div>\n\n @if (allowExecute) {\n <div class=\"rts-task-actions\">\n <button type=\"button\"\n class=\"rts-task-execute\"\n [disabled]=\"!task.canExecute\"\n (click)=\"execute()\"\n >\n @if (task.isRunning || task.executeInProgress) {\n <span class=\"rts-task-spinner\"></span> Executing\u2026\n } @else if (task.isFailed) {\n <span class=\"pi pi-refresh\"></span> Retry\n } @else if (task.isFinished) {\n <span class=\"pi pi-check\"></span> Executed\n } @else {\n <span class=\"pi pi-play\"></span> Execute\n }\n </button>\n </div>\n }\n\n <!-- Logs -->\n @if (hasLogs || task.isRunning) {\n <div class=\"rts-task-section\">\n <div class=\"rts-task-section-head\">\n <span class=\"rts-task-section-label\">Logs</span>\n @if (task.isRunning) {\n <span class=\"rts-task-live\">LIVE</span>\n }\n </div>\n <div #logsContainer class=\"rts-task-terminal\">\n @for (log of task.logs; track $index) {\n <div class=\"rts-task-log\" [ngClass]=\"'rts-task-log-' + log.level\">\n <span class=\"rts-task-log-time\">{{ log.createdAt | date: 'HH:mm:ss' }}</span>\n <span class=\"rts-task-log-level\">{{ log.level }}</span>\n <span class=\"rts-task-log-message\">{{ log.message }}</span>\n </div>\n }\n @if (task.liveText) {\n <div class=\"rts-task-live-text\">{{ task.liveText }}@if (task.isRunning) {<span class=\"rts-task-cursor\"></span>}</div>\n } @else if (task.isRunning && !task.logs.length) {\n <div class=\"rts-task-log rts-task-log-info\">\n <span class=\"rts-task-log-message\">Waiting for logs\u2026</span>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Output -->\n @if (hasOutput) {\n <div class=\"rts-task-section rts-task-section-output\">\n <div class=\"rts-task-section-head\">\n <span class=\"rts-task-section-label\">Output</span>\n <button type=\"button\" class=\"rts-task-copy\" (click)=\"copy('output')\">\n {{ copied === 'output' ? 'Copied' : 'Copy' }}\n </button>\n </div>\n <pre class=\"rts-task-code\"><code>{{ outputJson }}</code></pre>\n </div>\n }\n\n @if (task.errors.length) {\n <div class=\"rts-task-errors\">\n @for (error of task.errors; track $index) {\n <div class=\"rts-task-error\">{{ error.message }}</div>\n }\n </div>\n }\n\n @if (task.requestError) {\n <div class=\"rts-task-errors\">\n <div class=\"rts-task-error\">{{ task.requestError }}</div>\n </div>\n }\n } @else {\n <div class=\"rts-task-placeholder\">Task is not available yet.</div>\n }\n</div>\n", styles: [":host{display:block;--rts-task-accent: #8b5cf6;--rts-task-accent-2: #6366f1;--rts-task-success: #10b981;--rts-task-fail: #f43f5e;--rts-task-warn: #f59e0b}.rts-task{position:relative;display:flex;flex-direction:column;gap:10px;padding:12px;border-radius:12px;background:linear-gradient(var(--rts-bg-secondary, #fff),var(--rts-bg-secondary, #fff)) padding-box,linear-gradient(135deg,#6366f173,#8b5cf626 60%,#a78bfa59) border-box;border:1px solid transparent;box-shadow:0 6px 24px -12px #6366f159;min-width:260px;max-width:100%;font-size:13px;transition:box-shadow .25s ease}.rts-task.rts-task-status-running{animation:rts-task-glow 2.2s ease-in-out infinite}@keyframes rts-task-glow{0%,to{box-shadow:0 6px 24px -12px #6366f159}50%{box-shadow:0 6px 28px -8px #8b5cf699}}.rts-task-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.rts-task-identity{display:flex;align-items:center;gap:8px;min-width:0}.rts-task-icon{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;flex-shrink:0;border-radius:8px;color:#fff;font-size:14px;background:linear-gradient(135deg,var(--rts-task-accent-2),var(--rts-task-accent))}.rts-task-status-running .rts-task-icon{animation:rts-task-spin 2.4s linear infinite}.rts-task-titles{display:flex;flex-direction:column;min-width:0}.rts-task-name{font-weight:600;color:var(--rts-text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.rts-task-id{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;color:var(--rts-text-secondary, #8a8fa3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:220px}.rts-task-status{display:inline-flex;align-items:center;gap:5px;padding:2px 8px;border-radius:999px;font-size:10px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;flex-shrink:0;color:var(--rts-task-accent);background:#8b5cf61f}.rts-task-status-dot{width:6px;height:6px;border-radius:50%;background:currentColor}.rts-task-status-running .rts-task-status-dot{animation:rts-task-pulse 1s ease-in-out infinite}.rts-task-status-success .rts-task-status{color:var(--rts-task-success);background:#10b9811f}.rts-task-status-fail .rts-task-status{color:var(--rts-task-fail);background:#f43f5e1f}.rts-task-section{display:flex;flex-direction:column;gap:4px;animation:rts-task-fade-in .3s ease}.rts-task-section-head{display:flex;align-items:center;justify-content:space-between}.rts-task-section-label{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--rts-text-secondary, #8a8fa3)}.rts-task-copy{border:none;background:transparent;color:var(--rts-task-accent);font-size:11px;cursor:pointer;padding:0 2px}.rts-task-copy:hover{text-decoration:underline}.rts-task-live{font-size:9px;font-weight:700;letter-spacing:.08em;color:var(--rts-task-fail);animation:rts-task-pulse 1.2s ease-in-out infinite}.rts-task-code,.rts-task-terminal{margin:0;padding:10px 12px;border-radius:8px;background:#0f1020;color:#e4e4f0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;line-height:1.55;max-height:220px;overflow:auto;white-space:pre-wrap;word-break:break-word;border:1px solid rgba(139,92,246,.18)}.rts-task-section-output .rts-task-code{border-color:#10b98159}.rts-task-log{display:flex;gap:8px;align-items:baseline}.rts-task-log-time{color:#6b6f8a;flex-shrink:0}.rts-task-log-level{flex-shrink:0;min-width:34px;text-transform:uppercase;font-size:9.5px;font-weight:700;color:#a78bfa}.rts-task-log-warn .rts-task-log-level{color:var(--rts-task-warn)}.rts-task-log-error .rts-task-log-level,.rts-task-log-error .rts-task-log-message{color:#fb7185}.rts-task-live-text{margin-top:6px;padding-top:6px;border-top:1px dashed rgba(139,92,246,.25);color:#c4b5fd;white-space:pre-wrap}.rts-task-cursor{display:inline-block;width:6px;height:12px;margin-left:1px;vertical-align:text-bottom;background:#a78bfa;animation:rts-task-blink .8s step-end infinite}.rts-task-actions{display:flex;justify-content:flex-end}.rts-task-execute{display:inline-flex;align-items:center;gap:6px;padding:7px 16px;border:none;border-radius:8px;color:#fff;font-weight:600;font-size:12px;cursor:pointer;background:linear-gradient(135deg,var(--rts-task-accent-2),var(--rts-task-accent));box-shadow:0 4px 14px -4px #6366f199;transition:transform .15s ease,box-shadow .15s ease,opacity .15s ease}.rts-task-execute:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 6px 18px -4px #6366f1bf}.rts-task-execute:disabled{cursor:default;opacity:.6;box-shadow:none}.rts-task-spinner{width:11px;height:11px;border-radius:50%;border:2px solid rgba(255,255,255,.35);border-top-color:#fff;animation:rts-task-spin .8s linear infinite}.rts-task-placeholder{font-size:12px;color:var(--rts-text-secondary, #8a8fa3);font-style:italic}.rts-task-errors{display:flex;flex-direction:column;gap:4px}.rts-task-error{padding:6px 10px;border-radius:6px;font-size:12px;color:var(--rts-task-fail);background:#f43f5e14;border:1px solid rgba(244,63,94,.25)}@keyframes rts-task-spin{to{transform:rotate(360deg)}}@keyframes rts-task-pulse{0%,to{opacity:1}50%{opacity:.35}}@keyframes rts-task-blink{0%,to{opacity:1}50%{opacity:0}}@keyframes rts-task-fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: DatePipe, name: "date" }] }); }
3491
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RTSeeTaskComponent, isStandalone: true, selector: "rtsee-task", inputs: { task: "task", message: "message", messenger: "messenger", chat: "chat", allowExecute: "allowExecute" }, viewQueries: [{ propertyName: "actionsContainer", first: true, predicate: ["actionsContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"rts-task\" [ngClass]=\"statusClass\">\n @if (task) {\n <div class=\"rts-task-header\">\n <div class=\"rts-task-identity\">\n <span class=\"rts-task-icon\">\u2699</span>\n <div class=\"rts-task-titles\">\n <span class=\"rts-task-name\">{{ task.name || 'Task' }}</span>\n <span class=\"rts-task-id\" [title]=\"task.id\">#{{ task.id }}</span>\n </div>\n </div>\n <span class=\"rts-task-status\">\n <span class=\"rts-task-status-dot\"></span>\n {{ statusLabel }}\n </span>\n </div>\n\n <!-- Input -->\n <div class=\"rts-task-section\">\n <div class=\"rts-task-section-head\">\n <span class=\"rts-task-section-label\">Input</span>\n @if (inputJson) {\n <button type=\"button\" class=\"rts-task-copy\" (click)=\"copy('input')\">\n {{ copied === 'input' ? 'Copied' : 'Copy' }}\n </button>\n }\n </div>\n @if (inputJson) {\n <pre class=\"rts-task-code\"><code>{{ inputJson }}</code></pre>\n } @else if (task.loading) {\n <div class=\"rts-task-placeholder\">Loading\u2026</div>\n } @else {\n <div class=\"rts-task-placeholder\">No input</div>\n }\n </div>\n\n @if (allowExecute) {\n <div class=\"rts-task-actions\">\n <button type=\"button\"\n class=\"rts-task-execute\"\n [disabled]=\"!task.canExecute\"\n (click)=\"execute()\"\n >\n @if (task.isRunning || task.executeInProgress) {\n <span class=\"rts-task-spinner\"></span> Executing\u2026\n } @else if (task.isFailed) {\n <span class=\"pi pi-refresh\"></span> Retry\n } @else if (task.isFinished) {\n <span class=\"pi pi-check\"></span> Executed\n } @else {\n <span class=\"pi pi-play\"></span> Execute\n }\n </button>\n </div>\n }\n\n <!-- Prompts -->\n @if (hasPrompts) {\n <div class=\"rts-task-section\">\n <div class=\"rts-task-section-head\">\n <span class=\"rts-task-section-label\">Prompts</span>\n </div>\n <div class=\"rts-task-prompts-list\">\n @for (prompt of task.prompts; track prompt.id) {\n <rtsee-task-action-prompt\n [prompt]=\"prompt\"\n [task]=\"task\"\n ></rtsee-task-action-prompt>\n }\n </div>\n </div>\n }\n\n <!-- Actions (replaces Logs list) -->\n @if (hasActions || task.isRunning) {\n <div class=\"rts-task-section\">\n <div class=\"rts-task-section-head\">\n <span class=\"rts-task-section-label\">\n Actions @if (task.actionsTotal) { ({{ task.actions.length }}/{{ task.actionsTotal }}) }\n </span>\n @if (task.isRunning) {\n <span class=\"rts-task-live\">LIVE</span>\n }\n </div>\n <div #actionsContainer class=\"rts-task-actions-list\" (scroll)=\"onActionsScroll($event)\">\n @for (action of task.actions; track action.id) {\n <rtsee-task-action-thumbnail\n [action]=\"action\"\n [task]=\"task\"\n ></rtsee-task-action-thumbnail>\n }\n @if (task.isRunning && !task.actions.length) {\n <div class=\"rts-task-placeholder\">Starting actions\u2026</div>\n }\n @if (task.actionsLoading) {\n <div class=\"rts-task-placeholder\">Loading actions\u2026</div>\n }\n @if (task.hasMoreActions && !task.actionsLoading) {\n <button type=\"button\" class=\"rts-task-load-more\" (click)=\"loadMoreActions()\">\n Load more actions ({{ task.actions.length }}/{{ task.actionsTotal }})\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Output -->\n @if (hasOutput) {\n <div class=\"rts-task-section rts-task-section-output\">\n <div class=\"rts-task-section-head\">\n <span class=\"rts-task-section-label\">Output</span>\n <button type=\"button\" class=\"rts-task-copy\" (click)=\"copy('output')\">\n {{ copied === 'output' ? 'Copied' : 'Copy' }}\n </button>\n </div>\n <pre class=\"rts-task-code\"><code>{{ outputJson }}</code></pre>\n </div>\n }\n\n @if (task.errors.length) {\n <div class=\"rts-task-errors\">\n @for (error of task.errors; track $index) {\n <div class=\"rts-task-error\">{{ error.message }}</div>\n }\n </div>\n }\n\n @if (task.requestError) {\n <div class=\"rts-task-errors\">\n <div class=\"rts-task-error\">{{ task.requestError }}</div>\n </div>\n }\n } @else {\n <div class=\"rts-task-placeholder\">Task is not available yet.</div>\n }\n</div>\n", styles: [":host{display:block;--rts-task-accent: #8b5cf6;--rts-task-accent-2: #6366f1;--rts-task-success: #10b981;--rts-task-fail: #f43f5e;--rts-task-warn: #f59e0b}.rts-task{position:relative;display:flex;flex-direction:column;gap:10px;padding:12px;border-radius:12px;background:linear-gradient(var(--rts-bg-secondary, #fff),var(--rts-bg-secondary, #fff)) padding-box,linear-gradient(135deg,#6366f173,#8b5cf626 60%,#a78bfa59) border-box;border:1px solid transparent;box-shadow:0 6px 24px -12px #6366f159;min-width:260px;max-width:100%;font-size:13px;transition:box-shadow .25s ease}.rts-task.rts-task-status-running{animation:rts-task-glow 2.2s ease-in-out infinite}@keyframes rts-task-glow{0%,to{box-shadow:0 6px 24px -12px #6366f159}50%{box-shadow:0 6px 28px -8px #8b5cf699}}.rts-task-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.rts-task-identity{display:flex;align-items:center;gap:8px;min-width:0}.rts-task-icon{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;flex-shrink:0;border-radius:8px;color:#fff;font-size:14px;background:linear-gradient(135deg,var(--rts-task-accent-2),var(--rts-task-accent))}.rts-task-status-running .rts-task-icon{animation:rts-task-spin 2.4s linear infinite}.rts-task-titles{display:flex;flex-direction:column;min-width:0}.rts-task-name{font-weight:600;color:var(--rts-text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.rts-task-id{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;color:var(--rts-text-secondary, #8a8fa3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:220px}.rts-task-status{display:inline-flex;align-items:center;gap:5px;padding:2px 8px;border-radius:999px;font-size:10px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;flex-shrink:0;color:var(--rts-task-accent);background:#8b5cf61f}.rts-task-status-dot{width:6px;height:6px;border-radius:50%;background:currentColor}.rts-task-status-running .rts-task-status-dot{animation:rts-task-pulse 1s ease-in-out infinite}.rts-task-status-success .rts-task-status{color:var(--rts-task-success);background:#10b9811f}.rts-task-status-fail .rts-task-status{color:var(--rts-task-fail);background:#f43f5e1f}.rts-task-section{display:flex;flex-direction:column;gap:4px;animation:rts-task-fade-in .3s ease}.rts-task-section-head{display:flex;align-items:center;justify-content:space-between}.rts-task-section-label{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--rts-text-secondary, #8a8fa3)}.rts-task-copy{border:none;background:transparent;color:var(--rts-task-accent);font-size:11px;cursor:pointer;padding:0 2px}.rts-task-copy:hover{text-decoration:underline}.rts-task-live{font-size:9px;font-weight:700;letter-spacing:.08em;color:var(--rts-task-fail);animation:rts-task-pulse 1.2s ease-in-out infinite}.rts-task-code,.rts-task-terminal{margin:0;padding:10px 12px;border-radius:8px;background:#0f1020;color:#e4e4f0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;line-height:1.55;max-height:220px;overflow:auto;white-space:pre-wrap;word-break:break-word;border:1px solid rgba(139,92,246,.18)}.rts-task-section-output .rts-task-code{border-color:#10b98159}.rts-task-actions-list,.rts-task-prompts-list{display:flex;flex-direction:column;gap:6px;max-height:360px;overflow-y:auto;padding:2px}.rts-task-load-more{align-self:center;margin-top:4px;padding:5px 12px;border-radius:6px;border:1px solid rgba(139,92,246,.3);background:#8b5cf614;color:var(--rts-task-accent);font-size:11px;font-weight:600;cursor:pointer}.rts-task-load-more:hover{background:#8b5cf629}.rts-task-log{display:flex;gap:8px;align-items:baseline}.rts-task-log-time{color:#6b6f8a;flex-shrink:0}.rts-task-log-level{flex-shrink:0;min-width:34px;text-transform:uppercase;font-size:9.5px;font-weight:700;color:#a78bfa}.rts-task-log-warn .rts-task-log-level{color:var(--rts-task-warn)}.rts-task-log-error .rts-task-log-level,.rts-task-log-error .rts-task-log-message{color:#fb7185}.rts-task-live-text{margin-top:6px;padding-top:6px;border-top:1px dashed rgba(139,92,246,.25);color:#c4b5fd;white-space:pre-wrap}.rts-task-cursor{display:inline-block;width:6px;height:12px;margin-left:1px;vertical-align:text-bottom;background:#a78bfa;animation:rts-task-blink .8s step-end infinite}.rts-task-actions{display:flex;justify-content:flex-end}.rts-task-execute{display:inline-flex;align-items:center;gap:6px;padding:7px 16px;border:none;border-radius:8px;color:#fff;font-weight:600;font-size:12px;cursor:pointer;background:linear-gradient(135deg,var(--rts-task-accent-2),var(--rts-task-accent));box-shadow:0 4px 14px -4px #6366f199;transition:transform .15s ease,box-shadow .15s ease,opacity .15s ease}.rts-task-execute:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 6px 18px -4px #6366f1bf}.rts-task-execute:disabled{cursor:default;opacity:.6;box-shadow:none}.rts-task-spinner{width:11px;height:11px;border-radius:50%;border:2px solid rgba(255,255,255,.35);border-top-color:#fff;animation:rts-task-spin .8s linear infinite}.rts-task-placeholder{font-size:12px;color:var(--rts-text-secondary, #8a8fa3);font-style:italic}.rts-task-errors{display:flex;flex-direction:column;gap:4px}.rts-task-error{padding:6px 10px;border-radius:6px;font-size:12px;color:var(--rts-task-fail);background:#f43f5e14;border:1px solid rgba(244,63,94,.25)}@keyframes rts-task-spin{to{transform:rotate(360deg)}}@keyframes rts-task-pulse{0%,to{opacity:1}50%{opacity:.35}}@keyframes rts-task-blink{0%,to{opacity:1}50%{opacity:0}}@keyframes rts-task-fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: TaskActionThumbnailComponent, selector: "rtsee-task-action-thumbnail, task-action-thumbnail", inputs: ["action", "task"] }, { kind: "component", type: TaskActionPromptComponent, selector: "rtsee-task-action-prompt, task-action-prompt", inputs: ["prompt", "task"] }] }); }
2564
3492
  }
2565
3493
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RTSeeTaskComponent, decorators: [{
2566
3494
  type: Component,
2567
- args: [{ selector: 'rtsee-task', standalone: true, imports: [NgClass, DatePipe], template: "<div class=\"rts-task\" [ngClass]=\"statusClass\">\n @if (task) {\n <div class=\"rts-task-header\">\n <div class=\"rts-task-identity\">\n <span class=\"rts-task-icon\">\u2699</span>\n <div class=\"rts-task-titles\">\n <span class=\"rts-task-name\">{{ task.name || 'Task' }}</span>\n <span class=\"rts-task-id\" [title]=\"task.id\">#{{ task.id }}</span>\n </div>\n </div>\n <span class=\"rts-task-status\">\n <span class=\"rts-task-status-dot\"></span>\n {{ statusLabel }}\n </span>\n </div>\n\n <!-- Input -->\n <div class=\"rts-task-section\">\n <div class=\"rts-task-section-head\">\n <span class=\"rts-task-section-label\">Input</span>\n @if (inputJson) {\n <button type=\"button\" class=\"rts-task-copy\" (click)=\"copy('input')\">\n {{ copied === 'input' ? 'Copied' : 'Copy' }}\n </button>\n }\n </div>\n @if (inputJson) {\n <pre class=\"rts-task-code\"><code>{{ inputJson }}</code></pre>\n } @else if (task.loading) {\n <div class=\"rts-task-placeholder\">Loading\u2026</div>\n } @else {\n <div class=\"rts-task-placeholder\">No input</div>\n }\n </div>\n\n @if (allowExecute) {\n <div class=\"rts-task-actions\">\n <button type=\"button\"\n class=\"rts-task-execute\"\n [disabled]=\"!task.canExecute\"\n (click)=\"execute()\"\n >\n @if (task.isRunning || task.executeInProgress) {\n <span class=\"rts-task-spinner\"></span> Executing\u2026\n } @else if (task.isFailed) {\n <span class=\"pi pi-refresh\"></span> Retry\n } @else if (task.isFinished) {\n <span class=\"pi pi-check\"></span> Executed\n } @else {\n <span class=\"pi pi-play\"></span> Execute\n }\n </button>\n </div>\n }\n\n <!-- Logs -->\n @if (hasLogs || task.isRunning) {\n <div class=\"rts-task-section\">\n <div class=\"rts-task-section-head\">\n <span class=\"rts-task-section-label\">Logs</span>\n @if (task.isRunning) {\n <span class=\"rts-task-live\">LIVE</span>\n }\n </div>\n <div #logsContainer class=\"rts-task-terminal\">\n @for (log of task.logs; track $index) {\n <div class=\"rts-task-log\" [ngClass]=\"'rts-task-log-' + log.level\">\n <span class=\"rts-task-log-time\">{{ log.createdAt | date: 'HH:mm:ss' }}</span>\n <span class=\"rts-task-log-level\">{{ log.level }}</span>\n <span class=\"rts-task-log-message\">{{ log.message }}</span>\n </div>\n }\n @if (task.liveText) {\n <div class=\"rts-task-live-text\">{{ task.liveText }}@if (task.isRunning) {<span class=\"rts-task-cursor\"></span>}</div>\n } @else if (task.isRunning && !task.logs.length) {\n <div class=\"rts-task-log rts-task-log-info\">\n <span class=\"rts-task-log-message\">Waiting for logs\u2026</span>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Output -->\n @if (hasOutput) {\n <div class=\"rts-task-section rts-task-section-output\">\n <div class=\"rts-task-section-head\">\n <span class=\"rts-task-section-label\">Output</span>\n <button type=\"button\" class=\"rts-task-copy\" (click)=\"copy('output')\">\n {{ copied === 'output' ? 'Copied' : 'Copy' }}\n </button>\n </div>\n <pre class=\"rts-task-code\"><code>{{ outputJson }}</code></pre>\n </div>\n }\n\n @if (task.errors.length) {\n <div class=\"rts-task-errors\">\n @for (error of task.errors; track $index) {\n <div class=\"rts-task-error\">{{ error.message }}</div>\n }\n </div>\n }\n\n @if (task.requestError) {\n <div class=\"rts-task-errors\">\n <div class=\"rts-task-error\">{{ task.requestError }}</div>\n </div>\n }\n } @else {\n <div class=\"rts-task-placeholder\">Task is not available yet.</div>\n }\n</div>\n", styles: [":host{display:block;--rts-task-accent: #8b5cf6;--rts-task-accent-2: #6366f1;--rts-task-success: #10b981;--rts-task-fail: #f43f5e;--rts-task-warn: #f59e0b}.rts-task{position:relative;display:flex;flex-direction:column;gap:10px;padding:12px;border-radius:12px;background:linear-gradient(var(--rts-bg-secondary, #fff),var(--rts-bg-secondary, #fff)) padding-box,linear-gradient(135deg,#6366f173,#8b5cf626 60%,#a78bfa59) border-box;border:1px solid transparent;box-shadow:0 6px 24px -12px #6366f159;min-width:260px;max-width:100%;font-size:13px;transition:box-shadow .25s ease}.rts-task.rts-task-status-running{animation:rts-task-glow 2.2s ease-in-out infinite}@keyframes rts-task-glow{0%,to{box-shadow:0 6px 24px -12px #6366f159}50%{box-shadow:0 6px 28px -8px #8b5cf699}}.rts-task-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.rts-task-identity{display:flex;align-items:center;gap:8px;min-width:0}.rts-task-icon{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;flex-shrink:0;border-radius:8px;color:#fff;font-size:14px;background:linear-gradient(135deg,var(--rts-task-accent-2),var(--rts-task-accent))}.rts-task-status-running .rts-task-icon{animation:rts-task-spin 2.4s linear infinite}.rts-task-titles{display:flex;flex-direction:column;min-width:0}.rts-task-name{font-weight:600;color:var(--rts-text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.rts-task-id{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;color:var(--rts-text-secondary, #8a8fa3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:220px}.rts-task-status{display:inline-flex;align-items:center;gap:5px;padding:2px 8px;border-radius:999px;font-size:10px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;flex-shrink:0;color:var(--rts-task-accent);background:#8b5cf61f}.rts-task-status-dot{width:6px;height:6px;border-radius:50%;background:currentColor}.rts-task-status-running .rts-task-status-dot{animation:rts-task-pulse 1s ease-in-out infinite}.rts-task-status-success .rts-task-status{color:var(--rts-task-success);background:#10b9811f}.rts-task-status-fail .rts-task-status{color:var(--rts-task-fail);background:#f43f5e1f}.rts-task-section{display:flex;flex-direction:column;gap:4px;animation:rts-task-fade-in .3s ease}.rts-task-section-head{display:flex;align-items:center;justify-content:space-between}.rts-task-section-label{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--rts-text-secondary, #8a8fa3)}.rts-task-copy{border:none;background:transparent;color:var(--rts-task-accent);font-size:11px;cursor:pointer;padding:0 2px}.rts-task-copy:hover{text-decoration:underline}.rts-task-live{font-size:9px;font-weight:700;letter-spacing:.08em;color:var(--rts-task-fail);animation:rts-task-pulse 1.2s ease-in-out infinite}.rts-task-code,.rts-task-terminal{margin:0;padding:10px 12px;border-radius:8px;background:#0f1020;color:#e4e4f0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;line-height:1.55;max-height:220px;overflow:auto;white-space:pre-wrap;word-break:break-word;border:1px solid rgba(139,92,246,.18)}.rts-task-section-output .rts-task-code{border-color:#10b98159}.rts-task-log{display:flex;gap:8px;align-items:baseline}.rts-task-log-time{color:#6b6f8a;flex-shrink:0}.rts-task-log-level{flex-shrink:0;min-width:34px;text-transform:uppercase;font-size:9.5px;font-weight:700;color:#a78bfa}.rts-task-log-warn .rts-task-log-level{color:var(--rts-task-warn)}.rts-task-log-error .rts-task-log-level,.rts-task-log-error .rts-task-log-message{color:#fb7185}.rts-task-live-text{margin-top:6px;padding-top:6px;border-top:1px dashed rgba(139,92,246,.25);color:#c4b5fd;white-space:pre-wrap}.rts-task-cursor{display:inline-block;width:6px;height:12px;margin-left:1px;vertical-align:text-bottom;background:#a78bfa;animation:rts-task-blink .8s step-end infinite}.rts-task-actions{display:flex;justify-content:flex-end}.rts-task-execute{display:inline-flex;align-items:center;gap:6px;padding:7px 16px;border:none;border-radius:8px;color:#fff;font-weight:600;font-size:12px;cursor:pointer;background:linear-gradient(135deg,var(--rts-task-accent-2),var(--rts-task-accent));box-shadow:0 4px 14px -4px #6366f199;transition:transform .15s ease,box-shadow .15s ease,opacity .15s ease}.rts-task-execute:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 6px 18px -4px #6366f1bf}.rts-task-execute:disabled{cursor:default;opacity:.6;box-shadow:none}.rts-task-spinner{width:11px;height:11px;border-radius:50%;border:2px solid rgba(255,255,255,.35);border-top-color:#fff;animation:rts-task-spin .8s linear infinite}.rts-task-placeholder{font-size:12px;color:var(--rts-text-secondary, #8a8fa3);font-style:italic}.rts-task-errors{display:flex;flex-direction:column;gap:4px}.rts-task-error{padding:6px 10px;border-radius:6px;font-size:12px;color:var(--rts-task-fail);background:#f43f5e14;border:1px solid rgba(244,63,94,.25)}@keyframes rts-task-spin{to{transform:rotate(360deg)}}@keyframes rts-task-pulse{0%,to{opacity:1}50%{opacity:.35}}@keyframes rts-task-blink{0%,to{opacity:1}50%{opacity:0}}@keyframes rts-task-fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}\n"] }]
3495
+ args: [{ selector: 'rtsee-task', standalone: true, imports: [NgClass, TaskActionThumbnailComponent, TaskActionPromptComponent], template: "<div class=\"rts-task\" [ngClass]=\"statusClass\">\n @if (task) {\n <div class=\"rts-task-header\">\n <div class=\"rts-task-identity\">\n <span class=\"rts-task-icon\">\u2699</span>\n <div class=\"rts-task-titles\">\n <span class=\"rts-task-name\">{{ task.name || 'Task' }}</span>\n <span class=\"rts-task-id\" [title]=\"task.id\">#{{ task.id }}</span>\n </div>\n </div>\n <span class=\"rts-task-status\">\n <span class=\"rts-task-status-dot\"></span>\n {{ statusLabel }}\n </span>\n </div>\n\n <!-- Input -->\n <div class=\"rts-task-section\">\n <div class=\"rts-task-section-head\">\n <span class=\"rts-task-section-label\">Input</span>\n @if (inputJson) {\n <button type=\"button\" class=\"rts-task-copy\" (click)=\"copy('input')\">\n {{ copied === 'input' ? 'Copied' : 'Copy' }}\n </button>\n }\n </div>\n @if (inputJson) {\n <pre class=\"rts-task-code\"><code>{{ inputJson }}</code></pre>\n } @else if (task.loading) {\n <div class=\"rts-task-placeholder\">Loading\u2026</div>\n } @else {\n <div class=\"rts-task-placeholder\">No input</div>\n }\n </div>\n\n @if (allowExecute) {\n <div class=\"rts-task-actions\">\n <button type=\"button\"\n class=\"rts-task-execute\"\n [disabled]=\"!task.canExecute\"\n (click)=\"execute()\"\n >\n @if (task.isRunning || task.executeInProgress) {\n <span class=\"rts-task-spinner\"></span> Executing\u2026\n } @else if (task.isFailed) {\n <span class=\"pi pi-refresh\"></span> Retry\n } @else if (task.isFinished) {\n <span class=\"pi pi-check\"></span> Executed\n } @else {\n <span class=\"pi pi-play\"></span> Execute\n }\n </button>\n </div>\n }\n\n <!-- Prompts -->\n @if (hasPrompts) {\n <div class=\"rts-task-section\">\n <div class=\"rts-task-section-head\">\n <span class=\"rts-task-section-label\">Prompts</span>\n </div>\n <div class=\"rts-task-prompts-list\">\n @for (prompt of task.prompts; track prompt.id) {\n <rtsee-task-action-prompt\n [prompt]=\"prompt\"\n [task]=\"task\"\n ></rtsee-task-action-prompt>\n }\n </div>\n </div>\n }\n\n <!-- Actions (replaces Logs list) -->\n @if (hasActions || task.isRunning) {\n <div class=\"rts-task-section\">\n <div class=\"rts-task-section-head\">\n <span class=\"rts-task-section-label\">\n Actions @if (task.actionsTotal) { ({{ task.actions.length }}/{{ task.actionsTotal }}) }\n </span>\n @if (task.isRunning) {\n <span class=\"rts-task-live\">LIVE</span>\n }\n </div>\n <div #actionsContainer class=\"rts-task-actions-list\" (scroll)=\"onActionsScroll($event)\">\n @for (action of task.actions; track action.id) {\n <rtsee-task-action-thumbnail\n [action]=\"action\"\n [task]=\"task\"\n ></rtsee-task-action-thumbnail>\n }\n @if (task.isRunning && !task.actions.length) {\n <div class=\"rts-task-placeholder\">Starting actions\u2026</div>\n }\n @if (task.actionsLoading) {\n <div class=\"rts-task-placeholder\">Loading actions\u2026</div>\n }\n @if (task.hasMoreActions && !task.actionsLoading) {\n <button type=\"button\" class=\"rts-task-load-more\" (click)=\"loadMoreActions()\">\n Load more actions ({{ task.actions.length }}/{{ task.actionsTotal }})\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Output -->\n @if (hasOutput) {\n <div class=\"rts-task-section rts-task-section-output\">\n <div class=\"rts-task-section-head\">\n <span class=\"rts-task-section-label\">Output</span>\n <button type=\"button\" class=\"rts-task-copy\" (click)=\"copy('output')\">\n {{ copied === 'output' ? 'Copied' : 'Copy' }}\n </button>\n </div>\n <pre class=\"rts-task-code\"><code>{{ outputJson }}</code></pre>\n </div>\n }\n\n @if (task.errors.length) {\n <div class=\"rts-task-errors\">\n @for (error of task.errors; track $index) {\n <div class=\"rts-task-error\">{{ error.message }}</div>\n }\n </div>\n }\n\n @if (task.requestError) {\n <div class=\"rts-task-errors\">\n <div class=\"rts-task-error\">{{ task.requestError }}</div>\n </div>\n }\n } @else {\n <div class=\"rts-task-placeholder\">Task is not available yet.</div>\n }\n</div>\n", styles: [":host{display:block;--rts-task-accent: #8b5cf6;--rts-task-accent-2: #6366f1;--rts-task-success: #10b981;--rts-task-fail: #f43f5e;--rts-task-warn: #f59e0b}.rts-task{position:relative;display:flex;flex-direction:column;gap:10px;padding:12px;border-radius:12px;background:linear-gradient(var(--rts-bg-secondary, #fff),var(--rts-bg-secondary, #fff)) padding-box,linear-gradient(135deg,#6366f173,#8b5cf626 60%,#a78bfa59) border-box;border:1px solid transparent;box-shadow:0 6px 24px -12px #6366f159;min-width:260px;max-width:100%;font-size:13px;transition:box-shadow .25s ease}.rts-task.rts-task-status-running{animation:rts-task-glow 2.2s ease-in-out infinite}@keyframes rts-task-glow{0%,to{box-shadow:0 6px 24px -12px #6366f159}50%{box-shadow:0 6px 28px -8px #8b5cf699}}.rts-task-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.rts-task-identity{display:flex;align-items:center;gap:8px;min-width:0}.rts-task-icon{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;flex-shrink:0;border-radius:8px;color:#fff;font-size:14px;background:linear-gradient(135deg,var(--rts-task-accent-2),var(--rts-task-accent))}.rts-task-status-running .rts-task-icon{animation:rts-task-spin 2.4s linear infinite}.rts-task-titles{display:flex;flex-direction:column;min-width:0}.rts-task-name{font-weight:600;color:var(--rts-text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.rts-task-id{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;color:var(--rts-text-secondary, #8a8fa3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:220px}.rts-task-status{display:inline-flex;align-items:center;gap:5px;padding:2px 8px;border-radius:999px;font-size:10px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;flex-shrink:0;color:var(--rts-task-accent);background:#8b5cf61f}.rts-task-status-dot{width:6px;height:6px;border-radius:50%;background:currentColor}.rts-task-status-running .rts-task-status-dot{animation:rts-task-pulse 1s ease-in-out infinite}.rts-task-status-success .rts-task-status{color:var(--rts-task-success);background:#10b9811f}.rts-task-status-fail .rts-task-status{color:var(--rts-task-fail);background:#f43f5e1f}.rts-task-section{display:flex;flex-direction:column;gap:4px;animation:rts-task-fade-in .3s ease}.rts-task-section-head{display:flex;align-items:center;justify-content:space-between}.rts-task-section-label{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--rts-text-secondary, #8a8fa3)}.rts-task-copy{border:none;background:transparent;color:var(--rts-task-accent);font-size:11px;cursor:pointer;padding:0 2px}.rts-task-copy:hover{text-decoration:underline}.rts-task-live{font-size:9px;font-weight:700;letter-spacing:.08em;color:var(--rts-task-fail);animation:rts-task-pulse 1.2s ease-in-out infinite}.rts-task-code,.rts-task-terminal{margin:0;padding:10px 12px;border-radius:8px;background:#0f1020;color:#e4e4f0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;line-height:1.55;max-height:220px;overflow:auto;white-space:pre-wrap;word-break:break-word;border:1px solid rgba(139,92,246,.18)}.rts-task-section-output .rts-task-code{border-color:#10b98159}.rts-task-actions-list,.rts-task-prompts-list{display:flex;flex-direction:column;gap:6px;max-height:360px;overflow-y:auto;padding:2px}.rts-task-load-more{align-self:center;margin-top:4px;padding:5px 12px;border-radius:6px;border:1px solid rgba(139,92,246,.3);background:#8b5cf614;color:var(--rts-task-accent);font-size:11px;font-weight:600;cursor:pointer}.rts-task-load-more:hover{background:#8b5cf629}.rts-task-log{display:flex;gap:8px;align-items:baseline}.rts-task-log-time{color:#6b6f8a;flex-shrink:0}.rts-task-log-level{flex-shrink:0;min-width:34px;text-transform:uppercase;font-size:9.5px;font-weight:700;color:#a78bfa}.rts-task-log-warn .rts-task-log-level{color:var(--rts-task-warn)}.rts-task-log-error .rts-task-log-level,.rts-task-log-error .rts-task-log-message{color:#fb7185}.rts-task-live-text{margin-top:6px;padding-top:6px;border-top:1px dashed rgba(139,92,246,.25);color:#c4b5fd;white-space:pre-wrap}.rts-task-cursor{display:inline-block;width:6px;height:12px;margin-left:1px;vertical-align:text-bottom;background:#a78bfa;animation:rts-task-blink .8s step-end infinite}.rts-task-actions{display:flex;justify-content:flex-end}.rts-task-execute{display:inline-flex;align-items:center;gap:6px;padding:7px 16px;border:none;border-radius:8px;color:#fff;font-weight:600;font-size:12px;cursor:pointer;background:linear-gradient(135deg,var(--rts-task-accent-2),var(--rts-task-accent));box-shadow:0 4px 14px -4px #6366f199;transition:transform .15s ease,box-shadow .15s ease,opacity .15s ease}.rts-task-execute:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 6px 18px -4px #6366f1bf}.rts-task-execute:disabled{cursor:default;opacity:.6;box-shadow:none}.rts-task-spinner{width:11px;height:11px;border-radius:50%;border:2px solid rgba(255,255,255,.35);border-top-color:#fff;animation:rts-task-spin .8s linear infinite}.rts-task-placeholder{font-size:12px;color:var(--rts-text-secondary, #8a8fa3);font-style:italic}.rts-task-errors{display:flex;flex-direction:column;gap:4px}.rts-task-error{padding:6px 10px;border-radius:6px;font-size:12px;color:var(--rts-task-fail);background:#f43f5e14;border:1px solid rgba(244,63,94,.25)}@keyframes rts-task-spin{to{transform:rotate(360deg)}}@keyframes rts-task-pulse{0%,to{opacity:1}50%{opacity:.35}}@keyframes rts-task-blink{0%,to{opacity:1}50%{opacity:0}}@keyframes rts-task-fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}\n"] }]
2568
3496
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { task: [{
2569
3497
  type: Input
2570
3498
  }], message: [{
@@ -2575,9 +3503,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
2575
3503
  type: Input
2576
3504
  }], allowExecute: [{
2577
3505
  type: Input
2578
- }], logsContainer: [{
3506
+ }], actionsContainer: [{
2579
3507
  type: ViewChild,
2580
- args: ['logsContainer']
3508
+ args: ['actionsContainer']
2581
3509
  }] } });
2582
3510
 
2583
3511
  /**
@@ -3581,17 +4509,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
3581
4509
  }] } });
3582
4510
 
3583
4511
  class MessagesListComponent {
3584
- constructor(timeFormatService, scroller, document) {
4512
+ constructor(timeFormatService, scroller, hostRef, document) {
3585
4513
  this.timeFormatService = timeFormatService;
3586
4514
  this.scroller = scroller;
4515
+ this.hostRef = hostRef;
3587
4516
  this.document = document;
3588
4517
  this.messagesGroups = [];
3589
4518
  this.firstGroupedMessage = null;
3590
4519
  this.lastGroupedMessage = null;
3591
4520
  this.shouldStickToBottom = true;
4521
+ this.isWindowScroll = false;
3592
4522
  this.resizeObserver = null;
3593
4523
  this.onMediaCapture = null;
3594
4524
  this.initialScrollInterval = null;
4525
+ this.lastContainerScrollTop = 0;
4526
+ this.lastWindowScrollTop = 0;
4527
+ this.isFramed = false;
3595
4528
  this.RTSeeChatTypes = RTSeeChatTypes;
3596
4529
  this.bindScrollFunction = () => {
3597
4530
  this.shouldStickToBottom = true;
@@ -3604,29 +4537,66 @@ class MessagesListComponent {
3604
4537
  }
3605
4538
  };
3606
4539
  }
4540
+ get isStandalone() {
4541
+ return Boolean(this.chat?.isStandalone);
4542
+ }
3607
4543
  onWindowScroll(event) {
3608
- this.checkScrollPosition();
4544
+ this.updateScrollMode();
4545
+ if (!this.isWindowScroll) {
4546
+ return;
4547
+ }
3609
4548
  const verticalOffset = window.pageYOffset ||
3610
4549
  this.document.documentElement.scrollTop ||
3611
4550
  this.document.body.scrollTop ||
3612
4551
  0;
3613
- if (window.innerWidth >= COMMON_CONSTANTS.mobileBreakpoint) {
4552
+ const scrollingUp = verticalOffset < this.lastWindowScrollTop;
4553
+ const scrollingDown = verticalOffset > this.lastWindowScrollTop;
4554
+ this.lastWindowScrollTop = verticalOffset;
4555
+ if (this.isStandalone) {
4556
+ const el = this.contentBlock?.nativeElement || this.scrollContainer?.nativeElement;
4557
+ if (!el || el.getClientRects().length === 0) {
4558
+ return;
4559
+ }
4560
+ const rect = el.getBoundingClientRect();
4561
+ const viewportHeight = window.innerHeight || this.document.documentElement.clientHeight || 0;
4562
+ if (scrollingDown && rect.bottom - viewportHeight < 300) {
4563
+ this.onScroll();
4564
+ }
4565
+ else if (scrollingUp && rect.top > -300 && rect.top <= 300) {
4566
+ this.onScrolledToTop();
4567
+ }
4568
+ return;
4569
+ }
4570
+ if (!this.isShellMobileChatActive()) {
3614
4571
  return;
3615
4572
  }
3616
- if (verticalOffset < 300) {
4573
+ this.checkScrollPosition();
4574
+ if (scrollingUp && verticalOffset < 300) {
3617
4575
  this.onScrolledToTop();
3618
4576
  }
4577
+ else if (scrollingDown) {
4578
+ const scrollHeight = Math.max(this.document.documentElement.scrollHeight, this.document.body.scrollHeight);
4579
+ const clientHeight = window.innerHeight;
4580
+ if (scrollHeight - (verticalOffset + clientHeight) < 300) {
4581
+ this.onScroll();
4582
+ }
4583
+ }
3619
4584
  }
3620
4585
  onWindowResize() {
4586
+ this.updateScrollMode();
3621
4587
  if (this.shouldStickToBottom) {
3622
4588
  this.scrollToBottom();
3623
4589
  }
3624
4590
  }
3625
4591
  ngOnInit() {
4592
+ this.updateScrollMode();
3626
4593
  this.bindChatEvents(this.chat);
3627
4594
  this.groupMessages();
3628
4595
  }
3629
4596
  ngOnChanges(changes) {
4597
+ if (changes['chat'] || changes['isFramed']) {
4598
+ this.updateScrollMode();
4599
+ }
3630
4600
  if (changes['chat'] && !changes['chat'].firstChange) {
3631
4601
  const prevChat = changes['chat'].previousValue;
3632
4602
  this.unbindChatEvents(prevChat);
@@ -3636,7 +4606,8 @@ class MessagesListComponent {
3636
4606
  }
3637
4607
  }
3638
4608
  ngAfterViewInit() {
3639
- if (this.chat?.isStandalone) {
4609
+ this.updateScrollMode();
4610
+ if (this.isStandalone) {
3640
4611
  return;
3641
4612
  }
3642
4613
  this.enforceInitialScroll();
@@ -3681,8 +4652,25 @@ class MessagesListComponent {
3681
4652
  }
3682
4653
  }
3683
4654
  onContainerScroll(event) {
4655
+ this.updateScrollMode();
4656
+ if (this.isWindowScroll) {
4657
+ return;
4658
+ }
3684
4659
  this.checkScrollPosition();
3685
- this.onScroll();
4660
+ const el = this.scrollContainer?.nativeElement;
4661
+ if (!el) {
4662
+ return;
4663
+ }
4664
+ const scrollTop = el.scrollTop;
4665
+ const scrollingUp = scrollTop < this.lastContainerScrollTop;
4666
+ const scrollingDown = scrollTop > this.lastContainerScrollTop;
4667
+ this.lastContainerScrollTop = scrollTop;
4668
+ if (scrollingUp && scrollTop < 300) {
4669
+ this.onScrolledToTop();
4670
+ }
4671
+ else if (scrollingDown && el.scrollHeight - (scrollTop + el.clientHeight) < 300) {
4672
+ this.onScroll();
4673
+ }
3686
4674
  }
3687
4675
  onScrolledToTop() {
3688
4676
  if (this.chat.messagesLoadInProgress || this.chat.firstMessageLoaded) {
@@ -3691,36 +4679,26 @@ class MessagesListComponent {
3691
4679
  this.chat.loadRemoteMessages('back');
3692
4680
  }
3693
4681
  onScroll() {
3694
- if (this.chat.messagesLoadInProgress) {
4682
+ if (this.chat.messagesLoadInProgress || this.chat.lastMessageLoaded) {
3695
4683
  return;
3696
4684
  }
3697
4685
  this.chat.loadRemoteMessages('front');
3698
4686
  }
3699
4687
  scrollToBottom(immediate = false) {
3700
- if (this.chat?.isStandalone) {
4688
+ if (this.isStandalone) {
3701
4689
  return;
3702
4690
  }
4691
+ this.updateScrollMode();
3703
4692
  const performScroll = () => {
3704
- if (this.bottomAnchor?.nativeElement) {
3705
- try {
3706
- this.bottomAnchor.nativeElement.scrollIntoView({
3707
- block: 'end',
3708
- inline: 'nearest',
3709
- behavior: 'instant',
3710
- });
3711
- }
3712
- catch {
3713
- // ignore
3714
- }
3715
- }
3716
- if (window.innerWidth < COMMON_CONSTANTS.mobileBreakpoint) {
3717
- const target = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
4693
+ if (this.isShellMobileChatActive()) {
4694
+ const target = Math.max(this.document.documentElement.scrollHeight, this.document.body.scrollHeight);
3718
4695
  window.scrollTo({ top: target, behavior: 'instant' });
3719
4696
  this.scroller.scrollToPosition([0, target]);
3720
4697
  }
3721
- if (this.scrollContainer?.nativeElement) {
4698
+ else if (!this.isWindowScroll && this.scrollContainer?.nativeElement) {
3722
4699
  const el = this.scrollContainer.nativeElement;
3723
4700
  el.scrollTop = el.scrollHeight;
4701
+ this.lastContainerScrollTop = el.scrollTop;
3724
4702
  }
3725
4703
  };
3726
4704
  performScroll();
@@ -3743,11 +4721,11 @@ class MessagesListComponent {
3743
4721
  }
3744
4722
  isAtBottom() {
3745
4723
  const threshold = 150; // px threshold from bottom
3746
- if (window.innerWidth < COMMON_CONSTANTS.mobileBreakpoint) {
3747
- const scrollHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
4724
+ if (this.isShellMobileChatActive()) {
4725
+ const scrollHeight = Math.max(this.document.documentElement.scrollHeight, this.document.body.scrollHeight);
3748
4726
  const scrollTop = window.pageYOffset ||
3749
- document.documentElement.scrollTop ||
3750
- document.body.scrollTop ||
4727
+ this.document.documentElement.scrollTop ||
4728
+ this.document.body.scrollTop ||
3751
4729
  0;
3752
4730
  const clientHeight = window.innerHeight;
3753
4731
  return scrollHeight - (scrollTop + clientHeight) <= threshold;
@@ -3759,6 +4737,36 @@ class MessagesListComponent {
3759
4737
  return el.scrollHeight - (el.scrollTop + el.clientHeight) <= threshold;
3760
4738
  }
3761
4739
  }
4740
+ isMobileViewport() {
4741
+ return (typeof window !== 'undefined' &&
4742
+ window.innerWidth < COMMON_CONSTANTS.mobileBreakpoint);
4743
+ }
4744
+ isShellMobileChatActive() {
4745
+ if (this.isStandalone || this.isFramed || !this.isMobileViewport()) {
4746
+ return false;
4747
+ }
4748
+ const el = this.scrollContainer?.nativeElement || this.hostRef?.nativeElement;
4749
+ if (!el) {
4750
+ return false;
4751
+ }
4752
+ const shell = typeof el.closest === 'function' ? el.closest('.rtsee-shell') : null;
4753
+ if (shell && !shell.classList.contains('rtsee-shell-messenger-active')) {
4754
+ return false;
4755
+ }
4756
+ return el.getClientRects().length > 0;
4757
+ }
4758
+ computeIsWindowScroll() {
4759
+ if (this.isStandalone) {
4760
+ return true;
4761
+ }
4762
+ if (this.isFramed) {
4763
+ return false;
4764
+ }
4765
+ return this.isMobileViewport();
4766
+ }
4767
+ updateScrollMode() {
4768
+ this.isWindowScroll = this.computeIsWindowScroll();
4769
+ }
3762
4770
  enforceInitialScroll() {
3763
4771
  this.shouldStickToBottom = true;
3764
4772
  this.scrollToBottom();
@@ -3834,19 +4842,21 @@ class MessagesListComponent {
3834
4842
  this.firstGroupedMessage = this.chat.messages[0];
3835
4843
  this.lastGroupedMessage = this.chat.messages[this.chat.messages.length - 1];
3836
4844
  }
3837
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MessagesListComponent, deps: [{ token: TimeFormatHelperService }, { token: i2$1.ViewportScroller }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); }
3838
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MessagesListComponent, isStandalone: true, selector: "rtsee-messages-list", inputs: { chat: "chat", messenger: "messenger" }, host: { listeners: { "window:scroll": "onWindowScroll($event)", "window:resize": "onWindowResize()" } }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollBlock"], descendants: true }, { propertyName: "contentBlock", first: true, predicate: ["contentBlock"], descendants: true }, { propertyName: "bottomAnchor", first: true, predicate: ["bottomAnchor"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"rts-messages-list\"\n #scrollBlock\n infiniteScroll\n [infiniteScrollUpDistance]=\"2\"\n [infiniteScrollDistance]=\"2\"\n [infiniteScrollThrottle]=\"50\"\n [scrollWindow]=\"false\"\n (scrolledUp)=\"onScrolledToTop()\"\n (scroll)=\"onContainerScroll($event)\"\n [style.padding-bottom]=\"messenger.chatInputHeight + 'px'\"\n>\n <div class=\"rts-messages-list-inner\" #contentBlock>\n @for (messageGroup of messagesGroups; track messageGroup.id) {\n <div\n class=\"rts-messenger-message-wrapper\"\n data-ugc=\"true\"\n rel=\"ugc\"\n [ngClass]=\"{\n 'rts-messenger-message-wrapper-with-sender': messageGroup.senderVisible\n }\"\n >\n <div class=\"rts-messenger-message-inset\">\n <img [src]=\"messageGroup.sender.imageUrl\"\n class=\"rts-messenger-message-sender-image\"\n >\n </div>\n\n <div\n class=\"rts-messenger-message-sender-name\"\n itemprop=\"author\"\n itemscope\n itemtype=\"https://schema.org/Person\"\n >\n <p itemprop=\"name\">{{messageGroup.sender.name}}</p>\n </div>\n\n @for (message of messageGroup.messages; track message.id) {\n <rtsee-message [message]=\"message\"\n [messenger]=\"messenger\"\n [chat]=\"chat\"\n ></rtsee-message>\n }\n </div>\n }\n <div class=\"rts-messages-list-bottom-anchor\" #bottomAnchor></div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: InfiniteScrollDirective, selector: "[infiniteScroll], [infinite-scroll], [data-infinite-scroll]", inputs: ["infiniteScrollDistance", "infiniteScrollUpDistance", "infiniteScrollThrottle", "infiniteScrollDisabled", "infiniteScrollContainer", "scrollWindow", "immediateCheck", "horizontal", "alwaysCallback", "fromRoot"], outputs: ["scrolled", "scrolledUp"] }, { kind: "component", type: MessageComponent, selector: "rtsee-message", inputs: ["chat", "message", "member", "messenger"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
4845
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MessagesListComponent, deps: [{ token: TimeFormatHelperService }, { token: i1$3.ViewportScroller }, { token: i0.ElementRef }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); }
4846
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MessagesListComponent, isStandalone: true, selector: "rtsee-messages-list", inputs: { chat: "chat", messenger: "messenger", isFramed: "isFramed" }, host: { listeners: { "window:scroll": "onWindowScroll($event)", "window:resize": "onWindowResize()" } }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollBlock"], descendants: true }, { propertyName: "contentBlock", first: true, predicate: ["contentBlock"], descendants: true }, { propertyName: "bottomAnchor", first: true, predicate: ["bottomAnchor"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"rts-messages-list\"\n #scrollBlock\n infiniteScroll\n [infiniteScrollUpDistance]=\"2\"\n [infiniteScrollDistance]=\"2\"\n [infiniteScrollThrottle]=\"50\"\n [scrollWindow]=\"isWindowScroll\"\n [infiniteScrollContainer]=\"isWindowScroll ? null : scrollBlock\"\n (scrolledUp)=\"onScrolledToTop()\"\n (scrolled)=\"onScroll()\"\n (scroll)=\"onContainerScroll($event)\"\n [ngClass]=\"{\n 'rts-messages-list-scrollable': !isWindowScroll\n }\"\n [style.padding-bottom]=\"messenger.chatInputHeight + 'px'\"\n>\n <div class=\"rts-messages-list-inner\" #contentBlock>\n @for (messageGroup of messagesGroups; track messageGroup.id) {\n <div\n class=\"rts-messenger-message-wrapper\"\n data-ugc=\"true\"\n rel=\"ugc\"\n [ngClass]=\"{\n 'rts-messenger-message-wrapper-with-sender': messageGroup.senderVisible\n }\"\n >\n <div class=\"rts-messenger-message-inset\">\n <img [src]=\"messageGroup.sender.imageUrl\"\n class=\"rts-messenger-message-sender-image\"\n >\n </div>\n\n <div\n class=\"rts-messenger-message-sender-name\"\n itemprop=\"author\"\n itemscope\n itemtype=\"https://schema.org/Person\"\n >\n <p itemprop=\"name\">{{messageGroup.sender.name}}</p>\n </div>\n\n @for (message of messageGroup.messages; track message.id) {\n <rtsee-message [message]=\"message\"\n [messenger]=\"messenger\"\n [chat]=\"chat\"\n ></rtsee-message>\n }\n </div>\n }\n <div class=\"rts-messages-list-bottom-anchor\" #bottomAnchor></div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: InfiniteScrollDirective, selector: "[infiniteScroll], [infinite-scroll], [data-infinite-scroll]", inputs: ["infiniteScrollDistance", "infiniteScrollUpDistance", "infiniteScrollThrottle", "infiniteScrollDisabled", "infiniteScrollContainer", "scrollWindow", "immediateCheck", "horizontal", "alwaysCallback", "fromRoot"], outputs: ["scrolled", "scrolledUp"] }, { kind: "component", type: MessageComponent, selector: "rtsee-message", inputs: ["chat", "message", "member", "messenger"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
3839
4847
  }
3840
4848
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MessagesListComponent, decorators: [{
3841
4849
  type: Component,
3842
- args: [{ selector: 'rtsee-messages-list', imports: [InfiniteScrollDirective, MessageComponent, NgClass], standalone: true, template: "<div class=\"rts-messages-list\"\n #scrollBlock\n infiniteScroll\n [infiniteScrollUpDistance]=\"2\"\n [infiniteScrollDistance]=\"2\"\n [infiniteScrollThrottle]=\"50\"\n [scrollWindow]=\"false\"\n (scrolledUp)=\"onScrolledToTop()\"\n (scroll)=\"onContainerScroll($event)\"\n [style.padding-bottom]=\"messenger.chatInputHeight + 'px'\"\n>\n <div class=\"rts-messages-list-inner\" #contentBlock>\n @for (messageGroup of messagesGroups; track messageGroup.id) {\n <div\n class=\"rts-messenger-message-wrapper\"\n data-ugc=\"true\"\n rel=\"ugc\"\n [ngClass]=\"{\n 'rts-messenger-message-wrapper-with-sender': messageGroup.senderVisible\n }\"\n >\n <div class=\"rts-messenger-message-inset\">\n <img [src]=\"messageGroup.sender.imageUrl\"\n class=\"rts-messenger-message-sender-image\"\n >\n </div>\n\n <div\n class=\"rts-messenger-message-sender-name\"\n itemprop=\"author\"\n itemscope\n itemtype=\"https://schema.org/Person\"\n >\n <p itemprop=\"name\">{{messageGroup.sender.name}}</p>\n </div>\n\n @for (message of messageGroup.messages; track message.id) {\n <rtsee-message [message]=\"message\"\n [messenger]=\"messenger\"\n [chat]=\"chat\"\n ></rtsee-message>\n }\n </div>\n }\n <div class=\"rts-messages-list-bottom-anchor\" #bottomAnchor></div>\n </div>\n</div>\n" }]
3843
- }], ctorParameters: () => [{ type: TimeFormatHelperService }, { type: i2$1.ViewportScroller }, { type: Document, decorators: [{
4850
+ args: [{ selector: 'rtsee-messages-list', imports: [InfiniteScrollDirective, MessageComponent, NgClass], standalone: true, template: "<div class=\"rts-messages-list\"\n #scrollBlock\n infiniteScroll\n [infiniteScrollUpDistance]=\"2\"\n [infiniteScrollDistance]=\"2\"\n [infiniteScrollThrottle]=\"50\"\n [scrollWindow]=\"isWindowScroll\"\n [infiniteScrollContainer]=\"isWindowScroll ? null : scrollBlock\"\n (scrolledUp)=\"onScrolledToTop()\"\n (scrolled)=\"onScroll()\"\n (scroll)=\"onContainerScroll($event)\"\n [ngClass]=\"{\n 'rts-messages-list-scrollable': !isWindowScroll\n }\"\n [style.padding-bottom]=\"messenger.chatInputHeight + 'px'\"\n>\n <div class=\"rts-messages-list-inner\" #contentBlock>\n @for (messageGroup of messagesGroups; track messageGroup.id) {\n <div\n class=\"rts-messenger-message-wrapper\"\n data-ugc=\"true\"\n rel=\"ugc\"\n [ngClass]=\"{\n 'rts-messenger-message-wrapper-with-sender': messageGroup.senderVisible\n }\"\n >\n <div class=\"rts-messenger-message-inset\">\n <img [src]=\"messageGroup.sender.imageUrl\"\n class=\"rts-messenger-message-sender-image\"\n >\n </div>\n\n <div\n class=\"rts-messenger-message-sender-name\"\n itemprop=\"author\"\n itemscope\n itemtype=\"https://schema.org/Person\"\n >\n <p itemprop=\"name\">{{messageGroup.sender.name}}</p>\n </div>\n\n @for (message of messageGroup.messages; track message.id) {\n <rtsee-message [message]=\"message\"\n [messenger]=\"messenger\"\n [chat]=\"chat\"\n ></rtsee-message>\n }\n </div>\n }\n <div class=\"rts-messages-list-bottom-anchor\" #bottomAnchor></div>\n </div>\n</div>\n" }]
4851
+ }], ctorParameters: () => [{ type: TimeFormatHelperService }, { type: i1$3.ViewportScroller }, { type: i0.ElementRef }, { type: Document, decorators: [{
3844
4852
  type: Inject,
3845
4853
  args: [DOCUMENT]
3846
4854
  }] }], propDecorators: { chat: [{
3847
4855
  type: Input
3848
4856
  }], messenger: [{
3849
4857
  type: Input
4858
+ }], isFramed: [{
4859
+ type: Input
3850
4860
  }], scrollContainer: [{
3851
4861
  type: ViewChild,
3852
4862
  args: ['scrollBlock']
@@ -4288,75 +5298,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4288
5298
  args: ['messageTextarea']
4289
5299
  }] } });
4290
5300
 
4291
- class InviteLinkComponent {
4292
- constructor() {
4293
- this.inviteUrl = '';
4294
- this.disclaimer = 'Anyone who opens this link can join the chat.';
4295
- this.copied = false;
4296
- this.loading = false;
4297
- }
4298
- async ngOnInit() {
4299
- if (!this.inviteUrl && this.chatId && this.messenger) {
4300
- await this.loadInviteLink();
4301
- }
4302
- }
4303
- async loadInviteLink() {
4304
- if (!this.chatId || !this.messenger)
4305
- return;
4306
- this.loading = true;
4307
- try {
4308
- const result = await this.messenger.remoteActions.getChatInvitationLink.send({
4309
- chatId: this.chatId,
4310
- });
4311
- if (result?.invitationLink) {
4312
- this.inviteUrl = result.invitationLink;
4313
- }
4314
- }
4315
- catch (e) {
4316
- console.log('Failed to fetch chat invitation link', e);
4317
- }
4318
- finally {
4319
- this.loading = false;
4320
- }
4321
- }
4322
- async copyToClipboard() {
4323
- try {
4324
- await navigator.clipboard.writeText(this.inviteUrl);
4325
- this.copied = true;
4326
- setTimeout(() => {
4327
- this.copied = false;
4328
- }, 2000);
4329
- }
4330
- catch {
4331
- // Fallback for older browsers
4332
- const textArea = document.createElement('textarea');
4333
- textArea.value = this.inviteUrl;
4334
- document.body.appendChild(textArea);
4335
- textArea.select();
4336
- document.execCommand('copy');
4337
- document.body.removeChild(textArea);
4338
- this.copied = true;
4339
- setTimeout(() => {
4340
- this.copied = false;
4341
- }, 2000);
4342
- }
4343
- }
4344
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InviteLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4345
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: InviteLinkComponent, isStandalone: true, selector: "rtsee-invite-link", inputs: { inviteUrl: "inviteUrl", chatId: "chatId", messenger: "messenger", disclaimer: "disclaimer" }, ngImport: i0, template: "<div class=\"rts-invite-link\">\n <div class=\"rts-invite-link-info\">\n <span class=\"rts-invite-link-icon material-icons-outlined\">link</span>\n <div class=\"rts-invite-link-info-text\">\n <h4>Invite Link</h4>\n <p>{{ disclaimer }}</p>\n </div>\n </div>\n\n @if (loading) {\n <div class=\"rts-invite-link-loading\">\n <span class=\"material-icons-outlined rts-spin-icon\">autorenew</span>\n <span>Generating invite link...</span>\n </div>\n } @else {\n <div class=\"rts-invite-link-url-container\">\n <p-inputgroup>\n <input pInputText\n [value]=\"inviteUrl\"\n readonly\n class=\"rts-invite-link-url-input\"\n />\n <p-button [icon]=\"copied ? 'pi pi-check' : 'pi pi-copy'\"\n [severity]=\"copied ? 'success' : 'primary'\"\n (click)=\"copyToClipboard()\"\n [label]=\"copied ? 'Copied!' : 'Copy'\"\n />\n </p-inputgroup>\n </div>\n }\n</div>\n", dependencies: [{ kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }] }); }
4346
- }
4347
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InviteLinkComponent, decorators: [{
4348
- type: Component,
4349
- args: [{ selector: 'rtsee-invite-link', standalone: true, imports: [Button, InputText, InputGroup], template: "<div class=\"rts-invite-link\">\n <div class=\"rts-invite-link-info\">\n <span class=\"rts-invite-link-icon material-icons-outlined\">link</span>\n <div class=\"rts-invite-link-info-text\">\n <h4>Invite Link</h4>\n <p>{{ disclaimer }}</p>\n </div>\n </div>\n\n @if (loading) {\n <div class=\"rts-invite-link-loading\">\n <span class=\"material-icons-outlined rts-spin-icon\">autorenew</span>\n <span>Generating invite link...</span>\n </div>\n } @else {\n <div class=\"rts-invite-link-url-container\">\n <p-inputgroup>\n <input pInputText\n [value]=\"inviteUrl\"\n readonly\n class=\"rts-invite-link-url-input\"\n />\n <p-button [icon]=\"copied ? 'pi pi-check' : 'pi pi-copy'\"\n [severity]=\"copied ? 'success' : 'primary'\"\n (click)=\"copyToClipboard()\"\n [label]=\"copied ? 'Copied!' : 'Copy'\"\n />\n </p-inputgroup>\n </div>\n }\n</div>\n" }]
4350
- }], propDecorators: { inviteUrl: [{
4351
- type: Input
4352
- }], chatId: [{
4353
- type: Input
4354
- }], messenger: [{
4355
- type: Input
4356
- }], disclaimer: [{
4357
- type: Input
4358
- }] } });
4359
-
4360
5301
  class ViewportObserverDirective {
4361
5302
  constructor(element) {
4362
5303
  this.element = element;
@@ -4398,6 +5339,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4398
5339
 
4399
5340
  class ChatComponent {
4400
5341
  constructor() {
5342
+ this.isFramed = false;
4401
5343
  this.showInvite = false;
4402
5344
  }
4403
5345
  get isSoleAdmin() {
@@ -4443,7 +5385,7 @@ class ChatComponent {
4443
5385
  }
4444
5386
  }
4445
5387
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4446
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ChatComponent, isStandalone: true, selector: "rtsee-chat", inputs: { chat: "chat", chatData: "chatData", entity: "entity", messenger: "messenger" }, ngImport: i0, template: "<div class=\"rts-chat\"\n [ngClass]=\"{\n 'rts-chat-standalone': chat.isStandalone,\n 'rts-chat-in-viewport': chat.isInViewPort\n }\"\n rtseeViewportObserver\n (inViewport)=\"onInViewPortChange($event)\"\n>\n @if (isSoleAdmin) {\n <div class=\"rts-chat-sole-admin-banner\">\n <div class=\"rts-chat-sole-admin-header\">\n <div class=\"rts-chat-sole-admin-badge\">\n <span class=\"material-icons-outlined\">group_add</span>\n </div>\n <div class=\"rts-chat-sole-admin-info\">\n <h4>You are the only member in this chat</h4>\n <p>Invite people to start chatting</p>\n </div>\n <button class=\"rts-btn rts-btn-primary rts-chat-invite-toggle-btn\"\n (click)=\"toggleInvite()\"\n type=\"button\"\n >\n <span class=\"material-icons-outlined\">{{ showInvite ? 'expand_less' : 'person_add' }}</span>\n <span>{{ showInvite ? 'Hide Invite' : 'Invite to Chat' }}</span>\n </button>\n </div>\n\n @if (showInvite) {\n <div class=\"rts-chat-sole-admin-invite\">\n <rtsee-invite-link\n [chatId]=\"chat.id\"\n [messenger]=\"messenger\"\n ></rtsee-invite-link>\n </div>\n }\n </div>\n }\n\n <div class=\"rts-chat-footer-container\">\n <div class=\"rts-chat-footer-container-inner\">\n <rtsee-chat-input [messenger]=\"messenger\" [chat]=\"chat\"></rtsee-chat-input>\n </div>\n </div>\n <div class=\"rts-chat-body-container\">\n <rtsee-messages-list [messenger]=\"messenger\" [chat]=\"chat\"></rtsee-messages-list>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: MessagesListComponent, selector: "rtsee-messages-list", inputs: ["chat", "messenger"] }, { kind: "component", type: ChatInputComponent, selector: "rtsee-chat-input", inputs: ["messenger", "chat"] }, { kind: "component", type: InviteLinkComponent, selector: "rtsee-invite-link", inputs: ["inviteUrl", "chatId", "messenger", "disclaimer"] }, { kind: "directive", type: ViewportObserverDirective, selector: "[rtseeViewportObserver]", outputs: ["inViewport"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
5388
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ChatComponent, isStandalone: true, selector: "rtsee-chat", inputs: { chat: "chat", chatData: "chatData", entity: "entity", messenger: "messenger", isFramed: "isFramed" }, ngImport: i0, template: "<div class=\"rts-chat\"\n [ngClass]=\"{\n 'rts-chat-standalone': chat.isStandalone,\n 'rts-chat-in-viewport': chat.isInViewPort,\n 'rts-chat-framed': isFramed\n }\"\n rtseeViewportObserver\n (inViewport)=\"onInViewPortChange($event)\"\n>\n @if (isSoleAdmin) {\n <div class=\"rts-chat-sole-admin-banner\">\n <div class=\"rts-chat-sole-admin-header\">\n <div class=\"rts-chat-sole-admin-badge\">\n <span class=\"material-icons-outlined\">group_add</span>\n </div>\n <div class=\"rts-chat-sole-admin-info\">\n <h4>You are the only member in this chat</h4>\n <p>Invite people to start chatting</p>\n </div>\n <button class=\"rts-btn rts-btn-primary rts-chat-invite-toggle-btn\"\n (click)=\"toggleInvite()\"\n type=\"button\"\n >\n <span class=\"material-icons-outlined\">{{ showInvite ? 'expand_less' : 'person_add' }}</span>\n <span>{{ showInvite ? 'Hide Invite' : 'Invite to Chat' }}</span>\n </button>\n </div>\n\n @if (showInvite) {\n <div class=\"rts-chat-sole-admin-invite\">\n <rtsee-invite-link\n [chatId]=\"chat.id\"\n [messenger]=\"messenger\"\n ></rtsee-invite-link>\n </div>\n }\n </div>\n }\n\n <div class=\"rts-chat-footer-container\">\n <div class=\"rts-chat-footer-container-inner\">\n <rtsee-chat-input [messenger]=\"messenger\" [chat]=\"chat\"></rtsee-chat-input>\n </div>\n </div>\n <div class=\"rts-chat-body-container\">\n <rtsee-messages-list [messenger]=\"messenger\" [chat]=\"chat\" [isFramed]=\"isFramed\"></rtsee-messages-list>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: MessagesListComponent, selector: "rtsee-messages-list", inputs: ["chat", "messenger", "isFramed"] }, { kind: "component", type: ChatInputComponent, selector: "rtsee-chat-input", inputs: ["messenger", "chat"] }, { kind: "component", type: InviteLinkComponent, selector: "rtsee-invite-link", inputs: ["inviteUrl", "chatId", "messenger", "disclaimer"] }, { kind: "directive", type: ViewportObserverDirective, selector: "[rtseeViewportObserver]", outputs: ["inViewport"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
4447
5389
  }
4448
5390
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatComponent, decorators: [{
4449
5391
  type: Component,
@@ -4453,7 +5395,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4453
5395
  InviteLinkComponent,
4454
5396
  ViewportObserverDirective,
4455
5397
  NgClass,
4456
- ], standalone: true, template: "<div class=\"rts-chat\"\n [ngClass]=\"{\n 'rts-chat-standalone': chat.isStandalone,\n 'rts-chat-in-viewport': chat.isInViewPort\n }\"\n rtseeViewportObserver\n (inViewport)=\"onInViewPortChange($event)\"\n>\n @if (isSoleAdmin) {\n <div class=\"rts-chat-sole-admin-banner\">\n <div class=\"rts-chat-sole-admin-header\">\n <div class=\"rts-chat-sole-admin-badge\">\n <span class=\"material-icons-outlined\">group_add</span>\n </div>\n <div class=\"rts-chat-sole-admin-info\">\n <h4>You are the only member in this chat</h4>\n <p>Invite people to start chatting</p>\n </div>\n <button class=\"rts-btn rts-btn-primary rts-chat-invite-toggle-btn\"\n (click)=\"toggleInvite()\"\n type=\"button\"\n >\n <span class=\"material-icons-outlined\">{{ showInvite ? 'expand_less' : 'person_add' }}</span>\n <span>{{ showInvite ? 'Hide Invite' : 'Invite to Chat' }}</span>\n </button>\n </div>\n\n @if (showInvite) {\n <div class=\"rts-chat-sole-admin-invite\">\n <rtsee-invite-link\n [chatId]=\"chat.id\"\n [messenger]=\"messenger\"\n ></rtsee-invite-link>\n </div>\n }\n </div>\n }\n\n <div class=\"rts-chat-footer-container\">\n <div class=\"rts-chat-footer-container-inner\">\n <rtsee-chat-input [messenger]=\"messenger\" [chat]=\"chat\"></rtsee-chat-input>\n </div>\n </div>\n <div class=\"rts-chat-body-container\">\n <rtsee-messages-list [messenger]=\"messenger\" [chat]=\"chat\"></rtsee-messages-list>\n </div>\n</div>\n" }]
5398
+ ], standalone: true, template: "<div class=\"rts-chat\"\n [ngClass]=\"{\n 'rts-chat-standalone': chat.isStandalone,\n 'rts-chat-in-viewport': chat.isInViewPort,\n 'rts-chat-framed': isFramed\n }\"\n rtseeViewportObserver\n (inViewport)=\"onInViewPortChange($event)\"\n>\n @if (isSoleAdmin) {\n <div class=\"rts-chat-sole-admin-banner\">\n <div class=\"rts-chat-sole-admin-header\">\n <div class=\"rts-chat-sole-admin-badge\">\n <span class=\"material-icons-outlined\">group_add</span>\n </div>\n <div class=\"rts-chat-sole-admin-info\">\n <h4>You are the only member in this chat</h4>\n <p>Invite people to start chatting</p>\n </div>\n <button class=\"rts-btn rts-btn-primary rts-chat-invite-toggle-btn\"\n (click)=\"toggleInvite()\"\n type=\"button\"\n >\n <span class=\"material-icons-outlined\">{{ showInvite ? 'expand_less' : 'person_add' }}</span>\n <span>{{ showInvite ? 'Hide Invite' : 'Invite to Chat' }}</span>\n </button>\n </div>\n\n @if (showInvite) {\n <div class=\"rts-chat-sole-admin-invite\">\n <rtsee-invite-link\n [chatId]=\"chat.id\"\n [messenger]=\"messenger\"\n ></rtsee-invite-link>\n </div>\n }\n </div>\n }\n\n <div class=\"rts-chat-footer-container\">\n <div class=\"rts-chat-footer-container-inner\">\n <rtsee-chat-input [messenger]=\"messenger\" [chat]=\"chat\"></rtsee-chat-input>\n </div>\n </div>\n <div class=\"rts-chat-body-container\">\n <rtsee-messages-list [messenger]=\"messenger\" [chat]=\"chat\" [isFramed]=\"isFramed\"></rtsee-messages-list>\n </div>\n</div>\n" }]
4457
5399
  }], propDecorators: { chat: [{
4458
5400
  type: Input
4459
5401
  }], chatData: [{
@@ -4462,6 +5404,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4462
5404
  type: Input
4463
5405
  }], messenger: [{
4464
5406
  type: Input
5407
+ }], isFramed: [{
5408
+ type: Input
4465
5409
  }] } });
4466
5410
 
4467
5411
  class ManageProfileComponent {
@@ -4833,11 +5777,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4833
5777
  }] } });
4834
5778
 
4835
5779
  class MessengerComponent {
5780
+ constructor() {
5781
+ this.isFramed = false;
5782
+ this.RTSeeTextLabelKeys = RTSeeTextLabelKeys;
5783
+ }
4836
5784
  onScroll() {
4837
5785
  void this.messenger.loadChats();
4838
5786
  }
4839
5787
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MessengerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4840
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MessengerComponent, isStandalone: true, selector: "rtsee-messenger", inputs: { messenger: "messenger" }, ngImport: i0, template: "<div class=\"rts-messenger rts-theme-dark\" [ngClass]=\"{\n 'rts-messenger-header-expanded': messenger.openedProfile || messenger.openedChatDetails,\n 'rts-messenger-folded': messenger.folded,\n 'rts-messenger-overlay-window': messenger.isOverlayPageOpened\n}\">\n @if (messenger.manageProfile) {\n <div class=\"rts-manage-profile\">\n <rtsee-manage-profile [manageProfile]=\"messenger.manageProfile\"\n [messenger]=\"messenger\"\n ></rtsee-manage-profile>\n </div>\n }\n\n @if (messenger.isPaymentPageOpened) {\n <div class=\"rts-payment-page-container\">\n <rtsee-payment-page [messenger]=\"messenger\" theme=\"dark\"></rtsee-payment-page>\n </div>\n }\n\n @if (messenger.isPaymentValidationPageOpened) {\n <div class=\"rts-payment-page-container\">\n <rtsee-payment-validation-page [messenger]=\"messenger\" theme=\"dark\"></rtsee-payment-validation-page>\n </div>\n }\n\n @if (messenger.isManagePlanPageOpened) {\n <div class=\"rts-payment-page-container\">\n <rtsee-manage-plan [messenger]=\"messenger\"></rtsee-manage-plan>\n </div>\n }\n\n <div class=\"rts-messenger-header-container\">\n <rtsee-messenger-header [messenger]=\"messenger\"\n ></rtsee-messenger-header>\n </div>\n <div class=\"rts-messenger-body-container\"\n infiniteScroll\n [infiniteScrollDistance]=\"2\"\n [infiniteScrollThrottle]=\"50\"\n [scrollWindow]=\"false\"\n (scrolled)=\"onScroll()\"\n >\n @if (messenger.openedChat) {\n <rtsee-chat [messenger]=\"messenger\" [chat]=\"messenger.openedChat\"></rtsee-chat>\n } @else if (!messenger.openedChat) {\n <rtsee-chats-list [chats]=\"messenger.chats\" [messenger]=\"messenger\"></rtsee-chats-list>\n } @else if (messenger.openedProfile) {\n <rtsee-profile></rtsee-profile>\n }\n @if (messenger.loadingChatsInProgress) {\n <rtsee-preloader [diameter]=\"50\" ></rtsee-preloader>\n }\n </div>\n</div>\n", dependencies: [{ kind: "component", type: MessengerHeaderComponent, selector: "rtsee-messenger-header", inputs: ["messenger"] }, { kind: "directive", type: InfiniteScrollDirective, selector: "[infiniteScroll], [infinite-scroll], [data-infinite-scroll]", inputs: ["infiniteScrollDistance", "infiniteScrollUpDistance", "infiniteScrollThrottle", "infiniteScrollDisabled", "infiniteScrollContainer", "scrollWindow", "immediateCheck", "horizontal", "alwaysCallback", "fromRoot"], outputs: ["scrolled", "scrolledUp"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ChatsListComponent, selector: "rtsee-chats-list", inputs: ["messenger", "chats"] }, { kind: "component", type: ChatComponent, selector: "rtsee-chat", inputs: ["chat", "chatData", "entity", "messenger"] }, { kind: "component", type: PreloaderComponent, selector: "rtsee-preloader", inputs: ["diameter", "color"] }, { kind: "component", type: ProfileComponent, selector: "rtsee-profile", inputs: ["messenger", "peer"] }, { kind: "component", type: ManageProfileComponent, selector: "rtsee-manage-profile", inputs: ["messenger", "manageProfile"] }, { kind: "component", type: PaymentPageComponent, selector: "rtsee-payment-page", inputs: ["messenger", "theme"] }, { kind: "component", type: PaymentValidationPageComponent, selector: "rtsee-payment-validation-page", inputs: ["messenger", "theme"] }, { kind: "component", type: ManagePlanComponent, selector: "rtsee-manage-plan", inputs: ["messenger"] }] }); }
5788
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MessengerComponent, isStandalone: true, selector: "rtsee-messenger", inputs: { messenger: "messenger", isFramed: "isFramed" }, ngImport: i0, template: "<div class=\"rts-messenger rts-theme-dark\" [ngClass]=\"{\n 'rts-messenger-header-expanded': messenger.openedProfile || messenger.openedChatDetails || messenger.manageChatInfo || messenger.inviteUserOpened,\n 'rts-messenger-folded': messenger.folded,\n 'rts-messenger-overlay-window': messenger.isOverlayPageOpened,\n 'rts-messenger-framed': isFramed\n}\">\n @if (messenger.pendingInviteToken) {\n <div class=\"rts-invite-popup-modal\">\n <div class=\"rts-invite-popup-content\">\n <span class=\"material-icons-outlined rts-invite-popup-icon\">mail_outline</span>\n <div class=\"rts-invite-popup-text\">\n @if (messenger.pendingInviteInfo?.inviter?.name) {\n <strong>{{ messenger.pendingInviteInfo?.inviter?.name }}</strong>\n <span> {{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_POPUP_TEXT] }}</span>\n @if (messenger.pendingInviteInfo?.chat?.name) {\n <span class=\"rts-invite-popup-chat-name\"> ({{ messenger.pendingInviteInfo?.chat?.name }})</span>\n }\n } @else {\n <span>{{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_POPUP_GENERIC_TEXT] }}</span>\n }\n </div>\n </div>\n <div class=\"rts-invite-popup-actions\">\n <button type=\"button\"\n class=\"rts-btn rts-btn-secondary rts-invite-popup-btn\"\n [disabled]=\"messenger.inviteJoinInProgress\"\n (click)=\"messenger.ignoreChatInvitation()\"\n >\n {{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_IGNORE_BUTTON] }}\n </button>\n <button type=\"button\"\n class=\"rts-btn rts-btn-primary rts-invite-popup-btn\"\n [disabled]=\"messenger.inviteJoinInProgress\"\n (click)=\"messenger.acceptChatInvitation()\"\n >\n {{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_JOIN_BUTTON] }}\n </button>\n </div>\n </div>\n }\n @if (messenger.manageProfile) {\n <div class=\"rts-manage-profile\">\n <rtsee-manage-profile [manageProfile]=\"messenger.manageProfile\"\n [messenger]=\"messenger\"\n ></rtsee-manage-profile>\n </div>\n }\n\n @if (messenger.isPaymentPageOpened) {\n <div class=\"rts-payment-page-container\">\n <rtsee-payment-page [messenger]=\"messenger\" theme=\"dark\"></rtsee-payment-page>\n </div>\n }\n\n @if (messenger.isPaymentValidationPageOpened) {\n <div class=\"rts-payment-page-container\">\n <rtsee-payment-validation-page [messenger]=\"messenger\" theme=\"dark\"></rtsee-payment-validation-page>\n </div>\n }\n\n @if (messenger.isManagePlanPageOpened) {\n <div class=\"rts-payment-page-container\">\n <rtsee-manage-plan [messenger]=\"messenger\"></rtsee-manage-plan>\n </div>\n }\n <div class=\"rts-messenger-body-container\"\n infiniteScroll\n [infiniteScrollDistance]=\"2\"\n [infiniteScrollThrottle]=\"50\"\n [scrollWindow]=\"false\"\n (scrolled)=\"onScroll()\"\n >\n @if (messenger.openedChat) {\n <rtsee-chat [messenger]=\"messenger\" [chat]=\"messenger.openedChat\" [isFramed]=\"isFramed\"></rtsee-chat>\n } @else if (!messenger.openedChat) {\n <rtsee-chats-list [chats]=\"messenger.chats\" [messenger]=\"messenger\"></rtsee-chats-list>\n } @else if (messenger.openedProfile) {\n <rtsee-profile></rtsee-profile>\n }\n @if (messenger.loadingChatsInProgress) {\n <rtsee-preloader [diameter]=\"50\" ></rtsee-preloader>\n }\n </div>\n <div class=\"rts-messenger-header-container\">\n <rtsee-messenger-header [messenger]=\"messenger\"\n ></rtsee-messenger-header>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: MessengerHeaderComponent, selector: "rtsee-messenger-header", inputs: ["messenger"] }, { kind: "directive", type: InfiniteScrollDirective, selector: "[infiniteScroll], [infinite-scroll], [data-infinite-scroll]", inputs: ["infiniteScrollDistance", "infiniteScrollUpDistance", "infiniteScrollThrottle", "infiniteScrollDisabled", "infiniteScrollContainer", "scrollWindow", "immediateCheck", "horizontal", "alwaysCallback", "fromRoot"], outputs: ["scrolled", "scrolledUp"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ChatsListComponent, selector: "rtsee-chats-list", inputs: ["messenger", "chats"] }, { kind: "component", type: ChatComponent, selector: "rtsee-chat", inputs: ["chat", "chatData", "entity", "messenger", "isFramed"] }, { kind: "component", type: PreloaderComponent, selector: "rtsee-preloader", inputs: ["diameter", "color"] }, { kind: "component", type: ProfileComponent, selector: "rtsee-profile", inputs: ["messenger", "peer"] }, { kind: "component", type: ManageProfileComponent, selector: "rtsee-manage-profile", inputs: ["messenger", "manageProfile"] }, { kind: "component", type: PaymentPageComponent, selector: "rtsee-payment-page", inputs: ["messenger", "theme"] }, { kind: "component", type: PaymentValidationPageComponent, selector: "rtsee-payment-validation-page", inputs: ["messenger", "theme"] }, { kind: "component", type: ManagePlanComponent, selector: "rtsee-manage-plan", inputs: ["messenger"] }] }); }
4841
5789
  }
4842
5790
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MessengerComponent, decorators: [{
4843
5791
  type: Component,
@@ -4855,9 +5803,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4855
5803
  PaymentPageComponent,
4856
5804
  PaymentValidationPageComponent,
4857
5805
  ManagePlanComponent,
4858
- ], standalone: true, template: "<div class=\"rts-messenger rts-theme-dark\" [ngClass]=\"{\n 'rts-messenger-header-expanded': messenger.openedProfile || messenger.openedChatDetails,\n 'rts-messenger-folded': messenger.folded,\n 'rts-messenger-overlay-window': messenger.isOverlayPageOpened\n}\">\n @if (messenger.manageProfile) {\n <div class=\"rts-manage-profile\">\n <rtsee-manage-profile [manageProfile]=\"messenger.manageProfile\"\n [messenger]=\"messenger\"\n ></rtsee-manage-profile>\n </div>\n }\n\n @if (messenger.isPaymentPageOpened) {\n <div class=\"rts-payment-page-container\">\n <rtsee-payment-page [messenger]=\"messenger\" theme=\"dark\"></rtsee-payment-page>\n </div>\n }\n\n @if (messenger.isPaymentValidationPageOpened) {\n <div class=\"rts-payment-page-container\">\n <rtsee-payment-validation-page [messenger]=\"messenger\" theme=\"dark\"></rtsee-payment-validation-page>\n </div>\n }\n\n @if (messenger.isManagePlanPageOpened) {\n <div class=\"rts-payment-page-container\">\n <rtsee-manage-plan [messenger]=\"messenger\"></rtsee-manage-plan>\n </div>\n }\n\n <div class=\"rts-messenger-header-container\">\n <rtsee-messenger-header [messenger]=\"messenger\"\n ></rtsee-messenger-header>\n </div>\n <div class=\"rts-messenger-body-container\"\n infiniteScroll\n [infiniteScrollDistance]=\"2\"\n [infiniteScrollThrottle]=\"50\"\n [scrollWindow]=\"false\"\n (scrolled)=\"onScroll()\"\n >\n @if (messenger.openedChat) {\n <rtsee-chat [messenger]=\"messenger\" [chat]=\"messenger.openedChat\"></rtsee-chat>\n } @else if (!messenger.openedChat) {\n <rtsee-chats-list [chats]=\"messenger.chats\" [messenger]=\"messenger\"></rtsee-chats-list>\n } @else if (messenger.openedProfile) {\n <rtsee-profile></rtsee-profile>\n }\n @if (messenger.loadingChatsInProgress) {\n <rtsee-preloader [diameter]=\"50\" ></rtsee-preloader>\n }\n </div>\n</div>\n" }]
5806
+ ], standalone: true, template: "<div class=\"rts-messenger rts-theme-dark\" [ngClass]=\"{\n 'rts-messenger-header-expanded': messenger.openedProfile || messenger.openedChatDetails || messenger.manageChatInfo || messenger.inviteUserOpened,\n 'rts-messenger-folded': messenger.folded,\n 'rts-messenger-overlay-window': messenger.isOverlayPageOpened,\n 'rts-messenger-framed': isFramed\n}\">\n @if (messenger.pendingInviteToken) {\n <div class=\"rts-invite-popup-modal\">\n <div class=\"rts-invite-popup-content\">\n <span class=\"material-icons-outlined rts-invite-popup-icon\">mail_outline</span>\n <div class=\"rts-invite-popup-text\">\n @if (messenger.pendingInviteInfo?.inviter?.name) {\n <strong>{{ messenger.pendingInviteInfo?.inviter?.name }}</strong>\n <span> {{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_POPUP_TEXT] }}</span>\n @if (messenger.pendingInviteInfo?.chat?.name) {\n <span class=\"rts-invite-popup-chat-name\"> ({{ messenger.pendingInviteInfo?.chat?.name }})</span>\n }\n } @else {\n <span>{{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_POPUP_GENERIC_TEXT] }}</span>\n }\n </div>\n </div>\n <div class=\"rts-invite-popup-actions\">\n <button type=\"button\"\n class=\"rts-btn rts-btn-secondary rts-invite-popup-btn\"\n [disabled]=\"messenger.inviteJoinInProgress\"\n (click)=\"messenger.ignoreChatInvitation()\"\n >\n {{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_IGNORE_BUTTON] }}\n </button>\n <button type=\"button\"\n class=\"rts-btn rts-btn-primary rts-invite-popup-btn\"\n [disabled]=\"messenger.inviteJoinInProgress\"\n (click)=\"messenger.acceptChatInvitation()\"\n >\n {{ messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_JOIN_BUTTON] }}\n </button>\n </div>\n </div>\n }\n @if (messenger.manageProfile) {\n <div class=\"rts-manage-profile\">\n <rtsee-manage-profile [manageProfile]=\"messenger.manageProfile\"\n [messenger]=\"messenger\"\n ></rtsee-manage-profile>\n </div>\n }\n\n @if (messenger.isPaymentPageOpened) {\n <div class=\"rts-payment-page-container\">\n <rtsee-payment-page [messenger]=\"messenger\" theme=\"dark\"></rtsee-payment-page>\n </div>\n }\n\n @if (messenger.isPaymentValidationPageOpened) {\n <div class=\"rts-payment-page-container\">\n <rtsee-payment-validation-page [messenger]=\"messenger\" theme=\"dark\"></rtsee-payment-validation-page>\n </div>\n }\n\n @if (messenger.isManagePlanPageOpened) {\n <div class=\"rts-payment-page-container\">\n <rtsee-manage-plan [messenger]=\"messenger\"></rtsee-manage-plan>\n </div>\n }\n <div class=\"rts-messenger-body-container\"\n infiniteScroll\n [infiniteScrollDistance]=\"2\"\n [infiniteScrollThrottle]=\"50\"\n [scrollWindow]=\"false\"\n (scrolled)=\"onScroll()\"\n >\n @if (messenger.openedChat) {\n <rtsee-chat [messenger]=\"messenger\" [chat]=\"messenger.openedChat\" [isFramed]=\"isFramed\"></rtsee-chat>\n } @else if (!messenger.openedChat) {\n <rtsee-chats-list [chats]=\"messenger.chats\" [messenger]=\"messenger\"></rtsee-chats-list>\n } @else if (messenger.openedProfile) {\n <rtsee-profile></rtsee-profile>\n }\n @if (messenger.loadingChatsInProgress) {\n <rtsee-preloader [diameter]=\"50\" ></rtsee-preloader>\n }\n </div>\n <div class=\"rts-messenger-header-container\">\n <rtsee-messenger-header [messenger]=\"messenger\"\n ></rtsee-messenger-header>\n </div>\n</div>\n" }]
4859
5807
  }], propDecorators: { messenger: [{
4860
5808
  type: Input
5809
+ }], isFramed: [{
5810
+ type: Input
4861
5811
  }] } });
4862
5812
 
4863
5813
  class BaseEventWidgetComponent {
@@ -5087,6 +6037,245 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
5087
6037
  args: [{ selector: 'rtsee-slide-number-changed-widget', standalone: true, imports: [CommonModule], template: "<div class=\"rtsee-event-widget slide-number-changed-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge slide-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\"\n >view_carousel</span\n >\n <span class=\"widget-badge-label\">\n Slide {{ slideNumber }}\n @if (totalSlides) {\n / {{ totalSlides }}\n }\n </span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently viewing slide' : 'Time spent on this slide'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media\">\n @if (imageUrl) {\n <img\n [src]=\"imageUrl\"\n [alt]=\"slideText\"\n class=\"widget-thumbnail-image\"\n />\n } @else {\n <div class=\"widget-thumbnail-placeholder slide-placeholder\">\n <span class=\"material-icons-outlined\">image</span>\n </div>\n }\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"slideText\">{{ slideText }}</span>\n @if (storyName) {\n @if (storyUrl) {\n <a\n [href]=\"storyUrl\"\n target=\"_blank\"\n class=\"widget-story-link\"\n [title]=\"storyName\"\n >\n <span class=\"widget-story-name\">{{ storyName }}</span>\n <span class=\"material-icons-outlined external-icon\"\n >open_in_new</span\n >\n </a>\n } @else {\n <span class=\"widget-story-name\">{{ storyName }}</span>\n }\n }\n </div>\n </div>\n</div>\n" }]
5088
6038
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
5089
6039
 
6040
+ class ProfileOpenedWidgetComponent extends BaseEventWidgetComponent {
6041
+ constructor(cd) {
6042
+ super(cd);
6043
+ }
6044
+ get userName() {
6045
+ const raw = this.event?.payload?.text ||
6046
+ this.event?.payload?.data?.name ||
6047
+ 'User Profile';
6048
+ return String(raw).replace(/\*/g, ' ').trim();
6049
+ }
6050
+ get imageUrl() {
6051
+ return (this.event?.payload?.url ||
6052
+ this.event?.payload?.imageUrl ||
6053
+ this.event?.payload?.data?.imageUrl ||
6054
+ null);
6055
+ }
6056
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ProfileOpenedWidgetComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
6057
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ProfileOpenedWidgetComponent, isStandalone: true, selector: "rtsee-profile-opened-widget", usesInheritance: true, ngImport: i0, template: "<div class=\"rtsee-event-widget profile-opened-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge profile-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\">person</span>\n <span class=\"widget-badge-label\">Profile Opened</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media avatar-media\">\n @if (imageUrl) {\n <img\n [src]=\"imageUrl\"\n [alt]=\"userName\"\n class=\"widget-thumbnail-image\"\n />\n } @else {\n <div class=\"widget-thumbnail-placeholder profile-placeholder\">\n <span class=\"material-icons-outlined\">person</span>\n </div>\n }\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"userName\">{{ userName }}</span>\n <span class=\"widget-subtitle\">Viewing profile</span>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
6058
+ }
6059
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ProfileOpenedWidgetComponent, decorators: [{
6060
+ type: Component,
6061
+ args: [{ selector: 'rtsee-profile-opened-widget', standalone: true, imports: [CommonModule], template: "<div class=\"rtsee-event-widget profile-opened-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge profile-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\">person</span>\n <span class=\"widget-badge-label\">Profile Opened</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media avatar-media\">\n @if (imageUrl) {\n <img\n [src]=\"imageUrl\"\n [alt]=\"userName\"\n class=\"widget-thumbnail-image\"\n />\n } @else {\n <div class=\"widget-thumbnail-placeholder profile-placeholder\">\n <span class=\"material-icons-outlined\">person</span>\n </div>\n }\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"userName\">{{ userName }}</span>\n <span class=\"widget-subtitle\">Viewing profile</span>\n </div>\n </div>\n</div>\n" }]
6062
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
6063
+
6064
+ class ChatOpenedWidgetComponent extends BaseEventWidgetComponent {
6065
+ constructor(cd) {
6066
+ super(cd);
6067
+ }
6068
+ get chatName() {
6069
+ const raw = this.event?.payload?.text ||
6070
+ this.event?.payload?.data?.chatName ||
6071
+ 'Chat';
6072
+ return String(raw).replace(/\*/g, ' ').trim();
6073
+ }
6074
+ get imageUrl() {
6075
+ return (this.event?.payload?.imageUrl ||
6076
+ this.event?.payload?.url ||
6077
+ this.event?.payload?.data?.imageUrl ||
6078
+ null);
6079
+ }
6080
+ get chatTypeLabel() {
6081
+ const type = this.event?.payload?.data?.chatType;
6082
+ if (type === 'channel')
6083
+ return 'Channel conversation';
6084
+ if (type === 'group')
6085
+ return 'Group conversation';
6086
+ return 'Active conversation';
6087
+ }
6088
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatOpenedWidgetComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
6089
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ChatOpenedWidgetComponent, isStandalone: true, selector: "rtsee-chat-opened-widget", usesInheritance: true, ngImport: i0, template: "<div class=\"rtsee-event-widget chat-opened-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge chat-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\">forum</span>\n <span class=\"widget-badge-label\">Chat Opened</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media avatar-media\">\n @if (imageUrl) {\n <img\n [src]=\"imageUrl\"\n [alt]=\"chatName\"\n class=\"widget-thumbnail-image\"\n />\n } @else {\n <div class=\"widget-thumbnail-placeholder chat-placeholder\">\n <span class=\"material-icons-outlined\">chat_bubble_outline</span>\n </div>\n }\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"chatName\">{{ chatName }}</span>\n <span class=\"widget-subtitle\">{{ chatTypeLabel }}</span>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
6090
+ }
6091
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatOpenedWidgetComponent, decorators: [{
6092
+ type: Component,
6093
+ args: [{ selector: 'rtsee-chat-opened-widget', standalone: true, imports: [CommonModule], template: "<div class=\"rtsee-event-widget chat-opened-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge chat-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\">forum</span>\n <span class=\"widget-badge-label\">Chat Opened</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media avatar-media\">\n @if (imageUrl) {\n <img\n [src]=\"imageUrl\"\n [alt]=\"chatName\"\n class=\"widget-thumbnail-image\"\n />\n } @else {\n <div class=\"widget-thumbnail-placeholder chat-placeholder\">\n <span class=\"material-icons-outlined\">chat_bubble_outline</span>\n </div>\n }\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"chatName\">{{ chatName }}</span>\n <span class=\"widget-subtitle\">{{ chatTypeLabel }}</span>\n </div>\n </div>\n</div>\n" }]
6094
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
6095
+
6096
+ class ChatCreatedWidgetComponent extends BaseEventWidgetComponent {
6097
+ constructor(cd) {
6098
+ super(cd);
6099
+ }
6100
+ get chatName() {
6101
+ const raw = this.event?.payload?.text ||
6102
+ this.event?.payload?.data?.chatName ||
6103
+ 'New Chat';
6104
+ return String(raw).replace(/\*/g, ' ').trim();
6105
+ }
6106
+ get imageUrl() {
6107
+ return (this.event?.payload?.imageUrl ||
6108
+ this.event?.payload?.data?.imageUrl ||
6109
+ null);
6110
+ }
6111
+ get chatTypeLabel() {
6112
+ const type = this.event?.payload?.data?.chatType || this.event?.payload?.url;
6113
+ if (type === 'channel')
6114
+ return 'Created channel';
6115
+ if (type === 'group')
6116
+ return 'Created group chat';
6117
+ return 'Created new chat';
6118
+ }
6119
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatCreatedWidgetComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
6120
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ChatCreatedWidgetComponent, isStandalone: true, selector: "rtsee-chat-created-widget", usesInheritance: true, ngImport: i0, template: "<div class=\"rtsee-event-widget chat-created-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge created-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\">add_comment</span>\n <span class=\"widget-badge-label\">Chat Created</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media avatar-media\">\n @if (imageUrl) {\n <img\n [src]=\"imageUrl\"\n [alt]=\"chatName\"\n class=\"widget-thumbnail-image\"\n />\n } @else {\n <div class=\"widget-thumbnail-placeholder created-placeholder\">\n <span class=\"material-icons-outlined\">group_add</span>\n </div>\n }\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"chatName\">{{ chatName }}</span>\n <span class=\"widget-subtitle\">{{ chatTypeLabel }}</span>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
6121
+ }
6122
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatCreatedWidgetComponent, decorators: [{
6123
+ type: Component,
6124
+ args: [{ selector: 'rtsee-chat-created-widget', standalone: true, imports: [CommonModule], template: "<div class=\"rtsee-event-widget chat-created-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge created-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\">add_comment</span>\n <span class=\"widget-badge-label\">Chat Created</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media avatar-media\">\n @if (imageUrl) {\n <img\n [src]=\"imageUrl\"\n [alt]=\"chatName\"\n class=\"widget-thumbnail-image\"\n />\n } @else {\n <div class=\"widget-thumbnail-placeholder created-placeholder\">\n <span class=\"material-icons-outlined\">group_add</span>\n </div>\n }\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"chatName\">{{ chatName }}</span>\n <span class=\"widget-subtitle\">{{ chatTypeLabel }}</span>\n </div>\n </div>\n</div>\n" }]
6125
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
6126
+
6127
+ class ChatMemberInviteClickedWidgetComponent extends BaseEventWidgetComponent {
6128
+ constructor(cd) {
6129
+ super(cd);
6130
+ }
6131
+ get chatName() {
6132
+ const raw = this.event?.payload?.text ||
6133
+ this.event?.payload?.data?.chatName ||
6134
+ 'Chat';
6135
+ return String(raw).replace(/\*/g, ' ').trim();
6136
+ }
6137
+ get imageUrl() {
6138
+ return (this.event?.payload?.imageUrl ||
6139
+ this.event?.payload?.data?.imageUrl ||
6140
+ null);
6141
+ }
6142
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatMemberInviteClickedWidgetComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
6143
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ChatMemberInviteClickedWidgetComponent, isStandalone: true, selector: "rtsee-chat-member-invite-clicked-widget", usesInheritance: true, ngImport: i0, template: "<div class=\"rtsee-event-widget chat-member-invite-clicked-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge invite-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\">person_add</span>\n <span class=\"widget-badge-label\">Member Invite</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media avatar-media\">\n @if (imageUrl) {\n <img\n [src]=\"imageUrl\"\n [alt]=\"chatName\"\n class=\"widget-thumbnail-image\"\n />\n } @else {\n <div class=\"widget-thumbnail-placeholder invite-placeholder\">\n <span class=\"material-icons-outlined\">link</span>\n </div>\n }\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"chatName\">{{ chatName }}</span>\n <span class=\"widget-subtitle\">Invitation link</span>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
6144
+ }
6145
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatMemberInviteClickedWidgetComponent, decorators: [{
6146
+ type: Component,
6147
+ args: [{ selector: 'rtsee-chat-member-invite-clicked-widget', standalone: true, imports: [CommonModule], template: "<div class=\"rtsee-event-widget chat-member-invite-clicked-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge invite-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\">person_add</span>\n <span class=\"widget-badge-label\">Member Invite</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media avatar-media\">\n @if (imageUrl) {\n <img\n [src]=\"imageUrl\"\n [alt]=\"chatName\"\n class=\"widget-thumbnail-image\"\n />\n } @else {\n <div class=\"widget-thumbnail-placeholder invite-placeholder\">\n <span class=\"material-icons-outlined\">link</span>\n </div>\n }\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"chatName\">{{ chatName }}</span>\n <span class=\"widget-subtitle\">Invitation link</span>\n </div>\n </div>\n</div>\n" }]
6148
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
6149
+
6150
+ class ChatAgentCreatedWidgetComponent extends BaseEventWidgetComponent {
6151
+ constructor(cd) {
6152
+ super(cd);
6153
+ }
6154
+ get agentName() {
6155
+ const raw = this.event?.payload?.text ||
6156
+ this.event?.payload?.data?.agentName ||
6157
+ 'AI Agent';
6158
+ return String(raw).replace(/\*/g, ' ').trim();
6159
+ }
6160
+ get chatName() {
6161
+ const raw = this.event?.payload?.data?.chatName ||
6162
+ this.event?.payload?.url ||
6163
+ '';
6164
+ const cleaned = String(raw).replace(/\*/g, ' ').trim();
6165
+ return cleaned ? `Added to ${cleaned}` : 'AI Agent added to chat';
6166
+ }
6167
+ get imageUrl() {
6168
+ return (this.event?.payload?.imageUrl ||
6169
+ this.event?.payload?.data?.imageUrl ||
6170
+ null);
6171
+ }
6172
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatAgentCreatedWidgetComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
6173
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ChatAgentCreatedWidgetComponent, isStandalone: true, selector: "rtsee-chat-agent-created-widget", usesInheritance: true, ngImport: i0, template: "<div class=\"rtsee-event-widget chat-agent-created-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge agent-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\">smart_toy</span>\n <span class=\"widget-badge-label\">Agent Created</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media avatar-media\">\n @if (imageUrl) {\n <img\n [src]=\"imageUrl\"\n [alt]=\"agentName\"\n class=\"widget-thumbnail-image\"\n />\n } @else {\n <div class=\"widget-thumbnail-placeholder agent-placeholder\">\n <span class=\"material-icons-outlined\">smart_toy</span>\n </div>\n }\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"agentName\">{{ agentName }}</span>\n <span class=\"widget-subtitle\" [title]=\"chatName\">{{ chatName }}</span>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
6174
+ }
6175
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatAgentCreatedWidgetComponent, decorators: [{
6176
+ type: Component,
6177
+ args: [{ selector: 'rtsee-chat-agent-created-widget', standalone: true, imports: [CommonModule], template: "<div class=\"rtsee-event-widget chat-agent-created-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge agent-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\">smart_toy</span>\n <span class=\"widget-badge-label\">Agent Created</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media avatar-media\">\n @if (imageUrl) {\n <img\n [src]=\"imageUrl\"\n [alt]=\"agentName\"\n class=\"widget-thumbnail-image\"\n />\n } @else {\n <div class=\"widget-thumbnail-placeholder agent-placeholder\">\n <span class=\"material-icons-outlined\">smart_toy</span>\n </div>\n }\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"agentName\">{{ agentName }}</span>\n <span class=\"widget-subtitle\" [title]=\"chatName\">{{ chatName }}</span>\n </div>\n </div>\n</div>\n" }]
6178
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
6179
+
6180
+ class ChatMessageSentWidgetComponent extends BaseEventWidgetComponent {
6181
+ constructor(cd) {
6182
+ super(cd);
6183
+ }
6184
+ get chatName() {
6185
+ const raw = this.event?.payload?.text ||
6186
+ this.event?.payload?.data?.chatName ||
6187
+ 'Chat';
6188
+ return String(raw).replace(/\*/g, ' ').trim();
6189
+ }
6190
+ get imageUrl() {
6191
+ return (this.event?.payload?.imageUrl ||
6192
+ this.event?.payload?.data?.imageUrl ||
6193
+ null);
6194
+ }
6195
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatMessageSentWidgetComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
6196
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ChatMessageSentWidgetComponent, isStandalone: true, selector: "rtsee-chat-message-sent-widget", usesInheritance: true, ngImport: i0, template: "<div class=\"rtsee-event-widget chat-message-sent-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge message-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\">send</span>\n <span class=\"widget-badge-label\">Message Sent</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media avatar-media\">\n @if (imageUrl) {\n <img\n [src]=\"imageUrl\"\n [alt]=\"chatName\"\n class=\"widget-thumbnail-image\"\n />\n } @else {\n <div class=\"widget-thumbnail-placeholder message-placeholder\">\n <span class=\"material-icons-outlined\">chat</span>\n </div>\n }\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"chatName\">{{ chatName }}</span>\n <span class=\"widget-subtitle\">Sent a message</span>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
6197
+ }
6198
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatMessageSentWidgetComponent, decorators: [{
6199
+ type: Component,
6200
+ args: [{ selector: 'rtsee-chat-message-sent-widget', standalone: true, imports: [CommonModule], template: "<div class=\"rtsee-event-widget chat-message-sent-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge message-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\">send</span>\n <span class=\"widget-badge-label\">Message Sent</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media avatar-media\">\n @if (imageUrl) {\n <img\n [src]=\"imageUrl\"\n [alt]=\"chatName\"\n class=\"widget-thumbnail-image\"\n />\n } @else {\n <div class=\"widget-thumbnail-placeholder message-placeholder\">\n <span class=\"material-icons-outlined\">chat</span>\n </div>\n }\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"chatName\">{{ chatName }}</span>\n <span class=\"widget-subtitle\">Sent a message</span>\n </div>\n </div>\n</div>\n" }]
6201
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
6202
+
6203
+ class ApplicationEventWidgetComponent extends BaseEventWidgetComponent {
6204
+ constructor(cd) {
6205
+ super(cd);
6206
+ }
6207
+ get eventAction() {
6208
+ const key = this.event?.widget || this.event?.name || '';
6209
+ if (key.includes('deleted'))
6210
+ return 'deleted';
6211
+ if (key.includes('updated'))
6212
+ return 'updated';
6213
+ return 'created';
6214
+ }
6215
+ get badgeLabel() {
6216
+ if (this.eventAction === 'deleted')
6217
+ return 'App Deleted';
6218
+ if (this.eventAction === 'updated')
6219
+ return 'App Updated';
6220
+ return 'App Created';
6221
+ }
6222
+ get badgeIcon() {
6223
+ if (this.eventAction === 'deleted')
6224
+ return 'delete_outline';
6225
+ if (this.eventAction === 'updated')
6226
+ return 'edit';
6227
+ return 'add_box';
6228
+ }
6229
+ get badgeClass() {
6230
+ if (this.eventAction === 'deleted')
6231
+ return 'app-deleted-badge';
6232
+ if (this.eventAction === 'updated')
6233
+ return 'app-updated-badge';
6234
+ return 'app-created-badge';
6235
+ }
6236
+ get placeholderClass() {
6237
+ if (this.eventAction === 'deleted')
6238
+ return 'app-deleted-placeholder';
6239
+ if (this.eventAction === 'updated')
6240
+ return 'app-updated-placeholder';
6241
+ return 'app-created-placeholder';
6242
+ }
6243
+ get appName() {
6244
+ return (this.event?.payload?.text ||
6245
+ this.event?.payload?.data?.name ||
6246
+ 'Application');
6247
+ }
6248
+ get appUrl() {
6249
+ return (this.event?.payload?.url ||
6250
+ this.event?.payload?.data?.url ||
6251
+ null);
6252
+ }
6253
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ApplicationEventWidgetComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
6254
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ApplicationEventWidgetComponent, isStandalone: true, selector: "rtsee-application-event-widget", usesInheritance: true, ngImport: i0, template: "<div class=\"rtsee-event-widget application-event-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge\" [ngClass]=\"badgeClass\">\n <span class=\"material-icons-outlined widget-badge-icon\">{{ badgeIcon }}</span>\n <span class=\"widget-badge-label\">{{ badgeLabel }}</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media\">\n <div class=\"widget-thumbnail-placeholder\" [ngClass]=\"placeholderClass\">\n <span class=\"material-icons-outlined\">apps</span>\n </div>\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"appName\">{{ appName }}</span>\n @if (appUrl) {\n <a\n [href]=\"appUrl\"\n target=\"_blank\"\n class=\"widget-story-link\"\n [title]=\"appUrl\"\n >\n <span class=\"widget-story-name\">{{ appUrl }}</span>\n <span class=\"material-icons-outlined external-icon\">open_in_new</span>\n </a>\n } @else {\n <span class=\"widget-subtitle\">Application settings</span>\n }\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
6255
+ }
6256
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ApplicationEventWidgetComponent, decorators: [{
6257
+ type: Component,
6258
+ args: [{ selector: 'rtsee-application-event-widget', standalone: true, imports: [CommonModule], template: "<div class=\"rtsee-event-widget application-event-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge\" [ngClass]=\"badgeClass\">\n <span class=\"material-icons-outlined widget-badge-icon\">{{ badgeIcon }}</span>\n <span class=\"widget-badge-label\">{{ badgeLabel }}</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media\">\n <div class=\"widget-thumbnail-placeholder\" [ngClass]=\"placeholderClass\">\n <span class=\"material-icons-outlined\">apps</span>\n </div>\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"appName\">{{ appName }}</span>\n @if (appUrl) {\n <a\n [href]=\"appUrl\"\n target=\"_blank\"\n class=\"widget-story-link\"\n [title]=\"appUrl\"\n >\n <span class=\"widget-story-name\">{{ appUrl }}</span>\n <span class=\"material-icons-outlined external-icon\">open_in_new</span>\n </a>\n } @else {\n <span class=\"widget-subtitle\">Application settings</span>\n }\n </div>\n </div>\n</div>\n" }]
6259
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
6260
+
6261
+ class RequestDemoClickedWidgetComponent extends BaseEventWidgetComponent {
6262
+ constructor(cd) {
6263
+ super(cd);
6264
+ }
6265
+ get title() {
6266
+ return this.event?.payload?.text || 'Request A Demo';
6267
+ }
6268
+ get pageUrl() {
6269
+ return this.event?.payload?.url || null;
6270
+ }
6271
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RequestDemoClickedWidgetComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
6272
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: RequestDemoClickedWidgetComponent, isStandalone: true, selector: "rtsee-request-demo-clicked-widget", usesInheritance: true, ngImport: i0, template: "<div class=\"rtsee-event-widget request-demo-clicked-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge demo-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\">campaign</span>\n <span class=\"widget-badge-label\">Demo Requested</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media\">\n <div class=\"widget-thumbnail-placeholder demo-placeholder\">\n <span class=\"material-icons-outlined\">event_available</span>\n </div>\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"title\">{{ title }}</span>\n <span class=\"widget-subtitle\">Opened demo request modal</span>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
6273
+ }
6274
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RequestDemoClickedWidgetComponent, decorators: [{
6275
+ type: Component,
6276
+ args: [{ selector: 'rtsee-request-demo-clicked-widget', standalone: true, imports: [CommonModule], template: "<div class=\"rtsee-event-widget request-demo-clicked-widget\">\n <div class=\"widget-header\">\n <div class=\"widget-badge demo-badge\">\n <span class=\"material-icons-outlined widget-badge-icon\">campaign</span>\n <span class=\"widget-badge-label\">Demo Requested</span>\n </div>\n <div\n class=\"widget-timer\"\n [class.live]=\"isLive\"\n [title]=\"isLive ? 'Currently active' : 'Time spent before next event'\"\n >\n <span class=\"material-icons-outlined widget-timer-icon\">timer</span>\n <span class=\"widget-timer-text\">{{ durationText }}</span>\n </div>\n </div>\n\n <div class=\"widget-body\">\n <div class=\"widget-media\">\n <div class=\"widget-thumbnail-placeholder demo-placeholder\">\n <span class=\"material-icons-outlined\">event_available</span>\n </div>\n </div>\n\n <div class=\"widget-info\">\n <span class=\"widget-title\" [title]=\"title\">{{ title }}</span>\n <span class=\"widget-subtitle\">Opened demo request modal</span>\n </div>\n </div>\n</div>\n" }]
6277
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
6278
+
5090
6279
  class EventsWidgetsService {
5091
6280
  constructor() {
5092
6281
  this.widgetsMap = [
@@ -5102,10 +6291,53 @@ class EventsWidgetsService {
5102
6291
  name: 'slide-number-changed',
5103
6292
  component: SlideNumberChangedWidgetComponent,
5104
6293
  },
6294
+ {
6295
+ name: 'profile-opened',
6296
+ component: ProfileOpenedWidgetComponent,
6297
+ },
6298
+ {
6299
+ name: 'chat-opened',
6300
+ component: ChatOpenedWidgetComponent,
6301
+ },
6302
+ {
6303
+ name: 'chat-created',
6304
+ component: ChatCreatedWidgetComponent,
6305
+ },
6306
+ {
6307
+ name: 'chat-member-invite-clicked',
6308
+ component: ChatMemberInviteClickedWidgetComponent,
6309
+ },
6310
+ {
6311
+ name: 'chat-agent-created',
6312
+ component: ChatAgentCreatedWidgetComponent,
6313
+ },
6314
+ {
6315
+ name: 'chat-message-sent',
6316
+ component: ChatMessageSentWidgetComponent,
6317
+ },
6318
+ {
6319
+ name: 'application-created',
6320
+ component: ApplicationEventWidgetComponent,
6321
+ },
6322
+ {
6323
+ name: 'application-updated',
6324
+ component: ApplicationEventWidgetComponent,
6325
+ },
6326
+ {
6327
+ name: 'application-deleted',
6328
+ component: ApplicationEventWidgetComponent,
6329
+ },
6330
+ {
6331
+ name: 'request-demo-clicked',
6332
+ component: RequestDemoClickedWidgetComponent,
6333
+ },
5105
6334
  ];
5106
6335
  }
5107
6336
  getWidgetComponentByName(name) {
5108
6337
  /* eslint-disable */
6338
+ if (!name) {
6339
+ return null;
6340
+ }
5109
6341
  const mapping = this.widgetsMap.find((e) => e.name === name);
5110
6342
  if (!mapping) {
5111
6343
  return null;
@@ -5131,9 +6363,24 @@ class EventThumbnailComponent {
5131
6363
  this.cd = cd;
5132
6364
  this.timeInAgoFormat = '';
5133
6365
  }
6366
+ get widgetName() {
6367
+ return this.event?.widget || this.event?.name;
6368
+ }
6369
+ get hasWidget() {
6370
+ return !!this.widgetsService.getWidgetComponentByName(this.widgetName);
6371
+ }
6372
+ get hasDetails() {
6373
+ const payload = this.event?.payload;
6374
+ if (!payload) {
6375
+ return false;
6376
+ }
6377
+ const hasDataEntries = typeof payload.data === 'object' &&
6378
+ payload.data !== null &&
6379
+ Object.keys(payload.data).length > 0;
6380
+ return !!(hasDataEntries || payload.url || payload.text);
6381
+ }
5134
6382
  ngOnInit() {
5135
- const eventData = this.event.payload?.data || this.event.data;
5136
- if (eventData) {
6383
+ if (this.hasDetails) {
5137
6384
  this.generateTooltip();
5138
6385
  }
5139
6386
  this.timeInAgoFormat = this.timeFormatService.toAgo(this.event.createdAt);
@@ -5142,27 +6389,30 @@ class EventThumbnailComponent {
5142
6389
  }, 20000);
5143
6390
  }
5144
6391
  generateTooltip() {
5145
- /* eslint-disable */
5146
- let tooltip = '';
5147
- const eventData = this.event.payload?.data || this.event.data;
5148
- if (typeof eventData !== 'object' || !eventData) {
6392
+ const payload = this.event?.payload;
6393
+ if (!payload) {
5149
6394
  return;
5150
6395
  }
5151
- try {
5152
- for (const key in eventData) {
5153
- if (eventData.hasOwnProperty(key)) {
5154
- if (tooltip) {
5155
- tooltip += '\n';
5156
- }
5157
- tooltip += key + ' -> ' + eventData[key];
6396
+ const entries = new Map();
6397
+ const payloadData = payload.data;
6398
+ if (typeof payloadData === 'object' && payloadData !== null) {
6399
+ Object.entries(payloadData).forEach(([key, value]) => {
6400
+ if (value !== undefined && value !== null) {
6401
+ entries.set(key, value);
5158
6402
  }
5159
- }
5160
- this.tooltip = tooltip;
6403
+ });
5161
6404
  }
5162
- catch (e) {
5163
- console.log('Failed to generate a tooltip');
6405
+ if (payload.url && !entries.has('url')) {
6406
+ entries.set('url', payload.url);
5164
6407
  }
5165
- /* eslint-enable */
6408
+ if (payload.text && !entries.has('text')) {
6409
+ entries.set('text', payload.text);
6410
+ }
6411
+ const lines = [];
6412
+ entries.forEach((value, key) => {
6413
+ lines.push(`${key} -> ${String(value)}`);
6414
+ });
6415
+ this.tooltip = lines.join('\n');
5166
6416
  }
5167
6417
  ngOnChanges(changes) {
5168
6418
  if (this.componentRef) {
@@ -5177,12 +6427,8 @@ class EventThumbnailComponent {
5177
6427
  }
5178
6428
  ngAfterViewInit() {
5179
6429
  this.cd.detectChanges();
5180
- /* eslint-disable */
5181
- if (this.event.widget) {
5182
- const widget = this.widgetsService.getWidgetComponentByName(this.event.widget);
5183
- if (!widget) {
5184
- return;
5185
- }
6430
+ const widget = this.widgetsService.getWidgetComponentByName(this.widgetName);
6431
+ if (widget && this.widgetHost) {
5186
6432
  const viewContainerRef = this.widgetHost.viewContainerRef;
5187
6433
  viewContainerRef.clear();
5188
6434
  const componentToShow = this.componentFactoryResolver.resolveComponentFactory(widget);
@@ -5191,14 +6437,13 @@ class EventThumbnailComponent {
5191
6437
  this.componentRef.instance.session = this.session;
5192
6438
  this.componentRef.changeDetectorRef.detectChanges();
5193
6439
  }
5194
- /* eslint-enable */
5195
6440
  }
5196
6441
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: EventThumbnailComponent, deps: [{ token: EventsWidgetsService }, { token: i0.ComponentFactoryResolver }, { token: TimeFormatHelperService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
5197
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: EventThumbnailComponent, isStandalone: true, selector: "rtsee-event-thumbnail", inputs: { event: "event", session: "session" }, viewQueries: [{ propertyName: "widgetHost", first: true, predicate: WidgetDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"rtsee-events-dashboard-event-thumbnail\">\n @if (event.widget) {\n <ng-template widgetHost></ng-template>\n } @else if (!event.widget) {\n <div\n class=\"rtsee-events-dashboard-default-event-thumbnail\"\n [ngClass]=\"{\n 'rtsee-events-dashboard-default-event-thumbnail-with-data':\n event.payload?.data || event.data,\n }\"\n >\n <div class=\"rtsee-events-dashboard-default-event-thumbnail-name\">\n {{ event.name }}\n </div>\n <div class=\"rtsee-events-dashboard-default-event-thumbnail-info\">\n @if (event.payload?.data || event.data) {\n <div\n class=\"rtsee-events-dashboard-default-event-thumbnail-details\"\n [title]=\"tooltip\"\n >\n <span\n class=\"rtsee-events-dashboard-default-event-thumbnail-details-icon material-icons-outlined\"\n >info</span\n >\n </div>\n }\n <div class=\"rtsee-events-dashboard-default-event-thumbnail-time\">\n <span>{{ timeInAgoFormat }}</span>\n </div>\n </div>\n </div>\n }\n</div>\n", dependencies: [{ kind: "directive", type: WidgetDirective, selector: "[widgetHost]" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
6442
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: EventThumbnailComponent, isStandalone: true, selector: "rtsee-event-thumbnail", inputs: { event: "event", session: "session" }, viewQueries: [{ propertyName: "widgetHost", first: true, predicate: WidgetDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"rtsee-events-dashboard-event-thumbnail\">\n @if (hasWidget) {\n <ng-template widgetHost></ng-template>\n } @else {\n <div\n class=\"rtsee-events-dashboard-default-event-thumbnail\"\n [ngClass]=\"{\n 'rtsee-events-dashboard-default-event-thumbnail-with-data': hasDetails,\n }\"\n >\n <div class=\"rtsee-events-dashboard-default-event-thumbnail-name\">\n {{ event.name }}\n </div>\n <div class=\"rtsee-events-dashboard-default-event-thumbnail-info\">\n @if (hasDetails && tooltip) {\n <div\n class=\"rtsee-events-dashboard-default-event-thumbnail-details\"\n [title]=\"tooltip\"\n >\n <span\n class=\"rtsee-events-dashboard-default-event-thumbnail-details-icon material-icons-outlined\"\n >info</span\n >\n </div>\n }\n <div class=\"rtsee-events-dashboard-default-event-thumbnail-time\">\n <span>{{ timeInAgoFormat }}</span>\n </div>\n </div>\n </div>\n }\n</div>\n", dependencies: [{ kind: "directive", type: WidgetDirective, selector: "[widgetHost]" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
5198
6443
  }
5199
6444
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: EventThumbnailComponent, decorators: [{
5200
6445
  type: Component,
5201
- args: [{ selector: 'rtsee-event-thumbnail', imports: [WidgetDirective, NgClass], standalone: true, template: "<div class=\"rtsee-events-dashboard-event-thumbnail\">\n @if (event.widget) {\n <ng-template widgetHost></ng-template>\n } @else if (!event.widget) {\n <div\n class=\"rtsee-events-dashboard-default-event-thumbnail\"\n [ngClass]=\"{\n 'rtsee-events-dashboard-default-event-thumbnail-with-data':\n event.payload?.data || event.data,\n }\"\n >\n <div class=\"rtsee-events-dashboard-default-event-thumbnail-name\">\n {{ event.name }}\n </div>\n <div class=\"rtsee-events-dashboard-default-event-thumbnail-info\">\n @if (event.payload?.data || event.data) {\n <div\n class=\"rtsee-events-dashboard-default-event-thumbnail-details\"\n [title]=\"tooltip\"\n >\n <span\n class=\"rtsee-events-dashboard-default-event-thumbnail-details-icon material-icons-outlined\"\n >info</span\n >\n </div>\n }\n <div class=\"rtsee-events-dashboard-default-event-thumbnail-time\">\n <span>{{ timeInAgoFormat }}</span>\n </div>\n </div>\n </div>\n }\n</div>\n" }]
6446
+ args: [{ selector: 'rtsee-event-thumbnail', imports: [WidgetDirective, NgClass], standalone: true, template: "<div class=\"rtsee-events-dashboard-event-thumbnail\">\n @if (hasWidget) {\n <ng-template widgetHost></ng-template>\n } @else {\n <div\n class=\"rtsee-events-dashboard-default-event-thumbnail\"\n [ngClass]=\"{\n 'rtsee-events-dashboard-default-event-thumbnail-with-data': hasDetails,\n }\"\n >\n <div class=\"rtsee-events-dashboard-default-event-thumbnail-name\">\n {{ event.name }}\n </div>\n <div class=\"rtsee-events-dashboard-default-event-thumbnail-info\">\n @if (hasDetails && tooltip) {\n <div\n class=\"rtsee-events-dashboard-default-event-thumbnail-details\"\n [title]=\"tooltip\"\n >\n <span\n class=\"rtsee-events-dashboard-default-event-thumbnail-details-icon material-icons-outlined\"\n >info</span\n >\n </div>\n }\n <div class=\"rtsee-events-dashboard-default-event-thumbnail-time\">\n <span>{{ timeInAgoFormat }}</span>\n </div>\n </div>\n </div>\n }\n</div>\n" }]
5202
6447
  }], ctorParameters: () => [{ type: EventsWidgetsService }, { type: i0.ComponentFactoryResolver }, { type: TimeFormatHelperService }, { type: i0.ChangeDetectorRef }], propDecorators: { event: [{
5203
6448
  type: Input
5204
6449
  }], session: [{
@@ -5337,13 +6582,13 @@ class JoinCallComponent {
5337
6582
  this.recentlyCopied = false;
5338
6583
  }, 2000);
5339
6584
  }
5340
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: JoinCallComponent, deps: [{ token: i1$3.MessageService }], target: i0.ɵɵFactoryTarget.Component }); }
6585
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: JoinCallComponent, deps: [{ token: i1$4.MessageService }], target: i0.ɵɵFactoryTarget.Component }); }
5341
6586
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: JoinCallComponent, isStandalone: true, selector: "rtsee-join-call", inputs: { presentation: "presentation", room: "room" }, providers: [MessageService], ngImport: i0, template: "<div class=\"rtsee-join-call\">\n <div class=\"rtsee-join-call-button\">\n <p-button [label]=\"presentation.labels[RTSeeTextLabelKeys.START_A_CALL_BUTTON]\"\n (click)=\"presentation.emitJoinRoomCallEvent()\"\n ></p-button>\n </div>\n <div class=\"rtsee-share-call-link\">\n <div class=\"rtsee-share-call-explain-section\">\n <div class=\"rtsee-share-call-explain-section-icon\">\n <span class=\"pi pi-link rtsee-link-icon\"></span>\n </div>\n <div class=\"rtsee-share-call-explain-section-text\">\n <span>Anyone can join your storytelling session using this link.</span>\n </div>\n </div>\n <div class=\"rtsee-share-call-link-section\">\n <p-toast position=\"bottom-center\" />\n <p-button [icon]=\"recentlyCopied ? 'pi pi-check' : 'pi pi-copy'\"\n severity=\"secondary\"\n class=\"rtsee-share-call-link-copy-btn\"\n [cdkCopyToClipboard]=\"window.location.origin + '?room_id=' + room.id\"\n (cdkCopyToClipboardCopied)=\"copyClicked()\"\n ></p-button>\n <p-message severity=\"info\"\n class=\"rtsee-share-call-link-text\"\n >{{ window.location.origin + '?room_id=' + room.id }}</p-message>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: CdkCopyToClipboard, selector: "[cdkCopyToClipboard]", inputs: ["cdkCopyToClipboard", "cdkCopyToClipboardAttempts"], outputs: ["cdkCopyToClipboardCopied"] }, { kind: "component", type: Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }, { kind: "component", type: Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }] }); }
5342
6587
  }
5343
6588
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: JoinCallComponent, decorators: [{
5344
6589
  type: Component,
5345
6590
  args: [{ selector: 'rtsee-join-call', imports: [Button, CdkCopyToClipboard, Message, Toast], providers: [MessageService], template: "<div class=\"rtsee-join-call\">\n <div class=\"rtsee-join-call-button\">\n <p-button [label]=\"presentation.labels[RTSeeTextLabelKeys.START_A_CALL_BUTTON]\"\n (click)=\"presentation.emitJoinRoomCallEvent()\"\n ></p-button>\n </div>\n <div class=\"rtsee-share-call-link\">\n <div class=\"rtsee-share-call-explain-section\">\n <div class=\"rtsee-share-call-explain-section-icon\">\n <span class=\"pi pi-link rtsee-link-icon\"></span>\n </div>\n <div class=\"rtsee-share-call-explain-section-text\">\n <span>Anyone can join your storytelling session using this link.</span>\n </div>\n </div>\n <div class=\"rtsee-share-call-link-section\">\n <p-toast position=\"bottom-center\" />\n <p-button [icon]=\"recentlyCopied ? 'pi pi-check' : 'pi pi-copy'\"\n severity=\"secondary\"\n class=\"rtsee-share-call-link-copy-btn\"\n [cdkCopyToClipboard]=\"window.location.origin + '?room_id=' + room.id\"\n (cdkCopyToClipboardCopied)=\"copyClicked()\"\n ></p-button>\n <p-message severity=\"info\"\n class=\"rtsee-share-call-link-text\"\n >{{ window.location.origin + '?room_id=' + room.id }}</p-message>\n </div>\n </div>\n</div>\n" }]
5346
- }], ctorParameters: () => [{ type: i1$3.MessageService }], propDecorators: { presentation: [{
6591
+ }], ctorParameters: () => [{ type: i1$4.MessageService }], propDecorators: { presentation: [{
5347
6592
  type: Input
5348
6593
  }], room: [{
5349
6594
  type: Input
@@ -5982,7 +7227,7 @@ class IllustratorComponent {
5982
7227
  return item.id || `agent-${index}`;
5983
7228
  }
5984
7229
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: IllustratorComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
5985
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: IllustratorComponent, isStandalone: true, selector: "rtsee-illustrator", inputs: { illustrator: "illustrator" }, ngImport: i0, template: "<div class=\"rtsee-illustrator-container\" [ngClass]=\"{ 'rtsee-illustrator--expanded': illustrator.expanded }\">\n <!-- Collapsed Bottom Bar -->\n @if (!illustrator.expanded) {\n <div class=\"rtsee-illustrator-collapsed-bar\" (click)=\"toggleExpand()\">\n <div class=\"rtsee-illustrator-collapsed-info\">\n <div class=\"rtsee-illustrator-badge-icon\">\n <i class=\"pi pi-palette\"></i>\n </div>\n <div class=\"rtsee-illustrator-collapsed-title\">\n <span class=\"rtsee-illustrator-brand-text\">NanoBanana Illustrator</span>\n @if (illustrator.activeAgent) {\n <span class=\"rtsee-illustrator-agent-pill\">\n <i class=\"pi pi-bolt\"></i>\n {{ illustrator.activeAgent.name }}\n </span>\n } @else {\n <span class=\"rtsee-illustrator-agent-pill rtsee-illustrator-agent-pill--waiting\">\n <i class=\"pi pi-spin pi-spinner\"></i>\n Waiting for Chat Agent...\n </span>\n }\n </div>\n </div>\n\n <div class=\"rtsee-illustrator-collapsed-meta\">\n @if (illustrator.reviewingGeneratedImage && illustrator.currentGeneratedImageUrl) {\n <span class=\"rtsee-illustrator-collapsed-review-pill\">\n <img [src]=\"illustrator.currentGeneratedImageUrl\" alt=\"Draft\" class=\"rtsee-illustrator-collapsed-thumb\" />\n <span>\u2728 Reviewing Draft</span>\n </span>\n }\n @if (illustrator.contextImages.length > 0) {\n <span class=\"rtsee-illustrator-context-count\">\n <i class=\"pi pi-images\"></i>\n {{ illustrator.activeContextImages.length }} / {{ illustrator.contextImages.length }} context refs\n </span>\n }\n @if (illustrator.prompt) {\n <span class=\"rtsee-illustrator-prompt-preview\">\n \"{{ illustrator.prompt.length > 50 ? (illustrator.prompt | slice:0:50) + '\u2026' : illustrator.prompt }}\"\n </span>\n }\n <button type=\"button\" class=\"rtsee-illustrator-expand-btn\" aria-label=\"Expand Illustrator\">\n <i class=\"pi pi-chevron-up\"></i>\n </button>\n </div>\n </div>\n }\n\n <!-- Expanded Drawer -->\n @if (illustrator.expanded) {\n <div class=\"rtsee-illustrator-expanded-panel\">\n <!-- Header -->\n <header class=\"rtsee-illustrator-header\">\n <div class=\"rtsee-illustrator-title-group\">\n <div class=\"rtsee-illustrator-icon-circle\">\n <i class=\"pi pi-palette\"></i>\n </div>\n <div>\n <h3 class=\"rtsee-illustrator-heading\">NanoBanana Illustrator</h3>\n <p class=\"rtsee-illustrator-subheading\">Generate enchanted fairy tale visuals with rich contextual styling</p>\n </div>\n </div>\n\n <div class=\"rtsee-illustrator-header-controls\">\n <!-- Agent Picker -->\n <div class=\"rtsee-illustrator-agent-select-wrapper\">\n <label class=\"rtsee-illustrator-agent-label\" for=\"rtsee-illustrator-agent-select\">\n <i class=\"pi pi-sparkles\"></i> Agent:\n </label>\n @if (illustrator.agents.length > 0) {\n <select\n id=\"rtsee-illustrator-agent-select\"\n class=\"rtsee-illustrator-select\"\n [value]=\"illustrator.activeAgentId || ''\"\n (change)=\"onSelectAgent($event)\"\n >\n @for (agent of illustrator.agents; track trackByAgentId($index, agent)) {\n <option [value]=\"agent.id\">\n {{ agent.name }} {{ agent.model ? '(' + agent.model + ')' : '' }}\n </option>\n }\n </select>\n } @else {\n <button\n type=\"button\"\n class=\"rtsee-illustrator-btn-mini\"\n (click)=\"refreshAgents()\"\n title=\"Query active agents from RTSeeChat\"\n >\n <i class=\"pi pi-refresh\"></i>\n <span>Connect RTSeeChat</span>\n </button>\n }\n </div>\n\n <!-- Config Toggle Button -->\n <button\n type=\"button\"\n class=\"rtsee-illustrator-header-btn\"\n [ngClass]=\"{ 'rtsee-illustrator-header-btn--active': illustrator.configExpanded }\"\n (click)=\"toggleConfig()\"\n title=\"Toggle NanoBanana Configuration\"\n >\n <i class=\"pi pi-sliders-h\"></i>\n <span>Config</span>\n <i class=\"pi\" [ngClass]=\"illustrator.configExpanded ? 'pi-chevron-up' : 'pi-chevron-down'\"></i>\n </button>\n\n <!-- Collapse Drawer Button -->\n <button\n type=\"button\"\n class=\"rtsee-illustrator-header-btn rtsee-illustrator-header-btn--close\"\n (click)=\"toggleExpand()\"\n aria-label=\"Collapse Illustrator\"\n >\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </header>\n\n <!-- Collapsible Config Section -->\n @if (illustrator.configExpanded) {\n <div class=\"rtsee-illustrator-config-panel\">\n <div class=\"rtsee-illustrator-config-grid\">\n <!-- Aspect Ratio -->\n <div class=\"rtsee-illustrator-config-item\">\n <label class=\"rtsee-illustrator-field-label\" for=\"cfg-aspect-ratio\">\n <i class=\"pi pi-stop\"></i> Aspect Ratio (Default 1:1)\n </label>\n <select\n id=\"cfg-aspect-ratio\"\n class=\"rtsee-illustrator-select\"\n [(ngModel)]=\"illustrator.config.aspectRatio\"\n >\n @for (ratio of aspectRatios; track ratio) {\n <option [value]=\"ratio\">{{ ratio }}{{ ratio === '1:1' ? ' (Square - Fairy Tale Default)' : '' }}</option>\n }\n </select>\n </div>\n\n <!-- Style Preset -->\n <div class=\"rtsee-illustrator-config-item\">\n <label class=\"rtsee-illustrator-field-label\" for=\"cfg-style\">\n <i class=\"pi pi-paint-brush\"></i> Illustration Style\n </label>\n <select\n id=\"cfg-style\"\n class=\"rtsee-illustrator-select\"\n [(ngModel)]=\"illustrator.config.style\"\n >\n @for (s of styles; track s) {\n <option [value]=\"s\">{{ s }}</option>\n }\n </select>\n </div>\n\n <!-- Mood Preset -->\n <div class=\"rtsee-illustrator-config-item\">\n <label class=\"rtsee-illustrator-field-label\" for=\"cfg-mood\">\n <i class=\"pi pi-heart\"></i> Mood & Atmosphere\n </label>\n <select\n id=\"cfg-mood\"\n class=\"rtsee-illustrator-select\"\n [(ngModel)]=\"illustrator.config.mood\"\n >\n @for (m of moods; track m) {\n <option [value]=\"m\">{{ m }}</option>\n }\n </select>\n </div>\n\n <!-- Lighting Preset -->\n <div class=\"rtsee-illustrator-config-item\">\n <label class=\"rtsee-illustrator-field-label\" for=\"cfg-lighting\">\n <i class=\"pi pi-sun\"></i> Lighting\n </label>\n <select\n id=\"cfg-lighting\"\n class=\"rtsee-illustrator-select\"\n [(ngModel)]=\"illustrator.config.lighting\"\n >\n @for (l of lightings; track l) {\n <option [value]=\"l\">{{ l }}</option>\n }\n </select>\n </div>\n </div>\n\n <!-- Negative Prompt -->\n <div class=\"rtsee-illustrator-config-item rtsee-illustrator-config-item--full\">\n <label class=\"rtsee-illustrator-field-label\" for=\"cfg-negative-prompt\">\n <i class=\"pi pi-ban\"></i> Negative Prompt (What to exclude)\n </label>\n <input\n id=\"cfg-negative-prompt\"\n type=\"text\"\n class=\"rtsee-illustrator-input\"\n [(ngModel)]=\"illustrator.config.negativePrompt\"\n placeholder=\"e.g. modern items, cars, text, watermark, blurry...\"\n />\n </div>\n </div>\n }\n\n <!-- Context Images Section -->\n @if (illustrator.contextImages.length > 0) {\n <div class=\"rtsee-illustrator-context-section\">\n <div class=\"rtsee-illustrator-section-header\">\n <span class=\"rtsee-illustrator-section-title\">\n <i class=\"pi pi-images\"></i> Story Context References ({{ illustrator.activeContextImages.length }} of {{ illustrator.contextImages.length }} active)\n </span>\n <button\n type=\"button\"\n class=\"rtsee-illustrator-btn-text\"\n (click)=\"illustrator.clearContext()\"\n title=\"Clear all context references\"\n >\n <i class=\"pi pi-trash\"></i> Clear All\n </button>\n </div>\n\n <div class=\"rtsee-illustrator-context-cards\">\n @for (img of illustrator.contextImages; track trackByImageId($index, img)) {\n <div class=\"rtsee-illustrator-context-card\" [ngClass]=\"{ 'rtsee-illustrator-context-card--inactive': !img.active }\">\n <!-- Thumbnail & Active Checkbox -->\n <div class=\"rtsee-illustrator-card-thumb-col\">\n <div class=\"rtsee-illustrator-card-thumb-wrapper\">\n @if (img.imageUrl) {\n <img [src]=\"img.imageUrl\" [alt]=\"img.title\" class=\"rtsee-illustrator-card-img\" />\n } @else {\n <div class=\"rtsee-illustrator-card-no-img\">\n <i class=\"pi pi-image\"></i>\n </div>\n }\n </div>\n <label class=\"rtsee-illustrator-checkbox-label\">\n <input\n type=\"checkbox\"\n [checked]=\"img.active !== false\"\n (change)=\"toggleActive(img)\"\n />\n <span>Active</span>\n </label>\n </div>\n\n <!-- Editable Fields -->\n <div class=\"rtsee-illustrator-card-fields\">\n <div class=\"rtsee-illustrator-card-header\">\n <span class=\"rtsee-illustrator-source-badge\">{{ img.sourceType || 'reference' }}</span>\n <input\n type=\"text\"\n class=\"rtsee-illustrator-card-title-input\"\n [(ngModel)]=\"img.title\"\n placeholder=\"Reference title...\"\n />\n <button\n type=\"button\"\n class=\"rtsee-illustrator-card-remove-btn\"\n (click)=\"removeImage(img.id)\"\n aria-label=\"Remove image from context\"\n title=\"Remove from context\"\n >\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n\n <div class=\"rtsee-illustrator-card-inputs-grid\">\n <div class=\"rtsee-illustrator-input-group\">\n <label class=\"rtsee-illustrator-input-sublabel\">Visual Description (Style / Appearance):</label>\n <textarea\n class=\"rtsee-illustrator-card-textarea\"\n rows=\"2\"\n [(ngModel)]=\"img.visualDescription\"\n placeholder=\"Key visual features, colors, clothing, texture, lighting...\"\n ></textarea>\n </div>\n <div class=\"rtsee-illustrator-input-group\">\n <label class=\"rtsee-illustrator-input-sublabel\">Context / Role Description:</label>\n <textarea\n class=\"rtsee-illustrator-card-textarea\"\n rows=\"2\"\n [(ngModel)]=\"img.description\"\n placeholder=\"Context or lore in this fairy tale scene...\"\n ></textarea>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Generation Error Banner -->\n @if (illustrator.generationError) {\n <div class=\"rtsee-illustrator-error-banner\">\n <i class=\"pi pi-exclamation-triangle\"></i>\n <span class=\"rtsee-illustrator-error-text\">{{ illustrator.generationError }}</span>\n <button type=\"button\" class=\"rtsee-illustrator-error-close\" (click)=\"illustrator.generationError = null\" aria-label=\"Dismiss error\">\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n }\n\n <!-- Reviewing Generated Image Mode -->\n @if (illustrator.reviewingGeneratedImage && illustrator.currentGeneratedImageUrl) {\n <div class=\"rtsee-illustrator-review-panel\">\n <div class=\"rtsee-illustrator-review-header\">\n <div class=\"rtsee-illustrator-review-title\">\n <span class=\"rtsee-illustrator-review-badge\">\n <i class=\"pi pi-sparkles\"></i> Reviewing Generated Image\n </span>\n <span class=\"rtsee-illustrator-review-sub\">Review the result, request iterative modifications, or discard.</span>\n </div>\n <div class=\"rtsee-illustrator-review-quick-actions\">\n <p-button\n label=\"Accept & Keep\"\n icon=\"pi pi-check\"\n severity=\"success\"\n (click)=\"acceptGeneratedImage()\"\n />\n <p-button\n label=\"Discard\"\n icon=\"pi pi-trash\"\n severity=\"danger\"\n [text]=\"true\"\n (click)=\"discardGeneratedImage()\"\n />\n </div>\n </div>\n\n <!-- Image Preview -->\n <div class=\"rtsee-illustrator-preview-box\">\n <img [src]=\"illustrator.currentGeneratedImageUrl\" alt=\"Generated fairy tale illustration\" class=\"rtsee-illustrator-preview-img\" />\n <a [href]=\"illustrator.currentGeneratedImageUrl\" target=\"_blank\" rel=\"noopener\" class=\"rtsee-illustrator-preview-zoom-btn\" title=\"Open full image in new tab\">\n <i class=\"pi pi-external-link\"></i> Full View\n </a>\n </div>\n\n <!-- Iteration Modification Controls -->\n <div class=\"rtsee-illustrator-iteration-box\">\n <div class=\"rtsee-illustrator-iteration-info\">\n <span class=\"rtsee-illustrator-iteration-tag\">\n <i class=\"pi pi-refresh\"></i> Request Modifications & Iterate\n </span>\n <span class=\"rtsee-illustrator-iteration-context-hint\">\n <i class=\"pi pi-info-circle\"></i>\n All active context references ({{ illustrator.activeContextImages.length }}) are sent to NanoBanana alongside this base picture.\n </span>\n </div>\n\n <textarea\n class=\"rtsee-illustrator-prompt-textarea rtsee-illustrator-prompt-textarea--iteration\"\n rows=\"3\"\n [(ngModel)]=\"illustrator.iterationPrompt\"\n placeholder=\"Describe modifications to apply to this picture (e.g. 'Make the wizard's cloak sapphire blue with silver runes, add glowing fireflies, soften the background trees')...\"\n (keydown.meta.enter)=\"submitIteration()\"\n (keydown.control.enter)=\"submitIteration()\"\n ></textarea>\n\n <div class=\"rtsee-illustrator-prompt-footer\">\n <span class=\"rtsee-illustrator-tip\">\n <i class=\"pi pi-info-circle\"></i>\n Press <strong>\u2318+Enter</strong> to iterate on this picture.\n </span>\n\n <div class=\"rtsee-illustrator-actions\">\n <p-button\n label=\"Discard\"\n icon=\"pi pi-trash\"\n severity=\"danger\"\n [text]=\"true\"\n (click)=\"discardGeneratedImage()\"\n />\n <p-button\n label=\"Iterate & Regenerate\"\n icon=\"pi pi-refresh\"\n [loading]=\"illustrator.submitting\"\n [disabled]=\"!illustrator.canSubmit\"\n (click)=\"submitIteration()\"\n />\n </div>\n </div>\n </div>\n </div>\n } @else {\n <!-- Prompt Input & Submit Action (Standard Mode) -->\n <div class=\"rtsee-illustrator-prompt-section\">\n <div class=\"rtsee-illustrator-prompt-box\">\n <textarea\n class=\"rtsee-illustrator-prompt-textarea\"\n rows=\"3\"\n [(ngModel)]=\"illustrator.prompt\"\n placeholder=\"Describe the fairy tale illustration to generate (e.g. 'A cozy cottage tucked deep inside the emerald moss woods, magical amber lanterns glowing warmly from the windows, soft fireflies in the air')...\"\n (keydown.meta.enter)=\"submitPrompt()\"\n (keydown.control.enter)=\"submitPrompt()\"\n ></textarea>\n\n <div class=\"rtsee-illustrator-prompt-footer\">\n <span class=\"rtsee-illustrator-tip\">\n <i class=\"pi pi-info-circle\"></i>\n Press <strong>\u2318+Enter</strong> to submit. Context characters, artifacts, locations & slides are sent to NanoBanana.\n </span>\n\n <div class=\"rtsee-illustrator-actions\">\n <p-button\n label=\"Generate Illustration\"\n icon=\"pi pi-sparkles\"\n [loading]=\"illustrator.submitting\"\n [disabled]=\"!illustrator.canSubmit\"\n (click)=\"submitPrompt()\"\n />\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "pipe", type: i2$1.SlicePipe, name: "slice" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7230
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: IllustratorComponent, isStandalone: true, selector: "rtsee-illustrator", inputs: { illustrator: "illustrator" }, ngImport: i0, template: "<div class=\"rtsee-illustrator-container\" [ngClass]=\"{ 'rtsee-illustrator--expanded': illustrator.expanded }\">\n <!-- Collapsed Bottom Bar -->\n @if (!illustrator.expanded) {\n <div class=\"rtsee-illustrator-collapsed-bar\" (click)=\"toggleExpand()\">\n <div class=\"rtsee-illustrator-collapsed-info\">\n <div class=\"rtsee-illustrator-badge-icon\">\n <i class=\"pi pi-palette\"></i>\n </div>\n <div class=\"rtsee-illustrator-collapsed-title\">\n <span class=\"rtsee-illustrator-brand-text\">NanoBanana Illustrator</span>\n @if (illustrator.activeAgent) {\n <span class=\"rtsee-illustrator-agent-pill\">\n <i class=\"pi pi-bolt\"></i>\n {{ illustrator.activeAgent.name }}\n </span>\n } @else {\n <span class=\"rtsee-illustrator-agent-pill rtsee-illustrator-agent-pill--waiting\">\n <i class=\"pi pi-spin pi-spinner\"></i>\n Waiting for Chat Agent...\n </span>\n }\n </div>\n </div>\n\n <div class=\"rtsee-illustrator-collapsed-meta\">\n @if (illustrator.reviewingGeneratedImage && illustrator.currentGeneratedImageUrl) {\n <span class=\"rtsee-illustrator-collapsed-review-pill\">\n <img [src]=\"illustrator.currentGeneratedImageUrl\" alt=\"Draft\" class=\"rtsee-illustrator-collapsed-thumb\" />\n <span>\u2728 Reviewing Draft</span>\n </span>\n }\n @if (illustrator.contextImages.length > 0) {\n <span class=\"rtsee-illustrator-context-count\">\n <i class=\"pi pi-images\"></i>\n {{ illustrator.activeContextImages.length }} / {{ illustrator.contextImages.length }} context refs\n </span>\n }\n @if (illustrator.prompt) {\n <span class=\"rtsee-illustrator-prompt-preview\">\n \"{{ illustrator.prompt.length > 50 ? (illustrator.prompt | slice:0:50) + '\u2026' : illustrator.prompt }}\"\n </span>\n }\n <button type=\"button\" class=\"rtsee-illustrator-expand-btn\" aria-label=\"Expand Illustrator\">\n <i class=\"pi pi-chevron-up\"></i>\n </button>\n </div>\n </div>\n }\n\n <!-- Expanded Drawer -->\n @if (illustrator.expanded) {\n <div class=\"rtsee-illustrator-expanded-panel\">\n <!-- Header -->\n <header class=\"rtsee-illustrator-header\">\n <div class=\"rtsee-illustrator-title-group\">\n <div class=\"rtsee-illustrator-icon-circle\">\n <i class=\"pi pi-palette\"></i>\n </div>\n <div>\n <h3 class=\"rtsee-illustrator-heading\">NanoBanana Illustrator</h3>\n <p class=\"rtsee-illustrator-subheading\">Generate enchanted fairy tale visuals with rich contextual styling</p>\n </div>\n </div>\n\n <div class=\"rtsee-illustrator-header-controls\">\n <!-- Agent Picker -->\n <div class=\"rtsee-illustrator-agent-select-wrapper\">\n <label class=\"rtsee-illustrator-agent-label\" for=\"rtsee-illustrator-agent-select\">\n <i class=\"pi pi-sparkles\"></i> Agent:\n </label>\n @if (illustrator.agents.length > 0) {\n <select\n id=\"rtsee-illustrator-agent-select\"\n class=\"rtsee-illustrator-select\"\n [value]=\"illustrator.activeAgentId || ''\"\n (change)=\"onSelectAgent($event)\"\n >\n @for (agent of illustrator.agents; track trackByAgentId($index, agent)) {\n <option [value]=\"agent.id\">\n {{ agent.name }} {{ agent.model ? '(' + agent.model + ')' : '' }}\n </option>\n }\n </select>\n } @else {\n <button\n type=\"button\"\n class=\"rtsee-illustrator-btn-mini\"\n (click)=\"refreshAgents()\"\n title=\"Query active agents from RTSeeChat\"\n >\n <i class=\"pi pi-refresh\"></i>\n <span>Connect RTSeeChat</span>\n </button>\n }\n </div>\n\n <!-- Config Toggle Button -->\n <button\n type=\"button\"\n class=\"rtsee-illustrator-header-btn\"\n [ngClass]=\"{ 'rtsee-illustrator-header-btn--active': illustrator.configExpanded }\"\n (click)=\"toggleConfig()\"\n title=\"Toggle NanoBanana Configuration\"\n >\n <i class=\"pi pi-sliders-h\"></i>\n <span>Config</span>\n <i class=\"pi\" [ngClass]=\"illustrator.configExpanded ? 'pi-chevron-up' : 'pi-chevron-down'\"></i>\n </button>\n\n <!-- Collapse Drawer Button -->\n <button\n type=\"button\"\n class=\"rtsee-illustrator-header-btn rtsee-illustrator-header-btn--close\"\n (click)=\"toggleExpand()\"\n aria-label=\"Collapse Illustrator\"\n >\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </header>\n\n <!-- Collapsible Config Section -->\n @if (illustrator.configExpanded) {\n <div class=\"rtsee-illustrator-config-panel\">\n <div class=\"rtsee-illustrator-config-grid\">\n <!-- Aspect Ratio -->\n <div class=\"rtsee-illustrator-config-item\">\n <label class=\"rtsee-illustrator-field-label\" for=\"cfg-aspect-ratio\">\n <i class=\"pi pi-stop\"></i> Aspect Ratio (Default 1:1)\n </label>\n <select\n id=\"cfg-aspect-ratio\"\n class=\"rtsee-illustrator-select\"\n [(ngModel)]=\"illustrator.config.aspectRatio\"\n >\n @for (ratio of aspectRatios; track ratio) {\n <option [value]=\"ratio\">{{ ratio }}{{ ratio === '1:1' ? ' (Square - Fairy Tale Default)' : '' }}</option>\n }\n </select>\n </div>\n\n <!-- Style Preset -->\n <div class=\"rtsee-illustrator-config-item\">\n <label class=\"rtsee-illustrator-field-label\" for=\"cfg-style\">\n <i class=\"pi pi-paint-brush\"></i> Illustration Style\n </label>\n <select\n id=\"cfg-style\"\n class=\"rtsee-illustrator-select\"\n [(ngModel)]=\"illustrator.config.style\"\n >\n @for (s of styles; track s) {\n <option [value]=\"s\">{{ s }}</option>\n }\n </select>\n </div>\n\n <!-- Mood Preset -->\n <div class=\"rtsee-illustrator-config-item\">\n <label class=\"rtsee-illustrator-field-label\" for=\"cfg-mood\">\n <i class=\"pi pi-heart\"></i> Mood & Atmosphere\n </label>\n <select\n id=\"cfg-mood\"\n class=\"rtsee-illustrator-select\"\n [(ngModel)]=\"illustrator.config.mood\"\n >\n @for (m of moods; track m) {\n <option [value]=\"m\">{{ m }}</option>\n }\n </select>\n </div>\n\n <!-- Lighting Preset -->\n <div class=\"rtsee-illustrator-config-item\">\n <label class=\"rtsee-illustrator-field-label\" for=\"cfg-lighting\">\n <i class=\"pi pi-sun\"></i> Lighting\n </label>\n <select\n id=\"cfg-lighting\"\n class=\"rtsee-illustrator-select\"\n [(ngModel)]=\"illustrator.config.lighting\"\n >\n @for (l of lightings; track l) {\n <option [value]=\"l\">{{ l }}</option>\n }\n </select>\n </div>\n </div>\n\n <!-- Negative Prompt -->\n <div class=\"rtsee-illustrator-config-item rtsee-illustrator-config-item--full\">\n <label class=\"rtsee-illustrator-field-label\" for=\"cfg-negative-prompt\">\n <i class=\"pi pi-ban\"></i> Negative Prompt (What to exclude)\n </label>\n <input\n id=\"cfg-negative-prompt\"\n type=\"text\"\n class=\"rtsee-illustrator-input\"\n [(ngModel)]=\"illustrator.config.negativePrompt\"\n placeholder=\"e.g. modern items, cars, text, watermark, blurry...\"\n />\n </div>\n </div>\n }\n\n <!-- Context Images Section -->\n @if (illustrator.contextImages.length > 0) {\n <div class=\"rtsee-illustrator-context-section\">\n <div class=\"rtsee-illustrator-section-header\">\n <span class=\"rtsee-illustrator-section-title\">\n <i class=\"pi pi-images\"></i> Story Context References ({{ illustrator.activeContextImages.length }} of {{ illustrator.contextImages.length }} active)\n </span>\n <button\n type=\"button\"\n class=\"rtsee-illustrator-btn-text\"\n (click)=\"illustrator.clearContext()\"\n title=\"Clear all context references\"\n >\n <i class=\"pi pi-trash\"></i> Clear All\n </button>\n </div>\n\n <div class=\"rtsee-illustrator-context-cards\">\n @for (img of illustrator.contextImages; track trackByImageId($index, img)) {\n <div class=\"rtsee-illustrator-context-card\" [ngClass]=\"{ 'rtsee-illustrator-context-card--inactive': !img.active }\">\n <!-- Thumbnail & Active Checkbox -->\n <div class=\"rtsee-illustrator-card-thumb-col\">\n <div class=\"rtsee-illustrator-card-thumb-wrapper\">\n @if (img.imageUrl) {\n <img [src]=\"img.imageUrl\" [alt]=\"img.title\" class=\"rtsee-illustrator-card-img\" />\n } @else {\n <div class=\"rtsee-illustrator-card-no-img\">\n <i class=\"pi pi-image\"></i>\n </div>\n }\n </div>\n <label class=\"rtsee-illustrator-checkbox-label\">\n <input\n type=\"checkbox\"\n [checked]=\"img.active !== false\"\n (change)=\"toggleActive(img)\"\n />\n <span>Active</span>\n </label>\n </div>\n\n <!-- Editable Fields -->\n <div class=\"rtsee-illustrator-card-fields\">\n <div class=\"rtsee-illustrator-card-header\">\n <span class=\"rtsee-illustrator-source-badge\">{{ img.sourceType || 'reference' }}</span>\n <input\n type=\"text\"\n class=\"rtsee-illustrator-card-title-input\"\n [(ngModel)]=\"img.title\"\n placeholder=\"Reference title...\"\n />\n <button\n type=\"button\"\n class=\"rtsee-illustrator-card-remove-btn\"\n (click)=\"removeImage(img.id)\"\n aria-label=\"Remove image from context\"\n title=\"Remove from context\"\n >\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n\n <div class=\"rtsee-illustrator-card-inputs-grid\">\n <div class=\"rtsee-illustrator-input-group\">\n <label class=\"rtsee-illustrator-input-sublabel\">Visual Description (Style / Appearance):</label>\n <textarea\n class=\"rtsee-illustrator-card-textarea\"\n rows=\"2\"\n [(ngModel)]=\"img.visualDescription\"\n placeholder=\"Key visual features, colors, clothing, texture, lighting...\"\n ></textarea>\n </div>\n <div class=\"rtsee-illustrator-input-group\">\n <label class=\"rtsee-illustrator-input-sublabel\">Context / Role Description:</label>\n <textarea\n class=\"rtsee-illustrator-card-textarea\"\n rows=\"2\"\n [(ngModel)]=\"img.description\"\n placeholder=\"Context or lore in this fairy tale scene...\"\n ></textarea>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Generation Error Banner -->\n @if (illustrator.generationError) {\n <div class=\"rtsee-illustrator-error-banner\">\n <i class=\"pi pi-exclamation-triangle\"></i>\n <span class=\"rtsee-illustrator-error-text\">{{ illustrator.generationError }}</span>\n <button type=\"button\" class=\"rtsee-illustrator-error-close\" (click)=\"illustrator.generationError = null\" aria-label=\"Dismiss error\">\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n }\n\n <!-- Reviewing Generated Image Mode -->\n @if (illustrator.reviewingGeneratedImage && illustrator.currentGeneratedImageUrl) {\n <div class=\"rtsee-illustrator-review-panel\">\n <div class=\"rtsee-illustrator-review-header\">\n <div class=\"rtsee-illustrator-review-title\">\n <span class=\"rtsee-illustrator-review-badge\">\n <i class=\"pi pi-sparkles\"></i> Reviewing Generated Image\n </span>\n <span class=\"rtsee-illustrator-review-sub\">Review the result, request iterative modifications, or discard.</span>\n </div>\n <div class=\"rtsee-illustrator-review-quick-actions\">\n <p-button\n label=\"Accept & Keep\"\n icon=\"pi pi-check\"\n severity=\"success\"\n (click)=\"acceptGeneratedImage()\"\n />\n <p-button\n label=\"Discard\"\n icon=\"pi pi-trash\"\n severity=\"danger\"\n [text]=\"true\"\n (click)=\"discardGeneratedImage()\"\n />\n </div>\n </div>\n\n <!-- Image Preview -->\n <div class=\"rtsee-illustrator-preview-box\">\n <img [src]=\"illustrator.currentGeneratedImageUrl\" alt=\"Generated fairy tale illustration\" class=\"rtsee-illustrator-preview-img\" />\n <a [href]=\"illustrator.currentGeneratedImageUrl\" target=\"_blank\" rel=\"noopener\" class=\"rtsee-illustrator-preview-zoom-btn\" title=\"Open full image in new tab\">\n <i class=\"pi pi-external-link\"></i> Full View\n </a>\n </div>\n\n <!-- Iteration Modification Controls -->\n <div class=\"rtsee-illustrator-iteration-box\">\n <div class=\"rtsee-illustrator-iteration-info\">\n <span class=\"rtsee-illustrator-iteration-tag\">\n <i class=\"pi pi-refresh\"></i> Request Modifications & Iterate\n </span>\n <span class=\"rtsee-illustrator-iteration-context-hint\">\n <i class=\"pi pi-info-circle\"></i>\n All active context references ({{ illustrator.activeContextImages.length }}) are sent to NanoBanana alongside this base picture.\n </span>\n </div>\n\n <textarea\n class=\"rtsee-illustrator-prompt-textarea rtsee-illustrator-prompt-textarea--iteration\"\n rows=\"3\"\n [(ngModel)]=\"illustrator.iterationPrompt\"\n placeholder=\"Describe modifications to apply to this picture (e.g. 'Make the wizard's cloak sapphire blue with silver runes, add glowing fireflies, soften the background trees')...\"\n (keydown.meta.enter)=\"submitIteration()\"\n (keydown.control.enter)=\"submitIteration()\"\n ></textarea>\n\n <div class=\"rtsee-illustrator-prompt-footer\">\n <span class=\"rtsee-illustrator-tip\">\n <i class=\"pi pi-info-circle\"></i>\n Press <strong>\u2318+Enter</strong> to iterate on this picture.\n </span>\n\n <div class=\"rtsee-illustrator-actions\">\n <p-button\n label=\"Discard\"\n icon=\"pi pi-trash\"\n severity=\"danger\"\n [text]=\"true\"\n (click)=\"discardGeneratedImage()\"\n />\n <p-button\n label=\"Iterate & Regenerate\"\n icon=\"pi pi-refresh\"\n [loading]=\"illustrator.submitting\"\n [disabled]=\"!illustrator.canSubmit\"\n (click)=\"submitIteration()\"\n />\n </div>\n </div>\n </div>\n </div>\n } @else {\n <!-- Prompt Input & Submit Action (Standard Mode) -->\n <div class=\"rtsee-illustrator-prompt-section\">\n <div class=\"rtsee-illustrator-prompt-box\">\n <textarea\n class=\"rtsee-illustrator-prompt-textarea\"\n rows=\"3\"\n [(ngModel)]=\"illustrator.prompt\"\n placeholder=\"Describe the fairy tale illustration to generate (e.g. 'A cozy cottage tucked deep inside the emerald moss woods, magical amber lanterns glowing warmly from the windows, soft fireflies in the air')...\"\n (keydown.meta.enter)=\"submitPrompt()\"\n (keydown.control.enter)=\"submitPrompt()\"\n ></textarea>\n\n <div class=\"rtsee-illustrator-prompt-footer\">\n <span class=\"rtsee-illustrator-tip\">\n <i class=\"pi pi-info-circle\"></i>\n Press <strong>\u2318+Enter</strong> to submit. Context characters, artifacts, locations & slides are sent to NanoBanana.\n </span>\n\n <div class=\"rtsee-illustrator-actions\">\n <p-button\n label=\"Generate Illustration\"\n icon=\"pi pi-sparkles\"\n [loading]=\"illustrator.submitting\"\n [disabled]=\"!illustrator.canSubmit\"\n (click)=\"submitPrompt()\"\n />\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "pipe", type: i1$3.SlicePipe, name: "slice" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5986
7231
  }
5987
7232
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: IllustratorComponent, decorators: [{
5988
7233
  type: Component,
@@ -6562,7 +7807,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
6562
7807
 
6563
7808
  class RtseeEntityCommentsComponent {
6564
7809
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RtseeEntityCommentsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6565
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RtseeEntityCommentsComponent, isStandalone: true, selector: "rtsee-entity-comments", inputs: { messenger: "messenger", chat: "chat", entity: "entity" }, ngImport: i0, template: "<div class=\"rtsee-entity-comments\" data-ugc=\"true\" rel=\"ugc\" aria-label=\"User comments\">\n @if (messenger && chat) {\n <rtsee-chat [messenger]=\"messenger\"\n [chatData]=\"chat\"\n [entity]=\"entity\"\n ></rtsee-chat>\n }\n</div>\n", dependencies: [{ kind: "component", type: ChatComponent, selector: "rtsee-chat", inputs: ["chat", "chatData", "entity", "messenger"] }] }); }
7810
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RtseeEntityCommentsComponent, isStandalone: true, selector: "rtsee-entity-comments", inputs: { messenger: "messenger", chat: "chat", entity: "entity" }, ngImport: i0, template: "<div class=\"rtsee-entity-comments\" data-ugc=\"true\" rel=\"ugc\" aria-label=\"User comments\">\n @if (messenger && chat) {\n <rtsee-chat [messenger]=\"messenger\"\n [chatData]=\"chat\"\n [entity]=\"entity\"\n ></rtsee-chat>\n }\n</div>\n", dependencies: [{ kind: "component", type: ChatComponent, selector: "rtsee-chat", inputs: ["chat", "chatData", "entity", "messenger", "isFramed"] }] }); }
6566
7811
  }
6567
7812
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RtseeEntityCommentsComponent, decorators: [{
6568
7813
  type: Component,
@@ -6622,12 +7867,14 @@ class RateInputComponent {
6622
7867
  }
6623
7868
  }
6624
7869
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RateInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6625
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RateInputComponent, isStandalone: true, selector: "rtsee-rate-input", inputs: { config: "config" }, ngImport: i0, template: "<div class=\"rtsee-rate-input\">\n <div class=\"rtsee-rate-input-header\">\n <h3 class=\"rtsee-rate-input-name\">{{ config.name }}</h3>\n @if (config.description) {\n <p class=\"rtsee-rate-input-description\">{{ config.description }}</p>\n }\n </div>\n <div class=\"rtsee-rate-form-container\">\n <form [formGroup]=\"sendRateForm\" class=\"rtsee-rate-form\">\n <textarea\n [invalid]=\"false\"\n [autoResize]=\"true\"\n formControlName=\"comment\"\n pTextarea\n placeholder=\"Your comment here...\"\n class=\"rtsee-rate-comment-field\"\n rows=\"1\"\n cols=\"30\"\n ></textarea>\n </form>\n </div>\n <div class=\"rtsee-rate-select-container\">\n <rtsee-rating [config]=\"config\"></rtsee-rating>\n @if (!config.rate?.value && showMissingRateError) {\n <p-message severity=\"error\">Please add your rate!</p-message>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "component", type: RatingComponent, selector: "rtsee-rating", inputs: ["config", "rate"] }, { kind: "component", type: Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }] }); }
7870
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RateInputComponent, isStandalone: true, selector: "rtsee-rate-input", inputs: { showMissingRateError: "showMissingRateError", config: "config" }, ngImport: i0, template: "<div class=\"rtsee-rate-input\">\n <div class=\"rtsee-rate-input-header\">\n <h3 class=\"rtsee-rate-input-name\">{{ config.name }}</h3>\n @if (config.description) {\n <p class=\"rtsee-rate-input-description\">{{ config.description }}</p>\n }\n </div>\n <div class=\"rtsee-rate-form-container\">\n <form [formGroup]=\"sendRateForm\" class=\"rtsee-rate-form\">\n <textarea\n [invalid]=\"false\"\n [autoResize]=\"true\"\n formControlName=\"comment\"\n pTextarea\n placeholder=\"Your comment here...\"\n class=\"rtsee-rate-comment-field\"\n rows=\"1\"\n cols=\"30\"\n ></textarea>\n </form>\n </div>\n <div class=\"rtsee-rate-select-container\">\n <rtsee-rating [config]=\"config\"></rtsee-rating>\n @if (!config.rate?.value && showMissingRateError) {\n <p-message severity=\"error\">Please add your rate!</p-message>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "component", type: RatingComponent, selector: "rtsee-rating", inputs: ["config", "rate"] }, { kind: "component", type: Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }] }); }
6626
7871
  }
6627
7872
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RateInputComponent, decorators: [{
6628
7873
  type: Component,
6629
7874
  args: [{ selector: 'rtsee-rate-input', imports: [ReactiveFormsModule, Textarea, RatingComponent, Message], standalone: true, template: "<div class=\"rtsee-rate-input\">\n <div class=\"rtsee-rate-input-header\">\n <h3 class=\"rtsee-rate-input-name\">{{ config.name }}</h3>\n @if (config.description) {\n <p class=\"rtsee-rate-input-description\">{{ config.description }}</p>\n }\n </div>\n <div class=\"rtsee-rate-form-container\">\n <form [formGroup]=\"sendRateForm\" class=\"rtsee-rate-form\">\n <textarea\n [invalid]=\"false\"\n [autoResize]=\"true\"\n formControlName=\"comment\"\n pTextarea\n placeholder=\"Your comment here...\"\n class=\"rtsee-rate-comment-field\"\n rows=\"1\"\n cols=\"30\"\n ></textarea>\n </form>\n </div>\n <div class=\"rtsee-rate-select-container\">\n <rtsee-rating [config]=\"config\"></rtsee-rating>\n @if (!config.rate?.value && showMissingRateError) {\n <p-message severity=\"error\">Please add your rate!</p-message>\n }\n </div>\n</div>\n" }]
6630
- }], propDecorators: { config: [{
7875
+ }], propDecorators: { showMissingRateError: [{
7876
+ type: Input
7877
+ }], config: [{
6631
7878
  type: Input
6632
7879
  }] } });
6633
7880
 
@@ -6673,6 +7920,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
6673
7920
  class RaterComponent {
6674
7921
  constructor() {
6675
7922
  this.isEditing = false;
7923
+ this.showMissingRateError = false;
6676
7924
  this.RTSeeTextLabelKeys = RTSeeTextLabelKeys;
6677
7925
  }
6678
7926
  ngOnInit() {
@@ -6688,6 +7936,13 @@ class RaterComponent {
6688
7936
  const rates = this.rater.configsWithRates
6689
7937
  .map((config) => config.rate)
6690
7938
  .filter((r) => !!r);
7939
+ const hasInvalidRate = rates.length === 0 ||
7940
+ rates.some((r) => typeof r.value !== 'number' || !Number.isFinite(r.value) || r.value <= 0);
7941
+ if (hasInvalidRate) {
7942
+ this.showMissingRateError = true;
7943
+ return;
7944
+ }
7945
+ this.showMissingRateError = false;
6691
7946
  if (this.rater.userRateGroup) {
6692
7947
  await this.rater.editRateGroup({
6693
7948
  ...this.rater.userRateGroup,
@@ -6712,6 +7967,7 @@ class RaterComponent {
6712
7967
  }
6713
7968
  }
6714
7969
  startEdit() {
7970
+ this.showMissingRateError = false;
6715
7971
  this.isEditing = true;
6716
7972
  }
6717
7973
  async getRatingConfigurations() {
@@ -6724,11 +7980,11 @@ class RaterComponent {
6724
7980
  return rates;
6725
7981
  }
6726
7982
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RaterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6727
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RaterComponent, isStandalone: true, selector: "rtsee-rater", inputs: { entity: "entity", rater: "rater" }, ngImport: i0, template: "<div class=\"rtsee-rater\" [ngClass]=\"{'rtsee-rater-view-mode': rater.userRateGroup && !isEditing}\">\n @if (rater.userRateGroup && !isEditing) {\n <rtsee-rate-item\n [group]=\"rater.userRateGroup\"\n [rater]=\"rater\"\n [showActions]=\"true\"\n (edit)=\"startEdit()\"\n (delete)=\"deleteRate()\"\n ></rtsee-rate-item>\n } @else {\n <div class=\"rtsee-rater-user-header\">\n @if (rater.peer?.imageUrl) {\n <img\n class=\"rtsee-rater-avatar\"\n [src]=\"rater.peer?.imageUrl\"\n alt=\"User avatar\"\n />\n } @else {\n <div class=\"rtsee-rater-avatar-fallback\">\n {{ (rater.peer?.name || \"?\").substring(0, 1) }}\n </div>\n }\n <div class=\"rtsee-rater-user-info\">\n <span class=\"rtsee-rater-user-name\">{{\n rater.peer?.name || \"Anonymous\"\n }}</span>\n <span class=\"rtsee-rater-user-status\">Rating publicly</span>\n </div>\n </div>\n <hr class=\"rtsee-rater-divider\" />\n @for (config of rater.configsWithRates; track config.id) {\n <rtsee-rate-input [config]=\"config\"></rtsee-rate-input>\n }\n <div class=\"rtsee-rater-actions\">\n @if (rater.userRateGroup) {\n <p-button\n (click)=\"sendRate()\"\n [severity]=\"'success'\"\n [label]=\"rater.messenger.labels[RTSeeTextLabelKeys.RATER_UPDATE]\"\n type=\"submit\"\n class=\"rtsee-rater-btn-update rts-action-button\"\n >\n <span class=\"pi pi-check\"></span>\n </p-button>\n <p-button\n (click)=\"deleteRate()\"\n [severity]=\"'danger'\"\n [label]=\"rater.messenger.labels[RTSeeTextLabelKeys.RATER_DELETE]\"\n class=\"rtsee-rater-btn-delete rts-action-button\"\n >\n <span class=\"pi pi-trash\"></span>\n </p-button>\n } @else {\n <p-button\n (click)=\"sendRate()\"\n [severity]=\"'primary'\"\n [label]=\"rater.messenger.labels[RTSeeTextLabelKeys.RATER_SEND]\"\n type=\"submit\"\n class=\"rtsee-rater-btn-send rts-action-button\"\n >\n <span class=\"pi pi-send\"></span>\n </p-button>\n }\n </div>\n }\n</div>\n", dependencies: [{ kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: RateInputComponent, selector: "rtsee-rate-input", inputs: ["config"] }, { kind: "component", type: RateItemComponent, selector: "rtsee-rate-item", inputs: ["group", "rater", "showActions"], outputs: ["edit", "delete"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
7983
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RaterComponent, isStandalone: true, selector: "rtsee-rater", inputs: { entity: "entity", rater: "rater" }, ngImport: i0, template: "<div class=\"rtsee-rater\" [ngClass]=\"{'rtsee-rater-view-mode': rater.userRateGroup && !isEditing}\">\n @if (rater.userRateGroup && !isEditing) {\n <rtsee-rate-item\n [group]=\"rater.userRateGroup\"\n [rater]=\"rater\"\n [showActions]=\"true\"\n (edit)=\"startEdit()\"\n (delete)=\"deleteRate()\"\n ></rtsee-rate-item>\n } @else {\n <div class=\"rtsee-rater-user-header\">\n @if (rater.peer?.imageUrl) {\n <img\n class=\"rtsee-rater-avatar\"\n [src]=\"rater.peer?.imageUrl\"\n alt=\"User avatar\"\n />\n } @else {\n <div class=\"rtsee-rater-avatar-fallback\">\n {{ (rater.peer?.name || \"?\").substring(0, 1) }}\n </div>\n }\n <div class=\"rtsee-rater-user-info\">\n <span class=\"rtsee-rater-user-name\">{{\n rater.peer?.name || \"Anonymous\"\n }}</span>\n <span class=\"rtsee-rater-user-status\">Rating publicly</span>\n </div>\n </div>\n <hr class=\"rtsee-rater-divider\" />\n @for (config of rater.configsWithRates; track config.id) {\n <rtsee-rate-input\n [config]=\"config\"\n [showMissingRateError]=\"showMissingRateError\"\n ></rtsee-rate-input>\n }\n <div class=\"rtsee-rater-actions\">\n @if (rater.userRateGroup) {\n <p-button\n (click)=\"sendRate()\"\n [severity]=\"'success'\"\n [label]=\"rater.messenger.labels[RTSeeTextLabelKeys.RATER_UPDATE]\"\n type=\"submit\"\n class=\"rtsee-rater-btn-update rts-action-button\"\n >\n <span class=\"pi pi-check\"></span>\n </p-button>\n <p-button\n (click)=\"deleteRate()\"\n [severity]=\"'danger'\"\n [label]=\"rater.messenger.labels[RTSeeTextLabelKeys.RATER_DELETE]\"\n class=\"rtsee-rater-btn-delete rts-action-button\"\n >\n <span class=\"pi pi-trash\"></span>\n </p-button>\n } @else {\n <p-button\n (click)=\"sendRate()\"\n [severity]=\"'primary'\"\n [label]=\"rater.messenger.labels[RTSeeTextLabelKeys.RATER_SEND]\"\n type=\"submit\"\n class=\"rtsee-rater-btn-send rts-action-button\"\n >\n <span class=\"pi pi-send\"></span>\n </p-button>\n }\n </div>\n }\n</div>\n", dependencies: [{ kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: RateInputComponent, selector: "rtsee-rate-input", inputs: ["showMissingRateError", "config"] }, { kind: "component", type: RateItemComponent, selector: "rtsee-rate-item", inputs: ["group", "rater", "showActions"], outputs: ["edit", "delete"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
6728
7984
  }
6729
7985
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RaterComponent, decorators: [{
6730
7986
  type: Component,
6731
- args: [{ selector: 'rtsee-rater', imports: [Button, RateInputComponent, RateItemComponent, NgClass], template: "<div class=\"rtsee-rater\" [ngClass]=\"{'rtsee-rater-view-mode': rater.userRateGroup && !isEditing}\">\n @if (rater.userRateGroup && !isEditing) {\n <rtsee-rate-item\n [group]=\"rater.userRateGroup\"\n [rater]=\"rater\"\n [showActions]=\"true\"\n (edit)=\"startEdit()\"\n (delete)=\"deleteRate()\"\n ></rtsee-rate-item>\n } @else {\n <div class=\"rtsee-rater-user-header\">\n @if (rater.peer?.imageUrl) {\n <img\n class=\"rtsee-rater-avatar\"\n [src]=\"rater.peer?.imageUrl\"\n alt=\"User avatar\"\n />\n } @else {\n <div class=\"rtsee-rater-avatar-fallback\">\n {{ (rater.peer?.name || \"?\").substring(0, 1) }}\n </div>\n }\n <div class=\"rtsee-rater-user-info\">\n <span class=\"rtsee-rater-user-name\">{{\n rater.peer?.name || \"Anonymous\"\n }}</span>\n <span class=\"rtsee-rater-user-status\">Rating publicly</span>\n </div>\n </div>\n <hr class=\"rtsee-rater-divider\" />\n @for (config of rater.configsWithRates; track config.id) {\n <rtsee-rate-input [config]=\"config\"></rtsee-rate-input>\n }\n <div class=\"rtsee-rater-actions\">\n @if (rater.userRateGroup) {\n <p-button\n (click)=\"sendRate()\"\n [severity]=\"'success'\"\n [label]=\"rater.messenger.labels[RTSeeTextLabelKeys.RATER_UPDATE]\"\n type=\"submit\"\n class=\"rtsee-rater-btn-update rts-action-button\"\n >\n <span class=\"pi pi-check\"></span>\n </p-button>\n <p-button\n (click)=\"deleteRate()\"\n [severity]=\"'danger'\"\n [label]=\"rater.messenger.labels[RTSeeTextLabelKeys.RATER_DELETE]\"\n class=\"rtsee-rater-btn-delete rts-action-button\"\n >\n <span class=\"pi pi-trash\"></span>\n </p-button>\n } @else {\n <p-button\n (click)=\"sendRate()\"\n [severity]=\"'primary'\"\n [label]=\"rater.messenger.labels[RTSeeTextLabelKeys.RATER_SEND]\"\n type=\"submit\"\n class=\"rtsee-rater-btn-send rts-action-button\"\n >\n <span class=\"pi pi-send\"></span>\n </p-button>\n }\n </div>\n }\n</div>\n" }]
7987
+ args: [{ selector: 'rtsee-rater', imports: [Button, RateInputComponent, RateItemComponent, NgClass], template: "<div class=\"rtsee-rater\" [ngClass]=\"{'rtsee-rater-view-mode': rater.userRateGroup && !isEditing}\">\n @if (rater.userRateGroup && !isEditing) {\n <rtsee-rate-item\n [group]=\"rater.userRateGroup\"\n [rater]=\"rater\"\n [showActions]=\"true\"\n (edit)=\"startEdit()\"\n (delete)=\"deleteRate()\"\n ></rtsee-rate-item>\n } @else {\n <div class=\"rtsee-rater-user-header\">\n @if (rater.peer?.imageUrl) {\n <img\n class=\"rtsee-rater-avatar\"\n [src]=\"rater.peer?.imageUrl\"\n alt=\"User avatar\"\n />\n } @else {\n <div class=\"rtsee-rater-avatar-fallback\">\n {{ (rater.peer?.name || \"?\").substring(0, 1) }}\n </div>\n }\n <div class=\"rtsee-rater-user-info\">\n <span class=\"rtsee-rater-user-name\">{{\n rater.peer?.name || \"Anonymous\"\n }}</span>\n <span class=\"rtsee-rater-user-status\">Rating publicly</span>\n </div>\n </div>\n <hr class=\"rtsee-rater-divider\" />\n @for (config of rater.configsWithRates; track config.id) {\n <rtsee-rate-input\n [config]=\"config\"\n [showMissingRateError]=\"showMissingRateError\"\n ></rtsee-rate-input>\n }\n <div class=\"rtsee-rater-actions\">\n @if (rater.userRateGroup) {\n <p-button\n (click)=\"sendRate()\"\n [severity]=\"'success'\"\n [label]=\"rater.messenger.labels[RTSeeTextLabelKeys.RATER_UPDATE]\"\n type=\"submit\"\n class=\"rtsee-rater-btn-update rts-action-button\"\n >\n <span class=\"pi pi-check\"></span>\n </p-button>\n <p-button\n (click)=\"deleteRate()\"\n [severity]=\"'danger'\"\n [label]=\"rater.messenger.labels[RTSeeTextLabelKeys.RATER_DELETE]\"\n class=\"rtsee-rater-btn-delete rts-action-button\"\n >\n <span class=\"pi pi-trash\"></span>\n </p-button>\n } @else {\n <p-button\n (click)=\"sendRate()\"\n [severity]=\"'primary'\"\n [label]=\"rater.messenger.labels[RTSeeTextLabelKeys.RATER_SEND]\"\n type=\"submit\"\n class=\"rtsee-rater-btn-send rts-action-button\"\n >\n <span class=\"pi pi-send\"></span>\n </p-button>\n }\n </div>\n }\n</div>\n" }]
6732
7988
  }], propDecorators: { entity: [{
6733
7989
  type: Input
6734
7990
  }], rater: [{
@@ -7017,11 +8273,11 @@ class StoryDetailsComponent {
7017
8273
  return stars;
7018
8274
  }
7019
8275
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryDetailsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7020
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: StoryDetailsComponent, isStandalone: true, selector: "rtsee-story-details", inputs: { story: "story", presentation: "presentation", messenger: "messenger" }, ngImport: i0, template: "<div\n class=\"rtsee-story-details\"\n itemscope\n itemtype=\"https://schema.org/ShortStory\"\n>\n @if (story.imageUrl) {\n <meta itemprop=\"image\" [attr.content]=\"story.imageUrl\" />\n }\n @if (story.languageKey) {\n <meta itemprop=\"inLanguage\" [attr.content]=\"story.languageKey === 'ua' ? 'uk' : 'en'\" />\n }\n @if (story.totalSlides) {\n <meta itemprop=\"numberOfPages\" [attr.content]=\"story.totalSlides\" />\n }\n <section\n class=\"rtsee-story-details-cover\"\n [style.background-image]=\"'url(' + story.imageUrl + ')'\"\n >\n <button\n class=\"rtsee-story-details-btn-close\"\n [routerLink]=\"[presentation.homePage]\"\n (click)=\"presentation.closeStoryDetails()\"\n aria-label=\"Close\"\n >\n <span class=\"pi pi-times\"></span>\n </button>\n <div class=\"rtsee-story-details-cover-overlay\"></div>\n <div class=\"rtsee-story-details-cover-content\">\n <div class=\"rtsee-story-details-cover-badges\">\n @if (story.categories?.length && false) {\n @for (category of story.categories; track category.id) {\n <span class=\"rtsee-story-details-tag-pill\">\n {{ category.name }}\n </span>\n }\n }\n @if (story.tags?.length) {\n @for (tag of story.tags; track tag.id) {\n <span\n class=\"rtsee-story-details-tag-pill rtsee-story-details-tag-pill-label\"\n >\n @if (tag.symbol) {\n <span class=\"symbol\">{{ tag.symbol }}</span>\n }\n {{ tag.name }}\n </span>\n }\n }\n </div>\n\n <h1 class=\"rtsee-story-details-cover-title\" itemprop=\"name\">{{ story.name }}</h1>\n\n <div class=\"rtsee-story-details-cover-meta\">\n @if (story.rating !== null) {\n <div\n class=\"rtsee-story-details-cover-rating\"\n itemprop=\"aggregateRating\"\n itemscope\n itemtype=\"https://schema.org/AggregateRating\"\n >\n <meta itemprop=\"bestRating\" content=\"5\" />\n <meta itemprop=\"worstRating\" content=\"1\" />\n <span class=\"rtsee-story-details-stars\">\n @for (star of getStarArray(story.rating); track $index) {\n <span\n class=\"rtsee-story-details-star\"\n [class.rtsee-story-details-star-full]=\"star === 'full'\"\n [class.rtsee-story-details-star-half]=\"star === 'half'\"\n [class.rtsee-story-details-star-empty]=\"star === 'empty'\"\n >\n @if (star === \"full\") {\n \u2605\n } @else if (star === \"half\") {\n \u2605\n } @else {\n \u2606\n }\n </span>\n }\n </span>\n <span class=\"rtsee-story-details-rating-number\" itemprop=\"ratingValue\">{{\n story.rating\n }}</span>\n @if (story.ratesCount !== null) {\n <meta itemprop=\"ratingCount\" [attr.content]=\"story.ratesCount\" />\n <span class=\"rtsee-story-details-rating-count\">\n <span>(</span>\n <span>{{ presentation.labels[RTSeeTextLabelKeys.FEEDBACKS_LABEL] }}:</span>\n <span>&nbsp;</span>\n <span itemprop=\"reviewCount\">{{ story.ratesCount }}</span>\n <span>)</span>\n </span\n >\n }\n </div>\n }\n </div>\n </div>\n </section>\n\n <!-- CONTENT AREA -->\n <div class=\"rtsee-story-details-content-wrapper\">\n <!-- Reading panel: what the user is about to read + the main CTA -->\n <section class=\"rtsee-story-details-reading-panel\" aria-label=\"{{ story.name }}\">\n @if (story.totalSlides) {\n <rtsee-story-slides-preview\n [story]=\"story\"\n [slidesLabel]=\"presentation.labels[RTSeeTextLabelKeys.STORY_PAGES_LABEL]\"\n [minuteLabel]=\"presentation.labels[RTSeeTextLabelKeys.MINUTE_LABEL]\"\n ></rtsee-story-slides-preview>\n }\n <p-button\n (click)=\"presentation.setActiveStory(story)\"\n [severity]=\"'primary'\"\n [label]=\"story.preselectedSlideNumber ? presentation.labels[RTSeeTextLabelKeys.CONTINUE_READING_BUTTON] : presentation.labels[RTSeeTextLabelKeys.START_READING_BUTTON]\"\n icon=\"pi pi-book\"\n iconPos=\"left\"\n class=\"rtsee-story-details-start-reading rts-action-button\"\n >\n </p-button>\n </section>\n <div class=\"rtsee-story-details-content-grid\">\n <!-- Description Card -->\n <article class=\"rtsee-story-details-glass-card\">\n <div class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z\" />\n <path d=\"M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z\" />\n </svg>\n <h2>{{presentation.labels[RTSeeTextLabelKeys.STORY_ABOUT_LABEL]}}</h2>\n </div>\n <p class=\"rtsee-story-details-glass-card-text\" itemprop=\"description\">\n {{ story.description }}\n </p>\n </article>\n\n @if (story.history) {\n <article class=\"rtsee-story-details-glass-card\">\n <div class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12 6 12 12 14 14\" />\n </svg>\n <h2>{{presentation.labels[RTSeeTextLabelKeys.STORY_HISTORY_LABEL]}}</h2>\n </div>\n <p class=\"rtsee-story-details-glass-card-text\" itemprop=\"backstory\">\n {{ story.history }}\n </p>\n </article>\n }\n\n @if (story.moralMeaning) {\n <article class=\"rtsee-story-details-glass-card\">\n <div class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\" />\n </svg>\n <h2>{{presentation.labels[RTSeeTextLabelKeys.STORY_MORAL_LABEL]}}</h2>\n </div>\n <p class=\"rtsee-story-details-glass-card-text\" itemprop=\"teaches\">\n {{ story.moralMeaning }}\n </p>\n </article>\n }\n </div>\n\n <!-- Author -->\n @if (story.author) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-author-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M12 20h9\" />\n <path d=\"M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z\" />\n </svg>\n <h2 id=\"rtsee-story-details-author-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.STORY_AUTHOR_LABEL] }}\n </h2>\n </header>\n <div class=\"rtsee-story-details-elements-featured\">\n <rtsee-story-element-thumbnail\n [name]=\"story.author.name\"\n [description]=\"story.author.description\"\n [imageUrl]=\"story.author.imageUrl\"\n itemProp=\"author\"\n schemaType=\"Person\"\n [horizontal]=\"true\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </div>\n </section>\n }\n\n <!-- Characters -->\n @if (story.characters.length) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-characters-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\" />\n <circle cx=\"9\" cy=\"7\" r=\"4\" />\n <path d=\"M23 21v-2a4 4 0 0 0-3-3.87\" />\n <path d=\"M16 3.13a4 4 0 0 1 0 7.75\" />\n </svg>\n <h2 id=\"rtsee-story-details-characters-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.CHARACTERS_LABEL] }}\n </h2>\n </header>\n <ul class=\"rtsee-story-details-elements-grid\" role=\"list\">\n @for (character of story.characters; track character.id) {\n <li class=\"rtsee-story-details-elements-item\">\n <rtsee-story-element-thumbnail\n [name]=\"character.name\"\n [description]=\"character.description\"\n [imageUrl]=\"character.imageUrl\"\n itemProp=\"character\"\n schemaType=\"Person\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </li>\n }\n </ul>\n </section>\n }\n\n <!-- Artifacts -->\n @if (story.artifacts.length) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-artifacts-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M6 3h12l4 6-10 13L2 9z\" />\n <path d=\"M11 3 8 9l4 13 4-13-3-6\" />\n <path d=\"M2 9h20\" />\n </svg>\n <h2 id=\"rtsee-story-details-artifacts-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.ARTIFACTS_LABEL] }}\n </h2>\n </header>\n <ul class=\"rtsee-story-details-elements-grid\" role=\"list\">\n @for (artifact of story.artifacts; track artifact.id) {\n <li class=\"rtsee-story-details-elements-item\">\n <rtsee-story-element-thumbnail\n [name]=\"artifact.name\"\n [description]=\"artifact.description\"\n [imageUrl]=\"artifact.imageUrl\"\n itemProp=\"mentions\"\n schemaType=\"Thing\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </li>\n }\n </ul>\n </section>\n }\n\n <!-- Places -->\n @if (story.locations.length) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-places-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\" />\n <circle cx=\"12\" cy=\"10\" r=\"3\" />\n </svg>\n <h2 id=\"rtsee-story-details-places-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.LOCATIONS_LABEL] }}\n </h2>\n </header>\n <ul class=\"rtsee-story-details-elements-grid\" role=\"list\">\n @for (place of story.locations; track place.id) {\n <li class=\"rtsee-story-details-elements-item\">\n <rtsee-story-element-thumbnail\n [name]=\"place.name\"\n [description]=\"place.description\"\n [imageUrl]=\"place.imageUrl\"\n itemProp=\"contentLocation\"\n schemaType=\"Place\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </li>\n }\n </ul>\n </section>\n }\n\n @if (messenger) {\n <rtsee-entity-preview\n [entity]=\"story\"\n [messenger]=\"messenger\"\n ></rtsee-entity-preview>\n }\n\n @if (story.categories?.length && false) {\n <div class=\"rtsee-story-details-categories\">\n @for (category of story.categories; track category.id) {\n <p-tag [value]=\"category.name\"></p-tag>\n }\n </div>\n }\n\n @if (story.tags?.length && false) {\n <div class=\"rtsee-story-details-labels\">\n @for (tag of story.tags; track tag.id) {\n <p-chip class=\"rtsee-story-details-label\">\n @if (tag.symbol) {\n <span class=\"rtsee-story-details-label-left\">{{\n tag.symbol\n }}</span>\n }\n <span class=\"rtsee-story-details-label-right\">{{\n tag.name\n }}</span>\n </p-chip>\n }\n </div>\n }\n\n <div class=\"rtsee-story-details-description-history\"></div>\n @if (story.isPublished && false) {\n <div class=\"rtsee-story-details-feedback\">\n <p>feedback here</p>\n </div>\n } @else if (messenger && story.discussion && false) {\n <div class=\"rtsee-story-details-votes\">\n <p class=\"rtsee-story-details-comments-label\">Comments</p>\n <rtsee-chat\n [messenger]=\"messenger\"\n [chatData]=\"story.discussion\"\n ></rtsee-chat>\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "component", type: Chip, selector: "p-chip", inputs: ["label", "icon", "image", "alt", "styleClass", "disabled", "removable", "removeIcon", "chipProps"], outputs: ["onRemove", "onImageError"] }, { kind: "component", type: Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: ChatComponent, selector: "rtsee-chat", inputs: ["chat", "chatData", "entity", "messenger"] }, { kind: "component", type: RtseeEntityPreviewComponent, selector: "rtsee-entity-preview", inputs: ["entity", "messenger"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: StoryElementThumbnailComponent, selector: "rtsee-story-element-thumbnail", inputs: ["name", "description", "imageUrl", "itemProp", "schemaType", "horizontal", "showMoreLabel", "showLessLabel"] }, { kind: "component", type: StorySlidesPreviewComponent, selector: "rtsee-story-slides-preview", inputs: ["story", "slidesLabel", "minuteLabel", "count"] }] }); }
8276
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: StoryDetailsComponent, isStandalone: true, selector: "rtsee-story-details", inputs: { story: "story", presentation: "presentation", messenger: "messenger" }, ngImport: i0, template: "<div\n class=\"rtsee-story-details\"\n itemscope\n itemtype=\"https://schema.org/Book\"\n>\n @if (story.imageUrl) {\n <meta itemprop=\"image\" [attr.content]=\"story.imageUrl\" />\n }\n @if (story.languageKey) {\n <meta itemprop=\"inLanguage\" [attr.content]=\"story.languageKey === 'ua' ? 'uk' : 'en'\" />\n }\n @if (story.totalSlides) {\n <meta itemprop=\"numberOfPages\" [attr.content]=\"story.totalSlides\" />\n }\n <section\n class=\"rtsee-story-details-cover\"\n [style.background-image]=\"'url(' + story.imageUrl + ')'\"\n >\n <button\n class=\"rtsee-story-details-btn-close\"\n [routerLink]=\"[presentation.homePage]\"\n (click)=\"presentation.closeStoryDetails()\"\n aria-label=\"Close\"\n >\n <span class=\"pi pi-times\"></span>\n </button>\n <div class=\"rtsee-story-details-cover-overlay\"></div>\n <div class=\"rtsee-story-details-cover-content\">\n <div class=\"rtsee-story-details-cover-badges\">\n @if (story.categories?.length && false) {\n @for (category of story.categories; track category.id) {\n <span class=\"rtsee-story-details-tag-pill\">\n {{ category.name }}\n </span>\n }\n }\n @if (story.tags?.length) {\n @for (tag of story.tags; track tag.id) {\n <span\n class=\"rtsee-story-details-tag-pill rtsee-story-details-tag-pill-label\"\n >\n @if (tag.symbol) {\n <span class=\"symbol\">{{ tag.symbol }}</span>\n }\n {{ tag.name }}\n </span>\n }\n }\n </div>\n\n <h1 class=\"rtsee-story-details-cover-title\" itemprop=\"name\">{{ story.name }}</h1>\n\n <div class=\"rtsee-story-details-cover-meta\">\n @if (story.rating && story.rating > 0) {\n <div\n class=\"rtsee-story-details-cover-rating\"\n itemprop=\"aggregateRating\"\n itemscope\n itemtype=\"https://schema.org/AggregateRating\"\n >\n <meta itemprop=\"bestRating\" content=\"5\" />\n <meta itemprop=\"worstRating\" content=\"1\" />\n <span class=\"rtsee-story-details-stars\">\n @for (star of getStarArray(story.rating); track $index) {\n <span\n class=\"rtsee-story-details-star\"\n [class.rtsee-story-details-star-full]=\"star === 'full'\"\n [class.rtsee-story-details-star-half]=\"star === 'half'\"\n [class.rtsee-story-details-star-empty]=\"star === 'empty'\"\n >\n @if (star === \"full\") {\n \u2605\n } @else if (star === \"half\") {\n \u2605\n } @else {\n \u2606\n }\n </span>\n }\n </span>\n <span class=\"rtsee-story-details-rating-number\" itemprop=\"ratingValue\">{{\n story.rating\n }}</span>\n <meta itemprop=\"ratingCount\" [attr.content]=\"story.ratesCount || 1\" />\n <span class=\"rtsee-story-details-rating-count\">\n <span>(</span>\n <span>{{ presentation.labels[RTSeeTextLabelKeys.FEEDBACKS_LABEL] }}:</span>\n <span>&nbsp;</span>\n <span itemprop=\"reviewCount\">{{ story.ratesCount || 1 }}</span>\n <span>)</span>\n </span\n >\n </div>\n }\n </div>\n </div>\n </section>\n\n <!-- CONTENT AREA -->\n <div class=\"rtsee-story-details-content-wrapper\">\n <!-- Reading panel: what the user is about to read + the main CTA -->\n <section class=\"rtsee-story-details-reading-panel\" aria-label=\"{{ story.name }}\">\n @if (story.totalSlides) {\n <rtsee-story-slides-preview\n [story]=\"story\"\n [slidesLabel]=\"presentation.labels[RTSeeTextLabelKeys.STORY_PAGES_LABEL]\"\n [minuteLabel]=\"presentation.labels[RTSeeTextLabelKeys.MINUTE_LABEL]\"\n ></rtsee-story-slides-preview>\n }\n <p-button\n (click)=\"presentation.setActiveStory(story)\"\n [severity]=\"'primary'\"\n [label]=\"story.preselectedSlideNumber ? presentation.labels[RTSeeTextLabelKeys.CONTINUE_READING_BUTTON] : presentation.labels[RTSeeTextLabelKeys.START_READING_BUTTON]\"\n icon=\"pi pi-book\"\n iconPos=\"left\"\n class=\"rtsee-story-details-start-reading rts-action-button\"\n >\n </p-button>\n </section>\n <div class=\"rtsee-story-details-content-grid\">\n <!-- Description Card -->\n <article class=\"rtsee-story-details-glass-card\">\n <div class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z\" />\n <path d=\"M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z\" />\n </svg>\n <h2>{{presentation.labels[RTSeeTextLabelKeys.STORY_ABOUT_LABEL]}}</h2>\n </div>\n <p class=\"rtsee-story-details-glass-card-text\" itemprop=\"description\">\n {{ story.description }}\n </p>\n </article>\n\n @if (story.history) {\n <article class=\"rtsee-story-details-glass-card\">\n <div class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12 6 12 12 14 14\" />\n </svg>\n <h2>{{presentation.labels[RTSeeTextLabelKeys.STORY_HISTORY_LABEL]}}</h2>\n </div>\n <p class=\"rtsee-story-details-glass-card-text\" itemprop=\"backstory\">\n {{ story.history }}\n </p>\n </article>\n }\n\n @if (story.moralMeaning) {\n <article class=\"rtsee-story-details-glass-card\">\n <div class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\" />\n </svg>\n <h2>{{presentation.labels[RTSeeTextLabelKeys.STORY_MORAL_LABEL]}}</h2>\n </div>\n <p class=\"rtsee-story-details-glass-card-text\" itemprop=\"teaches\">\n {{ story.moralMeaning }}\n </p>\n </article>\n }\n </div>\n\n <!-- Author -->\n @if (story.author) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-author-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M12 20h9\" />\n <path d=\"M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z\" />\n </svg>\n <h2 id=\"rtsee-story-details-author-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.STORY_AUTHOR_LABEL] }}\n </h2>\n </header>\n <div class=\"rtsee-story-details-elements-featured\">\n <rtsee-story-element-thumbnail\n [name]=\"story.author.name\"\n [description]=\"story.author.description\"\n [imageUrl]=\"story.author.imageUrl\"\n itemProp=\"author\"\n schemaType=\"Person\"\n [horizontal]=\"true\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </div>\n </section>\n }\n\n <!-- Characters -->\n @if (story.characters.length) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-characters-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\" />\n <circle cx=\"9\" cy=\"7\" r=\"4\" />\n <path d=\"M23 21v-2a4 4 0 0 0-3-3.87\" />\n <path d=\"M16 3.13a4 4 0 0 1 0 7.75\" />\n </svg>\n <h2 id=\"rtsee-story-details-characters-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.CHARACTERS_LABEL] }}\n </h2>\n </header>\n <ul class=\"rtsee-story-details-elements-grid\" role=\"list\">\n @for (character of story.characters; track character.id) {\n <li class=\"rtsee-story-details-elements-item\">\n <rtsee-story-element-thumbnail\n [name]=\"character.name\"\n [description]=\"character.description\"\n [imageUrl]=\"character.imageUrl\"\n itemProp=\"character\"\n schemaType=\"Person\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </li>\n }\n </ul>\n </section>\n }\n\n <!-- Artifacts -->\n @if (story.artifacts.length) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-artifacts-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M6 3h12l4 6-10 13L2 9z\" />\n <path d=\"M11 3 8 9l4 13 4-13-3-6\" />\n <path d=\"M2 9h20\" />\n </svg>\n <h2 id=\"rtsee-story-details-artifacts-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.ARTIFACTS_LABEL] }}\n </h2>\n </header>\n <ul class=\"rtsee-story-details-elements-grid\" role=\"list\">\n @for (artifact of story.artifacts; track artifact.id) {\n <li class=\"rtsee-story-details-elements-item\">\n <rtsee-story-element-thumbnail\n [name]=\"artifact.name\"\n [description]=\"artifact.description\"\n [imageUrl]=\"artifact.imageUrl\"\n itemProp=\"mentions\"\n schemaType=\"Thing\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </li>\n }\n </ul>\n </section>\n }\n\n <!-- Places -->\n @if (story.locations.length) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-places-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\" />\n <circle cx=\"12\" cy=\"10\" r=\"3\" />\n </svg>\n <h2 id=\"rtsee-story-details-places-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.LOCATIONS_LABEL] }}\n </h2>\n </header>\n <ul class=\"rtsee-story-details-elements-grid\" role=\"list\">\n @for (place of story.locations; track place.id) {\n <li class=\"rtsee-story-details-elements-item\">\n <rtsee-story-element-thumbnail\n [name]=\"place.name\"\n [description]=\"place.description\"\n [imageUrl]=\"place.imageUrl\"\n itemProp=\"contentLocation\"\n schemaType=\"Place\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </li>\n }\n </ul>\n </section>\n }\n\n @if (messenger) {\n <rtsee-entity-preview\n [entity]=\"story\"\n [messenger]=\"messenger\"\n ></rtsee-entity-preview>\n }\n\n @if (story.categories?.length && false) {\n <div class=\"rtsee-story-details-categories\">\n @for (category of story.categories; track category.id) {\n <p-tag [value]=\"category.name\"></p-tag>\n }\n </div>\n }\n\n @if (story.tags?.length && false) {\n <div class=\"rtsee-story-details-labels\">\n @for (tag of story.tags; track tag.id) {\n <p-chip class=\"rtsee-story-details-label\">\n @if (tag.symbol) {\n <span class=\"rtsee-story-details-label-left\">{{\n tag.symbol\n }}</span>\n }\n <span class=\"rtsee-story-details-label-right\">{{\n tag.name\n }}</span>\n </p-chip>\n }\n </div>\n }\n\n <div class=\"rtsee-story-details-description-history\"></div>\n @if (story.isPublished && false) {\n <div class=\"rtsee-story-details-feedback\">\n <p>feedback here</p>\n </div>\n } @else if (messenger && story.discussion && false) {\n <div class=\"rtsee-story-details-votes\">\n <p class=\"rtsee-story-details-comments-label\">Comments</p>\n <rtsee-chat\n [messenger]=\"messenger\"\n [chatData]=\"story.discussion\"\n ></rtsee-chat>\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "component", type: Chip, selector: "p-chip", inputs: ["label", "icon", "image", "alt", "styleClass", "disabled", "removable", "removeIcon", "chipProps"], outputs: ["onRemove", "onImageError"] }, { kind: "component", type: Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: ChatComponent, selector: "rtsee-chat", inputs: ["chat", "chatData", "entity", "messenger", "isFramed"] }, { kind: "component", type: RtseeEntityPreviewComponent, selector: "rtsee-entity-preview", inputs: ["entity", "messenger"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: StoryElementThumbnailComponent, selector: "rtsee-story-element-thumbnail", inputs: ["name", "description", "imageUrl", "itemProp", "schemaType", "horizontal", "showMoreLabel", "showLessLabel"] }, { kind: "component", type: StorySlidesPreviewComponent, selector: "rtsee-story-slides-preview", inputs: ["story", "slidesLabel", "minuteLabel", "count"] }] }); }
7021
8277
  }
7022
8278
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryDetailsComponent, decorators: [{
7023
8279
  type: Component,
7024
- args: [{ selector: 'rtsee-story-details', imports: [Chip, Tag, Button, ChatComponent, RtseeEntityPreviewComponent, RouterLink, StoryElementThumbnailComponent, StorySlidesPreviewComponent], template: "<div\n class=\"rtsee-story-details\"\n itemscope\n itemtype=\"https://schema.org/ShortStory\"\n>\n @if (story.imageUrl) {\n <meta itemprop=\"image\" [attr.content]=\"story.imageUrl\" />\n }\n @if (story.languageKey) {\n <meta itemprop=\"inLanguage\" [attr.content]=\"story.languageKey === 'ua' ? 'uk' : 'en'\" />\n }\n @if (story.totalSlides) {\n <meta itemprop=\"numberOfPages\" [attr.content]=\"story.totalSlides\" />\n }\n <section\n class=\"rtsee-story-details-cover\"\n [style.background-image]=\"'url(' + story.imageUrl + ')'\"\n >\n <button\n class=\"rtsee-story-details-btn-close\"\n [routerLink]=\"[presentation.homePage]\"\n (click)=\"presentation.closeStoryDetails()\"\n aria-label=\"Close\"\n >\n <span class=\"pi pi-times\"></span>\n </button>\n <div class=\"rtsee-story-details-cover-overlay\"></div>\n <div class=\"rtsee-story-details-cover-content\">\n <div class=\"rtsee-story-details-cover-badges\">\n @if (story.categories?.length && false) {\n @for (category of story.categories; track category.id) {\n <span class=\"rtsee-story-details-tag-pill\">\n {{ category.name }}\n </span>\n }\n }\n @if (story.tags?.length) {\n @for (tag of story.tags; track tag.id) {\n <span\n class=\"rtsee-story-details-tag-pill rtsee-story-details-tag-pill-label\"\n >\n @if (tag.symbol) {\n <span class=\"symbol\">{{ tag.symbol }}</span>\n }\n {{ tag.name }}\n </span>\n }\n }\n </div>\n\n <h1 class=\"rtsee-story-details-cover-title\" itemprop=\"name\">{{ story.name }}</h1>\n\n <div class=\"rtsee-story-details-cover-meta\">\n @if (story.rating !== null) {\n <div\n class=\"rtsee-story-details-cover-rating\"\n itemprop=\"aggregateRating\"\n itemscope\n itemtype=\"https://schema.org/AggregateRating\"\n >\n <meta itemprop=\"bestRating\" content=\"5\" />\n <meta itemprop=\"worstRating\" content=\"1\" />\n <span class=\"rtsee-story-details-stars\">\n @for (star of getStarArray(story.rating); track $index) {\n <span\n class=\"rtsee-story-details-star\"\n [class.rtsee-story-details-star-full]=\"star === 'full'\"\n [class.rtsee-story-details-star-half]=\"star === 'half'\"\n [class.rtsee-story-details-star-empty]=\"star === 'empty'\"\n >\n @if (star === \"full\") {\n \u2605\n } @else if (star === \"half\") {\n \u2605\n } @else {\n \u2606\n }\n </span>\n }\n </span>\n <span class=\"rtsee-story-details-rating-number\" itemprop=\"ratingValue\">{{\n story.rating\n }}</span>\n @if (story.ratesCount !== null) {\n <meta itemprop=\"ratingCount\" [attr.content]=\"story.ratesCount\" />\n <span class=\"rtsee-story-details-rating-count\">\n <span>(</span>\n <span>{{ presentation.labels[RTSeeTextLabelKeys.FEEDBACKS_LABEL] }}:</span>\n <span>&nbsp;</span>\n <span itemprop=\"reviewCount\">{{ story.ratesCount }}</span>\n <span>)</span>\n </span\n >\n }\n </div>\n }\n </div>\n </div>\n </section>\n\n <!-- CONTENT AREA -->\n <div class=\"rtsee-story-details-content-wrapper\">\n <!-- Reading panel: what the user is about to read + the main CTA -->\n <section class=\"rtsee-story-details-reading-panel\" aria-label=\"{{ story.name }}\">\n @if (story.totalSlides) {\n <rtsee-story-slides-preview\n [story]=\"story\"\n [slidesLabel]=\"presentation.labels[RTSeeTextLabelKeys.STORY_PAGES_LABEL]\"\n [minuteLabel]=\"presentation.labels[RTSeeTextLabelKeys.MINUTE_LABEL]\"\n ></rtsee-story-slides-preview>\n }\n <p-button\n (click)=\"presentation.setActiveStory(story)\"\n [severity]=\"'primary'\"\n [label]=\"story.preselectedSlideNumber ? presentation.labels[RTSeeTextLabelKeys.CONTINUE_READING_BUTTON] : presentation.labels[RTSeeTextLabelKeys.START_READING_BUTTON]\"\n icon=\"pi pi-book\"\n iconPos=\"left\"\n class=\"rtsee-story-details-start-reading rts-action-button\"\n >\n </p-button>\n </section>\n <div class=\"rtsee-story-details-content-grid\">\n <!-- Description Card -->\n <article class=\"rtsee-story-details-glass-card\">\n <div class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z\" />\n <path d=\"M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z\" />\n </svg>\n <h2>{{presentation.labels[RTSeeTextLabelKeys.STORY_ABOUT_LABEL]}}</h2>\n </div>\n <p class=\"rtsee-story-details-glass-card-text\" itemprop=\"description\">\n {{ story.description }}\n </p>\n </article>\n\n @if (story.history) {\n <article class=\"rtsee-story-details-glass-card\">\n <div class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12 6 12 12 14 14\" />\n </svg>\n <h2>{{presentation.labels[RTSeeTextLabelKeys.STORY_HISTORY_LABEL]}}</h2>\n </div>\n <p class=\"rtsee-story-details-glass-card-text\" itemprop=\"backstory\">\n {{ story.history }}\n </p>\n </article>\n }\n\n @if (story.moralMeaning) {\n <article class=\"rtsee-story-details-glass-card\">\n <div class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\" />\n </svg>\n <h2>{{presentation.labels[RTSeeTextLabelKeys.STORY_MORAL_LABEL]}}</h2>\n </div>\n <p class=\"rtsee-story-details-glass-card-text\" itemprop=\"teaches\">\n {{ story.moralMeaning }}\n </p>\n </article>\n }\n </div>\n\n <!-- Author -->\n @if (story.author) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-author-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M12 20h9\" />\n <path d=\"M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z\" />\n </svg>\n <h2 id=\"rtsee-story-details-author-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.STORY_AUTHOR_LABEL] }}\n </h2>\n </header>\n <div class=\"rtsee-story-details-elements-featured\">\n <rtsee-story-element-thumbnail\n [name]=\"story.author.name\"\n [description]=\"story.author.description\"\n [imageUrl]=\"story.author.imageUrl\"\n itemProp=\"author\"\n schemaType=\"Person\"\n [horizontal]=\"true\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </div>\n </section>\n }\n\n <!-- Characters -->\n @if (story.characters.length) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-characters-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\" />\n <circle cx=\"9\" cy=\"7\" r=\"4\" />\n <path d=\"M23 21v-2a4 4 0 0 0-3-3.87\" />\n <path d=\"M16 3.13a4 4 0 0 1 0 7.75\" />\n </svg>\n <h2 id=\"rtsee-story-details-characters-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.CHARACTERS_LABEL] }}\n </h2>\n </header>\n <ul class=\"rtsee-story-details-elements-grid\" role=\"list\">\n @for (character of story.characters; track character.id) {\n <li class=\"rtsee-story-details-elements-item\">\n <rtsee-story-element-thumbnail\n [name]=\"character.name\"\n [description]=\"character.description\"\n [imageUrl]=\"character.imageUrl\"\n itemProp=\"character\"\n schemaType=\"Person\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </li>\n }\n </ul>\n </section>\n }\n\n <!-- Artifacts -->\n @if (story.artifacts.length) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-artifacts-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M6 3h12l4 6-10 13L2 9z\" />\n <path d=\"M11 3 8 9l4 13 4-13-3-6\" />\n <path d=\"M2 9h20\" />\n </svg>\n <h2 id=\"rtsee-story-details-artifacts-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.ARTIFACTS_LABEL] }}\n </h2>\n </header>\n <ul class=\"rtsee-story-details-elements-grid\" role=\"list\">\n @for (artifact of story.artifacts; track artifact.id) {\n <li class=\"rtsee-story-details-elements-item\">\n <rtsee-story-element-thumbnail\n [name]=\"artifact.name\"\n [description]=\"artifact.description\"\n [imageUrl]=\"artifact.imageUrl\"\n itemProp=\"mentions\"\n schemaType=\"Thing\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </li>\n }\n </ul>\n </section>\n }\n\n <!-- Places -->\n @if (story.locations.length) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-places-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\" />\n <circle cx=\"12\" cy=\"10\" r=\"3\" />\n </svg>\n <h2 id=\"rtsee-story-details-places-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.LOCATIONS_LABEL] }}\n </h2>\n </header>\n <ul class=\"rtsee-story-details-elements-grid\" role=\"list\">\n @for (place of story.locations; track place.id) {\n <li class=\"rtsee-story-details-elements-item\">\n <rtsee-story-element-thumbnail\n [name]=\"place.name\"\n [description]=\"place.description\"\n [imageUrl]=\"place.imageUrl\"\n itemProp=\"contentLocation\"\n schemaType=\"Place\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </li>\n }\n </ul>\n </section>\n }\n\n @if (messenger) {\n <rtsee-entity-preview\n [entity]=\"story\"\n [messenger]=\"messenger\"\n ></rtsee-entity-preview>\n }\n\n @if (story.categories?.length && false) {\n <div class=\"rtsee-story-details-categories\">\n @for (category of story.categories; track category.id) {\n <p-tag [value]=\"category.name\"></p-tag>\n }\n </div>\n }\n\n @if (story.tags?.length && false) {\n <div class=\"rtsee-story-details-labels\">\n @for (tag of story.tags; track tag.id) {\n <p-chip class=\"rtsee-story-details-label\">\n @if (tag.symbol) {\n <span class=\"rtsee-story-details-label-left\">{{\n tag.symbol\n }}</span>\n }\n <span class=\"rtsee-story-details-label-right\">{{\n tag.name\n }}</span>\n </p-chip>\n }\n </div>\n }\n\n <div class=\"rtsee-story-details-description-history\"></div>\n @if (story.isPublished && false) {\n <div class=\"rtsee-story-details-feedback\">\n <p>feedback here</p>\n </div>\n } @else if (messenger && story.discussion && false) {\n <div class=\"rtsee-story-details-votes\">\n <p class=\"rtsee-story-details-comments-label\">Comments</p>\n <rtsee-chat\n [messenger]=\"messenger\"\n [chatData]=\"story.discussion\"\n ></rtsee-chat>\n </div>\n }\n </div>\n</div>\n" }]
8280
+ args: [{ selector: 'rtsee-story-details', imports: [Chip, Tag, Button, ChatComponent, RtseeEntityPreviewComponent, RouterLink, StoryElementThumbnailComponent, StorySlidesPreviewComponent], template: "<div\n class=\"rtsee-story-details\"\n itemscope\n itemtype=\"https://schema.org/Book\"\n>\n @if (story.imageUrl) {\n <meta itemprop=\"image\" [attr.content]=\"story.imageUrl\" />\n }\n @if (story.languageKey) {\n <meta itemprop=\"inLanguage\" [attr.content]=\"story.languageKey === 'ua' ? 'uk' : 'en'\" />\n }\n @if (story.totalSlides) {\n <meta itemprop=\"numberOfPages\" [attr.content]=\"story.totalSlides\" />\n }\n <section\n class=\"rtsee-story-details-cover\"\n [style.background-image]=\"'url(' + story.imageUrl + ')'\"\n >\n <button\n class=\"rtsee-story-details-btn-close\"\n [routerLink]=\"[presentation.homePage]\"\n (click)=\"presentation.closeStoryDetails()\"\n aria-label=\"Close\"\n >\n <span class=\"pi pi-times\"></span>\n </button>\n <div class=\"rtsee-story-details-cover-overlay\"></div>\n <div class=\"rtsee-story-details-cover-content\">\n <div class=\"rtsee-story-details-cover-badges\">\n @if (story.categories?.length && false) {\n @for (category of story.categories; track category.id) {\n <span class=\"rtsee-story-details-tag-pill\">\n {{ category.name }}\n </span>\n }\n }\n @if (story.tags?.length) {\n @for (tag of story.tags; track tag.id) {\n <span\n class=\"rtsee-story-details-tag-pill rtsee-story-details-tag-pill-label\"\n >\n @if (tag.symbol) {\n <span class=\"symbol\">{{ tag.symbol }}</span>\n }\n {{ tag.name }}\n </span>\n }\n }\n </div>\n\n <h1 class=\"rtsee-story-details-cover-title\" itemprop=\"name\">{{ story.name }}</h1>\n\n <div class=\"rtsee-story-details-cover-meta\">\n @if (story.rating && story.rating > 0) {\n <div\n class=\"rtsee-story-details-cover-rating\"\n itemprop=\"aggregateRating\"\n itemscope\n itemtype=\"https://schema.org/AggregateRating\"\n >\n <meta itemprop=\"bestRating\" content=\"5\" />\n <meta itemprop=\"worstRating\" content=\"1\" />\n <span class=\"rtsee-story-details-stars\">\n @for (star of getStarArray(story.rating); track $index) {\n <span\n class=\"rtsee-story-details-star\"\n [class.rtsee-story-details-star-full]=\"star === 'full'\"\n [class.rtsee-story-details-star-half]=\"star === 'half'\"\n [class.rtsee-story-details-star-empty]=\"star === 'empty'\"\n >\n @if (star === \"full\") {\n \u2605\n } @else if (star === \"half\") {\n \u2605\n } @else {\n \u2606\n }\n </span>\n }\n </span>\n <span class=\"rtsee-story-details-rating-number\" itemprop=\"ratingValue\">{{\n story.rating\n }}</span>\n <meta itemprop=\"ratingCount\" [attr.content]=\"story.ratesCount || 1\" />\n <span class=\"rtsee-story-details-rating-count\">\n <span>(</span>\n <span>{{ presentation.labels[RTSeeTextLabelKeys.FEEDBACKS_LABEL] }}:</span>\n <span>&nbsp;</span>\n <span itemprop=\"reviewCount\">{{ story.ratesCount || 1 }}</span>\n <span>)</span>\n </span\n >\n </div>\n }\n </div>\n </div>\n </section>\n\n <!-- CONTENT AREA -->\n <div class=\"rtsee-story-details-content-wrapper\">\n <!-- Reading panel: what the user is about to read + the main CTA -->\n <section class=\"rtsee-story-details-reading-panel\" aria-label=\"{{ story.name }}\">\n @if (story.totalSlides) {\n <rtsee-story-slides-preview\n [story]=\"story\"\n [slidesLabel]=\"presentation.labels[RTSeeTextLabelKeys.STORY_PAGES_LABEL]\"\n [minuteLabel]=\"presentation.labels[RTSeeTextLabelKeys.MINUTE_LABEL]\"\n ></rtsee-story-slides-preview>\n }\n <p-button\n (click)=\"presentation.setActiveStory(story)\"\n [severity]=\"'primary'\"\n [label]=\"story.preselectedSlideNumber ? presentation.labels[RTSeeTextLabelKeys.CONTINUE_READING_BUTTON] : presentation.labels[RTSeeTextLabelKeys.START_READING_BUTTON]\"\n icon=\"pi pi-book\"\n iconPos=\"left\"\n class=\"rtsee-story-details-start-reading rts-action-button\"\n >\n </p-button>\n </section>\n <div class=\"rtsee-story-details-content-grid\">\n <!-- Description Card -->\n <article class=\"rtsee-story-details-glass-card\">\n <div class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z\" />\n <path d=\"M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z\" />\n </svg>\n <h2>{{presentation.labels[RTSeeTextLabelKeys.STORY_ABOUT_LABEL]}}</h2>\n </div>\n <p class=\"rtsee-story-details-glass-card-text\" itemprop=\"description\">\n {{ story.description }}\n </p>\n </article>\n\n @if (story.history) {\n <article class=\"rtsee-story-details-glass-card\">\n <div class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12 6 12 12 14 14\" />\n </svg>\n <h2>{{presentation.labels[RTSeeTextLabelKeys.STORY_HISTORY_LABEL]}}</h2>\n </div>\n <p class=\"rtsee-story-details-glass-card-text\" itemprop=\"backstory\">\n {{ story.history }}\n </p>\n </article>\n }\n\n @if (story.moralMeaning) {\n <article class=\"rtsee-story-details-glass-card\">\n <div class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\" />\n </svg>\n <h2>{{presentation.labels[RTSeeTextLabelKeys.STORY_MORAL_LABEL]}}</h2>\n </div>\n <p class=\"rtsee-story-details-glass-card-text\" itemprop=\"teaches\">\n {{ story.moralMeaning }}\n </p>\n </article>\n }\n </div>\n\n <!-- Author -->\n @if (story.author) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-author-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M12 20h9\" />\n <path d=\"M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z\" />\n </svg>\n <h2 id=\"rtsee-story-details-author-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.STORY_AUTHOR_LABEL] }}\n </h2>\n </header>\n <div class=\"rtsee-story-details-elements-featured\">\n <rtsee-story-element-thumbnail\n [name]=\"story.author.name\"\n [description]=\"story.author.description\"\n [imageUrl]=\"story.author.imageUrl\"\n itemProp=\"author\"\n schemaType=\"Person\"\n [horizontal]=\"true\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </div>\n </section>\n }\n\n <!-- Characters -->\n @if (story.characters.length) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-characters-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\" />\n <circle cx=\"9\" cy=\"7\" r=\"4\" />\n <path d=\"M23 21v-2a4 4 0 0 0-3-3.87\" />\n <path d=\"M16 3.13a4 4 0 0 1 0 7.75\" />\n </svg>\n <h2 id=\"rtsee-story-details-characters-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.CHARACTERS_LABEL] }}\n </h2>\n </header>\n <ul class=\"rtsee-story-details-elements-grid\" role=\"list\">\n @for (character of story.characters; track character.id) {\n <li class=\"rtsee-story-details-elements-item\">\n <rtsee-story-element-thumbnail\n [name]=\"character.name\"\n [description]=\"character.description\"\n [imageUrl]=\"character.imageUrl\"\n itemProp=\"character\"\n schemaType=\"Person\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </li>\n }\n </ul>\n </section>\n }\n\n <!-- Artifacts -->\n @if (story.artifacts.length) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-artifacts-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M6 3h12l4 6-10 13L2 9z\" />\n <path d=\"M11 3 8 9l4 13 4-13-3-6\" />\n <path d=\"M2 9h20\" />\n </svg>\n <h2 id=\"rtsee-story-details-artifacts-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.ARTIFACTS_LABEL] }}\n </h2>\n </header>\n <ul class=\"rtsee-story-details-elements-grid\" role=\"list\">\n @for (artifact of story.artifacts; track artifact.id) {\n <li class=\"rtsee-story-details-elements-item\">\n <rtsee-story-element-thumbnail\n [name]=\"artifact.name\"\n [description]=\"artifact.description\"\n [imageUrl]=\"artifact.imageUrl\"\n itemProp=\"mentions\"\n schemaType=\"Thing\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </li>\n }\n </ul>\n </section>\n }\n\n <!-- Places -->\n @if (story.locations.length) {\n <section\n class=\"rtsee-story-details-elements\"\n aria-labelledby=\"rtsee-story-details-places-heading\"\n >\n <header class=\"rtsee-story-details-glass-card-header\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\" />\n <circle cx=\"12\" cy=\"10\" r=\"3\" />\n </svg>\n <h2 id=\"rtsee-story-details-places-heading\">\n {{ presentation.labels[RTSeeTextLabelKeys.LOCATIONS_LABEL] }}\n </h2>\n </header>\n <ul class=\"rtsee-story-details-elements-grid\" role=\"list\">\n @for (place of story.locations; track place.id) {\n <li class=\"rtsee-story-details-elements-item\">\n <rtsee-story-element-thumbnail\n [name]=\"place.name\"\n [description]=\"place.description\"\n [imageUrl]=\"place.imageUrl\"\n itemProp=\"contentLocation\"\n schemaType=\"Place\"\n [showMoreLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_MORE_LABEL]\"\n [showLessLabel]=\"presentation.labels[RTSeeTextLabelKeys.SHOW_LESS_LABEL]\"\n ></rtsee-story-element-thumbnail>\n </li>\n }\n </ul>\n </section>\n }\n\n @if (messenger) {\n <rtsee-entity-preview\n [entity]=\"story\"\n [messenger]=\"messenger\"\n ></rtsee-entity-preview>\n }\n\n @if (story.categories?.length && false) {\n <div class=\"rtsee-story-details-categories\">\n @for (category of story.categories; track category.id) {\n <p-tag [value]=\"category.name\"></p-tag>\n }\n </div>\n }\n\n @if (story.tags?.length && false) {\n <div class=\"rtsee-story-details-labels\">\n @for (tag of story.tags; track tag.id) {\n <p-chip class=\"rtsee-story-details-label\">\n @if (tag.symbol) {\n <span class=\"rtsee-story-details-label-left\">{{\n tag.symbol\n }}</span>\n }\n <span class=\"rtsee-story-details-label-right\">{{\n tag.name\n }}</span>\n </p-chip>\n }\n </div>\n }\n\n <div class=\"rtsee-story-details-description-history\"></div>\n @if (story.isPublished && false) {\n <div class=\"rtsee-story-details-feedback\">\n <p>feedback here</p>\n </div>\n } @else if (messenger && story.discussion && false) {\n <div class=\"rtsee-story-details-votes\">\n <p class=\"rtsee-story-details-comments-label\">Comments</p>\n <rtsee-chat\n [messenger]=\"messenger\"\n [chatData]=\"story.discussion\"\n ></rtsee-chat>\n </div>\n }\n </div>\n</div>\n" }]
7025
8281
  }], propDecorators: { story: [{
7026
8282
  type: Input
7027
8283
  }], presentation: [{
@@ -7127,6 +8383,7 @@ class RTSeeContainerComponent {
7127
8383
  this.isSidenavExpanded = true;
7128
8384
  this.isSidenavContent = false;
7129
8385
  this.isSidenavFullScreen = false;
8386
+ this.RTSeeTextLabelKeys = RTSeeTextLabelKeys;
7130
8387
  }
7131
8388
  ngOnInit() {
7132
8389
  this.authService.init(this.auth);
@@ -7163,7 +8420,7 @@ class RTSeeContainerComponent {
7163
8420
  this.isSidenavFullScreen = rtseeRoute.fullScreen || false;
7164
8421
  }
7165
8422
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RTSeeContainerComponent, deps: [{ token: RTSeeAuthService }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Component }); }
7166
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RTSeeContainerComponent, isStandalone: true, selector: "rtsee-container", inputs: { rtsee: "rtsee", navigationConfig: "navigationConfig", auth: "auth" }, ngImport: i0, template: "<div class=\"rtsee-shell\"\n [ngClass]=\"{\n 'rtsee-shell-conference-mode': rtsee.conference && rtsee.conference.isInActiveCall,\n 'rtsee-shell-messenger-active': rtsee.messenger && rtsee.activeTab === 'messenger',\n 'rtsee-shell-dashboard-active': rtsee.eventsDashboard && rtsee.activeTab === 'events-dashboard',\n 'rtsee-shell-presentation-active': rtsee.presentation && rtsee.activeTab === 'presentation',\n 'rtsee-shell-side-nav-expanded': isSidenavExpanded,\n 'rtsee-shell-side-nav-is-content': isSidenavContent,\n 'rtsee-shell-side-nav-full-screen': isSidenavFullScreen,\n 'rtsee-lang-eng': rtsee.messenger && rtsee.messenger.currentLanguage === 'eng',\n 'rtsee-lang-ua': rtsee.messenger && rtsee.messenger.currentLanguage === 'ua'\n }\"\n>\n <div class=\"rtsee-nav-block\">\n <rtsee-nav [config]=\"navigationConfig\" [rtsee]=\"rtsee\"></rtsee-nav>\n </div>\n\n <div class=\"rtsee-shell-panel\">\n <div class=\"rtsee-shell-panel-inner\">\n @if (rtsee.conference && rtsee.conference.isInActiveCall) {\n <div class=\"rtsee-conference-container\">\n <rtsee-conference [rtSee]=\"rtsee.conference\"\n ></rtsee-conference>\n </div>\n }\n\n @if (rtsee.messenger) {\n <div class=\"rtsee-messenger-container\">\n <rtsee-messenger [messenger]=\"rtsee.messenger\"\n ></rtsee-messenger>\n </div>\n }\n\n @if (rtsee.eventsDashboard && rtsee.eventsDashboard.isReady) {\n <div class=\"rtsee-events-dashboard-container\">\n <rtsee-events-dashboard [eventsDashboard]=\"rtsee.eventsDashboard\"\n ></rtsee-events-dashboard>\n </div>\n }\n\n @if (rtsee.presentation && rtsee.presentation.isActive) {\n <div class=\"rtsee-presentation-container\">\n <rtsee-presentation [presentation]=\"rtsee.presentation\"\n [messenger]=\"rtsee.messenger\"\n ></rtsee-presentation>\n </div>\n }\n </div>\n </div>\n\n <div class=\"rtsee-content\">\n <ng-content></ng-content>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: RTSeeConferenceComponent, selector: "rtsee-conference", inputs: ["rtSee"] }, { kind: "component", type: MessengerComponent, selector: "rtsee-messenger", inputs: ["messenger"] }, { kind: "component", type: RtseeEventsDashboardComponent, selector: "rtsee-events-dashboard", inputs: ["eventsDashboard"] }, { kind: "component", type: PresentationComponent, selector: "rtsee-presentation", inputs: ["presentation", "messenger"] }, { kind: "component", type: RtseeNavComponent, selector: "rtsee-nav", inputs: ["config", "rtsee"] }] }); }
8423
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RTSeeContainerComponent, isStandalone: true, selector: "rtsee-container", inputs: { rtsee: "rtsee", navigationConfig: "navigationConfig", auth: "auth" }, ngImport: i0, template: "<div class=\"rtsee-shell\"\n [ngClass]=\"{\n 'rtsee-shell-conference-mode': rtsee.conference && rtsee.conference.isInActiveCall,\n 'rtsee-shell-messenger-active': rtsee.messenger && rtsee.activeTab === 'messenger',\n 'rtsee-shell-dashboard-active': rtsee.eventsDashboard && rtsee.activeTab === 'events-dashboard',\n 'rtsee-shell-presentation-active': rtsee.presentation && rtsee.activeTab === 'presentation',\n 'rtsee-shell-side-nav-expanded': isSidenavExpanded,\n 'rtsee-shell-side-nav-is-content': isSidenavContent,\n 'rtsee-shell-side-nav-full-screen': isSidenavFullScreen,\n 'rtsee-lang-eng': rtsee.messenger && rtsee.messenger.currentLanguage === 'eng',\n 'rtsee-lang-ua': rtsee.messenger && rtsee.messenger.currentLanguage === 'ua'\n }\"\n>\n <div class=\"rtsee-nav-block\">\n <rtsee-nav [config]=\"navigationConfig\" [rtsee]=\"rtsee\"></rtsee-nav>\n </div>\n\n <div class=\"rtsee-shell-panel\">\n <div class=\"rtsee-shell-panel-inner\">\n @if (rtsee.conference && rtsee.conference.isInActiveCall) {\n <div class=\"rtsee-conference-container\">\n <rtsee-conference [rtSee]=\"rtsee.conference\"\n ></rtsee-conference>\n </div>\n }\n\n @if (rtsee.messenger && rtsee.messenger.pendingInviteToken && rtsee.activeTab !== 'messenger') {\n <div class=\"rtsee-mobile-invite-popup-wrapper rts-theme-dark\">\n <div class=\"rts-invite-popup-modal\">\n <div class=\"rts-invite-popup-content\">\n <span class=\"material-icons-outlined rts-invite-popup-icon\">mail_outline</span>\n <div class=\"rts-invite-popup-text\">\n @if (rtsee.messenger.pendingInviteInfo?.inviter?.name) {\n <strong>{{ rtsee.messenger.pendingInviteInfo?.inviter?.name }}</strong>\n <span> {{ rtsee.messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_POPUP_TEXT] }}</span>\n @if (rtsee.messenger.pendingInviteInfo?.chat?.name) {\n <span class=\"rts-invite-popup-chat-name\"> ({{ rtsee.messenger.pendingInviteInfo?.chat?.name }})</span>\n }\n } @else {\n <span>{{ rtsee.messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_POPUP_GENERIC_TEXT] }}</span>\n }\n </div>\n </div>\n <div class=\"rts-invite-popup-actions\">\n <button type=\"button\"\n class=\"rts-btn rts-btn-secondary rts-invite-popup-btn\"\n [disabled]=\"rtsee.messenger.inviteJoinInProgress\"\n (click)=\"rtsee.messenger.ignoreChatInvitation()\"\n >\n {{ rtsee.messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_IGNORE_BUTTON] }}\n </button>\n <button type=\"button\"\n class=\"rts-btn rts-btn-primary rts-invite-popup-btn\"\n [disabled]=\"rtsee.messenger.inviteJoinInProgress\"\n (click)=\"rtsee.messenger.acceptChatInvitation()\"\n >\n {{ rtsee.messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_JOIN_BUTTON] }}\n </button>\n </div>\n </div>\n </div>\n }\n\n @if (rtsee.messenger) {\n <div class=\"rtsee-messenger-container\">\n <rtsee-messenger [messenger]=\"rtsee.messenger\"\n ></rtsee-messenger>\n </div>\n }\n\n @if (rtsee.eventsDashboard && rtsee.eventsDashboard.isReady) {\n <div class=\"rtsee-events-dashboard-container\">\n <rtsee-events-dashboard [eventsDashboard]=\"rtsee.eventsDashboard\"\n ></rtsee-events-dashboard>\n </div>\n }\n\n @if (rtsee.presentation && rtsee.presentation.isActive) {\n <div class=\"rtsee-presentation-container\">\n <rtsee-presentation [presentation]=\"rtsee.presentation\"\n [messenger]=\"rtsee.messenger\"\n ></rtsee-presentation>\n </div>\n }\n </div>\n </div>\n\n <div class=\"rtsee-content\">\n <ng-content></ng-content>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: RTSeeConferenceComponent, selector: "rtsee-conference", inputs: ["rtSee"] }, { kind: "component", type: MessengerComponent, selector: "rtsee-messenger", inputs: ["messenger", "isFramed"] }, { kind: "component", type: RtseeEventsDashboardComponent, selector: "rtsee-events-dashboard", inputs: ["eventsDashboard"] }, { kind: "component", type: PresentationComponent, selector: "rtsee-presentation", inputs: ["presentation", "messenger"] }, { kind: "component", type: RtseeNavComponent, selector: "rtsee-nav", inputs: ["config", "rtsee"] }] }); }
7167
8424
  }
7168
8425
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RTSeeContainerComponent, decorators: [{
7169
8426
  type: Component,
@@ -7174,7 +8431,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
7174
8431
  RtseeEventsDashboardComponent,
7175
8432
  PresentationComponent,
7176
8433
  RtseeNavComponent,
7177
- ], standalone: true, template: "<div class=\"rtsee-shell\"\n [ngClass]=\"{\n 'rtsee-shell-conference-mode': rtsee.conference && rtsee.conference.isInActiveCall,\n 'rtsee-shell-messenger-active': rtsee.messenger && rtsee.activeTab === 'messenger',\n 'rtsee-shell-dashboard-active': rtsee.eventsDashboard && rtsee.activeTab === 'events-dashboard',\n 'rtsee-shell-presentation-active': rtsee.presentation && rtsee.activeTab === 'presentation',\n 'rtsee-shell-side-nav-expanded': isSidenavExpanded,\n 'rtsee-shell-side-nav-is-content': isSidenavContent,\n 'rtsee-shell-side-nav-full-screen': isSidenavFullScreen,\n 'rtsee-lang-eng': rtsee.messenger && rtsee.messenger.currentLanguage === 'eng',\n 'rtsee-lang-ua': rtsee.messenger && rtsee.messenger.currentLanguage === 'ua'\n }\"\n>\n <div class=\"rtsee-nav-block\">\n <rtsee-nav [config]=\"navigationConfig\" [rtsee]=\"rtsee\"></rtsee-nav>\n </div>\n\n <div class=\"rtsee-shell-panel\">\n <div class=\"rtsee-shell-panel-inner\">\n @if (rtsee.conference && rtsee.conference.isInActiveCall) {\n <div class=\"rtsee-conference-container\">\n <rtsee-conference [rtSee]=\"rtsee.conference\"\n ></rtsee-conference>\n </div>\n }\n\n @if (rtsee.messenger) {\n <div class=\"rtsee-messenger-container\">\n <rtsee-messenger [messenger]=\"rtsee.messenger\"\n ></rtsee-messenger>\n </div>\n }\n\n @if (rtsee.eventsDashboard && rtsee.eventsDashboard.isReady) {\n <div class=\"rtsee-events-dashboard-container\">\n <rtsee-events-dashboard [eventsDashboard]=\"rtsee.eventsDashboard\"\n ></rtsee-events-dashboard>\n </div>\n }\n\n @if (rtsee.presentation && rtsee.presentation.isActive) {\n <div class=\"rtsee-presentation-container\">\n <rtsee-presentation [presentation]=\"rtsee.presentation\"\n [messenger]=\"rtsee.messenger\"\n ></rtsee-presentation>\n </div>\n }\n </div>\n </div>\n\n <div class=\"rtsee-content\">\n <ng-content></ng-content>\n </div>\n</div>\n" }]
8434
+ ], standalone: true, template: "<div class=\"rtsee-shell\"\n [ngClass]=\"{\n 'rtsee-shell-conference-mode': rtsee.conference && rtsee.conference.isInActiveCall,\n 'rtsee-shell-messenger-active': rtsee.messenger && rtsee.activeTab === 'messenger',\n 'rtsee-shell-dashboard-active': rtsee.eventsDashboard && rtsee.activeTab === 'events-dashboard',\n 'rtsee-shell-presentation-active': rtsee.presentation && rtsee.activeTab === 'presentation',\n 'rtsee-shell-side-nav-expanded': isSidenavExpanded,\n 'rtsee-shell-side-nav-is-content': isSidenavContent,\n 'rtsee-shell-side-nav-full-screen': isSidenavFullScreen,\n 'rtsee-lang-eng': rtsee.messenger && rtsee.messenger.currentLanguage === 'eng',\n 'rtsee-lang-ua': rtsee.messenger && rtsee.messenger.currentLanguage === 'ua'\n }\"\n>\n <div class=\"rtsee-nav-block\">\n <rtsee-nav [config]=\"navigationConfig\" [rtsee]=\"rtsee\"></rtsee-nav>\n </div>\n\n <div class=\"rtsee-shell-panel\">\n <div class=\"rtsee-shell-panel-inner\">\n @if (rtsee.conference && rtsee.conference.isInActiveCall) {\n <div class=\"rtsee-conference-container\">\n <rtsee-conference [rtSee]=\"rtsee.conference\"\n ></rtsee-conference>\n </div>\n }\n\n @if (rtsee.messenger && rtsee.messenger.pendingInviteToken && rtsee.activeTab !== 'messenger') {\n <div class=\"rtsee-mobile-invite-popup-wrapper rts-theme-dark\">\n <div class=\"rts-invite-popup-modal\">\n <div class=\"rts-invite-popup-content\">\n <span class=\"material-icons-outlined rts-invite-popup-icon\">mail_outline</span>\n <div class=\"rts-invite-popup-text\">\n @if (rtsee.messenger.pendingInviteInfo?.inviter?.name) {\n <strong>{{ rtsee.messenger.pendingInviteInfo?.inviter?.name }}</strong>\n <span> {{ rtsee.messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_POPUP_TEXT] }}</span>\n @if (rtsee.messenger.pendingInviteInfo?.chat?.name) {\n <span class=\"rts-invite-popup-chat-name\"> ({{ rtsee.messenger.pendingInviteInfo?.chat?.name }})</span>\n }\n } @else {\n <span>{{ rtsee.messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_POPUP_GENERIC_TEXT] }}</span>\n }\n </div>\n </div>\n <div class=\"rts-invite-popup-actions\">\n <button type=\"button\"\n class=\"rts-btn rts-btn-secondary rts-invite-popup-btn\"\n [disabled]=\"rtsee.messenger.inviteJoinInProgress\"\n (click)=\"rtsee.messenger.ignoreChatInvitation()\"\n >\n {{ rtsee.messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_IGNORE_BUTTON] }}\n </button>\n <button type=\"button\"\n class=\"rts-btn rts-btn-primary rts-invite-popup-btn\"\n [disabled]=\"rtsee.messenger.inviteJoinInProgress\"\n (click)=\"rtsee.messenger.acceptChatInvitation()\"\n >\n {{ rtsee.messenger.labels[RTSeeTextLabelKeys.MESSENGER_INVITE_JOIN_BUTTON] }}\n </button>\n </div>\n </div>\n </div>\n }\n\n @if (rtsee.messenger) {\n <div class=\"rtsee-messenger-container\">\n <rtsee-messenger [messenger]=\"rtsee.messenger\"\n ></rtsee-messenger>\n </div>\n }\n\n @if (rtsee.eventsDashboard && rtsee.eventsDashboard.isReady) {\n <div class=\"rtsee-events-dashboard-container\">\n <rtsee-events-dashboard [eventsDashboard]=\"rtsee.eventsDashboard\"\n ></rtsee-events-dashboard>\n </div>\n }\n\n @if (rtsee.presentation && rtsee.presentation.isActive) {\n <div class=\"rtsee-presentation-container\">\n <rtsee-presentation [presentation]=\"rtsee.presentation\"\n [messenger]=\"rtsee.messenger\"\n ></rtsee-presentation>\n </div>\n }\n </div>\n </div>\n\n <div class=\"rtsee-content\">\n <ng-content></ng-content>\n </div>\n</div>\n" }]
7178
8435
  }], ctorParameters: () => [{ type: RTSeeAuthService }, { type: i2.Router }], propDecorators: { rtsee: [{
7179
8436
  type: Input
7180
8437
  }], navigationConfig: [{
@@ -8091,7 +9348,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
8091
9348
 
8092
9349
  class PrivacyPolicyComponent {
8093
9350
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PrivacyPolicyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8094
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: PrivacyPolicyComponent, isStandalone: true, selector: "rtsee-privacy-policy", ngImport: i0, template: "<div class=\"privacy-policy-container\">\n <div class=\"policy-card rts-glass-card\">\n <div class=\"header-section\">\n <div class=\"header-content\">\n <h1>Terms of Use & Privacy Policy</h1>\n </div>\n </div>\n\n <div class=\"content-section\">\n <p-message severity=\"info\" [closable]=\"false\" class=\"info-banner\">\n <ng-template pTemplate>\n <div class=\"p-message-content\">\n <p class=\"last-updated\"><strong>Last Updated:</strong> December 2024</p>\n <p>By using our services, you agree to the terms and conditions outlined in this document. Please read this Privacy Policy and Terms of Use carefully before using our platform.</p>\n </div>\n </ng-template>\n </p-message>\n\n <h2>1. Acceptance of Terms</h2>\n <p>By accessing and using this service, you accept and agree to be bound by the terms and provision of this agreement. If you do not agree to abide by the above, please do not use this service.</p>\n\n <h2>2. Privacy Policy</h2>\n\n <h3>2.1 Information We Collect</h3>\n <p>We collect information you provide directly to us, such as when you create an account, use our services, or contact us for support. This may include:</p>\n <ul>\n <li><strong>Personal Information:</strong> Name, email address, phone number, and other contact details</li>\n <li><strong>Account Information:</strong> Username, password, and profile information</li>\n <li><strong>Usage Data:</strong> Information about how you use our services, including pages visited, time spent, and features used</li>\n <li><strong>Device Information:</strong> IP address, browser type, operating system, and device identifiers</li>\n <li><strong>Cookies and Tracking:</strong> We use cookies and similar technologies to enhance your experience</li>\n </ul>\n\n <h3>2.2 How We Use Your Information</h3>\n <p>We use the information we collect to:</p>\n <ul>\n <li>Provide, maintain, and improve our services</li>\n <li>Process transactions and send related information</li>\n <li>Send technical notices, updates, security alerts, and support messages</li>\n <li>Respond to your comments, questions, and requests</li>\n <li>Monitor and analyze trends, usage, and activities</li>\n <li>Personalize and improve your experience</li>\n <li>Detect, investigate, and prevent fraudulent transactions and other illegal activities</li>\n </ul>\n\n <h3>2.3 Information Sharing and Disclosure</h3>\n <p>We do not sell, trade, or otherwise transfer your personal information to third parties without your consent, except in the following circumstances:</p>\n <ul>\n <li><strong>Service Providers:</strong> We may share information with trusted third-party service providers who assist us in operating our platform</li>\n <li><strong>Legal Requirements:</strong> We may disclose information when required by law or to protect our rights and safety</li>\n <li><strong>Business Transfers:</strong> In connection with any merger, sale of assets, or acquisition of all or a portion of our business</li>\n <li><strong>Consent:</strong> We may share information with your explicit consent</li>\n </ul>\n\n <h3>2.4 Data Security</h3>\n <p>We implement appropriate technical and organizational security measures to protect your personal information against unauthorized access, alteration, disclosure, or destruction. However, no method of transmission over the internet or electronic storage is 100% secure.</p>\n\n <h3>2.5 Data Retention</h3>\n <p>We retain your personal information for as long as necessary to provide our services and fulfill the purposes outlined in this privacy policy, unless a longer retention period is required or permitted by law.</p>\n\n <h3>2.6 Your Rights</h3>\n <p>Depending on your location, you may have certain rights regarding your personal information, including:</p>\n <ul>\n <li>The right to access and receive a copy of your personal information</li>\n <li>The right to rectify or update your personal information</li>\n <li>The right to erase your personal information</li>\n <li>The right to restrict or object to the processing of your personal information</li>\n <li>The right to data portability</li>\n <li>The right to withdraw consent at any time</li>\n </ul>\n\n <h2>3. Terms of Service</h2>\n\n <h3>3.1 User Accounts</h3>\n <p>To access certain features of our service, you may be required to create an account. You are responsible for:</p>\n <ul>\n <li>Maintaining the confidentiality of your account credentials</li>\n <li>All activities that occur under your account</li>\n <li>Notifying us immediately of any unauthorized use of your account</li>\n <li>Providing accurate and up-to-date information</li>\n </ul>\n\n <h3>3.2 Acceptable Use</h3>\n <p>You agree not to use our service for any unlawful purpose or any purpose prohibited under this clause. You may not use our service in any manner that could damage, disable, overburden, or impair our servers or networks.</p>\n\n <h3>3.3 Prohibited Activities</h3>\n <p>The following activities are prohibited:</p>\n <ul>\n <li>Violating any applicable laws or regulations</li>\n <li>Transmitting or procuring the sending of any unsolicited or unauthorized advertising</li>\n <li>Attempting to gain unauthorized access to any portion of our service</li>\n <li>Interfering with or disrupting the service or servers connected to the service</li>\n <li>Using any automated system to access the service for any purpose</li>\n <li>Impersonating any person or entity or misrepresenting your affiliation with a person or entity</li>\n </ul>\n\n <h3>3.4 Intellectual Property</h3>\n <p>The service and its original content, features, and functionality are and will remain the exclusive property of our company and its licensors. The service is protected by copyright, trademark, and other laws.</p>\n\n <h3>3.5 Termination</h3>\n <p>We may terminate or suspend your account and bar access to the service immediately, without prior notice or liability, under our sole discretion, for any reason whatsoever, including without limitation if you breach the Terms.</p>\n\n <h3>3.6 Disclaimer</h3>\n <p>The information on this service is provided on an \"as is\" basis. To the fullest extent permitted by law, this company excludes all representations, warranties, conditions and terms relating to our service and the use of this service.</p>\n\n <h3>3.7 Limitation of Liability</h3>\n <p>In no event shall our company, nor its directors, employees, partners, agents, suppliers, or affiliates, be liable for any indirect, incidental, special, consequential, or punitive damages, including without limitation, loss of profits, data, use, goodwill, or other intangible losses, resulting from your use of the service.</p>\n\n <h2>4. Cookies and Tracking Technologies</h2>\n <p>We use cookies and similar tracking technologies to track activity on our service and hold certain information. Cookies are files with a small amount of data which may include an anonymous unique identifier. You can instruct your browser to refuse all cookies or to indicate when a cookie is being sent.</p>\n\n <h2>5. Third-Party Services</h2>\n <p>Our service may contain links to third-party websites or services that are not owned or controlled by us. We have no control over and assume no responsibility for the content, privacy policies, or practices of any third-party websites or services.</p>\n\n <h2>6. Children's Privacy</h2>\n <p>Our service does not address anyone under the age of 13. We do not knowingly collect personally identifiable information from children under 13. If you are a parent or guardian and you are aware that your child has provided us with personal information, please contact us.</p>\n\n <h2>7. International Data Transfers</h2>\n <p>Your information may be transferred to and processed in countries other than your own. We ensure that such transfers comply with applicable data protection laws and implement appropriate safeguards to protect your personal information.</p>\n\n <h2>8. Changes to This Policy</h2>\n <p>We reserve the right to update or change our Privacy Policy and Terms of Use at any time. We will notify you of any changes by posting the new Privacy Policy and Terms of Use on this page and updating the \"Last Updated\" date.</p>\n\n <div class=\"contact-section\">\n <h2>9. Contact Information</h2>\n <p>If you have any questions about this Privacy Policy and Terms of Use, please contact us:</p>\n <ul>\n <li><strong>Email:</strong> [Your Email Address]</li>\n <li><strong>Address:</strong> [Your Company Address]</li>\n <li><strong>Phone:</strong> [Your Contact Number]</li>\n </ul>\n </div>\n\n <div class=\"footer-section\">\n <p>This document was last updated on December 2024</p>\n </div>\n </div>\n </div>\n</div>\n\n", dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i2$2.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }] }); }
9351
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.4", type: PrivacyPolicyComponent, isStandalone: true, selector: "rtsee-privacy-policy", ngImport: i0, template: "<div class=\"privacy-policy-container\">\n <div class=\"policy-card rts-glass-card\">\n <div class=\"header-section\">\n <div class=\"header-content\">\n <h1>Terms of Use & Privacy Policy</h1>\n </div>\n </div>\n\n <div class=\"content-section\">\n <p-message severity=\"info\" [closable]=\"false\" class=\"info-banner\">\n <ng-template pTemplate>\n <div class=\"p-message-content\">\n <p class=\"last-updated\"><strong>Last Updated:</strong> December 2024</p>\n <p>By using our services, you agree to the terms and conditions outlined in this document. Please read this Privacy Policy and Terms of Use carefully before using our platform.</p>\n </div>\n </ng-template>\n </p-message>\n\n <h2>1. Acceptance of Terms</h2>\n <p>By accessing and using this service, you accept and agree to be bound by the terms and provision of this agreement. If you do not agree to abide by the above, please do not use this service.</p>\n\n <h2>2. Privacy Policy</h2>\n\n <h3>2.1 Information We Collect</h3>\n <p>We collect information you provide directly to us, such as when you create an account, use our services, or contact us for support. This may include:</p>\n <ul>\n <li><strong>Personal Information:</strong> Name, email address, phone number, and other contact details</li>\n <li><strong>Account Information:</strong> Username, password, and profile information</li>\n <li><strong>Usage Data:</strong> Information about how you use our services, including pages visited, time spent, and features used</li>\n <li><strong>Device Information:</strong> IP address, browser type, operating system, and device identifiers</li>\n <li><strong>Cookies and Tracking:</strong> We use cookies and similar technologies to enhance your experience</li>\n </ul>\n\n <h3>2.2 How We Use Your Information</h3>\n <p>We use the information we collect to:</p>\n <ul>\n <li>Provide, maintain, and improve our services</li>\n <li>Process transactions and send related information</li>\n <li>Send technical notices, updates, security alerts, and support messages</li>\n <li>Respond to your comments, questions, and requests</li>\n <li>Monitor and analyze trends, usage, and activities</li>\n <li>Personalize and improve your experience</li>\n <li>Detect, investigate, and prevent fraudulent transactions and other illegal activities</li>\n </ul>\n\n <h3>2.3 Information Sharing and Disclosure</h3>\n <p>We do not sell, trade, or otherwise transfer your personal information to third parties without your consent, except in the following circumstances:</p>\n <ul>\n <li><strong>Service Providers:</strong> We may share information with trusted third-party service providers who assist us in operating our platform</li>\n <li><strong>Legal Requirements:</strong> We may disclose information when required by law or to protect our rights and safety</li>\n <li><strong>Business Transfers:</strong> In connection with any merger, sale of assets, or acquisition of all or a portion of our business</li>\n <li><strong>Consent:</strong> We may share information with your explicit consent</li>\n </ul>\n\n <h3>2.4 Data Security</h3>\n <p>We implement appropriate technical and organizational security measures to protect your personal information against unauthorized access, alteration, disclosure, or destruction. However, no method of transmission over the internet or electronic storage is 100% secure.</p>\n\n <h3>2.5 Data Retention</h3>\n <p>We retain your personal information for as long as necessary to provide our services and fulfill the purposes outlined in this privacy policy, unless a longer retention period is required or permitted by law.</p>\n\n <h3>2.6 Your Rights</h3>\n <p>Depending on your location, you may have certain rights regarding your personal information, including:</p>\n <ul>\n <li>The right to access and receive a copy of your personal information</li>\n <li>The right to rectify or update your personal information</li>\n <li>The right to erase your personal information</li>\n <li>The right to restrict or object to the processing of your personal information</li>\n <li>The right to data portability</li>\n <li>The right to withdraw consent at any time</li>\n </ul>\n\n <h2>3. Terms of Service</h2>\n\n <h3>3.1 User Accounts</h3>\n <p>To access certain features of our service, you may be required to create an account. You are responsible for:</p>\n <ul>\n <li>Maintaining the confidentiality of your account credentials</li>\n <li>All activities that occur under your account</li>\n <li>Notifying us immediately of any unauthorized use of your account</li>\n <li>Providing accurate and up-to-date information</li>\n </ul>\n\n <h3>3.2 Acceptable Use</h3>\n <p>You agree not to use our service for any unlawful purpose or any purpose prohibited under this clause. You may not use our service in any manner that could damage, disable, overburden, or impair our servers or networks.</p>\n\n <h3>3.3 Prohibited Activities</h3>\n <p>The following activities are prohibited:</p>\n <ul>\n <li>Violating any applicable laws or regulations</li>\n <li>Transmitting or procuring the sending of any unsolicited or unauthorized advertising</li>\n <li>Attempting to gain unauthorized access to any portion of our service</li>\n <li>Interfering with or disrupting the service or servers connected to the service</li>\n <li>Using any automated system to access the service for any purpose</li>\n <li>Impersonating any person or entity or misrepresenting your affiliation with a person or entity</li>\n </ul>\n\n <h3>3.4 Intellectual Property</h3>\n <p>The service and its original content, features, and functionality are and will remain the exclusive property of our company and its licensors. The service is protected by copyright, trademark, and other laws.</p>\n\n <h3>3.5 Termination</h3>\n <p>We may terminate or suspend your account and bar access to the service immediately, without prior notice or liability, under our sole discretion, for any reason whatsoever, including without limitation if you breach the Terms.</p>\n\n <h3>3.6 Disclaimer</h3>\n <p>The information on this service is provided on an \"as is\" basis. To the fullest extent permitted by law, this company excludes all representations, warranties, conditions and terms relating to our service and the use of this service.</p>\n\n <h3>3.7 Limitation of Liability</h3>\n <p>In no event shall our company, nor its directors, employees, partners, agents, suppliers, or affiliates, be liable for any indirect, incidental, special, consequential, or punitive damages, including without limitation, loss of profits, data, use, goodwill, or other intangible losses, resulting from your use of the service.</p>\n\n <h2>4. Cookies and Tracking Technologies</h2>\n <p>We use cookies and similar tracking technologies to track activity on our service and hold certain information. Cookies are files with a small amount of data which may include an anonymous unique identifier. You can instruct your browser to refuse all cookies or to indicate when a cookie is being sent.</p>\n\n <h2>5. Third-Party Services</h2>\n <p>Our service may contain links to third-party websites or services that are not owned or controlled by us. We have no control over and assume no responsibility for the content, privacy policies, or practices of any third-party websites or services.</p>\n\n <h2>6. Children's Privacy</h2>\n <p>Our service does not address anyone under the age of 13. We do not knowingly collect personally identifiable information from children under 13. If you are a parent or guardian and you are aware that your child has provided us with personal information, please contact us.</p>\n\n <h2>7. International Data Transfers</h2>\n <p>Your information may be transferred to and processed in countries other than your own. We ensure that such transfers comply with applicable data protection laws and implement appropriate safeguards to protect your personal information.</p>\n\n <h2>8. Changes to This Policy</h2>\n <p>We reserve the right to update or change our Privacy Policy and Terms of Use at any time. We will notify you of any changes by posting the new Privacy Policy and Terms of Use on this page and updating the \"Last Updated\" date.</p>\n\n <div class=\"contact-section\">\n <h2>9. Contact Information</h2>\n <p>If you have any questions about this Privacy Policy and Terms of Use, please contact us:</p>\n <ul>\n <li><strong>Email:</strong> [Your Email Address]</li>\n <li><strong>Address:</strong> [Your Company Address]</li>\n <li><strong>Phone:</strong> [Your Contact Number]</li>\n </ul>\n </div>\n\n <div class=\"footer-section\">\n <p>This document was last updated on December 2024</p>\n </div>\n </div>\n </div>\n</div>\n\n", dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$4.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i2$1.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }] }); }
8095
9352
  }
8096
9353
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PrivacyPolicyComponent, decorators: [{
8097
9354
  type: Component,
@@ -8439,5 +9696,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
8439
9696
  * Generated bundle index. Do not edit.
8440
9697
  */
8441
9698
 
8442
- export { BaseEventWidgetComponent, EntitiesConfigurationsListComponent, EntitiesListComponent, EventsWidgetsService, FormComponent, GtagService, IllustratorComponent, InteractiveStoryEditorComponent, ManageEntityComponent, ManageEntityConfigurationComponent, MessengerComponent, NgxService, PaymentProductSnippetComponent, PresentationComponent, ProfileComponent, RTSeeAuthComponent, RTSeeConferenceComponent, RTSeeContainerComponent, RTSeeControlsComponent, RTSeeModule, RTSeeTaskComponent, RtseeEntityCommentsComponent, RtseeEntityPreviewComponent, RtseeEntityTagsComponent, RtseeEventsDashboardComponent, RtseePeerComponent, RtseeSettingsComponent, RtseeTagGroupManageComponent, RtseeTagGroupsManageComponent, RtseeTagManageComponent, RtseeTagsAccordionMenuComponent, SlideNumberChangedWidgetComponent, StoryDetailsOpenedWidgetComponent, StoryElementsSectionComponent, StoryReadingStartedWidgetComponent, TranslationsPanelComponent };
9699
+ export { ApplicationEventWidgetComponent, BaseEventWidgetComponent, ChatAgentCreatedWidgetComponent, ChatCreatedWidgetComponent, ChatMemberInviteClickedWidgetComponent, ChatMessageSentWidgetComponent, ChatOpenedWidgetComponent, DefaultTaskActionPromptComponent, DefaultTaskActionThumbnailComponent, EntitiesConfigurationsListComponent, EntitiesListComponent, EventsWidgetsService, FormComponent, GtagService, IllustratorComponent, InteractiveStoryEditorComponent, ManageEntityComponent, ManageEntityConfigurationComponent, MessengerComponent, NgxService, PaymentProductSnippetComponent, PresentationComponent, ProfileComponent, ProfileOpenedWidgetComponent, RTSeeAuthComponent, RTSeeConferenceComponent, RTSeeContainerComponent, RTSeeControlsComponent, RTSeeModule, RTSeeTaskActionComponent, RTSeeTaskComponent, RequestDemoClickedWidgetComponent, RtseeEntityCommentsComponent, RtseeEntityPreviewComponent, RtseeEntityTagsComponent, RtseeEventsDashboardComponent, RtseePeerComponent, RtseeSettingsComponent, RtseeTagGroupManageComponent, RtseeTagGroupsManageComponent, RtseeTagManageComponent, RtseeTagsAccordionMenuComponent, SlideNumberChangedWidgetComponent, SlideTaskActionThumbnailComponent, StoryDetailsOpenedWidgetComponent, StoryElementsSectionComponent, StoryReadingStartedWidgetComponent, StoryTaskActionThumbnailComponent, TaskActionPromptComponent, TaskActionThumbnailComponent, TaskActionWidgetsService, TranslationsPanelComponent };
8443
9700
  //# sourceMappingURL=rtsee-ngx.mjs.map