mirror of
https://github.com/urbit/shrub.git
synced 2024-12-24 03:14:30 +03:00
links-fe: infinite scroll for link displays
This commit is contained in:
parent
cd125fc71f
commit
3cfc96c31e
@ -11,6 +11,7 @@ import { RouteComponentProps } from "react-router-dom";
|
|||||||
import { LinkItem } from "./components/LinkItem";
|
import { LinkItem } from "./components/LinkItem";
|
||||||
import LinkSubmit from "./components/LinkSubmit";
|
import LinkSubmit from "./components/LinkSubmit";
|
||||||
import { LinkPreview } from "./components/link-preview";
|
import { LinkPreview } from "./components/link-preview";
|
||||||
|
import { LinkWindow } from "./LinkWindow";
|
||||||
import { Comments } from "~/views/components/Comments";
|
import { Comments } from "~/views/components/Comments";
|
||||||
|
|
||||||
import "./css/custom.css";
|
import "./css/custom.css";
|
||||||
@ -73,16 +74,12 @@ export function LinkResource(props: LinkResourceProps) {
|
|||||||
<Col width="100%" flexShrink='0'>
|
<Col width="100%" flexShrink='0'>
|
||||||
<LinkSubmit s3={s3} name={name} ship={ship.slice(1)} api={api} />
|
<LinkSubmit s3={s3} name={name} ship={ship.slice(1)} api={api} />
|
||||||
</Col>
|
</Col>
|
||||||
{Array.from(graph).map(([date, node]) => {
|
<LinkWindow
|
||||||
const contact = contactDetails[node.post.author];
|
|
||||||
return (
|
|
||||||
<LinkItem
|
|
||||||
association={resource}
|
association={resource}
|
||||||
contacts={contacts}
|
contacts={contacts}
|
||||||
key={date.toString()}
|
key={date.toString()}
|
||||||
resource={resourcePath}
|
resource={resourcePath}
|
||||||
node={node}
|
graph={graph}
|
||||||
contacts={contactDetails}
|
|
||||||
unreads={unreads}
|
unreads={unreads}
|
||||||
nickname={contact?.nickname}
|
nickname={contact?.nickname}
|
||||||
hideAvatars={hideAvatars}
|
hideAvatars={hideAvatars}
|
||||||
|
98
pkg/interface/src/views/apps/links/LinkWindow.tsx
Normal file
98
pkg/interface/src/views/apps/links/LinkWindow.tsx
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import React, { useRef, useCallback, useEffect } from "react";
|
||||||
|
import {
|
||||||
|
Association,
|
||||||
|
Graph,
|
||||||
|
Contacts,
|
||||||
|
Unreads,
|
||||||
|
LocalUpdateRemoteContentPolicy,
|
||||||
|
Group,
|
||||||
|
Rolodex,
|
||||||
|
} from "~/types";
|
||||||
|
import GlobalApi from "~/logic/api/global";
|
||||||
|
import VirtualScroller from "~/views/components/VirtualScroller";
|
||||||
|
import { LinkItem } from "./components/LinkItem";
|
||||||
|
|
||||||
|
interface LinkWindowProps {
|
||||||
|
association: Association;
|
||||||
|
contacts: Rolodex;
|
||||||
|
resource: string;
|
||||||
|
graph: Graph;
|
||||||
|
unreads: Unreads;
|
||||||
|
hideNicknames: boolean;
|
||||||
|
hideAvatars: boolean;
|
||||||
|
remoteContentPolicy: LocalUpdateRemoteContentPolicy;
|
||||||
|
baseUrl: string;
|
||||||
|
group: Group;
|
||||||
|
path: string;
|
||||||
|
api: GlobalApi;
|
||||||
|
}
|
||||||
|
export function LinkWindow(props: LinkWindowProps) {
|
||||||
|
const { graph, api, association } = props;
|
||||||
|
const loadedNewest = useRef(true);
|
||||||
|
const loadedOldest = useRef(false);
|
||||||
|
const virtualList = useRef<VirtualScroller>();
|
||||||
|
const fetchLinks = useCallback(
|
||||||
|
async (newer: boolean) => {
|
||||||
|
/* stubbed, should we generalize the display of graphs in virtualscroller?
|
||||||
|
* this is copied verbatim from chatwindow
|
||||||
|
const [, , ship, name] = association["app-path"].split("/");
|
||||||
|
const currSize = graph.size;
|
||||||
|
if (newer && !loadedNewest.current) {
|
||||||
|
const [index] = graph.peekLargest()!;
|
||||||
|
await api.graph.getYoungerSiblings(
|
||||||
|
ship,
|
||||||
|
name,
|
||||||
|
20,
|
||||||
|
`/${index.toString()}`
|
||||||
|
);
|
||||||
|
if (currSize === graph.size) {
|
||||||
|
loadedNewest.current = true;
|
||||||
|
}
|
||||||
|
} else if (!newer && !loadedOldest.current) {
|
||||||
|
const [index] = graph.peekSmallest()!;
|
||||||
|
await api.graph.getOlderSiblings(
|
||||||
|
ship,
|
||||||
|
name,
|
||||||
|
20,
|
||||||
|
`/${index.toString()}`
|
||||||
|
);
|
||||||
|
if (currSize === graph.size) {
|
||||||
|
console.log("loaded all oldest");
|
||||||
|
loadedOldest.current = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
[api, graph, association, loadedNewest, loadedOldest]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const list = virtualList?.current;
|
||||||
|
if(!list) return;
|
||||||
|
list.calculateVisibleItems();
|
||||||
|
}, [graph.size])
|
||||||
|
return (
|
||||||
|
<VirtualScroller
|
||||||
|
ref={(l) => (virtualList.current = l ?? undefined)}
|
||||||
|
origin="top"
|
||||||
|
style={{ height: "100%" }}
|
||||||
|
onStartReached={() => {}}
|
||||||
|
onScroll={() => {}}
|
||||||
|
data={graph}
|
||||||
|
size={graph.size}
|
||||||
|
renderer={({ index, measure, scrollWindow }) => {
|
||||||
|
const node = graph.get(index);
|
||||||
|
const post = node?.post;
|
||||||
|
if (!node || !post) return null;
|
||||||
|
const isPending = "pending" in post && post.pending;
|
||||||
|
const linkProps = {
|
||||||
|
...props,
|
||||||
|
node,
|
||||||
|
key: index.toString()
|
||||||
|
};
|
||||||
|
return <LinkItem {...linkProps} />;
|
||||||
|
}}
|
||||||
|
loadRows={fetchLinks}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
@ -21,7 +21,7 @@ interface LinkItemProps {
|
|||||||
api: GlobalApi;
|
api: GlobalApi;
|
||||||
group: Group;
|
group: Group;
|
||||||
path: string;
|
path: string;
|
||||||
contacts: Rolodex[];
|
contacts: Rolodex;
|
||||||
unreads: Unreads;
|
unreads: Unreads;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +141,6 @@ export default class VirtualScroller extends Component<VirtualScrollerProps, Vir
|
|||||||
const { scrollTop, offsetHeight: windowHeight } = this.window;
|
const { scrollTop, offsetHeight: windowHeight } = this.window;
|
||||||
const { averageHeight } = this.state;
|
const { averageHeight } = this.state;
|
||||||
const { data, size: totalSize, onCalculateVisibleItems } = this.props;
|
const { data, size: totalSize, onCalculateVisibleItems } = this.props;
|
||||||
console.log(windowHeight);
|
|
||||||
|
|
||||||
const overscan = Math.max(windowHeight / 2, 200);
|
const overscan = Math.max(windowHeight / 2, 200);
|
||||||
|
|
||||||
@ -162,10 +161,6 @@ export default class VirtualScroller extends Component<VirtualScrollerProps, Vir
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
startBuffer = new BigIntOrderedMap(
|
|
||||||
[...startBuffer].reverse().slice(0, (visibleItems.size - visibleItems.size % 5))
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
startBuffer.forEach((_datum, index) => {
|
startBuffer.forEach((_datum, index) => {
|
||||||
startgap -= this.heightOf(index);
|
startgap -= this.heightOf(index);
|
||||||
@ -303,7 +298,7 @@ export default class VirtualScroller extends Component<VirtualScrollerProps, Vir
|
|||||||
data
|
data
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const indexesToRender = visibleItems.keys().reverse();
|
const indexesToRender = origin === 'top' ? visibleItems.keys() : visibleItems.keys().reverse();
|
||||||
|
|
||||||
const transform = origin === 'top' ? 'scale3d(1, 1, 1)' : 'scale3d(1, -1, 1)';
|
const transform = origin === 'top' ? 'scale3d(1, 1, 1)' : 'scale3d(1, -1, 1)';
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user