New changes UI

This commit is contained in:
2026-01-05 18:53:25 +05:30
parent ad13634121
commit 676a40f0d9
3 changed files with 94 additions and 150 deletions

View File

@@ -8,15 +8,16 @@ import { toast } from "react-toastify";
const API_BASE = process.env.REACT_APP_API_BASE_URL; const API_BASE = process.env.REACT_APP_API_BASE_URL;
const SECTORS = [ const SECTORS = [
{ label: "Water Supply", value: "water supply" }, { label: "All", value: "All" },
{ label: "Storm Water", value: "storm water" }, { label: "Water Supply", value: "Water Supply" },
{ label: "Electromechanical", value: "electromechanical" }, { label: "Storm Water", value: "Storm Water" },
{ label: "Real Estate / Buildings", value: "real estate / buildings" }, { label: "Electromechanical", value: "Electromechanical & Instrumentation" },
{ label: "Tunnel", value: "tunnel" }, { label: "Real Estate / Buildings", value: "Real estate / Buildings" },
{ label: "Roads", value: "roads" }, { label: "Tunnel", value: "Tunnel" },
{ label: "Wastewater / Sewerage", value: "wastewater / sewerage" }, { label: "Roads", value: "Roads" },
{ label: "Irrigation", value: "irrigation" }, { label: "Wastewater / Sewerage", value: "Wastewater / Sewerage" },
{ label: "Renewable Energy", value: "renewable energy" }, { label: "Irrigation", value: "Irrigation" },
{ label: "Renewable Energy", value: "Renewable Energy" },
]; ];
const AddProjects = () => { const AddProjects = () => {

View File

@@ -1,45 +1,7 @@
import React, { useState, useEffect, useRef } from "react"; import React, { useState, useEffect, useRef } from "react";
import axios from "axios"; import axios from "axios";
import Slider from "react-slick";
import heroBg from "../assets/projects-hero.jpg"; import heroBg from "../assets/projects-hero.jpg";
import "../styles/Projects.css"; import "../styles/Projects.css";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
/* =====================
Custom Arrows
===================== */
const NextArrow = ({ className, style, onClick }) => (
<div
className={className}
style={{
...style,
display: "block",
background: "rgba(0,0,0,0.5)",
borderRadius: "50%",
padding: "10px",
right: "10px",
zIndex: 2,
}}
onClick={onClick}
/>
);
const PrevArrow = ({ className, style, onClick }) => (
<div
className={className}
style={{
...style,
display: "block",
background: "rgba(0,0,0,0.5)",
borderRadius: "50%",
padding: "10px",
left: "10px",
zIndex: 2,
}}
onClick={onClick}
/>
);
const Projects = () => { const Projects = () => {
const [selectedSector, setSelectedSector] = useState("all"); const [selectedSector, setSelectedSector] = useState("all");
@@ -54,7 +16,7 @@ const Projects = () => {
{ label: "All", value: "all" }, { label: "All", value: "all" },
{ label: "Water Supply", value: "water supply" }, { label: "Water Supply", value: "water supply" },
{ label: "Storm Water", value: "storm water" }, { label: "Storm Water", value: "storm water" },
{ label: "Electromechanical", value: "electromechanical" }, { label: "Electromechanical", value: "electromechanical & instrumentation" },
{ label: "Real Estate / Buildings", value: "real estate / buildings" }, { label: "Real Estate / Buildings", value: "real estate / buildings" },
{ label: "Tunnel", value: "tunnel" }, { label: "Tunnel", value: "tunnel" },
{ label: "Roads", value: "roads" }, { label: "Roads", value: "roads" },
@@ -63,9 +25,6 @@ const Projects = () => {
{ label: "Renewable Energy", value: "renewable energy" }, { label: "Renewable Energy", value: "renewable energy" },
]; ];
/* =====================
Fetch Projects
===================== */
useEffect(() => { useEffect(() => {
const fetchProjects = async () => { const fetchProjects = async () => {
try { try {
@@ -82,9 +41,6 @@ const Projects = () => {
fetchProjects(); fetchProjects();
}, []); }, []);
/* =====================
Scroll to sectors
===================== */
useEffect(() => { useEffect(() => {
if (window.location.hash === "#sectors" && sectorRef.current) { if (window.location.hash === "#sectors" && sectorRef.current) {
setTimeout(() => { setTimeout(() => {
@@ -108,32 +64,9 @@ const Projects = () => {
})); }));
}; };
/* =====================
Slider Settings
===================== */
const sliderSettings = {
dots: false,
infinite: true,
speed: 600,
slidesToShow: 3,
slidesToScroll: 1,
autoplay: true,
autoplaySpeed: 1500,
arrows: true,
nextArrow: <NextArrow />,
prevArrow: <PrevArrow />,
responsive: [
{ breakpoint: 1024, settings: { slidesToShow: 3 } },
{ breakpoint: 768, settings: { slidesToShow: 2 } },
{ breakpoint: 480, settings: { slidesToShow: 1 } },
],
};
return ( return (
<div className="min-h-screen bg-gray-50"> <div className="min-h-screen bg-gray-50">
{/* ===================== {/* Hero Section */}
Hero Section
====================== */}
<div <div
className="relative bg-cover bg-center h-[60vh] flex items-center justify-center" className="relative bg-cover bg-center h-[60vh] flex items-center justify-center"
style={{ backgroundImage: `url(${heroBg})` }} style={{ backgroundImage: `url(${heroBg})` }}
@@ -149,9 +82,7 @@ const Projects = () => {
</div> </div>
</div> </div>
{/* ===================== {/* Sector Buttons */}
Sector Buttons
====================== */}
<div <div
ref={sectorRef} ref={sectorRef}
className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4 px-4 mt-8 mb-10" className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4 px-4 mt-8 mb-10"
@@ -165,9 +96,7 @@ const Projects = () => {
"bg-gradient-to-r from-purple-400 to-purple-600", "bg-gradient-to-r from-purple-400 to-purple-600",
"bg-gradient-to-r from-red-400 to-red-600", "bg-gradient-to-r from-red-400 to-red-600",
]; ];
const isSelected = selectedSector === sector.value; const isSelected = selectedSector === sector.value;
return ( return (
<button <button
key={sector.value} key={sector.value}
@@ -182,81 +111,73 @@ const Projects = () => {
})} })}
</div> </div>
{/* ===================== {/* Projects Grid */}
Projects Slider <div className="px-6 mb-16 grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 gap-6">
====================== */}
<div className="px-6 mb-16">
{loading ? ( {loading ? (
<p className="text-center text-xl text-gray-500">Loading projects...</p> <p className="text-center text-xl text-gray-500">Loading projects...</p>
) : filteredProjects.length === 0 ? ( ) : filteredProjects.length === 0 ? (
<p className="text-center text-xl text-gray-600"> <p className="text-center text-xl text-gray-600">No projects available.</p>
No projects available.
</p>
) : ( ) : (
<Slider key={selectedSector} {...sliderSettings}> filteredProjects.map((project) => (
{filteredProjects.map((project) => ( <div key={project.id} className="radar-card bg-white rounded-xl shadow-lg overflow-hidden hover:shadow-2xl transition flex flex-col h-full">
<div key={project.id} className="px-2">
<div className="bg-white rounded-xl shadow-lg overflow-hidden hover:shadow-2xl transition"> {project.image && (
<div className="radar-image-container relative w-full aspect-[16/9] bg-gray-200 overflow-hidden flex-shrink-0">
<img
src={`${process.env.REACT_APP_API_BASE_URL}${project.image}`}
alt={project.name}
className="radar-image absolute inset-0 w-full h-full object-cover cursor-pointer"
onClick={(e) => {
e.stopPropagation();
setLightboxImage(`${process.env.REACT_APP_API_BASE_URL}${project.image}`);
}}
/>
</div>
)}
{/* ✅ FIXED IMAGE SIZE (NO BIG / SMALL ISSUE) */} <div className="p-4 flex flex-col flex-grow">
{project.image && ( <h3 className="radar-title text-lg font-bold text-blue-800 leading-tight">
<div className="relative w-full aspect-[16/9] bg-gray-200 overflow-hidden"> {project.name}
<img </h3>
src={`${process.env.REACT_APP_API_BASE_URL}${project.image}`} <p className="text-sm text-gray-600 mt-1 font-semibold">
alt={project.name} Sector: {project.sector
className="absolute inset-0 w-full h-full object-cover cursor-pointer" .split(" ")
onClick={(e) => { .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
e.stopPropagation(); .join(" ")}
setLightboxImage( </p>
`${process.env.REACT_APP_API_BASE_URL}${project.image}`
);
}}
/>
</div>
)}
<div className="p-4">
<h3 className="text-lg font-bold text-blue-800">
{project.name} {project.location && (
</h3> <p className="text-sm text-gray-600">
<p className="text-sm text-gray-600"> Location: {project.location}
Sector: {project.sector} </p>
)}
{project.description && (
<div className="text-sm text-gray-700 mt-auto pt-4">
<p>
{expandedDescriptions[project.id]
? project.description
: project.description.slice(0, 100) + "..."}
</p> </p>
{project.description.length > 100 && (
{project.location && ( <button
<p className="text-sm text-gray-600"> onClick={() => toggleDescription(project.id)}
Location: {project.location} className="text-blue-600 underline text-sm mt-1"
</p> >
)} {expandedDescriptions[project.id] ? "Read Less" : "Read More"}
</button>
{project.description && (
<p className="text-sm text-gray-700 mt-2">
{expandedDescriptions[project.id]
? project.description
: project.description.slice(0, 100) + "..."}
{project.description.length > 100 && (
<button
onClick={() => toggleDescription(project.id)}
className="ml-2 text-blue-600 underline text-sm"
>
{expandedDescriptions[project.id]
? "Read Less"
: "Read More"}
</button>
)}
</p>
)} )}
</div> </div>
</div> )}
</div> </div>
))} </div>
</Slider> ))
)} )}
</div> </div>
{/* ===================== {/* Image Lightbox */}
Image Lightbox
====================== */}
{lightboxImage && ( {lightboxImage && (
<div <div
className="fixed inset-0 bg-black bg-opacity-80 z-50 flex items-center justify-center" className="fixed inset-0 bg-black bg-opacity-80 z-50 flex items-center justify-center"
@@ -269,11 +190,7 @@ const Projects = () => {
> >
× ×
</button> </button>
<img <img src={lightboxImage} alt="Project" className="max-w-[90vw] max-h-[90vh] object-contain" />
src={lightboxImage}
alt="Project"
className="max-w-[90vw] max-h-[90vh] object-contain"
/>
</div> </div>
</div> </div>
)} )}

View File

@@ -28,3 +28,29 @@
stroke-width: 0.7; stroke-width: 0.7;
} }
} }
.map-wrapper {
width: 100%;
max-width: 100%;
overflow: hidden;
}
.map-wrapper svg {
width: 100%;
height: auto;
}
@media (max-width: 767px) {
/* Optional: reduce stroke width and marker size for mobile */
.map-wrapper svg .rsm-geography {
stroke-width: 0.5 !important;
}
.map-wrapper svg circle {
r: 6 !important; /* smaller circles on mobile */
stroke-width: 1 !important;
}
.map-wrapper svg text {
font-size: 12px !important; /* smaller text on mobile */
}
}