Compare commits

...

4 Commits

Author SHA1 Message Date
afe3565155 fix(map): optimize hit areas for desktop mouse clusters and add touch events for mobile responsiveness
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 27s
Build & Deploy / 🧪 QA (push) Successful in 1m21s
Build & Deploy / 🏗️ Build (push) Successful in 2m31s
Build & Deploy / 🚀 Deploy (push) Successful in 29s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 53s
Build & Deploy / 🔔 Notify (push) Successful in 4s
2026-06-19 00:02:13 +02:00
e677089ff9 fix(map): use useRef for hover timeout to prevent flyout flicker and immediate disappearance
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 32s
Build & Deploy / 🧪 QA (push) Successful in 1m31s
Build & Deploy / 🏗️ Build (push) Successful in 2m50s
Build & Deploy / 🚀 Deploy (push) Successful in 35s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 59s
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-06-18 23:41:09 +02:00
b7d9a4b0d0 fix(tests): update task-12-links test to verify minorLocations since defaultLocations was emptied
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 31s
Build & Deploy / 🧪 QA (push) Successful in 1m29s
Build & Deploy / 🏗️ Build (push) Successful in 2m46s
Build & Deploy / 🚀 Deploy (push) Successful in 33s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m4s
Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-06-18 23:26:07 +02:00
6c8614f147 feat(map): completely rebuild map data from raw 2016-2026 txt files, geocode missing locations, format to spec, and downgrade all projects to minor nodes
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 30s
Build & Deploy / 🧪 QA (push) Failing after 1m20s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-06-18 23:18:46 +02:00
3 changed files with 975 additions and 1013 deletions

View File

@@ -1,6 +1,6 @@
'use client'; 'use client';
import React, { useState } from 'react'; import React, { useState, useRef } from 'react';
import { motion, AnimatePresence } from 'framer-motion'; import { motion, AnimatePresence } from 'framer-motion';
import { MapPin, Factory, Zap, CheckCircle2, ArrowUpRight } from 'lucide-react'; import { MapPin, Factory, Zap, CheckCircle2, ArrowUpRight } from 'lucide-react';
import Image from 'next/image'; import Image from 'next/image';
@@ -38,10 +38,13 @@ export function InteractiveGermanyMap({
hideStandorte = false hideStandorte = false
}: InteractiveGermanyMapProps) { }: InteractiveGermanyMapProps) {
const [activeLocation, setActiveLocation] = useState<Location | null>(null); const [activeLocation, setActiveLocation] = useState<Location | null>(null);
const [hoverTimeout, setHoverTimeout] = useState<NodeJS.Timeout | null>(null); const hoverTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const handleMouseEnter = (loc: Location) => { const handleMouseEnter = (loc: Location) => {
if (hoverTimeout) clearTimeout(hoverTimeout); if (hoverTimeoutRef.current) {
clearTimeout(hoverTimeoutRef.current);
hoverTimeoutRef.current = null;
}
setActiveLocation(loc); setActiveLocation(loc);
}; };
@@ -49,7 +52,7 @@ export function InteractiveGermanyMap({
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
setActiveLocation(null); setActiveLocation(null);
}, 200); }, 200);
setHoverTimeout(timeout); hoverTimeoutRef.current = timeout;
}; };
const router = useRouter(); const router = useRouter();
@@ -162,10 +165,12 @@ export function InteractiveGermanyMap({
</div> </div>
{/* Minor Location Markers (The 100+ generic projects) */} {/* Minor Location Markers (The 100+ generic projects) */}
{finalLocations.filter(l => l.type === 'minor_node').map((loc, idx) => ( {finalLocations.filter(l => l.type === 'minor_node').map((loc, idx) => {
const isActive = activeLocation === loc;
return (
<div <div
key={`minor-${idx}`} key={`minor-${idx}`}
className="absolute z-10 group/minor cursor-pointer w-10 h-10 flex items-center justify-center" className={`absolute group/minor cursor-pointer w-8 h-8 md:w-5 md:h-5 flex items-center justify-center ${isActive ? 'z-[60]' : 'z-10 hover:z-30'}`}
style={{ style={{
left: `${loc.x}%`, left: `${loc.x}%`,
top: `${loc.y}%`, top: `${loc.y}%`,
@@ -173,12 +178,13 @@ export function InteractiveGermanyMap({
}} }}
onMouseEnter={() => handleMouseEnter(loc)} onMouseEnter={() => handleMouseEnter(loc)}
onMouseLeave={handleMouseLeave} onMouseLeave={handleMouseLeave}
onTouchStart={() => handleMouseEnter(loc)}
onClick={() => handleMouseEnter(loc)} onClick={() => handleMouseEnter(loc)}
> >
<div className="w-1.5 h-1.5 bg-primary/80 rounded-full group-hover/minor:bg-white group-hover/minor:scale-150 transition-all duration-300" /> <div className={`w-1.5 h-1.5 rounded-full transition-all duration-300 ${isActive ? 'bg-white scale-150 shadow-[0_0_10px_rgba(130,237,32,1)]' : 'bg-primary/80 group-hover/minor:bg-white group-hover/minor:scale-150'}`} />
<div className="absolute inset-0 m-auto w-2 h-2 bg-primary rounded-full opacity-0 group-hover/minor:animate-ping" /> <div className="absolute inset-0 m-auto w-2 h-2 bg-primary rounded-full opacity-0 group-hover/minor:animate-ping" />
</div> </div>
))} )})}
{/* Major Location Markers (HQ, Branch, Project) */} {/* Major Location Markers (HQ, Branch, Project) */}
{finalLocations.filter(l => l.type !== 'minor_node').map((loc, idx) => { {finalLocations.filter(l => l.type !== 'minor_node').map((loc, idx) => {
@@ -189,10 +195,11 @@ export function InteractiveGermanyMap({
return ( return (
<div <div
key={loc.id} key={loc.id}
className={`absolute transform -translate-x-1/2 -translate-y-1/2 group/pin cursor-pointer w-16 h-16 flex items-center justify-center ${isActive ? 'z-[60]' : 'z-20'}`} className={`absolute transform -translate-x-1/2 -translate-y-1/2 group/pin cursor-pointer w-16 h-16 flex items-center justify-center ${isActive ? 'z-[60]' : 'z-20 hover:z-40'}`}
style={{ left: `${loc.x}%`, top: `${loc.y}%` }} style={{ left: `${loc.x}%`, top: `${loc.y}%` }}
onMouseEnter={() => handleMouseEnter(loc)} onMouseEnter={() => handleMouseEnter(loc)}
onMouseLeave={handleMouseLeave} onMouseLeave={handleMouseLeave}
onTouchStart={() => handleMouseEnter(loc)}
onClick={() => handleMouseEnter(loc)} onClick={() => handleMouseEnter(loc)}
> >
{/* Ping Animation for HQ / Branch */} {/* Ping Animation for HQ / Branch */}

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
import { describe, it, expect } from 'vitest'; import { describe, it, expect } from 'vitest';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import { defaultLocations } from '../lib/map-data'; import { defaultLocations, minorLocations } from '../lib/map-data';
describe('Task 12 TDD - Bohrtechnik and Reference Links', () => { describe('Task 12 TDD - Bohrtechnik and Reference Links', () => {
const deHomePath = path.join(process.cwd(), 'content', 'de', 'home.mdx'); const deHomePath = path.join(process.cwd(), 'content', 'de', 'home.mdx');
@@ -27,10 +27,11 @@ describe('Task 12 TDD - Bohrtechnik and Reference Links', () => {
}); });
it('should verify that all reference projects in map-data have no href links', () => { it('should verify that all reference projects in map-data have no href links', () => {
// Check that all defaultLocations of type 'project' have href undefined or removed // Check that all minorLocations of type 'minor_node' have href undefined
const projects = defaultLocations.filter(loc => loc.type === 'project'); // since all projects were downgraded to minor nodes without links.
const projects = minorLocations.filter(loc => loc.type === 'minor_node');
expect(projects.length).toBeGreaterThan(0); expect(projects.length).toBeGreaterThan(0);
projects.forEach(project => { projects.forEach(project => {
expect(project.href).toBeUndefined(); expect(project.href).toBeUndefined();
}); });