@memberjunction/ng-artifacts 5.43.0 → 5.45.0

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.
Files changed (65) hide show
  1. package/README.md +6 -0
  2. package/dist/lib/artifacts.module.d.ts +28 -25
  3. package/dist/lib/artifacts.module.d.ts.map +1 -1
  4. package/dist/lib/artifacts.module.js +22 -2
  5. package/dist/lib/artifacts.module.js.map +1 -1
  6. package/dist/lib/components/artifact-version-history.component.d.ts +1 -0
  7. package/dist/lib/components/artifact-version-history.component.d.ts.map +1 -1
  8. package/dist/lib/components/artifact-version-history.component.js +30 -31
  9. package/dist/lib/components/artifact-version-history.component.js.map +1 -1
  10. package/dist/lib/components/artifact-viewer-panel.component.d.ts +3 -0
  11. package/dist/lib/components/artifact-viewer-panel.component.d.ts.map +1 -1
  12. package/dist/lib/components/artifact-viewer-panel.component.js +198 -112
  13. package/dist/lib/components/artifact-viewer-panel.component.js.map +1 -1
  14. package/dist/lib/components/plugins/audio-artifact-viewer.component.d.ts +11 -0
  15. package/dist/lib/components/plugins/audio-artifact-viewer.component.d.ts.map +1 -1
  16. package/dist/lib/components/plugins/audio-artifact-viewer.component.js +37 -12
  17. package/dist/lib/components/plugins/audio-artifact-viewer.component.js.map +1 -1
  18. package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.d.ts.map +1 -1
  19. package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.js +40 -51
  20. package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.js.map +1 -1
  21. package/dist/lib/components/plugins/data-artifact-viewer.component.js +27 -47
  22. package/dist/lib/components/plugins/data-artifact-viewer.component.js.map +1 -1
  23. package/dist/lib/components/plugins/data-requirements-viewer/data-requirements-viewer.component.js +89 -95
  24. package/dist/lib/components/plugins/data-requirements-viewer/data-requirements-viewer.component.js.map +1 -1
  25. package/dist/lib/components/plugins/ml-experiment-results-viewer.component.d.ts +227 -0
  26. package/dist/lib/components/plugins/ml-experiment-results-viewer.component.d.ts.map +1 -0
  27. package/dist/lib/components/plugins/ml-experiment-results-viewer.component.js +630 -0
  28. package/dist/lib/components/plugins/ml-experiment-results-viewer.component.js.map +1 -0
  29. package/dist/lib/components/plugins/video-artifact-viewer.component.d.ts +11 -0
  30. package/dist/lib/components/plugins/video-artifact-viewer.component.d.ts.map +1 -1
  31. package/dist/lib/components/plugins/video-artifact-viewer.component.js +37 -12
  32. package/dist/lib/components/plugins/video-artifact-viewer.component.js.map +1 -1
  33. package/dist/lib/components/previews/audio-artifact-preview.component.d.ts +18 -4
  34. package/dist/lib/components/previews/audio-artifact-preview.component.d.ts.map +1 -1
  35. package/dist/lib/components/previews/audio-artifact-preview.component.js +54 -21
  36. package/dist/lib/components/previews/audio-artifact-preview.component.js.map +1 -1
  37. package/dist/lib/components/previews/video-artifact-preview.component.d.ts +19 -5
  38. package/dist/lib/components/previews/video-artifact-preview.component.d.ts.map +1 -1
  39. package/dist/lib/components/previews/video-artifact-preview.component.js +54 -22
  40. package/dist/lib/components/previews/video-artifact-preview.component.js.map +1 -1
  41. package/dist/public-api.d.ts +1 -0
  42. package/dist/public-api.d.ts.map +1 -1
  43. package/dist/public-api.js +1 -0
  44. package/dist/public-api.js.map +1 -1
  45. package/package.json +21 -18
  46. package/dist/__tests__/exports.test.d.ts +0 -2
  47. package/dist/__tests__/exports.test.d.ts.map +0 -1
  48. package/dist/__tests__/exports.test.js +0 -17
  49. package/dist/__tests__/exports.test.js.map +0 -1
  50. package/dist/__tests__/image-artifact-viewer.test.d.ts +0 -2
  51. package/dist/__tests__/image-artifact-viewer.test.d.ts.map +0 -1
  52. package/dist/__tests__/image-artifact-viewer.test.js +0 -62
  53. package/dist/__tests__/image-artifact-viewer.test.js.map +0 -1
  54. package/dist/__tests__/index.test.d.ts +0 -2
  55. package/dist/__tests__/index.test.d.ts.map +0 -1
  56. package/dist/__tests__/index.test.js +0 -7
  57. package/dist/__tests__/index.test.js.map +0 -1
  58. package/dist/lib/__tests__/artifact-snapshots.test.d.ts +0 -2
  59. package/dist/lib/__tests__/artifact-snapshots.test.d.ts.map +0 -1
  60. package/dist/lib/__tests__/artifact-snapshots.test.js +0 -155
  61. package/dist/lib/__tests__/artifact-snapshots.test.js.map +0 -1
  62. package/dist/lib/__tests__/interactive-form-apply.service.test.d.ts +0 -2
  63. package/dist/lib/__tests__/interactive-form-apply.service.test.d.ts.map +0 -1
  64. package/dist/lib/__tests__/interactive-form-apply.service.test.js +0 -211
  65. package/dist/lib/__tests__/interactive-form-apply.service.test.js.map +0 -1
@@ -12,6 +12,7 @@ import { ArtifactFileService } from '../../services/artifact-file.service';
12
12
  import { AudioArtifactPreviewComponent } from '../previews/audio-artifact-preview.component';
13
13
  import * as i0 from "@angular/core";
14
14
  import * as i1 from "@angular/common";
15
+ import * as i2 from "@memberjunction/ng-media-player";
15
16
  function AudioArtifactViewerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
16
17
  i0.ɵɵelementStart(0, "div", 1);
17
18
  i0.ɵɵelement(1, "i", 4);
@@ -25,12 +26,12 @@ function AudioArtifactViewerComponent_Conditional_1_Template(rf, ctx) { if (rf &
25
26
  } }
26
27
  function AudioArtifactViewerComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
27
28
  const _r2 = i0.ɵɵgetCurrentView();
28
- i0.ɵɵelementStart(0, "audio", 5);
29
- i0.ɵɵlistener("error", function AudioArtifactViewerComponent_Conditional_2_Template_audio_error_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onMediaError()); });
29
+ i0.ɵɵelementStart(0, "mj-media-player", 5);
30
+ i0.ɵɵlistener("Ended", function AudioArtifactViewerComponent_Conditional_2_Template_mj_media_player_Ended_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onMediaEnded()); });
30
31
  i0.ɵɵelementEnd();
31
32
  } if (rf & 2) {
32
33
  const ctx_r0 = i0.ɵɵnextContext();
33
- i0.ɵɵproperty("src", ctx_r0.audioUrl);
34
+ i0.ɵɵproperty("Tracks", ctx_r0.MediaTracks);
34
35
  } }
35
36
  function AudioArtifactViewerComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
36
37
  i0.ɵɵelementStart(0, "div", 3);
@@ -51,6 +52,26 @@ let AudioArtifactViewerComponent = class AudioArtifactViewerComponent extends Ba
51
52
  cdr = inject(ChangeDetectorRef);
52
53
  audioUrl = '';
53
54
  errorMessage = '';
55
+ /**
56
+ * Single-track input for the generic {@link MJMediaPlayerComponent}. Rebuilt whenever
57
+ * {@link audioUrl} is (re)resolved via {@link setAudioUrl}; empty until a URL exists so the
58
+ * player shows its own empty state.
59
+ */
60
+ MediaTracks = [];
61
+ /** Set the resolved URL and recompute the single-element {@link MediaTracks} array in lockstep. */
62
+ setAudioUrl(url) {
63
+ this.audioUrl = url;
64
+ this.MediaTracks = url
65
+ ? [
66
+ {
67
+ Id: this.artifactVersion?.ID ?? 'audio',
68
+ Kind: 'audio',
69
+ Url: url,
70
+ MimeType: this.artifactVersion?.MimeType ?? undefined,
71
+ },
72
+ ]
73
+ : [];
74
+ }
54
75
  /**
55
76
  * Inline-preview component for audio artifacts ({@link IArtifactViewerPluginPreviewStatics}).
56
77
  * STATIC so the resolver reads it off the constructor without instantiating this DI-using component.
@@ -70,12 +91,12 @@ let AudioArtifactViewerComponent = class AudioArtifactViewerComponent extends Ba
70
91
  async ngOnInit() {
71
92
  try {
72
93
  if (this.artifactVersion?.ContentMode === 'File' && this.artifactVersion.ID) {
73
- this.audioUrl = await this.fileService.getDownloadUrl(this.artifactVersion.ID);
94
+ this.setAudioUrl(await this.fileService.getDownloadUrl(this.artifactVersion.ID));
74
95
  }
75
96
  else {
76
97
  const content = this.artifactVersion?.Content;
77
98
  if (content) {
78
- this.audioUrl = content;
99
+ this.setAudioUrl(content);
79
100
  }
80
101
  else {
81
102
  this.errorMessage = 'This artifact has no audio content.';
@@ -90,9 +111,13 @@ let AudioArtifactViewerComponent = class AudioArtifactViewerComponent extends Ba
90
111
  }
91
112
  onMediaError() {
92
113
  this.errorMessage = 'The audio could not be played. It may be corrupt or in an unsupported format.';
93
- this.audioUrl = '';
114
+ this.setAudioUrl('');
94
115
  this.cdr.markForCheck();
95
116
  }
117
+ /** Fired when the generic player reaches the end of the track. No-op affordance hook. */
118
+ onMediaEnded() {
119
+ // Playback finished — nothing to persist for a one-shot artifact viewer.
120
+ }
96
121
  GetCurrentStateSnapshot() {
97
122
  if (!this.artifactVersion) {
98
123
  return null;
@@ -108,15 +133,15 @@ let AudioArtifactViewerComponent = class AudioArtifactViewerComponent extends Ba
108
133
  return snap;
109
134
  }
110
135
  static ɵfac = /*@__PURE__*/ (() => { let ɵAudioArtifactViewerComponent_BaseFactory; return function AudioArtifactViewerComponent_Factory(__ngFactoryType__) { return (ɵAudioArtifactViewerComponent_BaseFactory || (ɵAudioArtifactViewerComponent_BaseFactory = i0.ɵɵgetInheritedFactory(AudioArtifactViewerComponent)))(__ngFactoryType__ || AudioArtifactViewerComponent); }; })();
111
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AudioArtifactViewerComponent, selectors: [["mj-audio-artifact-viewer"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 4, vars: 2, consts: [[1, "audio-viewer", 3, "ngClass"], [1, "audio-viewer__state", "audio-viewer__state--error"], ["controls", "", "preload", "metadata", 1, "audio-viewer__audio", 3, "src"], [1, "audio-viewer__state"], [1, "fa-solid", "fa-exclamation-triangle"], ["controls", "", "preload", "metadata", 1, "audio-viewer__audio", 3, "error", "src"], [1, "fa-solid", "fa-spinner", "fa-spin"]], template: function AudioArtifactViewerComponent_Template(rf, ctx) { if (rf & 1) {
136
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AudioArtifactViewerComponent, selectors: [["mj-audio-artifact-viewer"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 4, vars: 2, consts: [[1, "audio-viewer", 3, "ngClass"], [1, "audio-viewer__state", "audio-viewer__state--error"], [1, "audio-viewer__player", 3, "Tracks"], [1, "audio-viewer__state"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "audio-viewer__player", 3, "Ended", "Tracks"], [1, "fa-solid", "fa-spinner", "fa-spin"]], template: function AudioArtifactViewerComponent_Template(rf, ctx) { if (rf & 1) {
112
137
  i0.ɵɵelementStart(0, "div", 0);
113
- i0.ɵɵconditionalCreate(1, AudioArtifactViewerComponent_Conditional_1_Template, 4, 1, "div", 1)(2, AudioArtifactViewerComponent_Conditional_2_Template, 1, 1, "audio", 2)(3, AudioArtifactViewerComponent_Conditional_3_Template, 4, 0, "div", 3);
138
+ i0.ɵɵconditionalCreate(1, AudioArtifactViewerComponent_Conditional_1_Template, 4, 1, "div", 1)(2, AudioArtifactViewerComponent_Conditional_2_Template, 1, 1, "mj-media-player", 2)(3, AudioArtifactViewerComponent_Conditional_3_Template, 4, 0, "div", 3);
114
139
  i0.ɵɵelementEnd();
115
140
  } if (rf & 2) {
116
141
  i0.ɵɵproperty("ngClass", ctx.cssClass);
117
142
  i0.ɵɵadvance();
118
143
  i0.ɵɵconditional(ctx.errorMessage ? 1 : ctx.audioUrl ? 2 : 3);
119
- } }, dependencies: [i1.NgClass], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n }\n\n .audio-viewer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 24px;\n background: var(--mj-bg-surface-sunken);\n }\n\n .audio-viewer__audio[_ngcontent-%COMP%] {\n width: 100%;\n max-width: 480px;\n }\n\n .audio-viewer__state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .audio-viewer__state--error[_ngcontent-%COMP%] {\n color: var(--mj-status-error-text);\n }"] });
144
+ } }, dependencies: [i1.NgClass, i2.MJMediaPlayerComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n }\n\n .audio-viewer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 24px;\n background: var(--mj-bg-surface-sunken);\n }\n\n .audio-viewer__player[_ngcontent-%COMP%] {\n display: block;\n width: 100%;\n max-width: 640px;\n }\n\n .audio-viewer__state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .audio-viewer__state--error[_ngcontent-%COMP%] {\n color: var(--mj-status-error-text);\n }"] });
120
145
  };
121
146
  AudioArtifactViewerComponent = __decorate([
122
147
  RegisterClass(BaseArtifactViewerPluginComponent, 'AudioArtifactViewerPlugin')
@@ -132,7 +157,7 @@ export { AudioArtifactViewerComponent };
132
157
  <span>{{ errorMessage }}</span>
133
158
  </div>
134
159
  } @else if (audioUrl) {
135
- <audio class="audio-viewer__audio" controls preload="metadata" [src]="audioUrl" (error)="onMediaError()"></audio>
160
+ <mj-media-player class="audio-viewer__player" [Tracks]="MediaTracks" (Ended)="onMediaEnded()"></mj-media-player>
136
161
  } @else {
137
162
  <div class="audio-viewer__state">
138
163
  <i class="fa-solid fa-spinner fa-spin"></i>
@@ -140,7 +165,7 @@ export { AudioArtifactViewerComponent };
140
165
  </div>
141
166
  }
142
167
  </div>
143
- `, styles: ["\n :host {\n display: block;\n height: 100%;\n }\n\n .audio-viewer {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 24px;\n background: var(--mj-bg-surface-sunken);\n }\n\n .audio-viewer__audio {\n width: 100%;\n max-width: 480px;\n }\n\n .audio-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .audio-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n "] }]
168
+ `, styles: ["\n :host {\n display: block;\n height: 100%;\n }\n\n .audio-viewer {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 24px;\n background: var(--mj-bg-surface-sunken);\n }\n\n .audio-viewer__player {\n display: block;\n width: 100%;\n max-width: 640px;\n }\n\n .audio-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .audio-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n "] }]
144
169
  }], null, null); })();
145
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AudioArtifactViewerComponent, { className: "AudioArtifactViewerComponent", filePath: "src/lib/components/plugins/audio-artifact-viewer.component.ts", lineNumber: 73 }); })();
170
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AudioArtifactViewerComponent, { className: "AudioArtifactViewerComponent", filePath: "src/lib/components/plugins/audio-artifact-viewer.component.ts", lineNumber: 75 }); })();
146
171
  //# sourceMappingURL=audio-artifact-viewer.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"audio-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/audio-artifact-viewer.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectorRef, Component, inject, OnInit, Type } from '@angular/core';\nimport { DataSnapshot } from '@memberjunction/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';\nimport { ArtifactFileService } from '../../services/artifact-file.service';\nimport { IArtifactPreviewComponent } from '../../interfaces/artifact-viewer-plugin.interface';\nimport { AudioArtifactPreviewComponent } from '../previews/audio-artifact-preview.component';\n\n/**\n * Minimal full-size viewer plugin for audio artifacts. Renders an `<audio controls>` player.\n * Supports both storage modes (see {@link VideoArtifactViewerComponent} for the same contract).\n *\n * Deliberately minimal — the inline experience lives in {@link AudioArtifactPreviewComponent}\n * (exposed via {@link previewComponentType}); this satisfies the required `componentType`.\n */\n@Component({\n standalone: false,\n selector: 'mj-audio-artifact-viewer',\n template: `\n <div class=\"audio-viewer\" [ngClass]=\"cssClass\">\n @if (errorMessage) {\n <div class=\"audio-viewer__state audio-viewer__state--error\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage }}</span>\n </div>\n } @else if (audioUrl) {\n <audio class=\"audio-viewer__audio\" controls preload=\"metadata\" [src]=\"audioUrl\" (error)=\"onMediaError()\"></audio>\n } @else {\n <div class=\"audio-viewer__state\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading audio…</span>\n </div>\n }\n </div>\n `,\n styles: [\n `\n :host {\n display: block;\n height: 100%;\n }\n\n .audio-viewer {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 24px;\n background: var(--mj-bg-surface-sunken);\n }\n\n .audio-viewer__audio {\n width: 100%;\n max-width: 480px;\n }\n\n .audio-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .audio-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n `,\n ],\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'AudioArtifactViewerPlugin')\nexport class AudioArtifactViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit {\n private readonly fileService = inject(ArtifactFileService);\n private readonly cdr = inject(ChangeDetectorRef);\n\n public audioUrl = '';\n public errorMessage = '';\n\n /**\n * Inline-preview component for audio artifacts ({@link IArtifactViewerPluginPreviewStatics}).\n * STATIC so the resolver reads it off the constructor without instantiating this DI-using component.\n */\n public static readonly PreviewComponentType: Type<IArtifactPreviewComponent> = AudioArtifactPreviewComponent;\n\n /** Matches audio artifacts by type name or `audio/*` MIME. STATIC — drives preview resolution. */\n public static CanHandlePreview(artifactTypeName: string, contentType?: string): boolean {\n const mime = (contentType ?? '').toLowerCase();\n if (mime.startsWith('audio/')) {\n return true;\n }\n return (artifactTypeName ?? '').trim().toLowerCase() === 'audio';\n }\n\n public override get hasDisplayContent(): boolean {\n return true;\n }\n\n async ngOnInit(): Promise<void> {\n try {\n if (this.artifactVersion?.ContentMode === 'File' && this.artifactVersion.ID) {\n this.audioUrl = await this.fileService.getDownloadUrl(this.artifactVersion.ID);\n } else {\n const content = this.artifactVersion?.Content;\n if (content) {\n this.audioUrl = content;\n } else {\n this.errorMessage = 'This artifact has no audio content.';\n }\n }\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n this.errorMessage = `Could not load audio: ${detail}`;\n }\n this.cdr.markForCheck();\n }\n\n public onMediaError(): void {\n this.errorMessage = 'The audio could not be played. It may be corrupt or in an unsupported format.';\n this.audioUrl = '';\n this.cdr.markForCheck();\n }\n\n public override GetCurrentStateSnapshot(): DataSnapshot | null {\n if (!this.artifactVersion) {\n return null;\n }\n const snap = new DataSnapshot();\n snap.title = this.getDisplayTitle() ?? undefined;\n snap.interpretation = `Audio (${this.artifactVersion.MimeType ?? 'audio'}).`;\n snap.custom = {\n mimeType: this.artifactVersion.MimeType ?? undefined,\n fileName: this.artifactVersion.FileName ?? undefined,\n contentMode: this.artifactVersion.ContentMode,\n };\n return snap;\n }\n}\n"]}
1
+ {"version":3,"file":"audio-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/audio-artifact-viewer.component.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,EAAgB,MAAM,eAAe,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;AACtF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE3E,OAAO,EAAE,6BAA6B,EAAE,MAAM,8CAA8C,CAAC;;;;;IAgB7E,8BAA4D;IACxD,uBAAgD;IAChD,4BAAM;IAAA,YAAkB;IAC5B,AAD4B,iBAAO,EAC7B;;;IADI,eAAkB;IAAlB,yCAAkB;;;;IAG5B,0CAA8F;IAAzB,yMAAS,qBAAc,KAAC;IAAC,iBAAkB;;;IAAlE,2CAAsB;;;IAEpE,8BAAiC;IAC7B,uBAA2C;IAC3C,4BAAM;IAAA,mCAAc;IACxB,AADwB,iBAAO,EACzB;;AAvBtB;;;;;;GAMG;AA2DI,IAAM,4BAA4B,GAAlC,MAAM,4BAA6B,SAAQ,iCAAiC;IAC9D,WAAW,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC1C,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAE1C,QAAQ,GAAG,EAAE,CAAC;IACd,YAAY,GAAG,EAAE,CAAC;IAEzB;;;;OAIG;IACI,WAAW,GAAiB,EAAE,CAAC;IAEtC,mGAAmG;IAC3F,WAAW,CAAC,GAAW;QAC3B,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC;QACpB,IAAI,CAAC,WAAW,GAAG,GAAG;YAClB,CAAC,CAAC;gBACI;oBACI,EAAE,EAAE,IAAI,CAAC,eAAe,EAAE,EAAE,IAAI,OAAO;oBACvC,IAAI,EAAE,OAAO;oBACb,GAAG,EAAE,GAAG;oBACR,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,IAAI,SAAS;iBACxD;aACJ;YACH,CAAC,CAAC,EAAE,CAAC;IACb,CAAC;IAED;;;OAGG;IACI,MAAM,CAAU,oBAAoB,GAAoC,6BAA6B,CAAC;IAE7G,kGAAkG;IAC3F,MAAM,CAAC,gBAAgB,CAAC,gBAAwB,EAAE,WAAoB;QACzE,MAAM,IAAI,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAC/C,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,OAAO,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC;IACrE,CAAC;IAED,IAAoB,iBAAiB;QACjC,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,QAAQ;QACV,IAAI,CAAC;YACD,IAAI,IAAI,CAAC,eAAe,EAAE,WAAW,KAAK,MAAM,IAAI,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC;gBAC1E,IAAI,CAAC,WAAW,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;YACrF,CAAC;iBAAM,CAAC;gBACJ,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,OAAO,CAAC;gBAC9C,IAAI,OAAO,EAAE,CAAC;oBACV,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;gBAC9B,CAAC;qBAAM,CAAC;oBACJ,IAAI,CAAC,YAAY,GAAG,qCAAqC,CAAC;gBAC9D,CAAC;YACL,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAChE,IAAI,CAAC,YAAY,GAAG,yBAAyB,MAAM,EAAE,CAAC;QAC1D,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;IAC5B,CAAC;IAEM,YAAY;QACf,IAAI,CAAC,YAAY,GAAG,+EAA+E,CAAC;QACpG,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;IAC5B,CAAC;IAED,yFAAyF;IAClF,YAAY;QACf,yEAAyE;IAC7E,CAAC;IAEe,uBAAuB;QACnC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;QAChC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,eAAe,EAAE,IAAI,SAAS,CAAC;QACjD,IAAI,CAAC,cAAc,GAAG,UAAU,IAAI,CAAC,eAAe,CAAC,QAAQ,IAAI,OAAO,IAAI,CAAC;QAC7E,IAAI,CAAC,MAAM,GAAG;YACV,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,QAAQ,IAAI,SAAS;YACpD,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,QAAQ,IAAI,SAAS;YACpD,WAAW,EAAE,IAAI,CAAC,eAAe,CAAC,WAAW;SAChD,CAAC;QACF,OAAO,IAAI,CAAC;IAChB,CAAC;6RA3FQ,4BAA4B,yBAA5B,4BAA4B;6DAA5B,4BAA4B;YAtDjC,8BAA+C;YAQzC,AAFA,AALF,8FAAoB,oFAKG,wEAEd;YAMb,iBAAM;;YAdoB,sCAAoB;YAC1C,cAYC;YAZD,6DAYC;;;AAyCA,4BAA4B;IADxC,aAAa,CAAC,iCAAiC,EAAE,2BAA2B,CAAC;GACjE,4BAA4B,CA4FxC;;iFA5FY,4BAA4B;cA1DxC,SAAS;6BACM,KAAK,YACP,0BAA0B,YAC1B;;;;;;;;;;;;;;;;KAgBT;;kFAuCQ,4BAA4B","sourcesContent":["import { ChangeDetectorRef, Component, inject, OnInit, Type } from '@angular/core';\nimport { DataSnapshot } from '@memberjunction/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';\nimport { ArtifactFileService } from '../../services/artifact-file.service';\nimport { IArtifactPreviewComponent } from '../../interfaces/artifact-viewer-plugin.interface';\nimport { AudioArtifactPreviewComponent } from '../previews/audio-artifact-preview.component';\nimport { MJMediaPlayerComponent, MediaTrack } from '@memberjunction/ng-media-player';\n\n/**\n * Minimal full-size viewer plugin for audio artifacts. Renders an `<audio controls>` player.\n * Supports both storage modes (see {@link VideoArtifactViewerComponent} for the same contract).\n *\n * Deliberately minimal — the inline experience lives in {@link AudioArtifactPreviewComponent}\n * (exposed via {@link previewComponentType}); this satisfies the required `componentType`.\n */\n@Component({\n standalone: false,\n selector: 'mj-audio-artifact-viewer',\n template: `\n <div class=\"audio-viewer\" [ngClass]=\"cssClass\">\n @if (errorMessage) {\n <div class=\"audio-viewer__state audio-viewer__state--error\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage }}</span>\n </div>\n } @else if (audioUrl) {\n <mj-media-player class=\"audio-viewer__player\" [Tracks]=\"MediaTracks\" (Ended)=\"onMediaEnded()\"></mj-media-player>\n } @else {\n <div class=\"audio-viewer__state\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading audio…</span>\n </div>\n }\n </div>\n `,\n styles: [\n `\n :host {\n display: block;\n height: 100%;\n }\n\n .audio-viewer {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 24px;\n background: var(--mj-bg-surface-sunken);\n }\n\n .audio-viewer__player {\n display: block;\n width: 100%;\n max-width: 640px;\n }\n\n .audio-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .audio-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n `,\n ],\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'AudioArtifactViewerPlugin')\nexport class AudioArtifactViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit {\n private readonly fileService = inject(ArtifactFileService);\n private readonly cdr = inject(ChangeDetectorRef);\n\n public audioUrl = '';\n public errorMessage = '';\n\n /**\n * Single-track input for the generic {@link MJMediaPlayerComponent}. Rebuilt whenever\n * {@link audioUrl} is (re)resolved via {@link setAudioUrl}; empty until a URL exists so the\n * player shows its own empty state.\n */\n public MediaTracks: MediaTrack[] = [];\n\n /** Set the resolved URL and recompute the single-element {@link MediaTracks} array in lockstep. */\n private setAudioUrl(url: string): void {\n this.audioUrl = url;\n this.MediaTracks = url\n ? [\n {\n Id: this.artifactVersion?.ID ?? 'audio',\n Kind: 'audio',\n Url: url,\n MimeType: this.artifactVersion?.MimeType ?? undefined,\n },\n ]\n : [];\n }\n\n /**\n * Inline-preview component for audio artifacts ({@link IArtifactViewerPluginPreviewStatics}).\n * STATIC so the resolver reads it off the constructor without instantiating this DI-using component.\n */\n public static readonly PreviewComponentType: Type<IArtifactPreviewComponent> = AudioArtifactPreviewComponent;\n\n /** Matches audio artifacts by type name or `audio/*` MIME. STATIC — drives preview resolution. */\n public static CanHandlePreview(artifactTypeName: string, contentType?: string): boolean {\n const mime = (contentType ?? '').toLowerCase();\n if (mime.startsWith('audio/')) {\n return true;\n }\n return (artifactTypeName ?? '').trim().toLowerCase() === 'audio';\n }\n\n public override get hasDisplayContent(): boolean {\n return true;\n }\n\n async ngOnInit(): Promise<void> {\n try {\n if (this.artifactVersion?.ContentMode === 'File' && this.artifactVersion.ID) {\n this.setAudioUrl(await this.fileService.getDownloadUrl(this.artifactVersion.ID));\n } else {\n const content = this.artifactVersion?.Content;\n if (content) {\n this.setAudioUrl(content);\n } else {\n this.errorMessage = 'This artifact has no audio content.';\n }\n }\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n this.errorMessage = `Could not load audio: ${detail}`;\n }\n this.cdr.markForCheck();\n }\n\n public onMediaError(): void {\n this.errorMessage = 'The audio could not be played. It may be corrupt or in an unsupported format.';\n this.setAudioUrl('');\n this.cdr.markForCheck();\n }\n\n /** Fired when the generic player reaches the end of the track. No-op affordance hook. */\n public onMediaEnded(): void {\n // Playback finished — nothing to persist for a one-shot artifact viewer.\n }\n\n public override GetCurrentStateSnapshot(): DataSnapshot | null {\n if (!this.artifactVersion) {\n return null;\n }\n const snap = new DataSnapshot();\n snap.title = this.getDisplayTitle() ?? undefined;\n snap.interpretation = `Audio (${this.artifactVersion.MimeType ?? 'audio'}).`;\n snap.custom = {\n mimeType: this.artifactVersion.MimeType ?? undefined,\n fileName: this.artifactVersion.FileName ?? undefined,\n contentMode: this.artifactVersion.ContentMode,\n };\n return snap;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"component-feedback-panel.component.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,SAAS,EAA6B,MAAM,eAAe,CAAC;AAC7G,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAIrE,OAAO,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;;AAG5E;;GAEG;AACH,UAAU,QAAQ;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;;GAIG;AACH,qBAOa,+BAAgC,SAAQ,oBAAqB,YAAW,SAAS;IACnF,aAAa,EAAE,aAAa,GAAG,IAAI,CAAQ;IAC3C,qBAAqB,EAAE,WAAW,GAAG,IAAI,CAAQ;IACjD,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;IACrC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE1C,MAAM,qBAA4B;IAGrC,YAAY,EAAE,aAAa,GAAG,IAAI,CAAQ;IAC1C,UAAU,SAAK;IACf,WAAW,SAAK;IAChB,gBAAgB,SAAM;IACtB,YAAY,UAAS;IACrB,aAAa,UAAS;IACtB,WAAW,SAAM;IAGjB,aAAa,cAAqB;IAGzC,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,qBAAqB,CAA0C;IAEvE,OAAO,CAAC,GAAG,CAA6B;IAIxC,YAAY,IAAI,QAAQ,EAAE;IAQ1B,OAAO,CAAC,SAAS;IAcjB,UAAU,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IASxD,cAAc,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO;IAI5C,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAM1C,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO;IAIxC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAMrC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI9B,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAInC,gBAAgB,IAAI,IAAI;IAIxB,gBAAgB,IAAI,MAAM;IAI1B,yEAAyE;IACzE,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO;IAOtD,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAMpC,SAAS,IAAI,IAAI;IAQjB,SAAS,IAAI,OAAO;IAId,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IA8CrC,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAKxC,kBAAkB,IAAI,IAAI;IAI1B,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,kBAAkB;IAuC1B,OAAO,CAAC,yBAAyB;IAQjC;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,6BAA6B;IA0BrC,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,cAAc;IAWtB,UAAU,IAAI,IAAI;IAKlB,WAAW,IAAI,IAAI;yCAhXR,+BAA+B;2CAA/B,+BAA+B;CAmX3C"}
1
+ {"version":3,"file":"component-feedback-panel.component.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,SAAS,EAA6B,MAAM,eAAe,CAAC;AAC7G,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAIrE,OAAO,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;;AAI5E;;GAEG;AACH,UAAU,QAAQ;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;;GAIG;AACH,qBAOa,+BAAgC,SAAQ,oBAAqB,YAAW,SAAS;IACnF,aAAa,EAAE,aAAa,GAAG,IAAI,CAAQ;IAC3C,qBAAqB,EAAE,WAAW,GAAG,IAAI,CAAQ;IACjD,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;IACrC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE1C,MAAM,qBAA4B;IAGrC,YAAY,EAAE,aAAa,GAAG,IAAI,CAAQ;IAC1C,UAAU,SAAK;IACf,WAAW,SAAK;IAChB,gBAAgB,SAAM;IACtB,YAAY,UAAS;IACrB,aAAa,UAAS;IACtB,WAAW,SAAM;IAGjB,aAAa,cAAqB;IAGzC,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,qBAAqB,CAA0C;IAEvE,OAAO,CAAC,GAAG,CAA6B;IAIxC,YAAY,IAAI,QAAQ,EAAE;IAQ1B,OAAO,CAAC,SAAS;IAcjB,UAAU,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IASxD,cAAc,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO;IAI5C,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAM1C,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO;IAIxC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAMrC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI9B,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAInC,gBAAgB,IAAI,IAAI;IAIxB,gBAAgB,IAAI,MAAM;IAI1B,yEAAyE;IACzE,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO;IAOtD,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAMpC,SAAS,IAAI,IAAI;IAQjB,SAAS,IAAI,OAAO;IAId,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IA8CrC,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAKxC,kBAAkB,IAAI,IAAI;IAI1B,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,kBAAkB;IAuC1B,OAAO,CAAC,yBAAyB;IAQjC;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,6BAA6B;IA0BrC,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,cAAc;IAWtB,UAAU,IAAI,IAAI;IAKlB,WAAW,IAAI,IAAI;yCAhXR,+BAA+B;2CAA/B,+BAA+B;CAmX3C"}
@@ -3,6 +3,7 @@ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
3
3
  import { CommonModule } from '@angular/common';
4
4
  import { FormsModule } from '@angular/forms';
5
5
  import { MarkdownModule } from '@memberjunction/ng-markdown';
6
+ import { MJEmptyStateComponent, MJAlertComponent } from '@memberjunction/ng-ui-components';
6
7
  import * as i0 from "@angular/core";
7
8
  import * as i1 from "@angular/forms";
8
9
  import * as i2 from "@memberjunction/ng-markdown";
@@ -59,36 +60,32 @@ function ComponentFeedbackPanelComponent_Conditional_15_Template(rf, ctx) { if (
59
60
  i0.ɵɵrepeater(ctx_r2.GetTreeItems());
60
61
  } }
61
62
  function ComponentFeedbackPanelComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
62
- i0.ɵɵelementStart(0, "div", 12);
63
- i0.ɵɵelement(1, "i", 25);
64
- i0.ɵɵelementStart(2, "span");
65
- i0.ɵɵtext(3, "No component hierarchy available");
66
- i0.ɵɵelementEnd()();
63
+ i0.ɵɵelement(0, "mj-empty-state", 12);
67
64
  } }
68
65
  function ComponentFeedbackPanelComponent_Conditional_18_Conditional_5_Template(rf, ctx) { if (rf & 1) {
69
- i0.ɵɵelement(0, "mj-markdown", 27);
66
+ i0.ɵɵelement(0, "mj-markdown", 26);
70
67
  } if (rf & 2) {
71
68
  const ctx_r2 = i0.ɵɵnextContext(2);
72
69
  i0.ɵɵproperty("data", ctx_r2.SelectedSpec.description);
73
70
  } }
74
71
  function ComponentFeedbackPanelComponent_Conditional_18_For_11_Case_3_Template(rf, ctx) { if (rf & 1) {
75
- i0.ɵɵelement(0, "i", 44);
72
+ i0.ɵɵelement(0, "i", 43);
76
73
  } }
77
74
  function ComponentFeedbackPanelComponent_Conditional_18_For_11_Case_4_Template(rf, ctx) { if (rf & 1) {
78
- i0.ɵɵelement(0, "i", 45);
75
+ i0.ɵɵelement(0, "i", 44);
79
76
  } }
80
77
  function ComponentFeedbackPanelComponent_Conditional_18_For_11_Case_5_Template(rf, ctx) { if (rf & 1) {
81
- i0.ɵɵelement(0, "i", 46);
78
+ i0.ɵɵelement(0, "i", 45);
82
79
  } }
83
80
  function ComponentFeedbackPanelComponent_Conditional_18_For_11_Template(rf, ctx) { if (rf & 1) {
84
81
  const _r6 = i0.ɵɵgetCurrentView();
85
- i0.ɵɵelementStart(0, "span", 31)(1, "span", 42);
82
+ i0.ɵɵelementStart(0, "span", 30)(1, "span", 41);
86
83
  i0.ɵɵlistener("click", function ComponentFeedbackPanelComponent_Conditional_18_For_11_Template_span_click_1_listener() { const star_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.SetRating(star_r7 - 0.5)); })("mouseenter", function ComponentFeedbackPanelComponent_Conditional_18_For_11_Template_span_mouseenter_1_listener() { const star_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.SetHoverRating(star_r7 - 0.5)); });
87
84
  i0.ɵɵelementEnd();
88
- i0.ɵɵelementStart(2, "span", 43);
85
+ i0.ɵɵelementStart(2, "span", 42);
89
86
  i0.ɵɵlistener("click", function ComponentFeedbackPanelComponent_Conditional_18_For_11_Template_span_click_2_listener() { const star_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.SetRating(star_r7)); })("mouseenter", function ComponentFeedbackPanelComponent_Conditional_18_For_11_Template_span_mouseenter_2_listener() { const star_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.SetHoverRating(star_r7)); });
90
87
  i0.ɵɵelementEnd();
91
- i0.ɵɵconditionalCreate(3, ComponentFeedbackPanelComponent_Conditional_18_For_11_Case_3_Template, 1, 0, "i", 44)(4, ComponentFeedbackPanelComponent_Conditional_18_For_11_Case_4_Template, 1, 0, "i", 45)(5, ComponentFeedbackPanelComponent_Conditional_18_For_11_Case_5_Template, 1, 0, "i", 46);
88
+ i0.ɵɵconditionalCreate(3, ComponentFeedbackPanelComponent_Conditional_18_For_11_Case_3_Template, 1, 0, "i", 43)(4, ComponentFeedbackPanelComponent_Conditional_18_For_11_Case_4_Template, 1, 0, "i", 44)(5, ComponentFeedbackPanelComponent_Conditional_18_For_11_Case_5_Template, 1, 0, "i", 45);
92
89
  i0.ɵɵelementEnd();
93
90
  } if (rf & 2) {
94
91
  let tmp_11_0;
@@ -98,12 +95,12 @@ function ComponentFeedbackPanelComponent_Conditional_18_For_11_Template(rf, ctx)
98
95
  i0.ɵɵconditional((tmp_11_0 = ctx_r2.GetStarState(star_r7)) === "full" ? 3 : tmp_11_0 === "half" ? 4 : 5);
99
96
  } }
100
97
  function ComponentFeedbackPanelComponent_Conditional_18_Conditional_12_Template(rf, ctx) { if (rf & 1) {
101
- i0.ɵɵelementStart(0, "span", 32);
98
+ i0.ɵɵelementStart(0, "span", 31);
102
99
  i0.ɵɵtext(1, "Click to rate");
103
100
  i0.ɵɵelementEnd();
104
101
  } }
105
102
  function ComponentFeedbackPanelComponent_Conditional_18_Conditional_20_Template(rf, ctx) { if (rf & 1) {
106
- i0.ɵɵelementStart(0, "span", 37);
103
+ i0.ɵɵelementStart(0, "span", 36);
107
104
  i0.ɵɵtext(1);
108
105
  i0.ɵɵelementEnd();
109
106
  } if (rf & 2) {
@@ -112,69 +109,65 @@ function ComponentFeedbackPanelComponent_Conditional_18_Conditional_20_Template(
112
109
  i0.ɵɵtextInterpolate1("", ctx_r2.FeedbackComments.length, "/1000");
113
110
  } }
114
111
  function ComponentFeedbackPanelComponent_Conditional_18_Conditional_23_Template(rf, ctx) { if (rf & 1) {
115
- i0.ɵɵelement(0, "i", 47);
112
+ i0.ɵɵelement(0, "i", 46);
116
113
  i0.ɵɵelementStart(1, "span");
117
114
  i0.ɵɵtext(2, "Submitting...");
118
115
  i0.ɵɵelementEnd();
119
116
  } }
120
117
  function ComponentFeedbackPanelComponent_Conditional_18_Conditional_24_Template(rf, ctx) { if (rf & 1) {
121
- i0.ɵɵelement(0, "i", 48);
118
+ i0.ɵɵelement(0, "i", 47);
122
119
  i0.ɵɵelementStart(1, "span");
123
120
  i0.ɵɵtext(2, "Submit Feedback");
124
121
  i0.ɵɵelementEnd();
125
122
  } }
126
123
  function ComponentFeedbackPanelComponent_Conditional_18_Conditional_25_Template(rf, ctx) { if (rf & 1) {
127
- i0.ɵɵelementStart(0, "div", 40);
128
- i0.ɵɵelement(1, "i", 49);
129
- i0.ɵɵelementStart(2, "span");
130
- i0.ɵɵtext(3, "Feedback submitted successfully!");
131
- i0.ɵɵelementEnd()();
124
+ i0.ɵɵelementStart(0, "mj-alert", 39);
125
+ i0.ɵɵtext(1, "Feedback submitted successfully!");
126
+ i0.ɵɵelementEnd();
132
127
  } }
133
128
  function ComponentFeedbackPanelComponent_Conditional_18_Conditional_26_Template(rf, ctx) { if (rf & 1) {
134
- i0.ɵɵelementStart(0, "div", 41);
135
- i0.ɵɵelement(1, "i", 50);
136
- i0.ɵɵelementStart(2, "span");
137
- i0.ɵɵtext(3);
138
- i0.ɵɵelementEnd()();
129
+ i0.ɵɵelementStart(0, "mj-alert", 40);
130
+ i0.ɵɵtext(1);
131
+ i0.ɵɵelementEnd();
139
132
  } if (rf & 2) {
140
133
  const ctx_r2 = i0.ɵɵnextContext(2);
141
- i0.ɵɵadvance(3);
134
+ i0.ɵɵadvance();
142
135
  i0.ɵɵtextInterpolate(ctx_r2.SubmitError);
143
136
  } }
144
137
  function ComponentFeedbackPanelComponent_Conditional_18_Template(rf, ctx) { if (rf & 1) {
145
138
  const _r5 = i0.ɵɵgetCurrentView();
146
139
  i0.ɵɵelementStart(0, "div", 14)(1, "div", 9);
147
- i0.ɵɵelement(2, "i", 26);
140
+ i0.ɵɵelement(2, "i", 25);
148
141
  i0.ɵɵelementStart(3, "span");
149
142
  i0.ɵɵtext(4);
150
143
  i0.ɵɵelementEnd()();
151
- i0.ɵɵconditionalCreate(5, ComponentFeedbackPanelComponent_Conditional_18_Conditional_5_Template, 1, 1, "mj-markdown", 27);
152
- i0.ɵɵelementStart(6, "div", 28)(7, "label", 29);
144
+ i0.ɵɵconditionalCreate(5, ComponentFeedbackPanelComponent_Conditional_18_Conditional_5_Template, 1, 1, "mj-markdown", 26);
145
+ i0.ɵɵelementStart(6, "div", 27)(7, "label", 28);
153
146
  i0.ɵɵtext(8, "Your Rating");
154
147
  i0.ɵɵelementEnd();
155
- i0.ɵɵelementStart(9, "div", 30);
148
+ i0.ɵɵelementStart(9, "div", 29);
156
149
  i0.ɵɵlistener("mouseleave", function ComponentFeedbackPanelComponent_Conditional_18_Template_div_mouseleave_9_listener() { i0.ɵɵrestoreView(_r5); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.ClearHoverRating()); });
157
- i0.ɵɵrepeaterCreate(10, ComponentFeedbackPanelComponent_Conditional_18_For_11_Template, 6, 1, "span", 31, i0.ɵɵrepeaterTrackByIdentity);
150
+ i0.ɵɵrepeaterCreate(10, ComponentFeedbackPanelComponent_Conditional_18_For_11_Template, 6, 1, "span", 30, i0.ɵɵrepeaterTrackByIdentity);
158
151
  i0.ɵɵelementEnd();
159
- i0.ɵɵconditionalCreate(12, ComponentFeedbackPanelComponent_Conditional_18_Conditional_12_Template, 2, 0, "span", 32);
152
+ i0.ɵɵconditionalCreate(12, ComponentFeedbackPanelComponent_Conditional_18_Conditional_12_Template, 2, 0, "span", 31);
160
153
  i0.ɵɵelementEnd();
161
- i0.ɵɵelementStart(13, "div", 33)(14, "label", 34);
154
+ i0.ɵɵelementStart(13, "div", 32)(14, "label", 33);
162
155
  i0.ɵɵtext(15, " Comments ");
163
- i0.ɵɵelementStart(16, "span", 35);
156
+ i0.ɵɵelementStart(16, "span", 34);
164
157
  i0.ɵɵtext(17, "(optional)");
165
158
  i0.ɵɵelementEnd()();
166
- i0.ɵɵelementStart(18, "textarea", 36);
159
+ i0.ɵɵelementStart(18, "textarea", 35);
167
160
  i0.ɵɵtwoWayListener("ngModelChange", function ComponentFeedbackPanelComponent_Conditional_18_Template_textarea_ngModelChange_18_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r2 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r2.FeedbackComments, $event) || (ctx_r2.FeedbackComments = $event); return i0.ɵɵresetView($event); });
168
161
  i0.ɵɵtext(19, " ");
169
162
  i0.ɵɵelementEnd();
170
- i0.ɵɵconditionalCreate(20, ComponentFeedbackPanelComponent_Conditional_18_Conditional_20_Template, 2, 1, "span", 37);
163
+ i0.ɵɵconditionalCreate(20, ComponentFeedbackPanelComponent_Conditional_18_Conditional_20_Template, 2, 1, "span", 36);
171
164
  i0.ɵɵelementEnd();
172
- i0.ɵɵelementStart(21, "div", 38)(22, "button", 39);
165
+ i0.ɵɵelementStart(21, "div", 37)(22, "button", 38);
173
166
  i0.ɵɵlistener("click", function ComponentFeedbackPanelComponent_Conditional_18_Template_button_click_22_listener() { i0.ɵɵrestoreView(_r5); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.SubmitFeedback()); });
174
167
  i0.ɵɵconditionalCreate(23, ComponentFeedbackPanelComponent_Conditional_18_Conditional_23_Template, 3, 0)(24, ComponentFeedbackPanelComponent_Conditional_18_Conditional_24_Template, 3, 0);
175
168
  i0.ɵɵelementEnd()();
176
- i0.ɵɵconditionalCreate(25, ComponentFeedbackPanelComponent_Conditional_18_Conditional_25_Template, 4, 0, "div", 40);
177
- i0.ɵɵconditionalCreate(26, ComponentFeedbackPanelComponent_Conditional_18_Conditional_26_Template, 4, 1, "div", 41);
169
+ i0.ɵɵconditionalCreate(25, ComponentFeedbackPanelComponent_Conditional_18_Conditional_25_Template, 2, 0, "mj-alert", 39);
170
+ i0.ɵɵconditionalCreate(26, ComponentFeedbackPanelComponent_Conditional_18_Conditional_26_Template, 2, 1, "mj-alert", 40);
178
171
  i0.ɵɵelementEnd();
179
172
  } if (rf & 2) {
180
173
  const ctx_r2 = i0.ɵɵnextContext();
@@ -200,11 +193,7 @@ function ComponentFeedbackPanelComponent_Conditional_18_Template(rf, ctx) { if (
200
193
  i0.ɵɵconditional(ctx_r2.SubmitError ? 26 : -1);
201
194
  } }
202
195
  function ComponentFeedbackPanelComponent_Conditional_19_Template(rf, ctx) { if (rf & 1) {
203
- i0.ɵɵelementStart(0, "div", 15);
204
- i0.ɵɵelement(1, "i", 51);
205
- i0.ɵɵelementStart(2, "p");
206
- i0.ɵɵtext(3, "Select a component from the tree to provide feedback");
207
- i0.ɵɵelementEnd()();
196
+ i0.ɵɵelement(0, "mj-empty-state", 15);
208
197
  } }
209
198
  /**
210
199
  * Component feedback panel that displays component hierarchy tree
@@ -536,7 +525,7 @@ export class ComponentFeedbackPanelComponent extends BaseAngularComponent {
536
525
  this.ClearHighlight();
537
526
  }
538
527
  static ɵfac = /*@__PURE__*/ (() => { let ɵComponentFeedbackPanelComponent_BaseFactory; return function ComponentFeedbackPanelComponent_Factory(__ngFactoryType__) { return (ɵComponentFeedbackPanelComponent_BaseFactory || (ɵComponentFeedbackPanelComponent_BaseFactory = i0.ɵɵgetInheritedFactory(ComponentFeedbackPanelComponent)))(__ngFactoryType__ || ComponentFeedbackPanelComponent); }; })();
539
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ComponentFeedbackPanelComponent, selectors: [["mj-component-feedback-panel"]], inputs: { ComponentSpec: "ComponentSpec", ReactContainerElement: "ReactContainerElement", ConversationId: "ConversationId", ConversationDetailId: "ConversationDetailId" }, outputs: { Closed: "Closed" }, features: [i0.ɵɵInheritDefinitionFeature], decls: 20, vars: 2, consts: [[1, "feedback-panel-overlay", 3, "click"], [1, "feedback-panel", 3, "click"], [1, "panel-header"], [1, "panel-title"], [1, "fa-solid", "fa-magnifying-glass"], [1, "close-button", 3, "click"], [1, "fa-solid", "fa-times"], [1, "panel-content"], [1, "tree-section"], [1, "section-header"], [1, "fa-solid", "fa-sitemap"], [1, "component-tree"], [1, "empty-state"], [1, "feedback-section"], [1, "selected-component-info"], [1, "no-selection-message"], [1, "tree-item", 3, "selected", "padding-left"], [1, "tree-item", 3, "click", "mouseenter", "mouseleave"], [1, "tree-toggle", "fa-solid", 3, "fa-chevron-right", "fa-chevron-down"], [1, "tree-spacer"], [1, "fa-solid", "fa-cube", "component-icon"], [1, "component-info"], [1, "component-name"], [1, "component-badge", "registry"], [1, "tree-toggle", "fa-solid", 3, "click"], [1, "fa-solid", "fa-info-circle"], [1, "fa-solid", "fa-star"], [1, "component-description", 3, "data"], [1, "star-rating-container"], [1, "rating-label"], [1, "star-rating", 3, "mouseleave"], [1, "star-wrapper"], [1, "rating-text", "placeholder"], [1, "comment-container"], [1, "comment-label"], [1, "optional-label"], ["placeholder", "Share your thoughts about this component...", "rows", "4", "maxlength", "1000", 1, "comment-input", 3, "ngModelChange", "ngModel"], [1, "char-count"], [1, "submit-container"], [1, "submit-button", 3, "click", "disabled"], [1, "message", "success-message"], [1, "message", "error-message"], [1, "star-zone", "star-zone-left", 3, "click", "mouseenter"], [1, "star-zone", "star-zone-right", 3, "click", "mouseenter"], [1, "star", "fa-solid", "fa-star"], [1, "star", "fa-solid", "fa-star-half-stroke"], [1, "star", "fa-regular", "fa-star"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-paper-plane"], [1, "fa-solid", "fa-check-circle"], [1, "fa-solid", "fa-exclamation-circle"], [1, "fa-solid", "fa-hand-pointer"]], template: function ComponentFeedbackPanelComponent_Template(rf, ctx) { if (rf & 1) {
528
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ComponentFeedbackPanelComponent, selectors: [["mj-component-feedback-panel"]], inputs: { ComponentSpec: "ComponentSpec", ReactContainerElement: "ReactContainerElement", ConversationId: "ConversationId", ConversationDetailId: "ConversationDetailId" }, outputs: { Closed: "Closed" }, features: [i0.ɵɵInheritDefinitionFeature], decls: 20, vars: 2, consts: [[1, "feedback-panel-overlay", 3, "click"], [1, "feedback-panel", 3, "click"], [1, "panel-header"], [1, "panel-title"], [1, "fa-solid", "fa-magnifying-glass"], [1, "close-button", 3, "click"], [1, "fa-solid", "fa-times"], [1, "panel-content"], [1, "tree-section"], [1, "section-header"], [1, "fa-solid", "fa-sitemap"], [1, "component-tree"], ["Icon", "fa-solid fa-circle-info", "Title", "No component hierarchy available", "Size", "compact"], [1, "feedback-section"], [1, "selected-component-info"], ["Icon", "fa-solid fa-hand-pointer", "Title", "Select a component from the tree to provide feedback", "Size", "compact"], [1, "tree-item", 3, "selected", "padding-left"], [1, "tree-item", 3, "click", "mouseenter", "mouseleave"], [1, "tree-toggle", "fa-solid", 3, "fa-chevron-right", "fa-chevron-down"], [1, "tree-spacer"], [1, "fa-solid", "fa-cube", "component-icon"], [1, "component-info"], [1, "component-name"], [1, "component-badge", "registry"], [1, "tree-toggle", "fa-solid", 3, "click"], [1, "fa-solid", "fa-star"], [1, "component-description", 3, "data"], [1, "star-rating-container"], [1, "rating-label"], [1, "star-rating", 3, "mouseleave"], [1, "star-wrapper"], [1, "rating-text", "placeholder"], [1, "comment-container"], [1, "comment-label"], [1, "optional-label"], ["placeholder", "Share your thoughts about this component...", "rows", "4", "maxlength", "1000", 1, "comment-input", 3, "ngModelChange", "ngModel"], [1, "char-count"], [1, "submit-container"], [1, "submit-button", 3, "click", "disabled"], ["Variant", "success"], ["Variant", "error"], [1, "star-zone", "star-zone-left", 3, "click", "mouseenter"], [1, "star-zone", "star-zone-right", 3, "click", "mouseenter"], [1, "star", "fa-solid", "fa-star"], [1, "star", "fa-solid", "fa-star-half-stroke"], [1, "star", "fa-regular", "fa-star"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-paper-plane"]], template: function ComponentFeedbackPanelComponent_Template(rf, ctx) { if (rf & 1) {
540
529
  i0.ɵɵelementStart(0, "div", 0);
541
530
  i0.ɵɵlistener("click", function ComponentFeedbackPanelComponent_Template_div_click_0_listener() { return ctx.ClosePanel(); });
542
531
  i0.ɵɵelementStart(1, "div", 1);
@@ -555,21 +544,21 @@ export class ComponentFeedbackPanelComponent extends BaseAngularComponent {
555
544
  i0.ɵɵelementStart(13, "span");
556
545
  i0.ɵɵtext(14, "Select Component");
557
546
  i0.ɵɵelementEnd()();
558
- i0.ɵɵconditionalCreate(15, ComponentFeedbackPanelComponent_Conditional_15_Template, 3, 0, "div", 11)(16, ComponentFeedbackPanelComponent_Conditional_16_Template, 4, 0, "div", 12);
547
+ i0.ɵɵconditionalCreate(15, ComponentFeedbackPanelComponent_Conditional_15_Template, 3, 0, "div", 11)(16, ComponentFeedbackPanelComponent_Conditional_16_Template, 1, 0, "mj-empty-state", 12);
559
548
  i0.ɵɵelementEnd();
560
549
  i0.ɵɵelementStart(17, "div", 13);
561
- i0.ɵɵconditionalCreate(18, ComponentFeedbackPanelComponent_Conditional_18_Template, 27, 10, "div", 14)(19, ComponentFeedbackPanelComponent_Conditional_19_Template, 4, 0, "div", 15);
550
+ i0.ɵɵconditionalCreate(18, ComponentFeedbackPanelComponent_Conditional_18_Template, 27, 10, "div", 14)(19, ComponentFeedbackPanelComponent_Conditional_19_Template, 1, 0, "mj-empty-state", 15);
562
551
  i0.ɵɵelementEnd()()()();
563
552
  } if (rf & 2) {
564
553
  i0.ɵɵadvance(15);
565
554
  i0.ɵɵconditional(ctx.ComponentSpec ? 15 : 16);
566
555
  i0.ɵɵadvance(3);
567
556
  i0.ɵɵconditional(ctx.SelectedSpec ? 18 : 19);
568
- } }, dependencies: [CommonModule, FormsModule, i1.DefaultValueAccessor, i1.NgControlStatus, i1.MaxLengthValidator, i1.NgModel, MarkdownModule, i2.MarkdownComponent], styles: ["\n\n.feedback-panel-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 60px;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: var(--mj-bg-overlay);\n z-index: 9999;\n display: flex;\n justify-content: flex-start;\n animation: _ngcontent-%COMP%_fadeIn 0.2s ease-in-out;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n\n\n.feedback-panel[_ngcontent-%COMP%] {\n width: 540px;\n height: 100%;\n background-color: var(--mj-bg-surface);\n \n\n\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);\n display: flex;\n flex-direction: column;\n animation: _ngcontent-%COMP%_slideInFromLeft 0.3s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_slideInFromLeft {\n from { transform: translateX(-100%); }\n to { transform: translateX(0); }\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background-color: var(--mj-bg-surface-card);\n}\n\n.panel-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 20px;\n}\n\n.close-button[_ngcontent-%COMP%] {\n min-width: 32px;\n height: 32px;\n padding: 0;\n border: none;\n background: none;\n border-radius: 4px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 16px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.close-button[_ngcontent-%COMP%]:hover {\n background-color: var(--mj-bg-surface-hover);\n}\n\n\n\n.panel-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 20px;\n}\n\n\n\n.section-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-bottom: 12px;\n padding-bottom: 8px;\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n.section-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n\n\n.tree-section[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface-card);\n border-radius: 8px;\n padding: 16px;\n}\n\n.component-tree[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.tree-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n user-select: none;\n}\n\n.tree-item[_ngcontent-%COMP%]:hover {\n background-color: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.tree-item.selected[_ngcontent-%COMP%] {\n background-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-weight: 500;\n}\n\n.tree-item.selected[_ngcontent-%COMP%] .component-icon[_ngcontent-%COMP%], \n.tree-item.selected[_ngcontent-%COMP%] .tree-toggle[_ngcontent-%COMP%] {\n color: var(--mj-text-inverse);\n}\n\n.tree-item.selected[_ngcontent-%COMP%] .component-badge[_ngcontent-%COMP%] {\n background-color: rgba(255, 255, 255, 0.2);\n color: var(--mj-text-inverse);\n border-color: rgba(255, 255, 255, 0.3);\n}\n\n.tree-toggle[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: transform 0.2s ease;\n width: 16px;\n text-align: center;\n}\n\n.tree-spacer[_ngcontent-%COMP%] {\n width: 16px;\n display: inline-block;\n}\n\n.component-icon[_ngcontent-%COMP%] {\n font-size: 16px;\n color: var(--mj-brand-primary);\n}\n\n.component-info[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 8px;\n overflow: hidden;\n}\n\n.component-name[_ngcontent-%COMP%] {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: 14px;\n}\n\n.component-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n padding: 2px 6px;\n border-radius: 10px;\n background-color: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n white-space: nowrap;\n font-weight: 500;\n}\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 20px;\n color: var(--mj-text-disabled);\n font-size: 14px;\n}\n\n\n\n.feedback-section[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface);\n border-radius: 8px;\n border: 1px solid var(--mj-border-default);\n padding: 16px;\n min-height: 300px;\n}\n\n.selected-component-info[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n}\n\n.component-description[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n margin: 0;\n padding: 12px;\n background-color: var(--mj-bg-surface-card);\n border-radius: 6px;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n\n\n.star-rating-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.rating-label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.star-rating[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.star-wrapper[_ngcontent-%COMP%] {\n position: relative;\n display: inline-block;\n cursor: pointer;\n}\n\n.star-wrapper[_ngcontent-%COMP%]:hover .star[_ngcontent-%COMP%] {\n transform: scale(1.2);\n filter: brightness(1.1);\n}\n\n.star-zone[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n height: 100%;\n width: 50%;\n z-index: 1;\n}\n\n.star-zone-left[_ngcontent-%COMP%] {\n left: 0;\n}\n\n.star-zone-right[_ngcontent-%COMP%] {\n right: 0;\n}\n\n.star[_ngcontent-%COMP%] {\n font-size: 32px;\n \n\n color: #ffd700;\n transition: all 0.2s ease;\n pointer-events: none;\n}\n\n.star.fa-regular[_ngcontent-%COMP%] {\n color: var(--mj-border-strong);\n}\n\n.rating-text[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n margin-top: 4px;\n}\n\n.rating-text.placeholder[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n font-style: italic;\n}\n\n\n\n.comment-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n position: relative;\n}\n\n.comment-label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.optional-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: normal;\n color: var(--mj-text-disabled);\n}\n\n.comment-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n font-family: inherit;\n resize: vertical;\n min-height: 80px;\n transition: border-color 0.2s ease;\n background-color: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n box-sizing: border-box;\n}\n\n.comment-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.char-count[_ngcontent-%COMP%] {\n position: absolute;\n bottom: 8px;\n right: 12px;\n font-size: 11px;\n color: var(--mj-text-disabled);\n background-color: var(--mj-bg-surface);\n padding: 2px 4px;\n}\n\n\n\n.submit-container[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-start;\n}\n\n.submit-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n font-size: 14px;\n font-weight: 500;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n background-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transition: background-color 0.2s ease;\n}\n\n.submit-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background-color: var(--mj-brand-primary-hover);\n}\n\n.submit-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n\n\n.message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n border-radius: 6px;\n font-size: 14px;\n animation: _ngcontent-%COMP%_slideDown 0.3s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from { opacity: 0; transform: translateY(-10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.success-message[_ngcontent-%COMP%] {\n background-color: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.success-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.error-message[_ngcontent-%COMP%] {\n background-color: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.error-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.no-selection-message[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 40px 20px;\n color: var(--mj-text-disabled);\n text-align: center;\n}\n\n.no-selection-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n color: var(--mj-border-strong);\n}\n\n.no-selection-message[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n line-height: 1.5;\n}\n\n\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 8px;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background-color: var(--mj-border-strong);\n border-radius: 4px;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background-color: var(--mj-text-disabled);\n}"] });
557
+ } }, dependencies: [CommonModule, FormsModule, i1.DefaultValueAccessor, i1.NgControlStatus, i1.MaxLengthValidator, i1.NgModel, MarkdownModule, i2.MarkdownComponent, MJEmptyStateComponent, MJAlertComponent], styles: ["\n\n.feedback-panel-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 60px;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: var(--mj-bg-overlay);\n z-index: 9999;\n display: flex;\n justify-content: flex-start;\n animation: _ngcontent-%COMP%_fadeIn 0.2s ease-in-out;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n\n\n.feedback-panel[_ngcontent-%COMP%] {\n width: 540px;\n height: 100%;\n background-color: var(--mj-bg-surface);\n \n\n\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);\n display: flex;\n flex-direction: column;\n animation: _ngcontent-%COMP%_slideInFromLeft 0.3s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_slideInFromLeft {\n from { transform: translateX(-100%); }\n to { transform: translateX(0); }\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background-color: var(--mj-bg-surface-card);\n}\n\n.panel-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 20px;\n}\n\n.close-button[_ngcontent-%COMP%] {\n min-width: 32px;\n height: 32px;\n padding: 0;\n border: none;\n background: none;\n border-radius: 4px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 16px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.close-button[_ngcontent-%COMP%]:hover {\n background-color: var(--mj-bg-surface-hover);\n}\n\n\n\n.panel-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 20px;\n}\n\n\n\n.section-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-bottom: 12px;\n padding-bottom: 8px;\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n.section-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n\n\n.tree-section[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface-card);\n border-radius: 8px;\n padding: 16px;\n}\n\n.component-tree[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.tree-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n user-select: none;\n}\n\n.tree-item[_ngcontent-%COMP%]:hover {\n background-color: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.tree-item.selected[_ngcontent-%COMP%] {\n background-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-weight: 500;\n}\n\n.tree-item.selected[_ngcontent-%COMP%] .component-icon[_ngcontent-%COMP%], \n.tree-item.selected[_ngcontent-%COMP%] .tree-toggle[_ngcontent-%COMP%] {\n color: var(--mj-text-inverse);\n}\n\n.tree-item.selected[_ngcontent-%COMP%] .component-badge[_ngcontent-%COMP%] {\n background-color: rgba(255, 255, 255, 0.2);\n color: var(--mj-text-inverse);\n border-color: rgba(255, 255, 255, 0.3);\n}\n\n.tree-toggle[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: transform 0.2s ease;\n width: 16px;\n text-align: center;\n}\n\n.tree-spacer[_ngcontent-%COMP%] {\n width: 16px;\n display: inline-block;\n}\n\n.component-icon[_ngcontent-%COMP%] {\n font-size: 16px;\n color: var(--mj-brand-primary);\n}\n\n.component-info[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 8px;\n overflow: hidden;\n}\n\n.component-name[_ngcontent-%COMP%] {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: 14px;\n}\n\n.component-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n padding: 2px 6px;\n border-radius: 10px;\n background-color: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n white-space: nowrap;\n font-weight: 500;\n}\n\n\n\n.feedback-section[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface);\n border-radius: 8px;\n border: 1px solid var(--mj-border-default);\n padding: 16px;\n min-height: 300px;\n}\n\n.selected-component-info[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n}\n\n.component-description[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n margin: 0;\n padding: 12px;\n background-color: var(--mj-bg-surface-card);\n border-radius: 6px;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n\n\n.star-rating-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.rating-label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.star-rating[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.star-wrapper[_ngcontent-%COMP%] {\n position: relative;\n display: inline-block;\n cursor: pointer;\n}\n\n.star-wrapper[_ngcontent-%COMP%]:hover .star[_ngcontent-%COMP%] {\n transform: scale(1.2);\n filter: brightness(1.1);\n}\n\n.star-zone[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n height: 100%;\n width: 50%;\n z-index: 1;\n}\n\n.star-zone-left[_ngcontent-%COMP%] {\n left: 0;\n}\n\n.star-zone-right[_ngcontent-%COMP%] {\n right: 0;\n}\n\n.star[_ngcontent-%COMP%] {\n font-size: 32px;\n \n\n color: #ffd700;\n transition: all 0.2s ease;\n pointer-events: none;\n}\n\n.star.fa-regular[_ngcontent-%COMP%] {\n color: var(--mj-border-strong);\n}\n\n.rating-text[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n margin-top: 4px;\n}\n\n.rating-text.placeholder[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n font-style: italic;\n}\n\n\n\n.comment-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n position: relative;\n}\n\n.comment-label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.optional-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: normal;\n color: var(--mj-text-disabled);\n}\n\n.comment-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n font-family: inherit;\n resize: vertical;\n min-height: 80px;\n transition: border-color 0.2s ease;\n background-color: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n box-sizing: border-box;\n}\n\n.comment-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.char-count[_ngcontent-%COMP%] {\n position: absolute;\n bottom: 8px;\n right: 12px;\n font-size: 11px;\n color: var(--mj-text-disabled);\n background-color: var(--mj-bg-surface);\n padding: 2px 4px;\n}\n\n\n\n.submit-container[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-start;\n}\n\n.submit-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n font-size: 14px;\n font-weight: 500;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n background-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transition: background-color 0.2s ease;\n}\n\n.submit-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background-color: var(--mj-brand-primary-hover);\n}\n\n.submit-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from { opacity: 0; transform: translateY(-10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 8px;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background-color: var(--mj-border-strong);\n border-radius: 4px;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background-color: var(--mj-text-disabled);\n}"] });
569
558
  }
570
559
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ComponentFeedbackPanelComponent, [{
571
560
  type: Component,
572
- args: [{ selector: 'mj-component-feedback-panel', standalone: true, imports: [CommonModule, FormsModule, MarkdownModule], template: "<div class=\"feedback-panel-overlay\" (click)=\"ClosePanel()\">\n <div class=\"feedback-panel\" (click)=\"$event.stopPropagation()\">\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"panel-title\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <span>Inspect & Rate</span>\n </div>\n <button class=\"close-button\" (click)=\"ClosePanel()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"panel-content\">\n <!-- Component Tree Section -->\n <div class=\"tree-section\">\n <div class=\"section-header\">\n <i class=\"fa-solid fa-sitemap\"></i>\n <span>Select Component</span>\n </div>\n\n @if (ComponentSpec) {\n <div class=\"component-tree\">\n @for (item of GetTreeItems(); track item.spec.name) {\n <div\n class=\"tree-item\"\n [class.selected]=\"IsSelected(item.spec)\"\n [style.padding-left]=\"GetIndentation(item.depth)\"\n (click)=\"SelectComponent(item.spec)\"\n (mouseenter)=\"HoverTreeItem(item.spec)\"\n (mouseleave)=\"ClearTreeItemHover()\">\n\n @if (item.hasChildren) {\n <i\n class=\"tree-toggle fa-solid\"\n [class.fa-chevron-right]=\"!IsNodeExpanded(item.spec)\"\n [class.fa-chevron-down]=\"IsNodeExpanded(item.spec)\"\n (click)=\"ToggleNode(item.spec, $event)\">\n </i>\n } @else {\n <span class=\"tree-spacer\"></span>\n }\n\n <i class=\"fa-solid fa-cube component-icon\"></i>\n\n <div class=\"component-info\">\n <span class=\"component-name\">{{ item.spec.title || item.spec.name }}</span>\n @if (item.spec.location === 'registry') {\n <span class=\"component-badge registry\">Registry</span>\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-info-circle\"></i>\n <span>No component hierarchy available</span>\n </div>\n }\n </div>\n\n <!-- Feedback Form Section -->\n <div class=\"feedback-section\">\n @if (SelectedSpec) {\n <div class=\"selected-component-info\">\n <div class=\"section-header\">\n <i class=\"fa-solid fa-star\"></i>\n <span>Rate: {{ SelectedSpec.title || SelectedSpec.name }}</span>\n </div>\n\n @if (SelectedSpec.description) {\n <mj-markdown [data]=\"SelectedSpec.description\" class=\"component-description\"></mj-markdown>\n }\n\n <!-- Star Rating (half-star support) -->\n <div class=\"star-rating-container\">\n <label class=\"rating-label\">Your Rating</label>\n <div class=\"star-rating\" (mouseleave)=\"ClearHoverRating()\">\n @for (star of [1, 2, 3, 4, 5]; track star) {\n <span class=\"star-wrapper\">\n <!-- Left half (sets X.5 for previous half) -->\n <span class=\"star-zone star-zone-left\"\n (click)=\"SetRating(star - 0.5)\"\n (mouseenter)=\"SetHoverRating(star - 0.5)\"></span>\n <!-- Right half (sets full star) -->\n <span class=\"star-zone star-zone-right\"\n (click)=\"SetRating(star)\"\n (mouseenter)=\"SetHoverRating(star)\"></span>\n <!-- Star icon -->\n @switch (GetStarState(star)) {\n @case ('full') {\n <i class=\"star fa-solid fa-star\"></i>\n }\n @case ('half') {\n <i class=\"star fa-solid fa-star-half-stroke\"></i>\n }\n @default {\n <i class=\"star fa-regular fa-star\"></i>\n }\n }\n </span>\n }\n </div>\n @if (StarRating === 0) {\n <span class=\"rating-text placeholder\">Click to rate</span>\n }\n </div>\n\n <!-- Comment Input -->\n <div class=\"comment-container\">\n <label class=\"comment-label\">\n Comments\n <span class=\"optional-label\">(optional)</span>\n </label>\n <textarea\n class=\"comment-input\"\n [(ngModel)]=\"FeedbackComments\"\n placeholder=\"Share your thoughts about this component...\"\n rows=\"4\"\n maxlength=\"1000\">\n </textarea>\n @if (FeedbackComments.length > 0) {\n <span class=\"char-count\">{{ FeedbackComments.length }}/1000</span>\n }\n </div>\n\n <!-- Submit Button -->\n <div class=\"submit-container\">\n <button\n class=\"submit-button\"\n [disabled]=\"!CanSubmit()\"\n (click)=\"SubmitFeedback()\">\n @if (IsSubmitting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Submitting...</span>\n } @else {\n <i class=\"fa-solid fa-paper-plane\"></i>\n <span>Submit Feedback</span>\n }\n </button>\n </div>\n\n <!-- Success/Error Messages -->\n @if (SubmitSuccess) {\n <div class=\"message success-message\">\n <i class=\"fa-solid fa-check-circle\"></i>\n <span>Feedback submitted successfully!</span>\n </div>\n }\n @if (SubmitError) {\n <div class=\"message error-message\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n <span>{{ SubmitError }}</span>\n </div>\n }\n </div>\n } @else {\n <div class=\"no-selection-message\">\n <i class=\"fa-solid fa-hand-pointer\"></i>\n <p>Select a component from the tree to provide feedback</p>\n </div>\n }\n </div>\n </div>\n </div>\n</div>\n", styles: ["/* Overlay */\n.feedback-panel-overlay {\n position: fixed;\n top: 60px;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: var(--mj-bg-overlay);\n z-index: 9999;\n display: flex;\n justify-content: flex-start;\n animation: fadeIn 0.2s ease-in-out;\n}\n\n@keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n/* Panel Container */\n.feedback-panel {\n width: 540px;\n height: 100%;\n background-color: var(--mj-bg-surface);\n /* Side-panel shadow (horizontal): no semantic token covers a horizontal panel shadow,\n and the alpha keeps it readable in both light and dark themes. */\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);\n display: flex;\n flex-direction: column;\n animation: slideInFromLeft 0.3s ease-out;\n}\n\n@keyframes slideInFromLeft {\n from { transform: translateX(-100%); }\n to { transform: translateX(0); }\n}\n\n/* Header */\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background-color: var(--mj-bg-surface-card);\n}\n\n.panel-title {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.panel-title i {\n color: var(--mj-brand-primary);\n font-size: 20px;\n}\n\n.close-button {\n min-width: 32px;\n height: 32px;\n padding: 0;\n border: none;\n background: none;\n border-radius: 4px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 16px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.close-button:hover {\n background-color: var(--mj-bg-surface-hover);\n}\n\n/* Content */\n.panel-content {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 20px;\n}\n\n/* Section Headers */\n.section-header {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-bottom: 12px;\n padding-bottom: 8px;\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n.section-header i {\n color: var(--mj-brand-primary);\n}\n\n/* Component Tree */\n.tree-section {\n background-color: var(--mj-bg-surface-card);\n border-radius: 8px;\n padding: 16px;\n}\n\n.component-tree {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.tree-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n user-select: none;\n}\n\n.tree-item:hover {\n background-color: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.tree-item.selected {\n background-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-weight: 500;\n}\n\n.tree-item.selected .component-icon,\n.tree-item.selected .tree-toggle {\n color: var(--mj-text-inverse);\n}\n\n.tree-item.selected .component-badge {\n background-color: rgba(255, 255, 255, 0.2);\n color: var(--mj-text-inverse);\n border-color: rgba(255, 255, 255, 0.3);\n}\n\n.tree-toggle {\n font-size: 12px;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: transform 0.2s ease;\n width: 16px;\n text-align: center;\n}\n\n.tree-spacer {\n width: 16px;\n display: inline-block;\n}\n\n.component-icon {\n font-size: 16px;\n color: var(--mj-brand-primary);\n}\n\n.component-info {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 8px;\n overflow: hidden;\n}\n\n.component-name {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: 14px;\n}\n\n.component-badge {\n font-size: 10px;\n padding: 2px 6px;\n border-radius: 10px;\n background-color: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n white-space: nowrap;\n font-weight: 500;\n}\n\n.empty-state {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 20px;\n color: var(--mj-text-disabled);\n font-size: 14px;\n}\n\n/* Feedback Form Section */\n.feedback-section {\n background-color: var(--mj-bg-surface);\n border-radius: 8px;\n border: 1px solid var(--mj-border-default);\n padding: 16px;\n min-height: 300px;\n}\n\n.selected-component-info {\n display: flex;\n flex-direction: column;\n gap: 20px;\n}\n\n.component-description {\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n margin: 0;\n padding: 12px;\n background-color: var(--mj-bg-surface-card);\n border-radius: 6px;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n/* Star Rating */\n.star-rating-container {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.rating-label {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.star-rating {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.star-wrapper {\n position: relative;\n display: inline-block;\n cursor: pointer;\n}\n\n.star-wrapper:hover .star {\n transform: scale(1.2);\n filter: brightness(1.1);\n}\n\n.star-zone {\n position: absolute;\n top: 0;\n height: 100%;\n width: 50%;\n z-index: 1;\n}\n\n.star-zone-left {\n left: 0;\n}\n\n.star-zone-right {\n right: 0;\n}\n\n.star {\n font-size: 32px;\n /* Iconic gold star \u2014 categorical/branding color, not theme-dependent */\n color: #ffd700;\n transition: all 0.2s ease;\n pointer-events: none;\n}\n\n.star.fa-regular {\n color: var(--mj-border-strong);\n}\n\n.rating-text {\n font-size: 13px;\n color: var(--mj-text-secondary);\n margin-top: 4px;\n}\n\n.rating-text.placeholder {\n color: var(--mj-text-disabled);\n font-style: italic;\n}\n\n/* Comment Input */\n.comment-container {\n display: flex;\n flex-direction: column;\n gap: 8px;\n position: relative;\n}\n\n.comment-label {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.optional-label {\n font-size: 12px;\n font-weight: normal;\n color: var(--mj-text-disabled);\n}\n\n.comment-input {\n width: 100%;\n padding: 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n font-family: inherit;\n resize: vertical;\n min-height: 80px;\n transition: border-color 0.2s ease;\n background-color: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n box-sizing: border-box;\n}\n\n.comment-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.char-count {\n position: absolute;\n bottom: 8px;\n right: 12px;\n font-size: 11px;\n color: var(--mj-text-disabled);\n background-color: var(--mj-bg-surface);\n padding: 2px 4px;\n}\n\n/* Submit Button */\n.submit-container {\n display: flex;\n justify-content: flex-start;\n}\n\n.submit-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n font-size: 14px;\n font-weight: 500;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n background-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transition: background-color 0.2s ease;\n}\n\n.submit-button:hover:not(:disabled) {\n background-color: var(--mj-brand-primary-hover);\n}\n\n.submit-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* Messages */\n.message {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n border-radius: 6px;\n font-size: 14px;\n animation: slideDown 0.3s ease-out;\n}\n\n@keyframes slideDown {\n from { opacity: 0; transform: translateY(-10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.success-message {\n background-color: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.success-message i {\n color: var(--mj-status-success);\n}\n\n.error-message {\n background-color: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.error-message i {\n color: var(--mj-status-error);\n}\n\n/* No Selection Message */\n.no-selection-message {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 40px 20px;\n color: var(--mj-text-disabled);\n text-align: center;\n}\n\n.no-selection-message i {\n font-size: 48px;\n color: var(--mj-border-strong);\n}\n\n.no-selection-message p {\n margin: 0;\n font-size: 14px;\n line-height: 1.5;\n}\n\n/* Scrollbar Styling */\n.panel-content::-webkit-scrollbar {\n width: 8px;\n}\n\n.panel-content::-webkit-scrollbar-track {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n.panel-content::-webkit-scrollbar-thumb {\n background-color: var(--mj-border-strong);\n border-radius: 4px;\n}\n\n.panel-content::-webkit-scrollbar-thumb:hover {\n background-color: var(--mj-text-disabled);\n}\n"] }]
561
+ args: [{ selector: 'mj-component-feedback-panel', standalone: true, imports: [CommonModule, FormsModule, MarkdownModule, MJEmptyStateComponent, MJAlertComponent], template: "<div class=\"feedback-panel-overlay\" (click)=\"ClosePanel()\">\n <div class=\"feedback-panel\" (click)=\"$event.stopPropagation()\">\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"panel-title\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <span>Inspect & Rate</span>\n </div>\n <button class=\"close-button\" (click)=\"ClosePanel()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"panel-content\">\n <!-- Component Tree Section -->\n <div class=\"tree-section\">\n <div class=\"section-header\">\n <i class=\"fa-solid fa-sitemap\"></i>\n <span>Select Component</span>\n </div>\n\n @if (ComponentSpec) {\n <div class=\"component-tree\">\n @for (item of GetTreeItems(); track item.spec.name) {\n <div\n class=\"tree-item\"\n [class.selected]=\"IsSelected(item.spec)\"\n [style.padding-left]=\"GetIndentation(item.depth)\"\n (click)=\"SelectComponent(item.spec)\"\n (mouseenter)=\"HoverTreeItem(item.spec)\"\n (mouseleave)=\"ClearTreeItemHover()\">\n\n @if (item.hasChildren) {\n <i\n class=\"tree-toggle fa-solid\"\n [class.fa-chevron-right]=\"!IsNodeExpanded(item.spec)\"\n [class.fa-chevron-down]=\"IsNodeExpanded(item.spec)\"\n (click)=\"ToggleNode(item.spec, $event)\">\n </i>\n } @else {\n <span class=\"tree-spacer\"></span>\n }\n\n <i class=\"fa-solid fa-cube component-icon\"></i>\n\n <div class=\"component-info\">\n <span class=\"component-name\">{{ item.spec.title || item.spec.name }}</span>\n @if (item.spec.location === 'registry') {\n <span class=\"component-badge registry\">Registry</span>\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <mj-empty-state\n Icon=\"fa-solid fa-circle-info\"\n Title=\"No component hierarchy available\"\n Size=\"compact\" />\n }\n </div>\n\n <!-- Feedback Form Section -->\n <div class=\"feedback-section\">\n @if (SelectedSpec) {\n <div class=\"selected-component-info\">\n <div class=\"section-header\">\n <i class=\"fa-solid fa-star\"></i>\n <span>Rate: {{ SelectedSpec.title || SelectedSpec.name }}</span>\n </div>\n\n @if (SelectedSpec.description) {\n <mj-markdown [data]=\"SelectedSpec.description\" class=\"component-description\"></mj-markdown>\n }\n\n <!-- Star Rating (half-star support) -->\n <div class=\"star-rating-container\">\n <label class=\"rating-label\">Your Rating</label>\n <div class=\"star-rating\" (mouseleave)=\"ClearHoverRating()\">\n @for (star of [1, 2, 3, 4, 5]; track star) {\n <span class=\"star-wrapper\">\n <!-- Left half (sets X.5 for previous half) -->\n <span class=\"star-zone star-zone-left\"\n (click)=\"SetRating(star - 0.5)\"\n (mouseenter)=\"SetHoverRating(star - 0.5)\"></span>\n <!-- Right half (sets full star) -->\n <span class=\"star-zone star-zone-right\"\n (click)=\"SetRating(star)\"\n (mouseenter)=\"SetHoverRating(star)\"></span>\n <!-- Star icon -->\n @switch (GetStarState(star)) {\n @case ('full') {\n <i class=\"star fa-solid fa-star\"></i>\n }\n @case ('half') {\n <i class=\"star fa-solid fa-star-half-stroke\"></i>\n }\n @default {\n <i class=\"star fa-regular fa-star\"></i>\n }\n }\n </span>\n }\n </div>\n @if (StarRating === 0) {\n <span class=\"rating-text placeholder\">Click to rate</span>\n }\n </div>\n\n <!-- Comment Input -->\n <div class=\"comment-container\">\n <label class=\"comment-label\">\n Comments\n <span class=\"optional-label\">(optional)</span>\n </label>\n <textarea\n class=\"comment-input\"\n [(ngModel)]=\"FeedbackComments\"\n placeholder=\"Share your thoughts about this component...\"\n rows=\"4\"\n maxlength=\"1000\">\n </textarea>\n @if (FeedbackComments.length > 0) {\n <span class=\"char-count\">{{ FeedbackComments.length }}/1000</span>\n }\n </div>\n\n <!-- Submit Button -->\n <div class=\"submit-container\">\n <button\n class=\"submit-button\"\n [disabled]=\"!CanSubmit()\"\n (click)=\"SubmitFeedback()\">\n @if (IsSubmitting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Submitting...</span>\n } @else {\n <i class=\"fa-solid fa-paper-plane\"></i>\n <span>Submit Feedback</span>\n }\n </button>\n </div>\n\n <!-- Success/Error Messages -->\n @if (SubmitSuccess) {\n <mj-alert Variant=\"success\">Feedback submitted successfully!</mj-alert>\n }\n @if (SubmitError) {\n <mj-alert Variant=\"error\">{{ SubmitError }}</mj-alert>\n }\n </div>\n } @else {\n <mj-empty-state\n Icon=\"fa-solid fa-hand-pointer\"\n Title=\"Select a component from the tree to provide feedback\"\n Size=\"compact\" />\n }\n </div>\n </div>\n </div>\n</div>\n", styles: ["/* Overlay */\n.feedback-panel-overlay {\n position: fixed;\n top: 60px;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: var(--mj-bg-overlay);\n z-index: 9999;\n display: flex;\n justify-content: flex-start;\n animation: fadeIn 0.2s ease-in-out;\n}\n\n@keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n/* Panel Container */\n.feedback-panel {\n width: 540px;\n height: 100%;\n background-color: var(--mj-bg-surface);\n /* Side-panel shadow (horizontal): no semantic token covers a horizontal panel shadow,\n and the alpha keeps it readable in both light and dark themes. */\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);\n display: flex;\n flex-direction: column;\n animation: slideInFromLeft 0.3s ease-out;\n}\n\n@keyframes slideInFromLeft {\n from { transform: translateX(-100%); }\n to { transform: translateX(0); }\n}\n\n/* Header */\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background-color: var(--mj-bg-surface-card);\n}\n\n.panel-title {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.panel-title i {\n color: var(--mj-brand-primary);\n font-size: 20px;\n}\n\n.close-button {\n min-width: 32px;\n height: 32px;\n padding: 0;\n border: none;\n background: none;\n border-radius: 4px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 16px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.close-button:hover {\n background-color: var(--mj-bg-surface-hover);\n}\n\n/* Content */\n.panel-content {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 20px;\n}\n\n/* Section Headers */\n.section-header {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-bottom: 12px;\n padding-bottom: 8px;\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n.section-header i {\n color: var(--mj-brand-primary);\n}\n\n/* Component Tree */\n.tree-section {\n background-color: var(--mj-bg-surface-card);\n border-radius: 8px;\n padding: 16px;\n}\n\n.component-tree {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.tree-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n user-select: none;\n}\n\n.tree-item:hover {\n background-color: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.tree-item.selected {\n background-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-weight: 500;\n}\n\n.tree-item.selected .component-icon,\n.tree-item.selected .tree-toggle {\n color: var(--mj-text-inverse);\n}\n\n.tree-item.selected .component-badge {\n background-color: rgba(255, 255, 255, 0.2);\n color: var(--mj-text-inverse);\n border-color: rgba(255, 255, 255, 0.3);\n}\n\n.tree-toggle {\n font-size: 12px;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: transform 0.2s ease;\n width: 16px;\n text-align: center;\n}\n\n.tree-spacer {\n width: 16px;\n display: inline-block;\n}\n\n.component-icon {\n font-size: 16px;\n color: var(--mj-brand-primary);\n}\n\n.component-info {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 8px;\n overflow: hidden;\n}\n\n.component-name {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: 14px;\n}\n\n.component-badge {\n font-size: 10px;\n padding: 2px 6px;\n border-radius: 10px;\n background-color: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n white-space: nowrap;\n font-weight: 500;\n}\n\n/* Feedback Form Section */\n.feedback-section {\n background-color: var(--mj-bg-surface);\n border-radius: 8px;\n border: 1px solid var(--mj-border-default);\n padding: 16px;\n min-height: 300px;\n}\n\n.selected-component-info {\n display: flex;\n flex-direction: column;\n gap: 20px;\n}\n\n.component-description {\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n margin: 0;\n padding: 12px;\n background-color: var(--mj-bg-surface-card);\n border-radius: 6px;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n/* Star Rating */\n.star-rating-container {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.rating-label {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.star-rating {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.star-wrapper {\n position: relative;\n display: inline-block;\n cursor: pointer;\n}\n\n.star-wrapper:hover .star {\n transform: scale(1.2);\n filter: brightness(1.1);\n}\n\n.star-zone {\n position: absolute;\n top: 0;\n height: 100%;\n width: 50%;\n z-index: 1;\n}\n\n.star-zone-left {\n left: 0;\n}\n\n.star-zone-right {\n right: 0;\n}\n\n.star {\n font-size: 32px;\n /* Iconic gold star \u2014 categorical/branding color, not theme-dependent */\n color: #ffd700;\n transition: all 0.2s ease;\n pointer-events: none;\n}\n\n.star.fa-regular {\n color: var(--mj-border-strong);\n}\n\n.rating-text {\n font-size: 13px;\n color: var(--mj-text-secondary);\n margin-top: 4px;\n}\n\n.rating-text.placeholder {\n color: var(--mj-text-disabled);\n font-style: italic;\n}\n\n/* Comment Input */\n.comment-container {\n display: flex;\n flex-direction: column;\n gap: 8px;\n position: relative;\n}\n\n.comment-label {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.optional-label {\n font-size: 12px;\n font-weight: normal;\n color: var(--mj-text-disabled);\n}\n\n.comment-input {\n width: 100%;\n padding: 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n font-family: inherit;\n resize: vertical;\n min-height: 80px;\n transition: border-color 0.2s ease;\n background-color: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n box-sizing: border-box;\n}\n\n.comment-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.char-count {\n position: absolute;\n bottom: 8px;\n right: 12px;\n font-size: 11px;\n color: var(--mj-text-disabled);\n background-color: var(--mj-bg-surface);\n padding: 2px 4px;\n}\n\n/* Submit Button */\n.submit-container {\n display: flex;\n justify-content: flex-start;\n}\n\n.submit-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n font-size: 14px;\n font-weight: 500;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n background-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transition: background-color 0.2s ease;\n}\n\n.submit-button:hover:not(:disabled) {\n background-color: var(--mj-brand-primary-hover);\n}\n\n.submit-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n@keyframes slideDown {\n from { opacity: 0; transform: translateY(-10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n/* Scrollbar Styling */\n.panel-content::-webkit-scrollbar {\n width: 8px;\n}\n\n.panel-content::-webkit-scrollbar-track {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n.panel-content::-webkit-scrollbar-thumb {\n background-color: var(--mj-border-strong);\n border-radius: 4px;\n}\n\n.panel-content::-webkit-scrollbar-thumb:hover {\n background-color: var(--mj-text-disabled);\n}\n"] }]
573
562
  }], null, { ComponentSpec: [{
574
563
  type: Input
575
564
  }], ReactContainerElement: [{
@@ -581,5 +570,5 @@ export class ComponentFeedbackPanelComponent extends BaseAngularComponent {
581
570
  }], Closed: [{
582
571
  type: Output
583
572
  }] }); })();
584
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ComponentFeedbackPanelComponent, { className: "ComponentFeedbackPanelComponent", filePath: "src/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.ts", lineNumber: 30 }); })();
573
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ComponentFeedbackPanelComponent, { className: "ComponentFeedbackPanelComponent", filePath: "src/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.ts", lineNumber: 31 }); })();
585
574
  //# sourceMappingURL=component-feedback-panel.component.js.map