Skip to content

Commit 0602483

Browse files
authored
Merge pull request #206 from legend4tech/Skeleton-Loading-Component-Wrapper
feat: add skeleton loader component
2 parents 8c5b762 + 2c97292 commit 0602483

3 files changed

Lines changed: 98 additions & 27 deletions

File tree

‎frontend/src/app/[locale]/guilds/page.tsx‎

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,52 @@
1-
'use client'
1+
"use client";
22

3-
import { useState, useEffect } from 'react'
4-
import Link from 'next/link'
5-
import { Search, Plus, Filter } from 'lucide-react'
6-
import { useRouter } from 'next/navigation'
7-
import { useGuildStore } from '@/store/guildStore'
8-
import { GuildCard } from '@/features/guilds/components/GuildCard'
9-
import { Button } from '@/components/ui/Button'
10-
import { EmptyState } from '@/components/ui/EmptyState'
3+
import { useState, useEffect } from "react";
4+
import Link from "next/link";
5+
import { Search, Plus, Filter } from "lucide-react";
6+
import { useRouter } from "next/navigation";
7+
import { useGuildStore } from "@/store/guildStore";
8+
import { GuildCard } from "@/features/guilds/components/GuildCard";
9+
import { Button } from "@/components/ui/Button";
10+
import { EmptyState } from "@/components/ui/EmptyState";
1111

1212
export default function GuildsPage() {
13-
const router = useRouter()
14-
const { guilds, fetchGuilds } = useGuildStore()
15-
const [searchQuery, setSearchQuery] = useState('')
16-
const [selectedCategory, setSelectedCategory] = useState<string>('')
17-
const [selectedTier, setSelectedTier] = useState<string>('')
13+
const router = useRouter();
14+
const { guilds, fetchGuilds } = useGuildStore();
15+
const [searchQuery, setSearchQuery] = useState("");
16+
const [selectedCategory, setSelectedCategory] = useState<string>("");
17+
const [selectedTier, setSelectedTier] = useState<string>("");
1818

1919
useEffect(() => {
20-
fetchGuilds()
21-
}, [fetchGuilds])
20+
fetchGuilds();
21+
}, [fetchGuilds]);
2222

23-
const categories = ['All', 'Development', 'DeFi', 'Education', 'Gaming', 'NFT', 'DAO', 'Social']
24-
const tiers = ['All', 'bronze', 'silver', 'gold', 'platinum']
23+
const categories = [
24+
"All",
25+
"Development",
26+
"DeFi",
27+
"Education",
28+
"Gaming",
29+
"NFT",
30+
"DAO",
31+
"Social",
32+
];
33+
const tiers = ["All", "bronze", "silver", "gold", "platinum"];
2534

2635
const filteredGuilds = guilds.filter((guild) => {
2736
const matchesSearch =
2837
guild.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
29-
guild.description.toLowerCase().includes(searchQuery.toLowerCase())
38+
guild.description.toLowerCase().includes(searchQuery.toLowerCase());
3039

3140
const matchesCategory =
32-
!selectedCategory || selectedCategory === 'All' || guild.category === selectedCategory
41+
!selectedCategory ||
42+
selectedCategory === "All" ||
43+
guild.category === selectedCategory;
3344

34-
const matchesTier = !selectedTier || selectedTier === 'All' || guild.tier === selectedTier
45+
const matchesTier =
46+
!selectedTier || selectedTier === "All" || guild.tier === selectedTier;
3547

36-
return matchesSearch && matchesCategory && matchesTier
37-
})
48+
return matchesSearch && matchesCategory && matchesTier;
49+
});
3850

3951
return (
4052
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
@@ -81,7 +93,7 @@ export default function GuildsPage() {
8193
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:bg-gray-800 dark:text-white"
8294
>
8395
{categories.map((cat) => (
84-
<option key={cat} value={cat === 'All' ? '' : cat}>
96+
<option key={cat} value={cat === "All" ? "" : cat}>
8597
{cat}
8698
</option>
8799
))}
@@ -96,7 +108,7 @@ export default function GuildsPage() {
96108
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:bg-gray-800 dark:text-white capitalize"
97109
>
98110
{tiers.map((tier) => (
99-
<option key={tier} value={tier === 'All' ? '' : tier}>
111+
<option key={tier} value={tier === "All" ? "" : tier}>
100112
{tier}
101113
</option>
102114
))}
@@ -124,12 +136,12 @@ export default function GuildsPage() {
124136
title="No guilds found"
125137
description="Try adjusting your search or filters, or create a new guild."
126138
createLabel="Create Guild"
127-
onCreate={() => router.push('/guilds/create')}
139+
onCreate={() => router.push("/guilds/create")}
128140
illustration={<Filter className="h-14 w-14 text-gray-400" />}
129141
className="border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-800"
130142
/>
131143
)}
132144
</div>
133145
</div>
134-
)
146+
);
135147
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import React from 'react'
2+
import { cn } from '@/lib/utils'
3+
4+
export interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {
5+
/**
6+
* Animation variant
7+
* - shimmer: Sliding gradient effect (default)
8+
* - pulse: Simple opacity pulse
9+
*/
10+
animation?: 'shimmer' | 'pulse'
11+
/**
12+
* Skeleton shape variant
13+
* - text: Rounded corners for text lines
14+
* - circular: Circle for avatars
15+
* - rectangular: Full rounded corners for cards/images
16+
*/
17+
variant?: 'text' | 'circular' | 'rectangular'
18+
}
19+
20+
const Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(
21+
({ className, animation = 'shimmer', variant = 'text', ...props }, ref) => {
22+
const baseClasses = "bg-stellar-lightNavy overflow-hidden relative"
23+
24+
const variantClasses = {
25+
text: "rounded-md",
26+
circular: "rounded-full",
27+
rectangular: "rounded-lg",
28+
}
29+
30+
const animationClasses = {
31+
shimmer: "before:absolute before:inset-0 before:-translate-x-full before:animate-[shimmer_1.5s_infinite] before:bg-gradient-to-r before:from-transparent before:via-stellar-slate/10 before:to-transparent",
32+
pulse: "animate-[pulse_1.5s_ease-in-out_infinite]",
33+
}
34+
35+
return (
36+
<div
37+
className={cn(
38+
baseClasses,
39+
variantClasses[variant],
40+
animationClasses[animation],
41+
className
42+
)}
43+
ref={ref}
44+
{...props}
45+
/>
46+
)
47+
}
48+
)
49+
50+
Skeleton.displayName = "Skeleton"
51+
52+
export { Skeleton }

‎frontend/tailwind.config.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ const config: Config = {
5959
height: "height",
6060
spacing: "margin, padding",
6161
},
62+
keyframes: {
63+
shimmer: {
64+
"100%": {
65+
transform: "translateX(100%)",
66+
},
67+
},
68+
},
6269
},
6370
},
6471
plugins: [typography],

0 commit comments

Comments
 (0)