Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ab4f4af555 | |||
| b6bd2065bb | |||
| 8d69ac2de2 | |||
| a9f16b49cc | |||
| 21cf0725ab | |||
| 2c162f5314 | |||
| be3b2e6a7b | |||
| f2e59fa52f | |||
| 16d494689f | |||
| d24b8a8694 | |||
| 8d42946711 | |||
| b15217b9be | |||
| b138025380 | |||
| 18d2ace03b | |||
| 89ed1faa6b | |||
| 7307e812a4 | |||
| 20d6194a7e | |||
| 86e2fd7097 | |||
| bf8073f5bf | |||
| e8adb87b02 | |||
| 067e34c19b | |||
| e6017e7436 | |||
| 1955bfcd1b |
@@ -1,9 +0,0 @@
|
|||||||
<RULE[zero_trust_no_proof]>
|
|
||||||
# 🚫 ZERO TRUST & BEWEISPFLICHT
|
|
||||||
|
|
||||||
Dein Wort hat absolut keinen Wert, wenn du es nicht mit einem harten Test beweisen kannst.
|
|
||||||
|
|
||||||
- **Keine Behauptungen:** Wenn du sagst, dass etwas funktioniert, ist das wertlos. Code, der nicht getestet ist, gilt als defekt.
|
|
||||||
- **Beweispflicht:** Jede Code-Änderung, jeder Fix und jede Logik-Anpassung MUSS durch einen begleitenden, erfolgreichen automatisierten Test bewiesen werden.
|
|
||||||
- **TDD (Test-Driven Development) ist Gesetz:** Ohne einen fehlschlagenden Test darfst du keinen Code schreiben. Ohne einen grünen Test darfst du keinen Code als fertig deklarieren.
|
|
||||||
</RULE[zero_trust_no_proof]>
|
|
||||||
3
.env
3
.env
@@ -27,7 +27,7 @@ UMAMI_API_ENDPOINT=https://analytics.infra.mintel.me
|
|||||||
# Error Tracking (GlitchTip/Sentry)
|
# Error Tracking (GlitchTip/Sentry)
|
||||||
# ────────────────────────────────────────────────────────────────────────────
|
# ────────────────────────────────────────────────────────────────────────────
|
||||||
# Optional: Leave empty to disable error tracking
|
# Optional: Leave empty to disable error tracking
|
||||||
SENTRY_DSN=https://dcb81958dbf24a3db422875f4672c14b@errors.infra.mintel.me/5
|
SENTRY_DSN=https://dcb81958-dbf2-4a3d-b422-875f4672c14b@glitchtip.infra.mintel.me/5
|
||||||
|
|
||||||
# ────────────────────────────────────────────────────────────────────────────
|
# ────────────────────────────────────────────────────────────────────────────
|
||||||
# Email Configuration (SMTP)
|
# Email Configuration (SMTP)
|
||||||
@@ -45,6 +45,7 @@ MAIL_RECIPIENTS=info@e-tib.com
|
|||||||
# ────────────────────────────────────────────────────────────────────────────
|
# ────────────────────────────────────────────────────────────────────────────
|
||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
GATEKEEPER_PASSWORD=klz2026
|
GATEKEEPER_PASSWORD=klz2026
|
||||||
|
SENTRY_DSN=
|
||||||
# SENTRY_ENVIRONMENT is set automatically by CI
|
# SENTRY_ENVIRONMENT is set automatically by CI
|
||||||
|
|
||||||
# ────────────────────────────────────────────────────────────────────────────
|
# ────────────────────────────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ MAIL_RECIPIENTS=info@e-tib.com
|
|||||||
# ────────────────────────────────────────────────────────────────────────────
|
# ────────────────────────────────────────────────────────────────────────────
|
||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
GATEKEEPER_PASSWORD=klz2026
|
GATEKEEPER_PASSWORD=klz2026
|
||||||
|
SENTRY_DSN=
|
||||||
# SENTRY_ENVIRONMENT is set automatically by CI
|
# SENTRY_ENVIRONMENT is set automatically by CI
|
||||||
|
|
||||||
# ────────────────────────────────────────────────────────────────────────────
|
# ────────────────────────────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ UMAMI_WEBSITE_ID=d773ea10-a3b3-4ccf-9024-987e14c4d669
|
|||||||
UMAMI_API_ENDPOINT=https://analytics.infra.mintel.me
|
UMAMI_API_ENDPOINT=https://analytics.infra.mintel.me
|
||||||
|
|
||||||
# Error Tracking (GlitchTip/Sentry)
|
# Error Tracking (GlitchTip/Sentry)
|
||||||
SENTRY_DSN=https://dcb81958dbf24a3db422875f4672c14b@errors.infra.mintel.me/5
|
SENTRY_DSN=
|
||||||
|
|
||||||
# Email Configuration (Mailgun)
|
# Email Configuration (Mailgun)
|
||||||
MAIL_HOST=smtp.eu.mailgun.org
|
MAIL_HOST=smtp.eu.mailgun.org
|
||||||
|
|||||||
@@ -47,7 +47,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "=== System Disk Usage ==="
|
echo "=== System Disk Usage ==="
|
||||||
df -h || true
|
df -h || true
|
||||||
|
echo "=== Tool Cache Usage ==="
|
||||||
|
du -sh /opt/hostedtoolcache/* || true
|
||||||
|
du -sh /opt/hostedtoolcache/.[!.]* || true
|
||||||
echo "Purging old tool caches skipped to prevent runner corruption."
|
echo "Purging old tool caches skipped to prevent runner corruption."
|
||||||
|
echo "=== Host Disk Usage ==="
|
||||||
|
docker run --rm -v /:/host-root alpine df -h || true
|
||||||
|
echo "=== Host Inode Usage ==="
|
||||||
|
docker run --rm -v /:/host-root alpine df -i || true
|
||||||
echo "=== Running Host Containers ==="
|
echo "=== Running Host Containers ==="
|
||||||
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" || true
|
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" || true
|
||||||
echo "=== Host Docker Info ==="
|
echo "=== Host Docker Info ==="
|
||||||
@@ -333,9 +340,6 @@ jobs:
|
|||||||
{
|
{
|
||||||
echo "# Generated by CI - $TARGET"
|
echo "# Generated by CI - $TARGET"
|
||||||
echo "IMAGE_TAG=$IMAGE_TAG"
|
echo "IMAGE_TAG=$IMAGE_TAG"
|
||||||
if [[ "$TARGET" != "production" ]]; then
|
|
||||||
echo "NODE_TLS_REJECT_UNAUTHORIZED=0"
|
|
||||||
fi
|
|
||||||
echo "NEXT_PUBLIC_BASE_URL=$NEXT_PUBLIC_BASE_URL"
|
echo "NEXT_PUBLIC_BASE_URL=$NEXT_PUBLIC_BASE_URL"
|
||||||
echo "GATEKEEPER_ORIGIN=$GATEKEEPER_ORIGIN"
|
echo "GATEKEEPER_ORIGIN=$GATEKEEPER_ORIGIN"
|
||||||
echo "SENTRY_DSN=$SENTRY_DSN"
|
echo "SENTRY_DSN=$SENTRY_DSN"
|
||||||
|
|||||||
2895
.lighthouseci/lhr-1782911226698.html
Normal file
2895
.lighthouseci/lhr-1782911226698.html
Normal file
File diff suppressed because one or more lines are too long
11796
.lighthouseci/lhr-1782911226698.json
Normal file
11796
.lighthouseci/lhr-1782911226698.json
Normal file
File diff suppressed because one or more lines are too long
@@ -1,6 +1,4 @@
|
|||||||
import { notFound, redirect } from 'next/navigation';
|
import { notFound, redirect } from 'next/navigation';
|
||||||
import { getImageProps } from 'next/image';
|
|
||||||
import { ScaleOfImpact } from '@/components/blocks/ScaleOfImpact';
|
|
||||||
import { Container, Badge, Heading } from '@/components/ui';
|
import { Container, Badge, Heading } from '@/components/ui';
|
||||||
import { getTranslations, setRequestLocale } from 'next-intl/server';
|
import { getTranslations, setRequestLocale } from 'next-intl/server';
|
||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
@@ -51,34 +49,10 @@ const mdxComponents = {
|
|||||||
JsonLd,
|
JsonLd,
|
||||||
Button,
|
Button,
|
||||||
Badge,
|
Badge,
|
||||||
Heading,
|
|
||||||
AnimatedCounter,
|
AnimatedCounter,
|
||||||
GrowthChart,
|
GrowthChart,
|
||||||
DeepDrillAnimation,
|
DeepDrillAnimation,
|
||||||
DataGridPulse,
|
DataGridPulse,
|
||||||
ScaleOfImpact,
|
|
||||||
ResponsiveImage: (props: any) => {
|
|
||||||
let src = props.src;
|
|
||||||
if (typeof src === 'string' && src.startsWith('/_next/image')) {
|
|
||||||
try {
|
|
||||||
const urlParam = new URLSearchParams(src.split('?')[1]).get('url');
|
|
||||||
if (urlParam) src = decodeURIComponent(urlParam);
|
|
||||||
} catch (_e) {
|
|
||||||
// Ignore invalid URL parsing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const { props: { srcSet, src: finalSrc, sizes } } = getImageProps({
|
|
||||||
src,
|
|
||||||
alt: props.alt || '',
|
|
||||||
width: 1920,
|
|
||||||
height: 1080,
|
|
||||||
sizes: '(max-width: 768px) 100vw, (max-width: 1200px) 75vw, 50vw',
|
|
||||||
quality: 80,
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<img {...props} src={finalSrc} srcSet={srcSet} sizes={sizes} loading="lazy" decoding="async" />
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// Standard HTML element mapping for consistent E-TIB typography
|
// Standard HTML element mapping for consistent E-TIB typography
|
||||||
h1: (props: any) => <Heading level={1} size="2" className="hidden" {...props} />, // Hidden because Hero handles H1
|
h1: (props: any) => <Heading level={1} size="2" className="hidden" {...props} />, // Hidden because Hero handles H1
|
||||||
h2: (props: any) => <Heading level={2} size="3" className="mt-16 mb-6 border-b border-neutral-100 pb-4" {...props} />,
|
h2: (props: any) => <Heading level={2} size="3" className="mt-16 mb-6 border-b border-neutral-100 pb-4" {...props} />,
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { notFound, redirect } from 'next/navigation';
|
import { notFound, redirect } from 'next/navigation';
|
||||||
import { getImageProps } from 'next/image';
|
|
||||||
import { ScaleOfImpact } from '@/components/blocks/ScaleOfImpact';
|
|
||||||
import JsonLd from '@/components/JsonLd';
|
import JsonLd from '@/components/JsonLd';
|
||||||
import { SITE_URL } from '@/lib/schema';
|
import { SITE_URL } from '@/lib/schema';
|
||||||
import {
|
import {
|
||||||
@@ -26,29 +24,6 @@ const mdxComponents = {
|
|||||||
h2: (props: any) => <Heading level={2} size="3" className="mt-16 mb-6 border-b border-neutral-100 pb-4" {...props} />,
|
h2: (props: any) => <Heading level={2} size="3" className="mt-16 mb-6 border-b border-neutral-100 pb-4" {...props} />,
|
||||||
h3: (props: any) => <Heading level={3} size="4" className="mt-12 mb-4 text-primary" {...props} />,
|
h3: (props: any) => <Heading level={3} size="4" className="mt-12 mb-4 text-primary" {...props} />,
|
||||||
h4: (props: any) => <Heading level={4} size="5" className="mt-8 mb-4 uppercase tracking-widest text-neutral-500" {...props} />,
|
h4: (props: any) => <Heading level={4} size="5" className="mt-8 mb-4 uppercase tracking-widest text-neutral-500" {...props} />,
|
||||||
ScaleOfImpact,
|
|
||||||
ResponsiveImage: (props: any) => {
|
|
||||||
let src = props.src;
|
|
||||||
if (typeof src === 'string' && src.startsWith('/_next/image')) {
|
|
||||||
try {
|
|
||||||
const urlParam = new URLSearchParams(src.split('?')[1]).get('url');
|
|
||||||
if (urlParam) src = decodeURIComponent(urlParam);
|
|
||||||
} catch (_e) {
|
|
||||||
// Ignore invalid URL parsing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const { props: { srcSet, src: finalSrc, sizes } } = getImageProps({
|
|
||||||
src,
|
|
||||||
alt: props.alt || '',
|
|
||||||
width: 1920,
|
|
||||||
height: 1080,
|
|
||||||
sizes: '(max-width: 768px) 100vw, (max-width: 1200px) 75vw, 50vw',
|
|
||||||
quality: 80,
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<img {...props} src={finalSrc} srcSet={srcSet} sizes={sizes} loading="lazy" decoding="async" />
|
|
||||||
);
|
|
||||||
},
|
|
||||||
p: (props: any) => <p className="text-base md:text-lg text-text-secondary leading-[1.8] mb-6 font-normal max-w-3xl" {...props} />,
|
p: (props: any) => <p className="text-base md:text-lg text-text-secondary leading-[1.8] mb-6 font-normal max-w-3xl" {...props} />,
|
||||||
ul: (props: any) => <ul className="list-none mb-8 space-y-3 text-base md:text-lg text-text-secondary font-normal max-w-3xl" {...props} />,
|
ul: (props: any) => <ul className="list-none mb-8 space-y-3 text-base md:text-lg text-text-secondary font-normal max-w-3xl" {...props} />,
|
||||||
ol: (props: any) => <ol className="list-decimal pl-6 mb-8 space-y-3 text-base md:text-lg text-text-secondary font-normal max-w-3xl" {...props} />,
|
ol: (props: any) => <ol className="list-decimal pl-6 mb-8 space-y-3 text-base md:text-lg text-text-secondary font-normal max-w-3xl" {...props} />,
|
||||||
@@ -143,7 +118,7 @@ export default async function BlogPost({ params }: BlogPostProps) {
|
|||||||
|
|
||||||
{/* Title overlay on image */}
|
{/* Title overlay on image */}
|
||||||
<div className="absolute inset-0 flex flex-col justify-end pb-16 md:pb-24">
|
<div className="absolute inset-0 flex flex-col justify-end pb-16 md:pb-24">
|
||||||
<div className="container mx-auto max-w-7xl px-4">
|
<div className="container mx-auto px-4">
|
||||||
<div className="max-w-4xl bg-neutral-dark/40 backdrop-blur-md p-6 rounded-2xl border border-white/10">
|
<div className="max-w-4xl bg-neutral-dark/40 backdrop-blur-md p-6 rounded-2xl border border-white/10">
|
||||||
{post.frontmatter.category && (
|
{post.frontmatter.category && (
|
||||||
<div className="overflow-hidden mb-6">
|
<div className="overflow-hidden mb-6">
|
||||||
@@ -217,7 +192,7 @@ export default async function BlogPost({ params }: BlogPostProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Main Content Area with Sticky Narrative Layout */}
|
{/* Main Content Area with Sticky Narrative Layout */}
|
||||||
<div className="container mx-auto max-w-7xl px-4 py-16 md:py-24">
|
<div className="container mx-auto px-4 py-16 md:py-24">
|
||||||
<div className="sticky-narrative-container">
|
<div className="sticky-narrative-container">
|
||||||
{/* Left Column: Content */}
|
{/* Left Column: Content */}
|
||||||
<div className="sticky-narrative-content">
|
<div className="sticky-narrative-content">
|
||||||
|
|||||||
@@ -1,83 +1,13 @@
|
|||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import https from 'https';
|
|
||||||
|
|
||||||
const ALLOWED_HOSTS = ['glitchtip.infra.mintel.me', 'errors.infra.mintel.me'];
|
|
||||||
|
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
try {
|
try {
|
||||||
const rawText = await req.text();
|
const rawText = await req.text();
|
||||||
const items = rawText.split('\n');
|
// Sentry sends NDJSON (Newline Delimited JSON). Split by newline to parse safely.
|
||||||
|
const items = rawText.split('\n').filter(Boolean).map(line => JSON.parse(line));
|
||||||
if (items.length === 0 || !items[0]) {
|
console.log("CLIENT ERROR INTERCEPTED:", JSON.stringify(items[0], null, 2));
|
||||||
return NextResponse.json({ error: 'Empty payload' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const header = JSON.parse(items[0]);
|
|
||||||
// Use the server's configured DSN (if available) to override the client's potentially fake DSN
|
|
||||||
// This allows the client to work without exposing NEXT_PUBLIC_SENTRY_DSN
|
|
||||||
const dsn = process.env.SENTRY_DSN || header.dsn;
|
|
||||||
if (!dsn) {
|
|
||||||
return NextResponse.json({ error: 'No DSN found' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = new URL(dsn);
|
|
||||||
const projectId = url.pathname.replace('/', '');
|
|
||||||
const host = url.hostname;
|
|
||||||
|
|
||||||
if (!ALLOWED_HOSTS.includes(host)) {
|
|
||||||
return NextResponse.json({ error: 'Invalid Sentry Host' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rewrite the DSN in the envelope header so Glitchtip doesn't reject the fake client DSN
|
|
||||||
if (process.env.SENTRY_DSN) {
|
|
||||||
header.dsn = process.env.SENTRY_DSN;
|
|
||||||
items[0] = JSON.stringify(header);
|
|
||||||
}
|
|
||||||
|
|
||||||
const sentryIngestUrl = `https://${host}/api/${projectId}/envelope/`;
|
|
||||||
const payloadToForward = items.join('\n');
|
|
||||||
|
|
||||||
return new Promise<NextResponse>((resolve) => {
|
|
||||||
const req = https.request(
|
|
||||||
sentryIngestUrl,
|
|
||||||
{
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/x-sentry-envelope',
|
|
||||||
},
|
|
||||||
// Bypass self-signed cert error since glitchtip.infra.mintel.me uses an internal CA
|
|
||||||
// that the Next.js docker container doesn't trust by default.
|
|
||||||
rejectUnauthorized: false,
|
|
||||||
},
|
|
||||||
(res) => {
|
|
||||||
res.on('data', () => {
|
|
||||||
// Consume data to free up memory
|
|
||||||
});
|
|
||||||
res.on('end', () => {
|
|
||||||
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
||||||
resolve(NextResponse.json({ success: true }));
|
|
||||||
} else {
|
|
||||||
resolve(
|
|
||||||
NextResponse.json(
|
|
||||||
{ error: `Relay rejected (${res.statusCode})` },
|
|
||||||
{ status: res.statusCode || 500 }
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
req.on('error', (err) => {
|
|
||||||
console.error('[Sentry Tunnel] https.request failed', err);
|
|
||||||
resolve(NextResponse.json({ error: 'Relay failed' }, { status: 500 }));
|
|
||||||
});
|
|
||||||
|
|
||||||
req.write(payloadToForward);
|
|
||||||
req.end();
|
|
||||||
});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[Sentry Tunnel] Failed to parse or relay body", e);
|
console.log("Failed to parse relay body (NDJSON)", e);
|
||||||
return NextResponse.json({ error: 'Relay failed' }, { status: 500 });
|
|
||||||
}
|
}
|
||||||
|
return NextResponse.json({ success: true });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ import { DynamicInitialLoader as InitialLoader } from '@/components/providers/Dy
|
|||||||
import { DynamicMobileBottomNav as MobileBottomNav } from '@/components/layout/DynamicMobileBottomNav';
|
import { DynamicMobileBottomNav as MobileBottomNav } from '@/components/layout/DynamicMobileBottomNav';
|
||||||
|
|
||||||
import { DynamicCorporateBackground as CorporateBackground } from '@/components/decorations/DynamicCorporateBackground';
|
import { DynamicCorporateBackground as CorporateBackground } from '@/components/decorations/DynamicCorporateBackground';
|
||||||
import { DynamicPageTransitionShutter as PageTransitionShutter } from '@/components/providers/DynamicPageTransitionShutter';
|
const corporateBackground = null; // Removed to prevent line shifting
|
||||||
import { DynamicFramerMotion as FramerMotionProvider } from '@/components/providers/DynamicFramerMotion';
|
|
||||||
|
|
||||||
const inter = Inter({
|
const inter = Inter({
|
||||||
subsets: ['latin'],
|
subsets: ['latin'],
|
||||||
@@ -191,28 +190,26 @@ export default async function Layout(props: {
|
|||||||
<body className="relative flex flex-col min-h-screen font-sans antialiased overflow-x-hidden selection:bg-primary/90 selection:text-white" suppressHydrationWarning>
|
<body className="relative flex flex-col min-h-screen font-sans antialiased overflow-x-hidden selection:bg-primary/90 selection:text-white" suppressHydrationWarning>
|
||||||
<NextIntlClientProvider messages={clientMessages} locale={safeLocale}>
|
<NextIntlClientProvider messages={clientMessages} locale={safeLocale}>
|
||||||
<TransitionProvider>
|
<TransitionProvider>
|
||||||
<FramerMotionProvider>
|
<CorporateBackground />
|
||||||
<CorporateBackground />
|
{!hasSeenLoader && <InitialLoader shouldShowLoader={!hasSeenLoader} />}
|
||||||
<InitialLoader shouldShowLoader={!hasSeenLoader} />
|
{/* PageTransitionShutter loaded dynamically in TransitionProvider */}
|
||||||
<PageTransitionShutter />
|
<SkipLink />
|
||||||
<SkipLink />
|
<Header navLinks={navLinks} />
|
||||||
<Header navLinks={navLinks} />
|
<MobileBottomNav navLinks={navLinks} currentLocale={safeLocale} />
|
||||||
<MobileBottomNav navLinks={navLinks} currentLocale={safeLocale} />
|
|
||||||
|
<main
|
||||||
<main
|
id="main-content"
|
||||||
id="main-content"
|
className="flex-grow overflow-visible"
|
||||||
className="flex-grow overflow-visible"
|
tabIndex={-1}
|
||||||
tabIndex={-1}
|
>
|
||||||
>
|
{children}
|
||||||
{children}
|
</main>
|
||||||
</main>
|
|
||||||
|
|
||||||
<Footer companyInfo={companyInfo} />
|
<Footer companyInfo={companyInfo} />
|
||||||
<JsonLd />
|
<JsonLd />
|
||||||
<AnalyticsShell />
|
<AnalyticsShell />
|
||||||
|
|
||||||
<FeedbackClientWrapper />
|
<FeedbackClientWrapper />
|
||||||
</FramerMotionProvider>
|
|
||||||
</TransitionProvider>
|
</TransitionProvider>
|
||||||
</NextIntlClientProvider>
|
</NextIntlClientProvider>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -132,7 +132,12 @@ export default async function Home(props: { params: Promise<{ locale: string }>
|
|||||||
}
|
}
|
||||||
|
|
||||||
setRequestLocale(locale);
|
setRequestLocale(locale);
|
||||||
preload('/germany-map.svg', { as: 'image', fetchPriority: 'high' });
|
preload('/assets/videos/web/hero-kabelpflug-poster.webp', {
|
||||||
|
as: 'image',
|
||||||
|
fetchPriority: 'high',
|
||||||
|
imageSrcSet: '/assets/videos/web/hero-kabelpflug-poster-mobile.webp 800w, /assets/videos/web/hero-kabelpflug-poster.webp 1920w',
|
||||||
|
imageSizes: '100vw'
|
||||||
|
});
|
||||||
|
|
||||||
const mdx = await getMdxContent(locale, 'home');
|
const mdx = await getMdxContent(locale, 'home');
|
||||||
const allReferences = await getAllReferences(locale);
|
const allReferences = await getAllReferences(locale);
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { Container, Heading, Badge } from '@/components/ui';
|
import { Container, Heading, Badge } from '@/components/ui';
|
||||||
import { getImageProps } from 'next/image';
|
|
||||||
import { ScaleOfImpact } from '@/components/blocks/ScaleOfImpact';
|
|
||||||
import { getTranslations, setRequestLocale } from 'next-intl/server';
|
import { getTranslations, setRequestLocale } from 'next-intl/server';
|
||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
import { getAllReferences } from '@/lib/references';
|
import { getAllReferences } from '@/lib/references';
|
||||||
@@ -41,30 +39,6 @@ const mdxComponents = {
|
|||||||
ul: (props: any) => <ul className="grid grid-cols-1 gap-2 mb-6" {...props} />,
|
ul: (props: any) => <ul className="grid grid-cols-1 gap-2 mb-6" {...props} />,
|
||||||
li: CustomLi,
|
li: CustomLi,
|
||||||
p: (props: any) => <p className="text-neutral-600 text-sm mb-4 leading-relaxed" {...props} />,
|
p: (props: any) => <p className="text-neutral-600 text-sm mb-4 leading-relaxed" {...props} />,
|
||||||
Heading,
|
|
||||||
ScaleOfImpact,
|
|
||||||
ResponsiveImage: (props: any) => {
|
|
||||||
let src = props.src;
|
|
||||||
if (typeof src === 'string' && src.startsWith('/_next/image')) {
|
|
||||||
try {
|
|
||||||
const urlParam = new URLSearchParams(src.split('?')[1]).get('url');
|
|
||||||
if (urlParam) src = decodeURIComponent(urlParam);
|
|
||||||
} catch (_e) {
|
|
||||||
// Ignore invalid URL parsing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const { props: { srcSet, src: finalSrc, sizes } } = getImageProps({
|
|
||||||
src,
|
|
||||||
alt: props.alt || '',
|
|
||||||
width: 1920,
|
|
||||||
height: 1080,
|
|
||||||
sizes: '(max-width: 768px) 100vw, (max-width: 1200px) 75vw, 50vw',
|
|
||||||
quality: 80,
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<img {...props} src={finalSrc} srcSet={srcSet} sizes={sizes} loading="lazy" decoding="async" />
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
|
|||||||
@@ -3,34 +3,6 @@
|
|||||||
|
|
||||||
@config "../tailwind.config.cjs";
|
@config "../tailwind.config.cjs";
|
||||||
|
|
||||||
/* Tailwind v4 Container Polyfill */
|
|
||||||
@utility container {
|
|
||||||
width: 100%;
|
|
||||||
margin-inline: auto !important;
|
|
||||||
padding-inline: 1rem;
|
|
||||||
|
|
||||||
@media (min-width: 640px) {
|
|
||||||
max-width: 640px;
|
|
||||||
padding-inline: 1.5rem;
|
|
||||||
}
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
max-width: 768px;
|
|
||||||
padding-inline: 2rem;
|
|
||||||
}
|
|
||||||
@media (min-width: 1024px) {
|
|
||||||
max-width: 1024px;
|
|
||||||
padding-inline: 2.5rem;
|
|
||||||
}
|
|
||||||
@media (min-width: 1280px) {
|
|
||||||
max-width: 1280px;
|
|
||||||
padding-inline: 3rem;
|
|
||||||
}
|
|
||||||
@media (min-width: 1536px) {
|
|
||||||
max-width: 1536px;
|
|
||||||
padding-inline: 4rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* E-TIB Custom Utilities */
|
/* E-TIB Custom Utilities */
|
||||||
@layer utilities {
|
@layer utilities {
|
||||||
.text-balance {
|
.text-balance {
|
||||||
@@ -116,30 +88,34 @@
|
|||||||
}
|
}
|
||||||
/* trigger rebuild */
|
/* trigger rebuild */
|
||||||
|
|
||||||
@keyframes hero-fade-in-up {
|
@layer utilities {
|
||||||
from {
|
@keyframes hero-fade-in-up {
|
||||||
opacity: 0;
|
from {
|
||||||
transform: translateY(30px);
|
opacity: 0;
|
||||||
|
transform: translateY(30px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
to {
|
|
||||||
opacity: 1;
|
.animate-hero-fade-in-up {
|
||||||
transform: translateY(0);
|
animation: hero-fade-in-up 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@utility animate-hero-fade-in-up {
|
@layer utilities {
|
||||||
animation: hero-fade-in-up 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
@keyframes hero-zoom-out {
|
||||||
}
|
from {
|
||||||
|
transform: scale(1.05);
|
||||||
@keyframes hero-zoom-out {
|
}
|
||||||
from {
|
to {
|
||||||
transform: scale(1.05);
|
transform: scale(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
to {
|
|
||||||
transform: scale(1);
|
.animate-hero-zoom-out {
|
||||||
|
animation: hero-zoom-out 1.5s ease-out forwards;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@utility animate-hero-zoom-out {
|
|
||||||
animation: hero-zoom-out 1.5s ease-out forwards;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export default function ContactForm() {
|
|||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={3} d="M5 13l4 4L19 7" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={3} d="M5 13l4 4L19 7" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<Heading level={3} align="center" className="mb-4">
|
<Heading level={3} className="mb-4">
|
||||||
{t('form.successTitle') || 'Message Sent!'}
|
{t('form.successTitle') || 'Message Sent!'}
|
||||||
</Heading>
|
</Heading>
|
||||||
<p className="text-text-secondary text-lg mb-8">
|
<p className="text-text-secondary text-lg mb-8">
|
||||||
@@ -115,7 +115,7 @@ export default function ContactForm() {
|
|||||||
<line x1="9" y1="9" x2="15" y2="15" strokeLinecap="round" strokeLinejoin="round" />
|
<line x1="9" y1="9" x2="15" y2="15" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<Heading level={3} align="center" className="mb-4 text-destructive font-black">
|
<Heading level={3} className="mb-4 text-destructive font-black">
|
||||||
{t('form.errorTitle') || 'Submission Failed!'}
|
{t('form.errorTitle') || 'Submission Failed!'}
|
||||||
</Heading>
|
</Heading>
|
||||||
<p className="text-destructive/80 text-lg mb-8 leading-relaxed font-medium">
|
<p className="text-destructive/80 text-lg mb-8 leading-relaxed font-medium">
|
||||||
|
|||||||
@@ -22,18 +22,11 @@ export default function AnalyticsShell() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initServices = () => {
|
|
||||||
import('@/lib/services/create-services').then(({ getAppServices }) => {
|
|
||||||
getAppServices();
|
|
||||||
setShouldLoad(true);
|
|
||||||
}).catch(console.error);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Wait until browser is completely idle before loading heavy analytics/logger/sentry SDKs
|
// Wait until browser is completely idle before loading heavy analytics/logger/sentry SDKs
|
||||||
if (typeof window !== 'undefined' && 'requestIdleCallback' in window) {
|
if (typeof window !== 'undefined' && 'requestIdleCallback' in window) {
|
||||||
window.requestIdleCallback(initServices, { timeout: 3000 });
|
window.requestIdleCallback(() => setShouldLoad(true), { timeout: 3000 });
|
||||||
} else {
|
} else {
|
||||||
const timer = setTimeout(initServices, 2500);
|
const timer = setTimeout(() => setShouldLoad(true), 2500);
|
||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
@@ -148,8 +148,7 @@ export function CertificatesBlock({ badge, title, description, certificates = de
|
|||||||
const wrapperProps = cert.pdfUrl ? {
|
const wrapperProps = cert.pdfUrl ? {
|
||||||
href: encodeURI(cert.pdfUrl),
|
href: encodeURI(cert.pdfUrl),
|
||||||
target: "_blank",
|
target: "_blank",
|
||||||
rel: "noopener noreferrer",
|
rel: "noopener noreferrer"
|
||||||
download: cert.pdfUrl.split('/').pop()
|
|
||||||
} : {};
|
} : {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export function CompanyTimeline({
|
|||||||
<div className="absolute top-0 right-0 w-[600px] h-[600px] bg-primary/5 rounded-full blur-[100px] pointer-events-none -translate-y-1/2 translate-x-1/3" />
|
<div className="absolute top-0 right-0 w-[600px] h-[600px] bg-primary/5 rounded-full blur-[100px] pointer-events-none -translate-y-1/2 translate-x-1/3" />
|
||||||
<div className="absolute bottom-0 left-0 w-[800px] h-[800px] bg-neutral-200/40 rounded-full blur-[120px] pointer-events-none translate-y-1/3 -translate-x-1/3" />
|
<div className="absolute bottom-0 left-0 w-[800px] h-[800px] bg-neutral-200/40 rounded-full blur-[120px] pointer-events-none translate-y-1/3 -translate-x-1/3" />
|
||||||
|
|
||||||
<div className="container mx-auto max-w-5xl relative z-10">
|
<div className="container max-w-5xl relative z-10">
|
||||||
<div className="text-center mb-12 md:mb-24">
|
<div className="text-center mb-12 md:mb-24">
|
||||||
<div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-white border border-neutral-200 text-neutral-dark text-xs font-bold uppercase tracking-wider mb-6 shadow-sm">
|
<div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-white border border-neutral-200 text-neutral-dark text-xs font-bold uppercase tracking-wider mb-6 shadow-sm">
|
||||||
<span className="w-2 h-2 rounded-full bg-primary animate-pulse" />
|
<span className="w-2 h-2 rounded-full bg-primary animate-pulse" />
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export const HeroSection: React.FC<HeroSectionProps> = (props) => {
|
|||||||
objectPosition: `${backgroundImage?.focalX ?? 50}% ${backgroundImage?.focalY ?? 50}%`,
|
objectPosition: `${backgroundImage?.focalX ?? 50}% ${backgroundImage?.focalY ?? 50}%`,
|
||||||
}}
|
}}
|
||||||
sizes="100vw"
|
sizes="100vw"
|
||||||
|
quality={50}
|
||||||
priority
|
priority
|
||||||
/>
|
/>
|
||||||
{/* Cinematic Color Grading Overlay */}
|
{/* Cinematic Color Grading Overlay */}
|
||||||
@@ -60,26 +61,26 @@ export const HeroSection: React.FC<HeroSectionProps> = (props) => {
|
|||||||
className={`max-w-4xl ${alignment === 'center' ? 'mx-auto' : ''}`}
|
className={`max-w-4xl ${alignment === 'center' ? 'mx-auto' : ''}`}
|
||||||
>
|
>
|
||||||
{badge && (
|
{badge && (
|
||||||
<div className="animate-hero-fade-in-up" style={{ animationDelay: '0.1s', animationFillMode: 'both' }}>
|
<div className="animate-hero-fade-in-up" style={{ animationDelay: '0.1s', opacity: 0, animationFillMode: 'forwards' }}>
|
||||||
<Badge variant="saturated" className="mb-4 md:mb-8 shadow-lg">
|
<Badge variant="saturated" className="mb-4 md:mb-8 shadow-lg">
|
||||||
{badge}
|
{badge}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="animate-hero-fade-in-up" style={{ animationDelay: badge ? '0.25s' : '0.1s', animationFillMode: 'both' }}>
|
<div className="animate-hero-fade-in-up" style={{ animationDelay: badge ? '0.25s' : '0.1s', opacity: 0, animationFillMode: 'forwards' }}>
|
||||||
<Heading level={1} size="section" variant="white" align={alignment || 'left'} className="mb-4 md:mb-8">
|
<Heading level={1} size="section" variant="white" align={alignment || 'left'} className="mb-4 md:mb-8">
|
||||||
{title}
|
{title}
|
||||||
</Heading>
|
</Heading>
|
||||||
</div>
|
</div>
|
||||||
{subtitle && (
|
{subtitle && (
|
||||||
<div className="animate-hero-fade-in-up" style={{ animationDelay: badge ? '0.4s' : '0.25s', animationFillMode: 'both' }}>
|
<div className="animate-hero-fade-in-up" style={{ animationDelay: badge ? '0.4s' : '0.25s', opacity: 0, animationFillMode: 'forwards' }}>
|
||||||
<p className={`text-lg md:text-2xl text-white/70 font-medium leading-relaxed max-w-2xl ${alignment === 'center' ? 'mx-auto' : ''}`}>
|
<p className={`text-lg md:text-2xl text-white/70 font-medium leading-relaxed max-w-2xl ${alignment === 'center' ? 'mx-auto' : ''}`}>
|
||||||
{subtitle}
|
{subtitle}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{ctaLabel && ctaHref && (
|
{ctaLabel && ctaHref && (
|
||||||
<div className={`mt-8 animate-hero-fade-in-up ${alignment === 'center' ? 'flex flex-wrap justify-center gap-4' : 'flex flex-wrap gap-4'}`} style={{ animationDelay: badge ? '0.55s' : '0.4s', animationFillMode: 'both' }}>
|
<div className={`mt-8 animate-hero-fade-in-up ${alignment === 'center' ? 'flex flex-wrap justify-center gap-4' : 'flex flex-wrap gap-4'}`} style={{ animationDelay: badge ? '0.55s' : '0.4s', opacity: 0, animationFillMode: 'forwards' }}>
|
||||||
<Button
|
<Button
|
||||||
href={ctaHref}
|
href={ctaHref}
|
||||||
variant="accent"
|
variant="accent"
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export function HeroVideo(props: HeroVideoProps) {
|
|||||||
|
|
||||||
let defaultPoster = "/assets/photos/DJI_0048.JPG";
|
let defaultPoster = "/assets/photos/DJI_0048.JPG";
|
||||||
if (videoUrl && videoUrl.endsWith('.mp4')) {
|
if (videoUrl && videoUrl.endsWith('.mp4')) {
|
||||||
defaultPoster = videoUrl.replace('.mp4', '-poster.jpg');
|
defaultPoster = videoUrl.replace('.mp4', '-poster.webp');
|
||||||
}
|
}
|
||||||
|
|
||||||
const posterSrc = props.backgroundImage?.url || props.posterImage?.url || data?.posterImage?.url || defaultPoster;
|
const posterSrc = props.backgroundImage?.url || props.posterImage?.url || data?.posterImage?.url || defaultPoster;
|
||||||
@@ -80,16 +80,14 @@ export function HeroVideo(props: HeroVideoProps) {
|
|||||||
{/* Background color while video loads */}
|
{/* Background color while video loads */}
|
||||||
<div className="absolute inset-0 z-0 bg-neutral-dark" />
|
<div className="absolute inset-0 z-0 bg-neutral-dark" />
|
||||||
|
|
||||||
{/* ALWAYS render the Next.js optimized Image as the LCP element */}
|
<img
|
||||||
<Image
|
|
||||||
key={`img-${pathname}-${posterSrc}`}
|
key={`img-${pathname}-${posterSrc}`}
|
||||||
src={posterSrc}
|
src={posterSrc}
|
||||||
|
srcSet={posterSrc.includes('-poster.webp') ? `${posterSrc.replace('-poster.webp', '-poster-mobile.webp')} 800w, ${posterSrc} 1920w` : undefined}
|
||||||
|
sizes={posterSrc.includes('-poster.webp') ? "100vw" : undefined}
|
||||||
alt={posterAlt}
|
alt={posterAlt}
|
||||||
fill
|
className="absolute inset-0 w-full h-full object-cover z-[1] pointer-events-none"
|
||||||
className="object-cover z-[1] pointer-events-none"
|
decoding="sync"
|
||||||
sizes="100vw"
|
|
||||||
quality={25}
|
|
||||||
priority
|
|
||||||
fetchPriority="high"
|
fetchPriority="high"
|
||||||
/>
|
/>
|
||||||
{/* Fast compositing layer to replace the heavy CSS filters on the image */}
|
{/* Fast compositing layer to replace the heavy CSS filters on the image */}
|
||||||
@@ -119,7 +117,7 @@ export function HeroVideo(props: HeroVideoProps) {
|
|||||||
{/* Top Fade for Header Navigation Readability */}
|
{/* Top Fade for Header Navigation Readability */}
|
||||||
<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 mx-auto max-w-7xl relative z-[4] text-center px-4">
|
<div className="container relative z-[4] text-center px-4">
|
||||||
<div
|
<div
|
||||||
key={`hero-content-${pathname}`}
|
key={`hero-content-${pathname}`}
|
||||||
className="relative"
|
className="relative"
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export const JobListingBlock = (props: JobListingBlockProps) => {
|
|||||||
showFairs,
|
showFairs,
|
||||||
fairsTitle = t('fairsTitle'),
|
fairsTitle = t('fairsTitle'),
|
||||||
fairs = [
|
fairs = [
|
||||||
{ name: 'Intersolar München', date: '8. - 10. Juni 2027', type: 'Energie-Messe', location: 'Messe München' },
|
{ name: 'Intersolar München', date: 'Termin folgt', type: 'Energie-Messe', location: 'Messe München' },
|
||||||
{ name: 'Windenergietage Linstow', date: 'Termin folgt', type: 'Fachkongress', location: 'Linstow' },
|
{ name: 'Windenergietage Linstow', date: 'Termin folgt', type: 'Fachkongress', location: 'Linstow' },
|
||||||
{ name: 'Kabelwerkstatt Wiesbaden', date: 'Termin folgt', type: 'Fachmesse', location: 'Wiesbaden' }
|
{ name: 'Kabelwerkstatt Wiesbaden', date: 'Termin folgt', type: 'Fachmesse', location: 'Wiesbaden' }
|
||||||
],
|
],
|
||||||
@@ -69,7 +69,7 @@ export const JobListingBlock = (props: JobListingBlockProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="py-12 md:py-24">
|
<div className="py-12 md:py-24">
|
||||||
<div className="container max-w-7xl mx-auto">
|
<div className="container mx-auto">
|
||||||
{showFairs && (
|
{showFairs && (
|
||||||
<div className="mb-12 md:mb-24 relative">
|
<div className="mb-12 md:mb-24 relative">
|
||||||
<m.h3
|
<m.h3
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export function ReferencesSlider(props: ReferencesSliderProps) {
|
|||||||
<section id="referenzen" className="pt-16 pb-8 md:py-24 lg:py-32 bg-neutral-dark text-white relative overflow-hidden">
|
<section id="referenzen" className="pt-16 pb-8 md:py-24 lg:py-32 bg-neutral-dark text-white relative overflow-hidden">
|
||||||
<div className="absolute inset-0 bg-gradient-to-b from-neutral-dark via-neutral-900 to-neutral-dark z-0" />
|
<div className="absolute inset-0 bg-gradient-to-b from-neutral-dark via-neutral-900 to-neutral-dark z-0" />
|
||||||
|
|
||||||
<div className="container mx-auto max-w-7xl relative z-10 mb-12 flex flex-col items-center justify-center text-center gap-6">
|
<div className="container relative z-10 mb-12 flex flex-col items-center justify-center text-center gap-6">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-primary-light font-bold tracking-wider uppercase text-sm mb-3">{badge}</h2>
|
<h2 className="text-primary-light font-bold tracking-wider uppercase text-sm mb-3">{badge}</h2>
|
||||||
<h3 className="font-heading text-3xl md:text-5xl font-extrabold">{title}</h3>
|
<h3 className="font-heading text-3xl md:text-5xl font-extrabold">{title}</h3>
|
||||||
@@ -179,7 +179,7 @@ export function ReferencesSlider(props: ReferencesSliderProps) {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="container mx-auto max-w-7xl relative z-10 mt-4 flex justify-center">
|
<div className="container relative z-10 mt-4 flex justify-center">
|
||||||
<Link
|
<Link
|
||||||
href={ctaHref}
|
href={ctaHref}
|
||||||
className="px-8 py-4 rounded-xl bg-white/5 border border-white/20 hover:bg-white hover:text-neutral-dark hover:shadow-[0_0_20px_rgba(255,255,255,0.3)] transition-all font-bold flex items-center gap-3 backdrop-blur-sm"
|
className="px-8 py-4 rounded-xl bg-white/5 border border-white/20 hover:bg-white hover:text-neutral-dark hover:shadow-[0_0_20px_rgba(255,255,255,0.3)] transition-all font-bold flex items-center gap-3 backdrop-blur-sm"
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export function SubCompanyTiles(props: SubCompanyTilesProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section id="unternehmen" className="pt-12 pb-16 md:py-24 lg:py-32 bg-neutral-dark border-b border-neutral-800 relative overflow-hidden">
|
<section id="unternehmen" className="pt-12 pb-16 md:py-24 lg:py-32 bg-neutral-dark border-b border-neutral-800 relative overflow-hidden">
|
||||||
<div className="container mx-auto max-w-7xl relative z-10 px-4">
|
<div className="container relative z-10 px-4">
|
||||||
|
|
||||||
{(badge || title) && (
|
{(badge || title) && (
|
||||||
<div className="text-center md:text-left max-w-3xl mx-auto md:mx-0 mb-16">
|
<div className="text-center md:text-left max-w-3xl mx-auto md:mx-0 mb-16">
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export function TeamGrid({ members }: TeamGridProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="py-16 md:py-24 lg:py-32 bg-white relative overflow-hidden">
|
<section className="py-16 md:py-24 lg:py-32 bg-white relative overflow-hidden">
|
||||||
<div className="container mx-auto px-4 md:px-12 lg:px-16 max-w-7xl relative z-10">
|
<div className="container relative z-10">
|
||||||
<div className="mb-12">
|
<div className="mb-12">
|
||||||
<h2 className="text-primary font-bold tracking-wider uppercase text-sm mb-3">{t('badge')}</h2>
|
<h2 className="text-primary font-bold tracking-wider uppercase text-sm mb-3">{t('badge')}</h2>
|
||||||
<h3 className="font-heading text-3xl md:text-4xl font-extrabold text-neutral-dark mb-4">{t('title')}</h3>
|
<h3 className="font-heading text-3xl md:text-4xl font-extrabold text-neutral-dark mb-4">{t('title')}</h3>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export function EUFundingBadge() {
|
|||||||
alt="European Union Background"
|
alt="European Union Background"
|
||||||
fill
|
fill
|
||||||
className="object-cover object-top"
|
className="object-cover object-top"
|
||||||
priority
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export function Footer({ companyInfo }: FooterProps) {
|
|||||||
|
|
||||||
<EUFundingBadge />
|
<EUFundingBadge />
|
||||||
|
|
||||||
<div className="container mx-auto max-w-7xl relative z-10 grid grid-cols-1 md:grid-cols-4 lg:grid-cols-12 gap-4 md:gap-6 lg:gap-8 mb-4 md:mb-12">
|
<div className="container relative z-10 grid grid-cols-1 md:grid-cols-4 lg:grid-cols-12 gap-4 md:gap-6 lg:gap-8 mb-4 md:mb-12">
|
||||||
{/* Brand Column Bento */}
|
{/* Brand Column Bento */}
|
||||||
<div className="col-span-1 md:col-span-4 lg:col-span-5 flex flex-col justify-between bg-white/[0.02] border border-white/5 rounded-3xl p-5 md:p-8 lg:p-10 backdrop-blur-md relative group overflow-hidden">
|
<div className="col-span-1 md:col-span-4 lg:col-span-5 flex flex-col justify-between bg-white/[0.02] border border-white/5 rounded-3xl p-5 md:p-8 lg:p-10 backdrop-blur-md relative group overflow-hidden">
|
||||||
<div className="absolute inset-0 bg-gradient-to-br from-white/[0.04] to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-700" />
|
<div className="absolute inset-0 bg-gradient-to-br from-white/[0.04] to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-700" />
|
||||||
@@ -217,7 +217,7 @@ export function Footer({ companyInfo }: FooterProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="container mx-auto max-w-7xl relative z-10">
|
<div className="container relative z-10">
|
||||||
<div className="flex flex-col md:flex-row justify-between items-center gap-4 md:gap-6 py-4 px-5 md:py-6 md:px-8 rounded-2xl bg-white/[0.02] border border-white/5 backdrop-blur-md text-center md:text-left">
|
<div className="flex flex-col md:flex-row justify-between items-center gap-4 md:gap-6 py-4 px-5 md:py-6 md:px-8 rounded-2xl bg-white/[0.02] border border-white/5 backdrop-blur-md text-center md:text-left">
|
||||||
<div className="flex flex-col md:flex-row items-center gap-4 md:gap-6 h-full">
|
<div className="flex flex-col md:flex-row items-center gap-4 md:gap-6 h-full">
|
||||||
<p className="text-neutral-400 text-xs font-medium m-0">© {new Date().getFullYear()} E-TIB GmbH. {locale === 'de' ? 'Alle Rechte vorbehalten.' : 'All rights reserved.'}</p>
|
<p className="text-neutral-400 text-xs font-medium m-0">© {new Date().getFullYear()} E-TIB GmbH. {locale === 'de' ? 'Alle Rechte vorbehalten.' : 'All rights reserved.'}</p>
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
'use client';
|
|
||||||
import dynamic from 'next/dynamic';
|
|
||||||
|
|
||||||
export const DynamicFramerMotion = dynamic(
|
|
||||||
() => import('./FramerMotionProvider').then((mod) => mod.FramerMotionProvider),
|
|
||||||
{ ssr: true }
|
|
||||||
);
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
'use client';
|
|
||||||
import { LazyMotion } from 'framer-motion';
|
|
||||||
const loadFeatures = () => import('@/lib/framer-features').then(res => res.default);
|
|
||||||
|
|
||||||
export function FramerMotionProvider({ children }: { children: React.ReactNode }) {
|
|
||||||
return (
|
|
||||||
<LazyMotion features={loadFeatures} strict>
|
|
||||||
{children}
|
|
||||||
</LazyMotion>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -72,8 +72,8 @@ export function InitialLoader({ shouldShowLoader = true }: { shouldShowLoader?:
|
|||||||
{/* Sweeping intense white light */}
|
{/* Sweeping intense white light */}
|
||||||
<m.div
|
<m.div
|
||||||
className="absolute inset-0 bg-gradient-to-r from-transparent via-white to-transparent skew-x-[-25deg]"
|
className="absolute inset-0 bg-gradient-to-r from-transparent via-white to-transparent skew-x-[-25deg]"
|
||||||
initial={{ left: '-150%' }}
|
initial={{ x: '-150%' }}
|
||||||
animate={{ left: '250%' }}
|
animate={{ x: '250%' }}
|
||||||
transition={{ duration: 2.5, ease: "easeInOut", repeat: Infinity, repeatDelay: 0.5 }}
|
transition={{ duration: 2.5, ease: "easeInOut", repeat: Infinity, repeatDelay: 0.5 }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -91,9 +91,9 @@ export function InitialLoader({ shouldShowLoader = true }: { shouldShowLoader?:
|
|||||||
className="h-[2px] w-full bg-white/5 overflow-hidden relative rounded-full"
|
className="h-[2px] w-full bg-white/5 overflow-hidden relative rounded-full"
|
||||||
>
|
>
|
||||||
<m.div
|
<m.div
|
||||||
className="absolute inset-y-0 left-0 bg-gradient-to-r from-primary-dark via-primary to-primary-light"
|
className="absolute inset-y-0 left-0 w-full bg-gradient-to-r from-primary-dark via-primary to-primary-light origin-left"
|
||||||
initial={{ width: "0%" }}
|
initial={{ scaleX: 0 }}
|
||||||
animate={{ width: "100%" }}
|
animate={{ scaleX: 1 }}
|
||||||
transition={{ duration: 3.8, ease: [0.16, 1, 0.3, 1] }}
|
transition={{ duration: 3.8, ease: [0.16, 1, 0.3, 1] }}
|
||||||
/>
|
/>
|
||||||
</m.div>
|
</m.div>
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ export function PageTransitionShutter() {
|
|||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{isTransitioning && (
|
{isTransitioning && (
|
||||||
<m.div
|
<m.div
|
||||||
key="shutter"
|
key="page-transition-shutter"
|
||||||
initial={{ y: '-100%' }}
|
initial={{ y: '-100%' }}
|
||||||
animate={{ y: '0%' }}
|
animate={{ y: 0 }}
|
||||||
exit={{ y: '100%' }}
|
exit={{ y: '100%' }}
|
||||||
transition={{ duration: 0.9, ease: [0.16, 1, 0.3, 1] }}
|
transition={{ duration: 0.65, ease: [0.76, 0, 0.24, 1] }}
|
||||||
className="fixed left-0 w-full z-[9998] bg-[#050B14] pointer-events-none flex flex-col items-center justify-center overflow-visible"
|
className="fixed left-0 right-0 z-[9998] bg-[#050B14] flex flex-col items-center justify-center overflow-hidden"
|
||||||
style={{
|
style={{
|
||||||
height: '100vh',
|
height: '100vh',
|
||||||
top: '0',
|
top: '0',
|
||||||
@@ -56,8 +56,8 @@ export function PageTransitionShutter() {
|
|||||||
{/* Sweeping intense white light */}
|
{/* Sweeping intense white light */}
|
||||||
<m.div
|
<m.div
|
||||||
className="absolute inset-0 bg-gradient-to-r from-transparent via-white to-transparent skew-x-[-25deg]"
|
className="absolute inset-0 bg-gradient-to-r from-transparent via-white to-transparent skew-x-[-25deg]"
|
||||||
initial={{ left: '-150%' }}
|
initial={{ x: '-150%' }}
|
||||||
animate={{ left: '250%' }}
|
animate={{ x: '250%' }}
|
||||||
transition={{ duration: 1.5, ease: "easeInOut", repeat: Infinity, repeatDelay: 0.2 }}
|
transition={{ duration: 1.5, ease: "easeInOut", repeat: Infinity, repeatDelay: 0.2 }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,6 +2,16 @@
|
|||||||
|
|
||||||
import React, { createContext, useContext, useState, useCallback, ReactNode, useEffect } from 'react';
|
import React, { createContext, useContext, useState, useCallback, ReactNode, useEffect } from 'react';
|
||||||
import { useRouter, usePathname, useSearchParams } from 'next/navigation';
|
import { useRouter, usePathname, useSearchParams } from 'next/navigation';
|
||||||
|
import { LazyMotion } from 'framer-motion';
|
||||||
|
import dynamic from 'next/dynamic';
|
||||||
|
|
||||||
|
const loadFeatures = () => import('@/lib/framer-features').then(res => res.default);
|
||||||
|
|
||||||
|
// Defer loading the shutter to eliminate AnimatePresence from the initial bundle
|
||||||
|
const DynamicPageTransitionShutter = dynamic(
|
||||||
|
() => import('./PageTransitionShutter').then(mod => mod.PageTransitionShutter),
|
||||||
|
{ ssr: false }
|
||||||
|
);
|
||||||
|
|
||||||
interface TransitionContextType {
|
interface TransitionContextType {
|
||||||
isTransitioning: boolean;
|
isTransitioning: boolean;
|
||||||
@@ -14,8 +24,12 @@ const TransitionContext = createContext<TransitionContextType | undefined>(undef
|
|||||||
export function TransitionProvider({ children }: { children: ReactNode }) {
|
export function TransitionProvider({ children }: { children: ReactNode }) {
|
||||||
const [isTransitioning, setIsTransitioning] = useState(false);
|
const [isTransitioning, setIsTransitioning] = useState(false);
|
||||||
const [transitionMessage, setTransitionMessage] = useState<string | null>(null);
|
const [transitionMessage, setTransitionMessage] = useState<string | null>(null);
|
||||||
|
const [hasMountedShutter, setHasMountedShutter] = useState(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
// We no longer eagerly load the shutter in the background.
|
||||||
|
// It will be loaded precisely when the user initiates a transition.
|
||||||
|
|
||||||
// We use a ref to track transition state without triggering the route change effect when it turns true
|
// We use a ref to track transition state without triggering the route change effect when it turns true
|
||||||
const isTransitioningRef = React.useRef(isTransitioning);
|
const isTransitioningRef = React.useRef(isTransitioning);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -41,6 +55,7 @@ export function TransitionProvider({ children }: { children: ReactNode }) {
|
|||||||
|
|
||||||
setTransitionMessage(message);
|
setTransitionMessage(message);
|
||||||
setIsTransitioning(true);
|
setIsTransitioning(true);
|
||||||
|
setHasMountedShutter(true);
|
||||||
|
|
||||||
// Die Animation des Shutters abwarten (ca. 700ms), dann pushen
|
// Die Animation des Shutters abwarten (ca. 700ms), dann pushen
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -68,7 +83,10 @@ export function TransitionProvider({ children }: { children: ReactNode }) {
|
|||||||
setTransitionMessage={setTransitionMessage}
|
setTransitionMessage={setTransitionMessage}
|
||||||
/>
|
/>
|
||||||
</React.Suspense>
|
</React.Suspense>
|
||||||
{children}
|
<LazyMotion features={loadFeatures}>
|
||||||
|
{hasMountedShutter && <DynamicPageTransitionShutter />}
|
||||||
|
{children}
|
||||||
|
</LazyMotion>
|
||||||
</TransitionContext.Provider>
|
</TransitionContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ description: "Die E-TIB GmbH ist Ihr zuverlässiger Partner für komplexe Kabelt
|
|||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
title: "Kabelleitungsnetzbau",
|
title: "Kabelleitungsnetzbau",
|
||||||
description: "Kabelleitungsnetzbau (Hoch-/Mittel- und Niederspannung) sowie Kabelmontagen bis 110 kV",
|
description: "Kabelleitungsnetzbau (Nieder-/Mittel- und Hochspannung bis 110 kV)",
|
||||||
tag: "Energie",
|
tag: "Energie",
|
||||||
size: "large",
|
size: "large",
|
||||||
href: "/de/kabeltiefbau",
|
href: "/de/kabeltiefbau",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ layout: "fullBleed"
|
|||||||
<HeroSection
|
<HeroSection
|
||||||
badge="Kernkompetenz"
|
badge="Kernkompetenz"
|
||||||
title="Kabelleitungsnetzbau"
|
title="Kabelleitungsnetzbau"
|
||||||
subtitle="Komplette Infrastruktur-Lösungen für Hoch-, Mittel- und Niederspannungsnetze sowie Kabelmontagen bis 110 kV"
|
subtitle="Komplette Infrastruktur-Lösungen für Nieder-, Mittel- und Hochspannungsnetze bis 110 kV"
|
||||||
backgroundImage={{ url: '/assets/photos/DSC01123.JPG' }}
|
backgroundImage={{ url: '/assets/photos/DSC01123.JPG' }}
|
||||||
alignment="center"
|
alignment="center"
|
||||||
ctaLabel="Projekt anfragen"
|
ctaLabel="Projekt anfragen"
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ layout: "fullBleed"
|
|||||||
showFairs={true}
|
showFairs={true}
|
||||||
showJobs={false}
|
showJobs={false}
|
||||||
fairs={[
|
fairs={[
|
||||||
|
{ name: 'Intersolar München', date: '23. - 25. Juni 2026', type: 'Messe', location: 'München', url: 'https://www.intersolar.de/' },
|
||||||
{ name: 'Windenergietage Linstow', date: '10. - 12. November 2026', type: 'Fachkongress', location: 'Linstow', url: 'https://www.windenergietage.de/' },
|
{ name: 'Windenergietage Linstow', date: '10. - 12. November 2026', type: 'Fachkongress', location: 'Linstow', url: 'https://www.windenergietage.de/' },
|
||||||
{ name: 'Werkstatt Kabel 2026', date: '24. - 25. November 2026', type: 'Fachtagung', location: 'Wiesbaden', url: 'https://werkstatt-kabel.essociation.de/' },
|
{ name: 'Werkstatt Kabel 2026', date: '24. - 25. November 2026', type: 'Fachtagung', location: 'Wiesbaden', url: 'https://werkstatt-kabel.essociation.de/' }
|
||||||
{ name: 'Intersolar München', date: '8. - 10. Juni 2027', type: 'Messe', location: 'München', url: 'https://www.intersolar.de/' }
|
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -23,14 +23,6 @@ layout: "fullBleed"
|
|||||||
phone: "+49 1520 7230518",
|
phone: "+49 1520 7230518",
|
||||||
image: "/assets/photos/team/danny.jpg"
|
image: "/assets/photos/team/danny.jpg"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "kathrin-lemanski",
|
|
||||||
name: "Kathrin Lemanski",
|
|
||||||
position: "Kaufmännische Leitung",
|
|
||||||
email: "k.lemanski@e-tib.com",
|
|
||||||
phone: "+49 3561 6857733",
|
|
||||||
image: "/assets/photos/team/kathrin.jpg"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "dirk-schmidt",
|
id: "dirk-schmidt",
|
||||||
name: "Dirk Schmidt",
|
name: "Dirk Schmidt",
|
||||||
@@ -55,6 +47,22 @@ layout: "fullBleed"
|
|||||||
phone: "+49 171 3868167",
|
phone: "+49 171 3868167",
|
||||||
image: "/assets/photos/team/martin.jpg"
|
image: "/assets/photos/team/martin.jpg"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "kerstin-joseph",
|
||||||
|
name: "Kerstin Joseph",
|
||||||
|
position: "Sekretariat / Buchhaltung",
|
||||||
|
email: "k.joseph@e-tib.com",
|
||||||
|
phone: "+49 3561 6851692",
|
||||||
|
image: "/assets/photos/team/kerstin.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "kathrin-lemanski",
|
||||||
|
name: "Kathrin Lemanski",
|
||||||
|
position: "Sachbearbeitung",
|
||||||
|
email: "k.lemanski@e-tib.com",
|
||||||
|
phone: "+49 3561 6857733",
|
||||||
|
image: "/assets/photos/team/kathrin.jpg"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "sven-kirbs",
|
id: "sven-kirbs",
|
||||||
name: "Sven Kirbs",
|
name: "Sven Kirbs",
|
||||||
@@ -63,21 +71,6 @@ layout: "fullBleed"
|
|||||||
phone: "+49 151 29603652",
|
phone: "+49 151 29603652",
|
||||||
image: "/assets/photos/team/sven.jpg"
|
image: "/assets/photos/team/sven.jpg"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "kerstin-joseph",
|
|
||||||
name: "Kerstin Joseph",
|
|
||||||
position: "Buchhaltung / Controlling",
|
|
||||||
email: "k.joseph@e-tib.com",
|
|
||||||
phone: "+49 3561 6857733",
|
|
||||||
image: "/assets/photos/team/kerstin.jpg"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "katrin-haigold",
|
|
||||||
name: "Katrin Haigold",
|
|
||||||
position: "Buchhaltung / Personalwesen",
|
|
||||||
email: "k.haigold@e-tib.com",
|
|
||||||
phone: "+49 3561 6851692"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "maik-weichert",
|
id: "maik-weichert",
|
||||||
name: "Maik Weichert",
|
name: "Maik Weichert",
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ layout: "fullBleed"
|
|||||||
showFairs={true}
|
showFairs={true}
|
||||||
showJobs={false}
|
showJobs={false}
|
||||||
fairs={[
|
fairs={[
|
||||||
|
{ name: 'Intersolar Munich', date: 'June 23–25, 2026', type: 'Fair', location: 'Munich', url: 'https://www.intersolar.de/' },
|
||||||
{ name: 'Wind Energy Days Linstow', date: 'November 10–12, 2026', type: 'Specialist Congress', location: 'Linstow', url: 'https://www.windenergietage.de/' },
|
{ name: 'Wind Energy Days Linstow', date: 'November 10–12, 2026', type: 'Specialist Congress', location: 'Linstow', url: 'https://www.windenergietage.de/' },
|
||||||
{ name: 'Werkstatt Kabel 2026', date: 'November 24–25, 2026', type: 'Symposium', location: 'Wiesbaden', url: 'https://werkstatt-kabel.essociation.de/' },
|
{ name: 'Werkstatt Kabel 2026', date: 'November 24–25, 2026', type: 'Symposium', location: 'Wiesbaden', url: 'https://werkstatt-kabel.essociation.de/' }
|
||||||
{ name: 'Intersolar Munich', date: 'June 8–10, 2027', type: 'Fair', location: 'Munich', url: 'https://www.intersolar.de/' }
|
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -23,14 +23,6 @@ layout: "fullBleed"
|
|||||||
phone: "+49 1520 7230518",
|
phone: "+49 1520 7230518",
|
||||||
image: "/assets/photos/team/danny.jpg"
|
image: "/assets/photos/team/danny.jpg"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "kathrin-lemanski",
|
|
||||||
name: "Kathrin Lemanski",
|
|
||||||
position: "Commercial Management",
|
|
||||||
email: "k.lemanski@e-tib.com",
|
|
||||||
phone: "+49 3561 6857733",
|
|
||||||
image: "/assets/photos/team/kathrin.jpg"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "dirk-schmidt",
|
id: "dirk-schmidt",
|
||||||
name: "Dirk Schmidt",
|
name: "Dirk Schmidt",
|
||||||
@@ -55,6 +47,22 @@ layout: "fullBleed"
|
|||||||
phone: "+49 171 3868167",
|
phone: "+49 171 3868167",
|
||||||
image: "/assets/photos/team/martin.jpg"
|
image: "/assets/photos/team/martin.jpg"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "kerstin-joseph",
|
||||||
|
name: "Kerstin Joseph",
|
||||||
|
position: "Secretariat / Accounting",
|
||||||
|
email: "k.joseph@e-tib.com",
|
||||||
|
phone: "+49 3561 6851692",
|
||||||
|
image: "/assets/photos/team/kerstin.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "kathrin-lemanski",
|
||||||
|
name: "Kathrin Lemanski",
|
||||||
|
position: "Administration",
|
||||||
|
email: "k.lemanski@e-tib.com",
|
||||||
|
phone: "+49 3561 6857733",
|
||||||
|
image: "/assets/photos/team/kathrin.jpg"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "sven-kirbs",
|
id: "sven-kirbs",
|
||||||
name: "Sven Kirbs",
|
name: "Sven Kirbs",
|
||||||
@@ -63,21 +71,6 @@ layout: "fullBleed"
|
|||||||
phone: "+49 151 29603652",
|
phone: "+49 151 29603652",
|
||||||
image: "/assets/photos/team/sven.jpg"
|
image: "/assets/photos/team/sven.jpg"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "kerstin-joseph",
|
|
||||||
name: "Kerstin Joseph",
|
|
||||||
position: "Accounting / Controlling",
|
|
||||||
email: "k.joseph@e-tib.com",
|
|
||||||
phone: "+49 3561 6857733",
|
|
||||||
image: "/assets/photos/team/kerstin.jpg"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "katrin-haigold",
|
|
||||||
name: "Katrin Haigold",
|
|
||||||
position: "Accounting / Human Resources",
|
|
||||||
email: "k.haigold@e-tib.com",
|
|
||||||
phone: "+49 3561 6851692"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "maik-weichert",
|
id: "maik-weichert",
|
||||||
name: "Maik Weichert",
|
name: "Maik Weichert",
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ services:
|
|||||||
- "traefik.http.routers.${PROJECT_NAME:-klz}.middlewares=${AUTH_MIDDLEWARE:-etib-ratelimit,etib-forward,etib-compress}"
|
- "traefik.http.routers.${PROJECT_NAME:-klz}.middlewares=${AUTH_MIDDLEWARE:-etib-ratelimit,etib-forward,etib-compress}"
|
||||||
|
|
||||||
# Public Router – paths that bypass Gatekeeper auth (health, SEO, static assets, OG images)
|
# Public Router – paths that bypass Gatekeeper auth (health, SEO, static assets, OG images)
|
||||||
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.rule=(${TRAEFIK_HOST_RULE:-Host(`${TRAEFIK_HOST:-e-tib.com}`) || Host(`staging.${TRAEFIK_HOST:-e-tib.com}`) || Host(`testing.${TRAEFIK_HOST:-e-tib.com}`)}) && PathRegexp(`^/([a-z]{2}/)?(health|login|gatekeeper|uploads|media|assets|robots\\.txt|manifest\\.webmanifest|sitemap(-[0-9]+)?\\.xml|(.*/)?api/og(/.*)?|(.*/)?opengraph-image.*)`)"
|
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.rule=(${TRAEFIK_HOST_RULE:-Host(`${TRAEFIK_HOST:-e-tib.com}`) || Host(`staging.${TRAEFIK_HOST:-e-tib.com}`) || Host(`testing.${TRAEFIK_HOST:-e-tib.com}`)}) && PathRegexp(`^/([a-z]{2}/)?(health|login|gatekeeper|uploads|media|robots\\.txt|manifest\\.webmanifest|sitemap(-[0-9]+)?\\.xml|(.*/)?api/og(/.*)?|(.*/)?opengraph-image.*)`)"
|
||||||
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.entrypoints=${TRAEFIK_ENTRYPOINT:-web}"
|
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.entrypoints=${TRAEFIK_ENTRYPOINT:-web}"
|
||||||
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-}"
|
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-}"
|
||||||
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.tls=${TRAEFIK_TLS:-false}"
|
- "traefik.http.routers.${PROJECT_NAME:-klz}-public.tls=${TRAEFIK_TLS:-false}"
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { AppServices } from './app-services';
|
|||||||
import { NoopAnalyticsService } from './analytics/noop-analytics-service';
|
import { NoopAnalyticsService } from './analytics/noop-analytics-service';
|
||||||
import { UmamiAnalyticsService } from './analytics/umami-analytics-service';
|
import { UmamiAnalyticsService } from './analytics/umami-analytics-service';
|
||||||
import { MemoryCacheService } from './cache/memory-cache-service';
|
import { MemoryCacheService } from './cache/memory-cache-service';
|
||||||
import { GlitchtipErrorReportingService } from './errors/glitchtip-error-reporting-service';
|
|
||||||
import { NoopErrorReportingService } from './errors/noop-error-reporting-service';
|
import { NoopErrorReportingService } from './errors/noop-error-reporting-service';
|
||||||
import { NoopLoggerService } from './logging/noop-logger-service';
|
import { NoopLoggerService } from './logging/noop-logger-service';
|
||||||
import { PinoLoggerService } from './logging/pino-logger-service';
|
import { PinoLoggerService } from './logging/pino-logger-service';
|
||||||
@@ -68,17 +67,7 @@ export function getAppServices(): AppServices {
|
|||||||
logger.info('Notification service initialized (noop)');
|
logger.info('Notification service initialized (noop)');
|
||||||
|
|
||||||
// Create error reporting service (GlitchTip/Sentry or no-op)
|
// Create error reporting service (GlitchTip/Sentry or no-op)
|
||||||
const errors = sentryEnabled
|
const errors = new NoopErrorReportingService();
|
||||||
? new GlitchtipErrorReportingService(
|
|
||||||
{
|
|
||||||
enabled: true,
|
|
||||||
dsn: config.errors.glitchtip.dsn,
|
|
||||||
tracesSampleRate: 0.1, // Client-side we usually want lower sample rate
|
|
||||||
},
|
|
||||||
logger,
|
|
||||||
notifications,
|
|
||||||
)
|
|
||||||
: new NoopErrorReportingService();
|
|
||||||
|
|
||||||
if (sentryEnabled) {
|
if (sentryEnabled) {
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|||||||
@@ -56,9 +56,6 @@ export class GlitchtipErrorReportingService implements ErrorReportingService {
|
|||||||
tracesSampleRate: this.options.tracesSampleRate ?? 0.1,
|
tracesSampleRate: this.options.tracesSampleRate ?? 0.1,
|
||||||
replaysOnErrorSampleRate: 1.0,
|
replaysOnErrorSampleRate: 1.0,
|
||||||
replaysSessionSampleRate: 0.1,
|
replaysSessionSampleRate: 0.1,
|
||||||
ignoreErrors: [
|
|
||||||
'Failed to find Server Action. This request might be from an older or newer deployment.',
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Sentry;
|
return Sentry;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -280,7 +280,7 @@
|
|||||||
"TeamGrid": {
|
"TeamGrid": {
|
||||||
"badge": "Persönliche Beratung",
|
"badge": "Persönliche Beratung",
|
||||||
"title": "Ihre Ansprechpartner",
|
"title": "Ihre Ansprechpartner",
|
||||||
"subtitle": "Sprechen Sie direkt mit unseren Experten für Ihr Projekt.",
|
"subtitle": "Sprechen Sie direkt mit unseren Experten für Ihr regionales Projekt.",
|
||||||
"management": "Geschäftsführung",
|
"management": "Geschäftsführung",
|
||||||
"branchETIB": "E-TIB GmbH",
|
"branchETIB": "E-TIB GmbH",
|
||||||
"branchIng": "Ingenieurgesellschaft",
|
"branchIng": "Ingenieurgesellschaft",
|
||||||
|
|||||||
@@ -280,7 +280,7 @@
|
|||||||
"TeamGrid": {
|
"TeamGrid": {
|
||||||
"badge": "Personal Consultation",
|
"badge": "Personal Consultation",
|
||||||
"title": "Your Contacts",
|
"title": "Your Contacts",
|
||||||
"subtitle": "Speak directly with our experts for your project.",
|
"subtitle": "Speak directly with our experts for your regional project.",
|
||||||
"management": "Management",
|
"management": "Management",
|
||||||
"branchETIB": "E-TIB GmbH",
|
"branchETIB": "E-TIB GmbH",
|
||||||
"branchIng": "Engineering Company",
|
"branchIng": "Engineering Company",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"@mintel/next-utils": "1.9.5",
|
"@mintel/next-utils": "1.9.5",
|
||||||
"@next/mdx": "^16.1.6",
|
"@next/mdx": "^16.1.6",
|
||||||
"@react-email/components": "1.0.8",
|
"@react-email/components": "1.0.8",
|
||||||
|
"@react-pdf/renderer": "^4.5.1",
|
||||||
"@react-three/drei": "^10.7.7",
|
"@react-three/drei": "^10.7.7",
|
||||||
"@react-three/fiber": "^9.5.0",
|
"@react-three/fiber": "^9.5.0",
|
||||||
"@sentry/nextjs": "^10.39.0",
|
"@sentry/nextjs": "^10.39.0",
|
||||||
@@ -72,7 +73,6 @@
|
|||||||
"@types/sharp": "^0.31.1",
|
"@types/sharp": "^0.31.1",
|
||||||
"@types/three": "^0.183.1",
|
"@types/three": "^0.183.1",
|
||||||
"@vitejs/plugin-react": "^5.1.4",
|
"@vitejs/plugin-react": "^5.1.4",
|
||||||
"@vitejs/plugin-react-swc": "^4.3.1",
|
|
||||||
"@vitest/ui": "^4.0.16",
|
"@vitest/ui": "^4.0.16",
|
||||||
"autoprefixer": "^10.4.23",
|
"autoprefixer": "^10.4.23",
|
||||||
"cheerio": "^1.2.0",
|
"cheerio": "^1.2.0",
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"preinstall": "npx only-allow pnpm"
|
"preinstall": "npx only-allow pnpm"
|
||||||
},
|
},
|
||||||
"version": "2.4.43",
|
"version": "2.4.7",
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
"@parcel/watcher",
|
"@parcel/watcher",
|
||||||
@@ -164,4 +164,4 @@
|
|||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"lucide-react": "^0.563.0"
|
"lucide-react": "^0.563.0"
|
||||||
}
|
}
|
||||||
}
|
}\n
|
||||||
300
pnpm-lock.yaml
generated
300
pnpm-lock.yaml
generated
@@ -34,6 +34,9 @@ importers:
|
|||||||
'@react-email/components':
|
'@react-email/components':
|
||||||
specifier: 1.0.8
|
specifier: 1.0.8
|
||||||
version: 1.0.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
version: 1.0.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||||
|
'@react-pdf/renderer':
|
||||||
|
specifier: ^4.5.1
|
||||||
|
version: 4.5.1(react@19.2.4)
|
||||||
'@react-three/drei':
|
'@react-three/drei':
|
||||||
specifier: ^10.7.7
|
specifier: ^10.7.7
|
||||||
version: 10.7.7(@react-three/fiber@9.5.0(@types/react@19.2.14)(immer@11.1.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(three@0.183.2))(@types/react@19.2.14)(@types/three@0.183.1)(immer@11.1.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(three@0.183.2)
|
version: 10.7.7(@react-three/fiber@9.5.0(@types/react@19.2.14)(immer@11.1.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(three@0.183.2))(@types/react@19.2.14)(@types/three@0.183.1)(immer@11.1.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(three@0.183.2)
|
||||||
@@ -212,9 +215,6 @@ importers:
|
|||||||
'@vitejs/plugin-react':
|
'@vitejs/plugin-react':
|
||||||
specifier: ^5.1.4
|
specifier: ^5.1.4
|
||||||
version: 5.2.0(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@22.19.15)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))
|
version: 5.2.0(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@22.19.15)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))
|
||||||
'@vitejs/plugin-react-swc':
|
|
||||||
specifier: ^4.3.1
|
|
||||||
version: 4.3.1(@swc/helpers@0.5.20)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@22.19.15)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))
|
|
||||||
'@vitest/ui':
|
'@vitest/ui':
|
||||||
specifier: ^4.0.16
|
specifier: ^4.0.16
|
||||||
version: 4.1.2(vitest@4.1.2)
|
version: 4.1.2(vitest@4.1.2)
|
||||||
@@ -2213,6 +2213,49 @@ packages:
|
|||||||
react: ^18.0.0
|
react: ^18.0.0
|
||||||
react-dom: ^18.0.0
|
react-dom: ^18.0.0
|
||||||
|
|
||||||
|
'@react-pdf/fns@3.1.3':
|
||||||
|
resolution: {integrity: sha512-0I7pApDr1/RLAKbizuLy/IHTEa93LSPy/bEwYniboC3Xqnp6Od8xFJKbKEzGw2wh/5zKFFwl00g4t9RwgIMc3w==}
|
||||||
|
|
||||||
|
'@react-pdf/font@4.0.8':
|
||||||
|
resolution: {integrity: sha512-deNd+emtZAJho1IlzKL9bRoLAGv/6oXOIKO2oZfs4RuXUrK1onLHbJO7e2YoVLPFP/sQxisRTnzdJFtd35iKwA==}
|
||||||
|
|
||||||
|
'@react-pdf/image@3.1.0':
|
||||||
|
resolution: {integrity: sha512-ks7Ry8v711r8NvKWSELehj0BXBNPRihSnWsM09nDD8Ur175zbWBCK217LLwQMKDNYDVpkZaipdoJPom1LGaE9g==}
|
||||||
|
|
||||||
|
'@react-pdf/layout@4.6.1':
|
||||||
|
resolution: {integrity: sha512-gN6PmWoEffvlIkifLfEhMsVucRywVMyH3rnxdyOVOhGy0nWJKKGpHyPc4plbDdpP6EfZ0r8prHXujDSkIG2nSA==}
|
||||||
|
|
||||||
|
'@react-pdf/pdfkit@5.1.1':
|
||||||
|
resolution: {integrity: sha512-wNcdSsNlNYyGHGAgIdt453egBF7fiF9UxpRlklUfVvu8OWCrUppG9xiUrPLVoKiqWet5tMi0w6LmuFUJuYqjEg==}
|
||||||
|
|
||||||
|
'@react-pdf/primitives@4.3.0':
|
||||||
|
resolution: {integrity: sha512-nYXoZ36pvwNzbc54+DbL8RCn15jU7woJ9D/svnh5tpUXekJ+CbI4mZLo6boSv24CvJgychOu6h7gxX03B4ps0A==}
|
||||||
|
|
||||||
|
'@react-pdf/reconciler@2.0.0':
|
||||||
|
resolution: {integrity: sha512-7zaPRujpbHSmCpIrZ+b9HSTJHthcVZzX0Wx7RzvQGsGBUbHP4p6s5itXrAIOuQuPvDepoHGNOvf6xUuMVvdoyw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
|
'@react-pdf/render@4.5.1':
|
||||||
|
resolution: {integrity: sha512-IW/N4HWJWtioBXCf7n02IR24VJJ8gbdS3jGypf+vW/rSErEx3/URRzh9UK6Ma8Fpog9+T/W6GE2NHJ5AAKHhVA==}
|
||||||
|
|
||||||
|
'@react-pdf/renderer@4.5.1':
|
||||||
|
resolution: {integrity: sha512-5r1VQrE6FRLXX5wWUxwZzM24E2BJMo6g8AQWuS8WyPs9ugu5yMnb2g8/RpPYka/Z6J+RUEWc32wty2NoUJF42Q==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
|
'@react-pdf/stylesheet@6.2.1':
|
||||||
|
resolution: {integrity: sha512-2+UEk+7e+z8baaWi2l5kPLWmwtJeOI+T5wW9GGeN3iDH7vd3kbTqOpN1yt9mmfNVZFxQsnDHpznFb5v5UF983A==}
|
||||||
|
|
||||||
|
'@react-pdf/svg@1.1.0':
|
||||||
|
resolution: {integrity: sha512-cTIHXiz9x1HrbfqzfxfZP3FRdDwUXG77QWF6Fb5MP/lV3ONxR+g0Z3hwtBatCS9HeGBQCpxX/Lzb8wHE+co1PA==}
|
||||||
|
|
||||||
|
'@react-pdf/textkit@6.3.0':
|
||||||
|
resolution: {integrity: sha512-v6+V8nAcVwm7s2s1jIG2MD3Iw//x/k+XrH1foWOELBE4b32pyDgKyPXN/6KJE0dnX7+fVy27uctLNCLNMvzKzQ==}
|
||||||
|
|
||||||
|
'@react-pdf/types@2.11.1':
|
||||||
|
resolution: {integrity: sha512-i9xQgfaDU9QoeNnbp6rltXCWg1huEh195rpOuN8cE4BZ2FuLdQrsIcb2dhFF9aOxXf+XBA6LOSpIW051MDD/bw==}
|
||||||
|
|
||||||
'@react-three/drei@10.7.7':
|
'@react-three/drei@10.7.7':
|
||||||
resolution: {integrity: sha512-ff+J5iloR0k4tC++QtD/j9u3w5fzfgFAWDtAGQah9pF2B1YgOq/5JxqY0/aVoQG5r3xSZz0cv5tk2YuBob4xEQ==}
|
resolution: {integrity: sha512-ff+J5iloR0k4tC++QtD/j9u3w5fzfgFAWDtAGQah9pF2B1YgOq/5JxqY0/aVoQG5r3xSZz0cv5tk2YuBob4xEQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2355,9 +2398,6 @@ packages:
|
|||||||
'@rolldown/pluginutils@1.0.0-rc.3':
|
'@rolldown/pluginutils@1.0.0-rc.3':
|
||||||
resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==}
|
resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==}
|
||||||
|
|
||||||
'@rolldown/pluginutils@1.0.1':
|
|
||||||
resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==}
|
|
||||||
|
|
||||||
'@rollup/plugin-commonjs@28.0.1':
|
'@rollup/plugin-commonjs@28.0.1':
|
||||||
resolution: {integrity: sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==}
|
resolution: {integrity: sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==}
|
||||||
engines: {node: '>=16.0.0 || 14 >= 14.17'}
|
engines: {node: '>=16.0.0 || 14 >= 14.17'}
|
||||||
@@ -3292,12 +3332,6 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: '>= 16.8.0'
|
react: '>= 16.8.0'
|
||||||
|
|
||||||
'@vitejs/plugin-react-swc@4.3.1':
|
|
||||||
resolution: {integrity: sha512-PaeokKjAGraNN+s5SIApgsktnJprIyt3zgEIu7awnEdfn29QiB2crTcCzyi2XGpX9rUnTc0cKU07Wm0N0g7H2w==}
|
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
|
||||||
peerDependencies:
|
|
||||||
vite: ^4 || ^5 || ^6 || ^7 || ^8
|
|
||||||
|
|
||||||
'@vitejs/plugin-react@5.2.0':
|
'@vitejs/plugin-react@5.2.0':
|
||||||
resolution: {integrity: sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==}
|
resolution: {integrity: sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
@@ -3396,6 +3430,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==}
|
resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==}
|
||||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||||
|
|
||||||
|
abs-svg-path@0.1.1:
|
||||||
|
resolution: {integrity: sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==}
|
||||||
|
|
||||||
accepts@1.3.8:
|
accepts@1.3.8:
|
||||||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@@ -3731,6 +3768,9 @@ packages:
|
|||||||
brotli@1.3.3:
|
brotli@1.3.3:
|
||||||
resolution: {integrity: sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==}
|
resolution: {integrity: sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==}
|
||||||
|
|
||||||
|
browserify-zlib@0.2.0:
|
||||||
|
resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==}
|
||||||
|
|
||||||
browserslist@4.28.2:
|
browserslist@4.28.2:
|
||||||
resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==}
|
resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==}
|
||||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||||
@@ -3925,6 +3965,14 @@ packages:
|
|||||||
color-name@1.1.4:
|
color-name@1.1.4:
|
||||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||||
|
|
||||||
|
color-name@2.1.0:
|
||||||
|
resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==}
|
||||||
|
engines: {node: '>=12.20'}
|
||||||
|
|
||||||
|
color-string@2.1.4:
|
||||||
|
resolution: {integrity: sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
colorette@2.0.20:
|
colorette@2.0.20:
|
||||||
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
|
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
|
||||||
|
|
||||||
@@ -4376,6 +4424,9 @@ packages:
|
|||||||
electron-to-chromium@1.5.330:
|
electron-to-chromium@1.5.330:
|
||||||
resolution: {integrity: sha512-jFNydB5kFtYUobh4IkWUnXeyDbjf/r9gcUEXe1xcrcUxIGfTdzPXA+ld6zBRbwvgIGVzDll/LTIiDztEtckSnA==}
|
resolution: {integrity: sha512-jFNydB5kFtYUobh4IkWUnXeyDbjf/r9gcUEXe1xcrcUxIGfTdzPXA+ld6zBRbwvgIGVzDll/LTIiDztEtckSnA==}
|
||||||
|
|
||||||
|
emoji-regex-xs@1.0.0:
|
||||||
|
resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==}
|
||||||
|
|
||||||
emoji-regex@10.6.0:
|
emoji-regex@10.6.0:
|
||||||
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
|
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
|
||||||
|
|
||||||
@@ -5099,6 +5150,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==}
|
resolution: {integrity: sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==}
|
||||||
engines: {node: '>= 6.0.0'}
|
engines: {node: '>= 6.0.0'}
|
||||||
|
|
||||||
|
hsl-to-hex@1.0.0:
|
||||||
|
resolution: {integrity: sha512-K6GVpucS5wFf44X0h2bLVRDsycgJmf9FF2elg+CrqD8GcFU8c6vYhgXn8NjUkFCwj+xDFb70qgLbTUm6sxwPmA==}
|
||||||
|
|
||||||
|
hsl-to-rgb-for-reals@1.1.1:
|
||||||
|
resolution: {integrity: sha512-LgOWAkrN0rFaQpfdWBQlv/VhkOxb5AsBjk6NQVx4yEzWS923T07X0M1Y0VNko2H52HeSpZrZNNMJ0aFqsdVzQg==}
|
||||||
|
|
||||||
html-encoding-sniffer@6.0.0:
|
html-encoding-sniffer@6.0.0:
|
||||||
resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==}
|
resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==}
|
||||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||||
@@ -5180,6 +5237,9 @@ packages:
|
|||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
hyphen@1.14.1:
|
||||||
|
resolution: {integrity: sha512-kvL8xYl5QMTh+LwohVN72ciOxC0OEV79IPdJSTwEXok9y9QHebXGdFgrED4sWfiax/ODx++CAMk3hMy4XPJPOw==}
|
||||||
|
|
||||||
i18next-fs-backend@2.6.3:
|
i18next-fs-backend@2.6.3:
|
||||||
resolution: {integrity: sha512-/5aW996nbolGh/qVU9urjAJ2QiXpiyGuhG8x/ZvvZQ3bMlrK+ouUdD6whS4e+sU9CCdUIzl7x/heEjsBh/3xtw==}
|
resolution: {integrity: sha512-/5aW996nbolGh/qVU9urjAJ2QiXpiyGuhG8x/ZvvZQ3bMlrK+ouUdD6whS4e+sU9CCdUIzl7x/heEjsBh/3xtw==}
|
||||||
|
|
||||||
@@ -5471,6 +5531,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==}
|
resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
is-url@1.2.4:
|
||||||
|
resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==}
|
||||||
|
|
||||||
is-weakmap@2.0.2:
|
is-weakmap@2.0.2:
|
||||||
resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
|
resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -5512,6 +5575,9 @@ packages:
|
|||||||
jackspeak@3.4.3:
|
jackspeak@3.4.3:
|
||||||
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
|
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
|
||||||
|
|
||||||
|
jay-peg@1.1.1:
|
||||||
|
resolution: {integrity: sha512-D62KEuBxz/ip2gQKOEhk/mx14o7eiFRaU+VNNSP4MOiIkwb/D6B3G1Mfas7C/Fit8EsSV2/IWjZElx/Gs6A4ww==}
|
||||||
|
|
||||||
jest-worker@27.5.1:
|
jest-worker@27.5.1:
|
||||||
resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
|
resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
|
||||||
engines: {node: '>= 10.13.0'}
|
engines: {node: '>= 10.13.0'}
|
||||||
@@ -5945,6 +6011,9 @@ packages:
|
|||||||
mdn-data@2.27.1:
|
mdn-data@2.27.1:
|
||||||
resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==}
|
resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==}
|
||||||
|
|
||||||
|
media-engine@1.0.3:
|
||||||
|
resolution: {integrity: sha512-aa5tG6sDoK+k70B9iEX1NeyfT8ObCKhNDs6lJVpwF6r8vhUfuKMslIcirq6HIUYuuUYLefcEQOn9bSBOvawtwg==}
|
||||||
|
|
||||||
media-typer@0.3.0:
|
media-typer@0.3.0:
|
||||||
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
|
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@@ -6285,6 +6354,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
normalize-svg-path@1.1.0:
|
||||||
|
resolution: {integrity: sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==}
|
||||||
|
|
||||||
npm-run-path@4.0.1:
|
npm-run-path@4.0.1:
|
||||||
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
|
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -6431,6 +6503,9 @@ packages:
|
|||||||
pako@0.2.9:
|
pako@0.2.9:
|
||||||
resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
|
resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
|
||||||
|
|
||||||
|
pako@1.0.11:
|
||||||
|
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
|
||||||
|
|
||||||
parent-module@1.0.1:
|
parent-module@1.0.1:
|
||||||
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -6449,6 +6524,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
parse-svg-path@0.1.2:
|
||||||
|
resolution: {integrity: sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==}
|
||||||
|
|
||||||
parse5-htmlparser2-tree-adapter@7.1.0:
|
parse5-htmlparser2-tree-adapter@7.1.0:
|
||||||
resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==}
|
resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==}
|
||||||
|
|
||||||
@@ -6572,6 +6650,9 @@ packages:
|
|||||||
png-js@1.0.0:
|
png-js@1.0.0:
|
||||||
resolution: {integrity: sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==}
|
resolution: {integrity: sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==}
|
||||||
|
|
||||||
|
png-js@2.0.0:
|
||||||
|
resolution: {integrity: sha512-GdzJuUMc6ZSpxFJWVxtOH1bzYHym+TOnveqUjb+VJIbZWbZzyiRGFiKhbiielfpYbgMlhHVhsJ0FTazfuRFkMA==}
|
||||||
|
|
||||||
po-parser@2.1.1:
|
po-parser@2.1.1:
|
||||||
resolution: {integrity: sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==}
|
resolution: {integrity: sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==}
|
||||||
|
|
||||||
@@ -6716,6 +6797,9 @@ packages:
|
|||||||
queue-microtask@1.2.3:
|
queue-microtask@1.2.3:
|
||||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||||
|
|
||||||
|
queue@6.0.2:
|
||||||
|
resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==}
|
||||||
|
|
||||||
quick-format-unescaped@4.0.4:
|
quick-format-unescaped@4.0.4:
|
||||||
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
|
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
|
||||||
|
|
||||||
@@ -7009,6 +7093,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
|
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
|
||||||
engines: {node: '>=v12.22.7'}
|
engines: {node: '>=v12.22.7'}
|
||||||
|
|
||||||
|
scheduler@0.25.0-rc-603e6108-20241029:
|
||||||
|
resolution: {integrity: sha512-pFwF6H1XrSdYYNLfOcGlM28/j8CGLu8IvdrxqhjWULe2bPcKiKW4CV+OWqR/9fT52mywx65l7ysNkjLKBda7eA==}
|
||||||
|
|
||||||
scheduler@0.27.0:
|
scheduler@0.27.0:
|
||||||
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
|
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
|
||||||
|
|
||||||
@@ -7282,6 +7369,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
|
resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
string_decoder@1.3.0:
|
||||||
|
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
||||||
|
|
||||||
stringify-entities@4.0.4:
|
stringify-entities@4.0.4:
|
||||||
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
|
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
|
||||||
|
|
||||||
@@ -7367,6 +7457,9 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: '>=17.0'
|
react: '>=17.0'
|
||||||
|
|
||||||
|
svg-arc-to-cubic-bezier@3.2.0:
|
||||||
|
resolution: {integrity: sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==}
|
||||||
|
|
||||||
svg-to-pdfkit@0.1.8:
|
svg-to-pdfkit@0.1.8:
|
||||||
resolution: {integrity: sha512-QItiGZBy5TstGy+q8mjQTMGRlDDOARXLxH+sgVm1n/LYeo0zFcQlcCh8m4zi8QxctrxB9Kue/lStc/RD5iLadQ==}
|
resolution: {integrity: sha512-QItiGZBy5TstGy+q8mjQTMGRlDDOARXLxH+sgVm1n/LYeo0zFcQlcCh8m4zi8QxctrxB9Kue/lStc/RD5iLadQ==}
|
||||||
|
|
||||||
@@ -7750,6 +7843,10 @@ packages:
|
|||||||
victory-vendor@37.3.6:
|
victory-vendor@37.3.6:
|
||||||
resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==}
|
resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==}
|
||||||
|
|
||||||
|
vite-compatible-readable-stream@3.6.1:
|
||||||
|
resolution: {integrity: sha512-t20zYkrSf868+j/p31cRIGN28Phrjm3nRSLR2fyc2tiWi4cZGVdv68yNlwnIINTkMTmPoMiSlc0OadaO7DXZaQ==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
vite@8.0.3:
|
vite@8.0.3:
|
||||||
resolution: {integrity: sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==}
|
resolution: {integrity: sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
@@ -8088,6 +8185,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==}
|
resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
yoga-layout@3.2.1:
|
||||||
|
resolution: {integrity: sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==}
|
||||||
|
|
||||||
zod-validation-error@4.0.2:
|
zod-validation-error@4.0.2:
|
||||||
resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==}
|
resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
@@ -10010,6 +10110,110 @@ snapshots:
|
|||||||
react: 19.2.4
|
react: 19.2.4
|
||||||
react-dom: 19.2.4(react@19.2.4)
|
react-dom: 19.2.4(react@19.2.4)
|
||||||
|
|
||||||
|
'@react-pdf/fns@3.1.3': {}
|
||||||
|
|
||||||
|
'@react-pdf/font@4.0.8':
|
||||||
|
dependencies:
|
||||||
|
'@react-pdf/pdfkit': 5.1.1
|
||||||
|
'@react-pdf/types': 2.11.1
|
||||||
|
fontkit: 2.0.4
|
||||||
|
is-url: 1.2.4
|
||||||
|
|
||||||
|
'@react-pdf/image@3.1.0':
|
||||||
|
dependencies:
|
||||||
|
'@react-pdf/svg': 1.1.0
|
||||||
|
jay-peg: 1.1.1
|
||||||
|
png-js: 2.0.0
|
||||||
|
|
||||||
|
'@react-pdf/layout@4.6.1':
|
||||||
|
dependencies:
|
||||||
|
'@react-pdf/fns': 3.1.3
|
||||||
|
'@react-pdf/image': 3.1.0
|
||||||
|
'@react-pdf/primitives': 4.3.0
|
||||||
|
'@react-pdf/stylesheet': 6.2.1
|
||||||
|
'@react-pdf/textkit': 6.3.0
|
||||||
|
'@react-pdf/types': 2.11.1
|
||||||
|
emoji-regex-xs: 1.0.0
|
||||||
|
queue: 6.0.2
|
||||||
|
yoga-layout: 3.2.1
|
||||||
|
|
||||||
|
'@react-pdf/pdfkit@5.1.1':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.29.2
|
||||||
|
'@noble/ciphers': 1.3.0
|
||||||
|
'@noble/hashes': 1.8.0
|
||||||
|
browserify-zlib: 0.2.0
|
||||||
|
fontkit: 2.0.4
|
||||||
|
jay-peg: 1.1.1
|
||||||
|
js-md5: 0.8.3
|
||||||
|
linebreak: 1.1.0
|
||||||
|
png-js: 2.0.0
|
||||||
|
vite-compatible-readable-stream: 3.6.1
|
||||||
|
|
||||||
|
'@react-pdf/primitives@4.3.0': {}
|
||||||
|
|
||||||
|
'@react-pdf/reconciler@2.0.0(react@19.2.4)':
|
||||||
|
dependencies:
|
||||||
|
object-assign: 4.1.1
|
||||||
|
react: 19.2.4
|
||||||
|
scheduler: 0.25.0-rc-603e6108-20241029
|
||||||
|
|
||||||
|
'@react-pdf/render@4.5.1':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.29.2
|
||||||
|
'@react-pdf/fns': 3.1.3
|
||||||
|
'@react-pdf/primitives': 4.3.0
|
||||||
|
'@react-pdf/textkit': 6.3.0
|
||||||
|
'@react-pdf/types': 2.11.1
|
||||||
|
abs-svg-path: 0.1.1
|
||||||
|
color-string: 2.1.4
|
||||||
|
normalize-svg-path: 1.1.0
|
||||||
|
parse-svg-path: 0.1.2
|
||||||
|
svg-arc-to-cubic-bezier: 3.2.0
|
||||||
|
|
||||||
|
'@react-pdf/renderer@4.5.1(react@19.2.4)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.29.2
|
||||||
|
'@react-pdf/fns': 3.1.3
|
||||||
|
'@react-pdf/font': 4.0.8
|
||||||
|
'@react-pdf/layout': 4.6.1
|
||||||
|
'@react-pdf/pdfkit': 5.1.1
|
||||||
|
'@react-pdf/primitives': 4.3.0
|
||||||
|
'@react-pdf/reconciler': 2.0.0(react@19.2.4)
|
||||||
|
'@react-pdf/render': 4.5.1
|
||||||
|
'@react-pdf/types': 2.11.1
|
||||||
|
events: 3.3.0
|
||||||
|
object-assign: 4.1.1
|
||||||
|
prop-types: 15.8.1
|
||||||
|
queue: 6.0.2
|
||||||
|
react: 19.2.4
|
||||||
|
|
||||||
|
'@react-pdf/stylesheet@6.2.1':
|
||||||
|
dependencies:
|
||||||
|
'@react-pdf/fns': 3.1.3
|
||||||
|
'@react-pdf/types': 2.11.1
|
||||||
|
color-string: 2.1.4
|
||||||
|
hsl-to-hex: 1.0.0
|
||||||
|
media-engine: 1.0.3
|
||||||
|
postcss-value-parser: 4.2.0
|
||||||
|
|
||||||
|
'@react-pdf/svg@1.1.0':
|
||||||
|
dependencies:
|
||||||
|
'@react-pdf/primitives': 4.3.0
|
||||||
|
|
||||||
|
'@react-pdf/textkit@6.3.0':
|
||||||
|
dependencies:
|
||||||
|
'@react-pdf/fns': 3.1.3
|
||||||
|
bidi-js: 1.0.3
|
||||||
|
hyphen: 1.14.1
|
||||||
|
unicode-properties: 1.4.1
|
||||||
|
|
||||||
|
'@react-pdf/types@2.11.1':
|
||||||
|
dependencies:
|
||||||
|
'@react-pdf/font': 4.0.8
|
||||||
|
'@react-pdf/primitives': 4.3.0
|
||||||
|
'@react-pdf/stylesheet': 6.2.1
|
||||||
|
|
||||||
'@react-three/drei@10.7.7(@react-three/fiber@9.5.0(@types/react@19.2.14)(immer@11.1.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(three@0.183.2))(@types/react@19.2.14)(@types/three@0.183.1)(immer@11.1.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(three@0.183.2)':
|
'@react-three/drei@10.7.7(@react-three/fiber@9.5.0(@types/react@19.2.14)(immer@11.1.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(three@0.183.2))(@types/react@19.2.14)(@types/three@0.183.1)(immer@11.1.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(three@0.183.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.29.2
|
'@babel/runtime': 7.29.2
|
||||||
@@ -10129,8 +10333,6 @@ snapshots:
|
|||||||
|
|
||||||
'@rolldown/pluginutils@1.0.0-rc.3': {}
|
'@rolldown/pluginutils@1.0.0-rc.3': {}
|
||||||
|
|
||||||
'@rolldown/pluginutils@1.0.1': {}
|
|
||||||
|
|
||||||
'@rollup/plugin-commonjs@28.0.1(rollup@4.60.1)':
|
'@rollup/plugin-commonjs@28.0.1(rollup@4.60.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rollup/pluginutils': 5.3.0(rollup@4.60.1)
|
'@rollup/pluginutils': 5.3.0(rollup@4.60.1)
|
||||||
@@ -11042,14 +11244,6 @@ snapshots:
|
|||||||
'@use-gesture/core': 10.3.1
|
'@use-gesture/core': 10.3.1
|
||||||
react: 19.2.4
|
react: 19.2.4
|
||||||
|
|
||||||
'@vitejs/plugin-react-swc@4.3.1(@swc/helpers@0.5.20)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@22.19.15)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))':
|
|
||||||
dependencies:
|
|
||||||
'@rolldown/pluginutils': 1.0.1
|
|
||||||
'@swc/core': 1.15.21(@swc/helpers@0.5.20)
|
|
||||||
vite: 8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@22.19.15)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- '@swc/helpers'
|
|
||||||
|
|
||||||
'@vitejs/plugin-react@5.2.0(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@22.19.15)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))':
|
'@vitejs/plugin-react@5.2.0(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@22.19.15)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.29.0
|
'@babel/core': 7.29.0
|
||||||
@@ -11198,6 +11392,8 @@ snapshots:
|
|||||||
|
|
||||||
abbrev@2.0.0: {}
|
abbrev@2.0.0: {}
|
||||||
|
|
||||||
|
abs-svg-path@0.1.1: {}
|
||||||
|
|
||||||
accepts@1.3.8:
|
accepts@1.3.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
mime-types: 2.1.35
|
mime-types: 2.1.35
|
||||||
@@ -11518,6 +11714,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
base64-js: 1.5.1
|
base64-js: 1.5.1
|
||||||
|
|
||||||
|
browserify-zlib@0.2.0:
|
||||||
|
dependencies:
|
||||||
|
pako: 1.0.11
|
||||||
|
|
||||||
browserslist@4.28.2:
|
browserslist@4.28.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
baseline-browser-mapping: 2.10.13
|
baseline-browser-mapping: 2.10.13
|
||||||
@@ -11732,6 +11932,12 @@ snapshots:
|
|||||||
|
|
||||||
color-name@1.1.4: {}
|
color-name@1.1.4: {}
|
||||||
|
|
||||||
|
color-name@2.1.0: {}
|
||||||
|
|
||||||
|
color-string@2.1.4:
|
||||||
|
dependencies:
|
||||||
|
color-name: 2.1.0
|
||||||
|
|
||||||
colorette@2.0.20: {}
|
colorette@2.0.20: {}
|
||||||
|
|
||||||
combined-stream@1.0.8:
|
combined-stream@1.0.8:
|
||||||
@@ -12209,6 +12415,8 @@ snapshots:
|
|||||||
|
|
||||||
electron-to-chromium@1.5.330: {}
|
electron-to-chromium@1.5.330: {}
|
||||||
|
|
||||||
|
emoji-regex-xs@1.0.0: {}
|
||||||
|
|
||||||
emoji-regex@10.6.0: {}
|
emoji-regex@10.6.0: {}
|
||||||
|
|
||||||
emoji-regex@8.0.0: {}
|
emoji-regex@8.0.0: {}
|
||||||
@@ -13261,6 +13469,12 @@ snapshots:
|
|||||||
|
|
||||||
hoopy@0.1.4: {}
|
hoopy@0.1.4: {}
|
||||||
|
|
||||||
|
hsl-to-hex@1.0.0:
|
||||||
|
dependencies:
|
||||||
|
hsl-to-rgb-for-reals: 1.1.1
|
||||||
|
|
||||||
|
hsl-to-rgb-for-reals@1.1.1: {}
|
||||||
|
|
||||||
html-encoding-sniffer@6.0.0(@noble/hashes@1.8.0):
|
html-encoding-sniffer@6.0.0(@noble/hashes@1.8.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@exodus/bytes': 1.15.0(@noble/hashes@1.8.0)
|
'@exodus/bytes': 1.15.0(@noble/hashes@1.8.0)
|
||||||
@@ -13359,6 +13573,8 @@ snapshots:
|
|||||||
|
|
||||||
husky@9.1.7: {}
|
husky@9.1.7: {}
|
||||||
|
|
||||||
|
hyphen@1.14.1: {}
|
||||||
|
|
||||||
i18next-fs-backend@2.6.3: {}
|
i18next-fs-backend@2.6.3: {}
|
||||||
|
|
||||||
i18next@25.10.10(typescript@5.9.3):
|
i18next@25.10.10(typescript@5.9.3):
|
||||||
@@ -13647,6 +13863,8 @@ snapshots:
|
|||||||
|
|
||||||
is-unicode-supported@2.1.0: {}
|
is-unicode-supported@2.1.0: {}
|
||||||
|
|
||||||
|
is-url@1.2.4: {}
|
||||||
|
|
||||||
is-weakmap@2.0.2: {}
|
is-weakmap@2.0.2: {}
|
||||||
|
|
||||||
is-weakref@1.1.1:
|
is-weakref@1.1.1:
|
||||||
@@ -13697,6 +13915,10 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@pkgjs/parseargs': 0.11.0
|
'@pkgjs/parseargs': 0.11.0
|
||||||
|
|
||||||
|
jay-peg@1.1.1:
|
||||||
|
dependencies:
|
||||||
|
restructure: 3.0.2
|
||||||
|
|
||||||
jest-worker@27.5.1:
|
jest-worker@27.5.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 22.19.15
|
'@types/node': 22.19.15
|
||||||
@@ -14245,6 +14467,8 @@ snapshots:
|
|||||||
|
|
||||||
mdn-data@2.27.1: {}
|
mdn-data@2.27.1: {}
|
||||||
|
|
||||||
|
media-engine@1.0.3: {}
|
||||||
|
|
||||||
media-typer@0.3.0: {}
|
media-typer@0.3.0: {}
|
||||||
|
|
||||||
meow@13.2.0: {}
|
meow@13.2.0: {}
|
||||||
@@ -14705,6 +14929,10 @@ snapshots:
|
|||||||
|
|
||||||
normalize-path@3.0.0: {}
|
normalize-path@3.0.0: {}
|
||||||
|
|
||||||
|
normalize-svg-path@1.1.0:
|
||||||
|
dependencies:
|
||||||
|
svg-arc-to-cubic-bezier: 3.2.0
|
||||||
|
|
||||||
npm-run-path@4.0.1:
|
npm-run-path@4.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
path-key: 3.1.1
|
path-key: 3.1.1
|
||||||
@@ -14915,6 +15143,8 @@ snapshots:
|
|||||||
|
|
||||||
pako@0.2.9: {}
|
pako@0.2.9: {}
|
||||||
|
|
||||||
|
pako@1.0.11: {}
|
||||||
|
|
||||||
parent-module@1.0.1:
|
parent-module@1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
callsites: 3.1.0
|
callsites: 3.1.0
|
||||||
@@ -14942,6 +15172,8 @@ snapshots:
|
|||||||
json-parse-even-better-errors: 2.3.1
|
json-parse-even-better-errors: 2.3.1
|
||||||
lines-and-columns: 1.2.4
|
lines-and-columns: 1.2.4
|
||||||
|
|
||||||
|
parse-svg-path@0.1.2: {}
|
||||||
|
|
||||||
parse5-htmlparser2-tree-adapter@7.1.0:
|
parse5-htmlparser2-tree-adapter@7.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
domhandler: 5.0.3
|
domhandler: 5.0.3
|
||||||
@@ -15084,6 +15316,10 @@ snapshots:
|
|||||||
|
|
||||||
png-js@1.0.0: {}
|
png-js@1.0.0: {}
|
||||||
|
|
||||||
|
png-js@2.0.0:
|
||||||
|
dependencies:
|
||||||
|
fflate: 0.8.2
|
||||||
|
|
||||||
po-parser@2.1.1: {}
|
po-parser@2.1.1: {}
|
||||||
|
|
||||||
possible-typed-array-names@1.1.0: {}
|
possible-typed-array-names@1.1.0: {}
|
||||||
@@ -15241,6 +15477,10 @@ snapshots:
|
|||||||
|
|
||||||
queue-microtask@1.2.3: {}
|
queue-microtask@1.2.3: {}
|
||||||
|
|
||||||
|
queue@6.0.2:
|
||||||
|
dependencies:
|
||||||
|
inherits: 2.0.4
|
||||||
|
|
||||||
quick-format-unescaped@4.0.4: {}
|
quick-format-unescaped@4.0.4: {}
|
||||||
|
|
||||||
range-parser@1.2.1: {}
|
range-parser@1.2.1: {}
|
||||||
@@ -15659,6 +15899,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
xmlchars: 2.2.0
|
xmlchars: 2.2.0
|
||||||
|
|
||||||
|
scheduler@0.25.0-rc-603e6108-20241029: {}
|
||||||
|
|
||||||
scheduler@0.27.0: {}
|
scheduler@0.27.0: {}
|
||||||
|
|
||||||
schema-dts@1.1.5: {}
|
schema-dts@1.1.5: {}
|
||||||
@@ -16047,6 +16289,10 @@ snapshots:
|
|||||||
define-properties: 1.2.1
|
define-properties: 1.2.1
|
||||||
es-object-atoms: 1.1.1
|
es-object-atoms: 1.1.1
|
||||||
|
|
||||||
|
string_decoder@1.3.0:
|
||||||
|
dependencies:
|
||||||
|
safe-buffer: 5.2.1
|
||||||
|
|
||||||
stringify-entities@4.0.4:
|
stringify-entities@4.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
character-entities-html4: 2.1.0
|
character-entities-html4: 2.1.0
|
||||||
@@ -16117,6 +16363,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
react: 19.2.4
|
react: 19.2.4
|
||||||
|
|
||||||
|
svg-arc-to-cubic-bezier@3.2.0: {}
|
||||||
|
|
||||||
svg-to-pdfkit@0.1.8:
|
svg-to-pdfkit@0.1.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
pdfkit: 0.18.0
|
pdfkit: 0.18.0
|
||||||
@@ -16585,6 +16833,12 @@ snapshots:
|
|||||||
d3-time: 3.1.0
|
d3-time: 3.1.0
|
||||||
d3-timer: 3.0.1
|
d3-timer: 3.0.1
|
||||||
|
|
||||||
|
vite-compatible-readable-stream@3.6.1:
|
||||||
|
dependencies:
|
||||||
|
inherits: 2.0.4
|
||||||
|
string_decoder: 1.3.0
|
||||||
|
util-deprecate: 1.0.2
|
||||||
|
|
||||||
vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@22.19.15)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3):
|
vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@22.19.15)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
lightningcss: 1.32.0
|
lightningcss: 1.32.0
|
||||||
@@ -16916,6 +17170,8 @@ snapshots:
|
|||||||
|
|
||||||
yoctocolors@2.1.2: {}
|
yoctocolors@2.1.2: {}
|
||||||
|
|
||||||
|
yoga-layout@3.2.1: {}
|
||||||
|
|
||||||
zod-validation-error@4.0.2(zod@3.25.76):
|
zod-validation-error@4.0.2(zod@3.25.76):
|
||||||
dependencies:
|
dependencies:
|
||||||
zod: 3.25.76
|
zod: 3.25.76
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 4.7 KiB |
BIN
public/assets/videos/web/hero-kabelpflug-poster-mobile.webp
Normal file
BIN
public/assets/videos/web/hero-kabelpflug-poster-mobile.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
BIN
public/assets/videos/web/hero-kabelpflug-poster.webp
Normal file
BIN
public/assets/videos/web/hero-kabelpflug-poster.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
@@ -96,7 +96,26 @@ module.exports = {
|
|||||||
'lg': '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
|
'lg': '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
|
||||||
'xl': '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
|
'xl': '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
|
||||||
},
|
},
|
||||||
|
container: {
|
||||||
|
center: true,
|
||||||
|
padding: {
|
||||||
|
DEFAULT: '1rem',
|
||||||
|
sm: '1.5rem',
|
||||||
|
md: '2rem',
|
||||||
|
lg: '2.5rem',
|
||||||
|
xl: '3rem',
|
||||||
|
'2xl': '4rem',
|
||||||
|
},
|
||||||
|
screens: {
|
||||||
|
xs: '475px',
|
||||||
|
sm: '640px',
|
||||||
|
md: '768px',
|
||||||
|
lg: '1024px',
|
||||||
|
xl: '1280px',
|
||||||
|
'2xl': '1400px',
|
||||||
|
'3xl': '1600px',
|
||||||
|
},
|
||||||
|
},
|
||||||
maxWidth: {
|
maxWidth: {
|
||||||
'xs': '20rem',
|
'xs': '20rem',
|
||||||
'sm': '24rem',
|
'sm': '24rem',
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
||||||
import { getAppServices } from '../lib/services/create-services';
|
|
||||||
import { GlitchtipErrorReportingService } from '../lib/services/errors/glitchtip-error-reporting-service';
|
|
||||||
|
|
||||||
// Mock config to ensure sentry is enabled
|
|
||||||
vi.mock('../lib/config', () => ({
|
|
||||||
config: {
|
|
||||||
analytics: { umami: { enabled: false } },
|
|
||||||
errors: { glitchtip: { enabled: true, dsn: 'https://test@glitchtip.infra.mintel.me/5' } },
|
|
||||||
logging: { level: 'info' },
|
|
||||||
notifications: { gotify: { enabled: false } },
|
|
||||||
},
|
|
||||||
getMaskedConfig: () => ({}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('AppServices (Client)', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
// Reset singleton
|
|
||||||
globalThis.__appServices = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should instantiate GlitchtipErrorReportingService when enabled', () => {
|
|
||||||
const services = getAppServices();
|
|
||||||
expect(services.errors).toBeInstanceOf(GlitchtipErrorReportingService);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -39,7 +39,7 @@ describe('Task 6 Content Updates', () => {
|
|||||||
|
|
||||||
// DE Home
|
// DE Home
|
||||||
expect(deContent).toContain('title: "Kabelleitungsnetzbau"');
|
expect(deContent).toContain('title: "Kabelleitungsnetzbau"');
|
||||||
expect(deContent).toContain('description: "Kabelleitungsnetzbau (Hoch-/Mittel- und Niederspannung) sowie Kabelmontagen bis 110 kV"');
|
expect(deContent).toContain('description: "Kabelleitungsnetzbau (Nieder-/Mittel- und Hochspannung bis 110 kV)"');
|
||||||
expect(deContent).toContain('100+');
|
expect(deContent).toContain('100+');
|
||||||
expect(deContent).toContain('Mitarbeitende');
|
expect(deContent).toContain('Mitarbeitende');
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ describe('Task 6 Content Updates', () => {
|
|||||||
expect(deContent).toContain('title: "Kabelleitungsnetzbau"');
|
expect(deContent).toContain('title: "Kabelleitungsnetzbau"');
|
||||||
expect(deContent).toContain('excerpt: "Professioneller Kabelleitungsnetzbau');
|
expect(deContent).toContain('excerpt: "Professioneller Kabelleitungsnetzbau');
|
||||||
expect(deContent).toContain('Kabelmontagen bis 110 kV');
|
expect(deContent).toContain('Kabelmontagen bis 110 kV');
|
||||||
expect(deContent).toContain('subtitle="Komplette Infrastruktur-Lösungen für Hoch-, Mittel- und Niederspannungsnetze sowie Kabelmontagen bis 110 kV"');
|
expect(deContent).toContain('subtitle="Komplette Infrastruktur-Lösungen für Nieder-, Mittel- und Hochspannungsnetze bis 110 kV"');
|
||||||
expect(deContent).toContain('"Kabelmontagen bis 110 kV"');
|
expect(deContent).toContain('"Kabelmontagen bis 110 kV"');
|
||||||
|
|
||||||
// EN Kabelnetzbau
|
// EN Kabelnetzbau
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ describe('Messen Content and Translations', () => {
|
|||||||
|
|
||||||
// 1. Intersolar München
|
// 1. Intersolar München
|
||||||
expect(content).toContain("name: 'Intersolar München'");
|
expect(content).toContain("name: 'Intersolar München'");
|
||||||
expect(content).toContain("date: '8. - 10. Juni 2027'");
|
expect(content).toContain("date: '23. - 25. Juni 2026'");
|
||||||
expect(content).toContain("type: 'Messe'");
|
expect(content).toContain("type: 'Messe'");
|
||||||
expect(content).toContain("location: 'München'");
|
expect(content).toContain("location: 'München'");
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ describe('Messen Content and Translations', () => {
|
|||||||
|
|
||||||
// 1. Intersolar Munich
|
// 1. Intersolar Munich
|
||||||
expect(content).toContain("name: 'Intersolar Munich'");
|
expect(content).toContain("name: 'Intersolar Munich'");
|
||||||
expect(content).toContain("date: 'June 8–10, 2027'");
|
expect(content).toContain("date: 'June 23–25, 2026'");
|
||||||
expect(content).toContain("type: 'Fair'");
|
expect(content).toContain("type: 'Fair'");
|
||||||
expect(content).toContain("location: 'Munich'");
|
expect(content).toContain("location: 'Munich'");
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import { readFileSync } from 'fs';
|
|
||||||
import { resolve } from 'path';
|
|
||||||
import { describe, it, expect } from 'vitest';
|
|
||||||
import * as dotenv from 'dotenv';
|
|
||||||
|
|
||||||
describe('Sentry Configuration', () => {
|
|
||||||
it('should have a valid SENTRY_DSN in .env', () => {
|
|
||||||
// Read the .env file as a string
|
|
||||||
const envPath = resolve(process.cwd(), '.env');
|
|
||||||
const envContent = readFileSync(envPath, 'utf8');
|
|
||||||
|
|
||||||
// Parse it using dotenv
|
|
||||||
const envConfig = dotenv.parse(envContent);
|
|
||||||
|
|
||||||
// Assert that SENTRY_DSN is defined and not empty
|
|
||||||
expect(envConfig.SENTRY_DSN).toBeDefined();
|
|
||||||
expect(envConfig.SENTRY_DSN.length).toBeGreaterThan(0);
|
|
||||||
expect(envConfig.SENTRY_DSN).toMatch(/^https:\/\/.+@(?:glitchtip|errors)\.infra\.mintel\.me\/\d+$/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { defineConfig } from 'vitest/config';
|
import { defineConfig } from 'vitest/config';
|
||||||
import react from '@vitejs/plugin-react-swc';
|
import react from '@vitejs/plugin-react';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
|
|||||||
Reference in New Issue
Block a user