mirror of
https://github.com/infinilabs/coco-app.git
synced 2025-12-16 11:37:47 +01:00
fix: resolve pinned window shortcut not working (#917)
* fix: fix pinned window shortcut not working * docs: update changelog * refactor: update * Update _index.md --------- Co-authored-by: Medcl <m@medcl.net>
This commit is contained in:
@@ -20,6 +20,7 @@ feat: support opening logs from about page #915
|
||||
|
||||
fix: automatic update of service list #913
|
||||
fix: duplicate chat content #916
|
||||
fix: resolve pinned window shortcut not working (#917)
|
||||
|
||||
### ✈️ Improvements
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { MessageSquarePlus } from "lucide-react";
|
||||
import clsx from "clsx";
|
||||
|
||||
import HistoryIcon from "@/icons/History";
|
||||
import PinOffIcon from "@/icons/PinOff";
|
||||
import PinIcon from "@/icons/Pin";
|
||||
import WindowsFullIcon from "@/icons/WindowsFull";
|
||||
import { useAppStore } from "@/stores/appStore";
|
||||
import type { Chat } from "@/types/chat";
|
||||
@@ -12,6 +9,7 @@ import { useShortcutsStore } from "@/stores/shortcutsStore";
|
||||
import { HISTORY_PANEL_ID } from "@/constants";
|
||||
import { AssistantList } from "./AssistantList";
|
||||
import { ServerList } from "./ServerList";
|
||||
import TogglePin from "../Common/TogglePin";
|
||||
|
||||
interface ChatHeaderProps {
|
||||
clearChat: () => void;
|
||||
@@ -34,21 +32,9 @@ export function ChatHeader({
|
||||
showChatHistory = true,
|
||||
assistantIDs,
|
||||
}: ChatHeaderProps) {
|
||||
const { isPinned, setIsPinned, isTauri } = useAppStore();
|
||||
const { isTauri } = useAppStore();
|
||||
|
||||
const { historicalRecords, newSession, fixedWindow, external } =
|
||||
useShortcutsStore();
|
||||
|
||||
const togglePin = async () => {
|
||||
try {
|
||||
const { isPinned } = useAppStore.getState();
|
||||
|
||||
setIsPinned(!isPinned);
|
||||
} catch (err) {
|
||||
console.error("Failed to toggle window pin state:", err);
|
||||
setIsPinned(isPinned);
|
||||
}
|
||||
};
|
||||
const { historicalRecords, newSession, external } = useShortcutsStore();
|
||||
|
||||
return (
|
||||
<header
|
||||
@@ -101,16 +87,7 @@ export function ChatHeader({
|
||||
|
||||
{isTauri ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={togglePin}
|
||||
className={clsx("inline-flex", {
|
||||
"text-blue-500": isPinned,
|
||||
})}
|
||||
>
|
||||
<VisibleKey shortcut={fixedWindow} onKeyPress={togglePin}>
|
||||
{isPinned ? <PinIcon /> : <PinOffIcon />}
|
||||
</VisibleKey>
|
||||
</button>
|
||||
<TogglePin className="inline-flex" />
|
||||
|
||||
<ServerList clearChat={clearChat} />
|
||||
|
||||
|
||||
50
src/components/Common/TogglePin.tsx
Normal file
50
src/components/Common/TogglePin.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import { useAppStore } from "@/stores/appStore";
|
||||
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
||||
import clsx from "clsx";
|
||||
import VisibleKey from "./VisibleKey";
|
||||
import { FC, HTMLAttributes } from "react";
|
||||
import PinOffIcon from "@/icons/PinOff";
|
||||
import PinIcon from "@/icons/Pin";
|
||||
|
||||
interface TogglePinProps extends HTMLAttributes<HTMLButtonElement> {
|
||||
setIsPinnedWeb?: (value: boolean) => void;
|
||||
}
|
||||
|
||||
const TogglePin: FC<TogglePinProps> = (props) => {
|
||||
const { className, setIsPinnedWeb } = props;
|
||||
const { isPinned, setIsPinned } = useAppStore();
|
||||
const { fixedWindow } = useShortcutsStore();
|
||||
|
||||
const togglePin = async () => {
|
||||
const { isTauri, isPinned } = useAppStore.getState();
|
||||
|
||||
try {
|
||||
const nextPinned = !isPinned;
|
||||
|
||||
if (!isTauri) {
|
||||
setIsPinnedWeb?.(nextPinned);
|
||||
}
|
||||
|
||||
setIsPinned(nextPinned);
|
||||
} catch (err) {
|
||||
setIsPinned(isPinned);
|
||||
|
||||
console.error("Failed to toggle window pin state:", err);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={togglePin}
|
||||
className={clsx(className, {
|
||||
"text-blue-500": isPinned,
|
||||
})}
|
||||
>
|
||||
<VisibleKey shortcut={fixedWindow} onKeyPress={togglePin}>
|
||||
{isPinned ? <PinIcon /> : <PinOffIcon />}
|
||||
</VisibleKey>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default TogglePin;
|
||||
@@ -5,13 +5,10 @@ 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";
|
||||
@@ -19,6 +16,7 @@ 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";
|
||||
import TogglePin from "../TogglePin";
|
||||
|
||||
interface FooterProps {
|
||||
setIsPinnedWeb?: (value: boolean) => void;
|
||||
@@ -37,28 +35,11 @@ export default function Footer({ setIsPinnedWeb }: FooterProps) {
|
||||
|
||||
const isDark = useThemeStore((state) => state.isDark);
|
||||
|
||||
const { isTauri, isPinned, setIsPinned } = useAppStore();
|
||||
const { isTauri } = useAppStore();
|
||||
|
||||
const { setVisible, updateInfo, skipVersions } = useUpdateStore();
|
||||
|
||||
const { fixedWindow, modifierKey } = useShortcutsStore();
|
||||
|
||||
const togglePin = async () => {
|
||||
try {
|
||||
const { isTauri, isPinned } = useAppStore.getState();
|
||||
|
||||
const nextPinned = !isPinned;
|
||||
|
||||
if (!isTauri) {
|
||||
setIsPinnedWeb?.(nextPinned);
|
||||
}
|
||||
|
||||
setIsPinned(nextPinned);
|
||||
} catch (err) {
|
||||
console.error("Failed to toggle window pin state:", err);
|
||||
setIsPinned(isPinned);
|
||||
}
|
||||
};
|
||||
const { modifierKey } = useShortcutsStore();
|
||||
|
||||
const openSetting = useCallback(() => {
|
||||
return platformAdapter.emitEvent("open_settings", "");
|
||||
@@ -88,7 +69,10 @@ export default function Footer({ setIsPinnedWeb }: FooterProps) {
|
||||
if (visibleExtensionDetail && selectedExtension) {
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<img src={selectedExtension.icon} className="size-5 dark:drop-shadow-[0_0_6px_rgb(255,255,255)]" />
|
||||
<img
|
||||
src={selectedExtension.icon}
|
||||
className="size-5 dark:drop-shadow-[0_0_6px_rgb(255,255,255)]"
|
||||
/>
|
||||
<span className="text-sm">{selectedExtension.name}</span>
|
||||
</div>
|
||||
);
|
||||
@@ -139,17 +123,12 @@ export default function Footer({ setIsPinnedWeb }: FooterProps) {
|
||||
<div className="flex items-center space-x-2">
|
||||
{renderLeft()}
|
||||
|
||||
<button
|
||||
onClick={togglePin}
|
||||
<TogglePin
|
||||
className={clsx({
|
||||
"text-blue-500": isPinned,
|
||||
"pl-2": hasUpdate,
|
||||
})}
|
||||
>
|
||||
<VisibleKey shortcut={fixedWindow} onKeyPress={togglePin}>
|
||||
{isPinned ? <PinIcon /> : <PinOffIcon />}
|
||||
</VisibleKey>
|
||||
</button>
|
||||
setIsPinnedWeb={setIsPinnedWeb}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
|
||||
@@ -6,6 +6,9 @@ import { last } from "lodash-es";
|
||||
import { POPOVER_PANEL_SELECTOR } from "@/constants";
|
||||
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
||||
import { useAppStore } from "@/stores/appStore";
|
||||
import { KeyType } from "ahooks/lib/useKeyPress";
|
||||
|
||||
const keyTriggerMap = new Map<KeyType, number>();
|
||||
|
||||
interface VisibleKeyProps extends HTMLAttributes<HTMLDivElement> {
|
||||
shortcut: string;
|
||||
@@ -60,8 +63,16 @@ const VisibleKey: FC<VisibleKeyProps> = (props) => {
|
||||
setVisibleShortcut(isChildInPopover && modifierKeyPressed);
|
||||
}, [openPopover, modifierKeyPressed]);
|
||||
|
||||
useKeyPress(`${modifierKey}.${shortcut}`, (event) => {
|
||||
if (!visibleShortcut) return;
|
||||
useKeyPress(`${modifierKey}.${shortcut}`, (event, key) => {
|
||||
if (!visibleShortcut || event.repeat) return;
|
||||
|
||||
const now = Date.now();
|
||||
const last = keyTriggerMap.get(key) ?? 0;
|
||||
const wait = 100;
|
||||
|
||||
if (now - last < wait) return;
|
||||
|
||||
keyTriggerMap.set(key, now);
|
||||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
Reference in New Issue
Block a user