@principal-ade/code-quality-panels 0.1.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.
@@ -0,0 +1,955 @@
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
+ import React2, { forwardRef, createElement, createContext, useState, useEffect, useContext } from "react";
3
+ /**
4
+ * @license lucide-react v0.552.0 - ISC
5
+ *
6
+ * This source code is licensed under the ISC license.
7
+ * See the LICENSE file in the root directory of this source tree.
8
+ */
9
+ const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
10
+ const toCamelCase = (string) => string.replace(
11
+ /^([A-Z])|[\s-_]+(\w)/g,
12
+ (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()
13
+ );
14
+ const toPascalCase = (string) => {
15
+ const camelCase = toCamelCase(string);
16
+ return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
17
+ };
18
+ const mergeClasses = (...classes) => classes.filter((className, index, array) => {
19
+ return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
20
+ }).join(" ").trim();
21
+ const hasA11yProp = (props) => {
22
+ for (const prop in props) {
23
+ if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
24
+ return true;
25
+ }
26
+ }
27
+ };
28
+ /**
29
+ * @license lucide-react v0.552.0 - ISC
30
+ *
31
+ * This source code is licensed under the ISC license.
32
+ * See the LICENSE file in the root directory of this source tree.
33
+ */
34
+ var defaultAttributes = {
35
+ xmlns: "http://www.w3.org/2000/svg",
36
+ width: 24,
37
+ height: 24,
38
+ viewBox: "0 0 24 24",
39
+ fill: "none",
40
+ stroke: "currentColor",
41
+ strokeWidth: 2,
42
+ strokeLinecap: "round",
43
+ strokeLinejoin: "round"
44
+ };
45
+ /**
46
+ * @license lucide-react v0.552.0 - ISC
47
+ *
48
+ * This source code is licensed under the ISC license.
49
+ * See the LICENSE file in the root directory of this source tree.
50
+ */
51
+ const Icon = forwardRef(
52
+ ({
53
+ color = "currentColor",
54
+ size = 24,
55
+ strokeWidth = 2,
56
+ absoluteStrokeWidth,
57
+ className = "",
58
+ children,
59
+ iconNode,
60
+ ...rest
61
+ }, ref) => createElement(
62
+ "svg",
63
+ {
64
+ ref,
65
+ ...defaultAttributes,
66
+ width: size,
67
+ height: size,
68
+ stroke: color,
69
+ strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,
70
+ className: mergeClasses("lucide", className),
71
+ ...!children && !hasA11yProp(rest) && { "aria-hidden": "true" },
72
+ ...rest
73
+ },
74
+ [
75
+ ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),
76
+ ...Array.isArray(children) ? children : [children]
77
+ ]
78
+ )
79
+ );
80
+ /**
81
+ * @license lucide-react v0.552.0 - ISC
82
+ *
83
+ * This source code is licensed under the ISC license.
84
+ * See the LICENSE file in the root directory of this source tree.
85
+ */
86
+ const createLucideIcon = (iconName, iconNode) => {
87
+ const Component = forwardRef(
88
+ ({ className, ...props }, ref) => createElement(Icon, {
89
+ ref,
90
+ iconNode,
91
+ className: mergeClasses(
92
+ `lucide-${toKebabCase(toPascalCase(iconName))}`,
93
+ `lucide-${iconName}`,
94
+ className
95
+ ),
96
+ ...props
97
+ })
98
+ );
99
+ Component.displayName = toPascalCase(iconName);
100
+ return Component;
101
+ };
102
+ /**
103
+ * @license lucide-react v0.552.0 - ISC
104
+ *
105
+ * This source code is licensed under the ISC license.
106
+ * See the LICENSE file in the root directory of this source tree.
107
+ */
108
+ const __iconNode = [
109
+ [
110
+ "path",
111
+ {
112
+ d: "M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z",
113
+ key: "yt0hxn"
114
+ }
115
+ ]
116
+ ];
117
+ const Hexagon = createLucideIcon("hexagon", __iconNode);
118
+ var terminalTheme = {
119
+ space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
120
+ fonts: {
121
+ body: '"SF Mono", "Monaco", "Inconsolata", "Fira Code", monospace',
122
+ heading: '"SF Mono", "Monaco", "Inconsolata", "Fira Code", monospace',
123
+ monospace: '"SF Mono", "Monaco", "Inconsolata", "Fira Code", monospace'
124
+ },
125
+ fontSizes: [12, 14, 16, 18, 20, 24, 32, 48, 64, 96],
126
+ fontScale: 1,
127
+ fontWeights: {
128
+ body: 400,
129
+ heading: 500,
130
+ bold: 600,
131
+ light: 300,
132
+ medium: 500,
133
+ semibold: 600
134
+ },
135
+ lineHeights: {
136
+ body: 1.6,
137
+ heading: 1.3,
138
+ tight: 1.4,
139
+ relaxed: 1.8
140
+ },
141
+ breakpoints: ["640px", "768px", "1024px", "1280px"],
142
+ sizes: [16, 32, 64, 128, 256, 512, 768, 1024, 1536],
143
+ radii: [0, 2, 4, 6, 8, 12, 16, 24],
144
+ shadows: [
145
+ "none",
146
+ "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
147
+ "0 2px 4px 0 rgba(0, 0, 0, 0.06)",
148
+ "0 4px 6px 0 rgba(0, 0, 0, 0.07)",
149
+ "0 8px 12px 0 rgba(0, 0, 0, 0.08)",
150
+ "0 16px 24px 0 rgba(0, 0, 0, 0.10)"
151
+ ],
152
+ zIndices: [0, 1, 10, 20, 30, 40, 50],
153
+ colors: {
154
+ text: "#e4e4e4",
155
+ background: "rgba(10, 10, 10, 0.85)",
156
+ primary: "#66b3ff",
157
+ secondary: "#80c4ff",
158
+ accent: "#66ff99",
159
+ highlight: "rgba(102, 179, 255, 0.15)",
160
+ muted: "rgba(26, 26, 26, 0.8)",
161
+ success: "#66ff99",
162
+ warning: "#ffcc66",
163
+ error: "#ff6666",
164
+ info: "#66b3ff",
165
+ border: "rgba(255, 255, 255, 0.1)",
166
+ backgroundSecondary: "rgba(15, 15, 15, 0.9)",
167
+ backgroundTertiary: "rgba(20, 20, 20, 0.9)",
168
+ backgroundLight: "rgba(255, 255, 255, 0.05)",
169
+ backgroundHover: "rgba(102, 179, 255, 0.08)",
170
+ surface: "rgba(15, 15, 15, 0.95)",
171
+ textSecondary: "rgba(255, 255, 255, 0.7)",
172
+ textTertiary: "rgba(255, 255, 255, 0.5)",
173
+ textMuted: "rgba(255, 255, 255, 0.4)",
174
+ highlightBg: "rgba(255, 235, 59, 0.25)",
175
+ highlightBorder: "rgba(255, 235, 59, 0.5)"
176
+ },
177
+ modes: {
178
+ light: {
179
+ text: "#1a1a1a",
180
+ background: "rgba(255, 255, 255, 0.9)",
181
+ primary: "#0066cc",
182
+ secondary: "#0052a3",
183
+ accent: "#00cc88",
184
+ highlight: "rgba(0, 102, 204, 0.08)",
185
+ muted: "rgba(245, 245, 245, 0.8)",
186
+ success: "#00cc88",
187
+ warning: "#ffaa00",
188
+ error: "#ff3333",
189
+ info: "#0066cc",
190
+ border: "rgba(0, 0, 0, 0.1)",
191
+ backgroundSecondary: "rgba(250, 250, 250, 0.9)",
192
+ backgroundTertiary: "rgba(245, 245, 245, 0.9)",
193
+ backgroundLight: "rgba(0, 0, 0, 0.02)",
194
+ backgroundHover: "rgba(0, 102, 204, 0.04)",
195
+ surface: "rgba(255, 255, 255, 0.95)",
196
+ textSecondary: "rgba(0, 0, 0, 0.6)",
197
+ textTertiary: "rgba(0, 0, 0, 0.4)",
198
+ textMuted: "rgba(0, 0, 0, 0.3)",
199
+ highlightBg: "rgba(255, 235, 59, 0.3)",
200
+ highlightBorder: "rgba(255, 235, 59, 0.6)"
201
+ }
202
+ },
203
+ buttons: {
204
+ primary: {
205
+ color: "white",
206
+ bg: "primary",
207
+ borderWidth: 0,
208
+ "&:hover": {
209
+ bg: "secondary"
210
+ }
211
+ },
212
+ secondary: {
213
+ color: "primary",
214
+ bg: "transparent",
215
+ borderWidth: 1,
216
+ borderStyle: "solid",
217
+ borderColor: "primary",
218
+ "&:hover": {
219
+ bg: "highlight"
220
+ }
221
+ },
222
+ ghost: {
223
+ color: "text",
224
+ bg: "transparent",
225
+ "&:hover": {
226
+ bg: "backgroundHover"
227
+ }
228
+ }
229
+ },
230
+ text: {
231
+ heading: {
232
+ fontFamily: "heading",
233
+ fontWeight: "heading",
234
+ lineHeight: "heading"
235
+ },
236
+ body: {
237
+ fontFamily: "body",
238
+ fontWeight: "body",
239
+ lineHeight: "body"
240
+ },
241
+ caption: {
242
+ fontSize: 1,
243
+ color: "textSecondary"
244
+ }
245
+ },
246
+ cards: {
247
+ primary: {
248
+ bg: "surface",
249
+ border: "1px solid",
250
+ borderColor: "border",
251
+ borderRadius: 1
252
+ },
253
+ secondary: {
254
+ bg: "backgroundSecondary",
255
+ border: "1px solid",
256
+ borderColor: "border",
257
+ borderRadius: 1
258
+ }
259
+ }
260
+ };
261
+ function getMode(theme2, mode) {
262
+ if (!mode || !theme2.modes || !theme2.modes[mode]) {
263
+ return theme2.colors;
264
+ }
265
+ return {
266
+ ...theme2.colors,
267
+ ...theme2.modes[mode]
268
+ };
269
+ }
270
+ var ThemeContext;
271
+ var getThemeContext = () => {
272
+ if (typeof window !== "undefined") {
273
+ const globalWindow = window;
274
+ if (!globalWindow.__principlemd_theme_context__) {
275
+ globalWindow.__principlemd_theme_context__ = createContext(void 0);
276
+ }
277
+ return globalWindow.__principlemd_theme_context__;
278
+ } else {
279
+ if (!ThemeContext) {
280
+ ThemeContext = createContext(void 0);
281
+ }
282
+ return ThemeContext;
283
+ }
284
+ };
285
+ var ThemeContextSingleton = getThemeContext();
286
+ var useTheme = () => {
287
+ const context = useContext(ThemeContextSingleton);
288
+ if (!context) {
289
+ throw new Error("useTheme must be used within a ThemeProvider");
290
+ }
291
+ return context;
292
+ };
293
+ var ThemeProvider = ({
294
+ children,
295
+ theme: customTheme = theme,
296
+ initialMode
297
+ }) => {
298
+ const [mode, setMode] = useState(initialMode);
299
+ const activeTheme = React2.useMemo(() => {
300
+ if (!mode || !customTheme.modes || !customTheme.modes[mode]) {
301
+ return customTheme;
302
+ }
303
+ return {
304
+ ...customTheme,
305
+ colors: getMode(customTheme, mode)
306
+ };
307
+ }, [customTheme, mode]);
308
+ useEffect(() => {
309
+ if (!initialMode) {
310
+ const savedMode = localStorage.getItem("principlemd-theme-mode");
311
+ if (savedMode) {
312
+ setMode(savedMode);
313
+ }
314
+ }
315
+ }, [initialMode]);
316
+ useEffect(() => {
317
+ if (mode) {
318
+ localStorage.setItem("principlemd-theme-mode", mode);
319
+ } else {
320
+ localStorage.removeItem("principlemd-theme-mode");
321
+ }
322
+ }, [mode]);
323
+ const value = {
324
+ theme: activeTheme,
325
+ mode,
326
+ setMode
327
+ };
328
+ return /* @__PURE__ */ React2.createElement(ThemeContextSingleton.Provider, {
329
+ value
330
+ }, children);
331
+ };
332
+ var theme = terminalTheme;
333
+ function r(e) {
334
+ var t, f, n = "";
335
+ if ("string" == typeof e || "number" == typeof e) n += e;
336
+ else if ("object" == typeof e) if (Array.isArray(e)) {
337
+ var o = e.length;
338
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
339
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
340
+ return n;
341
+ }
342
+ function clsx() {
343
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
344
+ return n;
345
+ }
346
+ function cn(...inputs) {
347
+ return clsx(inputs);
348
+ }
349
+ function getThemeColors(theme2) {
350
+ return {
351
+ gridColor: theme2.colors.border,
352
+ axisColor: theme2.colors.muted,
353
+ textColor: theme2.colors.text,
354
+ scoreColor: theme2.colors.text,
355
+ tierColors: {
356
+ none: { fill: theme2.colors.muted, stroke: theme2.colors.border, bg: theme2.colors.backgroundLight },
357
+ bronze: { fill: theme2.colors.warning, stroke: theme2.colors.warning, bg: theme2.colors.backgroundLight },
358
+ silver: { fill: theme2.colors.secondary, stroke: theme2.colors.secondary, bg: theme2.colors.backgroundLight },
359
+ gold: { fill: theme2.colors.accent, stroke: theme2.colors.accent, bg: theme2.colors.backgroundLight },
360
+ platinum: { fill: theme2.colors.primary, stroke: theme2.colors.primary, bg: theme2.colors.backgroundLight }
361
+ },
362
+ metricColors: {
363
+ types: theme2.colors.warning,
364
+ documentation: theme2.colors.info,
365
+ tests: theme2.colors.success,
366
+ deadCode: theme2.colors.error,
367
+ formatting: theme2.colors.accent,
368
+ linting: theme2.colors.primary
369
+ },
370
+ qualityIndicators: {
371
+ good: theme2.colors.success,
372
+ medium: theme2.colors.warning,
373
+ poor: theme2.colors.error
374
+ }
375
+ };
376
+ }
377
+ const getMetricConfig = (themeColors) => [
378
+ { key: "types", label: "Types", color: themeColors.metricColors.types, angle: -120 },
379
+ { key: "documentation", label: "Docs", color: themeColors.metricColors.documentation, angle: -60 },
380
+ { key: "tests", label: "Tests", color: themeColors.metricColors.tests, angle: 0 },
381
+ { key: "deadCode", label: "Dead Code", color: themeColors.metricColors.deadCode, angle: 60 },
382
+ { key: "formatting", label: "Format", color: themeColors.metricColors.formatting, angle: 120 },
383
+ { key: "linting", label: "Linting", color: themeColors.metricColors.linting, angle: 180 }
384
+ ];
385
+ function calculateHexagonPoints(center, radius, metricConfig) {
386
+ return metricConfig.map(({ angle }) => {
387
+ const radian = angle * Math.PI / 180;
388
+ const x = center + radius * Math.cos(radian);
389
+ const y = center + radius * Math.sin(radian);
390
+ return `${x},${y}`;
391
+ }).join(" ");
392
+ }
393
+ function calculateMetricPoint(center, radius, angle, value) {
394
+ const actualRadius = radius * value / 100;
395
+ const radian = angle * Math.PI / 180;
396
+ return {
397
+ x: center + actualRadius * Math.cos(radian),
398
+ y: center + actualRadius * Math.sin(radian)
399
+ };
400
+ }
401
+ function QualityHexagon({
402
+ metrics,
403
+ tier,
404
+ theme: theme2,
405
+ showLabels = false,
406
+ showValues = false,
407
+ className
408
+ }) {
409
+ const themeColors = getThemeColors(theme2);
410
+ const colors = themeColors.tierColors[tier] ?? themeColors.tierColors.none;
411
+ const metricConfig = getMetricConfig(themeColors);
412
+ const viewBoxSize = 300;
413
+ const center = viewBoxSize / 2;
414
+ const radius = viewBoxSize * 0.28;
415
+ const padding = viewBoxSize * 0.1;
416
+ const fontSize = viewBoxSize * 0.04;
417
+ const strokeWidth = viewBoxSize * 8e-3;
418
+ const dotSize = viewBoxSize * 0.015;
419
+ const hexagonPoints = calculateHexagonPoints(center, radius, metricConfig);
420
+ const dataPoints = metricConfig.map(({ key, angle }) => {
421
+ let value = metrics[key];
422
+ if (key === "deadCode") {
423
+ value = 100 - value;
424
+ }
425
+ return calculateMetricPoint(center, radius, angle, value);
426
+ }).map((p) => `${p.x},${p.y}`).join(" ");
427
+ const metricsForAverage = { ...metrics };
428
+ metricsForAverage.deadCode = 100 - metricsForAverage.deadCode;
429
+ const averageScore = Math.round(
430
+ Object.values(metricsForAverage).reduce((a, b) => a + b, 0) / 6
431
+ );
432
+ const hexagon = /* @__PURE__ */ jsxs(
433
+ "svg",
434
+ {
435
+ viewBox: `0 0 ${viewBoxSize} ${viewBoxSize}`,
436
+ className: cn("w-full h-full transition-all duration-300", className),
437
+ preserveAspectRatio: "xMidYMid meet",
438
+ children: [
439
+ /* @__PURE__ */ jsx("g", { className: "opacity-20", children: [20, 40, 60, 80, 100].map((percent) => /* @__PURE__ */ jsx(
440
+ "polygon",
441
+ {
442
+ points: calculateHexagonPoints(center, radius * percent / 100, metricConfig),
443
+ fill: "none",
444
+ stroke: themeColors.gridColor,
445
+ strokeWidth: 0.5,
446
+ style: { opacity: 0.4 }
447
+ },
448
+ percent
449
+ )) }),
450
+ metricConfig.map(({ angle }) => {
451
+ const endPoint = calculateMetricPoint(center, radius, angle, 100);
452
+ return /* @__PURE__ */ jsx(
453
+ "line",
454
+ {
455
+ x1: center,
456
+ y1: center,
457
+ x2: endPoint.x,
458
+ y2: endPoint.y,
459
+ stroke: themeColors.axisColor,
460
+ strokeWidth: 0.5,
461
+ style: { opacity: 0.5 }
462
+ },
463
+ angle
464
+ );
465
+ }),
466
+ /* @__PURE__ */ jsx(
467
+ "polygon",
468
+ {
469
+ points: hexagonPoints,
470
+ fill: "none",
471
+ stroke: colors.stroke,
472
+ strokeWidth,
473
+ style: { opacity: 0.3 }
474
+ }
475
+ ),
476
+ /* @__PURE__ */ jsx(
477
+ "polygon",
478
+ {
479
+ points: dataPoints,
480
+ fill: colors.fill,
481
+ fillOpacity: 0.3,
482
+ stroke: colors.stroke,
483
+ strokeWidth,
484
+ style: { transition: "all 0.5s ease" }
485
+ }
486
+ ),
487
+ metricConfig.map(({ key, angle }) => {
488
+ let value = metrics[key];
489
+ if (key === "deadCode") {
490
+ value = 100 - value;
491
+ }
492
+ const point = calculateMetricPoint(center, radius, angle, 100);
493
+ const dataPoint = calculateMetricPoint(center, radius, angle, value);
494
+ return /* @__PURE__ */ jsxs("g", { children: [
495
+ /* @__PURE__ */ jsx(
496
+ "circle",
497
+ {
498
+ cx: point.x,
499
+ cy: point.y,
500
+ r: dotSize,
501
+ fill: "white",
502
+ stroke: colors.stroke,
503
+ strokeWidth: 1.5
504
+ }
505
+ ),
506
+ /* @__PURE__ */ jsx(
507
+ "circle",
508
+ {
509
+ cx: dataPoint.x,
510
+ cy: dataPoint.y,
511
+ r: dotSize * 0.7,
512
+ fill: colors.fill,
513
+ stroke: colors.stroke,
514
+ strokeWidth: 1,
515
+ style: { opacity: 0.9 }
516
+ }
517
+ )
518
+ ] }, key);
519
+ }),
520
+ /* @__PURE__ */ jsx(
521
+ "text",
522
+ {
523
+ x: center,
524
+ y: center,
525
+ textAnchor: "middle",
526
+ dominantBaseline: "middle",
527
+ fill: themeColors.scoreColor,
528
+ fontSize: fontSize * 1.5,
529
+ fontWeight: "600",
530
+ children: averageScore
531
+ }
532
+ ),
533
+ /* @__PURE__ */ jsx(
534
+ "text",
535
+ {
536
+ x: center,
537
+ y: center + fontSize,
538
+ textAnchor: "middle",
539
+ dominantBaseline: "middle",
540
+ fill: themeColors.textColor,
541
+ fontSize: fontSize * 0.8,
542
+ style: { opacity: 0.6 },
543
+ children: "avg"
544
+ }
545
+ ),
546
+ showLabels && /* @__PURE__ */ jsx(Fragment, { children: metricConfig.map(({ key, label, angle }) => {
547
+ const labelRadius = radius + padding * 1.2;
548
+ const point = calculateMetricPoint(center, labelRadius, angle, 100);
549
+ const value = metrics[key];
550
+ return /* @__PURE__ */ jsx(
551
+ "text",
552
+ {
553
+ x: point.x,
554
+ y: point.y,
555
+ textAnchor: "middle",
556
+ dominantBaseline: "middle",
557
+ fill: themeColors.textColor,
558
+ fontSize,
559
+ children: showValues ? `${value}%` : label
560
+ },
561
+ key
562
+ );
563
+ }) })
564
+ ]
565
+ }
566
+ );
567
+ return hexagon;
568
+ }
569
+ function QualityHexagonCompact({
570
+ metrics,
571
+ tier,
572
+ theme: theme2,
573
+ className
574
+ }) {
575
+ return /* @__PURE__ */ jsx("div", { className: cn("w-20 h-20", className), children: /* @__PURE__ */ jsx(
576
+ QualityHexagon,
577
+ {
578
+ metrics,
579
+ tier,
580
+ theme: theme2,
581
+ showLabels: false,
582
+ showValues: false
583
+ }
584
+ ) });
585
+ }
586
+ function QualityHexagonDetailed({
587
+ metrics,
588
+ tier,
589
+ theme: theme2,
590
+ className,
591
+ packageName,
592
+ packageVersion,
593
+ onRefresh,
594
+ isRefreshing = false
595
+ }) {
596
+ const themeColors = getThemeColors(theme2);
597
+ const colors = themeColors.tierColors[tier] ?? themeColors.tierColors.none;
598
+ const metricConfig = getMetricConfig(themeColors);
599
+ const hasHeader = packageName || onRefresh;
600
+ return /* @__PURE__ */ jsxs(
601
+ "div",
602
+ {
603
+ className: cn(className),
604
+ style: {
605
+ display: "flex",
606
+ flexDirection: "column",
607
+ gap: 12,
608
+ padding: 16,
609
+ borderRadius: 8,
610
+ backgroundColor: colors.bg
611
+ },
612
+ children: [
613
+ hasHeader && /* @__PURE__ */ jsxs("div", { style: {
614
+ display: "flex",
615
+ alignItems: "center",
616
+ justifyContent: "space-between",
617
+ gap: 12
618
+ }, children: [
619
+ packageName ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
620
+ packageName.startsWith("@") && packageName.includes("/") ? /* @__PURE__ */ jsxs(Fragment, { children: [
621
+ /* @__PURE__ */ jsx("span", { style: {
622
+ fontSize: 12,
623
+ color: theme2.colors.textMuted
624
+ }, children: packageName.split("/")[0] }),
625
+ /* @__PURE__ */ jsx("span", { style: {
626
+ fontSize: 14,
627
+ fontWeight: 500,
628
+ color: colors.stroke
629
+ }, children: packageName.split("/")[1] })
630
+ ] }) : /* @__PURE__ */ jsx("span", { style: {
631
+ fontSize: 14,
632
+ fontWeight: 500,
633
+ color: colors.stroke
634
+ }, children: packageName }),
635
+ packageVersion && /* @__PURE__ */ jsxs("span", { style: {
636
+ fontSize: 12,
637
+ color: theme2.colors.textMuted
638
+ }, children: [
639
+ "v",
640
+ packageVersion
641
+ ] })
642
+ ] }) : /* @__PURE__ */ jsx("span", {}),
643
+ onRefresh && /* @__PURE__ */ jsx(
644
+ "button",
645
+ {
646
+ onClick: onRefresh,
647
+ disabled: isRefreshing,
648
+ style: {
649
+ padding: 6,
650
+ display: "flex",
651
+ alignItems: "center",
652
+ justifyContent: "center",
653
+ border: `1px solid ${theme2.colors.border}`,
654
+ borderRadius: 4,
655
+ background: theme2.colors.surface,
656
+ color: theme2.colors.textMuted,
657
+ cursor: isRefreshing ? "not-allowed" : "pointer",
658
+ opacity: isRefreshing ? 0.6 : 1
659
+ },
660
+ title: "Refresh",
661
+ children: /* @__PURE__ */ jsxs(
662
+ "svg",
663
+ {
664
+ width: "14",
665
+ height: "14",
666
+ viewBox: "0 0 24 24",
667
+ fill: "none",
668
+ stroke: "currentColor",
669
+ strokeWidth: "2",
670
+ strokeLinecap: "round",
671
+ strokeLinejoin: "round",
672
+ style: {
673
+ animation: isRefreshing ? "spin 1s linear infinite" : "none"
674
+ },
675
+ children: [
676
+ /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
677
+ /* @__PURE__ */ jsx("path", { d: "M3 3v5h5" }),
678
+ /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" }),
679
+ /* @__PURE__ */ jsx("path", { d: "M16 16h5v5" })
680
+ ]
681
+ }
682
+ )
683
+ }
684
+ )
685
+ ] }),
686
+ /* @__PURE__ */ jsxs("div", { style: {
687
+ display: "flex",
688
+ flexWrap: "wrap",
689
+ alignItems: "center",
690
+ justifyContent: "center",
691
+ gap: 24
692
+ }, children: [
693
+ /* @__PURE__ */ jsx("div", { style: { flex: "1 1 200px", maxWidth: 300, aspectRatio: "1 / 1" }, children: /* @__PURE__ */ jsx(
694
+ QualityHexagon,
695
+ {
696
+ metrics,
697
+ tier,
698
+ theme: theme2,
699
+ showLabels: true,
700
+ showValues: false
701
+ }
702
+ ) }),
703
+ /* @__PURE__ */ jsx("div", { style: { flex: "1 1 200px", minWidth: 200, display: "flex", flexDirection: "column", gap: 8, padding: "8px 24px" }, children: metricConfig.map(({ key, label, color }) => {
704
+ const value = metrics[key];
705
+ const displayValue = value;
706
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12 }, children: [
707
+ /* @__PURE__ */ jsxs("span", { style: {
708
+ fontSize: 14,
709
+ color: theme2.colors.textMuted
710
+ }, children: [
711
+ label,
712
+ key === "deadCode" ? " ↓" : ""
713
+ ] }),
714
+ /* @__PURE__ */ jsxs("span", { style: {
715
+ fontSize: 14,
716
+ fontWeight: 500,
717
+ color
718
+ }, children: [
719
+ displayValue,
720
+ "%"
721
+ ] })
722
+ ] }, key);
723
+ }) })
724
+ ] })
725
+ ]
726
+ }
727
+ );
728
+ }
729
+ function calculateQualityTier(metrics) {
730
+ const metricsForAverage = { ...metrics };
731
+ metricsForAverage.deadCode = 100 - metricsForAverage.deadCode;
732
+ const average = Object.values(metricsForAverage).reduce((a, b) => a + b, 0) / 6;
733
+ if (average >= 90) return "platinum";
734
+ if (average >= 75) return "gold";
735
+ if (average >= 60) return "silver";
736
+ if (average >= 40) return "bronze";
737
+ return "none";
738
+ }
739
+ const mockPackages = [
740
+ {
741
+ name: "@principal-ade/code-quality-panels",
742
+ version: "0.1.0",
743
+ metrics: {
744
+ tests: 75,
745
+ deadCode: 15,
746
+ linting: 85,
747
+ formatting: 90,
748
+ types: 88,
749
+ documentation: 65
750
+ }
751
+ }
752
+ ];
753
+ const QualityHexagonPanelContent = ({
754
+ context,
755
+ events
756
+ }) => {
757
+ var _a;
758
+ const { theme: theme2 } = useTheme();
759
+ const [refreshingPackages, setRefreshingPackages] = React2.useState(/* @__PURE__ */ new Set());
760
+ const qualitySlice = context.getSlice("quality");
761
+ const hasQualitySlice = context.hasSlice("quality");
762
+ const isLoading = (qualitySlice == null ? void 0 : qualitySlice.loading) ?? false;
763
+ const packages = React2.useMemo(() => {
764
+ var _a2;
765
+ if ((_a2 = qualitySlice == null ? void 0 : qualitySlice.data) == null ? void 0 : _a2.packages) {
766
+ return qualitySlice.data.packages;
767
+ }
768
+ if (hasQualitySlice) {
769
+ return [];
770
+ }
771
+ return mockPackages;
772
+ }, [(_a = qualitySlice == null ? void 0 : qualitySlice.data) == null ? void 0 : _a.packages, hasQualitySlice]);
773
+ const handleRefreshPackage = async (packageName) => {
774
+ setRefreshingPackages((prev) => new Set(prev).add(packageName));
775
+ try {
776
+ if (context.hasSlice("quality")) {
777
+ await context.refresh("repository", "quality");
778
+ }
779
+ } finally {
780
+ setRefreshingPackages((prev) => {
781
+ const next = new Set(prev);
782
+ next.delete(packageName);
783
+ return next;
784
+ });
785
+ }
786
+ };
787
+ const handleRefreshAll = async () => {
788
+ const allNames = packages.map((p) => p.name);
789
+ setRefreshingPackages(new Set(allNames));
790
+ try {
791
+ if (context.hasSlice("quality")) {
792
+ await context.refresh("repository", "quality");
793
+ }
794
+ } finally {
795
+ setRefreshingPackages(/* @__PURE__ */ new Set());
796
+ }
797
+ };
798
+ React2.useEffect(() => {
799
+ const unsubscribers = [
800
+ events.on("principal-ade.quality-panel:refresh", async () => {
801
+ await handleRefreshAll();
802
+ })
803
+ ];
804
+ return () => unsubscribers.forEach((unsub) => unsub());
805
+ }, [events, context, packages]);
806
+ const tierColors = {
807
+ none: theme2.colors.muted,
808
+ bronze: theme2.colors.warning,
809
+ silver: theme2.colors.secondary,
810
+ gold: theme2.colors.accent,
811
+ platinum: theme2.colors.primary
812
+ };
813
+ const overallTier = packages.length > 0 ? calculateQualityTier(
814
+ packages.reduce((acc, pkg) => ({
815
+ tests: acc.tests + pkg.metrics.tests / packages.length,
816
+ deadCode: acc.deadCode + pkg.metrics.deadCode / packages.length,
817
+ linting: acc.linting + pkg.metrics.linting / packages.length,
818
+ formatting: acc.formatting + pkg.metrics.formatting / packages.length,
819
+ types: acc.types + pkg.metrics.types / packages.length,
820
+ documentation: acc.documentation + pkg.metrics.documentation / packages.length
821
+ }), { tests: 0, deadCode: 0, linting: 0, formatting: 0, types: 0, documentation: 0 })
822
+ ) : "none";
823
+ return /* @__PURE__ */ jsxs(
824
+ "div",
825
+ {
826
+ style: {
827
+ padding: 20,
828
+ fontFamily: theme2.fonts.body,
829
+ height: "100%",
830
+ display: "flex",
831
+ flexDirection: "column",
832
+ gap: 16,
833
+ backgroundColor: theme2.colors.background,
834
+ color: theme2.colors.text,
835
+ overflowY: "auto",
836
+ boxSizing: "border-box"
837
+ },
838
+ children: [
839
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
840
+ /* @__PURE__ */ jsx(Hexagon, { size: 24, color: tierColors[overallTier] }),
841
+ /* @__PURE__ */ jsx(
842
+ "h2",
843
+ {
844
+ style: {
845
+ margin: 0,
846
+ fontSize: 20,
847
+ fontWeight: 600,
848
+ color: theme2.colors.text
849
+ },
850
+ children: "Code Quality"
851
+ }
852
+ ),
853
+ /* @__PURE__ */ jsx(
854
+ "span",
855
+ {
856
+ title: "Platinum: 90%+ avg | Gold: 75%+ | Silver: 60%+ | Bronze: 40%+",
857
+ style: {
858
+ display: "inline-flex",
859
+ alignItems: "center",
860
+ justifyContent: "center",
861
+ width: 18,
862
+ height: 18,
863
+ borderRadius: "50%",
864
+ border: `1px solid ${theme2.colors.border}`,
865
+ fontSize: 12,
866
+ color: theme2.colors.textMuted,
867
+ cursor: "help"
868
+ },
869
+ children: "?"
870
+ }
871
+ ),
872
+ packages.length > 1 && /* @__PURE__ */ jsxs("span", { style: {
873
+ fontSize: 14,
874
+ color: theme2.colors.textMuted
875
+ }, children: [
876
+ packages.length,
877
+ " packages"
878
+ ] })
879
+ ] }),
880
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: 16 }, children: isLoading ? /* @__PURE__ */ jsx("div", { style: {
881
+ padding: 40,
882
+ textAlign: "center",
883
+ color: theme2.colors.textMuted
884
+ }, children: "Loading quality metrics..." }) : packages.length === 0 ? /* @__PURE__ */ jsx("div", { style: {
885
+ padding: 40,
886
+ textAlign: "center",
887
+ color: theme2.colors.textMuted
888
+ }, children: "No packages found" }) : packages.map((pkg) => {
889
+ const tier = calculateQualityTier(pkg.metrics);
890
+ return /* @__PURE__ */ jsx(
891
+ QualityHexagonDetailed,
892
+ {
893
+ metrics: pkg.metrics,
894
+ tier,
895
+ theme: theme2,
896
+ packageName: pkg.name,
897
+ packageVersion: pkg.version,
898
+ onRefresh: () => handleRefreshPackage(pkg.name),
899
+ isRefreshing: refreshingPackages.has(pkg.name)
900
+ },
901
+ pkg.name
902
+ );
903
+ }) })
904
+ ]
905
+ }
906
+ );
907
+ };
908
+ const QualityHexagonPanel = (props) => {
909
+ return /* @__PURE__ */ jsx(ThemeProvider, { children: /* @__PURE__ */ jsx(QualityHexagonPanelContent, { ...props }) });
910
+ };
911
+ const panels = [
912
+ {
913
+ metadata: {
914
+ id: "principal-ade.quality-hexagon-panel",
915
+ name: "Code Quality",
916
+ icon: "⬡",
917
+ version: "0.1.0",
918
+ author: "Principal ADE",
919
+ description: "Visualize code quality metrics using a hexagonal radar chart showing tests, types, linting, formatting, documentation, and dead code.",
920
+ slices: ["quality"],
921
+ tools: []
922
+ },
923
+ component: QualityHexagonPanel,
924
+ onMount: async (context) => {
925
+ var _a;
926
+ console.log(
927
+ "Quality Hexagon Panel mounted",
928
+ (_a = context.currentScope.repository) == null ? void 0 : _a.path
929
+ );
930
+ if (context.hasSlice("quality") && !context.isSliceLoading("quality")) {
931
+ await context.refresh("repository", "quality");
932
+ }
933
+ },
934
+ onUnmount: async (_context) => {
935
+ console.log("Quality Hexagon Panel unmounting");
936
+ }
937
+ }
938
+ ];
939
+ const onPackageLoad = async () => {
940
+ console.log("Panel package loaded - Code Quality Panels");
941
+ };
942
+ const onPackageUnload = async () => {
943
+ console.log("Panel package unloading - Code Quality Panels");
944
+ };
945
+ export {
946
+ QualityHexagon,
947
+ QualityHexagonCompact,
948
+ QualityHexagonDetailed,
949
+ QualityHexagonPanel,
950
+ calculateQualityTier,
951
+ onPackageLoad,
952
+ onPackageUnload,
953
+ panels
954
+ };
955
+ //# sourceMappingURL=panels.bundle.js.map