Unverified Commit c6e6b7b9 authored by Brian's avatar Brian Committed by GitHub

feat: add infinite scrolling for memos (#4715)

* feat(WIP): add prop-driven infinite scroll

* feat(WIP): add global toggle for infinite scrolling under settings

* feat: integrate newly added scroll-mode selection state with backend for persists across refreshes

* fix: default to infinite scrolling over load more button & remove redundant setting option

* fix: rectify linting issues

* Update web/src/components/PagedMemoList/PagedMemoList.tsx

---------
Co-authored-by: 's avatarJohnny <yourselfhosted@gmail.com>
parent 46d5307d
import { Button } from "@usememos/mui";
import { ArrowDownIcon, ArrowUpIcon, LoaderIcon } from "lucide-react";
import { ArrowUpIcon, LoaderIcon } from "lucide-react";
import { observer } from "mobx-react-lite";
import { useEffect, useState } from "react";
import { matchPath } from "react-router-dom";
......@@ -71,6 +71,18 @@ const PagedMemoList = observer((props: Props) => {
refreshList();
}, [props.owner, props.state, props.direction, props.filter, props.oldFilter, props.pageSize]);
useEffect(() => {
if (!state.nextPageToken) return;
const handleScroll = () => {
const nearBottom = window.innerHeight + window.scrollY >= document.body.offsetHeight - 300;
if (nearBottom && !state.isRequesting) {
fetchMoreMemos(state.nextPageToken);
}
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, [state.nextPageToken, state.isRequesting]);
const children = (
<div className="flex flex-col justify-start items-start w-full max-w-full">
<MasonryView
......@@ -93,12 +105,6 @@ const PagedMemoList = observer((props: Props) => {
</div>
) : (
<div className="w-full opacity-70 flex flex-row justify-center items-center my-4">
{state.nextPageToken && (
<Button variant="plain" onClick={() => fetchMoreMemos(state.nextPageToken)}>
{t("memo.load-more")}
<ArrowDownIcon className="ml-1 w-4 h-auto" />
</Button>
)}
<BackToTop />
</div>
)}
......
......@@ -15,44 +15,33 @@ const PreferencesSection = observer(() => {
const setting = userStore.state.userSetting as UserSetting;
const handleLocaleSelectChange = async (locale: Locale) => {
await userStore.updateUserSetting(
{
locale,
},
["locale"],
);
await userStore.updateUserSetting({ locale }, ["locale"]);
};
const handleAppearanceSelectChange = async (appearance: Appearance) => {
await userStore.updateUserSetting(
{
appearance,
},
["appearance"],
);
await userStore.updateUserSetting({ appearance }, ["appearance"]);
};
const handleDefaultMemoVisibilityChanged = async (value: string) => {
await userStore.updateUserSetting(
{
memoVisibility: value,
},
["memo_visibility"],
);
await userStore.updateUserSetting({ memoVisibility: value }, ["memo_visibility"]);
};
return (
<div className="w-full flex flex-col gap-2 pt-2 pb-4">
<p className="font-medium text-gray-700 dark:text-gray-500">{t("common.basic")}</p>
<div className="w-full flex flex-row justify-between items-center">
<span>{t("common.language")}</span>
<LocaleSelect value={setting.locale} onChange={handleLocaleSelectChange} />
</div>
<div className="w-full flex flex-row justify-between items-center">
<span>{t("setting.preference-section.theme")}</span>
<AppearanceSelect value={setting.appearance as Appearance} onChange={handleAppearanceSelectChange} />
</div>
<p className="font-medium text-gray-700 dark:text-gray-500">{t("setting.preference")}</p>
<div className="w-full flex flex-row justify-between items-center">
<span className="truncate">{t("setting.preference-section.default-memo-visibility")}</span>
<Select
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment