feat: replace literal decorations with AbstractBore and AbstractTrench
Former-commit-id: 4f7c5fcc7203aa4a36aabd8ffc13cf9f28a0f77a
This commit is contained in:
71
components/ui/decorations/AbstractBore.tsx
Normal file
71
components/ui/decorations/AbstractBore.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
'use client';
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
interface AbstractBoreProps {
|
||||
className?: string;
|
||||
invert?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* AbstractBore
|
||||
*
|
||||
* Visualizes Horizontal Directional Drilling (HDD).
|
||||
* A smooth, parabolic underground arc. A beam of energy (the drill/cable)
|
||||
* travels along this path, fading in gently at the start and fading out at the end.
|
||||
* Purely abstract, no literal drill bits or circles.
|
||||
*/
|
||||
export function AbstractBore({ className = '', invert = false }: AbstractBoreProps) {
|
||||
const color = invert ? 'rgba(10, 61, 40, 0.6)' : 'rgba(14, 122, 92, 0.6)';
|
||||
const glowColor = invert ? 'rgba(10, 61, 40, 1)' : 'rgba(20, 184, 138, 1)';
|
||||
|
||||
// Parabolic path: Starts left, dips deep in the middle, comes up right
|
||||
const pathD = "M -100 50 C 200 50 300 250 500 250 C 700 250 800 50 1100 50";
|
||||
// The length of this cubic bezier is approx 1260
|
||||
const pathLength = 1260;
|
||||
// The length of the moving beam
|
||||
const beamLength = 200;
|
||||
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 1000 300"
|
||||
preserveAspectRatio="none"
|
||||
className={`absolute pointer-events-none select-none w-full ${className}`}
|
||||
aria-hidden="true"
|
||||
>
|
||||
{/* Subtle track background */}
|
||||
<path
|
||||
d={pathD}
|
||||
stroke={color}
|
||||
strokeWidth="1"
|
||||
fill="none"
|
||||
opacity={0.15}
|
||||
/>
|
||||
|
||||
{/* Moving Energy Beam */}
|
||||
<motion.path
|
||||
d={pathD}
|
||||
stroke={glowColor}
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
// Dasharray: beam length, then gap for the rest of the path
|
||||
strokeDasharray={`${beamLength} ${pathLength}`}
|
||||
animate={{
|
||||
// Move from right off-screen to left off-screen (or vice versa)
|
||||
// Starting at pathLength pushes the dash off the start of the curve.
|
||||
// Ending at -beamLength pushes it completely off the end.
|
||||
strokeDashoffset: [pathLength, -beamLength],
|
||||
// Fade in during the first 20%, stay solid, fade out during last 20%
|
||||
opacity: [0, 1, 1, 0]
|
||||
}}
|
||||
transition={{
|
||||
duration: 6,
|
||||
ease: "linear",
|
||||
repeat: Infinity,
|
||||
times: [0, 0.15, 0.85, 1] // Syncs with the offset to fade exactly at edges
|
||||
}}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user