mirror of
https://github.com/infinilabs/coco-app.git
synced 2025-12-16 19:47:43 +01:00
feat: support pageup/pagedown to navigate search results (#920)
* feat: support pageup/pagedown to navigate search results * docs: add release note
This commit is contained in:
@@ -16,6 +16,7 @@ Information about release notes of Coco App is provided here.
|
|||||||
feat: support switching groups via keyboard shortcuts #911
|
feat: support switching groups via keyboard shortcuts #911
|
||||||
feat: support opening logs from about page #915
|
feat: support opening logs from about page #915
|
||||||
feat: support moving cursor with home and end keys #918
|
feat: support moving cursor with home and end keys #918
|
||||||
|
feat: support pageup/pagedown to navigate search results #920
|
||||||
|
|
||||||
### 🐛 Bug fix
|
### 🐛 Bug fix
|
||||||
|
|
||||||
|
|||||||
47
src/components/Common/Scrollbar.tsx
Normal file
47
src/components/Common/Scrollbar.tsx
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { useEventListener } from "ahooks";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import {
|
||||||
|
forwardRef,
|
||||||
|
HTMLAttributes,
|
||||||
|
useImperativeHandle,
|
||||||
|
useRef,
|
||||||
|
} from "react";
|
||||||
|
|
||||||
|
const Scrollbar = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||||
|
(props, ref) => {
|
||||||
|
const { children, className, ...rest } = props;
|
||||||
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => containerRef.current as HTMLDivElement);
|
||||||
|
|
||||||
|
useEventListener("keydown", (event) => {
|
||||||
|
const { key } = event;
|
||||||
|
|
||||||
|
if (key !== "PageDown" && key !== "PageUp") return;
|
||||||
|
|
||||||
|
if (!containerRef.current) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const delta = key === "PageDown" ? 1 : -1;
|
||||||
|
const el = containerRef.current;
|
||||||
|
|
||||||
|
el.scrollBy({
|
||||||
|
top: delta * el.clientHeight * 0.9,
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
{...rest}
|
||||||
|
ref={containerRef}
|
||||||
|
className={clsx("custom-scrollbar", className)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Scrollbar;
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
import React, { useState, useRef, useEffect, useCallback } from "react";
|
import React, { useState, useRef, useEffect, useCallback } from "react";
|
||||||
import { useInfiniteScroll } from "ahooks";
|
import { useInfiniteScroll } from "ahooks";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Data } from "ahooks/lib/useInfiniteScroll/types";
|
||||||
|
import { nanoid } from "nanoid";
|
||||||
|
import { isNil } from "lodash-es";
|
||||||
|
|
||||||
import { useSearchStore } from "@/stores/searchStore";
|
import { useSearchStore } from "@/stores/searchStore";
|
||||||
import { SearchHeader } from "./SearchHeader";
|
import { SearchHeader } from "./SearchHeader";
|
||||||
@@ -11,9 +14,7 @@ import { Get } from "@/api/axiosRequest";
|
|||||||
import { useAppStore } from "@/stores/appStore";
|
import { useAppStore } from "@/stores/appStore";
|
||||||
import { useConnectStore } from "@/stores/connectStore";
|
import { useConnectStore } from "@/stores/connectStore";
|
||||||
import SearchEmpty from "../Common/SearchEmpty";
|
import SearchEmpty from "../Common/SearchEmpty";
|
||||||
import { Data } from "ahooks/lib/useInfiniteScroll/types";
|
import Scrollbar from "@/components/Common/Scrollbar";
|
||||||
import { nanoid } from "nanoid";
|
|
||||||
import { isNil } from "lodash-es";
|
|
||||||
|
|
||||||
interface DocumentListProps {
|
interface DocumentListProps {
|
||||||
onSelectDocument: (id: string) => void;
|
onSelectDocument: (id: string) => void;
|
||||||
@@ -297,8 +298,8 @@ export const DocumentList: React.FC<DocumentListProps> = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<Scrollbar
|
||||||
className="flex-1 overflow-auto custom-scrollbar pr-0.5"
|
className="flex-1 overflow-auto pr-0.5"
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
>
|
>
|
||||||
{data?.list && data.list.length > 0 && (
|
{data?.list && data.list.length > 0 && (
|
||||||
@@ -334,7 +335,7 @@ export const DocumentList: React.FC<DocumentListProps> = ({
|
|||||||
<SearchEmpty />
|
<SearchEmpty />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</Scrollbar>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { useKeyboardNavigation } from "@/hooks/useKeyboardNavigation";
|
|||||||
import { SearchSource } from "./SearchSource";
|
import { SearchSource } from "./SearchSource";
|
||||||
import DropdownListItem from "./DropdownListItem";
|
import DropdownListItem from "./DropdownListItem";
|
||||||
import platformAdapter from "@/utils/platformAdapter";
|
import platformAdapter from "@/utils/platformAdapter";
|
||||||
|
import Scrollbar from "@/components/Common/Scrollbar";
|
||||||
|
|
||||||
type ISearchData = Record<string, QueryHits[]>;
|
type ISearchData = Record<string, QueryHits[]>;
|
||||||
|
|
||||||
@@ -149,10 +150,10 @@ function DropdownList({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<Scrollbar
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
data-tauri-drag-region
|
data-tauri-drag-region
|
||||||
className="h-full w-full p-2 flex flex-col overflow-y-auto custom-scrollbar focus:outline-none"
|
className="h-full w-full p-2 flex flex-col overflow-y-auto focus:outline-none"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
role="listbox"
|
role="listbox"
|
||||||
aria-label={t("search.header.results")}
|
aria-label={t("search.header.results")}
|
||||||
@@ -189,7 +190,7 @@ function DropdownList({
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</Scrollbar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user