mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
added lab loader
This commit is contained in:
parent
dfcf0a541d
commit
165c79d82f
4 changed files with 83 additions and 66 deletions
|
@ -1,52 +1,17 @@
|
||||||
import React, { FC } from 'react';
|
import { FC, memo } from 'react';
|
||||||
|
|
||||||
import { Columns } from '~/components/containers/Columns';
|
import { Columns } from '~/components/containers/Columns';
|
||||||
import { InfiniteScroll } from '~/components/containers/InfiniteScroll';
|
import { InfiniteScroll } from '~/components/containers/InfiniteScroll';
|
||||||
import { LabNoResults } from '~/components/lab/LabNoResults';
|
import { LabNoResults } from '~/components/lab/LabNoResults';
|
||||||
import { LabNode } from '~/components/lab/LabNode';
|
import { LabNode } from '~/components/lab/LabNode';
|
||||||
import { EMPTY_NODE, NODE_TYPES } from '~/constants/node';
|
|
||||||
import { useLabContext } from '~/utils/context/LabContextProvider';
|
import { useLabContext } from '~/utils/context/LabContextProvider';
|
||||||
import { values } from '~/utils/ramda';
|
|
||||||
|
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
|
|
||||||
interface IProps {}
|
interface IProps {}
|
||||||
|
|
||||||
const breakpointCols = {
|
const LabGrid: FC<IProps> = memo(() => {
|
||||||
default: 2,
|
const { nodes, hasMore, loadMore, search, setSearch } = useLabContext();
|
||||||
1280: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
const getRandomNodeType = () =>
|
|
||||||
values(NODE_TYPES)[Math.floor(Math.random() * values(NODE_TYPES).length)];
|
|
||||||
|
|
||||||
const LoadingNode = () => (
|
|
||||||
<LabNode
|
|
||||||
node={{ ...EMPTY_NODE, type: getRandomNodeType() }}
|
|
||||||
isLoading
|
|
||||||
lastSeen=""
|
|
||||||
commentCount={0}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
const LabGrid: FC<IProps> = () => {
|
|
||||||
const { isLoading, nodes, hasMore, loadMore, search, setSearch } = useLabContext();
|
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
return (
|
|
||||||
<Columns>
|
|
||||||
<LoadingNode />
|
|
||||||
<LoadingNode />
|
|
||||||
<LoadingNode />
|
|
||||||
<LoadingNode />
|
|
||||||
<LoadingNode />
|
|
||||||
<LoadingNode />
|
|
||||||
<LoadingNode />
|
|
||||||
<LoadingNode />
|
|
||||||
<LoadingNode />
|
|
||||||
</Columns>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (search && !nodes.length) {
|
if (search && !nodes.length) {
|
||||||
return <LabNoResults resetSearch={() => setSearch('')} />;
|
return <LabNoResults resetSearch={() => setSearch('')} />;
|
||||||
|
@ -56,7 +21,7 @@ const LabGrid: FC<IProps> = () => {
|
||||||
<InfiniteScroll hasMore={hasMore} loadMore={loadMore}>
|
<InfiniteScroll hasMore={hasMore} loadMore={loadMore}>
|
||||||
<div className={styles.wrap}>
|
<div className={styles.wrap}>
|
||||||
<Columns>
|
<Columns>
|
||||||
{nodes.map(node => (
|
{nodes.map((node) => (
|
||||||
<LabNode
|
<LabNode
|
||||||
node={node.node}
|
node={node.node}
|
||||||
key={node.node.id}
|
key={node.node.id}
|
||||||
|
@ -68,6 +33,6 @@ const LabGrid: FC<IProps> = () => {
|
||||||
</div>
|
</div>
|
||||||
</InfiniteScroll>
|
</InfiniteScroll>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
export { LabGrid };
|
export { LabGrid };
|
||||||
|
|
36
src/containers/lab/LabLoading/index.tsx
Normal file
36
src/containers/lab/LabLoading/index.tsx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import React, { FC, memo } from 'react';
|
||||||
|
|
||||||
|
import { Columns } from '~/components/containers/Columns';
|
||||||
|
import { LabNode } from '~/components/lab/LabNode';
|
||||||
|
import { EMPTY_NODE, NODE_TYPES } from '~/constants/node';
|
||||||
|
import { values } from '~/utils/ramda';
|
||||||
|
|
||||||
|
interface LabLoadingProps {}
|
||||||
|
|
||||||
|
const getRandomNodeType = () =>
|
||||||
|
values(NODE_TYPES)[Math.floor(Math.random() * values(NODE_TYPES).length)];
|
||||||
|
|
||||||
|
const LoadingNode = memo(() => (
|
||||||
|
<LabNode
|
||||||
|
node={{ ...EMPTY_NODE, type: getRandomNodeType() }}
|
||||||
|
isLoading
|
||||||
|
lastSeen=""
|
||||||
|
commentCount={0}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
const LabLoading: FC<LabLoadingProps> = memo(() => (
|
||||||
|
<Columns>
|
||||||
|
<LoadingNode />
|
||||||
|
<LoadingNode />
|
||||||
|
<LoadingNode />
|
||||||
|
<LoadingNode />
|
||||||
|
<LoadingNode />
|
||||||
|
<LoadingNode />
|
||||||
|
<LoadingNode />
|
||||||
|
<LoadingNode />
|
||||||
|
<LoadingNode />
|
||||||
|
</Columns>
|
||||||
|
));
|
||||||
|
|
||||||
|
export { LabLoading };
|
|
@ -10,11 +10,12 @@ import { INode } from '~/types';
|
||||||
import { GetLabNodesRequest, ILabNode, LabNodesSort } from '~/types/lab';
|
import { GetLabNodesRequest, ILabNode, LabNodesSort } from '~/types/lab';
|
||||||
import { flatten, uniqBy } from '~/utils/ramda';
|
import { flatten, uniqBy } from '~/utils/ramda';
|
||||||
|
|
||||||
const getKey: (isUser: boolean, sort?: LabNodesSort, search?: string) => SWRInfiniteKeyLoader = (
|
const getKey: (
|
||||||
isUser,
|
isUser: boolean,
|
||||||
sort,
|
sort?: LabNodesSort,
|
||||||
search
|
search?: string,
|
||||||
) => (index, prev: ILabNode[]) => {
|
) => SWRInfiniteKeyLoader =
|
||||||
|
(isUser, sort, search) => (index, prev: ILabNode[]) => {
|
||||||
if (!isUser) return null;
|
if (!isUser) return null;
|
||||||
if (index > 0 && (!prev?.length || prev.length < 20)) return null;
|
if (index > 0 && (!prev?.length || prev.length < 20)) return null;
|
||||||
|
|
||||||
|
@ -26,7 +27,7 @@ const getKey: (isUser: boolean, sort?: LabNodesSort, search?: string) => SWRInfi
|
||||||
};
|
};
|
||||||
|
|
||||||
return JSON.stringify(props);
|
return JSON.stringify(props);
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseKey = (key: string): GetLabNodesRequest => {
|
const parseKey = (key: string): GetLabNodesRequest => {
|
||||||
try {
|
try {
|
||||||
|
@ -49,12 +50,15 @@ export const useGetLabNodes = (sort?: LabNodesSort, search?: string) => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fallbackData: [labStore.nodes],
|
fallbackData: [labStore.nodes],
|
||||||
onSuccess: data => labStore.setNodes(flatten(data)),
|
onSuccess: (data) => labStore.setNodes(flatten(data)),
|
||||||
dedupingInterval: 300,
|
dedupingInterval: 300,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const nodes = useMemo(() => uniqBy(n => n.node.id, flatten(data || [])), [data]);
|
const nodes = useMemo(
|
||||||
|
() => uniqBy((n) => n.node.id, flatten(data || [])),
|
||||||
|
[data],
|
||||||
|
);
|
||||||
const hasMore = (data?.[size - 1]?.length || 0) >= 1;
|
const hasMore = (data?.[size - 1]?.length || 0) >= 1;
|
||||||
const loadMore = useCallback(() => setSize(size + 1), [setSize, size]);
|
const loadMore = useCallback(() => setSize(size + 1), [setSize, size]);
|
||||||
|
|
||||||
|
@ -63,20 +67,29 @@ export const useGetLabNodes = (sort?: LabNodesSort, search?: string) => {
|
||||||
async (node: ILabNode) => {
|
async (node: ILabNode) => {
|
||||||
await mutate([[node], ...(data || [])]);
|
await mutate([[node], ...(data || [])]);
|
||||||
},
|
},
|
||||||
[data, mutate]
|
[data, mutate],
|
||||||
);
|
);
|
||||||
|
|
||||||
/** updates node on cache */
|
/** updates node on cache */
|
||||||
const updateNode = useCallback(
|
const updateNode = useCallback(
|
||||||
async (nodeId: number, node: Partial<INode>) => {
|
async (nodeId: number, node: Partial<INode>) => {
|
||||||
await mutate(
|
await mutate(
|
||||||
data?.map(page =>
|
data?.map((page) =>
|
||||||
page.map(it => (it.node.id === nodeId ? { ...it, node: { ...it.node, node } } : it))
|
page.map((it) =>
|
||||||
)
|
it.node.id === nodeId ? { ...it, node: { ...it.node, node } } : it,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[data, mutate]
|
[data, mutate],
|
||||||
);
|
);
|
||||||
|
|
||||||
return { nodes, isLoading: !data && isValidating, hasMore, loadMore, unshift, updateNode };
|
return {
|
||||||
|
nodes,
|
||||||
|
isLoading: !!data?.length && isValidating,
|
||||||
|
hasMore,
|
||||||
|
loadMore,
|
||||||
|
unshift,
|
||||||
|
updateNode,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC, useMemo } from 'react';
|
||||||
|
|
||||||
import { Group } from '~/components/containers/Group';
|
import { Group } from '~/components/containers/Group';
|
||||||
import { Sticky } from '~/components/containers/Sticky';
|
import { Sticky } from '~/components/containers/Sticky';
|
||||||
import { LabHead } from '~/components/lab/LabHead';
|
import { LabHead } from '~/components/lab/LabHead';
|
||||||
import { LabGrid } from '~/containers/lab/LabGrid';
|
import { LabGrid } from '~/containers/lab/LabGrid';
|
||||||
|
import { LabLoading } from '~/containers/lab/LabLoading';
|
||||||
import { LabStats } from '~/containers/lab/LabStats';
|
import { LabStats } from '~/containers/lab/LabStats';
|
||||||
import { Container } from '~/containers/main/Container';
|
import { Container } from '~/containers/main/Container';
|
||||||
import { SidebarRouter } from '~/containers/main/SidebarRouter';
|
import { SidebarRouter } from '~/containers/main/SidebarRouter';
|
||||||
|
@ -13,6 +14,8 @@ import styles from './styles.module.scss';
|
||||||
|
|
||||||
interface IProps {}
|
interface IProps {}
|
||||||
|
|
||||||
|
const loader = <LabLoading />;
|
||||||
|
|
||||||
const LabLayout: FC<IProps> = () => {
|
const LabLayout: FC<IProps> = () => {
|
||||||
const { isLoading } = useLabContext();
|
const { isLoading } = useLabContext();
|
||||||
|
|
||||||
|
@ -25,7 +28,7 @@ const LabLayout: FC<IProps> = () => {
|
||||||
<LabHead isLoading={isLoading} />
|
<LabHead isLoading={isLoading} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<LabGrid />
|
{isLoading ? loader : <LabGrid />}
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<div className={styles.panel}>
|
<div className={styles.panel}>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue