promist
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
import { createFileRoute, Link } from "@tanstack/react-router";
|
||||
import { ArrowUpRight, Droplets, Wind, Factory, Sparkles, Gauge, ShieldCheck } from "lucide-react";
|
||||
import { useState, useCallback, useEffect } from "react";
|
||||
import useEmblaCarousel from "embla-carousel-react";
|
||||
import Autoplay from "embla-carousel-autoplay";
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
head: () => ({
|
||||
@@ -14,116 +17,168 @@ export const Route = createFileRoute("/")({
|
||||
});
|
||||
|
||||
const IMG = {
|
||||
nozzle: "https://promistcool.com/wp-content/uploads/2020/04/banner-sanitz.jpg",
|
||||
booth: "https://promistcool.com/wp-content/uploads/2020/04/image-002.png",
|
||||
humid: "https://promistcool.com/wp-content/uploads/2016/03/humidification-misting.jpg",
|
||||
commercial: "https://promistcool.com/wp-content/uploads/2016/03/commercial-misting.jpg",
|
||||
industrial: "https://promistcool.com/wp-content/uploads/2016/03/industrial-misting.jpg",
|
||||
project1: "https://promistcool.com/wp-content/uploads/2017/04/banner4.jpg",
|
||||
project2: "https://promistcool.com/wp-content/uploads/2017/04/banner2.jpg",
|
||||
project3: "https://promistcool.com/wp-content/uploads/2017/04/banner3.jpg",
|
||||
banner: "https://promistcool.com/wp-content/uploads/2017/04/new-banner.jpg",
|
||||
nozzle: "/wp-uploads/2020/04/banner-sanitz.jpg",
|
||||
booth: "/wp-uploads/2020/04/image-002.png",
|
||||
humid: "/wp-uploads/2016/03/humidification-misting.jpg",
|
||||
commercial: "/wp-uploads/2016/03/commercial-misting.jpg",
|
||||
industrial: "/wp-uploads/2016/03/industrial-misting.jpg",
|
||||
project1: "/wp-uploads/2017/04/banner4.jpg",
|
||||
project2: "/wp-uploads/2017/04/banner2.jpg",
|
||||
project3: "/wp-uploads/2017/04/banner3.jpg",
|
||||
banner: "/wp-uploads/2017/04/new-banner.jpg",
|
||||
};
|
||||
|
||||
const SLIDES = [
|
||||
{
|
||||
img: "/slide-sanitization.jpg",
|
||||
title: "Sanitization Booth",
|
||||
subtitle: "A turnkey solution for your disinfectant needs — engineered for continuous public use.",
|
||||
cta: "View details",
|
||||
ctaTo: "/products/sanitization-booth",
|
||||
},
|
||||
{
|
||||
img: "/slide-residential.jpg",
|
||||
title: "Residential Outdoor Cooling",
|
||||
subtitle: "Reclaim your outdoor spaces with high-pressure misting — even when temperatures push past 45°C.",
|
||||
cta: "Explore applications",
|
||||
ctaTo: "/applications",
|
||||
},
|
||||
{
|
||||
img: "/slide-humidity.jpg",
|
||||
title: "Humidity & Control",
|
||||
subtitle: "The most efficient way to keep the right humidity levels for industrial and commercial environments.",
|
||||
cta: "Request a quote",
|
||||
ctaTo: "/enquiry",
|
||||
},
|
||||
];
|
||||
|
||||
const APP_CARDS = [
|
||||
{ img: IMG.humid, title: "Humidification", desc: "Commercial and industrial environments where controlled humidity or temperature drive profitability.", icon: Droplets, href: "/applications/humidification" },
|
||||
{ img: IMG.commercial, title: "Commercial Outdoor Cooling", desc: "Reclaim patio dining and outdoor bars once temperatures push past 45°C.", icon: Wind, href: "/applications/commercial-outdoor-cooling" },
|
||||
{ img: IMG.industrial, title: "Industrial Cooling", desc: "A safer, more productive floor — cooling employees, equipment and processes.", icon: Factory, href: "/applications/industrial-outdoor-cooling" },
|
||||
];
|
||||
|
||||
function HeroSlider() {
|
||||
const [emblaRef, emblaApi] = useEmblaCarousel(
|
||||
{ loop: true, duration: 40 },
|
||||
[Autoplay({ delay: 5000, stopOnInteraction: true })],
|
||||
);
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
|
||||
const scrollTo = useCallback(
|
||||
(index: number) => emblaApi && emblaApi.scrollTo(index),
|
||||
[emblaApi],
|
||||
);
|
||||
|
||||
const onSelect = useCallback(() => {
|
||||
if (!emblaApi) return;
|
||||
setSelectedIndex(emblaApi.selectedScrollSnap());
|
||||
}, [emblaApi]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!emblaApi) return;
|
||||
onSelect();
|
||||
emblaApi.on("select", onSelect);
|
||||
return () => {
|
||||
emblaApi.off("select", onSelect);
|
||||
};
|
||||
}, [emblaApi, onSelect]);
|
||||
|
||||
return (
|
||||
<section className="relative overflow-hidden">
|
||||
<div ref={emblaRef} className="overflow-hidden">
|
||||
<div className="flex">
|
||||
{SLIDES.map((slide, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="relative min-w-0 shrink-0 grow-0 basis-full"
|
||||
>
|
||||
<div className="relative h-[75vh] min-h-[500px] max-h-[800px]">
|
||||
<img
|
||||
src={slide.img}
|
||||
alt={slide.title}
|
||||
className="absolute inset-0 w-full h-full object-cover"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-black/70 via-black/40 to-black/30" />
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<div className="container-page">
|
||||
<div className="max-w-2xl">
|
||||
<div className="inline-flex items-center gap-2 text-xs uppercase tracking-[0.25em] text-white/80 font-semibold mb-4">
|
||||
<span className="block w-8 h-0.5 bg-brand-red" /> Since 1979
|
||||
</div>
|
||||
<h1 className="font-display text-5xl md:text-7xl lg:text-8xl font-black leading-[0.95] text-white">
|
||||
{slide.title}
|
||||
</h1>
|
||||
<p className="mt-6 text-lg md:text-xl text-white/80 max-w-xl">
|
||||
{slide.subtitle}
|
||||
</p>
|
||||
<div className="mt-8 flex flex-wrap gap-3">
|
||||
<Link
|
||||
to={slide.ctaTo as any}
|
||||
className="inline-flex items-center gap-2 bg-brand-red text-white px-7 py-3.5 rounded-md text-sm font-semibold hover:opacity-90 transition-opacity"
|
||||
>
|
||||
{slide.cta} <ArrowUpRight className="h-4 w-4" />
|
||||
</Link>
|
||||
<Link
|
||||
to="/contact"
|
||||
className="inline-flex items-center gap-2 bg-white/10 backdrop-blur-sm text-white border border-white/30 px-7 py-3.5 rounded-md text-sm font-semibold hover:bg-white/20 transition-colors"
|
||||
>
|
||||
Contact us
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Dots */}
|
||||
<div className="absolute bottom-6 left-1/2 -translate-x-1/2 flex items-center gap-2.5">
|
||||
{SLIDES.map((_, i) => (
|
||||
<button
|
||||
key={i}
|
||||
onClick={() => scrollTo(i)}
|
||||
className={`rounded-full transition-all duration-300 ${
|
||||
i === selectedIndex
|
||||
? "w-8 h-2.5 bg-brand-red"
|
||||
: "w-2.5 h-2.5 bg-white/50 hover:bg-white/80"
|
||||
}`}
|
||||
aria-label={`Go to slide ${i + 1}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Arrows */}
|
||||
<button
|
||||
onClick={() => emblaApi?.scrollPrev()}
|
||||
className="absolute left-4 top-1/2 -translate-y-1/2 w-11 h-11 rounded-full bg-white/10 backdrop-blur-sm border border-white/20 flex items-center justify-center text-white hover:bg-white/20 transition-colors"
|
||||
aria-label="Previous slide"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => emblaApi?.scrollNext()}
|
||||
className="absolute right-4 top-1/2 -translate-y-1/2 w-11 h-11 rounded-full bg-white/10 backdrop-blur-sm border border-white/20 flex items-center justify-center text-white hover:bg-white/20 transition-colors"
|
||||
aria-label="Next slide"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</button>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function Home() {
|
||||
return (
|
||||
<>
|
||||
{/* HERO */}
|
||||
<section className="relative overflow-hidden border-b">
|
||||
<div className="container-page grid lg:grid-cols-12 gap-10 py-16 lg:py-24 items-center">
|
||||
<div className="lg:col-span-6">
|
||||
<div className="inline-flex items-center gap-2 text-xs uppercase tracking-[0.25em] text-brand-blue font-semibold">
|
||||
<span className="rule-blue" /> Since 1979
|
||||
</div>
|
||||
<h1 className="mt-6 font-display text-5xl md:text-7xl font-black leading-[0.95]">
|
||||
Humidity
|
||||
<br />
|
||||
<span className="text-brand-blue">and</span>{" "}
|
||||
<span className="text-brand-red italic">Control.</span>
|
||||
</h1>
|
||||
<p className="mt-6 text-lg text-muted-foreground max-w-xl">
|
||||
We engineer high-pressure misting systems that cool, humidify, suppress dust and sanitize —
|
||||
from residential patios to industrial factories across the region.
|
||||
</p>
|
||||
<div className="mt-8 flex flex-wrap gap-3">
|
||||
<Link to="/enquiry" className="inline-flex items-center gap-2 bg-brand-red text-white px-6 py-3.5 rounded-md text-sm font-semibold hover:opacity-90">
|
||||
Request a quote <ArrowUpRight className="h-4 w-4" />
|
||||
</Link>
|
||||
<Link to="/products" className="inline-flex items-center gap-2 border border-foreground/20 px-6 py-3.5 rounded-md text-sm font-semibold hover:border-brand-blue hover:text-brand-blue">
|
||||
Explore products
|
||||
</Link>
|
||||
</div>
|
||||
<dl className="mt-12 grid grid-cols-3 gap-6 max-w-lg">
|
||||
{[
|
||||
["45+", "Years of expertise"],
|
||||
["1000+", "Projects delivered"],
|
||||
["70 bar", "High-pressure precision"],
|
||||
].map(([k, v]) => (
|
||||
<div key={k}>
|
||||
<dt className="font-display text-3xl font-black text-brand-red">{k}</dt>
|
||||
<dd className="text-xs uppercase tracking-wider text-muted-foreground mt-1">{v}</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
<div className="lg:col-span-6">
|
||||
<div className="relative">
|
||||
<div className="absolute -inset-4 bg-gradient-to-br from-brand-blue/10 to-brand-red/10 blur-2xl" />
|
||||
<img src={IMG.nozzle} alt="Promist misting nozzle" className="relative w-full h-[520px] object-cover" />
|
||||
<div className="absolute bottom-0 left-0 right-0 bg-background/90 backdrop-blur border-t border-l border-r px-6 py-4 flex items-center justify-between">
|
||||
<div>
|
||||
<div className="text-xs uppercase tracking-widest text-muted-foreground">Featured</div>
|
||||
<div className="font-display text-xl font-bold">Sanitization Booth</div>
|
||||
</div>
|
||||
<Link to="/products" className="text-sm font-semibold text-brand-red inline-flex items-center gap-1">
|
||||
View <ArrowUpRight className="h-4 w-4" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* APPLICATIONS */}
|
||||
<section className="py-24">
|
||||
<div className="container-page">
|
||||
<div className="flex flex-wrap items-end justify-between gap-6 mb-14">
|
||||
<div>
|
||||
<span className="rule-red" />
|
||||
<h2 className="mt-4 font-display text-4xl md:text-5xl font-black">Applications</h2>
|
||||
<p className="mt-4 max-w-2xl text-muted-foreground">
|
||||
A cost-effective solution for outdoor cooling and humidification across industrial, commercial,
|
||||
residential, warehouses, greenhouses, gardens, patios, parks and amusement areas.
|
||||
</p>
|
||||
</div>
|
||||
<Link to="/applications" className="text-sm font-semibold text-brand-blue inline-flex items-center gap-1">
|
||||
All applications <ArrowUpRight className="h-4 w-4" />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-3 divide-y md:divide-y-0 md:divide-x border-y">
|
||||
{[
|
||||
{ img: IMG.humid, title: "Humidification", desc: "Commercial and industrial environments where controlled humidity or temperature drive profitability.", icon: Droplets },
|
||||
{ img: IMG.commercial, title: "Commercial Outdoor Cooling", desc: "Reclaim patio dining and outdoor bars once temperatures push past 45°C.", icon: Wind },
|
||||
{ img: IMG.industrial, title: "Industrial Cooling", desc: "A safer, more productive floor — cooling employees, equipment and processes.", icon: Factory },
|
||||
].map((a) => (
|
||||
<article key={a.title} className="p-8 group">
|
||||
<div className="aspect-[4/3] overflow-hidden">
|
||||
<img src={a.img} alt={a.title} className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105" />
|
||||
</div>
|
||||
<div className="mt-6 flex items-center gap-3">
|
||||
<a.icon className="h-5 w-5 text-brand-red" />
|
||||
<h3 className="font-display text-xl font-bold">{a.title}</h3>
|
||||
</div>
|
||||
<p className="mt-3 text-sm text-muted-foreground">{a.desc}</p>
|
||||
<Link to="/applications" className="mt-5 inline-flex items-center gap-1 text-sm font-semibold text-brand-red">
|
||||
Details <ArrowUpRight className="h-4 w-4" />
|
||||
</Link>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{/* HERO SLIDER */}
|
||||
<HeroSlider />
|
||||
|
||||
{/* SANITIZATION BOOTH FEATURE */}
|
||||
<section className="bg-muted/40 py-24 border-y">
|
||||
@@ -149,7 +204,7 @@ function Home() {
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Link to="/products" className="mt-8 inline-flex items-center gap-2 bg-brand-blue text-white px-6 py-3 rounded-md text-sm font-semibold hover:opacity-90">
|
||||
<Link to="/products/sanitization-booth" className="mt-8 inline-flex items-center gap-2 bg-brand-blue text-white px-6 py-3 rounded-md text-sm font-semibold hover:opacity-90">
|
||||
View details <ArrowUpRight className="h-4 w-4" />
|
||||
</Link>
|
||||
</div>
|
||||
@@ -159,6 +214,43 @@ function Home() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* APPLICATIONS */}
|
||||
<section className="py-24">
|
||||
<div className="container-page">
|
||||
<div className="flex flex-wrap items-end justify-between gap-6 mb-14">
|
||||
<div>
|
||||
<span className="rule-red" />
|
||||
<h2 className="mt-4 font-display text-4xl md:text-5xl font-black">Applications</h2>
|
||||
<p className="mt-4 max-w-2xl text-muted-foreground">
|
||||
A cost-effective solution for outdoor cooling and humidification across industrial, commercial,
|
||||
residential, warehouses, greenhouses, gardens, patios, parks and amusement areas.
|
||||
</p>
|
||||
</div>
|
||||
<Link to="/applications" className="text-sm font-semibold text-brand-blue inline-flex items-center gap-1">
|
||||
All applications <ArrowUpRight className="h-4 w-4" />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-3 divide-y md:divide-y-0 md:divide-x border-y">
|
||||
{APP_CARDS.map((a) => (
|
||||
<article key={a.title} className="p-8 group">
|
||||
<div className="aspect-[4/3] overflow-hidden">
|
||||
<img src={a.img} alt={a.title} className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105" />
|
||||
</div>
|
||||
<div className="mt-6 flex items-center gap-3">
|
||||
<a.icon className="h-5 w-5 text-brand-red" />
|
||||
<h3 className="font-display text-xl font-bold">{a.title}</h3>
|
||||
</div>
|
||||
<p className="mt-3 text-sm text-muted-foreground">{a.desc}</p>
|
||||
<Link to={a.href} className="mt-5 inline-flex items-center gap-1 text-sm font-semibold text-brand-red">
|
||||
Details <ArrowUpRight className="h-4 w-4" />
|
||||
</Link>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 5 REASONS */}
|
||||
<section className="py-24">
|
||||
<div className="container-page">
|
||||
|
||||
Reference in New Issue
Block a user