mirror of
https://github.com/infinilabs/coco-app.git
synced 2025-12-16 19:47:43 +01:00
216 lines
6.8 KiB
TypeScript
216 lines
6.8 KiB
TypeScript
import { useCallback } from "react";
|
|
import { ArrowDown01, CornerDownLeft } from "lucide-react";
|
|
import { useTranslation } from "react-i18next";
|
|
import clsx from "clsx";
|
|
|
|
import CommonIcon from "@/components/Common/Icons/CommonIcon";
|
|
import Copyright from "@/components/Common/Copyright";
|
|
import PinOffIcon from "@/icons/PinOff";
|
|
import PinIcon from "@/icons/Pin";
|
|
import logoImg from "@/assets/icon.svg";
|
|
import { useAppStore } from "@/stores/appStore";
|
|
import { useSearchStore } from "@/stores/searchStore";
|
|
import { useUpdateStore } from "@/stores/updateStore";
|
|
import VisibleKey from "../VisibleKey";
|
|
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
|
import { formatKey } from "@/utils/keyboardUtils";
|
|
import source_default_img from "@/assets/images/source_default.png";
|
|
import source_default_dark_img from "@/assets/images/source_default_dark.png";
|
|
import { useThemeStore } from "@/stores/themeStore";
|
|
import platformAdapter from "@/utils/platformAdapter";
|
|
import FontIcon from "../Icons/FontIcon";
|
|
|
|
interface FooterProps {
|
|
setIsPinnedWeb?: (value: boolean) => void;
|
|
}
|
|
|
|
export default function Footer({ setIsPinnedWeb }: FooterProps) {
|
|
const { t } = useTranslation();
|
|
|
|
const {
|
|
sourceData,
|
|
goAskAi,
|
|
selectedExtension,
|
|
visibleExtensionStore,
|
|
visibleExtensionDetail,
|
|
} = useSearchStore();
|
|
|
|
const isDark = useThemeStore((state) => state.isDark);
|
|
|
|
const { isTauri, isPinned, setIsPinned } = useAppStore();
|
|
|
|
const { setVisible, updateInfo } = useUpdateStore();
|
|
|
|
const { fixedWindow, modifierKey } = useShortcutsStore();
|
|
|
|
const setWindowAlwaysOnTop = useCallback(async (isPinned: boolean) => {
|
|
setIsPinnedWeb?.(isPinned);
|
|
return platformAdapter.setAlwaysOnTop(isPinned);
|
|
}, []);
|
|
|
|
const togglePin = async () => {
|
|
try {
|
|
const newPinned = !isPinned;
|
|
await setWindowAlwaysOnTop(newPinned);
|
|
setIsPinned(newPinned);
|
|
} catch (err) {
|
|
console.error("Failed to toggle window pin state:", err);
|
|
setIsPinned(isPinned);
|
|
}
|
|
};
|
|
|
|
const openSetting = useCallback(() => {
|
|
return platformAdapter.emitEvent("open_settings", "");
|
|
}, []);
|
|
|
|
const renderLeft = () => {
|
|
if (sourceData?.source?.name) {
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<CommonIcon
|
|
item={sourceData}
|
|
renderOrder={["connector_icon", "default_icon"]}
|
|
itemIcon={sourceData?.source?.icon}
|
|
defaultIcon={isDark ? source_default_dark_img : source_default_img}
|
|
className="w-4 h-4"
|
|
/>
|
|
|
|
<span className="text-sm">{sourceData.source.name}</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (visibleExtensionDetail && selectedExtension) {
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<img src={selectedExtension.icon} className="size-5" />
|
|
<span className="text-sm">{selectedExtension.name}</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (visibleExtensionStore) {
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<FontIcon name="font_Store" className="size-5" />
|
|
<span className="text-sm">Extension Store</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<img
|
|
src={logoImg}
|
|
className="w-4 h-4 cursor-pointer"
|
|
onClick={openSetting}
|
|
alt={t("search.footer.logoAlt")}
|
|
/>
|
|
|
|
<div className="relative text-xs text-gray-500 dark:text-gray-400">
|
|
{updateInfo?.available ? (
|
|
<div className="cursor-pointer" onClick={() => setVisible(true)}>
|
|
<span>{t("search.footer.updateAvailable")}</span>
|
|
<span className="absolute top-0 -right-2 size-1.5 bg-[#FF3434] rounded-full"></span>
|
|
</div>
|
|
) : (
|
|
sourceData?.source?.name ||
|
|
t("search.footer.version", {
|
|
version: process.env.VERSION || "v1.0.0",
|
|
})
|
|
)}
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div
|
|
data-tauri-drag-region={isTauri}
|
|
className="px-4 z-999 mx-[1px] h-8 absolute bottom-0 left-0 right-0 border-t border-gray-200 dark:border-gray-700 flex items-center justify-between rounded-md rounded-t-none overflow-hidden"
|
|
>
|
|
{isTauri ? (
|
|
<div className="flex items-center">
|
|
<div className="flex items-center space-x-2">
|
|
{renderLeft()}
|
|
|
|
<button
|
|
onClick={togglePin}
|
|
className={clsx({
|
|
"text-blue-500": isPinned,
|
|
"pl-2": updateInfo?.available,
|
|
})}
|
|
>
|
|
<VisibleKey shortcut={fixedWindow} onKeyPress={togglePin}>
|
|
{isPinned ? <PinIcon /> : <PinOffIcon />}
|
|
</VisibleKey>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<Copyright />
|
|
)}
|
|
|
|
<div className={`flex mobile:hidden items-center gap-3`}>
|
|
<div
|
|
className={clsx(
|
|
"gap-1 flex items-center text-[#666] dark:text-[#666] text-xs",
|
|
{
|
|
hidden:
|
|
(visibleExtensionStore && !selectedExtension) ||
|
|
visibleExtensionDetail ||
|
|
selectedExtension?.installed,
|
|
}
|
|
)}
|
|
>
|
|
<span className="mr-1.5">
|
|
{goAskAi
|
|
? t("search.askCocoAi.continueInChat")
|
|
: (visibleExtensionStore || visibleExtensionDetail) &&
|
|
!selectedExtension?.installed
|
|
? t("search.footer.install")
|
|
: t("search.footer.select")}
|
|
</span>
|
|
<kbd className="coco-modal-footer-commands-key pr-1">
|
|
<div className="flex items-center justify-center min-w-3 h-3">
|
|
{formatKey(modifierKey)}
|
|
</div>
|
|
</kbd>
|
|
+
|
|
<kbd className="coco-modal-footer-commands-key pr-1">
|
|
{goAskAi || selectedExtension ? (
|
|
<CornerDownLeft className="w-3 h-3" />
|
|
) : (
|
|
<ArrowDown01 className="w-3 h-3" />
|
|
)}
|
|
</kbd>
|
|
</div>
|
|
|
|
<div
|
|
className={clsx(
|
|
"flex items-center text-[#666] dark:text-[#666] text-xs",
|
|
{
|
|
hidden:
|
|
(visibleExtensionStore && !selectedExtension) ||
|
|
(visibleExtensionDetail && selectedExtension?.installed),
|
|
}
|
|
)}
|
|
>
|
|
<span className="mr-1.5">
|
|
{goAskAi
|
|
? t("search.askCocoAi.copy")
|
|
: visibleExtensionDetail && !selectedExtension?.installed
|
|
? t("search.footer.install")
|
|
: visibleExtensionStore
|
|
? t("search.footer.details")
|
|
: t("search.footer.open")}
|
|
</span>
|
|
<kbd className="coco-modal-footer-commands-key pr-1">
|
|
<CornerDownLeft className="w-3 h-3" />
|
|
</kbd>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|