feat: add loading component for /apps main page (#20924)
This commit is contained in:
1 parent
396ccb1cd2
commit
91ab27e070
4 files changed
+111
-2
No files matched your search
@@ -0,0 +1,5 @@
|
||||
import { AppHomePageSkeleton } from "app/(use-page-wrapper)/apps/(homepage)/skeleton";
|
||||
|
||||
export default function Loading() {
|
||||
return <AppHomePageSkeleton />;
|
||||
}
|
||||
+1
-1
@@ -22,8 +22,8 @@ const getData = withAppDirSsr(getServerSideProps);
|
||||
|
||||
const ServerPage = async ({ params, searchParams }: PageProps) => {
|
||||
const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams);
|
||||
|
||||
const props = await getData(context);
|
||||
|
||||
return <AppsPage {...props} />;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
"use client";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { SkeletonText, SkeletonContainer, SkeletonButton } from "@calcom/ui/components/skeleton";
|
||||
|
||||
import AppsLayout from "@components/apps/layouts/AppsLayout";
|
||||
|
||||
export function AppHomePageSkeleton() {
|
||||
const { t } = useLocale();
|
||||
|
||||
return (
|
||||
<AppsLayout
|
||||
isPublic
|
||||
heading={t("app_store")}
|
||||
subtitle={t("app_store_description")}
|
||||
headerClassName="sm:hidden lg:block hidden">
|
||||
<SkeletonContainer>
|
||||
<div className="flex flex-col gap-y-8">
|
||||
{/* Featured Categories section */}
|
||||
<div className="mb-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<SkeletonText className="h-6 w-40 font-semibold" />
|
||||
<div className="flex">
|
||||
<SkeletonButton className="mx-1 h-8 w-8 rounded-md" /> {/* Left arrow */}
|
||||
<SkeletonButton className="mx-1 h-8 w-8 rounded-md" /> {/* Right arrow */}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 grid grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5">
|
||||
{/* Category cards - 5 items based on screenshot */}
|
||||
{Array(5)
|
||||
.fill(0)
|
||||
.map((_, i) => (
|
||||
<div
|
||||
key={`category-${i}`}
|
||||
className="bg-subtle flex h-48 flex-col items-center justify-center rounded-md p-4">
|
||||
<div className="mb-3 h-14 w-14 rounded-full bg-gray-200" /> {/* Icon placeholder */}
|
||||
<SkeletonText className="h-5 w-24 text-center" /> {/* Category name */}
|
||||
<SkeletonText className="mt-1 h-4 w-16 text-center" /> {/* Apps count */}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Most Popular section */}
|
||||
<div className="mb-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<SkeletonText className="h-6 w-40 font-semibold" />
|
||||
<div className="flex">
|
||||
<SkeletonButton className="mx-1 h-8 w-8 rounded-md" /> {/* Left arrow */}
|
||||
<SkeletonButton className="mx-1 h-8 w-8 rounded-md" /> {/* Right arrow */}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 grid grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-3">
|
||||
{/* App cards - 3 items */}
|
||||
{Array(3)
|
||||
.fill(0)
|
||||
.map((_, i) => (
|
||||
<div key={`app-${i}`} className="border-subtle flex flex-col rounded-md border p-4">
|
||||
<div className="flex items-center">
|
||||
<div className="mr-3 h-10 w-10 rounded-md bg-gray-200" /> {/* App icon */}
|
||||
<div className="flex-1">
|
||||
<SkeletonText className="h-5 w-32" /> {/* App name */}
|
||||
<SkeletonText className="mt-1 h-4 w-24" /> {/* Developer name */}
|
||||
</div>
|
||||
</div>
|
||||
<SkeletonText className="mt-3 h-4 w-full" /> {/* Description line 1 */}
|
||||
<SkeletonText className="mt-2 h-4 w-3/4" /> {/* Description line 2 */}
|
||||
<div className="mt-4 flex justify-between">
|
||||
<SkeletonButton className="h-9 w-24 rounded-md" /> {/* Details button */}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* All apps section */}
|
||||
<div className="mt-4">
|
||||
<SkeletonText className="h-6 w-32 font-semibold" />
|
||||
<div className="mt-4 grid grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-3">
|
||||
{/* App cards - 6 items */}
|
||||
{Array(6)
|
||||
.fill(0)
|
||||
.map((_, i) => (
|
||||
<div key={`all-app-${i}`} className="border-subtle flex flex-col rounded-md border p-4">
|
||||
<div className="flex items-center">
|
||||
<div className="mr-3 h-10 w-10 rounded-md bg-gray-200" /> {/* App icon */}
|
||||
<div className="flex-1">
|
||||
<SkeletonText className="h-5 w-32" /> {/* App name */}
|
||||
<SkeletonText className="mt-1 h-4 w-24" /> {/* Developer name */}
|
||||
</div>
|
||||
</div>
|
||||
<SkeletonText className="mt-3 h-4 w-full" /> {/* Description line 1 */}
|
||||
<SkeletonText className="mt-2 h-4 w-3/4" /> {/* Description line 2 */}
|
||||
<div className="mt-4 flex justify-between">
|
||||
<SkeletonButton className="h-9 w-24 rounded-md" /> {/* Details button */}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SkeletonContainer>
|
||||
</AppsLayout>
|
||||
);
|
||||
}
|
||||
@@ -19,7 +19,6 @@ export default function AppsLayout({ children, actions, emptyStore, ...rest }: A
|
||||
const router = useRouter();
|
||||
const isAdmin = session.data?.user.role === "ADMIN";
|
||||
|
||||
if (session.status === "loading") return <></>;
|
||||
return (
|
||||
<Shell {...rest} actions={actions?.("block")}>
|
||||
<div className="flex flex-col xl:flex-row">
|
||||
|
||||
Reference in new issue
Block a user