Skip to content

Commit 9c046dc

Browse files
gitstart-twentyv1b3mMatheusBeniniFcharlesBochet
authored
Prefetch Skeleton Loading on Indexes and Shows (#5545)
### Description Prefetch Skeleton Loading on Indexes and Shows ### Refs #4458 ### Demo https://jam.dev/c/a1ad04e1-80b6-4b2a-b7df-373f52f4b169 https://jam.dev/c/c5038b97-2f18-4c29-8dee-18c09376e5ee Fixes: #4458 --------- Co-authored-by: gitstart-twenty <[email protected]> Co-authored-by: v1b3m <[email protected]> Co-authored-by: Matheus <[email protected]> Co-authored-by: Charles Bochet <[email protected]>
1 parent cfd83d6 commit 9c046dc

File tree

60 files changed

+490
-161
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+490
-161
lines changed

packages/twenty-front/src/modules/activities/timeline/components/Timeline.tsx

+4-68
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
2-
import { useTheme } from '@emotion/react';
31
import styled from '@emotion/styled';
42
import { useRecoilValue } from 'recoil';
53

64
import { TimelineCreateButtonGroup } from '@/activities/timeline/components/TimelineCreateButtonGroup';
5+
import { TimelineSkeletonLoader } from '@/activities/timeline/components/TimelineSkeletonLoader';
76
import { timelineActivitiesForGroupState } from '@/activities/timeline/states/timelineActivitiesForGroupState';
87
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
98
import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder';
@@ -29,82 +28,19 @@ const StyledMainContainer = styled.div`
2928
justify-content: center;
3029
`;
3130

32-
const StyledSkeletonContainer = styled.div`
33-
align-items: center;
34-
width: 100%;
35-
padding: ${({ theme }) => theme.spacing(8)};
36-
display: flex;
37-
flex-direction: column;
38-
gap: ${({ theme }) => theme.spacing(4)};
39-
flex-wrap: wrap;
40-
align-content: flex-start;
41-
`;
42-
43-
const StyledSkeletonSubSection = styled.div`
44-
display: flex;
45-
gap: ${({ theme }) => theme.spacing(4)};
46-
`;
47-
48-
const StyledSkeletonColumn = styled.div`
49-
display: flex;
50-
flex-direction: column;
51-
gap: ${({ theme }) => theme.spacing(3)};
52-
justify-content: center;
53-
`;
54-
55-
const StyledSkeletonLoader = () => {
56-
const theme = useTheme();
57-
return (
58-
<SkeletonTheme
59-
baseColor={theme.background.tertiary}
60-
highlightColor={theme.background.transparent.lighter}
61-
borderRadius={80}
62-
>
63-
<Skeleton width={24} height={84} />
64-
</SkeletonTheme>
65-
);
66-
};
67-
68-
const StyledTimelineSkeletonLoader = () => {
69-
const theme = useTheme();
70-
const skeletonItems = Array.from({ length: 3 }).map((_, index) => ({
71-
id: `skeleton-item-${index}`,
72-
}));
73-
return (
74-
<SkeletonTheme
75-
baseColor={theme.background.tertiary}
76-
highlightColor={theme.background.transparent.lighter}
77-
borderRadius={4}
78-
>
79-
<StyledSkeletonContainer>
80-
<Skeleton width={440} height={16} />
81-
{skeletonItems.map(({ id }) => (
82-
<StyledSkeletonSubSection key={id}>
83-
<StyledSkeletonLoader />
84-
<StyledSkeletonColumn>
85-
<Skeleton width={400} height={24} />
86-
<Skeleton width={400} height={24} />
87-
</StyledSkeletonColumn>
88-
</StyledSkeletonSubSection>
89-
))}
90-
</StyledSkeletonContainer>
91-
</SkeletonTheme>
92-
);
93-
};
94-
9531
export const Timeline = ({
9632
targetableObject,
9733
loading,
9834
}: {
9935
targetableObject: ActivityTargetableObject;
100-
loading?: boolean;
36+
loading: boolean;
10137
}) => {
10238
const timelineActivitiesForGroup = useRecoilValue(
10339
timelineActivitiesForGroupState,
10440
);
10541

106-
if (loading === true) {
107-
return <StyledTimelineSkeletonLoader />;
42+
if (loading) {
43+
return <TimelineSkeletonLoader />;
10844
}
10945

11046
if (timelineActivitiesForGroup.length === 0) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
2+
import { useTheme } from '@emotion/react';
3+
import styled from '@emotion/styled';
4+
5+
const StyledSkeletonContainer = styled.div`
6+
align-items: center;
7+
width: 100%;
8+
padding: ${({ theme }) => theme.spacing(8)};
9+
display: flex;
10+
flex-direction: column;
11+
gap: ${({ theme }) => theme.spacing(4)};
12+
flex-wrap: wrap;
13+
align-content: flex-start;
14+
`;
15+
16+
const StyledSkeletonSubSection = styled.div`
17+
display: flex;
18+
gap: ${({ theme }) => theme.spacing(4)};
19+
`;
20+
21+
const StyledSkeletonColumn = styled.div`
22+
display: flex;
23+
flex-direction: column;
24+
gap: ${({ theme }) => theme.spacing(3)};
25+
justify-content: center;
26+
`;
27+
28+
const StyledSkeletonLoader = ({
29+
isSecondColumn,
30+
}: {
31+
isSecondColumn: boolean;
32+
}) => {
33+
const theme = useTheme();
34+
return (
35+
<SkeletonTheme
36+
baseColor={theme.background.tertiary}
37+
highlightColor={theme.background.transparent.lighter}
38+
borderRadius={80}
39+
>
40+
<Skeleton width={24} height={isSecondColumn ? 120 : 84} />
41+
</SkeletonTheme>
42+
);
43+
};
44+
45+
export const TimelineSkeletonLoader = () => {
46+
const theme = useTheme();
47+
const skeletonItems = Array.from({ length: 3 }).map((_, index) => ({
48+
id: `skeleton-item-${index}`,
49+
}));
50+
51+
return (
52+
<SkeletonTheme
53+
baseColor={theme.background.tertiary}
54+
highlightColor={theme.background.transparent.lighter}
55+
borderRadius={4}
56+
>
57+
<StyledSkeletonContainer>
58+
<Skeleton width={440} height={16} />
59+
{skeletonItems.map(({ id }, index) => (
60+
<StyledSkeletonSubSection key={id}>
61+
<StyledSkeletonLoader isSecondColumn={index === 1} />
62+
<StyledSkeletonColumn>
63+
<Skeleton width={400} height={24} />
64+
<Skeleton width={400} height={24} />
65+
{index === 1 && <Skeleton width={400} height={24} />}
66+
</StyledSkeletonColumn>
67+
</StyledSkeletonSubSection>
68+
))}
69+
</StyledSkeletonContainer>
70+
</SkeletonTheme>
71+
);
72+
};

packages/twenty-front/src/modules/favorites/components/Favorites.tsx

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import styled from '@emotion/styled';
22
import { Avatar } from 'twenty-ui';
33

4+
import { FavoritesSkeletonLoader } from '@/favorites/components/FavoritesSkeletonLoader';
5+
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
46
import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem';
57
import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList';
68
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
@@ -32,6 +34,11 @@ const StyledNavigationDrawerItem = styled(NavigationDrawerItem)`
3234

3335
export const Favorites = () => {
3436
const { favorites, handleReorderFavorite } = useFavorites();
37+
const loading = useIsPrefetchLoading();
38+
39+
if (loading) {
40+
return <FavoritesSkeletonLoader />;
41+
}
3542

3643
if (!favorites || favorites.length === 0) return <></>;
3744

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
2+
import { useTheme } from '@emotion/react';
3+
import styled from '@emotion/styled';
4+
5+
const StyledSkeletonContainer = styled.div`
6+
display: flex;
7+
flex-direction: column;
8+
gap: ${({ theme }) => theme.spacing(2)};
9+
height: 71px;
10+
padding-left: ${({ theme }) => theme.spacing(1)};
11+
`;
12+
13+
const StyledSkeletonColumn = styled.div`
14+
display: flex;
15+
flex-direction: column;
16+
gap: ${({ theme }) => theme.spacing(1)};
17+
`;
18+
19+
export const FavoritesSkeletonLoader = () => {
20+
const theme = useTheme();
21+
return (
22+
<SkeletonTheme
23+
baseColor={theme.background.tertiary}
24+
highlightColor={theme.background.transparent.lighter}
25+
borderRadius={4}
26+
>
27+
<StyledSkeletonContainer>
28+
<Skeleton width={56} height={13} />
29+
<StyledSkeletonColumn>
30+
<Skeleton width={196} height={16} />
31+
<Skeleton width={196} height={16} />
32+
</StyledSkeletonColumn>
33+
</StyledSkeletonContainer>
34+
</SkeletonTheme>
35+
);
36+
};

packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataNavItems.tsx

+7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { useLocation } from 'react-router-dom';
22
import { useIcons } from 'twenty-ui';
33

4+
import { ObjectMetadataNavItemsSkeletonLoader } from '@/object-metadata/components/ObjectMetadataNavItemsSkeletonLoader';
45
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
6+
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
57
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
68
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
79
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
@@ -14,6 +16,11 @@ export const ObjectMetadataNavItems = () => {
1416
const currentPath = useLocation().pathname;
1517

1618
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
19+
const loading = useIsPrefetchLoading();
20+
21+
if (loading) {
22+
return <ObjectMetadataNavItemsSkeletonLoader />;
23+
}
1724

1825
return (
1926
<>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
2+
import { useTheme } from '@emotion/react';
3+
import styled from '@emotion/styled';
4+
5+
const StyledSkeletonColumn = styled.div`
6+
display: flex;
7+
flex-direction: column;
8+
gap: ${({ theme }) => theme.spacing(1)};
9+
height: 76px;
10+
padding-left: ${({ theme }) => theme.spacing(1)};
11+
`;
12+
13+
export const ObjectMetadataNavItemsSkeletonLoader: React.FC = () => {
14+
const theme = useTheme();
15+
return (
16+
<SkeletonTheme
17+
baseColor={theme.background.tertiary}
18+
highlightColor={theme.background.transparent.light}
19+
borderRadius={4}
20+
>
21+
<StyledSkeletonColumn>
22+
<Skeleton width={196} height={16} />
23+
<Skeleton width={196} height={16} />
24+
<Skeleton width={196} height={16} />
25+
</StyledSkeletonColumn>
26+
</SkeletonTheme>
27+
);
28+
};

packages/twenty-front/src/modules/object-metadata/components/__stories__/ObjectMetadataNavItems.stories.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/Componen
66
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
77
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
88
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
9+
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
910
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
1011
import { graphqlMocks } from '~/testing/graphqlMocks';
1112

@@ -20,6 +21,7 @@ const meta: Meta<typeof ObjectMetadataNavItems> = {
2021
ComponentWithRouterDecorator,
2122
ComponentWithRecoilScopeDecorator,
2223
SnackBarDecorator,
24+
PrefetchLoadingDecorator,
2325
],
2426
parameters: {
2527
msw: graphqlMocks,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
2+
import { useTheme } from '@emotion/react';
3+
import styled from '@emotion/styled';
4+
5+
const StyledSkeletonDiv = styled.div`
6+
align-items: center;
7+
display: flex;
8+
gap: ${({ theme }) => theme.spacing(1)};
9+
width: 100%;
10+
height: 24px;
11+
`;
12+
export const PropertyBoxSkeletonLoader = () => {
13+
const theme = useTheme();
14+
const skeletonItems = Array.from({ length: 4 }).map((_, index) => ({
15+
id: `skeleton-item-${index}`,
16+
}));
17+
return (
18+
<SkeletonTheme
19+
baseColor={theme.background.tertiary}
20+
highlightColor={theme.background.transparent.lighter}
21+
borderRadius={4}
22+
>
23+
{skeletonItems.map(({ id }) => (
24+
<StyledSkeletonDiv key={id}>
25+
<Skeleton width={92} height={16} />
26+
<Skeleton width={154} height={16} />
27+
</StyledSkeletonDiv>
28+
))}
29+
</SkeletonTheme>
30+
);
31+
};

0 commit comments

Comments
 (0)