update logistices

This commit is contained in:
2026-06-02 23:59:51 +05:30
parent bae2fa0daa
commit 3bad62851c
32 changed files with 2305 additions and 1222 deletions

View File

@@ -90,7 +90,7 @@ export default function ConnectedLogistics() {
</div>
<div className="elementor-element elementor-element-165dfa5 elementor-widget__width-initial elementor-widget elementor-widget-text-editor" data-id="165dfa5" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
<div className="elementor-widget-container">
<p>Detect SLA risks hours before they become problems. Act, don't react.</p>
<p>Detect SLA risks hours before they become problems. Act, don&apos;t react.</p>
</div>
</div>
</ScrollReveal>

View File

@@ -120,6 +120,72 @@ export default function ContactForm() {
return (
<div className="elementor elementor-6585">
<style dangerouslySetInnerHTML={{ __html: `
/* ---- Clean contact form (scoped to this section) ---- */
.elementor-6585 .elementor-element.elementor-element-a5c503d {
--padding-top: 60px;
--padding-bottom: 60px;
--padding-left: 60px;
--padding-right: 60px;
}
.elementor-6585 .elementor-element.elementor-element-0e6fedf > .elementor-widget-container {
margin: 4px 0 0 0;
}
/* drop the legacy notched / floating-label borders */
.elementor-6585 .wpforms-form .logico-form-field:before,
.elementor-6585 .wpforms-form .logico-form-field:after,
.elementor-6585 .wpforms-form .logico-label-placeholder { display: none !important; }
/* even field rhythm */
.elementor-6585 .wpforms-form .wpforms-field-container {
display: flex;
flex-direction: column;
gap: 16px;
}
.elementor-6585 .wpforms-form .wpforms-field { padding: 0 !important; margin: 0 !important; }
/* labels stay for screen readers; placeholders carry the visible text */
.elementor-6585 .wpforms-form .wpforms-field-label {
position: absolute !important;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden; clip: rect(0 0 0 0);
white-space: nowrap; border: 0;
}
/* clean rounded inputs */
.elementor-6585 .wpforms-form input[type="text"],
.elementor-6585 .wpforms-form input[type="email"],
.elementor-6585 .wpforms-form textarea {
width: 100%;
border: 1px solid #e3e3e3 !important;
border-radius: 12px !important;
padding: 16px 20px !important;
font-size: 15px;
line-height: 1.5;
color: #111;
background: #fff;
box-shadow: none !important;
transition: border-color .25s ease;
}
.elementor-6585 .wpforms-form textarea { min-height: 150px; resize: vertical; }
.elementor-6585 .wpforms-form input::placeholder,
.elementor-6585 .wpforms-form textarea::placeholder { color: #9a9a9a; opacity: 1; }
.elementor-6585 .wpforms-form input:focus,
.elementor-6585 .wpforms-form textarea:focus { border-color: #c01227 !important; outline: none; }
.elementor-6585 .wpforms-form .wpforms-submit-container { padding-top: 26px !important; }
@media (max-width: 1020px) {
.elementor-6585 .elementor-element.elementor-element-a5c503d {
--padding-top: 40px;
--padding-bottom: 40px;
--padding-left: 32px;
--padding-right: 32px;
}
}
` }} />
<div className="elementor-element elementor-element-3cd920c e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent" data-id="3cd920c" data-element_type="container" data-e-type="container">
<div className="elementor-element elementor-element-b29b8fc e-flex e-con-boxed cut-corner-no sticky-container-off e-con e-child" data-id="b29b8fc" data-element_type="container" data-e-type="container" data-settings="{&quot;background_background&quot;:&quot;classic&quot;}">
<div className="e-con-inner">
@@ -254,77 +320,57 @@ export default function ContactForm() {
<div className="elementor-widget-container">
<div className="logico-wpforms-widget">
<div className="wpforms-container wpforms-render-modern" id="wpforms-369-contact">
<form id="wpforms-form-369-contact" className="wpforms-validate wpforms-form" onSubmit={handleSubmit}>
<div className="wpforms-field-container" style={{ marginTop: "30px" }}>
<div className="wpforms-field wpforms-field-wrapper logico-form-field" style={{ marginBottom: "20px" }}>
<div className="logico-label-wrapper" >
<div className="logico-label-placeholder" >
<div className="logico-label-placeholder-text">Full name</div>
</div>
<label className="wpforms-field-label" htmlFor="contact-field-name" >Full name</label>
</div>
<form id="wpforms-form-369-contact" className="wpforms-validate wpforms-form" onSubmit={handleSubmit} noValidate>
<div className="wpforms-field-container">
<div className="wpforms-field logico-form-field">
<label className="wpforms-field-label" htmlFor="contact-field-name">Full name</label>
<input
type="text"
id="contact-field-name"
className="wpforms-field-large"
name="fullName"
placeholder="Full name"
value={formData.fullName}
onChange={handleInputChange}
required
/>
</div>
<div className="wpforms-field wpforms-field-wrapper logico-form-field" style={{ marginBottom: "20px" }}>
<div className="logico-label-wrapper">
<div className="logico-label-placeholder">
<div className="logico-label-placeholder-text">Email</div>
</div>
<label className="wpforms-field-label" htmlFor="contact-field-email">Email</label>
</div>
<div className="wpforms-field logico-form-field">
<label className="wpforms-field-label" htmlFor="contact-field-email">Email</label>
<input
type="email"
id="contact-field-email"
className="wpforms-field-large"
name="email"
placeholder="Email"
value={formData.email}
onChange={handleInputChange}
required
/>
</div>
<div className="wpforms-field wpforms-field-wrapper logico-form-field" style={{ marginBottom: "20px" }}>
<div className="logico-label-wrapper">
<div className="logico-label-placeholder">
<div className="logico-label-placeholder-text">Subject</div>
</div>
<label className="wpforms-field-label" htmlFor="contact-field-subject">Subject</label>
</div>
<div className="wpforms-field logico-form-field">
<label className="wpforms-field-label" htmlFor="contact-field-subject">Subject</label>
<input
type="text"
id="contact-field-subject"
className="wpforms-field-large"
name="subject"
placeholder="Subject"
value={formData.subject}
onChange={handleInputChange}
required
/>
</div>
<div className="wpforms-field wpforms-field-wrapper logico-form-field" style={{ marginBottom: "20px" }}>
<div className="logico-label-wrapper">
<div className="logico-label-placeholder">
<div className="logico-label-placeholder-text">Message</div>
</div>
<label className="wpforms-field-label" htmlFor="contact-field-message">Message</label>
</div>
<div className="wpforms-field logico-form-field">
<label className="wpforms-field-label" htmlFor="contact-field-message">Message</label>
<textarea
id="contact-field-message"
className="wpforms-field-large"
name="message"
placeholder="Message"
value={formData.message}
onChange={handleInputChange}
required
></textarea>
</div>
</div>
<div className="wpforms-submit-container" style={{ marginTop: "30px" }}>
<div className="wpforms-submit-container">
<button
type="submit"
id="wpforms-submit-369-contact"

View File

@@ -3,16 +3,37 @@ import React from "react";
export default function ContactMap() {
return (
<div className="elementor-element elementor-element-7304a53 e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent" data-id="7304a53" data-element_type="container" data-e-type="container">
<style dangerouslySetInnerHTML={{ __html: `
.elementor-element-7304a53 {
--padding-left: 20px;
--padding-right: 20px;
--margin-top: 40px;
--margin-bottom: 0px;
}
.elementor-element-7304a53 .elementor-custom-embed {
border-radius: 25px 25px 0 0;
overflow: hidden;
background: #ededed;
line-height: 0;
}
.elementor-element-7304a53 .elementor-custom-embed iframe {
display: block;
filter: grayscale(100%);
}
@media (max-width: 768px) {
.elementor-element-7304a53 .elementor-custom-embed { height: 360px !important; }
}
` }} />
<div className="elementor-element elementor-element-5a3eed4 elementor-widget elementor-widget-google_maps" data-id="5a3eed4" data-element_type="widget" data-e-type="widget" data-widget_type="google_maps.default">
<div className="elementor-widget-container">
<div className="elementor-custom-embed" style={{ width: "100%", height: "450px" }}>
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3806.1918122409634!2d78.35579498480733!3d17.45053110831999!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x3bcb93b8c5a049b3%3A0x6f4b5999fccad985!2sJayabheri%20Enclave%2C%20Gachibowli%2C%20Hyderabad%2C%20Telangana!5e0!3m2!1sen!2sin!4v1778663239768!5m2!1sen!2sin"
width="100%"
height="100%"
style={{ border: 0 }}
<div className="elementor-custom-embed" style={{ width: "100%", height: "500px" }}>
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3806.1918122409634!2d78.35579498480733!3d17.45053110831999!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x3bcb93b8c5a049b3%3A0x6f4b5999fccad985!2sJayabheri%20Enclave%2C%20Gachibowli%2C%20Hyderabad%2C%20Telangana!5e0!3m2!1sen!2sin!4v1778663239768!5m2!1sen!2sin"
width="100%"
height="100%"
style={{ border: 0 }}
allowFullScreen={true}
loading="lazy"
loading="lazy"
referrerPolicy="no-referrer-when-downgrade"
title="Doormile Location Map"
/>

View File

@@ -1,13 +1,9 @@
"use client";
import React, { useEffect, useRef, useState } from "react";
import dynamic from "next/dynamic";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
// Drifting particle background — client-only, mounted behind the section.
const EVParticles = dynamic(() => import("./EVParticles"), { ssr: false });
if (typeof window !== "undefined") {
gsap.registerPlugin(ScrollTrigger);
}
@@ -77,7 +73,7 @@ function CountUp({
if (!el) return;
const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
if (reduced) {
setN(value);
requestAnimationFrame(() => setN(value));
return;
}
const io = new IntersectionObserver(
@@ -444,10 +440,6 @@ export default function EVSection() {
{/* ===== EV-Native Design (redesigned) ===== */}
<section className="evnd" id="evnd" aria-label="EV-Native Design">
<div className="evnd__canvas-wrap" style={{ position: "absolute", inset: 0, zIndex: 0, pointerEvents: "none" }}>
<EVParticles />
</div>
<div className="evnd__inner">
{/* TOP ROW */}
<div className="evnd__top">

View File

@@ -1,7 +1,6 @@
"use client";
import React, { useState, useEffect } from "react";
import Link from "next/link";
export default function HowItWorksHero() {
const [activeSlide, setActiveSlide] = useState(0);

View File

@@ -1,7 +1,7 @@
"use client";
import React, { useState } from "react";
import IndustryStackMap from "./IndustryStackMap";
import IndustryWorldMap from "./IndustryWorldMap";
type Tab = "ch" | "so";
@@ -85,8 +85,7 @@ function Card({ sec }: { sec: Section }) {
return (
<section className="istk" aria-label={`${sec.title} solutions`}>
<div className="istk__card">
<span className="istk__map" aria-hidden="true" />
<IndustryStackMap />
<IndustryWorldMap />
<div className="istk__row">
{/* Image panel */}
@@ -186,25 +185,16 @@ const CSS = `
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 {
/* 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: 1;
z-index: 0;
opacity: 0.7;
pointer-events: none;
}
@@ -307,10 +297,6 @@ const CSS = `
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) {
@@ -321,6 +307,5 @@ const CSS = `
}
@media (prefers-reduced-motion: reduce) {
#ind-stack .istk__list li { animation: none !important; opacity: 1; transform: none; }
#ind-stack .istk__map { animation: none !important; }
}
`;

View File

@@ -1,198 +0,0 @@
"use client";
import React, { useEffect, useRef } from "react";
/**
* Animated logistics overlay drawn over the static dotted world map image
* (`/images/bg-map.png`, set as the card background in IndustryStack).
*
* - 6 city hub nodes placed on real continents (lon/lat → normalised coords),
* each with a sin() expanding pulse ring + a solid red centre dot.
* - 4 delivery packets (#ef4444) travelling quadratic-Bézier arcs between
* random node pairs at 0.0030.006 / frame; on arrival they pick a fresh
* random pair and restart — reading as live routes across the map.
*
* The canvas is full-bleed over the card and lines up with the background
* map because both fill the same rect (the map uses background-size 100% 100%).
*/
// 6 hub cities, normalised to an equirectangular map: x=(lon+180)/360, y=(90-lat)/180.
// Kept to the right/centre so they sit in the content area (the left is the photo).
const NODES: [number, number][] = [
[0.5, 0.217], // London
[0.653, 0.361], // Dubai
[0.703, 0.394], // Mumbai
[0.836, 0.328], // Shanghai
[0.789, 0.493], // Singapore
[0.919, 0.689], // Sydney
];
interface Packet {
from: number;
to: number;
t: number;
speed: number;
}
const randNode = () => Math.floor(Math.random() * NODES.length);
function newPacket(): Packet {
let from = randNode();
let to = randNode();
while (to === from) to = randNode();
return { from, to, t: 0, speed: 0.003 + Math.random() * 0.003 };
}
export default function IndustryStackMap() {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = canvasRef.current;
const parent = canvas?.parentElement;
if (!canvas || !parent) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
let w = 0;
let h = 0;
let packets: Packet[] = Array.from({ length: 4 }, newPacket);
let raf = 0;
let startTs = 0;
const resize = () => {
const rect = parent.getBoundingClientRect();
w = Math.max(1, rect.width);
h = Math.max(1, rect.height);
const dpr = Math.min(window.devicePixelRatio || 1, 2);
canvas.width = Math.round(w * dpr);
canvas.height = Math.round(h * dpr);
canvas.style.width = w + "px";
canvas.style.height = h + "px";
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
};
const nodePx = (i: number) => ({ x: NODES[i][0] * w, y: NODES[i][1] * h });
const ctrl = (p0: { x: number; y: number }, p1: { x: number; y: number }) => {
const mx = (p0.x + p1.x) / 2;
const my = (p0.y + p1.y) / 2;
const lift = Math.hypot(p1.x - p0.x, p1.y - p0.y) * 0.26;
return { x: mx, y: my - lift };
};
const bezier = (
p0: { x: number; y: number },
c: { x: number; y: number },
p1: { x: number; y: number },
t: number
) => {
const u = 1 - t;
return {
x: u * u * p0.x + 2 * u * t * c.x + t * t * p1.x,
y: u * u * p0.y + 2 * u * t * c.y + t * t * p1.y,
};
};
const draw = (time: number, advance: boolean) => {
ctx.clearRect(0, 0, w, h);
// Faint route arcs between every hub pair
ctx.save();
ctx.lineWidth = 1;
for (let a = 0; a < NODES.length; a++) {
for (let b = a + 1; b < NODES.length; b++) {
const p0 = nodePx(a);
const p1 = nodePx(b);
const c = ctrl(p0, p1);
ctx.strokeStyle = "rgba(220,38,38,0.10)";
ctx.beginPath();
ctx.moveTo(p0.x, p0.y);
ctx.quadraticCurveTo(c.x, c.y, p1.x, p1.y);
ctx.stroke();
}
}
ctx.restore();
// Delivery packets along Bézier arcs
for (const p of packets) {
const p0 = nodePx(p.from);
const p1 = nodePx(p.to);
const c = ctrl(p0, p1);
const pos = bezier(p0, c, p1, p.t);
// soft trail
const tt = Math.max(0, p.t - 0.06);
const prev = bezier(p0, c, p1, tt);
const grad = ctx.createLinearGradient(prev.x, prev.y, pos.x, pos.y);
grad.addColorStop(0, "rgba(239,68,68,0)");
grad.addColorStop(1, "rgba(239,68,68,0.55)");
ctx.strokeStyle = grad;
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(prev.x, prev.y);
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
ctx.shadowColor = "#ef4444";
ctx.shadowBlur = 12;
ctx.fillStyle = "#ef4444";
ctx.beginPath();
ctx.arc(pos.x, pos.y, 3.5, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0;
if (advance) {
p.t += p.speed;
if (p.t >= 1) Object.assign(p, newPacket());
}
}
// City hub nodes — expanding pulse ring + solid centre dot
for (let i = 0; i < NODES.length; i++) {
const n = nodePx(i);
const phase = (Math.sin(time * 1.6 + i * 1.1) + 1) / 2; // 0..1
const radius = 3 + phase * 20;
const alpha = (1 - phase) * 0.5;
ctx.beginPath();
ctx.strokeStyle = `rgba(220,38,38,${alpha})`;
ctx.lineWidth = 1.5;
ctx.arc(n.x, n.y, radius, 0, Math.PI * 2);
ctx.stroke();
ctx.fillStyle = "#dc2626";
ctx.shadowColor = "#dc2626";
ctx.shadowBlur = 8;
ctx.beginPath();
ctx.arc(n.x, n.y, 2.5, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0;
}
};
const loop = (ts: number) => {
if (!startTs) startTs = ts;
draw((ts - startTs) / 1000, true);
raf = requestAnimationFrame(loop);
};
resize();
if (reduced) {
draw(0, false);
} else {
raf = requestAnimationFrame(loop);
}
const ro = new ResizeObserver(() => {
resize();
if (reduced) draw(0, false);
});
ro.observe(parent);
return () => {
cancelAnimationFrame(raf);
ro.disconnect();
};
}, []);
return <canvas ref={canvasRef} className="istk__canvas" aria-hidden="true" />;
}

View File

@@ -1,7 +1,6 @@
"use client";
import React, { useState, useEffect, useRef } from "react";
import Image from "next/image";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";

View File

@@ -39,7 +39,7 @@ export default function MileTruthHero() {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
requestAnimationFrame(() => setMounted(true));
}, []);
return (

View File

@@ -173,7 +173,7 @@ export default function SolutionsHero() {
</h1>
<div className="content-slider-item-text logico-content-wrapper-2">
<div className="text-content">
<p>Discover how Doormile's connected logistics platform serves diverse industries with tailored solutions.</p>
<p>Discover how Doormile&apos;s connected logistics platform serves diverse industries with tailored solutions.</p>
</div>
</div>
</div>
@@ -199,7 +199,7 @@ export default function SolutionsHero() {
<div className="slide-content">
<div className="slide-content-inner">
<h1 className="content-slider-item-heading logico-content-wrapper-1">
<span className="heading-content">One Platform. All Verticals.</span>
<span className="heading-content">One Platform. All Verticals</span>
</h1>
<div className="content-slider-item-text logico-content-wrapper-2">
<div className="text-content">

View File

@@ -110,11 +110,11 @@ const styles = `
.dm-wf1-card {
position: relative;
z-index: 2;
margin: -28px 40px 0;
margin: 0 40px 0;
background: linear-gradient(180deg, #030a18 0%, #06101f 100%);
border: 1px solid rgba(255, 255, 255, 0.05);
border-top: none;
border-radius: 0 0 35px 35px;
border-radius: 0 0 42px 42px;
box-shadow: 0 10px 40px -10px rgba(0, 0, 0, 0.5);
padding: 48px 60px;
display: flex;
@@ -201,7 +201,7 @@ const styles = `
/* ── Responsive — keep insets/radius aligned to the optimisation card ── */
@media (max-width: 1024px) {
.dm-wf1-card {
margin: -20px 20px 0;
margin: 0 20px 0;
border-radius: 0 0 42px 42px;
padding: 44px 44px;
gap: 44px;
@@ -210,7 +210,7 @@ const styles = `
}
@media (max-width: 768px) {
.dm-wf1-card {
margin: -14px 10px 0;
margin: 0 10px 0;
border-radius: 0 0 28px 28px;
padding: 36px 28px;
gap: 36px;