Compare commits
19 Commits
v2.2.13-rc
...
feature/ta
| Author | SHA1 | Date | |
|---|---|---|---|
| d63f196693 | |||
| 6092f1d827 | |||
| 766c385704 | |||
| 6c9d2b6832 | |||
| 7a9d4d7f18 | |||
| 0b9929c2ec | |||
| aa0dfdf331 | |||
| 4c9028f58b | |||
| 9de5f2938b | |||
| de41a0e29d | |||
| 6689dd3013 | |||
| 31fbcb32dd | |||
| 68eca73df2 | |||
| 3bb6eb3447 | |||
| a3c732dd13 | |||
| aaa1a8793c | |||
| 233509db67 | |||
| 17a807c48b | |||
| d8634efa9a |
1
.turbo/41698960411f6bf6-manifest.json
Normal file
1
.turbo/41698960411f6bf6-manifest.json
Normal file
@@ -0,0 +1 @@
|
||||
{"files":{".turbo/turbo-test.log":{"size":2776,"mtime_nanos":1781469605328811961,"mode":420,"is_dir":false}},"order":[".turbo/turbo-test.log"]}
|
||||
1
.turbo/41698960411f6bf6-meta.json
Normal file
1
.turbo/41698960411f6bf6-meta.json
Normal file
@@ -0,0 +1 @@
|
||||
{"hash":"41698960411f6bf6","duration":4168,"sha":"a3c732dd133b1b8261b19cf64b3bf684e269e839","dirty_hash":"1ef3b75af417f41468b9558671572e75e0fc055f9dbe6e805cfa6f59b1cddf70"}
|
||||
BIN
.turbo/41698960411f6bf6.tar.zst
Normal file
BIN
.turbo/41698960411f6bf6.tar.zst
Normal file
Binary file not shown.
1
.turbo/bb46018d4a7bc516-manifest.json
Normal file
1
.turbo/bb46018d4a7bc516-manifest.json
Normal file
@@ -0,0 +1 @@
|
||||
{"files":{".turbo/turbo-lint.log":{"size":12987,"mtime_nanos":1781469609469080321,"mode":420,"is_dir":false}},"order":[".turbo/turbo-lint.log"]}
|
||||
1
.turbo/bb46018d4a7bc516-meta.json
Normal file
1
.turbo/bb46018d4a7bc516-meta.json
Normal file
@@ -0,0 +1 @@
|
||||
{"hash":"bb46018d4a7bc516","duration":8307,"sha":"a3c732dd133b1b8261b19cf64b3bf684e269e839","dirty_hash":"1ef3b75af417f41468b9558671572e75e0fc055f9dbe6e805cfa6f59b1cddf70"}
|
||||
BIN
.turbo/bb46018d4a7bc516.tar.zst
Normal file
BIN
.turbo/bb46018d4a7bc516.tar.zst
Normal file
Binary file not shown.
1
.turbo/eb4eeeb717c1af0c-manifest.json
Normal file
1
.turbo/eb4eeeb717c1af0c-manifest.json
Normal file
@@ -0,0 +1 @@
|
||||
{"files":{".turbo/turbo-typecheck.log":{"size":85,"mtime_nanos":1781469608726900998,"mode":420,"is_dir":false}},"order":[".turbo/turbo-typecheck.log"]}
|
||||
1
.turbo/eb4eeeb717c1af0c-meta.json
Normal file
1
.turbo/eb4eeeb717c1af0c-meta.json
Normal file
@@ -0,0 +1 @@
|
||||
{"hash":"eb4eeeb717c1af0c","duration":7565,"sha":"a3c732dd133b1b8261b19cf64b3bf684e269e839","dirty_hash":"1ef3b75af417f41468b9558671572e75e0fc055f9dbe6e805cfa6f59b1cddf70"}
|
||||
BIN
.turbo/eb4eeeb717c1af0c.tar.zst
Normal file
BIN
.turbo/eb4eeeb717c1af0c.tar.zst
Normal file
Binary file not shown.
@@ -2,128 +2,4 @@
|
||||
> e-tib-nextjs@2.2.12 lint /Volumes/Alpha SSD/Coding/e-tib.com
|
||||
> eslint .
|
||||
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/app/[locale]/[slug]/page.tsx
|
||||
1:20 warning 'redirect' is defined but never used @typescript-eslint/no-unused-vars
|
||||
75:24 warning Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/app/[locale]/blog/[slug]/page.tsx
|
||||
1:20 warning 'redirect' is defined but never used @typescript-eslint/no-unused-vars
|
||||
39:24 warning Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/app/[locale]/error.tsx
|
||||
7:30 warning 'AlertTriangle' is defined but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/app/[locale]/not-found.tsx
|
||||
6:10 warning 'Terminal' is defined but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/app/[locale]/referenzen/[slug]/page.tsx
|
||||
92:26 warning Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/app/[locale]/referenzen/page.tsx
|
||||
1:21 warning 'Heading' is defined but never used @typescript-eslint/no-unused-vars
|
||||
1:30 warning 'Badge' is defined but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/JsonLd.tsx
|
||||
1:30 warning 'Graph' is defined but never used @typescript-eslint/no-unused-vars
|
||||
43:31 warning '_' is assigned a value but never used @typescript-eslint/no-unused-vars
|
||||
48:29 warning '_' is assigned a value but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/blocks/CertificatesBlock.tsx
|
||||
6:10 warning 'Button' is defined but never used @typescript-eslint/no-unused-vars
|
||||
9:10 warning 'FileText' is defined but never used @typescript-eslint/no-unused-vars
|
||||
102:5 warning Error: Calling setState synchronously within an effect can trigger cascading renders
|
||||
|
||||
Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:
|
||||
* Update external systems with the latest state from React.
|
||||
* Subscribe for updates from some external system, calling setState in a callback function when external state changes.
|
||||
|
||||
Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect).
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/blocks/CertificatesBlock.tsx:102:5
|
||||
100 |
|
||||
101 | useEffect(() => {
|
||||
> 102 | setIsMounted(true);
|
||||
| ^^^^^^^^^^^^ Avoid calling setState() directly within an effect
|
||||
103 | }, []);
|
||||
104 |
|
||||
105 | const badgeText = badge || 'Zertifizierungen & Nachweise'; react-hooks/set-state-in-effect
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/blocks/CompetenceBentoGrid.tsx
|
||||
53:5 warning Error: Calling setState synchronously within an effect can trigger cascading renders
|
||||
|
||||
Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:
|
||||
* Update external systems with the latest state from React.
|
||||
* Subscribe for updates from some external system, calling setState in a callback function when external state changes.
|
||||
|
||||
Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect).
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/blocks/CompetenceBentoGrid.tsx:53:5
|
||||
51 |
|
||||
52 | useEffect(() => {
|
||||
> 53 | setIsMounted(true);
|
||||
| ^^^^^^^^^^^^ Avoid calling setState() directly within an effect
|
||||
54 | }, []);
|
||||
55 |
|
||||
56 | const badge = props.badge || data?.badge || 'Leistungsspektrum'; react-hooks/set-state-in-effect
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/blocks/HeroVideo.tsx
|
||||
5:18 warning 'AnimatePresence' is defined but never used @typescript-eslint/no-unused-vars
|
||||
6:10 warning 'useState' is defined but never used @typescript-eslint/no-unused-vars
|
||||
6:20 warning 'useEffect' is defined but never used @typescript-eslint/no-unused-vars
|
||||
45:12 warning 'e' is defined but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/blocks/InteractiveGermanyMap.tsx
|
||||
5:18 warning 'Factory' is defined but never used @typescript-eslint/no-unused-vars
|
||||
5:27 warning 'Zap' is defined but never used @typescript-eslint/no-unused-vars
|
||||
53:9 warning 'hq' is assigned a value but never used @typescript-eslint/no-unused-vars
|
||||
54:9 warning 'branch' is assigned a value but never used @typescript-eslint/no-unused-vars
|
||||
55:9 warning 'projects' is assigned a value but never used @typescript-eslint/no-unused-vars
|
||||
56:9 warning 'minorNodes' is assigned a value but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/blocks/ReferencesSlider.test.tsx
|
||||
5:10 warning 'NextIntlClientProvider' is defined but never used @typescript-eslint/no-unused-vars
|
||||
21:12 warning Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/blocks/TeamGridBlock.tsx
|
||||
20:39 warning 'title' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars
|
||||
20:46 warning 'department' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars
|
||||
20:58 warning 'showContact' is assigned a value but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/decorations/CorporateBackground.tsx
|
||||
36:13 warning 'distance' is assigned a value but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/home/Hero.tsx
|
||||
9:39 warning 'useCallback' is defined but never used @typescript-eslint/no-unused-vars
|
||||
77:6 warning React Hook useEffect has missing dependencies: 'HERO_PLACEHOLDERS' and 't'. Either include them or remove the dependency array react-hooks/exhaustive-deps
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/home/MeetTheTeam.tsx
|
||||
8:9 warning 'teamT' is assigned a value but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/layout/Footer.tsx
|
||||
4:35 warning 'Accessibility' is defined but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/providers/InitialLoader.tsx
|
||||
5:8 warning 'Image' is defined but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/providers/PageTransitionShutter.tsx
|
||||
6:8 warning 'Image' is defined but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/search/AIOrb.tsx
|
||||
153:13 warning 'breathe' is assigned a value but never used @typescript-eslint/no-unused-vars
|
||||
212:15 warning 'targetExcite' is assigned a value but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/search/AISearchResults.tsx
|
||||
100:6 warning React Hook useEffect has missing dependencies: 'handleSearch' and 'initialQuery'. Either include them or remove the dependency array react-hooks/exhaustive-deps
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/components/ui/AnimatedCounter.tsx
|
||||
3:28 warning 'useState' is defined but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
/Volumes/Alpha SSD/Coding/e-tib.com/lib/blog.ts
|
||||
6:7 warning 'BLOG_DIR' is assigned a value but never used @typescript-eslint/no-unused-vars
|
||||
94:7 warning 'next' is never reassigned. Use 'const' instead prefer-const
|
||||
95:7 warning 'prev' is never reassigned. Use 'const' instead prefer-const
|
||||
|
||||
✖ 45 problems (0 errors, 45 warnings)
|
||||
0 errors and 2 warnings potentially fixable with the `--fix` option.
|
||||
|
||||
ELIFECYCLE Command failed.
|
||||
|
||||
@@ -5,27 +5,51 @@
|
||||
|
||||
[1m[46m RUN [49m[22m [36mv4.1.2 [39m[90m/Volumes/Alpha SSD/Coding/e-tib.com[39m
|
||||
|
||||
[32m✓[39m tests/mdx-links.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 4[2mms[22m[39m
|
||||
[32m✓[39m lib/mail/mailer.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 2[2mms[22m[39m
|
||||
[32m✓[39m lib/env.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
||||
(node:64961) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead.
|
||||
(Use `node --trace-deprecation ...` to show where the warning was created)
|
||||
[32m✓[39m tests/mdx-links.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 29[2mms[22m[39m
|
||||
[32m✓[39m tests/homepage-and-competence-content.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 14[2mms[22m[39m
|
||||
[31m❯[39m tests/legal-pages.test.ts [2m([22m[2m2 tests[22m[2m | [22m[31m1 failed[39m[2m)[22m[32m 9[2mms[22m[39m
|
||||
[32m✓[39m should contain highly professional B2B sections in German AGB[32m 5[2mms[22m[39m
|
||||
[31m [31m×[31m should contain professional corresponding B2B sections in English Terms[39m[32m 2[2mms[22m[39m
|
||||
[32m✓[39m tests/task-12-links.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
||||
[32m✓[39m tests/messen-content.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
||||
[32m✓[39m lib/mail/mailer.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 7[2mms[22m[39m
|
||||
[90mstderr[2m | components/layout/LanguageSwitcher.test.tsx[2m > [22m[2mLanguageSwitcher TDD[2m > [22m[2mtranslates /en/trade-fairs to /de/messen when switching to German
|
||||
[22m[39mReact does not recognize the `transitionMessage` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `transitionmessage` instead. If you accidentally passed it from a parent component, remove it from the DOM element.
|
||||
|
||||
[32m✓[39m components/layout/LanguageSwitcher.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 21[2mms[22m[39m
|
||||
[32m✓[39m components/search/AISearchResults.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m 26[2mms[22m[39m
|
||||
[32m✓[39m components/layout/LanguageSwitcher.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 25[2mms[22m[39m
|
||||
[32m✓[39m components/search/AISearchResults.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m 52[2mms[22m[39m
|
||||
[90mstderr[2m | components/blocks/ReferencesSlider.test.tsx[2m > [22m[2mReferencesSlider TDD[2m > [22m[2mrenders reference tiles correctly
|
||||
[22m[39mReceived `true` for a non-boolean attribute `fill`.
|
||||
|
||||
If you want to write it to the DOM, pass a string instead: fill="true" or fill={value.toString()}.
|
||||
|
||||
[32m✓[39m components/blocks/ReferencesSlider.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 40[2mms[22m[39m
|
||||
[32m✓[39m components/blocks/ReferencesSlider.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 43[2mms[22m[39m
|
||||
[32m✓[39m lib/env.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
||||
[90mstdout[2m | app/[locale]/referenzen/[slug]/page.test.tsx
|
||||
[22m[39m[Config] Initializing Toggles: { feedbackEnabled: [33mfalse[39m }
|
||||
|
||||
[32m✓[39m app/[locale]/referenzen/[slug]/page.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m 6[2mms[22m[39m
|
||||
[32m✓[39m app/[locale]/referenzen/[slug]/page.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m 26[2mms[22m[39m
|
||||
|
||||
[2m Test Files [22m [1m[32m7 passed[39m[22m[90m (7)[39m
|
||||
[2m Tests [22m [1m[32m19 passed[39m[22m[90m (19)[39m
|
||||
[2m Start at [22m 14:12:48
|
||||
[2m Duration [22m 1.80s[2m (transform 863ms, setup 0ms, import 2.94s, tests 105ms, environment 3.18s)[22m
|
||||
[31m⎯⎯⎯⎯⎯⎯⎯[39m[1m[41m Failed Tests 1 [49m[22m[31m⎯⎯⎯⎯⎯⎯⎯[39m
|
||||
|
||||
[41m[1m FAIL [22m[49m tests/legal-pages.test.ts[2m > [22mLegal Pages Content Validation[2m > [22mshould contain professional corresponding B2B sections in English Terms
|
||||
[31m[1mError[22m: ENOENT: no such file or directory, open '/Volumes/Alpha SSD/Coding/e-tib.com/content/en/terms.mdx'[39m
|
||||
[36m [2m❯[22m tests/legal-pages.test.ts:[2m25:24[22m[39m
|
||||
[90m 23|[39m
|
||||
[90m 24|[39m it('should contain professional corresponding B2B sections in Englis…
|
||||
[90m 25|[39m [35mconst[39m content [33m=[39m fs[33m.[39m[34mreadFileSync[39m(enTermsPath[33m,[39m [32m'utf8'[39m)[33m;[39m
|
||||
[90m |[39m [31m^[39m
|
||||
[90m 26|[39m
|
||||
[90m 27|[39m [34mexpect[39m(content)[33m.[39m[34mtoContain[39m([32m'title: "Terms and Conditions"'[39m)[33m;[39m
|
||||
|
||||
[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯[22m[39m
|
||||
|
||||
|
||||
[2m Test Files [22m [1m[31m1 failed[39m[22m[2m | [22m[1m[32m10 passed[39m[22m[90m (11)[39m
|
||||
[2m Tests [22m [1m[31m1 failed[39m[22m[2m | [22m[1m[32m26 passed[39m[22m[90m (27)[39m
|
||||
[2m Start at [22m 14:54:33
|
||||
[2m Duration [22m 5.94s[2m (transform 5.27s, setup 0ms, import 9.43s, tests 222ms, environment 13.80s)[22m
|
||||
|
||||
ELIFECYCLE Test failed. See above for more details.
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
> e-tib-nextjs@2.2.12 typecheck /Volumes/Alpha SSD/Coding/e-tib.com
|
||||
> tsc --noEmit
|
||||
|
||||
ELIFECYCLE Command failed.
|
||||
|
||||
BIN
after-login.png
Normal file
BIN
after-login.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 274 KiB |
@@ -10,7 +10,6 @@ import TrackedLink from '@/components/analytics/TrackedLink';
|
||||
import { getButtonClasses, ButtonOverlay } from '@/components/ui/Button';
|
||||
import { getAllReferences } from '@/lib/references';
|
||||
import { defaultLocations, minorLocations } from '@/lib/map-data';
|
||||
|
||||
// Import components used in MDX
|
||||
import { HeroVideo as HomeHero } from '@/components/blocks/HeroVideo';
|
||||
import { SubCompanyTiles as HomeSubCompanyTiles } from '@/components/blocks/SubCompanyTiles';
|
||||
|
||||
@@ -93,13 +93,18 @@ export default async function Layout(props: {
|
||||
children: [
|
||||
{ label: safeLocale === 'de' ? 'Firma' : 'Company', url: `/${safeLocale}/${await mapFileSlugToTranslated('ueber-uns', safeLocale)}` },
|
||||
{ label: safeLocale === 'de' ? 'Unser Team' : 'Our Team', url: `/${safeLocale}/team` },
|
||||
{ label: safeLocale === 'de' ? 'Zertifikate' : 'Certificates', url: `/${safeLocale}/zertifikate` }
|
||||
{ label: safeLocale === 'de' ? 'Zertifikate' : 'Certificates', url: `/${safeLocale}/zertifikate` },
|
||||
{ label: safeLocale === 'de' ? 'Standorte' : 'Locations', url: `/${safeLocale}/standorte` }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: safeLocale === 'de' ? 'Referenzen' : 'References',
|
||||
url: `/${safeLocale}/referenzen`
|
||||
},
|
||||
{
|
||||
label: safeLocale === 'de' ? 'Karriere' : 'Career',
|
||||
url: `/${safeLocale}/${safeLocale === 'de' ? 'karriere' : 'career'}`
|
||||
},
|
||||
{
|
||||
label: safeLocale === 'de' ? 'Messen' : 'Events',
|
||||
url: `/${safeLocale}/${await mapFileSlugToTranslated('messen', safeLocale)}`
|
||||
|
||||
187
app/[locale]/standorte/[slug]/page.tsx
Normal file
187
app/[locale]/standorte/[slug]/page.tsx
Normal file
@@ -0,0 +1,187 @@
|
||||
import { Container, Badge, Heading } from '@/components/ui';
|
||||
import { getTranslations, setRequestLocale } from 'next-intl/server';
|
||||
import { Metadata } from 'next';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { standorteData, getStandortById } from '@/lib/standorte-data';
|
||||
import { SITE_URL } from '@/lib/schema';
|
||||
import Image from 'next/image';
|
||||
import { MapPin, Phone, Mail, Navigation, CheckCircle2, ArrowUpRight } from 'lucide-react';
|
||||
import { getButtonClasses, ButtonOverlay } from '@/components/ui/Button';
|
||||
import TrackedLink from '@/components/analytics/TrackedLink';
|
||||
import { AnimatedGlossyBorder } from '@/components/ui/AnimatedGlossyBorder';
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{
|
||||
locale: string;
|
||||
slug: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const locales = ['de', 'en'];
|
||||
const params: { locale: string; slug: string }[] = [];
|
||||
|
||||
for (const locale of locales) {
|
||||
for (const standort of standorteData) {
|
||||
params.push({ locale, slug: standort.id });
|
||||
}
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
|
||||
const { locale, slug } = await params;
|
||||
if (locale !== 'de' && locale !== 'en') return {};
|
||||
|
||||
const standort = getStandortById(slug);
|
||||
if (!standort) return {};
|
||||
|
||||
return {
|
||||
title: `${standort.name} | E-TIB Gruppe`,
|
||||
description: standort.description[locale],
|
||||
alternates: {
|
||||
canonical: `${SITE_URL}/${locale}/standorte/${slug}`,
|
||||
languages: {
|
||||
de: `${SITE_URL}/de/standorte/${slug}`,
|
||||
en: `${SITE_URL}/en/standorte/${slug}`,
|
||||
'x-default': `${SITE_URL}/en/standorte/${slug}`,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default async function StandortDetail(props: { params: Promise<{ locale: string; slug: string }> }) {
|
||||
const { locale, slug } = await props.params;
|
||||
const safeLocale = locale === 'de' ? 'de' : 'en';
|
||||
setRequestLocale(safeLocale);
|
||||
const t = await getTranslations('StandardPage');
|
||||
|
||||
const standort = getStandortById(slug);
|
||||
if (!standort) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col min-h-screen bg-white">
|
||||
{/* Generic Hero Section to match standard pages */}
|
||||
<section className="bg-primary-dark text-white pt-40 pb-12 md:pt-56 md:pb-16 min-h-[40vh] md:min-h-[45vh] flex flex-col justify-end relative overflow-hidden">
|
||||
<div className="absolute inset-0 opacity-20 pointer-events-none">
|
||||
<div className="absolute top-0 left-0 w-full h-full bg-[radial-gradient(circle_at_center,_var(--tw-gradient-stops))] from-accent/50 via-transparent to-transparent" />
|
||||
</div>
|
||||
<Container className="relative z-10">
|
||||
<div className="max-w-4xl">
|
||||
<Badge variant="accent" className="mb-4 md:mb-6 shadow-sm flex inline-flex items-center gap-2">
|
||||
<MapPin className="w-4 h-4" />
|
||||
{standort.type === 'hq' ? (safeLocale === 'de' ? 'Hauptsitz' : 'Headquarters') : (safeLocale === 'de' ? 'Niederlassung' : 'Branch')}
|
||||
</Badge>
|
||||
<Heading level={1} variant="white" className="mb-0 drop-shadow-sm">
|
||||
{standort.name}
|
||||
</Heading>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
|
||||
{/* Main Content Area */}
|
||||
<Container className="py-16 md:py-24">
|
||||
{/* Excerpt/Lead paragraph */}
|
||||
<div className="mb-16 max-w-4xl mx-auto">
|
||||
<p className="text-xl md:text-2xl text-text-primary leading-relaxed font-medium border-l-4 border-primary pl-8 py-2 italic">
|
||||
{standort.description[safeLocale]}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Main content in prose style */}
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="prose prose-lg md:prose-xl prose-neutral max-w-none prose-headings:font-heading prose-headings:font-bold prose-headings:tracking-tight prose-h1:text-4xl prose-h2:text-3xl prose-h2:mt-12 prose-h2:border-b prose-h2:border-neutral-200 prose-h2:pb-4 prose-h3:text-2xl prose-p:text-text-secondary prose-p:leading-relaxed prose-a:text-primary prose-a:font-medium prose-a:underline prose-a:underline-offset-4 prose-a:decoration-primary/30 hover:prose-a:decoration-primary prose-strong:text-text-primary prose-strong:font-semibold prose-li:text-text-secondary prose-ul:list-disc prose-ol:list-decimal">
|
||||
|
||||
<img className="rounded-2xl shadow-2xl my-12 max-w-full h-auto border border-neutral-100" src={standort.image} alt={standort.name} />
|
||||
|
||||
<h2 className="mt-16 mb-6 border-b border-neutral-100 pb-4">{safeLocale === 'de' ? 'Unsere Leistungen vor Ort' : 'Our Local Services'}</h2>
|
||||
<ul className="list-none mb-8 space-y-3 text-base md:text-lg text-text-secondary font-medium max-w-3xl">
|
||||
{standort.keyFeatures[safeLocale].map((feature, idx) => (
|
||||
<li key={idx} className="relative pl-6 before:content-[''] before:absolute before:left-0 before:top-[0.6em] before:w-2 before:h-2 before:bg-primary/50 before:rounded-sm">
|
||||
{feature}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<h2 className="mt-16 mb-6 border-b border-neutral-100 pb-4">{safeLocale === 'de' ? 'Kontakt & Anfahrt' : 'Contact & Directions'}</h2>
|
||||
|
||||
<p className="text-base md:text-lg text-text-secondary leading-[1.8] mb-6 font-medium max-w-3xl">
|
||||
<strong>{safeLocale === 'de' ? 'Adresse:' : 'Address:'}</strong><br/>
|
||||
{standort.address.street}<br/>
|
||||
{standort.address.city}
|
||||
</p>
|
||||
<p className="text-base md:text-lg text-text-secondary leading-[1.8] mb-6 font-medium max-w-3xl">
|
||||
<TrackedLink
|
||||
href={`https://maps.google.com/?q=${encodeURIComponent(`${standort.address.street}, ${standort.address.city}`)}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:text-primary-dark underline decoration-primary/30 underline-offset-4 hover:decoration-primary transition-all font-bold flex items-center gap-1 w-fit"
|
||||
eventProperties={{ location: 'standort_maps_link', slug: standort.id }}
|
||||
>
|
||||
{safeLocale === 'de' ? 'In Google Maps öffnen' : 'Open in Google Maps'}
|
||||
<ArrowUpRight className="w-4 h-4 inline-block" />
|
||||
</TrackedLink>
|
||||
</p>
|
||||
|
||||
<p className="text-base md:text-lg text-text-secondary leading-[1.8] mb-6 font-medium max-w-3xl">
|
||||
<strong>{safeLocale === 'de' ? 'Telefon:' : 'Phone:'}</strong><br/>
|
||||
<a href={`tel:${standort.contact.phone.replace(/[^0-9+]/g, '')}`} className="text-primary hover:text-primary-dark underline decoration-primary/30 underline-offset-4 hover:decoration-primary transition-all font-bold">
|
||||
{standort.contact.phone}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p className="text-base md:text-lg text-text-secondary leading-[1.8] mb-6 font-medium max-w-3xl">
|
||||
<strong>Email:</strong><br/>
|
||||
<a href={`mailto:${standort.contact.email}`} className="text-primary hover:text-primary-dark underline decoration-primary/30 underline-offset-4 hover:decoration-primary transition-all font-bold">
|
||||
{standort.contact.email}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
{standort.gallery && standort.gallery.length > 0 && (
|
||||
<>
|
||||
<h2 className="mt-16 mb-6 border-b border-neutral-100 pb-4">Galerie</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 not-prose my-12">
|
||||
{standort.gallery.map((img, idx) => (
|
||||
<div key={idx} className="relative aspect-[4/3] rounded-2xl overflow-hidden bg-neutral-100 border border-neutral-200 shadow-md hover:shadow-xl transition-shadow duration-300">
|
||||
<Image src={img} alt={`Gallery ${idx + 1}`} fill className="object-cover transition-transform duration-700 hover:scale-105" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
|
||||
{/* Support Section */}
|
||||
<Container>
|
||||
<div className="mt-12 mb-24 p-8 md:p-12 bg-primary-dark rounded-3xl text-white shadow-2xl relative overflow-hidden group animate-slight-fade-in-from-bottom">
|
||||
<div className="absolute top-0 right-0 w-64 h-full bg-accent/5 -skew-x-12 translate-x-1/2 transition-transform group-hover:translate-x-1/3" />
|
||||
<div className="relative z-10 max-w-2xl">
|
||||
<h3 className="text-2xl md:text-3xl font-bold mb-4">{t('needHelp')}</h3>
|
||||
<p className="text-lg text-white/70 mb-8">{t('supportTeamAvailable')}</p>
|
||||
<TrackedLink
|
||||
href={`/${locale}/${locale === 'de' ? 'kontakt' : 'contact'}`}
|
||||
className={getButtonClasses('accent', 'lg')}
|
||||
eventProperties={{
|
||||
location: 'standort_page_support_cta',
|
||||
page_slug: slug,
|
||||
}}
|
||||
>
|
||||
<span className="relative z-10 flex items-center justify-center gap-2 transition-colors duration-500 group-hover/btn:text-primary-dark">
|
||||
{t('contactUs')}
|
||||
<span className="ml-2 transition-transform group-hover/btn:translate-x-1">
|
||||
→
|
||||
</span>
|
||||
</span>
|
||||
<ButtonOverlay variant="accent" />
|
||||
</TrackedLink>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
142
app/[locale]/standorte/page.tsx
Normal file
142
app/[locale]/standorte/page.tsx
Normal file
@@ -0,0 +1,142 @@
|
||||
import { Container } from '@/components/ui';
|
||||
import { getTranslations, setRequestLocale } from 'next-intl/server';
|
||||
import { Metadata } from 'next';
|
||||
import TrackedLink from '@/components/analytics/TrackedLink';
|
||||
import { MapPin, Navigation, ArrowUpRight } from 'lucide-react';
|
||||
import { getButtonClasses, ButtonOverlay } from '@/components/ui/Button';
|
||||
import { SITE_URL } from '@/lib/schema';
|
||||
import Image from 'next/image';
|
||||
import { standorteData, standorteLocations } from '@/lib/standorte-data';
|
||||
import { InteractiveGermanyMap } from '@/components/blocks/InteractiveGermanyMap';
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{
|
||||
locale: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }): Promise<Metadata> {
|
||||
const { locale } = await params;
|
||||
const safeLocale = locale === 'de' ? 'de' : 'en';
|
||||
|
||||
return {
|
||||
title: safeLocale === 'en' ? 'Our Locations' : 'Unsere Standorte',
|
||||
description: safeLocale === 'en' ? 'Our operational locations across Germany.' : 'Unsere operativen Standorte deutschlandweit.',
|
||||
alternates: {
|
||||
canonical: `${SITE_URL}/${safeLocale}/standorte`,
|
||||
languages: {
|
||||
de: `${SITE_URL}/de/standorte`,
|
||||
en: `${SITE_URL}/en/standorte`,
|
||||
'x-default': `${SITE_URL}/en/standorte`,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default async function StandorteOverview(props: { params: Promise<{ locale: string }> }) {
|
||||
const { locale } = await props.params;
|
||||
const safeLocale = locale === 'de' ? 'de' : 'en';
|
||||
setRequestLocale(safeLocale);
|
||||
const t = await getTranslations('StandardPage');
|
||||
|
||||
return (
|
||||
<div className="flex flex-col min-h-screen bg-neutral-50 pb-16 md:pb-24">
|
||||
{/* Map Hero Section */}
|
||||
<InteractiveGermanyMap
|
||||
isHero={true}
|
||||
locations={standorteLocations}
|
||||
badge={safeLocale === 'en' ? 'Our Locations' : 'Unsere Standorte'}
|
||||
title={safeLocale === 'en' ? 'Nationwide operational for you.' : 'Deutschlandweit für Sie im Einsatz.'}
|
||||
description={safeLocale === 'en'
|
||||
? 'From our strategic locations in Guben, Kirchheilingen and Bülstedt, we control and implement complex infrastructure projects nationwide.'
|
||||
: 'Von unseren strategischen Standorten in Guben, Kirchheilingen und Bülstedt steuern und realisieren wir komplexe Infrastrukturprojekte im gesamten Bundesgebiet.'}
|
||||
/>
|
||||
|
||||
{/* Main Content Area */}
|
||||
<Container className="relative z-20 mt-16 md:mt-24">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 md:gap-8">
|
||||
{standorteData.map((standort) => (
|
||||
<TrackedLink
|
||||
key={standort.id}
|
||||
href={`/${safeLocale}/standorte/${standort.id}`}
|
||||
eventProperties={{ location: 'standorte_list_card', slug: standort.id }}
|
||||
className="group flex flex-col bg-white border border-neutral-100 rounded-3xl overflow-hidden shadow-sm hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1 cursor-pointer block"
|
||||
>
|
||||
<div className="flex flex-col h-full relative">
|
||||
{/* Image Section */}
|
||||
<div className="relative h-64 w-full bg-[#050B14] overflow-hidden shrink-0 border-b border-neutral-100">
|
||||
<Image
|
||||
src={standort.image}
|
||||
alt={standort.name}
|
||||
fill
|
||||
className="object-cover transition-transform duration-1000 ease-[cubic-bezier(0.16,1,0.3,1)] filter grayscale-[20%] group-hover:scale-105 group-hover:grayscale-0"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/10 transition-colors duration-500" />
|
||||
|
||||
{/* Location Badge */}
|
||||
<div className="absolute top-4 left-4 z-10">
|
||||
<span className="bg-white/95 backdrop-blur-md text-neutral-dark px-3 py-1.5 rounded-sm text-[10px] font-bold uppercase tracking-widest flex items-center gap-1.5 shadow-sm border border-neutral-200">
|
||||
<MapPin className="w-3 h-3 text-primary" />
|
||||
{standort.address.city}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content Section */}
|
||||
<div className="flex flex-col flex-grow p-6 md:p-8 bg-white">
|
||||
<div className="flex items-start justify-between gap-4 mb-4">
|
||||
<h3 className="text-xl md:text-2xl font-bold font-heading text-neutral-dark transition-colors leading-[1.2] group-hover:text-primary">
|
||||
{standort.name}
|
||||
</h3>
|
||||
<ArrowUpRight className="w-5 h-5 text-neutral-400 group-hover:text-primary transition-colors shrink-0" />
|
||||
</div>
|
||||
|
||||
<p className="text-neutral-500 text-sm leading-relaxed mb-8 line-clamp-3">
|
||||
{standort.description[safeLocale]}
|
||||
</p>
|
||||
|
||||
{/* Meta Data */}
|
||||
<div className="flex flex-col gap-3 mt-auto border-t border-neutral-100 pt-6 relative z-10">
|
||||
<div className="min-w-0">
|
||||
<span className="block text-[10px] uppercase tracking-widest text-neutral-400 font-bold mb-1">
|
||||
{safeLocale === 'de' ? 'Adresse' : 'Address'}
|
||||
</span>
|
||||
<span className="flex items-start gap-2 text-sm font-semibold text-neutral-700 leading-tight">
|
||||
<Navigation className="w-3.5 h-3.5 text-primary shrink-0 mt-[2px]" />
|
||||
<span className="line-clamp-2">{standort.address.street}, {standort.address.city}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</TrackedLink>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Support Section */}
|
||||
<div className="mt-24 p-8 md:p-12 bg-primary-dark rounded-3xl text-white shadow-2xl relative overflow-hidden group">
|
||||
<div className="absolute top-0 right-0 w-64 h-full bg-accent/5 -skew-x-12 translate-x-1/2 transition-transform group-hover:translate-x-1/3" />
|
||||
<div className="relative z-10 max-w-2xl">
|
||||
<h3 className="text-2xl md:text-3xl font-bold mb-4">{t('nextProjectTitle')}</h3>
|
||||
<p className="text-lg text-white/70 mb-8">{t('nextProjectDesc')}</p>
|
||||
<TrackedLink
|
||||
href={`/${safeLocale}/${safeLocale === 'de' ? 'kontakt' : 'contact'}`}
|
||||
className={getButtonClasses('accent', 'lg')}
|
||||
eventProperties={{
|
||||
location: 'standorte_support_cta',
|
||||
}}
|
||||
>
|
||||
<span className="relative z-10 flex items-center justify-center gap-2 transition-colors duration-500 group-hover/btn:text-primary-dark">
|
||||
{t('contactUs')}
|
||||
<span className="ml-2 transition-transform group-hover/btn:translate-x-1">
|
||||
→
|
||||
</span>
|
||||
</span>
|
||||
<ButtonOverlay variant="accent" />
|
||||
</TrackedLink>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -12,6 +12,8 @@ interface TrackedLinkProps {
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
onClick?: () => void;
|
||||
target?: string;
|
||||
rel?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -25,6 +27,8 @@ export default function TrackedLink({
|
||||
className,
|
||||
children,
|
||||
onClick,
|
||||
target,
|
||||
rel,
|
||||
}: TrackedLinkProps) {
|
||||
const { trackEvent } = useAnalytics();
|
||||
|
||||
@@ -41,7 +45,7 @@ export default function TrackedLink({
|
||||
};
|
||||
|
||||
return (
|
||||
<Link href={href} className={className} onClick={handleClick}>
|
||||
<Link href={href} className={className} onClick={handleClick} target={target} rel={rel}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
|
||||
@@ -5,16 +5,17 @@ import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { MapPin, Factory, Zap, CheckCircle2, ArrowUpRight } from 'lucide-react';
|
||||
import Image from 'next/image';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import { AnimatedGlossyBorder } from '@/components/ui/AnimatedGlossyBorder';
|
||||
import { Location, defaultLocations, minorLocations } from '@/lib/map-data';
|
||||
import { Location, defaultLocations, minorLocations, projectLocations } from '@/lib/map-data';
|
||||
import { standorteLocations } from '@/lib/standorte-data';
|
||||
import { useLocale, useTranslations } from 'next-intl';
|
||||
|
||||
const allLocations = [...defaultLocations, ...minorLocations];
|
||||
|
||||
interface Stat {
|
||||
value: string;
|
||||
suffix?: string;
|
||||
label: string;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
interface InteractiveGermanyMapProps {
|
||||
@@ -31,7 +32,7 @@ export function InteractiveGermanyMap({
|
||||
title,
|
||||
description,
|
||||
stats,
|
||||
locations = allLocations,
|
||||
locations = projectLocations,
|
||||
isHero = false
|
||||
}: InteractiveGermanyMapProps) {
|
||||
const [activeLocation, setActiveLocation] = useState<Location | null>(null);
|
||||
@@ -42,13 +43,13 @@ export function InteractiveGermanyMap({
|
||||
|
||||
const finalStats = stats || [
|
||||
{ value: '100', suffix: '%', label: locale === 'en' ? 'Nationwide Reach' : 'Überregionale Reichweite' },
|
||||
{ value: '3', suffix: '', label: locale === 'en' ? 'Operational Locations' : 'Operative Standorte' },
|
||||
{ value: '3', suffix: '', label: locale === 'en' ? 'Operational Locations' : 'Operative Standorte', href: `/${locale}/standorte` },
|
||||
];
|
||||
|
||||
const finalBadge = badge || tStandard('badge');
|
||||
// the map is mostly used with specific props, so we leave title & description to fallbacks if not provided
|
||||
const finalTitle = title || (locale === 'en' ? <>Nationwide<br/>in operation for you.</> : <>Deutschlandweit<br/>für Sie im Einsatz.</>);
|
||||
const finalDescription = description || (locale === 'en' ? 'From our strategic locations in Guben and Bülstedt, we control and implement complex infrastructure projects nationwide.' : 'Von unseren strategischen Standorten in Guben und Bülstedt steuern und realisieren wir komplexe Infrastrukturprojekte im gesamten Bundesgebiet.');
|
||||
const finalDescription = description || (locale === 'en' ? 'From our strategic locations in Guben, Kirchheilingen and Bülstedt, we control and implement complex infrastructure projects nationwide.' : 'Von unseren strategischen Standorten in Guben, Kirchheilingen und Bülstedt steuern und realisieren wir komplexe Infrastrukturprojekte im gesamten Bundesgebiet.');
|
||||
|
||||
const hq = locations.find((l) => l.type === 'hq');
|
||||
const branch = locations.find((l) => l.type === 'branch');
|
||||
@@ -90,17 +91,32 @@ export function InteractiveGermanyMap({
|
||||
|
||||
{/* Industrial Stats Grid */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{finalStats.map((stat, i) => (
|
||||
<div key={i} className="bg-white/5 border border-white/10 rounded-2xl p-6 backdrop-blur-md relative overflow-hidden group">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/10 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
||||
<div className="relative z-10">
|
||||
<div className="text-4xl font-extrabold text-white mb-1 flex items-baseline gap-1">
|
||||
{stat.value}<span className="text-xl text-primary">{stat.suffix}</span>
|
||||
{finalStats.map((stat, i) => {
|
||||
const StatCard = () => (
|
||||
<div className={`bg-white/5 border border-white/10 rounded-2xl p-6 backdrop-blur-md relative overflow-hidden group h-full ${stat.href ? 'cursor-pointer' : ''}`}>
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/10 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
||||
<div className="relative z-10 flex flex-col h-full justify-between">
|
||||
<div className="text-4xl font-extrabold text-white mb-1 flex items-baseline gap-1">
|
||||
{stat.value}<span className="text-xl text-primary">{stat.suffix}</span>
|
||||
</div>
|
||||
<div className={`text-sm text-white/50 font-medium flex items-center ${stat.href ? 'group-hover:text-primary transition-colors' : ''}`}>
|
||||
{stat.label}
|
||||
{stat.href && <ArrowUpRight className="w-4 h-4 ml-1 opacity-0 -translate-y-1 translate-x-1 group-hover:opacity-100 group-hover:translate-y-0 group-hover:translate-x-0 transition-all duration-300" />}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-sm text-white/50 font-medium">{stat.label}</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
|
||||
return stat.href ? (
|
||||
<Link key={i} href={stat.href} className="block group/link hover:-translate-y-1 transition-transform duration-300">
|
||||
<StatCard />
|
||||
</Link>
|
||||
) : (
|
||||
<div key={i}>
|
||||
<StatCard />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -130,8 +130,14 @@ export function ReferencesSlider(props: ReferencesSliderProps) {
|
||||
transition={{ delay: i * 0.1, duration: 0.6, ease: "easeOut" }}
|
||||
className="flex-shrink-0 w-[320px] md:w-[480px] snap-center group pointer-events-auto"
|
||||
>
|
||||
<div
|
||||
<Link
|
||||
href={`/${locale}/referenzen/${ref.slug}`}
|
||||
data-testid="reference-tile"
|
||||
onClick={(e) => {
|
||||
if (dragDistanceRef.current > 15) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}}
|
||||
className="block relative aspect-[16/10] bg-neutral-800 rounded-2xl overflow-hidden mb-5 border border-white/5 shadow-2xl"
|
||||
>
|
||||
<Image
|
||||
@@ -151,7 +157,7 @@ export function ReferencesSlider(props: ReferencesSliderProps) {
|
||||
</span>
|
||||
<h4 className="font-heading text-xl md:text-2xl font-bold leading-tight break-words">{ref.title}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import * as React from 'react';
|
||||
import { motion, Variants } from 'framer-motion';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { HoverShineOverlay } from '@/components/ui/HoverShineOverlay';
|
||||
import { AnimatedGlossyBorder } from '@/components/ui/AnimatedGlossyBorder';
|
||||
|
||||
@@ -87,8 +88,9 @@ export function SubCompanyTiles(props: SubCompanyTilesProps) {
|
||||
{companiesData.map((company: any, index: number) => {
|
||||
const isCurrent = company.title.toUpperCase() === 'E-TIB GMBH';
|
||||
const hasUrl = !!company.url;
|
||||
const CardWrapper = hasUrl ? 'a' : 'div';
|
||||
const wrapperProps = hasUrl ? { href: company.url, target: "_blank", rel: "noopener noreferrer" } : {};
|
||||
const isExternal = hasUrl && company.url.startsWith('http');
|
||||
const CardWrapper = hasUrl ? (isExternal ? 'a' : Link) : 'div';
|
||||
const wrapperProps = hasUrl ? (isExternal ? { href: company.url, target: "_blank", rel: "noopener noreferrer" } : { href: company.url }) : {};
|
||||
|
||||
// Generate logo representation based on title
|
||||
const isEtib = company.title.includes('E-TIB');
|
||||
@@ -112,33 +114,21 @@ export function SubCompanyTiles(props: SubCompanyTilesProps) {
|
||||
const positionClass = bgPositionClasses[index % bgPositionClasses.length];
|
||||
const animationClass = animationClasses[index % animationClasses.length];
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
key={index}
|
||||
variants={itemVariants}
|
||||
className="h-full"
|
||||
>
|
||||
<CardWrapper
|
||||
{...wrapperProps}
|
||||
className={`group relative overflow-hidden aspect-[4/3] flex flex-col justify-center items-center shadow-xl transition-all duration-500 bg-neutral-dark block w-full h-full sm:rounded-xl select-none ${
|
||||
isCurrent
|
||||
? 'border-2 border-primary shadow-[0_0_30px_rgba(17,124,97,0.15)] cursor-default'
|
||||
: 'border border-white/5 hover:shadow-2xl hover:-translate-y-1 hover:border-white/10 cursor-pointer'
|
||||
}`}
|
||||
>
|
||||
<div className="absolute inset-0 bg-[#0a192f] z-0">
|
||||
<Image
|
||||
src={company.backgroundImage}
|
||||
alt="Background"
|
||||
fill
|
||||
className={`object-cover transition-all duration-1000 ease-out ${
|
||||
isCurrent
|
||||
? 'opacity-30 grayscale-0 scale-105'
|
||||
: 'opacity-40 grayscale-[50%] group-hover:opacity-30 group-hover:grayscale-0 group-hover:scale-110'
|
||||
}`}
|
||||
sizes="(max-width: 768px) 100vw, 33vw"
|
||||
/>
|
||||
</div>
|
||||
const CardContent = (
|
||||
<>
|
||||
<div className="absolute inset-0 bg-[#0a192f] z-0">
|
||||
<Image
|
||||
src={company.backgroundImage}
|
||||
alt="Background"
|
||||
fill
|
||||
className={`object-cover transition-all duration-1000 ease-out ${
|
||||
isCurrent
|
||||
? 'opacity-30 grayscale-0 scale-105'
|
||||
: 'opacity-40 grayscale-[50%] group-hover:opacity-30 group-hover:grayscale-0 group-hover:scale-110'
|
||||
}`}
|
||||
sizes="(max-width: 768px) 100vw, 33vw"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Heavy dark gradient overlay to make logos pop */}
|
||||
<div className={`absolute inset-0 z-0 transition-colors duration-700 mix-blend-multiply ${
|
||||
@@ -227,13 +217,42 @@ export function SubCompanyTiles(props: SubCompanyTilesProps) {
|
||||
{company.url && (
|
||||
<div className="absolute bottom-6 left-0 right-0 flex justify-center opacity-0 group-hover:opacity-100 transform translate-y-4 group-hover:translate-y-0 transition-all duration-500 z-20">
|
||||
<div className="flex items-center text-white font-bold uppercase text-xs tracking-widest bg-white/10 backdrop-blur-md px-4 py-2 rounded-full border border-white/20">
|
||||
Website Besuchen
|
||||
{isExternal ? (isDe ? 'Website Besuchen' : 'Visit Website') : (isDe ? 'Zum Standort' : 'View Location')}
|
||||
<svg className="w-4 h-4 ml-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</CardWrapper>
|
||||
|
||||
</>
|
||||
);
|
||||
|
||||
const sharedClass = `group relative overflow-hidden aspect-[4/3] flex flex-col justify-center items-center shadow-xl transition-all duration-500 bg-neutral-dark block w-full h-full sm:rounded-xl select-none ${
|
||||
isCurrent
|
||||
? 'border border-white/5 hover:shadow-2xl hover:-translate-y-1 hover:border-white/10 cursor-pointer'
|
||||
: 'border border-white/5 hover:shadow-2xl hover:-translate-y-1 hover:border-white/10 cursor-pointer'
|
||||
}`;
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
key={index}
|
||||
variants={itemVariants}
|
||||
className="h-full"
|
||||
>
|
||||
{hasUrl ? (
|
||||
isExternal ? (
|
||||
<a href={company.url} target="_blank" rel="noopener noreferrer" className={sharedClass}>
|
||||
{CardContent}
|
||||
</a>
|
||||
) : (
|
||||
<Link href={company.url as string} className={sharedClass}>
|
||||
{CardContent}
|
||||
</Link>
|
||||
)
|
||||
) : (
|
||||
<div className={sharedClass}>
|
||||
{CardContent}
|
||||
</div>
|
||||
)}
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -108,6 +108,7 @@ export function Footer({ companyInfo }: FooterProps) {
|
||||
{ label: locale === 'de' ? 'Über uns' : 'About us', href: `/${locale}/${locale === 'de' ? 'ueber-uns' : 'about-us'}` },
|
||||
{ label: locale === 'de' ? 'Unser Team' : 'Our Team', href: `/${locale}/team` },
|
||||
{ label: locale === 'de' ? 'Zertifikate' : 'Certificates', href: `/${locale}/zertifikate` },
|
||||
{ label: locale === 'de' ? 'Referenzen' : 'References', href: `/${locale}/referenzen` },
|
||||
{ label: locale === 'de' ? 'Karriere' : 'Career', href: `/${locale}/${locale === 'de' ? 'karriere' : 'career'}` },
|
||||
{ label: locale === 'de' ? 'Messen & Events' : 'Fairs & Events', href: `/${locale}/${locale === 'de' ? 'messen' : 'trade-fairs'}` },
|
||||
{ label: locale === 'de' ? 'Kontakt' : 'Contact', href: `/${locale}/${locale === 'de' ? 'kontakt' : 'contact'}` },
|
||||
|
||||
@@ -11,6 +11,7 @@ export interface NavLink {
|
||||
label: string;
|
||||
url: string;
|
||||
children?: NavLink[];
|
||||
isGroupLabel?: boolean;
|
||||
}
|
||||
|
||||
interface HeaderProps {
|
||||
@@ -218,11 +219,20 @@ function NavItem({ link, currentLocale, pathname, isSolidMode }: { link: NavLink
|
||||
{/* Top glowing accent line */}
|
||||
<div className="absolute top-0 left-0 w-full h-[2px] bg-gradient-to-r from-transparent via-primary to-transparent opacity-70" />
|
||||
|
||||
{link.children.map((child) => {
|
||||
{link.children.map((child, idx) => {
|
||||
const childUrl = child.url.startsWith('/') && !child.url.match(/^\/(en|de)/)
|
||||
? `/${currentLocale}${child.url}`
|
||||
: child.url;
|
||||
const isChildActive = pathname === childUrl;
|
||||
|
||||
if (child.isGroupLabel) {
|
||||
return (
|
||||
<div key={`group-${idx}`} className={`mt-2 mb-1 px-4 text-[11px] font-bold uppercase tracking-wider ${isSolidMode ? 'text-neutral-400' : 'text-neutral-500'}`}>
|
||||
{child.label}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TransitionLink
|
||||
key={child.url}
|
||||
|
||||
1
contact-page-auth-debug.html
Normal file
1
contact-page-auth-debug.html
Normal file
File diff suppressed because one or more lines are too long
1
contact-page-debug.html
Normal file
1
contact-page-debug.html
Normal file
File diff suppressed because one or more lines are too long
BIN
contact.png
Normal file
BIN
contact.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 288 KiB |
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: "Grabenlose Leitungsverlegung"
|
||||
title: "Bohrtechnik"
|
||||
date: "2024-03-20"
|
||||
excerpt: "Präzise Horizontalspülbohrungen und Erdraketen in allen Bodenklassen für eine absolut oberflächenschonende und effiziente Leitungsverlegung."
|
||||
layout: "fullBleed"
|
||||
@@ -7,9 +7,9 @@ layout: "fullBleed"
|
||||
|
||||
<HeroSection
|
||||
badge="Kernkompetenz"
|
||||
title="Grabenlose Verlegung"
|
||||
subtitle="Oberflächenschonende Horizontalspülbohrungen und Erdraketen"
|
||||
backgroundImage={{ url: '/assets/photos/DSC08653.JPG' }}
|
||||
title="Bohrtechnik"
|
||||
subtitle="Grabenlose Leitungsverlegung, Horizontalspülbohrungen und Erdraketen"
|
||||
backgroundImage={{ url: '/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-47.jpg' }}
|
||||
alignment="center"
|
||||
ctaLabel="Projekt anfragen"
|
||||
ctaHref="/de/kontakt"
|
||||
|
||||
@@ -20,19 +20,21 @@ description: "Die E-TIB GmbH ist Ihr zuverlässiger Partner für komplexe Kabelt
|
||||
title: "E-TIB GMBH",
|
||||
description: "Das komplette Leistungsspektrum zur Errichtung von Kabeltrassen aus einer Hand.",
|
||||
icon: "M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",
|
||||
backgroundImage: "/assets/photos/DJI_0243.JPG"
|
||||
url: "/de/standorte/guben",
|
||||
backgroundImage: "/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-54.jpg"
|
||||
},
|
||||
{
|
||||
title: "E-TIB Ingenieurgesellschaft mbH",
|
||||
description: "Unsere Ingenieure planen für Sie die Energie- und Telekommunikationsnetze der Zukunft - Vermessung und Dokumentation inklusive.",
|
||||
icon: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4",
|
||||
url: "https://www.etib-ing.com/",
|
||||
backgroundImage: "/assets/photos/DSC01137.JPG"
|
||||
backgroundImage: "/assets/photos/etib_ingenieure_tiefbau_solar_pv_planung_vermessung_gis-298.jpg"
|
||||
},
|
||||
{
|
||||
title: "E-TIB Verwaltung GmbH",
|
||||
description: "Zentrale Dienste, Einkauf und Finanzen sowie Verwaltung von Immobilien, Grundstücken, Maschinen und Geräten.",
|
||||
icon: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4",
|
||||
url: "/de/standorte/buelstedt",
|
||||
backgroundImage: "/assets/photos/DJI_0048.JPG"
|
||||
},
|
||||
{
|
||||
@@ -120,7 +122,7 @@ description: "Die E-TIB GmbH ist Ihr zuverlässiger Partner für komplexe Kabelt
|
||||
tag: "Energie",
|
||||
size: "large",
|
||||
href: "/de/kabeltiefbau",
|
||||
image: { url: "/assets/photos/DSC01123.JPG", alt: "Kabelleitungstiefbau" }
|
||||
image: { url: "/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-54.jpg", alt: "Kabelleitungstiefbau" }
|
||||
},
|
||||
{
|
||||
title: "Bohrtechnik",
|
||||
@@ -128,7 +130,7 @@ description: "Die E-TIB GmbH ist Ihr zuverlässiger Partner für komplexe Kabelt
|
||||
tag: "Innovation",
|
||||
size: "medium",
|
||||
href: "/de/bohrtechnik",
|
||||
image: { url: "/assets/photos/DSC08653.JPG", alt: "Bohrtechnik" }
|
||||
image: { url: "/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-47.jpg", alt: "Bohrtechnik" }
|
||||
},
|
||||
{
|
||||
title: "Planung",
|
||||
@@ -136,14 +138,15 @@ description: "Die E-TIB GmbH ist Ihr zuverlässiger Partner für komplexe Kabelt
|
||||
tag: "Präzision",
|
||||
size: "small",
|
||||
href: "/de/planung",
|
||||
image: { url: "/assets/photos/DJI_0048.JPG", alt: "Planung" }
|
||||
image: { url: "/assets/photos/etib_ingenieure_tiefbau_solar_pv_planung_vermessung_gis-298.jpg", alt: "Planung" }
|
||||
},
|
||||
{
|
||||
title: "Vermessung",
|
||||
description: "Digitale Bestandsdokumentation",
|
||||
tag: "Digital",
|
||||
size: "accent",
|
||||
href: "/de/vermessung"
|
||||
href: "/de/vermessung",
|
||||
image: { url: "/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie_Vermessung_(26_von_99).jpg", alt: "Vermessung" }
|
||||
}
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -26,7 +26,7 @@ layout: "fullBleed"
|
||||
|
||||
## Alles aus einer Hand
|
||||
|
||||
Durch unsere langjährige Erfahrung erkennen wir Problemstellungen frühzeitig und erarbeiten für unsere Auftraggeber im Vorfeld sichere und zufriedenstellende Lösungen.
|
||||
Die E-TIB GmbH hat sich voll und ganz auf den Kabelnetzbau spezialisiert. Durch unsere langjährige Erfahrung erkennen wir Problemstellungen frühzeitig und erarbeiten für unsere Auftraggeber im Vorfeld sichere und zufriedenstellende Lösungen.
|
||||
|
||||
Wir bieten Ihnen das komplette Leistungsspektrum zur Errichtung von Kabeltrassen aus einer Hand – mit eigenem, hochmodernem Maschinenpark und festangestelltem Fachpersonal. In direkter Zusammenarbeit mit unserem Partnerbüro, der E-TIB Ingenieurgesellschaft mbH, können wir zudem frühzeitig Planungsfehler ausschließen und selbst die komplexesten Dokumentationsanforderungen souverän erfüllen.
|
||||
|
||||
@@ -36,7 +36,9 @@ layout: "fullBleed"
|
||||
<ServiceDetailGrid
|
||||
badge="Leistungsspektrum"
|
||||
title="Alles für Ihr Netz"
|
||||
descriptionParagraphs={[]}
|
||||
descriptionParagraphs={[
|
||||
"Wir bieten höchste Präzision, modernste Maschinen und zertifizierte Experten für Ihr Projekt."
|
||||
]}
|
||||
panels={[
|
||||
{
|
||||
id: "grabenbau",
|
||||
|
||||
@@ -18,8 +18,8 @@ layout: "fullBleed"
|
||||
|
||||
<BenefitGrid
|
||||
badge="E-TIB Standard"
|
||||
title="Wir bieten unseren Mitarbeitern"
|
||||
description="Die E-TIB GmbH wurde aus der Motivation gegründet, hochwertige Leistungen sowie faire Entlohnung zu ermöglichen. Neben der Entlohnung steht die Wertschätzung jedes einzelnen Mitarbeiters bei uns an oberster Stelle."
|
||||
title="Wir bieten unseren Mitarbeitenden"
|
||||
description="Die E-TIB GmbH wurde aus der Motivation gegründet, hochwertige Leistungen sowie faire Entlohnung zu ermöglichen. Neben der Entlohnung steht die Wertschätzung jedes einzelnen Mitarbeitenden bei uns an oberster Stelle."
|
||||
benefits={[
|
||||
{
|
||||
id: "region",
|
||||
|
||||
@@ -5,13 +5,14 @@ excerpt: "Treffen Sie das Team der E-TIB Gruppe persönlich auf Fachmessen und B
|
||||
layout: "fullBleed"
|
||||
---
|
||||
|
||||
<HomeHero
|
||||
<HeroSection
|
||||
badge="Messen & Events"
|
||||
title="Treffen Sie uns persönlich"
|
||||
description="Lernen Sie die E-TIB Gruppe auf den führenden Branchenmessen kennen."
|
||||
videoUrl="/assets/videos/web/hero-bahnkreuzung.mp4"
|
||||
linkText="Kontakt aufnehmen"
|
||||
linkHref="/de/kontakt"
|
||||
subtitle="Lernen Sie die E-TIB Gruppe auf den führenden Branchenmessen kennen."
|
||||
backgroundImage={{ url: '/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-100.jpg' }}
|
||||
alignment="center"
|
||||
ctaLabel="Kontakt aufnehmen"
|
||||
ctaHref="/de/kontakt"
|
||||
/>
|
||||
|
||||
<div id="termine">
|
||||
@@ -21,7 +22,7 @@ layout: "fullBleed"
|
||||
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: 'Werkstatt Kabel 2026', date: '24. - 25. November 2026', type: 'Fachtagung', location: 'Wiesbaden' }
|
||||
{ name: 'Werkstatt Kabel 2026', date: '24. - 25. November 2026', type: 'Fachtagung', location: 'Wiesbaden', url: 'https://werkstatt-kabel.essociation.de/' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@ layout: "fullBleed"
|
||||
badge="Kernkompetenz"
|
||||
title="Planung & Beratung"
|
||||
subtitle="Kompetente Begleitung für Energie- und Telekommunikationsnetze"
|
||||
backgroundImage={{ url: '/assets/photos/DJI_0048.JPG' }}
|
||||
backgroundImage={{ url: '/assets/photos/etib_ingenieure_tiefbau_solar_pv_planung_vermessung_gis-298.jpg' }}
|
||||
alignment="center"
|
||||
ctaLabel="Projekt anfragen"
|
||||
ctaHref="/de/kontakt"
|
||||
|
||||
@@ -33,7 +33,7 @@ layout: "fullBleed"
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
<div className="bg-white p-8 rounded-2xl shadow-sm border border-neutral-100">
|
||||
<div className="text-4xl font-extrabold text-primary mb-2">100+</div>
|
||||
<div className="text-neutral-dark font-semibold">Mitarbeiter</div>
|
||||
<div className="text-neutral-dark font-semibold">Mitarbeitende</div>
|
||||
</div>
|
||||
<div className="bg-white p-8 rounded-2xl shadow-sm border border-neutral-100">
|
||||
<div className="text-4xl font-extrabold text-primary mb-2">2015</div>
|
||||
@@ -65,59 +65,34 @@ layout: "fullBleed"
|
||||
title: "E-TIB GMBH",
|
||||
description: "Das komplette Leistungsspektrum zur Errichtung von Kabeltrassen aus einer Hand.",
|
||||
icon: "M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",
|
||||
url: "/de/kabeltiefbau",
|
||||
backgroundImage: "/assets/photos/DJI_0243.JPG"
|
||||
url: "/de/standorte/guben",
|
||||
backgroundImage: "/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-54.jpg"
|
||||
},
|
||||
{
|
||||
title: "E-TIB Ingenieurgesellschaft mbH",
|
||||
description: "Unsere Ingenieure planen für Sie die Energie- und Telekommunikationsnetze der Zukunft - Vermessung und Dokumentation inklusive.",
|
||||
icon: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4",
|
||||
url: "https://www.etib-ing.com/",
|
||||
backgroundImage: "/assets/photos/DSC01137.JPG"
|
||||
backgroundImage: "/assets/photos/etib_ingenieure_tiefbau_solar_pv_planung_vermessung_gis-298.jpg"
|
||||
},
|
||||
{
|
||||
title: "E-TIB Verwaltung GmbH",
|
||||
description: "Zentrale Dienste, Einkauf und Finanzen sowie Verwaltung von Immobilien, Grundstücken, Maschinen und Geräten.",
|
||||
icon: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4",
|
||||
url: "/de/standorte/buelstedt",
|
||||
backgroundImage: "/assets/photos/DJI_0048.JPG"
|
||||
},
|
||||
{
|
||||
title: "E-TIB Bohrtechnik GmbH",
|
||||
description: "Präzise Horizontalspülbohrungen in allen Bodenklassen für eine oberflächenschonende und grabenlose Leitungsverlegung.",
|
||||
icon: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z",
|
||||
url: "/de/bohrtechnik",
|
||||
backgroundImage: "/assets/photos/DSC08653.JPG"
|
||||
url: "/de/standorte/kirchheilingen",
|
||||
backgroundImage: "/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-47.jpg"
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="bg-white py-24 border-b border-neutral-100">
|
||||
<div className="container max-w-6xl mx-auto px-4">
|
||||
<div className="text-center mb-16">
|
||||
<div className="text-primary font-bold tracking-wider uppercase text-sm mb-4">Unser Team</div>
|
||||
<h2 className="font-heading text-4xl md:text-5xl font-extrabold text-neutral-dark mb-6">Über 100 Experten für Ihr Projekt</h2>
|
||||
<div className="w-20 h-2 bg-primary mx-auto"></div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
|
||||
<div className="text-center">
|
||||
<div className="text-5xl font-extrabold text-primary mb-2">72</div>
|
||||
<div className="text-neutral-dark font-bold text-lg">E-TIB GmbH</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-5xl font-extrabold text-primary mb-2">10</div>
|
||||
<div className="text-neutral-dark font-bold text-lg">E-TIB Bohrtechnik</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-5xl font-extrabold text-primary mb-2">8</div>
|
||||
<div className="text-neutral-dark font-bold text-lg">E-TIB ING</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-5xl font-extrabold text-primary mb-2">10</div>
|
||||
<div className="text-neutral-dark font-bold text-lg">Niedersachsen</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<CallToAction />
|
||||
|
||||
@@ -8,8 +8,8 @@ layout: "fullBleed"
|
||||
<HeroSection
|
||||
badge="Kernkompetenz"
|
||||
title="Vermessung & Dokumentation"
|
||||
subtitle="Lückenlose und rechtssichere Erfassung aller Bauphasen"
|
||||
backgroundImage={{ url: '/assets/photos/DSC08653.JPG' }}
|
||||
subtitle="Hochpräzise digitale Bestandsdokumentation, 3D-Scans und Drohnenvermessung für Ihre Leitungstrassen und Anlagen."
|
||||
backgroundImage={{ url: '/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie_Vermessung_(24_von_99)_groß2.jpg' }}
|
||||
alignment="center"
|
||||
ctaLabel="Projekt anfragen"
|
||||
ctaHref="/de/kontakt"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: "Trenchless Line Laying"
|
||||
title: "Drilling Technology"
|
||||
date: "2024-03-20"
|
||||
excerpt: "Precise horizontal directional drilling and earth rockets in all soil classes for surface-friendly and efficient line laying."
|
||||
layout: "fullBleed"
|
||||
@@ -7,9 +7,9 @@ layout: "fullBleed"
|
||||
|
||||
<HeroSection
|
||||
badge="Core Competency"
|
||||
title="Trenchless Laying"
|
||||
subtitle="Surface-friendly horizontal directional drilling and earth rockets"
|
||||
backgroundImage={{ url: '/assets/photos/DSC08653.JPG' }}
|
||||
title="Drilling Technology"
|
||||
subtitle="Trenchless Laying, horizontal directional drilling and earth rockets"
|
||||
backgroundImage={{ url: '/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-47.jpg' }}
|
||||
alignment="center"
|
||||
ctaLabel="Request a project"
|
||||
ctaHref="/en/contact"
|
||||
|
||||
@@ -20,19 +20,21 @@ description: "E-TIB GmbH is your reliable partner for complex cable routes, hori
|
||||
title: "E-TIB GMBH",
|
||||
description: "The complete range of services for the construction of cable routes from a single source.",
|
||||
icon: "M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",
|
||||
backgroundImage: "/assets/photos/DJI_0243.JPG"
|
||||
url: "/en/standorte/guben",
|
||||
backgroundImage: "/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-54.jpg"
|
||||
},
|
||||
{
|
||||
title: "E-TIB Ingenieurgesellschaft mbH",
|
||||
description: "Our engineers plan the energy and telecommunications networks of the future for you - surveying and documentation included.",
|
||||
icon: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4",
|
||||
url: "https://www.etib-ing.com/",
|
||||
backgroundImage: "/assets/photos/DSC01137.JPG"
|
||||
backgroundImage: "/assets/photos/etib_ingenieure_tiefbau_solar_pv_planung_vermessung_gis-298.jpg"
|
||||
},
|
||||
{
|
||||
title: "E-TIB Verwaltung GmbH",
|
||||
description: "Central services, purchasing, finance, and management of real estate, properties, machinery, and equipment.",
|
||||
icon: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4",
|
||||
url: "/en/standorte/buelstedt",
|
||||
backgroundImage: "/assets/photos/DJI_0048.JPG"
|
||||
},
|
||||
{
|
||||
@@ -120,7 +122,7 @@ description: "E-TIB GmbH is your reliable partner for complex cable routes, hori
|
||||
tag: "Energy",
|
||||
size: "large",
|
||||
href: "/en/cable-civil-engineering",
|
||||
image: { url: "/assets/photos/DSC01123.JPG", alt: "Cable Civil Engineering" }
|
||||
image: { url: "/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-54.jpg", alt: "Cable Civil Engineering" }
|
||||
},
|
||||
{
|
||||
title: "Drilling Technology",
|
||||
@@ -128,7 +130,7 @@ description: "E-TIB GmbH is your reliable partner for complex cable routes, hori
|
||||
tag: "Innovation",
|
||||
size: "medium",
|
||||
href: "/en/drilling-technology",
|
||||
image: { url: "/assets/photos/DSC08653.JPG", alt: "Drilling Technology" }
|
||||
image: { url: "/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-47.jpg", alt: "Drilling Technology" }
|
||||
},
|
||||
{
|
||||
title: "Planning",
|
||||
@@ -136,14 +138,15 @@ description: "E-TIB GmbH is your reliable partner for complex cable routes, hori
|
||||
tag: "Precision",
|
||||
size: "small",
|
||||
href: "/en/planning",
|
||||
image: { url: "/assets/photos/DJI_0048.JPG", alt: "Planning" }
|
||||
image: { url: "/assets/photos/etib_ingenieure_tiefbau_solar_pv_planung_vermessung_gis-298.jpg", alt: "Planning" }
|
||||
},
|
||||
{
|
||||
title: "Surveying",
|
||||
description: "Digital as-built documentation",
|
||||
tag: "Digital",
|
||||
size: "accent",
|
||||
href: "/en/surveying"
|
||||
href: "/en/surveying",
|
||||
image: { url: "/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie_Vermessung_(26_von_99).jpg", alt: "Surveying" }
|
||||
}
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -24,19 +24,21 @@ layout: "fullBleed"
|
||||
|
||||
Modern civil engineering is plagued by low-cost contractors who routinely **compromise on safety margins and technical documentation**. The repercussions are severe: catastrophic utility strikes (power, water, gas, telecom), costly project delays, and massive budget overruns. What begins as a low-bid shortcut quickly turns into a financial and legal nightmare.
|
||||
|
||||
## Integrated Excellence from a Single Source
|
||||
## Everything from a single source
|
||||
|
||||
At E-TIB, we leverage decades of collective expertise to anticipate structural and geological bottlenecks long before the first shovel hits the ground.
|
||||
E-TIB GmbH is fully specialized in cable network construction. Thanks to our many years of experience, we identify problems early on and develop safe and satisfactory solutions for our clients in advance.
|
||||
|
||||
We deliver turnkey cable routes entirely in-house. Our operations are powered by a cutting-edge fleet of heavy machinery and staffed exclusively by highly trained, permanent professionals. Working in close synergy with our sister firm, **E-TIB Ingenieurgesellschaft mbH**, we eliminate planning oversights at the inception phase and effortlessly handle the most complex GIS and administrative documentation requirements in the industry.
|
||||
We offer you the complete range of services for the construction of cable routes from a single source - with our own ultra-modern machine park and permanently employed specialist staff. In direct cooperation with our partner office, E-TIB Ingenieurgesellschaft mbH, we can also rule out planning errors early on and master even the most complex documentation requirements confidently.
|
||||
|
||||
<DataGridPulse />
|
||||
</div>
|
||||
|
||||
<ServiceDetailGrid
|
||||
badge="Service Portfolio"
|
||||
title="Everything for Your Network"
|
||||
descriptionParagraphs={[]}
|
||||
badge="Service Spectrum"
|
||||
title="Everything for your network"
|
||||
descriptionParagraphs={[
|
||||
"We offer the highest precision, state-of-the-art machinery, and certified experts for your project."
|
||||
]}
|
||||
panels={[
|
||||
{
|
||||
id: "grabenbau",
|
||||
|
||||
@@ -5,13 +5,14 @@ excerpt: "Meet the team of the E-TIB Group personally at trade fairs and industr
|
||||
layout: "fullBleed"
|
||||
---
|
||||
|
||||
<HomeHero
|
||||
<HeroSection
|
||||
badge="Fairs & Events"
|
||||
title="Meet us personally"
|
||||
description="Get to know the E-TIB Group at the leading industry trade fairs."
|
||||
videoUrl="/assets/videos/web/hero-bahnkreuzung.mp4"
|
||||
linkText="Get in Touch"
|
||||
linkHref="/en/contact"
|
||||
subtitle="Get to know the E-TIB Group at the leading industry trade fairs."
|
||||
backgroundImage={{ url: '/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-100.jpg' }}
|
||||
alignment="center"
|
||||
ctaLabel="Get in Touch"
|
||||
ctaHref="/en/contact"
|
||||
/>
|
||||
|
||||
<div id="termine">
|
||||
@@ -21,7 +22,7 @@ layout: "fullBleed"
|
||||
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: 'Werkstatt Kabel 2026', date: 'November 24–25, 2026', type: 'Symposium', location: 'Wiesbaden' }
|
||||
{ name: 'Werkstatt Kabel 2026', date: 'November 24–25, 2026', type: 'Symposium', location: 'Wiesbaden', url: 'https://werkstatt-kabel.essociation.de/' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@ layout: "fullBleed"
|
||||
badge="Core Competency"
|
||||
title="Planning & Consulting"
|
||||
subtitle="Competent support for energy and telecommunications networks"
|
||||
backgroundImage={{ url: '/assets/photos/DJI_0048.JPG' }}
|
||||
backgroundImage={{ url: '/assets/photos/etib_ingenieure_tiefbau_solar_pv_planung_vermessung_gis-298.jpg' }}
|
||||
alignment="center"
|
||||
ctaLabel="Request a project"
|
||||
ctaHref="/en/contact"
|
||||
|
||||
@@ -65,59 +65,34 @@ layout: "fullBleed"
|
||||
title: "E-TIB GMBH",
|
||||
description: "The complete range of services for the construction of cable routes from a single source.",
|
||||
icon: "M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",
|
||||
url: "/en/cable-civil-engineering",
|
||||
backgroundImage: "/assets/photos/DJI_0243.JPG"
|
||||
url: "/en/standorte/guben",
|
||||
backgroundImage: "/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-54.jpg"
|
||||
},
|
||||
{
|
||||
title: "E-TIB Ingenieurgesellschaft mbH",
|
||||
description: "Our engineers plan the energy and telecommunications networks of the future for you - surveying and documentation included.",
|
||||
icon: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4",
|
||||
url: "https://www.etib-ing.com/",
|
||||
backgroundImage: "/assets/photos/DSC01137.JPG"
|
||||
backgroundImage: "/assets/photos/etib_ingenieure_tiefbau_solar_pv_planung_vermessung_gis-298.jpg"
|
||||
},
|
||||
{
|
||||
title: "E-TIB Verwaltung GmbH",
|
||||
description: "Central services, purchasing, finance, and management of real estate, properties, machinery, and equipment.",
|
||||
icon: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4",
|
||||
url: "/en/standorte/buelstedt",
|
||||
backgroundImage: "/assets/photos/DJI_0048.JPG"
|
||||
},
|
||||
{
|
||||
title: "E-TIB Bohrtechnik GmbH",
|
||||
description: "Precise horizontal directional drilling in all soil classes for surface-friendly and trenchless pipe laying.",
|
||||
icon: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z",
|
||||
url: "/en/drilling-technology",
|
||||
backgroundImage: "/assets/photos/DSC08653.JPG"
|
||||
url: "/en/standorte/kirchheilingen",
|
||||
backgroundImage: "/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-47.jpg"
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="bg-white py-24 border-b border-neutral-100">
|
||||
<div className="container max-w-6xl mx-auto px-4">
|
||||
<div className="text-center mb-16">
|
||||
<div className="text-primary font-bold tracking-wider uppercase text-sm mb-4">Our Team</div>
|
||||
<h2 className="font-heading text-4xl md:text-5xl font-extrabold text-neutral-dark mb-6">Over 100 Experts for Your Project</h2>
|
||||
<div className="w-20 h-2 bg-primary mx-auto"></div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
|
||||
<div className="text-center">
|
||||
<div className="text-5xl font-extrabold text-primary mb-2">72</div>
|
||||
<div className="text-neutral-dark font-bold text-lg">E-TIB GmbH</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-5xl font-extrabold text-primary mb-2">10</div>
|
||||
<div className="text-neutral-dark font-bold text-lg">E-TIB Bohrtechnik</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-5xl font-extrabold text-primary mb-2">8</div>
|
||||
<div className="text-neutral-dark font-bold text-lg">E-TIB ING</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-5xl font-extrabold text-primary mb-2">10</div>
|
||||
<div className="text-neutral-dark font-bold text-lg">Lower Saxony</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<CallToAction />
|
||||
|
||||
@@ -8,8 +8,8 @@ layout: "fullBleed"
|
||||
<HeroSection
|
||||
badge="Core Competency"
|
||||
title="Surveying & Documentation"
|
||||
subtitle="Seamless and legally compliant recording of all construction phases"
|
||||
backgroundImage={{ url: '/assets/photos/DSC08653.JPG' }}
|
||||
subtitle="High-precision digital as-built documentation, 3D scans, and drone surveying for your line routes and facilities."
|
||||
backgroundImage={{ url: '/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie_Vermessung_(24_von_99)_groß2.jpg' }}
|
||||
alignment="center"
|
||||
ctaLabel="Request a project"
|
||||
ctaHref="/en/contact"
|
||||
|
||||
@@ -11,34 +11,6 @@ export interface Location {
|
||||
}
|
||||
|
||||
export const defaultLocations: Location[] = [
|
||||
{
|
||||
id: 'guben',
|
||||
name: 'Guben (Hauptsitz)',
|
||||
type: 'hq',
|
||||
x: 85,
|
||||
y: 41.1,
|
||||
description: 'E-TIB GmbH Holding & Bohrtechnik GmbH',
|
||||
details: ['Zentrale Steuerung', 'Kabelleitungstiefbau', 'Maschinenpark'],
|
||||
},
|
||||
{
|
||||
id: 'kirchheilingen',
|
||||
name: 'E-TIB Bohrtechnik GmbH',
|
||||
type: 'branch',
|
||||
x: 52,
|
||||
y: 55,
|
||||
description: 'Standort in Thüringen',
|
||||
href: '/bohrtechnik',
|
||||
details: ['Bahnhofstraße 180a', '99947 Kirchheilingen'],
|
||||
},
|
||||
{
|
||||
id: 'buelstedt',
|
||||
name: 'Bülstedt (Ingenieurgesellschaft)',
|
||||
type: 'branch',
|
||||
x: 37,
|
||||
y: 25.33,
|
||||
description: 'E-TIB Ingenieurgesellschaft mbH',
|
||||
details: ['Planung & Projektierung', 'Vermessung', 'Dokumentation'],
|
||||
},
|
||||
{
|
||||
id: 'dettmannsdorf',
|
||||
name: 'Dettmannsdorf (PV)',
|
||||
@@ -924,3 +896,4 @@ export const minorLocations: Location[] = [
|
||||
description: 'pv',
|
||||
},
|
||||
];
|
||||
export const projectLocations = [...defaultLocations, ...minorLocations];
|
||||
|
||||
174
lib/standorte-data.ts
Normal file
174
lib/standorte-data.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
import { LucideIcon, MapPin, Building2, HardHat, Phone, Mail, Navigation } from 'lucide-react';
|
||||
|
||||
export interface ContactPerson {
|
||||
name: string;
|
||||
role: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
image?: string;
|
||||
}
|
||||
|
||||
export interface StandortData {
|
||||
id: string;
|
||||
name: string;
|
||||
shortName: string;
|
||||
description: Record<'de' | 'en', string>;
|
||||
address: {
|
||||
street: string;
|
||||
city: string;
|
||||
};
|
||||
contact: {
|
||||
phone: string;
|
||||
email: string;
|
||||
};
|
||||
coordinates: {
|
||||
lat: number;
|
||||
lng: number;
|
||||
};
|
||||
keyFeatures: Record<'de' | 'en', string[]>;
|
||||
image: string;
|
||||
gallery: string[];
|
||||
type: 'hq' | 'branch';
|
||||
}
|
||||
|
||||
export const standorteData: StandortData[] = [
|
||||
{
|
||||
id: 'guben',
|
||||
name: 'E-TIB GmbH Holding & Bohrtechnik GmbH',
|
||||
shortName: 'Guben (Hauptsitz)',
|
||||
type: 'hq',
|
||||
description: {
|
||||
de: 'Unser Hauptsitz in Guben bildet das strategische und operative Zentrum der E-TIB Gruppe. Von hier aus steuern wir bundesweit Großprojekte im Kabelleitungstiefbau und koordinieren unseren hochmodernen Maschinenpark.',
|
||||
en: 'Our headquarters in Guben forms the strategic and operational center of the E-TIB Group. From here, we manage large-scale civil engineering projects nationwide and coordinate our state-of-the-art machinery fleet.'
|
||||
},
|
||||
address: {
|
||||
street: 'Gewerbestraße 22',
|
||||
city: '03172 Guben'
|
||||
},
|
||||
contact: {
|
||||
phone: '+49 (0) 3561 / 68577 33',
|
||||
email: 'info@e-tib.com'
|
||||
},
|
||||
coordinates: {
|
||||
lat: 51.942,
|
||||
lng: 14.717
|
||||
},
|
||||
keyFeatures: {
|
||||
de: [
|
||||
'Zentrale strategische Steuerung',
|
||||
'Kabelleitungstiefbau & Infrastruktur',
|
||||
'Koordination Großmaschinenpark',
|
||||
'Zentrales Projektmanagement'
|
||||
],
|
||||
en: [
|
||||
'Central strategic management',
|
||||
'Underground cable engineering & infrastructure',
|
||||
'Coordination of heavy machinery',
|
||||
'Central project management'
|
||||
]
|
||||
},
|
||||
image: '/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-100.jpg',
|
||||
gallery: [
|
||||
'/assets/photos/DSC02114.jpg',
|
||||
'/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-45.jpg'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'kirchheilingen',
|
||||
name: 'E-TIB Bohrtechnik GmbH',
|
||||
shortName: 'Standort Thüringen',
|
||||
type: 'branch',
|
||||
description: {
|
||||
de: 'Unser spezialisierter Standort für Horizontalspülbohrtechnik in Thüringen. Mit modernsten Bohranlagen realisieren wir grabenlose Leitungsverlegungen für komplexe Infrastrukturprojekte, umweltschonend und hocheffizient.',
|
||||
en: 'Our specialized location for horizontal directional drilling in Thuringia. Utilizing state-of-the-art drilling rigs, we implement trenchless cable laying for complex infrastructure projects, environmentally friendly and highly efficient.'
|
||||
},
|
||||
address: {
|
||||
street: 'Bahnhofstraße 180a',
|
||||
city: '99947 Kirchheilingen'
|
||||
},
|
||||
contact: {
|
||||
phone: '+49 (0) 3561 / 68577 33', // Placeholder, using central
|
||||
email: 'info@e-tib.com'
|
||||
},
|
||||
coordinates: {
|
||||
lat: 51.1852,
|
||||
lng: 10.6865
|
||||
},
|
||||
keyFeatures: {
|
||||
de: [
|
||||
'Horizontalspülbohrtechnik (HDD)',
|
||||
'Grabenlose Rohrverlegung',
|
||||
'Felsbohrungen',
|
||||
'Unterquerung von Gewässern & Straßen'
|
||||
],
|
||||
en: [
|
||||
'Horizontal Directional Drilling (HDD)',
|
||||
'Trenchless pipe laying',
|
||||
'Rock drilling',
|
||||
'Crossing underneath water bodies & roads'
|
||||
]
|
||||
},
|
||||
image: '/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie_Vermessung_(247_von_80).jpg',
|
||||
gallery: [
|
||||
'/assets/photos/DSC02089.jpg',
|
||||
'/assets/photos/Etib_E-tib_Tiefbau_Guben_Netzanbindung_Energie-6.jpg'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'buelstedt',
|
||||
name: 'E-TIB Ingenieurgesellschaft mbH',
|
||||
shortName: 'Bülstedt (Ingenieurgesellschaft)',
|
||||
type: 'branch',
|
||||
description: {
|
||||
de: 'Unsere Ingenieurgesellschaft in Bülstedt ist spezialisiert auf die hochpräzise Planung, Vermessung und Projektierung von Energie- und Telekommunikationsnetzen. Hier verschmelzen technische Expertise und modernes Datenmanagement.',
|
||||
en: 'Our engineering firm in Bülstedt specializes in the high-precision planning, surveying, and project management of energy and telecommunication networks. This is where technical expertise and modern data management converge.'
|
||||
},
|
||||
address: {
|
||||
street: 'Dorfstraße 1', // Placeholder
|
||||
city: '27412 Bülstedt'
|
||||
},
|
||||
contact: {
|
||||
phone: '+49 (0) 3561 / 68577 33', // Placeholder, using central
|
||||
email: 'info@e-tib.com'
|
||||
},
|
||||
coordinates: {
|
||||
lat: 53.2167,
|
||||
lng: 9.15
|
||||
},
|
||||
keyFeatures: {
|
||||
de: [
|
||||
'Trassenplanung & Projektierung',
|
||||
'Geodätische Vermessung (GPS/Tachymetrie)',
|
||||
'As-Built Dokumentation (GIS/CAD)',
|
||||
'Genehmigungsmanagement'
|
||||
],
|
||||
en: [
|
||||
'Route planning & project management',
|
||||
'Geodetic surveying (GPS/Tacheometry)',
|
||||
'As-built documentation (GIS/CAD)',
|
||||
'Permit management'
|
||||
]
|
||||
},
|
||||
image: '/assets/photos/etib_ingenieure_tiefbau_solar_pv_planung_vermessung_gis-256.jpg',
|
||||
gallery: [
|
||||
'/assets/photos/etib_ingenieure_tiefbau_solar_pv_planung_vermessung_gis-294.jpg',
|
||||
'/assets/photos/etib_ingenieure_tiefbau_solar_pv_planung_vermessung_gis-298.jpg'
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export function getStandortById(id: string): StandortData | undefined {
|
||||
return standorteData.find(s => s.id === id);
|
||||
}
|
||||
|
||||
// Convert StandortData to the Location format required by the map
|
||||
export const standorteLocations = standorteData.map(standort => ({
|
||||
id: standort.id,
|
||||
name: standort.shortName,
|
||||
type: standort.type,
|
||||
x: standort.id === 'kirchheilingen' ? 52 : standort.id === 'buelstedt' ? 37 : 85,
|
||||
y: standort.id === 'kirchheilingen' ? 55 : standort.id === 'buelstedt' ? 25.33 : 41.1,
|
||||
description: standort.name,
|
||||
href: `/standorte/${standort.id}`,
|
||||
details: standort.keyFeatures.de.slice(0, 3)
|
||||
}));
|
||||
1
login-result.html
Normal file
1
login-result.html
Normal file
File diff suppressed because one or more lines are too long
1
runs.json
Normal file
1
runs.json
Normal file
@@ -0,0 +1 @@
|
||||
{"message":"token is required","url":"https://git.infra.mintel.me/api/swagger"}
|
||||
@@ -29,7 +29,12 @@ async function run() {
|
||||
console.log(` Waiting for potential Gatekeeper redirect...`);
|
||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||
|
||||
const isGatekeeper = await page.$('input[name="password"]');
|
||||
let isGatekeeper = null;
|
||||
try {
|
||||
isGatekeeper = await page.$('input[name="password"]');
|
||||
} catch (e) {
|
||||
console.log('Navigation happened while checking gatekeeper:', e.message);
|
||||
}
|
||||
if (isGatekeeper) {
|
||||
await page.type('input[name="password"]', gatekeeperPassword);
|
||||
await Promise.all([
|
||||
@@ -65,7 +70,7 @@ async function run() {
|
||||
urls.map(async (url) => {
|
||||
if (url.includes('openstreetmap.org') || url.includes('unpkg.com')) return;
|
||||
try {
|
||||
const res = await fetch(url, { method: 'HEAD' });
|
||||
const res = await fetch(url, { method: 'GET' });
|
||||
if (res.status >= 400) {
|
||||
// Diagnostic: check if the raw source is available
|
||||
const rawUrlMatch = url.match(/[?&]url=([^&]+)/);
|
||||
@@ -73,7 +78,7 @@ async function run() {
|
||||
const rawPath = decodeURIComponent(rawUrlMatch[1]);
|
||||
const baseUrl = new URL(url).origin;
|
||||
const rawUrl = `${baseUrl}${rawPath}`;
|
||||
const rawRes = await fetch(rawUrl, { method: 'HEAD' });
|
||||
const rawRes = await fetch(rawUrl, { method: 'GET' });
|
||||
broken.push(`${url} (Status: ${res.status}, Raw Status: ${rawRes.status})`);
|
||||
} else {
|
||||
broken.push(`${url} (Status: ${res.status})`);
|
||||
|
||||
32
test-contact-auth.cjs
Normal file
32
test-contact-auth.cjs
Normal file
@@ -0,0 +1,32 @@
|
||||
const puppeteer = require('puppeteer');
|
||||
(async () => {
|
||||
const targetUrl = 'https://test.e-tib.com';
|
||||
const gatekeeperPassword = process.env.GATEKEEPER_PASSWORD || 'klz2026';
|
||||
|
||||
const browser = await puppeteer.launch({ headless: true });
|
||||
const page = await browser.newPage();
|
||||
|
||||
await page.goto(targetUrl, { waitUntil: 'domcontentloaded' });
|
||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||
|
||||
const isGatekeeper = await page.$('input[name="password"]');
|
||||
if (isGatekeeper) {
|
||||
await page.type('input[name="password"]', gatekeeperPassword);
|
||||
await Promise.all([
|
||||
page.click('button[type="submit"]'),
|
||||
]);
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
}
|
||||
|
||||
await page.screenshot({ path: 'after-login.png' });
|
||||
|
||||
await page.goto(`${targetUrl}/de/kontakt`, { waitUntil: 'domcontentloaded' });
|
||||
await new Promise(r => setTimeout(r, 2000));
|
||||
|
||||
const html = await page.content();
|
||||
const fs = require('fs');
|
||||
fs.writeFileSync('contact-page-auth-debug.html', html);
|
||||
await page.screenshot({ path: 'contact.png' });
|
||||
|
||||
await browser.close();
|
||||
})();
|
||||
12
test-contact.cjs
Normal file
12
test-contact.cjs
Normal file
@@ -0,0 +1,12 @@
|
||||
const puppeteer = require('puppeteer');
|
||||
(async () => {
|
||||
const browser = await puppeteer.launch({ headless: true });
|
||||
const page = await browser.newPage();
|
||||
|
||||
await page.goto('https://test.e-tib.com/de/kontakt', { waitUntil: 'networkidle0' });
|
||||
const html = await page.content();
|
||||
const fs = require('fs');
|
||||
fs.writeFileSync('contact-page-debug.html', html);
|
||||
|
||||
await browser.close();
|
||||
})();
|
||||
12
test-contact.js
Normal file
12
test-contact.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const puppeteer = require('puppeteer');
|
||||
(async () => {
|
||||
const browser = await puppeteer.launch({ headless: true });
|
||||
const page = await browser.newPage();
|
||||
|
||||
await page.goto('https://test.e-tib.com/de/kontakt', { waitUntil: 'networkidle0' });
|
||||
const html = await page.content();
|
||||
const fs = require('fs');
|
||||
fs.writeFileSync('contact-page-debug.html', html);
|
||||
|
||||
await browser.close();
|
||||
})();
|
||||
24
test-login-error.cjs
Normal file
24
test-login-error.cjs
Normal file
@@ -0,0 +1,24 @@
|
||||
const puppeteer = require('puppeteer');
|
||||
(async () => {
|
||||
const targetUrl = 'https://test.e-tib.com';
|
||||
const gatekeeperPassword = process.env.GATEKEEPER_PASSWORD || 'klz2026';
|
||||
|
||||
const browser = await puppeteer.launch({ headless: true });
|
||||
const page = await browser.newPage();
|
||||
|
||||
await page.goto(targetUrl, { waitUntil: 'networkidle0' });
|
||||
const isGatekeeper = await page.$('input[name="password"]');
|
||||
if (isGatekeeper) {
|
||||
await page.type('input[name="password"]', gatekeeperPassword);
|
||||
await Promise.all([
|
||||
page.click('button[type="submit"]'),
|
||||
page.waitForNavigation({ waitUntil: 'networkidle0' }).catch(() => {})
|
||||
]);
|
||||
const html = await page.content();
|
||||
const fs = require('fs');
|
||||
fs.writeFileSync('login-result.html', html);
|
||||
} else {
|
||||
console.log("No gatekeeper found!");
|
||||
}
|
||||
await browser.close();
|
||||
})();
|
||||
@@ -4,7 +4,7 @@ import path from 'path';
|
||||
|
||||
describe('Legal Pages Content Validation', () => {
|
||||
const deAgbPath = path.join(process.cwd(), 'content', 'de', 'agb.mdx');
|
||||
const enTermsPath = path.join(process.cwd(), 'content', 'en', 'terms.mdx');
|
||||
const enTermsPath = path.join(process.cwd(), 'content', 'en', 'agb.mdx');
|
||||
|
||||
it('should contain highly professional B2B sections in German AGB', () => {
|
||||
const content = fs.readFileSync(deAgbPath, 'utf8');
|
||||
|
||||
Reference in New Issue
Block a user