Files
pagodera/components/sections/featured-items.tsx
Evandro Fonseca Junior 5c1ccbc69a feat: integrate Tailwind CSS with custom theme and animations
Added Tailwind CSS and tw-animate-css imports to globals.css. Introduced a custom dark variant and an extensive @theme inline block with CSS variables for colors, radii, and animations. Included keyframes for shimmer-slide, spin-around, gradient, shine, and background-position-spin to enable consistent theming and dynamic UI effects across the application.
2025-10-23 19:57:09 -03:00

187 lines
5.4 KiB
TypeScript

"use client";
import { useState, useMemo } from "react";
import { useTranslations } from "next-intl";
import { ItemCard } from "@/components/item-card";
import { MarketplaceFilters } from "@/components/marketplace-filters";
import { featuredItems } from "@/lib/mock-data";
import { BlurFade } from "@/components/ui/blur-fade";
import { Skeleton } from "@/components/ui/skeleton";
export function FeaturedItems() {
const t = useTranslations("home.featured");
const [searchQuery, setSearchQuery] = useState("");
const [filters, setFilters] = useState<{
rarity: string[];
category: string[];
priceRange: { min: number; max: number };
}>({
rarity: [],
category: [],
priceRange: { min: 0, max: 100000 },
});
const [sortBy, setSortBy] = useState("name");
const [isLoading, setIsLoading] = useState(false);
// Filtrar e ordenar itens
const filteredItems = useMemo(() => {
let filtered = [...featuredItems];
// Filtro por busca
if (searchQuery) {
filtered = filtered.filter((item) =>
item.name.toLowerCase().includes(searchQuery.toLowerCase())
);
}
// Filtro por raridade
if (filters.rarity.length > 0) {
filtered = filtered.filter((item) =>
filters.rarity.includes(item.rarity)
);
}
// Filtro por categoria
if (filters.category.length > 0) {
filtered = filtered.filter((item) =>
filters.category.includes(item.category)
);
}
// Filtro por faixa de preço
filtered = filtered.filter(
(item) =>
item.price.buy >= filters.priceRange.min &&
item.price.buy <= filters.priceRange.max
);
// Ordenação
filtered.sort((a, b) => {
switch (sortBy) {
case "name":
return a.name.localeCompare(b.name);
case "price-asc":
return a.price.buy - b.price.buy;
case "price-desc":
return b.price.buy - a.price.buy;
case "rarity":
const rarityOrder = {
common: 0,
uncommon: 1,
rare: 2,
epic: 3,
legendary: 4,
};
return rarityOrder[a.rarity] - rarityOrder[b.rarity];
case "trending":
return b.priceHistory.highest - a.priceHistory.highest;
case "recent":
// Simular ordenação por data (mais recente primeiro)
return Math.random() - 0.5;
default:
return 0;
}
});
return filtered;
}, [searchQuery, filters, sortBy]);
const handleSearch = (query: string) => {
setSearchQuery(query);
};
const handleFilter = (newFilters: any) => {
setFilters(newFilters);
};
const handleSort = (sortValue: string) => {
setSortBy(sortValue);
};
// Skeleton para loading
const LoadingSkeleton = () => (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
{Array.from({ length: 8 }).map((_, index) => (
<div key={index} className="space-y-4">
<Skeleton className="h-48 w-full rounded-xl" />
<div className="space-y-2">
<Skeleton className="h-6 w-3/4" />
<Skeleton className="h-4 w-1/2" />
<Skeleton className="h-4 w-1/3" />
</div>
<div className="space-y-2">
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-2/3" />
</div>
</div>
))}
</div>
);
return (
<section className="py-20 bg-muted/30">
<div className="container">
<BlurFade delay={0.2}>
<div className="text-center mb-16">
<h2 className="text-4xl font-bold mb-4">{t("title")}</h2>
<p className="text-lg text-muted-foreground max-w-2xl mx-auto">
Descubra os melhores itens do servidor com preços atualizados em
tempo real
</p>
</div>
</BlurFade>
{/* Filtros e busca */}
<div className="mb-12">
<MarketplaceFilters
onSearch={handleSearch}
onFilter={handleFilter}
onSort={handleSort}
totalItems={filteredItems.length}
/>
</div>
{/* Grid de itens */}
{isLoading ? (
<LoadingSkeleton />
) : (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
{filteredItems.map((item, index) => (
<BlurFade key={item.id} delay={0.2 + index * 0.05}>
<ItemCard item={item} />
</BlurFade>
))}
</div>
)}
{/* Mensagem quando não há resultados */}
{filteredItems.length === 0 && !isLoading && (
<div className="text-center py-12">
<div className="text-6xl mb-4">🔍</div>
<h3 className="text-xl font-semibold mb-2">
Nenhum item encontrado
</h3>
<p className="text-muted-foreground mb-4">
Tente ajustar os filtros ou fazer uma nova busca
</p>
<button
onClick={() => {
setSearchQuery("");
setFilters({
rarity: [],
category: [],
priceRange: { min: 0, max: 100000 },
});
setSortBy("name");
}}
className="text-primary hover:underline"
>
Limpar todos os filtros
</button>
</div>
)}
</div>
</section>
);
}