Visual edit in Lovable

Edited UI in Lovable
This commit is contained in:
gpt-engineer-app[bot] 2026-01-29 20:18:51 +00:00
parent 516f18a742
commit 34fe6ad5be

View file

@ -10,31 +10,25 @@ import Fuse from 'fuse.js';
// Animated counter hook
function useAnimatedCounter(end: number, duration: number = 2000) {
const [count, setCount] = useState(0);
useEffect(() => {
let startTime: number;
let animationFrame: number;
const animate = (timestamp: number) => {
if (!startTime) startTime = timestamp;
const progress = Math.min((timestamp - startTime) / duration, 1);
// Easing function for smooth animation
const easeOutQuart = 1 - Math.pow(1 - progress, 4);
setCount(Math.floor(easeOutQuart * end));
if (progress < 1) {
animationFrame = requestAnimationFrame(animate);
}
};
animationFrame = requestAnimationFrame(animate);
return () => cancelAnimationFrame(animationFrame);
}, [end, duration]);
return count;
}
const Index = () => {
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
const [searchQuery, setSearchQuery] = useState('');
@ -43,18 +37,23 @@ const Index = () => {
const productsCount = useAnimatedCounter(1000, 2000);
const clientsCount = useAnimatedCounter(500, 2000);
const hoursCount = useAnimatedCounter(24, 1500);
const fuse = useMemo(() => new Fuse(products, {
keys: [
{ name: 'name', weight: 0.4 },
{ name: 'tags', weight: 0.3 },
{ name: 'description', weight: 0.2 },
{ name: 'sku', weight: 0.1 },
],
keys: [{
name: 'name',
weight: 0.4
}, {
name: 'tags',
weight: 0.3
}, {
name: 'description',
weight: 0.2
}, {
name: 'sku',
weight: 0.1
}],
threshold: 0.4,
includeScore: true,
includeScore: true
}), []);
const displayProducts = useMemo(() => {
let filtered = products;
@ -68,29 +67,24 @@ const Index = () => {
if (selectedCategory) {
filtered = filtered.filter(p => p.category === selectedCategory);
}
return filtered;
}, [searchQuery, selectedCategory, fuse]);
return (
<div className="min-h-screen bg-background">
return <div className="min-h-screen bg-background">
{/* Hero Section */}
<section
className="relative min-h-[320px] md:min-h-[400px] flex items-center justify-center bg-cover bg-center"
style={{ backgroundImage: `url(${heroBg})` }}
>
<section className="relative min-h-[320px] md:min-h-[400px] flex items-center justify-center bg-cover bg-center" style={{
backgroundImage: `url(${heroBg})`
}}>
<div className="absolute inset-0 gradient-industrial opacity-90" />
<div className="relative z-10 container mx-auto px-4 py-12 text-center">
<h1 className="font-display text-3xl md:text-4xl lg:text-5xl font-bold text-primary-foreground mb-3 animate-fade-in">
Industrial Supplies for
<span className="block text-brand-yellow">Mining & Construction</span>
</h1>
<p className="text-base md:text-lg text-primary-foreground/80 mb-6 max-w-2xl mx-auto animate-fade-in">
Quality fasteners, tools, and equipment. Request a quote today.
</p>
{/* Quick Stats with Animated Numbers */}
<div className="flex flex-wrap justify-center gap-6 md:gap-8 animate-fade-in" style={{ animationDelay: '0.2s' }}>
<div className="flex flex-wrap justify-center gap-6 md:gap-8 animate-fade-in" style={{
animationDelay: '0.2s'
}}>
<div className="text-center">
<p className="text-2xl md:text-3xl font-bold text-brand-yellow">{productsCount.toLocaleString()}+</p>
<p className="text-primary-foreground/70 text-xs md:text-sm">Products</p>
@ -115,32 +109,21 @@ const Index = () => {
<div className="flex flex-col lg:flex-row gap-6 lg:gap-8">
{/* Category Sidebar - Sticky */}
<div className="lg:sticky lg:top-4 lg:self-start">
<CategorySidebar
selectedCategory={selectedCategory}
onSelectCategory={setSelectedCategory}
/>
<CategorySidebar selectedCategory={selectedCategory} onSelectCategory={setSelectedCategory} />
</div>
{/* Products Section */}
<div className="flex-1">
{/* Search Bar - Above Products */}
<div className="mb-6">
<SearchBar
large
value={searchQuery}
onChange={setSearchQuery}
/>
<SearchBar large value={searchQuery} onChange={setSearchQuery} />
</div>
{/* Products Header */}
<div className="flex items-center justify-between mb-6">
<div>
<h2 className="font-display text-xl md:text-2xl font-bold text-foreground">
{selectedCategory
? `${selectedCategory.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}`
: searchQuery.length >= 2
? `Results for "${searchQuery}"`
: 'Featured Products'}
{selectedCategory ? `${selectedCategory.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}` : searchQuery.length >= 2 ? `Results for "${searchQuery}"` : 'Featured Products'}
</h2>
<p className="text-muted-foreground text-sm mt-1">
{displayProducts.length} products available
@ -151,19 +134,15 @@ const Index = () => {
{/* Scrollable Products Grid */}
<div className="max-h-[70vh] overflow-y-auto pr-2 scrollbar-thin">
<div className="grid grid-cols-2 lg:grid-cols-3 gap-3 md:gap-4">
{displayProducts.map((product) => (
<ProductCard key={product.id} product={product} />
))}
{displayProducts.map(product => <ProductCard key={product.id} product={product} />)}
</div>
{displayProducts.length === 0 && (
<div className="text-center py-12">
{displayProducts.length === 0 && <div className="text-center py-12">
<p className="text-muted-foreground">No products found.</p>
<p className="text-sm text-muted-foreground mt-1">
Try different keywords or browse categories.
</p>
</div>
)}
</div>}
</div>
</div>
</div>
@ -180,23 +159,15 @@ const Index = () => {
Add items to your cart and request a personalized quote today.
</p>
<div className="flex flex-wrap justify-center gap-4">
<a
href="tel:+27123456789"
className="inline-flex items-center gap-2 bg-brand-yellow text-brand-yellow-foreground font-semibold px-8 py-3 rounded-lg hover:opacity-90 transition-opacity"
>
<a href="tel:+27123456789" className="inline-flex items-center gap-2 bg-brand-yellow text-brand-yellow-foreground font-semibold px-8 py-3 rounded-lg hover:opacity-90 transition-opacity">
Call Us Now
</a>
<a
href="mailto:sales@westscottfasteners.co.za"
className="inline-flex items-center gap-2 bg-primary-foreground text-primary font-semibold px-8 py-3 rounded-lg hover:opacity-90 transition-opacity"
>
<a href="mailto:sales@westscottfasteners.co.za" className="inline-flex items-center gap-2 bg-primary-foreground text-primary font-semibold px-8 py-3 rounded-lg hover:opacity-90 transition-opacity">
Email Us
</a>
</div>
</div>
</section>
</div>
);
</div>;
};
export default Index;
export default Index;