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:
ayangweb
2025-10-11 14:46:24 +08:00
committed by GitHub
parent 4e58bc4b2c
commit 6aec9cbae2
5 changed files with 78 additions and 60 deletions

View File

@@ -20,6 +20,7 @@ feat: support opening logs from about page #915
fix: automatic update of service list #913 fix: automatic update of service list #913
fix: duplicate chat content #916 fix: duplicate chat content #916
fix: resolve pinned window shortcut not working (#917)
### ✈️ Improvements ### ✈️ Improvements

View File

@@ -1,9 +1,6 @@
import { MessageSquarePlus } from "lucide-react"; import { MessageSquarePlus } from "lucide-react";
import clsx from "clsx";
import HistoryIcon from "@/icons/History"; import HistoryIcon from "@/icons/History";
import PinOffIcon from "@/icons/PinOff";
import PinIcon from "@/icons/Pin";
import WindowsFullIcon from "@/icons/WindowsFull"; import WindowsFullIcon from "@/icons/WindowsFull";
import { useAppStore } from "@/stores/appStore"; import { useAppStore } from "@/stores/appStore";
import type { Chat } from "@/types/chat"; import type { Chat } from "@/types/chat";
@@ -12,6 +9,7 @@ import { useShortcutsStore } from "@/stores/shortcutsStore";
import { HISTORY_PANEL_ID } from "@/constants"; import { HISTORY_PANEL_ID } from "@/constants";
import { AssistantList } from "./AssistantList"; import { AssistantList } from "./AssistantList";
import { ServerList } from "./ServerList"; import { ServerList } from "./ServerList";
import TogglePin from "../Common/TogglePin";
interface ChatHeaderProps { interface ChatHeaderProps {
clearChat: () => void; clearChat: () => void;
@@ -34,21 +32,9 @@ export function ChatHeader({
showChatHistory = true, showChatHistory = true,
assistantIDs, assistantIDs,
}: ChatHeaderProps) { }: ChatHeaderProps) {
const { isPinned, setIsPinned, isTauri } = useAppStore(); const { isTauri } = useAppStore();
const { historicalRecords, newSession, fixedWindow, external } = const { historicalRecords, newSession, external } = useShortcutsStore();
useShortcutsStore();
const togglePin = async () => {
try {
const { isPinned } = useAppStore.getState();
setIsPinned(!isPinned);
} catch (err) {
console.error("Failed to toggle window pin state:", err);
setIsPinned(isPinned);
}
};
return ( return (
<header <header
@@ -101,16 +87,7 @@ export function ChatHeader({
{isTauri ? ( {isTauri ? (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<button <TogglePin className="inline-flex" />
onClick={togglePin}
className={clsx("inline-flex", {
"text-blue-500": isPinned,
})}
>
<VisibleKey shortcut={fixedWindow} onKeyPress={togglePin}>
{isPinned ? <PinIcon /> : <PinOffIcon />}
</VisibleKey>
</button>
<ServerList clearChat={clearChat} /> <ServerList clearChat={clearChat} />

View 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;

View File

@@ -5,13 +5,10 @@ import clsx from "clsx";
import CommonIcon from "@/components/Common/Icons/CommonIcon"; import CommonIcon from "@/components/Common/Icons/CommonIcon";
import Copyright from "@/components/Common/Copyright"; import Copyright from "@/components/Common/Copyright";
import PinOffIcon from "@/icons/PinOff";
import PinIcon from "@/icons/Pin";
import logoImg from "@/assets/icon.svg"; import logoImg from "@/assets/icon.svg";
import { useAppStore } from "@/stores/appStore"; import { useAppStore } from "@/stores/appStore";
import { useSearchStore } from "@/stores/searchStore"; import { useSearchStore } from "@/stores/searchStore";
import { useUpdateStore } from "@/stores/updateStore"; import { useUpdateStore } from "@/stores/updateStore";
import VisibleKey from "../VisibleKey";
import { useShortcutsStore } from "@/stores/shortcutsStore"; import { useShortcutsStore } from "@/stores/shortcutsStore";
import { formatKey } from "@/utils/keyboardUtils"; import { formatKey } from "@/utils/keyboardUtils";
import source_default_img from "@/assets/images/source_default.png"; 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 { useThemeStore } from "@/stores/themeStore";
import platformAdapter from "@/utils/platformAdapter"; import platformAdapter from "@/utils/platformAdapter";
import FontIcon from "../Icons/FontIcon"; import FontIcon from "../Icons/FontIcon";
import TogglePin from "../TogglePin";
interface FooterProps { interface FooterProps {
setIsPinnedWeb?: (value: boolean) => void; setIsPinnedWeb?: (value: boolean) => void;
@@ -37,28 +35,11 @@ export default function Footer({ setIsPinnedWeb }: FooterProps) {
const isDark = useThemeStore((state) => state.isDark); const isDark = useThemeStore((state) => state.isDark);
const { isTauri, isPinned, setIsPinned } = useAppStore(); const { isTauri } = useAppStore();
const { setVisible, updateInfo, skipVersions } = useUpdateStore(); const { setVisible, updateInfo, skipVersions } = useUpdateStore();
const { fixedWindow, modifierKey } = useShortcutsStore(); const { 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 openSetting = useCallback(() => { const openSetting = useCallback(() => {
return platformAdapter.emitEvent("open_settings", ""); return platformAdapter.emitEvent("open_settings", "");
@@ -88,7 +69,10 @@ export default function Footer({ setIsPinnedWeb }: FooterProps) {
if (visibleExtensionDetail && selectedExtension) { if (visibleExtensionDetail && selectedExtension) {
return ( return (
<div className="flex items-center gap-2"> <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> <span className="text-sm">{selectedExtension.name}</span>
</div> </div>
); );
@@ -139,17 +123,12 @@ export default function Footer({ setIsPinnedWeb }: FooterProps) {
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
{renderLeft()} {renderLeft()}
<button <TogglePin
onClick={togglePin}
className={clsx({ className={clsx({
"text-blue-500": isPinned,
"pl-2": hasUpdate, "pl-2": hasUpdate,
})} })}
> setIsPinnedWeb={setIsPinnedWeb}
<VisibleKey shortcut={fixedWindow} onKeyPress={togglePin}> />
{isPinned ? <PinIcon /> : <PinOffIcon />}
</VisibleKey>
</button>
</div> </div>
</div> </div>
) : ( ) : (

View File

@@ -6,6 +6,9 @@ import { last } from "lodash-es";
import { POPOVER_PANEL_SELECTOR } from "@/constants"; import { POPOVER_PANEL_SELECTOR } from "@/constants";
import { useShortcutsStore } from "@/stores/shortcutsStore"; import { useShortcutsStore } from "@/stores/shortcutsStore";
import { useAppStore } from "@/stores/appStore"; import { useAppStore } from "@/stores/appStore";
import { KeyType } from "ahooks/lib/useKeyPress";
const keyTriggerMap = new Map<KeyType, number>();
interface VisibleKeyProps extends HTMLAttributes<HTMLDivElement> { interface VisibleKeyProps extends HTMLAttributes<HTMLDivElement> {
shortcut: string; shortcut: string;
@@ -60,8 +63,16 @@ const VisibleKey: FC<VisibleKeyProps> = (props) => {
setVisibleShortcut(isChildInPopover && modifierKeyPressed); setVisibleShortcut(isChildInPopover && modifierKeyPressed);
}, [openPopover, modifierKeyPressed]); }, [openPopover, modifierKeyPressed]);
useKeyPress(`${modifierKey}.${shortcut}`, (event) => { useKeyPress(`${modifierKey}.${shortcut}`, (event, key) => {
if (!visibleShortcut) return; 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.stopPropagation();
event.preventDefault(); event.preventDefault();