@doccov/ui 0.2.2 → 0.2.3
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/badge/index.d.ts +14 -0
- package/dist/badge/index.js +86 -0
- package/dist/breadcrumb/index.d.ts +24 -0
- package/dist/breadcrumb/index.js +77 -0
- package/dist/button/index.d.ts +18 -0
- package/dist/button/index.js +109 -0
- package/dist/coverage-trends/index.d.ts +46 -0
- package/dist/coverage-trends/index.js +182 -0
- package/dist/file-change-row/index.d.ts +34 -0
- package/dist/file-change-row/index.js +4415 -0
- package/dist/file-chip/index.d.ts +7 -0
- package/dist/file-chip/index.js +30 -0
- package/dist/input/index.d.ts +23 -0
- package/dist/input/index.js +242 -0
- package/dist/tabs/index.d.ts +56 -0
- package/dist/tabs/index.js +224 -0
- package/package.json +33 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { VariantProps } from "class-variance-authority";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
declare const kindBadgeVariants: unknown;
|
|
4
|
+
interface KindBadgeProps extends React.HTMLAttributes<HTMLSpanElement>, VariantProps<typeof kindBadgeVariants> {
|
|
5
|
+
label?: string;
|
|
6
|
+
}
|
|
7
|
+
declare const KindBadge: unknown;
|
|
8
|
+
declare const statusBadgeVariants: unknown;
|
|
9
|
+
interface StatusBadgeProps extends React.HTMLAttributes<HTMLSpanElement>, VariantProps<typeof statusBadgeVariants> {
|
|
10
|
+
label?: string;
|
|
11
|
+
icon?: React.ReactNode;
|
|
12
|
+
}
|
|
13
|
+
declare const StatusBadge: unknown;
|
|
14
|
+
export { statusBadgeVariants, kindBadgeVariants, StatusBadgeProps, StatusBadge, KindBadgeProps, KindBadge };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// src/components/badge/badge.tsx
|
|
2
|
+
import { cva } from "class-variance-authority";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
|
|
5
|
+
// src/lib/utils.ts
|
|
6
|
+
import { clsx } from "clsx";
|
|
7
|
+
import { twMerge } from "tailwind-merge";
|
|
8
|
+
function cn(...inputs) {
|
|
9
|
+
return twMerge(clsx(inputs));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// src/components/badge/badge.tsx
|
|
13
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
var kindBadgeVariants = cva("inline-flex items-center justify-center font-mono font-medium rounded shrink-0", {
|
|
15
|
+
variants: {
|
|
16
|
+
kind: {
|
|
17
|
+
function: "bg-kind-function/15 text-kind-function",
|
|
18
|
+
class: "bg-kind-class/15 text-kind-class",
|
|
19
|
+
interface: "bg-kind-interface/15 text-kind-interface",
|
|
20
|
+
type: "bg-kind-type/15 text-kind-type",
|
|
21
|
+
enum: "bg-kind-enum/15 text-kind-enum",
|
|
22
|
+
variable: "bg-kind-variable/15 text-kind-variable"
|
|
23
|
+
},
|
|
24
|
+
size: {
|
|
25
|
+
sm: "h-4 px-1 text-[10px]",
|
|
26
|
+
md: "h-5 px-1.5 text-xs"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
kind: "function",
|
|
31
|
+
size: "md"
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
var KindBadge = React.forwardRef(({ className, kind, size, label, ...props }, ref) => {
|
|
35
|
+
const defaultLabels = {
|
|
36
|
+
function: "fn",
|
|
37
|
+
class: "cls",
|
|
38
|
+
interface: "int",
|
|
39
|
+
type: "type",
|
|
40
|
+
enum: "enum",
|
|
41
|
+
variable: "var"
|
|
42
|
+
};
|
|
43
|
+
return /* @__PURE__ */ jsx("span", {
|
|
44
|
+
ref,
|
|
45
|
+
className: cn(kindBadgeVariants({ kind, size, className })),
|
|
46
|
+
...props,
|
|
47
|
+
children: label || defaultLabels[kind || "function"]
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
KindBadge.displayName = "KindBadge";
|
|
51
|
+
var statusBadgeVariants = cva("inline-flex items-center justify-center gap-1 font-medium rounded-full", {
|
|
52
|
+
variants: {
|
|
53
|
+
status: {
|
|
54
|
+
success: "bg-success-light text-success",
|
|
55
|
+
warning: "bg-warning-light text-warning",
|
|
56
|
+
error: "bg-destructive-light text-destructive",
|
|
57
|
+
neutral: "bg-muted text-muted-foreground"
|
|
58
|
+
},
|
|
59
|
+
size: {
|
|
60
|
+
sm: "h-5 px-2 text-xs",
|
|
61
|
+
md: "h-6 px-2.5 text-sm"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
defaultVariants: {
|
|
65
|
+
status: "neutral",
|
|
66
|
+
size: "md"
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
var StatusBadge = React.forwardRef(({ className, status, size, label, icon, children, ...props }, ref) => {
|
|
70
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
71
|
+
ref,
|
|
72
|
+
className: cn(statusBadgeVariants({ status, size, className })),
|
|
73
|
+
...props,
|
|
74
|
+
children: [
|
|
75
|
+
icon,
|
|
76
|
+
label || children
|
|
77
|
+
]
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
StatusBadge.displayName = "StatusBadge";
|
|
81
|
+
export {
|
|
82
|
+
statusBadgeVariants,
|
|
83
|
+
kindBadgeVariants,
|
|
84
|
+
StatusBadge,
|
|
85
|
+
KindBadge
|
|
86
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
interface BreadcrumbItem {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
truncate?: boolean;
|
|
6
|
+
maxWidth?: number;
|
|
7
|
+
hasDropdown?: boolean;
|
|
8
|
+
onClick?: () => void;
|
|
9
|
+
}
|
|
10
|
+
interface BreadcrumbProps {
|
|
11
|
+
items: BreadcrumbItem[];
|
|
12
|
+
separator?: React.ReactNode;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
declare const Breadcrumb: unknown;
|
|
16
|
+
interface BreadcrumbDropdownProps {
|
|
17
|
+
label: string;
|
|
18
|
+
truncate?: boolean;
|
|
19
|
+
maxWidth?: number;
|
|
20
|
+
className?: string;
|
|
21
|
+
onClick?: () => void;
|
|
22
|
+
}
|
|
23
|
+
declare const BreadcrumbDropdown: unknown;
|
|
24
|
+
export { BreadcrumbProps, BreadcrumbItem, BreadcrumbDropdownProps, BreadcrumbDropdown, Breadcrumb };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/components/breadcrumb/breadcrumb.tsx
|
|
3
|
+
import { ChevronDown } from "lucide-react";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
|
|
6
|
+
// src/lib/utils.ts
|
|
7
|
+
import { clsx } from "clsx";
|
|
8
|
+
import { twMerge } from "tailwind-merge";
|
|
9
|
+
function cn(...inputs) {
|
|
10
|
+
return twMerge(clsx(inputs));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// src/components/breadcrumb/breadcrumb.tsx
|
|
14
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
+
|
|
16
|
+
var Breadcrumb = React.forwardRef(({ items, separator = "/", className }, ref) => {
|
|
17
|
+
return /* @__PURE__ */ jsx("nav", {
|
|
18
|
+
ref,
|
|
19
|
+
className: cn("flex items-center gap-2 text-sm", className),
|
|
20
|
+
"aria-label": "Breadcrumb",
|
|
21
|
+
children: items.map((item, index) => /* @__PURE__ */ jsxs(React.Fragment, {
|
|
22
|
+
children: [
|
|
23
|
+
index > 0 && /* @__PURE__ */ jsx("span", {
|
|
24
|
+
className: "text-muted-foreground/50 select-none",
|
|
25
|
+
children: separator
|
|
26
|
+
}),
|
|
27
|
+
/* @__PURE__ */ jsx(BreadcrumbItemButton, {
|
|
28
|
+
item
|
|
29
|
+
})
|
|
30
|
+
]
|
|
31
|
+
}, item.id))
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
Breadcrumb.displayName = "Breadcrumb";
|
|
35
|
+
function BreadcrumbItemButton({ item }) {
|
|
36
|
+
const { label, truncate, maxWidth = 200, hasDropdown, onClick } = item;
|
|
37
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
38
|
+
type: "button",
|
|
39
|
+
onClick,
|
|
40
|
+
className: cn("flex items-center gap-1 font-medium text-foreground hover:text-foreground/80 transition-colors", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded", !onClick && "cursor-default"),
|
|
41
|
+
children: [
|
|
42
|
+
/* @__PURE__ */ jsx("span", {
|
|
43
|
+
className: cn(truncate && "truncate"),
|
|
44
|
+
style: truncate ? { maxWidth } : undefined,
|
|
45
|
+
title: truncate ? label : undefined,
|
|
46
|
+
children: label
|
|
47
|
+
}),
|
|
48
|
+
hasDropdown && /* @__PURE__ */ jsx(ChevronDown, {
|
|
49
|
+
className: "size-4 text-muted-foreground"
|
|
50
|
+
})
|
|
51
|
+
]
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
var BreadcrumbDropdown = React.forwardRef(({ label, truncate, maxWidth = 200, className, onClick }, ref) => {
|
|
55
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
56
|
+
ref,
|
|
57
|
+
type: "button",
|
|
58
|
+
onClick,
|
|
59
|
+
className: cn("flex items-center gap-1 font-medium text-foreground hover:text-foreground/80 transition-colors", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded px-1 -mx-1", className),
|
|
60
|
+
children: [
|
|
61
|
+
/* @__PURE__ */ jsx("span", {
|
|
62
|
+
className: cn(truncate && "truncate"),
|
|
63
|
+
style: truncate ? { maxWidth } : undefined,
|
|
64
|
+
title: truncate ? label : undefined,
|
|
65
|
+
children: label
|
|
66
|
+
}),
|
|
67
|
+
/* @__PURE__ */ jsx(ChevronDown, {
|
|
68
|
+
className: "size-4 text-muted-foreground"
|
|
69
|
+
})
|
|
70
|
+
]
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
BreadcrumbDropdown.displayName = "BreadcrumbDropdown";
|
|
74
|
+
export {
|
|
75
|
+
BreadcrumbDropdown,
|
|
76
|
+
Breadcrumb
|
|
77
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { VariantProps } from "class-variance-authority";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
declare function ArrowIcon({ className }: {
|
|
4
|
+
className?: string;
|
|
5
|
+
});
|
|
6
|
+
declare const buttonVariants: unknown;
|
|
7
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
8
|
+
asChild?: boolean;
|
|
9
|
+
isLoading?: boolean;
|
|
10
|
+
leftIcon?: React.ReactNode;
|
|
11
|
+
rightIcon?: React.ReactNode;
|
|
12
|
+
/** Show the trailing arrow */
|
|
13
|
+
withArrow?: boolean;
|
|
14
|
+
/** For nav links with muted count like "GitHub [34K]" */
|
|
15
|
+
count?: string;
|
|
16
|
+
}
|
|
17
|
+
declare const Button: unknown;
|
|
18
|
+
export { buttonVariants, ButtonProps, Button, ArrowIcon };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// src/components/button/button.tsx
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
import { Loader2 } from "lucide-react";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
|
|
7
|
+
// src/lib/utils.ts
|
|
8
|
+
import { clsx } from "clsx";
|
|
9
|
+
import { twMerge } from "tailwind-merge";
|
|
10
|
+
function cn(...inputs) {
|
|
11
|
+
return twMerge(clsx(inputs));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// src/components/button/button.tsx
|
|
15
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
function ArrowIcon({ className }) {
|
|
17
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
18
|
+
width: "24",
|
|
19
|
+
height: "24",
|
|
20
|
+
viewBox: "0 0 24 24",
|
|
21
|
+
fill: "none",
|
|
22
|
+
className,
|
|
23
|
+
"aria-hidden": "true",
|
|
24
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
25
|
+
d: "M6.5 12L17 12M13 16.5L17.5 12L13 7.5",
|
|
26
|
+
stroke: "currentColor",
|
|
27
|
+
strokeWidth: "1.5",
|
|
28
|
+
strokeLinecap: "square"
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
var buttonVariants = cva("inline-flex items-center justify-center whitespace-nowrap font-mono font-medium transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0", {
|
|
33
|
+
variants: {
|
|
34
|
+
variant: {
|
|
35
|
+
primary: "bg-[var(--btn-primary-bg)] text-[var(--btn-primary-text)] border-none rounded hover:opacity-90 active:opacity-80 active:scale-[0.98]",
|
|
36
|
+
secondary: "bg-transparent text-[var(--btn-secondary-text)] border border-[var(--btn-secondary-border)] rounded hover:bg-[var(--btn-secondary-hover)] active:scale-[0.98]",
|
|
37
|
+
ghost: "bg-transparent text-[var(--btn-ghost-text)] border-none rounded hover:opacity-70 active:opacity-60 active:scale-[0.98]",
|
|
38
|
+
nav: "bg-transparent text-[var(--btn-nav-text)] border-none font-normal hover:underline underline-offset-4",
|
|
39
|
+
danger: "bg-red-50 text-red-600 border border-red-200 rounded hover:bg-red-600 hover:text-white hover:border-red-600 active:bg-red-700 active:scale-[0.98] dark:bg-red-950 dark:text-red-400 dark:border-red-800 dark:hover:bg-red-600 dark:hover:text-white"
|
|
40
|
+
},
|
|
41
|
+
size: {
|
|
42
|
+
sm: "h-8 px-3 py-1 text-sm gap-2 [&_svg]:size-4",
|
|
43
|
+
md: "h-10 px-5 py-1 text-base gap-3 [&_svg]:size-5",
|
|
44
|
+
lg: "h-12 px-6 py-2 text-base gap-3 [&_svg]:size-6",
|
|
45
|
+
nav: "h-auto p-0 text-base"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
defaultVariants: {
|
|
49
|
+
variant: "primary",
|
|
50
|
+
size: "md"
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
var Button = React.forwardRef(({
|
|
54
|
+
className,
|
|
55
|
+
variant,
|
|
56
|
+
size,
|
|
57
|
+
asChild = false,
|
|
58
|
+
isLoading,
|
|
59
|
+
leftIcon,
|
|
60
|
+
rightIcon,
|
|
61
|
+
withArrow,
|
|
62
|
+
count,
|
|
63
|
+
children,
|
|
64
|
+
disabled,
|
|
65
|
+
...props
|
|
66
|
+
}, ref) => {
|
|
67
|
+
const _Comp = asChild ? Slot : "button";
|
|
68
|
+
const effectiveSize = variant === "nav" ? "nav" : size;
|
|
69
|
+
const arrowPaddingClass = withArrow && effectiveSize !== "nav" ? effectiveSize === "sm" ? "pl-3 pr-2" : effectiveSize === "lg" ? "pl-6 pr-4" : "pl-5 pr-3" : "";
|
|
70
|
+
if (asChild) {
|
|
71
|
+
return /* @__PURE__ */ jsx(Slot, {
|
|
72
|
+
className: cn(buttonVariants({ variant, size: effectiveSize, className }), arrowPaddingClass),
|
|
73
|
+
ref,
|
|
74
|
+
...props,
|
|
75
|
+
children
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
79
|
+
className: cn(buttonVariants({ variant, size: effectiveSize, className }), arrowPaddingClass),
|
|
80
|
+
ref,
|
|
81
|
+
disabled: disabled || isLoading,
|
|
82
|
+
...props,
|
|
83
|
+
children: [
|
|
84
|
+
isLoading ? /* @__PURE__ */ jsx(Loader2, {
|
|
85
|
+
className: "animate-spin"
|
|
86
|
+
}) : leftIcon ? leftIcon : null,
|
|
87
|
+
/* @__PURE__ */ jsxs("span", {
|
|
88
|
+
children: [
|
|
89
|
+
children,
|
|
90
|
+
count && /* @__PURE__ */ jsxs("span", {
|
|
91
|
+
className: "text-[var(--btn-count-text)]",
|
|
92
|
+
children: [
|
|
93
|
+
" [",
|
|
94
|
+
count,
|
|
95
|
+
"]"
|
|
96
|
+
]
|
|
97
|
+
})
|
|
98
|
+
]
|
|
99
|
+
}),
|
|
100
|
+
!isLoading && (withArrow ? /* @__PURE__ */ jsx(ArrowIcon, {}) : rightIcon)
|
|
101
|
+
]
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
Button.displayName = "Button";
|
|
105
|
+
export {
|
|
106
|
+
buttonVariants,
|
|
107
|
+
Button,
|
|
108
|
+
ArrowIcon
|
|
109
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
interface CoverageDataPoint {
|
|
2
|
+
version: string;
|
|
3
|
+
date: string;
|
|
4
|
+
coverageScore: number;
|
|
5
|
+
documentedExports: number;
|
|
6
|
+
totalExports: number;
|
|
7
|
+
driftCount: number;
|
|
8
|
+
}
|
|
9
|
+
type TimeRange = "7d" | "30d" | "90d" | "all" | "versions";
|
|
10
|
+
type TrendDirection = "up" | "down" | "stable";
|
|
11
|
+
interface CoverageInsight {
|
|
12
|
+
type: "improvement" | "regression" | "prediction" | "milestone";
|
|
13
|
+
message: string;
|
|
14
|
+
severity?: "info" | "warning" | "success";
|
|
15
|
+
}
|
|
16
|
+
interface RegressionInfo {
|
|
17
|
+
fromVersion: string;
|
|
18
|
+
toVersion: string;
|
|
19
|
+
coverageDrop: number;
|
|
20
|
+
exportsLost: number;
|
|
21
|
+
}
|
|
22
|
+
interface InsightsPanelProps {
|
|
23
|
+
insights: CoverageInsight[];
|
|
24
|
+
className?: string;
|
|
25
|
+
}
|
|
26
|
+
declare function InsightsPanel({ insights, className }: InsightsPanelProps);
|
|
27
|
+
interface RegressionAlertProps {
|
|
28
|
+
regression: RegressionInfo;
|
|
29
|
+
className?: string;
|
|
30
|
+
}
|
|
31
|
+
declare function RegressionAlert({ regression, className }: RegressionAlertProps);
|
|
32
|
+
interface TimeRangeSelectorProps {
|
|
33
|
+
value: TimeRange;
|
|
34
|
+
onChange: (range: TimeRange) => void;
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
declare function TimeRangeSelector({ value, onChange, className }: TimeRangeSelectorProps);
|
|
38
|
+
interface TrendIndicatorProps {
|
|
39
|
+
value: number;
|
|
40
|
+
direction: TrendDirection;
|
|
41
|
+
size?: "sm" | "md";
|
|
42
|
+
showIcon?: boolean;
|
|
43
|
+
className?: string;
|
|
44
|
+
}
|
|
45
|
+
declare function TrendIndicator({ value, direction, size, showIcon, className }: TrendIndicatorProps);
|
|
46
|
+
export { TrendIndicator, TrendDirection, TimeRangeSelector, TimeRange, RegressionInfo, RegressionAlert, InsightsPanel, CoverageInsight, CoverageDataPoint };
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/components/coverage-trends/insights-panel.tsx
|
|
3
|
+
import { Award, Target, TrendingDown, TrendingUp } from "lucide-react";
|
|
4
|
+
|
|
5
|
+
// src/lib/utils.ts
|
|
6
|
+
import { clsx } from "clsx";
|
|
7
|
+
import { twMerge } from "tailwind-merge";
|
|
8
|
+
function cn(...inputs) {
|
|
9
|
+
return twMerge(clsx(inputs));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// src/components/coverage-trends/insights-panel.tsx
|
|
13
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
|
|
15
|
+
var insightIcons = {
|
|
16
|
+
improvement: TrendingUp,
|
|
17
|
+
regression: TrendingDown,
|
|
18
|
+
prediction: Target,
|
|
19
|
+
milestone: Award
|
|
20
|
+
};
|
|
21
|
+
var insightColors = {
|
|
22
|
+
info: "text-muted-foreground",
|
|
23
|
+
warning: "text-warning",
|
|
24
|
+
success: "text-success"
|
|
25
|
+
};
|
|
26
|
+
function InsightsPanel({ insights, className }) {
|
|
27
|
+
if (insights.length === 0)
|
|
28
|
+
return null;
|
|
29
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
30
|
+
className: cn("space-y-2", className),
|
|
31
|
+
children: [
|
|
32
|
+
/* @__PURE__ */ jsx("h4", {
|
|
33
|
+
className: "text-xs font-medium text-muted-foreground uppercase tracking-wide",
|
|
34
|
+
children: "Insights"
|
|
35
|
+
}),
|
|
36
|
+
/* @__PURE__ */ jsx("div", {
|
|
37
|
+
className: "space-y-1.5",
|
|
38
|
+
children: insights.map((insight) => {
|
|
39
|
+
const Icon = insightIcons[insight.type];
|
|
40
|
+
const colorClass = insightColors[insight.severity || "info"];
|
|
41
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
42
|
+
className: cn("flex items-start gap-2 text-sm", colorClass),
|
|
43
|
+
children: [
|
|
44
|
+
/* @__PURE__ */ jsx(Icon, {
|
|
45
|
+
className: "size-4 mt-0.5 shrink-0"
|
|
46
|
+
}),
|
|
47
|
+
/* @__PURE__ */ jsx("span", {
|
|
48
|
+
className: "text-foreground",
|
|
49
|
+
children: insight.message
|
|
50
|
+
})
|
|
51
|
+
]
|
|
52
|
+
}, `${insight.type}-${insight.message}`);
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
]
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// src/components/coverage-trends/regression-alert.tsx
|
|
59
|
+
import { AlertTriangle } from "lucide-react";
|
|
60
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
61
|
+
|
|
62
|
+
function RegressionAlert({ regression, className }) {
|
|
63
|
+
return /* @__PURE__ */ jsxs2("div", {
|
|
64
|
+
className: cn("flex items-start gap-3 p-3 rounded-lg", "bg-warning-light border border-warning/20", className),
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ jsx2(AlertTriangle, {
|
|
67
|
+
className: "size-4 text-warning mt-0.5 shrink-0"
|
|
68
|
+
}),
|
|
69
|
+
/* @__PURE__ */ jsxs2("div", {
|
|
70
|
+
className: "flex-1 min-w-0",
|
|
71
|
+
children: [
|
|
72
|
+
/* @__PURE__ */ jsxs2("p", {
|
|
73
|
+
className: "text-sm font-medium text-foreground",
|
|
74
|
+
children: [
|
|
75
|
+
"Coverage dropped ",
|
|
76
|
+
regression.coverageDrop,
|
|
77
|
+
"%"
|
|
78
|
+
]
|
|
79
|
+
}),
|
|
80
|
+
/* @__PURE__ */ jsxs2("p", {
|
|
81
|
+
className: "text-xs text-muted-foreground mt-0.5",
|
|
82
|
+
children: [
|
|
83
|
+
regression.exportsLost,
|
|
84
|
+
" exports lost documentation between",
|
|
85
|
+
" ",
|
|
86
|
+
/* @__PURE__ */ jsx2("span", {
|
|
87
|
+
className: "font-mono",
|
|
88
|
+
children: regression.fromVersion
|
|
89
|
+
}),
|
|
90
|
+
" and",
|
|
91
|
+
" ",
|
|
92
|
+
/* @__PURE__ */ jsx2("span", {
|
|
93
|
+
className: "font-mono",
|
|
94
|
+
children: regression.toVersion
|
|
95
|
+
})
|
|
96
|
+
]
|
|
97
|
+
})
|
|
98
|
+
]
|
|
99
|
+
})
|
|
100
|
+
]
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// src/components/coverage-trends/time-range-selector.tsx
|
|
104
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
105
|
+
|
|
106
|
+
var ranges = [
|
|
107
|
+
{ value: "7d", label: "7d" },
|
|
108
|
+
{ value: "30d", label: "30d" },
|
|
109
|
+
{ value: "90d", label: "90d" },
|
|
110
|
+
{ value: "all", label: "All" },
|
|
111
|
+
{ value: "versions", label: "Versions" }
|
|
112
|
+
];
|
|
113
|
+
function TimeRangeSelector({ value, onChange, className }) {
|
|
114
|
+
return /* @__PURE__ */ jsx3("div", {
|
|
115
|
+
className: cn("inline-flex items-stretch border border-border rounded-md bg-background", className),
|
|
116
|
+
children: ranges.map((range, index) => {
|
|
117
|
+
const isActive = range.value === value;
|
|
118
|
+
const isLast = index === ranges.length - 1;
|
|
119
|
+
return /* @__PURE__ */ jsx3("button", {
|
|
120
|
+
type: "button",
|
|
121
|
+
onClick: () => onChange(range.value),
|
|
122
|
+
className: cn("px-3 py-1.5 text-xs font-mono transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset", !isLast && "border-r border-border", isActive ? "bg-accent text-foreground font-medium" : "text-muted-foreground hover:bg-accent/50 hover:text-foreground"),
|
|
123
|
+
children: range.label
|
|
124
|
+
}, range.value);
|
|
125
|
+
})
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
// src/components/coverage-trends/trend-indicator.tsx
|
|
129
|
+
import { Minus, TrendingDown as TrendingDown2, TrendingUp as TrendingUp2 } from "lucide-react";
|
|
130
|
+
import { jsx as jsx4, jsxs as jsxs3, Fragment } from "react/jsx-runtime";
|
|
131
|
+
|
|
132
|
+
function TrendIndicator({
|
|
133
|
+
value,
|
|
134
|
+
direction,
|
|
135
|
+
size = "md",
|
|
136
|
+
showIcon = true,
|
|
137
|
+
className
|
|
138
|
+
}) {
|
|
139
|
+
const isPositive = direction === "up";
|
|
140
|
+
const isNegative = direction === "down";
|
|
141
|
+
const isStable = direction === "stable";
|
|
142
|
+
const sizeClasses = {
|
|
143
|
+
sm: "text-xs px-1.5 py-0.5 gap-0.5",
|
|
144
|
+
md: "text-sm px-2 py-1 gap-1"
|
|
145
|
+
};
|
|
146
|
+
const iconSizes = {
|
|
147
|
+
sm: "size-3",
|
|
148
|
+
md: "size-3.5"
|
|
149
|
+
};
|
|
150
|
+
return /* @__PURE__ */ jsxs3("span", {
|
|
151
|
+
className: cn("inline-flex items-center font-mono font-medium rounded-full", sizeClasses[size], isPositive && "bg-success-light text-success", isNegative && "bg-destructive-light text-destructive", isStable && "bg-muted text-muted-foreground", className),
|
|
152
|
+
children: [
|
|
153
|
+
showIcon && /* @__PURE__ */ jsxs3(Fragment, {
|
|
154
|
+
children: [
|
|
155
|
+
isPositive && /* @__PURE__ */ jsx4(TrendingUp2, {
|
|
156
|
+
className: iconSizes[size]
|
|
157
|
+
}),
|
|
158
|
+
isNegative && /* @__PURE__ */ jsx4(TrendingDown2, {
|
|
159
|
+
className: iconSizes[size]
|
|
160
|
+
}),
|
|
161
|
+
isStable && /* @__PURE__ */ jsx4(Minus, {
|
|
162
|
+
className: iconSizes[size]
|
|
163
|
+
})
|
|
164
|
+
]
|
|
165
|
+
}),
|
|
166
|
+
/* @__PURE__ */ jsxs3("span", {
|
|
167
|
+
className: "tabular-nums",
|
|
168
|
+
children: [
|
|
169
|
+
isPositive ? "+" : isNegative ? "" : "",
|
|
170
|
+
value,
|
|
171
|
+
"%"
|
|
172
|
+
]
|
|
173
|
+
})
|
|
174
|
+
]
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
export {
|
|
178
|
+
TrendIndicator,
|
|
179
|
+
TimeRangeSelector,
|
|
180
|
+
RegressionAlert,
|
|
181
|
+
InsightsPanel
|
|
182
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { AnnotationHandler, RawCode } from "codehike/code";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
declare function StackedChevrons({ isOpen, className }: {
|
|
4
|
+
isOpen?: boolean;
|
|
5
|
+
className?: string;
|
|
6
|
+
});
|
|
7
|
+
/** Get language from filename extension */
|
|
8
|
+
declare function getLangFromFilename(filename: string): string;
|
|
9
|
+
interface FileChangeRowProps {
|
|
10
|
+
path: string;
|
|
11
|
+
filename: string;
|
|
12
|
+
additions?: number;
|
|
13
|
+
deletions?: number;
|
|
14
|
+
/** Code block to highlight and render */
|
|
15
|
+
codeblock?: RawCode;
|
|
16
|
+
/** Extra annotation handlers for code */
|
|
17
|
+
handlers?: AnnotationHandler[];
|
|
18
|
+
/** Show copy button */
|
|
19
|
+
showCopy?: boolean;
|
|
20
|
+
/** Fallback children if no codeblock provided */
|
|
21
|
+
children?: React.ReactNode;
|
|
22
|
+
defaultOpen?: boolean;
|
|
23
|
+
className?: string;
|
|
24
|
+
}
|
|
25
|
+
declare function FileChangeRow({ path, filename, additions, deletions, codeblock, handlers: extraHandlers, showCopy, children, defaultOpen, className }: FileChangeRowProps);
|
|
26
|
+
interface FileChangeListProps {
|
|
27
|
+
title?: string;
|
|
28
|
+
count?: number;
|
|
29
|
+
children: React.ReactNode;
|
|
30
|
+
defaultOpen?: boolean;
|
|
31
|
+
className?: string;
|
|
32
|
+
}
|
|
33
|
+
declare function FileChangeList({ title, count, children, defaultOpen, className }: FileChangeListProps);
|
|
34
|
+
export { getLangFromFilename, StackedChevrons, FileChangeRowProps, FileChangeRow, FileChangeListProps, FileChangeList };
|