@rtsee/ngx 0.0.105 → 0.0.106

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,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, Input, Component, ViewChild, EventEmitter, Output, forwardRef, Directive, DOCUMENT, HostListener, Inject, output, CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
2
+ import { Injectable, Input, Component, ViewChild, EventEmitter, Output, forwardRef, Directive, DOCUMENT, HostListener, Inject, ChangeDetectionStrategy, output, CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
3
3
  import * as i2$1 from '@angular/common';
4
- import { NgClass, NgIf, NgForOf, DatePipe, NgComponentOutlet, SlicePipe, JsonPipe, DOCUMENT as DOCUMENT$1, NgStyle, NgOptimizedImage, CommonModule } from '@angular/common';
4
+ import { NgClass, NgIf, NgForOf, DatePipe, NgComponentOutlet, SlicePipe, JsonPipe, DOCUMENT as DOCUMENT$1, NgStyle, CommonModule, NgOptimizedImage } from '@angular/common';
5
5
  import * as i1 from '@angular/forms';
6
6
  import { FormsModule, FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
7
7
  import { Select } from 'primeng/select';
@@ -9,7 +9,7 @@ import { FloatLabel } from 'primeng/floatlabel';
9
9
  import * as i4 from 'primeng/button';
10
10
  import { Button, ButtonModule } from 'primeng/button';
11
11
  import { interval, tap, map, filter } from 'rxjs';
12
- import { RTSeeTextLabelKeys, hasPermission, RTSeePeerPermissions } from '@rtsee/core';
12
+ import { RTSeeTextLabelKeys, RTSeeCore, hasPermission, RTSeePeerPermissions } from '@rtsee/core';
13
13
  import * as i2$2 from 'primeng/message';
14
14
  import { Message, MessageModule } from 'primeng/message';
15
15
  import { AuthEndpointsKeys, LS_TOKEN_LABEL, LS_USER_LABEL, DEFAULT_ROUTE_NAMES } from '@rtsee/auth';
@@ -17,7 +17,7 @@ import * as i2 from '@angular/router';
17
17
  import { RouterLink, RouterLinkActive, NavigationEnd } from '@angular/router';
18
18
  import { Divider } from 'primeng/divider';
19
19
  import * as i1$1 from '@angular/common/http';
20
- import { RTSeeChatMemberRoles, RTSeeChatTypes, OzzyTaskStatus } from '@rtsee/common';
20
+ import { RTSeeChatMemberRoles, RTSeeIllustratorEvents, RTSeeChatTypes, OzzyTaskStatus } from '@rtsee/common';
21
21
  import { ManageAgentForm, RTSeeForm, RTSeeFormFieldRadioGroup, RTSeeFormField, RTSeeFormFieldImageUploader, RTSeeRater } from '@rtsee/utilities-ui';
22
22
  import { InputText } from 'primeng/inputtext';
23
23
  import { InputGroup } from 'primeng/inputgroup';
@@ -45,6 +45,7 @@ import { MessageService } from 'primeng/api';
45
45
  import Swiper from 'swiper';
46
46
  import { EffectCards, Manipulation } from 'swiper/modules';
47
47
  import { OrderList } from 'primeng/orderlist';
48
+ import { RTSeeIllustrator, RTSeeStoryEditorSection } from '@rtsee/presentation';
48
49
  import { Tabs, TabList, Tab, TabPanels, TabPanel } from 'primeng/tabs';
49
50
  import { ColorPicker } from 'primeng/colorpicker';
50
51
  import { Slider } from 'primeng/slider';
@@ -674,6 +675,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
674
675
  }] } });
675
676
 
676
677
  class RTSeeImageUploaderComponent {
678
+ constructor(elementRef) {
679
+ this.elementRef = elementRef;
680
+ this.submittingFromPainting = false;
681
+ }
677
682
  ngOnInit() {
678
683
  this.attachEventHandlers();
679
684
  }
@@ -686,13 +691,91 @@ class RTSeeImageUploaderComponent {
686
691
  onImagesUploaded(response) {
687
692
  console.log(response);
688
693
  }
689
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RTSeeImageUploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
690
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RTSeeImageUploaderComponent, isStandalone: true, selector: "rtsee-image-uploader", inputs: { imageUploader: "imageUploader" }, viewQueries: [{ propertyName: "cropperComponent", first: true, predicate: RTSeeCropperComponent, descendants: true }], ngImport: i0, template: "<div class=\"rtsee-image-uploader\">\n @if (!imageUploader.awaitsUploadOrCrop) {\n <div class=\"rtsee-image-uploader-image\"\n (click)=\"imageUploader.init()\"\n >\n @if (imageUploader.uploadedPhotoPreview) {\n <img [src]=\"imageUploader.uploadedPhotoPreview\"\n class=\"rtsee-image-uploader-preview-image\"\n alt=\"uploaded_photo\"\n >\n }\n @if (!imageUploader.uploadedPhotoPreview) {\n <div class=\"rtsee-preloader-image-placeholder\">\n <span class=\"material-icons-outlined rtsee-upload-icon\">cloud_upload</span>\n <span class=\"rtsee-upload-text\">Tap to upload image</span>\n </div>\n }\n <div class=\"rtsee-image-uploader-image-change-btn\">\n <p-button icon=\"pi pi-pencil\" severity=\"info\"></p-button>\n </div>\n </div>\n }\n\n @if (imageUploader.awaitsUploadOrCrop) {\n <rtsee-uploader [uploader]=\"imageUploader.uploader\"\n [hidden]=\"imageUploader.cropper?.activeImage\"\n ></rtsee-uploader>\n\n @if (imageUploader.cropper?.activeImage) {\n <rtsee-cropper [cropper]=\"imageUploader.cropper\"\n (nextClicked)=\"onNextButtonClicked()\"\n ></rtsee-cropper>\n }\n }\n</div>\n", dependencies: [{ kind: "component", type: RTSeeUploaderComponent, selector: "rtsee-uploader", inputs: ["uploader"] }, { kind: "component", type: RTSeeCropperComponent, selector: "rtsee-cropper", inputs: ["cropper"], outputs: ["nextClicked"] }, { 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"] }] }); }
694
+ onPaintingIconClicked(event) {
695
+ event.stopPropagation();
696
+ event.preventDefault();
697
+ if (typeof window === 'undefined' || this.submittingFromPainting) {
698
+ return;
699
+ }
700
+ const requestId = RTSeeCore.uuidv4();
701
+ let handled = false;
702
+ const handleResponse = (response) => {
703
+ if (handled) {
704
+ return;
705
+ }
706
+ handled = true;
707
+ if (!response || !response.isLoaded) {
708
+ // 3. If RTSeeIllustrator is not loaded - do nothing
709
+ return;
710
+ }
711
+ if (response.reviewingGeneratedImage && response.imageUrl) {
712
+ // 1. If RTSeeIllustrator is in reviewingGeneratedImage mode, apply currently reviewed image to ImageUploader
713
+ this.submittingFromPainting = true;
714
+ this.imageUploader.applyImageUrl(response.imageUrl);
715
+ // and if Imageuploader is part of the form it should immediately submit the form
716
+ setTimeout(() => {
717
+ this.submitParentForm();
718
+ setTimeout(() => {
719
+ this.submittingFromPainting = false;
720
+ }, 1000);
721
+ }, 50);
722
+ }
723
+ // 2. If RTSeeIllustrator is not active, it expands and scrolls into view (handled by RTSeeIllustrator)
724
+ };
725
+ const responseListener = (e) => {
726
+ const customEvent = e;
727
+ if (!customEvent.detail || (customEvent.detail.requestId && customEvent.detail.requestId !== requestId)) {
728
+ return;
729
+ }
730
+ window.removeEventListener(RTSeeIllustratorEvents.CURRENT_IMAGE_RESPONSE, responseListener);
731
+ clearTimeout(timer);
732
+ handleResponse(customEvent.detail);
733
+ };
734
+ window.addEventListener(RTSeeIllustratorEvents.CURRENT_IMAGE_RESPONSE, responseListener);
735
+ const timer = setTimeout(() => {
736
+ window.removeEventListener(RTSeeIllustratorEvents.CURRENT_IMAGE_RESPONSE, responseListener);
737
+ }, 600);
738
+ window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.GET_CURRENT_IMAGE, {
739
+ detail: {
740
+ requestId,
741
+ callback: (res) => {
742
+ window.removeEventListener(RTSeeIllustratorEvents.CURRENT_IMAGE_RESPONSE, responseListener);
743
+ clearTimeout(timer);
744
+ handleResponse(res);
745
+ },
746
+ },
747
+ }));
748
+ }
749
+ submitParentForm() {
750
+ try {
751
+ // 1. Native HTML form submit so Angular (ngSubmit) / (formSubmit) fires
752
+ const formEl = this.elementRef.nativeElement.closest('form');
753
+ if (formEl) {
754
+ if (typeof formEl.requestSubmit === 'function') {
755
+ formEl.requestSubmit();
756
+ return;
757
+ }
758
+ else {
759
+ formEl.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
760
+ return;
761
+ }
762
+ }
763
+ // 2. Programmatic RTSeeForm submit
764
+ if (this.imageUploader.form && typeof this.imageUploader.form.submit === 'function') {
765
+ this.imageUploader.form.submit();
766
+ }
767
+ }
768
+ catch (e) {
769
+ console.warn('[RTSeeImageUploaderComponent] submitParentForm error:', e);
770
+ }
771
+ }
772
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RTSeeImageUploaderComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
773
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: RTSeeImageUploaderComponent, isStandalone: true, selector: "rtsee-image-uploader", inputs: { imageUploader: "imageUploader" }, viewQueries: [{ propertyName: "cropperComponent", first: true, predicate: RTSeeCropperComponent, descendants: true }], ngImport: i0, template: "<div class=\"rtsee-image-uploader\">\n @if (!imageUploader.awaitsUploadOrCrop) {\n <div class=\"rtsee-image-uploader-image\"\n (click)=\"imageUploader.init()\"\n >\n @if (imageUploader.uploadedPhotoPreview) {\n <img [src]=\"imageUploader.uploadedPhotoPreview\"\n class=\"rtsee-image-uploader-preview-image\"\n alt=\"uploaded_photo\"\n >\n }\n @if (!imageUploader.uploadedPhotoPreview) {\n <div class=\"rtsee-preloader-image-placeholder\">\n <span class=\"material-icons-outlined rtsee-upload-icon\">cloud_upload</span>\n <span class=\"rtsee-upload-text\">Tap to upload image</span>\n </div>\n }\n <div class=\"rtsee-image-uploader-illustrator-btn\"\n (click)=\"onPaintingIconClicked($event)\"\n title=\"Apply illustration from NanoBanana Illustrator\"\n >\n <p-button icon=\"pi pi-palette\" severity=\"help\" [rounded]=\"true\"></p-button>\n </div>\n <div class=\"rtsee-image-uploader-image-change-btn\">\n <p-button icon=\"pi pi-pencil\" severity=\"info\"></p-button>\n </div>\n </div>\n }\n\n @if (imageUploader.awaitsUploadOrCrop) {\n <rtsee-uploader [uploader]=\"imageUploader.uploader\"\n [hidden]=\"imageUploader.cropper?.activeImage\"\n ></rtsee-uploader>\n\n @if (imageUploader.cropper?.activeImage) {\n <rtsee-cropper [cropper]=\"imageUploader.cropper\"\n (nextClicked)=\"onNextButtonClicked()\"\n ></rtsee-cropper>\n }\n }\n</div>\n", dependencies: [{ kind: "component", type: RTSeeUploaderComponent, selector: "rtsee-uploader", inputs: ["uploader"] }, { kind: "component", type: RTSeeCropperComponent, selector: "rtsee-cropper", inputs: ["cropper"], outputs: ["nextClicked"] }, { 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"] }] }); }
691
774
  }
692
775
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RTSeeImageUploaderComponent, decorators: [{
693
776
  type: Component,
694
- args: [{ selector: 'rtsee-image-uploader', imports: [RTSeeUploaderComponent, RTSeeCropperComponent, Button], template: "<div class=\"rtsee-image-uploader\">\n @if (!imageUploader.awaitsUploadOrCrop) {\n <div class=\"rtsee-image-uploader-image\"\n (click)=\"imageUploader.init()\"\n >\n @if (imageUploader.uploadedPhotoPreview) {\n <img [src]=\"imageUploader.uploadedPhotoPreview\"\n class=\"rtsee-image-uploader-preview-image\"\n alt=\"uploaded_photo\"\n >\n }\n @if (!imageUploader.uploadedPhotoPreview) {\n <div class=\"rtsee-preloader-image-placeholder\">\n <span class=\"material-icons-outlined rtsee-upload-icon\">cloud_upload</span>\n <span class=\"rtsee-upload-text\">Tap to upload image</span>\n </div>\n }\n <div class=\"rtsee-image-uploader-image-change-btn\">\n <p-button icon=\"pi pi-pencil\" severity=\"info\"></p-button>\n </div>\n </div>\n }\n\n @if (imageUploader.awaitsUploadOrCrop) {\n <rtsee-uploader [uploader]=\"imageUploader.uploader\"\n [hidden]=\"imageUploader.cropper?.activeImage\"\n ></rtsee-uploader>\n\n @if (imageUploader.cropper?.activeImage) {\n <rtsee-cropper [cropper]=\"imageUploader.cropper\"\n (nextClicked)=\"onNextButtonClicked()\"\n ></rtsee-cropper>\n }\n }\n</div>\n" }]
695
- }], propDecorators: { cropperComponent: [{
777
+ args: [{ selector: 'rtsee-image-uploader', imports: [RTSeeUploaderComponent, RTSeeCropperComponent, Button], template: "<div class=\"rtsee-image-uploader\">\n @if (!imageUploader.awaitsUploadOrCrop) {\n <div class=\"rtsee-image-uploader-image\"\n (click)=\"imageUploader.init()\"\n >\n @if (imageUploader.uploadedPhotoPreview) {\n <img [src]=\"imageUploader.uploadedPhotoPreview\"\n class=\"rtsee-image-uploader-preview-image\"\n alt=\"uploaded_photo\"\n >\n }\n @if (!imageUploader.uploadedPhotoPreview) {\n <div class=\"rtsee-preloader-image-placeholder\">\n <span class=\"material-icons-outlined rtsee-upload-icon\">cloud_upload</span>\n <span class=\"rtsee-upload-text\">Tap to upload image</span>\n </div>\n }\n <div class=\"rtsee-image-uploader-illustrator-btn\"\n (click)=\"onPaintingIconClicked($event)\"\n title=\"Apply illustration from NanoBanana Illustrator\"\n >\n <p-button icon=\"pi pi-palette\" severity=\"help\" [rounded]=\"true\"></p-button>\n </div>\n <div class=\"rtsee-image-uploader-image-change-btn\">\n <p-button icon=\"pi pi-pencil\" severity=\"info\"></p-button>\n </div>\n </div>\n }\n\n @if (imageUploader.awaitsUploadOrCrop) {\n <rtsee-uploader [uploader]=\"imageUploader.uploader\"\n [hidden]=\"imageUploader.cropper?.activeImage\"\n ></rtsee-uploader>\n\n @if (imageUploader.cropper?.activeImage) {\n <rtsee-cropper [cropper]=\"imageUploader.cropper\"\n (nextClicked)=\"onNextButtonClicked()\"\n ></rtsee-cropper>\n }\n }\n</div>\n" }]
778
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { cropperComponent: [{
696
779
  type: ViewChild,
697
780
  args: [RTSeeCropperComponent]
698
781
  }], imageUploader: [{
@@ -3042,10 +3125,14 @@ class ChatComponent {
3042
3125
  });
3043
3126
  this.chat.loadRemoteMessages('back');
3044
3127
  }
3128
+ this.chat?.broadcastAgents();
3045
3129
  }
3046
3130
  ngOnDestroy() {
3047
- if (this.chat.isStandalone) {
3048
- this.messenger.removeStandaloneChat(this.chat.id);
3131
+ if (this.chat) {
3132
+ this.chat.unbindIllustratorEvents();
3133
+ if (this.chat.isStandalone) {
3134
+ this.messenger.removeStandaloneChat(this.chat.id);
3135
+ }
3049
3136
  }
3050
3137
  }
3051
3138
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
@@ -3835,16 +3922,393 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
3835
3922
  type: Input
3836
3923
  }] } });
3837
3924
 
3925
+ /**
3926
+ * Collapsible section rendering the thumbnails of one kind of story element
3927
+ * (characters / artifacts / locations) and the expanded edit form.
3928
+ * All the logic lives in RTSeeStoryElementsEditor.
3929
+ */
3930
+ class StoryElementsSectionComponent {
3931
+ constructor() {
3932
+ this.icon = "pi pi-box";
3933
+ this.collapsed = false;
3934
+ this.canDetach = true;
3935
+ this.toggled = new EventEmitter();
3936
+ }
3937
+ submit() {
3938
+ this.editor.submit();
3939
+ }
3940
+ addToIllustrator(event, item) {
3941
+ event.stopPropagation();
3942
+ event.preventDefault();
3943
+ if (typeof window !== 'undefined') {
3944
+ window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
3945
+ detail: {
3946
+ id: item.id,
3947
+ title: item.name || this.editor.label,
3948
+ imageUrl: item.imageUrl || '',
3949
+ visualDescription: item.visualDescription || item.description || '',
3950
+ description: item.description || '',
3951
+ sourceType: this.editor.section,
3952
+ },
3953
+ }));
3954
+ }
3955
+ }
3956
+ trackById(index, item) {
3957
+ return item.id || `new-${index}`;
3958
+ }
3959
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryElementsSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3960
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: StoryElementsSectionComponent, isStandalone: true, selector: "rtsee-story-elements-section", inputs: { editor: "editor", title: "title", icon: "icon", collapsed: "collapsed", canDetach: "canDetach" }, outputs: { toggled: "toggled" }, ngImport: i0, template: "<section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': collapsed }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\"\n class=\"rtsee-ise-section-toggle\"\n [attr.aria-expanded]=\"!collapsed\"\n [id]=\"'rtsee-ise-toggle-' + editor.section\"\n (click)=\"toggled.emit()\">\n <i class=\"rtsee-ise-section-icon\" [ngClass]=\"icon\"></i>\n <h3 class=\"rtsee-ise-section-title\">{{ title }}</h3>\n <span class=\"rtsee-ise-section-count\">{{ editor.items.length }}</span>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!collapsed) {\n <div class=\"rtsee-ise-section-body\">\n <div class=\"rtsee-ise-thumbs-grid\">\n @for (item of editor.items; track trackById($index, item)) {\n <div class=\"rtsee-ise-thumb-card-container\" style=\"position: relative; display: flex; flex-direction: column;\">\n <button type=\"button\"\n class=\"rtsee-ise-thumb\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': editor.isExpanded(item) }\"\n [id]=\"'rtsee-ise-' + editor.section + '-' + item.id\"\n (click)=\"editor.expand(item)\">\n <div class=\"rtsee-ise-thumb-image\">\n @if (item.imageUrl) {\n <img [src]=\"item.imageUrl\" [alt]=\"item.name\" loading=\"lazy\" />\n } @else {\n <i [ngClass]=\"icon\"></i>\n }\n </div>\n <div class=\"rtsee-ise-thumb-body\">\n <span class=\"rtsee-ise-thumb-name\">{{ item.name }}</span>\n <span class=\"rtsee-ise-thumb-description\">{{ item.getTruncatedDescription(90) }}</span>\n </div>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n style=\"position: absolute; top: 8px; right: 8px;\"\n title=\"Add {{ item.name }} to Illustrator context\"\n (click)=\"addToIllustrator($event, item)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n </div>\n }\n\n <button type=\"button\"\n class=\"rtsee-ise-thumb rtsee-ise-thumb--add\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': editor.isCreating }\"\n [id]=\"'rtsee-ise-add-' + editor.section\"\n (click)=\"editor.expandNew()\">\n <i class=\"pi pi-plus\"></i>\n <span>New {{ editor.label }}</span>\n </button>\n </div>\n\n @if (editor.expanded && editor.form) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n <div class=\"rtsee-ise-expanded-header\">\n <h4>{{ editor.expanded.isNew ? 'New ' + editor.label : editor.expanded.name }}</h4>\n <div style=\"display: flex; align-items: center; gap: 8px;\">\n @if (!editor.expanded.isNew) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n title=\"Add to Illustrator context\"\n (click)=\"addToIllustrator($event, editor.expanded)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8 Illustrator</span>\n </button>\n }\n <button type=\"button\" class=\"rtsee-ise-icon-button\" (click)=\"editor.collapse()\" aria-label=\"Close\">\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </div>\n\n @if (editor.error) {\n <div class=\"rtsee-ise-error\">{{ editor.error }}</div>\n }\n\n <rtsee-form [form]=\"editor.form\" (formSubmit)=\"submit()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\"\n [label]=\"editor.expanded.isNew ? 'Create' : 'Save'\"\n [loading]=\"editor.saveInProgress\"\n [disabled]=\"editor.busy\" />\n <p-button label=\"Cancel\"\n severity=\"secondary\"\n (click)=\"editor.collapse()\"\n [disabled]=\"editor.busy\" />\n @if (!editor.expanded.isNew) {\n <span class=\"rtsee-ise-actions-spacer\"></span>\n @if (canDetach) {\n <p-button label=\"Remove from story\"\n icon=\"pi pi-minus-circle\"\n severity=\"secondary\"\n [text]=\"true\"\n (click)=\"editor.detach(editor.expanded)\"\n [disabled]=\"editor.busy\" />\n }\n <p-button label=\"Delete\"\n icon=\"pi pi-trash\"\n severity=\"danger\"\n [text]=\"true\"\n [loading]=\"editor.removeInProgress\"\n (click)=\"editor.delete(editor.expanded)\"\n [disabled]=\"editor.busy\" />\n }\n </div>\n </rtsee-form>\n </div>\n }\n </div>\n }\n</section>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: FormComponent, selector: "rtsee-form", inputs: ["form"], outputs: ["formSubmit"] }] }); }
3961
+ }
3962
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryElementsSectionComponent, decorators: [{
3963
+ type: Component,
3964
+ args: [{ selector: "rtsee-story-elements-section", standalone: true, imports: [NgClass, Button, FormComponent], template: "<section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': collapsed }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\"\n class=\"rtsee-ise-section-toggle\"\n [attr.aria-expanded]=\"!collapsed\"\n [id]=\"'rtsee-ise-toggle-' + editor.section\"\n (click)=\"toggled.emit()\">\n <i class=\"rtsee-ise-section-icon\" [ngClass]=\"icon\"></i>\n <h3 class=\"rtsee-ise-section-title\">{{ title }}</h3>\n <span class=\"rtsee-ise-section-count\">{{ editor.items.length }}</span>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!collapsed) {\n <div class=\"rtsee-ise-section-body\">\n <div class=\"rtsee-ise-thumbs-grid\">\n @for (item of editor.items; track trackById($index, item)) {\n <div class=\"rtsee-ise-thumb-card-container\" style=\"position: relative; display: flex; flex-direction: column;\">\n <button type=\"button\"\n class=\"rtsee-ise-thumb\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': editor.isExpanded(item) }\"\n [id]=\"'rtsee-ise-' + editor.section + '-' + item.id\"\n (click)=\"editor.expand(item)\">\n <div class=\"rtsee-ise-thumb-image\">\n @if (item.imageUrl) {\n <img [src]=\"item.imageUrl\" [alt]=\"item.name\" loading=\"lazy\" />\n } @else {\n <i [ngClass]=\"icon\"></i>\n }\n </div>\n <div class=\"rtsee-ise-thumb-body\">\n <span class=\"rtsee-ise-thumb-name\">{{ item.name }}</span>\n <span class=\"rtsee-ise-thumb-description\">{{ item.getTruncatedDescription(90) }}</span>\n </div>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n style=\"position: absolute; top: 8px; right: 8px;\"\n title=\"Add {{ item.name }} to Illustrator context\"\n (click)=\"addToIllustrator($event, item)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n </div>\n }\n\n <button type=\"button\"\n class=\"rtsee-ise-thumb rtsee-ise-thumb--add\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': editor.isCreating }\"\n [id]=\"'rtsee-ise-add-' + editor.section\"\n (click)=\"editor.expandNew()\">\n <i class=\"pi pi-plus\"></i>\n <span>New {{ editor.label }}</span>\n </button>\n </div>\n\n @if (editor.expanded && editor.form) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n <div class=\"rtsee-ise-expanded-header\">\n <h4>{{ editor.expanded.isNew ? 'New ' + editor.label : editor.expanded.name }}</h4>\n <div style=\"display: flex; align-items: center; gap: 8px;\">\n @if (!editor.expanded.isNew) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n title=\"Add to Illustrator context\"\n (click)=\"addToIllustrator($event, editor.expanded)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8 Illustrator</span>\n </button>\n }\n <button type=\"button\" class=\"rtsee-ise-icon-button\" (click)=\"editor.collapse()\" aria-label=\"Close\">\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </div>\n\n @if (editor.error) {\n <div class=\"rtsee-ise-error\">{{ editor.error }}</div>\n }\n\n <rtsee-form [form]=\"editor.form\" (formSubmit)=\"submit()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\"\n [label]=\"editor.expanded.isNew ? 'Create' : 'Save'\"\n [loading]=\"editor.saveInProgress\"\n [disabled]=\"editor.busy\" />\n <p-button label=\"Cancel\"\n severity=\"secondary\"\n (click)=\"editor.collapse()\"\n [disabled]=\"editor.busy\" />\n @if (!editor.expanded.isNew) {\n <span class=\"rtsee-ise-actions-spacer\"></span>\n @if (canDetach) {\n <p-button label=\"Remove from story\"\n icon=\"pi pi-minus-circle\"\n severity=\"secondary\"\n [text]=\"true\"\n (click)=\"editor.detach(editor.expanded)\"\n [disabled]=\"editor.busy\" />\n }\n <p-button label=\"Delete\"\n icon=\"pi pi-trash\"\n severity=\"danger\"\n [text]=\"true\"\n [loading]=\"editor.removeInProgress\"\n (click)=\"editor.delete(editor.expanded)\"\n [disabled]=\"editor.busy\" />\n }\n </div>\n </rtsee-form>\n </div>\n }\n </div>\n }\n</section>\n" }]
3965
+ }], propDecorators: { editor: [{
3966
+ type: Input,
3967
+ args: [{ required: true }]
3968
+ }], title: [{
3969
+ type: Input,
3970
+ args: [{ required: true }]
3971
+ }], icon: [{
3972
+ type: Input
3973
+ }], collapsed: [{
3974
+ type: Input
3975
+ }], canDetach: [{
3976
+ type: Input
3977
+ }], toggled: [{
3978
+ type: Output
3979
+ }] } });
3980
+
3981
+ class IllustratorComponent {
3982
+ constructor(cdr, elementRef) {
3983
+ this.cdr = cdr;
3984
+ this.elementRef = elementRef;
3985
+ this.ownIllustrator = false;
3986
+ this.aspectRatios = ['1:1', '4:3', '3:4', '16:9', '9:16', '3:2', '2:3'];
3987
+ this.styles = [
3988
+ 'Classic Fairy Tale pixel-art Storybook',
3989
+ 'Whimsical Watercolor & Ink',
3990
+ 'Golden Age Storybook Illustration',
3991
+ 'Enchanted Fantasy Digital Art',
3992
+ 'Vibrant Children\'s Book Illustration',
3993
+ 'Ethereal Oil Painting',
3994
+ ];
3995
+ this.moods = [
3996
+ 'Dreamy & Magical',
3997
+ 'Warm, Cozy & Hearth-lit',
3998
+ 'Epic, Wonder-filled & Adventurous',
3999
+ 'Mysterious & Enchanted',
4000
+ 'Playful & Charming',
4001
+ 'Dark Fantasy & Gothic',
4002
+ ];
4003
+ this.lightings = [
4004
+ 'Soft Diffused Storybook Glow',
4005
+ 'Golden Hour Sunbeams & Dappled Rays',
4006
+ 'Twilight Starlight & Fireflies',
4007
+ 'Cozy Candlelight & Lantern Glow',
4008
+ 'Dramatic Volumetric Rays',
4009
+ 'Moonlit Midnight Glow',
4010
+ ];
4011
+ this.onIllustratorChanged = () => {
4012
+ this.cdr.markForCheck();
4013
+ };
4014
+ this.onScrollIntoView = () => {
4015
+ this.cdr.markForCheck();
4016
+ setTimeout(() => {
4017
+ this.elementRef.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
4018
+ }, 60);
4019
+ };
4020
+ }
4021
+ ngOnInit() {
4022
+ if (!this.illustrator) {
4023
+ this.illustrator = new RTSeeIllustrator();
4024
+ this.ownIllustrator = true;
4025
+ }
4026
+ this.illustrator.on('changed', this.onIllustratorChanged);
4027
+ this.illustrator.on('scroll-into-view', this.onScrollIntoView);
4028
+ this.illustrator.requestAgents();
4029
+ }
4030
+ ngOnDestroy() {
4031
+ if (this.illustrator) {
4032
+ this.illustrator.off('changed', this.onIllustratorChanged);
4033
+ this.illustrator.off('scroll-into-view', this.onScrollIntoView);
4034
+ if (this.ownIllustrator) {
4035
+ this.illustrator.destroy();
4036
+ }
4037
+ }
4038
+ }
4039
+ toggleExpand() {
4040
+ this.illustrator.toggleExpand();
4041
+ }
4042
+ toggleConfig() {
4043
+ this.illustrator.toggleConfig();
4044
+ }
4045
+ onSelectAgent(event) {
4046
+ const target = event.target;
4047
+ if (target?.value) {
4048
+ this.illustrator.selectAgent(target.value);
4049
+ }
4050
+ }
4051
+ refreshAgents() {
4052
+ this.illustrator.requestAgents();
4053
+ }
4054
+ removeImage(id) {
4055
+ this.illustrator.removeContextImage(id);
4056
+ }
4057
+ toggleActive(image) {
4058
+ this.illustrator.toggleImageActive(image.id);
4059
+ }
4060
+ discardGeneratedImage() {
4061
+ this.illustrator.discardGeneratedImage();
4062
+ }
4063
+ acceptGeneratedImage() {
4064
+ this.illustrator.acceptGeneratedImage();
4065
+ }
4066
+ submitIteration() {
4067
+ this.illustrator.submitIteration();
4068
+ }
4069
+ submitPrompt() {
4070
+ this.illustrator.submitPrompt();
4071
+ }
4072
+ trackByImageId(index, item) {
4073
+ return item.id || `context-img-${index}`;
4074
+ }
4075
+ trackByAgentId(index, item) {
4076
+ return item.id || `agent-${index}`;
4077
+ }
4078
+ 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 }); }
4079
+ 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 }); }
4080
+ }
4081
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: IllustratorComponent, decorators: [{
4082
+ type: Component,
4083
+ args: [{ selector: 'rtsee-illustrator', standalone: true, imports: [CommonModule, FormsModule, Button, Checkbox, Textarea], changeDetection: ChangeDetectionStrategy.OnPush, 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" }]
4084
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }], propDecorators: { illustrator: [{
4085
+ type: Input
4086
+ }] } });
4087
+
4088
+ /**
4089
+ * Interactive story editor: collapsible sections of thumbnails (details, characters,
4090
+ * artifacts, locations, slides, author) that expand into the edit forms.
4091
+ * Rendering only, the orchestration lives in RTSeeInteractiveStoryEditorVm.
4092
+ */
4093
+ class InteractiveStoryEditorComponent {
4094
+ constructor() {
4095
+ /** set to false when the vm is initialized by the host */
4096
+ this.autoInit = true;
4097
+ this.sections = RTSeeStoryEditorSection;
4098
+ this.illustrator = new RTSeeIllustrator();
4099
+ }
4100
+ ngOnInit() {
4101
+ if (this.autoInit && !this.vm.story) {
4102
+ void this.vm.init();
4103
+ }
4104
+ }
4105
+ ngOnDestroy() {
4106
+ this.vm.collapseSlide();
4107
+ this.illustrator.destroy();
4108
+ }
4109
+ submitDetails() {
4110
+ this.vm.detailsForm?.submit();
4111
+ }
4112
+ submitAuthor() {
4113
+ this.vm.authorForm?.submit();
4114
+ }
4115
+ submitNewAuthor() {
4116
+ this.vm.newAuthorForm?.submit();
4117
+ }
4118
+ addSlideToContext(event, slide) {
4119
+ event.stopPropagation();
4120
+ event.preventDefault();
4121
+ if (typeof window !== 'undefined') {
4122
+ const anySlide = slide;
4123
+ window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
4124
+ detail: {
4125
+ id: slide.id,
4126
+ title: `Slide ${slide.slideNumber}: ${slide.name || 'Story Scene'}`,
4127
+ imageUrl: slide.imageUrl || '',
4128
+ visualDescription: anySlide.visualDescription || slide.text || '',
4129
+ description: anySlide.description || slide.text || '',
4130
+ sourceType: 'slide',
4131
+ },
4132
+ }));
4133
+ }
4134
+ }
4135
+ addSlideEntitiesToContext(event, slide) {
4136
+ event.stopPropagation();
4137
+ event.preventDefault();
4138
+ if (typeof window === 'undefined') {
4139
+ return;
4140
+ }
4141
+ // 1. Characters: populate all related characters from story level
4142
+ const slideCharacters = slide.characters || [];
4143
+ const storyChars = this.vm.story?.characters ||
4144
+ this.vm.charactersEditor?.items ||
4145
+ [];
4146
+ for (const charRef of slideCharacters) {
4147
+ const fullChar = storyChars.find((c) => c.id === charRef.id || c.name?.toLowerCase() === charRef.name?.toLowerCase());
4148
+ if (fullChar) {
4149
+ window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
4150
+ detail: {
4151
+ id: fullChar.id,
4152
+ title: fullChar.name || 'Character',
4153
+ imageUrl: fullChar.imageUrl || '',
4154
+ visualDescription: fullChar.visualDescription || fullChar.description || '',
4155
+ description: fullChar.description || '',
4156
+ sourceType: 'character',
4157
+ },
4158
+ }));
4159
+ }
4160
+ }
4161
+ if (slide.charactersIds) {
4162
+ for (const charId of slide.charactersIds) {
4163
+ if (!slideCharacters.some((c) => c.id === charId)) {
4164
+ const fullChar = storyChars.find((c) => c.id === charId);
4165
+ if (fullChar) {
4166
+ window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
4167
+ detail: {
4168
+ id: fullChar.id,
4169
+ title: fullChar.name || 'Character',
4170
+ imageUrl: fullChar.imageUrl || '',
4171
+ visualDescription: fullChar.visualDescription || fullChar.description || '',
4172
+ description: fullChar.description || '',
4173
+ sourceType: 'character',
4174
+ },
4175
+ }));
4176
+ }
4177
+ }
4178
+ }
4179
+ }
4180
+ // 2. Locations: populate related location from story level
4181
+ const slideLocations = slide.locations || [];
4182
+ const storyLocs = this.vm.story?.locations ||
4183
+ this.vm.locationsEditor?.items ||
4184
+ [];
4185
+ for (const locRef of slideLocations) {
4186
+ const fullLoc = storyLocs.find((l) => l.id === locRef.id || l.name?.toLowerCase() === locRef.name?.toLowerCase());
4187
+ if (fullLoc) {
4188
+ window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
4189
+ detail: {
4190
+ id: fullLoc.id,
4191
+ title: fullLoc.name || 'Location',
4192
+ imageUrl: fullLoc.imageUrl || '',
4193
+ visualDescription: fullLoc.visualDescription || fullLoc.description || '',
4194
+ description: fullLoc.description || '',
4195
+ sourceType: 'location',
4196
+ },
4197
+ }));
4198
+ }
4199
+ }
4200
+ if (slide.locationId && !slideLocations.some((l) => l.id === slide.locationId)) {
4201
+ const fullLoc = storyLocs.find((l) => l.id === slide.locationId);
4202
+ if (fullLoc) {
4203
+ window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
4204
+ detail: {
4205
+ id: fullLoc.id,
4206
+ title: fullLoc.name || 'Location',
4207
+ imageUrl: fullLoc.imageUrl || '',
4208
+ visualDescription: fullLoc.visualDescription || fullLoc.description || '',
4209
+ description: fullLoc.description || '',
4210
+ sourceType: 'location',
4211
+ },
4212
+ }));
4213
+ }
4214
+ }
4215
+ // 3. Artifacts: populate related artifacts from story level
4216
+ const slideArtifacts = slide.artifacts || [];
4217
+ const storyArts = this.vm.story?.artifacts ||
4218
+ this.vm.artifactsEditor?.items ||
4219
+ [];
4220
+ for (const artRef of slideArtifacts) {
4221
+ const fullArt = storyArts.find((a) => a.id === artRef.id || a.name?.toLowerCase() === artRef.name?.toLowerCase());
4222
+ if (fullArt) {
4223
+ window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
4224
+ detail: {
4225
+ id: fullArt.id,
4226
+ title: fullArt.name || 'Artifact',
4227
+ imageUrl: fullArt.imageUrl || '',
4228
+ visualDescription: fullArt.visualDescription || fullArt.description || '',
4229
+ description: fullArt.description || '',
4230
+ sourceType: 'artifact',
4231
+ },
4232
+ }));
4233
+ }
4234
+ }
4235
+ if (slide.artifactsIds) {
4236
+ for (const artId of slide.artifactsIds) {
4237
+ if (!slideArtifacts.some((a) => a.id === artId)) {
4238
+ const fullArt = storyArts.find((a) => a.id === artId);
4239
+ if (fullArt) {
4240
+ window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
4241
+ detail: {
4242
+ id: fullArt.id,
4243
+ title: fullArt.name || 'Artifact',
4244
+ imageUrl: fullArt.imageUrl || '',
4245
+ visualDescription: fullArt.visualDescription || fullArt.description || '',
4246
+ description: fullArt.description || '',
4247
+ sourceType: 'artifact',
4248
+ },
4249
+ }));
4250
+ }
4251
+ }
4252
+ }
4253
+ }
4254
+ // 4. Illustration prompt: populate prompt box with slide illustrationDescription
4255
+ const illustrationDesc = slide.illustrationDescription ?? slide.illustrationDescription;
4256
+ if (typeof illustrationDesc === 'string' && illustrationDesc.trim()) {
4257
+ this.illustrator.setPrompt(illustrationDesc.trim());
4258
+ window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.SET_PROMPT, {
4259
+ detail: { prompt: illustrationDesc.trim() },
4260
+ }));
4261
+ }
4262
+ }
4263
+ addAuthorToContext(event) {
4264
+ event.stopPropagation();
4265
+ event.preventDefault();
4266
+ if (typeof window !== 'undefined' && this.vm.author) {
4267
+ window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
4268
+ detail: {
4269
+ id: this.vm.author.id,
4270
+ title: `Author: ${this.vm.author.name || ''}`,
4271
+ imageUrl: this.vm.author.imageUrl || '',
4272
+ visualDescription: this.vm.author.description || '',
4273
+ description: this.vm.author.description || '',
4274
+ sourceType: 'author',
4275
+ },
4276
+ }));
4277
+ }
4278
+ }
4279
+ trackSlide(index, slide) {
4280
+ return slide.id || `slide-${index}`;
4281
+ }
4282
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InteractiveStoryEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4283
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: InteractiveStoryEditorComponent, isStandalone: true, selector: "rtsee-interactive-story-editor", inputs: { vm: "vm", autoInit: "autoInit" }, ngImport: i0, template: "<div class=\"rtsee-interactive-story-editor\" [style.padding-bottom]=\"illustrator.expanded ? '460px' : '72px'\">\n @if (vm.initInProgress) {\n <div class=\"rtsee-ise-loading\">\n <i class=\"pi pi-spin pi-spinner\"></i>\n <span>Loading story\u2026</span>\n </div>\n } @else if (vm.initError) {\n <div class=\"rtsee-ise-error\">{{ vm.initError }}</div>\n } @else if (vm.story) {\n <header class=\"rtsee-ise-header\">\n <span class=\"rtsee-ise-eyebrow\">{{ vm.isNewStory ? 'New story' : 'Story editor' }}</span>\n <h2 class=\"rtsee-ise-heading\">{{ vm.story.name || 'Untitled story' }}</h2>\n </header>\n\n <!-- 1. Details -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.details) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-details\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.details)\"\n (click)=\"vm.toggleSection(sections.details)\">\n <i class=\"rtsee-ise-section-icon pi pi-book\"></i>\n <h3 class=\"rtsee-ise-section-title\">Story details</h3>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.details)) {\n <div class=\"rtsee-ise-section-body\">\n <button type=\"button\" class=\"rtsee-ise-details-card\" id=\"rtsee-ise-details-card\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.detailsExpanded }\"\n (click)=\"vm.toggleDetails()\">\n <div class=\"rtsee-ise-details-image\">\n @if (vm.story.imageUrl) {\n <img [src]=\"vm.story.imageUrl\" [alt]=\"vm.story.name\" />\n } @else {\n <i class=\"pi pi-image\"></i>\n }\n </div>\n <div class=\"rtsee-ise-details-body\">\n <span class=\"rtsee-ise-details-name\">{{ vm.story.name || 'Untitled story' }}</span>\n <p class=\"rtsee-ise-details-description\">{{ vm.story.getTruncatedDescription(220) || 'No description yet' }}</p>\n @if (vm.story.tags.length) {\n <div class=\"rtsee-ise-chips\">\n @for (tag of vm.story.tags; track tag.id) {\n <span class=\"rtsee-ise-chip\">{{ tag.name }}</span>\n }\n </div>\n }\n </div>\n <i class=\"pi pi-pencil rtsee-ise-details-edit\"></i>\n </button>\n\n @if (vm.detailsExpanded && vm.detailsForm) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n @if (vm.detailsError) {\n <div class=\"rtsee-ise-error\">{{ vm.detailsError }}</div>\n }\n <rtsee-form [form]=\"vm.detailsForm\" (formSubmit)=\"submitDetails()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" [label]=\"vm.isNewStory ? 'Create story' : 'Save'\"\n [loading]=\"vm.detailsSaveInProgress\"\n [disabled]=\"vm.detailsSaveInProgress\" />\n <p-button label=\"Cancel\" severity=\"secondary\"\n (click)=\"vm.collapseDetails()\"\n [disabled]=\"vm.detailsSaveInProgress\" />\n </div>\n </rtsee-form>\n </div>\n }\n </div>\n }\n </section>\n\n <!-- 2-4. Characters, artifacts, locations -->\n <rtsee-story-elements-section [editor]=\"vm.charactersEditor\"\n title=\"Characters\"\n icon=\"pi pi-user\"\n [collapsed]=\"vm.isCollapsed(sections.characters)\"\n (toggled)=\"vm.toggleSection(sections.characters)\" />\n\n <rtsee-story-elements-section [editor]=\"vm.artifactsEditor\"\n title=\"Artifacts\"\n icon=\"pi pi-star\"\n [collapsed]=\"vm.isCollapsed(sections.artifacts)\"\n (toggled)=\"vm.toggleSection(sections.artifacts)\" />\n\n <rtsee-story-elements-section [editor]=\"vm.locationsEditor\"\n title=\"Locations\"\n icon=\"pi pi-map-marker\"\n [collapsed]=\"vm.isCollapsed(sections.locations)\"\n (toggled)=\"vm.toggleSection(sections.locations)\" />\n\n <!-- 5. Slides -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.slides) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-slides\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.slides)\"\n (click)=\"vm.toggleSection(sections.slides)\">\n <i class=\"rtsee-ise-section-icon pi pi-images\"></i>\n <h3 class=\"rtsee-ise-section-title\">Slides</h3>\n <span class=\"rtsee-ise-section-count\">{{ vm.slides.length }}</span>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.slides)) {\n <div class=\"rtsee-ise-section-body\">\n @if (vm.isNewStory) {\n <p class=\"rtsee-ise-hint\">Save the story details first to add slides.</p>\n } @else {\n <div class=\"rtsee-ise-slides-strip\">\n @for (slide of vm.slides; track trackSlide($index, slide)) {\n <div class=\"rtsee-ise-slide-thumb-wrapper\" style=\"position: relative; display: inline-flex;\">\n <button type=\"button\" class=\"rtsee-ise-slide-thumb\"\n [id]=\"'rtsee-ise-slide-' + slide.id\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.isSlideExpanded(slide) }\"\n [attr.aria-label]=\"'Slide ' + slide.slideNumber\"\n (click)=\"vm.expandSlide(slide)\">\n @if (slide.imageUrl) {\n <img [src]=\"slide.imageUrl\" [alt]=\"slide.name\" loading=\"lazy\" />\n } @else {\n <i class=\"pi pi-image\"></i>\n }\n <span class=\"rtsee-ise-slide-number\">{{ slide.slideNumber }}</span>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator rtsee-ise-btn-add-context\"\n style=\"position: absolute; top: 4px; left: 4px;\"\n title=\"Add Slide {{ slide.slideNumber }} context (characters, locations, artifacts) to Illustrator\"\n (click)=\"addSlideEntitiesToContext($event, slide)\">\n <i class=\"pi pi-plus\"></i>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n style=\"position: absolute; top: 4px; right: 4px;\"\n title=\"Add Slide {{ slide.slideNumber }} to Illustrator context\"\n (click)=\"addSlideToContext($event, slide)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n </div>\n }\n <button type=\"button\" class=\"rtsee-ise-slide-thumb rtsee-ise-slide-thumb--add\"\n id=\"rtsee-ise-add-slide\"\n [disabled]=\"vm.slidesLoadInProgress\"\n (click)=\"vm.expandNewSlide()\">\n <i class=\"pi pi-plus\"></i>\n </button>\n </div>\n\n @if (vm.activeSlide) {\n <div class=\"rtsee-ise-expanded\">\n <rtsee-manage-slide [manageSlide]=\"vm.activeSlide\" />\n </div>\n }\n }\n </div>\n }\n </section>\n\n <!-- 6. Author -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.author) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-author\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.author)\"\n (click)=\"vm.toggleSection(sections.author)\">\n <i class=\"rtsee-ise-section-icon pi pi-pen-to-square\"></i>\n <h3 class=\"rtsee-ise-section-title\">Author</h3>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.author)) {\n <div class=\"rtsee-ise-section-body\">\n <button type=\"button\" class=\"rtsee-ise-author-card\" id=\"rtsee-ise-author-card\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.authorExpanded }\"\n (click)=\"vm.toggleAuthor()\">\n <div class=\"rtsee-ise-avatar\">\n @if (vm.author?.imageUrl) {\n <img [src]=\"vm.author?.imageUrl\" [alt]=\"vm.author?.name\" />\n } @else {\n <i class=\"pi pi-user\"></i>\n }\n </div>\n <div class=\"rtsee-ise-author-body\">\n <span class=\"rtsee-ise-thumb-name\">{{ vm.author?.name || 'No author assigned' }}</span>\n <span class=\"rtsee-ise-thumb-description\">{{ vm.author?.description || 'Click to pick or create an author' }}</span>\n </div>\n @if (vm.author) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n title=\"Add Author to Illustrator context\"\n (click)=\"addAuthorToContext($event)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n }\n <i class=\"pi pi-pencil rtsee-ise-details-edit\"></i>\n </button>\n\n @if (vm.authorExpanded) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n @if (vm.authorError) {\n <div class=\"rtsee-ise-error\">{{ vm.authorError }}</div>\n }\n\n @if (vm.newAuthor && vm.newAuthorForm) {\n <h4 class=\"rtsee-ise-subheading\">New author</h4>\n <rtsee-form [form]=\"vm.newAuthorForm\" (formSubmit)=\"submitNewAuthor()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" label=\"Create & assign\"\n [loading]=\"vm.authorSaveInProgress\"\n [disabled]=\"vm.authorSaveInProgress\" />\n <p-button label=\"Back\" severity=\"secondary\"\n (click)=\"vm.cancelNewAuthor()\"\n [disabled]=\"vm.authorSaveInProgress\" />\n </div>\n </rtsee-form>\n } @else if (vm.authorForm) {\n <rtsee-form [form]=\"vm.authorForm\" (formSubmit)=\"submitAuthor()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" label=\"Assign\"\n [loading]=\"vm.authorSaveInProgress\"\n [disabled]=\"vm.authorSaveInProgress\" />\n <p-button label=\"New author\" icon=\"pi pi-plus\" severity=\"secondary\"\n (click)=\"vm.startNewAuthor()\"\n [disabled]=\"vm.authorSaveInProgress\" />\n @if (vm.author) {\n <span class=\"rtsee-ise-actions-spacer\"></span>\n <p-button label=\"Clear\" icon=\"pi pi-times\" severity=\"danger\" [text]=\"true\"\n (click)=\"vm.assignAuthor(null)\"\n [disabled]=\"vm.authorSaveInProgress\" />\n }\n </div>\n </rtsee-form>\n }\n </div>\n }\n </div>\n }\n </section>\n\n <!-- 7. NanoBanana Illustrator Overlay -->\n <rtsee-illustrator [illustrator]=\"illustrator\" />\n }\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: FormComponent, selector: "rtsee-form", inputs: ["form"], outputs: ["formSubmit"] }, { kind: "component", type: ManageSlideComponent, selector: "rtsee-manage-slide", inputs: ["manageSlide"] }, { kind: "component", type: StoryElementsSectionComponent, selector: "rtsee-story-elements-section", inputs: ["editor", "title", "icon", "collapsed", "canDetach"], outputs: ["toggled"] }, { kind: "component", type: IllustratorComponent, selector: "rtsee-illustrator", inputs: ["illustrator"] }] }); }
4284
+ }
4285
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InteractiveStoryEditorComponent, decorators: [{
4286
+ type: Component,
4287
+ args: [{ selector: "rtsee-interactive-story-editor", standalone: true, imports: [
4288
+ NgClass,
4289
+ Button,
4290
+ FormComponent,
4291
+ ManageSlideComponent,
4292
+ StoryElementsSectionComponent,
4293
+ IllustratorComponent,
4294
+ ], template: "<div class=\"rtsee-interactive-story-editor\" [style.padding-bottom]=\"illustrator.expanded ? '460px' : '72px'\">\n @if (vm.initInProgress) {\n <div class=\"rtsee-ise-loading\">\n <i class=\"pi pi-spin pi-spinner\"></i>\n <span>Loading story\u2026</span>\n </div>\n } @else if (vm.initError) {\n <div class=\"rtsee-ise-error\">{{ vm.initError }}</div>\n } @else if (vm.story) {\n <header class=\"rtsee-ise-header\">\n <span class=\"rtsee-ise-eyebrow\">{{ vm.isNewStory ? 'New story' : 'Story editor' }}</span>\n <h2 class=\"rtsee-ise-heading\">{{ vm.story.name || 'Untitled story' }}</h2>\n </header>\n\n <!-- 1. Details -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.details) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-details\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.details)\"\n (click)=\"vm.toggleSection(sections.details)\">\n <i class=\"rtsee-ise-section-icon pi pi-book\"></i>\n <h3 class=\"rtsee-ise-section-title\">Story details</h3>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.details)) {\n <div class=\"rtsee-ise-section-body\">\n <button type=\"button\" class=\"rtsee-ise-details-card\" id=\"rtsee-ise-details-card\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.detailsExpanded }\"\n (click)=\"vm.toggleDetails()\">\n <div class=\"rtsee-ise-details-image\">\n @if (vm.story.imageUrl) {\n <img [src]=\"vm.story.imageUrl\" [alt]=\"vm.story.name\" />\n } @else {\n <i class=\"pi pi-image\"></i>\n }\n </div>\n <div class=\"rtsee-ise-details-body\">\n <span class=\"rtsee-ise-details-name\">{{ vm.story.name || 'Untitled story' }}</span>\n <p class=\"rtsee-ise-details-description\">{{ vm.story.getTruncatedDescription(220) || 'No description yet' }}</p>\n @if (vm.story.tags.length) {\n <div class=\"rtsee-ise-chips\">\n @for (tag of vm.story.tags; track tag.id) {\n <span class=\"rtsee-ise-chip\">{{ tag.name }}</span>\n }\n </div>\n }\n </div>\n <i class=\"pi pi-pencil rtsee-ise-details-edit\"></i>\n </button>\n\n @if (vm.detailsExpanded && vm.detailsForm) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n @if (vm.detailsError) {\n <div class=\"rtsee-ise-error\">{{ vm.detailsError }}</div>\n }\n <rtsee-form [form]=\"vm.detailsForm\" (formSubmit)=\"submitDetails()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" [label]=\"vm.isNewStory ? 'Create story' : 'Save'\"\n [loading]=\"vm.detailsSaveInProgress\"\n [disabled]=\"vm.detailsSaveInProgress\" />\n <p-button label=\"Cancel\" severity=\"secondary\"\n (click)=\"vm.collapseDetails()\"\n [disabled]=\"vm.detailsSaveInProgress\" />\n </div>\n </rtsee-form>\n </div>\n }\n </div>\n }\n </section>\n\n <!-- 2-4. Characters, artifacts, locations -->\n <rtsee-story-elements-section [editor]=\"vm.charactersEditor\"\n title=\"Characters\"\n icon=\"pi pi-user\"\n [collapsed]=\"vm.isCollapsed(sections.characters)\"\n (toggled)=\"vm.toggleSection(sections.characters)\" />\n\n <rtsee-story-elements-section [editor]=\"vm.artifactsEditor\"\n title=\"Artifacts\"\n icon=\"pi pi-star\"\n [collapsed]=\"vm.isCollapsed(sections.artifacts)\"\n (toggled)=\"vm.toggleSection(sections.artifacts)\" />\n\n <rtsee-story-elements-section [editor]=\"vm.locationsEditor\"\n title=\"Locations\"\n icon=\"pi pi-map-marker\"\n [collapsed]=\"vm.isCollapsed(sections.locations)\"\n (toggled)=\"vm.toggleSection(sections.locations)\" />\n\n <!-- 5. Slides -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.slides) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-slides\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.slides)\"\n (click)=\"vm.toggleSection(sections.slides)\">\n <i class=\"rtsee-ise-section-icon pi pi-images\"></i>\n <h3 class=\"rtsee-ise-section-title\">Slides</h3>\n <span class=\"rtsee-ise-section-count\">{{ vm.slides.length }}</span>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.slides)) {\n <div class=\"rtsee-ise-section-body\">\n @if (vm.isNewStory) {\n <p class=\"rtsee-ise-hint\">Save the story details first to add slides.</p>\n } @else {\n <div class=\"rtsee-ise-slides-strip\">\n @for (slide of vm.slides; track trackSlide($index, slide)) {\n <div class=\"rtsee-ise-slide-thumb-wrapper\" style=\"position: relative; display: inline-flex;\">\n <button type=\"button\" class=\"rtsee-ise-slide-thumb\"\n [id]=\"'rtsee-ise-slide-' + slide.id\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.isSlideExpanded(slide) }\"\n [attr.aria-label]=\"'Slide ' + slide.slideNumber\"\n (click)=\"vm.expandSlide(slide)\">\n @if (slide.imageUrl) {\n <img [src]=\"slide.imageUrl\" [alt]=\"slide.name\" loading=\"lazy\" />\n } @else {\n <i class=\"pi pi-image\"></i>\n }\n <span class=\"rtsee-ise-slide-number\">{{ slide.slideNumber }}</span>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator rtsee-ise-btn-add-context\"\n style=\"position: absolute; top: 4px; left: 4px;\"\n title=\"Add Slide {{ slide.slideNumber }} context (characters, locations, artifacts) to Illustrator\"\n (click)=\"addSlideEntitiesToContext($event, slide)\">\n <i class=\"pi pi-plus\"></i>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n style=\"position: absolute; top: 4px; right: 4px;\"\n title=\"Add Slide {{ slide.slideNumber }} to Illustrator context\"\n (click)=\"addSlideToContext($event, slide)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n </div>\n }\n <button type=\"button\" class=\"rtsee-ise-slide-thumb rtsee-ise-slide-thumb--add\"\n id=\"rtsee-ise-add-slide\"\n [disabled]=\"vm.slidesLoadInProgress\"\n (click)=\"vm.expandNewSlide()\">\n <i class=\"pi pi-plus\"></i>\n </button>\n </div>\n\n @if (vm.activeSlide) {\n <div class=\"rtsee-ise-expanded\">\n <rtsee-manage-slide [manageSlide]=\"vm.activeSlide\" />\n </div>\n }\n }\n </div>\n }\n </section>\n\n <!-- 6. Author -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.author) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-author\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.author)\"\n (click)=\"vm.toggleSection(sections.author)\">\n <i class=\"rtsee-ise-section-icon pi pi-pen-to-square\"></i>\n <h3 class=\"rtsee-ise-section-title\">Author</h3>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.author)) {\n <div class=\"rtsee-ise-section-body\">\n <button type=\"button\" class=\"rtsee-ise-author-card\" id=\"rtsee-ise-author-card\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.authorExpanded }\"\n (click)=\"vm.toggleAuthor()\">\n <div class=\"rtsee-ise-avatar\">\n @if (vm.author?.imageUrl) {\n <img [src]=\"vm.author?.imageUrl\" [alt]=\"vm.author?.name\" />\n } @else {\n <i class=\"pi pi-user\"></i>\n }\n </div>\n <div class=\"rtsee-ise-author-body\">\n <span class=\"rtsee-ise-thumb-name\">{{ vm.author?.name || 'No author assigned' }}</span>\n <span class=\"rtsee-ise-thumb-description\">{{ vm.author?.description || 'Click to pick or create an author' }}</span>\n </div>\n @if (vm.author) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n title=\"Add Author to Illustrator context\"\n (click)=\"addAuthorToContext($event)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n }\n <i class=\"pi pi-pencil rtsee-ise-details-edit\"></i>\n </button>\n\n @if (vm.authorExpanded) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n @if (vm.authorError) {\n <div class=\"rtsee-ise-error\">{{ vm.authorError }}</div>\n }\n\n @if (vm.newAuthor && vm.newAuthorForm) {\n <h4 class=\"rtsee-ise-subheading\">New author</h4>\n <rtsee-form [form]=\"vm.newAuthorForm\" (formSubmit)=\"submitNewAuthor()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" label=\"Create & assign\"\n [loading]=\"vm.authorSaveInProgress\"\n [disabled]=\"vm.authorSaveInProgress\" />\n <p-button label=\"Back\" severity=\"secondary\"\n (click)=\"vm.cancelNewAuthor()\"\n [disabled]=\"vm.authorSaveInProgress\" />\n </div>\n </rtsee-form>\n } @else if (vm.authorForm) {\n <rtsee-form [form]=\"vm.authorForm\" (formSubmit)=\"submitAuthor()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" label=\"Assign\"\n [loading]=\"vm.authorSaveInProgress\"\n [disabled]=\"vm.authorSaveInProgress\" />\n <p-button label=\"New author\" icon=\"pi pi-plus\" severity=\"secondary\"\n (click)=\"vm.startNewAuthor()\"\n [disabled]=\"vm.authorSaveInProgress\" />\n @if (vm.author) {\n <span class=\"rtsee-ise-actions-spacer\"></span>\n <p-button label=\"Clear\" icon=\"pi pi-times\" severity=\"danger\" [text]=\"true\"\n (click)=\"vm.assignAuthor(null)\"\n [disabled]=\"vm.authorSaveInProgress\" />\n }\n </div>\n </rtsee-form>\n }\n </div>\n }\n </div>\n }\n </section>\n\n <!-- 7. NanoBanana Illustrator Overlay -->\n <rtsee-illustrator [illustrator]=\"illustrator\" />\n }\n</div>\n" }]
4295
+ }], propDecorators: { vm: [{
4296
+ type: Input,
4297
+ args: [{ required: true }]
4298
+ }], autoInit: [{
4299
+ type: Input
4300
+ }] } });
4301
+
3838
4302
  class ManageStoriesComponent {
3839
4303
  ngOnInit() {
3840
4304
  this.manageStories.init();
3841
4305
  }
3842
4306
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ManageStoriesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3843
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ManageStoriesComponent, isStandalone: true, selector: "rtsee-manage-stories", inputs: { manageStories: "manageStories" }, ngImport: i0, template: "<div class=\"rtsee-manage-stories\">\n <div class=\"rtsee-manage-stories-header\">\n @if (!manageStories.selectedStory) {\n <p-button (click)=\"manageStories.selectNewStory()\"\n label=\"Create A New Story\"\n ></p-button>\n }\n </div>\n @if (manageStories.selectedStory) {\n <div class=\"rtsee-manage-story-container\">\n <rtsee-manage-story [manageStory]=\"manageStories.selectedStory\"\n ></rtsee-manage-story>\n </div>\n }\n @if (!manageStories.selectedStory) {\n <div class=\"rtsee-manage-stories-list rtsee-ordered-list\">\n <p-orderList [value]=\"manageStories.stories\"\n dataKey=\"id\"\n [dragdrop]=\"true\"\n [responsive]=\"true\"\n [scrollHeight]=\"'40rem'\"\n class=\"rtsee-ordered-list-inner\"\n (onReorder)=\"manageStories.onReorder()\"\n >\n <ng-template let-option let-selected=\"selected\" #item>\n <div class=\"rtsee-presentation-manage-stories-list-item rtsee-ordered-list-item\">\n <img\n [src]=\"option.imageUrl\"\n [alt]=\"'slide_image'\"\n [style.width]=\"'60px'\"\n class=\"rtsee-presentation-manage-stories-list-item-image rtsee-ordered-list-item-image\"\n />\n <div class=\"rtsee-presentation-manage-stories-list-item-info rtsee-ordered-list-item-info\">\n <span [ngClass]=\"{\n 'text-sm': true,\n 'text-surface-500': !selected,\n 'dark:text-surface-400': !selected,\n 'text-inherit': selected,\n }\"\n >{{ option.name }}</span>\n <div class=\"rtsee-ordered-list-item-info-buttons\">\n <p-button label=\"Edit\"\n class=\"rtsee-ordered-list-item-info-button\"\n (click)=\"manageStories.selectStory(option.id)\"\n ></p-button>\n <p-button label=\"Delete\"\n [severity]=\"'warn'\"\n class=\"rtsee-ordered-list-item-info-button\"\n (click)=\"manageStories.selectStory(option.id)\"\n ></p-button>\n <p-button label=\"Clone\"\n [severity]=\"'secondary'\"\n class=\"rtsee-ordered-list-item-info-button\"\n (click)=\"manageStories.cloneStory(option.id)\"\n ></p-button>\n </div>\n </div>\n </div>\n </ng-template>\n </p-orderList>\n </div>\n }\n</div>\n", dependencies: [{ kind: "component", type: ManageStoryComponent, selector: "rtsee-manage-story", inputs: ["manageStory"] }, { 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: OrderList, selector: "p-orderList, p-orderlist, p-order-list", inputs: ["header", "styleClass", "tabindex", "ariaLabel", "ariaLabelledBy", "listStyle", "responsive", "filterBy", "filterPlaceholder", "filterLocale", "metaKeySelection", "dragdrop", "controlsPosition", "ariaFilterLabel", "filterMatchMode", "breakpoint", "stripedRows", "disabled", "trackBy", "scrollHeight", "autoOptionFocus", "dataKey", "selection", "value", "buttonProps", "moveUpButtonProps", "moveTopButtonProps", "moveDownButtonProps", "moveBottomButtonProps"], outputs: ["selectionChange", "onReorder", "onSelectionChange", "onFilterEvent", "onFocus", "onBlur"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
4307
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: ManageStoriesComponent, isStandalone: true, selector: "rtsee-manage-stories", inputs: { manageStories: "manageStories" }, ngImport: i0, template: "<div class=\"rtsee-manage-stories\">\n <div class=\"rtsee-manage-stories-header\">\n @if (!manageStories.selectedStory && !manageStories.interactiveStoryEditor) {\n <p-button (click)=\"manageStories.selectNewStory()\"\n label=\"Create A New Story\"\n ></p-button>\n }\n </div>\n @if (manageStories.selectedStory) {\n <div class=\"rtsee-manage-story-container\">\n <rtsee-manage-story [manageStory]=\"manageStories.selectedStory\"\n ></rtsee-manage-story>\n </div>\n }\n @if (manageStories.interactiveStoryEditor) {\n <div class=\"rtsee-manage-story-container\">\n <div style=\"margin-bottom: 1rem;\">\n <p-button icon=\"pi pi-arrow-left\" label=\"Back to Stories\" (click)=\"manageStories.interactiveStoryEditor = null\" [text]=\"true\"></p-button>\n </div>\n <rtsee-interactive-story-editor [vm]=\"manageStories.interactiveStoryEditor\"></rtsee-interactive-story-editor>\n </div>\n }\n @if (!manageStories.selectedStory && !manageStories.interactiveStoryEditor) {\n <div class=\"rtsee-manage-stories-list rtsee-ordered-list\">\n <p-orderList [value]=\"manageStories.stories\"\n dataKey=\"id\"\n [dragdrop]=\"true\"\n [responsive]=\"true\"\n [scrollHeight]=\"'40rem'\"\n class=\"rtsee-ordered-list-inner\"\n (onReorder)=\"manageStories.onReorder()\"\n >\n <ng-template let-option let-selected=\"selected\" #item>\n <div class=\"rtsee-presentation-manage-stories-list-item rtsee-ordered-list-item\">\n <img\n [src]=\"option.imageUrl\"\n [alt]=\"'slide_image'\"\n [style.width]=\"'60px'\"\n class=\"rtsee-presentation-manage-stories-list-item-image rtsee-ordered-list-item-image\"\n />\n <div class=\"rtsee-presentation-manage-stories-list-item-info rtsee-ordered-list-item-info\">\n <span [ngClass]=\"{\n 'text-sm': true,\n 'text-surface-500': !selected,\n 'dark:text-surface-400': !selected,\n 'text-inherit': selected,\n }\"\n >{{ option.name }}</span>\n <div class=\"rtsee-ordered-list-item-info-buttons\">\n <p-button label=\"Edit\"\n class=\"rtsee-ordered-list-item-info-button\"\n (click)=\"manageStories.selectStory(option.id)\"\n ></p-button>\n <p-button label=\"iEdit\"\n [severity]=\"'info'\"\n class=\"rtsee-ordered-list-item-info-button\"\n (click)=\"manageStories.selectInteractiveStory(option.id)\"\n ></p-button>\n <p-button label=\"Delete\"\n [severity]=\"'warn'\"\n class=\"rtsee-ordered-list-item-info-button\"\n (click)=\"manageStories.selectStory(option.id)\"\n ></p-button>\n <p-button label=\"Clone\"\n [severity]=\"'secondary'\"\n class=\"rtsee-ordered-list-item-info-button\"\n (click)=\"manageStories.cloneStory(option.id)\"\n ></p-button>\n </div>\n </div>\n </div>\n </ng-template>\n </p-orderList>\n </div>\n }\n</div>\n", dependencies: [{ kind: "component", type: ManageStoryComponent, selector: "rtsee-manage-story", inputs: ["manageStory"] }, { kind: "component", type: InteractiveStoryEditorComponent, selector: "rtsee-interactive-story-editor", inputs: ["vm", "autoInit"] }, { 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: OrderList, selector: "p-orderList, p-orderlist, p-order-list", inputs: ["header", "styleClass", "tabindex", "ariaLabel", "ariaLabelledBy", "listStyle", "responsive", "filterBy", "filterPlaceholder", "filterLocale", "metaKeySelection", "dragdrop", "controlsPosition", "ariaFilterLabel", "filterMatchMode", "breakpoint", "stripedRows", "disabled", "trackBy", "scrollHeight", "autoOptionFocus", "dataKey", "selection", "value", "buttonProps", "moveUpButtonProps", "moveTopButtonProps", "moveDownButtonProps", "moveBottomButtonProps"], outputs: ["selectionChange", "onReorder", "onSelectionChange", "onFilterEvent", "onFocus", "onBlur"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
3844
4308
  }
3845
4309
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ManageStoriesComponent, decorators: [{
3846
4310
  type: Component,
3847
- args: [{ selector: 'rtsee-manage-stories', imports: [ManageStoryComponent, Button, OrderList, NgClass], template: "<div class=\"rtsee-manage-stories\">\n <div class=\"rtsee-manage-stories-header\">\n @if (!manageStories.selectedStory) {\n <p-button (click)=\"manageStories.selectNewStory()\"\n label=\"Create A New Story\"\n ></p-button>\n }\n </div>\n @if (manageStories.selectedStory) {\n <div class=\"rtsee-manage-story-container\">\n <rtsee-manage-story [manageStory]=\"manageStories.selectedStory\"\n ></rtsee-manage-story>\n </div>\n }\n @if (!manageStories.selectedStory) {\n <div class=\"rtsee-manage-stories-list rtsee-ordered-list\">\n <p-orderList [value]=\"manageStories.stories\"\n dataKey=\"id\"\n [dragdrop]=\"true\"\n [responsive]=\"true\"\n [scrollHeight]=\"'40rem'\"\n class=\"rtsee-ordered-list-inner\"\n (onReorder)=\"manageStories.onReorder()\"\n >\n <ng-template let-option let-selected=\"selected\" #item>\n <div class=\"rtsee-presentation-manage-stories-list-item rtsee-ordered-list-item\">\n <img\n [src]=\"option.imageUrl\"\n [alt]=\"'slide_image'\"\n [style.width]=\"'60px'\"\n class=\"rtsee-presentation-manage-stories-list-item-image rtsee-ordered-list-item-image\"\n />\n <div class=\"rtsee-presentation-manage-stories-list-item-info rtsee-ordered-list-item-info\">\n <span [ngClass]=\"{\n 'text-sm': true,\n 'text-surface-500': !selected,\n 'dark:text-surface-400': !selected,\n 'text-inherit': selected,\n }\"\n >{{ option.name }}</span>\n <div class=\"rtsee-ordered-list-item-info-buttons\">\n <p-button label=\"Edit\"\n class=\"rtsee-ordered-list-item-info-button\"\n (click)=\"manageStories.selectStory(option.id)\"\n ></p-button>\n <p-button label=\"Delete\"\n [severity]=\"'warn'\"\n class=\"rtsee-ordered-list-item-info-button\"\n (click)=\"manageStories.selectStory(option.id)\"\n ></p-button>\n <p-button label=\"Clone\"\n [severity]=\"'secondary'\"\n class=\"rtsee-ordered-list-item-info-button\"\n (click)=\"manageStories.cloneStory(option.id)\"\n ></p-button>\n </div>\n </div>\n </div>\n </ng-template>\n </p-orderList>\n </div>\n }\n</div>\n" }]
4311
+ args: [{ selector: 'rtsee-manage-stories', imports: [ManageStoryComponent, InteractiveStoryEditorComponent, Button, OrderList, NgClass], template: "<div class=\"rtsee-manage-stories\">\n <div class=\"rtsee-manage-stories-header\">\n @if (!manageStories.selectedStory && !manageStories.interactiveStoryEditor) {\n <p-button (click)=\"manageStories.selectNewStory()\"\n label=\"Create A New Story\"\n ></p-button>\n }\n </div>\n @if (manageStories.selectedStory) {\n <div class=\"rtsee-manage-story-container\">\n <rtsee-manage-story [manageStory]=\"manageStories.selectedStory\"\n ></rtsee-manage-story>\n </div>\n }\n @if (manageStories.interactiveStoryEditor) {\n <div class=\"rtsee-manage-story-container\">\n <div style=\"margin-bottom: 1rem;\">\n <p-button icon=\"pi pi-arrow-left\" label=\"Back to Stories\" (click)=\"manageStories.interactiveStoryEditor = null\" [text]=\"true\"></p-button>\n </div>\n <rtsee-interactive-story-editor [vm]=\"manageStories.interactiveStoryEditor\"></rtsee-interactive-story-editor>\n </div>\n }\n @if (!manageStories.selectedStory && !manageStories.interactiveStoryEditor) {\n <div class=\"rtsee-manage-stories-list rtsee-ordered-list\">\n <p-orderList [value]=\"manageStories.stories\"\n dataKey=\"id\"\n [dragdrop]=\"true\"\n [responsive]=\"true\"\n [scrollHeight]=\"'40rem'\"\n class=\"rtsee-ordered-list-inner\"\n (onReorder)=\"manageStories.onReorder()\"\n >\n <ng-template let-option let-selected=\"selected\" #item>\n <div class=\"rtsee-presentation-manage-stories-list-item rtsee-ordered-list-item\">\n <img\n [src]=\"option.imageUrl\"\n [alt]=\"'slide_image'\"\n [style.width]=\"'60px'\"\n class=\"rtsee-presentation-manage-stories-list-item-image rtsee-ordered-list-item-image\"\n />\n <div class=\"rtsee-presentation-manage-stories-list-item-info rtsee-ordered-list-item-info\">\n <span [ngClass]=\"{\n 'text-sm': true,\n 'text-surface-500': !selected,\n 'dark:text-surface-400': !selected,\n 'text-inherit': selected,\n }\"\n >{{ option.name }}</span>\n <div class=\"rtsee-ordered-list-item-info-buttons\">\n <p-button label=\"Edit\"\n class=\"rtsee-ordered-list-item-info-button\"\n (click)=\"manageStories.selectStory(option.id)\"\n ></p-button>\n <p-button label=\"iEdit\"\n [severity]=\"'info'\"\n class=\"rtsee-ordered-list-item-info-button\"\n (click)=\"manageStories.selectInteractiveStory(option.id)\"\n ></p-button>\n <p-button label=\"Delete\"\n [severity]=\"'warn'\"\n class=\"rtsee-ordered-list-item-info-button\"\n (click)=\"manageStories.selectStory(option.id)\"\n ></p-button>\n <p-button label=\"Clone\"\n [severity]=\"'secondary'\"\n class=\"rtsee-ordered-list-item-info-button\"\n (click)=\"manageStories.cloneStory(option.id)\"\n ></p-button>\n </div>\n </div>\n </div>\n </ng-template>\n </p-orderList>\n </div>\n }\n</div>\n" }]
3848
4312
  }], propDecorators: { manageStories: [{
3849
4313
  type: Input
3850
4314
  }] } });
@@ -5845,5 +6309,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
5845
6309
  * Generated bundle index. Do not edit.
5846
6310
  */
5847
6311
 
5848
- export { EntitiesConfigurationsListComponent, EntitiesListComponent, FormComponent, GtagService, ManageEntityComponent, ManageEntityConfigurationComponent, MessengerComponent, NgxService, PaymentProductSnippetComponent, PresentationComponent, ProfileComponent, RTSeeAuthComponent, RTSeeConferenceComponent, RTSeeContainerComponent, RTSeeControlsComponent, RTSeeModule, RTSeeTaskComponent, RtseeEntityCommentsComponent, RtseeEntityPreviewComponent, RtseeEntityTagsComponent, RtseeEventsDashboardComponent, RtseePeerComponent, RtseeSettingsComponent, RtseeTagGroupManageComponent, RtseeTagGroupsManageComponent, RtseeTagManageComponent, RtseeTagsAccordionMenuComponent, WorkflowStepsService };
6312
+ export { EntitiesConfigurationsListComponent, EntitiesListComponent, 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, StoryElementsSectionComponent, WorkflowStepsService };
5849
6313
  //# sourceMappingURL=rtsee-ngx.mjs.map