Compare commits
18 Commits
v2.2.13-rc
...
v2.2.19
| Author | SHA1 | Date | |
|---|---|---|---|
| 57cc429b54 | |||
| 01cf4013df | |||
| caf3fe8c1e | |||
| 51eac9fb50 | |||
| 6426512192 | |||
| a63ee1b9f5 | |||
| 43667e7d68 | |||
| 0191fdb770 | |||
| afaa5e038c | |||
| e0d6ea0d6c | |||
| 34839ad5a5 | |||
| a8d6a45aad | |||
| 6de8ad8516 | |||
| 023fef5343 | |||
| 7181dafca2 | |||
| 8b6d2da821 | |||
| 17736860d6 | |||
| d67acdbcc1 |
@@ -1,5 +1,5 @@
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
# KLZ Cables - Production Environment Configuration
|
# E-TIB - Production Environment Configuration
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# This file contains runtime environment variables for the production deployment.
|
# This file contains runtime environment variables for the production deployment.
|
||||||
# It should be placed on the production server at: /home/deploy/sites/e-tib.com/.env
|
# It should be placed on the production server at: /home/deploy/sites/e-tib.com/.env
|
||||||
@@ -23,7 +23,7 @@ MAIL_HOST=smtp.eu.mailgun.org
|
|||||||
MAIL_PORT=587
|
MAIL_PORT=587
|
||||||
MAIL_USERNAME=
|
MAIL_USERNAME=
|
||||||
MAIL_PASSWORD=
|
MAIL_PASSWORD=
|
||||||
MAIL_FROM=KLZ Cables <noreply@e-tib.com>
|
MAIL_FROM=E-TIB GmbH <noreply@e-tib.com>
|
||||||
MAIL_RECIPIENTS=info@e-tib.com
|
MAIL_RECIPIENTS=info@e-tib.com
|
||||||
|
|
||||||
# Varnish Cache Size (optional)
|
# Varnish Cache Size (optional)
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ jobs:
|
|||||||
NEXT_PUBLIC_BASE_URL: ${{ needs.prepare.outputs.next_public_url }}
|
NEXT_PUBLIC_BASE_URL: ${{ needs.prepare.outputs.next_public_url }}
|
||||||
NEXT_PUBLIC_TARGET: ${{ needs.prepare.outputs.target }}
|
NEXT_PUBLIC_TARGET: ${{ needs.prepare.outputs.target }}
|
||||||
NEXT_PUBLIC_APP_VERSION: ${{ needs.prepare.outputs.image_tag }}
|
NEXT_PUBLIC_APP_VERSION: ${{ needs.prepare.outputs.image_tag }}
|
||||||
UMAMI_WEBSITE_ID: ${{ secrets.UMAMI_WEBSITE_ID || vars.UMAMI_WEBSITE_ID }}
|
UMAMI_WEBSITE_ID: ${{ secrets.UMAMI_WEBSITE_ID || vars.UMAMI_WEBSITE_ID || 'd773ea10-a3b3-4ccf-9024-987e14c4d669' }}
|
||||||
UMAMI_API_ENDPOINT: ${{ secrets.UMAMI_API_ENDPOINT || vars.UMAMI_API_ENDPOINT || 'https://analytics.infra.mintel.me' }}
|
UMAMI_API_ENDPOINT: ${{ secrets.UMAMI_API_ENDPOINT || vars.UMAMI_API_ENDPOINT || 'https://analytics.infra.mintel.me' }}
|
||||||
NPM_TOKEN: ${{ steps.auth.outputs.working_token }}
|
NPM_TOKEN: ${{ steps.auth.outputs.working_token }}
|
||||||
NPM_DOMAIN: ${{ steps.auth.outputs.working_domain }}
|
NPM_DOMAIN: ${{ steps.auth.outputs.working_domain }}
|
||||||
@@ -282,14 +282,18 @@ jobs:
|
|||||||
MAIL_RECIPIENTS: ${{ secrets.CONTACT_RECIPIENT || vars.CONTACT_RECIPIENT || 'info@e-tib.com' }}
|
MAIL_RECIPIENTS: ${{ secrets.CONTACT_RECIPIENT || vars.CONTACT_RECIPIENT || 'info@e-tib.com' }}
|
||||||
|
|
||||||
# Monitoring
|
# Monitoring
|
||||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN || vars.SENTRY_DSN }}
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN || vars.SENTRY_DSN || 'https://dcb81958-dbf2-4a3d-b422-875f4672c14b@glitchtip.infra.mintel.me/5' }}
|
||||||
|
|
||||||
# Gatekeeper
|
# Gatekeeper
|
||||||
GATEKEEPER_PASSWORD: ${{ secrets.GATEKEEPER_PASSWORD }}
|
GATEKEEPER_PASSWORD: ${{ secrets.GATEKEEPER_PASSWORD }}
|
||||||
|
|
||||||
# Analytics
|
# Analytics
|
||||||
UMAMI_WEBSITE_ID: ${{ secrets.UMAMI_WEBSITE_ID || vars.UMAMI_WEBSITE_ID }}
|
UMAMI_WEBSITE_ID: ${{ secrets.UMAMI_WEBSITE_ID || vars.UMAMI_WEBSITE_ID || 'd773ea10-a3b3-4ccf-9024-987e14c4d669' }}
|
||||||
UMAMI_API_ENDPOINT: ${{ secrets.UMAMI_API_ENDPOINT || vars.UMAMI_API_ENDPOINT || 'https://analytics.infra.mintel.me' }}
|
UMAMI_API_ENDPOINT: ${{ secrets.UMAMI_API_ENDPOINT || vars.UMAMI_API_ENDPOINT || 'https://analytics.infra.mintel.me' }}
|
||||||
|
|
||||||
|
# Notifications
|
||||||
|
GOTIFY_URL: ${{ secrets.GOTIFY_URL }}
|
||||||
|
GOTIFY_TOKEN: ${{ secrets.GOTIFY_TOKEN }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -350,6 +354,10 @@ jobs:
|
|||||||
echo "UMAMI_WEBSITE_ID=$UMAMI_WEBSITE_ID"
|
echo "UMAMI_WEBSITE_ID=$UMAMI_WEBSITE_ID"
|
||||||
echo "UMAMI_API_ENDPOINT=$UMAMI_API_ENDPOINT"
|
echo "UMAMI_API_ENDPOINT=$UMAMI_API_ENDPOINT"
|
||||||
echo ""
|
echo ""
|
||||||
|
echo "# Notifications"
|
||||||
|
echo "GOTIFY_URL=$GOTIFY_URL"
|
||||||
|
echo "GOTIFY_TOKEN=$GOTIFY_TOKEN"
|
||||||
|
echo ""
|
||||||
echo "TARGET=$TARGET"
|
echo "TARGET=$TARGET"
|
||||||
echo "SENTRY_ENVIRONMENT=$TARGET"
|
echo "SENTRY_ENVIRONMENT=$TARGET"
|
||||||
echo "PROJECT_NAME=$PROJECT_NAME"
|
echo "PROJECT_NAME=$PROJECT_NAME"
|
||||||
|
|||||||
@@ -186,8 +186,6 @@ export default async function Layout(props: {
|
|||||||
data-scroll-behavior="smooth"
|
data-scroll-behavior="smooth"
|
||||||
>
|
>
|
||||||
<head>
|
<head>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
|
||||||
<link rel="preconnect" href="https://img.infra.mintel.me" />
|
<link rel="preconnect" href="https://img.infra.mintel.me" />
|
||||||
<link rel="icon" href="/favicon.ico" sizes="any" />
|
<link rel="icon" href="/favicon.ico" sizes="any" />
|
||||||
<link rel="apple-touch-icon" href="/apple-icon.png" sizes="180x180" />
|
<link rel="apple-touch-icon" href="/apple-icon.png" sizes="180x180" />
|
||||||
|
|||||||
@@ -6,21 +6,22 @@ import { MDXRemote } from 'next-mdx-remote/rsc';
|
|||||||
|
|
||||||
export const dynamic = 'force-dynamic';
|
export const dynamic = 'force-dynamic';
|
||||||
|
|
||||||
// Import components used in MDX
|
import nextDynamic from 'next/dynamic';
|
||||||
import { HeroVideo as HomeHero } from '@/components/blocks/HeroVideo';
|
|
||||||
import { SubCompanyTiles as HomeSubCompanyTiles } from '@/components/blocks/SubCompanyTiles';
|
const HomeHero = nextDynamic(() => import('@/components/blocks/HeroVideo').then(mod => mod.HeroVideo), { ssr: true });
|
||||||
import { CompetenceBentoGrid as HomeCompetenceBentoGrid } from '@/components/blocks/CompetenceBentoGrid';
|
const HomeSubCompanyTiles = nextDynamic(() => import('@/components/blocks/SubCompanyTiles').then(mod => mod.SubCompanyTiles));
|
||||||
import { ReferencesSlider as HomeReferencesSlider } from '@/components/blocks/ReferencesSlider';
|
const HomeCompetenceBentoGrid = nextDynamic(() => import('@/components/blocks/CompetenceBentoGrid').then(mod => mod.CompetenceBentoGrid));
|
||||||
import { FaqBlock } from '@/components/blocks/FaqBlock';
|
const HomeReferencesSlider = nextDynamic(() => import('@/components/blocks/ReferencesSlider').then(mod => mod.ReferencesSlider));
|
||||||
import { CertificatesBlock } from '@/components/blocks/CertificatesBlock';
|
const FaqBlock = nextDynamic(() => import('@/components/blocks/FaqBlock').then(mod => mod.FaqBlock));
|
||||||
import { HeroSection } from '@/components/blocks/HeroSection';
|
const CertificatesBlock = nextDynamic(() => import('@/components/blocks/CertificatesBlock').then(mod => mod.CertificatesBlock));
|
||||||
|
const HeroSection = nextDynamic(() => import('@/components/blocks/HeroSection').then(mod => mod.HeroSection), { ssr: true });
|
||||||
import JsonLd from '@/components/JsonLd';
|
import JsonLd from '@/components/JsonLd';
|
||||||
|
|
||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Heading } from '@/components/ui/Heading';
|
import { Heading } from '@/components/ui/Heading';
|
||||||
import { AnimatedCounter } from '@/components/ui';
|
const AnimatedCounter = nextDynamic(() => import('@/components/ui').then(mod => mod.AnimatedCounter));
|
||||||
import { InteractiveGermanyMap } from '@/components/blocks/InteractiveGermanyMap';
|
const InteractiveGermanyMap = nextDynamic(() => import('@/components/blocks/InteractiveGermanyMap').then(mod => mod.InteractiveGermanyMap));
|
||||||
import { ScaleOfImpact } from '@/components/blocks/ScaleOfImpact';
|
const ScaleOfImpact = nextDynamic(() => import('@/components/blocks/ScaleOfImpact').then(mod => mod.ScaleOfImpact));
|
||||||
import { getAllReferences } from '@/lib/references';
|
import { getAllReferences } from '@/lib/references';
|
||||||
|
|
||||||
const mdxComponents = (references: any[]) => ({
|
const mdxComponents = (references: any[]) => ({
|
||||||
|
|||||||
@@ -122,7 +122,8 @@ export default async function ReferenzenOverview(props: { params: Promise<{ loca
|
|||||||
{references.map((ref) => (
|
{references.map((ref) => (
|
||||||
<div
|
<div
|
||||||
key={ref.slug}
|
key={ref.slug}
|
||||||
className="flex flex-col bg-white border border-neutral-100 rounded-3xl overflow-hidden shadow-sm block"
|
id={ref.slug}
|
||||||
|
className="flex flex-col bg-white border border-neutral-100 rounded-3xl overflow-hidden shadow-sm block scroll-mt-32"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col h-full relative">
|
<div className="flex flex-col h-full relative">
|
||||||
{/* Image Section */}
|
{/* Image Section */}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React from 'react';
|
||||||
import { cn } from '@/components/ui';
|
import { cn } from '@/components/ui';
|
||||||
|
|
||||||
interface RevealProps {
|
interface RevealProps {
|
||||||
@@ -10,40 +10,12 @@ interface RevealProps {
|
|||||||
delay?: number;
|
delay?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Reveal({ children, className, threshold = 0.1, delay = 0 }: RevealProps) {
|
export default function Reveal({ children, className }: RevealProps) {
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
// Reveal animation disabled due to flickering issues on mobile/hydration
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const observer = new IntersectionObserver(
|
|
||||||
([entry]) => {
|
|
||||||
if (entry.isIntersecting) {
|
|
||||||
setIsVisible(true);
|
|
||||||
observer.unobserve(entry.target);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ threshold }
|
|
||||||
);
|
|
||||||
|
|
||||||
const currentRef = ref.current;
|
|
||||||
if (currentRef) {
|
|
||||||
observer.observe(currentRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (currentRef) {
|
|
||||||
observer.unobserve(currentRef);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [threshold]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={cn(className)}>
|
||||||
ref={ref}
|
|
||||||
className={cn('reveal-on-scroll', isVisible && 'is-visible', className)}
|
|
||||||
style={{ transitionDelay: `${delay}ms` }}
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const containerVariants: Variants = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const itemVariants: Variants = {
|
const itemVariants: Variants = {
|
||||||
hidden: { opacity: 0, y: 40 },
|
hidden: { opacity: 0, y: 20 },
|
||||||
visible: { opacity: 1, y: 0, transition: { duration: 1.0, ease: [0.16, 1, 0.3, 1] } },
|
visible: { opacity: 1, y: 0, transition: { duration: 1.0, ease: [0.16, 1, 0.3, 1] } },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export function CertificatesBlock({ badge, title, description, certificates = de
|
|||||||
};
|
};
|
||||||
|
|
||||||
const itemVariants = {
|
const itemVariants = {
|
||||||
hidden: { opacity: 0, y: 40 },
|
hidden: { opacity: 0, y: 20 },
|
||||||
show: { opacity: 1, y: 0, transition: { duration: 1.0, ease: [0.16, 1, 0.3, 1] } },
|
show: { opacity: 1, y: 0, transition: { duration: 1.0, ease: [0.16, 1, 0.3, 1] } },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ export function CertificatesBlock({ badge, title, description, certificates = de
|
|||||||
variants={containerVariants}
|
variants={containerVariants}
|
||||||
initial="hidden"
|
initial="hidden"
|
||||||
whileInView="show"
|
whileInView="show"
|
||||||
viewport={{ once: true, amount: 0.1 }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
>
|
>
|
||||||
{certificates.map((cert, index) => {
|
{certificates.map((cert, index) => {
|
||||||
const isIso = cert.type === 'iso';
|
const isIso = cert.type === 'iso';
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ export function CompanyTimeline({
|
|||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={i}
|
key={i}
|
||||||
initial={{ opacity: 0, y: 40 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
transition={{ duration: 1.0, ease: [0.16, 1, 0.3, 1] }}
|
transition={{ duration: 1.0, ease: [0.16, 1, 0.3, 1] }}
|
||||||
|
|||||||
@@ -86,10 +86,6 @@ export function CompetenceBentoGrid(props: CompetenceBentoGridProps) {
|
|||||||
<h2 className="text-primary font-bold tracking-wider uppercase text-sm mb-3">{badge}</h2>
|
<h2 className="text-primary font-bold tracking-wider uppercase text-sm mb-3">{badge}</h2>
|
||||||
<h3 className="font-heading text-3xl md:text-5xl font-extrabold text-neutral-dark mb-4">{title}</h3>
|
<h3 className="font-heading text-3xl md:text-5xl font-extrabold text-neutral-dark mb-4">{title}</h3>
|
||||||
</div>
|
</div>
|
||||||
<Button href={ctaHref} variant="ghost" className="bg-primary/5 hover:bg-primary/10 mx-4 md:mx-0 whitespace-nowrap">
|
|
||||||
{ctaLabel}
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" className="w-5 h-5 ml-2 transform group-hover:translate-x-1 transition-transform" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-4 auto-rows-[220px] px-4 md:px-0">
|
<div className="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-4 auto-rows-[220px] px-4 md:px-0">
|
||||||
@@ -109,7 +105,7 @@ export function CompetenceBentoGrid(props: CompetenceBentoGridProps) {
|
|||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={idx}
|
key={idx}
|
||||||
initial={{ opacity: 0, y: 40 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
transition={{ delay: idx * 0.1, duration: 1.0, ease: [0.16, 1, 0.3, 1] }}
|
transition={{ delay: idx * 0.1, duration: 1.0, ease: [0.16, 1, 0.3, 1] }}
|
||||||
@@ -136,7 +132,7 @@ export function CompetenceBentoGrid(props: CompetenceBentoGridProps) {
|
|||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={idx}
|
key={idx}
|
||||||
initial={{ opacity: 0, y: 40, scale: 0.98 }}
|
initial={{ opacity: 0, y: 20, scale: 0.98 }}
|
||||||
whileInView={{ opacity: 1, y: 0, scale: 1 }}
|
whileInView={{ opacity: 1, y: 0, scale: 1 }}
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
transition={{ delay: idx * 0.1, duration: 1.0, ease: [0.16, 1, 0.3, 1] }}
|
transition={{ delay: idx * 0.1, duration: 1.0, ease: [0.16, 1, 0.3, 1] }}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export const ContactSection: React.FC<ContactSectionProps> = (props) => {
|
|||||||
variants={containerVariants}
|
variants={containerVariants}
|
||||||
initial="hidden"
|
initial="hidden"
|
||||||
whileInView="visible"
|
whileInView="visible"
|
||||||
viewport={{ once: true, amount: 0.1 }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
>
|
>
|
||||||
<motion.h2 variants={itemVariants} className="text-primary font-bold tracking-wider uppercase text-sm mb-3">Direktkontakt</motion.h2>
|
<motion.h2 variants={itemVariants} className="text-primary font-bold tracking-wider uppercase text-sm mb-3">Direktkontakt</motion.h2>
|
||||||
<motion.h3 variants={itemVariants} className="font-heading text-3xl md:text-4xl font-extrabold text-neutral-dark mb-6">Wir sind für Sie da.</motion.h3>
|
<motion.h3 variants={itemVariants} className="font-heading text-3xl md:text-4xl font-extrabold text-neutral-dark mb-6">Wir sind für Sie da.</motion.h3>
|
||||||
@@ -104,7 +104,7 @@ export const ContactSection: React.FC<ContactSectionProps> = (props) => {
|
|||||||
variants={formVariants}
|
variants={formVariants}
|
||||||
initial="hidden"
|
initial="hidden"
|
||||||
whileInView="visible"
|
whileInView="visible"
|
||||||
viewport={{ once: true, amount: 0.1 }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
>
|
>
|
||||||
<Suspense
|
<Suspense
|
||||||
fallback={
|
fallback={
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export function DeepDrillAnimation() {
|
|||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
viewport={{ once: true, margin: "-100px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
transition={{ duration: 0.8 }}
|
transition={{ duration: 0.8 }}
|
||||||
className="flex flex-col items-center"
|
className="flex flex-col items-center"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export function GrowthChart() {
|
|||||||
<motion.div
|
<motion.div
|
||||||
initial={{ width: 0 }}
|
initial={{ width: 0 }}
|
||||||
whileInView={{ width: `${kabelWidth}%` }}
|
whileInView={{ width: `${kabelWidth}%` }}
|
||||||
viewport={{ once: true, amount: 0.1 }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
transition={{ duration: 1.5, delay: 0.1 * index, ease: "easeOut" }}
|
transition={{ duration: 1.5, delay: 0.1 * index, ease: "easeOut" }}
|
||||||
className="absolute top-0 left-0 h-full bg-primary rounded-full"
|
className="absolute top-0 left-0 h-full bg-primary rounded-full"
|
||||||
/>
|
/>
|
||||||
@@ -61,7 +61,7 @@ export function GrowthChart() {
|
|||||||
<motion.div
|
<motion.div
|
||||||
initial={{ width: 0 }}
|
initial={{ width: 0 }}
|
||||||
whileInView={{ width: `${offenerWidth}%` }}
|
whileInView={{ width: `${offenerWidth}%` }}
|
||||||
viewport={{ once: true, amount: 0.1 }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
transition={{ duration: 1.5, delay: 0.15 + 0.1 * index, ease: "easeOut" }}
|
transition={{ duration: 1.5, delay: 0.15 + 0.1 * index, ease: "easeOut" }}
|
||||||
className="absolute top-0 left-0 h-full bg-neutral-300 rounded-full"
|
className="absolute top-0 left-0 h-full bg-neutral-300 rounded-full"
|
||||||
/>
|
/>
|
||||||
@@ -77,7 +77,7 @@ export function GrowthChart() {
|
|||||||
<motion.div
|
<motion.div
|
||||||
initial={{ width: 0 }}
|
initial={{ width: 0 }}
|
||||||
whileInView={{ width: `${hddWidth}%` }}
|
whileInView={{ width: `${hddWidth}%` }}
|
||||||
viewport={{ once: true, amount: 0.1 }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
transition={{ duration: 1.5, delay: 0.2 + 0.1 * index, ease: "easeOut" }}
|
transition={{ duration: 1.5, delay: 0.2 + 0.1 * index, ease: "easeOut" }}
|
||||||
className="absolute top-0 left-0 h-full bg-neutral-dark rounded-full"
|
className="absolute top-0 left-0 h-full bg-neutral-dark rounded-full"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { usePathname } from 'next/navigation';
|
import { usePathname } from 'next/navigation';
|
||||||
|
|
||||||
@@ -81,11 +80,9 @@ export function HeroVideo(props: HeroVideoProps) {
|
|||||||
<div className="absolute top-0 left-0 w-full h-48 bg-gradient-to-b from-black/70 to-transparent z-[3] pointer-events-none" />
|
<div className="absolute top-0 left-0 w-full h-48 bg-gradient-to-b from-black/70 to-transparent z-[3] pointer-events-none" />
|
||||||
|
|
||||||
<div className="container relative z-[4] text-center px-4">
|
<div className="container relative z-[4] text-center px-4">
|
||||||
<motion.div
|
<div
|
||||||
key={`hero-content-${pathname}`}
|
key={`hero-content-${pathname}`}
|
||||||
initial={{ opacity: 0, y: 40 }}
|
className="animate-in fade-in slide-in-from-bottom-10 duration-1000 ease-out fill-mode-both"
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ duration: 1.2, ease: [0.16, 1, 0.3, 1] }}
|
|
||||||
>
|
>
|
||||||
<h1
|
<h1
|
||||||
className="font-heading font-bold text-3xl sm:text-4xl md:text-6xl lg:text-8xl text-white mb-6 uppercase tracking-tight drop-shadow-lg"
|
className="font-heading font-bold text-3xl sm:text-4xl md:text-6xl lg:text-8xl text-white mb-6 uppercase tracking-tight drop-shadow-lg"
|
||||||
@@ -114,7 +111,7 @@ export function HeroVideo(props: HeroVideoProps) {
|
|||||||
{secondaryCtaLabel}
|
{secondaryCtaLabel}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const containerVariants = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const itemVariants = {
|
const itemVariants = {
|
||||||
hidden: { opacity: 0, y: 40 },
|
hidden: { opacity: 0, y: 20 },
|
||||||
visible: {
|
visible: {
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
y: 0,
|
y: 0,
|
||||||
@@ -75,7 +75,7 @@ export const JobListingBlock = (props: JobListingBlockProps) => {
|
|||||||
<motion.h3
|
<motion.h3
|
||||||
initial={{ opacity: 0, x: -20 }}
|
initial={{ opacity: 0, x: -20 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
viewport={{ once: true, amount: 0.1 }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
transition={{ duration: 0.8, ease: [0.16, 1, 0.3, 1] as const }}
|
transition={{ duration: 0.8, ease: [0.16, 1, 0.3, 1] as const }}
|
||||||
className="font-heading font-extrabold text-3xl md:text-4xl text-neutral-dark mb-8 md:mb-12 flex items-center gap-4"
|
className="font-heading font-extrabold text-3xl md:text-4xl text-neutral-dark mb-8 md:mb-12 flex items-center gap-4"
|
||||||
>
|
>
|
||||||
@@ -86,7 +86,7 @@ export const JobListingBlock = (props: JobListingBlockProps) => {
|
|||||||
variants={containerVariants}
|
variants={containerVariants}
|
||||||
initial="hidden"
|
initial="hidden"
|
||||||
whileInView="visible"
|
whileInView="visible"
|
||||||
viewport={{ once: true, amount: 0.1 }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"
|
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"
|
||||||
>
|
>
|
||||||
{fairs.map((messe, idx) => {
|
{fairs.map((messe, idx) => {
|
||||||
@@ -180,7 +180,7 @@ export const JobListingBlock = (props: JobListingBlockProps) => {
|
|||||||
<motion.h2
|
<motion.h2
|
||||||
initial={{ opacity: 0, x: -20 }}
|
initial={{ opacity: 0, x: -20 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
viewport={{ once: true, amount: 0.1 }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
transition={{ duration: 0.8, ease: [0.16, 1, 0.3, 1] as const }}
|
transition={{ duration: 0.8, ease: [0.16, 1, 0.3, 1] as const }}
|
||||||
className="font-heading font-extrabold text-3xl md:text-4xl text-neutral-dark mb-6 md:mb-8"
|
className="font-heading font-extrabold text-3xl md:text-4xl text-neutral-dark mb-6 md:mb-8"
|
||||||
>
|
>
|
||||||
@@ -192,7 +192,7 @@ export const JobListingBlock = (props: JobListingBlockProps) => {
|
|||||||
variants={containerVariants}
|
variants={containerVariants}
|
||||||
initial="hidden"
|
initial="hidden"
|
||||||
whileInView="visible"
|
whileInView="visible"
|
||||||
viewport={{ once: true, amount: 0.1 }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
className="grid gap-6"
|
className="grid gap-6"
|
||||||
>
|
>
|
||||||
{jobs.map((job: any) => (
|
{jobs.map((job: any) => (
|
||||||
@@ -221,7 +221,7 @@ export const JobListingBlock = (props: JobListingBlockProps) => {
|
|||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
viewport={{ once: true, amount: 0.1 }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
transition={{ duration: 0.8, ease: [0.16, 1, 0.3, 1] as const }}
|
transition={{ duration: 0.8, ease: [0.16, 1, 0.3, 1] as const }}
|
||||||
className="bg-neutral-50 border border-neutral-100 rounded-2xl p-12 text-center"
|
className="bg-neutral-50 border border-neutral-100 rounded-2xl p-12 text-center"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -125,14 +125,14 @@ export function ReferencesSlider(props: ReferencesSliderProps) {
|
|||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={ref.id}
|
key={ref.id}
|
||||||
initial={{ opacity: 0, x: 50 }}
|
initial={{ opacity: 0, x: 20 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
transition={{ delay: i * 0.1, duration: 1.0, ease: [0.16, 1, 0.3, 1] }}
|
transition={{ delay: i * 0.1, duration: 1.0, ease: [0.16, 1, 0.3, 1] }}
|
||||||
className="flex-shrink-0 w-[320px] md:w-[480px] snap-start group pointer-events-auto"
|
className="flex-shrink-0 w-[320px] md:w-[480px] snap-start group pointer-events-auto"
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={`/${locale}/referenzen/${ref.slug}`}
|
href={`/${locale}/referenzen#${ref.slug}`}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
if (dragDistanceRef.current > 5) {
|
if (dragDistanceRef.current > 5) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const containerVariants: Variants = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const itemVariants: Variants = {
|
const itemVariants: Variants = {
|
||||||
hidden: { opacity: 0, y: 40 },
|
hidden: { opacity: 0, y: 20 },
|
||||||
visible: { opacity: 1, y: 0, transition: { duration: 1.0, ease: [0.16, 1, 0.3, 1] } },
|
visible: { opacity: 1, y: 0, transition: { duration: 1.0, ease: [0.16, 1, 0.3, 1] } },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export function SubCompanyTiles(props: SubCompanyTilesProps) {
|
|||||||
variants={containerVariants}
|
variants={containerVariants}
|
||||||
initial="hidden"
|
initial="hidden"
|
||||||
whileInView="visible"
|
whileInView="visible"
|
||||||
viewport={{ once: true, amount: 0.1 }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
>
|
>
|
||||||
{companiesData.map((company: any, index: number) => {
|
{companiesData.map((company: any, index: number) => {
|
||||||
const isCurrent = company.title.toUpperCase() === 'E-TIB GMBH';
|
const isCurrent = company.title.toUpperCase() === 'E-TIB GMBH';
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export const SupportCTA: React.FC<SupportCTAProps> = (props) => {
|
|||||||
variants={containerVariants}
|
variants={containerVariants}
|
||||||
initial="hidden"
|
initial="hidden"
|
||||||
whileInView="visible"
|
whileInView="visible"
|
||||||
viewport={{ once: true, margin: "-100px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
className="mt-12 md:mt-24 p-6 md:p-12 bg-primary-dark rounded-3xl text-white shadow-2xl relative overflow-hidden group"
|
className="mt-12 md:mt-24 p-6 md:p-12 bg-primary-dark rounded-3xl text-white shadow-2xl relative overflow-hidden group"
|
||||||
>
|
>
|
||||||
<div className="absolute top-0 right-0 w-64 h-full bg-accent/5 -skew-x-12 translate-x-1/2 transition-transform duration-700 group-hover:translate-x-1/3" />
|
<div className="absolute top-0 right-0 w-64 h-full bg-accent/5 -skew-x-12 translate-x-1/2 transition-transform duration-700 group-hover:translate-x-1/3" />
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export function TeamGrid({ members }: TeamGridProps) {
|
|||||||
{members.map((member, i) => (
|
{members.map((member, i) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={member.id}
|
key={member.id}
|
||||||
initial={{ opacity: 0, y: 40 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
transition={{ delay: i * 0.1, duration: 1.0, ease: [0.16, 1, 0.3, 1] }}
|
transition={{ delay: i * 0.1, duration: 1.0, ease: [0.16, 1, 0.3, 1] }}
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ export function Header({ navLinks }: HeaderProps) {
|
|||||||
fill
|
fill
|
||||||
className="object-contain object-left group-hover:scale-105 transition-transform duration-500 origin-left"
|
className="object-contain object-left group-hover:scale-105 transition-transform duration-500 origin-left"
|
||||||
priority
|
priority
|
||||||
|
fetchPriority="high"
|
||||||
sizes="192px"
|
sizes="192px"
|
||||||
/>
|
/>
|
||||||
{/* Masked sweep overlay on hover */}
|
{/* Masked sweep overlay on hover */}
|
||||||
@@ -138,8 +139,54 @@ export function Header({ navLinks }: HeaderProps) {
|
|||||||
<div className="flex items-center gap-2 md:gap-4 lg:gap-6">
|
<div className="flex items-center gap-2 md:gap-4 lg:gap-6">
|
||||||
<div className={`hidden md:block h-5 w-px transition-colors duration-300 ${isSolidMode ? 'bg-neutral-200' : 'bg-white/20'}`} />
|
<div className={`hidden md:block h-5 w-px transition-colors duration-300 ${isSolidMode ? 'bg-neutral-200' : 'bg-white/20'}`} />
|
||||||
|
|
||||||
{/* Language Switcher visible on all devices */}
|
{/* Quick Actions (Mobile Only) */}
|
||||||
<div className="z-50 relative flex items-center">
|
<div className="md:hidden flex items-center gap-2">
|
||||||
|
<a
|
||||||
|
href="tel:+492572946760"
|
||||||
|
className={`relative flex items-center justify-center w-9 h-9 rounded-full transition-all duration-300 ${
|
||||||
|
isSolidMode
|
||||||
|
? 'bg-primary text-white shadow-md shadow-primary/20 hover:-translate-y-0.5'
|
||||||
|
: 'bg-white text-primary shadow-md hover:-translate-y-0.5'
|
||||||
|
}`}
|
||||||
|
aria-label="Anrufen"
|
||||||
|
>
|
||||||
|
<svg className="w-[16px] h-[16px]" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="mailto:info@e-tib.com"
|
||||||
|
className={`relative flex items-center justify-center w-9 h-9 rounded-full transition-all duration-300 ${
|
||||||
|
isSolidMode
|
||||||
|
? 'bg-neutral-100 text-neutral-600 hover:text-primary hover:bg-neutral-200'
|
||||||
|
: 'bg-white/10 text-white backdrop-blur-md border border-white/20 hover:bg-white/20'
|
||||||
|
}`}
|
||||||
|
aria-label="E-Mail"
|
||||||
|
>
|
||||||
|
<svg className="w-[16px] h-[16px]" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.2} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://maps.google.com/?q=E-TIB+GmbH,+Greven"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className={`relative flex items-center justify-center w-9 h-9 rounded-full transition-all duration-300 ${
|
||||||
|
isSolidMode
|
||||||
|
? 'bg-neutral-100 text-neutral-600 hover:text-primary hover:bg-neutral-200'
|
||||||
|
: 'bg-white/10 text-white backdrop-blur-md border border-white/20 hover:bg-white/20'
|
||||||
|
}`}
|
||||||
|
aria-label="Route"
|
||||||
|
>
|
||||||
|
<svg className="w-[16px] h-[16px]" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Language Switcher visible on desktop only */}
|
||||||
|
<div className="z-50 relative hidden md:flex items-center">
|
||||||
<LanguageSwitcher isSolidMode={isSolidMode} />
|
<LanguageSwitcher isSolidMode={isSolidMode} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -25,11 +25,14 @@ export function MobileBottomNav({ navLinks, currentLocale }: MobileBottomNavProp
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (isFlyoutOpen) {
|
if (isFlyoutOpen) {
|
||||||
document.body.style.overflow = 'hidden';
|
document.body.style.overflow = 'hidden';
|
||||||
|
document.documentElement.style.overflow = 'hidden';
|
||||||
} else {
|
} else {
|
||||||
document.body.style.overflow = '';
|
document.body.style.overflow = '';
|
||||||
|
document.documentElement.style.overflow = '';
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
document.body.style.overflow = '';
|
document.body.style.overflow = '';
|
||||||
|
document.documentElement.style.overflow = '';
|
||||||
};
|
};
|
||||||
}, [isFlyoutOpen]);
|
}, [isFlyoutOpen]);
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ featuredImage: "/assets/photos/DJI_0037.JPG"
|
|||||||
|
|
||||||
- 500 m Kabelgraben ausheben und verfüllen
|
- 500 m Kabelgraben ausheben und verfüllen
|
||||||
- 4.500 m Einpflügen von 3 x PE-Schutzrohr d 160
|
- 4.500 m Einpflügen von 3 x PE-Schutzrohr d 160
|
||||||
- 3.200 m Horizontalspülbohrung d 160
|
- 12.000 m Horizontalspülbohrung d 160
|
||||||
- 8.500 m Verlegung HS-Kabel 1.000 mm² 64/110 kV
|
- 8.500 m Verlegung HS-Kabel 1.000 mm² 64/110 kV
|
||||||
- 11 Satz Verbindungsmuffen 1.000 mm² 64/110 kV
|
- 11 Satz Verbindungsmuffen 1.000 mm² 64/110 kV
|
||||||
- 2 Satz Freiluftendverschlüsse 1.000 mm² 64/110 kV
|
- 2 Satz Freiluftendverschlüsse 1.000 mm² 64/110 kV
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ layout: "fullBleed"
|
|||||||
{
|
{
|
||||||
id: "martin-polan",
|
id: "martin-polan",
|
||||||
name: "Martin Polan",
|
name: "Martin Polan",
|
||||||
position: "Bauleiter",
|
position: "Bauleitung",
|
||||||
email: "m.polan@e-tib.com",
|
email: "m.polan@e-tib.com",
|
||||||
phone: "+49 171 3868167",
|
phone: "+49 171 3868167",
|
||||||
image: "/assets/photos/team/martin.jpg"
|
image: "/assets/photos/team/martin.jpg"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ featuredImage: "/assets/photos/DJI_0037.JPG"
|
|||||||
|
|
||||||
- Excavation and backfilling of 500 m cable trench
|
- Excavation and backfilling of 500 m cable trench
|
||||||
- 4,500 m plowing of 3 x PE protective pipe d 160
|
- 4,500 m plowing of 3 x PE protective pipe d 160
|
||||||
- 3,200 m HDD directional drilling d 160
|
- 12,000 m HDD directional drilling d 160
|
||||||
- 8,500 m laying of HV cable 1,000 mm² 64/110 kV
|
- 8,500 m laying of HV cable 1,000 mm² 64/110 kV
|
||||||
- 11 sets of connection joints 1,000 mm² 64/110 kV
|
- 11 sets of connection joints 1,000 mm² 64/110 kV
|
||||||
- 2 sets of outdoor terminations 1,000 mm² 64/110 kV
|
- 2 sets of outdoor terminations 1,000 mm² 64/110 kV
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ layout: "fullBleed"
|
|||||||
{
|
{
|
||||||
id: "martin-polan",
|
id: "martin-polan",
|
||||||
name: "Martin Polan",
|
name: "Martin Polan",
|
||||||
position: "Site Manager",
|
position: "Site Management",
|
||||||
email: "m.polan@e-tib.com",
|
email: "m.polan@e-tib.com",
|
||||||
phone: "+49 171 3868167",
|
phone: "+49 171 3868167",
|
||||||
image: "/assets/photos/team/martin.jpg"
|
image: "/assets/photos/team/martin.jpg"
|
||||||
|
|||||||
@@ -189,62 +189,6 @@ export const minorLocations: Location[] = [
|
|||||||
y: 83.33,
|
y: 83.33,
|
||||||
description: 'fiber',
|
description: 'fiber',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'hdd-29436-meter-29436',
|
|
||||||
name: 'HDD 29436 Meter',
|
|
||||||
type: 'minor_node',
|
|
||||||
x: 46.89,
|
|
||||||
y: 41.34,
|
|
||||||
description: 'power',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'hdd-28680-meter-28680',
|
|
||||||
name: 'HDD 28680 Meter',
|
|
||||||
type: 'minor_node',
|
|
||||||
x: 44.84,
|
|
||||||
y: 43.61,
|
|
||||||
description: 'power',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'hdd-44655-meter-44655',
|
|
||||||
name: 'HDD 44655 Meter',
|
|
||||||
type: 'minor_node',
|
|
||||||
x: 49.36,
|
|
||||||
y: 48.57,
|
|
||||||
description: 'power',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'kabelverlegung-76727-meter-76727',
|
|
||||||
name: 'Kabelverlegung 76727 Meter',
|
|
||||||
type: 'minor_node',
|
|
||||||
x: 45.57,
|
|
||||||
y: 49.95,
|
|
||||||
description: 'power',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'offener-tiefbau-21288-meter-21288',
|
|
||||||
name: 'Offener Tiefbau 21288 Meter',
|
|
||||||
type: 'minor_node',
|
|
||||||
x: 40.15,
|
|
||||||
y: 49.41,
|
|
||||||
description: 'power',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'offener-tiefbau-30773-meter-30773',
|
|
||||||
name: 'Offener Tiefbau 30773 Meter',
|
|
||||||
type: 'minor_node',
|
|
||||||
x: 41.74,
|
|
||||||
y: 43.78,
|
|
||||||
description: 'power',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'offener-tiefbau-34815-meter-34815',
|
|
||||||
name: 'Offener Tiefbau 34815 Meter',
|
|
||||||
type: 'minor_node',
|
|
||||||
x: 43.91,
|
|
||||||
y: 42.14,
|
|
||||||
description: 'power',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'pv-anlage-01909-grosshartau-01909',
|
id: 'pv-anlage-01909-grosshartau-01909',
|
||||||
name: 'PV-Anlage, 01909 Großhartau',
|
name: 'PV-Anlage, 01909 Großhartau',
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export const standorteData: StandortData[] = [
|
|||||||
{
|
{
|
||||||
id: 'guben',
|
id: 'guben',
|
||||||
name: 'E-TIB GmbH',
|
name: 'E-TIB GmbH',
|
||||||
shortName: 'Guben (Hauptsitz)',
|
shortName: 'Standort Brandenburg (Hauptsitz)',
|
||||||
type: 'hq',
|
type: 'hq',
|
||||||
description: {
|
description: {
|
||||||
de: 'Unser Hauptsitz in Guben bildet das strategische und operative Zentrum der E-TIB Gruppe. Von hier aus steuern wir bundesweit Großprojekte im Kabelleitungsnetzbau und koordinieren unseren hochmodernen Maschinenpark.',
|
de: 'Unser Hauptsitz in Guben bildet das strategische und operative Zentrum der E-TIB Gruppe. Von hier aus steuern wir bundesweit Großprojekte im Kabelleitungsnetzbau und koordinieren unseren hochmodernen Maschinenpark.',
|
||||||
@@ -67,7 +67,7 @@ export const standorteData: StandortData[] = [
|
|||||||
'Central project management'
|
'Central project management'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
image: '/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-100.jpg',
|
image: '/assets/photos/DSC02114.jpg',
|
||||||
gallery: [
|
gallery: [
|
||||||
'/assets/photos/DSC02114.jpg',
|
'/assets/photos/DSC02114.jpg',
|
||||||
'/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-45.jpg'
|
'/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-45.jpg'
|
||||||
@@ -117,7 +117,7 @@ export const standorteData: StandortData[] = [
|
|||||||
{
|
{
|
||||||
id: 'buelstedt',
|
id: 'buelstedt',
|
||||||
name: 'E-TIB Ingenieurgesellschaft mbH',
|
name: 'E-TIB Ingenieurgesellschaft mbH',
|
||||||
shortName: 'Bülstedt (Ingenieurgesellschaft)',
|
shortName: 'Standort Niedersachsen',
|
||||||
type: 'branch',
|
type: 'branch',
|
||||||
description: {
|
description: {
|
||||||
de: 'Unsere Ingenieurgesellschaft in Bülstedt ist spezialisiert auf die hochpräzise Planung, Vermessung und Projektierung von Energie- und Telekommunikationsnetzen. Hier verschmelzen technische Expertise und modernes Datenmanagement.',
|
de: 'Unsere Ingenieurgesellschaft in Bülstedt ist spezialisiert auf die hochpräzise Planung, Vermessung und Projektierung von Energie- und Telekommunikationsnetzen. Hier verschmelzen technische Expertise und modernes Datenmanagement.',
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ const nextConfig = {
|
|||||||
pagesBufferLength: 2,
|
pagesBufferLength: 2,
|
||||||
},
|
},
|
||||||
experimental: {
|
experimental: {
|
||||||
|
staleTimes: {
|
||||||
|
dynamic: 0,
|
||||||
|
static: 30,
|
||||||
|
},
|
||||||
optimizePackageImports: [
|
optimizePackageImports: [
|
||||||
'lucide-react',
|
'lucide-react',
|
||||||
'framer-motion',
|
'framer-motion',
|
||||||
|
|||||||
@@ -138,7 +138,7 @@
|
|||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"preinstall": "npx only-allow pnpm"
|
"preinstall": "npx only-allow pnpm"
|
||||||
},
|
},
|
||||||
"version": "2.2.13-rc.59",
|
"version": "2.2.19",
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
"@parcel/watcher",
|
"@parcel/watcher",
|
||||||
|
|||||||
Reference in New Issue
Block a user