move loadMore button to TimelineRenderer
This commit is contained in:
parent
3fa4dbf100
commit
f3272bed57
35
packages/app/src/Components/Event/LoadMore.tsx
Normal file
35
packages/app/src/Components/Event/LoadMore.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import { useEffect } from "react";
|
||||
import { useInView } from "react-intersection-observer";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
interface ShowMoreProps {
|
||||
text?: string;
|
||||
className?: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
const LoadMore = ({ text, onClick, className = "" }: ShowMoreProps) => {
|
||||
return (
|
||||
<button type="button" className={className} onClick={onClick}>
|
||||
{text || <FormattedMessage defaultMessage="Load more" id="00LcfG" />}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoadMore;
|
||||
|
||||
export function AutoLoadMore({ text, onClick, className }: ShowMoreProps) {
|
||||
const { ref, inView } = useInView({ rootMargin: "2000px" });
|
||||
|
||||
useEffect(() => {
|
||||
if (inView) {
|
||||
onClick();
|
||||
}
|
||||
}, [inView]);
|
||||
|
||||
return (
|
||||
<div ref={ref}>
|
||||
<LoadMore onClick={onClick} text={text} className={className} />
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
import classNames from "classnames";
|
||||
import { useEffect } from "react";
|
||||
import { useInView } from "react-intersection-observer";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
interface ShowMoreProps {
|
||||
text?: string;
|
||||
className?: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
const ShowMore = ({ text, onClick, className = "" }: ShowMoreProps) => {
|
||||
return (
|
||||
<div className="show-more-container">
|
||||
<button type="button" className={classNames("show-more", className)} onClick={onClick}>
|
||||
{text || <FormattedMessage defaultMessage="Show More" id="O8Z8t9" />}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ShowMore;
|
||||
|
||||
export function AutoShowMore({ text, onClick, className }: ShowMoreProps) {
|
||||
const { ref, inView } = useInView({ rootMargin: "2000px" });
|
||||
|
||||
useEffect(() => {
|
||||
if (inView) {
|
||||
onClick();
|
||||
}
|
||||
}, [inView]);
|
||||
|
||||
return (
|
||||
<div ref={ref}>
|
||||
<ShowMore onClick={onClick} text={text} className={className} />
|
||||
</div>
|
||||
);
|
||||
}
|
@ -31,16 +31,6 @@
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.thread-container .show-more {
|
||||
background: var(--gray-superdark);
|
||||
padding-left: 76px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
border-radius: 0;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.subthread-container {
|
||||
position: relative;
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import "./Timeline.css";
|
||||
|
||||
import { socialGraphInstance, TaggedNostrEvent } from "@snort/system";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { DisplayAs, DisplayAsSelector } from "@/Components/Feed/DisplayAsSelector";
|
||||
import { TimelineRenderer } from "@/Components/Feed/TimelineRenderer";
|
||||
@ -18,7 +17,6 @@ export interface TimelineProps {
|
||||
ignoreModeration?: boolean;
|
||||
window?: number;
|
||||
now?: number;
|
||||
loadMore?: boolean;
|
||||
noSort?: boolean;
|
||||
displayAs?: DisplayAs;
|
||||
showDisplayAsSelector?: boolean;
|
||||
@ -91,14 +89,8 @@ const Timeline = (props: TimelineProps) => {
|
||||
latest={latestAuthors}
|
||||
showLatest={t => onShowLatest(t)}
|
||||
displayAs={displayAs}
|
||||
loadMore={() => feed.loadMore()}
|
||||
/>
|
||||
{(props.loadMore === undefined || props.loadMore === true) && (
|
||||
<div className="flex items-center px-3 py-4">
|
||||
<button type="button" onClick={() => feed.loadMore()}>
|
||||
<FormattedMessage defaultMessage="Load more" id="00LcfG" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -4,7 +4,6 @@ import { EventKind, NostrEvent, TaggedNostrEvent } from "@snort/system";
|
||||
import { ReactNode, useCallback, useMemo, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import { AutoShowMore } from "@/Components/Event/ShowMore";
|
||||
import { DisplayAs, DisplayAsSelector } from "@/Components/Feed/DisplayAsSelector";
|
||||
import { TimelineRenderer } from "@/Components/Feed/TimelineRenderer";
|
||||
import useTimelineFeed, { TimelineFeedOptions, TimelineSubject } from "@/Feed/TimelineFeed";
|
||||
@ -98,15 +97,8 @@ const TimelineFollows = (props: TimelineFollowsProps) => {
|
||||
}
|
||||
}}
|
||||
displayAs={displayAs}
|
||||
loadMore={() => feed.loadMore()}
|
||||
/>
|
||||
{mainFeed.length > 0 && (
|
||||
<AutoShowMore
|
||||
onClick={() => {
|
||||
feed.loadMore();
|
||||
}}
|
||||
className="mx-3 my-4"
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -4,6 +4,7 @@ import { useInView } from "react-intersection-observer";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import ErrorBoundary from "@/Components/ErrorBoundary";
|
||||
import { AutoLoadMore } from "@/Components/Event/LoadMore";
|
||||
import { DisplayAs } from "@/Components/Feed/DisplayAsSelector";
|
||||
import ImageGridItem from "@/Components/Feed/ImageGridItem";
|
||||
import { TimelineFragment } from "@/Components/Feed/TimelineFragment";
|
||||
@ -23,6 +24,7 @@ export interface TimelineRendererProps {
|
||||
noteOnClick?: (ev: TaggedNostrEvent) => void;
|
||||
noteContext?: (ev: TaggedNostrEvent) => ReactNode;
|
||||
displayAs?: DisplayAs;
|
||||
loadMore?: () => void;
|
||||
}
|
||||
|
||||
// filter frags[0].events that have media
|
||||
@ -151,6 +153,7 @@ export function TimelineRenderer(props: TimelineRendererProps) {
|
||||
</>
|
||||
)}
|
||||
{props.displayAs === "grid" ? <Grid frags={props.frags} /> : renderNotes()}
|
||||
{props.loadMore && <AutoLoadMore className="mx-3 my-4" onClick={props.loadMore} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
26
packages/app/src/Hooks/usePageDimensions.tsx
Normal file
26
packages/app/src/Hooks/usePageDimensions.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
export default function usePageDimensions() {
|
||||
const ref = useRef<HTMLDivElement | null>(document.querySelector("#root"));
|
||||
const [dimensions, setDimensions] = useState({
|
||||
width: ref.current?.clientWidth ?? 0,
|
||||
height: ref.current?.clientHeight ?? 0,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (ref.current && "ResizeObserver" in window) {
|
||||
const observer = new ResizeObserver(entries => {
|
||||
if (entries[0].target === ref.current) {
|
||||
const { width, height } = entries[0].contentRect;
|
||||
setDimensions({ width, height });
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(ref.current);
|
||||
|
||||
return () => observer.disconnect();
|
||||
}
|
||||
}, [ref]);
|
||||
|
||||
return dimensions;
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
export default function usePageWidth() {
|
||||
const ref = useRef<HTMLDivElement | null>(document.querySelector("#root"));
|
||||
const [width, setWidth] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const updateSize = () => {
|
||||
if (ref.current) {
|
||||
setWidth(ref.current.offsetWidth);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("resize", updateSize);
|
||||
updateSize();
|
||||
return () => window.removeEventListener("resize", updateSize);
|
||||
}, [ref]);
|
||||
|
||||
return width;
|
||||
}
|
@ -8,7 +8,7 @@ import NoteTime from "@/Components/Event/Note/NoteTime";
|
||||
import NoteToSelf from "@/Components/User/NoteToSelf";
|
||||
import ProfileImage from "@/Components/User/ProfileImage";
|
||||
import useLogin from "@/Hooks/useLogin";
|
||||
import usePageWidth from "@/Hooks/usePageWidth";
|
||||
import usePageDimensions from "@/Hooks/usePageDimensions";
|
||||
import { ChatParticipantProfile } from "@/Pages/Messages/ChatParticipant";
|
||||
import DmWindow from "@/Pages/Messages/DmWindow";
|
||||
import NewChatWindow from "@/Pages/Messages/NewChatWindow";
|
||||
@ -21,7 +21,7 @@ export default function MessagesPage() {
|
||||
const { formatMessage } = useIntl();
|
||||
const navigate = useNavigate();
|
||||
const { id } = useParams();
|
||||
const pageWidth = usePageWidth();
|
||||
const { width: pageWidth } = usePageDimensions();
|
||||
|
||||
const chats = useChatSystems();
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { unwrap } from "@snort/shared";
|
||||
import { NostrEvent, NostrLink, TaggedNostrEvent } from "@snort/system";
|
||||
import { lazy, Suspense, useEffect, useMemo } from "react";
|
||||
|
||||
import { AutoShowMore } from "@/Components/Event/ShowMore";
|
||||
import { AutoLoadMore } from "@/Components/Event/LoadMore";
|
||||
import PageSpinner from "@/Components/PageSpinner";
|
||||
import { useNotificationsView } from "@/Feed/WorkerRelayView";
|
||||
import useLogin from "@/Hooks/useLogin";
|
||||
@ -63,7 +63,7 @@ export default function NotificationsPage({ onClick }: { onClick?: (link: NostrL
|
||||
{login.publicKey &&
|
||||
[...timeGrouped.entries()].map(([k, g]) => <NotificationGroup key={k} evs={g} onClick={onClick} />)}
|
||||
|
||||
<AutoShowMore onClick={() => {}} />
|
||||
<AutoLoadMore onClick={() => {}} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
@ -77,7 +77,6 @@ export function ProfileNotesTab({ id, relays, isMe }: { id: HexKey; relays?: Arr
|
||||
subject={subject}
|
||||
postsOnly={false}
|
||||
method={"LIMIT_UNTIL"}
|
||||
loadMore={true}
|
||||
ignoreModeration={true}
|
||||
window={60 * 60 * 6}
|
||||
/>
|
||||
|
@ -14,5 +14,5 @@ export function TopicsPage() {
|
||||
[tags, pubKey],
|
||||
);
|
||||
|
||||
return <Timeline subject={subject} postsOnly={true} method="TIME_RANGE" loadMore={true} window={60 * 60 * 6} />;
|
||||
return <Timeline subject={subject} postsOnly={true} method="TIME_RANGE" showLoadMore={true} window={60 * 60 * 6} />;
|
||||
}
|
||||
|
@ -773,9 +773,6 @@
|
||||
"O3Jz4E": {
|
||||
"defaultMessage": "Use your invite code to earn sats!"
|
||||
},
|
||||
"O8Z8t9": {
|
||||
"defaultMessage": "Show More"
|
||||
},
|
||||
"OEW7yJ": {
|
||||
"defaultMessage": "Zaps"
|
||||
},
|
||||
|
@ -255,7 +255,6 @@
|
||||
"NepkXH": "Can't vote with {amount} sats, please set a different default zap amount",
|
||||
"NndBJE": "New users page",
|
||||
"O3Jz4E": "Use your invite code to earn sats!",
|
||||
"O8Z8t9": "Show More",
|
||||
"OEW7yJ": "Zaps",
|
||||
"OKhRC6": "Share",
|
||||
"OLEm6z": "Unknown login error",
|
||||
|
Loading…
x
Reference in New Issue
Block a user