feat: Introduce new service pages for 'Leistungen', 'Telefonie', 'Fernsehen', and 'Internet', accompanied by new layout components and image assets.

This commit is contained in:
1elle1
2026-02-03 19:35:44 +01:00
parent 93d3a6a25d
commit d182ceeb75
39 changed files with 1904 additions and 82 deletions
+11 -3
View File
@@ -1,20 +1,28 @@
import type { ElementType, ReactNode } from "react";
type ContainerVariant = "default" | "narrow" | "wide";
interface ContainerProps {
children: ReactNode;
className?: string;
as?: ElementType;
variant?: ContainerVariant;
}
const variantClasses: Record<ContainerVariant, string> = {
default: "container",
narrow: "container container--narrow",
wide: "container container--wide",
};
export function Container({
children,
className = "",
as: Tag = "div",
variant = "default",
}: ContainerProps) {
return (
<Tag
className={`mx-auto w-full max-w-[var(--container-max-width)] px-[var(--container-padding-x)] ${className}`.trim()}
>
<Tag className={`${variantClasses[variant]} ${className}`.trim()}>
{children}
</Tag>
);
+139
View File
@@ -0,0 +1,139 @@
import Link from "next/link";
import Image from "next/image";
import { MapPin, Phone, Mail, Clock } from "lucide-react";
const navigation = {
leistungen: [
{ name: "Fernsehen", href: "/fernsehen" },
{ name: "Internet", href: "/internet" },
{ name: "Telefonie", href: "/telefonie" },
{ name: "IT-Services", href: "/leistungen" },
],
unternehmen: [
{ name: "Über uns", href: "/ueber-uns" },
{ name: "Kontakt", href: "/kontakt" },
],
rechtliches: [
{ name: "Impressum", href: "/impressum" },
{ name: "Datenschutz", href: "/datenschutz" },
],
};
export function Footer() {
const currentYear = new Date().getFullYear();
return (
<footer className="bg-[var(--color-foreground)] text-[var(--color-background)]">
<div className="container">
{/* Main Footer Content */}
<div className="py-[var(--spacing-4xl)]">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-[var(--spacing-2xl)]">
{/* Company Info */}
<div className="lg:col-span-1">
<Image
src="/images/brand/logo-weiss-ffa4cbf6.png"
alt="Telenet Systems GmbH"
width={160}
height={51}
className="h-10 w-auto mb-[var(--spacing-lg)]"
/>
<p className="text-sm text-gray-300 mb-[var(--spacing-lg)]">
Ihr regionaler Partner für Telekommunikation und IT-Services in Tirol. Seit 1976 verbinden wir Menschen und Technik.
</p>
<div className="space-y-[var(--spacing-sm)]">
<div className="flex items-start gap-[var(--spacing-sm)] text-sm text-gray-300">
<MapPin className="h-4 w-4 mt-0.5 flex-shrink-0" aria-hidden="true" />
<span>Reutte, Tirol, Österreich</span>
</div>
<a
href="tel:+4356725000"
className="flex items-center gap-[var(--spacing-sm)] text-sm text-gray-300 hover:text-white transition-colors"
>
<Phone className="h-4 w-4 flex-shrink-0" aria-hidden="true" />
<span>+43 5672 5000</span>
</a>
<a
href="mailto:info@tnr.at"
className="flex items-center gap-[var(--spacing-sm)] text-sm text-gray-300 hover:text-white transition-colors"
>
<Mail className="h-4 w-4 flex-shrink-0" aria-hidden="true" />
<span>info@tnr.at</span>
</a>
<div className="flex items-start gap-[var(--spacing-sm)] text-sm text-gray-300">
<Clock className="h-4 w-4 mt-0.5 flex-shrink-0" aria-hidden="true" />
<span>MoFr: 8:0012:00 &amp; 13:0017:00</span>
</div>
</div>
</div>
{/* Leistungen */}
<div>
<h3 className="text-base font-semibold mb-[var(--spacing-lg)]">Leistungen</h3>
<ul className="space-y-[var(--spacing-sm)]">
{navigation.leistungen.map((item) => (
<li key={item.name}>
<Link
href={item.href}
className="text-sm text-gray-300 hover:text-white transition-colors"
>
{item.name}
</Link>
</li>
))}
</ul>
</div>
{/* Unternehmen */}
<div>
<h3 className="text-base font-semibold mb-[var(--spacing-lg)]">Unternehmen</h3>
<ul className="space-y-[var(--spacing-sm)]">
{navigation.unternehmen.map((item) => (
<li key={item.name}>
<Link
href={item.href}
className="text-sm text-gray-300 hover:text-white transition-colors"
>
{item.name}
</Link>
</li>
))}
</ul>
</div>
{/* Rechtliches & CTA */}
<div>
<h3 className="text-base font-semibold mb-[var(--spacing-lg)]">Rechtliches</h3>
<ul className="space-y-[var(--spacing-sm)] mb-[var(--spacing-xl)]">
{navigation.rechtliches.map((item) => (
<li key={item.name}>
<Link
href={item.href}
className="text-sm text-gray-300 hover:text-white transition-colors"
>
{item.name}
</Link>
</li>
))}
</ul>
<Link href="/kontakt" className="btn btn-primary">
Kontakt aufnehmen
</Link>
</div>
</div>
</div>
{/* Bottom Bar */}
<div className="border-t border-gray-700 py-[var(--spacing-lg)]">
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-[var(--spacing-sm)]">
<p className="text-sm text-gray-400">
© {currentYear} Telenet Systems GmbH. Alle Rechte vorbehalten.
</p>
<p className="text-sm text-gray-400">
Ihr Partner für Telekommunikation seit 1976
</p>
</div>
</div>
</div>
</footer>
);
}
+116
View File
@@ -0,0 +1,116 @@
"use client";
import Link from "next/link";
import Image from "next/image";
import { useState } from "react";
import { Menu, X, Phone } from "lucide-react";
const navigation = [
{ name: "Startseite", href: "/" },
{ name: "Fernsehen", href: "/fernsehen" },
{ name: "Internet", href: "/internet" },
{ name: "Telefonie", href: "/telefonie" },
{ name: "Leistungen", href: "/leistungen" },
{ name: "Über uns", href: "/ueber-uns" },
{ name: "Kontakt", href: "/kontakt" },
];
export function Header() {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
return (
<header className="sticky top-0 z-50 bg-[var(--color-background)] border-b border-[var(--color-border)]">
<div className="container">
<nav className="flex items-center justify-between py-[var(--spacing-md)]">
{/* Logo */}
<Link href="/" className="flex-shrink-0">
<Image
src="/images/brand/logo-systems-9fd0db14.png"
alt="Telenet Systems GmbH"
width={180}
height={57}
priority
className="h-10 w-auto md:h-12"
/>
</Link>
{/* Desktop Navigation */}
<div className="hidden lg:flex lg:items-center lg:gap-[var(--spacing-lg)]">
{navigation.map((item) => (
<Link
key={item.name}
href={item.href}
className="text-sm font-medium text-[var(--color-foreground)] hover:text-[var(--color-primary)] transition-colors"
>
{item.name}
</Link>
))}
</div>
{/* CTA & Phone (Desktop) */}
<div className="hidden lg:flex lg:items-center lg:gap-[var(--spacing-md)]">
<a
href="tel:+4356725000"
className="flex items-center gap-[var(--spacing-xs)] text-sm font-medium text-[var(--color-muted-foreground)] hover:text-[var(--color-primary)] transition-colors"
aria-label="Anrufen: +43 5672 5000"
>
<Phone className="h-4 w-4" aria-hidden="true" />
<span>+43 5672 5000</span>
</a>
<Link href="/kontakt" className="btn btn-primary">
Jetzt beraten lassen
</Link>
</div>
{/* Mobile Menu Button */}
<button
type="button"
className="lg:hidden p-[var(--spacing-sm)] -mr-[var(--spacing-sm)] text-[var(--color-foreground)]"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
aria-expanded={mobileMenuOpen}
aria-label={mobileMenuOpen ? "Menü schließen" : "Menü öffnen"}
>
{mobileMenuOpen ? (
<X className="h-6 w-6" aria-hidden="true" />
) : (
<Menu className="h-6 w-6" aria-hidden="true" />
)}
</button>
</nav>
{/* Mobile Navigation */}
{mobileMenuOpen && (
<div className="lg:hidden border-t border-[var(--color-border)] py-[var(--spacing-md)]">
<div className="flex flex-col gap-[var(--spacing-sm)]">
{navigation.map((item) => (
<Link
key={item.name}
href={item.href}
className="py-[var(--spacing-sm)] text-base font-medium text-[var(--color-foreground)] hover:text-[var(--color-primary)] transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
{item.name}
</Link>
))}
<hr className="border-[var(--color-border)] my-[var(--spacing-sm)]" />
<a
href="tel:+4356725000"
className="flex items-center gap-[var(--spacing-sm)] py-[var(--spacing-sm)] text-base font-medium text-[var(--color-muted-foreground)]"
>
<Phone className="h-5 w-5" aria-hidden="true" />
<span>+43 5672 5000</span>
</a>
<Link
href="/kontakt"
className="btn btn-primary mt-[var(--spacing-sm)]"
onClick={() => setMobileMenuOpen(false)}
>
Jetzt beraten lassen
</Link>
</div>
</div>
)}
</div>
</header>
);
}
+15 -3
View File
@@ -1,20 +1,32 @@
import type { ElementType, ReactNode } from "react";
type SectionVariant = "default" | "sm" | "lg" | "hero" | "flush";
interface SectionProps {
children: ReactNode;
className?: string;
as?: ElementType;
variant?: SectionVariant;
id?: string;
}
const variantClasses: Record<SectionVariant, string> = {
default: "section",
sm: "section section--sm",
lg: "section section--lg",
hero: "section section--hero",
flush: "section section--flush",
};
export function Section({
children,
className = "",
as: Tag = "section",
variant = "default",
id,
}: SectionProps) {
return (
<Tag
className={`py-[var(--section-spacing-y)] ${className}`.trim()}
>
<Tag id={id} className={`${variantClasses[variant]} ${className}`.trim()}>
{children}
</Tag>
);