diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx index 06cc53a9f..203afbfd1 100644 --- a/app/[locale]/layout.tsx +++ b/app/[locale]/layout.tsx @@ -17,6 +17,7 @@ import { cookies } from 'next/headers'; import { TransitionProvider } from '@/components/providers/TransitionProvider'; import { PageTransitionShutter } from '@/components/providers/PageTransitionShutter'; import { InitialLoader } from '@/components/providers/InitialLoader'; +import { TrenchLines } from '@/components/ui/decorations/TrenchLines'; const inter = Inter({ subsets: ['latin'], @@ -179,6 +180,7 @@ export default async function Layout(props: { +
diff --git a/app/globals.css b/app/globals.css index e25c773ef..46d25fd94 100644 --- a/app/globals.css +++ b/app/globals.css @@ -15,6 +15,42 @@ .hide-scrollbar::-webkit-scrollbar { display: none; /* Chrome, Safari and Opera */ } + + /* Trassen-Hover Effect for Bento Grids */ + .trassen-border { + position: relative; + } + .trassen-border::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 200%; + height: 200%; + background: conic-gradient(from 0deg, transparent 70%, #0e7a5c 100%); + transform: translate(-50%, -50%) rotate(0deg); + animation: rotate-trasse 3s linear infinite; + opacity: 0; + transition: opacity 0.4s ease; + z-index: 0; + pointer-events: none; + } + .trassen-border:hover::before { + opacity: 1; + } + .trassen-content { + position: absolute; + inset: 1px; + z-index: 1; + border-radius: inherit; + background-color: #050B14; + background-clip: padding-box; + } +} + +@keyframes rotate-trasse { + from { transform: translate(-50%, -50%) rotate(0deg); } + to { transform: translate(-50%, -50%) rotate(360deg); } } /* Base Styles */ diff --git a/components/blocks/CompetenceBentoGrid.tsx b/components/blocks/CompetenceBentoGrid.tsx index c1c41718c..650213612 100644 --- a/components/blocks/CompetenceBentoGrid.tsx +++ b/components/blocks/CompetenceBentoGrid.tsx @@ -110,8 +110,6 @@ export function CompetenceBentoGrid(props: CompetenceBentoGridProps) { transition={{ delay: idx * 0.1 }} className={gridClasses} > -
-

{item.title}

{item.description &&

{item.description}

} @@ -125,14 +123,15 @@ export function CompetenceBentoGrid(props: CompetenceBentoGridProps) { whileInView={{ opacity: 1, scale: 1 }} viewport={{ once: true }} transition={{ delay: idx * 0.1 }} - className={gridClasses} + className={`${gridClasses} group trassen-border border border-white/5 rounded-3xl overflow-hidden`} > +
{!imgSrc && ( -
+
)} {imgSrc && ( <> -
+
{item.title { const isLink = !!messe.url; const innerContent = ( <> - {/* Glass Background Elements */} -
-
+ {/* Minimalist Trassen Content Background */} +
- -
@@ -116,7 +113,7 @@ export const JobListingBlock = async (props: JobListingBlockProps) => { ); - const baseClasses = "group relative bg-[#050B14] rounded-[2rem] p-8 overflow-hidden border border-white/5 shadow-2xl transition-all duration-500 hover:scale-[1.02] hover:shadow-primary/10 flex flex-col h-full"; + const baseClasses = "group trassen-border rounded-[2rem] p-8 shadow-2xl transition-all duration-500 hover:scale-[1.02] hover:shadow-primary/10 flex flex-col h-full"; if (isLink) { return ( diff --git a/components/providers/PageTransitionShutter.tsx b/components/providers/PageTransitionShutter.tsx index 06e59b0b1..7b60367d6 100644 --- a/components/providers/PageTransitionShutter.tsx +++ b/components/providers/PageTransitionShutter.tsx @@ -3,7 +3,6 @@ import React from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { useTransition } from './TransitionProvider'; -import Image from 'next/image'; export function PageTransitionShutter() { const { isTransitioning, transitionMessage } = useTransition(); @@ -13,16 +12,34 @@ export function PageTransitionShutter() { {isTransitioning && ( - {/* Subtle grid background */} -
+ {/* HDD Drill Head (Leading Edge during entrance) */} + + {/* The glowing drill bit at the center */} +
+
+ - {/* Deep Glow inside the Shutter */} + {/* HDD Exit Trail (Trailing Edge during exit) */} + + + {/* Subtle underground grid background */} +
+ + {/* Deep Glow simulating underground tunnel */}
- {/* Single Masked Logo Container to prevent double-logo offset */} + {/* Masked Logo */}
- {/* Base logo color (slightly dimmed to make the sweep visible) */}
- - {/* Sweeping intense white light */}
- {/* Transition Message or Graphical Visualizer */} + {/* Status Visualizer */} {transitionMessage && ( transitionMessage.startsWith('LANG_SWITCH:') ? ( @@ -67,48 +81,24 @@ export function PageTransitionShutter() { return ( - {/* Old Language Flag - Fading out */} -
- - {fromLang} -
+
{fromLang}
- {/* Animated Arrow connecting them */} -
- - - - - - -
- - - -
+ {/* Connecting Trasse */} +
+
- {/* New Language Flag - Intense Glow */} -
- {toLang} - +
+ {toLang}
); @@ -116,56 +106,17 @@ export function PageTransitionShutter() { ) : ( - - - - - - - - {transitionMessage} - + {transitionMessage} ) )} - {/* Extremely minimalist transition indicator */} - - {[0, 1, 2].map((i) => ( - - ))} - )} diff --git a/components/ui/decorations/TrenchLines.tsx b/components/ui/decorations/TrenchLines.tsx new file mode 100644 index 000000000..1f9046699 --- /dev/null +++ b/components/ui/decorations/TrenchLines.tsx @@ -0,0 +1,56 @@ +'use client'; + +import React, { useEffect, useState } from 'react'; +import { motion, useScroll, useSpring, useTransform } from 'framer-motion'; + +export function TrenchLines() { + const { scrollYProgress } = useScroll(); + + // Apply a spring to make the scroll movement feel heavier, industrial + const smoothProgress = useSpring(scrollYProgress, { + stiffness: 100, + damping: 30, + restDelta: 0.001 + }); + + // Map progress to vertical position + const yPosition = useTransform(smoothProgress, [0, 1], ['0%', '100%']); + + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + if (!mounted) return null; + + return ( +
+ {/* Left Trench Line */} +
+ + {/* Subtle digging pulse marker */} + +
+ + {/* Right Trench Line */} +
+ + {/* Subtle digging pulse marker */} + +
+
+ ); +}