@canmingir/link 1.2.55 → 1.2.57

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 (220) hide show
  1. package/.eslintignore +0 -1
  2. package/.github/workflows/publish.yml +6 -1
  3. package/LICENSE +201 -0
  4. package/bun.lock +20 -30
  5. package/package.json +4 -1
  6. package/src/assets/illustrations/avatar-shape.jsx +10 -8
  7. package/src/assets/illustrations/background-shape.jsx +0 -2
  8. package/src/assets/illustrations/booking-illustration.jsx +8 -6
  9. package/src/assets/illustrations/check-in-illustration.jsx +8 -6
  10. package/src/assets/illustrations/check-out-illustration.jsx +8 -6
  11. package/src/assets/illustrations/coming-soon-illustration.jsx +8 -6
  12. package/src/assets/illustrations/forbidden-illustration.jsx +8 -6
  13. package/src/assets/illustrations/maintenance-illustration.jsx +8 -6
  14. package/src/assets/illustrations/motivation-illustration.jsx +8 -6
  15. package/src/assets/illustrations/order-complete-illustration.jsx +8 -6
  16. package/src/assets/illustrations/page-not-found-illustration.jsx +8 -6
  17. package/src/assets/illustrations/seo-illustration.jsx +8 -6
  18. package/src/assets/illustrations/sever-error-illustration.jsx +8 -6
  19. package/src/assets/illustrations/upgrade-storage-illustration.jsx +8 -6
  20. package/src/assets/illustrations/upload-illustration.jsx +8 -6
  21. package/src/components/Iconify/Iconify.jsx +0 -1
  22. package/src/components/chart/chart.js +0 -2
  23. package/src/components/chart/index.js +0 -2
  24. package/src/components/chart/use-chart.js +0 -2
  25. package/src/components/custom-popover/styles.js +0 -2
  26. package/src/components/custom-popover/use-popover.js +0 -2
  27. package/src/components/custom-popover/utils.js +0 -2
  28. package/src/components/file-thumbnail/utils.js +0 -12
  29. package/src/components/image/utils.js +0 -2
  30. package/src/components/label/styles.js +0 -2
  31. package/src/components/logo/logo.jsx +1 -1
  32. package/src/components/scrollbar/styles.js +0 -2
  33. package/src/components/settings/context/settings-context.js +0 -2
  34. package/src/hooks/use-boolean.js +0 -2
  35. package/src/hooks/use-event-listener.js +0 -2
  36. package/src/hooks/use-local-storage.js +0 -4
  37. package/src/hooks/use-off-set-top.js +0 -2
  38. package/src/hooks/use-responsive.js +0 -4
  39. package/src/hooks/use-scroll-to-top.js +0 -2
  40. package/src/layouts/CompactLayout/CompactLayout.jsx +0 -2
  41. package/src/layouts/DashboardLayout/DashboardLayout.jsx +0 -2
  42. package/src/layouts/DashboardLayout/main.jsx +0 -2
  43. package/src/layouts/DashboardLayout/nav-horizontal.jsx +0 -2
  44. package/src/layouts/DashboardLayout/nav-vertical.jsx +6 -5
  45. package/src/layouts/FullScreenLayout/FullScreenLayout.jsx +3 -4
  46. package/src/layouts/FullScreenLayout/nav-horizontal.jsx +0 -2
  47. package/src/layouts/FullScreenLayout/nav-vertical.jsx +4 -5
  48. package/src/layouts/MainLayout/header.jsx +1 -3
  49. package/src/layouts/MainLayout/nav/desktop/index.jsx +0 -2
  50. package/src/layouts/MainLayout/nav/desktop/nav-item.jsx +0 -6
  51. package/src/layouts/MainLayout/nav/desktop/nav-list.jsx +16 -16
  52. package/src/layouts/MainLayout/nav/mobile/index.jsx +1 -3
  53. package/src/layouts/MainLayout/nav/mobile/nav-item.jsx +0 -4
  54. package/src/layouts/MainLayout/nav/mobile/nav-list.jsx +0 -2
  55. package/src/layouts/TwoSideLayout/TwoSideLayout.jsx +0 -1
  56. package/src/layouts/auth/classic.jsx +3 -4
  57. package/src/layouts/auth/modern-compact.jsx +0 -2
  58. package/src/layouts/auth/modern.jsx +0 -2
  59. package/src/layouts/common/ProjectBar/utils.js +0 -10
  60. package/src/layouts/common/account-popover.jsx +0 -2
  61. package/src/layouts/common/header-shadow.jsx +0 -2
  62. package/src/layouts/common/header-sim.jsx +7 -4
  63. package/src/layouts/common/header-simple.jsx +14 -8
  64. package/src/layouts/common/nav-toggle-button.jsx +1 -3
  65. package/src/layouts/common/notifications-popover/index.jsx +9 -10
  66. package/src/layouts/common/notifications-popover/notification-item.jsx +20 -17
  67. package/src/layouts/common/settings-button.jsx +0 -2
  68. package/src/layouts/config-layout.js +0 -2
  69. package/src/lib/ChatMessage/AIMessage.tsx +163 -0
  70. package/src/lib/ChatMessage/ErrorMessage.tsx +63 -0
  71. package/src/lib/ChatMessage/HumanMessage.tsx +142 -0
  72. package/src/lib/ChatMessage/LoadingMessage.tsx +27 -0
  73. package/src/lib/ChatMessage/MessageList.tsx +81 -0
  74. package/src/lib/ChatMessage/ToolMessage.tsx +346 -0
  75. package/src/lib/ChatMessage/index.js +6 -0
  76. package/src/lib/Image/utils.js +0 -2
  77. package/src/lib/PresetSelector/PresetSelector.tsx +112 -0
  78. package/src/lib/PresetSelector/index.js +1 -0
  79. package/src/lib/Scrollbar/styles.js +0 -2
  80. package/src/lib/SidebarChat/ChatDrawer.tsx +407 -0
  81. package/src/lib/SidebarChat/SessionPopover.tsx +221 -0
  82. package/src/lib/SidebarChat/SidebarChat.tsx +222 -0
  83. package/src/lib/SidebarChat/SidebarSessionList.tsx +304 -0
  84. package/src/lib/SidebarChat/assets.d.ts +4 -0
  85. package/src/lib/SidebarChat/cleanIconName.ts +4 -0
  86. package/src/lib/SidebarChat/index.js +1 -0
  87. package/src/lib/SidebarChat/messageSFX.mp3 +0 -0
  88. package/src/lib/SidebarChat/types.ts +14 -0
  89. package/src/lib/index.js +11 -0
  90. package/src/pages/404.jsx +0 -2
  91. package/src/routes/components/router-link.jsx +0 -2
  92. package/src/routes/hooks/use-active-link.js +0 -2
  93. package/src/routes/hooks/use-pathname.js +0 -2
  94. package/src/routes/hooks/use-router.js +0 -2
  95. package/src/theme/css.js +0 -12
  96. package/src/theme/custom-shadows.js +0 -2
  97. package/src/theme/options/contrast.js +0 -2
  98. package/src/theme/options/presets.js +0 -4
  99. package/src/theme/options/right-to-left.jsx +0 -2
  100. package/src/theme/overrides/components/accordion.js +0 -2
  101. package/src/theme/overrides/components/alert.js +0 -4
  102. package/src/theme/overrides/components/appbar.js +0 -2
  103. package/src/theme/overrides/components/autocomplete.js +0 -2
  104. package/src/theme/overrides/components/avatar.js +0 -4
  105. package/src/theme/overrides/components/backdrop.js +0 -2
  106. package/src/theme/overrides/components/badge.js +0 -2
  107. package/src/theme/overrides/components/breadcrumbs.js +0 -2
  108. package/src/theme/overrides/components/button-group.js +0 -4
  109. package/src/theme/overrides/components/button.js +0 -4
  110. package/src/theme/overrides/components/card.js +0 -2
  111. package/src/theme/overrides/components/checkbox.js +0 -2
  112. package/src/theme/overrides/components/chip.js +0 -4
  113. package/src/theme/overrides/components/css-baseline.js +0 -2
  114. package/src/theme/overrides/components/data-grid.js +0 -2
  115. package/src/theme/overrides/components/date-picker.jsx +0 -2
  116. package/src/theme/overrides/components/dialog.js +0 -2
  117. package/src/theme/overrides/components/drawer.js +0 -2
  118. package/src/theme/overrides/components/fab.js +0 -4
  119. package/src/theme/overrides/components/form.js +0 -2
  120. package/src/theme/overrides/components/list.js +0 -2
  121. package/src/theme/overrides/components/loading-button.js +0 -2
  122. package/src/theme/overrides/components/menu.js +0 -2
  123. package/src/theme/overrides/components/pagination.js +0 -4
  124. package/src/theme/overrides/components/paper.js +0 -2
  125. package/src/theme/overrides/components/popover.js +0 -2
  126. package/src/theme/overrides/components/progress.js +0 -4
  127. package/src/theme/overrides/components/radio.js +0 -2
  128. package/src/theme/overrides/components/rating.js +0 -2
  129. package/src/theme/overrides/components/select.js +0 -2
  130. package/src/theme/overrides/components/skeleton.js +0 -2
  131. package/src/theme/overrides/components/slider.js +0 -2
  132. package/src/theme/overrides/components/stepper.js +0 -2
  133. package/src/theme/overrides/components/svg-icon.js +0 -2
  134. package/src/theme/overrides/components/switch.js +0 -2
  135. package/src/theme/overrides/components/table.js +0 -2
  136. package/src/theme/overrides/components/tabs.js +0 -2
  137. package/src/theme/overrides/components/textfield.js +0 -2
  138. package/src/theme/overrides/components/timeline.js +0 -2
  139. package/src/theme/overrides/components/toggle-button.js +0 -4
  140. package/src/theme/overrides/components/tooltip.js +0 -2
  141. package/src/theme/overrides/components/tree-view.js +0 -2
  142. package/src/theme/overrides/components/typography.js +0 -2
  143. package/src/theme/overrides/default-props.jsx +4 -7
  144. package/src/theme/palette.js +0 -4
  145. package/src/theme/shadows.js +0 -2
  146. package/src/theme/typography.js +0 -4
  147. package/src/utils/flatten-array.js +0 -2
  148. package/src/utils/format-number.js +0 -2
  149. package/src/utils/format-time.js +0 -2
  150. package/src/utils/storage-available.js +0 -2
  151. package/src/widgets/Login/Login.jsx +0 -2
  152. package/src/widgets/error/not-found-view.jsx +0 -2
  153. package/vite/vite.js +8 -1
  154. package/project/.eslintrc.cjs +0 -22
  155. package/project/config.js +0 -18
  156. package/project/config.menu.js +0 -39
  157. package/project/config.template.js +0 -31
  158. package/project/cypress/e2e/layouts.cy.js +0 -170
  159. package/project/cypress/e2e/login.cy.js +0 -35
  160. package/project/cypress/e2e/selectbar.cy.js +0 -80
  161. package/project/cypress/fixtures/CONFIG/MENU_CONFIG.js +0 -39
  162. package/project/cypress/fixtures/EMPEROR/EMPERORS_GET.json +0 -51
  163. package/project/cypress/fixtures/EMPEROR/EMPERORS_POST.json +0 -9
  164. package/project/cypress/fixtures/OAUTH/GITHUB/user.json +0 -46
  165. package/project/cypress/fixtures/example.json +0 -5
  166. package/project/cypress/support/commands.js +0 -104
  167. package/project/cypress/support/e2e.js +0 -1
  168. package/project/cypress.config.js +0 -10
  169. package/project/index.html +0 -12
  170. package/project/media/ProjectIcons/3d.png +0 -0
  171. package/project/media/ProjectIcons/box.png +0 -0
  172. package/project/media/ProjectIcons/cafe.png +0 -0
  173. package/project/media/ProjectIcons/cargo.png +0 -0
  174. package/project/media/ProjectIcons/cloud.png +0 -0
  175. package/project/media/ProjectIcons/code.png +0 -0
  176. package/project/media/ProjectIcons/company.png +0 -0
  177. package/project/media/ProjectIcons/conversation.png +0 -0
  178. package/project/media/ProjectIcons/distributed.png +0 -0
  179. package/project/media/ProjectIcons/fingerprint.png +0 -0
  180. package/project/media/ProjectIcons/forest.png +0 -0
  181. package/project/media/ProjectIcons/headphones.png +0 -0
  182. package/project/media/ProjectIcons/office.png +0 -0
  183. package/project/media/ProjectIcons/path.png +0 -0
  184. package/project/media/ProjectIcons/printer.png +0 -0
  185. package/project/media/ProjectIcons/project.png +0 -0
  186. package/project/media/ProjectIcons/resume.png +0 -0
  187. package/project/media/ProjectIcons/rocket.png +0 -0
  188. package/project/media/ProjectIcons/rtruck.png +0 -0
  189. package/project/media/ProjectIcons/sign.png +0 -0
  190. package/project/media/ProjectIcons/site.png +0 -0
  191. package/project/media/ProjectIcons/truck.png +0 -0
  192. package/project/media/logo.png +0 -0
  193. package/project/package-lock.json +0 -22434
  194. package/project/package.json +0 -42
  195. package/project/public/assets/background/overlay_2.jpg +0 -0
  196. package/project/public/assets/illustrations/illustration_dashboard.png +0 -0
  197. package/project/public/media/largeLogo.png +0 -0
  198. package/project/public/media/logo.png +0 -0
  199. package/project/public/vite.svg +0 -1
  200. package/project/routes.jsx +0 -47
  201. package/project/server/mock.json +0 -110
  202. package/project/server/oauthMock.js +0 -27
  203. package/project/server/package-lock.json +0 -1505
  204. package/project/server/package.json +0 -20
  205. package/project/server/server.js +0 -127
  206. package/project/src/Container.jsx +0 -7
  207. package/project/src/components/ActionButton.jsx +0 -18
  208. package/project/src/hooks/useEmperor.jsx +0 -21
  209. package/project/src/http/index.js +0 -39
  210. package/project/src/main.jsx +0 -10
  211. package/project/src/pages/Battles.jsx +0 -16
  212. package/project/src/pages/Emperor.jsx +0 -50
  213. package/project/src/pages/index.jsx +0 -33
  214. package/project/src/theme.js +0 -151
  215. package/project/src/widgets/ActionButton.jsx +0 -68
  216. package/project/src/widgets/AddNewEmperor.jsx +0 -120
  217. package/project/src/widgets/ProjectContainer.jsx +0 -27
  218. package/project/vite.config.js +0 -6
  219. package/project/vite.config.js.timestamp-1709564450418-45fdd27900806.mjs +0 -341
  220. package/src/layouts/MainLayout/footer.jsx +0 -153
@@ -0,0 +1,112 @@
1
+ import { Iconify } from "@canmingir/link/platform/components";
2
+ import React from "react";
3
+ import { alpha } from "@mui/material/styles";
4
+
5
+ import {
6
+ Box,
7
+ FormControl,
8
+ InputLabel,
9
+ MenuItem,
10
+ Select,
11
+ Typography,
12
+ } from "@mui/material";
13
+
14
+ const PresetSelector = ({
15
+ Presets,
16
+ selectedPreset,
17
+ onPresetChange,
18
+ }: {
19
+ Presets: Array<{
20
+ id: string;
21
+ title: string;
22
+ description?: string;
23
+ }>;
24
+ selectedPreset?: string;
25
+ onPresetChange: (presetId: string) => void;
26
+ }) => {
27
+ return (
28
+ <Box
29
+ className="noDrag"
30
+ sx={{
31
+ width: "100%",
32
+ p: 1.5,
33
+ bgcolor: (theme) => alpha(theme.palette.grey[900], 0.8),
34
+ boxShadow: 2,
35
+ }}
36
+ >
37
+ <FormControl fullWidth>
38
+ <InputLabel
39
+ sx={{
40
+ color: "rgba(255, 255, 255, 0.7)",
41
+ "&.Mui-focused": {
42
+ color: "white",
43
+ },
44
+ }}
45
+ >
46
+ Preset
47
+ </InputLabel>
48
+ <Select
49
+ value={selectedPreset || "Automatic"}
50
+ onChange={(e) => onPresetChange(e.target.value)}
51
+ label="Preset"
52
+ sx={{
53
+ color: "white",
54
+ "& .MuiOutlinedInput-notchedOutline": {
55
+ borderColor: "rgba(255, 255, 255, 0.3)",
56
+ },
57
+ "&:hover .MuiOutlinedInput-notchedOutline": {
58
+ borderColor: "rgba(255, 255, 255, 0.5)",
59
+ },
60
+ "&.Mui-focused .MuiOutlinedInput-notchedOutline": {
61
+ borderColor: "white",
62
+ },
63
+ "& .MuiSelect-icon": {
64
+ color: "rgba(255, 255, 255, 0.7)",
65
+ },
66
+ }}
67
+ MenuProps={{
68
+ PaperProps: {
69
+ sx: {
70
+ bgcolor: (theme) => alpha(theme.palette.grey[900], 0.95),
71
+ "& .MuiMenuItem-root": {
72
+ color: "white",
73
+ "&:hover": {
74
+ bgcolor: (theme) => alpha(theme.palette.primary.main, 0.2),
75
+ },
76
+ "&.Mui-selected": {
77
+ bgcolor: (theme) => alpha(theme.palette.primary.main, 0.3),
78
+ "&:hover": {
79
+ bgcolor: (theme) =>
80
+ alpha(theme.palette.primary.main, 0.4),
81
+ },
82
+ },
83
+ },
84
+ },
85
+ },
86
+ }}
87
+ >
88
+ <MenuItem value="Automatic">
89
+ <Typography sx={{ color: "white" }}>Automatic</Typography>
90
+ </MenuItem>
91
+ {Presets.map((Preset) => (
92
+ <MenuItem key={Preset.id} value={Preset.id}>
93
+ <Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
94
+ <Iconify
95
+ icon="healthicons:crisis-response-center-person-outline"
96
+ width={20}
97
+ height={20}
98
+ sx={{ color: "white" }}
99
+ />
100
+ <Typography sx={{ color: "white" }}>
101
+ {Preset.title}
102
+ </Typography>
103
+ </Box>
104
+ </MenuItem>
105
+ ))}
106
+ </Select>
107
+ </FormControl>
108
+ </Box>
109
+ );
110
+ };
111
+
112
+ export default PresetSelector;
@@ -0,0 +1 @@
1
+ export { default } from "./PresetSelector";
@@ -2,8 +2,6 @@ import SimpleBar from "simplebar-react";
2
2
 
3
3
  import { alpha, styled } from "@mui/material/styles";
4
4
 
5
- // ----------------------------------------------------------------------
6
-
7
5
  export const StyledRootScrollbar = styled("div")(() => ({
8
6
  flexGrow: 1,
9
7
  height: "100%",
@@ -0,0 +1,407 @@
1
+ import PresetSelector from "../PresetSelector/PresetSelector";
2
+ import Editor from "@monaco-editor/react";
3
+ import { Iconify } from "@canmingir/link/platform/components";
4
+ import { Scrollbar } from "@canmingir/link/platform/components";
5
+ import Stack from "@mui/material/Stack";
6
+ import { alpha } from "@mui/material/styles";
7
+
8
+ import {
9
+ Box,
10
+ Drawer,
11
+ IconButton,
12
+ TextField,
13
+ ToggleButton,
14
+ ToggleButtonGroup,
15
+ Tooltip,
16
+ Typography,
17
+ } from "@mui/material";
18
+ import { LoadingMessage, MessageList } from "../ChatMessage";
19
+ import { ToolDecision, ToolRenderers } from "../ChatMessage/ToolMessage";
20
+ import React, { memo, useCallback, useRef, useState } from "react";
21
+
22
+ const DRAWER_WIDTH = 400;
23
+
24
+ type InputMode = "chat" | "json";
25
+
26
+ interface ChatDrawerProps {
27
+ title: string;
28
+ open: boolean;
29
+ onClose: () => void;
30
+ history: { id?: string; content: string; role: string }[];
31
+ selectedConversationId?: string;
32
+ readOnly?: boolean;
33
+ mute: boolean;
34
+ onMuteToggle: () => void;
35
+ showLoading: boolean;
36
+ onSend: (content: string) => void;
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
+ Presets?: any[];
39
+ selectedPreset?: string;
40
+ onPresetChange?: (preset: string) => void;
41
+ messagesEndRef: React.RefObject<HTMLDivElement>;
42
+ highlightedMessage: React.RefObject<HTMLDivElement>;
43
+ onNewSession?: () => void;
44
+ toolRenderers?: ToolRenderers;
45
+ onToolDecision?: (toolCallId: string, decision: ToolDecision) => void;
46
+ }
47
+
48
+ const DEFAULT_JSON = `{\n \n}`;
49
+
50
+ const ChatDrawer = ({
51
+ title,
52
+ open,
53
+ onClose,
54
+ history,
55
+ selectedConversationId,
56
+ readOnly,
57
+ mute,
58
+ onMuteToggle,
59
+ showLoading,
60
+ onSend,
61
+ Presets = [],
62
+ selectedPreset,
63
+ onPresetChange,
64
+ messagesEndRef,
65
+ highlightedMessage,
66
+ toolRenderers,
67
+ onToolDecision,
68
+ }: ChatDrawerProps) => {
69
+ const inputRef = useRef(null);
70
+ const [inputMode, setInputMode] = useState<InputMode>("chat");
71
+ const [jsonValue, setJsonValue] = useState(DEFAULT_JSON);
72
+ const [jsonError, setJsonError] = useState<string | null>(null);
73
+
74
+ const handleModeChange = useCallback(
75
+ (_: React.MouseEvent<HTMLElement>, newMode: InputMode | null) => {
76
+ if (newMode) setInputMode(newMode);
77
+ },
78
+ []
79
+ );
80
+
81
+ const handleKeyDown = useCallback(
82
+ (event: React.KeyboardEvent) => {
83
+ if (event.key === "Enter" && !event.shiftKey) {
84
+ event.preventDefault();
85
+ const content = inputRef.current?.value?.trim();
86
+ if (content) {
87
+ onSend(content);
88
+ inputRef.current.value = "";
89
+ }
90
+ }
91
+ },
92
+ [onSend]
93
+ );
94
+
95
+ const handleJsonChange = useCallback((value: string | undefined) => {
96
+ const v = value ?? "";
97
+ setJsonValue(v);
98
+ try {
99
+ JSON.parse(v);
100
+ setJsonError(null);
101
+ } catch {
102
+ setJsonError("Invalid JSON");
103
+ }
104
+ }, []);
105
+
106
+ const handleJsonSend = useCallback(() => {
107
+ try {
108
+ const parsed = JSON.parse(jsonValue);
109
+ onSend(JSON.stringify(parsed));
110
+ setJsonValue(DEFAULT_JSON);
111
+ setJsonError(null);
112
+ } catch {
113
+ setJsonError("Invalid JSON — fix before sending");
114
+ }
115
+ }, [jsonValue, onSend]);
116
+
117
+ const handleJsonKeyDown = useCallback(
118
+ (event: React.KeyboardEvent) => {
119
+ if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
120
+ event.preventDefault();
121
+ handleJsonSend();
122
+ }
123
+ },
124
+ [handleJsonSend]
125
+ );
126
+
127
+ return (
128
+ <Drawer
129
+ anchor="right"
130
+ open={open}
131
+ onClose={onClose}
132
+ variant="persistent"
133
+ sx={{
134
+ width: open ? DRAWER_WIDTH : 0,
135
+ flexShrink: 0,
136
+ "& .MuiDrawer-paper": {
137
+ width: DRAWER_WIDTH,
138
+ boxSizing: "border-box",
139
+ border: "none",
140
+ boxShadow: (theme) => theme.shadows[8],
141
+ },
142
+ }}
143
+ >
144
+ <Box
145
+ sx={{
146
+ display: "flex",
147
+ flexDirection: "column",
148
+ height: "100%",
149
+ bgcolor: (theme) => theme.palette.background.default,
150
+ }}
151
+ >
152
+ {/* Header */}
153
+ <Box
154
+ sx={{
155
+ bgcolor: (theme) => alpha(theme.palette.grey[900], 0.9),
156
+ display: "flex",
157
+ justifyContent: "space-between",
158
+ alignItems: "center",
159
+ p: 2,
160
+ borderBottom: (theme) =>
161
+ `1px solid ${alpha(theme.palette.divider, 0.1)}`,
162
+ }}
163
+ >
164
+ <Typography variant="h6" sx={{ color: "white", fontWeight: 600 }}>
165
+ {title}
166
+ </Typography>
167
+ <Stack direction="row" spacing={1}>
168
+ {!readOnly && (
169
+ <IconButton onClick={onMuteToggle} size="small">
170
+ <Iconify
171
+ icon={
172
+ mute
173
+ ? "solar:volume-cross-bold-duotone"
174
+ : "solar:volume-loud-bold-duotone"
175
+ }
176
+ sx={{ width: 20, height: 20, color: "white" }}
177
+ />
178
+ </IconButton>
179
+ )}
180
+ <IconButton onClick={onClose} size="small">
181
+ <Iconify
182
+ icon="mdi:chevron-right"
183
+ sx={{ width: 24, height: 24, color: "white" }}
184
+ />
185
+ </IconButton>
186
+ </Stack>
187
+ </Box>
188
+
189
+ {Presets.length > 0 && !readOnly && (
190
+ <Box sx={{ px: 2, pt: 1 }}>
191
+ <PresetSelector
192
+ Presets={Presets}
193
+ selectedPreset={selectedPreset}
194
+ onPresetChange={onPresetChange}
195
+ />
196
+ </Box>
197
+ )}
198
+
199
+ {/* Messages */}
200
+ <Box sx={{ flex: 1, overflow: "hidden", p: 2 }}>
201
+ <Scrollbar sx={{ height: "100%" }}>
202
+ <MessageList
203
+ messages={
204
+ history as { id: string; content: string; role: string }[]
205
+ }
206
+ selectedId={selectedConversationId}
207
+ messagesEndRef={messagesEndRef}
208
+ highlightedMessage={highlightedMessage}
209
+ toolRenderers={toolRenderers}
210
+ onToolDecision={onToolDecision}
211
+ />
212
+ {showLoading && <LoadingMessage messagesEndRef={messagesEndRef} />}
213
+ </Scrollbar>
214
+ </Box>
215
+
216
+ {/* Input Area */}
217
+ {!readOnly && (
218
+ <Box
219
+ sx={{
220
+ borderTop: (theme) =>
221
+ `1px solid ${alpha(theme.palette.divider, 0.1)}`,
222
+ bgcolor: (theme) => alpha(theme.palette.grey[900], 0.5),
223
+ }}
224
+ >
225
+ {/* Mode Toggle */}
226
+ <Box
227
+ sx={{
228
+ display: "flex",
229
+ alignItems: "center",
230
+ px: 2,
231
+ pt: 1.5,
232
+ pb: 1,
233
+ gap: 1,
234
+ }}
235
+ >
236
+ <ToggleButtonGroup
237
+ value={inputMode}
238
+ exclusive
239
+ onChange={handleModeChange}
240
+ size="small"
241
+ sx={{
242
+ "& .MuiToggleButton-root": {
243
+ px: 1.5,
244
+ py: 0.5,
245
+ fontSize: "0.7rem",
246
+ fontWeight: 600,
247
+ letterSpacing: 0.5,
248
+ textTransform: "uppercase",
249
+ color: (theme) => alpha(theme.palette.text.secondary, 0.7),
250
+ borderColor: (theme) => alpha(theme.palette.divider, 0.3),
251
+ "&.Mui-selected": {
252
+ color: (theme) => theme.palette.primary.light,
253
+ bgcolor: (theme) =>
254
+ alpha(theme.palette.primary.main, 0.15),
255
+ borderColor: (theme) =>
256
+ alpha(theme.palette.primary.main, 0.4),
257
+ },
258
+ },
259
+ }}
260
+ >
261
+ <ToggleButton value="chat">
262
+ <Iconify
263
+ icon="solar:chat-round-line-bold-duotone"
264
+ sx={{ width: 14, height: 14, mr: 0.5 }}
265
+ />
266
+ Chat
267
+ </ToggleButton>
268
+ <ToggleButton value="json">
269
+ <Iconify
270
+ icon="solar:code-bold-duotone"
271
+ sx={{ width: 14, height: 14, mr: 0.5 }}
272
+ />
273
+ JSON
274
+ </ToggleButton>
275
+ </ToggleButtonGroup>
276
+ </Box>
277
+
278
+ {/* Chat Input */}
279
+ {inputMode === "chat" && (
280
+ <Box sx={{ px: 2, pb: 2 }}>
281
+ <TextField
282
+ variant="outlined"
283
+ autoComplete="off"
284
+ fullWidth
285
+ placeholder="Type a message..."
286
+ inputRef={inputRef}
287
+ onKeyDown={handleKeyDown}
288
+ size="small"
289
+ sx={{
290
+ "& .MuiOutlinedInput-root": {
291
+ bgcolor: (theme) =>
292
+ alpha(theme.palette.background.paper, 0.8),
293
+ },
294
+ }}
295
+ slotProps={{
296
+ input: {
297
+ endAdornment: (
298
+ <IconButton
299
+ onClick={() => {
300
+ const content = inputRef.current?.value?.trim();
301
+ if (content) {
302
+ onSend(content);
303
+ inputRef.current.value = "";
304
+ }
305
+ }}
306
+ size="small"
307
+ >
308
+ <Iconify
309
+ icon="material-symbols:send"
310
+ sx={{ width: 20, height: 20 }}
311
+ />
312
+ </IconButton>
313
+ ),
314
+ },
315
+ }}
316
+ />
317
+ </Box>
318
+ )}
319
+
320
+ {/* JSON Input */}
321
+ {inputMode === "json" && (
322
+ <Box sx={{ px: 2, pb: 2 }} onKeyDown={handleJsonKeyDown}>
323
+ <Box
324
+ sx={{
325
+ border: (theme) =>
326
+ `1px solid ${
327
+ jsonError
328
+ ? theme.palette.error.main
329
+ : alpha(theme.palette.primary.main, 0.3)
330
+ }`,
331
+ borderRadius: 1,
332
+ overflow: "hidden",
333
+ bgcolor: "#1e1e1e",
334
+ }}
335
+ >
336
+ <Editor
337
+ height="160px"
338
+ defaultLanguage="json"
339
+ value={jsonValue}
340
+ onChange={handleJsonChange}
341
+ theme="vs-dark"
342
+ options={{
343
+ minimap: { enabled: false },
344
+ fontSize: 12,
345
+ lineNumbers: "off",
346
+ scrollBeyondLastLine: false,
347
+ wordWrap: "on",
348
+ tabSize: 2,
349
+ folding: false,
350
+ glyphMargin: false,
351
+ lineDecorationsWidth: 0,
352
+ lineNumbersMinChars: 0,
353
+ padding: { top: 8, bottom: 8 },
354
+ }}
355
+ />
356
+ </Box>
357
+
358
+ <Box
359
+ sx={{
360
+ display: "flex",
361
+ alignItems: "center",
362
+ justifyContent: "space-between",
363
+ mt: 1,
364
+ }}
365
+ >
366
+ <Typography
367
+ variant="caption"
368
+ sx={{
369
+ color: jsonError
370
+ ? "error.main"
371
+ : (theme) => alpha(theme.palette.text.secondary, 0.5),
372
+ fontSize: "0.7rem",
373
+ }}
374
+ >
375
+ {jsonError ?? "⌘↵ to send"}
376
+ </Typography>
377
+ <Tooltip title="Send JSON (⌘↵)" placement="top">
378
+ <span>
379
+ <IconButton
380
+ onClick={handleJsonSend}
381
+ size="small"
382
+ disabled={!!jsonError}
383
+ sx={{
384
+ color: (theme) =>
385
+ jsonError
386
+ ? theme.palette.action.disabled
387
+ : theme.palette.primary.light,
388
+ }}
389
+ >
390
+ <Iconify
391
+ icon="material-symbols:send"
392
+ sx={{ width: 18, height: 18 }}
393
+ />
394
+ </IconButton>
395
+ </span>
396
+ </Tooltip>
397
+ </Box>
398
+ </Box>
399
+ )}
400
+ </Box>
401
+ )}
402
+ </Box>
403
+ </Drawer>
404
+ );
405
+ };
406
+
407
+ export default memo(ChatDrawer);