Adds a loading skeleton to posts, comments and trending communities (#2311)

* creates the initial loading skeleton for the home page

* initial setup for the trending communities loading skeleton

* adds posts loading skeleton to the community page

* finishes the creation of all loading skeletons for large devices

* finishes loading skeleton for smaller screens

* removes unecessary code for the loading skeleton

* [loading skeleton] removes unecessary mock code

* [loading skeleton] removes custom css classes and adds more bootstrap css classes on the skeleton loading

* replaces custom styles with bootstrap classes

* rendes only one component for desktop and mobile screens

Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com>

* fixes lint's indentation problems

* transforms span tags into self-closing tags

* removes every inline style from the loading-skeleton.tsx file

---------

Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com>
This commit is contained in:
Rodrigo 2024-03-27 17:25:49 -03:00 committed by GitHub
parent 4dbf8fd2f1
commit 72553e429b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 139 additions and 47 deletions

@ -1 +1 @@
Subproject commit b4c63029e598c022a04fc21acb45855645bd6794 Subproject commit 62c8418021bc39543c87b4ae3dcf2419d13f61e0

View file

@ -0,0 +1,118 @@
import { Component } from "inferno";
interface LoadingSkeletonProps {
itemCount?: number;
}
interface LoadingSkeletonLineProps {
size: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
}
class LoadingSkeletonLine extends Component<LoadingSkeletonLineProps, any> {
render() {
const className = "placeholder placeholder-lg col-" + this.props.size;
return (
<p className="placeholder-glow m-0">
<span className={`${className} h-100`} />
</p>
);
}
}
export class PostsLoadingSkeleton extends Component<LoadingSkeletonProps, any> {
render() {
return Array.from({ length: this.props.itemCount ?? 10 }, (_, index) => (
<PostsLoadingSkeletonItem key={index} />
));
}
}
class PostThumbnailLoadingSkeleton extends Component<any, any> {
render() {
return (
<div className="thumbnail rounded d-flex justify-content-center placeholder-glow">
<span className="placeholder placeholder-lg h-100 w-100 rounded" />
</div>
);
}
}
class PostsLoadingSkeletonItem extends Component<any, any> {
render() {
return (
<div className="my-3">
<div className="col flex-grow-1">
<div className="row">
<div className="col flex-grow-0 order-last order-sm-first">
<PostThumbnailLoadingSkeleton />
</div>
<div className="col flex-grow-1">
<LoadingSkeletonLine size={12} />
<LoadingSkeletonLine size={8} />
<LoadingSkeletonLine size={4} />
</div>
</div>
</div>
</div>
);
}
}
export class TrendingCommunitiesLoadingSkeleton extends Component<
LoadingSkeletonProps,
any
> {
render() {
return (
<div className="mb-2">
{Array.from({ length: this.props.itemCount ?? 10 }, (_, index) => (
<TrendingCommunitiesLoadingSkeletonItem key={index} />
))}
</div>
);
}
}
class TrendingCommunitiesLoadingSkeletonItem extends Component<any, any> {
render() {
return (
<div className="col flex-grow-1 mt-2 ps-2 pe-4">
<div className="row">
<div className="col flex-grow-0 pe-0">
<div className="d-flex placeholder-glow img-icon">
<span className="placeholder placeholder-lg w-100 h-100 rounded-circle" />
</div>
</div>
<div className="col flex-grow-1 pe-0">
<LoadingSkeletonLine size={12} />
</div>
</div>
</div>
);
}
}
export class CommentsLoadingSkeleton extends Component<any, any> {
render() {
return Array.from({ length: this.props.itemCount ?? 10 }, (_, index) => (
<CommentsLoadingSkeletonItem key={index} />
));
}
}
class CommentsLoadingSkeletonItem extends Component<any, any> {
render() {
return (
<div className="col flex-grow-1 my-2 p-2">
<div className="row">
<div className="col flex-grow-1">
<LoadingSkeletonLine size={6} />
<LoadingSkeletonLine size={12} />
<LoadingSkeletonLine size={7} />
<LoadingSkeletonLine size={4} />
</div>
</div>
</div>
);
}
}

View file

@ -100,6 +100,10 @@ import { PostListings } from "../post/post-listings";
import { CommunityLink } from "./community-link"; import { CommunityLink } from "./community-link";
import { PaginatorCursor } from "../common/paginator-cursor"; import { PaginatorCursor } from "../common/paginator-cursor";
import { getHttpBaseInternal } from "../../utils/env"; import { getHttpBaseInternal } from "../../utils/env";
import {
CommentsLoadingSkeleton,
PostsLoadingSkeleton,
} from "../common/loading-skeleton";
import { Sidebar } from "./sidebar"; import { Sidebar } from "./sidebar";
import { IRoutePropsWithFetch } from "../../routes"; import { IRoutePropsWithFetch } from "../../routes";
@ -435,11 +439,7 @@ export class Community extends Component<CommunityRouteProps, State> {
if (dataType === DataType.Post) { if (dataType === DataType.Post) {
switch (this.state.postsRes.state) { switch (this.state.postsRes.state) {
case "loading": case "loading":
return ( return <PostsLoadingSkeleton />;
<h5>
<Spinner large />
</h5>
);
case "success": case "success":
return ( return (
<PostListings <PostListings
@ -472,11 +472,7 @@ export class Community extends Component<CommunityRouteProps, State> {
} else { } else {
switch (this.state.commentsRes.state) { switch (this.state.commentsRes.state) {
case "loading": case "loading":
return ( return <CommentsLoadingSkeleton />;
<h5>
<Spinner large />
</h5>
);
case "success": case "success":
return ( return (
<CommentNodes <CommentNodes

View file

@ -92,7 +92,7 @@ import { toast } from "../../toast";
import { CommentNodes } from "../comment/comment-nodes"; import { CommentNodes } from "../comment/comment-nodes";
import { DataTypeSelect } from "../common/data-type-select"; import { DataTypeSelect } from "../common/data-type-select";
import { HtmlTags } from "../common/html-tags"; import { HtmlTags } from "../common/html-tags";
import { Icon, Spinner } from "../common/icon"; import { Icon } from "../common/icon";
import { ListingTypeSelect } from "../common/listing-type-select"; import { ListingTypeSelect } from "../common/listing-type-select";
import { SortSelect } from "../common/sort-select"; import { SortSelect } from "../common/sort-select";
import { CommunityLink } from "../community/community-link"; import { CommunityLink } from "../community/community-link";
@ -100,6 +100,11 @@ import { PostListings } from "../post/post-listings";
import { SiteSidebar } from "./site-sidebar"; import { SiteSidebar } from "./site-sidebar";
import { PaginatorCursor } from "../common/paginator-cursor"; import { PaginatorCursor } from "../common/paginator-cursor";
import { getHttpBaseInternal } from "../../utils/env"; import { getHttpBaseInternal } from "../../utils/env";
import {
CommentsLoadingSkeleton,
PostsLoadingSkeleton,
TrendingCommunitiesLoadingSkeleton,
} from "../common/loading-skeleton";
import { RouteComponentProps } from "inferno-router/dist/Route"; import { RouteComponentProps } from "inferno-router/dist/Route";
import { IRoutePropsWithFetch } from "../../routes"; import { IRoutePropsWithFetch } from "../../routes";
@ -531,11 +536,7 @@ export class Home extends Component<HomeRouteProps, HomeState> {
trendingCommunities() { trendingCommunities() {
switch (this.state.trendingCommunitiesRes?.state) { switch (this.state.trendingCommunitiesRes?.state) {
case "loading": case "loading":
return ( return <TrendingCommunitiesLoadingSkeleton itemCount={5} />;
<h5>
<Spinner large />
</h5>
);
case "success": { case "success": {
const trending = this.state.trendingCommunitiesRes.data.communities; const trending = this.state.trendingCommunitiesRes.data.communities;
return ( return (
@ -704,11 +705,7 @@ export class Home extends Component<HomeRouteProps, HomeState> {
case "empty": case "empty":
return <div style="min-height: 20000px;"></div>; return <div style="min-height: 20000px;"></div>;
case "loading": case "loading":
return ( return <PostsLoadingSkeleton />;
<h5>
<Spinner large />
</h5>
);
case "success": { case "success": {
const posts = this.state.postsRes.data.posts; const posts = this.state.postsRes.data.posts;
return ( return (
@ -744,11 +741,7 @@ export class Home extends Component<HomeRouteProps, HomeState> {
} else { } else {
switch (this.state.commentsRes.state) { switch (this.state.commentsRes.state) {
case "loading": case "loading":
return ( return <CommentsLoadingSkeleton />;
<h5>
<Spinner large />
</h5>
);
case "success": { case "success": {
const comments = this.state.commentsRes.data.comments; const comments = this.state.commentsRes.data.comments;
return ( return (

View file

@ -80,6 +80,7 @@ import { Icon, Spinner } from "../common/icon";
import { Paginator } from "../common/paginator"; import { Paginator } from "../common/paginator";
import { PrivateMessage } from "../private_message/private-message"; import { PrivateMessage } from "../private_message/private-message";
import { getHttpBaseInternal } from "../../utils/env"; import { getHttpBaseInternal } from "../../utils/env";
import { CommentsLoadingSkeleton } from "../common/loading-skeleton";
import { RouteComponentProps } from "inferno-router/dist/Route"; import { RouteComponentProps } from "inferno-router/dist/Route";
import { IRoutePropsWithFetch } from "../../routes"; import { IRoutePropsWithFetch } from "../../routes";
@ -583,11 +584,7 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
this.state.mentionsRes.state === "loading" || this.state.mentionsRes.state === "loading" ||
this.state.messagesRes.state === "loading" this.state.messagesRes.state === "loading"
) { ) {
return ( return <CommentsLoadingSkeleton />;
<h1 className="h4">
<Spinner large />
</h1>
);
} else { } else {
return ( return (
<div>{this.buildCombined().map(r => this.renderReplyType(r))}</div> <div>{this.buildCombined().map(r => this.renderReplyType(r))}</div>
@ -598,11 +595,7 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
replies() { replies() {
switch (this.state.repliesRes.state) { switch (this.state.repliesRes.state) {
case "loading": case "loading":
return ( return <CommentsLoadingSkeleton />;
<h1 className="h4">
<Spinner large />
</h1>
);
case "success": { case "success": {
const replies = this.state.repliesRes.data.replies; const replies = this.state.repliesRes.data.replies;
return ( return (
@ -645,11 +638,7 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
mentions() { mentions() {
switch (this.state.mentionsRes.state) { switch (this.state.mentionsRes.state) {
case "loading": case "loading":
return ( return <CommentsLoadingSkeleton />;
<h1 className="h4">
<Spinner large />
</h1>
);
case "success": { case "success": {
const mentions = this.state.mentionsRes.data.mentions; const mentions = this.state.mentionsRes.data.mentions;
return ( return (
@ -695,11 +684,7 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
messages() { messages() {
switch (this.state.messagesRes.state) { switch (this.state.messagesRes.state) {
case "loading": case "loading":
return ( return <CommentsLoadingSkeleton />;
<h1 className="h4">
<Spinner large />
</h1>
);
case "success": { case "success": {
const messages = this.state.messagesRes.data.private_messages; const messages = this.state.messagesRes.data.private_messages;
return ( return (