update about page
This commit is contained in:
326
src/components/sections/IndustryStack.tsx
Normal file
326
src/components/sections/IndustryStack.tsx
Normal file
@@ -0,0 +1,326 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import IndustryStackMap from "./IndustryStackMap";
|
||||
|
||||
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.jpeg",
|
||||
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.jpeg",
|
||||
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.jpeg",
|
||||
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">
|
||||
<span className="istk__map" aria-hidden="true" />
|
||||
<IndustryStackMap />
|
||||
|
||||
<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;
|
||||
}
|
||||
|
||||
/* Static dotted world map (image) — inverted to light dots on the dark card */
|
||||
#ind-stack .istk__map {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
background: url('/images/bg-map.png') center / 100% 100% no-repeat;
|
||||
filter: invert(1) brightness(1.4);
|
||||
opacity: 0.16;
|
||||
pointer-events: none;
|
||||
animation: istkMapBreathe 7s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Animated logistics overlay (hub pulses + travelling packets) sits over the map */
|
||||
#ind-stack .istk__canvas {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
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); }
|
||||
}
|
||||
@keyframes istkMapBreathe {
|
||||
0%, 100% { opacity: 0.12; }
|
||||
50% { opacity: 0.2; }
|
||||
}
|
||||
|
||||
/* ---- 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 (prefers-reduced-motion: reduce) {
|
||||
#ind-stack .istk__list li { animation: none !important; opacity: 1; transform: none; }
|
||||
#ind-stack .istk__map { animation: none !important; }
|
||||
}
|
||||
`;
|
||||
Reference in New Issue
Block a user