Browse Source

feat(home): add search submit and clear functionality for shows section

优化首页作品搜索体验:
1. 新增防抖搜索逻辑,使用提交搜索状态避免实时请求
2. 添加搜索框清除按钮,支持一键清空搜索内容
3. 支持回车触发搜索,优化交互体验
4. 新增搜索框聚焦边框样式,提升可交互辨识度
feature/group
huangmin 1 month ago
parent
commit
4bbd72c8de
  1. 43
      src/components/HomeProjectsContent.tsx

43
src/components/HomeProjectsContent.tsx

@ -1283,6 +1283,7 @@ function ShowsSection() {
]);
const [dataList, setDataList] = useState<ShowData[]>([]);
const [searchQuery, setSearchQuery] = useState("");
const [submittedSearchQuery, setSubmittedSearchQuery] = useState("");
const selectedCategoryId = categoryList[activeTab]?.id ?? null;
const [isCreating, setIsCreating] = useState(false);
const [isLoadingShows, setIsLoadingShows] = useState(false);
@ -1359,7 +1360,7 @@ function ShowsSection() {
setIsLoadingShows(true);
try {
const params = new URLSearchParams({
keyword: searchQuery,
keyword: submittedSearchQuery,
categoryId: selectedCategoryId ? String(selectedCategoryId) : "",
type: "",
userId: "",
@ -1411,7 +1412,7 @@ function ShowsSection() {
setIsLoadingShows(false);
}
}
}, [searchQuery, selectedCategoryId, t]);
}, [submittedSearchQuery, selectedCategoryId, t]);
useEffect(() => {
const controller = new AbortController();
@ -1421,12 +1422,9 @@ function ShowsSection() {
page: 1,
pageSize: SHOWS_PAGE_SIZE,
});
const timeout = window.setTimeout(() => {
void loadShowsPage(1, { signal: controller.signal });
}, 250);
return () => {
window.clearTimeout(timeout);
controller.abort();
loadingMoreShowsPageRef.current = null;
};
@ -1444,6 +1442,15 @@ function ShowsSection() {
});
}, [isLoadingShows, loadShowsPage, showsPage, showsPageInfo.pageCount]);
const handleSubmitSearch = useCallback(() => {
setSubmittedSearchQuery(searchQuery.trim());
}, [searchQuery]);
const handleClearSearch = useCallback(() => {
setSearchQuery("");
setSubmittedSearchQuery("");
}, []);
useEffect(() => {
const handleScroll = () => {
if (!canLoadMoreShows || isLoadingShows) return;
@ -1506,14 +1513,38 @@ function ShowsSection() {
))}
</div>
</div>
<div className="flex h-[35px] w-full items-center justify-between rounded-full bg-white px-[15px] text-[#999] shadow-[0_2px_5px_rgba(0,0,0,0.1)] lg:w-[295px]">
<div className="flex h-[35px] w-full items-center justify-between rounded-full border border-transparent bg-white px-[15px] text-[#999] shadow-[0_2px_5px_rgba(0,0,0,0.1)] transition focus-within:border-[#5c3bc7] lg:w-[295px]">
<input
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
onKeyDown={(event) => {
if (event.key === "Enter") {
handleSubmitSearch();
}
}}
placeholder={t("home.searchPlaceholder")}
className="min-w-0 flex-1 bg-transparent text-[14px] outline-none placeholder:text-[#999]"
/>
{searchQuery ? (
<button
type="button"
onClick={handleClearSearch}
aria-label={t("common.clear")}
title={t("common.clear")}
className="mr-1 grid h-7 w-7 shrink-0 place-items-center rounded-full text-[#999] transition hover:bg-[#f0f0f0] hover:text-[#666]"
>
<CloseIcon />
</button>
) : null}
<button
type="button"
onClick={handleSubmitSearch}
aria-label={t("home.searchPlaceholder")}
title={t("home.searchPlaceholder")}
className="grid h-7 w-7 shrink-0 place-items-center rounded-full text-[#999] transition hover:bg-[#f0f0f0] hover:text-[#5c3bc7]"
>
<SearchIcon />
</button>
</div>
</div>
<div className="grid gap-5 md:grid-cols-2 xl:grid-cols-4">

Loading…
Cancel
Save