mirror of
https://github.com/infinilabs/coco-app.git
synced 2026-08-29 10:09:30 +02:00
feat: add web pages (#277)
* feat: add web pages * feat: add web page * refactor: search page * feat: add tsup build web componet * chore: update timeout time * build: build web page * build: build search chat * chore: add web page * docs: update release note
This commit is contained in:
@@ -1,197 +1,47 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { invoke, isTauri } from "@tauri-apps/api/core";
|
||||
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
||||
import { LogicalSize } from "@tauri-apps/api/dpi";
|
||||
import clsx from "clsx";
|
||||
import { useCallback } from "react";
|
||||
|
||||
import InputBox from "@/components/Search/InputBox";
|
||||
import Search from "@/components/Search/Search";
|
||||
import ChatAI, { ChatAIRef } from "@/components/Assistant/Chat";
|
||||
import { useAppStore } from "@/stores/appStore";
|
||||
import { useAuthStore } from "@/stores/authStore";
|
||||
import { isLinux, isWin } from "@/utils/platform";
|
||||
import UpdateApp from "@/components/UpdateApp";
|
||||
import { listen, UnlistenFn } from "@tauri-apps/api/event";
|
||||
import { IStartupStore, useStartupStore } from "@/stores/startupStore";
|
||||
import { useAsyncEffect } from "ahooks";
|
||||
import SearchChat from "@/pages/web/SearchChat";
|
||||
import platformAdapter from "@/utils/platformAdapter";
|
||||
|
||||
let showCocoListen: UnlistenFn;
|
||||
function MainApp() {
|
||||
const querySearch = useCallback(async (input: string) => {
|
||||
try {
|
||||
const response: any = await platformAdapter.invokeBackend("query_coco_fusion", {
|
||||
from: 0,
|
||||
size: 10,
|
||||
queryStrings: { query: input },
|
||||
});
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error("query_coco_fusion error:", error);
|
||||
throw error;
|
||||
}
|
||||
}, []);
|
||||
|
||||
export default function DesktopApp() {
|
||||
const initializeListeners = useAppStore((state) => state.initializeListeners);
|
||||
const initializeListeners_auth = useAuthStore(
|
||||
(state) => state.initializeListeners
|
||||
const queryDocuments = useCallback(
|
||||
async (from: number, size: number, queryStrings: any) => {
|
||||
try {
|
||||
const response: any = await platformAdapter.invokeBackend("query_coco_fusion", {
|
||||
from,
|
||||
size,
|
||||
queryStrings,
|
||||
});
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error("query_coco_fusion error:", error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const isPinned = useAppStore((state) => state.isPinned);
|
||||
|
||||
useEffect(() => {
|
||||
invoke("get_app_search_source");
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
initializeListeners();
|
||||
initializeListeners_auth();
|
||||
|
||||
// Listen for window focus and blur events
|
||||
const handleBlur = async () => {
|
||||
console.log("Window blurred");
|
||||
if (isPinned) {
|
||||
return;
|
||||
}
|
||||
|
||||
invoke("hide_coco").then(() => {
|
||||
console.log("Hide Coco");
|
||||
});
|
||||
};
|
||||
|
||||
const handleFocus = () => {
|
||||
// Optionally, show the window if needed when focus is regained
|
||||
// console.log("Window focused");
|
||||
};
|
||||
|
||||
window.addEventListener("blur", handleBlur);
|
||||
window.addEventListener("focus", handleFocus);
|
||||
|
||||
// Clean up event listeners on component unmount
|
||||
return () => {
|
||||
window.removeEventListener("blur", handleBlur);
|
||||
window.removeEventListener("focus", handleFocus);
|
||||
};
|
||||
}, [isPinned]);
|
||||
|
||||
const chatAIRef = useRef<ChatAIRef>(null);
|
||||
|
||||
const [isChatMode, setIsChatMode] = useState(false);
|
||||
const [input, setInput] = useState("");
|
||||
const [isTransitioned, setIsTransitioned] = useState(false);
|
||||
|
||||
const [isSearchActive, setIsSearchActive] = useState(false);
|
||||
const [isDeepThinkActive, setIsDeepThinkActive] = useState(false);
|
||||
|
||||
const defaultStartupWindow = useStartupStore((state) => {
|
||||
return state.defaultStartupWindow;
|
||||
});
|
||||
const setDefaultStartupWindow = useStartupStore((state) => {
|
||||
return state.setDefaultStartupWindow;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
listen<IStartupStore>("change-startup-store", ({ payload }) => {
|
||||
setDefaultStartupWindow(payload.defaultStartupWindow);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useAsyncEffect(async () => {
|
||||
showCocoListen?.();
|
||||
|
||||
showCocoListen = await listen("show-coco", () => {
|
||||
changeMode(defaultStartupWindow === "chatMode");
|
||||
});
|
||||
}, [defaultStartupWindow]);
|
||||
|
||||
async function changeMode(value: boolean) {
|
||||
setIsChatMode(value);
|
||||
setIsTransitioned(value);
|
||||
}
|
||||
|
||||
function changeInput(value: string) {
|
||||
setInput(value);
|
||||
}
|
||||
|
||||
const handleSendMessage = async (value: string) => {
|
||||
setInput(value);
|
||||
if (isChatMode) {
|
||||
if (isTauri()) {
|
||||
await getCurrentWebviewWindow()?.setSize(new LogicalSize(680, 596));
|
||||
}
|
||||
chatAIRef.current?.init(value);
|
||||
}
|
||||
};
|
||||
const cancelChat = () => {
|
||||
chatAIRef.current?.cancelChat();
|
||||
};
|
||||
|
||||
const reconnect = () => {
|
||||
chatAIRef.current?.reconnect();
|
||||
};
|
||||
const isTyping = false;
|
||||
|
||||
return (
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
className={clsx(
|
||||
"size-full m-auto overflow-hidden relative bg-no-repeat bg-cover bg-center",
|
||||
[
|
||||
isTransitioned
|
||||
? "bg-chat_bg_light dark:bg-chat_bg_dark"
|
||||
: "bg-search_bg_light dark:bg-search_bg_dark",
|
||||
],
|
||||
{
|
||||
"rounded-xl": !isWin,
|
||||
"border border-[#E6E6E6] dark:border-[#272626]": isLinux,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
className={`p-2 pb-0 absolute w-full flex items-center justify-center transition-all duration-500 ${
|
||||
isTransitioned
|
||||
? "top-[calc(100vh-90px)] h-[90px] border-t"
|
||||
: "top-0 h-[90px] border-b"
|
||||
} border-[#E6E6E6] dark:border-[#272626]`}
|
||||
>
|
||||
<InputBox
|
||||
isChatMode={isChatMode}
|
||||
inputValue={input}
|
||||
onSend={handleSendMessage}
|
||||
disabled={isTyping}
|
||||
disabledChange={cancelChat}
|
||||
changeMode={changeMode}
|
||||
changeInput={changeInput}
|
||||
reconnect={reconnect}
|
||||
isSearchActive={isSearchActive}
|
||||
setIsSearchActive={() => setIsSearchActive((prev) => !prev)}
|
||||
isDeepThinkActive={isDeepThinkActive}
|
||||
setIsDeepThinkActive={() => setIsDeepThinkActive((prev) => !prev)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
className={`absolute w-full transition-opacity duration-500 ${
|
||||
isTransitioned ? "opacity-0 pointer-events-none" : "opacity-100"
|
||||
} bottom-0 h-[calc(100vh-90px)] `}
|
||||
>
|
||||
<Search
|
||||
key="Search"
|
||||
input={input}
|
||||
isChatMode={isChatMode}
|
||||
changeInput={changeInput}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
className={`absolute w-full transition-all duration-500 select-auto ${
|
||||
isTransitioned
|
||||
? "top-0 opacity-100 pointer-events-auto"
|
||||
: "-top-[506px] opacity-0 pointer-events-none"
|
||||
} h-[calc(100vh-90px)]`}
|
||||
>
|
||||
{isTransitioned && isChatMode ? (
|
||||
<ChatAI
|
||||
ref={chatAIRef}
|
||||
key="ChatAI"
|
||||
isTransitioned={isTransitioned}
|
||||
changeInput={changeInput}
|
||||
isSearchActive={isSearchActive}
|
||||
isDeepThinkActive={isDeepThinkActive}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<UpdateApp />
|
||||
</div>
|
||||
<SearchChat
|
||||
querySearch={querySearch}
|
||||
queryDocuments={queryDocuments}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default MainApp;
|
||||
|
||||
Reference in New Issue
Block a user