update doormile wings page
This commit is contained in:
392
src/components/sections/WingsMileTruth.tsx
Normal file
392
src/components/sections/WingsMileTruth.tsx
Normal file
@@ -0,0 +1,392 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import { ScrollReveal, StaggerChildren } from "@/animations/Reveal";
|
||||
|
||||
const CAPABILITIES = [
|
||||
{
|
||||
title: "Demand Forecasting",
|
||||
desc: "AI-driven forward projection of cargo demand, preemptively positioning aircraft and ground capacity.",
|
||||
icon: (
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.25" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M3 3v18h18" />
|
||||
<path d="M7 14l4-4 3 3 6-7" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Dynamic Pricing",
|
||||
desc: "Real-time rate adjustments that track market capacity fluctuations and optimize yield.",
|
||||
icon: (
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.25" strokeLinecap="round" strokeLinejoin="round">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="M9.5 9.5c0-1.4 1.1-2.3 2.5-2.3s2.5.9 2.5 2c0 1.6-2.2 1.8-2.5 3.3M12 17h.01" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Route Optimization",
|
||||
desc: "Dynamic scheduling for ground EV pickups and flights that bypasses congestion for the fastest path.",
|
||||
icon: (
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.25" strokeLinecap="round" strokeLinejoin="round">
|
||||
<line x1="5" y1="12" x2="19" y2="12" />
|
||||
<polyline points="13 6 19 12 13 18" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Load Balancing",
|
||||
desc: "Automated weight-and-balance modeling for optimal, safe aircraft load layout within minutes.",
|
||||
icon: (
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.25" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M12 3v18M5 8l7-5 7 5M5 8v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Predictive Maintenance",
|
||||
desc: "Continuous telemetry monitoring triggers preemptive alerts, drastically reducing aircraft downtime.",
|
||||
icon: (
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.25" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M22 12h-6l-4 8-4-16-4 8H2" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Real-Time Tracking",
|
||||
desc: "End-to-end sensor monitoring keeps shippers, airline, and EV operators updated on exact shipment state.",
|
||||
icon: (
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.25" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7Z" />
|
||||
<circle cx="12" cy="12" r="3" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
export default function WingsMileTruth() {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) return;
|
||||
|
||||
const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
||||
|
||||
let width = (canvas.width = canvas.offsetWidth);
|
||||
let height = (canvas.height = canvas.offsetHeight);
|
||||
const handleResize = () => {
|
||||
width = canvas.width = canvas.offsetWidth;
|
||||
height = canvas.height = canvas.offsetHeight;
|
||||
};
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
const nodes = [
|
||||
{ x: 0.12, y: 0.5 },
|
||||
{ x: 0.34, y: 0.25 },
|
||||
{ x: 0.56, y: 0.65 },
|
||||
{ x: 0.78, y: 0.3 },
|
||||
{ x: 0.92, y: 0.6 },
|
||||
];
|
||||
const particles = [
|
||||
{ from: 0, to: 1, t: 0, speed: 0.006 },
|
||||
{ from: 1, to: 2, t: 0.4, speed: 0.005 },
|
||||
{ from: 2, to: 3, t: 0.15, speed: 0.007 },
|
||||
{ from: 3, to: 4, t: 0.6, speed: 0.005 },
|
||||
];
|
||||
|
||||
let raf: number;
|
||||
const draw = () => {
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.setLineDash([6, 6]);
|
||||
ctx.strokeStyle = "rgba(200, 16, 46, 0.16)";
|
||||
ctx.beginPath();
|
||||
for (let i = 0; i < nodes.length - 1; i++) {
|
||||
ctx.moveTo(nodes[i].x * width, nodes[i].y * height);
|
||||
ctx.lineTo(nodes[i + 1].x * width, nodes[i + 1].y * height);
|
||||
}
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
|
||||
if (!reduced) {
|
||||
particles.forEach((p) => {
|
||||
p.t += p.speed;
|
||||
if (p.t >= 1) p.t = 0;
|
||||
const a = nodes[p.from];
|
||||
const b = nodes[p.to];
|
||||
const x = a.x * width + (b.x * width - a.x * width) * p.t;
|
||||
const y = a.y * height + (b.y * height - a.y * height) * p.t;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 3.5, 0, Math.PI * 2);
|
||||
ctx.fillStyle = "#c8102e";
|
||||
ctx.shadowColor = "#c8102e";
|
||||
ctx.shadowBlur = 10;
|
||||
ctx.fill();
|
||||
ctx.shadowBlur = 0;
|
||||
});
|
||||
}
|
||||
|
||||
nodes.forEach((n) => {
|
||||
const x = n.x * width;
|
||||
const y = n.y * height;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 7, 0, Math.PI * 2);
|
||||
ctx.fillStyle = "rgba(200, 16, 46, 0.1)";
|
||||
ctx.fill();
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 3, 0, Math.PI * 2);
|
||||
ctx.fillStyle = "rgba(255, 255, 255, 0.25)";
|
||||
ctx.fill();
|
||||
});
|
||||
|
||||
if (!reduced) raf = requestAnimationFrame(draw);
|
||||
};
|
||||
draw();
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleResize);
|
||||
if (raf) cancelAnimationFrame(raf);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<style
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
.wmt-section {
|
||||
position: relative;
|
||||
width: calc(100% - 40px);
|
||||
margin: 0 auto;
|
||||
border-radius: 28px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
background: #09090b;
|
||||
padding: clamp(64px, 8vw, 100px) clamp(24px, 5vw, 48px);
|
||||
}
|
||||
|
||||
.wmt-canvas {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
opacity: 0.12;
|
||||
}
|
||||
|
||||
.wmt-glow {
|
||||
position: absolute;
|
||||
width: 480px;
|
||||
height: 480px;
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
filter: blur(140px);
|
||||
z-index: 0;
|
||||
opacity: 0.06;
|
||||
}
|
||||
|
||||
.wmt-glow.tl { left: -8%; top: -12%; background: radial-gradient(circle, #c8102e 0%, transparent 70%); }
|
||||
.wmt-glow.br { right: -8%; bottom: -12%; background: radial-gradient(circle, #ff3b3b 0%, transparent 70%); }
|
||||
|
||||
.wmt-inner {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.wmt-header {
|
||||
margin: 0 auto 48px auto;
|
||||
max-width: 720px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wmt-eyebrow {
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 2.5px;
|
||||
text-transform: uppercase;
|
||||
color: #c8102e;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.wmt-title {
|
||||
font-size: clamp(28px, 3.4vw, 48px) !important;
|
||||
font-weight: 800 !important;
|
||||
letter-spacing: -0.03em !important;
|
||||
line-height: 1.15 !important;
|
||||
text-transform: none !important;
|
||||
color: #ffffff !important;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wmt-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 18px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.wmt-card {
|
||||
min-width: 0;
|
||||
position: relative;
|
||||
background: rgba(255, 255, 255, 0.035);
|
||||
border: 1px solid rgba(255, 255, 255, 0.07);
|
||||
border-radius: 18px;
|
||||
padding: 26px 22px;
|
||||
transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1), border-color 0.5s cubic-bezier(0.16, 1, 0.3, 1), background-color 0.5s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.5s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
.wmt-card:hover {
|
||||
transform: translateY(-6px);
|
||||
border-color: rgba(255, 255, 255, 0.16);
|
||||
background-color: rgba(255, 255, 255, 0.055);
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.wmt-card-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
background: rgba(200, 16, 46, 0.12);
|
||||
color: #ffffff;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.wmt-card-title {
|
||||
font-size: 15.5px !important;
|
||||
font-weight: 700 !important;
|
||||
line-height: 1.3 !important;
|
||||
text-transform: none !important;
|
||||
color: #ffffff !important;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.wmt-card-desc {
|
||||
font-size: 13px;
|
||||
line-height: 1.55;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wmt-callout {
|
||||
position: relative;
|
||||
border-radius: 20px;
|
||||
padding: 34px 32px;
|
||||
background: linear-gradient(135deg, rgba(200, 16, 46, 0.95) 0%, rgba(110, 8, 26, 0.98) 100%);
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
flex-wrap: wrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wmt-callout::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: -1.5px;
|
||||
border-radius: 20px;
|
||||
background: linear-gradient(90deg, #c8102e, #ff3366, #ff0033, #c8102e);
|
||||
background-size: 300% 100%;
|
||||
animation: wmt-sweep 6s linear infinite;
|
||||
z-index: -1;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
@keyframes wmt-sweep {
|
||||
0% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
100% { background-position: 0% 50%; }
|
||||
}
|
||||
|
||||
.wmt-callout-body { max-width: 640px; }
|
||||
|
||||
.wmt-callout-title {
|
||||
font-size: 20px !important;
|
||||
font-weight: 800 !important;
|
||||
line-height: 1.3 !important;
|
||||
text-transform: none !important;
|
||||
color: #ffffff !important;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.wmt-callout-desc {
|
||||
font-size: 14px;
|
||||
line-height: 1.55;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wmt-callout-badge {
|
||||
flex-shrink: 0;
|
||||
font-size: 11.5px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 1px;
|
||||
text-transform: uppercase;
|
||||
color: #ffffff;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
border-radius: 999px;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.wmt-section { width: calc(100% - 24px); border-radius: 22px; }
|
||||
.wmt-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.wmt-grid { grid-template-columns: 1fr; }
|
||||
.wmt-callout { flex-direction: column; align-items: flex-start; }
|
||||
}
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
|
||||
<section className="wmt-section" id="wings-miletruth">
|
||||
<canvas ref={canvasRef} className="wmt-canvas" aria-hidden="true" />
|
||||
<div className="wmt-glow tl" aria-hidden="true" />
|
||||
<div className="wmt-glow br" aria-hidden="true" />
|
||||
|
||||
<div className="wmt-inner">
|
||||
<ScrollReveal delay={0.05} duration={0.75} yOffset={25} className="wmt-header">
|
||||
<div className="wmt-eyebrow">/ MileTruth™ AI /</div>
|
||||
<h2 className="wmt-title">The intelligence layer behind every delivery</h2>
|
||||
</ScrollReveal>
|
||||
|
||||
<StaggerChildren stagger={0.08} duration={0.65} yOffset={25} className="wmt-grid">
|
||||
{CAPABILITIES.map((c) => (
|
||||
<div key={c.title} className="wmt-card">
|
||||
<div className="wmt-card-icon" aria-hidden="true">{c.icon}</div>
|
||||
<h3 className="wmt-card-title">{c.title}</h3>
|
||||
<p className="wmt-card-desc">{c.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</StaggerChildren>
|
||||
|
||||
<ScrollReveal delay={0.15} duration={0.8} yOffset={25}>
|
||||
<div className="wmt-callout">
|
||||
<div className="wmt-callout-body">
|
||||
<h3 className="wmt-callout-title">Digital Twin of the Logistics Network</h3>
|
||||
<p className="wmt-callout-desc">
|
||||
A live virtual model of every ground vehicle, terminal, and flight — simulating
|
||||
what-if scenarios before bottlenecks ever form.
|
||||
</p>
|
||||
</div>
|
||||
<span className="wmt-callout-badge">SaaS Ready</span>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user