fix: match events loading skeleton to page layout
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { ListingPageLoading } from "@/components/page-loading";
|
||||
import { EventsPageLoading } from "@/components/page-loading";
|
||||
|
||||
export default function Loading() {
|
||||
return <ListingPageLoading />;
|
||||
return <EventsPageLoading />;
|
||||
}
|
||||
|
||||
32
src/components/events/EventResultsSkeleton.tsx
Normal file
32
src/components/events/EventResultsSkeleton.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
export function EventResultsSkeleton() {
|
||||
return (
|
||||
<div role="status" aria-live="polite" className="space-y-3">
|
||||
<span className="sr-only">در حال اعمال فیلترها و دریافت رویدادها…</span>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="grid grid-cols-1 gap-3 sm:grid-cols-2 sm:gap-4 xl:grid-cols-3"
|
||||
>
|
||||
{Array.from({ length: 6 }, (_, index) => (
|
||||
<article
|
||||
key={index}
|
||||
className="flex h-full min-w-0 flex-col overflow-hidden rounded-xl border border-border bg-card"
|
||||
>
|
||||
<div className="aspect-video w-full shrink-0 animate-pulse bg-muted motion-reduce:animate-none" />
|
||||
<div className="flex flex-1 flex-col p-3 md:p-4">
|
||||
<div className="ms-auto h-5 w-4/5 animate-pulse rounded bg-muted motion-reduce:animate-none" />
|
||||
<div className="mt-3 grid gap-3 md:mt-4">
|
||||
{["w-32", "w-40", "w-24", "w-36"].map((width, lineIndex) => (
|
||||
<div key={`${width}-${lineIndex}`} className="flex items-center justify-end gap-2">
|
||||
<div className={`h-3.5 ${width} animate-pulse rounded bg-muted motion-reduce:animate-none`} />
|
||||
<div className="size-4 animate-pulse rounded-full bg-muted motion-reduce:animate-none" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-auto min-h-10 w-full animate-pulse rounded-md bg-muted pt-2 md:mt-5 md:min-h-11 motion-reduce:animate-none" />
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { EventResultsSkeleton } from "@/components/events/EventResultsSkeleton";
|
||||
|
||||
export function BlogCardsSkeleton({ count = 6 }: { count?: number }) {
|
||||
return (
|
||||
@@ -131,35 +132,27 @@ export function BlogDetailPageLoading() {
|
||||
);
|
||||
}
|
||||
|
||||
export function ListingPageLoading() {
|
||||
export function EventsPageLoading() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background" dir="rtl">
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<Skeleton className="mb-8 h-10 w-40" />
|
||||
<Skeleton className="mb-8 h-10 w-full max-w-md" />
|
||||
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
{Array.from({ length: 6 }).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="overflow-hidden rounded-lg border bg-card"
|
||||
>
|
||||
<Skeleton className="aspect-video w-full rounded-none" />
|
||||
<div className="space-y-4 p-6">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<Skeleton className="h-6 flex-1" />
|
||||
<Skeleton className="h-6 w-16" />
|
||||
</div>
|
||||
<Skeleton className="h-4 w-32" />
|
||||
<div className="space-y-3 pt-2">
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-5/6" />
|
||||
<Skeleton className="h-10 w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<main className="container mx-auto max-w-screen-2xl px-3 py-5 sm:px-4 sm:py-8 lg:px-6">
|
||||
<header className="mb-6 border-b border-border pb-5 sm:mb-8 sm:pb-6" aria-hidden="true">
|
||||
<Skeleton className="h-8 w-48 sm:h-9 sm:w-56 motion-reduce:animate-none" />
|
||||
<div className="mt-2 grid max-w-3xl gap-2">
|
||||
<Skeleton className="h-4 w-full max-w-3xl motion-reduce:animate-none" />
|
||||
<Skeleton className="h-4 w-3/5 max-w-xl motion-reduce:animate-none" />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section aria-label="نتایج رویدادها" aria-busy="true" className="min-w-0">
|
||||
<div aria-hidden="true" dir="rtl" className="mb-4 flex items-center gap-2 sm:mb-5">
|
||||
<Skeleton className="h-11 min-w-0 flex-1 rounded-md motion-reduce:animate-none" />
|
||||
<Skeleton className="h-11 w-10 shrink-0 rounded-md min-[640px]:w-24 motion-reduce:animate-none" />
|
||||
</div>
|
||||
|
||||
<EventResultsSkeleton />
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Link } from "@/lib/router";
|
||||
import { buildAuthPath } from "@/lib/auth-return";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { EventCard } from "@/components/events/EventCard";
|
||||
import { EventResultsSkeleton } from "@/components/events/EventResultsSkeleton";
|
||||
import { EventFiltersDrawer } from "@/components/events/EventFiltersDrawer";
|
||||
import type { EventBrowsePageSchema } from "@/lib/types";
|
||||
import { api } from "@/lib/api";
|
||||
@@ -34,37 +35,6 @@ function defaultFilters(search: string, priceCeiling: number): EventCatalogFilte
|
||||
};
|
||||
}
|
||||
|
||||
function EventCardSkeleton() {
|
||||
return (
|
||||
<article aria-hidden="true" className="flex h-full min-w-0 flex-col overflow-hidden rounded-xl border border-border bg-card">
|
||||
<div className="aspect-video w-full shrink-0 animate-pulse bg-muted motion-reduce:animate-none" />
|
||||
<div className="flex flex-1 flex-col p-3 md:p-4">
|
||||
<div className="ms-auto h-5 w-4/5 animate-pulse rounded bg-muted motion-reduce:animate-none" />
|
||||
<div className="mt-3 grid gap-3 md:mt-4">
|
||||
{["w-32", "w-40", "w-24", "w-36"].map((width) => (
|
||||
<div key={width} className="flex items-center justify-end gap-2">
|
||||
<div className={`h-3.5 ${width} animate-pulse rounded bg-muted motion-reduce:animate-none`} />
|
||||
<div className="size-4 animate-pulse rounded-full bg-muted motion-reduce:animate-none" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-auto min-h-10 w-full animate-pulse rounded-md bg-muted pt-2 md:mt-5 md:min-h-11 motion-reduce:animate-none" />
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
function EventResultsSkeleton() {
|
||||
return (
|
||||
<div role="status" aria-live="polite" className="space-y-3">
|
||||
<span className="sr-only">در حال اعمال فیلترها و دریافت رویدادها…</span>
|
||||
<div aria-hidden="true" className="grid grid-cols-1 gap-3 sm:grid-cols-2 sm:gap-4 xl:grid-cols-3">
|
||||
{Array.from({ length: 6 }, (_, index) => <EventCardSkeleton key={index} />)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function getPageNumbers(total: number, current: number): Array<number | "ellipsis-left" | "ellipsis-right"> {
|
||||
if (total <= 7) return Array.from({ length: total }, (_, index) => index + 1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user