Files
doormile_react/src/components/sections/IndustryStack.tsx
2026-06-15 18:20:48 +05:30

323 lines
10 KiB
TypeScript

"use client";
import React, { useState } from "react";
import IndustryWorldMap from "./IndustryWorldMap";
type Tab = "ch" | "so";
interface Section {
id: number;
title: string;
image: string;
alt: string;
desc: string;
ch: string[];
so: string[];
}
const SECTIONS: Section[] = [
{
id: 1,
title: "FMCG",
image: "/images/tab-pic-1-solution.webp",
alt: "FMCG logistics",
desc:
"FMCG logistics demands speed, precision, and continuous fulfillment across high-volume delivery networks. Businesses must balance tight delivery timelines, inventory movement, and operational efficiency without compromising product availability.",
ch: [
"Unpredictable demand spikes create delivery pressure and reduce operational efficiency during peak periods.",
"Fresh product expiry constraints require faster, precisely timed deliveries to maintain product quality.",
"Multi-stop route complexity increases travel time, operational costs, and delivery coordination challenges.",
"Inventory stockout risks increase when delivery delays disrupt fast-moving product distribution.",
],
so: [
"AI demand forecasting adapts delivery plans instantly to real-time order demand.",
"Expiry-aware routing prioritises perishable goods for on-time freshness.",
"Smart multi-stop optimisation groups orders to cut cost and travel time.",
"Real-time inventory sync prevents stockouts and improves fulfilment accuracy.",
],
},
{
id: 2,
title: "Pharma",
image: "/images/tab-pic-2-solution.webp",
alt: "Pharma logistics",
desc:
"Pharma logistics requires precision, compliance, and real-time monitoring so every shipment arrives safely and on time — from temperature-sensitive medicines to urgent emergency deliveries.",
ch: [
"Cold chain integrity demands precise temperature control throughout transit.",
"Regulatory compliance must be tracked and documented on every delivery.",
"Critical delivery time windows require highly accurate scheduling.",
"Emergency shipments need instant dispatch and zero-delay execution.",
],
so: [
"Cold chain monitoring with automatic re-routing keeps shipments in-spec.",
"Compliance engine with audit trails ensures full chain-of-custody visibility.",
"Precision scheduling locks in critical delivery windows reliably.",
"Priority dispatch queue fast-tracks urgent, life-critical shipments.",
],
},
{
id: 3,
title: "Enterprise & B2B",
image: "/images/tab-pic-3-solution.webp",
alt: "Enterprise and B2B logistics",
desc:
"Enterprise and B2B logistics require coordination and reliability to manage high-value shipments at scale — with appointment scheduling, white-glove standards, and strict SLA commitments.",
ch: [
"Appointment scheduling requires precise timing across many locations.",
"White-glove delivery standards demand premium handling and accuracy.",
"Multi-location routing complexity grows with large-scale operations.",
"Strict SLA commitments pressure teams to stay timely and error-free.",
],
so: [
"Intelligent appointment engine streamlines and automates delivery slots.",
"White-glove workflow module enforces premium handling end to end.",
"Enterprise route planner coordinates efficient multi-location delivery.",
"SLA monitoring dashboard tracks commitments and flags risk in real time.",
],
},
];
function Card({ sec }: { sec: Section }) {
const [tab, setTab] = useState<Tab>("ch");
const bullets = tab === "ch" ? sec.ch : sec.so;
return (
<section className="istk" aria-label={`${sec.title} solutions`}>
<div className="istk__card">
<IndustryWorldMap />
<div className="istk__row">
{/* Image panel */}
<div className="istk__media">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img className="istk__img" src={sec.image} alt={sec.alt} decoding="async" loading="lazy" />
</div>
{/* Content panel */}
<div className="istk__content">
<h3 className="istk__title">{sec.title}</h3>
<p className="istk__desc">{sec.desc}</p>
<div className="istk__tabs" role="tablist" aria-label="Challenges or Solutions">
<button
type="button"
role="tab"
aria-selected={tab === "ch"}
className={`istk__tab ${tab === "ch" ? "active" : ""}`}
onClick={() => setTab("ch")}
>
Challenges
</button>
<button
type="button"
role="tab"
aria-selected={tab === "so"}
className={`istk__tab ${tab === "so" ? "active" : ""}`}
onClick={() => setTab("so")}
>
Solutions
</button>
</div>
<ul className="istk__list" key={tab}>
{bullets.map((b, i) => (
<li key={b} style={{ animationDelay: `${i * 80}ms` }}>
{b}
</li>
))}
</ul>
</div>
</div>
</div>
</section>
);
}
export default function IndustryStack() {
return (
<>
<style dangerouslySetInnerHTML={{ __html: CSS }} />
<div id="ind-stack">
{SECTIONS.map((sec) => (
<Card key={sec.id} sec={sec} />
))}
</div>
</>
);
}
/* ============================================================
Styles — faithful to the original PHP Solutions layout:
one large rounded dark card per industry, inset rounded image
on the left, simple large title, paragraph, Challenges/Solutions
pill tabs with an underline rule, and round red-dot bullets.
Uses the site's Manrope (no extra typefaces).
============================================================ */
const CSS = `
/* No outer frame — the cards float on the page background. */
#ind-stack { background: transparent; }
/* The kit-5 theme forces heading size/color on h3 via !important — re-assert. */
#ind-stack .istk__title {
font-family: var(--font-manrope), 'Manrope', system-ui, sans-serif !important;
font-size: clamp(42px, 4.4vw, 62px) !important;
font-weight: 600 !important;
line-height: 1.04 !important;
letter-spacing: -0.02em !important;
color: #ffffff !important;
text-transform: none !important;
margin: 0 0 22px !important;
}
#ind-stack .istk {
padding: 14px 20px;
}
#ind-stack .istk:first-child { padding-top: 24px; }
#ind-stack .istk:last-child { padding-bottom: 24px; }
#ind-stack .istk__card {
position: relative;
overflow: hidden;
background: #0d0d0d;
border: 1px solid rgba(255,255,255,0.06);
border-radius: 40px;
padding: 44px;
}
/* Procedurally-drawn dotted world map (continent dots + hub pulses + routes).
Vector canvas, so it never distorts on the card's aspect ratio the way a
stretched bitmap did. Faint gray dots read as a subtle backdrop on the dark card. */
#ind-stack .ind__map {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
z-index: 0;
opacity: 0.7;
pointer-events: none;
}
#ind-stack .istk__row {
position: relative;
z-index: 2;
display: flex;
flex-direction: row;
align-items: center;
gap: clamp(44px, 6vw, 104px);
}
/* ---- Image — inset rounded, portrait, drives the card height ---- */
#ind-stack .istk__media {
flex: 0 0 35%;
align-self: stretch;
min-height: 560px;
}
#ind-stack .istk__img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 26px;
}
/* ---- Content ---- */
#ind-stack .istk__content {
flex: 1;
min-width: 0;
max-width: 680px;
}
#ind-stack .istk__desc {
font-size: clamp(16px, 1.25vw, 20px);
font-weight: 400;
line-height: 1.62;
color: rgba(255,255,255,0.8);
margin: 0 0 30px;
}
/* Tabs — pills above a full-width underline rule */
#ind-stack .istk__tabs {
display: flex;
gap: 10px;
padding-bottom: 16px;
margin-bottom: 26px;
border-bottom: 1px solid rgba(255,255,255,0.2);
}
#ind-stack .istk__tab {
appearance: none;
border: none;
cursor: pointer;
font-size: 14px;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
padding: 13px 30px;
border-radius: 9px;
background: #f3dede;
color: #555;
transition: background-color 0.25s ease, color 0.25s ease;
}
#ind-stack .istk__tab:hover { background: #ecd2d2; }
#ind-stack .istk__tab.active {
background: #dc2626;
color: #fff;
box-shadow: 0 8px 22px -10px rgba(220,38,38,0.8);
}
/* Bullets — round red dots, full-sentence items */
#ind-stack .istk__list {
list-style: none;
margin: 0;
padding: 0;
}
#ind-stack .istk__list li {
position: relative;
padding-left: 28px;
margin-bottom: 22px;
font-size: clamp(15px, 1.15vw, 18px);
font-weight: 400;
line-height: 1.55;
color: rgba(255,255,255,0.85);
animation: istkSlideIn 0.4s ease both;
}
#ind-stack .istk__list li:last-child { margin-bottom: 0; }
#ind-stack .istk__list li::before {
content: '';
position: absolute;
left: 2px;
top: 9px;
width: 9px;
height: 9px;
border-radius: 50%;
background: #dc2626;
box-shadow: 0 0 8px rgba(220,38,38,0.55);
}
@keyframes istkSlideIn {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
/* ---- Responsive ---- */
@media (max-width: 1024px) {
#ind-stack .istk__card { padding: 28px; border-radius: 28px; }
#ind-stack .istk__row { flex-direction: column; align-items: stretch; gap: 28px; }
#ind-stack .istk__media { flex: none; min-height: 0; height: 300px; }
#ind-stack .istk__content { max-width: none; }
}
@media (max-width: 600px) {
#ind-stack .istk { padding: 10px; }
#ind-stack .istk__card { padding: 22px 20px; border-radius: 24px; }
#ind-stack .istk__media { height: 240px; }
#ind-stack .istk__title { margin-bottom: 16px !important; }
#ind-stack .istk__desc { margin: 0 0 24px; }
/* Two equal-width pills that always fit the card — no horizontal overflow. */
#ind-stack .istk__tabs { gap: 8px; margin-bottom: 22px; }
#ind-stack .istk__tab { flex: 1 1 0; min-width: 0; padding: 12px 8px; text-align: center; font-size: 13px; }
#ind-stack .istk__list li { margin-bottom: 18px; }
}
@media (prefers-reduced-motion: reduce) {
#ind-stack .istk__list li { animation: none !important; opacity: 1; transform: none; }
}
`;