@orion-studios/payload-seo-audit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/README.md +127 -0
  2. package/bin/init.js +267 -0
  3. package/dist/api/backlinks-import.d.ts +4 -0
  4. package/dist/api/backlinks-import.d.ts.map +1 -0
  5. package/dist/api/backlinks-import.js +182 -0
  6. package/dist/api/cron.d.ts +4 -0
  7. package/dist/api/cron.d.ts.map +1 -0
  8. package/dist/api/cron.js +89 -0
  9. package/dist/api/index.d.ts +10 -0
  10. package/dist/api/index.d.ts.map +1 -0
  11. package/dist/api/index.js +21 -0
  12. package/dist/api/page-result.d.ts +4 -0
  13. package/dist/api/page-result.d.ts.map +1 -0
  14. package/dist/api/page-result.js +93 -0
  15. package/dist/api/page-results.d.ts +4 -0
  16. package/dist/api/page-results.d.ts.map +1 -0
  17. package/dist/api/page-results.js +83 -0
  18. package/dist/api/run-stream.d.ts +4 -0
  19. package/dist/api/run-stream.d.ts.map +1 -0
  20. package/dist/api/run-stream.js +273 -0
  21. package/dist/api/run.d.ts +4 -0
  22. package/dist/api/run.d.ts.map +1 -0
  23. package/dist/api/run.js +102 -0
  24. package/dist/api/snapshot-report.d.ts +4 -0
  25. package/dist/api/snapshot-report.d.ts.map +1 -0
  26. package/dist/api/snapshot-report.js +130 -0
  27. package/dist/api/snapshots.d.ts +4 -0
  28. package/dist/api/snapshots.d.ts.map +1 -0
  29. package/dist/api/snapshots.js +138 -0
  30. package/dist/api/trend.d.ts +4 -0
  31. package/dist/api/trend.d.ts.map +1 -0
  32. package/dist/api/trend.js +71 -0
  33. package/dist/collections/SeoAuthoritySnapshots.d.ts +3 -0
  34. package/dist/collections/SeoAuthoritySnapshots.d.ts.map +1 -0
  35. package/dist/collections/SeoAuthoritySnapshots.js +83 -0
  36. package/dist/collections/SeoKeywordVisibility.d.ts +3 -0
  37. package/dist/collections/SeoKeywordVisibility.d.ts.map +1 -0
  38. package/dist/collections/SeoKeywordVisibility.js +65 -0
  39. package/dist/collections/SeoPageResults.d.ts +3 -0
  40. package/dist/collections/SeoPageResults.d.ts.map +1 -0
  41. package/dist/collections/SeoPageResults.js +170 -0
  42. package/dist/collections/SeoSnapshots.d.ts +3 -0
  43. package/dist/collections/SeoSnapshots.d.ts.map +1 -0
  44. package/dist/collections/SeoSnapshots.js +131 -0
  45. package/dist/components/hooks/useSeoApi.d.ts +7 -0
  46. package/dist/components/hooks/useSeoApi.d.ts.map +1 -0
  47. package/dist/components/hooks/useSeoApi.js +31 -0
  48. package/dist/components/hooks/useSeoPageResults.d.ts +19 -0
  49. package/dist/components/hooks/useSeoPageResults.d.ts.map +1 -0
  50. package/dist/components/hooks/useSeoPageResults.js +62 -0
  51. package/dist/components/hooks/useSeoSnapshot.d.ts +8 -0
  52. package/dist/components/hooks/useSeoSnapshot.d.ts.map +1 -0
  53. package/dist/components/hooks/useSeoSnapshot.js +39 -0
  54. package/dist/components/hooks/useSeoTrend.d.ts +8 -0
  55. package/dist/components/hooks/useSeoTrend.d.ts.map +1 -0
  56. package/dist/components/hooks/useSeoTrend.js +38 -0
  57. package/dist/components/layout/SeoReportHeader.d.ts +10 -0
  58. package/dist/components/layout/SeoReportHeader.d.ts.map +1 -0
  59. package/dist/components/layout/SeoReportHeader.js +18 -0
  60. package/dist/components/layout/SeoReportShell.d.ts +9 -0
  61. package/dist/components/layout/SeoReportShell.d.ts.map +1 -0
  62. package/dist/components/layout/SeoReportShell.js +17 -0
  63. package/dist/components/pdf/PdfDownloadButton.d.ts +9 -0
  64. package/dist/components/pdf/PdfDownloadButton.d.ts.map +1 -0
  65. package/dist/components/pdf/PdfDownloadButton.js +80 -0
  66. package/dist/components/tables/IssueTable.d.ts +11 -0
  67. package/dist/components/tables/IssueTable.d.ts.map +1 -0
  68. package/dist/components/tables/IssueTable.js +121 -0
  69. package/dist/components/tables/PageResultsTable.d.ts +18 -0
  70. package/dist/components/tables/PageResultsTable.d.ts.map +1 -0
  71. package/dist/components/tables/PageResultsTable.js +96 -0
  72. package/dist/components/types.d.ts +107 -0
  73. package/dist/components/types.d.ts.map +1 -0
  74. package/dist/components/types.js +22 -0
  75. package/dist/components/utils/formatters.d.ts +15 -0
  76. package/dist/components/utils/formatters.d.ts.map +1 -0
  77. package/dist/components/utils/formatters.js +98 -0
  78. package/dist/components/utils/scoreHelpers.d.ts +17 -0
  79. package/dist/components/utils/scoreHelpers.d.ts.map +1 -0
  80. package/dist/components/utils/scoreHelpers.js +139 -0
  81. package/dist/components/views/SeoDashboard.d.ts +3 -0
  82. package/dist/components/views/SeoDashboard.d.ts.map +1 -0
  83. package/dist/components/views/SeoDashboard.js +239 -0
  84. package/dist/components/views/SeoPageReport.d.ts +3 -0
  85. package/dist/components/views/SeoPageReport.d.ts.map +1 -0
  86. package/dist/components/views/SeoPageReport.js +234 -0
  87. package/dist/components/views/SeoSnapshotReport.d.ts +3 -0
  88. package/dist/components/views/SeoSnapshotReport.d.ts.map +1 -0
  89. package/dist/components/views/SeoSnapshotReport.js +224 -0
  90. package/dist/components/visualization/CategoryScoreCard.d.ts +11 -0
  91. package/dist/components/visualization/CategoryScoreCard.d.ts.map +1 -0
  92. package/dist/components/visualization/CategoryScoreCard.js +17 -0
  93. package/dist/components/visualization/CategoryScoreGrid.d.ts +9 -0
  94. package/dist/components/visualization/CategoryScoreGrid.d.ts.map +1 -0
  95. package/dist/components/visualization/CategoryScoreGrid.js +32 -0
  96. package/dist/components/visualization/IssueCategoryChart.d.ts +8 -0
  97. package/dist/components/visualization/IssueCategoryChart.d.ts.map +1 -0
  98. package/dist/components/visualization/IssueCategoryChart.js +47 -0
  99. package/dist/components/visualization/MetricCard.d.ts +11 -0
  100. package/dist/components/visualization/MetricCard.d.ts.map +1 -0
  101. package/dist/components/visualization/MetricCard.js +17 -0
  102. package/dist/components/visualization/MetricCardRow.d.ts +7 -0
  103. package/dist/components/visualization/MetricCardRow.d.ts.map +1 -0
  104. package/dist/components/visualization/MetricCardRow.js +12 -0
  105. package/dist/components/visualization/ScoreBar.d.ts +11 -0
  106. package/dist/components/visualization/ScoreBar.d.ts.map +1 -0
  107. package/dist/components/visualization/ScoreBar.js +34 -0
  108. package/dist/components/visualization/ScoreGauge.d.ts +11 -0
  109. package/dist/components/visualization/ScoreGauge.d.ts.map +1 -0
  110. package/dist/components/visualization/ScoreGauge.js +28 -0
  111. package/dist/components/visualization/ScoreTrendChart.d.ts +9 -0
  112. package/dist/components/visualization/ScoreTrendChart.d.ts.map +1 -0
  113. package/dist/components/visualization/ScoreTrendChart.js +43 -0
  114. package/dist/components/visualization/SeverityBadge.d.ts +8 -0
  115. package/dist/components/visualization/SeverityBadge.d.ts.map +1 -0
  116. package/dist/components/visualization/SeverityBadge.js +14 -0
  117. package/dist/config.d.ts +38 -0
  118. package/dist/config.d.ts.map +1 -0
  119. package/dist/config.js +36 -0
  120. package/dist/exports/components.d.ts +4 -0
  121. package/dist/exports/components.d.ts.map +1 -0
  122. package/dist/exports/components.js +9 -0
  123. package/dist/globals/SeoDashboard.d.ts +3 -0
  124. package/dist/globals/SeoDashboard.d.ts.map +1 -0
  125. package/dist/globals/SeoDashboard.js +25 -0
  126. package/dist/index.d.ts +6 -0
  127. package/dist/index.d.ts.map +1 -0
  128. package/dist/index.js +39 -0
  129. package/dist/utilities/access.d.ts +8 -0
  130. package/dist/utilities/access.d.ts.map +1 -0
  131. package/dist/utilities/access.js +11 -0
  132. package/dist/utilities/auth.d.ts +7 -0
  133. package/dist/utilities/auth.d.ts.map +1 -0
  134. package/dist/utilities/auth.js +28 -0
  135. package/dist/utilities/checks.d.ts +3 -0
  136. package/dist/utilities/checks.d.ts.map +1 -0
  137. package/dist/utilities/checks.js +255 -0
  138. package/dist/utilities/crawler.d.ts +14 -0
  139. package/dist/utilities/crawler.d.ts.map +1 -0
  140. package/dist/utilities/crawler.js +152 -0
  141. package/dist/utilities/gsc.d.ts +15 -0
  142. package/dist/utilities/gsc.d.ts.map +1 -0
  143. package/dist/utilities/gsc.js +69 -0
  144. package/dist/utilities/helpers.d.ts +7 -0
  145. package/dist/utilities/helpers.d.ts.map +1 -0
  146. package/dist/utilities/helpers.js +44 -0
  147. package/dist/utilities/pagespeed.d.ts +3 -0
  148. package/dist/utilities/pagespeed.d.ts.map +1 -0
  149. package/dist/utilities/pagespeed.js +49 -0
  150. package/dist/utilities/providers.d.ts +3 -0
  151. package/dist/utilities/providers.d.ts.map +1 -0
  152. package/dist/utilities/providers.js +18 -0
  153. package/dist/utilities/runAudit.d.ts +14 -0
  154. package/dist/utilities/runAudit.d.ts.map +1 -0
  155. package/dist/utilities/runAudit.js +224 -0
  156. package/dist/utilities/scoring.d.ts +3 -0
  157. package/dist/utilities/scoring.d.ts.map +1 -0
  158. package/dist/utilities/scoring.js +45 -0
  159. package/dist/utilities/triggers.d.ts +3 -0
  160. package/dist/utilities/triggers.d.ts.map +1 -0
  161. package/dist/utilities/triggers.js +39 -0
  162. package/dist/utilities/types.d.ts +87 -0
  163. package/dist/utilities/types.d.ts.map +1 -0
  164. package/dist/utilities/types.js +2 -0
  165. package/package.json +63 -0
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ 'use client';
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.PdfDownloadButton = void 0;
38
+ const react_1 = __importStar(require("react"));
39
+ const PdfDownloadButton = ({ targetId, filename, label = 'Download PDF', }) => {
40
+ const [generating, setGenerating] = (0, react_1.useState)(false);
41
+ const handleDownload = (0, react_1.useCallback)(async () => {
42
+ const element = document.getElementById(targetId);
43
+ if (!element)
44
+ return;
45
+ setGenerating(true);
46
+ try {
47
+ const html2pdf = (await Promise.resolve().then(() => __importStar(require('html2pdf.js')))).default;
48
+ element.classList.add('seo-pdf-printing');
49
+ await html2pdf()
50
+ .set({
51
+ margin: [10, 10, 10, 10],
52
+ filename: `${filename}.pdf`,
53
+ image: { type: 'jpeg', quality: 0.95 },
54
+ html2canvas: {
55
+ scale: 2,
56
+ useCORS: true,
57
+ logging: false,
58
+ },
59
+ jsPDF: {
60
+ unit: 'mm',
61
+ format: 'a4',
62
+ orientation: 'portrait',
63
+ },
64
+ pagebreak: { mode: ['avoid-all', 'css', 'legacy'] },
65
+ })
66
+ .from(element)
67
+ .save();
68
+ element.classList.remove('seo-pdf-printing');
69
+ }
70
+ catch (err) {
71
+ console.error('PDF generation failed:', err);
72
+ element.classList.remove('seo-pdf-printing');
73
+ }
74
+ finally {
75
+ setGenerating(false);
76
+ }
77
+ }, [targetId, filename]);
78
+ return (react_1.default.createElement("button", { type: "button", onClick: () => void handleDownload(), disabled: generating, className: "rounded-md border border-slate-300 bg-white px-3 py-2 text-sm text-slate-700 hover:bg-slate-50 disabled:opacity-60" }, generating ? 'Generating...' : label));
79
+ };
80
+ exports.PdfDownloadButton = PdfDownloadButton;
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import type { IssueWithUrl } from '../types';
3
+ type IssueTableProps = {
4
+ issues: IssueWithUrl[];
5
+ showUrl?: boolean;
6
+ showCategory?: boolean;
7
+ pageSize?: number;
8
+ };
9
+ export declare const IssueTable: React.FC<IssueTableProps>;
10
+ export {};
11
+ //# sourceMappingURL=IssueTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IssueTable.d.ts","sourceRoot":"","sources":["../../../src/components/tables/IssueTable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA4B,MAAM,OAAO,CAAA;AAGhD,OAAO,KAAK,EAAoB,YAAY,EAAE,MAAM,UAAU,CAAA;AAG9D,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,YAAY,EAAE,CAAA;IACtB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA2KhD,CAAA"}
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ 'use client';
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.IssueTable = void 0;
38
+ const react_1 = __importStar(require("react"));
39
+ const SeverityBadge_1 = require("../visualization/SeverityBadge");
40
+ const types_1 = require("../types");
41
+ const formatters_1 = require("../utils/formatters");
42
+ const IssueTable = ({ issues, showUrl = true, showCategory = true, pageSize = 15, }) => {
43
+ const [severityFilter, setSeverityFilter] = (0, react_1.useState)('all');
44
+ const [categoryFilter, setCategoryFilter] = (0, react_1.useState)('all');
45
+ const [searchText, setSearchText] = (0, react_1.useState)('');
46
+ const [page, setPage] = (0, react_1.useState)(1);
47
+ const [expandedIndex, setExpandedIndex] = (0, react_1.useState)(null);
48
+ const filtered = (0, react_1.useMemo)(() => {
49
+ return issues.filter((issue) => {
50
+ if (severityFilter !== 'all' && issue.severity !== severityFilter)
51
+ return false;
52
+ if (categoryFilter !== 'all' && issue.category !== categoryFilter)
53
+ return false;
54
+ if (searchText) {
55
+ const search = searchText.toLowerCase();
56
+ const matchesMessage = issue.message?.toLowerCase().includes(search);
57
+ const matchesUrl = issue.url?.toLowerCase().includes(search);
58
+ if (!matchesMessage && !matchesUrl)
59
+ return false;
60
+ }
61
+ return true;
62
+ });
63
+ }, [issues, severityFilter, categoryFilter, searchText]);
64
+ const totalPages = Math.max(1, Math.ceil(filtered.length / pageSize));
65
+ const currentPage = Math.min(page, totalPages);
66
+ const paginated = filtered.slice((currentPage - 1) * pageSize, currentPage * pageSize);
67
+ if (issues.length === 0) {
68
+ return (react_1.default.createElement("div", { className: "flex h-24 items-center justify-center rounded-lg border border-slate-200 bg-slate-50 dark:border-slate-700 dark:bg-slate-800" },
69
+ react_1.default.createElement("p", { className: "text-sm text-slate-500 dark:text-slate-400" }, "No issues found.")));
70
+ }
71
+ return (react_1.default.createElement("div", { className: "space-y-3" },
72
+ react_1.default.createElement("div", { className: "flex flex-wrap items-center gap-2" },
73
+ react_1.default.createElement("select", { value: severityFilter, onChange: (e) => { setSeverityFilter(e.target.value); setPage(1); }, className: "rounded-md border border-slate-200 bg-white px-2.5 py-1.5 text-sm text-slate-700 focus:border-slate-400 focus:outline-none dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300" },
74
+ react_1.default.createElement("option", { value: "all" }, "All Severities"),
75
+ types_1.SEVERITY_ORDER.map((s) => (react_1.default.createElement("option", { key: s, value: s }, s.charAt(0).toUpperCase() + s.slice(1))))),
76
+ showCategory && (react_1.default.createElement("select", { value: categoryFilter, onChange: (e) => { setCategoryFilter(e.target.value); setPage(1); }, className: "rounded-md border border-slate-200 bg-white px-2.5 py-1.5 text-sm text-slate-700 focus:border-slate-400 focus:outline-none dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300" },
77
+ react_1.default.createElement("option", { value: "all" }, "All Categories"),
78
+ Object.entries(types_1.CATEGORY_LABELS).map(([key, label]) => (react_1.default.createElement("option", { key: key, value: key }, label))))),
79
+ react_1.default.createElement("input", { type: "text", placeholder: "Search issues...", value: searchText, onChange: (e) => { setSearchText(e.target.value); setPage(1); }, className: "rounded-md border border-slate-200 bg-white px-2.5 py-1.5 text-sm text-slate-700 placeholder:text-slate-400 focus:border-slate-400 focus:outline-none dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300 dark:placeholder:text-slate-500" }),
80
+ react_1.default.createElement("span", { className: "ml-auto text-xs text-slate-500 dark:text-slate-400" },
81
+ filtered.length,
82
+ " issue",
83
+ filtered.length !== 1 ? 's' : '')),
84
+ react_1.default.createElement("div", { className: "overflow-x-auto rounded-lg border border-slate-200 dark:border-slate-700" },
85
+ react_1.default.createElement("table", { className: "w-full text-sm" },
86
+ react_1.default.createElement("thead", null,
87
+ react_1.default.createElement("tr", { className: "border-b border-slate-200 bg-slate-50 dark:border-slate-700 dark:bg-slate-800" },
88
+ react_1.default.createElement("th", { className: "px-3 py-2 text-left font-medium text-slate-600 dark:text-slate-400" }, "Severity"),
89
+ showCategory && (react_1.default.createElement("th", { className: "px-3 py-2 text-left font-medium text-slate-600 dark:text-slate-400" }, "Category")),
90
+ showUrl && (react_1.default.createElement("th", { className: "px-3 py-2 text-left font-medium text-slate-600 dark:text-slate-400" }, "URL")),
91
+ react_1.default.createElement("th", { className: "px-3 py-2 text-left font-medium text-slate-600 dark:text-slate-400" }, "Issue"))),
92
+ react_1.default.createElement("tbody", null, paginated.map((issue, idx) => {
93
+ const globalIdx = (currentPage - 1) * pageSize + idx;
94
+ const isExpanded = expandedIndex === globalIdx;
95
+ return (react_1.default.createElement(react_1.default.Fragment, { key: `${issue.fingerprint || issue.message}-${idx}` },
96
+ react_1.default.createElement("tr", { className: `border-b border-slate-100 transition-colors hover:bg-slate-50 dark:border-slate-700 dark:hover:bg-slate-800 ${issue.recommendation ? 'cursor-pointer' : ''}`, onClick: () => {
97
+ if (issue.recommendation) {
98
+ setExpandedIndex(isExpanded ? null : globalIdx);
99
+ }
100
+ } },
101
+ react_1.default.createElement("td", { className: "px-3 py-2.5" },
102
+ react_1.default.createElement(SeverityBadge_1.SeverityBadge, { severity: issue.severity })),
103
+ showCategory && (react_1.default.createElement("td", { className: "px-3 py-2.5 text-slate-600 dark:text-slate-400" }, types_1.CATEGORY_LABELS[issue.category] || issue.category)),
104
+ showUrl && (react_1.default.createElement("td", { className: "px-3 py-2.5" },
105
+ react_1.default.createElement("span", { className: "text-xs text-blue-600 dark:text-blue-400", title: issue.url }, (0, formatters_1.truncateUrl)(issue.url || '', 40)))),
106
+ react_1.default.createElement("td", { className: "px-3 py-2.5 text-slate-800 dark:text-slate-200" }, issue.message)),
107
+ isExpanded && issue.recommendation && (react_1.default.createElement("tr", { className: "border-b border-slate-100 dark:border-slate-700" },
108
+ react_1.default.createElement("td", { colSpan: 1 + (showCategory ? 1 : 0) + (showUrl ? 1 : 0) + 1, className: "bg-blue-50 px-4 py-3 dark:bg-blue-900/30" },
109
+ react_1.default.createElement("p", { className: "text-xs font-medium uppercase tracking-wide text-blue-600 dark:text-blue-400" }, "Recommendation"),
110
+ react_1.default.createElement("p", { className: "mt-1 text-sm text-blue-900 dark:text-blue-300" }, issue.recommendation))))));
111
+ })))),
112
+ totalPages > 1 && (react_1.default.createElement("div", { className: "flex items-center justify-between" },
113
+ react_1.default.createElement("button", { type: "button", onClick: () => setPage(Math.max(1, currentPage - 1)), disabled: !filtered.length || currentPage <= 1, className: "rounded-md border border-slate-200 bg-white px-3 py-1.5 text-sm text-slate-600 disabled:opacity-50 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300" }, "Previous"),
114
+ react_1.default.createElement("span", { className: "text-xs text-slate-500 dark:text-slate-400" },
115
+ "Page ",
116
+ currentPage,
117
+ " of ",
118
+ totalPages),
119
+ react_1.default.createElement("button", { type: "button", onClick: () => setPage(Math.min(totalPages, currentPage + 1)), disabled: currentPage >= totalPages, className: "rounded-md border border-slate-200 bg-white px-3 py-1.5 text-sm text-slate-600 disabled:opacity-50 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300" }, "Next")))));
120
+ };
121
+ exports.IssueTable = IssueTable;
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import type { SEOPageResult } from '../types';
3
+ type PageResultsTableProps = {
4
+ docs: SEOPageResult[];
5
+ pagination: {
6
+ totalDocs: number;
7
+ totalPages: number;
8
+ page: number;
9
+ hasNextPage: boolean;
10
+ hasPrevPage: boolean;
11
+ };
12
+ loading: boolean;
13
+ onPageChange: (page: number) => void;
14
+ onSelectPage: (pageResult: SEOPageResult) => void;
15
+ };
16
+ export declare const PageResultsTable: React.FC<PageResultsTableProps>;
17
+ export {};
18
+ //# sourceMappingURL=PageResultsTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageResultsTable.d.ts","sourceRoot":"","sources":["../../../src/components/tables/PageResultsTable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmB,MAAM,OAAO,CAAA;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAK7C,KAAK,qBAAqB,GAAG;IAC3B,IAAI,EAAE,aAAa,EAAE,CAAA;IACrB,UAAU,EAAE;QACV,SAAS,EAAE,MAAM,CAAA;QACjB,UAAU,EAAE,MAAM,CAAA;QAClB,IAAI,EAAE,MAAM,CAAA;QACZ,WAAW,EAAE,OAAO,CAAA;QACpB,WAAW,EAAE,OAAO,CAAA;KACrB,CAAA;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,YAAY,EAAE,CAAC,UAAU,EAAE,aAAa,KAAK,IAAI,CAAA;CAClD,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAsI5D,CAAA"}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ 'use client';
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.PageResultsTable = void 0;
38
+ const react_1 = __importStar(require("react"));
39
+ const scoreHelpers_1 = require("../utils/scoreHelpers");
40
+ const formatters_1 = require("../utils/formatters");
41
+ const SeverityBadge_1 = require("../visualization/SeverityBadge");
42
+ const PageResultsTable = ({ docs, pagination, loading, onPageChange, onSelectPage, }) => {
43
+ const [searchText, setSearchText] = (0, react_1.useState)('');
44
+ const filtered = searchText
45
+ ? docs.filter((d) => d.url.toLowerCase().includes(searchText.toLowerCase()) ||
46
+ d.title?.toLowerCase().includes(searchText.toLowerCase()))
47
+ : docs;
48
+ if (!loading && docs.length === 0) {
49
+ return (react_1.default.createElement("div", { className: "flex h-24 items-center justify-center rounded-lg border border-slate-200 bg-slate-50 dark:border-slate-700 dark:bg-slate-800" },
50
+ react_1.default.createElement("p", { className: "text-sm text-slate-500 dark:text-slate-400" }, "No page results available.")));
51
+ }
52
+ const countSeverity = (issues, severity) => (issues || []).filter((i) => i.severity === severity).length;
53
+ return (react_1.default.createElement("div", { className: "space-y-3" },
54
+ react_1.default.createElement("div", { className: "flex items-center gap-2" },
55
+ react_1.default.createElement("input", { type: "text", placeholder: "Filter pages...", value: searchText, onChange: (e) => setSearchText(e.target.value), className: "rounded-md border border-slate-200 bg-white px-2.5 py-1.5 text-sm text-slate-700 placeholder:text-slate-400 focus:border-slate-400 focus:outline-none dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300 dark:placeholder:text-slate-500" }),
56
+ react_1.default.createElement("span", { className: "ml-auto text-xs text-slate-500 dark:text-slate-400" },
57
+ pagination.totalDocs,
58
+ " page",
59
+ pagination.totalDocs !== 1 ? 's' : '',
60
+ " total")),
61
+ react_1.default.createElement("div", { className: "overflow-x-auto rounded-lg border border-slate-200 dark:border-slate-700" },
62
+ react_1.default.createElement("table", { className: "w-full text-sm" },
63
+ react_1.default.createElement("thead", null,
64
+ react_1.default.createElement("tr", { className: "border-b border-slate-200 bg-slate-50 dark:border-slate-700 dark:bg-slate-800" },
65
+ react_1.default.createElement("th", { className: "px-3 py-2 text-left font-medium text-slate-600 dark:text-slate-400" }, "Page"),
66
+ react_1.default.createElement("th", { className: "px-3 py-2 text-center font-medium text-slate-600 dark:text-slate-400" }, "Score"),
67
+ react_1.default.createElement("th", { className: "px-3 py-2 text-center font-medium text-slate-600 dark:text-slate-400" }, "Issues"),
68
+ react_1.default.createElement("th", { className: "px-3 py-2 text-left font-medium text-slate-600 dark:text-slate-400" }, "Title"))),
69
+ react_1.default.createElement("tbody", null, loading ? (react_1.default.createElement("tr", null,
70
+ react_1.default.createElement("td", { colSpan: 4, className: "px-3 py-8 text-center text-slate-500 dark:text-slate-400" }, "Loading..."))) : (filtered.map((doc) => {
71
+ const score = doc.overallScore ?? 0;
72
+ const criticalCount = countSeverity(doc.issues, 'critical');
73
+ const highCount = countSeverity(doc.issues, 'high');
74
+ const totalIssues = (doc.issues || []).length;
75
+ return (react_1.default.createElement("tr", { key: doc.id, className: "cursor-pointer border-b border-slate-100 transition-colors hover:bg-slate-50 dark:border-slate-700 dark:hover:bg-slate-800", onClick: () => onSelectPage(doc) },
76
+ react_1.default.createElement("td", { className: "px-3 py-2.5" },
77
+ react_1.default.createElement("span", { className: "text-blue-600 dark:text-blue-400", title: doc.url }, (0, formatters_1.truncateUrl)(doc.url, 50))),
78
+ react_1.default.createElement("td", { className: "px-3 py-2.5 text-center" },
79
+ react_1.default.createElement("span", { className: `inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold ${(0, scoreHelpers_1.getScoreBgClass)(score)} ${(0, scoreHelpers_1.getScoreTextClass)(score)}` }, (0, formatters_1.formatScore)(score))),
80
+ react_1.default.createElement("td", { className: "px-3 py-2.5 text-center" },
81
+ react_1.default.createElement("div", { className: "flex items-center justify-center gap-1" },
82
+ criticalCount > 0 && (react_1.default.createElement(SeverityBadge_1.SeverityBadge, { severity: "critical", className: "text-[10px]" })),
83
+ highCount > 0 && (react_1.default.createElement(SeverityBadge_1.SeverityBadge, { severity: "high", className: "text-[10px]" })),
84
+ totalIssues > 0 && (react_1.default.createElement("span", { className: "text-xs text-slate-500 dark:text-slate-400" }, totalIssues)))),
85
+ react_1.default.createElement("td", { className: "max-w-[200px] truncate px-3 py-2.5 text-slate-600 dark:text-slate-400" }, doc.title || '-')));
86
+ }))))),
87
+ pagination.totalPages > 1 && (react_1.default.createElement("div", { className: "flex items-center justify-between" },
88
+ react_1.default.createElement("button", { type: "button", onClick: () => onPageChange(pagination.page - 1), disabled: !pagination.hasPrevPage || loading, className: "rounded-md border border-slate-200 bg-white px-3 py-1.5 text-sm text-slate-600 disabled:opacity-50 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300" }, "Previous"),
89
+ react_1.default.createElement("span", { className: "text-xs text-slate-500 dark:text-slate-400" },
90
+ "Page ",
91
+ pagination.page,
92
+ " of ",
93
+ pagination.totalPages),
94
+ react_1.default.createElement("button", { type: "button", onClick: () => onPageChange(pagination.page + 1), disabled: !pagination.hasNextPage || loading, className: "rounded-md border border-slate-200 bg-white px-3 py-1.5 text-sm text-slate-600 disabled:opacity-50 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300" }, "Next")))));
95
+ };
96
+ exports.PageResultsTable = PageResultsTable;
@@ -0,0 +1,107 @@
1
+ export type SEOIssueSeverity = 'critical' | 'high' | 'medium' | 'low' | 'info';
2
+ export type SEOIssueCategory = 'metadata' | 'indexability' | 'structure' | 'links' | 'media' | 'structuredData' | 'performance';
3
+ export type SEOIssue = {
4
+ id?: string | number;
5
+ fingerprint: string;
6
+ ruleID: string;
7
+ category: SEOIssueCategory;
8
+ severity: SEOIssueSeverity;
9
+ message: string;
10
+ recommendation?: string | null;
11
+ };
12
+ export type SEOScores = {
13
+ overall?: number | null;
14
+ metadata?: number | null;
15
+ indexability?: number | null;
16
+ structure?: number | null;
17
+ links?: number | null;
18
+ media?: number | null;
19
+ structuredData?: number | null;
20
+ performance?: number | null;
21
+ };
22
+ export type SEOIssueCounts = {
23
+ critical?: number | null;
24
+ high?: number | null;
25
+ medium?: number | null;
26
+ low?: number | null;
27
+ info?: number | null;
28
+ };
29
+ export type SEOMetrics = {
30
+ pagesCrawled?: number | null;
31
+ pagesChecked?: number | null;
32
+ avgLighthousePerformance?: number | null;
33
+ avgLCPMs?: number | null;
34
+ avgCLS?: number | null;
35
+ };
36
+ export type SEOSnapshot = {
37
+ id: number | string;
38
+ runLabel?: string | null;
39
+ runType?: string | null;
40
+ status?: string | null;
41
+ startedAt?: string | null;
42
+ completedAt?: string | null;
43
+ scores?: SEOScores | null;
44
+ metrics?: SEOMetrics | null;
45
+ issueCounts?: SEOIssueCounts | null;
46
+ summary?: string | null;
47
+ errorMessage?: string | null;
48
+ };
49
+ export type SEOPageResult = {
50
+ id: number | string;
51
+ snapshot?: number | string | SEOSnapshot | null;
52
+ site?: number | string | null;
53
+ url: string;
54
+ path?: string | null;
55
+ statusCode?: number | null;
56
+ title?: string | null;
57
+ metaDescription?: string | null;
58
+ canonical?: string | null;
59
+ robotsMeta?: string | null;
60
+ h1Count?: number | null;
61
+ headingOrderIssues?: number | null;
62
+ internalLinks?: number | null;
63
+ externalLinks?: number | null;
64
+ imagesTotal?: number | null;
65
+ imagesMissingAlt?: number | null;
66
+ structuredDataBlocks?: number | null;
67
+ scoreBreakdown?: Omit<SEOScores, 'overall' | 'performance'> | null;
68
+ overallScore?: number | null;
69
+ issues?: SEOIssue[] | null;
70
+ checkedAt?: string | null;
71
+ };
72
+ export type SEOTrendPoint = {
73
+ snapshotId: number | string;
74
+ startedAt: string;
75
+ runLabel: string;
76
+ scores: SEOScores;
77
+ issueCounts: SEOIssueCounts;
78
+ metrics: SEOMetrics;
79
+ };
80
+ export type SEOSnapshotReportData = {
81
+ snapshot: SEOSnapshot;
82
+ pageResults: SEOPageResult[];
83
+ aggregated: {
84
+ worstPages: Array<{
85
+ url: string;
86
+ score: number;
87
+ issueCount: number;
88
+ }>;
89
+ bestPages: Array<{
90
+ url: string;
91
+ score: number;
92
+ }>;
93
+ categoryDistribution: Record<string, number>;
94
+ severityDistribution: Record<string, number>;
95
+ scoreHistogram: Array<{
96
+ range: string;
97
+ count: number;
98
+ }>;
99
+ };
100
+ };
101
+ export type IssueWithUrl = SEOIssue & {
102
+ url?: string;
103
+ };
104
+ export declare const CATEGORY_LABELS: Record<SEOIssueCategory, string>;
105
+ export declare const SEVERITY_ORDER: SEOIssueSeverity[];
106
+ export declare const CATEGORY_WEIGHTS: Record<SEOIssueCategory, number>;
107
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/components/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CATEGORY_WEIGHTS = exports.SEVERITY_ORDER = exports.CATEGORY_LABELS = void 0;
4
+ exports.CATEGORY_LABELS = {
5
+ metadata: 'Metadata',
6
+ indexability: 'Indexability',
7
+ structure: 'Structure',
8
+ links: 'Links',
9
+ media: 'Media',
10
+ structuredData: 'Structured Data',
11
+ performance: 'Performance',
12
+ };
13
+ exports.SEVERITY_ORDER = ['critical', 'high', 'medium', 'low', 'info'];
14
+ exports.CATEGORY_WEIGHTS = {
15
+ metadata: 0.2,
16
+ indexability: 0.2,
17
+ structure: 0.15,
18
+ links: 0.1,
19
+ media: 0.1,
20
+ structuredData: 0.1,
21
+ performance: 0.15,
22
+ };
@@ -0,0 +1,15 @@
1
+ export declare const formatTimestamp: (value?: string | null) => string;
2
+ export declare const formatDate: (value?: string | null) => string;
3
+ export declare const formatScore: (value?: number | null) => string;
4
+ export declare const formatMs: (value?: number | null) => string;
5
+ export declare const formatCLS: (value?: number | null) => string;
6
+ export declare const formatPercentage: (value?: number | null) => string;
7
+ export declare const truncateUrl: (url: string, maxLength?: number) => string;
8
+ export declare const getPathFromUrl: (url: string) => string;
9
+ export declare const formatCharCount: (text: string | null | undefined, min: number, max: number) => {
10
+ count: number;
11
+ status: "good" | "warning" | "error";
12
+ label: string;
13
+ };
14
+ export declare const formatNumber: (value?: number | null) => string;
15
+ //# sourceMappingURL=formatters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.d.ts","sourceRoot":"","sources":["../../../src/components/utils/formatters.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,GAAG,IAAI,KAAG,MAWvD,CAAA;AAED,eAAO,MAAM,UAAU,GAAI,QAAQ,MAAM,GAAG,IAAI,KAAG,MASlD,CAAA;AAED,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,GAAG,IAAI,KAAG,MAGnD,CAAA;AAED,eAAO,MAAM,QAAQ,GAAI,QAAQ,MAAM,GAAG,IAAI,KAAG,MAIhD,CAAA;AAED,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,GAAG,IAAI,KAAG,MAGjD,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,QAAQ,MAAM,GAAG,IAAI,KAAG,MAGxD,CAAA;AAED,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,EAAE,kBAAc,KAAG,MAUzD,CAAA;AAED,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,MAM5C,CAAA;AAED,eAAO,MAAM,eAAe,GAC1B,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,KAAK,MAAM,EACX,KAAK,MAAM,KACV;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAMtE,CAAA;AAED,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,GAAG,IAAI,KAAG,MAGpD,CAAA"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatNumber = exports.formatCharCount = exports.getPathFromUrl = exports.truncateUrl = exports.formatPercentage = exports.formatCLS = exports.formatMs = exports.formatScore = exports.formatDate = exports.formatTimestamp = void 0;
4
+ const formatTimestamp = (value) => {
5
+ if (!value)
6
+ return 'N/A';
7
+ const date = new Date(value);
8
+ if (Number.isNaN(date.getTime()))
9
+ return value;
10
+ return date.toLocaleDateString('en-US', {
11
+ month: 'short',
12
+ day: 'numeric',
13
+ year: 'numeric',
14
+ hour: 'numeric',
15
+ minute: '2-digit',
16
+ });
17
+ };
18
+ exports.formatTimestamp = formatTimestamp;
19
+ const formatDate = (value) => {
20
+ if (!value)
21
+ return 'N/A';
22
+ const date = new Date(value);
23
+ if (Number.isNaN(date.getTime()))
24
+ return value;
25
+ return date.toLocaleDateString('en-US', {
26
+ month: 'short',
27
+ day: 'numeric',
28
+ year: 'numeric',
29
+ });
30
+ };
31
+ exports.formatDate = formatDate;
32
+ const formatScore = (value) => {
33
+ if (value == null)
34
+ return '-';
35
+ return String(Math.round(value));
36
+ };
37
+ exports.formatScore = formatScore;
38
+ const formatMs = (value) => {
39
+ if (value == null)
40
+ return '-';
41
+ if (value >= 1000)
42
+ return `${(value / 1000).toFixed(1)}s`;
43
+ return `${Math.round(value)}ms`;
44
+ };
45
+ exports.formatMs = formatMs;
46
+ const formatCLS = (value) => {
47
+ if (value == null)
48
+ return '-';
49
+ return value.toFixed(3);
50
+ };
51
+ exports.formatCLS = formatCLS;
52
+ const formatPercentage = (value) => {
53
+ if (value == null)
54
+ return '-';
55
+ return `${Math.round(value)}%`;
56
+ };
57
+ exports.formatPercentage = formatPercentage;
58
+ const truncateUrl = (url, maxLength = 50) => {
59
+ if (url.length <= maxLength)
60
+ return url;
61
+ try {
62
+ const parsed = new URL(url);
63
+ const path = parsed.pathname + parsed.search;
64
+ if (path.length <= maxLength)
65
+ return path;
66
+ return path.slice(0, maxLength - 3) + '...';
67
+ }
68
+ catch {
69
+ return url.slice(0, maxLength - 3) + '...';
70
+ }
71
+ };
72
+ exports.truncateUrl = truncateUrl;
73
+ const getPathFromUrl = (url) => {
74
+ try {
75
+ return new URL(url).pathname;
76
+ }
77
+ catch {
78
+ return url;
79
+ }
80
+ };
81
+ exports.getPathFromUrl = getPathFromUrl;
82
+ const formatCharCount = (text, min, max) => {
83
+ const count = text?.length ?? 0;
84
+ if (count === 0)
85
+ return { count, status: 'error', label: 'Missing' };
86
+ if (count < min)
87
+ return { count, status: 'warning', label: `Too short (${min}-${max})` };
88
+ if (count > max)
89
+ return { count, status: 'warning', label: `Too long (${min}-${max})` };
90
+ return { count, status: 'good', label: `Good (${min}-${max})` };
91
+ };
92
+ exports.formatCharCount = formatCharCount;
93
+ const formatNumber = (value) => {
94
+ if (value == null)
95
+ return '-';
96
+ return value.toLocaleString();
97
+ };
98
+ exports.formatNumber = formatNumber;
@@ -0,0 +1,17 @@
1
+ export declare const getScoreColor: (score: number) => string;
2
+ export declare const getScoreBgClass: (score: number) => string;
3
+ export declare const getScoreTextClass: (score: number) => string;
4
+ export declare const getScoreBarColorClass: (score: number) => string;
5
+ export declare const getScoreGrade: (score: number) => string;
6
+ export declare const getGradeColorClass: (grade: string) => string;
7
+ export declare const getSeverityColorClasses: (severity: string) => {
8
+ badge: string;
9
+ text: string;
10
+ bg: string;
11
+ };
12
+ export declare const getSeverityBarColor: (severity: string) => string;
13
+ export declare const getDeltaDisplay: (current: number, previous?: number | null) => {
14
+ text: string;
15
+ className: string;
16
+ } | null;
17
+ //# sourceMappingURL=scoreHelpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoreHelpers.d.ts","sourceRoot":"","sources":["../../../src/components/utils/scoreHelpers.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,MAM7C,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,KAAG,MAM/C,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,KAAG,MAMjD,CAAA;AAED,eAAO,MAAM,qBAAqB,GAAI,OAAO,MAAM,KAAG,MAMrD,CAAA;AAED,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,MAM7C,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,KAAG,MAalD,CAAA;AAED,eAAO,MAAM,uBAAuB,GAClC,UAAU,MAAM,KACf;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAiC3C,CAAA;AAED,eAAO,MAAM,mBAAmB,GAAI,UAAU,MAAM,KAAG,MAatD,CAAA;AAED,eAAO,MAAM,eAAe,GAC1B,SAAS,MAAM,EACf,WAAW,MAAM,GAAG,IAAI,KACvB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAMxC,CAAA"}