@memberjunction/ng-artifacts 5.20.0 → 5.22.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.
- package/dist/lib/components/artifact-type-plugin-viewer.component.d.ts +10 -0
- package/dist/lib/components/artifact-type-plugin-viewer.component.d.ts.map +1 -1
- package/dist/lib/components/artifact-type-plugin-viewer.component.js +15 -1
- package/dist/lib/components/artifact-type-plugin-viewer.component.js.map +1 -1
- package/dist/lib/components/artifact-viewer-panel.component.js +155 -145
- package/dist/lib/components/artifact-viewer-panel.component.js.map +1 -1
- package/dist/lib/components/base-artifact-viewer.component.d.ts +16 -0
- package/dist/lib/components/base-artifact-viewer.component.d.ts.map +1 -1
- package/dist/lib/components/base-artifact-viewer.component.js +20 -0
- package/dist/lib/components/base-artifact-viewer.component.js.map +1 -1
- package/dist/lib/components/plugins/component-artifact-viewer.component.d.ts +8 -1
- package/dist/lib/components/plugins/component-artifact-viewer.component.d.ts.map +1 -1
- package/dist/lib/components/plugins/component-artifact-viewer.component.js +26 -27
- package/dist/lib/components/plugins/component-artifact-viewer.component.js.map +1 -1
- package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.d.ts +4 -2
- package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.d.ts.map +1 -1
- package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.js +79 -63
- package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.js.map +1 -1
- package/package.json +15 -16
package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.js
CHANGED
|
@@ -2,8 +2,10 @@ import { Component, Input, Output, EventEmitter, ChangeDetectorRef, inject } fro
|
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import { FormsModule } from '@angular/forms';
|
|
4
4
|
import { Metadata } from '@memberjunction/core';
|
|
5
|
+
import { MarkdownModule } from '@memberjunction/ng-markdown';
|
|
5
6
|
import * as i0 from "@angular/core";
|
|
6
7
|
import * as i1 from "@angular/forms";
|
|
8
|
+
import * as i2 from "@memberjunction/ng-markdown";
|
|
7
9
|
const _c0 = () => [1, 2, 3, 4, 5];
|
|
8
10
|
const _forTrack0 = ($index, $item) => $item.spec.name;
|
|
9
11
|
function ComponentFeedbackPanelComponent_Conditional_15_For_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
@@ -64,40 +66,44 @@ function ComponentFeedbackPanelComponent_Conditional_16_Template(rf, ctx) { if (
|
|
|
64
66
|
i0.ɵɵelementEnd()();
|
|
65
67
|
} }
|
|
66
68
|
function ComponentFeedbackPanelComponent_Conditional_18_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
67
|
-
i0.ɵɵ
|
|
68
|
-
i0.ɵɵtext(1);
|
|
69
|
-
i0.ɵɵelementEnd();
|
|
69
|
+
i0.ɵɵelement(0, "mj-markdown", 27);
|
|
70
70
|
} if (rf & 2) {
|
|
71
71
|
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
72
|
-
i0.ɵɵ
|
|
73
|
-
|
|
72
|
+
i0.ɵɵproperty("data", ctx_r2.SelectedSpec.description);
|
|
73
|
+
} }
|
|
74
|
+
function ComponentFeedbackPanelComponent_Conditional_18_For_11_Case_3_Template(rf, ctx) { if (rf & 1) {
|
|
75
|
+
i0.ɵɵelement(0, "i", 44);
|
|
76
|
+
} }
|
|
77
|
+
function ComponentFeedbackPanelComponent_Conditional_18_For_11_Case_4_Template(rf, ctx) { if (rf & 1) {
|
|
78
|
+
i0.ɵɵelement(0, "i", 45);
|
|
79
|
+
} }
|
|
80
|
+
function ComponentFeedbackPanelComponent_Conditional_18_For_11_Case_5_Template(rf, ctx) { if (rf & 1) {
|
|
81
|
+
i0.ɵɵelement(0, "i", 46);
|
|
74
82
|
} }
|
|
75
83
|
function ComponentFeedbackPanelComponent_Conditional_18_For_11_Template(rf, ctx) { if (rf & 1) {
|
|
76
84
|
const _r6 = i0.ɵɵgetCurrentView();
|
|
77
|
-
i0.ɵɵelementStart(0, "
|
|
78
|
-
i0.ɵɵlistener("click", function
|
|
85
|
+
i0.ɵɵelementStart(0, "span", 31)(1, "span", 42);
|
|
86
|
+
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
|
+
i0.ɵɵelementEnd();
|
|
88
|
+
i0.ɵɵelementStart(2, "span", 43);
|
|
89
|
+
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
|
+
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);
|
|
79
92
|
i0.ɵɵelementEnd();
|
|
80
93
|
} if (rf & 2) {
|
|
94
|
+
let tmp_11_0;
|
|
81
95
|
const star_r7 = ctx.$implicit;
|
|
82
96
|
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
83
|
-
i0.ɵɵ
|
|
97
|
+
i0.ɵɵadvance(3);
|
|
98
|
+
i0.ɵɵconditional((tmp_11_0 = ctx_r2.GetStarState(star_r7)) === "full" ? 3 : tmp_11_0 === "half" ? 4 : 5);
|
|
84
99
|
} }
|
|
85
100
|
function ComponentFeedbackPanelComponent_Conditional_18_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
86
101
|
i0.ɵɵelementStart(0, "span", 32);
|
|
87
|
-
i0.ɵɵtext(1);
|
|
88
|
-
i0.ɵɵelementEnd();
|
|
89
|
-
} if (rf & 2) {
|
|
90
|
-
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
91
|
-
i0.ɵɵadvance();
|
|
92
|
-
i0.ɵɵtextInterpolate1("", ctx_r2.StarRating, " out of 5 stars");
|
|
93
|
-
} }
|
|
94
|
-
function ComponentFeedbackPanelComponent_Conditional_18_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
95
|
-
i0.ɵɵelementStart(0, "span", 33);
|
|
96
102
|
i0.ɵɵtext(1, "Click to rate");
|
|
97
103
|
i0.ɵɵelementEnd();
|
|
98
104
|
} }
|
|
99
|
-
function
|
|
100
|
-
i0.ɵɵelementStart(0, "span",
|
|
105
|
+
function ComponentFeedbackPanelComponent_Conditional_18_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
106
|
+
i0.ɵɵelementStart(0, "span", 37);
|
|
101
107
|
i0.ɵɵtext(1);
|
|
102
108
|
i0.ɵɵelementEnd();
|
|
103
109
|
} if (rf & 2) {
|
|
@@ -105,28 +111,28 @@ function ComponentFeedbackPanelComponent_Conditional_18_Conditional_21_Template(
|
|
|
105
111
|
i0.ɵɵadvance();
|
|
106
112
|
i0.ɵɵtextInterpolate1("", ctx_r2.FeedbackComments.length, "/1000");
|
|
107
113
|
} }
|
|
108
|
-
function
|
|
109
|
-
i0.ɵɵelement(0, "i",
|
|
114
|
+
function ComponentFeedbackPanelComponent_Conditional_18_Conditional_23_Template(rf, ctx) { if (rf & 1) {
|
|
115
|
+
i0.ɵɵelement(0, "i", 47);
|
|
110
116
|
i0.ɵɵelementStart(1, "span");
|
|
111
117
|
i0.ɵɵtext(2, "Submitting...");
|
|
112
118
|
i0.ɵɵelementEnd();
|
|
113
119
|
} }
|
|
114
|
-
function
|
|
115
|
-
i0.ɵɵelement(0, "i",
|
|
120
|
+
function ComponentFeedbackPanelComponent_Conditional_18_Conditional_24_Template(rf, ctx) { if (rf & 1) {
|
|
121
|
+
i0.ɵɵelement(0, "i", 48);
|
|
116
122
|
i0.ɵɵelementStart(1, "span");
|
|
117
123
|
i0.ɵɵtext(2, "Submit Feedback");
|
|
118
124
|
i0.ɵɵelementEnd();
|
|
119
125
|
} }
|
|
120
|
-
function
|
|
121
|
-
i0.ɵɵelementStart(0, "div",
|
|
122
|
-
i0.ɵɵelement(1, "i",
|
|
126
|
+
function ComponentFeedbackPanelComponent_Conditional_18_Conditional_25_Template(rf, ctx) { if (rf & 1) {
|
|
127
|
+
i0.ɵɵelementStart(0, "div", 40);
|
|
128
|
+
i0.ɵɵelement(1, "i", 49);
|
|
123
129
|
i0.ɵɵelementStart(2, "span");
|
|
124
130
|
i0.ɵɵtext(3, "Feedback submitted successfully!");
|
|
125
131
|
i0.ɵɵelementEnd()();
|
|
126
132
|
} }
|
|
127
|
-
function
|
|
128
|
-
i0.ɵɵelementStart(0, "div",
|
|
129
|
-
i0.ɵɵelement(1, "i",
|
|
133
|
+
function ComponentFeedbackPanelComponent_Conditional_18_Conditional_26_Template(rf, ctx) { if (rf & 1) {
|
|
134
|
+
i0.ɵɵelementStart(0, "div", 41);
|
|
135
|
+
i0.ɵɵelement(1, "i", 50);
|
|
130
136
|
i0.ɵɵelementStart(2, "span");
|
|
131
137
|
i0.ɵɵtext(3);
|
|
132
138
|
i0.ɵɵelementEnd()();
|
|
@@ -142,32 +148,33 @@ function ComponentFeedbackPanelComponent_Conditional_18_Template(rf, ctx) { if (
|
|
|
142
148
|
i0.ɵɵelementStart(3, "span");
|
|
143
149
|
i0.ɵɵtext(4);
|
|
144
150
|
i0.ɵɵelementEnd()();
|
|
145
|
-
i0.ɵɵconditionalCreate(5, ComponentFeedbackPanelComponent_Conditional_18_Conditional_5_Template,
|
|
151
|
+
i0.ɵɵconditionalCreate(5, ComponentFeedbackPanelComponent_Conditional_18_Conditional_5_Template, 1, 1, "mj-markdown", 27);
|
|
146
152
|
i0.ɵɵelementStart(6, "div", 28)(7, "label", 29);
|
|
147
153
|
i0.ɵɵtext(8, "Your Rating");
|
|
148
154
|
i0.ɵɵelementEnd();
|
|
149
155
|
i0.ɵɵelementStart(9, "div", 30);
|
|
150
|
-
i0.ɵɵ
|
|
156
|
+
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);
|
|
151
158
|
i0.ɵɵelementEnd();
|
|
152
|
-
i0.ɵɵconditionalCreate(12, ComponentFeedbackPanelComponent_Conditional_18_Conditional_12_Template, 2,
|
|
159
|
+
i0.ɵɵconditionalCreate(12, ComponentFeedbackPanelComponent_Conditional_18_Conditional_12_Template, 2, 0, "span", 32);
|
|
153
160
|
i0.ɵɵelementEnd();
|
|
154
|
-
i0.ɵɵelementStart(
|
|
155
|
-
i0.ɵɵtext(
|
|
156
|
-
i0.ɵɵelementStart(
|
|
157
|
-
i0.ɵɵtext(
|
|
161
|
+
i0.ɵɵelementStart(13, "div", 33)(14, "label", 34);
|
|
162
|
+
i0.ɵɵtext(15, " Comments ");
|
|
163
|
+
i0.ɵɵelementStart(16, "span", 35);
|
|
164
|
+
i0.ɵɵtext(17, "(optional)");
|
|
158
165
|
i0.ɵɵelementEnd()();
|
|
159
|
-
i0.ɵɵelementStart(
|
|
160
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
161
|
-
i0.ɵɵtext(
|
|
166
|
+
i0.ɵɵelementStart(18, "textarea", 36);
|
|
167
|
+
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
|
+
i0.ɵɵtext(19, " ");
|
|
162
169
|
i0.ɵɵelementEnd();
|
|
163
|
-
i0.ɵɵconditionalCreate(
|
|
170
|
+
i0.ɵɵconditionalCreate(20, ComponentFeedbackPanelComponent_Conditional_18_Conditional_20_Template, 2, 1, "span", 37);
|
|
164
171
|
i0.ɵɵelementEnd();
|
|
165
|
-
i0.ɵɵelementStart(
|
|
166
|
-
i0.ɵɵlistener("click", function
|
|
167
|
-
i0.ɵɵconditionalCreate(
|
|
172
|
+
i0.ɵɵelementStart(21, "div", 38)(22, "button", 39);
|
|
173
|
+
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
|
+
i0.ɵɵconditionalCreate(23, ComponentFeedbackPanelComponent_Conditional_18_Conditional_23_Template, 3, 0)(24, ComponentFeedbackPanelComponent_Conditional_18_Conditional_24_Template, 3, 0);
|
|
168
175
|
i0.ɵɵelementEnd()();
|
|
169
|
-
i0.ɵɵconditionalCreate(
|
|
170
|
-
i0.ɵɵconditionalCreate(
|
|
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);
|
|
171
178
|
i0.ɵɵelementEnd();
|
|
172
179
|
} if (rf & 2) {
|
|
173
180
|
const ctx_r2 = i0.ɵɵnextContext();
|
|
@@ -178,23 +185,23 @@ function ComponentFeedbackPanelComponent_Conditional_18_Template(rf, ctx) { if (
|
|
|
178
185
|
i0.ɵɵadvance(5);
|
|
179
186
|
i0.ɵɵrepeater(i0.ɵɵpureFunction0(9, _c0));
|
|
180
187
|
i0.ɵɵadvance(2);
|
|
181
|
-
i0.ɵɵconditional(ctx_r2.StarRating
|
|
182
|
-
i0.ɵɵadvance(
|
|
188
|
+
i0.ɵɵconditional(ctx_r2.StarRating === 0 ? 12 : -1);
|
|
189
|
+
i0.ɵɵadvance(6);
|
|
183
190
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.FeedbackComments);
|
|
184
191
|
i0.ɵɵadvance(2);
|
|
185
|
-
i0.ɵɵconditional(ctx_r2.FeedbackComments.length > 0 ?
|
|
192
|
+
i0.ɵɵconditional(ctx_r2.FeedbackComments.length > 0 ? 20 : -1);
|
|
186
193
|
i0.ɵɵadvance(2);
|
|
187
194
|
i0.ɵɵproperty("disabled", !ctx_r2.CanSubmit());
|
|
188
195
|
i0.ɵɵadvance();
|
|
189
|
-
i0.ɵɵconditional(ctx_r2.IsSubmitting ?
|
|
196
|
+
i0.ɵɵconditional(ctx_r2.IsSubmitting ? 23 : 24);
|
|
190
197
|
i0.ɵɵadvance(2);
|
|
191
|
-
i0.ɵɵconditional(ctx_r2.SubmitSuccess ?
|
|
198
|
+
i0.ɵɵconditional(ctx_r2.SubmitSuccess ? 25 : -1);
|
|
192
199
|
i0.ɵɵadvance();
|
|
193
|
-
i0.ɵɵconditional(ctx_r2.SubmitError ?
|
|
200
|
+
i0.ɵɵconditional(ctx_r2.SubmitError ? 26 : -1);
|
|
194
201
|
} }
|
|
195
202
|
function ComponentFeedbackPanelComponent_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
196
203
|
i0.ɵɵelementStart(0, "div", 15);
|
|
197
|
-
i0.ɵɵelement(1, "i",
|
|
204
|
+
i0.ɵɵelement(1, "i", 51);
|
|
198
205
|
i0.ɵɵelementStart(2, "p");
|
|
199
206
|
i0.ɵɵtext(3, "Select a component from the tree to provide feedback");
|
|
200
207
|
i0.ɵɵelementEnd()();
|
|
@@ -271,12 +278,12 @@ export class ComponentFeedbackPanelComponent {
|
|
|
271
278
|
GetIndentation(depth) {
|
|
272
279
|
return `${depth * 20}px`;
|
|
273
280
|
}
|
|
274
|
-
// --- Star Rating ---
|
|
275
|
-
SetRating(
|
|
276
|
-
this.StarRating =
|
|
281
|
+
// --- Star Rating (supports half-star increments) ---
|
|
282
|
+
SetRating(value) {
|
|
283
|
+
this.StarRating = value;
|
|
277
284
|
}
|
|
278
|
-
SetHoverRating(
|
|
279
|
-
this.HoverRating =
|
|
285
|
+
SetHoverRating(value) {
|
|
286
|
+
this.HoverRating = value;
|
|
280
287
|
}
|
|
281
288
|
ClearHoverRating() {
|
|
282
289
|
this.HoverRating = 0;
|
|
@@ -284,6 +291,15 @@ export class ComponentFeedbackPanelComponent {
|
|
|
284
291
|
GetDisplayRating() {
|
|
285
292
|
return this.HoverRating || this.StarRating;
|
|
286
293
|
}
|
|
294
|
+
/** Returns 'full' | 'half' | 'empty' for the given 1-based star index */
|
|
295
|
+
GetStarState(index) {
|
|
296
|
+
const rating = this.GetDisplayRating();
|
|
297
|
+
if (index <= rating)
|
|
298
|
+
return 'full';
|
|
299
|
+
if (index - 0.5 <= rating)
|
|
300
|
+
return 'half';
|
|
301
|
+
return 'empty';
|
|
302
|
+
}
|
|
287
303
|
IsStarFilled(index) {
|
|
288
304
|
return index <= this.GetDisplayRating();
|
|
289
305
|
}
|
|
@@ -520,7 +536,7 @@ export class ComponentFeedbackPanelComponent {
|
|
|
520
536
|
this.ClearHighlight();
|
|
521
537
|
}
|
|
522
538
|
static ɵfac = function ComponentFeedbackPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ComponentFeedbackPanelComponent)(); };
|
|
523
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ComponentFeedbackPanelComponent, selectors: [["mj-component-feedback-panel"]], inputs: { ComponentSpec: "ComponentSpec", ReactContainerElement: "ReactContainerElement", ConversationId: "ConversationId", ConversationDetailId: "ConversationDetailId" }, outputs: { Closed: "Closed" }, 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-
|
|
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" }, 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) {
|
|
524
540
|
i0.ɵɵelementStart(0, "div", 0);
|
|
525
541
|
i0.ɵɵlistener("click", function ComponentFeedbackPanelComponent_Template_div_click_0_listener() { return ctx.ClosePanel(); });
|
|
526
542
|
i0.ɵɵelementStart(1, "div", 1);
|
|
@@ -528,7 +544,7 @@ export class ComponentFeedbackPanelComponent {
|
|
|
528
544
|
i0.ɵɵelementStart(2, "div", 2)(3, "div", 3);
|
|
529
545
|
i0.ɵɵelement(4, "i", 4);
|
|
530
546
|
i0.ɵɵelementStart(5, "span");
|
|
531
|
-
i0.ɵɵtext(6, "
|
|
547
|
+
i0.ɵɵtext(6, "Inspect & Rate");
|
|
532
548
|
i0.ɵɵelementEnd()();
|
|
533
549
|
i0.ɵɵelementStart(7, "button", 5);
|
|
534
550
|
i0.ɵɵlistener("click", function ComponentFeedbackPanelComponent_Template_button_click_7_listener() { return ctx.ClosePanel(); });
|
|
@@ -542,18 +558,18 @@ export class ComponentFeedbackPanelComponent {
|
|
|
542
558
|
i0.ɵɵconditionalCreate(15, ComponentFeedbackPanelComponent_Conditional_15_Template, 3, 0, "div", 11)(16, ComponentFeedbackPanelComponent_Conditional_16_Template, 4, 0, "div", 12);
|
|
543
559
|
i0.ɵɵelementEnd();
|
|
544
560
|
i0.ɵɵelementStart(17, "div", 13);
|
|
545
|
-
i0.ɵɵconditionalCreate(18, ComponentFeedbackPanelComponent_Conditional_18_Template,
|
|
561
|
+
i0.ɵɵconditionalCreate(18, ComponentFeedbackPanelComponent_Conditional_18_Template, 27, 10, "div", 14)(19, ComponentFeedbackPanelComponent_Conditional_19_Template, 4, 0, "div", 15);
|
|
546
562
|
i0.ɵɵelementEnd()()()();
|
|
547
563
|
} if (rf & 2) {
|
|
548
564
|
i0.ɵɵadvance(15);
|
|
549
565
|
i0.ɵɵconditional(ctx.ComponentSpec ? 15 : 16);
|
|
550
566
|
i0.ɵɵadvance(3);
|
|
551
567
|
i0.ɵɵconditional(ctx.SelectedSpec ? 18 : 19);
|
|
552
|
-
} }, dependencies: [CommonModule, FormsModule, i1.DefaultValueAccessor, i1.NgControlStatus, i1.MaxLengthValidator, i1.NgModel], 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, rgba(0, 0, 0, 0.4));\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: 450px;\n height: 100%;\n background-color: var(--mj-bg-surface, #ffffff);\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, #e0e0e0);\n background-color: var(--mj-bg-surface-card, #f8f9fa);\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, #333);\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary, #3B82F6);\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, #555);\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, #e0e0e0);\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, #555);\n margin-bottom: 12px;\n padding-bottom: 8px;\n border-bottom: 2px solid var(--mj-brand-primary, #3B82F6);\n}\n\n.section-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary, #3B82F6);\n}\n\n\n\n.tree-section[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface-card, #f8f9fa);\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, #3B82F6) 10%, var(--mj-bg-surface, #ffffff));\n}\n\n.tree-item.selected[_ngcontent-%COMP%] {\n background-color: var(--mj-brand-primary, #3B82F6);\n color: var(--mj-text-inverse, #ffffff);\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, #ffffff);\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, #ffffff);\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, #666);\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, #3B82F6);\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, #3B82F6) 10%, var(--mj-bg-surface, #ffffff));\n color: var(--mj-brand-primary, #3B82F6);\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary, #3B82F6) 30%, var(--mj-bg-surface, #ffffff));\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, #999);\n font-size: 14px;\n}\n\n\n\n.feedback-section[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface, #ffffff);\n border-radius: 8px;\n border: 1px solid var(--mj-border-default, #e0e0e0);\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, #666);\n line-height: 1.5;\n margin: 0;\n padding: 12px;\n background-color: var(--mj-bg-surface-card, #f8f9fa);\n border-radius: 6px;\n border-left: 3px solid var(--mj-brand-primary, #3B82F6);\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, #333);\n}\n\n.star-rating[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.star[_ngcontent-%COMP%] {\n font-size: 32px;\n color: #ffd700;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.star[_ngcontent-%COMP%]:hover {\n transform: scale(1.2);\n filter: brightness(1.1);\n}\n\n.star.fa-regular[_ngcontent-%COMP%] {\n color: var(--mj-border-default, #d0d0d0);\n}\n\n.rating-text[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary, #666);\n margin-top: 4px;\n}\n\n.rating-text.placeholder[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled, #999);\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, #333);\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, #999);\n}\n\n.comment-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 12px;\n border: 1px solid var(--mj-border-default, #d0d0d0);\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, #ffffff);\n color: var(--mj-text-primary, #333);\n box-sizing: border-box;\n}\n\n.comment-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary, #3B82F6);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary, #3B82F6) 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, #999);\n background-color: var(--mj-bg-surface, #ffffff);\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, #3B82F6);\n color: var(--mj-text-inverse, #ffffff);\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, #2563EB);\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, #d4edda);\n color: var(--mj-status-success-text, #155724);\n border: 1px solid var(--mj-status-success-border, #c3e6cb);\n}\n\n.success-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success, #28a745);\n}\n\n.error-message[_ngcontent-%COMP%] {\n background-color: var(--mj-status-error-bg, #f8d7da);\n color: var(--mj-status-error-text, #721c24);\n border: 1px solid var(--mj-status-error-border, #f5c6cb);\n}\n\n.error-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error, #dc3545);\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, #999);\n text-align: center;\n}\n\n.no-selection-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n color: var(--mj-border-default, #d0d0d0);\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, #f1f1f1);\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background-color: var(--mj-border-strong, #c0c0c0);\n border-radius: 4px;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background-color: var(--mj-text-disabled, #a0a0a0);\n}"] });
|
|
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, rgba(0, 0, 0, 0.4));\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, #ffffff);\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, #e0e0e0);\n background-color: var(--mj-bg-surface-card, #f8f9fa);\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, #333);\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary, #3B82F6);\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, #555);\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, #e0e0e0);\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, #555);\n margin-bottom: 12px;\n padding-bottom: 8px;\n border-bottom: 2px solid var(--mj-brand-primary, #3B82F6);\n}\n\n.section-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary, #3B82F6);\n}\n\n\n\n.tree-section[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface-card, #f8f9fa);\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, #3B82F6) 10%, var(--mj-bg-surface, #ffffff));\n}\n\n.tree-item.selected[_ngcontent-%COMP%] {\n background-color: var(--mj-brand-primary, #3B82F6);\n color: var(--mj-text-inverse, #ffffff);\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, #ffffff);\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, #ffffff);\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, #666);\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, #3B82F6);\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, #3B82F6) 10%, var(--mj-bg-surface, #ffffff));\n color: var(--mj-brand-primary, #3B82F6);\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary, #3B82F6) 30%, var(--mj-bg-surface, #ffffff));\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, #999);\n font-size: 14px;\n}\n\n\n\n.feedback-section[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface, #ffffff);\n border-radius: 8px;\n border: 1px solid var(--mj-border-default, #e0e0e0);\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, #666);\n line-height: 1.5;\n margin: 0;\n padding: 12px;\n background-color: var(--mj-bg-surface-card, #f8f9fa);\n border-radius: 6px;\n border-left: 3px solid var(--mj-brand-primary, #3B82F6);\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, #333);\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 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-default, #d0d0d0);\n}\n\n.rating-text[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary, #666);\n margin-top: 4px;\n}\n\n.rating-text.placeholder[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled, #999);\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, #333);\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, #999);\n}\n\n.comment-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 12px;\n border: 1px solid var(--mj-border-default, #d0d0d0);\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, #ffffff);\n color: var(--mj-text-primary, #333);\n box-sizing: border-box;\n}\n\n.comment-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary, #3B82F6);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary, #3B82F6) 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, #999);\n background-color: var(--mj-bg-surface, #ffffff);\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, #3B82F6);\n color: var(--mj-text-inverse, #ffffff);\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, #2563EB);\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, #d4edda);\n color: var(--mj-status-success-text, #155724);\n border: 1px solid var(--mj-status-success-border, #c3e6cb);\n}\n\n.success-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success, #28a745);\n}\n\n.error-message[_ngcontent-%COMP%] {\n background-color: var(--mj-status-error-bg, #f8d7da);\n color: var(--mj-status-error-text, #721c24);\n border: 1px solid var(--mj-status-error-border, #f5c6cb);\n}\n\n.error-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error, #dc3545);\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, #999);\n text-align: center;\n}\n\n.no-selection-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n color: var(--mj-border-default, #d0d0d0);\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, #f1f1f1);\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background-color: var(--mj-border-strong, #c0c0c0);\n border-radius: 4px;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background-color: var(--mj-text-disabled, #a0a0a0);\n}"] });
|
|
553
569
|
}
|
|
554
570
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ComponentFeedbackPanelComponent, [{
|
|
555
571
|
type: Component,
|
|
556
|
-
args: [{ selector: 'mj-component-feedback-panel', standalone: true, imports: [CommonModule, FormsModule], 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-comment-dots\"></i>\n <span>Component Feedback</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 <p class=\"component-description\">{{ SelectedSpec.description }}</p>\n }\n\n <!-- Star Rating -->\n <div class=\"star-rating-container\">\n <label class=\"rating-label\">Your Rating</label>\n <div class=\"star-rating\">\n @for (star of [1, 2, 3, 4, 5]; track star) {\n <i\n class=\"star\"\n [class.fa-solid]=\"IsStarFilled(star)\"\n [class.fa-regular]=\"!IsStarFilled(star)\"\n [class.fa-star]=\"true\"\n (click)=\"SetRating(star)\"\n (mouseenter)=\"SetHoverRating(star)\"\n (mouseleave)=\"ClearHoverRating()\">\n </i>\n }\n </div>\n @if (StarRating > 0) {\n <span class=\"rating-text\">{{ StarRating }} out of 5 stars</span>\n } @else {\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, rgba(0, 0, 0, 0.4));\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: 450px;\n height: 100%;\n background-color: var(--mj-bg-surface, #ffffff);\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, #e0e0e0);\n background-color: var(--mj-bg-surface-card, #f8f9fa);\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, #333);\n}\n\n.panel-title i {\n color: var(--mj-brand-primary, #3B82F6);\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, #555);\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, #e0e0e0);\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, #555);\n margin-bottom: 12px;\n padding-bottom: 8px;\n border-bottom: 2px solid var(--mj-brand-primary, #3B82F6);\n}\n\n.section-header i {\n color: var(--mj-brand-primary, #3B82F6);\n}\n\n/* Component Tree */\n.tree-section {\n background-color: var(--mj-bg-surface-card, #f8f9fa);\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, #3B82F6) 10%, var(--mj-bg-surface, #ffffff));\n}\n\n.tree-item.selected {\n background-color: var(--mj-brand-primary, #3B82F6);\n color: var(--mj-text-inverse, #ffffff);\n font-weight: 500;\n}\n\n.tree-item.selected .component-icon,\n.tree-item.selected .tree-toggle {\n color: var(--mj-text-inverse, #ffffff);\n}\n\n.tree-item.selected .component-badge {\n background-color: rgba(255, 255, 255, 0.2);\n color: var(--mj-text-inverse, #ffffff);\n border-color: rgba(255, 255, 255, 0.3);\n}\n\n.tree-toggle {\n font-size: 12px;\n color: var(--mj-text-muted, #666);\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, #3B82F6);\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, #3B82F6) 10%, var(--mj-bg-surface, #ffffff));\n color: var(--mj-brand-primary, #3B82F6);\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary, #3B82F6) 30%, var(--mj-bg-surface, #ffffff));\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, #999);\n font-size: 14px;\n}\n\n/* Feedback Form Section */\n.feedback-section {\n background-color: var(--mj-bg-surface, #ffffff);\n border-radius: 8px;\n border: 1px solid var(--mj-border-default, #e0e0e0);\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, #666);\n line-height: 1.5;\n margin: 0;\n padding: 12px;\n background-color: var(--mj-bg-surface-card, #f8f9fa);\n border-radius: 6px;\n border-left: 3px solid var(--mj-brand-primary, #3B82F6);\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, #333);\n}\n\n.star-rating {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.star {\n font-size: 32px;\n color: #ffd700;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.star:hover {\n transform: scale(1.2);\n filter: brightness(1.1);\n}\n\n.star.fa-regular {\n color: var(--mj-border-default, #d0d0d0);\n}\n\n.rating-text {\n font-size: 13px;\n color: var(--mj-text-secondary, #666);\n margin-top: 4px;\n}\n\n.rating-text.placeholder {\n color: var(--mj-text-disabled, #999);\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, #333);\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, #999);\n}\n\n.comment-input {\n width: 100%;\n padding: 12px;\n border: 1px solid var(--mj-border-default, #d0d0d0);\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, #ffffff);\n color: var(--mj-text-primary, #333);\n box-sizing: border-box;\n}\n\n.comment-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary, #3B82F6);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary, #3B82F6) 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, #999);\n background-color: var(--mj-bg-surface, #ffffff);\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, #3B82F6);\n color: var(--mj-text-inverse, #ffffff);\n transition: background-color 0.2s ease;\n}\n\n.submit-button:hover:not(:disabled) {\n background-color: var(--mj-brand-primary-hover, #2563EB);\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, #d4edda);\n color: var(--mj-status-success-text, #155724);\n border: 1px solid var(--mj-status-success-border, #c3e6cb);\n}\n\n.success-message i {\n color: var(--mj-status-success, #28a745);\n}\n\n.error-message {\n background-color: var(--mj-status-error-bg, #f8d7da);\n color: var(--mj-status-error-text, #721c24);\n border: 1px solid var(--mj-status-error-border, #f5c6cb);\n}\n\n.error-message i {\n color: var(--mj-status-error, #dc3545);\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, #999);\n text-align: center;\n}\n\n.no-selection-message i {\n font-size: 48px;\n color: var(--mj-border-default, #d0d0d0);\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, #f1f1f1);\n}\n\n.panel-content::-webkit-scrollbar-thumb {\n background-color: var(--mj-border-strong, #c0c0c0);\n border-radius: 4px;\n}\n\n.panel-content::-webkit-scrollbar-thumb:hover {\n background-color: var(--mj-text-disabled, #a0a0a0);\n}\n"] }]
|
|
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, rgba(0, 0, 0, 0.4));\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, #ffffff);\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, #e0e0e0);\n background-color: var(--mj-bg-surface-card, #f8f9fa);\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, #333);\n}\n\n.panel-title i {\n color: var(--mj-brand-primary, #3B82F6);\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, #555);\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, #e0e0e0);\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, #555);\n margin-bottom: 12px;\n padding-bottom: 8px;\n border-bottom: 2px solid var(--mj-brand-primary, #3B82F6);\n}\n\n.section-header i {\n color: var(--mj-brand-primary, #3B82F6);\n}\n\n/* Component Tree */\n.tree-section {\n background-color: var(--mj-bg-surface-card, #f8f9fa);\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, #3B82F6) 10%, var(--mj-bg-surface, #ffffff));\n}\n\n.tree-item.selected {\n background-color: var(--mj-brand-primary, #3B82F6);\n color: var(--mj-text-inverse, #ffffff);\n font-weight: 500;\n}\n\n.tree-item.selected .component-icon,\n.tree-item.selected .tree-toggle {\n color: var(--mj-text-inverse, #ffffff);\n}\n\n.tree-item.selected .component-badge {\n background-color: rgba(255, 255, 255, 0.2);\n color: var(--mj-text-inverse, #ffffff);\n border-color: rgba(255, 255, 255, 0.3);\n}\n\n.tree-toggle {\n font-size: 12px;\n color: var(--mj-text-muted, #666);\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, #3B82F6);\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, #3B82F6) 10%, var(--mj-bg-surface, #ffffff));\n color: var(--mj-brand-primary, #3B82F6);\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary, #3B82F6) 30%, var(--mj-bg-surface, #ffffff));\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, #999);\n font-size: 14px;\n}\n\n/* Feedback Form Section */\n.feedback-section {\n background-color: var(--mj-bg-surface, #ffffff);\n border-radius: 8px;\n border: 1px solid var(--mj-border-default, #e0e0e0);\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, #666);\n line-height: 1.5;\n margin: 0;\n padding: 12px;\n background-color: var(--mj-bg-surface-card, #f8f9fa);\n border-radius: 6px;\n border-left: 3px solid var(--mj-brand-primary, #3B82F6);\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, #333);\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 color: #ffd700;\n transition: all 0.2s ease;\n pointer-events: none;\n}\n\n.star.fa-regular {\n color: var(--mj-border-default, #d0d0d0);\n}\n\n.rating-text {\n font-size: 13px;\n color: var(--mj-text-secondary, #666);\n margin-top: 4px;\n}\n\n.rating-text.placeholder {\n color: var(--mj-text-disabled, #999);\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, #333);\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, #999);\n}\n\n.comment-input {\n width: 100%;\n padding: 12px;\n border: 1px solid var(--mj-border-default, #d0d0d0);\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, #ffffff);\n color: var(--mj-text-primary, #333);\n box-sizing: border-box;\n}\n\n.comment-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary, #3B82F6);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary, #3B82F6) 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, #999);\n background-color: var(--mj-bg-surface, #ffffff);\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, #3B82F6);\n color: var(--mj-text-inverse, #ffffff);\n transition: background-color 0.2s ease;\n}\n\n.submit-button:hover:not(:disabled) {\n background-color: var(--mj-brand-primary-hover, #2563EB);\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, #d4edda);\n color: var(--mj-status-success-text, #155724);\n border: 1px solid var(--mj-status-success-border, #c3e6cb);\n}\n\n.success-message i {\n color: var(--mj-status-success, #28a745);\n}\n\n.error-message {\n background-color: var(--mj-status-error-bg, #f8d7da);\n color: var(--mj-status-error-text, #721c24);\n border: 1px solid var(--mj-status-error-border, #f5c6cb);\n}\n\n.error-message i {\n color: var(--mj-status-error, #dc3545);\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, #999);\n text-align: center;\n}\n\n.no-selection-message i {\n font-size: 48px;\n color: var(--mj-border-default, #d0d0d0);\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, #f1f1f1);\n}\n\n.panel-content::-webkit-scrollbar-thumb {\n background-color: var(--mj-border-strong, #c0c0c0);\n border-radius: 4px;\n}\n\n.panel-content::-webkit-scrollbar-thumb:hover {\n background-color: var(--mj-text-disabled, #a0a0a0);\n}\n"] }]
|
|
557
573
|
}], null, { ComponentSpec: [{
|
|
558
574
|
type: Input
|
|
559
575
|
}], ReactContainerElement: [{
|
|
@@ -565,5 +581,5 @@ export class ComponentFeedbackPanelComponent {
|
|
|
565
581
|
}], Closed: [{
|
|
566
582
|
type: Output
|
|
567
583
|
}] }); })();
|
|
568
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ComponentFeedbackPanelComponent, { className: "ComponentFeedbackPanelComponent", filePath: "src/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.ts", lineNumber:
|
|
584
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ComponentFeedbackPanelComponent, { className: "ComponentFeedbackPanelComponent", filePath: "src/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.ts", lineNumber: 29 }); })();
|
|
569
585
|
//# sourceMappingURL=component-feedback-panel.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-feedback-panel.component.js","sourceRoot":"","sources":["../../../../../src/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.ts","../../../../../src/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnDestroy, ChangeDetectorRef, inject } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { Metadata } from '@memberjunction/core';\nimport { ComponentSpec } from '@memberjunction/interactive-component-types';\n\n/**\n * Flattened tree item for rendering the component hierarchy\n */\ninterface TreeItem {\n spec: ComponentSpec;\n depth: number;\n hasChildren: boolean;\n}\n\n/**\n * Component feedback panel that displays component hierarchy tree\n * and allows users to select components and provide star ratings with comments.\n * Registry-agnostic: works with any component registry (Skip, MJ Central, etc.)\n */\n@Component({\n selector: 'mj-component-feedback-panel',\n standalone: true,\n imports: [CommonModule, FormsModule],\n templateUrl: './component-feedback-panel.component.html',\n styleUrls: ['./component-feedback-panel.component.css']\n})\nexport class ComponentFeedbackPanelComponent implements OnDestroy {\n @Input() ComponentSpec: ComponentSpec | null = null;\n @Input() ReactContainerElement: HTMLElement | null = null;\n @Input() ConversationId: string | null = null;\n @Input() ConversationDetailId: string | null = null;\n\n @Output() Closed = new EventEmitter<void>();\n\n // Feedback form state\n public SelectedSpec: ComponentSpec | null = null;\n public StarRating = 0;\n public HoverRating = 0;\n public FeedbackComments = '';\n public IsSubmitting = false;\n public SubmitSuccess = false;\n public SubmitError = '';\n\n // Tree state\n public ExpandedNodes = new Set<string>();\n\n // Highlight overlays\n private highlightOverlay: HTMLElement | null = null;\n private hoverOverlay: HTMLElement | null = null;\n private resizeObserver: ResizeObserver | null = null;\n private containerClickHandler: ((e: MouseEvent) => void) | null = null;\n\n private cdr = inject(ChangeDetectorRef);\n\n // --- Tree Methods ---\n\n GetTreeItems(): TreeItem[] {\n if (!this.ComponentSpec) return [];\n if (!this.ExpandedNodes.has(this.ComponentSpec.name)) {\n this.ExpandedNodes.add(this.ComponentSpec.name);\n }\n return this.buildTree(this.ComponentSpec, 0);\n }\n\n private buildTree(spec: ComponentSpec, depth: number): TreeItem[] {\n const items: TreeItem[] = [{\n spec,\n depth,\n hasChildren: !!(spec.dependencies && spec.dependencies.length > 0)\n }];\n if (this.ExpandedNodes.has(spec.name) && spec.dependencies) {\n for (const child of spec.dependencies) {\n items.push(...this.buildTree(child, depth + 1));\n }\n }\n return items;\n }\n\n ToggleNode(spec: ComponentSpec, event: MouseEvent): void {\n event.stopPropagation();\n if (this.ExpandedNodes.has(spec.name)) {\n this.ExpandedNodes.delete(spec.name);\n } else {\n this.ExpandedNodes.add(spec.name);\n }\n }\n\n IsNodeExpanded(spec: ComponentSpec): boolean {\n return this.ExpandedNodes.has(spec.name);\n }\n\n SelectComponent(spec: ComponentSpec): void {\n this.SelectedSpec = spec;\n this.ResetForm();\n this.HighlightComponent(spec.name);\n }\n\n IsSelected(spec: ComponentSpec): boolean {\n return this.SelectedSpec?.name === spec.name;\n }\n\n GetIndentation(depth: number): string {\n return `${depth * 20}px`;\n }\n\n // --- Star Rating ---\n\n SetRating(stars: number): void {\n this.StarRating = stars;\n }\n\n SetHoverRating(stars: number): void {\n this.HoverRating = stars;\n }\n\n ClearHoverRating(): void {\n this.HoverRating = 0;\n }\n\n GetDisplayRating(): number {\n return this.HoverRating || this.StarRating;\n }\n\n IsStarFilled(index: number): boolean {\n return index <= this.GetDisplayRating();\n }\n\n // --- Form ---\n\n ResetForm(): void {\n this.StarRating = 0;\n this.HoverRating = 0;\n this.FeedbackComments = '';\n this.SubmitSuccess = false;\n this.SubmitError = '';\n }\n\n CanSubmit(): boolean {\n return !!this.SelectedSpec && this.StarRating > 0 && !this.IsSubmitting;\n }\n\n async SubmitFeedback(): Promise<void> {\n if (!this.CanSubmit() || !this.SelectedSpec) return;\n\n this.IsSubmitting = true;\n this.SubmitError = '';\n this.SubmitSuccess = false;\n this.cdr.detectChanges();\n\n try {\n // Dynamic import to avoid adding graphql-dataprovider as a package dependency.\n // At runtime in the browser, Metadata.Provider is always a GraphQLDataProvider.\n const { GraphQLComponentRegistryClient } = await import('@memberjunction/graphql-dataprovider');\n const provider = Metadata.Provider;\n const client = new GraphQLComponentRegistryClient(provider as ConstructorParameters<typeof GraphQLComponentRegistryClient>[0]);\n\n const response = await client.SendComponentFeedback({\n componentName: this.SelectedSpec.name,\n componentNamespace: this.SelectedSpec.namespace || this.SelectedSpec.registry || '',\n componentVersion: this.SelectedSpec.version,\n registryName: this.SelectedSpec.registry,\n rating: this.StarRating * 20, // 0-5 -> 0-100\n comments: this.FeedbackComments.trim() || undefined,\n conversationID: this.ConversationId || undefined,\n conversationDetailID: this.ConversationDetailId || undefined\n });\n\n if (response.success) {\n this.SubmitSuccess = true;\n setTimeout(() => {\n this.ResetForm();\n this.cdr.detectChanges();\n }, 2000);\n } else {\n this.SubmitError = response.error || 'Failed to submit feedback.';\n }\n } catch (error) {\n this.SubmitError = 'Failed to submit feedback. Please try again.';\n console.error('Error submitting component feedback:', error);\n } finally {\n this.IsSubmitting = false;\n this.cdr.detectChanges();\n }\n }\n\n // --- Hover Highlight (light preview on tree hover) ---\n\n HoverTreeItem(spec: ComponentSpec): void {\n if (!this.ReactContainerElement || this.IsSelected(spec)) return;\n this.showHoverOverlay(spec.name);\n }\n\n ClearTreeItemHover(): void {\n this.removeHoverOverlay();\n }\n\n private showHoverOverlay(componentName: string): void {\n if (!this.ReactContainerElement) return;\n\n const targetEl = this.ReactContainerElement.querySelector(\n `[data-mj-component=\"${componentName}\"]`\n );\n if (!targetEl) {\n this.removeHoverOverlay();\n return;\n }\n\n this.ensureContainerPositioned();\n\n if (!this.hoverOverlay) {\n this.hoverOverlay = document.createElement('div');\n this.ReactContainerElement.appendChild(this.hoverOverlay);\n }\n\n this.positionOverlay(this.hoverOverlay, targetEl);\n this.hoverOverlay.style.border = '2px dashed var(--mj-brand-primary, #3B82F6)';\n this.hoverOverlay.style.background = 'color-mix(in srgb, var(--mj-brand-primary, #3B82F6) 5%, transparent)';\n }\n\n private removeHoverOverlay(): void {\n if (this.hoverOverlay?.parentNode) {\n this.hoverOverlay.parentNode.removeChild(this.hoverOverlay);\n }\n this.hoverOverlay = null;\n }\n\n // --- Region Highlighting (solid selection) ---\n\n private HighlightComponent(componentName: string): void {\n if (!this.ReactContainerElement) {\n this.ClearHighlight();\n return;\n }\n\n const targetEl = this.ReactContainerElement.querySelector(\n `[data-mj-component=\"${componentName}\"]`\n );\n if (!targetEl) {\n this.ClearHighlight();\n return;\n }\n\n this.ensureContainerPositioned();\n\n if (!this.highlightOverlay) {\n this.highlightOverlay = document.createElement('div');\n this.ReactContainerElement.appendChild(this.highlightOverlay);\n }\n\n this.positionOverlay(this.highlightOverlay, targetEl);\n this.highlightOverlay.style.border = '2px solid var(--mj-brand-primary, #3B82F6)';\n this.highlightOverlay.style.background = 'color-mix(in srgb, var(--mj-brand-primary, #3B82F6) 10%, transparent)';\n\n // Watch for resize/layout changes\n this.resizeObserver?.disconnect();\n this.resizeObserver = new ResizeObserver(() => {\n if (this.highlightOverlay) {\n this.positionOverlay(this.highlightOverlay, targetEl);\n }\n });\n this.resizeObserver.observe(targetEl);\n this.resizeObserver.observe(this.ReactContainerElement);\n\n // Set up bidirectional click selection on container\n this.installContainerClickListener();\n }\n\n private ensureContainerPositioned(): void {\n if (!this.ReactContainerElement) return;\n const containerStyle = getComputedStyle(this.ReactContainerElement);\n if (containerStyle.position === 'static') {\n this.ReactContainerElement.style.position = 'relative';\n }\n }\n\n /**\n * Gets the effective bounding rect for a component marker element.\n * display:contents elements return zero-size rects, so we compute\n * the union bounding box of their children instead.\n */\n private getEffectiveRect(el: Element): DOMRect {\n const rect = el.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) return rect;\n\n // display:contents wrapper — union the bounding rects of all children\n const children = el.children;\n if (children.length === 0) return rect;\n\n let top = Infinity, left = Infinity, bottom = -Infinity, right = -Infinity;\n for (let i = 0; i < children.length; i++) {\n const childRect = children[i].getBoundingClientRect();\n if (childRect.width === 0 && childRect.height === 0) continue;\n top = Math.min(top, childRect.top);\n left = Math.min(left, childRect.left);\n bottom = Math.max(bottom, childRect.bottom);\n right = Math.max(right, childRect.right);\n }\n\n if (top === Infinity) return rect; // no visible children\n return new DOMRect(left, top, right - left, bottom - top);\n }\n\n private positionOverlay(overlay: HTMLElement, targetEl: Element): void {\n if (!this.ReactContainerElement) return;\n\n const targetRect = this.getEffectiveRect(targetEl);\n const containerRect = this.ReactContainerElement.getBoundingClientRect();\n\n overlay.style.position = 'absolute';\n overlay.style.top = `${targetRect.top - containerRect.top + this.ReactContainerElement.scrollTop}px`;\n overlay.style.left = `${targetRect.left - containerRect.left + this.ReactContainerElement.scrollLeft}px`;\n overlay.style.width = `${targetRect.width}px`;\n overlay.style.height = `${targetRect.height}px`;\n overlay.style.pointerEvents = 'none';\n overlay.style.zIndex = '10';\n overlay.style.borderRadius = '4px';\n overlay.style.transition = 'all 0.2s ease';\n }\n\n // --- Bidirectional click: clicking a component region selects it in the tree ---\n\n private installContainerClickListener(): void {\n if (this.containerClickHandler || !this.ReactContainerElement) return;\n\n this.containerClickHandler = (e: MouseEvent) => {\n const target = e.target as HTMLElement | null;\n if (!target) return;\n\n // Walk up from click target to find nearest [data-mj-component]\n const componentEl = target.closest('[data-mj-component]');\n if (!componentEl) return;\n\n const componentName = componentEl.getAttribute('data-mj-component');\n if (!componentName) return;\n\n // Find matching spec in the tree\n const matchingSpec = this.findSpecByName(componentName);\n if (matchingSpec && matchingSpec.name !== this.SelectedSpec?.name) {\n this.SelectComponent(matchingSpec);\n this.cdr.detectChanges();\n }\n };\n\n // Use capture phase so we observe the click without interfering with component handlers\n this.ReactContainerElement.addEventListener('click', this.containerClickHandler, true);\n }\n\n private removeContainerClickListener(): void {\n if (this.containerClickHandler && this.ReactContainerElement) {\n this.ReactContainerElement.removeEventListener('click', this.containerClickHandler, true);\n }\n this.containerClickHandler = null;\n }\n\n private findSpecByName(name: string): ComponentSpec | null {\n if (!this.ComponentSpec) return null;\n return this.walkSpecTree(this.ComponentSpec, name);\n }\n\n private walkSpecTree(spec: ComponentSpec, name: string): ComponentSpec | null {\n if (spec.name === name) return spec;\n if (spec.dependencies) {\n for (const child of spec.dependencies) {\n const found = this.walkSpecTree(child, name);\n if (found) return found;\n }\n }\n return null;\n }\n\n private ClearHighlight(): void {\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n if (this.highlightOverlay?.parentNode) {\n this.highlightOverlay.parentNode.removeChild(this.highlightOverlay);\n }\n this.highlightOverlay = null;\n this.removeHoverOverlay();\n this.removeContainerClickListener();\n }\n\n ClosePanel(): void {\n this.ClearHighlight();\n this.Closed.emit();\n }\n\n ngOnDestroy(): void {\n this.ClearHighlight();\n }\n}\n","<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-comment-dots\"></i>\n <span>Component Feedback</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 <p class=\"component-description\">{{ SelectedSpec.description }}</p>\n }\n\n <!-- Star Rating -->\n <div class=\"star-rating-container\">\n <label class=\"rating-label\">Your Rating</label>\n <div class=\"star-rating\">\n @for (star of [1, 2, 3, 4, 5]; track star) {\n <i\n class=\"star\"\n [class.fa-solid]=\"IsStarFilled(star)\"\n [class.fa-regular]=\"!IsStarFilled(star)\"\n [class.fa-star]=\"true\"\n (click)=\"SetRating(star)\"\n (mouseenter)=\"SetHoverRating(star)\"\n (mouseleave)=\"ClearHoverRating()\">\n </i>\n }\n </div>\n @if (StarRating > 0) {\n <span class=\"rating-text\">{{ StarRating }} out of 5 stars</span>\n } @else {\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"]}
|
|
1
|
+
{"version":3,"file":"component-feedback-panel.component.js","sourceRoot":"","sources":["../../../../../src/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.ts","../../../../../src/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnDestroy, ChangeDetectorRef, inject } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { Metadata } from '@memberjunction/core';\nimport { ComponentSpec } from '@memberjunction/interactive-component-types';\nimport { MarkdownModule } from '@memberjunction/ng-markdown';\n\n/**\n * Flattened tree item for rendering the component hierarchy\n */\ninterface TreeItem {\n spec: ComponentSpec;\n depth: number;\n hasChildren: boolean;\n}\n\n/**\n * Component feedback panel that displays component hierarchy tree\n * and allows users to select components and provide star ratings with comments.\n * Registry-agnostic: works with any component registry (Skip, MJ Central, etc.)\n */\n@Component({\n selector: 'mj-component-feedback-panel',\n standalone: true,\n imports: [CommonModule, FormsModule, MarkdownModule],\n templateUrl: './component-feedback-panel.component.html',\n styleUrls: ['./component-feedback-panel.component.css']\n})\nexport class ComponentFeedbackPanelComponent implements OnDestroy {\n @Input() ComponentSpec: ComponentSpec | null = null;\n @Input() ReactContainerElement: HTMLElement | null = null;\n @Input() ConversationId: string | null = null;\n @Input() ConversationDetailId: string | null = null;\n\n @Output() Closed = new EventEmitter<void>();\n\n // Feedback form state\n public SelectedSpec: ComponentSpec | null = null;\n public StarRating = 0;\n public HoverRating = 0;\n public FeedbackComments = '';\n public IsSubmitting = false;\n public SubmitSuccess = false;\n public SubmitError = '';\n\n // Tree state\n public ExpandedNodes = new Set<string>();\n\n // Highlight overlays\n private highlightOverlay: HTMLElement | null = null;\n private hoverOverlay: HTMLElement | null = null;\n private resizeObserver: ResizeObserver | null = null;\n private containerClickHandler: ((e: MouseEvent) => void) | null = null;\n\n private cdr = inject(ChangeDetectorRef);\n\n // --- Tree Methods ---\n\n GetTreeItems(): TreeItem[] {\n if (!this.ComponentSpec) return [];\n if (!this.ExpandedNodes.has(this.ComponentSpec.name)) {\n this.ExpandedNodes.add(this.ComponentSpec.name);\n }\n return this.buildTree(this.ComponentSpec, 0);\n }\n\n private buildTree(spec: ComponentSpec, depth: number): TreeItem[] {\n const items: TreeItem[] = [{\n spec,\n depth,\n hasChildren: !!(spec.dependencies && spec.dependencies.length > 0)\n }];\n if (this.ExpandedNodes.has(spec.name) && spec.dependencies) {\n for (const child of spec.dependencies) {\n items.push(...this.buildTree(child, depth + 1));\n }\n }\n return items;\n }\n\n ToggleNode(spec: ComponentSpec, event: MouseEvent): void {\n event.stopPropagation();\n if (this.ExpandedNodes.has(spec.name)) {\n this.ExpandedNodes.delete(spec.name);\n } else {\n this.ExpandedNodes.add(spec.name);\n }\n }\n\n IsNodeExpanded(spec: ComponentSpec): boolean {\n return this.ExpandedNodes.has(spec.name);\n }\n\n SelectComponent(spec: ComponentSpec): void {\n this.SelectedSpec = spec;\n this.ResetForm();\n this.HighlightComponent(spec.name);\n }\n\n IsSelected(spec: ComponentSpec): boolean {\n return this.SelectedSpec?.name === spec.name;\n }\n\n GetIndentation(depth: number): string {\n return `${depth * 20}px`;\n }\n\n // --- Star Rating (supports half-star increments) ---\n\n SetRating(value: number): void {\n this.StarRating = value;\n }\n\n SetHoverRating(value: number): void {\n this.HoverRating = value;\n }\n\n ClearHoverRating(): void {\n this.HoverRating = 0;\n }\n\n GetDisplayRating(): number {\n return this.HoverRating || this.StarRating;\n }\n\n /** Returns 'full' | 'half' | 'empty' for the given 1-based star index */\n GetStarState(index: number): 'full' | 'half' | 'empty' {\n const rating = this.GetDisplayRating();\n if (index <= rating) return 'full';\n if (index - 0.5 <= rating) return 'half';\n return 'empty';\n }\n\n IsStarFilled(index: number): boolean {\n return index <= this.GetDisplayRating();\n }\n\n // --- Form ---\n\n ResetForm(): void {\n this.StarRating = 0;\n this.HoverRating = 0;\n this.FeedbackComments = '';\n this.SubmitSuccess = false;\n this.SubmitError = '';\n }\n\n CanSubmit(): boolean {\n return !!this.SelectedSpec && this.StarRating > 0 && !this.IsSubmitting;\n }\n\n async SubmitFeedback(): Promise<void> {\n if (!this.CanSubmit() || !this.SelectedSpec) return;\n\n this.IsSubmitting = true;\n this.SubmitError = '';\n this.SubmitSuccess = false;\n this.cdr.detectChanges();\n\n try {\n // Dynamic import to avoid adding graphql-dataprovider as a package dependency.\n // At runtime in the browser, Metadata.Provider is always a GraphQLDataProvider.\n const { GraphQLComponentRegistryClient } = await import('@memberjunction/graphql-dataprovider');\n const provider = Metadata.Provider;\n const client = new GraphQLComponentRegistryClient(provider as ConstructorParameters<typeof GraphQLComponentRegistryClient>[0]);\n\n const response = await client.SendComponentFeedback({\n componentName: this.SelectedSpec.name,\n componentNamespace: this.SelectedSpec.namespace || this.SelectedSpec.registry || '',\n componentVersion: this.SelectedSpec.version,\n registryName: this.SelectedSpec.registry,\n rating: this.StarRating * 20, // 0-5 -> 0-100\n comments: this.FeedbackComments.trim() || undefined,\n conversationID: this.ConversationId || undefined,\n conversationDetailID: this.ConversationDetailId || undefined\n });\n\n if (response.success) {\n this.SubmitSuccess = true;\n setTimeout(() => {\n this.ResetForm();\n this.cdr.detectChanges();\n }, 2000);\n } else {\n this.SubmitError = response.error || 'Failed to submit feedback.';\n }\n } catch (error) {\n this.SubmitError = 'Failed to submit feedback. Please try again.';\n console.error('Error submitting component feedback:', error);\n } finally {\n this.IsSubmitting = false;\n this.cdr.detectChanges();\n }\n }\n\n // --- Hover Highlight (light preview on tree hover) ---\n\n HoverTreeItem(spec: ComponentSpec): void {\n if (!this.ReactContainerElement || this.IsSelected(spec)) return;\n this.showHoverOverlay(spec.name);\n }\n\n ClearTreeItemHover(): void {\n this.removeHoverOverlay();\n }\n\n private showHoverOverlay(componentName: string): void {\n if (!this.ReactContainerElement) return;\n\n const targetEl = this.ReactContainerElement.querySelector(\n `[data-mj-component=\"${componentName}\"]`\n );\n if (!targetEl) {\n this.removeHoverOverlay();\n return;\n }\n\n this.ensureContainerPositioned();\n\n if (!this.hoverOverlay) {\n this.hoverOverlay = document.createElement('div');\n this.ReactContainerElement.appendChild(this.hoverOverlay);\n }\n\n this.positionOverlay(this.hoverOverlay, targetEl);\n this.hoverOverlay.style.border = '2px dashed var(--mj-brand-primary, #3B82F6)';\n this.hoverOverlay.style.background = 'color-mix(in srgb, var(--mj-brand-primary, #3B82F6) 5%, transparent)';\n }\n\n private removeHoverOverlay(): void {\n if (this.hoverOverlay?.parentNode) {\n this.hoverOverlay.parentNode.removeChild(this.hoverOverlay);\n }\n this.hoverOverlay = null;\n }\n\n // --- Region Highlighting (solid selection) ---\n\n private HighlightComponent(componentName: string): void {\n if (!this.ReactContainerElement) {\n this.ClearHighlight();\n return;\n }\n\n const targetEl = this.ReactContainerElement.querySelector(\n `[data-mj-component=\"${componentName}\"]`\n );\n if (!targetEl) {\n this.ClearHighlight();\n return;\n }\n\n this.ensureContainerPositioned();\n\n if (!this.highlightOverlay) {\n this.highlightOverlay = document.createElement('div');\n this.ReactContainerElement.appendChild(this.highlightOverlay);\n }\n\n this.positionOverlay(this.highlightOverlay, targetEl);\n this.highlightOverlay.style.border = '2px solid var(--mj-brand-primary, #3B82F6)';\n this.highlightOverlay.style.background = 'color-mix(in srgb, var(--mj-brand-primary, #3B82F6) 10%, transparent)';\n\n // Watch for resize/layout changes\n this.resizeObserver?.disconnect();\n this.resizeObserver = new ResizeObserver(() => {\n if (this.highlightOverlay) {\n this.positionOverlay(this.highlightOverlay, targetEl);\n }\n });\n this.resizeObserver.observe(targetEl);\n this.resizeObserver.observe(this.ReactContainerElement);\n\n // Set up bidirectional click selection on container\n this.installContainerClickListener();\n }\n\n private ensureContainerPositioned(): void {\n if (!this.ReactContainerElement) return;\n const containerStyle = getComputedStyle(this.ReactContainerElement);\n if (containerStyle.position === 'static') {\n this.ReactContainerElement.style.position = 'relative';\n }\n }\n\n /**\n * Gets the effective bounding rect for a component marker element.\n * display:contents elements return zero-size rects, so we compute\n * the union bounding box of their children instead.\n */\n private getEffectiveRect(el: Element): DOMRect {\n const rect = el.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) return rect;\n\n // display:contents wrapper — union the bounding rects of all children\n const children = el.children;\n if (children.length === 0) return rect;\n\n let top = Infinity, left = Infinity, bottom = -Infinity, right = -Infinity;\n for (let i = 0; i < children.length; i++) {\n const childRect = children[i].getBoundingClientRect();\n if (childRect.width === 0 && childRect.height === 0) continue;\n top = Math.min(top, childRect.top);\n left = Math.min(left, childRect.left);\n bottom = Math.max(bottom, childRect.bottom);\n right = Math.max(right, childRect.right);\n }\n\n if (top === Infinity) return rect; // no visible children\n return new DOMRect(left, top, right - left, bottom - top);\n }\n\n private positionOverlay(overlay: HTMLElement, targetEl: Element): void {\n if (!this.ReactContainerElement) return;\n\n const targetRect = this.getEffectiveRect(targetEl);\n const containerRect = this.ReactContainerElement.getBoundingClientRect();\n\n overlay.style.position = 'absolute';\n overlay.style.top = `${targetRect.top - containerRect.top + this.ReactContainerElement.scrollTop}px`;\n overlay.style.left = `${targetRect.left - containerRect.left + this.ReactContainerElement.scrollLeft}px`;\n overlay.style.width = `${targetRect.width}px`;\n overlay.style.height = `${targetRect.height}px`;\n overlay.style.pointerEvents = 'none';\n overlay.style.zIndex = '10';\n overlay.style.borderRadius = '4px';\n overlay.style.transition = 'all 0.2s ease';\n }\n\n // --- Bidirectional click: clicking a component region selects it in the tree ---\n\n private installContainerClickListener(): void {\n if (this.containerClickHandler || !this.ReactContainerElement) return;\n\n this.containerClickHandler = (e: MouseEvent) => {\n const target = e.target as HTMLElement | null;\n if (!target) return;\n\n // Walk up from click target to find nearest [data-mj-component]\n const componentEl = target.closest('[data-mj-component]');\n if (!componentEl) return;\n\n const componentName = componentEl.getAttribute('data-mj-component');\n if (!componentName) return;\n\n // Find matching spec in the tree\n const matchingSpec = this.findSpecByName(componentName);\n if (matchingSpec && matchingSpec.name !== this.SelectedSpec?.name) {\n this.SelectComponent(matchingSpec);\n this.cdr.detectChanges();\n }\n };\n\n // Use capture phase so we observe the click without interfering with component handlers\n this.ReactContainerElement.addEventListener('click', this.containerClickHandler, true);\n }\n\n private removeContainerClickListener(): void {\n if (this.containerClickHandler && this.ReactContainerElement) {\n this.ReactContainerElement.removeEventListener('click', this.containerClickHandler, true);\n }\n this.containerClickHandler = null;\n }\n\n private findSpecByName(name: string): ComponentSpec | null {\n if (!this.ComponentSpec) return null;\n return this.walkSpecTree(this.ComponentSpec, name);\n }\n\n private walkSpecTree(spec: ComponentSpec, name: string): ComponentSpec | null {\n if (spec.name === name) return spec;\n if (spec.dependencies) {\n for (const child of spec.dependencies) {\n const found = this.walkSpecTree(child, name);\n if (found) return found;\n }\n }\n return null;\n }\n\n private ClearHighlight(): void {\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n if (this.highlightOverlay?.parentNode) {\n this.highlightOverlay.parentNode.removeChild(this.highlightOverlay);\n }\n this.highlightOverlay = null;\n this.removeHoverOverlay();\n this.removeContainerClickListener();\n }\n\n ClosePanel(): void {\n this.ClearHighlight();\n this.Closed.emit();\n }\n\n ngOnDestroy(): void {\n this.ClearHighlight();\n }\n}\n","<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"]}
|