Files
doormile_react/src/components/sections/MileTruthHero.tsx

442 lines
19 KiB
TypeScript

"use client";
import React, { useState, useEffect } from "react";
interface CounterProps {
from: number;
to: number;
duration?: number;
decimals?: number;
suffix?: string;
}
function Counter({ from, to, duration = 2000, decimals = 0, suffix = "" }: CounterProps) {
const [value, setValue] = useState(from);
useEffect(() => {
let startTimestamp: number | null = null;
const step = (timestamp: number) => {
if (!startTimestamp) startTimestamp = timestamp;
const progress = Math.min((timestamp - startTimestamp) / duration, 1);
const currentValue = progress * (to - from) + from;
setValue(currentValue);
if (progress < 1) {
window.requestAnimationFrame(step);
}
};
window.requestAnimationFrame(step);
}, [from, to, duration]);
return (
<>
{value.toFixed(decimals)}
{suffix}
</>
);
}
export default function MileTruthHero() {
const [mounted, setMounted] = useState(false);
useEffect(() => {
requestAnimationFrame(() => setMounted(true));
}, []);
return (
<>
<link rel="preload" as="image" href="/images/miletruth-bg.webp" />
<style dangerouslySetInnerHTML={{ __html: `
/* ── Hero wrapper: column layout, zero gap between hero + stats ── */
.miletruth-hero .elementor-element-86f3204 {
display: flex;
flex-direction: column;
gap: 0;
margin: 0;
padding: 0 20px;
}
/* ── Hero slider card ── */
.miletruth-hero-container {
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.05) 0%, rgba(0, 0, 0, 0.15) 55%, rgba(0, 0, 0, 0.3) 100%), url('/images/miletruth-bg.webp') !important;
background-size: cover !important;
background-position: center !important;
background-repeat: no-repeat !important;
/* Match the home page hero card (800px) so MileTruth has the same visual
presence on large desktop, MacBook M1/Pro, and standard laptops. */
min-height: 800px;
display: flex;
flex-direction: column;
justify-content: center;
border-radius: 25px 25px 0 0;
margin-top: 20px;
padding: 100px 40px;
}
.miletruth-hero-container::before {
display: none !important;
}
.miletruth-content {
position: relative;
z-index: 2;
width: 100%;
padding: 0 40px !important;
box-sizing: border-box;
}
.miletruth-hero .content-slider-item-heading,
.miletruth-hero .content-slider-item-heading .heading-content {
color: rgba(255, 255, 255, 0.96) !important;
font-family: var(--font-manrope), "Manrope", sans-serif !important;
font-size: clamp(34px, 5.5vw, 72px) !important;
font-weight: 850 !important;
line-height: 1.05 !important;
letter-spacing: -1.5px !important;
text-transform: uppercase !important;
text-align: center !important;
display: block;
}
.miletruth-hero .content-slider-item-text {
margin-top: 22px !important;
text-align: center !important;
}
.miletruth-hero .content-slider-item-text p {
color: rgba(255, 255, 255, 0.72) !important;
font-family: var(--font-manrope), "Manrope", sans-serif !important;
font-size: clamp(17px, 1.6vw, 23px) !important;
font-weight: 500 !important;
line-height: 1.65 !important;
margin: 0 auto !important;
max-width: 820px;
}
.miletruth-hero .slide-content {
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: center !important;
text-align: center !important;
width: 100% !important;
height: 100% !important;
padding: 0 40px !important;
box-sizing: border-box !important;
}
.miletruth-hero .slide-content,
.miletruth-hero .slide-content-inner {
/* These carry inherited 20px padding from the slider theme with
content-box sizing, so width:100% + padding overflowed the viewport
by ~40px and pushed the hero off-center. Force border-box so the
padding is contained and the block stays centered. */
box-sizing: border-box !important;
}
.miletruth-hero .slide-content-inner {
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: center !important;
text-align: center !important;
margin-left: auto !important;
margin-right: auto !important;
max-width: 1000px !important;
width: 100% !important;
}
.miletruth-hero .content-slider-item-heading,
.miletruth-hero .content-slider-item-heading .heading-content {
text-align: center !important;
display: block !important;
width: 100% !important;
margin-left: auto !important;
margin-right: auto !important;
}
.miletruth-hero .content-slider-item-text {
display: flex !important;
justify-content: center !important;
width: 100% !important;
margin-top: 23px !important;
text-align: center !important;
}
.miletruth-hero .text-content {
text-align: center !important;
max-width: 800px !important;
margin: 0 auto !important;
}
/* The "logico" slider reveal animation leaves these at opacity:0 until
its JS runs (absent in this rebuild), hiding the heading + subtitle.
Force them visible. */
.miletruth-hero .content-slider-item-heading,
.miletruth-hero .content-slider-item-text,
.miletruth-hero .logico-content-wrapper-1,
.miletruth-hero .logico-content-wrapper-2 {
opacity: 1 !important;
transform: none !important;
visibility: visible !important;
}
/* ══════════════════════════════════════════════════════════════════
Stats bar — dark rounded card overlapping the hero bottom
══════════════════════════════════════════════════════════════════ */
.miletruth-hero .elementor-element-8e5c81e {
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
width: 100% !important;
margin: -25px 0 0 0 !important;
background-color: #1F1F1F !important;
border-radius: 25px !important;
padding: 40px 0 !important;
position: relative !important;
z-index: 1 !important;
}
.miletruth-hero .elementor-element-8e5c81e > .e-con-inner {
width: 100% !important;
max-width: 1440px !important;
height: auto !important;
margin: 0 auto !important;
padding: 0 40px !important;
flex-grow: 0 !important;
box-sizing: border-box !important;
}
/* 4-col grid for counter widgets — rows size to content (not 1fr of the
container) so the counters aren't parked at the top of a tall row. */
.miletruth-hero .elementor-element-628123a {
display: grid !important;
grid-template-columns: repeat(4, 1fr) !important;
grid-template-rows: auto !important;
height: auto !important;
gap: 40px !important;
width: 100% !important;
justify-items: start !important;
align-items: start !important;
align-content: start !important;
}
/* Counter: title on top, number below, left-aligned */
.miletruth-hero .elementor-counter {
display: flex !important;
flex-direction: column !important;
align-items: flex-start !important;
text-align: left !important;
}
/* Counter title — above the number */
.miletruth-hero .elementor-counter-title {
font-family: var(--font-manrope), "Manrope", sans-serif !important;
font-size: 20px !important;
font-weight: 600 !important;
line-height: 1.3em !important;
color: #FFFFFF !important;
margin-bottom: 12px !important;
text-transform: none !important;
}
/* Counter number wrapper — centered */
.miletruth-hero .elementor-counter-number-wrapper {
font-family: var(--font-space-grotesk), "Space Grotesk", var(--font-manrope), "Manrope", sans-serif !important;
font-size: clamp(48px, 6.5vw, 100px) !important;
font-weight: 700 !important;
line-height: 1em !important;
color: #C01227 !important;
letter-spacing: -0.03em !important;
display: flex !important;
align-items: baseline !important;
justify-content: flex-start !important;
}
.miletruth-hero .elementor-counter-number {
color: #C01227 !important;
font-size: inherit !important;
font-weight: inherit !important;
}
.miletruth-hero .elementor-counter-number-suffix {
color: #C01227 !important;
font-size: inherit !important;
font-weight: inherit !important;
letter-spacing: -0.03em !important;
}
/* ── Responsive ── */
@media (max-width: 1200px) {
.miletruth-hero .content-slider-item-heading,
.miletruth-hero .content-slider-item-heading .heading-content {
font-size: 60px !important;
}
}
@media (max-width: 1024px) {
.miletruth-hero-container {
min-height: 600px;
padding: 120px 0;
}
.miletruth-hero .elementor-element-8e5c81e {
padding: 40px 0 !important;
}
.miletruth-hero .elementor-element-628123a {
grid-template-columns: repeat(2, 1fr) !important;
gap: 50px 40px !important;
}
.miletruth-hero .content-slider-item-heading,
.miletruth-hero .content-slider-item-heading .heading-content {
font-size: 50px !important;
line-height: 1.1 !important;
}
}
@media (max-width: 768px) {
.miletruth-hero .content-slider-item-heading,
.miletruth-hero .content-slider-item-heading .heading-content {
font-size: 40px !important;
line-height: 1.12 !important;
}
.miletruth-hero .content-slider-item-text p {
font-size: 16px !important;
}
}
@media (max-width: 580px) {
.miletruth-hero-container {
min-height: 500px;
padding: 100px 0;
}
.miletruth-hero .elementor-element-86f3204 {
padding: 0 12px;
}
/* Collapse the nested horizontal padding (was 40px + 40px on top of the
12px wrapper) — at 320px that left only ~136px for text and the long
heading words overflowed, causing horizontal scroll + off-center look. */
.miletruth-content {
padding: 0 14px !important;
}
.miletruth-hero .slide-content {
padding: 0 !important;
}
.miletruth-hero .elementor-element-8e5c81e {
padding: 30px 0 !important;
border-radius: 20px !important;
}
.miletruth-hero .elementor-element-8e5c81e > .e-con-inner {
padding: 0 20px !important;
}
.miletruth-hero .elementor-element-628123a {
grid-template-columns: 1fr !important;
gap: 36px !important;
/* Single column on mobile → center each stat in the card */
justify-items: center !important;
}
.miletruth-hero .elementor-counter {
align-items: center !important;
text-align: center !important;
}
.miletruth-hero .elementor-counter-number-wrapper {
justify-content: center !important;
}
.miletruth-hero .content-slider-item-heading,
.miletruth-hero .content-slider-item-heading .heading-content {
font-size: clamp(26px, 8vw, 32px) !important;
letter-spacing: -0.5px !important;
/* never let a single long word push past the viewport */
overflow-wrap: break-word;
word-break: break-word;
}
}
`}} />
<div className="elementor-63 miletruth-hero">
{/* Parent wrapper matching reference elementor-element-86f3204 */}
<div className="elementor-element elementor-element-86f3204 e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent" data-id="86f3204" data-element_type="container" data-e-type="container">
{/* Hero slider card — NOT using custom-standard-hero-container/card
because this hero has a unique structure: hero + stats bar in a
single column with -25px overlap and no overflow:hidden */}
<div className="miletruth-hero-container">
<div className="e-con-inner miletruth-content">
<div className="logico-content-slider-widget">
<div className="content-slider-wrapper">
<div className="content-slider-container">
<div className="content-slider owl-carousel owl-theme">
<div className="content-item slider-item elementor-repeater-item-6867061 slide-style-standard">
<div className="slide-content" style={{ paddingLeft: 0, paddingRight: 0 }}>
<div className="slide-content-inner">
<h1 className="content-slider-item-heading logico-content-wrapper-1">
<span className="heading-content">The Only AI Built<br />Exclusively for Logistics</span>
</h1>
<div className="content-slider-item-text logico-content-wrapper-2">
<div className="text-content">
<p>Optimizes every stage of the delivery journey for maximum efficiency.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Metric Stats Bar */}
<div className="elementor-element elementor-element-8e5c81e e-flex e-con-boxed cut-corner-no sticky-container-off e-con e-child" data-id="8e5c81e" data-element_type="container" data-e-type="container" data-settings='{"background_background":"classic"}'>
<div className="e-con-inner">
<div className="elementor-element elementor-element-628123a e-con-full e-grid cut-corner-no sticky-container-off e-con e-child" data-id="628123a" data-element_type="container" data-e-type="container">
{/* SLA Compliance */}
<div className="elementor-element elementor-element-1da88b5 elementor-widget elementor-widget-counter" data-id="1da88b5" data-element_type="widget" data-e-type="widget" data-widget_type="counter.default">
<div className="elementor-widget-container">
<div className="elementor-counter">
<div className="elementor-counter-title">SLA Compliance</div>
<div className="elementor-counter-number-wrapper">
<span className="elementor-counter-number">
{mounted ? <Counter from={1} to={99.9} decimals={1} suffix="" /> : "1"}
</span>
<span className="elementor-counter-number-suffix">&nbsp;%</span>
</div>
</div>
</div>
</div>
{/* Distance Saved */}
<div className="elementor-element elementor-element-1da88b5 elementor-widget elementor-widget-counter" data-id="1da88b5-2" data-element_type="widget" data-e-type="widget" data-widget_type="counter.default">
<div className="elementor-widget-container">
<div className="elementor-counter">
<div className="elementor-counter-title">Distance Saved</div>
<div className="elementor-counter-number-wrapper">
<span className="elementor-counter-number">
{mounted ? <Counter from={1} to={42} decimals={0} suffix="" /> : "1"}
</span>
<span className="elementor-counter-number-suffix">&nbsp;%</span>
</div>
</div>
</div>
</div>
{/* Fewer Vehicles */}
<div className="elementor-element elementor-element-1da88b5 elementor-widget elementor-widget-counter" data-id="1da88b5-3" data-element_type="widget" data-e-type="widget" data-widget_type="counter.default">
<div className="elementor-widget-container">
<div className="elementor-counter">
<div className="elementor-counter-title">Fewer Vehicles</div>
<div className="elementor-counter-number-wrapper">
<span className="elementor-counter-number">
{mounted ? <Counter from={1} to={37} decimals={0} suffix="" /> : "1"}
</span>
<span className="elementor-counter-number-suffix">&nbsp;%</span>
</div>
</div>
</div>
</div>
{/* Dispatch Latency */}
<div className="elementor-element elementor-element-a1cf3d4 elementor-widget elementor-widget-counter" data-id="a1cf3d4" data-element_type="widget" data-e-type="widget" data-widget_type="counter.default">
<div className="elementor-widget-container">
<div className="elementor-counter">
<div className="elementor-counter-title">Dispatch Latency</div>
<div className="elementor-counter-number-wrapper">
<span className="elementor-counter-number">
{mounted ? <Counter from={1} to={45} decimals={0} suffix="" /> : "45"}
</span>
<span className="elementor-counter-number-suffix">ms</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</>
);
}