@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.
- package/dist/main/index.js +17 -2
- package/dist/main/index.mjs +17 -2
- package/dist/preload/index.d.ts +7 -0
- package/dist/preload/index.js +3 -1
- package/dist/renderer/index.js +72 -43
- package/dist/renderer/index.mjs +41 -12
- package/package.json +2 -2
package/dist/main/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
}
|
package/dist/main/index.mjs
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
}
|
package/dist/preload/index.d.ts
CHANGED
|
@@ -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 {
|
package/dist/preload/index.js
CHANGED
|
@@ -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");
|
package/dist/renderer/index.js
CHANGED
|
@@ -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,
|
|
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,
|
|
7651
|
-
const chatInputRef = (0,
|
|
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
|
-
|
|
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,
|
|
7698
|
+
const resolvedStrings = (0, import_react24.useMemo)(
|
|
7670
7699
|
() => resolveChatStrings(resolvedLocale, resolvedConfig?.strings),
|
|
7671
7700
|
[resolvedLocale, resolvedConfig?.strings]
|
|
7672
7701
|
);
|
|
7673
|
-
const headerConfig = (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
7923
|
-
const loadMoreRef = (0,
|
|
7924
|
-
const isLoadingRef = (0,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
8066
|
-
const headerConfig = (0,
|
|
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,
|
|
8080
|
-
const chatContainerRef = (0,
|
|
8081
|
-
const chatInputRef = (0,
|
|
8082
|
-
const [showHistory, setShowHistory] = (0,
|
|
8083
|
-
const [connectionAlert, setConnectionAlert] = (0,
|
|
8084
|
-
const portalContainerRef = (0,
|
|
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,
|
|
8151
|
+
(0, import_react26.useEffect)(() => {
|
|
8123
8152
|
if (sendMessageRef) {
|
|
8124
8153
|
sendMessageRef.current = chat.sendMessage;
|
|
8125
8154
|
}
|
|
8126
8155
|
}, [sendMessageRef, chat.sendMessage]);
|
|
8127
|
-
(0,
|
|
8156
|
+
(0, import_react26.useEffect)(() => {
|
|
8128
8157
|
if (newConversationRef) {
|
|
8129
8158
|
newConversationRef.current = chat.newConversation;
|
|
8130
8159
|
}
|
|
8131
8160
|
}, [newConversationRef, chat.newConversation]);
|
|
8132
|
-
(0,
|
|
8161
|
+
(0, import_react26.useEffect)(() => {
|
|
8133
8162
|
if (parentFocusInputRef) {
|
|
8134
8163
|
parentFocusInputRef.current = () => chatInputRef.current?.focus();
|
|
8135
8164
|
}
|
|
8136
8165
|
}, [parentFocusInputRef]);
|
|
8137
|
-
(0,
|
|
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,
|
|
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,
|
|
8179
|
+
(0, import_react26.useEffect)(() => {
|
|
8151
8180
|
if (onLoadingChange) {
|
|
8152
8181
|
onLoadingChange(chat.isLoading);
|
|
8153
8182
|
}
|
|
8154
8183
|
}, [chat.isLoading, onLoadingChange]);
|
|
8155
|
-
(0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
8284
|
+
const containerStyle = (0, import_react26.useMemo)(() => {
|
|
8256
8285
|
if (!floating || !baseColors) return accentStyle;
|
|
8257
8286
|
return {
|
|
8258
8287
|
...accentStyle,
|
package/dist/renderer/index.mjs
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
8095
|
+
useEffect18(() => {
|
|
8067
8096
|
if (sendMessageRef) {
|
|
8068
8097
|
sendMessageRef.current = chat.sendMessage;
|
|
8069
8098
|
}
|
|
8070
8099
|
}, [sendMessageRef, chat.sendMessage]);
|
|
8071
|
-
|
|
8100
|
+
useEffect18(() => {
|
|
8072
8101
|
if (newConversationRef) {
|
|
8073
8102
|
newConversationRef.current = chat.newConversation;
|
|
8074
8103
|
}
|
|
8075
8104
|
}, [newConversationRef, chat.newConversation]);
|
|
8076
|
-
|
|
8105
|
+
useEffect18(() => {
|
|
8077
8106
|
if (parentFocusInputRef) {
|
|
8078
8107
|
parentFocusInputRef.current = () => chatInputRef.current?.focus();
|
|
8079
8108
|
}
|
|
8080
8109
|
}, [parentFocusInputRef]);
|
|
8081
|
-
|
|
8110
|
+
useEffect18(() => {
|
|
8082
8111
|
if (parentSetTextRef) {
|
|
8083
8112
|
parentSetTextRef.current = (text) => chatInputRef.current?.setValue(text);
|
|
8084
8113
|
}
|
|
8085
8114
|
}, [parentSetTextRef]);
|
|
8086
|
-
|
|
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
|
-
|
|
8123
|
+
useEffect18(() => {
|
|
8095
8124
|
if (onLoadingChange) {
|
|
8096
8125
|
onLoadingChange(chat.isLoading);
|
|
8097
8126
|
}
|
|
8098
8127
|
}, [chat.isLoading, onLoadingChange]);
|
|
8099
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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": "
|
|
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",
|