@canmingir/link 1.2.54 → 1.2.56

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,304 @@
1
+ import type { StoredSession } from "./types";
2
+ import { alpha } from "@mui/material/styles";
3
+ import { cleanIconName } from "./cleanIconName";
4
+ import { publish } from "@nucleoidai/react-event";
5
+
6
+ import { Badge, Box, Tooltip, Typography } from "@mui/material";
7
+ import { DevTool, Iconify } from "@canmingir/link/platform/components";
8
+ import React, { memo } from "react";
9
+
10
+ interface SidebarSessionListProps {
11
+ sessions: StoredSession[];
12
+ currentSessionId?: string;
13
+ unreadCount: number;
14
+ onToggleChat: () => void;
15
+ onSessionClick: (
16
+ event: React.MouseEvent<HTMLElement>,
17
+ sessionId: string
18
+ ) => void;
19
+ onClearAll: () => void;
20
+ onNewSession?: () => void;
21
+ wrapperRef?: React.Ref<HTMLDivElement>;
22
+ beta?: boolean;
23
+ }
24
+
25
+ const btnBase = {
26
+ width: 32,
27
+ height: 32,
28
+ borderRadius: "10px",
29
+ display: "flex",
30
+ alignItems: "center",
31
+ justifyContent: "center",
32
+ alignSelf: "center",
33
+ flexDirection: "column",
34
+ cursor: "pointer",
35
+ flexShrink: 0,
36
+ transition: "all 0.18s ease",
37
+ border: "1px solid transparent",
38
+ };
39
+
40
+ const SidebarSessionList = ({
41
+ sessions,
42
+ currentSessionId,
43
+ unreadCount,
44
+ onToggleChat,
45
+ onSessionClick,
46
+ onClearAll,
47
+ onNewSession,
48
+ wrapperRef,
49
+ beta,
50
+ }: SidebarSessionListProps) => {
51
+ const sidebarSessions = sessions;
52
+
53
+ const header = (
54
+ <>
55
+ <Tooltip
56
+ title="New Chat"
57
+ placement="left"
58
+ enterDelay={1000}
59
+ enterNextDelay={1000}
60
+ >
61
+ <Box
62
+ onClick={() => {
63
+ onNewSession?.();
64
+ onToggleChat();
65
+ }}
66
+ sx={{
67
+ ...btnBase,
68
+ flexDirection: "column",
69
+ gap: 0.5,
70
+ mb: 0.5,
71
+ color: "text.secondary",
72
+ "&:hover": {
73
+ color: "primary.main",
74
+ bgcolor: (theme) => alpha(theme.palette.primary.main, 0.12),
75
+ borderColor: (theme) => alpha(theme.palette.primary.main, 0.2),
76
+ transform: "scale(1.08)",
77
+ },
78
+ }}
79
+ >
80
+ <Iconify
81
+ icon="solar:add-square-bold-duotone"
82
+ sx={{ width: 20, height: 20 }}
83
+ />
84
+ <Typography
85
+ sx={{
86
+ fontSize: "0.5rem",
87
+ fontWeight: 500,
88
+ letterSpacing: 0.5,
89
+ lineHeight: 1,
90
+ textTransform: "capitalize",
91
+ }}
92
+ >
93
+ New
94
+ </Typography>
95
+ </Box>
96
+ </Tooltip>
97
+
98
+ {!beta && (
99
+ <Tooltip
100
+ title="Open API"
101
+ placement="left"
102
+ enterDelay={1000}
103
+ enterNextDelay={1000}
104
+ >
105
+ <Box
106
+ onClick={() => publish("SWAGGER_DIALOG_OPEN", { open: true })}
107
+ sx={{
108
+ ...btnBase,
109
+ flexDirection: "column",
110
+ gap: 0.5,
111
+ mb: 1,
112
+ color: "text.secondary",
113
+ "&:hover": {
114
+ bgcolor: (theme) =>
115
+ theme.palette.mode === "dark"
116
+ ? "rgba(255,255,255,0.1)"
117
+ : "rgba(0,0,0,0.08)",
118
+ transform: "scale(1.08)",
119
+ },
120
+ }}
121
+ >
122
+ <Iconify
123
+ icon="logos:swagger"
124
+ sx={{ width: 20, height: 20, transition: "all 0.2s ease-in-out" }}
125
+ />
126
+ <Typography
127
+ sx={{
128
+ fontSize: "0.5rem",
129
+ fontWeight: 500,
130
+ letterSpacing: 0.5,
131
+ lineHeight: 1,
132
+ textTransform: "capitalize",
133
+ }}
134
+ >
135
+ API
136
+ </Typography>
137
+ </Box>
138
+ </Tooltip>
139
+ )}
140
+ </>
141
+ );
142
+
143
+ const content = (
144
+ <Box
145
+ ref={wrapperRef}
146
+ sx={{
147
+ display: "flex",
148
+ flexDirection: "column",
149
+ alignItems: "center",
150
+ gap: 1,
151
+ width: "100%",
152
+ py: 1,
153
+ }}
154
+ >
155
+ {sidebarSessions.map((session, idx) => {
156
+ const isCurrent = session.sessionId === currentSessionId;
157
+ const sessionNum = idx + 1;
158
+ const hasUnread = isCurrent && unreadCount > 0;
159
+
160
+ return (
161
+ <Tooltip
162
+ key={session.sessionId}
163
+ title={
164
+ hasUnread
165
+ ? `${unreadCount} new · message${unreadCount !== 1 ? "s" : ""}`
166
+ : `${session.messages.length} message${
167
+ session.messages.length !== 1 ? "s" : ""
168
+ }`
169
+ }
170
+ placement="left"
171
+ enterDelay={1000}
172
+ enterNextDelay={1000}
173
+ >
174
+ <Box
175
+ onClick={(e) => onSessionClick(e, session.sessionId)}
176
+ sx={{
177
+ ...btnBase,
178
+ flexDirection: "column",
179
+ gap: 0.4,
180
+ color: isCurrent ? "primary.main" : "text.secondary",
181
+ borderColor: isCurrent
182
+ ? (theme) => alpha(theme.palette.primary.main, 0.28)
183
+ : "transparent",
184
+ boxShadow: isCurrent
185
+ ? (theme) =>
186
+ `0 0 0 1px ${alpha(theme.palette.primary.main, 0.2)}`
187
+ : "none",
188
+ "&:hover": {
189
+ bgcolor: isCurrent
190
+ ? (theme) => alpha(theme.palette.primary.main, 0.2)
191
+ : (theme) =>
192
+ theme.palette.mode === "dark"
193
+ ? "rgba(255,255,255,0.1)"
194
+ : "rgba(0,0,0,0.08)",
195
+ transform: "scale(1.08)",
196
+ },
197
+ }}
198
+ >
199
+ <Badge
200
+ badgeContent={hasUnread ? unreadCount : 0}
201
+ color="error"
202
+ max={9}
203
+ sx={{
204
+ "& .MuiBadge-badge": {
205
+ fontSize: "0.55rem",
206
+ minWidth: 14,
207
+ height: 14,
208
+ padding: "0 3px",
209
+ transform: "scale(0.85) translate(25%, -25%)",
210
+ transition: "all 0.2s ease",
211
+ },
212
+ }}
213
+ >
214
+ <Box
215
+ sx={{
216
+ width: 20,
217
+ height: 20,
218
+ borderRadius: "7px",
219
+ display: "flex",
220
+ alignItems: "center",
221
+ justifyContent: "center",
222
+ transition: "all 0.2s ease-in-out",
223
+ bgcolor: (theme) =>
224
+ isCurrent
225
+ ? alpha(theme.palette.primary.main, 0.2)
226
+ : alpha(theme.palette.text.secondary, 0.1),
227
+ }}
228
+ >
229
+ {session.agentIcon ? (
230
+ <Iconify
231
+ icon={cleanIconName(session.agentIcon)}
232
+ sx={{ width: 15, height: 15 }}
233
+ />
234
+ ) : (
235
+ <Typography
236
+ sx={{
237
+ fontSize: "0.65rem",
238
+ fontWeight: 800,
239
+ lineHeight: 1,
240
+ }}
241
+ >
242
+ {sessionNum}
243
+ </Typography>
244
+ )}
245
+ </Box>
246
+ </Badge>
247
+
248
+ <Typography
249
+ sx={{
250
+ fontSize: "0.55rem",
251
+ fontWeight: 700,
252
+ lineHeight: 1,
253
+ letterSpacing: 0.3,
254
+ }}
255
+ >
256
+ {`Ses. ${sessionNum}`}
257
+ </Typography>
258
+ </Box>
259
+ </Tooltip>
260
+ );
261
+ })}
262
+ </Box>
263
+ );
264
+
265
+ const footer = (
266
+ <Tooltip
267
+ title={sidebarSessions.length > 0 ? "Clear all sessions" : "No sessions"}
268
+ placement="left"
269
+ >
270
+ <Box
271
+ onClick={sidebarSessions.length > 0 ? onClearAll : undefined}
272
+ sx={{
273
+ ...btnBase,
274
+ color: "text.disabled",
275
+ bgcolor: "transparent",
276
+ opacity: sidebarSessions.length > 0 ? 1 : 0.4,
277
+ cursor: sidebarSessions.length > 0 ? "pointer" : "not-allowed",
278
+ ...(sidebarSessions.length > 0 && {
279
+ "&:hover": {
280
+ bgcolor: (theme) => alpha(theme.palette.error.main, 0.1),
281
+ color: "error.main",
282
+ borderColor: (theme) => alpha(theme.palette.error.main, 0.2),
283
+ transform: "scale(1.08)",
284
+ },
285
+ }),
286
+ }}
287
+ >
288
+ <Iconify icon="solar:trash-bin-2-bold" sx={{ width: 18, height: 18 }} />
289
+ </Box>
290
+ </Tooltip>
291
+ );
292
+
293
+ return (
294
+ <DevTool
295
+ width={45}
296
+ height={310}
297
+ header={header}
298
+ content={content}
299
+ footer={footer}
300
+ />
301
+ );
302
+ };
303
+
304
+ export default memo(SidebarSessionList);
@@ -0,0 +1,4 @@
1
+ declare module "*.mp3" {
2
+ const src: string;
3
+ export default src;
4
+ }
@@ -0,0 +1,4 @@
1
+ export const cleanIconName = (icon?: string) => {
2
+ if (!icon) return "";
3
+ return icon.replace(/^:+|:+$/g, "");
4
+ };
@@ -0,0 +1 @@
1
+ export { default } from "./SidebarChat";
@@ -0,0 +1,14 @@
1
+ export interface Message {
2
+ id?: string;
3
+ content: string;
4
+ role: string;
5
+ }
6
+
7
+ export interface StoredSession {
8
+ sessionId: string;
9
+ agentId?: string;
10
+ messages: Message[];
11
+ lastUpdated: number;
12
+ agentIcon?: string;
13
+ agentName?: string;
14
+ }
package/src/lib/index.js CHANGED
@@ -56,3 +56,14 @@ export {
56
56
  GlassCardActions,
57
57
  } from "./GlassCard/GlassCard";
58
58
  export { default as DevTool } from "./DevTool";
59
+
60
+ export { default as SidebarChat } from "./SidebarChat/SidebarChat";
61
+ export { default as PresetSelector } from "./PresetSelector/PresetSelector";
62
+ export {
63
+ AIMessage,
64
+ ErrorMessage,
65
+ HumanMessage,
66
+ LoadingMessage,
67
+ MessageList,
68
+ ToolMessage,
69
+ } from "./ChatMessage";
package/vite/vite.js CHANGED
@@ -1,10 +1,17 @@
1
1
  import { ConfigSchema } from "../src/config/schemas.js";
2
2
  import checker from "vite-plugin-checker";
3
- import config from "../../../../config.js";
4
3
  import path from "path";
5
4
  import react from "@vitejs/plugin-react";
6
5
  import { splitVendorChunkPlugin } from "vite";
7
6
  import svgr from "vite-plugin-svgr";
7
+ import { pathToFileURL } from "url";
8
+
9
+ // Resolved against the consumer's cwd (not a relative import) so this keeps
10
+ // working whether @canmingir/link is a real copy or a symlinked/linked package.
11
+ const configUrl = pathToFileURL(
12
+ path.join(process.cwd(), "config.js")
13
+ ).href;
14
+ const { default: config } = await import(configUrl);
8
15
 
9
16
  const { value, error } = ConfigSchema.validate(config);
10
17