diff --git a/apps/renderer/src/modules/feed-column/list.tsx b/apps/renderer/src/modules/feed-column/list.tsx index eeb7f87231..98ffb87130 100644 --- a/apps/renderer/src/modules/feed-column/list.tsx +++ b/apps/renderer/src/modules/feed-column/list.tsx @@ -2,6 +2,7 @@ import { useDraggable } from "@dnd-kit/core" import { ScrollArea } from "@follow/components/ui/scroll-area/index.js" import type { FeedViewType } from "@follow/constants" import { views } from "@follow/constants" +import { useKeyPressing } from "@follow/hooks" import { stopPropagation } from "@follow/utils/dom" import { cn } from "@follow/utils/utils" import * as HoverCard from "@radix-ui/react-hover-card" @@ -190,6 +191,8 @@ function FeedListImpl({ className, view }: { className?: string; view: number }) const shouldFreeUpSpace = useShouldFreeUpSpace() + const isMetaKeyPressed = useKeyPressing("Meta") + return (
@@ -198,24 +201,18 @@ function FeedListImpl({ className, view }: { className?: string; view: number }) ref={selectoRef} rootContainer={document.body} dragContainer={"#feeds-area"} - dragCondition={() => selectedFeedIds.length === 0} + dragCondition={() => selectedFeedIds.length === 0 || isMetaKeyPressed} selectableTargets={["[data-feed-id]"]} continueSelect hitRate={10} onSelect={(e) => { const allChanged = [...e.added, ...e.removed] + .map((el) => el.dataset.feedId) + .filter((id) => id !== undefined) setSelectedFeedIds((prev) => { - const added = allChanged - .map((el) => el.dataset.feedId) - .filter((id) => id !== undefined) - .filter((id) => !prev.includes(id)) - const removed = new Set( - allChanged - .map((el) => el.dataset.feedId) - .filter((id) => id !== undefined) - .filter((id) => prev.includes(id)), - ) + const added = allChanged.filter((id) => !prev.includes(id)) + const removed = new Set(allChanged.filter((id) => prev.includes(id))) return [...prev.filter((id) => !removed.has(id)), ...added] }) }} diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index cc321c9baf..5579cf1d98 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -5,6 +5,7 @@ export * from "./useDark" export * from "./useInputComposition" export * from "./useInterval" export * from "./useIsOnline" +export * from "./useKeyPressing" export * from "./useMeasure" export * from "./useOnce" export * from "./usePageVisibility" diff --git a/packages/hooks/src/useKeyPressing.ts b/packages/hooks/src/useKeyPressing.ts new file mode 100644 index 0000000000..04fc8a0581 --- /dev/null +++ b/packages/hooks/src/useKeyPressing.ts @@ -0,0 +1,29 @@ +import { useEffect, useMemo, useState } from "react" + +export function useKeyPressing(key: string) { + const [keysPressed, setKeysPressed] = useState(() => new Set()) + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + setKeysPressed((prev) => new Set(prev).add(event.key)) + } + + const handleKeyUp = (event: KeyboardEvent) => { + setKeysPressed((prev) => { + const newSet = new Set(prev) + newSet.delete(event.key) + return newSet + }) + } + + window.addEventListener("keydown", handleKeyDown) + window.addEventListener("keyup", handleKeyUp) + + return () => { + window.removeEventListener("keydown", handleKeyDown) + window.removeEventListener("keyup", handleKeyUp) + } + }, []) + + return useMemo(() => keysPressed.has(key), [keysPressed, key]) +}