@rtsee/ngx 0.0.106 → 0.0.108

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,7 @@ 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
715
  // and if Imageuploader is part of the form it should immediately submit the form
716
716
  setTimeout(() => {
717
717
  this.submitParentForm();
@@ -1880,6 +1880,20 @@ class MediaWidgetComponent {
1880
1880
  this.showAll = !this.showAll;
1881
1881
  this.updateVisibleImages();
1882
1882
  }
1883
+ sendToIllustrator(event, img) {
1884
+ event.stopPropagation();
1885
+ event.preventDefault();
1886
+ if (typeof window !== 'undefined' && img?.url) {
1887
+ const cleanUrl = sanitizeImageUrl(img.url);
1888
+ window.dispatchEvent(new CustomEvent(RTSeeIllustratorEvents.SET_IMAGE_FOR_REVIEW, {
1889
+ detail: {
1890
+ imageUrl: cleanUrl,
1891
+ prompt: img.name || (typeof this.message.text === 'string' ? this.message.text : '') || '',
1892
+ source: 'messenger',
1893
+ },
1894
+ }));
1895
+ }
1896
+ }
1883
1897
  updateVisibleImages() {
1884
1898
  const all = this.message.images || [];
1885
1899
  if (this.showAll || all.length <= this.MAX_GRID) {
@@ -1892,11 +1906,11 @@ class MediaWidgetComponent {
1892
1906
  }
1893
1907
  }
1894
1908
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MediaWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1895
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: MediaWidgetComponent, isStandalone: true, selector: "rtsee-media-widget", inputs: { message: "message", messenger: "messenger", chat: "chat", showCost: "showCost" }, ngImport: i0, template: "<div class=\"rts-media-widget\">\n <!-- Video player -->\n @if (message.video) {\n <div class=\"rts-media-video\">\n <video\n controls\n playsinline\n preload=\"metadata\"\n [src]=\"message.video.url\"\n class=\"rts-video-player\"\n >\n Your browser does not support video playback.\n </video>\n </div>\n }\n\n <!-- Image grid -->\n @if (hasImages) {\n <div class=\"rts-media-images\" [ngClass]=\"gridClass\">\n @for (img of visibleImages; track img.url) {\n <div class=\"rts-media-image-wrapper\">\n <img [src]=\"img.url\" [alt]=\"img.name\" class=\"rts-media-image\" loading=\"lazy\" />\n </div>\n }\n </div>\n }\n\n <!-- Show more / less toggle -->\n @if (hiddenCount > 0 || showAll) {\n <button class=\"rts-media-toggle\" (click)=\"toggleShowAll()\">\n {{ showAll ? 'Show less' : 'Show ' + hiddenCount + ' more' }}\n </button>\n }\n\n <!-- Cost display (optional, disabled when nested inside agentic widget) -->\n @if (showCost && message.cost) {\n <div class=\"rts-media-cost\">\n <rtsee-cost-display [cost]=\"message.cost\"></rtsee-cost-display>\n </div>\n }\n</div>\n", styles: [".rts-media-widget{max-width:100%}.rts-media-video{border-radius:8px;overflow:hidden;margin-bottom:6px}.rts-video-player{width:100%;max-height:360px;border-radius:8px;background:#000;display:block}.rts-media-images{display:grid;gap:4px;border-radius:8px;overflow:hidden;margin-bottom:4px}.rts-media-grid-1{grid-template-columns:1fr}.rts-media-grid-2{grid-template-columns:1fr 1fr}.rts-media-grid-4{grid-template-columns:1fr 1fr;grid-template-rows:auto auto}.rts-media-image-wrapper{position:relative;overflow:hidden;border-radius:6px;background:var(--rts-bg-secondary, #1e1e2e)}.rts-media-image{width:100%;height:auto;max-height:280px;object-fit:cover;display:block;transition:transform .2s ease;cursor:pointer}.rts-media-image:hover{transform:scale(1.02)}.rts-media-grid-1 .rts-media-image{max-height:400px;object-fit:contain}.rts-media-toggle{display:block;width:100%;padding:6px 0;border:none;background:none;color:var(--rts-agent-accent, #8b5cf6);font-size:12px;font-weight:500;cursor:pointer;text-align:center;transition:opacity .15s ease}.rts-media-toggle:hover{opacity:.8}.rts-media-cost{display:flex;justify-content:flex-end;padding-top:4px}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: CostDisplayComponent, selector: "rtsee-cost-display", inputs: ["cost"] }] }); }
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.url\" [alt]=\"img.name\" class=\"rts-media-image\" loading=\"lazy\" />\n <button\n type=\"button\"\n class=\"rts-media-btn-paint\"\n title=\"Send image to Illustrator\"\n (click)=\"sendToIllustrator($event, img)\"\n >\n <i class=\"pi pi-palette\"></i>\n <span>+ paint</span>\n </button>\n </div>\n }\n </div>\n }\n\n <!-- Show more / less toggle -->\n @if (hiddenCount > 0 || showAll) {\n <button class=\"rts-media-toggle\" (click)=\"toggleShowAll()\">\n {{ showAll ? 'Show less' : 'Show ' + hiddenCount + ' more' }}\n </button>\n }\n\n <!-- Cost display (optional, disabled when nested inside agentic widget) -->\n @if (showCost && message.cost) {\n <div class=\"rts-media-cost\">\n <rtsee-cost-display [cost]=\"message.cost\"></rtsee-cost-display>\n </div>\n }\n</div>\n", styles: [".rts-media-widget{max-width:100%}.rts-media-video{border-radius:8px;overflow:hidden;margin-bottom:6px}.rts-video-player{width:100%;max-height:360px;border-radius:8px;background:#000;display:block}.rts-media-images{display:grid;gap:4px;border-radius:8px;overflow:hidden;margin-bottom:4px}.rts-media-grid-1{grid-template-columns:1fr}.rts-media-grid-2{grid-template-columns:1fr 1fr}.rts-media-grid-4{grid-template-columns:1fr 1fr;grid-template-rows:auto auto}.rts-media-image-wrapper{position:relative;overflow:hidden;border-radius:6px;background:var(--rts-bg-secondary, #1e1e2e)}.rts-media-btn-paint{position:absolute;top:8px;right:8px;z-index:5;display:inline-flex;align-items:center;gap:4px;padding:4px 8px;background:#12121cd9;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);color:#e9d5ff;border:1px solid rgba(168,85,247,.45);border-radius:6px;font-size:11px;font-weight:600;cursor:pointer;transition:all .2s cubic-bezier(.34,1.56,.64,1);box-shadow:0 2px 8px #00000080}.rts-media-btn-paint i{font-size:11px;color:#c084fc}.rts-media-btn-paint span{line-height:1}.rts-media-btn-paint:hover{background:#9333eae6;color:#fff;border-color:#a855f7;transform:translateY(-1px) scale(1.04);box-shadow:0 4px 12px #a855f773}.rts-media-btn-paint:hover i{color:#fff}.rts-media-btn-paint:active{transform:translateY(0) scale(.98)}.rts-media-image{width:100%;height:auto;max-height:280px;object-fit:cover;display:block;transition:transform .2s ease;cursor:pointer}.rts-media-image:hover{transform:scale(1.02)}.rts-media-grid-1 .rts-media-image{max-height:400px;object-fit:contain}.rts-media-toggle{display:block;width:100%;padding:6px 0;border:none;background:none;color:var(--rts-agent-accent, #8b5cf6);font-size:12px;font-weight:500;cursor:pointer;text-align:center;transition:opacity .15s ease}.rts-media-toggle:hover{opacity:.8}.rts-media-cost{display:flex;justify-content:flex-end;padding-top:4px}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: CostDisplayComponent, selector: "rtsee-cost-display", inputs: ["cost"] }] }); }
1896
1910
  }
1897
1911
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: MediaWidgetComponent, decorators: [{
1898
1912
  type: Component,
1899
- args: [{ selector: 'rtsee-media-widget', standalone: true, imports: [NgClass, CostDisplayComponent], template: "<div class=\"rts-media-widget\">\n <!-- Video player -->\n @if (message.video) {\n <div class=\"rts-media-video\">\n <video\n controls\n playsinline\n preload=\"metadata\"\n [src]=\"message.video.url\"\n class=\"rts-video-player\"\n >\n Your browser does not support video playback.\n </video>\n </div>\n }\n\n <!-- Image grid -->\n @if (hasImages) {\n <div class=\"rts-media-images\" [ngClass]=\"gridClass\">\n @for (img of visibleImages; track img.url) {\n <div class=\"rts-media-image-wrapper\">\n <img [src]=\"img.url\" [alt]=\"img.name\" class=\"rts-media-image\" loading=\"lazy\" />\n </div>\n }\n </div>\n }\n\n <!-- Show more / less toggle -->\n @if (hiddenCount > 0 || showAll) {\n <button class=\"rts-media-toggle\" (click)=\"toggleShowAll()\">\n {{ showAll ? 'Show less' : 'Show ' + hiddenCount + ' more' }}\n </button>\n }\n\n <!-- Cost display (optional, disabled when nested inside agentic widget) -->\n @if (showCost && message.cost) {\n <div class=\"rts-media-cost\">\n <rtsee-cost-display [cost]=\"message.cost\"></rtsee-cost-display>\n </div>\n }\n</div>\n", styles: [".rts-media-widget{max-width:100%}.rts-media-video{border-radius:8px;overflow:hidden;margin-bottom:6px}.rts-video-player{width:100%;max-height:360px;border-radius:8px;background:#000;display:block}.rts-media-images{display:grid;gap:4px;border-radius:8px;overflow:hidden;margin-bottom:4px}.rts-media-grid-1{grid-template-columns:1fr}.rts-media-grid-2{grid-template-columns:1fr 1fr}.rts-media-grid-4{grid-template-columns:1fr 1fr;grid-template-rows:auto auto}.rts-media-image-wrapper{position:relative;overflow:hidden;border-radius:6px;background:var(--rts-bg-secondary, #1e1e2e)}.rts-media-image{width:100%;height:auto;max-height:280px;object-fit:cover;display:block;transition:transform .2s ease;cursor:pointer}.rts-media-image:hover{transform:scale(1.02)}.rts-media-grid-1 .rts-media-image{max-height:400px;object-fit:contain}.rts-media-toggle{display:block;width:100%;padding:6px 0;border:none;background:none;color:var(--rts-agent-accent, #8b5cf6);font-size:12px;font-weight:500;cursor:pointer;text-align:center;transition:opacity .15s ease}.rts-media-toggle:hover{opacity:.8}.rts-media-cost{display:flex;justify-content:flex-end;padding-top:4px}\n"] }]
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.url\" [alt]=\"img.name\" class=\"rts-media-image\" loading=\"lazy\" />\n <button\n type=\"button\"\n class=\"rts-media-btn-paint\"\n title=\"Send image to Illustrator\"\n (click)=\"sendToIllustrator($event, img)\"\n >\n <i class=\"pi pi-palette\"></i>\n <span>+ paint</span>\n </button>\n </div>\n }\n </div>\n }\n\n <!-- Show more / less toggle -->\n @if (hiddenCount > 0 || showAll) {\n <button class=\"rts-media-toggle\" (click)=\"toggleShowAll()\">\n {{ showAll ? 'Show less' : 'Show ' + hiddenCount + ' more' }}\n </button>\n }\n\n <!-- Cost display (optional, disabled when nested inside agentic widget) -->\n @if (showCost && message.cost) {\n <div class=\"rts-media-cost\">\n <rtsee-cost-display [cost]=\"message.cost\"></rtsee-cost-display>\n </div>\n }\n</div>\n", styles: [".rts-media-widget{max-width:100%}.rts-media-video{border-radius:8px;overflow:hidden;margin-bottom:6px}.rts-video-player{width:100%;max-height:360px;border-radius:8px;background:#000;display:block}.rts-media-images{display:grid;gap:4px;border-radius:8px;overflow:hidden;margin-bottom:4px}.rts-media-grid-1{grid-template-columns:1fr}.rts-media-grid-2{grid-template-columns:1fr 1fr}.rts-media-grid-4{grid-template-columns:1fr 1fr;grid-template-rows:auto auto}.rts-media-image-wrapper{position:relative;overflow:hidden;border-radius:6px;background:var(--rts-bg-secondary, #1e1e2e)}.rts-media-btn-paint{position:absolute;top:8px;right:8px;z-index:5;display:inline-flex;align-items:center;gap:4px;padding:4px 8px;background:#12121cd9;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);color:#e9d5ff;border:1px solid rgba(168,85,247,.45);border-radius:6px;font-size:11px;font-weight:600;cursor:pointer;transition:all .2s cubic-bezier(.34,1.56,.64,1);box-shadow:0 2px 8px #00000080}.rts-media-btn-paint i{font-size:11px;color:#c084fc}.rts-media-btn-paint span{line-height:1}.rts-media-btn-paint:hover{background:#9333eae6;color:#fff;border-color:#a855f7;transform:translateY(-1px) scale(1.04);box-shadow:0 4px 12px #a855f773}.rts-media-btn-paint:hover i{color:#fff}.rts-media-btn-paint:active{transform:translateY(0) scale(.98)}.rts-media-image{width:100%;height:auto;max-height:280px;object-fit:cover;display:block;transition:transform .2s ease;cursor:pointer}.rts-media-image:hover{transform:scale(1.02)}.rts-media-grid-1 .rts-media-image{max-height:400px;object-fit:contain}.rts-media-toggle{display:block;width:100%;padding:6px 0;border:none;background:none;color:var(--rts-agent-accent, #8b5cf6);font-size:12px;font-weight:500;cursor:pointer;text-align:center;transition:opacity .15s ease}.rts-media-toggle:hover{opacity:.8}.rts-media-cost{display:flex;justify-content:flex-end;padding-top:4px}\n"] }]
1900
1914
  }], propDecorators: { message: [{
1901
1915
  type: Input
1902
1916
  }], messenger: [{
@@ -3928,11 +3942,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
3928
3942
  * All the logic lives in RTSeeStoryElementsEditor.
3929
3943
  */
3930
3944
  class StoryElementsSectionComponent {
3931
- constructor() {
3945
+ set illustrator(val) {
3946
+ if (this._illustrator) {
3947
+ this._illustrator.off('changed', this.onIllustratorChanged);
3948
+ }
3949
+ this._illustrator = val;
3950
+ if (this._illustrator) {
3951
+ this._illustrator.on('changed', this.onIllustratorChanged);
3952
+ }
3953
+ this.cdr.markForCheck();
3954
+ }
3955
+ get illustrator() {
3956
+ return this._illustrator;
3957
+ }
3958
+ constructor(cdr) {
3959
+ this.cdr = cdr;
3932
3960
  this.icon = "pi pi-box";
3933
3961
  this.collapsed = false;
3934
3962
  this.canDetach = true;
3935
3963
  this.toggled = new EventEmitter();
3964
+ this.onIllustratorChanged = () => {
3965
+ this.cdr.markForCheck();
3966
+ };
3967
+ }
3968
+ ngOnDestroy() {
3969
+ if (this._illustrator) {
3970
+ this._illustrator.off('changed', this.onIllustratorChanged);
3971
+ }
3972
+ }
3973
+ async applyReviewedImageToItem(event, item) {
3974
+ event.stopPropagation();
3975
+ event.preventDefault();
3976
+ const imageUrl = sanitizeImageUrl(this._illustrator?.currentGeneratedImageUrl);
3977
+ if (!imageUrl)
3978
+ return;
3979
+ this.cdr.markForCheck();
3980
+ try {
3981
+ await item.save({ imageUrl });
3982
+ if (this.editor.expanded && this.editor.expanded.id === item.id && this.editor.form) {
3983
+ const imageField = this.editor.form.fields.find((f) => f.name === 'imageUrl' || f.type === 'image-uploader');
3984
+ if (imageField) {
3985
+ imageField.value = imageUrl;
3986
+ if (imageField.imageUploader) {
3987
+ imageField.imageUploader.uploadedPhotoPreview = imageUrl;
3988
+ }
3989
+ }
3990
+ }
3991
+ }
3992
+ catch (e) {
3993
+ console.error(`Failed to apply image to ${this.editor.label}:`, e);
3994
+ }
3995
+ finally {
3996
+ this.cdr.markForCheck();
3997
+ }
3936
3998
  }
3937
3999
  submit() {
3938
4000
  this.editor.submit();
@@ -3956,13 +4018,13 @@ class StoryElementsSectionComponent {
3956
4018
  trackById(index, item) {
3957
4019
  return item.id || `new-${index}`;
3958
4020
  }
3959
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryElementsSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3960
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: StoryElementsSectionComponent, isStandalone: true, selector: "rtsee-story-elements-section", inputs: { editor: "editor", title: "title", icon: "icon", collapsed: "collapsed", canDetach: "canDetach" }, outputs: { toggled: "toggled" }, ngImport: i0, template: "<section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': collapsed }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\"\n class=\"rtsee-ise-section-toggle\"\n [attr.aria-expanded]=\"!collapsed\"\n [id]=\"'rtsee-ise-toggle-' + editor.section\"\n (click)=\"toggled.emit()\">\n <i class=\"rtsee-ise-section-icon\" [ngClass]=\"icon\"></i>\n <h3 class=\"rtsee-ise-section-title\">{{ title }}</h3>\n <span class=\"rtsee-ise-section-count\">{{ editor.items.length }}</span>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!collapsed) {\n <div class=\"rtsee-ise-section-body\">\n <div class=\"rtsee-ise-thumbs-grid\">\n @for (item of editor.items; track trackById($index, item)) {\n <div class=\"rtsee-ise-thumb-card-container\" style=\"position: relative; display: flex; flex-direction: column;\">\n <button type=\"button\"\n class=\"rtsee-ise-thumb\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': editor.isExpanded(item) }\"\n [id]=\"'rtsee-ise-' + editor.section + '-' + item.id\"\n (click)=\"editor.expand(item)\">\n <div class=\"rtsee-ise-thumb-image\">\n @if (item.imageUrl) {\n <img [src]=\"item.imageUrl\" [alt]=\"item.name\" loading=\"lazy\" />\n } @else {\n <i [ngClass]=\"icon\"></i>\n }\n </div>\n <div class=\"rtsee-ise-thumb-body\">\n <span class=\"rtsee-ise-thumb-name\">{{ item.name }}</span>\n <span class=\"rtsee-ise-thumb-description\">{{ item.getTruncatedDescription(90) }}</span>\n </div>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n style=\"position: absolute; top: 8px; right: 8px;\"\n title=\"Add {{ item.name }} to Illustrator context\"\n (click)=\"addToIllustrator($event, item)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n </div>\n }\n\n <button type=\"button\"\n class=\"rtsee-ise-thumb rtsee-ise-thumb--add\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': editor.isCreating }\"\n [id]=\"'rtsee-ise-add-' + editor.section\"\n (click)=\"editor.expandNew()\">\n <i class=\"pi pi-plus\"></i>\n <span>New {{ editor.label }}</span>\n </button>\n </div>\n\n @if (editor.expanded && editor.form) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n <div class=\"rtsee-ise-expanded-header\">\n <h4>{{ editor.expanded.isNew ? 'New ' + editor.label : editor.expanded.name }}</h4>\n <div style=\"display: flex; align-items: center; gap: 8px;\">\n @if (!editor.expanded.isNew) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n title=\"Add to Illustrator context\"\n (click)=\"addToIllustrator($event, editor.expanded)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8 Illustrator</span>\n </button>\n }\n <button type=\"button\" class=\"rtsee-ise-icon-button\" (click)=\"editor.collapse()\" aria-label=\"Close\">\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </div>\n\n @if (editor.error) {\n <div class=\"rtsee-ise-error\">{{ editor.error }}</div>\n }\n\n <rtsee-form [form]=\"editor.form\" (formSubmit)=\"submit()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\"\n [label]=\"editor.expanded.isNew ? 'Create' : 'Save'\"\n [loading]=\"editor.saveInProgress\"\n [disabled]=\"editor.busy\" />\n <p-button label=\"Cancel\"\n severity=\"secondary\"\n (click)=\"editor.collapse()\"\n [disabled]=\"editor.busy\" />\n @if (!editor.expanded.isNew) {\n <span class=\"rtsee-ise-actions-spacer\"></span>\n @if (canDetach) {\n <p-button label=\"Remove from story\"\n icon=\"pi pi-minus-circle\"\n severity=\"secondary\"\n [text]=\"true\"\n (click)=\"editor.detach(editor.expanded)\"\n [disabled]=\"editor.busy\" />\n }\n <p-button label=\"Delete\"\n icon=\"pi pi-trash\"\n severity=\"danger\"\n [text]=\"true\"\n [loading]=\"editor.removeInProgress\"\n (click)=\"editor.delete(editor.expanded)\"\n [disabled]=\"editor.busy\" />\n }\n </div>\n </rtsee-form>\n </div>\n }\n </div>\n }\n</section>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: FormComponent, selector: "rtsee-form", inputs: ["form"], outputs: ["formSubmit"] }] }); }
4021
+ 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"] }] }); }
3961
4023
  }
3962
4024
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StoryElementsSectionComponent, decorators: [{
3963
4025
  type: Component,
3964
- args: [{ selector: "rtsee-story-elements-section", standalone: true, imports: [NgClass, Button, FormComponent], template: "<section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': collapsed }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\"\n class=\"rtsee-ise-section-toggle\"\n [attr.aria-expanded]=\"!collapsed\"\n [id]=\"'rtsee-ise-toggle-' + editor.section\"\n (click)=\"toggled.emit()\">\n <i class=\"rtsee-ise-section-icon\" [ngClass]=\"icon\"></i>\n <h3 class=\"rtsee-ise-section-title\">{{ title }}</h3>\n <span class=\"rtsee-ise-section-count\">{{ editor.items.length }}</span>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!collapsed) {\n <div class=\"rtsee-ise-section-body\">\n <div class=\"rtsee-ise-thumbs-grid\">\n @for (item of editor.items; track trackById($index, item)) {\n <div class=\"rtsee-ise-thumb-card-container\" style=\"position: relative; display: flex; flex-direction: column;\">\n <button type=\"button\"\n class=\"rtsee-ise-thumb\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': editor.isExpanded(item) }\"\n [id]=\"'rtsee-ise-' + editor.section + '-' + item.id\"\n (click)=\"editor.expand(item)\">\n <div class=\"rtsee-ise-thumb-image\">\n @if (item.imageUrl) {\n <img [src]=\"item.imageUrl\" [alt]=\"item.name\" loading=\"lazy\" />\n } @else {\n <i [ngClass]=\"icon\"></i>\n }\n </div>\n <div class=\"rtsee-ise-thumb-body\">\n <span class=\"rtsee-ise-thumb-name\">{{ item.name }}</span>\n <span class=\"rtsee-ise-thumb-description\">{{ item.getTruncatedDescription(90) }}</span>\n </div>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n style=\"position: absolute; top: 8px; right: 8px;\"\n title=\"Add {{ item.name }} to Illustrator context\"\n (click)=\"addToIllustrator($event, item)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n </div>\n }\n\n <button type=\"button\"\n class=\"rtsee-ise-thumb rtsee-ise-thumb--add\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': editor.isCreating }\"\n [id]=\"'rtsee-ise-add-' + editor.section\"\n (click)=\"editor.expandNew()\">\n <i class=\"pi pi-plus\"></i>\n <span>New {{ editor.label }}</span>\n </button>\n </div>\n\n @if (editor.expanded && editor.form) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n <div class=\"rtsee-ise-expanded-header\">\n <h4>{{ editor.expanded.isNew ? 'New ' + editor.label : editor.expanded.name }}</h4>\n <div style=\"display: flex; align-items: center; gap: 8px;\">\n @if (!editor.expanded.isNew) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n title=\"Add to Illustrator context\"\n (click)=\"addToIllustrator($event, editor.expanded)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8 Illustrator</span>\n </button>\n }\n <button type=\"button\" class=\"rtsee-ise-icon-button\" (click)=\"editor.collapse()\" aria-label=\"Close\">\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </div>\n\n @if (editor.error) {\n <div class=\"rtsee-ise-error\">{{ editor.error }}</div>\n }\n\n <rtsee-form [form]=\"editor.form\" (formSubmit)=\"submit()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\"\n [label]=\"editor.expanded.isNew ? 'Create' : 'Save'\"\n [loading]=\"editor.saveInProgress\"\n [disabled]=\"editor.busy\" />\n <p-button label=\"Cancel\"\n severity=\"secondary\"\n (click)=\"editor.collapse()\"\n [disabled]=\"editor.busy\" />\n @if (!editor.expanded.isNew) {\n <span class=\"rtsee-ise-actions-spacer\"></span>\n @if (canDetach) {\n <p-button label=\"Remove from story\"\n icon=\"pi pi-minus-circle\"\n severity=\"secondary\"\n [text]=\"true\"\n (click)=\"editor.detach(editor.expanded)\"\n [disabled]=\"editor.busy\" />\n }\n <p-button label=\"Delete\"\n icon=\"pi pi-trash\"\n severity=\"danger\"\n [text]=\"true\"\n [loading]=\"editor.removeInProgress\"\n (click)=\"editor.delete(editor.expanded)\"\n [disabled]=\"editor.busy\" />\n }\n </div>\n </rtsee-form>\n </div>\n }\n </div>\n }\n</section>\n" }]
3965
- }], propDecorators: { editor: [{
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]=\"{ '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" }]
4027
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { editor: [{
3966
4028
  type: Input,
3967
4029
  args: [{ required: true }]
3968
4030
  }], title: [{
@@ -3976,6 +4038,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
3976
4038
  type: Input
3977
4039
  }], toggled: [{
3978
4040
  type: Output
4041
+ }], illustrator: [{
4042
+ type: Input
3979
4043
  }] } });
3980
4044
 
3981
4045
  class IllustratorComponent {
@@ -4091,21 +4155,50 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4091
4155
  * Rendering only, the orchestration lives in RTSeeInteractiveStoryEditorVm.
4092
4156
  */
4093
4157
  class InteractiveStoryEditorComponent {
4094
- constructor() {
4158
+ constructor(cdr) {
4159
+ this.cdr = cdr;
4095
4160
  /** set to false when the vm is initialized by the host */
4096
4161
  this.autoInit = true;
4097
4162
  this.sections = RTSeeStoryEditorSection;
4098
4163
  this.illustrator = new RTSeeIllustrator();
4164
+ this.slideUpdatingIds = new Set();
4165
+ this.onIllustratorChanged = () => {
4166
+ this.cdr.markForCheck();
4167
+ };
4099
4168
  }
4100
4169
  ngOnInit() {
4101
4170
  if (this.autoInit && !this.vm.story) {
4102
4171
  void this.vm.init();
4103
4172
  }
4173
+ this.illustrator.on('changed', this.onIllustratorChanged);
4104
4174
  }
4105
4175
  ngOnDestroy() {
4176
+ this.illustrator.off('changed', this.onIllustratorChanged);
4106
4177
  this.vm.collapseSlide();
4107
4178
  this.illustrator.destroy();
4108
4179
  }
4180
+ isSlideUpdating(id) {
4181
+ return this.slideUpdatingIds.has(id);
4182
+ }
4183
+ async applyReviewedImageToSlide(event, slide) {
4184
+ event.stopPropagation();
4185
+ event.preventDefault();
4186
+ const imageUrl = sanitizeImageUrl(this.illustrator.currentGeneratedImageUrl);
4187
+ if (!imageUrl || !slide.id)
4188
+ return;
4189
+ this.slideUpdatingIds.add(slide.id);
4190
+ this.cdr.markForCheck();
4191
+ try {
4192
+ await this.vm.updateSlideImage(slide, imageUrl);
4193
+ }
4194
+ catch (e) {
4195
+ console.error('Failed to apply image to slide:', e);
4196
+ }
4197
+ finally {
4198
+ this.slideUpdatingIds.delete(slide.id);
4199
+ this.cdr.markForCheck();
4200
+ }
4201
+ }
4109
4202
  submitDetails() {
4110
4203
  this.vm.detailsForm?.submit();
4111
4204
  }
@@ -4279,8 +4372,8 @@ class InteractiveStoryEditorComponent {
4279
4372
  trackSlide(index, slide) {
4280
4373
  return slide.id || `slide-${index}`;
4281
4374
  }
4282
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InteractiveStoryEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4283
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: InteractiveStoryEditorComponent, isStandalone: true, selector: "rtsee-interactive-story-editor", inputs: { vm: "vm", autoInit: "autoInit" }, ngImport: i0, template: "<div class=\"rtsee-interactive-story-editor\" [style.padding-bottom]=\"illustrator.expanded ? '460px' : '72px'\">\n @if (vm.initInProgress) {\n <div class=\"rtsee-ise-loading\">\n <i class=\"pi pi-spin pi-spinner\"></i>\n <span>Loading story\u2026</span>\n </div>\n } @else if (vm.initError) {\n <div class=\"rtsee-ise-error\">{{ vm.initError }}</div>\n } @else if (vm.story) {\n <header class=\"rtsee-ise-header\">\n <span class=\"rtsee-ise-eyebrow\">{{ vm.isNewStory ? 'New story' : 'Story editor' }}</span>\n <h2 class=\"rtsee-ise-heading\">{{ vm.story.name || 'Untitled story' }}</h2>\n </header>\n\n <!-- 1. Details -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.details) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-details\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.details)\"\n (click)=\"vm.toggleSection(sections.details)\">\n <i class=\"rtsee-ise-section-icon pi pi-book\"></i>\n <h3 class=\"rtsee-ise-section-title\">Story details</h3>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.details)) {\n <div class=\"rtsee-ise-section-body\">\n <button type=\"button\" class=\"rtsee-ise-details-card\" id=\"rtsee-ise-details-card\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.detailsExpanded }\"\n (click)=\"vm.toggleDetails()\">\n <div class=\"rtsee-ise-details-image\">\n @if (vm.story.imageUrl) {\n <img [src]=\"vm.story.imageUrl\" [alt]=\"vm.story.name\" />\n } @else {\n <i class=\"pi pi-image\"></i>\n }\n </div>\n <div class=\"rtsee-ise-details-body\">\n <span class=\"rtsee-ise-details-name\">{{ vm.story.name || 'Untitled story' }}</span>\n <p class=\"rtsee-ise-details-description\">{{ vm.story.getTruncatedDescription(220) || 'No description yet' }}</p>\n @if (vm.story.tags.length) {\n <div class=\"rtsee-ise-chips\">\n @for (tag of vm.story.tags; track tag.id) {\n <span class=\"rtsee-ise-chip\">{{ tag.name }}</span>\n }\n </div>\n }\n </div>\n <i class=\"pi pi-pencil rtsee-ise-details-edit\"></i>\n </button>\n\n @if (vm.detailsExpanded && vm.detailsForm) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n @if (vm.detailsError) {\n <div class=\"rtsee-ise-error\">{{ vm.detailsError }}</div>\n }\n <rtsee-form [form]=\"vm.detailsForm\" (formSubmit)=\"submitDetails()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" [label]=\"vm.isNewStory ? 'Create story' : 'Save'\"\n [loading]=\"vm.detailsSaveInProgress\"\n [disabled]=\"vm.detailsSaveInProgress\" />\n <p-button label=\"Cancel\" severity=\"secondary\"\n (click)=\"vm.collapseDetails()\"\n [disabled]=\"vm.detailsSaveInProgress\" />\n </div>\n </rtsee-form>\n </div>\n }\n </div>\n }\n </section>\n\n <!-- 2-4. Characters, artifacts, locations -->\n <rtsee-story-elements-section [editor]=\"vm.charactersEditor\"\n title=\"Characters\"\n icon=\"pi pi-user\"\n [collapsed]=\"vm.isCollapsed(sections.characters)\"\n (toggled)=\"vm.toggleSection(sections.characters)\" />\n\n <rtsee-story-elements-section [editor]=\"vm.artifactsEditor\"\n title=\"Artifacts\"\n icon=\"pi pi-star\"\n [collapsed]=\"vm.isCollapsed(sections.artifacts)\"\n (toggled)=\"vm.toggleSection(sections.artifacts)\" />\n\n <rtsee-story-elements-section [editor]=\"vm.locationsEditor\"\n title=\"Locations\"\n icon=\"pi pi-map-marker\"\n [collapsed]=\"vm.isCollapsed(sections.locations)\"\n (toggled)=\"vm.toggleSection(sections.locations)\" />\n\n <!-- 5. Slides -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.slides) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-slides\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.slides)\"\n (click)=\"vm.toggleSection(sections.slides)\">\n <i class=\"rtsee-ise-section-icon pi pi-images\"></i>\n <h3 class=\"rtsee-ise-section-title\">Slides</h3>\n <span class=\"rtsee-ise-section-count\">{{ vm.slides.length }}</span>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.slides)) {\n <div class=\"rtsee-ise-section-body\">\n @if (vm.isNewStory) {\n <p class=\"rtsee-ise-hint\">Save the story details first to add slides.</p>\n } @else {\n <div class=\"rtsee-ise-slides-strip\">\n @for (slide of vm.slides; track trackSlide($index, slide)) {\n <div class=\"rtsee-ise-slide-thumb-wrapper\" style=\"position: relative; display: inline-flex;\">\n <button type=\"button\" class=\"rtsee-ise-slide-thumb\"\n [id]=\"'rtsee-ise-slide-' + slide.id\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.isSlideExpanded(slide) }\"\n [attr.aria-label]=\"'Slide ' + slide.slideNumber\"\n (click)=\"vm.expandSlide(slide)\">\n @if (slide.imageUrl) {\n <img [src]=\"slide.imageUrl\" [alt]=\"slide.name\" loading=\"lazy\" />\n } @else {\n <i class=\"pi pi-image\"></i>\n }\n <span class=\"rtsee-ise-slide-number\">{{ slide.slideNumber }}</span>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator rtsee-ise-btn-add-context\"\n style=\"position: absolute; top: 4px; left: 4px;\"\n title=\"Add Slide {{ slide.slideNumber }} context (characters, locations, artifacts) to Illustrator\"\n (click)=\"addSlideEntitiesToContext($event, slide)\">\n <i class=\"pi pi-plus\"></i>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n style=\"position: absolute; top: 4px; right: 4px;\"\n title=\"Add Slide {{ slide.slideNumber }} to Illustrator context\"\n (click)=\"addSlideToContext($event, slide)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n </div>\n }\n <button type=\"button\" class=\"rtsee-ise-slide-thumb rtsee-ise-slide-thumb--add\"\n id=\"rtsee-ise-add-slide\"\n [disabled]=\"vm.slidesLoadInProgress\"\n (click)=\"vm.expandNewSlide()\">\n <i class=\"pi pi-plus\"></i>\n </button>\n </div>\n\n @if (vm.activeSlide) {\n <div class=\"rtsee-ise-expanded\">\n <rtsee-manage-slide [manageSlide]=\"vm.activeSlide\" />\n </div>\n }\n }\n </div>\n }\n </section>\n\n <!-- 6. Author -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.author) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-author\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.author)\"\n (click)=\"vm.toggleSection(sections.author)\">\n <i class=\"rtsee-ise-section-icon pi pi-pen-to-square\"></i>\n <h3 class=\"rtsee-ise-section-title\">Author</h3>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.author)) {\n <div class=\"rtsee-ise-section-body\">\n <button type=\"button\" class=\"rtsee-ise-author-card\" id=\"rtsee-ise-author-card\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.authorExpanded }\"\n (click)=\"vm.toggleAuthor()\">\n <div class=\"rtsee-ise-avatar\">\n @if (vm.author?.imageUrl) {\n <img [src]=\"vm.author?.imageUrl\" [alt]=\"vm.author?.name\" />\n } @else {\n <i class=\"pi pi-user\"></i>\n }\n </div>\n <div class=\"rtsee-ise-author-body\">\n <span class=\"rtsee-ise-thumb-name\">{{ vm.author?.name || 'No author assigned' }}</span>\n <span class=\"rtsee-ise-thumb-description\">{{ vm.author?.description || 'Click to pick or create an author' }}</span>\n </div>\n @if (vm.author) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n title=\"Add Author to Illustrator context\"\n (click)=\"addAuthorToContext($event)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n }\n <i class=\"pi pi-pencil rtsee-ise-details-edit\"></i>\n </button>\n\n @if (vm.authorExpanded) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n @if (vm.authorError) {\n <div class=\"rtsee-ise-error\">{{ vm.authorError }}</div>\n }\n\n @if (vm.newAuthor && vm.newAuthorForm) {\n <h4 class=\"rtsee-ise-subheading\">New author</h4>\n <rtsee-form [form]=\"vm.newAuthorForm\" (formSubmit)=\"submitNewAuthor()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" label=\"Create & assign\"\n [loading]=\"vm.authorSaveInProgress\"\n [disabled]=\"vm.authorSaveInProgress\" />\n <p-button label=\"Back\" severity=\"secondary\"\n (click)=\"vm.cancelNewAuthor()\"\n [disabled]=\"vm.authorSaveInProgress\" />\n </div>\n </rtsee-form>\n } @else if (vm.authorForm) {\n <rtsee-form [form]=\"vm.authorForm\" (formSubmit)=\"submitAuthor()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" label=\"Assign\"\n [loading]=\"vm.authorSaveInProgress\"\n [disabled]=\"vm.authorSaveInProgress\" />\n <p-button label=\"New author\" icon=\"pi pi-plus\" severity=\"secondary\"\n (click)=\"vm.startNewAuthor()\"\n [disabled]=\"vm.authorSaveInProgress\" />\n @if (vm.author) {\n <span class=\"rtsee-ise-actions-spacer\"></span>\n <p-button label=\"Clear\" icon=\"pi pi-times\" severity=\"danger\" [text]=\"true\"\n (click)=\"vm.assignAuthor(null)\"\n [disabled]=\"vm.authorSaveInProgress\" />\n }\n </div>\n </rtsee-form>\n }\n </div>\n }\n </div>\n }\n </section>\n\n <!-- 7. NanoBanana Illustrator Overlay -->\n <rtsee-illustrator [illustrator]=\"illustrator\" />\n }\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: FormComponent, selector: "rtsee-form", inputs: ["form"], outputs: ["formSubmit"] }, { kind: "component", type: ManageSlideComponent, selector: "rtsee-manage-slide", inputs: ["manageSlide"] }, { kind: "component", type: StoryElementsSectionComponent, selector: "rtsee-story-elements-section", inputs: ["editor", "title", "icon", "collapsed", "canDetach"], outputs: ["toggled"] }, { kind: "component", type: IllustratorComponent, selector: "rtsee-illustrator", inputs: ["illustrator"] }] }); }
4375
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InteractiveStoryEditorComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
4376
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: InteractiveStoryEditorComponent, isStandalone: true, selector: "rtsee-interactive-story-editor", inputs: { vm: "vm", autoInit: "autoInit" }, ngImport: i0, template: "<div class=\"rtsee-interactive-story-editor\" [style.padding-bottom]=\"illustrator.expanded ? '460px' : '72px'\">\n @if (vm.initInProgress) {\n <div class=\"rtsee-ise-loading\">\n <i class=\"pi pi-spin pi-spinner\"></i>\n <span>Loading story\u2026</span>\n </div>\n } @else if (vm.initError) {\n <div class=\"rtsee-ise-error\">{{ vm.initError }}</div>\n } @else if (vm.story) {\n <header class=\"rtsee-ise-header\">\n <span class=\"rtsee-ise-eyebrow\">{{ vm.isNewStory ? 'New story' : 'Story editor' }}</span>\n <h2 class=\"rtsee-ise-heading\">{{ vm.story.name || 'Untitled story' }}</h2>\n </header>\n\n <!-- 1. Details -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.details) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-details\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.details)\"\n (click)=\"vm.toggleSection(sections.details)\">\n <i class=\"rtsee-ise-section-icon pi pi-book\"></i>\n <h3 class=\"rtsee-ise-section-title\">Story details</h3>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.details)) {\n <div class=\"rtsee-ise-section-body\">\n <button type=\"button\" class=\"rtsee-ise-details-card\" id=\"rtsee-ise-details-card\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.detailsExpanded }\"\n (click)=\"vm.toggleDetails()\">\n <div class=\"rtsee-ise-details-image\">\n @if (vm.story.imageUrl) {\n <img [src]=\"vm.story.imageUrl\" [alt]=\"vm.story.name\" />\n } @else {\n <i class=\"pi pi-image\"></i>\n }\n </div>\n <div class=\"rtsee-ise-details-body\">\n <span class=\"rtsee-ise-details-name\">{{ vm.story.name || 'Untitled story' }}</span>\n <p class=\"rtsee-ise-details-description\">{{ vm.story.getTruncatedDescription(220) || 'No description yet' }}</p>\n @if (vm.story.tags.length) {\n <div class=\"rtsee-ise-chips\">\n @for (tag of vm.story.tags; track tag.id) {\n <span class=\"rtsee-ise-chip\">{{ tag.name }}</span>\n }\n </div>\n }\n </div>\n <i class=\"pi pi-pencil rtsee-ise-details-edit\"></i>\n </button>\n\n @if (vm.detailsExpanded && vm.detailsForm) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n @if (vm.detailsError) {\n <div class=\"rtsee-ise-error\">{{ vm.detailsError }}</div>\n }\n <rtsee-form [form]=\"vm.detailsForm\" (formSubmit)=\"submitDetails()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" [label]=\"vm.isNewStory ? 'Create story' : 'Save'\"\n [loading]=\"vm.detailsSaveInProgress\"\n [disabled]=\"vm.detailsSaveInProgress\" />\n <p-button label=\"Cancel\" severity=\"secondary\"\n (click)=\"vm.collapseDetails()\"\n [disabled]=\"vm.detailsSaveInProgress\" />\n </div>\n </rtsee-form>\n </div>\n }\n </div>\n }\n </section>\n\n <!-- 2-4. Characters, artifacts, locations -->\n <rtsee-story-elements-section [editor]=\"vm.charactersEditor\"\n title=\"Characters\"\n icon=\"pi pi-user\"\n [illustrator]=\"illustrator\"\n [collapsed]=\"vm.isCollapsed(sections.characters)\"\n (toggled)=\"vm.toggleSection(sections.characters)\" />\n\n <rtsee-story-elements-section [editor]=\"vm.artifactsEditor\"\n title=\"Artifacts\"\n icon=\"pi pi-star\"\n [illustrator]=\"illustrator\"\n [collapsed]=\"vm.isCollapsed(sections.artifacts)\"\n (toggled)=\"vm.toggleSection(sections.artifacts)\" />\n\n <rtsee-story-elements-section [editor]=\"vm.locationsEditor\"\n title=\"Locations\"\n icon=\"pi pi-map-marker\"\n [illustrator]=\"illustrator\"\n [collapsed]=\"vm.isCollapsed(sections.locations)\"\n (toggled)=\"vm.toggleSection(sections.locations)\" />\n\n <!-- 5. Slides -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.slides) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-slides\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.slides)\"\n (click)=\"vm.toggleSection(sections.slides)\">\n <i class=\"rtsee-ise-section-icon pi pi-images\"></i>\n <h3 class=\"rtsee-ise-section-title\">Slides</h3>\n <span class=\"rtsee-ise-section-count\">{{ vm.slides.length }}</span>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.slides)) {\n <div class=\"rtsee-ise-section-body\">\n @if (vm.isNewStory) {\n <p class=\"rtsee-ise-hint\">Save the story details first to add slides.</p>\n } @else {\n <div class=\"rtsee-ise-slides-strip\">\n @for (slide of vm.slides; track trackSlide($index, slide)) {\n <div class=\"rtsee-ise-slide-thumb-wrapper\" style=\"position: relative; display: inline-flex;\">\n <button type=\"button\" class=\"rtsee-ise-slide-thumb\"\n [id]=\"'rtsee-ise-slide-' + slide.id\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.isSlideExpanded(slide) }\"\n [attr.aria-label]=\"'Slide ' + slide.slideNumber\"\n (click)=\"vm.expandSlide(slide)\">\n @if (slide.imageUrl) {\n <img [src]=\"slide.imageUrl\" [alt]=\"slide.name\" loading=\"lazy\" />\n } @else {\n <i class=\"pi pi-image\"></i>\n }\n <span class=\"rtsee-ise-slide-number\">{{ slide.slideNumber }}</span>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator rtsee-ise-btn-add-context\"\n style=\"position: absolute; top: 4px; left: 4px;\"\n title=\"Add Slide {{ slide.slideNumber }} context (characters, locations, artifacts) to Illustrator\"\n (click)=\"addSlideEntitiesToContext($event, slide)\">\n <i class=\"pi pi-plus\"></i>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n style=\"position: absolute; top: 4px; right: 4px;\"\n title=\"Add Slide {{ slide.slideNumber }} to Illustrator context\"\n (click)=\"addSlideToContext($event, slide)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n @if (illustrator.reviewingGeneratedImage && illustrator.currentGeneratedImageUrl) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-quick-apply\"\n style=\"position: absolute; bottom: 4px; right: 4px;\"\n [disabled]=\"isSlideUpdating(slide.id)\"\n [title]=\"'Apply reviewed image to Slide ' + slide.slideNumber\"\n (click)=\"applyReviewedImageToSlide($event, slide)\">\n @if (isSlideUpdating(slide.id)) {\n <i class=\"pi pi-spin pi-spinner\"></i>\n } @else {\n <i class=\"pi pi-plus\"></i>\n }\n </button>\n }\n </div>\n }\n <button type=\"button\" class=\"rtsee-ise-slide-thumb rtsee-ise-slide-thumb--add\"\n id=\"rtsee-ise-add-slide\"\n [disabled]=\"vm.slidesLoadInProgress\"\n (click)=\"vm.expandNewSlide()\">\n <i class=\"pi pi-plus\"></i>\n </button>\n </div>\n\n @if (vm.activeSlide) {\n <div class=\"rtsee-ise-expanded\">\n <rtsee-manage-slide [manageSlide]=\"vm.activeSlide\" />\n </div>\n }\n }\n </div>\n }\n </section>\n\n <!-- 6. Author -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.author) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-author\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.author)\"\n (click)=\"vm.toggleSection(sections.author)\">\n <i class=\"rtsee-ise-section-icon pi pi-pen-to-square\"></i>\n <h3 class=\"rtsee-ise-section-title\">Author</h3>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.author)) {\n <div class=\"rtsee-ise-section-body\">\n <button type=\"button\" class=\"rtsee-ise-author-card\" id=\"rtsee-ise-author-card\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.authorExpanded }\"\n (click)=\"vm.toggleAuthor()\">\n <div class=\"rtsee-ise-avatar\">\n @if (vm.author?.imageUrl) {\n <img [src]=\"vm.author?.imageUrl\" [alt]=\"vm.author?.name\" />\n } @else {\n <i class=\"pi pi-user\"></i>\n }\n </div>\n <div class=\"rtsee-ise-author-body\">\n <span class=\"rtsee-ise-thumb-name\">{{ vm.author?.name || 'No author assigned' }}</span>\n <span class=\"rtsee-ise-thumb-description\">{{ vm.author?.description || 'Click to pick or create an author' }}</span>\n </div>\n @if (vm.author) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n title=\"Add Author to Illustrator context\"\n (click)=\"addAuthorToContext($event)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n }\n <i class=\"pi pi-pencil rtsee-ise-details-edit\"></i>\n </button>\n\n @if (vm.authorExpanded) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n @if (vm.authorError) {\n <div class=\"rtsee-ise-error\">{{ vm.authorError }}</div>\n }\n\n @if (vm.newAuthor && vm.newAuthorForm) {\n <h4 class=\"rtsee-ise-subheading\">New author</h4>\n <rtsee-form [form]=\"vm.newAuthorForm\" (formSubmit)=\"submitNewAuthor()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" label=\"Create & assign\"\n [loading]=\"vm.authorSaveInProgress\"\n [disabled]=\"vm.authorSaveInProgress\" />\n <p-button label=\"Back\" severity=\"secondary\"\n (click)=\"vm.cancelNewAuthor()\"\n [disabled]=\"vm.authorSaveInProgress\" />\n </div>\n </rtsee-form>\n } @else if (vm.authorForm) {\n <rtsee-form [form]=\"vm.authorForm\" (formSubmit)=\"submitAuthor()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" label=\"Assign\"\n [loading]=\"vm.authorSaveInProgress\"\n [disabled]=\"vm.authorSaveInProgress\" />\n <p-button label=\"New author\" icon=\"pi pi-plus\" severity=\"secondary\"\n (click)=\"vm.startNewAuthor()\"\n [disabled]=\"vm.authorSaveInProgress\" />\n @if (vm.author) {\n <span class=\"rtsee-ise-actions-spacer\"></span>\n <p-button label=\"Clear\" icon=\"pi pi-times\" severity=\"danger\" [text]=\"true\"\n (click)=\"vm.assignAuthor(null)\"\n [disabled]=\"vm.authorSaveInProgress\" />\n }\n </div>\n </rtsee-form>\n }\n </div>\n }\n </div>\n }\n </section>\n\n <!-- 7. NanoBanana Illustrator Overlay -->\n <rtsee-illustrator [illustrator]=\"illustrator\" />\n }\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: FormComponent, selector: "rtsee-form", inputs: ["form"], outputs: ["formSubmit"] }, { kind: "component", type: ManageSlideComponent, selector: "rtsee-manage-slide", inputs: ["manageSlide"] }, { kind: "component", type: StoryElementsSectionComponent, selector: "rtsee-story-elements-section", inputs: ["editor", "title", "icon", "collapsed", "canDetach", "illustrator"], outputs: ["toggled"] }, { kind: "component", type: IllustratorComponent, selector: "rtsee-illustrator", inputs: ["illustrator"] }] }); }
4284
4377
  }
4285
4378
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: InteractiveStoryEditorComponent, decorators: [{
4286
4379
  type: Component,
@@ -4291,8 +4384,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4291
4384
  ManageSlideComponent,
4292
4385
  StoryElementsSectionComponent,
4293
4386
  IllustratorComponent,
4294
- ], template: "<div class=\"rtsee-interactive-story-editor\" [style.padding-bottom]=\"illustrator.expanded ? '460px' : '72px'\">\n @if (vm.initInProgress) {\n <div class=\"rtsee-ise-loading\">\n <i class=\"pi pi-spin pi-spinner\"></i>\n <span>Loading story\u2026</span>\n </div>\n } @else if (vm.initError) {\n <div class=\"rtsee-ise-error\">{{ vm.initError }}</div>\n } @else if (vm.story) {\n <header class=\"rtsee-ise-header\">\n <span class=\"rtsee-ise-eyebrow\">{{ vm.isNewStory ? 'New story' : 'Story editor' }}</span>\n <h2 class=\"rtsee-ise-heading\">{{ vm.story.name || 'Untitled story' }}</h2>\n </header>\n\n <!-- 1. Details -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.details) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-details\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.details)\"\n (click)=\"vm.toggleSection(sections.details)\">\n <i class=\"rtsee-ise-section-icon pi pi-book\"></i>\n <h3 class=\"rtsee-ise-section-title\">Story details</h3>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.details)) {\n <div class=\"rtsee-ise-section-body\">\n <button type=\"button\" class=\"rtsee-ise-details-card\" id=\"rtsee-ise-details-card\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.detailsExpanded }\"\n (click)=\"vm.toggleDetails()\">\n <div class=\"rtsee-ise-details-image\">\n @if (vm.story.imageUrl) {\n <img [src]=\"vm.story.imageUrl\" [alt]=\"vm.story.name\" />\n } @else {\n <i class=\"pi pi-image\"></i>\n }\n </div>\n <div class=\"rtsee-ise-details-body\">\n <span class=\"rtsee-ise-details-name\">{{ vm.story.name || 'Untitled story' }}</span>\n <p class=\"rtsee-ise-details-description\">{{ vm.story.getTruncatedDescription(220) || 'No description yet' }}</p>\n @if (vm.story.tags.length) {\n <div class=\"rtsee-ise-chips\">\n @for (tag of vm.story.tags; track tag.id) {\n <span class=\"rtsee-ise-chip\">{{ tag.name }}</span>\n }\n </div>\n }\n </div>\n <i class=\"pi pi-pencil rtsee-ise-details-edit\"></i>\n </button>\n\n @if (vm.detailsExpanded && vm.detailsForm) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n @if (vm.detailsError) {\n <div class=\"rtsee-ise-error\">{{ vm.detailsError }}</div>\n }\n <rtsee-form [form]=\"vm.detailsForm\" (formSubmit)=\"submitDetails()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" [label]=\"vm.isNewStory ? 'Create story' : 'Save'\"\n [loading]=\"vm.detailsSaveInProgress\"\n [disabled]=\"vm.detailsSaveInProgress\" />\n <p-button label=\"Cancel\" severity=\"secondary\"\n (click)=\"vm.collapseDetails()\"\n [disabled]=\"vm.detailsSaveInProgress\" />\n </div>\n </rtsee-form>\n </div>\n }\n </div>\n }\n </section>\n\n <!-- 2-4. Characters, artifacts, locations -->\n <rtsee-story-elements-section [editor]=\"vm.charactersEditor\"\n title=\"Characters\"\n icon=\"pi pi-user\"\n [collapsed]=\"vm.isCollapsed(sections.characters)\"\n (toggled)=\"vm.toggleSection(sections.characters)\" />\n\n <rtsee-story-elements-section [editor]=\"vm.artifactsEditor\"\n title=\"Artifacts\"\n icon=\"pi pi-star\"\n [collapsed]=\"vm.isCollapsed(sections.artifacts)\"\n (toggled)=\"vm.toggleSection(sections.artifacts)\" />\n\n <rtsee-story-elements-section [editor]=\"vm.locationsEditor\"\n title=\"Locations\"\n icon=\"pi pi-map-marker\"\n [collapsed]=\"vm.isCollapsed(sections.locations)\"\n (toggled)=\"vm.toggleSection(sections.locations)\" />\n\n <!-- 5. Slides -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.slides) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-slides\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.slides)\"\n (click)=\"vm.toggleSection(sections.slides)\">\n <i class=\"rtsee-ise-section-icon pi pi-images\"></i>\n <h3 class=\"rtsee-ise-section-title\">Slides</h3>\n <span class=\"rtsee-ise-section-count\">{{ vm.slides.length }}</span>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.slides)) {\n <div class=\"rtsee-ise-section-body\">\n @if (vm.isNewStory) {\n <p class=\"rtsee-ise-hint\">Save the story details first to add slides.</p>\n } @else {\n <div class=\"rtsee-ise-slides-strip\">\n @for (slide of vm.slides; track trackSlide($index, slide)) {\n <div class=\"rtsee-ise-slide-thumb-wrapper\" style=\"position: relative; display: inline-flex;\">\n <button type=\"button\" class=\"rtsee-ise-slide-thumb\"\n [id]=\"'rtsee-ise-slide-' + slide.id\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.isSlideExpanded(slide) }\"\n [attr.aria-label]=\"'Slide ' + slide.slideNumber\"\n (click)=\"vm.expandSlide(slide)\">\n @if (slide.imageUrl) {\n <img [src]=\"slide.imageUrl\" [alt]=\"slide.name\" loading=\"lazy\" />\n } @else {\n <i class=\"pi pi-image\"></i>\n }\n <span class=\"rtsee-ise-slide-number\">{{ slide.slideNumber }}</span>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator rtsee-ise-btn-add-context\"\n style=\"position: absolute; top: 4px; left: 4px;\"\n title=\"Add Slide {{ slide.slideNumber }} context (characters, locations, artifacts) to Illustrator\"\n (click)=\"addSlideEntitiesToContext($event, slide)\">\n <i class=\"pi pi-plus\"></i>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n style=\"position: absolute; top: 4px; right: 4px;\"\n title=\"Add Slide {{ slide.slideNumber }} to Illustrator context\"\n (click)=\"addSlideToContext($event, slide)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n </div>\n }\n <button type=\"button\" class=\"rtsee-ise-slide-thumb rtsee-ise-slide-thumb--add\"\n id=\"rtsee-ise-add-slide\"\n [disabled]=\"vm.slidesLoadInProgress\"\n (click)=\"vm.expandNewSlide()\">\n <i class=\"pi pi-plus\"></i>\n </button>\n </div>\n\n @if (vm.activeSlide) {\n <div class=\"rtsee-ise-expanded\">\n <rtsee-manage-slide [manageSlide]=\"vm.activeSlide\" />\n </div>\n }\n }\n </div>\n }\n </section>\n\n <!-- 6. Author -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.author) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-author\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.author)\"\n (click)=\"vm.toggleSection(sections.author)\">\n <i class=\"rtsee-ise-section-icon pi pi-pen-to-square\"></i>\n <h3 class=\"rtsee-ise-section-title\">Author</h3>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.author)) {\n <div class=\"rtsee-ise-section-body\">\n <button type=\"button\" class=\"rtsee-ise-author-card\" id=\"rtsee-ise-author-card\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.authorExpanded }\"\n (click)=\"vm.toggleAuthor()\">\n <div class=\"rtsee-ise-avatar\">\n @if (vm.author?.imageUrl) {\n <img [src]=\"vm.author?.imageUrl\" [alt]=\"vm.author?.name\" />\n } @else {\n <i class=\"pi pi-user\"></i>\n }\n </div>\n <div class=\"rtsee-ise-author-body\">\n <span class=\"rtsee-ise-thumb-name\">{{ vm.author?.name || 'No author assigned' }}</span>\n <span class=\"rtsee-ise-thumb-description\">{{ vm.author?.description || 'Click to pick or create an author' }}</span>\n </div>\n @if (vm.author) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n title=\"Add Author to Illustrator context\"\n (click)=\"addAuthorToContext($event)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n }\n <i class=\"pi pi-pencil rtsee-ise-details-edit\"></i>\n </button>\n\n @if (vm.authorExpanded) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n @if (vm.authorError) {\n <div class=\"rtsee-ise-error\">{{ vm.authorError }}</div>\n }\n\n @if (vm.newAuthor && vm.newAuthorForm) {\n <h4 class=\"rtsee-ise-subheading\">New author</h4>\n <rtsee-form [form]=\"vm.newAuthorForm\" (formSubmit)=\"submitNewAuthor()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" label=\"Create & assign\"\n [loading]=\"vm.authorSaveInProgress\"\n [disabled]=\"vm.authorSaveInProgress\" />\n <p-button label=\"Back\" severity=\"secondary\"\n (click)=\"vm.cancelNewAuthor()\"\n [disabled]=\"vm.authorSaveInProgress\" />\n </div>\n </rtsee-form>\n } @else if (vm.authorForm) {\n <rtsee-form [form]=\"vm.authorForm\" (formSubmit)=\"submitAuthor()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" label=\"Assign\"\n [loading]=\"vm.authorSaveInProgress\"\n [disabled]=\"vm.authorSaveInProgress\" />\n <p-button label=\"New author\" icon=\"pi pi-plus\" severity=\"secondary\"\n (click)=\"vm.startNewAuthor()\"\n [disabled]=\"vm.authorSaveInProgress\" />\n @if (vm.author) {\n <span class=\"rtsee-ise-actions-spacer\"></span>\n <p-button label=\"Clear\" icon=\"pi pi-times\" severity=\"danger\" [text]=\"true\"\n (click)=\"vm.assignAuthor(null)\"\n [disabled]=\"vm.authorSaveInProgress\" />\n }\n </div>\n </rtsee-form>\n }\n </div>\n }\n </div>\n }\n </section>\n\n <!-- 7. NanoBanana Illustrator Overlay -->\n <rtsee-illustrator [illustrator]=\"illustrator\" />\n }\n</div>\n" }]
4295
- }], propDecorators: { vm: [{
4387
+ ], template: "<div class=\"rtsee-interactive-story-editor\" [style.padding-bottom]=\"illustrator.expanded ? '460px' : '72px'\">\n @if (vm.initInProgress) {\n <div class=\"rtsee-ise-loading\">\n <i class=\"pi pi-spin pi-spinner\"></i>\n <span>Loading story\u2026</span>\n </div>\n } @else if (vm.initError) {\n <div class=\"rtsee-ise-error\">{{ vm.initError }}</div>\n } @else if (vm.story) {\n <header class=\"rtsee-ise-header\">\n <span class=\"rtsee-ise-eyebrow\">{{ vm.isNewStory ? 'New story' : 'Story editor' }}</span>\n <h2 class=\"rtsee-ise-heading\">{{ vm.story.name || 'Untitled story' }}</h2>\n </header>\n\n <!-- 1. Details -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.details) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-details\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.details)\"\n (click)=\"vm.toggleSection(sections.details)\">\n <i class=\"rtsee-ise-section-icon pi pi-book\"></i>\n <h3 class=\"rtsee-ise-section-title\">Story details</h3>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.details)) {\n <div class=\"rtsee-ise-section-body\">\n <button type=\"button\" class=\"rtsee-ise-details-card\" id=\"rtsee-ise-details-card\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.detailsExpanded }\"\n (click)=\"vm.toggleDetails()\">\n <div class=\"rtsee-ise-details-image\">\n @if (vm.story.imageUrl) {\n <img [src]=\"vm.story.imageUrl\" [alt]=\"vm.story.name\" />\n } @else {\n <i class=\"pi pi-image\"></i>\n }\n </div>\n <div class=\"rtsee-ise-details-body\">\n <span class=\"rtsee-ise-details-name\">{{ vm.story.name || 'Untitled story' }}</span>\n <p class=\"rtsee-ise-details-description\">{{ vm.story.getTruncatedDescription(220) || 'No description yet' }}</p>\n @if (vm.story.tags.length) {\n <div class=\"rtsee-ise-chips\">\n @for (tag of vm.story.tags; track tag.id) {\n <span class=\"rtsee-ise-chip\">{{ tag.name }}</span>\n }\n </div>\n }\n </div>\n <i class=\"pi pi-pencil rtsee-ise-details-edit\"></i>\n </button>\n\n @if (vm.detailsExpanded && vm.detailsForm) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n @if (vm.detailsError) {\n <div class=\"rtsee-ise-error\">{{ vm.detailsError }}</div>\n }\n <rtsee-form [form]=\"vm.detailsForm\" (formSubmit)=\"submitDetails()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" [label]=\"vm.isNewStory ? 'Create story' : 'Save'\"\n [loading]=\"vm.detailsSaveInProgress\"\n [disabled]=\"vm.detailsSaveInProgress\" />\n <p-button label=\"Cancel\" severity=\"secondary\"\n (click)=\"vm.collapseDetails()\"\n [disabled]=\"vm.detailsSaveInProgress\" />\n </div>\n </rtsee-form>\n </div>\n }\n </div>\n }\n </section>\n\n <!-- 2-4. Characters, artifacts, locations -->\n <rtsee-story-elements-section [editor]=\"vm.charactersEditor\"\n title=\"Characters\"\n icon=\"pi pi-user\"\n [illustrator]=\"illustrator\"\n [collapsed]=\"vm.isCollapsed(sections.characters)\"\n (toggled)=\"vm.toggleSection(sections.characters)\" />\n\n <rtsee-story-elements-section [editor]=\"vm.artifactsEditor\"\n title=\"Artifacts\"\n icon=\"pi pi-star\"\n [illustrator]=\"illustrator\"\n [collapsed]=\"vm.isCollapsed(sections.artifacts)\"\n (toggled)=\"vm.toggleSection(sections.artifacts)\" />\n\n <rtsee-story-elements-section [editor]=\"vm.locationsEditor\"\n title=\"Locations\"\n icon=\"pi pi-map-marker\"\n [illustrator]=\"illustrator\"\n [collapsed]=\"vm.isCollapsed(sections.locations)\"\n (toggled)=\"vm.toggleSection(sections.locations)\" />\n\n <!-- 5. Slides -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.slides) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-slides\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.slides)\"\n (click)=\"vm.toggleSection(sections.slides)\">\n <i class=\"rtsee-ise-section-icon pi pi-images\"></i>\n <h3 class=\"rtsee-ise-section-title\">Slides</h3>\n <span class=\"rtsee-ise-section-count\">{{ vm.slides.length }}</span>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.slides)) {\n <div class=\"rtsee-ise-section-body\">\n @if (vm.isNewStory) {\n <p class=\"rtsee-ise-hint\">Save the story details first to add slides.</p>\n } @else {\n <div class=\"rtsee-ise-slides-strip\">\n @for (slide of vm.slides; track trackSlide($index, slide)) {\n <div class=\"rtsee-ise-slide-thumb-wrapper\" style=\"position: relative; display: inline-flex;\">\n <button type=\"button\" class=\"rtsee-ise-slide-thumb\"\n [id]=\"'rtsee-ise-slide-' + slide.id\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.isSlideExpanded(slide) }\"\n [attr.aria-label]=\"'Slide ' + slide.slideNumber\"\n (click)=\"vm.expandSlide(slide)\">\n @if (slide.imageUrl) {\n <img [src]=\"slide.imageUrl\" [alt]=\"slide.name\" loading=\"lazy\" />\n } @else {\n <i class=\"pi pi-image\"></i>\n }\n <span class=\"rtsee-ise-slide-number\">{{ slide.slideNumber }}</span>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator rtsee-ise-btn-add-context\"\n style=\"position: absolute; top: 4px; left: 4px;\"\n title=\"Add Slide {{ slide.slideNumber }} context (characters, locations, artifacts) to Illustrator\"\n (click)=\"addSlideEntitiesToContext($event, slide)\">\n <i class=\"pi pi-plus\"></i>\n </button>\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n style=\"position: absolute; top: 4px; right: 4px;\"\n title=\"Add Slide {{ slide.slideNumber }} to Illustrator context\"\n (click)=\"addSlideToContext($event, slide)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n @if (illustrator.reviewingGeneratedImage && illustrator.currentGeneratedImageUrl) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-quick-apply\"\n style=\"position: absolute; bottom: 4px; right: 4px;\"\n [disabled]=\"isSlideUpdating(slide.id)\"\n [title]=\"'Apply reviewed image to Slide ' + slide.slideNumber\"\n (click)=\"applyReviewedImageToSlide($event, slide)\">\n @if (isSlideUpdating(slide.id)) {\n <i class=\"pi pi-spin pi-spinner\"></i>\n } @else {\n <i class=\"pi pi-plus\"></i>\n }\n </button>\n }\n </div>\n }\n <button type=\"button\" class=\"rtsee-ise-slide-thumb rtsee-ise-slide-thumb--add\"\n id=\"rtsee-ise-add-slide\"\n [disabled]=\"vm.slidesLoadInProgress\"\n (click)=\"vm.expandNewSlide()\">\n <i class=\"pi pi-plus\"></i>\n </button>\n </div>\n\n @if (vm.activeSlide) {\n <div class=\"rtsee-ise-expanded\">\n <rtsee-manage-slide [manageSlide]=\"vm.activeSlide\" />\n </div>\n }\n }\n </div>\n }\n </section>\n\n <!-- 6. Author -->\n <section class=\"rtsee-ise-section\" [ngClass]=\"{ 'rtsee-ise-section--collapsed': vm.isCollapsed(sections.author) }\">\n <header class=\"rtsee-ise-section-header\">\n <button type=\"button\" class=\"rtsee-ise-section-toggle\" id=\"rtsee-ise-toggle-author\"\n [attr.aria-expanded]=\"!vm.isCollapsed(sections.author)\"\n (click)=\"vm.toggleSection(sections.author)\">\n <i class=\"rtsee-ise-section-icon pi pi-pen-to-square\"></i>\n <h3 class=\"rtsee-ise-section-title\">Author</h3>\n <i class=\"pi pi-chevron-down rtsee-ise-chevron\"></i>\n </button>\n </header>\n\n @if (!vm.isCollapsed(sections.author)) {\n <div class=\"rtsee-ise-section-body\">\n <button type=\"button\" class=\"rtsee-ise-author-card\" id=\"rtsee-ise-author-card\"\n [ngClass]=\"{ 'rtsee-ise-thumb--active': vm.authorExpanded }\"\n (click)=\"vm.toggleAuthor()\">\n <div class=\"rtsee-ise-avatar\">\n @if (vm.author?.imageUrl) {\n <img [src]=\"vm.author?.imageUrl\" [alt]=\"vm.author?.name\" />\n } @else {\n <i class=\"pi pi-user\"></i>\n }\n </div>\n <div class=\"rtsee-ise-author-body\">\n <span class=\"rtsee-ise-thumb-name\">{{ vm.author?.name || 'No author assigned' }}</span>\n <span class=\"rtsee-ise-thumb-description\">{{ vm.author?.description || 'Click to pick or create an author' }}</span>\n </div>\n @if (vm.author) {\n <button type=\"button\"\n class=\"rtsee-ise-btn-add-illustrator\"\n title=\"Add Author to Illustrator context\"\n (click)=\"addAuthorToContext($event)\">\n <i class=\"pi pi-palette\"></i>\n <span>+\uD83C\uDFA8</span>\n </button>\n }\n <i class=\"pi pi-pencil rtsee-ise-details-edit\"></i>\n </button>\n\n @if (vm.authorExpanded) {\n <div class=\"rtsee-ise-expanded rtsee-form-container\">\n @if (vm.authorError) {\n <div class=\"rtsee-ise-error\">{{ vm.authorError }}</div>\n }\n\n @if (vm.newAuthor && vm.newAuthorForm) {\n <h4 class=\"rtsee-ise-subheading\">New author</h4>\n <rtsee-form [form]=\"vm.newAuthorForm\" (formSubmit)=\"submitNewAuthor()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" label=\"Create & assign\"\n [loading]=\"vm.authorSaveInProgress\"\n [disabled]=\"vm.authorSaveInProgress\" />\n <p-button label=\"Back\" severity=\"secondary\"\n (click)=\"vm.cancelNewAuthor()\"\n [disabled]=\"vm.authorSaveInProgress\" />\n </div>\n </rtsee-form>\n } @else if (vm.authorForm) {\n <rtsee-form [form]=\"vm.authorForm\" (formSubmit)=\"submitAuthor()\">\n <div class=\"rtsee-ise-actions\">\n <p-button type=\"submit\" label=\"Assign\"\n [loading]=\"vm.authorSaveInProgress\"\n [disabled]=\"vm.authorSaveInProgress\" />\n <p-button label=\"New author\" icon=\"pi pi-plus\" severity=\"secondary\"\n (click)=\"vm.startNewAuthor()\"\n [disabled]=\"vm.authorSaveInProgress\" />\n @if (vm.author) {\n <span class=\"rtsee-ise-actions-spacer\"></span>\n <p-button label=\"Clear\" icon=\"pi pi-times\" severity=\"danger\" [text]=\"true\"\n (click)=\"vm.assignAuthor(null)\"\n [disabled]=\"vm.authorSaveInProgress\" />\n }\n </div>\n </rtsee-form>\n }\n </div>\n }\n </div>\n }\n </section>\n\n <!-- 7. NanoBanana Illustrator Overlay -->\n <rtsee-illustrator [illustrator]=\"illustrator\" />\n }\n</div>\n" }]
4388
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { vm: [{
4296
4389
  type: Input,
4297
4390
  args: [{ required: true }]
4298
4391
  }], autoInit: [{