@yushaw/sanqian-chat 0.2.0 → 0.2.2

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.
@@ -257,6 +257,7 @@ var FloatingWindow = class _FloatingWindow {
257
257
  const { alwaysOnTop, showInTaskbar, preloadPath } = this.options;
258
258
  const initialBounds = this.getInitialBounds();
259
259
  const { minWidth, minHeight } = this.getMinSize();
260
+ const isWindows = process.platform === "win32";
260
261
  const win = new import_electron.BrowserWindow({
261
262
  width: initialBounds.width,
262
263
  height: initialBounds.height,
@@ -264,11 +265,13 @@ var FloatingWindow = class _FloatingWindow {
264
265
  y: initialBounds.y,
265
266
  show: false,
266
267
  frame: false,
267
- transparent: true,
268
+ // Windows: transparent 会移除 resize 边框,需要禁用
269
+ transparent: !isWindows,
268
270
  hasShadow: false,
269
271
  // Disable system shadow to avoid white border on macOS
270
272
  resizable: true,
271
- backgroundColor: "#00000000",
273
+ // Windows: 非透明时需要设置背景色(默认深色,renderer 会根据主题同步)
274
+ backgroundColor: isWindows ? "#1F1F1F" : "#00000000",
272
275
  minWidth,
273
276
  minHeight,
274
277
  alwaysOnTop,
@@ -623,6 +626,17 @@ var FloatingWindow = class _FloatingWindow {
623
626
  if (!activeInstance) return { success: false, error: "Window not available" };
624
627
  return { success: true, data: activeInstance.getResolvedUiConfig() };
625
628
  });
629
+ import_electron.ipcMain.handle("sanqian-chat:setBackgroundColor", (_event, params) => {
630
+ if (!activeInstance) return { success: false, error: "Window not available" };
631
+ const win = activeInstance.getWindow();
632
+ if (!win) return { success: false, error: "Window not available" };
633
+ try {
634
+ win.setBackgroundColor(params.color);
635
+ return { success: true };
636
+ } catch (e) {
637
+ return { success: false, error: e instanceof Error ? e.message : "Failed to set background color" };
638
+ }
639
+ });
626
640
  }
627
641
  // Public API
628
642
  show() {
@@ -711,6 +725,7 @@ var FloatingWindow = class _FloatingWindow {
711
725
  import_electron.ipcMain.removeHandler("sanqian-chat:setAlwaysOnTop");
712
726
  import_electron.ipcMain.removeHandler("sanqian-chat:getAlwaysOnTop");
713
727
  import_electron.ipcMain.removeHandler("sanqian-chat:getUiConfig");
728
+ import_electron.ipcMain.removeHandler("sanqian-chat:setBackgroundColor");
714
729
  ipcHandlersRegistered = false;
715
730
  }
716
731
  }
@@ -220,6 +220,7 @@ var FloatingWindow = class _FloatingWindow {
220
220
  const { alwaysOnTop, showInTaskbar, preloadPath } = this.options;
221
221
  const initialBounds = this.getInitialBounds();
222
222
  const { minWidth, minHeight } = this.getMinSize();
223
+ const isWindows = process.platform === "win32";
223
224
  const win = new BrowserWindow({
224
225
  width: initialBounds.width,
225
226
  height: initialBounds.height,
@@ -227,11 +228,13 @@ var FloatingWindow = class _FloatingWindow {
227
228
  y: initialBounds.y,
228
229
  show: false,
229
230
  frame: false,
230
- transparent: true,
231
+ // Windows: transparent 会移除 resize 边框,需要禁用
232
+ transparent: !isWindows,
231
233
  hasShadow: false,
232
234
  // Disable system shadow to avoid white border on macOS
233
235
  resizable: true,
234
- backgroundColor: "#00000000",
236
+ // Windows: 非透明时需要设置背景色(默认深色,renderer 会根据主题同步)
237
+ backgroundColor: isWindows ? "#1F1F1F" : "#00000000",
235
238
  minWidth,
236
239
  minHeight,
237
240
  alwaysOnTop,
@@ -586,6 +589,17 @@ var FloatingWindow = class _FloatingWindow {
586
589
  if (!activeInstance) return { success: false, error: "Window not available" };
587
590
  return { success: true, data: activeInstance.getResolvedUiConfig() };
588
591
  });
592
+ ipcMain.handle("sanqian-chat:setBackgroundColor", (_event, params) => {
593
+ if (!activeInstance) return { success: false, error: "Window not available" };
594
+ const win = activeInstance.getWindow();
595
+ if (!win) return { success: false, error: "Window not available" };
596
+ try {
597
+ win.setBackgroundColor(params.color);
598
+ return { success: true };
599
+ } catch (e) {
600
+ return { success: false, error: e instanceof Error ? e.message : "Failed to set background color" };
601
+ }
602
+ });
589
603
  }
590
604
  // Public API
591
605
  show() {
@@ -674,6 +688,7 @@ var FloatingWindow = class _FloatingWindow {
674
688
  ipcMain.removeHandler("sanqian-chat:setAlwaysOnTop");
675
689
  ipcMain.removeHandler("sanqian-chat:getAlwaysOnTop");
676
690
  ipcMain.removeHandler("sanqian-chat:getUiConfig");
691
+ ipcMain.removeHandler("sanqian-chat:setBackgroundColor");
677
692
  ipcHandlersRegistered = false;
678
693
  }
679
694
  }
@@ -144,6 +144,13 @@ interface SanqianChatAPI {
144
144
  data?: ChatUiConfigSerializable | null;
145
145
  error?: string;
146
146
  }>;
147
+ setBackgroundColor(params: {
148
+ color: string;
149
+ }): Promise<{
150
+ success: boolean;
151
+ error?: string;
152
+ }>;
153
+ getPlatform(): string;
147
154
  }
148
155
  declare global {
149
156
  interface Window {
@@ -36,7 +36,9 @@ var api = {
36
36
  hide: () => import_electron.ipcRenderer.invoke("sanqian-chat:hide"),
37
37
  setAlwaysOnTop: (params) => import_electron.ipcRenderer.invoke("sanqian-chat:setAlwaysOnTop", params),
38
38
  getAlwaysOnTop: () => import_electron.ipcRenderer.invoke("sanqian-chat:getAlwaysOnTop"),
39
- getUiConfig: () => import_electron.ipcRenderer.invoke("sanqian-chat:getUiConfig")
39
+ getUiConfig: () => import_electron.ipcRenderer.invoke("sanqian-chat:getUiConfig"),
40
+ setBackgroundColor: (params) => import_electron.ipcRenderer.invoke("sanqian-chat:setBackgroundColor", params),
41
+ getPlatform: () => process.platform
40
42
  };
41
43
  import_electron.contextBridge.exposeInMainWorld("sanqianChat", api);
42
44
  import_electron.contextBridge.exposeInMainWorld("__SANQIAN_CHAT_STYLE_MODE__", "full");
@@ -7624,9 +7624,37 @@ var SanqianChat = (0, import_react22.memo)(function SanqianChat2({
7624
7624
  });
7625
7625
 
7626
7626
  // src/renderer/components/FloatingChat.tsx
7627
+ var import_react24 = require("react");
7628
+
7629
+ // src/renderer/hooks/useWindowBackgroundSync.ts
7627
7630
  var import_react23 = require("react");
7631
+ var cachedPlatform = null;
7632
+ var getPlatform = () => {
7633
+ if (cachedPlatform !== null) return cachedPlatform;
7634
+ const api = typeof window !== "undefined" ? window.sanqianChat : null;
7635
+ if (api?.getPlatform) {
7636
+ cachedPlatform = api.getPlatform();
7637
+ return cachedPlatform;
7638
+ }
7639
+ return null;
7640
+ };
7641
+ var setBackgroundColor = (color) => {
7642
+ const api = typeof window !== "undefined" ? window.sanqianChat : null;
7643
+ if (api?.setBackgroundColor) {
7644
+ void api.setBackgroundColor({ color });
7645
+ }
7646
+ };
7647
+ function useWindowBackgroundSync(isDarkMode) {
7648
+ (0, import_react23.useEffect)(() => {
7649
+ if (getPlatform() !== "win32") return;
7650
+ const colors = getBaseColors(isDarkMode);
7651
+ setBackgroundColor(colors.bg);
7652
+ }, [isDarkMode]);
7653
+ }
7654
+
7655
+ // src/renderer/components/FloatingChat.tsx
7628
7656
  var import_jsx_runtime15 = require("react/jsx-runtime");
7629
- var FloatingChat = (0, import_react23.memo)(function FloatingChat2({
7657
+ var FloatingChat = (0, import_react24.memo)(function FloatingChat2({
7630
7658
  messages,
7631
7659
  isLoading,
7632
7660
  isStreaming,
@@ -7647,8 +7675,8 @@ var FloatingChat = (0, import_react23.memo)(function FloatingChat2({
7647
7675
  header,
7648
7676
  footer
7649
7677
  }) {
7650
- const chatContainerRef = (0, import_react23.useRef)(null);
7651
- const chatInputRef = (0, import_react23.useRef)(null);
7678
+ const chatContainerRef = (0, import_react24.useRef)(null);
7679
+ const chatInputRef = (0, import_react24.useRef)(null);
7652
7680
  useChatStyles();
7653
7681
  useFocusPersistence({
7654
7682
  containerRef: chatContainerRef,
@@ -7659,18 +7687,19 @@ var FloatingChat = (0, import_react23.memo)(function FloatingChat2({
7659
7687
  const themeMode = resolvedConfig?.theme ?? "auto";
7660
7688
  const { themeClass, isDarkMode } = useResolvedTheme(themeMode);
7661
7689
  const accentStyle = useAccentStyle(resolvedConfig?.accentColor);
7662
- const rootStyle = (0, import_react23.useMemo)(() => ({
7690
+ useWindowBackgroundSync(isDarkMode);
7691
+ const rootStyle = (0, import_react24.useMemo)(() => ({
7663
7692
  ...accentStyle || {},
7664
7693
  minHeight: "100vh",
7665
7694
  minWidth: "100vw"
7666
7695
  }), [accentStyle]);
7667
7696
  const resolvedLogo = logo ?? resolvedConfig?.logo;
7668
7697
  const resolvedLocale = resolvedConfig?.locale ?? locale;
7669
- const resolvedStrings = (0, import_react23.useMemo)(
7698
+ const resolvedStrings = (0, import_react24.useMemo)(
7670
7699
  () => resolveChatStrings(resolvedLocale, resolvedConfig?.strings),
7671
7700
  [resolvedLocale, resolvedConfig?.strings]
7672
7701
  );
7673
- const headerConfig = (0, import_react23.useMemo)(
7702
+ const headerConfig = (0, import_react24.useMemo)(
7674
7703
  () => {
7675
7704
  if (!resolvedConfig) {
7676
7705
  return resolvedLogo ? { logo: resolvedLogo } : void 0;
@@ -7683,7 +7712,7 @@ var FloatingChat = (0, import_react23.memo)(function FloatingChat2({
7683
7712
  [resolvedConfig, resolvedLogo]
7684
7713
  );
7685
7714
  const { logoNode, showPin, showClose, isPinned, togglePin, resolvedOnClose } = useChatHeader(headerConfig);
7686
- const emptyLogoNode = (0, import_react23.useMemo)(() => resolveLogoNode(resolvedLogo, "empty"), [resolvedLogo]);
7715
+ const emptyLogoNode = (0, import_react24.useMemo)(() => resolveLogoNode(resolvedLogo, "empty"), [resolvedLogo]);
7687
7716
  const inputPlaceholder = placeholder ?? resolvedStrings.inputPlaceholder;
7688
7717
  const showHeader = !!(header || logoNode || showPin || showClose);
7689
7718
  const defaultHeader = /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("header", { className: "flex h-9 flex-shrink-0 items-center px-2 border-b chat-divider-border", children: [
@@ -7722,7 +7751,7 @@ var FloatingChat = (0, import_react23.memo)(function FloatingChat2({
7722
7751
  ] })
7723
7752
  ] });
7724
7753
  const resolvedHeader = header ?? (showHeader ? defaultHeader : null);
7725
- const defaultRenderMessage = (0, import_react23.useCallback)(
7754
+ const defaultRenderMessage = (0, import_react24.useCallback)(
7726
7755
  (message) => {
7727
7756
  if (message.role === "tool") return null;
7728
7757
  const isUser = message.role === "user";
@@ -7736,7 +7765,7 @@ var FloatingChat = (0, import_react23.memo)(function FloatingChat2({
7736
7765
  },
7737
7766
  [renderContent]
7738
7767
  );
7739
- const defaultRenderHitl = (0, import_react23.useCallback)(
7768
+ const defaultRenderHitl = (0, import_react24.useCallback)(
7740
7769
  (interrupt, onApprove, onReject) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "p-4 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg m-2", children: [
7741
7770
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "font-medium mb-2", children: interrupt.type === "approval_request" ? resolvedStrings.hitlApprovalRequired : resolvedStrings.hitlInputRequired }),
7742
7771
  interrupt.tool && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("p", { className: "text-sm mb-2", children: [
@@ -7810,10 +7839,10 @@ var FloatingChat = (0, import_react23.memo)(function FloatingChat2({
7810
7839
  });
7811
7840
 
7812
7841
  // src/renderer/components/HistoryList.tsx
7813
- var import_react24 = require("react");
7842
+ var import_react25 = require("react");
7814
7843
  var import_jsx_runtime16 = require("react/jsx-runtime");
7815
7844
  function DeleteButton({ onClick, title, colors }) {
7816
- const [isHovered, setIsHovered] = (0, import_react24.useState)(false);
7845
+ const [isHovered, setIsHovered] = (0, import_react25.useState)(false);
7817
7846
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7818
7847
  "button",
7819
7848
  {
@@ -7857,7 +7886,7 @@ function DeleteButton({ onClick, title, colors }) {
7857
7886
  );
7858
7887
  }
7859
7888
  function LoadMoreButton({ onClick, colors, children }) {
7860
- const [isHovered, setIsHovered] = (0, import_react24.useState)(false);
7889
+ const [isHovered, setIsHovered] = (0, import_react25.useState)(false);
7861
7890
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7862
7891
  "button",
7863
7892
  {
@@ -7907,7 +7936,7 @@ function formatRelativeTime(dateStr, strings) {
7907
7936
  return date.toLocaleDateString(void 0, { month: "short", day: "numeric" });
7908
7937
  }
7909
7938
  }
7910
- var HistoryList = (0, import_react24.memo)(function HistoryList2({
7939
+ var HistoryList = (0, import_react25.memo)(function HistoryList2({
7911
7940
  conversations,
7912
7941
  selectedId,
7913
7942
  isLoading,
@@ -7919,11 +7948,11 @@ var HistoryList = (0, import_react24.memo)(function HistoryList2({
7919
7948
  isDarkMode = false,
7920
7949
  strings = {}
7921
7950
  }) {
7922
- const [hoveredId, setHoveredId] = (0, import_react24.useState)(null);
7923
- const loadMoreRef = (0, import_react24.useRef)(null);
7924
- const isLoadingRef = (0, import_react24.useRef)(isLoading);
7951
+ const [hoveredId, setHoveredId] = (0, import_react25.useState)(null);
7952
+ const loadMoreRef = (0, import_react25.useRef)(null);
7953
+ const isLoadingRef = (0, import_react25.useRef)(isLoading);
7925
7954
  isLoadingRef.current = isLoading;
7926
- (0, import_react24.useEffect)(() => {
7955
+ (0, import_react25.useEffect)(() => {
7927
7956
  if (!hasMore || loadError || !onLoadMore) return;
7928
7957
  const sentinel = loadMoreRef.current;
7929
7958
  if (!sentinel) return;
@@ -8020,10 +8049,10 @@ var HistoryList = (0, import_react24.memo)(function HistoryList2({
8020
8049
  });
8021
8050
 
8022
8051
  // src/renderer/components/CompactChat.tsx
8023
- var import_react25 = require("react");
8052
+ var import_react26 = require("react");
8024
8053
  var import_react_dom = require("react-dom");
8025
8054
  var import_jsx_runtime17 = require("react/jsx-runtime");
8026
- var CompactChat = (0, import_react25.memo)(function CompactChat2({
8055
+ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8027
8056
  adapter,
8028
8057
  config,
8029
8058
  logo,
@@ -8058,12 +8087,12 @@ var CompactChat = (0, import_react25.memo)(function CompactChat2({
8058
8087
  const { themeClass, isDarkMode: resolvedIsDarkMode } = useResolvedTheme(themeMode);
8059
8088
  const accentStyle = useAccentStyle(resolvedConfig?.accentColor);
8060
8089
  const resolvedLogo = logo ?? resolvedConfig?.logo;
8061
- const baseStrings = (0, import_react25.useMemo)(
8090
+ const baseStrings = (0, import_react26.useMemo)(
8062
8091
  () => resolveChatStrings(resolvedConfig?.locale, resolvedConfig?.strings),
8063
8092
  [resolvedConfig?.locale, resolvedConfig?.strings]
8064
8093
  );
8065
- const mergedStrings = (0, import_react25.useMemo)(() => ({ ...baseStrings, ...strings }), [baseStrings, strings]);
8066
- const headerConfig = (0, import_react25.useMemo)(
8094
+ const mergedStrings = (0, import_react26.useMemo)(() => ({ ...baseStrings, ...strings }), [baseStrings, strings]);
8095
+ const headerConfig = (0, import_react26.useMemo)(
8067
8096
  () => {
8068
8097
  if (!resolvedConfig) {
8069
8098
  return resolvedLogo ? { logo: resolvedLogo } : void 0;
@@ -8076,12 +8105,12 @@ var CompactChat = (0, import_react25.memo)(function CompactChat2({
8076
8105
  [resolvedConfig, resolvedLogo]
8077
8106
  );
8078
8107
  const { logoNode, showPin, showClose, isPinned, togglePin, resolvedOnClose } = useChatHeader(headerConfig);
8079
- const emptyLogoNode = (0, import_react25.useMemo)(() => resolveLogoNode(resolvedLogo, "empty"), [resolvedLogo]);
8080
- const chatContainerRef = (0, import_react25.useRef)(null);
8081
- const chatInputRef = (0, import_react25.useRef)(null);
8082
- const [showHistory, setShowHistory] = (0, import_react25.useState)(false);
8083
- const [connectionAlert, setConnectionAlert] = (0, import_react25.useState)(null);
8084
- const portalContainerRef = (0, import_react25.useRef)(inputPortalContainer ?? null);
8108
+ const emptyLogoNode = (0, import_react26.useMemo)(() => resolveLogoNode(resolvedLogo, "empty"), [resolvedLogo]);
8109
+ const chatContainerRef = (0, import_react26.useRef)(null);
8110
+ const chatInputRef = (0, import_react26.useRef)(null);
8111
+ const [showHistory, setShowHistory] = (0, import_react26.useState)(false);
8112
+ const [connectionAlert, setConnectionAlert] = (0, import_react26.useState)(null);
8113
+ const portalContainerRef = (0, import_react26.useRef)(inputPortalContainer ?? null);
8085
8114
  portalContainerRef.current = inputPortalContainer ?? null;
8086
8115
  const shouldRenderInputExternally = !!inputPortalContainer;
8087
8116
  const inputPlaceholder = placeholder ?? mergedStrings.inputPlaceholder;
@@ -8119,27 +8148,27 @@ var CompactChat = (0, import_react25.memo)(function CompactChat2({
8119
8148
  adapter,
8120
8149
  onError
8121
8150
  });
8122
- (0, import_react25.useEffect)(() => {
8151
+ (0, import_react26.useEffect)(() => {
8123
8152
  if (sendMessageRef) {
8124
8153
  sendMessageRef.current = chat.sendMessage;
8125
8154
  }
8126
8155
  }, [sendMessageRef, chat.sendMessage]);
8127
- (0, import_react25.useEffect)(() => {
8156
+ (0, import_react26.useEffect)(() => {
8128
8157
  if (newConversationRef) {
8129
8158
  newConversationRef.current = chat.newConversation;
8130
8159
  }
8131
8160
  }, [newConversationRef, chat.newConversation]);
8132
- (0, import_react25.useEffect)(() => {
8161
+ (0, import_react26.useEffect)(() => {
8133
8162
  if (parentFocusInputRef) {
8134
8163
  parentFocusInputRef.current = () => chatInputRef.current?.focus();
8135
8164
  }
8136
8165
  }, [parentFocusInputRef]);
8137
- (0, import_react25.useEffect)(() => {
8166
+ (0, import_react26.useEffect)(() => {
8138
8167
  if (parentSetTextRef) {
8139
8168
  parentSetTextRef.current = (text) => chatInputRef.current?.setValue(text);
8140
8169
  }
8141
8170
  }, [parentSetTextRef]);
8142
- (0, import_react25.useEffect)(() => {
8171
+ (0, import_react26.useEffect)(() => {
8143
8172
  if (onMessageReceived && chat.messages.length > 0) {
8144
8173
  const lastMessage = chat.messages[chat.messages.length - 1];
8145
8174
  if (lastMessage.role === "assistant" && !lastMessage.isStreaming) {
@@ -8147,12 +8176,12 @@ var CompactChat = (0, import_react25.memo)(function CompactChat2({
8147
8176
  }
8148
8177
  }
8149
8178
  }, [chat.messages, onMessageReceived]);
8150
- (0, import_react25.useEffect)(() => {
8179
+ (0, import_react26.useEffect)(() => {
8151
8180
  if (onLoadingChange) {
8152
8181
  onLoadingChange(chat.isLoading);
8153
8182
  }
8154
8183
  }, [chat.isLoading, onLoadingChange]);
8155
- (0, import_react25.useEffect)(() => {
8184
+ (0, import_react26.useEffect)(() => {
8156
8185
  if (onStateChange) {
8157
8186
  onStateChange({
8158
8187
  messages: chat.messages,
@@ -8160,19 +8189,19 @@ var CompactChat = (0, import_react25.memo)(function CompactChat2({
8160
8189
  });
8161
8190
  }
8162
8191
  }, [chat.messages, chat.conversationId, onStateChange]);
8163
- (0, import_react25.useEffect)(() => {
8192
+ (0, import_react26.useEffect)(() => {
8164
8193
  if (showHistory && connection.isConnected) {
8165
8194
  conversations.loadConversations();
8166
8195
  }
8167
8196
  }, [showHistory, connection.isConnected]);
8168
- const handleSelectConversation = (0, import_react25.useCallback)(
8197
+ const handleSelectConversation = (0, import_react26.useCallback)(
8169
8198
  async (id) => {
8170
8199
  await chat.loadConversation(id);
8171
8200
  setShowHistory(false);
8172
8201
  },
8173
8202
  [chat]
8174
8203
  );
8175
- const handleDeleteConversation = (0, import_react25.useCallback)(
8204
+ const handleDeleteConversation = (0, import_react26.useCallback)(
8176
8205
  async (id) => {
8177
8206
  await conversations.deleteConversation(id);
8178
8207
  if (id === chat.conversationId) {
@@ -8181,14 +8210,14 @@ var CompactChat = (0, import_react25.memo)(function CompactChat2({
8181
8210
  },
8182
8211
  [conversations, chat]
8183
8212
  );
8184
- const handleNewChat = (0, import_react25.useCallback)(() => {
8213
+ const handleNewChat = (0, import_react26.useCallback)(() => {
8185
8214
  chat.newConversation();
8186
8215
  setShowHistory(false);
8187
8216
  setTimeout(() => {
8188
8217
  chatInputRef.current?.focus();
8189
8218
  }, 0);
8190
8219
  }, [chat]);
8191
- (0, import_react25.useEffect)(() => {
8220
+ (0, import_react26.useEffect)(() => {
8192
8221
  const handleKeyDown = (e) => {
8193
8222
  const isMac2 = navigator.platform.includes("Mac");
8194
8223
  const modifierKey = isMac2 ? e.metaKey : e.ctrlKey;
@@ -8202,7 +8231,7 @@ var CompactChat = (0, import_react25.memo)(function CompactChat2({
8202
8231
  }, [handleNewChat]);
8203
8232
  const isMac = typeof navigator !== "undefined" && navigator.platform.includes("Mac");
8204
8233
  const shortcutKey = isMac ? "\u2318N" : "Ctrl+N";
8205
- const defaultRenderMessage = (0, import_react25.useCallback)((message) => {
8234
+ const defaultRenderMessage = (0, import_react26.useCallback)((message) => {
8206
8235
  if (message.role === "tool") return null;
8207
8236
  const isUser = message.role === "user";
8208
8237
  const hasToolCalls = message.toolCalls && message.toolCalls.length > 0;
@@ -8248,11 +8277,11 @@ var CompactChat = (0, import_react25.memo)(function CompactChat2({
8248
8277
  ] }) });
8249
8278
  }, [mergedStrings]);
8250
8279
  const containerClass = floating ? `chat-window-container ${themeClass} ${className}` : `flex h-full flex-col bg-[var(--chat-bg)] text-[var(--chat-text)] ${themeClass} ${className}`;
8251
- const baseColors = (0, import_react25.useMemo)(() => {
8280
+ const baseColors = (0, import_react26.useMemo)(() => {
8252
8281
  if (!floating) return null;
8253
8282
  return getBaseColors(resolvedIsDarkMode);
8254
8283
  }, [floating, resolvedIsDarkMode]);
8255
- const containerStyle = (0, import_react25.useMemo)(() => {
8284
+ const containerStyle = (0, import_react26.useMemo)(() => {
8256
8285
  if (!floating || !baseColors) return accentStyle;
8257
8286
  return {
8258
8287
  ...accentStyle,
@@ -7569,6 +7569,34 @@ var SanqianChat = memo10(function SanqianChat2({
7569
7569
 
7570
7570
  // src/renderer/components/FloatingChat.tsx
7571
7571
  import { memo as memo11, useCallback as useCallback12, useMemo as useMemo9, useRef as useRef11 } from "react";
7572
+
7573
+ // src/renderer/hooks/useWindowBackgroundSync.ts
7574
+ import { useEffect as useEffect16 } from "react";
7575
+ var cachedPlatform = null;
7576
+ var getPlatform = () => {
7577
+ if (cachedPlatform !== null) return cachedPlatform;
7578
+ const api = typeof window !== "undefined" ? window.sanqianChat : null;
7579
+ if (api?.getPlatform) {
7580
+ cachedPlatform = api.getPlatform();
7581
+ return cachedPlatform;
7582
+ }
7583
+ return null;
7584
+ };
7585
+ var setBackgroundColor = (color) => {
7586
+ const api = typeof window !== "undefined" ? window.sanqianChat : null;
7587
+ if (api?.setBackgroundColor) {
7588
+ void api.setBackgroundColor({ color });
7589
+ }
7590
+ };
7591
+ function useWindowBackgroundSync(isDarkMode) {
7592
+ useEffect16(() => {
7593
+ if (getPlatform() !== "win32") return;
7594
+ const colors = getBaseColors(isDarkMode);
7595
+ setBackgroundColor(colors.bg);
7596
+ }, [isDarkMode]);
7597
+ }
7598
+
7599
+ // src/renderer/components/FloatingChat.tsx
7572
7600
  import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
7573
7601
  var FloatingChat = memo11(function FloatingChat2({
7574
7602
  messages,
@@ -7603,6 +7631,7 @@ var FloatingChat = memo11(function FloatingChat2({
7603
7631
  const themeMode = resolvedConfig?.theme ?? "auto";
7604
7632
  const { themeClass, isDarkMode } = useResolvedTheme(themeMode);
7605
7633
  const accentStyle = useAccentStyle(resolvedConfig?.accentColor);
7634
+ useWindowBackgroundSync(isDarkMode);
7606
7635
  const rootStyle = useMemo9(() => ({
7607
7636
  ...accentStyle || {},
7608
7637
  minHeight: "100vh",
@@ -7754,7 +7783,7 @@ var FloatingChat = memo11(function FloatingChat2({
7754
7783
  });
7755
7784
 
7756
7785
  // src/renderer/components/HistoryList.tsx
7757
- import { memo as memo12, useState as useState14, useEffect as useEffect16, useRef as useRef12 } from "react";
7786
+ import { memo as memo12, useState as useState14, useEffect as useEffect17, useRef as useRef12 } from "react";
7758
7787
  import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
7759
7788
  function DeleteButton({ onClick, title, colors }) {
7760
7789
  const [isHovered, setIsHovered] = useState14(false);
@@ -7867,7 +7896,7 @@ var HistoryList = memo12(function HistoryList2({
7867
7896
  const loadMoreRef = useRef12(null);
7868
7897
  const isLoadingRef = useRef12(isLoading);
7869
7898
  isLoadingRef.current = isLoading;
7870
- useEffect16(() => {
7899
+ useEffect17(() => {
7871
7900
  if (!hasMore || loadError || !onLoadMore) return;
7872
7901
  const sentinel = loadMoreRef.current;
7873
7902
  if (!sentinel) return;
@@ -7964,7 +7993,7 @@ var HistoryList = memo12(function HistoryList2({
7964
7993
  });
7965
7994
 
7966
7995
  // src/renderer/components/CompactChat.tsx
7967
- import { memo as memo13, useRef as useRef13, useState as useState15, useEffect as useEffect17, useCallback as useCallback14, useMemo as useMemo10 } from "react";
7996
+ import { memo as memo13, useRef as useRef13, useState as useState15, useEffect as useEffect18, useCallback as useCallback14, useMemo as useMemo10 } from "react";
7968
7997
  import { createPortal } from "react-dom";
7969
7998
  import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
7970
7999
  var CompactChat = memo13(function CompactChat2({
@@ -8063,27 +8092,27 @@ var CompactChat = memo13(function CompactChat2({
8063
8092
  adapter,
8064
8093
  onError
8065
8094
  });
8066
- useEffect17(() => {
8095
+ useEffect18(() => {
8067
8096
  if (sendMessageRef) {
8068
8097
  sendMessageRef.current = chat.sendMessage;
8069
8098
  }
8070
8099
  }, [sendMessageRef, chat.sendMessage]);
8071
- useEffect17(() => {
8100
+ useEffect18(() => {
8072
8101
  if (newConversationRef) {
8073
8102
  newConversationRef.current = chat.newConversation;
8074
8103
  }
8075
8104
  }, [newConversationRef, chat.newConversation]);
8076
- useEffect17(() => {
8105
+ useEffect18(() => {
8077
8106
  if (parentFocusInputRef) {
8078
8107
  parentFocusInputRef.current = () => chatInputRef.current?.focus();
8079
8108
  }
8080
8109
  }, [parentFocusInputRef]);
8081
- useEffect17(() => {
8110
+ useEffect18(() => {
8082
8111
  if (parentSetTextRef) {
8083
8112
  parentSetTextRef.current = (text) => chatInputRef.current?.setValue(text);
8084
8113
  }
8085
8114
  }, [parentSetTextRef]);
8086
- useEffect17(() => {
8115
+ useEffect18(() => {
8087
8116
  if (onMessageReceived && chat.messages.length > 0) {
8088
8117
  const lastMessage = chat.messages[chat.messages.length - 1];
8089
8118
  if (lastMessage.role === "assistant" && !lastMessage.isStreaming) {
@@ -8091,12 +8120,12 @@ var CompactChat = memo13(function CompactChat2({
8091
8120
  }
8092
8121
  }
8093
8122
  }, [chat.messages, onMessageReceived]);
8094
- useEffect17(() => {
8123
+ useEffect18(() => {
8095
8124
  if (onLoadingChange) {
8096
8125
  onLoadingChange(chat.isLoading);
8097
8126
  }
8098
8127
  }, [chat.isLoading, onLoadingChange]);
8099
- useEffect17(() => {
8128
+ useEffect18(() => {
8100
8129
  if (onStateChange) {
8101
8130
  onStateChange({
8102
8131
  messages: chat.messages,
@@ -8104,7 +8133,7 @@ var CompactChat = memo13(function CompactChat2({
8104
8133
  });
8105
8134
  }
8106
8135
  }, [chat.messages, chat.conversationId, onStateChange]);
8107
- useEffect17(() => {
8136
+ useEffect18(() => {
8108
8137
  if (showHistory && connection.isConnected) {
8109
8138
  conversations.loadConversations();
8110
8139
  }
@@ -8132,7 +8161,7 @@ var CompactChat = memo13(function CompactChat2({
8132
8161
  chatInputRef.current?.focus();
8133
8162
  }, 0);
8134
8163
  }, [chat]);
8135
- useEffect17(() => {
8164
+ useEffect18(() => {
8136
8165
  const handleKeyDown = (e) => {
8137
8166
  const isMac2 = navigator.platform.includes("Mac");
8138
8167
  const modifierKey = isMac2 ? e.metaKey : e.ctrlKey;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yushaw/sanqian-chat",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Floating chat window SDK for Sanqian AI Assistant",
5
5
  "main": "./dist/main/index.js",
6
6
  "types": "./dist/main/index.d.ts",
@@ -43,7 +43,7 @@
43
43
  "test:watch": "vitest"
44
44
  },
45
45
  "dependencies": {
46
- "@yushaw/sanqian-sdk": "file:../sdk",
46
+ "@yushaw/sanqian-sdk": "^0.3.0",
47
47
  "react-virtuoso": "^4.15.0",
48
48
  "rehype-harden": "^1.1.6",
49
49
  "remark-gfm": "^4.0.1",