@rtsee/ngx 0.0.107 → 0.0.109
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.
|
@@ -18,7 +18,7 @@ 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
20
|
import { RTSeeChatMemberRoles, RTSeeIllustratorEvents, RTSeeChatTypes, OzzyTaskStatus } from '@rtsee/common';
|
|
21
|
-
import { ManageAgentForm, RTSeeForm, RTSeeFormFieldRadioGroup, RTSeeFormField, RTSeeFormFieldImageUploader, RTSeeRater } from '@rtsee/utilities-ui';
|
|
21
|
+
import { sanitizeImageUrl, ManageAgentForm, RTSeeForm, RTSeeFormFieldRadioGroup, RTSeeFormField, RTSeeFormFieldImageUploader, 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';
|
|
@@ -711,7 +711,11 @@ class RTSeeImageUploaderComponent {
|
|
|
711
711
|
if (response.reviewingGeneratedImage && response.imageUrl) {
|
|
712
712
|
// 1. If RTSeeIllustrator is in reviewingGeneratedImage mode, apply currently reviewed image to ImageUploader
|
|
713
713
|
this.submittingFromPainting = true;
|
|
714
|
-
this.imageUploader.applyImageUrl(response.imageUrl);
|
|
714
|
+
this.imageUploader.applyImageUrl(sanitizeImageUrl(response.imageUrl));
|
|
715
|
+
// Reset illustrator state and UI
|
|
716
|
+
if (typeof window !== 'undefined') {
|
|
717
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.RESET_STATE));
|
|
718
|
+
}
|
|
715
719
|
// and if Imageuploader is part of the form it should immediately submit the form
|
|
716
720
|
setTimeout(() => {
|
|
717
721
|
this.submitParentForm();
|
|
@@ -1884,6 +1888,7 @@ class MediaWidgetComponent {
|
|
|
1884
1888
|
event.stopPropagation();
|
|
1885
1889
|
event.preventDefault();
|
|
1886
1890
|
if (typeof window !== 'undefined' && img?.url) {
|
|
1891
|
+
// Retain AWS presigned URL so Illustrator can render the image preview!
|
|
1887
1892
|
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.SET_IMAGE_FOR_REVIEW, {
|
|
1888
1893
|
detail: {
|
|
1889
1894
|
imageUrl: img.url,
|
|
@@ -1893,6 +1898,23 @@ class MediaWidgetComponent {
|
|
|
1893
1898
|
}));
|
|
1894
1899
|
}
|
|
1895
1900
|
}
|
|
1901
|
+
addToContext(event, img) {
|
|
1902
|
+
event.stopPropagation();
|
|
1903
|
+
event.preventDefault();
|
|
1904
|
+
if (typeof window !== 'undefined' && img?.url) {
|
|
1905
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.ADD_IMAGE_TO_CONTEXT, {
|
|
1906
|
+
detail: {
|
|
1907
|
+
id: 'chat-img-' + Math.random().toString(36).substring(2, 9),
|
|
1908
|
+
imageUrl: img.url,
|
|
1909
|
+
title: img.name || 'Chat image',
|
|
1910
|
+
description: (typeof this.message.text === 'string' ? this.message.text : '') || '',
|
|
1911
|
+
visualDescription: '',
|
|
1912
|
+
sourceType: 'custom',
|
|
1913
|
+
active: true,
|
|
1914
|
+
},
|
|
1915
|
+
}));
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1896
1918
|
updateVisibleImages() {
|
|
1897
1919
|
const all = this.message.images || [];
|
|
1898
1920
|
if (this.showAll || all.length <= this.MAX_GRID) {
|
|
@@ -1903,13 +1925,24 @@ class MediaWidgetComponent {
|
|
|
1903
1925
|
this.visibleImages = all.slice(0, this.MAX_GRID);
|
|
1904
1926
|
this.hiddenCount = all.length - this.MAX_GRID;
|
|
1905
1927
|
}
|
|
1928
|
+
const reqId = this.message?.data?.requestId;
|
|
1929
|
+
if (reqId && this.visibleImages.length > 0 && typeof window !== 'undefined') {
|
|
1930
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.REQUESTED_GENERATION_SUCCEED, {
|
|
1931
|
+
detail: {
|
|
1932
|
+
requestId: reqId,
|
|
1933
|
+
imageUrl: this.visibleImages[0].url,
|
|
1934
|
+
messageId: this.message.id,
|
|
1935
|
+
chatId: this.chat?.id,
|
|
1936
|
+
},
|
|
1937
|
+
}));
|
|
1938
|
+
}
|
|
1906
1939
|
}
|
|
1907
1940
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MediaWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1908
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MediaWidgetComponent, isStandalone: true, selector: "rtsee-media-widget", inputs: { message: "message", messenger: "messenger", chat: "chat", showCost: "showCost" }, ngImport: i0, template: "<div class=\"rts-media-widget\">\n <!-- Video player -->\n @if (message.video) {\n <div class=\"rts-media-video\">\n <video\n controls\n playsinline\n preload=\"metadata\"\n [src]=\"message.video.url\"\n class=\"rts-video-player\"\n >\n Your browser does not support video playback.\n </video>\n </div>\n }\n\n <!-- Image grid -->\n @if (hasImages) {\n <div class=\"rts-media-images\" [ngClass]=\"gridClass\">\n @for (img of visibleImages; track img.url) {\n <div class=\"rts-media-image-wrapper\">\n <img [src]=\"img.url\" [alt]=\"img.name\" class=\"rts-media-image\" loading=\"lazy\" />\n <button\n
|
|
1941
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MediaWidgetComponent, isStandalone: true, selector: "rtsee-media-widget", inputs: { message: "message", messenger: "messenger", chat: "chat", showCost: "showCost" }, ngImport: i0, template: "<div class=\"rts-media-widget\">\n <!-- Video player -->\n @if (message.video) {\n <div class=\"rts-media-video\">\n <video\n controls\n playsinline\n preload=\"metadata\"\n [src]=\"message.video.url\"\n class=\"rts-video-player\"\n >\n Your browser does not support video playback.\n </video>\n </div>\n }\n\n <!-- Image grid -->\n @if (hasImages) {\n <div class=\"rts-media-images\" [ngClass]=\"gridClass\">\n @for (img of visibleImages; track img.url) {\n <div class=\"rts-media-image-wrapper\">\n <img [src]=\"img.url\" [alt]=\"img.name\" class=\"rts-media-image\" loading=\"lazy\" />\n <div 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-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"] }] }); }
|
|
1909
1942
|
}
|
|
1910
1943
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MediaWidgetComponent, decorators: [{
|
|
1911
1944
|
type: Component,
|
|
1912
|
-
args: [{ selector: 'rtsee-media-widget', standalone: true, imports: [NgClass, CostDisplayComponent], template: "<div class=\"rts-media-widget\">\n <!-- Video player -->\n @if (message.video) {\n <div class=\"rts-media-video\">\n <video\n controls\n playsinline\n preload=\"metadata\"\n [src]=\"message.video.url\"\n class=\"rts-video-player\"\n >\n Your browser does not support video playback.\n </video>\n </div>\n }\n\n <!-- Image grid -->\n @if (hasImages) {\n <div class=\"rts-media-images\" [ngClass]=\"gridClass\">\n @for (img of visibleImages; track img.url) {\n <div class=\"rts-media-image-wrapper\">\n <img [src]=\"img.url\" [alt]=\"img.name\" class=\"rts-media-image\" loading=\"lazy\" />\n <button\n
|
|
1945
|
+
args: [{ selector: 'rtsee-media-widget', standalone: true, imports: [NgClass, CostDisplayComponent], template: "<div class=\"rts-media-widget\">\n <!-- Video player -->\n @if (message.video) {\n <div class=\"rts-media-video\">\n <video\n controls\n playsinline\n preload=\"metadata\"\n [src]=\"message.video.url\"\n class=\"rts-video-player\"\n >\n Your browser does not support video playback.\n </video>\n </div>\n }\n\n <!-- Image grid -->\n @if (hasImages) {\n <div class=\"rts-media-images\" [ngClass]=\"gridClass\">\n @for (img of visibleImages; track img.url) {\n <div class=\"rts-media-image-wrapper\">\n <img [src]=\"img.url\" [alt]=\"img.name\" class=\"rts-media-image\" loading=\"lazy\" />\n <div 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-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"] }]
|
|
1913
1946
|
}], propDecorators: { message: [{
|
|
1914
1947
|
type: Input
|
|
1915
1948
|
}], messenger: [{
|
|
@@ -3858,11 +3891,11 @@ class StoryPlayerComponent {
|
|
|
3858
3891
|
this.story.initSwiper(swiper);
|
|
3859
3892
|
}
|
|
3860
3893
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryPlayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3861
|
-
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"] }] }); }
|
|
3894
|
+
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"] }] }); }
|
|
3862
3895
|
}
|
|
3863
3896
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryPlayerComponent, decorators: [{
|
|
3864
3897
|
type: Component,
|
|
3865
|
-
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" }]
|
|
3898
|
+
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" }]
|
|
3866
3899
|
}], ctorParameters: () => [], propDecorators: { story: [{
|
|
3867
3900
|
type: Input
|
|
3868
3901
|
}], settings: [{
|
|
@@ -3960,6 +3993,11 @@ class StoryElementsSectionComponent {
|
|
|
3960
3993
|
this.collapsed = false;
|
|
3961
3994
|
this.canDetach = true;
|
|
3962
3995
|
this.toggled = new EventEmitter();
|
|
3996
|
+
this.batchMode = false;
|
|
3997
|
+
this.selectedItemIds = new Set();
|
|
3998
|
+
this.batchAdditionalPrompt = '';
|
|
3999
|
+
this.generatingItemIds = new Set();
|
|
4000
|
+
this.activeGenerationListeners = new Map();
|
|
3963
4001
|
this.onIllustratorChanged = () => {
|
|
3964
4002
|
this.cdr.markForCheck();
|
|
3965
4003
|
};
|
|
@@ -3968,11 +4006,129 @@ class StoryElementsSectionComponent {
|
|
|
3968
4006
|
if (this._illustrator) {
|
|
3969
4007
|
this._illustrator.off('changed', this.onIllustratorChanged);
|
|
3970
4008
|
}
|
|
4009
|
+
for (const [requestId, listener] of this.activeGenerationListeners.entries()) {
|
|
4010
|
+
window.removeEventListener(RTSeeIllustrator.REQUESTED_GENERATION_SUCCEED, listener);
|
|
4011
|
+
}
|
|
4012
|
+
this.activeGenerationListeners.clear();
|
|
4013
|
+
}
|
|
4014
|
+
startBatchSelection(event) {
|
|
4015
|
+
event.stopPropagation();
|
|
4016
|
+
event.preventDefault();
|
|
4017
|
+
if (this.collapsed) {
|
|
4018
|
+
this.toggled.emit();
|
|
4019
|
+
}
|
|
4020
|
+
this.batchMode = true;
|
|
4021
|
+
this.selectedItemIds.clear();
|
|
4022
|
+
for (const item of this.editor.items) {
|
|
4023
|
+
const url = (item.imageUrl || '').toLowerCase();
|
|
4024
|
+
if (!url || url.includes('default')) {
|
|
4025
|
+
this.selectedItemIds.add(item.id);
|
|
4026
|
+
}
|
|
4027
|
+
}
|
|
4028
|
+
this.cdr.markForCheck();
|
|
4029
|
+
}
|
|
4030
|
+
cancelBatchSelection() {
|
|
4031
|
+
this.batchMode = false;
|
|
4032
|
+
this.selectedItemIds.clear();
|
|
4033
|
+
this.batchAdditionalPrompt = '';
|
|
4034
|
+
this.cdr.markForCheck();
|
|
4035
|
+
}
|
|
4036
|
+
toggleItemSelection(id) {
|
|
4037
|
+
if (this.selectedItemIds.has(id)) {
|
|
4038
|
+
this.selectedItemIds.delete(id);
|
|
4039
|
+
}
|
|
4040
|
+
else {
|
|
4041
|
+
this.selectedItemIds.add(id);
|
|
4042
|
+
}
|
|
4043
|
+
this.cdr.markForCheck();
|
|
4044
|
+
}
|
|
4045
|
+
isItemSelected(id) {
|
|
4046
|
+
return this.selectedItemIds.has(id);
|
|
4047
|
+
}
|
|
4048
|
+
isItemGenerating(id) {
|
|
4049
|
+
return this.generatingItemIds.has(id);
|
|
4050
|
+
}
|
|
4051
|
+
async submitBatchGeneration() {
|
|
4052
|
+
if (this.selectedItemIds.size === 0)
|
|
4053
|
+
return;
|
|
4054
|
+
const selectedItems = this.editor.items.filter((item) => this.selectedItemIds.has(item.id));
|
|
4055
|
+
const additionalPrompt = this.batchAdditionalPrompt.trim();
|
|
4056
|
+
this.batchMode = false;
|
|
4057
|
+
this.selectedItemIds.clear();
|
|
4058
|
+
this.batchAdditionalPrompt = '';
|
|
4059
|
+
this.cdr.markForCheck();
|
|
4060
|
+
for (const item of selectedItems) {
|
|
4061
|
+
const requestId = RTSeeCore.uuidv4();
|
|
4062
|
+
this.generatingItemIds.add(item.id);
|
|
4063
|
+
const listener = async (e) => {
|
|
4064
|
+
const customEvent = e;
|
|
4065
|
+
if (customEvent.detail?.requestId === requestId && customEvent.detail?.imageUrl) {
|
|
4066
|
+
window.removeEventListener(RTSeeIllustrator.REQUESTED_GENERATION_SUCCEED, listener);
|
|
4067
|
+
this.activeGenerationListeners.delete(requestId);
|
|
4068
|
+
this.generatingItemIds.delete(item.id);
|
|
4069
|
+
const cleanUrl = sanitizeImageUrl(customEvent.detail.imageUrl);
|
|
4070
|
+
try {
|
|
4071
|
+
item.imageUrl = cleanUrl;
|
|
4072
|
+
await item.save({ imageUrl: cleanUrl });
|
|
4073
|
+
if (this.editor.expanded && this.editor.expanded.id === item.id && this.editor.form) {
|
|
4074
|
+
const imageField = this.editor.form.fields.find((f) => f.name === 'imageUrl' || f.type === 'image-uploader');
|
|
4075
|
+
if (imageField) {
|
|
4076
|
+
imageField.value = cleanUrl;
|
|
4077
|
+
if (imageField.imageUploader) {
|
|
4078
|
+
imageField.imageUploader.uploadedPhotoPreview = cleanUrl;
|
|
4079
|
+
imageField.imageUploader.value = cleanUrl;
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
}
|
|
4084
|
+
catch (err) {
|
|
4085
|
+
console.error(`Failed to apply generated image to ${this.editor.label}:`, err);
|
|
4086
|
+
}
|
|
4087
|
+
finally {
|
|
4088
|
+
this.cdr.markForCheck();
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
};
|
|
4092
|
+
window.addEventListener(RTSeeIllustrator.REQUESTED_GENERATION_SUCCEED, listener);
|
|
4093
|
+
this.activeGenerationListeners.set(requestId, listener);
|
|
4094
|
+
const promptParts = [];
|
|
4095
|
+
promptParts.push(`${this.editor.label}: ${item.name || ''}`);
|
|
4096
|
+
if (item.visualDescription) {
|
|
4097
|
+
promptParts.push(`Visual appearance: ${item.visualDescription}`);
|
|
4098
|
+
}
|
|
4099
|
+
if (item.description && item.description !== item.visualDescription) {
|
|
4100
|
+
promptParts.push(`Description/Role: ${item.description}`);
|
|
4101
|
+
}
|
|
4102
|
+
if (additionalPrompt) {
|
|
4103
|
+
promptParts.push(`Additional prompt: ${additionalPrompt}`);
|
|
4104
|
+
}
|
|
4105
|
+
const entityPrompt = promptParts.join('\n');
|
|
4106
|
+
const config = this.illustrator?.config || {
|
|
4107
|
+
aspectRatio: '1:1',
|
|
4108
|
+
style: 'Classic Fairy Tale pixel-art Storybook',
|
|
4109
|
+
mood: 'Dreamy & Magical',
|
|
4110
|
+
lighting: 'Soft Diffused Storybook Glow',
|
|
4111
|
+
negativePrompt: 'modern elements, cars, text, watermark, signature, blurry, low quality',
|
|
4112
|
+
numberOfImages: 1,
|
|
4113
|
+
};
|
|
4114
|
+
const payload = {
|
|
4115
|
+
chatId: this.illustrator?.activeChatId || undefined,
|
|
4116
|
+
agentId: this.illustrator?.activeAgentId || '',
|
|
4117
|
+
prompt: entityPrompt,
|
|
4118
|
+
config: { ...config },
|
|
4119
|
+
contextImages: [],
|
|
4120
|
+
requestId,
|
|
4121
|
+
};
|
|
4122
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.SUBMIT_PROMPT, {
|
|
4123
|
+
detail: payload,
|
|
4124
|
+
}));
|
|
4125
|
+
}
|
|
4126
|
+
this.cdr.markForCheck();
|
|
3971
4127
|
}
|
|
3972
4128
|
async applyReviewedImageToItem(event, item) {
|
|
3973
4129
|
event.stopPropagation();
|
|
3974
4130
|
event.preventDefault();
|
|
3975
|
-
const imageUrl = this._illustrator?.currentGeneratedImageUrl;
|
|
4131
|
+
const imageUrl = sanitizeImageUrl(this._illustrator?.currentGeneratedImageUrl);
|
|
3976
4132
|
if (!imageUrl)
|
|
3977
4133
|
return;
|
|
3978
4134
|
this.cdr.markForCheck();
|
|
@@ -3987,6 +4143,11 @@ class StoryElementsSectionComponent {
|
|
|
3987
4143
|
}
|
|
3988
4144
|
}
|
|
3989
4145
|
}
|
|
4146
|
+
// Reset illustrator state and UI
|
|
4147
|
+
this._illustrator?.resetState();
|
|
4148
|
+
if (typeof window !== 'undefined') {
|
|
4149
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.RESET_STATE));
|
|
4150
|
+
}
|
|
3990
4151
|
}
|
|
3991
4152
|
catch (e) {
|
|
3992
4153
|
console.error(`Failed to apply image to ${this.editor.label}:`, e);
|
|
@@ -4018,11 +4179,11 @@ class StoryElementsSectionComponent {
|
|
|
4018
4179
|
return item.id || `new-${index}`;
|
|
4019
4180
|
}
|
|
4020
4181
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryElementsSectionComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4021
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: StoryElementsSectionComponent, isStandalone: true, selector: "rtsee-story-elements-section", inputs: { editor: "editor", title: "title", icon: "icon", collapsed: "collapsed", canDetach: "canDetach", illustrator: "illustrator" }, outputs: { toggled: "toggled" }, ngImport: i0, template: "<section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': collapsed }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\"\n class=\"rtsee-ise-section-toggle\"\n [attr.aria-expanded]=\"!collapsed\"\n [id]=\"'rtsee-ise-toggle-' + editor.section\"\n (click)=\"toggled.emit()\">\n <i class=\"rtsee-ise-section-icon\" [ngClass]=\"icon\"></i>\n <h3 class=\"rtsee-ise-section-title\">{{ title }}</h3>\n <span class=\"rtsee-ise-section-count\">{{ editor.items.length }}</span>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!collapsed) {\n <div class=\"rtsee-ise-section-body\">\n <div class=\"rtsee-ise-thumbs-grid\">\n @for (item of editor.items; track trackById($index, item)) {\n <div class=\"rtsee-ise-thumb-card-container\" style=\"position: relative; display: flex; flex-direction: column;\">\n <button type=\"button\"\n class=\"rtsee-ise-thumb\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': editor.isExpanded(item) }\"\n [id]=\"'rtsee-ise-' + editor.section + '-' + item.id\"\n (click)=\"editor.expand(item)\">\n <div class=\"rtsee-ise-thumb-image\">\n @if (item.imageUrl) {\n <img [src]=\"item.imageUrl\" [alt]=\"item.name\" loading=\"lazy\" />\n } @else {\n <i [ngClass]=\"icon\"></i>\n }\n </div>\n <div class=\"rtsee-ise-thumb-body\">\n <span class=\"rtsee-ise-thumb-name\">{{ item.name }}</span>\n <span class=\"rtsee-ise-thumb-description\">{{ item.getTruncatedDescription(90) }}</span>\n </div>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n style=\"position: absolute; top: 8px; right: 8px;\"\n title=\"Add {{ item.name }} to Illustrator context\"\n (click)=\"addToIllustrator($event, item)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n @if (illustrator?.reviewingGeneratedImage && illustrator?.currentGeneratedImageUrl) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-quick-apply\"\n style=\"position: absolute; bottom: 8px; right: 8px;\"\n [disabled]=\"item.saveInProgress\"\n [title]=\"'Apply reviewed image to ' + item.name\"\n (click)=\"applyReviewedImageToItem($event, item)\">\n @if (item.saveInProgress) {\n <i class=\"pi pi-spin pi-spinner\"></i>\n } @else {\n <i class=\"pi pi-plus\"></i>\n }\n </button>\n }\n </div>\n }\n\n <button type=\"button\"\n class=\"rtsee-ise-thumb rtsee-ise-thumb--add\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': editor.isCreating }\"\n [id]=\"'rtsee-ise-add-' + editor.section\"\n (click)=\"editor.expandNew()\">\n <i class=\"pi pi-plus\"></i>\n <span>New {{ editor.label }}</span>\n </button>\n </div>\n\n @if (editor.expanded && editor.form) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n <div class=\"rtsee-ise-expanded-header\">\n <h4>{{ editor.expanded.isNew ? 'New ' + editor.label : editor.expanded.name }}</h4>\n <div style=\"display: flex; align-items: center; gap: 8px;\">\n @if (!editor.expanded.isNew) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n title=\"Add to Illustrator context\"\n (click)=\"addToIllustrator($event, editor.expanded)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8 Illustrator</span>\n </button>\n }\n <button type=\"button\" class=\"rtsee-ise-icon-button\" (click)=\"editor.collapse()\" aria-label=\"Close\">\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </div>\n\n @if (editor.error) {\n <div class=\"rtsee-ise-error\">{{ editor.error }}</div>\n }\n\n <rtsee-form [form]=\"editor.form\" (formSubmit)=\"submit()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\"\n [label]=\"editor.expanded.isNew ? 'Create' : 'Save'\"\n [loading]=\"editor.saveInProgress\"\n [disabled]=\"editor.busy\" />\n <p-button label=\"Cancel\"\n severity=\"secondary\"\n (click)=\"editor.collapse()\"\n [disabled]=\"editor.busy\" />\n @if (!editor.expanded.isNew) {\n <span class=\"rtsee-ise-actions-spacer\"></span>\n @if (canDetach) {\n <p-button label=\"Remove from story\"\n icon=\"pi pi-minus-circle\"\n severity=\"secondary\"\n [text]=\"true\"\n (click)=\"editor.detach(editor.expanded)\"\n [disabled]=\"editor.busy\" />\n }\n <p-button label=\"Delete\"\n icon=\"pi pi-trash\"\n severity=\"danger\"\n [text]=\"true\"\n [loading]=\"editor.removeInProgress\"\n (click)=\"editor.delete(editor.expanded)\"\n [disabled]=\"editor.busy\" />\n }\n </div>\n </rtsee-form>\n </div>\n }\n </div>\n }\n</section>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: FormComponent, selector: "rtsee-form", inputs: ["form"], outputs: ["formSubmit"] }] }); }
|
|
4182
|
+
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"] }] }); }
|
|
4022
4183
|
}
|
|
4023
4184
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryElementsSectionComponent, decorators: [{
|
|
4024
4185
|
type: Component,
|
|
4025
|
-
args: [{ selector: "rtsee-story-elements-section", standalone: true, imports: [NgClass, Button, FormComponent], template: "<section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': collapsed }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\"\n class=\"rtsee-ise-section-toggle\"\n [attr.aria-expanded]=\"!collapsed\"\n [id]=\"'rtsee-ise-toggle-' + editor.section\"\n (click)=\"toggled.emit()\">\n <i class=\"rtsee-ise-section-icon\" [ngClass]=\"icon\"></i>\n <h3 class=\"rtsee-ise-section-title\">{{ title }}</h3>\n <span class=\"rtsee-ise-section-count\">{{ editor.items.length }}</span>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!collapsed) {\n <div class=\"rtsee-ise-section-body\">\n <div class=\"rtsee-ise-thumbs-grid\">\n @for (item of editor.items; track trackById($index, item)) {\n <div class=\"rtsee-ise-thumb-card-container\" style=\"position: relative; display: flex; flex-direction: column;\">\n <button type=\"button\"\n class=\"rtsee-ise-thumb\"\n [ngClass]=\"{
|
|
4186
|
+
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" }]
|
|
4026
4187
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { editor: [{
|
|
4027
4188
|
type: Input,
|
|
4028
4189
|
args: [{ required: true }]
|
|
@@ -4182,13 +4343,18 @@ class InteractiveStoryEditorComponent {
|
|
|
4182
4343
|
async applyReviewedImageToSlide(event, slide) {
|
|
4183
4344
|
event.stopPropagation();
|
|
4184
4345
|
event.preventDefault();
|
|
4185
|
-
const imageUrl = this.illustrator.currentGeneratedImageUrl;
|
|
4346
|
+
const imageUrl = sanitizeImageUrl(this.illustrator.currentGeneratedImageUrl);
|
|
4186
4347
|
if (!imageUrl || !slide.id)
|
|
4187
4348
|
return;
|
|
4188
4349
|
this.slideUpdatingIds.add(slide.id);
|
|
4189
4350
|
this.cdr.markForCheck();
|
|
4190
4351
|
try {
|
|
4191
4352
|
await this.vm.updateSlideImage(slide, imageUrl);
|
|
4353
|
+
// Reset illustrator state and UI
|
|
4354
|
+
this.illustrator.resetState();
|
|
4355
|
+
if (typeof window !== 'undefined') {
|
|
4356
|
+
window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.RESET_STATE));
|
|
4357
|
+
}
|
|
4192
4358
|
}
|
|
4193
4359
|
catch (e) {
|
|
4194
4360
|
console.error('Failed to apply image to slide:', e);
|