feat: initial Funktechnik Schubert website
This commit is contained in:
commit
9a648e2ec8
35 changed files with 7521 additions and 0 deletions
25
app/api/contact/route.ts
Normal file
25
app/api/contact/route.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { NextResponse } from "next/server";
|
||||
|
||||
function text(value: FormDataEntryValue | null) {
|
||||
return typeof value === "string" ? value.trim() : "";
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const form = await request.formData();
|
||||
const name = text(form.get("name"));
|
||||
const email = text(form.get("email"));
|
||||
const message = text(form.get("message"));
|
||||
|
||||
if (!name || !email.includes("@") || message.length < 10 || form.get("privacy") !== "on") {
|
||||
return NextResponse.json({ message: "Bitte füllen Sie alle Pflichtfelder aus." }, { status: 400 });
|
||||
}
|
||||
|
||||
console.info("contact_request.received", {
|
||||
messageLength: message.length,
|
||||
hasEmail: true,
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
message: "Ihre Nachricht wurde erfasst. Sie erhalten eine Rückmeldung.",
|
||||
});
|
||||
}
|
||||
34
app/api/repair/route.ts
Normal file
34
app/api/repair/route.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { NextResponse } from "next/server";
|
||||
|
||||
function required(value: FormDataEntryValue | null) {
|
||||
return typeof value === "string" && value.trim().length > 0;
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const form = await request.formData();
|
||||
const name = form.get("name");
|
||||
const email = form.get("email");
|
||||
const manufacturer = form.get("manufacturer");
|
||||
const model = form.get("model");
|
||||
const description = form.get("description");
|
||||
const privacy = form.get("privacy");
|
||||
|
||||
if (!required(name) || !required(email) || !required(manufacturer) || !required(model) || !required(description) || privacy !== "on") {
|
||||
return NextResponse.json({ message: "Bitte füllen Sie alle Pflichtfelder aus." }, { status: 400 });
|
||||
}
|
||||
|
||||
const intakeUrl = process.env.OLYMPUS_INTAKE_API_URL;
|
||||
const hasIntegrationToken = Boolean(process.env.OLYMPUS_INTAKE_API_TOKEN);
|
||||
|
||||
console.info("repair_intake.received", {
|
||||
hasIntakeIntegration: Boolean(intakeUrl && hasIntegrationToken),
|
||||
manufacturer: String(manufacturer),
|
||||
model: String(model),
|
||||
hasPhone: required(form.get("phone")),
|
||||
hasSerialNumber: required(form.get("serialNumber")),
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
message: "Ihre Reparaturanfrage wurde erfasst. Sie erhalten nach Prüfung eine Rückmeldung.",
|
||||
});
|
||||
}
|
||||
26
app/datenschutz/page.tsx
Normal file
26
app/datenschutz/page.tsx
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import type { Metadata } from "next";
|
||||
import PageHero from "@/components/PageHero";
|
||||
import { createMetadata } from "../seo";
|
||||
|
||||
export const metadata: Metadata = createMetadata("Datenschutz", "Datenschutzhinweise von Funktechnik Schubert.", "/datenschutz");
|
||||
|
||||
export default function DatenschutzPage() {
|
||||
return (
|
||||
<>
|
||||
<PageHero eyebrow="Rechtliches" title="Datenschutz">Informationen zur Verarbeitung personenbezogener Daten.</PageHero>
|
||||
<section className="section">
|
||||
<div className="container legal">
|
||||
<p className="notice">TODO: Rechtliche Angaben ergänzen</p>
|
||||
<h2>Verantwortlicher</h2>
|
||||
<p>TODO: Rechtliche Angaben ergänzen</p>
|
||||
<h2>Kontakt- und Reparaturanfragen</h2>
|
||||
<p>Die Formulare erfassen Angaben, die zur Bearbeitung der jeweiligen Anfrage erforderlich sind. Eine produktive Datenschutzerklärung muss vor Veröffentlichung rechtlich geprüft und ergänzt werden.</p>
|
||||
<h2>Hosting und Server-Logs</h2>
|
||||
<p>TODO: Rechtliche Angaben ergänzen</p>
|
||||
<h2>Betroffenenrechte</h2>
|
||||
<p>TODO: Rechtliche Angaben ergänzen</p>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
35
app/funkgeraete-service/page.tsx
Normal file
35
app/funkgeraete-service/page.tsx
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import PageHero from "@/components/PageHero";
|
||||
import { createMetadata } from "../seo";
|
||||
|
||||
export const metadata: Metadata = createMetadata("Funkgeräte-Service", "Werkstattservice für CB-Funk, Amateurfunk und Funkgeräte-Abgleich.", "/funkgeraete-service");
|
||||
|
||||
export default function RadioServicePage() {
|
||||
return (
|
||||
<>
|
||||
<PageHero eyebrow="Funkgeräte-Service" title="Prüfung, Diagnose und Abgleich">
|
||||
Funkgeräte zeigen Fehler oft erst im Zusammenspiel von Empfang, Sendeteil, Versorgung, Antennenanpassung und Bedienung. Der Service betrachtet diese Zusammenhänge strukturiert.
|
||||
</PageHero>
|
||||
<section className="section">
|
||||
<div className="container split">
|
||||
<div>
|
||||
<h2>Typische Fehlerbilder</h2>
|
||||
<ul className="list">
|
||||
<li>Kein oder schwacher Empfang</li>
|
||||
<li>Keine, leise oder verzerrte Modulation</li>
|
||||
<li>Frequenzversatz, PLL-Rasten oder instabile Kanäle</li>
|
||||
<li>Aussetzer durch Stromversorgung, Buchsen oder Bedienelemente</li>
|
||||
<li>Unklare Vorarbeiten oder verbastelte Geräte</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="panel">
|
||||
<h2>Serviceablauf</h2>
|
||||
<p className="lead">Eine gute Reparatur beginnt mit vollständigen Angaben zu Gerät, Fehlerbild und Vorgeschichte. Danach folgt eine technische Einschätzung und die weitere Abstimmung.</p>
|
||||
<Link className="button" href="/reparatur">Reparatur anfragen</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
404
app/globals.css
Normal file
404
app/globals.css
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
:root {
|
||||
--bg: #f6f8fb;
|
||||
--surface: #ffffff;
|
||||
--ink: #101827;
|
||||
--muted: #5b677a;
|
||||
--line: #d9e1ec;
|
||||
--navy: #0b1728;
|
||||
--navy-2: #13243a;
|
||||
--cyan: #16b6d9;
|
||||
--orange: #f28c28;
|
||||
--radius: 8px;
|
||||
--shadow: 0 20px 50px rgba(10, 23, 40, 0.12);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--bg);
|
||||
color: var(--ink);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: min(1120px, calc(100% - 32px));
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.site-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 20;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: rgba(11, 23, 40, 0.96);
|
||||
color: #fff;
|
||||
backdrop-filter: blur(14px);
|
||||
}
|
||||
|
||||
.header-inner {
|
||||
display: flex;
|
||||
min-height: 72px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.brand {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.brand-mark {
|
||||
display: grid;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
place-items: center;
|
||||
border: 1px solid rgba(22, 182, 217, 0.45);
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(135deg, rgba(22, 182, 217, 0.22), rgba(242, 140, 40, 0.18));
|
||||
}
|
||||
|
||||
.brand-mark::before {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 3px solid var(--cyan);
|
||||
border-left-color: transparent;
|
||||
border-radius: 999px;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
border-radius: 8px;
|
||||
padding: 9px 11px;
|
||||
color: rgba(255, 255, 255, 0.82);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.nav a:hover {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.hero {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
min-height: calc(100vh - 72px);
|
||||
display: grid;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
background:
|
||||
linear-gradient(90deg, rgba(8, 18, 32, 0.94), rgba(8, 18, 32, 0.72), rgba(8, 18, 32, 0.58)),
|
||||
url("/workbench-signal.svg"),
|
||||
linear-gradient(135deg, #0b1728, #17324e);
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
max-width: 760px;
|
||||
padding: 76px 0 118px;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
color: var(--cyan);
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 18px;
|
||||
font-size: clamp(44px, 7vw, 76px);
|
||||
line-height: 0.96;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 14px;
|
||||
color: var(--ink);
|
||||
font-size: clamp(30px, 4vw, 44px);
|
||||
line-height: 1.05;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 8px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.lead {
|
||||
max-width: 720px;
|
||||
color: var(--muted);
|
||||
font-size: 19px;
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
.hero .lead {
|
||||
color: rgba(255, 255, 255, 0.82);
|
||||
font-size: 21px;
|
||||
}
|
||||
|
||||
.hero-actions,
|
||||
.actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
margin-top: 28px;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-flex;
|
||||
min-height: 44px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 8px;
|
||||
padding: 0 18px;
|
||||
background: var(--cyan);
|
||||
color: #06111d;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.button.secondary {
|
||||
border-color: rgba(255, 255, 255, 0.22);
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.button.light {
|
||||
border-color: var(--line);
|
||||
background: #fff;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 82px 0;
|
||||
}
|
||||
|
||||
.section.dark {
|
||||
background: var(--navy);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.section.dark h2,
|
||||
.section.dark h3 {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.section.dark .lead,
|
||||
.section.dark p {
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
}
|
||||
|
||||
.section-head {
|
||||
max-width: 760px;
|
||||
margin-bottom: 34px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.grid.three {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid.two {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.card {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
background: var(--surface);
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 26px rgba(12, 28, 48, 0.05);
|
||||
}
|
||||
|
||||
.dark .card {
|
||||
border-color: rgba(255, 255, 255, 0.12);
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
.card p,
|
||||
.list li {
|
||||
color: var(--muted);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.dark .card p,
|
||||
.dark .list li {
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
}
|
||||
|
||||
.list {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
padding-left: 19px;
|
||||
}
|
||||
|
||||
.split {
|
||||
display: grid;
|
||||
grid-template-columns: 1.05fr 0.95fr;
|
||||
gap: 34px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.panel {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
background: #fff;
|
||||
padding: 28px;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.form {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.field {
|
||||
display: grid;
|
||||
gap: 7px;
|
||||
}
|
||||
|
||||
.field label {
|
||||
color: var(--ink);
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.field input,
|
||||
.field select,
|
||||
.field textarea {
|
||||
width: 100%;
|
||||
border: 1px solid #cfd8e5;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
padding: 11px 12px;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.field textarea {
|
||||
min-height: 130px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
color: var(--muted);
|
||||
font-size: 14px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #b42318;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.success {
|
||||
border: 1px solid #a6d8bd;
|
||||
border-radius: 8px;
|
||||
background: #edf9f1;
|
||||
padding: 12px;
|
||||
color: #15562d;
|
||||
}
|
||||
|
||||
.notice {
|
||||
border-left: 4px solid var(--orange);
|
||||
background: #fff8ef;
|
||||
padding: 14px 16px;
|
||||
color: #5a3713;
|
||||
}
|
||||
|
||||
.footer {
|
||||
background: #08111f;
|
||||
color: rgba(255, 255, 255, 0.76);
|
||||
padding: 44px 0;
|
||||
}
|
||||
|
||||
.footer-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.3fr 1fr 1fr;
|
||||
gap: 28px;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.legal {
|
||||
max-width: 860px;
|
||||
}
|
||||
|
||||
.legal h2 {
|
||||
margin-top: 28px;
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
.header-inner,
|
||||
.nav {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.header-inner {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
padding: 14px 0;
|
||||
}
|
||||
|
||||
.hero {
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
padding: 64px 0 92px;
|
||||
}
|
||||
|
||||
.grid.three,
|
||||
.grid.two,
|
||||
.split,
|
||||
.footer-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
24
app/impressum/page.tsx
Normal file
24
app/impressum/page.tsx
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import type { Metadata } from "next";
|
||||
import PageHero from "@/components/PageHero";
|
||||
import { createMetadata } from "../seo";
|
||||
|
||||
export const metadata: Metadata = createMetadata("Impressum", "Impressum von Funktechnik Schubert.", "/impressum");
|
||||
|
||||
export default function ImpressumPage() {
|
||||
return (
|
||||
<>
|
||||
<PageHero eyebrow="Rechtliches" title="Impressum">Rechtliche Angaben für die öffentliche Firmenwebsite.</PageHero>
|
||||
<section className="section">
|
||||
<div className="container legal">
|
||||
<p className="notice">TODO: Rechtliche Angaben ergänzen</p>
|
||||
<h2>Anbieterkennzeichnung</h2>
|
||||
<p>TODO: Rechtliche Angaben ergänzen</p>
|
||||
<h2>Kontakt</h2>
|
||||
<p>TODO: Rechtliche Angaben ergänzen</p>
|
||||
<h2>Umsatzsteuer / Registerangaben</h2>
|
||||
<p>TODO: Rechtliche Angaben ergänzen</p>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
27
app/kontakt/page.tsx
Normal file
27
app/kontakt/page.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import type { Metadata } from "next";
|
||||
import PageHero from "@/components/PageHero";
|
||||
import ContactForm from "@/components/ContactForm";
|
||||
import { createMetadata } from "../seo";
|
||||
|
||||
export const metadata: Metadata = createMetadata("Kontakt", "Kontakt zu Funktechnik Schubert aufnehmen.", "/kontakt");
|
||||
|
||||
export default function ContactPage() {
|
||||
return (
|
||||
<>
|
||||
<PageHero eyebrow="Kontakt" title="Kontakt aufnehmen">
|
||||
Beschreiben Sie kurz Ihr Anliegen. Für Reparaturen nutzen Sie idealerweise die strukturierte Reparaturannahme.
|
||||
</PageHero>
|
||||
<section className="section">
|
||||
<div className="container split">
|
||||
<div>
|
||||
<h2>Direkt und technisch</h2>
|
||||
<p className="lead">Je genauer Gerät, Anliegen und gewünschte Unterstützung beschrieben werden, desto gezielter kann die Rückmeldung erfolgen.</p>
|
||||
</div>
|
||||
<div className="panel">
|
||||
<ContactForm />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
22
app/layout.tsx
Normal file
22
app/layout.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import type { Metadata } from "next";
|
||||
import Header from "@/components/Header";
|
||||
import Footer from "@/components/Footer";
|
||||
import "./globals.css";
|
||||
import { createMetadata } from "./seo";
|
||||
|
||||
export const metadata: Metadata = createMetadata(
|
||||
"Funktechnik Schubert",
|
||||
"Service, Reparatur und technische Unterstützung für Funkgeräte und Kommunikationstechnik.",
|
||||
);
|
||||
|
||||
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
|
||||
return (
|
||||
<html lang="de">
|
||||
<body>
|
||||
<Header />
|
||||
<main>{children}</main>
|
||||
<Footer />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
33
app/leistungen/page.tsx
Normal file
33
app/leistungen/page.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import type { Metadata } from "next";
|
||||
import PageHero from "@/components/PageHero";
|
||||
import ServiceCard from "@/components/ServiceCard";
|
||||
import { createMetadata } from "../seo";
|
||||
|
||||
export const metadata: Metadata = createMetadata("Leistungen", "Funkgeräte-Service, Diagnose, Abgleich und Dokumentation für Kommunikationstechnik.", "/leistungen");
|
||||
|
||||
const services = [
|
||||
["Funkgeräte-Service", "Prüfung, Wartung und technische Beurteilung von Funkgeräten mit Fokus auf nachvollziehbare Fehlerbilder."],
|
||||
["CB-Funk", "Service für klassische und moderne CB-Funkgeräte, inklusive Empfangs-, Sende- und Modulationsproblemen."],
|
||||
["Amateurfunk", "Unterstützung bei ausgewählter Amateurfunktechnik, Abgleichfragen und gerätespezifischen Fehlern."],
|
||||
["Betriebsfunk", "Technische Einschätzung und Prüfung von betriebsnaher Kommunikationstechnik im Rahmen der Werkstattmöglichkeiten."],
|
||||
["Fehlersuche", "Strukturierte Diagnose bei Aussetzern, Störungen, instabiler Versorgung oder auffälligem Verhalten."],
|
||||
["Modulationsprobleme", "Analyse von leiser, verzerrter oder fehlender Modulation sowie Prüfung relevanter Baugruppen."],
|
||||
["PLL-/Frequenzprobleme", "Prüfung von Frequenzstabilität, Rastung, Synthesizer- und Referenzproblemen."],
|
||||
["Abgleich und Prüfung", "Sorgfältiger Abgleich nach technischen Unterlagen und dokumentierte Funktionsprüfung."],
|
||||
["Dokumentation", "Einbindung von Serviceunterlagen, Schaltplänen und Reparaturhinweisen in den Prüfprozess."],
|
||||
] as const;
|
||||
|
||||
export default function ServicesPage() {
|
||||
return (
|
||||
<>
|
||||
<PageHero eyebrow="Leistungen" title="Service für Funkgeräte und Kommunikationstechnik">
|
||||
Technische Unterstützung für Geräte, bei denen Diagnose, Erfahrung und saubere Dokumentation zählen.
|
||||
</PageHero>
|
||||
<section className="section">
|
||||
<div className="container grid three">
|
||||
{services.map(([title, text]) => <ServiceCard key={title} title={title}>{text}</ServiceCard>)}
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
57
app/page.tsx
Normal file
57
app/page.tsx
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import Link from "next/link";
|
||||
import ServiceCard from "@/components/ServiceCard";
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<>
|
||||
<section className="hero">
|
||||
<div className="container hero-content">
|
||||
<p className="eyebrow">Funktechnik, Elektronikservice, Werkstatt</p>
|
||||
<h1>Funktechnik Schubert</h1>
|
||||
<p className="lead">Service, Reparatur und technische Unterstützung für Funkgeräte und Kommunikationstechnik.</p>
|
||||
<div className="hero-actions">
|
||||
<Link className="button" href="/reparatur">Reparatur anfragen</Link>
|
||||
<Link className="button secondary" href="/leistungen">Leistungen ansehen</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="section">
|
||||
<div className="container">
|
||||
<div className="section-head">
|
||||
<p className="eyebrow">Leistungsbereiche</p>
|
||||
<h2>Technischer Service mit sauberer Diagnose</h2>
|
||||
<p className="lead">Von der ersten Fehlerbeschreibung bis zur dokumentierten Prüfung: Funktechnik Schubert verbindet Werkstatterfahrung mit strukturierter Kommunikation.</p>
|
||||
</div>
|
||||
<div className="grid three">
|
||||
<ServiceCard title="Funkgeräte-Service">Prüfung, Abgleich und Service für CB-Funk, Amateurfunk und ausgewählte Kommunikationstechnik.</ServiceCard>
|
||||
<ServiceCard title="Reparatur & Diagnose">Systematische Fehlersuche bei Empfang, Modulation, PLL, Frequenzstabilität und Stromversorgung.</ServiceCard>
|
||||
<ServiceCard title="Serviceunterlagen">Sorgfältiger Umgang mit Schaltplänen, Service Manuals und gerätespezifischen Dokumentationen.</ServiceCard>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="section dark">
|
||||
<div className="container split">
|
||||
<div>
|
||||
<p className="eyebrow">Persönlicher Support</p>
|
||||
<h2>Direkte technische Einschätzung statt anonymer Abwicklung</h2>
|
||||
<p className="lead">Viele Fehlerbilder lassen sich bereits mit einer klaren Beschreibung eingrenzen. Die Reparaturannahme fragt deshalb die wichtigsten technischen Details strukturiert ab.</p>
|
||||
<div className="actions">
|
||||
<Link className="button" href="/reparatur">Reparaturformular öffnen</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card">
|
||||
<h3>Warum Funktechnik Schubert?</h3>
|
||||
<ul className="list">
|
||||
<li>Technischer Fokus auf Funkgeräte und Kommunikationstechnik</li>
|
||||
<li>Nachvollziehbare Diagnose statt pauschaler Austauschlogik</li>
|
||||
<li>Klare Rückmeldung zu Aufwand, Zustand und nächsten Schritten</li>
|
||||
<li>Vorbereitung für strukturierte Service- und Dokumentationsprozesse</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
33
app/reparatur/page.tsx
Normal file
33
app/reparatur/page.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import type { Metadata } from "next";
|
||||
import PageHero from "@/components/PageHero";
|
||||
import RepairForm from "@/components/RepairForm";
|
||||
import { createMetadata } from "../seo";
|
||||
|
||||
export const metadata: Metadata = createMetadata("Reparaturannahme", "Reparaturanfrage für Funkgeräte strukturiert vorbereiten.", "/reparatur");
|
||||
|
||||
export default function RepairPage() {
|
||||
return (
|
||||
<>
|
||||
<PageHero eyebrow="Reparaturannahme" title="Reparatur anfragen">
|
||||
Beschreiben Sie Gerät, Fehlerbild und bisherige Vorarbeiten. Die Anfrage wird strukturiert erfasst und für eine spätere technische Übergabe vorbereitet.
|
||||
</PageHero>
|
||||
<section className="section">
|
||||
<div className="container split">
|
||||
<div>
|
||||
<h2>Vor der Einsendung</h2>
|
||||
<p className="lead">Bitte senden Sie Geräte erst nach Rückmeldung ein. Eine klare Fehlerbeschreibung hilft, den Aufwand besser einzuschätzen.</p>
|
||||
<ul className="list">
|
||||
<li>Hersteller, Modell und Seriennummer bereithalten</li>
|
||||
<li>Fehler möglichst reproduzierbar beschreiben</li>
|
||||
<li>Vorarbeiten und geöffnete Geräte ehrlich angeben</li>
|
||||
<li>Zubehör nur nach Absprache mitsenden</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="panel">
|
||||
<RepairForm />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
12
app/robots.ts
Normal file
12
app/robots.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import type { MetadataRoute } from "next";
|
||||
import { siteUrl } from "./seo";
|
||||
|
||||
export default function robots(): MetadataRoute.Robots {
|
||||
return {
|
||||
rules: {
|
||||
userAgent: "*",
|
||||
allow: "/",
|
||||
},
|
||||
sitemap: new URL("/sitemap.xml", siteUrl).toString(),
|
||||
};
|
||||
}
|
||||
37
app/seo.ts
Normal file
37
app/seo.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import type { Metadata } from "next";
|
||||
|
||||
const siteName = "Funktechnik Schubert";
|
||||
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3010";
|
||||
const keywords = [
|
||||
"Funktechnik Schubert",
|
||||
"Funkgeräte Reparatur",
|
||||
"CB Funk Service",
|
||||
"Amateurfunk Reparatur",
|
||||
"Funkgeräte Abgleich",
|
||||
"Funktechnik Service",
|
||||
"Kommunikationstechnik",
|
||||
];
|
||||
|
||||
export function createMetadata(title: string, description: string, path = "/"): Metadata {
|
||||
const url = new URL(path, siteUrl).toString();
|
||||
const fullTitle = title === siteName ? title : `${title} | ${siteName}`;
|
||||
|
||||
return {
|
||||
title: fullTitle,
|
||||
description,
|
||||
keywords,
|
||||
alternates: {
|
||||
canonical: url,
|
||||
},
|
||||
openGraph: {
|
||||
type: "website",
|
||||
locale: "de_DE",
|
||||
url,
|
||||
siteName,
|
||||
title: fullTitle,
|
||||
description,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export { siteName, siteUrl };
|
||||
22
app/sitemap.ts
Normal file
22
app/sitemap.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import type { MetadataRoute } from "next";
|
||||
import { siteUrl } from "./seo";
|
||||
|
||||
const routes = [
|
||||
"",
|
||||
"/leistungen",
|
||||
"/funkgeraete-service",
|
||||
"/reparatur",
|
||||
"/ueber-uns",
|
||||
"/kontakt",
|
||||
"/impressum",
|
||||
"/datenschutz",
|
||||
];
|
||||
|
||||
export default function sitemap(): MetadataRoute.Sitemap {
|
||||
return routes.map((route) => ({
|
||||
url: new URL(route, siteUrl).toString(),
|
||||
lastModified: new Date(),
|
||||
changeFrequency: route === "" ? "weekly" : "monthly",
|
||||
priority: route === "" ? 1 : 0.7,
|
||||
}));
|
||||
}
|
||||
27
app/ueber-uns/page.tsx
Normal file
27
app/ueber-uns/page.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import type { Metadata } from "next";
|
||||
import PageHero from "@/components/PageHero";
|
||||
import { createMetadata } from "../seo";
|
||||
|
||||
export const metadata: Metadata = createMetadata("Über uns", "Funktechnik Schubert steht für technischen Service und klare Kommunikation.", "/ueber-uns");
|
||||
|
||||
export default function AboutPage() {
|
||||
return (
|
||||
<>
|
||||
<PageHero eyebrow="Über uns" title="Technik verstehen, Fehler nachvollziehbar lösen">
|
||||
Funktechnik Schubert richtet sich an Kunden, die bei Funkgeräten und Kommunikationstechnik eine persönliche, technische Einschätzung suchen.
|
||||
</PageHero>
|
||||
<section className="section">
|
||||
<div className="container grid two">
|
||||
<article className="card">
|
||||
<h2>Arbeitsweise</h2>
|
||||
<p>Im Mittelpunkt stehen saubere Diagnose, transparente Kommunikation und der respektvolle Umgang mit bestehenden Geräten und Serviceunterlagen.</p>
|
||||
</article>
|
||||
<article className="card">
|
||||
<h2>Fokus</h2>
|
||||
<p>Der Schwerpunkt liegt auf Funktechnik, Elektronikservice, Abgleichfragen und technischer Unterstützung rund um Kommunikationstechnik.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue