@forgeroute/ui 0.4.28 → 0.4.30

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.
@@ -42379,6 +42379,9 @@ var SetupWizardComponent = class SetupWizardComponent {
42379
42379
  error: () => this.error.set(this.t().connectIntegrationFailed(i.title))
42380
42380
  });
42381
42381
  }
42382
+ iconD(name) {
42383
+ return iconPath(name) ?? "";
42384
+ }
42382
42385
  areaCodeLabelFor(i) {
42383
42386
  return (i.connect.type === "area-code" ? i.connect.areaCodeLabel : void 0) ?? this.t().areaCode;
42384
42387
  }
@@ -42473,7 +42476,7 @@ var SetupWizardComponent = class SetupWizardComponent {
42473
42476
  <main class="sw-content">
42474
42477
  <div class="sw-content-header">
42475
42478
  <h1 class="sw-step-title" data-testid="wizard-step-title">{{ current().label }}</h1>
42476
- <ui-button variant="ghost" size="sm" data-testid="wizard-exit" (click)="exited.emit()">{{ t().exit }}</ui-button>
42479
+ <ui-button variant="ghost" size="sm" data-testid="wizard-exit" (click)="exited.emit()"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('close')" /></svg> {{ t().exit }}</ui-button>
42477
42480
  </div>
42478
42481
 
42479
42482
  @if (isDone()) {
@@ -42481,7 +42484,7 @@ var SetupWizardComponent = class SetupWizardComponent {
42481
42484
  <p class="sw-step-desc">{{ t().doneDescription }}</p>
42482
42485
  <ui-panel-info-list class="sw-summary" data-testid="wizard-summary" [sections]="summarySections()" />
42483
42486
  <p class="sw-done-hint">{{ t().doneHint }}</p>
42484
- <ui-button variant="primary" size="lg" data-testid="wizard-finish" (click)="finished.emit()">{{ t().finish }}</ui-button>
42487
+ <ui-button variant="primary" size="sm" data-testid="wizard-finish" (click)="finished.emit()"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('check')" /></svg> {{ t().finish }}</ui-button>
42485
42488
  </div>
42486
42489
  } @else {
42487
42490
  <div class="sw-step-content" [attr.data-step]="current().key">
@@ -42502,11 +42505,11 @@ var SetupWizardComponent = class SetupWizardComponent {
42502
42505
  @if (importResult(current().key); as res) {
42503
42506
  <ui-alert variant="success" [title]="importTitle(current().key)" [attr.data-testid]="'import-result-' + current().key">
42504
42507
  {{ imp.resultText }}
42505
- <ui-button variant="link" size="sm" data-testid="import-more" (click)="clearImport(current().key)">{{ t().importMore }}</ui-button>
42508
+ <ui-button variant="link" size="sm" data-testid="import-more" (click)="clearImport(current().key)"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('upload')" /></svg> {{ t().importMore }}</ui-button>
42506
42509
  </ui-alert>
42507
42510
  } @else {
42508
42511
  @if (imp.hint) { <p class="sw-hint">{{ imp.hint }}</p> }
42509
- <ui-button variant="primary" size="lg" [attr.data-testid]="'open-import-' + current().key" (click)="openImport(current().key)">{{ imp.buttonLabel }}</ui-button>
42512
+ <ui-button variant="primary" size="sm" [attr.data-testid]="'open-import-' + current().key" (click)="openImport(current().key)"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('upload')" /></svg> {{ imp.buttonLabel }}</ui-button>
42510
42513
  }
42511
42514
  <ui-import-export #importer style="display:none" [config]="imp.config" [importSources]="imp.sources" (imported)="onImported(current().key)" />
42512
42515
  }
@@ -42518,13 +42521,13 @@ var SetupWizardComponent = class SetupWizardComponent {
42518
42521
  [icon]="it.icon ?? 'link'" iconColor="blue" [title]="it.title" [details]="[detailFor(it)]"
42519
42522
  [badge]="t().connected" badgeVariant="green" [alwaysShowBadge]="isConnected(it)">
42520
42523
  <ui-button list-item-action variant="secondary" size="sm" [ariaLabel]="(isConnected(it) ? t().reconnect : t().connect) + ' ' + it.title" (click)="connect(it)">
42521
- {{ isConnected(it) ? t().reconnect : t().connect }}
42524
+ <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('link')" /></svg> {{ isConnected(it) ? t().reconnect : t().connect }}
42522
42525
  </ui-button>
42523
42526
  </ui-list-item>
42524
42527
  @if (areaCodeOpen() === it.key) {
42525
42528
  <div class="sw-area-code" [attr.data-testid]="'area-code-' + it.key">
42526
42529
  <ui-text-input [label]="areaCodeLabelFor(it)" [maxlength]="3" inputmode="numeric" [ngModel]="areaCode()" (ngModelChange)="areaCode.set($event ?? '')" [inputTestId]="'area-code-input-' + it.key" />
42527
- <ui-button variant="primary" size="sm" [loading]="busy()" [disabled]="!validAreaCode()" (click)="submitAreaCode(it)">{{ t().connect }}</ui-button>
42530
+ <ui-button variant="primary" size="sm" [loading]="busy()" [disabled]="!validAreaCode()" (click)="submitAreaCode(it)"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('link')" /></svg> {{ t().connect }}</ui-button>
42528
42531
  </div>
42529
42532
  }
42530
42533
  }
@@ -42535,19 +42538,19 @@ var SetupWizardComponent = class SetupWizardComponent {
42535
42538
  @if (error()) { <ui-alert variant="danger" data-testid="wizard-save-error">{{ error() }}</ui-alert> }
42536
42539
 
42537
42540
  <div class="sw-step-actions">
42538
- @if (index() > 0) { <ui-button variant="ghost" size="md" data-testid="wizard-back" [disabled]="busy()" (click)="back()">{{ t().back }}</ui-button> } @else { <span></span> }
42541
+ @if (index() > 0) { <ui-button variant="ghost" size="sm" data-testid="wizard-back" [disabled]="busy()" (click)="back()"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-left')" /></svg> {{ t().back }}</ui-button> } @else { <span></span> }
42539
42542
  <div class="sw-actions-right">
42540
42543
  @if (current().skippable !== false) {
42541
- <ui-button variant="ghost" size="md" data-testid="wizard-skip" [disabled]="busy()" (click)="skip()">{{ t().skip }}</ui-button>
42544
+ <ui-button variant="ghost" size="sm" data-testid="wizard-skip" [disabled]="busy()" (click)="skip()">{{ t().skip }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('chevron-right')" /></svg></ui-button>
42542
42545
  }
42543
42546
  @if (current().kind === 'custom') {
42544
- <ui-button variant="primary" size="lg" data-testid="wizard-save" [loading]="busy()" [disabled]="current().canContinue ? !current().canContinue!() : false" (click)="saveAndContinue()">
42545
- {{ current().saveLabel ?? t().saveAndContinue }}
42547
+ <ui-button variant="primary" size="sm" data-testid="wizard-save" [loading]="busy()" [disabled]="current().canContinue ? !current().canContinue!() : false" (click)="saveAndContinue()">
42548
+ {{ current().saveLabel ?? t().saveAndContinue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg>
42546
42549
  </ui-button>
42547
42550
  } @else if (current().kind === 'integrations') {
42548
- <ui-button variant="primary" size="lg" data-testid="wizard-save" [loading]="busy()" (click)="saveAndContinue()">{{ t().saveAndContinue }}</ui-button>
42551
+ <ui-button variant="primary" size="sm" data-testid="wizard-save" [loading]="busy()" (click)="saveAndContinue()">{{ t().saveAndContinue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg></ui-button>
42549
42552
  } @else if (importResult(current().key)) {
42550
- <ui-button variant="primary" size="lg" data-testid="wizard-continue" (click)="continueFromImport()">{{ t().continue }}</ui-button>
42553
+ <ui-button variant="primary" size="sm" data-testid="wizard-continue" (click)="continueFromImport()">{{ t().continue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg></ui-button>
42551
42554
  }
42552
42555
  </div>
42553
42556
  </div>
@@ -42557,7 +42560,7 @@ var SetupWizardComponent = class SetupWizardComponent {
42557
42560
  </div>
42558
42561
  `,
42559
42562
  isInline: true,
42560
- styles: [".sw-page{display:flex;min-height:100vh;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.sw-sidebar{width:260px;min-width:260px;background:#faf9f7;border-right:1px solid #e5e2dc;display:flex;flex-direction:column;justify-content:space-between;padding:28px 20px}.sw-brand{display:flex;align-items:center;gap:10px;margin-bottom:28px}.sw-brand-text{font-size:1.125rem;font-weight:700;color:#1e293b}.sw-step-nav{display:block}.sw-sidebar-bottom{margin-top:24px}.sw-progress-text{display:block;margin-top:8px;font-size:.75rem;color:#94a3b8}.sw-content{flex:1;min-width:0;background:#fff;display:flex;flex-direction:column;overflow-y:auto}.sw-content-header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 32px;border-bottom:1px solid #f1f5f9}.sw-step-title{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.sw-step-content{max-width:780px;padding:16px 48px 60px}.sw-step-desc{font-size:.9375rem;color:#6b7280;line-height:1.5;margin:0 0 32px}.sw-hint{font-size:.8125rem;color:#94a3b8;margin:0 0 16px}.sw-import-tags{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:28px}.sw-tag{font-size:.6875rem;font-weight:700;letter-spacing:1px;color:#6b7280}.sw-provider-grid{display:flex;flex-direction:column;gap:8px;margin-bottom:24px}.sw-area-code{display:flex;align-items:flex-end;gap:12px;padding:0 0 8px 4px;max-width:320px}.sw-area-code ui-text-input{flex:1}.sw-content ui-alert{display:block;margin-bottom:16px}.sw-step-actions{display:flex;justify-content:space-between;align-items:center;margin-top:16px;padding-top:20px;border-top:1px solid #f1f5f9}.sw-actions-right{display:flex;align-items:center;gap:16px}.sw-done{text-align:center;display:flex;flex-direction:column;align-items:center;max-width:none}.sw-done .sw-step-desc{max-width:480px}.sw-summary{display:block;width:100%;max-width:480px;margin-bottom:24px;text-align:left}.sw-done-hint{font-size:.8125rem;color:#9ca3af;margin-bottom:24px}@media(max-width:768px){.sw-page{flex-direction:column}.sw-sidebar{width:100%;min-width:unset;padding:16px}.sw-brand{margin-bottom:12px}.sw-sidebar-bottom{display:none}.sw-step-content{padding:12px 20px 40px}}\n"],
42563
+ styles: [".sw-page{display:flex;min-height:100vh;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.sw-sidebar{width:260px;min-width:260px;background:#faf9f7;border-right:1px solid #e5e2dc;display:flex;flex-direction:column;justify-content:space-between;padding:28px 20px}.sw-brand{display:flex;align-items:center;gap:10px;margin-bottom:28px}.sw-brand-text{font-size:1.125rem;font-weight:700;color:#1e293b}.sw-step-nav{display:block}.sw-sidebar-bottom{margin-top:24px}.sw-progress-text{display:block;margin-top:8px;font-size:.75rem;color:#94a3b8}.sw-content{flex:1;min-width:0;background:#fff;display:flex;flex-direction:column;overflow-y:auto}.sw-content-header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 32px;border-bottom:1px solid #f1f5f9}.sw-step-title{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.sw-step-content{max-width:780px;padding:16px 48px 60px}.sw-step-desc{font-size:.9375rem;color:#6b7280;line-height:1.5;margin:0 0 32px}.sw-hint{font-size:.8125rem;color:#94a3b8;margin:0 0 16px}.sw-import-tags{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:28px}.sw-tag{font-size:.6875rem;font-weight:700;letter-spacing:1px;color:#6b7280}.sw-provider-grid{display:flex;flex-direction:column;gap:8px;margin-bottom:24px}.sw-area-code{display:flex;align-items:flex-end;gap:12px;padding:0 0 8px 4px;max-width:320px}.sw-area-code ui-text-input{flex:1}.sw-content ui-alert{display:block;margin-bottom:16px}.sw-step-actions{display:flex;justify-content:space-between;align-items:center;margin-top:16px;padding-top:20px;border-top:1px solid #f1f5f9}.sw-ico{flex-shrink:0;vertical-align:-2px}.sw-actions-right{display:flex;align-items:center;gap:16px}.sw-done{text-align:center;display:flex;flex-direction:column;align-items:center;max-width:none}.sw-done .sw-step-desc{max-width:480px}.sw-summary{display:block;width:100%;max-width:480px;margin-bottom:24px;text-align:left}.sw-done-hint{font-size:.8125rem;color:#9ca3af;margin-bottom:24px}@media(max-width:768px){.sw-page{flex-direction:column}.sw-sidebar{width:100%;min-width:unset;padding:16px}.sw-brand{margin-bottom:12px}.sw-sidebar-bottom{display:none}.sw-step-content{padding:12px 20px 40px}}\n"],
42561
42564
  dependencies: [
42562
42565
  {
42563
42566
  kind: "directive",
@@ -42825,7 +42828,7 @@ i0.ɵɵngDeclareClassMetadata({
42825
42828
  <main class="sw-content">
42826
42829
  <div class="sw-content-header">
42827
42830
  <h1 class="sw-step-title" data-testid="wizard-step-title">{{ current().label }}</h1>
42828
- <ui-button variant="ghost" size="sm" data-testid="wizard-exit" (click)="exited.emit()">{{ t().exit }}</ui-button>
42831
+ <ui-button variant="ghost" size="sm" data-testid="wizard-exit" (click)="exited.emit()"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('close')" /></svg> {{ t().exit }}</ui-button>
42829
42832
  </div>
42830
42833
 
42831
42834
  @if (isDone()) {
@@ -42833,7 +42836,7 @@ i0.ɵɵngDeclareClassMetadata({
42833
42836
  <p class="sw-step-desc">{{ t().doneDescription }}</p>
42834
42837
  <ui-panel-info-list class="sw-summary" data-testid="wizard-summary" [sections]="summarySections()" />
42835
42838
  <p class="sw-done-hint">{{ t().doneHint }}</p>
42836
- <ui-button variant="primary" size="lg" data-testid="wizard-finish" (click)="finished.emit()">{{ t().finish }}</ui-button>
42839
+ <ui-button variant="primary" size="sm" data-testid="wizard-finish" (click)="finished.emit()"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('check')" /></svg> {{ t().finish }}</ui-button>
42837
42840
  </div>
42838
42841
  } @else {
42839
42842
  <div class="sw-step-content" [attr.data-step]="current().key">
@@ -42854,11 +42857,11 @@ i0.ɵɵngDeclareClassMetadata({
42854
42857
  @if (importResult(current().key); as res) {
42855
42858
  <ui-alert variant="success" [title]="importTitle(current().key)" [attr.data-testid]="'import-result-' + current().key">
42856
42859
  {{ imp.resultText }}
42857
- <ui-button variant="link" size="sm" data-testid="import-more" (click)="clearImport(current().key)">{{ t().importMore }}</ui-button>
42860
+ <ui-button variant="link" size="sm" data-testid="import-more" (click)="clearImport(current().key)"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('upload')" /></svg> {{ t().importMore }}</ui-button>
42858
42861
  </ui-alert>
42859
42862
  } @else {
42860
42863
  @if (imp.hint) { <p class="sw-hint">{{ imp.hint }}</p> }
42861
- <ui-button variant="primary" size="lg" [attr.data-testid]="'open-import-' + current().key" (click)="openImport(current().key)">{{ imp.buttonLabel }}</ui-button>
42864
+ <ui-button variant="primary" size="sm" [attr.data-testid]="'open-import-' + current().key" (click)="openImport(current().key)"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('upload')" /></svg> {{ imp.buttonLabel }}</ui-button>
42862
42865
  }
42863
42866
  <ui-import-export #importer style="display:none" [config]="imp.config" [importSources]="imp.sources" (imported)="onImported(current().key)" />
42864
42867
  }
@@ -42870,13 +42873,13 @@ i0.ɵɵngDeclareClassMetadata({
42870
42873
  [icon]="it.icon ?? 'link'" iconColor="blue" [title]="it.title" [details]="[detailFor(it)]"
42871
42874
  [badge]="t().connected" badgeVariant="green" [alwaysShowBadge]="isConnected(it)">
42872
42875
  <ui-button list-item-action variant="secondary" size="sm" [ariaLabel]="(isConnected(it) ? t().reconnect : t().connect) + ' ' + it.title" (click)="connect(it)">
42873
- {{ isConnected(it) ? t().reconnect : t().connect }}
42876
+ <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('link')" /></svg> {{ isConnected(it) ? t().reconnect : t().connect }}
42874
42877
  </ui-button>
42875
42878
  </ui-list-item>
42876
42879
  @if (areaCodeOpen() === it.key) {
42877
42880
  <div class="sw-area-code" [attr.data-testid]="'area-code-' + it.key">
42878
42881
  <ui-text-input [label]="areaCodeLabelFor(it)" [maxlength]="3" inputmode="numeric" [ngModel]="areaCode()" (ngModelChange)="areaCode.set($event ?? '')" [inputTestId]="'area-code-input-' + it.key" />
42879
- <ui-button variant="primary" size="sm" [loading]="busy()" [disabled]="!validAreaCode()" (click)="submitAreaCode(it)">{{ t().connect }}</ui-button>
42882
+ <ui-button variant="primary" size="sm" [loading]="busy()" [disabled]="!validAreaCode()" (click)="submitAreaCode(it)"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('link')" /></svg> {{ t().connect }}</ui-button>
42880
42883
  </div>
42881
42884
  }
42882
42885
  }
@@ -42887,19 +42890,19 @@ i0.ɵɵngDeclareClassMetadata({
42887
42890
  @if (error()) { <ui-alert variant="danger" data-testid="wizard-save-error">{{ error() }}</ui-alert> }
42888
42891
 
42889
42892
  <div class="sw-step-actions">
42890
- @if (index() > 0) { <ui-button variant="ghost" size="md" data-testid="wizard-back" [disabled]="busy()" (click)="back()">{{ t().back }}</ui-button> } @else { <span></span> }
42893
+ @if (index() > 0) { <ui-button variant="ghost" size="sm" data-testid="wizard-back" [disabled]="busy()" (click)="back()"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-left')" /></svg> {{ t().back }}</ui-button> } @else { <span></span> }
42891
42894
  <div class="sw-actions-right">
42892
42895
  @if (current().skippable !== false) {
42893
- <ui-button variant="ghost" size="md" data-testid="wizard-skip" [disabled]="busy()" (click)="skip()">{{ t().skip }}</ui-button>
42896
+ <ui-button variant="ghost" size="sm" data-testid="wizard-skip" [disabled]="busy()" (click)="skip()">{{ t().skip }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('chevron-right')" /></svg></ui-button>
42894
42897
  }
42895
42898
  @if (current().kind === 'custom') {
42896
- <ui-button variant="primary" size="lg" data-testid="wizard-save" [loading]="busy()" [disabled]="current().canContinue ? !current().canContinue!() : false" (click)="saveAndContinue()">
42897
- {{ current().saveLabel ?? t().saveAndContinue }}
42899
+ <ui-button variant="primary" size="sm" data-testid="wizard-save" [loading]="busy()" [disabled]="current().canContinue ? !current().canContinue!() : false" (click)="saveAndContinue()">
42900
+ {{ current().saveLabel ?? t().saveAndContinue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg>
42898
42901
  </ui-button>
42899
42902
  } @else if (current().kind === 'integrations') {
42900
- <ui-button variant="primary" size="lg" data-testid="wizard-save" [loading]="busy()" (click)="saveAndContinue()">{{ t().saveAndContinue }}</ui-button>
42903
+ <ui-button variant="primary" size="sm" data-testid="wizard-save" [loading]="busy()" (click)="saveAndContinue()">{{ t().saveAndContinue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg></ui-button>
42901
42904
  } @else if (importResult(current().key)) {
42902
- <ui-button variant="primary" size="lg" data-testid="wizard-continue" (click)="continueFromImport()">{{ t().continue }}</ui-button>
42905
+ <ui-button variant="primary" size="sm" data-testid="wizard-continue" (click)="continueFromImport()">{{ t().continue }} <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('arrow-right')" /></svg></ui-button>
42903
42906
  }
42904
42907
  </div>
42905
42908
  </div>
@@ -42908,7 +42911,7 @@ i0.ɵɵngDeclareClassMetadata({
42908
42911
  </main>
42909
42912
  </div>
42910
42913
  `,
42911
- styles: [".sw-page{display:flex;min-height:100vh;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.sw-sidebar{width:260px;min-width:260px;background:#faf9f7;border-right:1px solid #e5e2dc;display:flex;flex-direction:column;justify-content:space-between;padding:28px 20px}.sw-brand{display:flex;align-items:center;gap:10px;margin-bottom:28px}.sw-brand-text{font-size:1.125rem;font-weight:700;color:#1e293b}.sw-step-nav{display:block}.sw-sidebar-bottom{margin-top:24px}.sw-progress-text{display:block;margin-top:8px;font-size:.75rem;color:#94a3b8}.sw-content{flex:1;min-width:0;background:#fff;display:flex;flex-direction:column;overflow-y:auto}.sw-content-header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 32px;border-bottom:1px solid #f1f5f9}.sw-step-title{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.sw-step-content{max-width:780px;padding:16px 48px 60px}.sw-step-desc{font-size:.9375rem;color:#6b7280;line-height:1.5;margin:0 0 32px}.sw-hint{font-size:.8125rem;color:#94a3b8;margin:0 0 16px}.sw-import-tags{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:28px}.sw-tag{font-size:.6875rem;font-weight:700;letter-spacing:1px;color:#6b7280}.sw-provider-grid{display:flex;flex-direction:column;gap:8px;margin-bottom:24px}.sw-area-code{display:flex;align-items:flex-end;gap:12px;padding:0 0 8px 4px;max-width:320px}.sw-area-code ui-text-input{flex:1}.sw-content ui-alert{display:block;margin-bottom:16px}.sw-step-actions{display:flex;justify-content:space-between;align-items:center;margin-top:16px;padding-top:20px;border-top:1px solid #f1f5f9}.sw-actions-right{display:flex;align-items:center;gap:16px}.sw-done{text-align:center;display:flex;flex-direction:column;align-items:center;max-width:none}.sw-done .sw-step-desc{max-width:480px}.sw-summary{display:block;width:100%;max-width:480px;margin-bottom:24px;text-align:left}.sw-done-hint{font-size:.8125rem;color:#9ca3af;margin-bottom:24px}@media(max-width:768px){.sw-page{flex-direction:column}.sw-sidebar{width:100%;min-width:unset;padding:16px}.sw-brand{margin-bottom:12px}.sw-sidebar-bottom{display:none}.sw-step-content{padding:12px 20px 40px}}\n"]
42914
+ styles: [".sw-page{display:flex;min-height:100vh;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.sw-sidebar{width:260px;min-width:260px;background:#faf9f7;border-right:1px solid #e5e2dc;display:flex;flex-direction:column;justify-content:space-between;padding:28px 20px}.sw-brand{display:flex;align-items:center;gap:10px;margin-bottom:28px}.sw-brand-text{font-size:1.125rem;font-weight:700;color:#1e293b}.sw-step-nav{display:block}.sw-sidebar-bottom{margin-top:24px}.sw-progress-text{display:block;margin-top:8px;font-size:.75rem;color:#94a3b8}.sw-content{flex:1;min-width:0;background:#fff;display:flex;flex-direction:column;overflow-y:auto}.sw-content-header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 32px;border-bottom:1px solid #f1f5f9}.sw-step-title{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.sw-step-content{max-width:780px;padding:16px 48px 60px}.sw-step-desc{font-size:.9375rem;color:#6b7280;line-height:1.5;margin:0 0 32px}.sw-hint{font-size:.8125rem;color:#94a3b8;margin:0 0 16px}.sw-import-tags{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:28px}.sw-tag{font-size:.6875rem;font-weight:700;letter-spacing:1px;color:#6b7280}.sw-provider-grid{display:flex;flex-direction:column;gap:8px;margin-bottom:24px}.sw-area-code{display:flex;align-items:flex-end;gap:12px;padding:0 0 8px 4px;max-width:320px}.sw-area-code ui-text-input{flex:1}.sw-content ui-alert{display:block;margin-bottom:16px}.sw-step-actions{display:flex;justify-content:space-between;align-items:center;margin-top:16px;padding-top:20px;border-top:1px solid #f1f5f9}.sw-ico{flex-shrink:0;vertical-align:-2px}.sw-actions-right{display:flex;align-items:center;gap:16px}.sw-done{text-align:center;display:flex;flex-direction:column;align-items:center;max-width:none}.sw-done .sw-step-desc{max-width:480px}.sw-summary{display:block;width:100%;max-width:480px;margin-bottom:24px;text-align:left}.sw-done-hint{font-size:.8125rem;color:#9ca3af;margin-bottom:24px}@media(max-width:768px){.sw-page{flex-direction:column}.sw-sidebar{width:100%;min-width:unset;padding:16px}.sw-brand{margin-bottom:12px}.sw-sidebar-bottom{display:none}.sw-step-content{padding:12px 20px 40px}}\n"]
42912
42915
  }]
42913
42916
  }],
42914
42917
  ctorParameters: () => [],
@@ -43206,12 +43209,6 @@ const PLAYBACK_OPTIONS = [{
43206
43209
  value: "autoplay",
43207
43210
  label: "Autoplay"
43208
43211
  }];
43209
- const DEFAULT_AI_EXAMPLES = [
43210
- "Follow up after a showing",
43211
- "Open house invitation",
43212
- "Market update",
43213
- "Thank you after closing"
43214
- ];
43215
43212
  const DEFAULT_VIDEO_LINK = (video) => video.shareLink;
43216
43213
  const EMPTY_VIDEO_DEFAULTS = {
43217
43214
  autoplay: false,
@@ -43235,12 +43232,8 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43235
43232
  this.textEnabled = input(false, ...ngDevMode ? [{ debugName: "textEnabled" }] : /* istanbul ignore next */ []);
43236
43233
  this.variableGroups = input(DEFAULT_EMAIL_TEMPLATE_VARIABLE_GROUPS, ...ngDevMode ? [{ debugName: "variableGroups" }] : /* istanbul ignore next */ []);
43237
43234
  this.blockGroups = input(DEFAULT_EMAIL_TEMPLATE_BLOCK_GROUPS, ...ngDevMode ? [{ debugName: "blockGroups" }] : /* istanbul ignore next */ []);
43238
- this.aiExamples = input(DEFAULT_AI_EXAMPLES, ...ngDevMode ? [{ debugName: "aiExamples" }] : /* istanbul ignore next */ []);
43239
43235
  this.namePlaceholder = input("e.g. Follow-Up — Friendly", ...ngDevMode ? [{ debugName: "namePlaceholder" }] : /* istanbul ignore next */ []);
43240
43236
  this.subjectPlaceholder = input("e.g. Following up on {{property_address}}", ...ngDevMode ? [{ debugName: "subjectPlaceholder" }] : /* istanbul ignore next */ []);
43241
- this.backLabel = input("Email Messages", ...ngDevMode ? [{ debugName: "backLabel" }] : /* istanbul ignore next */ []);
43242
- this.createLabel = input("Create Template", ...ngDevMode ? [{ debugName: "createLabel" }] : /* istanbul ignore next */ []);
43243
- this.editLabel = input("Edit Template", ...ngDevMode ? [{ debugName: "editLabel" }] : /* istanbul ignore next */ []);
43244
43237
  this.systemNote = input("This is a built-in system template, so it can be viewed but not changed.", ...ngDevMode ? [{ debugName: "systemNote" }] : /* istanbul ignore next */ []);
43245
43238
  this.readOnlyNote = input("You have read-only access to email templates, so this template can be viewed but not saved.", ...ngDevMode ? [{ debugName: "readOnlyNote" }] : /* istanbul ignore next */ []);
43246
43239
  this.idPrefix = input("tpl", ...ngDevMode ? [{ debugName: "idPrefix" }] : /* istanbul ignore next */ []);
@@ -43248,21 +43241,19 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43248
43241
  this.maxTextLength = input(255, ...ngDevMode ? [{ debugName: "maxTextLength" }] : /* istanbul ignore next */ []);
43249
43242
  this.fullAccess = input(true, ...ngDevMode ? [{ debugName: "fullAccess" }] : /* istanbul ignore next */ []);
43250
43243
  this.systemTemplate = input(false, ...ngDevMode ? [{ debugName: "systemTemplate" }] : /* istanbul ignore next */ []);
43251
- this.aiEnabled = input(true, ...ngDevMode ? [{ debugName: "aiEnabled" }] : /* istanbul ignore next */ []);
43252
43244
  this.testSendEnabled = input(true, ...ngDevMode ? [{ debugName: "testSendEnabled" }] : /* istanbul ignore next */ []);
43253
- this.videosEnabled = input(true, ...ngDevMode ? [{ debugName: "videosEnabled" }] : /* istanbul ignore next */ []);
43254
43245
  this.saving = input(false, ...ngDevMode ? [{ debugName: "saving" }] : /* istanbul ignore next */ []);
43255
43246
  this.testSending = input(false, ...ngDevMode ? [{ debugName: "testSending" }] : /* istanbul ignore next */ []);
43256
- this.aiGenerating = input(false, ...ngDevMode ? [{ debugName: "aiGenerating" }] : /* istanbul ignore next */ []);
43257
- this.videos = input([], ...ngDevMode ? [{ debugName: "videos" }] : /* istanbul ignore next */ []);
43247
+ this.videos = input(null, ...ngDevMode ? [{ debugName: "videos" }] : /* istanbul ignore next */ []);
43248
+ this.hideVideos = input(false, ...ngDevMode ? [{ debugName: "hideVideos" }] : /* istanbul ignore next */ []);
43249
+ this.videosEnabled = computed(() => this.videos() !== null && !this.hideVideos(), ...ngDevMode ? [{ debugName: "videosEnabled" }] : /* istanbul ignore next */ []);
43250
+ this.videoList = computed(() => this.videos() ?? [], ...ngDevMode ? [{ debugName: "videoList" }] : /* istanbul ignore next */ []);
43258
43251
  this.videosLoading = input(false, ...ngDevMode ? [{ debugName: "videosLoading" }] : /* istanbul ignore next */ []);
43259
43252
  this.videoDefaults = input(EMPTY_VIDEO_DEFAULTS, ...ngDevMode ? [{ debugName: "videoDefaults" }] : /* istanbul ignore next */ []);
43260
43253
  this.videoLink = input(DEFAULT_VIDEO_LINK, ...ngDevMode ? [{ debugName: "videoLink" }] : /* istanbul ignore next */ []);
43261
43254
  this.noVideosHint = input("Upload videos on the Video Messages page.", ...ngDevMode ? [{ debugName: "noVideosHint" }] : /* istanbul ignore next */ []);
43262
- this.back = output();
43263
43255
  this.save = output();
43264
43256
  this.testSend = output();
43265
- this.aiGenerate = output();
43266
43257
  this.videosRequested = output();
43267
43258
  this.useAsMine = output();
43268
43259
  this.editingId = signal(null, ...ngDevMode ? [{ debugName: "editingId" }] : /* istanbul ignore next */ []);
@@ -43311,8 +43302,6 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43311
43302
  this.imageAlt = signal("", ...ngDevMode ? [{ debugName: "imageAlt" }] : /* istanbul ignore next */ []);
43312
43303
  this.showTestSendDialog = signal(false, ...ngDevMode ? [{ debugName: "showTestSendDialog" }] : /* istanbul ignore next */ []);
43313
43304
  this.testSendEmail = signal("", ...ngDevMode ? [{ debugName: "testSendEmail" }] : /* istanbul ignore next */ []);
43314
- this.showAiPanel = signal(false, ...ngDevMode ? [{ debugName: "showAiPanel" }] : /* istanbul ignore next */ []);
43315
- this.aiPrompt = signal("", ...ngDevMode ? [{ debugName: "aiPrompt" }] : /* istanbul ignore next */ []);
43316
43305
  this.showAssignmentConfig = signal(false, ...ngDevMode ? [{ debugName: "showAssignmentConfig" }] : /* istanbul ignore next */ []);
43317
43306
  this.configTarget = signal(null, ...ngDevMode ? [{ debugName: "configTarget" }] : /* istanbul ignore next */ []);
43318
43307
  this.configEmail = signal(false, ...ngDevMode ? [{ debugName: "configEmail" }] : /* istanbul ignore next */ []);
@@ -43371,8 +43360,14 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43371
43360
  if (this.useAllYear() || !this.activeFrom() || !this.activeTo()) return "";
43372
43361
  return this.activeTo() < this.activeFrom() ? "Active To must be on or after Active From." : "";
43373
43362
  }, ...ngDevMode ? [{ debugName: "datesError" }] : /* istanbul ignore next */ []);
43363
+ this.submitAttempted = signal(false, ...ngDevMode ? [{ debugName: "submitAttempted" }] : /* istanbul ignore next */ []);
43364
+ this.nameTouched = signal(false, ...ngDevMode ? [{ debugName: "nameTouched" }] : /* istanbul ignore next */ []);
43365
+ this.subjectTouched = signal(false, ...ngDevMode ? [{ debugName: "subjectTouched" }] : /* istanbul ignore next */ []);
43366
+ this.nameErrorShown = computed(() => this.nameTouched() || this.submitAttempted() ? this.nameError() : "", ...ngDevMode ? [{ debugName: "nameErrorShown" }] : /* istanbul ignore next */ []);
43367
+ this.subjectErrorShown = computed(() => this.subjectTouched() || this.submitAttempted() ? this.subjectError() : "", ...ngDevMode ? [{ debugName: "subjectErrorShown" }] : /* istanbul ignore next */ []);
43368
+ this.bodyErrorShown = computed(() => this.bodyEdited() || this.submitAttempted() ? this.bodyError() : "", ...ngDevMode ? [{ debugName: "bodyErrorShown" }] : /* istanbul ignore next */ []);
43374
43369
  this.canSave = computed(() => !this.nameError() && !this.subjectError() && !this.bodyError() && !this.datesError(), ...ngDevMode ? [{ debugName: "canSave" }] : /* istanbul ignore next */ []);
43375
- this.saveDisabled = computed(() => !this.canWrite() || !this.canSave(), ...ngDevMode ? [{ debugName: "saveDisabled" }] : /* istanbul ignore next */ []);
43370
+ this.saveDisabled = computed(() => !this.canWrite(), ...ngDevMode ? [{ debugName: "saveDisabled" }] : /* istanbul ignore next */ []);
43376
43371
  this.normalizedLink = computed(() => {
43377
43372
  const url = this.linkUrl().trim();
43378
43373
  if (!url) return "";
@@ -43396,7 +43391,6 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43396
43391
  }, ...ngDevMode ? [{ debugName: "testEmailError" }] : /* istanbul ignore next */ []);
43397
43392
  this.canSendTest = computed(() => this.canWrite() && !!this.editingId() && !!this.testSendEmail().trim() && !this.testEmailError() && !this.testSending(), ...ngDevMode ? [{ debugName: "canSendTest" }] : /* istanbul ignore next */ []);
43398
43393
  this.hasUnsavedChanges = computed(() => !!this.editingId() && this.savedSnapshot() !== null && this.savedSnapshot() !== this.snapshot(), ...ngDevMode ? [{ debugName: "hasUnsavedChanges" }] : /* istanbul ignore next */ []);
43399
- this.canGenerate = computed(() => !!this.aiPrompt().trim() && !this.aiGenerating(), ...ngDevMode ? [{ debugName: "canGenerate" }] : /* istanbul ignore next */ []);
43400
43394
  effect(() => {
43401
43395
  const t = this.template();
43402
43396
  untracked(() => this.applyTemplate(t));
@@ -43412,6 +43406,9 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43412
43406
  this.videoHideReactions.set(d.hideReactions);
43413
43407
  });
43414
43408
  });
43409
+ effect(() => {
43410
+ if (!this.videosEnabled() && this.activeRightTab() === "video") untracked(() => this.activeRightTab.set("blocks"));
43411
+ });
43415
43412
  effect(() => {
43416
43413
  if (this.showLinkDialog() || this.showImageDialog()) afterNextRender(() => this.host.nativeElement.querySelector(".link-dialog input")?.focus(), { injector: this.injector });
43417
43414
  });
@@ -43439,17 +43436,6 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43439
43436
  closeTestSend() {
43440
43437
  this.showTestSendDialog.set(false);
43441
43438
  }
43442
- addGeneratedHtml(html) {
43443
- const block = {
43444
- id: this.genId(),
43445
- html: this.stripBlockWrappers(html)
43446
- };
43447
- this.blocks.update((b) => [...b, block]);
43448
- this.bodyEdited.set(true);
43449
- this.selectedBlockId.set(block.id);
43450
- this.showAiPanel.set(false);
43451
- this.toast.show("AI content added to your email");
43452
- }
43453
43439
  applyTemplate(t) {
43454
43440
  this.initializedBlockIds = /* @__PURE__ */ new Set();
43455
43441
  this.editingId.set(t?.id ?? null);
@@ -43469,6 +43455,9 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43469
43455
  this.blockSpacing.set("");
43470
43456
  this.loadedBody.set(t?.id ? t.body ?? "" : null);
43471
43457
  this.bodyEdited.set(false);
43458
+ this.submitAttempted.set(false);
43459
+ this.nameTouched.set(false);
43460
+ this.subjectTouched.set(false);
43472
43461
  this.assignmentChannels.set(Object.fromEntries((t?.assignments ?? []).map((c) => [c.key, {
43473
43462
  email: !!c.email,
43474
43463
  text: !!c.text
@@ -43476,7 +43465,11 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43476
43465
  this.savedSnapshot.set(t?.id ? this.snapshot() : null);
43477
43466
  }
43478
43467
  onSave() {
43479
- if (this.saving() || !this.canSave() || !this.canWrite()) return;
43468
+ if (this.saving() || !this.canWrite()) return;
43469
+ if (!this.canSave()) {
43470
+ this.submitAttempted.set(true);
43471
+ return;
43472
+ }
43480
43473
  const keepStoredBody = this.bodyUnchanged() && this.bodyLength() > this.maxBodyLength();
43481
43474
  this.syncActiveBlockHtml();
43482
43475
  this.save.emit({
@@ -43538,10 +43531,6 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43538
43531
  html
43539
43532
  }];
43540
43533
  }
43541
- stripBlockWrappers(html) {
43542
- if (!html || !html.includes("data-block")) return html;
43543
- return html.replace(/<\/div>\s*(?=<div[^>]*data-block)/g, "").replace(/<div[^>]*data-block[^>]*>/g, "").replace(/<\/div>\s*$/, "");
43544
- }
43545
43534
  genId() {
43546
43535
  return Math.random().toString(36).slice(2, 10);
43547
43536
  }
@@ -43893,15 +43882,6 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43893
43882
  if (!this.canSendTest()) return;
43894
43883
  this.testSend.emit(this.testSendEmail().trim());
43895
43884
  }
43896
- openAiPanel() {
43897
- if (!this.canWrite() || !this.aiEnabled()) return;
43898
- this.aiPrompt.set("");
43899
- this.showAiPanel.set(true);
43900
- }
43901
- onAiGenerate() {
43902
- if (!this.canWrite() || !this.canGenerate()) return;
43903
- this.aiGenerate.emit(this.aiPrompt());
43904
- }
43905
43885
  openVideoTab() {
43906
43886
  this.activeRightTab.set("video");
43907
43887
  this.videosRequested.emit();
@@ -44060,13 +44040,6 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44060
44040
  isRequired: false,
44061
44041
  transformFunction: null
44062
44042
  },
44063
- aiExamples: {
44064
- classPropertyName: "aiExamples",
44065
- publicName: "aiExamples",
44066
- isSignal: true,
44067
- isRequired: false,
44068
- transformFunction: null
44069
- },
44070
44043
  namePlaceholder: {
44071
44044
  classPropertyName: "namePlaceholder",
44072
44045
  publicName: "namePlaceholder",
@@ -44081,27 +44054,6 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44081
44054
  isRequired: false,
44082
44055
  transformFunction: null
44083
44056
  },
44084
- backLabel: {
44085
- classPropertyName: "backLabel",
44086
- publicName: "backLabel",
44087
- isSignal: true,
44088
- isRequired: false,
44089
- transformFunction: null
44090
- },
44091
- createLabel: {
44092
- classPropertyName: "createLabel",
44093
- publicName: "createLabel",
44094
- isSignal: true,
44095
- isRequired: false,
44096
- transformFunction: null
44097
- },
44098
- editLabel: {
44099
- classPropertyName: "editLabel",
44100
- publicName: "editLabel",
44101
- isSignal: true,
44102
- isRequired: false,
44103
- transformFunction: null
44104
- },
44105
44057
  systemNote: {
44106
44058
  classPropertyName: "systemNote",
44107
44059
  publicName: "systemNote",
@@ -44151,13 +44103,6 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44151
44103
  isRequired: false,
44152
44104
  transformFunction: null
44153
44105
  },
44154
- aiEnabled: {
44155
- classPropertyName: "aiEnabled",
44156
- publicName: "aiEnabled",
44157
- isSignal: true,
44158
- isRequired: false,
44159
- transformFunction: null
44160
- },
44161
44106
  testSendEnabled: {
44162
44107
  classPropertyName: "testSendEnabled",
44163
44108
  publicName: "testSendEnabled",
@@ -44165,13 +44110,6 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44165
44110
  isRequired: false,
44166
44111
  transformFunction: null
44167
44112
  },
44168
- videosEnabled: {
44169
- classPropertyName: "videosEnabled",
44170
- publicName: "videosEnabled",
44171
- isSignal: true,
44172
- isRequired: false,
44173
- transformFunction: null
44174
- },
44175
44113
  saving: {
44176
44114
  classPropertyName: "saving",
44177
44115
  publicName: "saving",
@@ -44186,16 +44124,16 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44186
44124
  isRequired: false,
44187
44125
  transformFunction: null
44188
44126
  },
44189
- aiGenerating: {
44190
- classPropertyName: "aiGenerating",
44191
- publicName: "aiGenerating",
44127
+ videos: {
44128
+ classPropertyName: "videos",
44129
+ publicName: "videos",
44192
44130
  isSignal: true,
44193
44131
  isRequired: false,
44194
44132
  transformFunction: null
44195
44133
  },
44196
- videos: {
44197
- classPropertyName: "videos",
44198
- publicName: "videos",
44134
+ hideVideos: {
44135
+ classPropertyName: "hideVideos",
44136
+ publicName: "hideVideos",
44199
44137
  isSignal: true,
44200
44138
  isRequired: false,
44201
44139
  transformFunction: null
@@ -44230,10 +44168,8 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44230
44168
  }
44231
44169
  },
44232
44170
  outputs: {
44233
- back: "back",
44234
44171
  save: "save",
44235
44172
  testSend: "testSend",
44236
- aiGenerate: "aiGenerate",
44237
44173
  videosRequested: "videosRequested",
44238
44174
  useAsMine: "useAsMine"
44239
44175
  },
@@ -44252,31 +44188,20 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44252
44188
  ngImport: i0,
44253
44189
  template: `
44254
44190
  <div class="editor-page">
44255
- <!-- Top Bar -->
44256
- <div class="editor-topbar">
44257
- <div class="topbar-left">
44258
- <ui-button variant="ghost" size="sm" ariaLabel="Go back" (click)="back.emit()">
44259
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M15 18l-6-6 6-6"/></svg>
44191
+ <!-- Actions (outside the white panels) -->
44192
+ <div class="editor-actions">
44193
+ @if (canWrite() && testSendEnabled()) {
44194
+ <ui-button variant="secondary" size="sm" (click)="openTestSendDialog()">
44195
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
44196
+ Test Send
44260
44197
  </ui-button>
44261
- <nav class="breadcrumb" aria-label="Breadcrumb">
44262
- <a href="#" (click)="$event.preventDefault(); back.emit()">{{ backLabel() }}</a>
44263
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M9 18l6-6-6-6"/></svg>
44264
- <span>{{ isNew() ? createLabel() : editLabel() }}</span>
44265
- </nav>
44266
- </div>
44267
- <div class="topbar-right">
44268
- @if (canWrite() && testSendEnabled()) {
44269
- <ui-button variant="secondary" size="sm" (click)="openTestSendDialog()">
44270
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
44271
- Test Send
44272
- </ui-button>
44273
- }
44274
- <ui-button variant="primary" size="sm" [loading]="saving()" [disabled]="saveDisabled()" (click)="onSave()">
44275
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>
44276
- Save Template
44277
- </ui-button>
44278
- </div>
44198
+ }
44199
+ <ui-button variant="primary" size="sm" [loading]="saving()" [disabled]="saveDisabled()" (click)="onSave()">
44200
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>
44201
+ Save Template
44202
+ </ui-button>
44279
44203
  </div>
44204
+ <ui-divider />
44280
44205
 
44281
44206
  @if (systemTemplate()) {
44282
44207
  <div class="readonly-note system-note" role="note" data-testid="editor-system-note">
@@ -44297,15 +44222,12 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44297
44222
 
44298
44223
  <div class="form-field">
44299
44224
  <ui-text-input label="Name" [required]="true" [(ngModel)]="name" [readonly]="!canWrite()" [maxlength]="maxTextLength()"
44300
- [placeholder]="namePlaceholder()" [error]="nameError()" />
44225
+ [placeholder]="namePlaceholder()" [error]="nameErrorShown()" (blurred)="nameTouched.set(true)" />
44301
44226
  </div>
44302
44227
 
44303
44228
  <div class="form-field">
44304
44229
  <ui-text-input label="Subject" [required]="true" [(ngModel)]="subject" [readonly]="!canWrite()" [maxlength]="maxTextLength()"
44305
- [placeholder]="subjectPlaceholder()" [error]="subjectError()">
44306
- @if (canWrite()) {
44307
- <span uiLabelEnd><ng-content select="[uiSubjectAction]" /></span>
44308
- }
44230
+ [placeholder]="subjectPlaceholder()" [error]="subjectErrorShown()" (blurred)="subjectTouched.set(true)">
44309
44231
  </ui-text-input>
44310
44232
  </div>
44311
44233
 
@@ -44328,7 +44250,10 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44328
44250
  <h4 class="section-title">Assignments</h4>
44329
44251
  <p class="section-desc">{{ assignmentsDescription() }}</p>
44330
44252
  <ui-search-input placeholder="Search..." ariaLabel="Search assignments" [(value)]="assignmentSearch" />
44331
- <div class="assignment-list">
44253
+ @if (filteredAssignments().length === 0) {
44254
+ <ui-empty-state iconType="search" title="No assignments found" message="No assignments match your search." />
44255
+ }
44256
+ <div class="assignment-list" [hidden]="filteredAssignments().length === 0">
44332
44257
  @for (item of filteredAssignments(); track item.key) {
44333
44258
  <div class="assignment-item" [class.assignment-readonly]="!canWrite()" [attr.role]="canWrite() ? 'button' : null" [attr.tabindex]="canWrite() ? 0 : null"
44334
44259
  [attr.aria-label]="canWrite() ? 'Configure ' + item.name : null"
@@ -44374,9 +44299,9 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44374
44299
  <!-- Toolbar row 1: mousedown preventDefault keeps focus (and the selection) in the editor -->
44375
44300
  <div class="editor-toolbar" role="toolbar" aria-label="Text formatting" (mousedown)="preventFocusLoss($event)">
44376
44301
  <div class="toolbar-group">
44377
- <ui-button variant="icon" size="sm" ariaLabel="Bold" uiTooltip="Bold" (click)="execCommand('bold')"><strong>B</strong></ui-button>
44378
- <ui-button variant="icon" size="sm" ariaLabel="Italic" uiTooltip="Italic" (click)="execCommand('italic')"><em>I</em></ui-button>
44379
- <ui-button variant="icon" size="sm" ariaLabel="Underline" uiTooltip="Underline" (click)="execCommand('underline')"><u>U</u></ui-button>
44302
+ <ui-button variant="ghost" size="sm" ariaLabel="Bold" uiTooltip="Bold" (click)="execCommand('bold')"><strong>B</strong></ui-button>
44303
+ <ui-button variant="ghost" size="sm" ariaLabel="Italic" uiTooltip="Italic" (click)="execCommand('italic')"><em>I</em></ui-button>
44304
+ <ui-button variant="ghost" size="sm" ariaLabel="Underline" uiTooltip="Underline" (click)="execCommand('underline')"><u>U</u></ui-button>
44380
44305
  </div>
44381
44306
  <div class="toolbar-group">
44382
44307
  @for (k of [headingKey()]; track k) {
@@ -44391,28 +44316,28 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44391
44316
  }
44392
44317
  </div>
44393
44318
  <div class="toolbar-group">
44394
- <ui-button variant="icon" size="sm" ariaLabel="Align left" uiTooltip="Align Left" (click)="execCommand('justifyLeft')">
44319
+ <ui-button variant="ghost" size="sm" ariaLabel="Align left" uiTooltip="Align Left" (click)="execCommand('justifyLeft')">
44395
44320
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="17" y1="10" x2="3" y2="10"/><line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="14" x2="3" y2="14"/><line x1="17" y1="18" x2="3" y2="18"/></svg>
44396
44321
  </ui-button>
44397
- <ui-button variant="icon" size="sm" ariaLabel="Align center" uiTooltip="Align Center" (click)="execCommand('justifyCenter')">
44322
+ <ui-button variant="ghost" size="sm" ariaLabel="Align center" uiTooltip="Align Center" (click)="execCommand('justifyCenter')">
44398
44323
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="18" y1="10" x2="6" y2="10"/><line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="14" x2="3" y2="14"/><line x1="18" y1="18" x2="6" y2="18"/></svg>
44399
44324
  </ui-button>
44400
- <ui-button variant="icon" size="sm" ariaLabel="Align right" uiTooltip="Align Right" (click)="execCommand('justifyRight')">
44325
+ <ui-button variant="ghost" size="sm" ariaLabel="Align right" uiTooltip="Align Right" (click)="execCommand('justifyRight')">
44401
44326
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="21" y1="10" x2="7" y2="10"/><line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="14" x2="3" y2="14"/><line x1="21" y1="18" x2="7" y2="18"/></svg>
44402
44327
  </ui-button>
44403
44328
  </div>
44404
44329
  <div class="toolbar-group">
44405
- <ui-button variant="icon" size="sm" ariaLabel="Bulleted list" uiTooltip="Bulleted List" (click)="execCommand('insertUnorderedList')">
44330
+ <ui-button variant="ghost" size="sm" ariaLabel="Bulleted list" uiTooltip="Bulleted List" (click)="execCommand('insertUnorderedList')">
44406
44331
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>
44407
44332
  </ui-button>
44408
- <ui-button variant="icon" size="sm" ariaLabel="Numbered list" uiTooltip="Numbered List" (click)="execCommand('insertOrderedList')">
44333
+ <ui-button variant="ghost" size="sm" ariaLabel="Numbered list" uiTooltip="Numbered List" (click)="execCommand('insertOrderedList')">
44409
44334
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/></svg>
44410
44335
  </ui-button>
44411
44336
  </div>
44412
44337
  <div class="toolbar-group">
44413
44338
  <!-- The browser's own colour dialog is the picker; a button opens it so the toolbar keeps one look. -->
44414
44339
  <input #colorInput type="color" class="hidden-color-input" aria-label="Text color" tabindex="-1" [value]="currentColor()" (change)="applyTextColor($any($event.target).value)" (mousedown)="$event.stopPropagation()" />
44415
- <ui-button variant="icon" size="sm" ariaLabel="Text color" uiTooltip="Text Color" (mousedown)="openColorPicker()">
44340
+ <ui-button variant="ghost" size="sm" ariaLabel="Text color" uiTooltip="Text Color" (mousedown)="openColorPicker()">
44416
44341
  <span class="color-indicator">
44417
44342
  <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><text y="20" font-size="20" font-weight="700">A</text></svg>
44418
44343
  <span class="color-bar" [style.background]="currentColor()"></span>
@@ -44420,35 +44345,29 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44420
44345
  </ui-button>
44421
44346
  </div>
44422
44347
  <div class="toolbar-group">
44423
- <ui-button variant="icon" size="sm" ariaLabel="Insert link" uiTooltip="Insert Link" (mousedown)="saveSelection()" (click)="openLinkDialog()">
44348
+ <ui-button variant="ghost" size="sm" ariaLabel="Insert link" uiTooltip="Insert Link" (mousedown)="saveSelection()" (click)="openLinkDialog()">
44424
44349
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
44425
44350
  </ui-button>
44426
- <ui-button variant="icon" size="sm" ariaLabel="Insert image" uiTooltip="Insert Image" (mousedown)="saveSelection()" (click)="openImageDialog()">
44351
+ <ui-button variant="ghost" size="sm" ariaLabel="Insert image" uiTooltip="Insert Image" (mousedown)="saveSelection()" (click)="openImageDialog()">
44427
44352
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
44428
44353
  </ui-button>
44429
44354
  </div>
44430
44355
  <div class="toolbar-group">
44431
- <ui-button variant="icon" size="sm" ariaLabel="Undo" uiTooltip="Undo" (click)="execCommand('undo')">
44356
+ <ui-button variant="ghost" size="sm" ariaLabel="Undo" uiTooltip="Undo" (click)="execCommand('undo')">
44432
44357
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M3 7v6h6"/><path d="M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6.69 3L3 13"/></svg>
44433
44358
  </ui-button>
44434
- <ui-button variant="icon" size="sm" ariaLabel="Redo" uiTooltip="Redo" (click)="execCommand('redo')">
44359
+ <ui-button variant="ghost" size="sm" ariaLabel="Redo" uiTooltip="Redo" (click)="execCommand('redo')">
44435
44360
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 7v6h-6"/><path d="M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6.69 3L21 13"/></svg>
44436
44361
  </ui-button>
44437
44362
  </div>
44438
44363
  </div>
44439
44364
 
44440
- <!-- Toolbar row 2: block spacing + AI -->
44365
+ <!-- Toolbar row 2: block spacing -->
44441
44366
  <div class="toolbar-row-2">
44442
44367
  <div class="toolbar-group" (mousedown)="preventFocusLoss($event)">
44443
44368
  <span class="toolbar-label" id="tpl-spacing-label">Block spacing</span>
44444
44369
  <ui-select class="toolbar-select" size="sm" ariaLabel="Block spacing" [options]="spacingOptions" [ngModel]="blockSpacing()" (ngModelChange)="applySpacing($event)" />
44445
44370
  </div>
44446
- @if (aiEnabled()) {
44447
- <ui-button variant="secondary" size="sm" (click)="openAiPanel()">
44448
- <span class="ai-dot" aria-hidden="true"></span>
44449
- Generate with AI
44450
- </ui-button>
44451
- }
44452
44371
  </div>
44453
44372
  }
44454
44373
 
@@ -44484,7 +44403,7 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44484
44403
  </div>
44485
44404
  }
44486
44405
 
44487
- <ui-error [errorId]="idPrefix() + '-body-error'" [message]="bodyError()" />
44406
+ <ui-error [errorId]="idPrefix() + '-body-error'" [message]="bodyErrorShown()" />
44488
44407
 
44489
44408
  <!-- Block Canvas with DnD -->
44490
44409
  <div class="blocks-canvas" (dragover)="onCanvasDragOver($event)" (drop)="onDropZoneDrop($event, blocks().length)">
@@ -44509,16 +44428,16 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44509
44428
 
44510
44429
  @if (canWrite()) {
44511
44430
  <div class="block-controls">
44512
- <ui-button variant="icon" size="xs" ariaLabel="Move block up" uiTooltip="Move up" [disabled]="i === 0" (mousedown)="preventFocusLoss($event)" (click)="moveBlock(i, -1)">
44431
+ <ui-button variant="ghost" size="xs" ariaLabel="Move block up" uiTooltip="Move up" [disabled]="i === 0" (mousedown)="preventFocusLoss($event)" (click)="moveBlock(i, -1)">
44513
44432
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M18 15l-6-6-6 6"/></svg>
44514
44433
  </ui-button>
44515
- <ui-button variant="icon" size="xs" ariaLabel="Move block down" uiTooltip="Move down" [disabled]="i === blocks().length - 1" (mousedown)="preventFocusLoss($event)" (click)="moveBlock(i, 1)">
44434
+ <ui-button variant="ghost" size="xs" ariaLabel="Move block down" uiTooltip="Move down" [disabled]="i === blocks().length - 1" (mousedown)="preventFocusLoss($event)" (click)="moveBlock(i, 1)">
44516
44435
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
44517
44436
  </ui-button>
44518
- <ui-button variant="icon" size="xs" ariaLabel="Duplicate block" uiTooltip="Duplicate" (mousedown)="preventFocusLoss($event)" (click)="duplicateBlock(i)">
44437
+ <ui-button variant="ghost" size="xs" ariaLabel="Duplicate block" uiTooltip="Duplicate" (mousedown)="preventFocusLoss($event)" (click)="duplicateBlock(i)">
44519
44438
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
44520
44439
  </ui-button>
44521
- <ui-button variant="icon-danger" size="xs" ariaLabel="Delete block" uiTooltip="Delete block" (mousedown)="preventFocusLoss($event)" (click)="deleteBlock(i)">
44440
+ <ui-button variant="ghost" size="xs" ariaLabel="Delete block" uiTooltip="Delete block" (mousedown)="preventFocusLoss($event)" (click)="deleteBlock(i)">
44522
44441
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6M14 11v6"/></svg>
44523
44442
  </ui-button>
44524
44443
  </div>
@@ -44586,6 +44505,9 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44586
44505
  <p class="right-section-desc">Click to insert or drag into the editor.</p>
44587
44506
  <ui-search-input placeholder="Search blocks..." ariaLabel="Search blocks" [(value)]="blockSearch" />
44588
44507
 
44508
+ @if (filteredBlockGroups().length === 0) {
44509
+ <ui-empty-state iconType="search" title="No blocks found" message="No blocks match your search." />
44510
+ }
44589
44511
  @for (group of filteredBlockGroups(); track group.name) {
44590
44512
  <div class="block-group">
44591
44513
  <button type="button" class="block-group-header" [attr.aria-expanded]="isOpen('b:' + group.name)" (click)="toggleGroup('b:' + group.name)">
@@ -44670,15 +44592,11 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44670
44592
  </div>
44671
44593
  }
44672
44594
  </div>
44673
- } @else if (videos().length === 0) {
44674
- <div class="video-lib-empty">
44675
- <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="1.5" aria-hidden="true"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/></svg>
44676
- <p>No videos yet</p>
44677
- <span>{{ noVideosHint() }}</span>
44678
- </div>
44595
+ } @else if (videoList().length === 0) {
44596
+ <ui-empty-state iconType="video" title="No videos created" [message]="noVideosHint()" />
44679
44597
  } @else {
44680
44598
  <div class="video-lib-list">
44681
- @for (video of videos(); track video.id) {
44599
+ @for (video of videoList(); track video.id) {
44682
44600
  <button type="button" class="video-lib-item" [class.selected]="video.id === videoId()" [attr.aria-pressed]="video.id === videoId()" (click)="insertVideo(video)">
44683
44601
  <span class="vli-thumb">
44684
44602
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="1.5" aria-hidden="true"><polygon points="5 3 19 12 5 21 5 3"/></svg>
@@ -44724,20 +44642,6 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44724
44642
  }
44725
44643
  </ui-side-panel>
44726
44644
 
44727
- <!-- AI Generate -->
44728
- <ui-side-panel [open]="showAiPanel()" title="Generate with AI" primaryLabel="Generate" [primaryLoading]="aiGenerating()" [primaryDisabled]="!canGenerate()"
44729
- (closed)="showAiPanel.set(false)" (primaryClick)="onAiGenerate()">
44730
- <p class="config-desc">Describe the email you want to write. The AI will generate professional content and add it as a new block.</p>
44731
- <div class="ai-prompt-examples">
44732
- <span class="ai-example-label">Try:</span>
44733
- @for (ex of aiExamples(); track ex) {
44734
- <ui-chip [label]="ex" size="sm" (select)="aiPrompt.set(ex)" />
44735
- }
44736
- </div>
44737
- <div class="config-field config-field-mt">
44738
- <ui-textarea-input label="What do you want to write?" [rows]="5" placeholder="e.g. A friendly follow-up email for a buyer who attended an open house last weekend" [(ngModel)]="aiPrompt" />
44739
- </div>
44740
- </ui-side-panel>
44741
44645
 
44742
44646
  <!-- Assignment config -->
44743
44647
  <ui-side-panel [wide]="true" [open]="showAssignmentConfig()" [title]="configTarget()?.name || 'Configure Automation'" primaryLabel="Save Configuration"
@@ -44763,7 +44667,7 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44763
44667
  </ui-side-panel>
44764
44668
  `,
44765
44669
  isInline: true,
44766
- styles: [":host{display:block}.required{color:#ef4444;font-weight:400}.editor-page{display:flex;flex-direction:column;height:100vh;height:100dvh;background:#f8fafc;overflow:hidden}.editor-topbar{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap;padding:12px 24px;background:#fff;border-bottom:1px solid #e2e8f0;flex-shrink:0}.topbar-left{display:flex;align-items:center;gap:8px;min-width:0}.topbar-right{display:flex;align-items:center;gap:8px}.breadcrumb{display:flex;align-items:center;gap:6px;font-size:.9375rem;font-weight:700;color:#1e293b;min-width:0}.breadcrumb a{color:#1e293b;text-decoration:none;cursor:pointer}.breadcrumb a:hover{color:#3b82f6}.breadcrumb svg{color:#94a3b8;flex-shrink:0}.breadcrumb span{color:#64748b;font-weight:500}.readonly-note{margin:0;padding:8px 16px;font-size:.8125rem;color:#92400e;background:#fffbeb;border-bottom:1px solid #fde68a}.readonly-note.system-note{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.editor-body{display:grid;grid-template-columns:340px minmax(0,1fr) 300px;flex:1;min-height:0;overflow:hidden}.panel-left{background:#fff;border-right:1px solid #e2e8f0;padding:24px;overflow-y:auto}.panel-title{font-size:1.0625rem;font-weight:700;color:#1e293b;margin:0 0 20px}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:16px}.form-row-dates{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:16px}.assignments-section{border-top:1px solid #e2e8f0;padding-top:20px;margin-top:16px}.section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 6px}.section-desc{font-size:.8125rem;color:#64748b;line-height:1.5;margin:0 0 12px}.assignment-list{max-height:340px;overflow-y:auto;margin-top:12px;border:1px solid #e2e8f0;border-radius:8px}.assignment-item{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 14px;cursor:pointer;border-bottom:1px solid #f1f5f9;transition:background .1s}.assignment-item:last-child{border-bottom:none}.assignment-item:hover{background:#f8fafc}.assignment-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.assignment-item.assignment-readonly{cursor:default}.assignment-item.assignment-readonly:hover{background:transparent}.assignment-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.assignment-text strong{font-size:.8125rem;color:#1e293b}.assignment-text span{font-size:.75rem;color:#64748b}.assignment-channels{display:flex;gap:4px;flex-shrink:0}.channel-badge{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:4px;background:#f1f5f9;color:#94a3b8;transition:all .15s}.channel-badge.active{background:#3b82f6;color:#fff}.channel-badge.disabled{opacity:.4;cursor:not-allowed}.config-desc{font-size:.875rem;color:#64748b;line-height:1.5;margin:0}.config-divider{border:none;border-top:1px solid #e2e8f0;margin:20px 0}.config-section{display:flex;flex-direction:column;gap:12px}.config-section-label{font-size:.6875rem;font-weight:700;color:#3b82f6;text-transform:uppercase;letter-spacing:.04em}.config-field{display:flex;flex-direction:column;gap:6px}.config-field-mt{margin-top:16px}.config-label{font-size:.8125rem;font-weight:600;color:#1e293b}.config-readonly{padding:9px 12px;border:1px solid #e2e8f0;border-radius:8px;background:#f8fafc;font-size:.875rem;color:#1e293b}.config-hint{font-size:.75rem;color:#64748b}.test-save-note{display:flex;align-items:center;gap:8px;padding:10px 14px;background:#fef3c7;border:1px solid #fcd34d;border-radius:8px;font-size:.8125rem;color:#92400e;margin-top:12px}.test-save-note svg{flex-shrink:0}.ai-prompt-examples{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-top:12px}.ai-example-label{font-size:.75rem;color:#64748b;font-weight:600}.panel-center{display:flex;flex-direction:column;min-height:0;min-width:0;overflow:hidden}.editor-tabs{display:flex;gap:2px;padding:12px 20px 0;background:#fff;border-bottom:1px solid #e2e8f0;overflow-x:auto;-webkit-overflow-scrolling:touch}.editor-tab{display:flex;align-items:center;gap:6px;padding:10px 16px;border:1px solid #e2e8f0;border-bottom:none;border-radius:8px 8px 0 0;background:#f8fafc;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;white-space:nowrap}.editor-tab:hover{background:#fff;color:#1e293b}.editor-tab.active{background:#eff6ff;color:#3b82f6;border-color:#93c5fd}.editor-tab:focus-visible,.right-tab:focus-visible,.block-group-header:focus-visible,.variable-item:focus-visible,.add-block-btn:focus-visible,.block-item:focus-visible,.video-lib-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.editor-toolbar{display:flex;align-items:center;gap:8px;padding:10px 20px;background:#fff;border-bottom:1px solid #e2e8f0;flex-wrap:wrap}.toolbar-row-2{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 20px;background:#fff;border-bottom:1px solid #e2e8f0}.toolbar-group{display:flex;align-items:center;gap:2px;padding-right:8px;border-right:1px solid #e2e8f0}.toolbar-group:last-child{border-right:none;padding-right:0}.toolbar-select{display:block;min-width:96px}.toolbar-label{font-size:.75rem;font-weight:600;color:#64748b;white-space:nowrap;margin-right:6px}.ai-dot{width:8px;height:8px;border-radius:50%;background:#3b82f6;display:inline-block;margin-right:6px}.hidden-color-input{position:absolute;width:0;height:0;opacity:0;pointer-events:none;border:none;padding:0}.color-indicator{display:flex;flex-direction:column;align-items:center;gap:2px;color:#475569}.color-bar{display:block;width:16px;height:3px;border-radius:2px;border:1px solid rgba(0,0,0,.1)}.link-dialog{background:#fff;border-bottom:1px solid #e2e8f0;padding:12px 20px}.link-dialog-inner{display:flex;align-items:flex-start;gap:8px;flex-wrap:wrap}.link-dialog-title{font-size:.8125rem;font-weight:700;color:#1e293b;white-space:nowrap;padding-top:10px}.link-dialog-input{display:block;width:240px;max-width:100%}.link-dialog-actions{display:flex;gap:6px}.preview-frame{flex:1;display:flex;justify-content:center;padding:24px;overflow-y:auto;background:#f1f5f9}.preview-frame.mobile{align-items:flex-start}.preview-content{max-width:600px;width:100%;box-sizing:border-box;background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:32px;min-height:400px;font-size:.9375rem;line-height:1.6;color:#1e293b;overflow-wrap:anywhere}.preview-content p{margin:0 0 8px}.mobile-shell{width:375px;max-width:100%;box-sizing:border-box;min-height:600px;border:2px solid #1e293b;border-radius:24px;padding:40px 12px 24px;background:#fff;box-shadow:0 8px 32px #0000001f}.mobile-shell .preview-content{border:none;border-radius:0;padding:16px;max-width:100%}.blocks-canvas{flex:1;padding:16px 20px 24px;overflow-y:auto;background:#f1f5f9;display:flex;flex-direction:column}.block-wrapper{position:relative;display:flex;align-items:flex-start;background:#fff;border:2px solid transparent;border-radius:8px;transition:border-color .15s,box-shadow .15s}.block-wrapper:hover,.block-wrapper.selected,.block-wrapper:focus-within{border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.block-wrapper:hover .block-drag-handle,.block-wrapper.selected .block-drag-handle,.block-wrapper:focus-within .block-drag-handle{opacity:1}.block-wrapper:hover .block-controls,.block-wrapper.selected .block-controls,.block-wrapper:focus-within .block-controls{opacity:1;pointer-events:all}.block-wrapper.dragging{opacity:.4}.block-drag-handle{flex-shrink:0;width:28px;display:flex;align-items:flex-start;justify-content:center;padding-top:14px;opacity:0;transition:opacity .15s;cursor:grab;color:#94a3b8}.block-drag-handle:active{cursor:grabbing}.block-content{flex:1;min-width:0;padding:12px 16px;outline:none;font-size:.9375rem;color:#1e293b;line-height:1.6;min-height:48px;overflow-wrap:anywhere}.block-content:empty:before{content:\"Click to edit...\";color:#94a3b8;font-style:italic;pointer-events:none}.block-content p{margin:0 0 8px}.block-content p:last-child{margin:0}.block-content h1,.block-content h2,.block-content h3{margin:8px 0 6px;color:#1e293b}.block-content a{color:#3b82f6}.block-content img{max-width:100%;border-radius:6px}.block-content ul,.block-content ol{padding-left:20px;margin:0 0 8px}.block-controls{position:absolute;top:6px;right:6px;display:flex;gap:2px;opacity:0;pointer-events:none;transition:opacity .15s;background:#fff;border:1px solid #e2e8f0;border-radius:6px;padding:3px;box-shadow:0 2px 6px #00000014}@media(hover:none){.block-wrapper.selected .block-controls{opacity:1;pointer-events:all}}.drop-zone{height:8px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:height .15s,background .15s;position:relative}.drop-zone-label{font-size:.75rem;font-weight:600;color:#3b82f6;opacity:0;transition:opacity .1s}.drop-zone.active{height:40px;background:#3b82f614;border:2px dashed #3b82f6}.drop-zone.active .drop-zone-label{opacity:1}.add-block-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-height:44px;padding:12px;margin-top:8px;border:2px dashed #e2e8f0;border-radius:8px;background:none;font-size:.875rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;transition:border-color .15s,color .15s,background .15s}.add-block-btn:hover{border-color:#3b82f6;color:#3b82f6;background:#3b82f60a}.panel-right{background:#fff;border-left:1px solid #e2e8f0;display:flex;flex-direction:column;min-height:0;min-width:0}.right-tabs{display:flex;border-bottom:1px solid #e2e8f0}.right-tab{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:12px;min-height:44px;border:none;background:none;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;border-bottom:2px solid transparent}.right-tab:hover{color:#1e293b}.right-tab.active{color:#3b82f6;background:#eff6ff;border-bottom-color:#3b82f6}.right-panel-body{flex:1;padding:20px;overflow-y:auto}.right-section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 12px}.right-section-desc{font-size:.8125rem;color:#64748b;margin:0 0 16px;line-height:1.5}.right-section-hint{font-size:.8125rem;color:#64748b;margin:0 0 12px;line-height:1.5}.block-group{border-bottom:1px solid #f1f5f9}.block-group-header{display:flex;align-items:center;gap:8px;width:100%;min-height:44px;padding:12px 0;border:none;background:none;font-size:.875rem;font-weight:600;color:#1e293b;cursor:pointer;font-family:inherit;text-align:left}.block-group-header .chevron{transition:transform .2s;color:#94a3b8}.block-group-header .chevron.expanded{transform:rotate(90deg)}.block-group-header span:nth-of-type(1){flex:1}.block-count{font-size:.75rem;font-weight:600;color:#64748b;background:#f1f5f9;padding:2px 8px;border-radius:10px;margin-left:auto}.block-list,.variable-list{display:flex;flex-direction:column;gap:2px;padding-bottom:8px}.block-item{display:flex;align-items:center;gap:6px;box-sizing:border-box;width:100%;min-height:44px;padding:8px 12px 8px 28px;font-size:.8125rem;color:#64748b;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit;-webkit-user-select:none;user-select:none}.block-item:hover{background:#f8fafc;color:#1e293b}.block-item-drag{color:#cbd5e1;flex-shrink:0;cursor:grab}.variable-item{display:grid;grid-template-columns:auto 1fr auto;gap:8px;align-items:center;min-height:44px;padding:8px 12px 8px 28px;border:none;background:none;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit}.variable-item:hover{background:#f8fafc}.var-tag{font-size:.75rem;font-weight:600;color:#3b82f6;background:#3b82f614;padding:2px 6px;border-radius:4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.var-label{font-size:.8125rem;color:#1e293b}.var-example{font-size:.75rem;color:#64748b;overflow-wrap:anywhere}.video-library-panel{padding:0}.video-library-panel .right-section-title,.video-library-panel .right-section-hint{padding:0 16px}.video-library-panel .right-section-title{padding-top:16px}.video-config-section{display:flex;flex-direction:column;gap:8px;padding:12px 16px;border-bottom:1px solid #f1f5f9}.video-config-section:last-of-type{border-bottom:none}.video-lib-list{display:flex;flex-direction:column;gap:2px;padding:8px 8px 16px}.video-lib-item{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:8px;border:1px solid transparent;border-radius:8px;background:none;cursor:pointer;text-align:left;font-family:inherit;transition:background .15s,border-color .15s}.video-lib-item:hover{background:#f8fafc;border-color:#e2e8f0}.video-lib-item.selected{background:#eff6ff;border-color:#93c5fd}.vli-thumb{position:relative;flex-shrink:0;width:56px;height:40px;border-radius:6px;background:linear-gradient(135deg,#f1f5f9,#e2e8f0);display:flex;align-items:center;justify-content:center}.vli-dur{position:absolute;bottom:2px;right:3px;font-size:.625rem;font-weight:600;color:#fff;background:#000000a6;padding:1px 4px;border-radius:3px}.vli-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.vli-title{font-size:.8125rem;font-weight:600;color:#1e293b;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vli-cat{font-size:.75rem;color:#64748b}.vli-check{flex-shrink:0}.video-lib-empty{display:flex;flex-direction:column;align-items:center;padding:32px 16px;text-align:center;gap:8px}.video-lib-empty p{font-size:.875rem;font-weight:500;color:#475569;margin:0}.video-lib-empty span{font-size:.8125rem;color:#64748b}.video-lib-loading{padding:8px}.video-lib-skeleton{display:flex;align-items:center;gap:10px;padding:8px;margin-bottom:4px}.vls-info{flex:1;display:flex;flex-direction:column;gap:6px}@media(max-width:1200px){.editor-body{grid-template-columns:280px minmax(0,1fr) 260px}}@media(max-width:900px){.editor-page{height:auto;min-height:100vh;min-height:100dvh;overflow:visible}.editor-body{display:flex;flex-direction:column;overflow:visible}.editor-topbar{padding:12px 16px}.panel-left{border-right:none;border-bottom:1px solid #e2e8f0;overflow:visible;padding:16px}.panel-center{overflow:visible;min-height:480px}.blocks-canvas{overflow:visible;min-height:320px}.panel-right{border-left:none;border-top:1px solid #e2e8f0}.right-panel-body{overflow:visible}.editor-toolbar,.toolbar-row-2,.link-dialog,.editor-tabs{padding-left:12px;padding-right:12px}.preview-frame{padding:12px}.preview-content{padding:16px}.form-row-dates{grid-template-columns:1fr}}@media(prefers-reduced-motion:reduce){*{transition:none!important}}\n"],
44670
+ styles: [":host{display:block}.required{color:#ef4444;font-weight:400}.editor-page{display:flex;flex-direction:column;height:100vh;height:100dvh;background:#f8fafc;overflow:hidden}.editor-actions{display:flex;justify-content:flex-end;align-items:center;gap:8px;flex-wrap:wrap;padding:0 0 12px;flex-shrink:0}.readonly-note{margin:0;padding:8px 16px;font-size:.8125rem;color:#92400e;background:#fffbeb;border-bottom:1px solid #fde68a}.readonly-note.system-note{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.editor-body{display:grid;grid-template-columns:340px minmax(0,1fr) 300px;flex:1;min-height:0;overflow:hidden}.panel-left{background:#fff;border-right:1px solid #e2e8f0;padding:24px;overflow-y:auto}.panel-title{font-size:1.0625rem;font-weight:700;color:#1e293b;margin:0 0 20px}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:16px}.form-row-dates{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:16px}.assignments-section{border-top:1px solid #e2e8f0;padding-top:20px;margin-top:16px}.section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 6px}.section-desc{font-size:.8125rem;color:#64748b;line-height:1.5;margin:0 0 12px}.assignment-list{max-height:340px;overflow-y:auto;margin-top:12px;border:1px solid #e2e8f0;border-radius:8px}.assignment-item{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 14px;cursor:pointer;border-bottom:1px solid #f1f5f9;transition:background .1s}.assignment-item:last-child{border-bottom:none}.assignment-item:hover{background:#f8fafc}.assignment-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.assignment-item.assignment-readonly{cursor:default}.assignment-item.assignment-readonly:hover{background:transparent}.assignment-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.assignment-text strong{font-size:.8125rem;color:#1e293b}.assignment-text span{font-size:.75rem;color:#64748b}.assignment-channels{display:flex;gap:4px;flex-shrink:0}.channel-badge{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:4px;background:#f1f5f9;color:#94a3b8;transition:all .15s}.channel-badge.active{background:#3b82f6;color:#fff}.channel-badge.disabled{opacity:.4;cursor:not-allowed}.config-desc{font-size:.875rem;color:#64748b;line-height:1.5;margin:0}.config-divider{border:none;border-top:1px solid #e2e8f0;margin:20px 0}.config-section{display:flex;flex-direction:column;gap:12px}.config-section-label{font-size:.6875rem;font-weight:700;color:#3b82f6;text-transform:uppercase;letter-spacing:.04em}.config-field{display:flex;flex-direction:column;gap:6px}.config-field-mt{margin-top:16px}.config-label{font-size:.8125rem;font-weight:600;color:#1e293b}.config-readonly{padding:9px 12px;border:1px solid #e2e8f0;border-radius:8px;background:#f8fafc;font-size:.875rem;color:#1e293b}.config-hint{font-size:.75rem;color:#64748b}.test-save-note{display:flex;align-items:center;gap:8px;padding:10px 14px;background:#fef3c7;border:1px solid #fcd34d;border-radius:8px;font-size:.8125rem;color:#92400e;margin-top:12px}.test-save-note svg{flex-shrink:0}.panel-center{display:flex;flex-direction:column;min-height:0;min-width:0;overflow:hidden}.editor-tabs{display:flex;gap:2px;padding:12px 20px 0;background:#fff;border-bottom:1px solid #e2e8f0;overflow-x:auto;-webkit-overflow-scrolling:touch}.editor-tab{display:flex;align-items:center;gap:6px;padding:10px 16px;border:1px solid #e2e8f0;border-bottom:none;border-radius:8px 8px 0 0;background:#f8fafc;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;white-space:nowrap}.editor-tab:hover{background:#fff;color:#1e293b}.editor-tab.active{background:#eff6ff;color:#3b82f6;border-color:#93c5fd}.editor-tab:focus-visible,.right-tab:focus-visible,.block-group-header:focus-visible,.variable-item:focus-visible,.add-block-btn:focus-visible,.block-item:focus-visible,.video-lib-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.editor-toolbar{display:flex;align-items:center;gap:8px;padding:10px 20px;background:#fff;border-bottom:1px solid #e2e8f0;flex-wrap:wrap}.toolbar-row-2{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 20px;background:#fff;border-bottom:1px solid #e2e8f0}.toolbar-group{display:flex;align-items:center;gap:2px;padding-right:8px;border-right:1px solid #e2e8f0}.toolbar-group:last-child{border-right:none;padding-right:0}.toolbar-select{display:block;min-width:96px}.toolbar-label{font-size:.75rem;font-weight:600;color:#64748b;white-space:nowrap;margin-right:6px}.hidden-color-input{position:absolute;width:0;height:0;opacity:0;pointer-events:none;border:none;padding:0}.color-indicator{display:flex;flex-direction:column;align-items:center;gap:2px;color:#475569}.color-bar{display:block;width:16px;height:3px;border-radius:2px;border:1px solid rgba(0,0,0,.1)}.link-dialog{background:#fff;border-bottom:1px solid #e2e8f0;padding:12px 20px}.link-dialog-inner{display:flex;align-items:flex-start;gap:8px;flex-wrap:wrap}.link-dialog-title{font-size:.8125rem;font-weight:700;color:#1e293b;white-space:nowrap;padding-top:10px}.link-dialog-input{display:block;width:240px;max-width:100%}.link-dialog-actions{display:flex;gap:6px}.preview-frame{flex:1;display:flex;justify-content:center;padding:24px;overflow-y:auto;background:#f1f5f9}.preview-frame.mobile{align-items:flex-start}.preview-content{max-width:600px;width:100%;box-sizing:border-box;background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:32px;min-height:400px;font-size:.9375rem;line-height:1.6;color:#1e293b;overflow-wrap:anywhere}.preview-content p{margin:0 0 8px}.mobile-shell{width:375px;max-width:100%;box-sizing:border-box;min-height:600px;border:2px solid #1e293b;border-radius:24px;padding:40px 12px 24px;background:#fff;box-shadow:0 8px 32px #0000001f}.mobile-shell .preview-content{border:none;border-radius:0;padding:16px;max-width:100%}.blocks-canvas{flex:1;padding:16px 20px 24px;overflow-y:auto;background:#f1f5f9;display:flex;flex-direction:column}.block-wrapper{position:relative;display:flex;align-items:flex-start;background:#fff;border:2px solid transparent;border-radius:8px;transition:border-color .15s,box-shadow .15s}.block-wrapper:hover,.block-wrapper.selected,.block-wrapper:focus-within{border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.block-wrapper:hover .block-drag-handle,.block-wrapper.selected .block-drag-handle,.block-wrapper:focus-within .block-drag-handle{opacity:1}.block-wrapper:hover .block-controls,.block-wrapper.selected .block-controls,.block-wrapper:focus-within .block-controls{opacity:1;pointer-events:all}.block-wrapper.dragging{opacity:.4}.block-drag-handle{flex-shrink:0;width:28px;display:flex;align-items:flex-start;justify-content:center;padding-top:14px;opacity:0;transition:opacity .15s;cursor:grab;color:#94a3b8}.block-drag-handle:active{cursor:grabbing}.block-content{flex:1;min-width:0;padding:12px 16px;outline:none;font-size:.9375rem;color:#1e293b;line-height:1.6;min-height:48px;overflow-wrap:anywhere}.block-content:empty:before{content:\"Click to edit...\";color:#94a3b8;font-style:italic;pointer-events:none}.block-content p{margin:0 0 8px}.block-content p:last-child{margin:0}.block-content h1,.block-content h2,.block-content h3{margin:8px 0 6px;color:#1e293b}.block-content a{color:#3b82f6}.block-content img{max-width:100%;border-radius:6px}.block-content ul,.block-content ol{padding-left:20px;margin:0 0 8px}.block-controls{position:absolute;top:6px;right:6px;display:flex;gap:2px;opacity:0;pointer-events:none;transition:opacity .15s;background:#fff;border:1px solid #e2e8f0;border-radius:6px;padding:3px;box-shadow:0 2px 6px #00000014}@media(hover:none){.block-wrapper.selected .block-controls{opacity:1;pointer-events:all}}.drop-zone{height:8px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:height .15s,background .15s;position:relative}.drop-zone-label{font-size:.75rem;font-weight:600;color:#3b82f6;opacity:0;transition:opacity .1s}.drop-zone.active{height:40px;background:#3b82f614;border:2px dashed #3b82f6}.drop-zone.active .drop-zone-label{opacity:1}.add-block-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-height:44px;padding:12px;margin-top:8px;border:2px dashed #e2e8f0;border-radius:8px;background:none;font-size:.875rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;transition:border-color .15s,color .15s,background .15s}.add-block-btn:hover{border-color:#3b82f6;color:#3b82f6;background:#3b82f60a}.panel-right{background:#fff;border-left:1px solid #e2e8f0;display:flex;flex-direction:column;min-height:0;min-width:0}.right-tabs{display:flex;border-bottom:1px solid #e2e8f0}.right-tab{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:12px;min-height:44px;border:none;background:none;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;border-bottom:2px solid transparent}.right-tab:hover{color:#1e293b}.right-tab.active{color:#3b82f6;background:#eff6ff;border-bottom-color:#3b82f6}.right-panel-body{flex:1;padding:20px;overflow-y:auto}.right-section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 12px}.right-section-desc{font-size:.8125rem;color:#64748b;margin:0 0 16px;line-height:1.5}.right-section-hint{font-size:.8125rem;color:#64748b;margin:0 0 12px;line-height:1.5}.block-group{border-bottom:1px solid #f1f5f9}.block-group-header{display:flex;align-items:center;gap:8px;width:100%;min-height:44px;padding:12px 0;border:none;background:none;font-size:.875rem;font-weight:600;color:#1e293b;cursor:pointer;font-family:inherit;text-align:left}.block-group-header .chevron{transition:transform .2s;color:#94a3b8}.block-group-header .chevron.expanded{transform:rotate(90deg)}.block-group-header span:nth-of-type(1){flex:1}.block-count{font-size:.75rem;font-weight:600;color:#64748b;background:#f1f5f9;padding:2px 8px;border-radius:10px;margin-left:auto}.block-list,.variable-list{display:flex;flex-direction:column;gap:2px;padding-bottom:8px}.block-item{display:flex;align-items:center;gap:6px;box-sizing:border-box;width:100%;min-height:44px;padding:8px 12px 8px 28px;font-size:.8125rem;color:#64748b;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit;-webkit-user-select:none;user-select:none}.block-item:hover{background:#f8fafc;color:#1e293b}.block-item-drag{color:#cbd5e1;flex-shrink:0;cursor:grab}.variable-item{display:grid;grid-template-columns:auto 1fr auto;gap:8px;align-items:center;min-height:44px;padding:8px 12px 8px 28px;border:none;background:none;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit}.variable-item:hover{background:#f8fafc}.var-tag{font-size:.75rem;font-weight:600;color:#3b82f6;background:#3b82f614;padding:2px 6px;border-radius:4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.var-label{font-size:.8125rem;color:#1e293b}.var-example{font-size:.75rem;color:#64748b;overflow-wrap:anywhere}.video-library-panel{padding:0}.video-library-panel .right-section-title,.video-library-panel .right-section-hint{padding:0 16px}.video-library-panel .right-section-title{padding-top:16px}.video-config-section{display:flex;flex-direction:column;gap:8px;padding:12px 16px;border-bottom:1px solid #f1f5f9}.video-config-section:last-of-type{border-bottom:none}.video-lib-list{display:flex;flex-direction:column;gap:2px;padding:8px 8px 16px}.video-lib-item{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:8px;border:1px solid transparent;border-radius:8px;background:none;cursor:pointer;text-align:left;font-family:inherit;transition:background .15s,border-color .15s}.video-lib-item:hover{background:#f8fafc;border-color:#e2e8f0}.video-lib-item.selected{background:#eff6ff;border-color:#93c5fd}.vli-thumb{position:relative;flex-shrink:0;width:56px;height:40px;border-radius:6px;background:linear-gradient(135deg,#f1f5f9,#e2e8f0);display:flex;align-items:center;justify-content:center}.vli-dur{position:absolute;bottom:2px;right:3px;font-size:.625rem;font-weight:600;color:#fff;background:#000000a6;padding:1px 4px;border-radius:3px}.vli-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.vli-title{font-size:.8125rem;font-weight:600;color:#1e293b;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vli-cat{font-size:.75rem;color:#64748b}.vli-check{flex-shrink:0}.video-lib-loading{padding:8px}.video-lib-skeleton{display:flex;align-items:center;gap:10px;padding:8px;margin-bottom:4px}.vls-info{flex:1;display:flex;flex-direction:column;gap:6px}@media(max-width:1200px){.editor-body{grid-template-columns:280px minmax(0,1fr) 260px}}@media(max-width:900px){.editor-page{height:auto;min-height:100vh;min-height:100dvh;overflow:visible}.editor-body{display:flex;flex-direction:column;overflow:visible}.panel-left{border-right:none;border-bottom:1px solid #e2e8f0;overflow:visible;padding:16px}.panel-center{overflow:visible;min-height:480px}.blocks-canvas{overflow:visible;min-height:320px}.panel-right{border-left:none;border-top:1px solid #e2e8f0}.right-panel-body{overflow:visible}.editor-toolbar,.toolbar-row-2,.link-dialog,.editor-tabs{padding-left:12px;padding-right:12px}.preview-frame{padding:12px}.preview-content{padding:16px}.form-row-dates{grid-template-columns:1fr}}@media(prefers-reduced-motion:reduce){*{transition:none!important}}\n"],
44767
44671
  dependencies: [
44768
44672
  {
44769
44673
  kind: "ngmodule",
@@ -44860,18 +44764,6 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44860
44764
  "invalidChange"
44861
44765
  ]
44862
44766
  },
44863
- {
44864
- kind: "component",
44865
- type: ChipComponent,
44866
- selector: "ui-chip",
44867
- inputs: [
44868
- "label",
44869
- "size",
44870
- "dismissible",
44871
- "active"
44872
- ],
44873
- outputs: ["select", "dismiss"]
44874
- },
44875
44767
  {
44876
44768
  kind: "component",
44877
44769
  type: DateInputComponent,
@@ -44888,6 +44780,26 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44888
44780
  ],
44889
44781
  outputs: ["invalidChange", "valueChange"]
44890
44782
  },
44783
+ {
44784
+ kind: "component",
44785
+ type: DividerComponent,
44786
+ selector: "ui-divider",
44787
+ inputs: [
44788
+ "spaceAbove",
44789
+ "spaceBelow",
44790
+ "decorative"
44791
+ ]
44792
+ },
44793
+ {
44794
+ kind: "component",
44795
+ type: EmptyStateComponent,
44796
+ selector: "ui-empty-state",
44797
+ inputs: [
44798
+ "message",
44799
+ "title",
44800
+ "iconType"
44801
+ ]
44802
+ },
44891
44803
  {
44892
44804
  kind: "component",
44893
44805
  type: ErrorComponent,
@@ -45020,27 +44932,6 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
45020
44932
  "invalidChange"
45021
44933
  ]
45022
44934
  },
45023
- {
45024
- kind: "component",
45025
- type: TextareaInputComponent,
45026
- selector: "ui-textarea-input",
45027
- inputs: [
45028
- "label",
45029
- "ariaLabel",
45030
- "placeholder",
45031
- "rows",
45032
- "maxlength",
45033
- "required",
45034
- "readonly",
45035
- "hint",
45036
- "hintAsDescription",
45037
- "error",
45038
- "monospace",
45039
- "showErrors",
45040
- "disabled"
45041
- ],
45042
- outputs: ["invalidChange"]
45043
- },
45044
44935
  {
45045
44936
  kind: "directive",
45046
44937
  type: TooltipDirective,
@@ -45067,8 +44958,9 @@ i0.ɵɵngDeclareClassMetadata({
45067
44958
  FormsModule,
45068
44959
  ButtonComponent,
45069
44960
  CheckboxComponent,
45070
- ChipComponent,
45071
44961
  DateInputComponent,
44962
+ DividerComponent,
44963
+ EmptyStateComponent,
45072
44964
  ErrorComponent,
45073
44965
  RadioGroupComponent,
45074
44966
  SearchInputComponent,
@@ -45076,36 +44968,24 @@ i0.ɵɵngDeclareClassMetadata({
45076
44968
  SidePanelComponent,
45077
44969
  SkeletonComponent,
45078
44970
  TextInputComponent,
45079
- TextareaInputComponent,
45080
44971
  TooltipDirective
45081
44972
  ],
45082
44973
  template: `
45083
44974
  <div class="editor-page">
45084
- <!-- Top Bar -->
45085
- <div class="editor-topbar">
45086
- <div class="topbar-left">
45087
- <ui-button variant="ghost" size="sm" ariaLabel="Go back" (click)="back.emit()">
45088
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M15 18l-6-6 6-6"/></svg>
45089
- </ui-button>
45090
- <nav class="breadcrumb" aria-label="Breadcrumb">
45091
- <a href="#" (click)="$event.preventDefault(); back.emit()">{{ backLabel() }}</a>
45092
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M9 18l6-6-6-6"/></svg>
45093
- <span>{{ isNew() ? createLabel() : editLabel() }}</span>
45094
- </nav>
45095
- </div>
45096
- <div class="topbar-right">
45097
- @if (canWrite() && testSendEnabled()) {
45098
- <ui-button variant="secondary" size="sm" (click)="openTestSendDialog()">
45099
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
45100
- Test Send
45101
- </ui-button>
45102
- }
45103
- <ui-button variant="primary" size="sm" [loading]="saving()" [disabled]="saveDisabled()" (click)="onSave()">
45104
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>
45105
- Save Template
44975
+ <!-- Actions (outside the white panels) -->
44976
+ <div class="editor-actions">
44977
+ @if (canWrite() && testSendEnabled()) {
44978
+ <ui-button variant="secondary" size="sm" (click)="openTestSendDialog()">
44979
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
44980
+ Test Send
45106
44981
  </ui-button>
45107
- </div>
44982
+ }
44983
+ <ui-button variant="primary" size="sm" [loading]="saving()" [disabled]="saveDisabled()" (click)="onSave()">
44984
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>
44985
+ Save Template
44986
+ </ui-button>
45108
44987
  </div>
44988
+ <ui-divider />
45109
44989
 
45110
44990
  @if (systemTemplate()) {
45111
44991
  <div class="readonly-note system-note" role="note" data-testid="editor-system-note">
@@ -45126,15 +45006,12 @@ i0.ɵɵngDeclareClassMetadata({
45126
45006
 
45127
45007
  <div class="form-field">
45128
45008
  <ui-text-input label="Name" [required]="true" [(ngModel)]="name" [readonly]="!canWrite()" [maxlength]="maxTextLength()"
45129
- [placeholder]="namePlaceholder()" [error]="nameError()" />
45009
+ [placeholder]="namePlaceholder()" [error]="nameErrorShown()" (blurred)="nameTouched.set(true)" />
45130
45010
  </div>
45131
45011
 
45132
45012
  <div class="form-field">
45133
45013
  <ui-text-input label="Subject" [required]="true" [(ngModel)]="subject" [readonly]="!canWrite()" [maxlength]="maxTextLength()"
45134
- [placeholder]="subjectPlaceholder()" [error]="subjectError()">
45135
- @if (canWrite()) {
45136
- <span uiLabelEnd><ng-content select="[uiSubjectAction]" /></span>
45137
- }
45014
+ [placeholder]="subjectPlaceholder()" [error]="subjectErrorShown()" (blurred)="subjectTouched.set(true)">
45138
45015
  </ui-text-input>
45139
45016
  </div>
45140
45017
 
@@ -45157,7 +45034,10 @@ i0.ɵɵngDeclareClassMetadata({
45157
45034
  <h4 class="section-title">Assignments</h4>
45158
45035
  <p class="section-desc">{{ assignmentsDescription() }}</p>
45159
45036
  <ui-search-input placeholder="Search..." ariaLabel="Search assignments" [(value)]="assignmentSearch" />
45160
- <div class="assignment-list">
45037
+ @if (filteredAssignments().length === 0) {
45038
+ <ui-empty-state iconType="search" title="No assignments found" message="No assignments match your search." />
45039
+ }
45040
+ <div class="assignment-list" [hidden]="filteredAssignments().length === 0">
45161
45041
  @for (item of filteredAssignments(); track item.key) {
45162
45042
  <div class="assignment-item" [class.assignment-readonly]="!canWrite()" [attr.role]="canWrite() ? 'button' : null" [attr.tabindex]="canWrite() ? 0 : null"
45163
45043
  [attr.aria-label]="canWrite() ? 'Configure ' + item.name : null"
@@ -45203,9 +45083,9 @@ i0.ɵɵngDeclareClassMetadata({
45203
45083
  <!-- Toolbar row 1: mousedown preventDefault keeps focus (and the selection) in the editor -->
45204
45084
  <div class="editor-toolbar" role="toolbar" aria-label="Text formatting" (mousedown)="preventFocusLoss($event)">
45205
45085
  <div class="toolbar-group">
45206
- <ui-button variant="icon" size="sm" ariaLabel="Bold" uiTooltip="Bold" (click)="execCommand('bold')"><strong>B</strong></ui-button>
45207
- <ui-button variant="icon" size="sm" ariaLabel="Italic" uiTooltip="Italic" (click)="execCommand('italic')"><em>I</em></ui-button>
45208
- <ui-button variant="icon" size="sm" ariaLabel="Underline" uiTooltip="Underline" (click)="execCommand('underline')"><u>U</u></ui-button>
45086
+ <ui-button variant="ghost" size="sm" ariaLabel="Bold" uiTooltip="Bold" (click)="execCommand('bold')"><strong>B</strong></ui-button>
45087
+ <ui-button variant="ghost" size="sm" ariaLabel="Italic" uiTooltip="Italic" (click)="execCommand('italic')"><em>I</em></ui-button>
45088
+ <ui-button variant="ghost" size="sm" ariaLabel="Underline" uiTooltip="Underline" (click)="execCommand('underline')"><u>U</u></ui-button>
45209
45089
  </div>
45210
45090
  <div class="toolbar-group">
45211
45091
  @for (k of [headingKey()]; track k) {
@@ -45220,28 +45100,28 @@ i0.ɵɵngDeclareClassMetadata({
45220
45100
  }
45221
45101
  </div>
45222
45102
  <div class="toolbar-group">
45223
- <ui-button variant="icon" size="sm" ariaLabel="Align left" uiTooltip="Align Left" (click)="execCommand('justifyLeft')">
45103
+ <ui-button variant="ghost" size="sm" ariaLabel="Align left" uiTooltip="Align Left" (click)="execCommand('justifyLeft')">
45224
45104
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="17" y1="10" x2="3" y2="10"/><line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="14" x2="3" y2="14"/><line x1="17" y1="18" x2="3" y2="18"/></svg>
45225
45105
  </ui-button>
45226
- <ui-button variant="icon" size="sm" ariaLabel="Align center" uiTooltip="Align Center" (click)="execCommand('justifyCenter')">
45106
+ <ui-button variant="ghost" size="sm" ariaLabel="Align center" uiTooltip="Align Center" (click)="execCommand('justifyCenter')">
45227
45107
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="18" y1="10" x2="6" y2="10"/><line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="14" x2="3" y2="14"/><line x1="18" y1="18" x2="6" y2="18"/></svg>
45228
45108
  </ui-button>
45229
- <ui-button variant="icon" size="sm" ariaLabel="Align right" uiTooltip="Align Right" (click)="execCommand('justifyRight')">
45109
+ <ui-button variant="ghost" size="sm" ariaLabel="Align right" uiTooltip="Align Right" (click)="execCommand('justifyRight')">
45230
45110
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="21" y1="10" x2="7" y2="10"/><line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="14" x2="3" y2="14"/><line x1="21" y1="18" x2="7" y2="18"/></svg>
45231
45111
  </ui-button>
45232
45112
  </div>
45233
45113
  <div class="toolbar-group">
45234
- <ui-button variant="icon" size="sm" ariaLabel="Bulleted list" uiTooltip="Bulleted List" (click)="execCommand('insertUnorderedList')">
45114
+ <ui-button variant="ghost" size="sm" ariaLabel="Bulleted list" uiTooltip="Bulleted List" (click)="execCommand('insertUnorderedList')">
45235
45115
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>
45236
45116
  </ui-button>
45237
- <ui-button variant="icon" size="sm" ariaLabel="Numbered list" uiTooltip="Numbered List" (click)="execCommand('insertOrderedList')">
45117
+ <ui-button variant="ghost" size="sm" ariaLabel="Numbered list" uiTooltip="Numbered List" (click)="execCommand('insertOrderedList')">
45238
45118
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/></svg>
45239
45119
  </ui-button>
45240
45120
  </div>
45241
45121
  <div class="toolbar-group">
45242
45122
  <!-- The browser's own colour dialog is the picker; a button opens it so the toolbar keeps one look. -->
45243
45123
  <input #colorInput type="color" class="hidden-color-input" aria-label="Text color" tabindex="-1" [value]="currentColor()" (change)="applyTextColor($any($event.target).value)" (mousedown)="$event.stopPropagation()" />
45244
- <ui-button variant="icon" size="sm" ariaLabel="Text color" uiTooltip="Text Color" (mousedown)="openColorPicker()">
45124
+ <ui-button variant="ghost" size="sm" ariaLabel="Text color" uiTooltip="Text Color" (mousedown)="openColorPicker()">
45245
45125
  <span class="color-indicator">
45246
45126
  <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><text y="20" font-size="20" font-weight="700">A</text></svg>
45247
45127
  <span class="color-bar" [style.background]="currentColor()"></span>
@@ -45249,35 +45129,29 @@ i0.ɵɵngDeclareClassMetadata({
45249
45129
  </ui-button>
45250
45130
  </div>
45251
45131
  <div class="toolbar-group">
45252
- <ui-button variant="icon" size="sm" ariaLabel="Insert link" uiTooltip="Insert Link" (mousedown)="saveSelection()" (click)="openLinkDialog()">
45132
+ <ui-button variant="ghost" size="sm" ariaLabel="Insert link" uiTooltip="Insert Link" (mousedown)="saveSelection()" (click)="openLinkDialog()">
45253
45133
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
45254
45134
  </ui-button>
45255
- <ui-button variant="icon" size="sm" ariaLabel="Insert image" uiTooltip="Insert Image" (mousedown)="saveSelection()" (click)="openImageDialog()">
45135
+ <ui-button variant="ghost" size="sm" ariaLabel="Insert image" uiTooltip="Insert Image" (mousedown)="saveSelection()" (click)="openImageDialog()">
45256
45136
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
45257
45137
  </ui-button>
45258
45138
  </div>
45259
45139
  <div class="toolbar-group">
45260
- <ui-button variant="icon" size="sm" ariaLabel="Undo" uiTooltip="Undo" (click)="execCommand('undo')">
45140
+ <ui-button variant="ghost" size="sm" ariaLabel="Undo" uiTooltip="Undo" (click)="execCommand('undo')">
45261
45141
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M3 7v6h6"/><path d="M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6.69 3L3 13"/></svg>
45262
45142
  </ui-button>
45263
- <ui-button variant="icon" size="sm" ariaLabel="Redo" uiTooltip="Redo" (click)="execCommand('redo')">
45143
+ <ui-button variant="ghost" size="sm" ariaLabel="Redo" uiTooltip="Redo" (click)="execCommand('redo')">
45264
45144
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 7v6h-6"/><path d="M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6.69 3L21 13"/></svg>
45265
45145
  </ui-button>
45266
45146
  </div>
45267
45147
  </div>
45268
45148
 
45269
- <!-- Toolbar row 2: block spacing + AI -->
45149
+ <!-- Toolbar row 2: block spacing -->
45270
45150
  <div class="toolbar-row-2">
45271
45151
  <div class="toolbar-group" (mousedown)="preventFocusLoss($event)">
45272
45152
  <span class="toolbar-label" id="tpl-spacing-label">Block spacing</span>
45273
45153
  <ui-select class="toolbar-select" size="sm" ariaLabel="Block spacing" [options]="spacingOptions" [ngModel]="blockSpacing()" (ngModelChange)="applySpacing($event)" />
45274
45154
  </div>
45275
- @if (aiEnabled()) {
45276
- <ui-button variant="secondary" size="sm" (click)="openAiPanel()">
45277
- <span class="ai-dot" aria-hidden="true"></span>
45278
- Generate with AI
45279
- </ui-button>
45280
- }
45281
45155
  </div>
45282
45156
  }
45283
45157
 
@@ -45313,7 +45187,7 @@ i0.ɵɵngDeclareClassMetadata({
45313
45187
  </div>
45314
45188
  }
45315
45189
 
45316
- <ui-error [errorId]="idPrefix() + '-body-error'" [message]="bodyError()" />
45190
+ <ui-error [errorId]="idPrefix() + '-body-error'" [message]="bodyErrorShown()" />
45317
45191
 
45318
45192
  <!-- Block Canvas with DnD -->
45319
45193
  <div class="blocks-canvas" (dragover)="onCanvasDragOver($event)" (drop)="onDropZoneDrop($event, blocks().length)">
@@ -45338,16 +45212,16 @@ i0.ɵɵngDeclareClassMetadata({
45338
45212
 
45339
45213
  @if (canWrite()) {
45340
45214
  <div class="block-controls">
45341
- <ui-button variant="icon" size="xs" ariaLabel="Move block up" uiTooltip="Move up" [disabled]="i === 0" (mousedown)="preventFocusLoss($event)" (click)="moveBlock(i, -1)">
45215
+ <ui-button variant="ghost" size="xs" ariaLabel="Move block up" uiTooltip="Move up" [disabled]="i === 0" (mousedown)="preventFocusLoss($event)" (click)="moveBlock(i, -1)">
45342
45216
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M18 15l-6-6-6 6"/></svg>
45343
45217
  </ui-button>
45344
- <ui-button variant="icon" size="xs" ariaLabel="Move block down" uiTooltip="Move down" [disabled]="i === blocks().length - 1" (mousedown)="preventFocusLoss($event)" (click)="moveBlock(i, 1)">
45218
+ <ui-button variant="ghost" size="xs" ariaLabel="Move block down" uiTooltip="Move down" [disabled]="i === blocks().length - 1" (mousedown)="preventFocusLoss($event)" (click)="moveBlock(i, 1)">
45345
45219
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
45346
45220
  </ui-button>
45347
- <ui-button variant="icon" size="xs" ariaLabel="Duplicate block" uiTooltip="Duplicate" (mousedown)="preventFocusLoss($event)" (click)="duplicateBlock(i)">
45221
+ <ui-button variant="ghost" size="xs" ariaLabel="Duplicate block" uiTooltip="Duplicate" (mousedown)="preventFocusLoss($event)" (click)="duplicateBlock(i)">
45348
45222
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
45349
45223
  </ui-button>
45350
- <ui-button variant="icon-danger" size="xs" ariaLabel="Delete block" uiTooltip="Delete block" (mousedown)="preventFocusLoss($event)" (click)="deleteBlock(i)">
45224
+ <ui-button variant="ghost" size="xs" ariaLabel="Delete block" uiTooltip="Delete block" (mousedown)="preventFocusLoss($event)" (click)="deleteBlock(i)">
45351
45225
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6M14 11v6"/></svg>
45352
45226
  </ui-button>
45353
45227
  </div>
@@ -45415,6 +45289,9 @@ i0.ɵɵngDeclareClassMetadata({
45415
45289
  <p class="right-section-desc">Click to insert or drag into the editor.</p>
45416
45290
  <ui-search-input placeholder="Search blocks..." ariaLabel="Search blocks" [(value)]="blockSearch" />
45417
45291
 
45292
+ @if (filteredBlockGroups().length === 0) {
45293
+ <ui-empty-state iconType="search" title="No blocks found" message="No blocks match your search." />
45294
+ }
45418
45295
  @for (group of filteredBlockGroups(); track group.name) {
45419
45296
  <div class="block-group">
45420
45297
  <button type="button" class="block-group-header" [attr.aria-expanded]="isOpen('b:' + group.name)" (click)="toggleGroup('b:' + group.name)">
@@ -45499,15 +45376,11 @@ i0.ɵɵngDeclareClassMetadata({
45499
45376
  </div>
45500
45377
  }
45501
45378
  </div>
45502
- } @else if (videos().length === 0) {
45503
- <div class="video-lib-empty">
45504
- <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="1.5" aria-hidden="true"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/></svg>
45505
- <p>No videos yet</p>
45506
- <span>{{ noVideosHint() }}</span>
45507
- </div>
45379
+ } @else if (videoList().length === 0) {
45380
+ <ui-empty-state iconType="video" title="No videos created" [message]="noVideosHint()" />
45508
45381
  } @else {
45509
45382
  <div class="video-lib-list">
45510
- @for (video of videos(); track video.id) {
45383
+ @for (video of videoList(); track video.id) {
45511
45384
  <button type="button" class="video-lib-item" [class.selected]="video.id === videoId()" [attr.aria-pressed]="video.id === videoId()" (click)="insertVideo(video)">
45512
45385
  <span class="vli-thumb">
45513
45386
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="1.5" aria-hidden="true"><polygon points="5 3 19 12 5 21 5 3"/></svg>
@@ -45553,20 +45426,6 @@ i0.ɵɵngDeclareClassMetadata({
45553
45426
  }
45554
45427
  </ui-side-panel>
45555
45428
 
45556
- <!-- AI Generate -->
45557
- <ui-side-panel [open]="showAiPanel()" title="Generate with AI" primaryLabel="Generate" [primaryLoading]="aiGenerating()" [primaryDisabled]="!canGenerate()"
45558
- (closed)="showAiPanel.set(false)" (primaryClick)="onAiGenerate()">
45559
- <p class="config-desc">Describe the email you want to write. The AI will generate professional content and add it as a new block.</p>
45560
- <div class="ai-prompt-examples">
45561
- <span class="ai-example-label">Try:</span>
45562
- @for (ex of aiExamples(); track ex) {
45563
- <ui-chip [label]="ex" size="sm" (select)="aiPrompt.set(ex)" />
45564
- }
45565
- </div>
45566
- <div class="config-field config-field-mt">
45567
- <ui-textarea-input label="What do you want to write?" [rows]="5" placeholder="e.g. A friendly follow-up email for a buyer who attended an open house last weekend" [(ngModel)]="aiPrompt" />
45568
- </div>
45569
- </ui-side-panel>
45570
45429
 
45571
45430
  <!-- Assignment config -->
45572
45431
  <ui-side-panel [wide]="true" [open]="showAssignmentConfig()" [title]="configTarget()?.name || 'Configure Automation'" primaryLabel="Save Configuration"
@@ -45591,7 +45450,7 @@ i0.ɵɵngDeclareClassMetadata({
45591
45450
  }
45592
45451
  </ui-side-panel>
45593
45452
  `,
45594
- styles: [":host{display:block}.required{color:#ef4444;font-weight:400}.editor-page{display:flex;flex-direction:column;height:100vh;height:100dvh;background:#f8fafc;overflow:hidden}.editor-topbar{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap;padding:12px 24px;background:#fff;border-bottom:1px solid #e2e8f0;flex-shrink:0}.topbar-left{display:flex;align-items:center;gap:8px;min-width:0}.topbar-right{display:flex;align-items:center;gap:8px}.breadcrumb{display:flex;align-items:center;gap:6px;font-size:.9375rem;font-weight:700;color:#1e293b;min-width:0}.breadcrumb a{color:#1e293b;text-decoration:none;cursor:pointer}.breadcrumb a:hover{color:#3b82f6}.breadcrumb svg{color:#94a3b8;flex-shrink:0}.breadcrumb span{color:#64748b;font-weight:500}.readonly-note{margin:0;padding:8px 16px;font-size:.8125rem;color:#92400e;background:#fffbeb;border-bottom:1px solid #fde68a}.readonly-note.system-note{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.editor-body{display:grid;grid-template-columns:340px minmax(0,1fr) 300px;flex:1;min-height:0;overflow:hidden}.panel-left{background:#fff;border-right:1px solid #e2e8f0;padding:24px;overflow-y:auto}.panel-title{font-size:1.0625rem;font-weight:700;color:#1e293b;margin:0 0 20px}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:16px}.form-row-dates{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:16px}.assignments-section{border-top:1px solid #e2e8f0;padding-top:20px;margin-top:16px}.section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 6px}.section-desc{font-size:.8125rem;color:#64748b;line-height:1.5;margin:0 0 12px}.assignment-list{max-height:340px;overflow-y:auto;margin-top:12px;border:1px solid #e2e8f0;border-radius:8px}.assignment-item{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 14px;cursor:pointer;border-bottom:1px solid #f1f5f9;transition:background .1s}.assignment-item:last-child{border-bottom:none}.assignment-item:hover{background:#f8fafc}.assignment-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.assignment-item.assignment-readonly{cursor:default}.assignment-item.assignment-readonly:hover{background:transparent}.assignment-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.assignment-text strong{font-size:.8125rem;color:#1e293b}.assignment-text span{font-size:.75rem;color:#64748b}.assignment-channels{display:flex;gap:4px;flex-shrink:0}.channel-badge{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:4px;background:#f1f5f9;color:#94a3b8;transition:all .15s}.channel-badge.active{background:#3b82f6;color:#fff}.channel-badge.disabled{opacity:.4;cursor:not-allowed}.config-desc{font-size:.875rem;color:#64748b;line-height:1.5;margin:0}.config-divider{border:none;border-top:1px solid #e2e8f0;margin:20px 0}.config-section{display:flex;flex-direction:column;gap:12px}.config-section-label{font-size:.6875rem;font-weight:700;color:#3b82f6;text-transform:uppercase;letter-spacing:.04em}.config-field{display:flex;flex-direction:column;gap:6px}.config-field-mt{margin-top:16px}.config-label{font-size:.8125rem;font-weight:600;color:#1e293b}.config-readonly{padding:9px 12px;border:1px solid #e2e8f0;border-radius:8px;background:#f8fafc;font-size:.875rem;color:#1e293b}.config-hint{font-size:.75rem;color:#64748b}.test-save-note{display:flex;align-items:center;gap:8px;padding:10px 14px;background:#fef3c7;border:1px solid #fcd34d;border-radius:8px;font-size:.8125rem;color:#92400e;margin-top:12px}.test-save-note svg{flex-shrink:0}.ai-prompt-examples{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-top:12px}.ai-example-label{font-size:.75rem;color:#64748b;font-weight:600}.panel-center{display:flex;flex-direction:column;min-height:0;min-width:0;overflow:hidden}.editor-tabs{display:flex;gap:2px;padding:12px 20px 0;background:#fff;border-bottom:1px solid #e2e8f0;overflow-x:auto;-webkit-overflow-scrolling:touch}.editor-tab{display:flex;align-items:center;gap:6px;padding:10px 16px;border:1px solid #e2e8f0;border-bottom:none;border-radius:8px 8px 0 0;background:#f8fafc;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;white-space:nowrap}.editor-tab:hover{background:#fff;color:#1e293b}.editor-tab.active{background:#eff6ff;color:#3b82f6;border-color:#93c5fd}.editor-tab:focus-visible,.right-tab:focus-visible,.block-group-header:focus-visible,.variable-item:focus-visible,.add-block-btn:focus-visible,.block-item:focus-visible,.video-lib-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.editor-toolbar{display:flex;align-items:center;gap:8px;padding:10px 20px;background:#fff;border-bottom:1px solid #e2e8f0;flex-wrap:wrap}.toolbar-row-2{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 20px;background:#fff;border-bottom:1px solid #e2e8f0}.toolbar-group{display:flex;align-items:center;gap:2px;padding-right:8px;border-right:1px solid #e2e8f0}.toolbar-group:last-child{border-right:none;padding-right:0}.toolbar-select{display:block;min-width:96px}.toolbar-label{font-size:.75rem;font-weight:600;color:#64748b;white-space:nowrap;margin-right:6px}.ai-dot{width:8px;height:8px;border-radius:50%;background:#3b82f6;display:inline-block;margin-right:6px}.hidden-color-input{position:absolute;width:0;height:0;opacity:0;pointer-events:none;border:none;padding:0}.color-indicator{display:flex;flex-direction:column;align-items:center;gap:2px;color:#475569}.color-bar{display:block;width:16px;height:3px;border-radius:2px;border:1px solid rgba(0,0,0,.1)}.link-dialog{background:#fff;border-bottom:1px solid #e2e8f0;padding:12px 20px}.link-dialog-inner{display:flex;align-items:flex-start;gap:8px;flex-wrap:wrap}.link-dialog-title{font-size:.8125rem;font-weight:700;color:#1e293b;white-space:nowrap;padding-top:10px}.link-dialog-input{display:block;width:240px;max-width:100%}.link-dialog-actions{display:flex;gap:6px}.preview-frame{flex:1;display:flex;justify-content:center;padding:24px;overflow-y:auto;background:#f1f5f9}.preview-frame.mobile{align-items:flex-start}.preview-content{max-width:600px;width:100%;box-sizing:border-box;background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:32px;min-height:400px;font-size:.9375rem;line-height:1.6;color:#1e293b;overflow-wrap:anywhere}.preview-content p{margin:0 0 8px}.mobile-shell{width:375px;max-width:100%;box-sizing:border-box;min-height:600px;border:2px solid #1e293b;border-radius:24px;padding:40px 12px 24px;background:#fff;box-shadow:0 8px 32px #0000001f}.mobile-shell .preview-content{border:none;border-radius:0;padding:16px;max-width:100%}.blocks-canvas{flex:1;padding:16px 20px 24px;overflow-y:auto;background:#f1f5f9;display:flex;flex-direction:column}.block-wrapper{position:relative;display:flex;align-items:flex-start;background:#fff;border:2px solid transparent;border-radius:8px;transition:border-color .15s,box-shadow .15s}.block-wrapper:hover,.block-wrapper.selected,.block-wrapper:focus-within{border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.block-wrapper:hover .block-drag-handle,.block-wrapper.selected .block-drag-handle,.block-wrapper:focus-within .block-drag-handle{opacity:1}.block-wrapper:hover .block-controls,.block-wrapper.selected .block-controls,.block-wrapper:focus-within .block-controls{opacity:1;pointer-events:all}.block-wrapper.dragging{opacity:.4}.block-drag-handle{flex-shrink:0;width:28px;display:flex;align-items:flex-start;justify-content:center;padding-top:14px;opacity:0;transition:opacity .15s;cursor:grab;color:#94a3b8}.block-drag-handle:active{cursor:grabbing}.block-content{flex:1;min-width:0;padding:12px 16px;outline:none;font-size:.9375rem;color:#1e293b;line-height:1.6;min-height:48px;overflow-wrap:anywhere}.block-content:empty:before{content:\"Click to edit...\";color:#94a3b8;font-style:italic;pointer-events:none}.block-content p{margin:0 0 8px}.block-content p:last-child{margin:0}.block-content h1,.block-content h2,.block-content h3{margin:8px 0 6px;color:#1e293b}.block-content a{color:#3b82f6}.block-content img{max-width:100%;border-radius:6px}.block-content ul,.block-content ol{padding-left:20px;margin:0 0 8px}.block-controls{position:absolute;top:6px;right:6px;display:flex;gap:2px;opacity:0;pointer-events:none;transition:opacity .15s;background:#fff;border:1px solid #e2e8f0;border-radius:6px;padding:3px;box-shadow:0 2px 6px #00000014}@media(hover:none){.block-wrapper.selected .block-controls{opacity:1;pointer-events:all}}.drop-zone{height:8px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:height .15s,background .15s;position:relative}.drop-zone-label{font-size:.75rem;font-weight:600;color:#3b82f6;opacity:0;transition:opacity .1s}.drop-zone.active{height:40px;background:#3b82f614;border:2px dashed #3b82f6}.drop-zone.active .drop-zone-label{opacity:1}.add-block-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-height:44px;padding:12px;margin-top:8px;border:2px dashed #e2e8f0;border-radius:8px;background:none;font-size:.875rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;transition:border-color .15s,color .15s,background .15s}.add-block-btn:hover{border-color:#3b82f6;color:#3b82f6;background:#3b82f60a}.panel-right{background:#fff;border-left:1px solid #e2e8f0;display:flex;flex-direction:column;min-height:0;min-width:0}.right-tabs{display:flex;border-bottom:1px solid #e2e8f0}.right-tab{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:12px;min-height:44px;border:none;background:none;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;border-bottom:2px solid transparent}.right-tab:hover{color:#1e293b}.right-tab.active{color:#3b82f6;background:#eff6ff;border-bottom-color:#3b82f6}.right-panel-body{flex:1;padding:20px;overflow-y:auto}.right-section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 12px}.right-section-desc{font-size:.8125rem;color:#64748b;margin:0 0 16px;line-height:1.5}.right-section-hint{font-size:.8125rem;color:#64748b;margin:0 0 12px;line-height:1.5}.block-group{border-bottom:1px solid #f1f5f9}.block-group-header{display:flex;align-items:center;gap:8px;width:100%;min-height:44px;padding:12px 0;border:none;background:none;font-size:.875rem;font-weight:600;color:#1e293b;cursor:pointer;font-family:inherit;text-align:left}.block-group-header .chevron{transition:transform .2s;color:#94a3b8}.block-group-header .chevron.expanded{transform:rotate(90deg)}.block-group-header span:nth-of-type(1){flex:1}.block-count{font-size:.75rem;font-weight:600;color:#64748b;background:#f1f5f9;padding:2px 8px;border-radius:10px;margin-left:auto}.block-list,.variable-list{display:flex;flex-direction:column;gap:2px;padding-bottom:8px}.block-item{display:flex;align-items:center;gap:6px;box-sizing:border-box;width:100%;min-height:44px;padding:8px 12px 8px 28px;font-size:.8125rem;color:#64748b;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit;-webkit-user-select:none;user-select:none}.block-item:hover{background:#f8fafc;color:#1e293b}.block-item-drag{color:#cbd5e1;flex-shrink:0;cursor:grab}.variable-item{display:grid;grid-template-columns:auto 1fr auto;gap:8px;align-items:center;min-height:44px;padding:8px 12px 8px 28px;border:none;background:none;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit}.variable-item:hover{background:#f8fafc}.var-tag{font-size:.75rem;font-weight:600;color:#3b82f6;background:#3b82f614;padding:2px 6px;border-radius:4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.var-label{font-size:.8125rem;color:#1e293b}.var-example{font-size:.75rem;color:#64748b;overflow-wrap:anywhere}.video-library-panel{padding:0}.video-library-panel .right-section-title,.video-library-panel .right-section-hint{padding:0 16px}.video-library-panel .right-section-title{padding-top:16px}.video-config-section{display:flex;flex-direction:column;gap:8px;padding:12px 16px;border-bottom:1px solid #f1f5f9}.video-config-section:last-of-type{border-bottom:none}.video-lib-list{display:flex;flex-direction:column;gap:2px;padding:8px 8px 16px}.video-lib-item{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:8px;border:1px solid transparent;border-radius:8px;background:none;cursor:pointer;text-align:left;font-family:inherit;transition:background .15s,border-color .15s}.video-lib-item:hover{background:#f8fafc;border-color:#e2e8f0}.video-lib-item.selected{background:#eff6ff;border-color:#93c5fd}.vli-thumb{position:relative;flex-shrink:0;width:56px;height:40px;border-radius:6px;background:linear-gradient(135deg,#f1f5f9,#e2e8f0);display:flex;align-items:center;justify-content:center}.vli-dur{position:absolute;bottom:2px;right:3px;font-size:.625rem;font-weight:600;color:#fff;background:#000000a6;padding:1px 4px;border-radius:3px}.vli-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.vli-title{font-size:.8125rem;font-weight:600;color:#1e293b;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vli-cat{font-size:.75rem;color:#64748b}.vli-check{flex-shrink:0}.video-lib-empty{display:flex;flex-direction:column;align-items:center;padding:32px 16px;text-align:center;gap:8px}.video-lib-empty p{font-size:.875rem;font-weight:500;color:#475569;margin:0}.video-lib-empty span{font-size:.8125rem;color:#64748b}.video-lib-loading{padding:8px}.video-lib-skeleton{display:flex;align-items:center;gap:10px;padding:8px;margin-bottom:4px}.vls-info{flex:1;display:flex;flex-direction:column;gap:6px}@media(max-width:1200px){.editor-body{grid-template-columns:280px minmax(0,1fr) 260px}}@media(max-width:900px){.editor-page{height:auto;min-height:100vh;min-height:100dvh;overflow:visible}.editor-body{display:flex;flex-direction:column;overflow:visible}.editor-topbar{padding:12px 16px}.panel-left{border-right:none;border-bottom:1px solid #e2e8f0;overflow:visible;padding:16px}.panel-center{overflow:visible;min-height:480px}.blocks-canvas{overflow:visible;min-height:320px}.panel-right{border-left:none;border-top:1px solid #e2e8f0}.right-panel-body{overflow:visible}.editor-toolbar,.toolbar-row-2,.link-dialog,.editor-tabs{padding-left:12px;padding-right:12px}.preview-frame{padding:12px}.preview-content{padding:16px}.form-row-dates{grid-template-columns:1fr}}@media(prefers-reduced-motion:reduce){*{transition:none!important}}\n"]
45453
+ styles: [":host{display:block}.required{color:#ef4444;font-weight:400}.editor-page{display:flex;flex-direction:column;height:100vh;height:100dvh;background:#f8fafc;overflow:hidden}.editor-actions{display:flex;justify-content:flex-end;align-items:center;gap:8px;flex-wrap:wrap;padding:0 0 12px;flex-shrink:0}.readonly-note{margin:0;padding:8px 16px;font-size:.8125rem;color:#92400e;background:#fffbeb;border-bottom:1px solid #fde68a}.readonly-note.system-note{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.editor-body{display:grid;grid-template-columns:340px minmax(0,1fr) 300px;flex:1;min-height:0;overflow:hidden}.panel-left{background:#fff;border-right:1px solid #e2e8f0;padding:24px;overflow-y:auto}.panel-title{font-size:1.0625rem;font-weight:700;color:#1e293b;margin:0 0 20px}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:16px}.form-row-dates{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:16px}.assignments-section{border-top:1px solid #e2e8f0;padding-top:20px;margin-top:16px}.section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 6px}.section-desc{font-size:.8125rem;color:#64748b;line-height:1.5;margin:0 0 12px}.assignment-list{max-height:340px;overflow-y:auto;margin-top:12px;border:1px solid #e2e8f0;border-radius:8px}.assignment-item{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 14px;cursor:pointer;border-bottom:1px solid #f1f5f9;transition:background .1s}.assignment-item:last-child{border-bottom:none}.assignment-item:hover{background:#f8fafc}.assignment-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.assignment-item.assignment-readonly{cursor:default}.assignment-item.assignment-readonly:hover{background:transparent}.assignment-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.assignment-text strong{font-size:.8125rem;color:#1e293b}.assignment-text span{font-size:.75rem;color:#64748b}.assignment-channels{display:flex;gap:4px;flex-shrink:0}.channel-badge{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:4px;background:#f1f5f9;color:#94a3b8;transition:all .15s}.channel-badge.active{background:#3b82f6;color:#fff}.channel-badge.disabled{opacity:.4;cursor:not-allowed}.config-desc{font-size:.875rem;color:#64748b;line-height:1.5;margin:0}.config-divider{border:none;border-top:1px solid #e2e8f0;margin:20px 0}.config-section{display:flex;flex-direction:column;gap:12px}.config-section-label{font-size:.6875rem;font-weight:700;color:#3b82f6;text-transform:uppercase;letter-spacing:.04em}.config-field{display:flex;flex-direction:column;gap:6px}.config-field-mt{margin-top:16px}.config-label{font-size:.8125rem;font-weight:600;color:#1e293b}.config-readonly{padding:9px 12px;border:1px solid #e2e8f0;border-radius:8px;background:#f8fafc;font-size:.875rem;color:#1e293b}.config-hint{font-size:.75rem;color:#64748b}.test-save-note{display:flex;align-items:center;gap:8px;padding:10px 14px;background:#fef3c7;border:1px solid #fcd34d;border-radius:8px;font-size:.8125rem;color:#92400e;margin-top:12px}.test-save-note svg{flex-shrink:0}.panel-center{display:flex;flex-direction:column;min-height:0;min-width:0;overflow:hidden}.editor-tabs{display:flex;gap:2px;padding:12px 20px 0;background:#fff;border-bottom:1px solid #e2e8f0;overflow-x:auto;-webkit-overflow-scrolling:touch}.editor-tab{display:flex;align-items:center;gap:6px;padding:10px 16px;border:1px solid #e2e8f0;border-bottom:none;border-radius:8px 8px 0 0;background:#f8fafc;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;white-space:nowrap}.editor-tab:hover{background:#fff;color:#1e293b}.editor-tab.active{background:#eff6ff;color:#3b82f6;border-color:#93c5fd}.editor-tab:focus-visible,.right-tab:focus-visible,.block-group-header:focus-visible,.variable-item:focus-visible,.add-block-btn:focus-visible,.block-item:focus-visible,.video-lib-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.editor-toolbar{display:flex;align-items:center;gap:8px;padding:10px 20px;background:#fff;border-bottom:1px solid #e2e8f0;flex-wrap:wrap}.toolbar-row-2{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 20px;background:#fff;border-bottom:1px solid #e2e8f0}.toolbar-group{display:flex;align-items:center;gap:2px;padding-right:8px;border-right:1px solid #e2e8f0}.toolbar-group:last-child{border-right:none;padding-right:0}.toolbar-select{display:block;min-width:96px}.toolbar-label{font-size:.75rem;font-weight:600;color:#64748b;white-space:nowrap;margin-right:6px}.hidden-color-input{position:absolute;width:0;height:0;opacity:0;pointer-events:none;border:none;padding:0}.color-indicator{display:flex;flex-direction:column;align-items:center;gap:2px;color:#475569}.color-bar{display:block;width:16px;height:3px;border-radius:2px;border:1px solid rgba(0,0,0,.1)}.link-dialog{background:#fff;border-bottom:1px solid #e2e8f0;padding:12px 20px}.link-dialog-inner{display:flex;align-items:flex-start;gap:8px;flex-wrap:wrap}.link-dialog-title{font-size:.8125rem;font-weight:700;color:#1e293b;white-space:nowrap;padding-top:10px}.link-dialog-input{display:block;width:240px;max-width:100%}.link-dialog-actions{display:flex;gap:6px}.preview-frame{flex:1;display:flex;justify-content:center;padding:24px;overflow-y:auto;background:#f1f5f9}.preview-frame.mobile{align-items:flex-start}.preview-content{max-width:600px;width:100%;box-sizing:border-box;background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:32px;min-height:400px;font-size:.9375rem;line-height:1.6;color:#1e293b;overflow-wrap:anywhere}.preview-content p{margin:0 0 8px}.mobile-shell{width:375px;max-width:100%;box-sizing:border-box;min-height:600px;border:2px solid #1e293b;border-radius:24px;padding:40px 12px 24px;background:#fff;box-shadow:0 8px 32px #0000001f}.mobile-shell .preview-content{border:none;border-radius:0;padding:16px;max-width:100%}.blocks-canvas{flex:1;padding:16px 20px 24px;overflow-y:auto;background:#f1f5f9;display:flex;flex-direction:column}.block-wrapper{position:relative;display:flex;align-items:flex-start;background:#fff;border:2px solid transparent;border-radius:8px;transition:border-color .15s,box-shadow .15s}.block-wrapper:hover,.block-wrapper.selected,.block-wrapper:focus-within{border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.block-wrapper:hover .block-drag-handle,.block-wrapper.selected .block-drag-handle,.block-wrapper:focus-within .block-drag-handle{opacity:1}.block-wrapper:hover .block-controls,.block-wrapper.selected .block-controls,.block-wrapper:focus-within .block-controls{opacity:1;pointer-events:all}.block-wrapper.dragging{opacity:.4}.block-drag-handle{flex-shrink:0;width:28px;display:flex;align-items:flex-start;justify-content:center;padding-top:14px;opacity:0;transition:opacity .15s;cursor:grab;color:#94a3b8}.block-drag-handle:active{cursor:grabbing}.block-content{flex:1;min-width:0;padding:12px 16px;outline:none;font-size:.9375rem;color:#1e293b;line-height:1.6;min-height:48px;overflow-wrap:anywhere}.block-content:empty:before{content:\"Click to edit...\";color:#94a3b8;font-style:italic;pointer-events:none}.block-content p{margin:0 0 8px}.block-content p:last-child{margin:0}.block-content h1,.block-content h2,.block-content h3{margin:8px 0 6px;color:#1e293b}.block-content a{color:#3b82f6}.block-content img{max-width:100%;border-radius:6px}.block-content ul,.block-content ol{padding-left:20px;margin:0 0 8px}.block-controls{position:absolute;top:6px;right:6px;display:flex;gap:2px;opacity:0;pointer-events:none;transition:opacity .15s;background:#fff;border:1px solid #e2e8f0;border-radius:6px;padding:3px;box-shadow:0 2px 6px #00000014}@media(hover:none){.block-wrapper.selected .block-controls{opacity:1;pointer-events:all}}.drop-zone{height:8px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:height .15s,background .15s;position:relative}.drop-zone-label{font-size:.75rem;font-weight:600;color:#3b82f6;opacity:0;transition:opacity .1s}.drop-zone.active{height:40px;background:#3b82f614;border:2px dashed #3b82f6}.drop-zone.active .drop-zone-label{opacity:1}.add-block-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-height:44px;padding:12px;margin-top:8px;border:2px dashed #e2e8f0;border-radius:8px;background:none;font-size:.875rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;transition:border-color .15s,color .15s,background .15s}.add-block-btn:hover{border-color:#3b82f6;color:#3b82f6;background:#3b82f60a}.panel-right{background:#fff;border-left:1px solid #e2e8f0;display:flex;flex-direction:column;min-height:0;min-width:0}.right-tabs{display:flex;border-bottom:1px solid #e2e8f0}.right-tab{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:12px;min-height:44px;border:none;background:none;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;border-bottom:2px solid transparent}.right-tab:hover{color:#1e293b}.right-tab.active{color:#3b82f6;background:#eff6ff;border-bottom-color:#3b82f6}.right-panel-body{flex:1;padding:20px;overflow-y:auto}.right-section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 12px}.right-section-desc{font-size:.8125rem;color:#64748b;margin:0 0 16px;line-height:1.5}.right-section-hint{font-size:.8125rem;color:#64748b;margin:0 0 12px;line-height:1.5}.block-group{border-bottom:1px solid #f1f5f9}.block-group-header{display:flex;align-items:center;gap:8px;width:100%;min-height:44px;padding:12px 0;border:none;background:none;font-size:.875rem;font-weight:600;color:#1e293b;cursor:pointer;font-family:inherit;text-align:left}.block-group-header .chevron{transition:transform .2s;color:#94a3b8}.block-group-header .chevron.expanded{transform:rotate(90deg)}.block-group-header span:nth-of-type(1){flex:1}.block-count{font-size:.75rem;font-weight:600;color:#64748b;background:#f1f5f9;padding:2px 8px;border-radius:10px;margin-left:auto}.block-list,.variable-list{display:flex;flex-direction:column;gap:2px;padding-bottom:8px}.block-item{display:flex;align-items:center;gap:6px;box-sizing:border-box;width:100%;min-height:44px;padding:8px 12px 8px 28px;font-size:.8125rem;color:#64748b;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit;-webkit-user-select:none;user-select:none}.block-item:hover{background:#f8fafc;color:#1e293b}.block-item-drag{color:#cbd5e1;flex-shrink:0;cursor:grab}.variable-item{display:grid;grid-template-columns:auto 1fr auto;gap:8px;align-items:center;min-height:44px;padding:8px 12px 8px 28px;border:none;background:none;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit}.variable-item:hover{background:#f8fafc}.var-tag{font-size:.75rem;font-weight:600;color:#3b82f6;background:#3b82f614;padding:2px 6px;border-radius:4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.var-label{font-size:.8125rem;color:#1e293b}.var-example{font-size:.75rem;color:#64748b;overflow-wrap:anywhere}.video-library-panel{padding:0}.video-library-panel .right-section-title,.video-library-panel .right-section-hint{padding:0 16px}.video-library-panel .right-section-title{padding-top:16px}.video-config-section{display:flex;flex-direction:column;gap:8px;padding:12px 16px;border-bottom:1px solid #f1f5f9}.video-config-section:last-of-type{border-bottom:none}.video-lib-list{display:flex;flex-direction:column;gap:2px;padding:8px 8px 16px}.video-lib-item{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:8px;border:1px solid transparent;border-radius:8px;background:none;cursor:pointer;text-align:left;font-family:inherit;transition:background .15s,border-color .15s}.video-lib-item:hover{background:#f8fafc;border-color:#e2e8f0}.video-lib-item.selected{background:#eff6ff;border-color:#93c5fd}.vli-thumb{position:relative;flex-shrink:0;width:56px;height:40px;border-radius:6px;background:linear-gradient(135deg,#f1f5f9,#e2e8f0);display:flex;align-items:center;justify-content:center}.vli-dur{position:absolute;bottom:2px;right:3px;font-size:.625rem;font-weight:600;color:#fff;background:#000000a6;padding:1px 4px;border-radius:3px}.vli-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.vli-title{font-size:.8125rem;font-weight:600;color:#1e293b;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vli-cat{font-size:.75rem;color:#64748b}.vli-check{flex-shrink:0}.video-lib-loading{padding:8px}.video-lib-skeleton{display:flex;align-items:center;gap:10px;padding:8px;margin-bottom:4px}.vls-info{flex:1;display:flex;flex-direction:column;gap:6px}@media(max-width:1200px){.editor-body{grid-template-columns:280px minmax(0,1fr) 260px}}@media(max-width:900px){.editor-page{height:auto;min-height:100vh;min-height:100dvh;overflow:visible}.editor-body{display:flex;flex-direction:column;overflow:visible}.panel-left{border-right:none;border-bottom:1px solid #e2e8f0;overflow:visible;padding:16px}.panel-center{overflow:visible;min-height:480px}.blocks-canvas{overflow:visible;min-height:320px}.panel-right{border-left:none;border-top:1px solid #e2e8f0}.right-panel-body{overflow:visible}.editor-toolbar,.toolbar-row-2,.link-dialog,.editor-tabs{padding-left:12px;padding-right:12px}.preview-frame{padding:12px}.preview-content{padding:16px}.form-row-dates{grid-template-columns:1fr}}@media(prefers-reduced-motion:reduce){*{transition:none!important}}\n"]
45595
45454
  }]
45596
45455
  }],
45597
45456
  ctorParameters: () => [],
@@ -45668,14 +45527,6 @@ i0.ɵɵngDeclareClassMetadata({
45668
45527
  required: false
45669
45528
  }]
45670
45529
  }],
45671
- aiExamples: [{
45672
- type: i0.Input,
45673
- args: [{
45674
- isSignal: true,
45675
- alias: "aiExamples",
45676
- required: false
45677
- }]
45678
- }],
45679
45530
  namePlaceholder: [{
45680
45531
  type: i0.Input,
45681
45532
  args: [{
@@ -45692,30 +45543,6 @@ i0.ɵɵngDeclareClassMetadata({
45692
45543
  required: false
45693
45544
  }]
45694
45545
  }],
45695
- backLabel: [{
45696
- type: i0.Input,
45697
- args: [{
45698
- isSignal: true,
45699
- alias: "backLabel",
45700
- required: false
45701
- }]
45702
- }],
45703
- createLabel: [{
45704
- type: i0.Input,
45705
- args: [{
45706
- isSignal: true,
45707
- alias: "createLabel",
45708
- required: false
45709
- }]
45710
- }],
45711
- editLabel: [{
45712
- type: i0.Input,
45713
- args: [{
45714
- isSignal: true,
45715
- alias: "editLabel",
45716
- required: false
45717
- }]
45718
- }],
45719
45546
  systemNote: [{
45720
45547
  type: i0.Input,
45721
45548
  args: [{
@@ -45772,14 +45599,6 @@ i0.ɵɵngDeclareClassMetadata({
45772
45599
  required: false
45773
45600
  }]
45774
45601
  }],
45775
- aiEnabled: [{
45776
- type: i0.Input,
45777
- args: [{
45778
- isSignal: true,
45779
- alias: "aiEnabled",
45780
- required: false
45781
- }]
45782
- }],
45783
45602
  testSendEnabled: [{
45784
45603
  type: i0.Input,
45785
45604
  args: [{
@@ -45788,14 +45607,6 @@ i0.ɵɵngDeclareClassMetadata({
45788
45607
  required: false
45789
45608
  }]
45790
45609
  }],
45791
- videosEnabled: [{
45792
- type: i0.Input,
45793
- args: [{
45794
- isSignal: true,
45795
- alias: "videosEnabled",
45796
- required: false
45797
- }]
45798
- }],
45799
45610
  saving: [{
45800
45611
  type: i0.Input,
45801
45612
  args: [{
@@ -45812,19 +45623,19 @@ i0.ɵɵngDeclareClassMetadata({
45812
45623
  required: false
45813
45624
  }]
45814
45625
  }],
45815
- aiGenerating: [{
45626
+ videos: [{
45816
45627
  type: i0.Input,
45817
45628
  args: [{
45818
45629
  isSignal: true,
45819
- alias: "aiGenerating",
45630
+ alias: "videos",
45820
45631
  required: false
45821
45632
  }]
45822
45633
  }],
45823
- videos: [{
45634
+ hideVideos: [{
45824
45635
  type: i0.Input,
45825
45636
  args: [{
45826
45637
  isSignal: true,
45827
- alias: "videos",
45638
+ alias: "hideVideos",
45828
45639
  required: false
45829
45640
  }]
45830
45641
  }],
@@ -45860,10 +45671,6 @@ i0.ɵɵngDeclareClassMetadata({
45860
45671
  required: false
45861
45672
  }]
45862
45673
  }],
45863
- back: [{
45864
- type: i0.Output,
45865
- args: ["back"]
45866
- }],
45867
45674
  save: [{
45868
45675
  type: i0.Output,
45869
45676
  args: ["save"]
@@ -45872,10 +45679,6 @@ i0.ɵɵngDeclareClassMetadata({
45872
45679
  type: i0.Output,
45873
45680
  args: ["testSend"]
45874
45681
  }],
45875
- aiGenerate: [{
45876
- type: i0.Output,
45877
- args: ["aiGenerate"]
45878
- }],
45879
45682
  videosRequested: [{
45880
45683
  type: i0.Output,
45881
45684
  args: ["videosRequested"]