Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol. wisp.place

lets try skeletons again

Changed files
+101 -6
public
components
editor
styles
+31
public/components/ui/skeleton.tsx
···
+
import { cn } from '@public/lib/utils'
+
+
interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {}
+
+
function Skeleton({ className, ...props }: SkeletonProps) {
+
return (
+
<div
+
className={cn(
+
'animate-pulse rounded-md bg-muted',
+
className
+
)}
+
{...props}
+
/>
+
)
+
}
+
+
interface SkeletonShimmerProps extends React.HTMLAttributes<HTMLDivElement> {}
+
+
function SkeletonShimmer({ className, ...props }: SkeletonShimmerProps) {
+
return (
+
<div
+
className={cn(
+
'relative overflow-hidden rounded-md bg-muted before:absolute before:inset-0 before:-translate-x-full before:animate-[shimmer_2s_infinite] before:bg-gradient-to-r before:from-transparent before:via-white/10 before:to-transparent',
+
className
+
)}
+
{...props}
+
/>
+
)
+
}
+
+
export { Skeleton, SkeletonShimmer }
+47 -4
public/editor/tabs/DomainsTab.tsx
···
import { Input } from '@public/components/ui/input'
import { Label } from '@public/components/ui/label'
import { Badge } from '@public/components/ui/badge'
+
import { SkeletonShimmer } from '@public/components/ui/skeleton'
import {
Dialog,
DialogContent,
···
</CardHeader>
<CardContent>
{domainsLoading ? (
-
<div className="flex items-center justify-center py-4">
-
<Loader2 className="w-6 h-6 animate-spin text-muted-foreground" />
+
<div className="space-y-4">
+
<div className="space-y-2">
+
{[...Array(2)].map((_, i) => (
+
<div
+
key={i}
+
className="flex items-center justify-between p-3 border border-border rounded-lg"
+
>
+
<div className="flex flex-col gap-2 flex-1">
+
<div className="flex items-center gap-2">
+
<SkeletonShimmer className="h-4 w-4 rounded-full" />
+
<SkeletonShimmer className="h-4 w-40" />
+
</div>
+
<SkeletonShimmer className="h-3 w-32 ml-6" />
+
</div>
+
<SkeletonShimmer className="h-8 w-8" />
+
</div>
+
))}
+
</div>
+
<div className="p-4 bg-muted/30 rounded-lg space-y-3">
+
<SkeletonShimmer className="h-4 w-full" />
+
<div className="space-y-2">
+
<SkeletonShimmer className="h-4 w-24" />
+
<SkeletonShimmer className="h-10 w-full" />
+
</div>
+
<SkeletonShimmer className="h-10 w-full" />
+
</div>
</div>
) : (
<div className="space-y-4">
···
</Button>
{domainsLoading ? (
-
<div className="flex items-center justify-center py-4">
-
<Loader2 className="w-6 h-6 animate-spin text-muted-foreground" />
+
<div className="space-y-2">
+
{[...Array(2)].map((_, i) => (
+
<div
+
key={i}
+
className="flex items-center justify-between p-3 border border-border rounded-lg"
+
>
+
<div className="flex flex-col gap-2 flex-1">
+
<div className="flex items-center gap-2">
+
<SkeletonShimmer className="h-4 w-4 rounded-full" />
+
<SkeletonShimmer className="h-4 w-48" />
+
</div>
+
<SkeletonShimmer className="h-3 w-36 ml-6" />
+
</div>
+
<div className="flex items-center gap-2">
+
<SkeletonShimmer className="h-8 w-20" />
+
<SkeletonShimmer className="h-8 w-20" />
+
<SkeletonShimmer className="h-8 w-8" />
+
</div>
+
</div>
+
))}
</div>
) : customDomains.length === 0 ? (
<div className="text-center py-4 text-muted-foreground text-sm">
+17 -2
public/editor/tabs/SitesTab.tsx
···
} from '@public/components/ui/card'
import { Button } from '@public/components/ui/button'
import { Badge } from '@public/components/ui/badge'
+
import { SkeletonShimmer } from '@public/components/ui/skeleton'
import {
Globe,
ExternalLink,
···
</CardHeader>
<CardContent className="space-y-4">
{sitesLoading ? (
-
<div className="flex items-center justify-center py-8">
-
<Loader2 className="w-6 h-6 animate-spin text-muted-foreground" />
+
<div className="space-y-4">
+
{[...Array(3)].map((_, i) => (
+
<div
+
key={i}
+
className="flex items-center justify-between p-4 border border-border rounded-lg"
+
>
+
<div className="flex-1 space-y-3">
+
<div className="flex items-center gap-3">
+
<SkeletonShimmer className="h-6 w-48" />
+
<SkeletonShimmer className="h-5 w-16" />
+
</div>
+
<SkeletonShimmer className="h-4 w-64" />
+
</div>
+
<SkeletonShimmer className="h-9 w-28" />
+
</div>
+
))}
</div>
) : sites.length === 0 ? (
<div className="text-center py-8 text-muted-foreground">
+6
public/styles/global.css
···
animation: arrow-bounce 1.5s ease-in-out infinite;
}
+
@keyframes shimmer {
+
100% {
+
transform: translateX(100%);
+
}
+
}
+
/* Shiki syntax highlighting styles */
.shiki-wrapper {
border-radius: 0.5rem;