Skeleton component on timeline loading for better user experience (#190)

* the LoadMore component should accept children to have something different than "Loading..."

* skeleton component

* the timeline component now loads with a skeleton

* border radius for skeleton

* dark mode for skeleton
This commit is contained in:
Leonardo Tuna 2023-02-06 16:05:22 -03:00 committed by GitHub
parent cc185674b0
commit 72ab0e25b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 86 additions and 3 deletions

View File

@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import { useInView } from "react-intersection-observer";
export default function LoadMore({ onLoadMore, shouldLoadMore }: { onLoadMore: () => void, shouldLoadMore: boolean }) {
export default function LoadMore({ onLoadMore, shouldLoadMore, children }: { onLoadMore: () => void, shouldLoadMore: boolean, children?: React.ReactNode }) {
const { ref, inView } = useInView();
const [tick, setTick] = useState<number>(0);
@ -18,5 +18,5 @@ export default function LoadMore({ onLoadMore, shouldLoadMore }: { onLoadMore: (
return () => clearInterval(t);
}, []);
return <div ref={ref} className="mb10">Loading...</div>;
return <div ref={ref} className="mb10">{children ?? 'Loading...'}</div>;
}

48
src/Element/Skeleton.css Normal file
View File

@ -0,0 +1,48 @@
.skeleton {
display: inline-block;
height: 1em;
position: relative;
overflow: hidden;
background-color: #dddbdd;
border-radius: 16px;
}
.skeleton::after {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
transform: translateX(-100%);
background-image: linear-gradient(
90deg,
rgba(255, 255, 255, 0) 0,
rgba(255, 255, 255, 0.2) 20%,
rgba(255, 255, 255, 0.5) 60%,
rgba(255, 255, 255, 0)
);
animation: shimmer 2s infinite;
content: "";
}
@keyframes shimmer {
100% {
transform: translateX(100%);
}
}
@media screen and (prefers-color-scheme: dark) {
.skeleton {
background-color: #50535a;
}
.skeleton::after {
background-image: linear-gradient(
90deg,
#50535a 0%,
#656871 20%,
#50535a 40%,
#50535a 100%
);
}
}

30
src/Element/Skeleton.tsx Normal file
View File

@ -0,0 +1,30 @@
import "./Skeleton.css";
interface ISkepetonProps {
children?: React.ReactNode;
loading?: boolean;
width?: string;
height?: string;
margin?: string;
}
export default function Skeleton({
children,
width,
height,
margin,
loading = true,
}: ISkepetonProps) {
if (!loading) {
return <>{children}</>;
}
return (
<div
className="skeleton"
style={{ width: width, height: height, margin: margin }}
>
{children}
</div>
);
}

View File

@ -12,6 +12,7 @@ import Note from "Element/Note";
import NoteReaction from "Element/NoteReaction";
import useModeration from "Hooks/useModeration";
import ProfilePreview from "./ProfilePreview";
import Skeleton from "Element/Skeleton";
export interface TimelineProps {
postsOnly: boolean,
@ -71,7 +72,11 @@ export default function Timeline({ subject, postsOnly = false, method, ignoreMod
Show latest {latestFeed.length - 1} notes
</div>)}
{mainFeed.map(eventElement)}
<LoadMore onLoadMore={loadMore} shouldLoadMore={main.end} />
<LoadMore onLoadMore={loadMore} shouldLoadMore={main.end}>
<Skeleton width="100%" height="120px" margin="0 0 16px 0" />
<Skeleton width="100%" height="120px" margin="0 0 16px 0" />
<Skeleton width="100%" height="120px" margin="0 0 16px 0" />
</LoadMore>
</div>
);
}