@rtsee/ngx 0.0.105 → 0.0.107
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ngx/fesm2022/rtsee-ngx.mjs +571 -15
- package/dist/ngx/fesm2022/rtsee-ngx.mjs.map +1 -1
- package/dist/ngx/index.d.ts +92 -4
- package/dist/ngx/src/lib/theme/common-components/image-uploader.scss +28 -0
- package/dist/ngx/src/lib/theme/presentation/dashboard.scss +6 -0
- package/dist/ngx/src/lib/theme/presentation/illustrator.scss +891 -0
- package/dist/ngx/src/lib/theme/presentation/index.scss +2 -0
- package/dist/ngx/src/lib/theme/presentation/interactive-story-editor.scss +521 -0
- package/package.json +11 -11
|
@@ -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,
|
|
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
|
-
|
|
690
|
-
|
|
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: [{
|
|
@@ -1797,6 +1880,19 @@ class MediaWidgetComponent {
|
|
|
1797
1880
|
this.showAll = !this.showAll;
|
|
1798
1881
|
this.updateVisibleImages();
|
|
1799
1882
|
}
|
|
1883
|
+
sendToIllustrator(event, img) {
|
|
1884
|
+
event.stopPropagation();
|
|
1885
|
+
event.preventDefault();
|
|
1886
|
+
if (typeof window !== 'undefined' && img?.url) {
|
|
1887
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.SET_IMAGE_FOR_REVIEW, {
|
|
1888
|
+
detail: {
|
|
1889
|
+
imageUrl: img.url,
|
|
1890
|
+
prompt: img.name || (typeof this.message.text === 'string' ? this.message.text : '') || '',
|
|
1891
|
+
source: 'messenger',
|
|
1892
|
+
},
|
|
1893
|
+
}));
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1800
1896
|
updateVisibleImages() {
|
|
1801
1897
|
const all = this.message.images || [];
|
|
1802
1898
|
if (this.showAll || all.length <= this.MAX_GRID) {
|
|
@@ -1809,11 +1905,11 @@ class MediaWidgetComponent {
|
|
|
1809
1905
|
}
|
|
1810
1906
|
}
|
|
1811
1907
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MediaWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1812
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MediaWidgetComponent, isStandalone: true, selector: "rtsee-media-widget", inputs: { message: "message", messenger: "messenger", chat: "chat", showCost: "showCost" }, ngImport: i0, template: "<div class=\"rts-media-widget\">\n <!-- Video player -->\n @if (message.video) {\n <div class=\"rts-media-video\">\n <video\n controls\n playsinline\n preload=\"metadata\"\n [src]=\"message.video.url\"\n class=\"rts-video-player\"\n >\n Your browser does not support video playback.\n </video>\n </div>\n }\n\n <!-- Image grid -->\n @if (hasImages) {\n <div class=\"rts-media-images\" [ngClass]=\"gridClass\">\n @for (img of visibleImages; track img.url) {\n <div class=\"rts-media-image-wrapper\">\n <img [src]=\"img.url\" [alt]=\"img.name\" class=\"rts-media-image\" loading=\"lazy\" />\n </div>\n }\n </div>\n }\n\n <!-- Show more / less toggle -->\n @if (hiddenCount > 0 || showAll) {\n <button class=\"rts-media-toggle\" (click)=\"toggleShowAll()\">\n {{ showAll ? 'Show less' : 'Show ' + hiddenCount + ' more' }}\n </button>\n }\n\n <!-- Cost display (optional, disabled when nested inside agentic widget) -->\n @if (showCost && message.cost) {\n <div class=\"rts-media-cost\">\n <rtsee-cost-display [cost]=\"message.cost\"></rtsee-cost-display>\n </div>\n }\n</div>\n", styles: [".rts-media-widget{max-width:100%}.rts-media-video{border-radius:8px;overflow:hidden;margin-bottom:6px}.rts-video-player{width:100%;max-height:360px;border-radius:8px;background:#000;display:block}.rts-media-images{display:grid;gap:4px;border-radius:8px;overflow:hidden;margin-bottom:4px}.rts-media-grid-1{grid-template-columns:1fr}.rts-media-grid-2{grid-template-columns:1fr 1fr}.rts-media-grid-4{grid-template-columns:1fr 1fr;grid-template-rows:auto auto}.rts-media-image-wrapper{position:relative;overflow:hidden;border-radius:6px;background:var(--rts-bg-secondary, #1e1e2e)}.rts-media-image{width:100%;height:auto;max-height:280px;object-fit:cover;display:block;transition:transform .2s ease;cursor:pointer}.rts-media-image:hover{transform:scale(1.02)}.rts-media-grid-1 .rts-media-image{max-height:400px;object-fit:contain}.rts-media-toggle{display:block;width:100%;padding:6px 0;border:none;background:none;color:var(--rts-agent-accent, #8b5cf6);font-size:12px;font-weight:500;cursor:pointer;text-align:center;transition:opacity .15s ease}.rts-media-toggle:hover{opacity:.8}.rts-media-cost{display:flex;justify-content:flex-end;padding-top:4px}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: CostDisplayComponent, selector: "rtsee-cost-display", inputs: ["cost"] }] }); }
|
|
1908
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MediaWidgetComponent, isStandalone: true, selector: "rtsee-media-widget", inputs: { message: "message", messenger: "messenger", chat: "chat", showCost: "showCost" }, ngImport: i0, template: "<div class=\"rts-media-widget\">\n <!-- Video player -->\n @if (message.video) {\n <div class=\"rts-media-video\">\n <video\n controls\n playsinline\n preload=\"metadata\"\n [src]=\"message.video.url\"\n class=\"rts-video-player\"\n >\n Your browser does not support video playback.\n </video>\n </div>\n }\n\n <!-- Image grid -->\n @if (hasImages) {\n <div class=\"rts-media-images\" [ngClass]=\"gridClass\">\n @for (img of visibleImages; track img.url) {\n <div class=\"rts-media-image-wrapper\">\n <img [src]=\"img.url\" [alt]=\"img.name\" class=\"rts-media-image\" loading=\"lazy\" />\n <button\n type=\"button\"\n class=\"rts-media-btn-paint\"\n title=\"Send image to Illustrator\"\n (click)=\"sendToIllustrator($event, img)\"\n >\n <i class=\"pi pi-palette\"></i>\n <span>+ paint</span>\n </button>\n </div>\n }\n </div>\n }\n\n <!-- Show more / less toggle -->\n @if (hiddenCount > 0 || showAll) {\n <button class=\"rts-media-toggle\" (click)=\"toggleShowAll()\">\n {{ showAll ? 'Show less' : 'Show ' + hiddenCount + ' more' }}\n </button>\n }\n\n <!-- Cost display (optional, disabled when nested inside agentic widget) -->\n @if (showCost && message.cost) {\n <div class=\"rts-media-cost\">\n <rtsee-cost-display [cost]=\"message.cost\"></rtsee-cost-display>\n </div>\n }\n</div>\n", styles: [".rts-media-widget{max-width:100%}.rts-media-video{border-radius:8px;overflow:hidden;margin-bottom:6px}.rts-video-player{width:100%;max-height:360px;border-radius:8px;background:#000;display:block}.rts-media-images{display:grid;gap:4px;border-radius:8px;overflow:hidden;margin-bottom:4px}.rts-media-grid-1{grid-template-columns:1fr}.rts-media-grid-2{grid-template-columns:1fr 1fr}.rts-media-grid-4{grid-template-columns:1fr 1fr;grid-template-rows:auto auto}.rts-media-image-wrapper{position:relative;overflow:hidden;border-radius:6px;background:var(--rts-bg-secondary, #1e1e2e)}.rts-media-btn-paint{position:absolute;top:8px;right:8px;z-index:5;display:inline-flex;align-items:center;gap:4px;padding:4px 8px;background:#12121cd9;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);color:#e9d5ff;border:1px solid rgba(168,85,247,.45);border-radius:6px;font-size:11px;font-weight:600;cursor:pointer;transition:all .2s cubic-bezier(.34,1.56,.64,1);box-shadow:0 2px 8px #00000080}.rts-media-btn-paint i{font-size:11px;color:#c084fc}.rts-media-btn-paint span{line-height:1}.rts-media-btn-paint:hover{background:#9333eae6;color:#fff;border-color:#a855f7;transform:translateY(-1px) scale(1.04);box-shadow:0 4px 12px #a855f773}.rts-media-btn-paint:hover i{color:#fff}.rts-media-btn-paint:active{transform:translateY(0) scale(.98)}.rts-media-image{width:100%;height:auto;max-height:280px;object-fit:cover;display:block;transition:transform .2s ease;cursor:pointer}.rts-media-image:hover{transform:scale(1.02)}.rts-media-grid-1 .rts-media-image{max-height:400px;object-fit:contain}.rts-media-toggle{display:block;width:100%;padding:6px 0;border:none;background:none;color:var(--rts-agent-accent, #8b5cf6);font-size:12px;font-weight:500;cursor:pointer;text-align:center;transition:opacity .15s ease}.rts-media-toggle:hover{opacity:.8}.rts-media-cost{display:flex;justify-content:flex-end;padding-top:4px}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: CostDisplayComponent, selector: "rtsee-cost-display", inputs: ["cost"] }] }); }
|
|
1813
1909
|
}
|
|
1814
1910
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MediaWidgetComponent, decorators: [{
|
|
1815
1911
|
type: Component,
|
|
1816
|
-
args: [{ selector: 'rtsee-media-widget', standalone: true, imports: [NgClass, CostDisplayComponent], template: "<div class=\"rts-media-widget\">\n <!-- Video player -->\n @if (message.video) {\n <div class=\"rts-media-video\">\n <video\n controls\n playsinline\n preload=\"metadata\"\n [src]=\"message.video.url\"\n class=\"rts-video-player\"\n >\n Your browser does not support video playback.\n </video>\n </div>\n }\n\n <!-- Image grid -->\n @if (hasImages) {\n <div class=\"rts-media-images\" [ngClass]=\"gridClass\">\n @for (img of visibleImages; track img.url) {\n <div class=\"rts-media-image-wrapper\">\n <img [src]=\"img.url\" [alt]=\"img.name\" class=\"rts-media-image\" loading=\"lazy\" />\n </div>\n }\n </div>\n }\n\n <!-- Show more / less toggle -->\n @if (hiddenCount > 0 || showAll) {\n <button class=\"rts-media-toggle\" (click)=\"toggleShowAll()\">\n {{ showAll ? 'Show less' : 'Show ' + hiddenCount + ' more' }}\n </button>\n }\n\n <!-- Cost display (optional, disabled when nested inside agentic widget) -->\n @if (showCost && message.cost) {\n <div class=\"rts-media-cost\">\n <rtsee-cost-display [cost]=\"message.cost\"></rtsee-cost-display>\n </div>\n }\n</div>\n", styles: [".rts-media-widget{max-width:100%}.rts-media-video{border-radius:8px;overflow:hidden;margin-bottom:6px}.rts-video-player{width:100%;max-height:360px;border-radius:8px;background:#000;display:block}.rts-media-images{display:grid;gap:4px;border-radius:8px;overflow:hidden;margin-bottom:4px}.rts-media-grid-1{grid-template-columns:1fr}.rts-media-grid-2{grid-template-columns:1fr 1fr}.rts-media-grid-4{grid-template-columns:1fr 1fr;grid-template-rows:auto auto}.rts-media-image-wrapper{position:relative;overflow:hidden;border-radius:6px;background:var(--rts-bg-secondary, #1e1e2e)}.rts-media-image{width:100%;height:auto;max-height:280px;object-fit:cover;display:block;transition:transform .2s ease;cursor:pointer}.rts-media-image:hover{transform:scale(1.02)}.rts-media-grid-1 .rts-media-image{max-height:400px;object-fit:contain}.rts-media-toggle{display:block;width:100%;padding:6px 0;border:none;background:none;color:var(--rts-agent-accent, #8b5cf6);font-size:12px;font-weight:500;cursor:pointer;text-align:center;transition:opacity .15s ease}.rts-media-toggle:hover{opacity:.8}.rts-media-cost{display:flex;justify-content:flex-end;padding-top:4px}\n"] }]
|
|
1912
|
+
args: [{ selector: 'rtsee-media-widget', standalone: true, imports: [NgClass, CostDisplayComponent], template: "<div class=\"rts-media-widget\">\n <!-- Video player -->\n @if (message.video) {\n <div class=\"rts-media-video\">\n <video\n controls\n playsinline\n preload=\"metadata\"\n [src]=\"message.video.url\"\n class=\"rts-video-player\"\n >\n Your browser does not support video playback.\n </video>\n </div>\n }\n\n <!-- Image grid -->\n @if (hasImages) {\n <div class=\"rts-media-images\" [ngClass]=\"gridClass\">\n @for (img of visibleImages; track img.url) {\n <div class=\"rts-media-image-wrapper\">\n <img [src]=\"img.url\" [alt]=\"img.name\" class=\"rts-media-image\" loading=\"lazy\" />\n <button\n type=\"button\"\n class=\"rts-media-btn-paint\"\n title=\"Send image to Illustrator\"\n (click)=\"sendToIllustrator($event, img)\"\n >\n <i class=\"pi pi-palette\"></i>\n <span>+ paint</span>\n </button>\n </div>\n }\n </div>\n }\n\n <!-- Show more / less toggle -->\n @if (hiddenCount > 0 || showAll) {\n <button class=\"rts-media-toggle\" (click)=\"toggleShowAll()\">\n {{ showAll ? 'Show less' : 'Show ' + hiddenCount + ' more' }}\n </button>\n }\n\n <!-- Cost display (optional, disabled when nested inside agentic widget) -->\n @if (showCost && message.cost) {\n <div class=\"rts-media-cost\">\n <rtsee-cost-display [cost]=\"message.cost\"></rtsee-cost-display>\n </div>\n }\n</div>\n", styles: [".rts-media-widget{max-width:100%}.rts-media-video{border-radius:8px;overflow:hidden;margin-bottom:6px}.rts-video-player{width:100%;max-height:360px;border-radius:8px;background:#000;display:block}.rts-media-images{display:grid;gap:4px;border-radius:8px;overflow:hidden;margin-bottom:4px}.rts-media-grid-1{grid-template-columns:1fr}.rts-media-grid-2{grid-template-columns:1fr 1fr}.rts-media-grid-4{grid-template-columns:1fr 1fr;grid-template-rows:auto auto}.rts-media-image-wrapper{position:relative;overflow:hidden;border-radius:6px;background:var(--rts-bg-secondary, #1e1e2e)}.rts-media-btn-paint{position:absolute;top:8px;right:8px;z-index:5;display:inline-flex;align-items:center;gap:4px;padding:4px 8px;background:#12121cd9;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);color:#e9d5ff;border:1px solid rgba(168,85,247,.45);border-radius:6px;font-size:11px;font-weight:600;cursor:pointer;transition:all .2s cubic-bezier(.34,1.56,.64,1);box-shadow:0 2px 8px #00000080}.rts-media-btn-paint i{font-size:11px;color:#c084fc}.rts-media-btn-paint span{line-height:1}.rts-media-btn-paint:hover{background:#9333eae6;color:#fff;border-color:#a855f7;transform:translateY(-1px) scale(1.04);box-shadow:0 4px 12px #a855f773}.rts-media-btn-paint:hover i{color:#fff}.rts-media-btn-paint:active{transform:translateY(0) scale(.98)}.rts-media-image{width:100%;height:auto;max-height:280px;object-fit:cover;display:block;transition:transform .2s ease;cursor:pointer}.rts-media-image:hover{transform:scale(1.02)}.rts-media-grid-1 .rts-media-image{max-height:400px;object-fit:contain}.rts-media-toggle{display:block;width:100%;padding:6px 0;border:none;background:none;color:var(--rts-agent-accent, #8b5cf6);font-size:12px;font-weight:500;cursor:pointer;text-align:center;transition:opacity .15s ease}.rts-media-toggle:hover{opacity:.8}.rts-media-cost{display:flex;justify-content:flex-end;padding-top:4px}\n"] }]
|
|
1817
1913
|
}], propDecorators: { message: [{
|
|
1818
1914
|
type: Input
|
|
1819
1915
|
}], messenger: [{
|
|
@@ -3042,10 +3138,14 @@ class ChatComponent {
|
|
|
3042
3138
|
});
|
|
3043
3139
|
this.chat.loadRemoteMessages('back');
|
|
3044
3140
|
}
|
|
3141
|
+
this.chat?.broadcastAgents();
|
|
3045
3142
|
}
|
|
3046
3143
|
ngOnDestroy() {
|
|
3047
|
-
if (this.chat
|
|
3048
|
-
this.
|
|
3144
|
+
if (this.chat) {
|
|
3145
|
+
this.chat.unbindIllustratorEvents();
|
|
3146
|
+
if (this.chat.isStandalone) {
|
|
3147
|
+
this.messenger.removeStandaloneChat(this.chat.id);
|
|
3148
|
+
}
|
|
3049
3149
|
}
|
|
3050
3150
|
}
|
|
3051
3151
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ChatComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
@@ -3835,16 +3935,472 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
3835
3935
|
type: Input
|
|
3836
3936
|
}] } });
|
|
3837
3937
|
|
|
3938
|
+
/**
|
|
3939
|
+
* Collapsible section rendering the thumbnails of one kind of story element
|
|
3940
|
+
* (characters / artifacts / locations) and the expanded edit form.
|
|
3941
|
+
* All the logic lives in RTSeeStoryElementsEditor.
|
|
3942
|
+
*/
|
|
3943
|
+
class StoryElementsSectionComponent {
|
|
3944
|
+
set illustrator(val) {
|
|
3945
|
+
if (this._illustrator) {
|
|
3946
|
+
this._illustrator.off('changed', this.onIllustratorChanged);
|
|
3947
|
+
}
|
|
3948
|
+
this._illustrator = val;
|
|
3949
|
+
if (this._illustrator) {
|
|
3950
|
+
this._illustrator.on('changed', this.onIllustratorChanged);
|
|
3951
|
+
}
|
|
3952
|
+
this.cdr.markForCheck();
|
|
3953
|
+
}
|
|
3954
|
+
get illustrator() {
|
|
3955
|
+
return this._illustrator;
|
|
3956
|
+
}
|
|
3957
|
+
constructor(cdr) {
|
|
3958
|
+
this.cdr = cdr;
|
|
3959
|
+
this.icon = "pi pi-box";
|
|
3960
|
+
this.collapsed = false;
|
|
3961
|
+
this.canDetach = true;
|
|
3962
|
+
this.toggled = new EventEmitter();
|
|
3963
|
+
this.onIllustratorChanged = () => {
|
|
3964
|
+
this.cdr.markForCheck();
|
|
3965
|
+
};
|
|
3966
|
+
}
|
|
3967
|
+
ngOnDestroy() {
|
|
3968
|
+
if (this._illustrator) {
|
|
3969
|
+
this._illustrator.off('changed', this.onIllustratorChanged);
|
|
3970
|
+
}
|
|
3971
|
+
}
|
|
3972
|
+
async applyReviewedImageToItem(event, item) {
|
|
3973
|
+
event.stopPropagation();
|
|
3974
|
+
event.preventDefault();
|
|
3975
|
+
const imageUrl = this._illustrator?.currentGeneratedImageUrl;
|
|
3976
|
+
if (!imageUrl)
|
|
3977
|
+
return;
|
|
3978
|
+
this.cdr.markForCheck();
|
|
3979
|
+
try {
|
|
3980
|
+
await item.save({ imageUrl });
|
|
3981
|
+
if (this.editor.expanded && this.editor.expanded.id === item.id && this.editor.form) {
|
|
3982
|
+
const imageField = this.editor.form.fields.find((f) => f.name === 'imageUrl' || f.type === 'image-uploader');
|
|
3983
|
+
if (imageField) {
|
|
3984
|
+
imageField.value = imageUrl;
|
|
3985
|
+
if (imageField.imageUploader) {
|
|
3986
|
+
imageField.imageUploader.uploadedPhotoPreview = imageUrl;
|
|
3987
|
+
}
|
|
3988
|
+
}
|
|
3989
|
+
}
|
|
3990
|
+
}
|
|
3991
|
+
catch (e) {
|
|
3992
|
+
console.error(`Failed to apply image to ${this.editor.label}:`, e);
|
|
3993
|
+
}
|
|
3994
|
+
finally {
|
|
3995
|
+
this.cdr.markForCheck();
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
submit() {
|
|
3999
|
+
this.editor.submit();
|
|
4000
|
+
}
|
|
4001
|
+
addToIllustrator(event, item) {
|
|
4002
|
+
event.stopPropagation();
|
|
4003
|
+
event.preventDefault();
|
|
4004
|
+
if (typeof window !== 'undefined') {
|
|
4005
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
|
|
4006
|
+
detail: {
|
|
4007
|
+
id: item.id,
|
|
4008
|
+
title: item.name || this.editor.label,
|
|
4009
|
+
imageUrl: item.imageUrl || '',
|
|
4010
|
+
visualDescription: item.visualDescription || item.description || '',
|
|
4011
|
+
description: item.description || '',
|
|
4012
|
+
sourceType: this.editor.section,
|
|
4013
|
+
},
|
|
4014
|
+
}));
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
trackById(index, item) {
|
|
4018
|
+
return item.id || `new-${index}`;
|
|
4019
|
+
}
|
|
4020
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryElementsSectionComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4021
|
+
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", illustrator: "illustrator" }, 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 @if (illustrator?.reviewingGeneratedImage && illustrator?.currentGeneratedImageUrl) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-quick-apply\"\n style=\"position: absolute; bottom: 8px; right: 8px;\"\n [disabled]=\"item.saveInProgress\"\n [title]=\"'Apply reviewed image to ' + item.name\"\n (click)=\"applyReviewedImageToItem($event, item)\">\n @if (item.saveInProgress) {\n <i class=\"pi pi-spin pi-spinner\"></i>\n } @else {\n <i class=\"pi pi-plus\"></i>\n }\n </button>\n }\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"] }] }); }
|
|
4022
|
+
}
|
|
4023
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryElementsSectionComponent, decorators: [{
|
|
4024
|
+
type: Component,
|
|
4025
|
+
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 @if (illustrator?.reviewingGeneratedImage && illustrator?.currentGeneratedImageUrl) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-quick-apply\"\n style=\"position: absolute; bottom: 8px; right: 8px;\"\n [disabled]=\"item.saveInProgress\"\n [title]=\"'Apply reviewed image to ' + item.name\"\n (click)=\"applyReviewedImageToItem($event, item)\">\n @if (item.saveInProgress) {\n <i class=\"pi pi-spin pi-spinner\"></i>\n } @else {\n <i class=\"pi pi-plus\"></i>\n }\n </button>\n }\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" }]
|
|
4026
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { editor: [{
|
|
4027
|
+
type: Input,
|
|
4028
|
+
args: [{ required: true }]
|
|
4029
|
+
}], title: [{
|
|
4030
|
+
type: Input,
|
|
4031
|
+
args: [{ required: true }]
|
|
4032
|
+
}], icon: [{
|
|
4033
|
+
type: Input
|
|
4034
|
+
}], collapsed: [{
|
|
4035
|
+
type: Input
|
|
4036
|
+
}], canDetach: [{
|
|
4037
|
+
type: Input
|
|
4038
|
+
}], toggled: [{
|
|
4039
|
+
type: Output
|
|
4040
|
+
}], illustrator: [{
|
|
4041
|
+
type: Input
|
|
4042
|
+
}] } });
|
|
4043
|
+
|
|
4044
|
+
class IllustratorComponent {
|
|
4045
|
+
constructor(cdr, elementRef) {
|
|
4046
|
+
this.cdr = cdr;
|
|
4047
|
+
this.elementRef = elementRef;
|
|
4048
|
+
this.ownIllustrator = false;
|
|
4049
|
+
this.aspectRatios = ['1:1', '4:3', '3:4', '16:9', '9:16', '3:2', '2:3'];
|
|
4050
|
+
this.styles = [
|
|
4051
|
+
'Classic Fairy Tale pixel-art Storybook',
|
|
4052
|
+
'Whimsical Watercolor & Ink',
|
|
4053
|
+
'Golden Age Storybook Illustration',
|
|
4054
|
+
'Enchanted Fantasy Digital Art',
|
|
4055
|
+
'Vibrant Children\'s Book Illustration',
|
|
4056
|
+
'Ethereal Oil Painting',
|
|
4057
|
+
];
|
|
4058
|
+
this.moods = [
|
|
4059
|
+
'Dreamy & Magical',
|
|
4060
|
+
'Warm, Cozy & Hearth-lit',
|
|
4061
|
+
'Epic, Wonder-filled & Adventurous',
|
|
4062
|
+
'Mysterious & Enchanted',
|
|
4063
|
+
'Playful & Charming',
|
|
4064
|
+
'Dark Fantasy & Gothic',
|
|
4065
|
+
];
|
|
4066
|
+
this.lightings = [
|
|
4067
|
+
'Soft Diffused Storybook Glow',
|
|
4068
|
+
'Golden Hour Sunbeams & Dappled Rays',
|
|
4069
|
+
'Twilight Starlight & Fireflies',
|
|
4070
|
+
'Cozy Candlelight & Lantern Glow',
|
|
4071
|
+
'Dramatic Volumetric Rays',
|
|
4072
|
+
'Moonlit Midnight Glow',
|
|
4073
|
+
];
|
|
4074
|
+
this.onIllustratorChanged = () => {
|
|
4075
|
+
this.cdr.markForCheck();
|
|
4076
|
+
};
|
|
4077
|
+
this.onScrollIntoView = () => {
|
|
4078
|
+
this.cdr.markForCheck();
|
|
4079
|
+
setTimeout(() => {
|
|
4080
|
+
this.elementRef.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
4081
|
+
}, 60);
|
|
4082
|
+
};
|
|
4083
|
+
}
|
|
4084
|
+
ngOnInit() {
|
|
4085
|
+
if (!this.illustrator) {
|
|
4086
|
+
this.illustrator = new RTSeeIllustrator();
|
|
4087
|
+
this.ownIllustrator = true;
|
|
4088
|
+
}
|
|
4089
|
+
this.illustrator.on('changed', this.onIllustratorChanged);
|
|
4090
|
+
this.illustrator.on('scroll-into-view', this.onScrollIntoView);
|
|
4091
|
+
this.illustrator.requestAgents();
|
|
4092
|
+
}
|
|
4093
|
+
ngOnDestroy() {
|
|
4094
|
+
if (this.illustrator) {
|
|
4095
|
+
this.illustrator.off('changed', this.onIllustratorChanged);
|
|
4096
|
+
this.illustrator.off('scroll-into-view', this.onScrollIntoView);
|
|
4097
|
+
if (this.ownIllustrator) {
|
|
4098
|
+
this.illustrator.destroy();
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
}
|
|
4102
|
+
toggleExpand() {
|
|
4103
|
+
this.illustrator.toggleExpand();
|
|
4104
|
+
}
|
|
4105
|
+
toggleConfig() {
|
|
4106
|
+
this.illustrator.toggleConfig();
|
|
4107
|
+
}
|
|
4108
|
+
onSelectAgent(event) {
|
|
4109
|
+
const target = event.target;
|
|
4110
|
+
if (target?.value) {
|
|
4111
|
+
this.illustrator.selectAgent(target.value);
|
|
4112
|
+
}
|
|
4113
|
+
}
|
|
4114
|
+
refreshAgents() {
|
|
4115
|
+
this.illustrator.requestAgents();
|
|
4116
|
+
}
|
|
4117
|
+
removeImage(id) {
|
|
4118
|
+
this.illustrator.removeContextImage(id);
|
|
4119
|
+
}
|
|
4120
|
+
toggleActive(image) {
|
|
4121
|
+
this.illustrator.toggleImageActive(image.id);
|
|
4122
|
+
}
|
|
4123
|
+
discardGeneratedImage() {
|
|
4124
|
+
this.illustrator.discardGeneratedImage();
|
|
4125
|
+
}
|
|
4126
|
+
acceptGeneratedImage() {
|
|
4127
|
+
this.illustrator.acceptGeneratedImage();
|
|
4128
|
+
}
|
|
4129
|
+
submitIteration() {
|
|
4130
|
+
this.illustrator.submitIteration();
|
|
4131
|
+
}
|
|
4132
|
+
submitPrompt() {
|
|
4133
|
+
this.illustrator.submitPrompt();
|
|
4134
|
+
}
|
|
4135
|
+
trackByImageId(index, item) {
|
|
4136
|
+
return item.id || `context-img-${index}`;
|
|
4137
|
+
}
|
|
4138
|
+
trackByAgentId(index, item) {
|
|
4139
|
+
return item.id || `agent-${index}`;
|
|
4140
|
+
}
|
|
4141
|
+
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 }); }
|
|
4142
|
+
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 }); }
|
|
4143
|
+
}
|
|
4144
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: IllustratorComponent, decorators: [{
|
|
4145
|
+
type: Component,
|
|
4146
|
+
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" }]
|
|
4147
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }], propDecorators: { illustrator: [{
|
|
4148
|
+
type: Input
|
|
4149
|
+
}] } });
|
|
4150
|
+
|
|
4151
|
+
/**
|
|
4152
|
+
* Interactive story editor: collapsible sections of thumbnails (details, characters,
|
|
4153
|
+
* artifacts, locations, slides, author) that expand into the edit forms.
|
|
4154
|
+
* Rendering only, the orchestration lives in RTSeeInteractiveStoryEditorVm.
|
|
4155
|
+
*/
|
|
4156
|
+
class InteractiveStoryEditorComponent {
|
|
4157
|
+
constructor(cdr) {
|
|
4158
|
+
this.cdr = cdr;
|
|
4159
|
+
/** set to false when the vm is initialized by the host */
|
|
4160
|
+
this.autoInit = true;
|
|
4161
|
+
this.sections = RTSeeStoryEditorSection;
|
|
4162
|
+
this.illustrator = new RTSeeIllustrator();
|
|
4163
|
+
this.slideUpdatingIds = new Set();
|
|
4164
|
+
this.onIllustratorChanged = () => {
|
|
4165
|
+
this.cdr.markForCheck();
|
|
4166
|
+
};
|
|
4167
|
+
}
|
|
4168
|
+
ngOnInit() {
|
|
4169
|
+
if (this.autoInit && !this.vm.story) {
|
|
4170
|
+
void this.vm.init();
|
|
4171
|
+
}
|
|
4172
|
+
this.illustrator.on('changed', this.onIllustratorChanged);
|
|
4173
|
+
}
|
|
4174
|
+
ngOnDestroy() {
|
|
4175
|
+
this.illustrator.off('changed', this.onIllustratorChanged);
|
|
4176
|
+
this.vm.collapseSlide();
|
|
4177
|
+
this.illustrator.destroy();
|
|
4178
|
+
}
|
|
4179
|
+
isSlideUpdating(id) {
|
|
4180
|
+
return this.slideUpdatingIds.has(id);
|
|
4181
|
+
}
|
|
4182
|
+
async applyReviewedImageToSlide(event, slide) {
|
|
4183
|
+
event.stopPropagation();
|
|
4184
|
+
event.preventDefault();
|
|
4185
|
+
const imageUrl = this.illustrator.currentGeneratedImageUrl;
|
|
4186
|
+
if (!imageUrl || !slide.id)
|
|
4187
|
+
return;
|
|
4188
|
+
this.slideUpdatingIds.add(slide.id);
|
|
4189
|
+
this.cdr.markForCheck();
|
|
4190
|
+
try {
|
|
4191
|
+
await this.vm.updateSlideImage(slide, imageUrl);
|
|
4192
|
+
}
|
|
4193
|
+
catch (e) {
|
|
4194
|
+
console.error('Failed to apply image to slide:', e);
|
|
4195
|
+
}
|
|
4196
|
+
finally {
|
|
4197
|
+
this.slideUpdatingIds.delete(slide.id);
|
|
4198
|
+
this.cdr.markForCheck();
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
submitDetails() {
|
|
4202
|
+
this.vm.detailsForm?.submit();
|
|
4203
|
+
}
|
|
4204
|
+
submitAuthor() {
|
|
4205
|
+
this.vm.authorForm?.submit();
|
|
4206
|
+
}
|
|
4207
|
+
submitNewAuthor() {
|
|
4208
|
+
this.vm.newAuthorForm?.submit();
|
|
4209
|
+
}
|
|
4210
|
+
addSlideToContext(event, slide) {
|
|
4211
|
+
event.stopPropagation();
|
|
4212
|
+
event.preventDefault();
|
|
4213
|
+
if (typeof window !== 'undefined') {
|
|
4214
|
+
const anySlide = slide;
|
|
4215
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
|
|
4216
|
+
detail: {
|
|
4217
|
+
id: slide.id,
|
|
4218
|
+
title: `Slide ${slide.slideNumber}: ${slide.name || 'Story Scene'}`,
|
|
4219
|
+
imageUrl: slide.imageUrl || '',
|
|
4220
|
+
visualDescription: anySlide.visualDescription || slide.text || '',
|
|
4221
|
+
description: anySlide.description || slide.text || '',
|
|
4222
|
+
sourceType: 'slide',
|
|
4223
|
+
},
|
|
4224
|
+
}));
|
|
4225
|
+
}
|
|
4226
|
+
}
|
|
4227
|
+
addSlideEntitiesToContext(event, slide) {
|
|
4228
|
+
event.stopPropagation();
|
|
4229
|
+
event.preventDefault();
|
|
4230
|
+
if (typeof window === 'undefined') {
|
|
4231
|
+
return;
|
|
4232
|
+
}
|
|
4233
|
+
// 1. Characters: populate all related characters from story level
|
|
4234
|
+
const slideCharacters = slide.characters || [];
|
|
4235
|
+
const storyChars = this.vm.story?.characters ||
|
|
4236
|
+
this.vm.charactersEditor?.items ||
|
|
4237
|
+
[];
|
|
4238
|
+
for (const charRef of slideCharacters) {
|
|
4239
|
+
const fullChar = storyChars.find((c) => c.id === charRef.id || c.name?.toLowerCase() === charRef.name?.toLowerCase());
|
|
4240
|
+
if (fullChar) {
|
|
4241
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
|
|
4242
|
+
detail: {
|
|
4243
|
+
id: fullChar.id,
|
|
4244
|
+
title: fullChar.name || 'Character',
|
|
4245
|
+
imageUrl: fullChar.imageUrl || '',
|
|
4246
|
+
visualDescription: fullChar.visualDescription || fullChar.description || '',
|
|
4247
|
+
description: fullChar.description || '',
|
|
4248
|
+
sourceType: 'character',
|
|
4249
|
+
},
|
|
4250
|
+
}));
|
|
4251
|
+
}
|
|
4252
|
+
}
|
|
4253
|
+
if (slide.charactersIds) {
|
|
4254
|
+
for (const charId of slide.charactersIds) {
|
|
4255
|
+
if (!slideCharacters.some((c) => c.id === charId)) {
|
|
4256
|
+
const fullChar = storyChars.find((c) => c.id === charId);
|
|
4257
|
+
if (fullChar) {
|
|
4258
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
|
|
4259
|
+
detail: {
|
|
4260
|
+
id: fullChar.id,
|
|
4261
|
+
title: fullChar.name || 'Character',
|
|
4262
|
+
imageUrl: fullChar.imageUrl || '',
|
|
4263
|
+
visualDescription: fullChar.visualDescription || fullChar.description || '',
|
|
4264
|
+
description: fullChar.description || '',
|
|
4265
|
+
sourceType: 'character',
|
|
4266
|
+
},
|
|
4267
|
+
}));
|
|
4268
|
+
}
|
|
4269
|
+
}
|
|
4270
|
+
}
|
|
4271
|
+
}
|
|
4272
|
+
// 2. Locations: populate related location from story level
|
|
4273
|
+
const slideLocations = slide.locations || [];
|
|
4274
|
+
const storyLocs = this.vm.story?.locations ||
|
|
4275
|
+
this.vm.locationsEditor?.items ||
|
|
4276
|
+
[];
|
|
4277
|
+
for (const locRef of slideLocations) {
|
|
4278
|
+
const fullLoc = storyLocs.find((l) => l.id === locRef.id || l.name?.toLowerCase() === locRef.name?.toLowerCase());
|
|
4279
|
+
if (fullLoc) {
|
|
4280
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
|
|
4281
|
+
detail: {
|
|
4282
|
+
id: fullLoc.id,
|
|
4283
|
+
title: fullLoc.name || 'Location',
|
|
4284
|
+
imageUrl: fullLoc.imageUrl || '',
|
|
4285
|
+
visualDescription: fullLoc.visualDescription || fullLoc.description || '',
|
|
4286
|
+
description: fullLoc.description || '',
|
|
4287
|
+
sourceType: 'location',
|
|
4288
|
+
},
|
|
4289
|
+
}));
|
|
4290
|
+
}
|
|
4291
|
+
}
|
|
4292
|
+
if (slide.locationId && !slideLocations.some((l) => l.id === slide.locationId)) {
|
|
4293
|
+
const fullLoc = storyLocs.find((l) => l.id === slide.locationId);
|
|
4294
|
+
if (fullLoc) {
|
|
4295
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
|
|
4296
|
+
detail: {
|
|
4297
|
+
id: fullLoc.id,
|
|
4298
|
+
title: fullLoc.name || 'Location',
|
|
4299
|
+
imageUrl: fullLoc.imageUrl || '',
|
|
4300
|
+
visualDescription: fullLoc.visualDescription || fullLoc.description || '',
|
|
4301
|
+
description: fullLoc.description || '',
|
|
4302
|
+
sourceType: 'location',
|
|
4303
|
+
},
|
|
4304
|
+
}));
|
|
4305
|
+
}
|
|
4306
|
+
}
|
|
4307
|
+
// 3. Artifacts: populate related artifacts from story level
|
|
4308
|
+
const slideArtifacts = slide.artifacts || [];
|
|
4309
|
+
const storyArts = this.vm.story?.artifacts ||
|
|
4310
|
+
this.vm.artifactsEditor?.items ||
|
|
4311
|
+
[];
|
|
4312
|
+
for (const artRef of slideArtifacts) {
|
|
4313
|
+
const fullArt = storyArts.find((a) => a.id === artRef.id || a.name?.toLowerCase() === artRef.name?.toLowerCase());
|
|
4314
|
+
if (fullArt) {
|
|
4315
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
|
|
4316
|
+
detail: {
|
|
4317
|
+
id: fullArt.id,
|
|
4318
|
+
title: fullArt.name || 'Artifact',
|
|
4319
|
+
imageUrl: fullArt.imageUrl || '',
|
|
4320
|
+
visualDescription: fullArt.visualDescription || fullArt.description || '',
|
|
4321
|
+
description: fullArt.description || '',
|
|
4322
|
+
sourceType: 'artifact',
|
|
4323
|
+
},
|
|
4324
|
+
}));
|
|
4325
|
+
}
|
|
4326
|
+
}
|
|
4327
|
+
if (slide.artifactsIds) {
|
|
4328
|
+
for (const artId of slide.artifactsIds) {
|
|
4329
|
+
if (!slideArtifacts.some((a) => a.id === artId)) {
|
|
4330
|
+
const fullArt = storyArts.find((a) => a.id === artId);
|
|
4331
|
+
if (fullArt) {
|
|
4332
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
|
|
4333
|
+
detail: {
|
|
4334
|
+
id: fullArt.id,
|
|
4335
|
+
title: fullArt.name || 'Artifact',
|
|
4336
|
+
imageUrl: fullArt.imageUrl || '',
|
|
4337
|
+
visualDescription: fullArt.visualDescription || fullArt.description || '',
|
|
4338
|
+
description: fullArt.description || '',
|
|
4339
|
+
sourceType: 'artifact',
|
|
4340
|
+
},
|
|
4341
|
+
}));
|
|
4342
|
+
}
|
|
4343
|
+
}
|
|
4344
|
+
}
|
|
4345
|
+
}
|
|
4346
|
+
// 4. Illustration prompt: populate prompt box with slide illustrationDescription
|
|
4347
|
+
const illustrationDesc = slide.illustrationDescription ?? slide.illustrationDescription;
|
|
4348
|
+
if (typeof illustrationDesc === 'string' && illustrationDesc.trim()) {
|
|
4349
|
+
this.illustrator.setPrompt(illustrationDesc.trim());
|
|
4350
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.SET_PROMPT, {
|
|
4351
|
+
detail: { prompt: illustrationDesc.trim() },
|
|
4352
|
+
}));
|
|
4353
|
+
}
|
|
4354
|
+
}
|
|
4355
|
+
addAuthorToContext(event) {
|
|
4356
|
+
event.stopPropagation();
|
|
4357
|
+
event.preventDefault();
|
|
4358
|
+
if (typeof window !== 'undefined' && this.vm.author) {
|
|
4359
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
|
|
4360
|
+
detail: {
|
|
4361
|
+
id: this.vm.author.id,
|
|
4362
|
+
title: `Author: ${this.vm.author.name || ''}`,
|
|
4363
|
+
imageUrl: this.vm.author.imageUrl || '',
|
|
4364
|
+
visualDescription: this.vm.author.description || '',
|
|
4365
|
+
description: this.vm.author.description || '',
|
|
4366
|
+
sourceType: 'author',
|
|
4367
|
+
},
|
|
4368
|
+
}));
|
|
4369
|
+
}
|
|
4370
|
+
}
|
|
4371
|
+
trackSlide(index, slide) {
|
|
4372
|
+
return slide.id || `slide-${index}`;
|
|
4373
|
+
}
|
|
4374
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InteractiveStoryEditorComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4375
|
+
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 [illustrator]=\"illustrator\"\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 [illustrator]=\"illustrator\"\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 [illustrator]=\"illustrator\"\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 @if (illustrator.reviewingGeneratedImage && illustrator.currentGeneratedImageUrl) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-quick-apply\"\n style=\"position: absolute; bottom: 4px; right: 4px;\"\n [disabled]=\"isSlideUpdating(slide.id)\"\n [title]=\"'Apply reviewed image to Slide ' + slide.slideNumber\"\n (click)=\"applyReviewedImageToSlide($event, slide)\">\n @if (isSlideUpdating(slide.id)) {\n <i class=\"pi pi-spin pi-spinner\"></i>\n } @else {\n <i class=\"pi pi-plus\"></i>\n }\n </button>\n }\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", "illustrator"], outputs: ["toggled"] }, { kind: "component", type: IllustratorComponent, selector: "rtsee-illustrator", inputs: ["illustrator"] }] }); }
|
|
4376
|
+
}
|
|
4377
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InteractiveStoryEditorComponent, decorators: [{
|
|
4378
|
+
type: Component,
|
|
4379
|
+
args: [{ selector: "rtsee-interactive-story-editor", standalone: true, imports: [
|
|
4380
|
+
NgClass,
|
|
4381
|
+
Button,
|
|
4382
|
+
FormComponent,
|
|
4383
|
+
ManageSlideComponent,
|
|
4384
|
+
StoryElementsSectionComponent,
|
|
4385
|
+
IllustratorComponent,
|
|
4386
|
+
], 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 [illustrator]=\"illustrator\"\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 [illustrator]=\"illustrator\"\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 [illustrator]=\"illustrator\"\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 @if (illustrator.reviewingGeneratedImage && illustrator.currentGeneratedImageUrl) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-quick-apply\"\n style=\"position: absolute; bottom: 4px; right: 4px;\"\n [disabled]=\"isSlideUpdating(slide.id)\"\n [title]=\"'Apply reviewed image to Slide ' + slide.slideNumber\"\n (click)=\"applyReviewedImageToSlide($event, slide)\">\n @if (isSlideUpdating(slide.id)) {\n <i class=\"pi pi-spin pi-spinner\"></i>\n } @else {\n <i class=\"pi pi-plus\"></i>\n }\n </button>\n }\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" }]
|
|
4387
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { vm: [{
|
|
4388
|
+
type: Input,
|
|
4389
|
+
args: [{ required: true }]
|
|
4390
|
+
}], autoInit: [{
|
|
4391
|
+
type: Input
|
|
4392
|
+
}] } });
|
|
4393
|
+
|
|
3838
4394
|
class ManageStoriesComponent {
|
|
3839
4395
|
ngOnInit() {
|
|
3840
4396
|
this.manageStories.init();
|
|
3841
4397
|
}
|
|
3842
4398
|
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"] }] }); }
|
|
4399
|
+
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
4400
|
}
|
|
3845
4401
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: ManageStoriesComponent, decorators: [{
|
|
3846
4402
|
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" }]
|
|
4403
|
+
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
4404
|
}], propDecorators: { manageStories: [{
|
|
3849
4405
|
type: Input
|
|
3850
4406
|
}] } });
|
|
@@ -5845,5 +6401,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
5845
6401
|
* Generated bundle index. Do not edit.
|
|
5846
6402
|
*/
|
|
5847
6403
|
|
|
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 };
|
|
6404
|
+
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
6405
|
//# sourceMappingURL=rtsee-ngx.mjs.map
|