mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-26 17:26:23 +02:00
feat: implement skeleton loading states in sidebar components for improved user experience
This commit is contained in:
parent
8c3b65bac2
commit
db27ee95ce
3 changed files with 89 additions and 11 deletions
|
|
@ -27,6 +27,7 @@ import {
|
|||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
|
|
@ -303,8 +304,16 @@ export function AllPrivateChatsSidebar({
|
|||
|
||||
<div className="flex-1 overflow-y-auto overflow-x-hidden p-2">
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center py-8">
|
||||
<Spinner size="md" className="text-muted-foreground" />
|
||||
<div className="space-y-1">
|
||||
{[75, 90, 55, 80, 65, 85].map((titleWidth, i) => (
|
||||
<div
|
||||
key={`skeleton-${i}`}
|
||||
className="flex items-center gap-2 rounded-md px-2 py-1.5"
|
||||
>
|
||||
<Skeleton className="h-4 w-4 shrink-0 rounded" />
|
||||
<Skeleton className="h-4 rounded" style={{ width: `${titleWidth}%` }} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : error ? (
|
||||
<div className="text-center py-8 text-sm text-destructive">
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {
|
|||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
|
|
@ -303,8 +304,16 @@ export function AllSharedChatsSidebar({
|
|||
|
||||
<div className="flex-1 overflow-y-auto overflow-x-hidden p-2">
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center py-8">
|
||||
<Spinner size="md" className="text-muted-foreground" />
|
||||
<div className="space-y-1">
|
||||
{[75, 90, 55, 80, 65, 85].map((titleWidth, i) => (
|
||||
<div
|
||||
key={`skeleton-${i}`}
|
||||
className="flex items-center gap-2 rounded-md px-2 py-1.5"
|
||||
>
|
||||
<Skeleton className="h-4 w-4 shrink-0 rounded" />
|
||||
<Skeleton className="h-4 rounded" style={{ width: `${titleWidth}%` }} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : error ? (
|
||||
<div className="text-center py-8 text-sm text-destructive">
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import {
|
|||
Inbox,
|
||||
LayoutGrid,
|
||||
ListFilter,
|
||||
Loader2,
|
||||
MessageSquare,
|
||||
Search,
|
||||
X,
|
||||
|
|
@ -43,6 +42,7 @@ import {
|
|||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
|
|
@ -928,12 +928,39 @@ export function InboxSidebar({
|
|||
|
||||
<div className="flex-1 overflow-y-auto overflow-x-hidden p-2">
|
||||
{(isSearchMode ? isSearchLoading : loading) ? (
|
||||
<div className="flex items-center justify-center py-8">
|
||||
{isSearchMode ? (
|
||||
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
|
||||
) : (
|
||||
<Spinner size="md" className="text-muted-foreground" />
|
||||
)}
|
||||
<div className="space-y-2">
|
||||
{activeTab === "comments"
|
||||
? /* Comments skeleton: avatar + two-line text + time */
|
||||
[85, 60, 90, 70, 50, 75].map((titleWidth, i) => (
|
||||
<div
|
||||
key={`skeleton-comment-${i}`}
|
||||
className="flex items-center gap-3 rounded-lg px-3 py-3 h-[80px]"
|
||||
>
|
||||
<Skeleton className="h-8 w-8 rounded-full shrink-0" />
|
||||
<div className="flex-1 min-w-0 space-y-2">
|
||||
<Skeleton className="h-3 rounded" style={{ width: `${titleWidth}%` }} />
|
||||
<Skeleton className="h-2.5 w-[70%] rounded" />
|
||||
</div>
|
||||
<Skeleton className="h-3 w-6 shrink-0 rounded" />
|
||||
</div>
|
||||
))
|
||||
: /* Status skeleton: status icon circle + two-line text + time */
|
||||
[75, 90, 55, 80, 65, 85].map((titleWidth, i) => (
|
||||
<div
|
||||
key={`skeleton-status-${i}`}
|
||||
className="flex items-center gap-3 rounded-lg px-3 py-3 h-[80px]"
|
||||
>
|
||||
<Skeleton className="h-8 w-8 rounded-full shrink-0" />
|
||||
<div className="flex-1 min-w-0 space-y-2">
|
||||
<Skeleton className="h-3 rounded" style={{ width: `${titleWidth}%` }} />
|
||||
<Skeleton className="h-2.5 w-[60%] rounded" />
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5 shrink-0">
|
||||
<Skeleton className="h-3 w-6 rounded" />
|
||||
<Skeleton className="h-2 w-2 rounded-full" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : filteredItems.length > 0 ? (
|
||||
<div className="space-y-2">
|
||||
|
|
@ -1000,6 +1027,39 @@ export function InboxSidebar({
|
|||
{!isSearchMode && filteredItems.length < 5 && hasMore && (
|
||||
<div ref={prefetchTriggerRef} className="h-1" />
|
||||
)}
|
||||
{/* Loading more skeletons at the bottom during infinite scroll */}
|
||||
{loadingMore && (
|
||||
activeTab === "comments"
|
||||
? [80, 60, 90].map((titleWidth, i) => (
|
||||
<div
|
||||
key={`loading-more-comment-${i}`}
|
||||
className="flex items-center gap-3 rounded-lg px-3 py-3 h-[80px]"
|
||||
>
|
||||
<Skeleton className="h-8 w-8 rounded-full shrink-0" />
|
||||
<div className="flex-1 min-w-0 space-y-2">
|
||||
<Skeleton className="h-3 rounded" style={{ width: `${titleWidth}%` }} />
|
||||
<Skeleton className="h-2.5 w-[70%] rounded" />
|
||||
</div>
|
||||
<Skeleton className="h-3 w-6 shrink-0 rounded" />
|
||||
</div>
|
||||
))
|
||||
: [70, 85, 55].map((titleWidth, i) => (
|
||||
<div
|
||||
key={`loading-more-status-${i}`}
|
||||
className="flex items-center gap-3 rounded-lg px-3 py-3 h-[80px]"
|
||||
>
|
||||
<Skeleton className="h-8 w-8 rounded-full shrink-0" />
|
||||
<div className="flex-1 min-w-0 space-y-2">
|
||||
<Skeleton className="h-3 rounded" style={{ width: `${titleWidth}%` }} />
|
||||
<Skeleton className="h-2.5 w-[60%] rounded" />
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5 shrink-0">
|
||||
<Skeleton className="h-3 w-6 rounded" />
|
||||
<Skeleton className="h-2 w-2 rounded-full" />
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
) : isSearchMode ? (
|
||||
<div className="text-center py-8">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue