@alpaca-editor/core 1.0.4134 → 1.0.4140
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/config/config.js +7 -0
- package/dist/config/config.js.map +1 -1
- package/dist/editor/FieldListField.js +3 -4
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/Terminal.js +1 -1
- package/dist/editor/Terminal.js.map +1 -1
- package/dist/editor/Titlebar.js +0 -1
- package/dist/editor/Titlebar.js.map +1 -1
- package/dist/editor/ai/AgentCostDisplay.d.ts +3 -1
- package/dist/editor/ai/AgentCostDisplay.js +26 -2
- package/dist/editor/ai/AgentCostDisplay.js.map +1 -1
- package/dist/editor/ai/AgentStatusBadge.d.ts +26 -0
- package/dist/editor/ai/AgentStatusBadge.js +110 -0
- package/dist/editor/ai/AgentStatusBadge.js.map +1 -0
- package/dist/editor/ai/AgentTerminal.js +289 -198
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/Agents.d.ts +2 -2
- package/dist/editor/ai/Agents.js +115 -19
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.js +259 -45
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/ContextInfoBar.js +124 -113
- package/dist/editor/ai/ContextInfoBar.js.map +1 -1
- package/dist/editor/ai/ToolCallDisplay.d.ts +1 -0
- package/dist/editor/ai/ToolCallDisplay.js +70 -58
- package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
- package/dist/editor/ai/useAgentStatus.d.ts +13 -0
- package/dist/editor/ai/useAgentStatus.js +101 -0
- package/dist/editor/ai/useAgentStatus.js.map +1 -0
- package/dist/editor/client/EditorShell.js +23 -8
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/itemsRepository.js.map +1 -1
- package/dist/editor/commands/localizeItem/LocalizeItemDialog.js +5 -5
- package/dist/editor/commands/localizeItem/LocalizeItemDialog.js.map +1 -1
- package/dist/editor/control-center/About.js +1 -1
- package/dist/editor/control-center/About.js.map +1 -1
- package/dist/editor/control-center/AllAgentsPanel.d.ts +5 -0
- package/dist/editor/control-center/AllAgentsPanel.js +126 -0
- package/dist/editor/control-center/AllAgentsPanel.js.map +1 -0
- package/dist/editor/control-center/WebSocketMessages.js +1 -0
- package/dist/editor/control-center/WebSocketMessages.js.map +1 -1
- package/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.js +42 -7
- package/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.js.map +1 -1
- package/dist/editor/media-selector/AiImageSearch.d.ts +1 -1
- package/dist/editor/media-selector/AiImageSearch.js +162 -103
- package/dist/editor/media-selector/AiImageSearch.js.map +1 -1
- package/dist/editor/media-selector/TreeSelector.js +20 -4
- package/dist/editor/media-selector/TreeSelector.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/UtilityControls.js +5 -2
- package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.d.ts +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +7 -5
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
- package/dist/editor/page-viewer/DeviceToolbar.js +2 -2
- package/dist/editor/page-viewer/DeviceToolbar.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +18 -11
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +53 -48
- package/dist/editor/services/agentService.js +137 -79
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/aiService.d.ts +1 -1
- package/dist/editor/services/editService.js +1 -0
- package/dist/editor/services/editService.js.map +1 -1
- package/dist/editor/sidebar/GraphQL.js +20 -7
- package/dist/editor/sidebar/GraphQL.js.map +1 -1
- package/dist/editor/sidebar/SEOInfo.js +1 -2
- package/dist/editor/sidebar/SEOInfo.js.map +1 -1
- package/dist/editor/sidebar/Translations.js +10 -7
- package/dist/editor/sidebar/Translations.js.map +1 -1
- package/dist/editor/ui/ItemNameDialogNew.js +1 -1
- package/dist/editor/ui/ItemSearch.js +10 -4
- package/dist/editor/ui/ItemSearch.js.map +1 -1
- package/dist/page-wizard/steps/CollectStep.js +2 -2
- package/dist/page-wizard/steps/CollectStep.js.map +1 -1
- package/dist/page-wizard/steps/FieldEditor.js +2 -2
- package/dist/page-wizard/steps/FieldEditor.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/splash-screen/NewPage.js +2 -2
- package/dist/splash-screen/NewPage.js.map +1 -1
- package/dist/splash-screen/RecentPages.js +1 -1
- package/dist/splash-screen/RecentPages.js.map +1 -1
- package/dist/styles.css +167 -22
- package/dist/tour/Tour.js +15 -11
- package/dist/tour/Tour.js.map +1 -1
- package/package.json +1 -1
- package/src/config/config.tsx +7 -0
- package/src/editor/FieldListField.tsx +13 -13
- package/src/editor/Terminal.tsx +1 -1
- package/src/editor/Titlebar.tsx +0 -1
- package/src/editor/ai/AgentCostDisplay.tsx +57 -1
- package/src/editor/ai/AgentStatusBadge.tsx +144 -0
- package/src/editor/ai/AgentTerminal.tsx +345 -219
- package/src/editor/ai/Agents.tsx +179 -30
- package/src/editor/ai/AiResponseMessage.tsx +411 -114
- package/src/editor/ai/ContextInfoBar.tsx +134 -131
- package/src/editor/ai/ToolCallDisplay.tsx +217 -176
- package/src/editor/ai/useAgentStatus.ts +123 -0
- package/src/editor/client/EditorShell.tsx +34 -8
- package/src/editor/client/itemsRepository.ts +1 -2
- package/src/editor/commands/localizeItem/LocalizeItemDialog.tsx +5 -5
- package/src/editor/control-center/About.tsx +0 -14
- package/src/editor/control-center/AllAgentsPanel.tsx +300 -0
- package/src/editor/control-center/WebSocketMessages.tsx +1 -0
- package/src/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.tsx +49 -8
- package/src/editor/media-selector/AiImageSearch.tsx +162 -172
- package/src/editor/media-selector/TreeSelector.tsx +137 -116
- package/src/editor/menubar/toolbar-sections/UtilityControls.tsx +9 -1
- package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +7 -4
- package/src/editor/page-viewer/DeviceToolbar.tsx +15 -11
- package/src/editor/page-viewer/PageViewerFrame.tsx +20 -14
- package/src/editor/services/agentService.ts +217 -129
- package/src/editor/services/aiService.ts +2 -2
- package/src/editor/services/editService.ts +1 -0
- package/src/editor/sidebar/GraphQL.tsx +143 -117
- package/src/editor/sidebar/SEOInfo.tsx +1 -2
- package/src/editor/sidebar/Translations.tsx +14 -12
- package/src/editor/ui/ItemNameDialogNew.tsx +1 -1
- package/src/editor/ui/ItemSearch.tsx +11 -4
- package/src/editor/ui/SimpleTabs.tsx +1 -1
- package/src/page-wizard/steps/CollectStep.tsx +2 -2
- package/src/page-wizard/steps/FieldEditor.tsx +13 -15
- package/src/revision.ts +2 -2
- package/src/splash-screen/NewPage.tsx +2 -2
- package/src/splash-screen/RecentPages.tsx +1 -1
- package/src/tour/Tour.tsx +61 -48
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { Tooltip } from "primereact/tooltip";
|
|
2
|
-
|
|
3
1
|
import { useEditContext, useFieldsEditContext } from "./client/editContext";
|
|
4
2
|
import { useFieldModification } from "./client/fieldModificationStore";
|
|
5
3
|
import { EditorConfiguration } from "../config/types";
|
|
@@ -35,7 +33,7 @@ import {
|
|
|
35
33
|
PopoverTrigger,
|
|
36
34
|
} from "../components/ui/popover";
|
|
37
35
|
import {
|
|
38
|
-
Tooltip
|
|
36
|
+
Tooltip,
|
|
39
37
|
TooltipContent,
|
|
40
38
|
TooltipTrigger,
|
|
41
39
|
} from "../components/ui/tooltip";
|
|
@@ -244,19 +242,21 @@ export default function FieldListField({
|
|
|
244
242
|
className={classNames}
|
|
245
243
|
>
|
|
246
244
|
{validationBarClassNames && (
|
|
247
|
-
|
|
248
|
-
<
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
245
|
+
<Tooltip>
|
|
246
|
+
<TooltipTrigger asChild>
|
|
247
|
+
<div
|
|
248
|
+
className={validationBarClassNames}
|
|
249
|
+
id={"validation_" + field.id}
|
|
250
|
+
/>
|
|
251
|
+
</TooltipTrigger>
|
|
252
|
+
<TooltipContent>
|
|
253
253
|
{validators
|
|
254
254
|
.filter((x) => x.result > 1)
|
|
255
255
|
.map((x) => (
|
|
256
256
|
<div key={x.validator}>{x.message}</div>
|
|
257
257
|
))}
|
|
258
|
-
</
|
|
259
|
-
|
|
258
|
+
</TooltipContent>
|
|
259
|
+
</Tooltip>
|
|
260
260
|
)}
|
|
261
261
|
|
|
262
262
|
<div className="flex-1">
|
|
@@ -443,7 +443,7 @@ export default function FieldListField({
|
|
|
443
443
|
/>
|
|
444
444
|
)}
|
|
445
445
|
{!readonly && renderGeneratorButtons}
|
|
446
|
-
<
|
|
446
|
+
<Tooltip>
|
|
447
447
|
<Popover
|
|
448
448
|
open={fieldHistoryOpen}
|
|
449
449
|
onOpenChange={(open) => {
|
|
@@ -476,7 +476,7 @@ export default function FieldListField({
|
|
|
476
476
|
</PopoverContent>
|
|
477
477
|
</Popover>
|
|
478
478
|
<TooltipContent>Field History</TooltipContent>
|
|
479
|
-
</
|
|
479
|
+
</Tooltip>
|
|
480
480
|
</div>
|
|
481
481
|
</>
|
|
482
482
|
)}
|
package/src/editor/Terminal.tsx
CHANGED
|
@@ -97,7 +97,7 @@ export const Terminal = forwardRef<
|
|
|
97
97
|
setMessages([...messageRef.current, { type: "response", text }]);
|
|
98
98
|
}
|
|
99
99
|
};
|
|
100
|
-
// @ts-ignore
|
|
100
|
+
// @ts-ignore
|
|
101
101
|
TerminalService.on("response", responseHandler);
|
|
102
102
|
return () => {
|
|
103
103
|
// @ts-ignore
|
package/src/editor/Titlebar.tsx
CHANGED
|
@@ -36,7 +36,6 @@ export function Titlebar() {
|
|
|
36
36
|
const isInsideMenu = menuElement && menuElement.contains(target);
|
|
37
37
|
const isInsideButton = buttonElement && buttonElement.contains(target);
|
|
38
38
|
|
|
39
|
-
// Check if the click is inside a PrimeReact overlay (which renders in portals)
|
|
40
39
|
const isInsideOverlay = target.closest(".p-overlaypanel") !== null;
|
|
41
40
|
|
|
42
41
|
// Close menu only if click is outside menu, button, and overlays
|
|
@@ -33,12 +33,15 @@ interface AgentCostDisplayProps {
|
|
|
33
33
|
outputCost: number;
|
|
34
34
|
cachedCost: number;
|
|
35
35
|
};
|
|
36
|
+
/** Cost limit for the agent (in USD) */
|
|
37
|
+
costLimit?: number | null;
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
export function AgentCostDisplay({
|
|
39
41
|
className = "",
|
|
40
42
|
response,
|
|
41
43
|
totalTokens,
|
|
44
|
+
costLimit,
|
|
42
45
|
}: AgentCostDisplayProps) {
|
|
43
46
|
const [showCostPopover, setShowCostPopover] = useState(false);
|
|
44
47
|
const costPopoverRef = useRef<HTMLDivElement>(null);
|
|
@@ -118,16 +121,31 @@ export function AgentCostDisplay({
|
|
|
118
121
|
return null;
|
|
119
122
|
}
|
|
120
123
|
|
|
124
|
+
// Calculate percentage of limit used
|
|
125
|
+
const percentUsed = costLimit && costLimit > 0
|
|
126
|
+
? Math.min((displayTotalCost / costLimit) * 100, 100)
|
|
127
|
+
: null;
|
|
128
|
+
|
|
129
|
+
// Determine color based on usage
|
|
130
|
+
const getColorClass = () => {
|
|
131
|
+
if (!percentUsed) return "text-gray-400";
|
|
132
|
+
if (percentUsed >= 100) return "text-red-500";
|
|
133
|
+
if (percentUsed >= 80) return "text-orange-500";
|
|
134
|
+
if (percentUsed >= 60) return "text-yellow-600";
|
|
135
|
+
return "text-gray-400";
|
|
136
|
+
};
|
|
137
|
+
|
|
121
138
|
return (
|
|
122
139
|
<div className={`relative ${className}`} ref={costPopoverRef}>
|
|
123
140
|
<Popover open={showCostPopover} onOpenChange={setShowCostPopover}>
|
|
124
141
|
<PopoverTrigger asChild>
|
|
125
142
|
<div
|
|
126
|
-
className=
|
|
143
|
+
className={`cursor-pointer text-right hover:text-gray-600 ${getColorClass()}`}
|
|
127
144
|
style={{ fontSize: "10px" }}
|
|
128
145
|
onClick={() => setShowCostPopover(!showCostPopover)}
|
|
129
146
|
>
|
|
130
147
|
Total Cost: {displayTotalCost.toFixed(2)} {currency}
|
|
148
|
+
{costLimit && costLimit > 0 && ` / ${costLimit.toFixed(2)} ${currency}`}
|
|
131
149
|
</div>
|
|
132
150
|
</PopoverTrigger>
|
|
133
151
|
<PopoverContent className="w-80 p-4" align="end" side="bottom">
|
|
@@ -137,10 +155,48 @@ export function AgentCostDisplay({
|
|
|
137
155
|
<div>Cost Breakdown</div>
|
|
138
156
|
<span className="text-sm font-semibold">
|
|
139
157
|
{displayTotalCost.toFixed(2)} {currency}
|
|
158
|
+
{costLimit && costLimit > 0 && (
|
|
159
|
+
<span className="ml-1 text-xs text-gray-500">
|
|
160
|
+
/ {costLimit.toFixed(2)} {currency}
|
|
161
|
+
</span>
|
|
162
|
+
)}
|
|
140
163
|
</span>
|
|
141
164
|
</h4>
|
|
142
165
|
</div>
|
|
143
166
|
|
|
167
|
+
{/* Cost limit warning */}
|
|
168
|
+
{costLimit && costLimit > 0 && (
|
|
169
|
+
<div className="rounded-md bg-gray-50 p-3">
|
|
170
|
+
<div className="mb-2 flex items-center justify-between text-xs">
|
|
171
|
+
<span className="font-medium text-gray-700">Cost Limit Usage</span>
|
|
172
|
+
<span className={`font-semibold ${getColorClass()}`}>
|
|
173
|
+
{percentUsed?.toFixed(1)}%
|
|
174
|
+
</span>
|
|
175
|
+
</div>
|
|
176
|
+
<div className="h-2 w-full overflow-hidden rounded-full bg-gray-200">
|
|
177
|
+
<div
|
|
178
|
+
className={`h-full transition-all ${
|
|
179
|
+
percentUsed && percentUsed >= 100
|
|
180
|
+
? "bg-red-500"
|
|
181
|
+
: percentUsed && percentUsed >= 80
|
|
182
|
+
? "bg-orange-500"
|
|
183
|
+
: percentUsed && percentUsed >= 60
|
|
184
|
+
? "bg-yellow-500"
|
|
185
|
+
: "bg-blue-500"
|
|
186
|
+
}`}
|
|
187
|
+
style={{ width: `${Math.min(percentUsed || 0, 100)}%` }}
|
|
188
|
+
/>
|
|
189
|
+
</div>
|
|
190
|
+
{percentUsed && percentUsed >= 90 && (
|
|
191
|
+
<p className="mt-2 text-xs text-gray-600">
|
|
192
|
+
{percentUsed >= 100
|
|
193
|
+
? "Cost limit reached. Execution will stop on next API call."
|
|
194
|
+
: "Approaching cost limit. Consider extending if needed."}
|
|
195
|
+
</p>
|
|
196
|
+
)}
|
|
197
|
+
</div>
|
|
198
|
+
)}
|
|
199
|
+
|
|
144
200
|
<div className="space-y-3">
|
|
145
201
|
{/* Session Cost Breakdown */}
|
|
146
202
|
{(hasTotalData || hasTokenData) && (
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { cn } from "../../lib/utils";
|
|
3
|
+
import { AgentStatusSummary } from "./useAgentStatus";
|
|
4
|
+
import { Agent } from "../services/agentService";
|
|
5
|
+
|
|
6
|
+
interface AgentStatusBadgeProps {
|
|
7
|
+
status: AgentStatusSummary;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface BadgeConfig {
|
|
12
|
+
baseClasses: string;
|
|
13
|
+
bgColor: string;
|
|
14
|
+
title: string;
|
|
15
|
+
content?: React.ReactNode;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface AgentStatusConfig {
|
|
19
|
+
color: string;
|
|
20
|
+
label: string;
|
|
21
|
+
shouldPulse: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Helper function to get status configuration for an individual agent
|
|
26
|
+
* Handles both numeric and string status values
|
|
27
|
+
* Enum: New=0, Running=1, WaitingForApproval=2, Completed=3, Error=4, Closed=5, Idle=6
|
|
28
|
+
*/
|
|
29
|
+
export function getAgentStatusConfig(agent: Agent): AgentStatusConfig {
|
|
30
|
+
const status: string | number = agent.status;
|
|
31
|
+
|
|
32
|
+
// Handle both string (camelCase from backend) and numeric (enum value) status
|
|
33
|
+
if (status === "new" || status === 0) {
|
|
34
|
+
return {
|
|
35
|
+
color: "bg-gray-400",
|
|
36
|
+
label: "Status: New",
|
|
37
|
+
shouldPulse: false,
|
|
38
|
+
};
|
|
39
|
+
} else if (status === "running" || status === 1) {
|
|
40
|
+
return {
|
|
41
|
+
color: "bg-blue-500",
|
|
42
|
+
label: "Status: Running",
|
|
43
|
+
shouldPulse: true,
|
|
44
|
+
};
|
|
45
|
+
} else if (status === "waitingForApproval" || status === 2) {
|
|
46
|
+
return {
|
|
47
|
+
color: "bg-amber-500",
|
|
48
|
+
label: "Status: Waiting for Approval",
|
|
49
|
+
shouldPulse: false,
|
|
50
|
+
};
|
|
51
|
+
} else if (status === "completed" || status === 3) {
|
|
52
|
+
return {
|
|
53
|
+
color: "bg-green-500",
|
|
54
|
+
label: "Status: Completed",
|
|
55
|
+
shouldPulse: false,
|
|
56
|
+
};
|
|
57
|
+
} else if (status === "error" || status === 4) {
|
|
58
|
+
return {
|
|
59
|
+
color: "bg-red-500",
|
|
60
|
+
label: "Status: Error",
|
|
61
|
+
shouldPulse: false,
|
|
62
|
+
};
|
|
63
|
+
} else if (status === "closed" || status === 5) {
|
|
64
|
+
return {
|
|
65
|
+
color: "bg-gray-400",
|
|
66
|
+
label: "Status: Closed",
|
|
67
|
+
shouldPulse: false,
|
|
68
|
+
};
|
|
69
|
+
} else if (status === "idle" || status === 6) {
|
|
70
|
+
return {
|
|
71
|
+
color: "bg-gray-300",
|
|
72
|
+
label: "Status: Idle",
|
|
73
|
+
shouldPulse: false,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Default fallback - log for debugging
|
|
78
|
+
console.warn("Unknown agent status:", status, typeof status);
|
|
79
|
+
return {
|
|
80
|
+
color: "bg-gray-400",
|
|
81
|
+
label: `Status: Unknown (${status})`,
|
|
82
|
+
shouldPulse: false,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Badge that overlays on the agent icon to show status
|
|
88
|
+
* Always displays the total number of active agents with color-coded status:
|
|
89
|
+
* - Amber: Agents waiting for approval (highest priority)
|
|
90
|
+
* - Blue (pulsing): Agents actively running
|
|
91
|
+
* - Green: Other active agents
|
|
92
|
+
*/
|
|
93
|
+
export function AgentStatusBadge({ status, className }: AgentStatusBadgeProps) {
|
|
94
|
+
// No activity - don't show anything
|
|
95
|
+
if (!status.hasActivity) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const getBadgeConfig = (): BadgeConfig => {
|
|
100
|
+
// Waiting for approval takes priority (most urgent)
|
|
101
|
+
if (status.waitingForApproval > 0) {
|
|
102
|
+
return {
|
|
103
|
+
baseClasses: "-right-2 -top-2",
|
|
104
|
+
bgColor: "bg-amber-500",
|
|
105
|
+
title: `${status.waitingForApproval} agent${status.waitingForApproval > 1 ? "s" : ""} waiting for approval (${status.total} total active)`,
|
|
106
|
+
content: <span className="text-[8px] font-bold">{status.total}</span>,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Running agents - show count with pulsing indicator
|
|
111
|
+
if (status.running > 0) {
|
|
112
|
+
return {
|
|
113
|
+
baseClasses: "-right-2 -top-2",
|
|
114
|
+
bgColor: "bg-blue-500 animate-pulse",
|
|
115
|
+
title: `${status.running} agent${status.running > 1 ? "s" : ""} running (${status.total} total active)`,
|
|
116
|
+
content: <span className="text-[8px] font-bold">{status.total}</span>,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Other active agents - show count
|
|
121
|
+
return {
|
|
122
|
+
baseClasses: "-right-2 -top-2",
|
|
123
|
+
bgColor: "bg-green-500",
|
|
124
|
+
title: `${status.total} active agent${status.total > 1 ? "s" : ""}`,
|
|
125
|
+
content: <span className="text-[8px] font-bold">{status.total}</span>,
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const config = getBadgeConfig();
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<div
|
|
133
|
+
className={cn(
|
|
134
|
+
"absolute flex h-3 w-3 items-center justify-center rounded-full text-white shadow-md ring-1 ring-white",
|
|
135
|
+
config.baseClasses,
|
|
136
|
+
config.bgColor,
|
|
137
|
+
className,
|
|
138
|
+
)}
|
|
139
|
+
title={config.title}
|
|
140
|
+
>
|
|
141
|
+
{config.content}
|
|
142
|
+
</div>
|
|
143
|
+
);
|
|
144
|
+
}
|