@rtsee/ngx 0.0.108 → 0.0.110
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 +508 -22
- package/dist/ngx/fesm2022/rtsee-ngx.mjs.map +1 -1
- package/dist/ngx/index.d.ts +16 -2
- package/dist/ngx/src/lib/theme/common-components/image-uploader.scss +48 -0
- package/dist/ngx/src/lib/theme/presentation/interactive-story-editor.scss +196 -0
- package/package.json +11 -11
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, Input, Component, ViewChild, EventEmitter, Output, forwardRef, Directive,
|
|
2
|
+
import { Injectable, Input, Component, ViewChild, EventEmitter, Output, forwardRef, Directive, HostListener, reflectComponentType, DOCUMENT, Inject, ChangeDetectionStrategy, output, CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
|
3
3
|
import * as i2$1 from '@angular/common';
|
|
4
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';
|
|
@@ -17,8 +17,8 @@ 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, RTSeeIllustratorEvents, RTSeeChatTypes, OzzyTaskStatus } from '@rtsee/common';
|
|
21
|
-
import { sanitizeImageUrl, ManageAgentForm, RTSeeForm, RTSeeFormFieldRadioGroup, RTSeeFormField, RTSeeFormFieldImageUploader, RTSeeRater } from '@rtsee/utilities-ui';
|
|
20
|
+
import { RTSeeChatMemberRoles, RTSeeIllustratorEvents, RTSeeChatTypes, OzzyTaskStatus, getStoryTranslatorLanguage, STORY_TRANSLATOR_LANGUAGES } from '@rtsee/common';
|
|
21
|
+
import { sanitizeImageUrl, ManageAgentForm, RTSeeForm, RTSeeFormFieldRadioGroup, RTSeeFormField, RTSeeFormFieldImageUploader, fetchImageBlob, RTSeeRater } from '@rtsee/utilities-ui';
|
|
22
22
|
import { InputText } from 'primeng/inputtext';
|
|
23
23
|
import { InputGroup } from 'primeng/inputgroup';
|
|
24
24
|
import { Textarea } from 'primeng/textarea';
|
|
@@ -28,6 +28,7 @@ import { InputNumber } from 'primeng/inputnumber';
|
|
|
28
28
|
import * as i1$2 from 'primeng/autocomplete';
|
|
29
29
|
import { AutoCompleteModule } from 'primeng/autocomplete';
|
|
30
30
|
import { ImageCropperComponent } from 'ngx-image-cropper';
|
|
31
|
+
import { Tooltip } from 'primeng/tooltip';
|
|
31
32
|
import { Fieldset } from 'primeng/fieldset';
|
|
32
33
|
import { DatePicker } from 'primeng/datepicker';
|
|
33
34
|
import { RTSeeManageChatInfo, RTSeeChatEvents, OzzyClientTaskEvents, OzzyWorkflowClientEvents, RTSeeMentionAutocomplete, RTSeeWorkflowAutocomplete } from '@rtsee/messenger';
|
|
@@ -54,7 +55,6 @@ import { Listbox } from 'primeng/listbox';
|
|
|
54
55
|
import { RTSeeRoutesList } from '@rtsee/factory';
|
|
55
56
|
import { Avatar } from 'primeng/avatar';
|
|
56
57
|
import { Image } from 'primeng/image';
|
|
57
|
-
import { Tooltip } from 'primeng/tooltip';
|
|
58
58
|
import { PanelMenu } from 'primeng/panelmenu';
|
|
59
59
|
import { Menu } from 'primeng/menu';
|
|
60
60
|
import { Password } from 'primeng/password';
|
|
@@ -675,15 +675,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
675
675
|
}] } });
|
|
676
676
|
|
|
677
677
|
class RTSeeImageUploaderComponent {
|
|
678
|
-
constructor(elementRef) {
|
|
678
|
+
constructor(elementRef, cdr) {
|
|
679
679
|
this.elementRef = elementRef;
|
|
680
|
+
this.cdr = cdr;
|
|
681
|
+
this.onUploaderChanged = () => this.cdr.markForCheck();
|
|
680
682
|
this.submittingFromPainting = false;
|
|
681
683
|
}
|
|
682
684
|
ngOnInit() {
|
|
683
685
|
this.attachEventHandlers();
|
|
684
686
|
}
|
|
687
|
+
ngOnDestroy() {
|
|
688
|
+
this.imageUploader?.off('changed', this.onUploaderChanged);
|
|
689
|
+
}
|
|
685
690
|
attachEventHandlers() {
|
|
686
691
|
this.imageUploader.on('completed', this.onImagesUploaded.bind(this));
|
|
692
|
+
this.imageUploader.on('changed', this.onUploaderChanged);
|
|
693
|
+
}
|
|
694
|
+
get optimizeTooltip() {
|
|
695
|
+
if (this.imageUploader.optimizing) {
|
|
696
|
+
return 'Optimizing…';
|
|
697
|
+
}
|
|
698
|
+
const base = `Optimize (curr size: ${this.imageUploader.currentImageSizeMb}mb)`;
|
|
699
|
+
return this.imageUploader.optimizationError
|
|
700
|
+
? `${base} - last attempt failed: ${this.imageUploader.optimizationError}`
|
|
701
|
+
: base;
|
|
702
|
+
}
|
|
703
|
+
async onOptimizeClicked(event) {
|
|
704
|
+
// The preview container opens the uploader on click
|
|
705
|
+
event.stopPropagation();
|
|
706
|
+
event.preventDefault();
|
|
707
|
+
const optimizedUrl = await this.imageUploader.optimizeCurrentImage();
|
|
708
|
+
if (optimizedUrl) {
|
|
709
|
+
// The optimized url is already propagated to the form field (`completed`) - persist it
|
|
710
|
+
setTimeout(() => this.submitParentForm(), 50);
|
|
711
|
+
}
|
|
687
712
|
}
|
|
688
713
|
onNextButtonClicked() {
|
|
689
714
|
this.imageUploader.onNextClicked();
|
|
@@ -712,6 +737,10 @@ class RTSeeImageUploaderComponent {
|
|
|
712
737
|
// 1. If RTSeeIllustrator is in reviewingGeneratedImage mode, apply currently reviewed image to ImageUploader
|
|
713
738
|
this.submittingFromPainting = true;
|
|
714
739
|
this.imageUploader.applyImageUrl(sanitizeImageUrl(response.imageUrl));
|
|
740
|
+
// Reset illustrator state and UI
|
|
741
|
+
if (typeof window !== 'undefined') {
|
|
742
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.RESET_STATE));
|
|
743
|
+
}
|
|
715
744
|
// and if Imageuploader is part of the form it should immediately submit the form
|
|
716
745
|
setTimeout(() => {
|
|
717
746
|
this.submitParentForm();
|
|
@@ -760,8 +789,11 @@ class RTSeeImageUploaderComponent {
|
|
|
760
789
|
return;
|
|
761
790
|
}
|
|
762
791
|
}
|
|
763
|
-
// 2.
|
|
764
|
-
if (this.imageUploader.
|
|
792
|
+
// 2. Custom submit hook, then programmatic RTSeeForm submit
|
|
793
|
+
if (this.imageUploader.onSubmitForm) {
|
|
794
|
+
this.imageUploader.onSubmitForm();
|
|
795
|
+
}
|
|
796
|
+
else if (this.imageUploader.form && typeof this.imageUploader.form.submit === 'function') {
|
|
765
797
|
this.imageUploader.form.submit();
|
|
766
798
|
}
|
|
767
799
|
}
|
|
@@ -769,13 +801,13 @@ class RTSeeImageUploaderComponent {
|
|
|
769
801
|
console.warn('[RTSeeImageUploaderComponent] submitParentForm error:', e);
|
|
770
802
|
}
|
|
771
803
|
}
|
|
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"] }] }); }
|
|
804
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RTSeeImageUploaderComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
805
|
+
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 [class.rtsee-shifted]=\"imageUploader.needsOptimization\"\n >\n <p-button icon=\"pi pi-pencil\" severity=\"info\"></p-button>\n </div>\n @if (imageUploader.needsOptimization) {\n <div class=\"rtsee-image-uploader-optimize-btn\"\n id=\"rtsee-image-uploader-optimize-btn\"\n [class.rtsee-optimizing]=\"imageUploader.optimizing\"\n [pTooltip]=\"optimizeTooltip\"\n tooltipPosition=\"top\"\n (click)=\"onOptimizeClicked($event)\"\n >\n <p-button [icon]=\"imageUploader.optimizing ? 'pi pi-spin pi-spinner' : 'pi pi-exclamation-triangle'\"\n severity=\"warn\"\n [rounded]=\"true\"\n [disabled]=\"imageUploader.optimizing\"\n [attr.aria-label]=\"optimizeTooltip\"\n ></p-button>\n </div>\n }\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"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }] }); }
|
|
774
806
|
}
|
|
775
807
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: RTSeeImageUploaderComponent, decorators: [{
|
|
776
808
|
type: Component,
|
|
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: [{
|
|
809
|
+
args: [{ selector: 'rtsee-image-uploader', imports: [RTSeeUploaderComponent, RTSeeCropperComponent, Button, Tooltip], 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 [class.rtsee-shifted]=\"imageUploader.needsOptimization\"\n >\n <p-button icon=\"pi pi-pencil\" severity=\"info\"></p-button>\n </div>\n @if (imageUploader.needsOptimization) {\n <div class=\"rtsee-image-uploader-optimize-btn\"\n id=\"rtsee-image-uploader-optimize-btn\"\n [class.rtsee-optimizing]=\"imageUploader.optimizing\"\n [pTooltip]=\"optimizeTooltip\"\n tooltipPosition=\"top\"\n (click)=\"onOptimizeClicked($event)\"\n >\n <p-button [icon]=\"imageUploader.optimizing ? 'pi pi-spin pi-spinner' : 'pi pi-exclamation-triangle'\"\n severity=\"warn\"\n [rounded]=\"true\"\n [disabled]=\"imageUploader.optimizing\"\n [attr.aria-label]=\"optimizeTooltip\"\n ></p-button>\n </div>\n }\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" }]
|
|
810
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { cropperComponent: [{
|
|
779
811
|
type: ViewChild,
|
|
780
812
|
args: [RTSeeCropperComponent]
|
|
781
813
|
}], imageUploader: [{
|
|
@@ -1857,10 +1889,54 @@ class MediaWidgetComponent {
|
|
|
1857
1889
|
this.visibleImages = [];
|
|
1858
1890
|
this.hiddenCount = 0;
|
|
1859
1891
|
this.showAll = false;
|
|
1892
|
+
this.downloadingUrl = null;
|
|
1860
1893
|
this.MAX_GRID = 4;
|
|
1861
1894
|
}
|
|
1862
1895
|
ngOnInit() {
|
|
1863
1896
|
this.updateVisibleImages();
|
|
1897
|
+
this.notifyRequestedGeneration();
|
|
1898
|
+
}
|
|
1899
|
+
ngOnChanges(changes) {
|
|
1900
|
+
// e.g. downsized versions got attached to the message images
|
|
1901
|
+
if (changes['message'] && !changes['message'].firstChange) {
|
|
1902
|
+
this.updateVisibleImages();
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
/** Downsized version for rendering, the original otherwise */
|
|
1906
|
+
previewUrl(img) {
|
|
1907
|
+
return img.smallVersionUrl || img.url;
|
|
1908
|
+
}
|
|
1909
|
+
async downloadOriginal(event, img) {
|
|
1910
|
+
event.stopPropagation();
|
|
1911
|
+
event.preventDefault();
|
|
1912
|
+
if (typeof window === 'undefined' || !img?.url || this.downloadingUrl) {
|
|
1913
|
+
return;
|
|
1914
|
+
}
|
|
1915
|
+
this.downloadingUrl = img.url;
|
|
1916
|
+
try {
|
|
1917
|
+
const blob = await fetchImageBlob(img.url);
|
|
1918
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
1919
|
+
const link = document.createElement('a');
|
|
1920
|
+
link.href = objectUrl;
|
|
1921
|
+
link.download = this.getDownloadFileName(img, blob);
|
|
1922
|
+
document.body.appendChild(link);
|
|
1923
|
+
link.click();
|
|
1924
|
+
link.remove();
|
|
1925
|
+
setTimeout(() => URL.revokeObjectURL(objectUrl), 1000);
|
|
1926
|
+
}
|
|
1927
|
+
catch (e) {
|
|
1928
|
+
// CORS / network failure - let the browser open the original instead
|
|
1929
|
+
console.warn('[MediaWidget] Blob download failed, opening original image:', e);
|
|
1930
|
+
window.open(img.url, '_blank', 'noopener');
|
|
1931
|
+
}
|
|
1932
|
+
finally {
|
|
1933
|
+
this.downloadingUrl = null;
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
getDownloadFileName(img, blob) {
|
|
1937
|
+
const extension = blob.type?.split('/')[1]?.split('+')[0] || 'png';
|
|
1938
|
+
const base = (img.name || img.id || 'image').replace(/[^\w.-]+/g, '-');
|
|
1939
|
+
return base.includes('.') ? base : `${base}.${extension}`;
|
|
1864
1940
|
}
|
|
1865
1941
|
get hasVideo() {
|
|
1866
1942
|
return !!this.message.video;
|
|
@@ -1884,16 +1960,33 @@ class MediaWidgetComponent {
|
|
|
1884
1960
|
event.stopPropagation();
|
|
1885
1961
|
event.preventDefault();
|
|
1886
1962
|
if (typeof window !== 'undefined' && img?.url) {
|
|
1887
|
-
|
|
1963
|
+
// Retain AWS presigned URL so Illustrator can render the image preview!
|
|
1888
1964
|
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.SET_IMAGE_FOR_REVIEW, {
|
|
1889
1965
|
detail: {
|
|
1890
|
-
imageUrl:
|
|
1966
|
+
imageUrl: img.url,
|
|
1891
1967
|
prompt: img.name || (typeof this.message.text === 'string' ? this.message.text : '') || '',
|
|
1892
1968
|
source: 'messenger',
|
|
1893
1969
|
},
|
|
1894
1970
|
}));
|
|
1895
1971
|
}
|
|
1896
1972
|
}
|
|
1973
|
+
addToContext(event, img) {
|
|
1974
|
+
event.stopPropagation();
|
|
1975
|
+
event.preventDefault();
|
|
1976
|
+
if (typeof window !== 'undefined' && img?.url) {
|
|
1977
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
|
|
1978
|
+
detail: {
|
|
1979
|
+
id: 'chat-img-' + Math.random().toString(36).substring(2, 9),
|
|
1980
|
+
imageUrl: img.url,
|
|
1981
|
+
title: img.name || 'Chat image',
|
|
1982
|
+
description: (typeof this.message.text === 'string' ? this.message.text : '') || '',
|
|
1983
|
+
visualDescription: '',
|
|
1984
|
+
sourceType: 'custom',
|
|
1985
|
+
active: true,
|
|
1986
|
+
},
|
|
1987
|
+
}));
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1897
1990
|
updateVisibleImages() {
|
|
1898
1991
|
const all = this.message.images || [];
|
|
1899
1992
|
if (this.showAll || all.length <= this.MAX_GRID) {
|
|
@@ -1905,12 +1998,25 @@ class MediaWidgetComponent {
|
|
|
1905
1998
|
this.hiddenCount = all.length - this.MAX_GRID;
|
|
1906
1999
|
}
|
|
1907
2000
|
}
|
|
2001
|
+
notifyRequestedGeneration() {
|
|
2002
|
+
const reqId = this.message?.data?.requestId;
|
|
2003
|
+
if (reqId && this.visibleImages.length > 0 && typeof window !== 'undefined') {
|
|
2004
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.REQUESTED_GENERATION_SUCCEED, {
|
|
2005
|
+
detail: {
|
|
2006
|
+
requestId: reqId,
|
|
2007
|
+
imageUrl: this.visibleImages[0].url,
|
|
2008
|
+
messageId: this.message.id,
|
|
2009
|
+
chatId: this.chat?.id,
|
|
2010
|
+
},
|
|
2011
|
+
}));
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
1908
2014
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MediaWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1909
|
-
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
|
|
2015
|
+
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" }, usesOnChanges: true, 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.id || img.url) {\n <div class=\"rts-media-image-wrapper\">\n <img [src]=\"previewUrl(img)\" [alt]=\"img.name\" class=\"rts-media-image\" loading=\"lazy\" />\n <button\n type=\"button\"\n class=\"rts-media-btn-download\"\n [class.rts-downloading]=\"downloadingUrl === img.url\"\n title=\"Download original image\"\n aria-label=\"Download original image\"\n (click)=\"downloadOriginal($event, img)\"\n >\n <i class=\"pi\" [ngClass]=\"downloadingUrl === img.url ? 'pi-spin pi-spinner' : 'pi-download'\"></i>\n </button>\n <div class=\"rts-media-image-actions\">\n <button\n type=\"button\"\n class=\"rts-media-btn-paint\"\n title=\"Send image to Illustrator (Review & Iterate)\"\n (click)=\"sendToIllustrator($event, img)\"\n >\n <i class=\"pi pi-palette\"></i>\n <span>+ paint</span>\n </button>\n <button\n type=\"button\"\n class=\"rts-media-btn-context\"\n title=\"Add image to Illustrator context references\"\n (click)=\"addToContext($event, img)\"\n >\n <i class=\"pi pi-plus\"></i>\n <span>+ context</span>\n </button>\n </div>\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-actions{position:absolute;top:8px;right:8px;z-index:5;display:inline-flex;align-items:center;gap:6px}.rts-media-btn-paint{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-btn-context{display:inline-flex;align-items:center;gap:4px;padding:4px 8px;background:#12121cd9;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);color:#bae6fd;border:1px solid rgba(56,189,248,.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-context i{font-size:11px;color:#38bdf8}.rts-media-btn-context span{line-height:1}.rts-media-btn-context:hover{background:#0ea5e9e6;color:#fff;border-color:#38bdf8;transform:translateY(-1px) scale(1.04);box-shadow:0 4px 12px #38bdf873}.rts-media-btn-context:hover i{color:#fff}.rts-media-btn-context:active{transform:translateY(0) scale(.98)}.rts-media-btn-download{position:absolute;left:8px;bottom:8px;z-index:5;width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;padding:0;background:#12121cd9;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);color:#d1fae5;border:1px solid rgba(52,211,153,.45);border-radius:50%;cursor:pointer;opacity:.85;transition:all .2s cubic-bezier(.34,1.56,.64,1);box-shadow:0 2px 8px #00000080}.rts-media-btn-download i{font-size:12px;color:#34d399}.rts-media-btn-download:hover{opacity:1;background:#10b981e6;border-color:#34d399;transform:translateY(-1px) scale(1.08);box-shadow:0 4px 12px #34d39973}.rts-media-btn-download:hover i{color:#fff}.rts-media-btn-download:active{transform:translateY(0) scale(.96)}.rts-media-btn-download.rts-downloading{cursor:progress;opacity:1}.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"] }] }); }
|
|
1910
2016
|
}
|
|
1911
2017
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MediaWidgetComponent, decorators: [{
|
|
1912
2018
|
type: Component,
|
|
1913
|
-
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
|
|
2019
|
+
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.id || img.url) {\n <div class=\"rts-media-image-wrapper\">\n <img [src]=\"previewUrl(img)\" [alt]=\"img.name\" class=\"rts-media-image\" loading=\"lazy\" />\n <button\n type=\"button\"\n class=\"rts-media-btn-download\"\n [class.rts-downloading]=\"downloadingUrl === img.url\"\n title=\"Download original image\"\n aria-label=\"Download original image\"\n (click)=\"downloadOriginal($event, img)\"\n >\n <i class=\"pi\" [ngClass]=\"downloadingUrl === img.url ? 'pi-spin pi-spinner' : 'pi-download'\"></i>\n </button>\n <div class=\"rts-media-image-actions\">\n <button\n type=\"button\"\n class=\"rts-media-btn-paint\"\n title=\"Send image to Illustrator (Review & Iterate)\"\n (click)=\"sendToIllustrator($event, img)\"\n >\n <i class=\"pi pi-palette\"></i>\n <span>+ paint</span>\n </button>\n <button\n type=\"button\"\n class=\"rts-media-btn-context\"\n title=\"Add image to Illustrator context references\"\n (click)=\"addToContext($event, img)\"\n >\n <i class=\"pi pi-plus\"></i>\n <span>+ context</span>\n </button>\n </div>\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-actions{position:absolute;top:8px;right:8px;z-index:5;display:inline-flex;align-items:center;gap:6px}.rts-media-btn-paint{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-btn-context{display:inline-flex;align-items:center;gap:4px;padding:4px 8px;background:#12121cd9;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);color:#bae6fd;border:1px solid rgba(56,189,248,.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-context i{font-size:11px;color:#38bdf8}.rts-media-btn-context span{line-height:1}.rts-media-btn-context:hover{background:#0ea5e9e6;color:#fff;border-color:#38bdf8;transform:translateY(-1px) scale(1.04);box-shadow:0 4px 12px #38bdf873}.rts-media-btn-context:hover i{color:#fff}.rts-media-btn-context:active{transform:translateY(0) scale(.98)}.rts-media-btn-download{position:absolute;left:8px;bottom:8px;z-index:5;width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;padding:0;background:#12121cd9;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);color:#d1fae5;border:1px solid rgba(52,211,153,.45);border-radius:50%;cursor:pointer;opacity:.85;transition:all .2s cubic-bezier(.34,1.56,.64,1);box-shadow:0 2px 8px #00000080}.rts-media-btn-download i{font-size:12px;color:#34d399}.rts-media-btn-download:hover{opacity:1;background:#10b981e6;border-color:#34d399;transform:translateY(-1px) scale(1.08);box-shadow:0 4px 12px #34d39973}.rts-media-btn-download:hover i{color:#fff}.rts-media-btn-download:active{transform:translateY(0) scale(.96)}.rts-media-btn-download.rts-downloading{cursor:progress;opacity:1}.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"] }]
|
|
1914
2020
|
}], propDecorators: { message: [{
|
|
1915
2021
|
type: Input
|
|
1916
2022
|
}], messenger: [{
|
|
@@ -2276,12 +2382,16 @@ class StorytellerStoryLinkStepComponent {
|
|
|
2276
2382
|
get storyUrl() {
|
|
2277
2383
|
return this.story.storyId ? `/story/${this.story.storyId}` : '';
|
|
2278
2384
|
}
|
|
2385
|
+
get kicker() {
|
|
2386
|
+
const language = this.story.language ? getStoryTranslatorLanguage(this.story.language) : undefined;
|
|
2387
|
+
return language ? `Translated to ${language.nativeName}` : 'Your story is ready';
|
|
2388
|
+
}
|
|
2279
2389
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StorytellerStoryLinkStepComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2280
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: StorytellerStoryLinkStepComponent, isStandalone: true, selector: "rtsee-storyteller-story-link-step", inputs: { step: "step", workflow: "workflow", chat: "chat", messenger: "messenger" }, ngImport: i0, template: "@if (storyUrl) {\n <a class=\"rts-story-link-card\" [href]=\"storyUrl\" target=\"_blank\" rel=\"noopener\">\n <div class=\"rts-story-link-icon\">\uD83D\uDCD6</div>\n <div class=\"rts-story-link-body\">\n <span class=\"rts-story-link-kicker\">
|
|
2390
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: StorytellerStoryLinkStepComponent, isStandalone: true, selector: "rtsee-storyteller-story-link-step", inputs: { step: "step", workflow: "workflow", chat: "chat", messenger: "messenger" }, ngImport: i0, template: "@if (storyUrl) {\n <a class=\"rts-story-link-card\" [href]=\"storyUrl\" target=\"_blank\" rel=\"noopener\">\n <div class=\"rts-story-link-icon\">\uD83D\uDCD6</div>\n <div class=\"rts-story-link-body\">\n <span class=\"rts-story-link-kicker\">{{ kicker }}</span>\n <span class=\"rts-story-link-title\">{{ story.name || 'Open story' }}</span>\n @if (story.description) {\n <span class=\"rts-story-link-description\">{{ story.description }}</span>\n }\n @if (story.slidesCount) {\n <span class=\"rts-story-link-meta\">{{ story.slidesCount }} slides</span>\n }\n </div>\n <span class=\"rts-story-link-arrow pi pi-arrow-right\"></span>\n </a>\n} @else {\n <div class=\"rts-storyteller-hint\">The story link will appear here once the story is created.</div>\n}\n", styles: [":host{display:block;--rts-st-accent: #8b5cf6;--rts-st-accent-2: #6366f1}.rts-storyteller-form{display:flex;flex-direction:column;gap:12px}.rts-storyteller-field{display:flex;flex-direction:column;gap:5px}.rts-storyteller-label{display:flex;justify-content:space-between;align-items:baseline;font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--rts-text-secondary, #8a8fa3)}.rts-storyteller-counter{font-weight:500;letter-spacing:0;text-transform:none}.rts-storyteller-input{width:100%;box-sizing:border-box;padding:9px 12px;border-radius:9px;border:1px solid var(--rts-border-dim, rgba(120, 120, 160, .25));background:var(--rts-bg-primary, rgba(127, 127, 160, .06));color:var(--rts-text-primary);font:inherit;font-size:13px;outline:none;transition:border-color .15s ease,box-shadow .15s ease,background .15s ease}.rts-storyteller-input:focus{border-color:var(--rts-st-accent);box-shadow:0 0 0 3px #8b5cf62e}.rts-storyteller-input:disabled{opacity:.75;cursor:default}.rts-storyteller-input.rts-storyteller-invalid{border-color:#f43f5e;box-shadow:0 0 0 3px #f43f5e1f}.rts-storyteller-textarea{min-height:80px;resize:vertical;line-height:1.5}.rts-storyteller-textarea-lg{min-height:160px;max-height:480px}.rts-storyteller-select-wrap{position:relative}.rts-storyteller-select{appearance:none;padding-right:32px;cursor:pointer}.rts-storyteller-select-caret{position:absolute;right:12px;top:50%;transform:translateY(-50%);font-size:10px;pointer-events:none;color:var(--rts-text-secondary, #8a8fa3)}.rts-storyteller-hint{font-size:12px;font-style:italic;color:var(--rts-text-secondary, #8a8fa3)}.rts-storyteller-error{padding:6px 10px;border-radius:6px;font-size:12px;color:#f43f5e;background:#f43f5e14;border:1px solid rgba(244,63,94,.25)}.rts-storyteller-actions{display:flex;justify-content:flex-end}.rts-storyteller-submit{display:inline-flex;align-items:center;gap:6px;padding:8px 18px;border:none;border-radius:9px;color:#fff;font-weight:600;font-size:13px;cursor:pointer;background:linear-gradient(135deg,var(--rts-st-accent-2),var(--rts-st-accent) 60%,#a78bfa);background-size:160% 160%;box-shadow:0 4px 14px -4px #6366f199;transition:transform .15s ease,box-shadow .15s ease,background-position .4s ease}.rts-storyteller-submit:hover:not(:disabled){transform:translateY(-1px);background-position:100% 0;box-shadow:0 6px 18px -4px #6366f1bf}.rts-storyteller-submit:disabled{opacity:.6;cursor:default;box-shadow:none}.rts-storyteller-spinner{width:11px;height:11px;border-radius:50%;border:2px solid rgba(255,255,255,.35);border-top-color:#fff;animation:rts-st-spin .8s linear infinite}.rts-story-link-card{display:flex;align-items:center;gap:12px;padding:14px;border-radius:12px;text-decoration:none;color:inherit;background:linear-gradient(135deg,#6366f11a,#8b5cf60f);border:1px solid rgba(139,92,246,.3);transition:transform .2s ease,box-shadow .2s ease,border-color .2s ease;animation:rts-st-pop .4s cubic-bezier(.2,.9,.3,1.3)}.rts-story-link-card:hover{transform:translateY(-2px);border-color:var(--rts-st-accent);box-shadow:0 10px 28px -12px #8b5cf699}.rts-story-link-card:hover .rts-story-link-arrow{transform:translate(3px)}.rts-story-link-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:42px;height:42px;border-radius:12px;font-size:20px;background:linear-gradient(135deg,var(--rts-st-accent-2),var(--rts-st-accent))}.rts-story-link-body{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}.rts-story-link-kicker{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--rts-st-accent)}.rts-story-link-title{font-size:15px;font-weight:600;color:var(--rts-text-primary)}.rts-story-link-description{font-size:12px;color:var(--rts-text-secondary, #8a8fa3);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.rts-story-link-meta{font-size:11px;color:var(--rts-text-secondary, #8a8fa3)}.rts-story-link-arrow{color:var(--rts-st-accent);transition:transform .2s ease}@keyframes rts-st-spin{to{transform:rotate(360deg)}}@keyframes rts-st-pop{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:none}}\n"] }); }
|
|
2281
2391
|
}
|
|
2282
2392
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StorytellerStoryLinkStepComponent, decorators: [{
|
|
2283
2393
|
type: Component,
|
|
2284
|
-
args: [{ selector: 'rtsee-storyteller-story-link-step', standalone: true, template: "@if (storyUrl) {\n <a class=\"rts-story-link-card\" [href]=\"storyUrl\" target=\"_blank\" rel=\"noopener\">\n <div class=\"rts-story-link-icon\">\uD83D\uDCD6</div>\n <div class=\"rts-story-link-body\">\n <span class=\"rts-story-link-kicker\">
|
|
2394
|
+
args: [{ selector: 'rtsee-storyteller-story-link-step', standalone: true, template: "@if (storyUrl) {\n <a class=\"rts-story-link-card\" [href]=\"storyUrl\" target=\"_blank\" rel=\"noopener\">\n <div class=\"rts-story-link-icon\">\uD83D\uDCD6</div>\n <div class=\"rts-story-link-body\">\n <span class=\"rts-story-link-kicker\">{{ kicker }}</span>\n <span class=\"rts-story-link-title\">{{ story.name || 'Open story' }}</span>\n @if (story.description) {\n <span class=\"rts-story-link-description\">{{ story.description }}</span>\n }\n @if (story.slidesCount) {\n <span class=\"rts-story-link-meta\">{{ story.slidesCount }} slides</span>\n }\n </div>\n <span class=\"rts-story-link-arrow pi pi-arrow-right\"></span>\n </a>\n} @else {\n <div class=\"rts-storyteller-hint\">The story link will appear here once the story is created.</div>\n}\n", styles: [":host{display:block;--rts-st-accent: #8b5cf6;--rts-st-accent-2: #6366f1}.rts-storyteller-form{display:flex;flex-direction:column;gap:12px}.rts-storyteller-field{display:flex;flex-direction:column;gap:5px}.rts-storyteller-label{display:flex;justify-content:space-between;align-items:baseline;font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--rts-text-secondary, #8a8fa3)}.rts-storyteller-counter{font-weight:500;letter-spacing:0;text-transform:none}.rts-storyteller-input{width:100%;box-sizing:border-box;padding:9px 12px;border-radius:9px;border:1px solid var(--rts-border-dim, rgba(120, 120, 160, .25));background:var(--rts-bg-primary, rgba(127, 127, 160, .06));color:var(--rts-text-primary);font:inherit;font-size:13px;outline:none;transition:border-color .15s ease,box-shadow .15s ease,background .15s ease}.rts-storyteller-input:focus{border-color:var(--rts-st-accent);box-shadow:0 0 0 3px #8b5cf62e}.rts-storyteller-input:disabled{opacity:.75;cursor:default}.rts-storyteller-input.rts-storyteller-invalid{border-color:#f43f5e;box-shadow:0 0 0 3px #f43f5e1f}.rts-storyteller-textarea{min-height:80px;resize:vertical;line-height:1.5}.rts-storyteller-textarea-lg{min-height:160px;max-height:480px}.rts-storyteller-select-wrap{position:relative}.rts-storyteller-select{appearance:none;padding-right:32px;cursor:pointer}.rts-storyteller-select-caret{position:absolute;right:12px;top:50%;transform:translateY(-50%);font-size:10px;pointer-events:none;color:var(--rts-text-secondary, #8a8fa3)}.rts-storyteller-hint{font-size:12px;font-style:italic;color:var(--rts-text-secondary, #8a8fa3)}.rts-storyteller-error{padding:6px 10px;border-radius:6px;font-size:12px;color:#f43f5e;background:#f43f5e14;border:1px solid rgba(244,63,94,.25)}.rts-storyteller-actions{display:flex;justify-content:flex-end}.rts-storyteller-submit{display:inline-flex;align-items:center;gap:6px;padding:8px 18px;border:none;border-radius:9px;color:#fff;font-weight:600;font-size:13px;cursor:pointer;background:linear-gradient(135deg,var(--rts-st-accent-2),var(--rts-st-accent) 60%,#a78bfa);background-size:160% 160%;box-shadow:0 4px 14px -4px #6366f199;transition:transform .15s ease,box-shadow .15s ease,background-position .4s ease}.rts-storyteller-submit:hover:not(:disabled){transform:translateY(-1px);background-position:100% 0;box-shadow:0 6px 18px -4px #6366f1bf}.rts-storyteller-submit:disabled{opacity:.6;cursor:default;box-shadow:none}.rts-storyteller-spinner{width:11px;height:11px;border-radius:50%;border:2px solid rgba(255,255,255,.35);border-top-color:#fff;animation:rts-st-spin .8s linear infinite}.rts-story-link-card{display:flex;align-items:center;gap:12px;padding:14px;border-radius:12px;text-decoration:none;color:inherit;background:linear-gradient(135deg,#6366f11a,#8b5cf60f);border:1px solid rgba(139,92,246,.3);transition:transform .2s ease,box-shadow .2s ease,border-color .2s ease;animation:rts-st-pop .4s cubic-bezier(.2,.9,.3,1.3)}.rts-story-link-card:hover{transform:translateY(-2px);border-color:var(--rts-st-accent);box-shadow:0 10px 28px -12px #8b5cf699}.rts-story-link-card:hover .rts-story-link-arrow{transform:translate(3px)}.rts-story-link-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:42px;height:42px;border-radius:12px;font-size:20px;background:linear-gradient(135deg,var(--rts-st-accent-2),var(--rts-st-accent))}.rts-story-link-body{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}.rts-story-link-kicker{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--rts-st-accent)}.rts-story-link-title{font-size:15px;font-weight:600;color:var(--rts-text-primary)}.rts-story-link-description{font-size:12px;color:var(--rts-text-secondary, #8a8fa3);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.rts-story-link-meta{font-size:11px;color:var(--rts-text-secondary, #8a8fa3)}.rts-story-link-arrow{color:var(--rts-st-accent);transition:transform .2s ease}@keyframes rts-st-spin{to{transform:rotate(360deg)}}@keyframes rts-st-pop{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:none}}\n"] }]
|
|
2285
2395
|
}], propDecorators: { step: [{
|
|
2286
2396
|
type: Input
|
|
2287
2397
|
}], workflow: [{
|
|
@@ -2292,6 +2402,232 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
2292
2402
|
type: Input
|
|
2293
2403
|
}] } });
|
|
2294
2404
|
|
|
2405
|
+
const SEARCH_DEBOUNCE_MS = 250;
|
|
2406
|
+
/**
|
|
2407
|
+
* Story Translator step 1: pick a story (autocomplete by name) and the target language.
|
|
2408
|
+
*/
|
|
2409
|
+
class StoryTranslatorFormStepComponent {
|
|
2410
|
+
constructor(cdr, host) {
|
|
2411
|
+
this.cdr = cdr;
|
|
2412
|
+
this.host = host;
|
|
2413
|
+
this.languages = STORY_TRANSLATOR_LANGUAGES;
|
|
2414
|
+
this.form = new FormGroup({
|
|
2415
|
+
/* eslint-disable */
|
|
2416
|
+
storyQuery: new FormControl(''),
|
|
2417
|
+
storyId: new FormControl('', Validators.required),
|
|
2418
|
+
language: new FormControl('', Validators.required),
|
|
2419
|
+
agentId: new FormControl('', Validators.required),
|
|
2420
|
+
/* eslint-enable */
|
|
2421
|
+
});
|
|
2422
|
+
this.selectedStory = null;
|
|
2423
|
+
this.suggestions = [];
|
|
2424
|
+
this.suggestionsOpened = false;
|
|
2425
|
+
this.highlightedIndex = 0;
|
|
2426
|
+
this.searchInProgress = false;
|
|
2427
|
+
this.searchError = null;
|
|
2428
|
+
this.searchTimer = null;
|
|
2429
|
+
this.searchRequestId = 0;
|
|
2430
|
+
this.onChangedBound = () => this.onWorkflowChanged();
|
|
2431
|
+
}
|
|
2432
|
+
get agents() {
|
|
2433
|
+
return (this.chat?.members || []).filter((m) => m.isAgent);
|
|
2434
|
+
}
|
|
2435
|
+
get readonly() {
|
|
2436
|
+
return !this.step?.isActive || !!this.workflow?.submitInProgress;
|
|
2437
|
+
}
|
|
2438
|
+
get canCancel() {
|
|
2439
|
+
return !!this.workflow?.isDraft && !this.workflow?.submitInProgress && !!this.messenger;
|
|
2440
|
+
}
|
|
2441
|
+
get selectedLanguage() {
|
|
2442
|
+
return this.languages.find((l) => l.code === this.form.get('language')?.value);
|
|
2443
|
+
}
|
|
2444
|
+
ngOnInit() {
|
|
2445
|
+
this.workflow?.on(OzzyWorkflowClientEvents.CHANGED, this.onChangedBound);
|
|
2446
|
+
const agents = this.agents;
|
|
2447
|
+
if (agents.length === 1) {
|
|
2448
|
+
this.form.get('agentId')?.setValue(agents[0].id);
|
|
2449
|
+
}
|
|
2450
|
+
this.syncWithStep();
|
|
2451
|
+
}
|
|
2452
|
+
ngOnDestroy() {
|
|
2453
|
+
this.workflow?.off(OzzyWorkflowClientEvents.CHANGED, this.onChangedBound);
|
|
2454
|
+
this.clearSearchTimer();
|
|
2455
|
+
}
|
|
2456
|
+
onStoryFocus() {
|
|
2457
|
+
if (this.readonly) {
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2460
|
+
this.suggestionsOpened = true;
|
|
2461
|
+
if (!this.suggestions.length) {
|
|
2462
|
+
this.scheduleSearch(0);
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
onStoryInput() {
|
|
2466
|
+
// typing invalidates the previous selection
|
|
2467
|
+
if (this.selectedStory) {
|
|
2468
|
+
this.selectedStory = null;
|
|
2469
|
+
this.form.get('storyId')?.setValue('');
|
|
2470
|
+
}
|
|
2471
|
+
this.suggestionsOpened = true;
|
|
2472
|
+
this.scheduleSearch(SEARCH_DEBOUNCE_MS);
|
|
2473
|
+
}
|
|
2474
|
+
onStoryKeydown(event) {
|
|
2475
|
+
if (!this.suggestionsOpened || !this.suggestions.length) {
|
|
2476
|
+
if (event.key === 'ArrowDown') {
|
|
2477
|
+
this.suggestionsOpened = true;
|
|
2478
|
+
this.scheduleSearch(0);
|
|
2479
|
+
}
|
|
2480
|
+
return;
|
|
2481
|
+
}
|
|
2482
|
+
switch (event.key) {
|
|
2483
|
+
case 'ArrowDown':
|
|
2484
|
+
event.preventDefault();
|
|
2485
|
+
this.highlightedIndex = (this.highlightedIndex + 1) % this.suggestions.length;
|
|
2486
|
+
break;
|
|
2487
|
+
case 'ArrowUp':
|
|
2488
|
+
event.preventDefault();
|
|
2489
|
+
this.highlightedIndex = (this.highlightedIndex - 1 + this.suggestions.length) % this.suggestions.length;
|
|
2490
|
+
break;
|
|
2491
|
+
case 'Enter':
|
|
2492
|
+
event.preventDefault();
|
|
2493
|
+
this.selectStory(this.suggestions[this.highlightedIndex]);
|
|
2494
|
+
break;
|
|
2495
|
+
case 'Escape':
|
|
2496
|
+
event.preventDefault();
|
|
2497
|
+
this.suggestionsOpened = false;
|
|
2498
|
+
break;
|
|
2499
|
+
}
|
|
2500
|
+
}
|
|
2501
|
+
selectStory(story) {
|
|
2502
|
+
if (!story || this.readonly) {
|
|
2503
|
+
return;
|
|
2504
|
+
}
|
|
2505
|
+
this.selectedStory = story;
|
|
2506
|
+
this.form.patchValue({ storyId: story.id, storyQuery: story.name }, { emitEvent: false });
|
|
2507
|
+
this.form.get('storyId')?.markAsTouched();
|
|
2508
|
+
this.suggestionsOpened = false;
|
|
2509
|
+
}
|
|
2510
|
+
clearStory() {
|
|
2511
|
+
if (this.readonly) {
|
|
2512
|
+
return;
|
|
2513
|
+
}
|
|
2514
|
+
this.selectedStory = null;
|
|
2515
|
+
this.form.patchValue({ storyId: '', storyQuery: '' }, { emitEvent: false });
|
|
2516
|
+
this.suggestionsOpened = true;
|
|
2517
|
+
this.scheduleSearch(0);
|
|
2518
|
+
setTimeout(() => this.storyInput?.nativeElement.focus());
|
|
2519
|
+
}
|
|
2520
|
+
onDocumentMouseDown(event) {
|
|
2521
|
+
if (this.suggestionsOpened && !this.host.nativeElement.contains(event.target)) {
|
|
2522
|
+
this.suggestionsOpened = false;
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
submit() {
|
|
2526
|
+
if (this.readonly) {
|
|
2527
|
+
return;
|
|
2528
|
+
}
|
|
2529
|
+
if (this.form.invalid || !this.selectedStory) {
|
|
2530
|
+
this.form.markAllAsTouched();
|
|
2531
|
+
return;
|
|
2532
|
+
}
|
|
2533
|
+
void this.workflow.submitStep({
|
|
2534
|
+
storyId: this.selectedStory.id,
|
|
2535
|
+
storyName: this.selectedStory.name,
|
|
2536
|
+
language: this.form.get('language')?.value,
|
|
2537
|
+
agentId: this.form.get('agentId')?.value,
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2540
|
+
cancel() {
|
|
2541
|
+
if (!this.canCancel) {
|
|
2542
|
+
return;
|
|
2543
|
+
}
|
|
2544
|
+
this.messenger?.discardDraftWorkflow(this.workflow);
|
|
2545
|
+
}
|
|
2546
|
+
isInvalid(name) {
|
|
2547
|
+
const control = this.form.get(name);
|
|
2548
|
+
return !!control && control.invalid && control.touched;
|
|
2549
|
+
}
|
|
2550
|
+
scheduleSearch(delay) {
|
|
2551
|
+
this.clearSearchTimer();
|
|
2552
|
+
this.searchTimer = setTimeout(() => void this.search(), delay);
|
|
2553
|
+
}
|
|
2554
|
+
clearSearchTimer() {
|
|
2555
|
+
if (this.searchTimer) {
|
|
2556
|
+
clearTimeout(this.searchTimer);
|
|
2557
|
+
this.searchTimer = null;
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
async search() {
|
|
2561
|
+
if (!this.messenger) {
|
|
2562
|
+
return;
|
|
2563
|
+
}
|
|
2564
|
+
const requestId = ++this.searchRequestId;
|
|
2565
|
+
const query = this.form.get('storyQuery')?.value || '';
|
|
2566
|
+
this.searchInProgress = true;
|
|
2567
|
+
this.searchError = null;
|
|
2568
|
+
this.cdr.markForCheck();
|
|
2569
|
+
try {
|
|
2570
|
+
const stories = await this.messenger.ozzy.searchStories(query);
|
|
2571
|
+
if (requestId !== this.searchRequestId) {
|
|
2572
|
+
return;
|
|
2573
|
+
}
|
|
2574
|
+
this.suggestions = stories;
|
|
2575
|
+
this.highlightedIndex = 0;
|
|
2576
|
+
}
|
|
2577
|
+
catch (e) {
|
|
2578
|
+
if (requestId !== this.searchRequestId) {
|
|
2579
|
+
return;
|
|
2580
|
+
}
|
|
2581
|
+
this.suggestions = [];
|
|
2582
|
+
this.searchError = e?.friendlyMessage || e?.message || 'Failed to load stories.';
|
|
2583
|
+
}
|
|
2584
|
+
finally {
|
|
2585
|
+
if (requestId === this.searchRequestId) {
|
|
2586
|
+
this.searchInProgress = false;
|
|
2587
|
+
this.cdr.detectChanges();
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
onWorkflowChanged() {
|
|
2592
|
+
this.syncWithStep();
|
|
2593
|
+
this.cdr.detectChanges();
|
|
2594
|
+
}
|
|
2595
|
+
syncWithStep() {
|
|
2596
|
+
const output = this.step?.output;
|
|
2597
|
+
if (output?.storyId) {
|
|
2598
|
+
this.selectedStory = { id: output.storyId, name: output.storyName || output.storyId };
|
|
2599
|
+
this.form.patchValue({ storyId: output.storyId, storyQuery: output.storyName || '', language: output.language, agentId: output.agentId }, { emitEvent: false });
|
|
2600
|
+
}
|
|
2601
|
+
if (this.readonly) {
|
|
2602
|
+
this.suggestionsOpened = false;
|
|
2603
|
+
this.form.disable({ emitEvent: false });
|
|
2604
|
+
}
|
|
2605
|
+
else {
|
|
2606
|
+
this.form.enable({ emitEvent: false });
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryTranslatorFormStepComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2610
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: StoryTranslatorFormStepComponent, isStandalone: true, selector: "rtsee-story-translator-form-step", inputs: { step: "step", workflow: "workflow", chat: "chat", messenger: "messenger" }, host: { listeners: { "document:mousedown": "onDocumentMouseDown($event)" } }, viewQueries: [{ propertyName: "storyInput", first: true, predicate: ["storyInput"], descendants: true }], ngImport: i0, template: "<form class=\"rts-storyteller-form\" [formGroup]=\"form\" (ngSubmit)=\"submit()\" autocomplete=\"off\">\n <div class=\"rts-storyteller-field\">\n <label class=\"rts-storyteller-label\" for=\"story-translator-story-{{ step.id }}\">Story</label>\n <div class=\"rts-st-autocomplete\">\n <span class=\"rts-st-autocomplete-icon pi\" [class.pi-search]=\"!searchInProgress\" [class.pi-spin]=\"searchInProgress\" [class.pi-spinner]=\"searchInProgress\"></span>\n <input #storyInput\n class=\"rts-storyteller-input rts-st-autocomplete-input\"\n [class.rts-storyteller-invalid]=\"isInvalid('storyId')\"\n [class.rts-st-autocomplete-selected]=\"!!selectedStory\"\n formControlName=\"storyQuery\"\n type=\"text\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n [attr.aria-expanded]=\"suggestionsOpened\"\n placeholder=\"Search stories by name\u2026\"\n id=\"story-translator-story-{{ step.id }}\"\n (focus)=\"onStoryFocus()\"\n (input)=\"onStoryInput()\"\n (keydown)=\"onStoryKeydown($event)\"\n />\n @if (selectedStory && !readonly) {\n <button type=\"button\"\n class=\"rts-st-autocomplete-clear pi pi-times\"\n aria-label=\"Clear story\"\n id=\"story-translator-clear-{{ step.id }}\"\n (click)=\"clearStory()\"\n ></button>\n }\n\n @if (suggestionsOpened && !readonly) {\n <ul class=\"rts-st-autocomplete-panel\" role=\"listbox\">\n @if (searchError) {\n <li class=\"rts-st-autocomplete-empty rts-st-autocomplete-error\">{{ searchError }}</li>\n } @else if (!suggestions.length && !searchInProgress) {\n <li class=\"rts-st-autocomplete-empty\">No stories found</li>\n }\n @for (story of suggestions; track story.id; let i = $index) {\n <li class=\"rts-st-autocomplete-option\"\n role=\"option\"\n [class.rts-st-autocomplete-option-active]=\"i === highlightedIndex\"\n [attr.aria-selected]=\"story.id === selectedStory?.id\"\n (mouseenter)=\"highlightedIndex = i\"\n (mousedown)=\"$event.preventDefault(); selectStory(story)\"\n >\n @if (story.imageUrl) {\n <img class=\"rts-st-autocomplete-thumb\" [src]=\"story.imageUrl\" [alt]=\"story.name\" loading=\"lazy\" />\n } @else {\n <span class=\"rts-st-autocomplete-thumb rts-st-autocomplete-thumb-empty\">\uD83D\uDCD6</span>\n }\n <span class=\"rts-st-autocomplete-option-body\">\n <span class=\"rts-st-autocomplete-option-name\">{{ story.name }}</span>\n @if (story.totalSlides) {\n <span class=\"rts-st-autocomplete-option-meta\">{{ story.totalSlides }} slides</span>\n }\n </span>\n </li>\n }\n </ul>\n }\n </div>\n </div>\n\n <label class=\"rts-storyteller-field\">\n <span class=\"rts-storyteller-label\">Translate to</span>\n <div class=\"rts-storyteller-select-wrap\">\n <select class=\"rts-storyteller-input rts-storyteller-select\"\n [class.rts-storyteller-invalid]=\"isInvalid('language')\"\n formControlName=\"language\"\n id=\"story-translator-language-{{ step.id }}\"\n >\n <option value=\"\" disabled>Select a language</option>\n @for (language of languages; track language.code) {\n <option [value]=\"language.code\">{{ language.nativeName }}</option>\n }\n </select>\n <span class=\"rts-storyteller-select-caret pi pi-chevron-down\"></span>\n </div>\n </label>\n\n <label class=\"rts-storyteller-field\">\n <span class=\"rts-storyteller-label\">Agent</span>\n @if (agents.length) {\n <div class=\"rts-storyteller-select-wrap\">\n <select class=\"rts-storyteller-input rts-storyteller-select\"\n [class.rts-storyteller-invalid]=\"isInvalid('agentId')\"\n formControlName=\"agentId\"\n id=\"story-translator-agent-{{ step.id }}\"\n >\n <option value=\"\" disabled>Select an agent</option>\n @for (agent of agents; track agent.id) {\n <option [value]=\"agent.id\">\n {{ agent.name }}{{ agent.agentConfiguration?.model?.model ? ' \u00B7 ' + agent.agentConfiguration?.model?.model : '' }}\n </option>\n }\n </select>\n <span class=\"rts-storyteller-select-caret pi pi-chevron-down\"></span>\n </div>\n } @else {\n <div class=\"rts-storyteller-hint\">There are no agentic members in this chat. Add an agent to continue.</div>\n }\n </label>\n\n @if (workflow.submitError) {\n <div class=\"rts-storyteller-error\">{{ workflow.submitError }}</div>\n }\n\n @if (step.isActive) {\n <div class=\"rts-storyteller-actions rts-st-translator-actions\">\n @if (canCancel) {\n <button class=\"rts-st-cancel\"\n type=\"button\"\n id=\"story-translator-cancel-{{ step.id }}\"\n (click)=\"cancel()\"\n >Cancel</button>\n }\n <button class=\"rts-storyteller-submit\"\n type=\"submit\"\n [disabled]=\"workflow.submitInProgress || !agents.length\"\n id=\"story-translator-submit-{{ step.id }}\"\n >\n @if (workflow.submitInProgress) {\n <span class=\"rts-storyteller-spinner\"></span> Translating\u2026\n } @else {\n \uD83C\uDF10 Translate{{ selectedLanguage ? ' to ' + selectedLanguage.nativeName : '' }}\n }\n </button>\n </div>\n }\n</form>\n", styles: [":host{display:block;--rts-st-accent: #8b5cf6;--rts-st-accent-2: #6366f1}.rts-storyteller-form{display:flex;flex-direction:column;gap:12px}.rts-storyteller-field{display:flex;flex-direction:column;gap:5px}.rts-storyteller-label{display:flex;justify-content:space-between;align-items:baseline;font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--rts-text-secondary, #8a8fa3)}.rts-storyteller-counter{font-weight:500;letter-spacing:0;text-transform:none}.rts-storyteller-input{width:100%;box-sizing:border-box;padding:9px 12px;border-radius:9px;border:1px solid var(--rts-border-dim, rgba(120, 120, 160, .25));background:var(--rts-bg-primary, rgba(127, 127, 160, .06));color:var(--rts-text-primary);font:inherit;font-size:13px;outline:none;transition:border-color .15s ease,box-shadow .15s ease,background .15s ease}.rts-storyteller-input:focus{border-color:var(--rts-st-accent);box-shadow:0 0 0 3px #8b5cf62e}.rts-storyteller-input:disabled{opacity:.75;cursor:default}.rts-storyteller-input.rts-storyteller-invalid{border-color:#f43f5e;box-shadow:0 0 0 3px #f43f5e1f}.rts-storyteller-textarea{min-height:80px;resize:vertical;line-height:1.5}.rts-storyteller-textarea-lg{min-height:160px;max-height:480px}.rts-storyteller-select-wrap{position:relative}.rts-storyteller-select{appearance:none;padding-right:32px;cursor:pointer}.rts-storyteller-select-caret{position:absolute;right:12px;top:50%;transform:translateY(-50%);font-size:10px;pointer-events:none;color:var(--rts-text-secondary, #8a8fa3)}.rts-storyteller-hint{font-size:12px;font-style:italic;color:var(--rts-text-secondary, #8a8fa3)}.rts-storyteller-error{padding:6px 10px;border-radius:6px;font-size:12px;color:#f43f5e;background:#f43f5e14;border:1px solid rgba(244,63,94,.25)}.rts-storyteller-actions{display:flex;justify-content:flex-end}.rts-storyteller-submit{display:inline-flex;align-items:center;gap:6px;padding:8px 18px;border:none;border-radius:9px;color:#fff;font-weight:600;font-size:13px;cursor:pointer;background:linear-gradient(135deg,var(--rts-st-accent-2),var(--rts-st-accent) 60%,#a78bfa);background-size:160% 160%;box-shadow:0 4px 14px -4px #6366f199;transition:transform .15s ease,box-shadow .15s ease,background-position .4s ease}.rts-storyteller-submit:hover:not(:disabled){transform:translateY(-1px);background-position:100% 0;box-shadow:0 6px 18px -4px #6366f1bf}.rts-storyteller-submit:disabled{opacity:.6;cursor:default;box-shadow:none}.rts-storyteller-spinner{width:11px;height:11px;border-radius:50%;border:2px solid rgba(255,255,255,.35);border-top-color:#fff;animation:rts-st-spin .8s linear infinite}.rts-story-link-card{display:flex;align-items:center;gap:12px;padding:14px;border-radius:12px;text-decoration:none;color:inherit;background:linear-gradient(135deg,#6366f11a,#8b5cf60f);border:1px solid rgba(139,92,246,.3);transition:transform .2s ease,box-shadow .2s ease,border-color .2s ease;animation:rts-st-pop .4s cubic-bezier(.2,.9,.3,1.3)}.rts-story-link-card:hover{transform:translateY(-2px);border-color:var(--rts-st-accent);box-shadow:0 10px 28px -12px #8b5cf699}.rts-story-link-card:hover .rts-story-link-arrow{transform:translate(3px)}.rts-story-link-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:42px;height:42px;border-radius:12px;font-size:20px;background:linear-gradient(135deg,var(--rts-st-accent-2),var(--rts-st-accent))}.rts-story-link-body{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}.rts-story-link-kicker{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--rts-st-accent)}.rts-story-link-title{font-size:15px;font-weight:600;color:var(--rts-text-primary)}.rts-story-link-description{font-size:12px;color:var(--rts-text-secondary, #8a8fa3);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.rts-story-link-meta{font-size:11px;color:var(--rts-text-secondary, #8a8fa3)}.rts-story-link-arrow{color:var(--rts-st-accent);transition:transform .2s ease}@keyframes rts-st-spin{to{transform:rotate(360deg)}}@keyframes rts-st-pop{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:none}}\n", ".rts-st-autocomplete{position:relative}.rts-st-autocomplete-icon{position:absolute;left:12px;top:50%;transform:translateY(-50%);font-size:12px;pointer-events:none;color:var(--rts-text-secondary, #8a8fa3)}.rts-st-autocomplete-input{padding-left:32px;padding-right:32px}.rts-st-autocomplete-input.rts-st-autocomplete-selected{font-weight:600}.rts-st-autocomplete-clear{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:22px;height:22px;padding:0;border:none;border-radius:50%;font-size:10px;cursor:pointer;color:var(--rts-text-secondary, #8a8fa3);background:transparent;transition:background .15s ease,color .15s ease}.rts-st-autocomplete-clear:hover{color:var(--rts-text-primary);background:#8b5cf626}.rts-st-autocomplete-panel{position:absolute;z-index:20;left:0;right:0;top:calc(100% + 4px);max-height:240px;margin:0;padding:4px;overflow-y:auto;list-style:none;border-radius:10px;border:1px solid var(--rts-border-dim, rgba(120, 120, 160, .25));background:var(--rts-bg-secondary, var(--rts-bg-primary, #1d1f2b));-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:0 14px 32px -12px #00000073;animation:rts-st-panel-in .14s ease-out}.rts-st-autocomplete-option{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:7px;cursor:pointer;transition:background .12s ease}.rts-st-autocomplete-option.rts-st-autocomplete-option-active{background:linear-gradient(135deg,#6366f129,#8b5cf61a)}.rts-st-autocomplete-option[aria-selected=true] .rts-st-autocomplete-option-name{color:var(--rts-st-accent)}.rts-st-autocomplete-thumb{flex-shrink:0;width:30px;height:30px;border-radius:7px;object-fit:cover}.rts-st-autocomplete-thumb-empty{display:flex;align-items:center;justify-content:center;font-size:15px;background:#8b5cf624}.rts-st-autocomplete-option-body{display:flex;flex-direction:column;min-width:0}.rts-st-autocomplete-option-name{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:13px;font-weight:500;color:var(--rts-text-primary)}.rts-st-autocomplete-option-meta{font-size:11px;color:var(--rts-text-secondary, #8a8fa3)}.rts-st-autocomplete-empty{padding:8px;font-size:12px;font-style:italic;color:var(--rts-text-secondary, #8a8fa3)}.rts-st-autocomplete-error{font-style:normal;color:#f43f5e}.rts-st-translator-actions{gap:8px}.rts-st-cancel{padding:8px 16px;border-radius:9px;border:1px solid var(--rts-border-dim, rgba(120, 120, 160, .25));background:transparent;color:var(--rts-text-secondary, #8a8fa3);font:inherit;font-size:13px;font-weight:600;cursor:pointer;transition:color .15s ease,border-color .15s ease,background .15s ease}.rts-st-cancel:hover{color:var(--rts-text-primary);border-color:#f43f5e73;background:#f43f5e0f}@keyframes rts-st-panel-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] }); }
|
|
2611
|
+
}
|
|
2612
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryTranslatorFormStepComponent, decorators: [{
|
|
2613
|
+
type: Component,
|
|
2614
|
+
args: [{ selector: 'rtsee-story-translator-form-step', standalone: true, imports: [ReactiveFormsModule], template: "<form class=\"rts-storyteller-form\" [formGroup]=\"form\" (ngSubmit)=\"submit()\" autocomplete=\"off\">\n <div class=\"rts-storyteller-field\">\n <label class=\"rts-storyteller-label\" for=\"story-translator-story-{{ step.id }}\">Story</label>\n <div class=\"rts-st-autocomplete\">\n <span class=\"rts-st-autocomplete-icon pi\" [class.pi-search]=\"!searchInProgress\" [class.pi-spin]=\"searchInProgress\" [class.pi-spinner]=\"searchInProgress\"></span>\n <input #storyInput\n class=\"rts-storyteller-input rts-st-autocomplete-input\"\n [class.rts-storyteller-invalid]=\"isInvalid('storyId')\"\n [class.rts-st-autocomplete-selected]=\"!!selectedStory\"\n formControlName=\"storyQuery\"\n type=\"text\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n [attr.aria-expanded]=\"suggestionsOpened\"\n placeholder=\"Search stories by name\u2026\"\n id=\"story-translator-story-{{ step.id }}\"\n (focus)=\"onStoryFocus()\"\n (input)=\"onStoryInput()\"\n (keydown)=\"onStoryKeydown($event)\"\n />\n @if (selectedStory && !readonly) {\n <button type=\"button\"\n class=\"rts-st-autocomplete-clear pi pi-times\"\n aria-label=\"Clear story\"\n id=\"story-translator-clear-{{ step.id }}\"\n (click)=\"clearStory()\"\n ></button>\n }\n\n @if (suggestionsOpened && !readonly) {\n <ul class=\"rts-st-autocomplete-panel\" role=\"listbox\">\n @if (searchError) {\n <li class=\"rts-st-autocomplete-empty rts-st-autocomplete-error\">{{ searchError }}</li>\n } @else if (!suggestions.length && !searchInProgress) {\n <li class=\"rts-st-autocomplete-empty\">No stories found</li>\n }\n @for (story of suggestions; track story.id; let i = $index) {\n <li class=\"rts-st-autocomplete-option\"\n role=\"option\"\n [class.rts-st-autocomplete-option-active]=\"i === highlightedIndex\"\n [attr.aria-selected]=\"story.id === selectedStory?.id\"\n (mouseenter)=\"highlightedIndex = i\"\n (mousedown)=\"$event.preventDefault(); selectStory(story)\"\n >\n @if (story.imageUrl) {\n <img class=\"rts-st-autocomplete-thumb\" [src]=\"story.imageUrl\" [alt]=\"story.name\" loading=\"lazy\" />\n } @else {\n <span class=\"rts-st-autocomplete-thumb rts-st-autocomplete-thumb-empty\">\uD83D\uDCD6</span>\n }\n <span class=\"rts-st-autocomplete-option-body\">\n <span class=\"rts-st-autocomplete-option-name\">{{ story.name }}</span>\n @if (story.totalSlides) {\n <span class=\"rts-st-autocomplete-option-meta\">{{ story.totalSlides }} slides</span>\n }\n </span>\n </li>\n }\n </ul>\n }\n </div>\n </div>\n\n <label class=\"rts-storyteller-field\">\n <span class=\"rts-storyteller-label\">Translate to</span>\n <div class=\"rts-storyteller-select-wrap\">\n <select class=\"rts-storyteller-input rts-storyteller-select\"\n [class.rts-storyteller-invalid]=\"isInvalid('language')\"\n formControlName=\"language\"\n id=\"story-translator-language-{{ step.id }}\"\n >\n <option value=\"\" disabled>Select a language</option>\n @for (language of languages; track language.code) {\n <option [value]=\"language.code\">{{ language.nativeName }}</option>\n }\n </select>\n <span class=\"rts-storyteller-select-caret pi pi-chevron-down\"></span>\n </div>\n </label>\n\n <label class=\"rts-storyteller-field\">\n <span class=\"rts-storyteller-label\">Agent</span>\n @if (agents.length) {\n <div class=\"rts-storyteller-select-wrap\">\n <select class=\"rts-storyteller-input rts-storyteller-select\"\n [class.rts-storyteller-invalid]=\"isInvalid('agentId')\"\n formControlName=\"agentId\"\n id=\"story-translator-agent-{{ step.id }}\"\n >\n <option value=\"\" disabled>Select an agent</option>\n @for (agent of agents; track agent.id) {\n <option [value]=\"agent.id\">\n {{ agent.name }}{{ agent.agentConfiguration?.model?.model ? ' \u00B7 ' + agent.agentConfiguration?.model?.model : '' }}\n </option>\n }\n </select>\n <span class=\"rts-storyteller-select-caret pi pi-chevron-down\"></span>\n </div>\n } @else {\n <div class=\"rts-storyteller-hint\">There are no agentic members in this chat. Add an agent to continue.</div>\n }\n </label>\n\n @if (workflow.submitError) {\n <div class=\"rts-storyteller-error\">{{ workflow.submitError }}</div>\n }\n\n @if (step.isActive) {\n <div class=\"rts-storyteller-actions rts-st-translator-actions\">\n @if (canCancel) {\n <button class=\"rts-st-cancel\"\n type=\"button\"\n id=\"story-translator-cancel-{{ step.id }}\"\n (click)=\"cancel()\"\n >Cancel</button>\n }\n <button class=\"rts-storyteller-submit\"\n type=\"submit\"\n [disabled]=\"workflow.submitInProgress || !agents.length\"\n id=\"story-translator-submit-{{ step.id }}\"\n >\n @if (workflow.submitInProgress) {\n <span class=\"rts-storyteller-spinner\"></span> Translating\u2026\n } @else {\n \uD83C\uDF10 Translate{{ selectedLanguage ? ' to ' + selectedLanguage.nativeName : '' }}\n }\n </button>\n </div>\n }\n</form>\n", styles: [":host{display:block;--rts-st-accent: #8b5cf6;--rts-st-accent-2: #6366f1}.rts-storyteller-form{display:flex;flex-direction:column;gap:12px}.rts-storyteller-field{display:flex;flex-direction:column;gap:5px}.rts-storyteller-label{display:flex;justify-content:space-between;align-items:baseline;font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--rts-text-secondary, #8a8fa3)}.rts-storyteller-counter{font-weight:500;letter-spacing:0;text-transform:none}.rts-storyteller-input{width:100%;box-sizing:border-box;padding:9px 12px;border-radius:9px;border:1px solid var(--rts-border-dim, rgba(120, 120, 160, .25));background:var(--rts-bg-primary, rgba(127, 127, 160, .06));color:var(--rts-text-primary);font:inherit;font-size:13px;outline:none;transition:border-color .15s ease,box-shadow .15s ease,background .15s ease}.rts-storyteller-input:focus{border-color:var(--rts-st-accent);box-shadow:0 0 0 3px #8b5cf62e}.rts-storyteller-input:disabled{opacity:.75;cursor:default}.rts-storyteller-input.rts-storyteller-invalid{border-color:#f43f5e;box-shadow:0 0 0 3px #f43f5e1f}.rts-storyteller-textarea{min-height:80px;resize:vertical;line-height:1.5}.rts-storyteller-textarea-lg{min-height:160px;max-height:480px}.rts-storyteller-select-wrap{position:relative}.rts-storyteller-select{appearance:none;padding-right:32px;cursor:pointer}.rts-storyteller-select-caret{position:absolute;right:12px;top:50%;transform:translateY(-50%);font-size:10px;pointer-events:none;color:var(--rts-text-secondary, #8a8fa3)}.rts-storyteller-hint{font-size:12px;font-style:italic;color:var(--rts-text-secondary, #8a8fa3)}.rts-storyteller-error{padding:6px 10px;border-radius:6px;font-size:12px;color:#f43f5e;background:#f43f5e14;border:1px solid rgba(244,63,94,.25)}.rts-storyteller-actions{display:flex;justify-content:flex-end}.rts-storyteller-submit{display:inline-flex;align-items:center;gap:6px;padding:8px 18px;border:none;border-radius:9px;color:#fff;font-weight:600;font-size:13px;cursor:pointer;background:linear-gradient(135deg,var(--rts-st-accent-2),var(--rts-st-accent) 60%,#a78bfa);background-size:160% 160%;box-shadow:0 4px 14px -4px #6366f199;transition:transform .15s ease,box-shadow .15s ease,background-position .4s ease}.rts-storyteller-submit:hover:not(:disabled){transform:translateY(-1px);background-position:100% 0;box-shadow:0 6px 18px -4px #6366f1bf}.rts-storyteller-submit:disabled{opacity:.6;cursor:default;box-shadow:none}.rts-storyteller-spinner{width:11px;height:11px;border-radius:50%;border:2px solid rgba(255,255,255,.35);border-top-color:#fff;animation:rts-st-spin .8s linear infinite}.rts-story-link-card{display:flex;align-items:center;gap:12px;padding:14px;border-radius:12px;text-decoration:none;color:inherit;background:linear-gradient(135deg,#6366f11a,#8b5cf60f);border:1px solid rgba(139,92,246,.3);transition:transform .2s ease,box-shadow .2s ease,border-color .2s ease;animation:rts-st-pop .4s cubic-bezier(.2,.9,.3,1.3)}.rts-story-link-card:hover{transform:translateY(-2px);border-color:var(--rts-st-accent);box-shadow:0 10px 28px -12px #8b5cf699}.rts-story-link-card:hover .rts-story-link-arrow{transform:translate(3px)}.rts-story-link-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:42px;height:42px;border-radius:12px;font-size:20px;background:linear-gradient(135deg,var(--rts-st-accent-2),var(--rts-st-accent))}.rts-story-link-body{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}.rts-story-link-kicker{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--rts-st-accent)}.rts-story-link-title{font-size:15px;font-weight:600;color:var(--rts-text-primary)}.rts-story-link-description{font-size:12px;color:var(--rts-text-secondary, #8a8fa3);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.rts-story-link-meta{font-size:11px;color:var(--rts-text-secondary, #8a8fa3)}.rts-story-link-arrow{color:var(--rts-st-accent);transition:transform .2s ease}@keyframes rts-st-spin{to{transform:rotate(360deg)}}@keyframes rts-st-pop{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:none}}\n", ".rts-st-autocomplete{position:relative}.rts-st-autocomplete-icon{position:absolute;left:12px;top:50%;transform:translateY(-50%);font-size:12px;pointer-events:none;color:var(--rts-text-secondary, #8a8fa3)}.rts-st-autocomplete-input{padding-left:32px;padding-right:32px}.rts-st-autocomplete-input.rts-st-autocomplete-selected{font-weight:600}.rts-st-autocomplete-clear{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:22px;height:22px;padding:0;border:none;border-radius:50%;font-size:10px;cursor:pointer;color:var(--rts-text-secondary, #8a8fa3);background:transparent;transition:background .15s ease,color .15s ease}.rts-st-autocomplete-clear:hover{color:var(--rts-text-primary);background:#8b5cf626}.rts-st-autocomplete-panel{position:absolute;z-index:20;left:0;right:0;top:calc(100% + 4px);max-height:240px;margin:0;padding:4px;overflow-y:auto;list-style:none;border-radius:10px;border:1px solid var(--rts-border-dim, rgba(120, 120, 160, .25));background:var(--rts-bg-secondary, var(--rts-bg-primary, #1d1f2b));-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:0 14px 32px -12px #00000073;animation:rts-st-panel-in .14s ease-out}.rts-st-autocomplete-option{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:7px;cursor:pointer;transition:background .12s ease}.rts-st-autocomplete-option.rts-st-autocomplete-option-active{background:linear-gradient(135deg,#6366f129,#8b5cf61a)}.rts-st-autocomplete-option[aria-selected=true] .rts-st-autocomplete-option-name{color:var(--rts-st-accent)}.rts-st-autocomplete-thumb{flex-shrink:0;width:30px;height:30px;border-radius:7px;object-fit:cover}.rts-st-autocomplete-thumb-empty{display:flex;align-items:center;justify-content:center;font-size:15px;background:#8b5cf624}.rts-st-autocomplete-option-body{display:flex;flex-direction:column;min-width:0}.rts-st-autocomplete-option-name{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:13px;font-weight:500;color:var(--rts-text-primary)}.rts-st-autocomplete-option-meta{font-size:11px;color:var(--rts-text-secondary, #8a8fa3)}.rts-st-autocomplete-empty{padding:8px;font-size:12px;font-style:italic;color:var(--rts-text-secondary, #8a8fa3)}.rts-st-autocomplete-error{font-style:normal;color:#f43f5e}.rts-st-translator-actions{gap:8px}.rts-st-cancel{padding:8px 16px;border-radius:9px;border:1px solid var(--rts-border-dim, rgba(120, 120, 160, .25));background:transparent;color:var(--rts-text-secondary, #8a8fa3);font:inherit;font-size:13px;font-weight:600;cursor:pointer;transition:color .15s ease,border-color .15s ease,background .15s ease}.rts-st-cancel:hover{color:var(--rts-text-primary);border-color:#f43f5e73;background:#f43f5e0f}@keyframes rts-st-panel-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}\n"] }]
|
|
2615
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }], propDecorators: { step: [{
|
|
2616
|
+
type: Input
|
|
2617
|
+
}], workflow: [{
|
|
2618
|
+
type: Input
|
|
2619
|
+
}], chat: [{
|
|
2620
|
+
type: Input
|
|
2621
|
+
}], messenger: [{
|
|
2622
|
+
type: Input
|
|
2623
|
+
}], storyInput: [{
|
|
2624
|
+
type: ViewChild,
|
|
2625
|
+
args: ['storyInput']
|
|
2626
|
+
}], onDocumentMouseDown: [{
|
|
2627
|
+
type: HostListener,
|
|
2628
|
+
args: ['document:mousedown', ['$event']]
|
|
2629
|
+
}] } });
|
|
2630
|
+
|
|
2295
2631
|
/**
|
|
2296
2632
|
* Registry of the components which render workflow steps inside the rts-workflow widget.
|
|
2297
2633
|
*/
|
|
@@ -2301,6 +2637,7 @@ class WorkflowStepsService {
|
|
|
2301
2637
|
{ name: 'workflow-task-step', component: WorkflowTaskStepComponent },
|
|
2302
2638
|
{ name: 'storyteller-form-step', component: StorytellerFormStepComponent },
|
|
2303
2639
|
{ name: 'storyteller-story-link-step', component: StorytellerStoryLinkStepComponent },
|
|
2640
|
+
{ name: 'story-translator-form-step', component: StoryTranslatorFormStepComponent },
|
|
2304
2641
|
];
|
|
2305
2642
|
}
|
|
2306
2643
|
register(widget) {
|
|
@@ -2476,8 +2813,22 @@ class MessageComponent {
|
|
|
2476
2813
|
this.widgetsService = widgetsService;
|
|
2477
2814
|
this.componentFactoryResolver = componentFactoryResolver;
|
|
2478
2815
|
this.timeFormatService = timeFormatService;
|
|
2816
|
+
this.widgetRef = null;
|
|
2817
|
+
this.widgetHasMessageInput = false;
|
|
2479
2818
|
}
|
|
2480
2819
|
ngOnInit() { }
|
|
2820
|
+
ngOnChanges(changes) {
|
|
2821
|
+
// The message instance can be replaced (e.g. images got downsized versions) - forward it to the widget
|
|
2822
|
+
if (changes['message'] && !changes['message'].firstChange && this.widgetRef) {
|
|
2823
|
+
if (this.widgetHasMessageInput) {
|
|
2824
|
+
this.widgetRef.setInput('message', this.message);
|
|
2825
|
+
}
|
|
2826
|
+
else {
|
|
2827
|
+
this.widgetRef.instance.message = this.message;
|
|
2828
|
+
this.widgetRef.changeDetectorRef.markForCheck();
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
}
|
|
2481
2832
|
ngAfterViewInit() {
|
|
2482
2833
|
/* eslint-disable */
|
|
2483
2834
|
if (this.message.widget) {
|
|
@@ -2493,11 +2844,13 @@ class MessageComponent {
|
|
|
2493
2844
|
componentRef.instance.messenger = this.messenger;
|
|
2494
2845
|
componentRef.instance.chat = this.chat;
|
|
2495
2846
|
componentRef.changeDetectorRef.detectChanges();
|
|
2847
|
+
this.widgetRef = componentRef;
|
|
2848
|
+
this.widgetHasMessageInput = !!reflectComponentType(widget)?.inputs.some((input) => input.propName === 'message');
|
|
2496
2849
|
}
|
|
2497
2850
|
/* eslint-enable */
|
|
2498
2851
|
}
|
|
2499
2852
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MessageComponent, deps: [{ token: MessageWidgetsService }, { token: i0.ComponentFactoryResolver }, { token: TimeFormatHelperService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2500
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MessageComponent, isStandalone: true, selector: "rtsee-message", inputs: { chat: "chat", message: "message", member: "member", messenger: "messenger" }, viewQueries: [{ propertyName: "widgetHost", first: true, predicate: WidgetDirective, descendants: true }], ngImport: i0, template: "<div class=\"rts-message-container\" #rtsMessageContainer\n [ngClass]=\"{'rts-message-from-me': message.from.id === messenger.clientId}\"\n>\n <div class=\"rts-messenger-message\">\n @if (message.widget) {\n <ng-template widgetHost></ng-template>\n }\n @if (!message.widget) {\n <p class=\"rts-messenger-message-text\"\n >{{ message.text }}</p>\n }\n <div class=\"rts-messenger-message-info\" #rtsMessageInfo>\n <rtsee-message-time-and-status [message]=\"message\"\n [inChat]=\"true\"\n [hideStatus]=\"message.from.id !== messenger.clientId\"\n ></rtsee-message-time-and-status>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MessageTimeAndStatusComponent, selector: "rtsee-message-time-and-status", inputs: ["message", "hideStatus", "inChat"] }, { kind: "directive", type: WidgetDirective, selector: "[widgetHost]" }] }); }
|
|
2853
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MessageComponent, isStandalone: true, selector: "rtsee-message", inputs: { chat: "chat", message: "message", member: "member", messenger: "messenger" }, viewQueries: [{ propertyName: "widgetHost", first: true, predicate: WidgetDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"rts-message-container\" #rtsMessageContainer\n [ngClass]=\"{'rts-message-from-me': message.from.id === messenger.clientId}\"\n>\n <div class=\"rts-messenger-message\">\n @if (message.widget) {\n <ng-template widgetHost></ng-template>\n }\n @if (!message.widget) {\n <p class=\"rts-messenger-message-text\"\n >{{ message.text }}</p>\n }\n <div class=\"rts-messenger-message-info\" #rtsMessageInfo>\n <rtsee-message-time-and-status [message]=\"message\"\n [inChat]=\"true\"\n [hideStatus]=\"message.from.id !== messenger.clientId\"\n ></rtsee-message-time-and-status>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MessageTimeAndStatusComponent, selector: "rtsee-message-time-and-status", inputs: ["message", "hideStatus", "inChat"] }, { kind: "directive", type: WidgetDirective, selector: "[widgetHost]" }] }); }
|
|
2501
2854
|
}
|
|
2502
2855
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MessageComponent, decorators: [{
|
|
2503
2856
|
type: Component,
|
|
@@ -3859,11 +4212,11 @@ class StoryPlayerComponent {
|
|
|
3859
4212
|
this.story.initSwiper(swiper);
|
|
3860
4213
|
}
|
|
3861
4214
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryPlayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3862
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: StoryPlayerComponent, isStandalone: true, selector: "rtsee-story-player", inputs: { story: "story", settings: "settings", presentation: "presentation" }, viewQueries: [{ propertyName: "swiperEl", first: true, predicate: ["swiperContainer"], descendants: true }], ngImport: i0, template: "<div class=\"rtsee-story-player\">\n <div class=\"rtsee-story-player-slider swiper\" #swiperContainer>\n <div class=\"rtsee-story-player-slider-inner swiper-wrapper\">\n @for (slide of story.slides; track slide.id) {\n <div class=\"story-player-slide-container swiper-slide\"\n [ngClass]=\"{'story-player-slide-active': slide.isActive}\"\n >\n <rtsee-slide [slide]=\"slide\"\n [story]=\"story\"\n [presentation]=\"presentation\"\n [settings]=\"settings\"\n ></rtsee-slide>\n </div>\n }\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: SlideComponent, selector: "rtsee-slide", inputs: ["presentation", "story", "slide", "settings"] }] }); }
|
|
4215
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: StoryPlayerComponent, isStandalone: true, selector: "rtsee-story-player", inputs: { story: "story", settings: "settings", presentation: "presentation" }, viewQueries: [{ propertyName: "swiperEl", first: true, predicate: ["swiperContainer"], descendants: true }], ngImport: i0, template: "<div class=\"rtsee-story-player\">\n <div class=\"rtsee-story-player-slider swiper\" #swiperContainer>\n <div class=\"rtsee-story-player-slider-inner swiper-wrapper\">\n @for (slide of story.slides; track (slide.id || slide.slideNumber)) {\n <div class=\"story-player-slide-container swiper-slide\"\n [ngClass]=\"{'story-player-slide-active': slide.isActive}\"\n >\n <rtsee-slide [slide]=\"slide\"\n [story]=\"story\"\n [presentation]=\"presentation\"\n [settings]=\"settings\"\n ></rtsee-slide>\n </div>\n }\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: SlideComponent, selector: "rtsee-slide", inputs: ["presentation", "story", "slide", "settings"] }] }); }
|
|
3863
4216
|
}
|
|
3864
4217
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryPlayerComponent, decorators: [{
|
|
3865
4218
|
type: Component,
|
|
3866
|
-
args: [{ selector: 'rtsee-story-player', imports: [NgClass, SlideComponent], standalone: true, template: "<div class=\"rtsee-story-player\">\n <div class=\"rtsee-story-player-slider swiper\" #swiperContainer>\n <div class=\"rtsee-story-player-slider-inner swiper-wrapper\">\n @for (slide of story.slides; track slide.id) {\n <div class=\"story-player-slide-container swiper-slide\"\n [ngClass]=\"{'story-player-slide-active': slide.isActive}\"\n >\n <rtsee-slide [slide]=\"slide\"\n [story]=\"story\"\n [presentation]=\"presentation\"\n [settings]=\"settings\"\n ></rtsee-slide>\n </div>\n }\n </div>\n </div>\n</div>\n" }]
|
|
4219
|
+
args: [{ selector: 'rtsee-story-player', imports: [NgClass, SlideComponent], standalone: true, template: "<div class=\"rtsee-story-player\">\n <div class=\"rtsee-story-player-slider swiper\" #swiperContainer>\n <div class=\"rtsee-story-player-slider-inner swiper-wrapper\">\n @for (slide of story.slides; track (slide.id || slide.slideNumber)) {\n <div class=\"story-player-slide-container swiper-slide\"\n [ngClass]=\"{'story-player-slide-active': slide.isActive}\"\n >\n <rtsee-slide [slide]=\"slide\"\n [story]=\"story\"\n [presentation]=\"presentation\"\n [settings]=\"settings\"\n ></rtsee-slide>\n </div>\n }\n </div>\n </div>\n</div>\n" }]
|
|
3867
4220
|
}], ctorParameters: () => [], propDecorators: { story: [{
|
|
3868
4221
|
type: Input
|
|
3869
4222
|
}], settings: [{
|
|
@@ -3961,6 +4314,11 @@ class StoryElementsSectionComponent {
|
|
|
3961
4314
|
this.collapsed = false;
|
|
3962
4315
|
this.canDetach = true;
|
|
3963
4316
|
this.toggled = new EventEmitter();
|
|
4317
|
+
this.batchMode = false;
|
|
4318
|
+
this.selectedItemIds = new Set();
|
|
4319
|
+
this.batchAdditionalPrompt = '';
|
|
4320
|
+
this.generatingItemIds = new Set();
|
|
4321
|
+
this.activeGenerationListeners = new Map();
|
|
3964
4322
|
this.onIllustratorChanged = () => {
|
|
3965
4323
|
this.cdr.markForCheck();
|
|
3966
4324
|
};
|
|
@@ -3969,6 +4327,124 @@ class StoryElementsSectionComponent {
|
|
|
3969
4327
|
if (this._illustrator) {
|
|
3970
4328
|
this._illustrator.off('changed', this.onIllustratorChanged);
|
|
3971
4329
|
}
|
|
4330
|
+
for (const [requestId, listener] of this.activeGenerationListeners.entries()) {
|
|
4331
|
+
window.removeEventListener(RTSeeIllustrator.REQUESTED_GENERATION_SUCCEED, listener);
|
|
4332
|
+
}
|
|
4333
|
+
this.activeGenerationListeners.clear();
|
|
4334
|
+
}
|
|
4335
|
+
startBatchSelection(event) {
|
|
4336
|
+
event.stopPropagation();
|
|
4337
|
+
event.preventDefault();
|
|
4338
|
+
if (this.collapsed) {
|
|
4339
|
+
this.toggled.emit();
|
|
4340
|
+
}
|
|
4341
|
+
this.batchMode = true;
|
|
4342
|
+
this.selectedItemIds.clear();
|
|
4343
|
+
for (const item of this.editor.items) {
|
|
4344
|
+
const url = (item.imageUrl || '').toLowerCase();
|
|
4345
|
+
if (!url || url.includes('default')) {
|
|
4346
|
+
this.selectedItemIds.add(item.id);
|
|
4347
|
+
}
|
|
4348
|
+
}
|
|
4349
|
+
this.cdr.markForCheck();
|
|
4350
|
+
}
|
|
4351
|
+
cancelBatchSelection() {
|
|
4352
|
+
this.batchMode = false;
|
|
4353
|
+
this.selectedItemIds.clear();
|
|
4354
|
+
this.batchAdditionalPrompt = '';
|
|
4355
|
+
this.cdr.markForCheck();
|
|
4356
|
+
}
|
|
4357
|
+
toggleItemSelection(id) {
|
|
4358
|
+
if (this.selectedItemIds.has(id)) {
|
|
4359
|
+
this.selectedItemIds.delete(id);
|
|
4360
|
+
}
|
|
4361
|
+
else {
|
|
4362
|
+
this.selectedItemIds.add(id);
|
|
4363
|
+
}
|
|
4364
|
+
this.cdr.markForCheck();
|
|
4365
|
+
}
|
|
4366
|
+
isItemSelected(id) {
|
|
4367
|
+
return this.selectedItemIds.has(id);
|
|
4368
|
+
}
|
|
4369
|
+
isItemGenerating(id) {
|
|
4370
|
+
return this.generatingItemIds.has(id);
|
|
4371
|
+
}
|
|
4372
|
+
async submitBatchGeneration() {
|
|
4373
|
+
if (this.selectedItemIds.size === 0)
|
|
4374
|
+
return;
|
|
4375
|
+
const selectedItems = this.editor.items.filter((item) => this.selectedItemIds.has(item.id));
|
|
4376
|
+
const additionalPrompt = this.batchAdditionalPrompt.trim();
|
|
4377
|
+
this.batchMode = false;
|
|
4378
|
+
this.selectedItemIds.clear();
|
|
4379
|
+
this.batchAdditionalPrompt = '';
|
|
4380
|
+
this.cdr.markForCheck();
|
|
4381
|
+
for (const item of selectedItems) {
|
|
4382
|
+
const requestId = RTSeeCore.uuidv4();
|
|
4383
|
+
this.generatingItemIds.add(item.id);
|
|
4384
|
+
const listener = async (e) => {
|
|
4385
|
+
const customEvent = e;
|
|
4386
|
+
if (customEvent.detail?.requestId === requestId && customEvent.detail?.imageUrl) {
|
|
4387
|
+
window.removeEventListener(RTSeeIllustrator.REQUESTED_GENERATION_SUCCEED, listener);
|
|
4388
|
+
this.activeGenerationListeners.delete(requestId);
|
|
4389
|
+
this.generatingItemIds.delete(item.id);
|
|
4390
|
+
const cleanUrl = sanitizeImageUrl(customEvent.detail.imageUrl);
|
|
4391
|
+
try {
|
|
4392
|
+
item.imageUrl = cleanUrl;
|
|
4393
|
+
await item.save({ imageUrl: cleanUrl });
|
|
4394
|
+
if (this.editor.expanded && this.editor.expanded.id === item.id && this.editor.form) {
|
|
4395
|
+
const imageField = this.editor.form.fields.find((f) => f.name === 'imageUrl' || f.type === 'image-uploader');
|
|
4396
|
+
if (imageField) {
|
|
4397
|
+
imageField.value = cleanUrl;
|
|
4398
|
+
if (imageField.imageUploader) {
|
|
4399
|
+
imageField.imageUploader.uploadedPhotoPreview = cleanUrl;
|
|
4400
|
+
imageField.imageUploader.value = cleanUrl;
|
|
4401
|
+
}
|
|
4402
|
+
}
|
|
4403
|
+
}
|
|
4404
|
+
}
|
|
4405
|
+
catch (err) {
|
|
4406
|
+
console.error(`Failed to apply generated image to ${this.editor.label}:`, err);
|
|
4407
|
+
}
|
|
4408
|
+
finally {
|
|
4409
|
+
this.cdr.markForCheck();
|
|
4410
|
+
}
|
|
4411
|
+
}
|
|
4412
|
+
};
|
|
4413
|
+
window.addEventListener(RTSeeIllustrator.REQUESTED_GENERATION_SUCCEED, listener);
|
|
4414
|
+
this.activeGenerationListeners.set(requestId, listener);
|
|
4415
|
+
const promptParts = [];
|
|
4416
|
+
promptParts.push(`${this.editor.label}: ${item.name || ''}`);
|
|
4417
|
+
if (item.visualDescription) {
|
|
4418
|
+
promptParts.push(`Visual appearance: ${item.visualDescription}`);
|
|
4419
|
+
}
|
|
4420
|
+
if (item.description && item.description !== item.visualDescription) {
|
|
4421
|
+
promptParts.push(`Description/Role: ${item.description}`);
|
|
4422
|
+
}
|
|
4423
|
+
if (additionalPrompt) {
|
|
4424
|
+
promptParts.push(`Additional prompt: ${additionalPrompt}`);
|
|
4425
|
+
}
|
|
4426
|
+
const entityPrompt = promptParts.join('\n');
|
|
4427
|
+
const config = this.illustrator?.config || {
|
|
4428
|
+
aspectRatio: '1:1',
|
|
4429
|
+
style: 'Classic Fairy Tale pixel-art Storybook',
|
|
4430
|
+
mood: 'Dreamy & Magical',
|
|
4431
|
+
lighting: 'Soft Diffused Storybook Glow',
|
|
4432
|
+
negativePrompt: 'modern elements, cars, text, watermark, signature, blurry, low quality',
|
|
4433
|
+
numberOfImages: 1,
|
|
4434
|
+
};
|
|
4435
|
+
const payload = {
|
|
4436
|
+
chatId: this.illustrator?.activeChatId || undefined,
|
|
4437
|
+
agentId: this.illustrator?.activeAgentId || '',
|
|
4438
|
+
prompt: entityPrompt,
|
|
4439
|
+
config: { ...config },
|
|
4440
|
+
contextImages: [],
|
|
4441
|
+
requestId,
|
|
4442
|
+
};
|
|
4443
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.SUBMIT_PROMPT, {
|
|
4444
|
+
detail: payload,
|
|
4445
|
+
}));
|
|
4446
|
+
}
|
|
4447
|
+
this.cdr.markForCheck();
|
|
3972
4448
|
}
|
|
3973
4449
|
async applyReviewedImageToItem(event, item) {
|
|
3974
4450
|
event.stopPropagation();
|
|
@@ -3988,6 +4464,11 @@ class StoryElementsSectionComponent {
|
|
|
3988
4464
|
}
|
|
3989
4465
|
}
|
|
3990
4466
|
}
|
|
4467
|
+
// Reset illustrator state and UI
|
|
4468
|
+
this._illustrator?.resetState();
|
|
4469
|
+
if (typeof window !== 'undefined') {
|
|
4470
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.RESET_STATE));
|
|
4471
|
+
}
|
|
3991
4472
|
}
|
|
3992
4473
|
catch (e) {
|
|
3993
4474
|
console.error(`Failed to apply image to ${this.editor.label}:`, e);
|
|
@@ -4019,11 +4500,11 @@ class StoryElementsSectionComponent {
|
|
|
4019
4500
|
return item.id || `new-${index}`;
|
|
4020
4501
|
}
|
|
4021
4502
|
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 }); }
|
|
4022
|
-
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"] }] }); }
|
|
4503
|
+
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 @if (editor.items.length > 0 && !batchMode) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-batch-generate\"\n (click)=\"startBatchSelection($event)\"\n [title]=\"'Batch generate images for ' + title\">\n <i class=\"pi pi-sparkles\"></i>\n <span>Generate Images</span>\n </button>\n }\n </header>\n\n @if (batchMode) {\n <div class=\"rtsee-ise-batch-panel\">\n <div class=\"rtsee-ise-batch-header\">\n <span class=\"rtsee-ise-batch-title\">\n <i class=\"pi pi-sparkles\"></i>\n Batch Generate for {{ title }} ({{ selectedItemIds.size }} of {{ editor.items.length }} selected)\n </span>\n <span class=\"rtsee-ise-batch-hint\">\n Click items to select/deselect. Entities with default images are auto-selected.\n </span>\n </div>\n\n <textarea\n class=\"rtsee-ise-batch-prompt-input\"\n rows=\"2\"\n [(ngModel)]=\"batchAdditionalPrompt\"\n placeholder=\"Additional prompt instructions for all selected {{ title }} (optional)...\"\n ></textarea>\n\n <div class=\"rtsee-ise-batch-actions\">\n <button\n type=\"button\"\n class=\"rtsee-ise-btn-batch-cancel\"\n (click)=\"cancelBatchSelection()\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n class=\"rtsee-ise-btn-batch-submit\"\n [disabled]=\"selectedItemIds.size === 0\"\n (click)=\"submitBatchGeneration()\"\n >\n <i class=\"pi pi-sparkles\"></i>\n <span>Generate {{ selectedItemIds.size }} image{{ selectedItemIds.size === 1 ? '' : 's' }}</span>\n </button>\n </div>\n </div>\n }\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]=\"{\n 'rtsee-ise-thumb--active': editor.isExpanded(item),\n 'rtsee-ise-thumb-card--selected': batchMode && isItemSelected(item.id)\n }\"\n [id]=\"'rtsee-ise-' + editor.section + '-' + item.id\"\n (click)=\"batchMode ? toggleItemSelection(item.id) : 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 @if (isItemGenerating(item.id)) {\n <div class=\"rtsee-ise-thumb-generating-overlay\">\n <i class=\"pi pi-spin pi-spinner\"></i>\n <span>Generating\u2026</span>\n </div>\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 @if (batchMode) {\n <div class=\"rtsee-ise-thumb-batch-checkbox\" (click)=\"toggleItemSelection(item.id); $event.stopPropagation()\">\n <input type=\"checkbox\" [checked]=\"isItemSelected(item.id)\" />\n </div>\n }\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: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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"] }] }); }
|
|
4023
4504
|
}
|
|
4024
4505
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryElementsSectionComponent, decorators: [{
|
|
4025
4506
|
type: Component,
|
|
4026
|
-
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]=\"{
|
|
4507
|
+
args: [{ selector: "rtsee-story-elements-section", standalone: true, imports: [NgClass, FormsModule, 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 @if (editor.items.length > 0 && !batchMode) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-batch-generate\"\n (click)=\"startBatchSelection($event)\"\n [title]=\"'Batch generate images for ' + title\">\n <i class=\"pi pi-sparkles\"></i>\n <span>Generate Images</span>\n </button>\n }\n </header>\n\n @if (batchMode) {\n <div class=\"rtsee-ise-batch-panel\">\n <div class=\"rtsee-ise-batch-header\">\n <span class=\"rtsee-ise-batch-title\">\n <i class=\"pi pi-sparkles\"></i>\n Batch Generate for {{ title }} ({{ selectedItemIds.size }} of {{ editor.items.length }} selected)\n </span>\n <span class=\"rtsee-ise-batch-hint\">\n Click items to select/deselect. Entities with default images are auto-selected.\n </span>\n </div>\n\n <textarea\n class=\"rtsee-ise-batch-prompt-input\"\n rows=\"2\"\n [(ngModel)]=\"batchAdditionalPrompt\"\n placeholder=\"Additional prompt instructions for all selected {{ title }} (optional)...\"\n ></textarea>\n\n <div class=\"rtsee-ise-batch-actions\">\n <button\n type=\"button\"\n class=\"rtsee-ise-btn-batch-cancel\"\n (click)=\"cancelBatchSelection()\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n class=\"rtsee-ise-btn-batch-submit\"\n [disabled]=\"selectedItemIds.size === 0\"\n (click)=\"submitBatchGeneration()\"\n >\n <i class=\"pi pi-sparkles\"></i>\n <span>Generate {{ selectedItemIds.size }} image{{ selectedItemIds.size === 1 ? '' : 's' }}</span>\n </button>\n </div>\n </div>\n }\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]=\"{\n 'rtsee-ise-thumb--active': editor.isExpanded(item),\n 'rtsee-ise-thumb-card--selected': batchMode && isItemSelected(item.id)\n }\"\n [id]=\"'rtsee-ise-' + editor.section + '-' + item.id\"\n (click)=\"batchMode ? toggleItemSelection(item.id) : 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 @if (isItemGenerating(item.id)) {\n <div class=\"rtsee-ise-thumb-generating-overlay\">\n <i class=\"pi pi-spin pi-spinner\"></i>\n <span>Generating\u2026</span>\n </div>\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 @if (batchMode) {\n <div class=\"rtsee-ise-thumb-batch-checkbox\" (click)=\"toggleItemSelection(item.id); $event.stopPropagation()\">\n <input type=\"checkbox\" [checked]=\"isItemSelected(item.id)\" />\n </div>\n }\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" }]
|
|
4027
4508
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { editor: [{
|
|
4028
4509
|
type: Input,
|
|
4029
4510
|
args: [{ required: true }]
|
|
@@ -4190,6 +4671,11 @@ class InteractiveStoryEditorComponent {
|
|
|
4190
4671
|
this.cdr.markForCheck();
|
|
4191
4672
|
try {
|
|
4192
4673
|
await this.vm.updateSlideImage(slide, imageUrl);
|
|
4674
|
+
// Reset illustrator state and UI
|
|
4675
|
+
this.illustrator.resetState();
|
|
4676
|
+
if (typeof window !== 'undefined') {
|
|
4677
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.RESET_STATE));
|
|
4678
|
+
}
|
|
4193
4679
|
}
|
|
4194
4680
|
catch (e) {
|
|
4195
4681
|
console.error('Failed to apply image to slide:', e);
|