feat: add restaurant and about us pages with animated sections
- Implemented RestaurantPage with features, atmosphere, gallery, and contact CTA. - Created UeberUnsPage detailing the history, values, and team of Storfwirt. - Added AnimatedSection component for smooth animations on scroll. - Introduced ContactCTA component for event inquiries. - Developed ContactForm component for user inquiries with validation. - Created Footer and Header components for site navigation and branding. - Added PlaceholderImage and Section components for consistent layout. - Configured TypeScript settings in tsconfig.json for improved development experience.
BIN
BilderTemp/SCR-20260223-oyoa.png
Normal file
|
After Width: | Height: | Size: 398 KiB |
41
website/.gitignore
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/versions
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# next.js
|
||||||
|
/.next/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# env files (can opt-in for committing if needed)
|
||||||
|
.env*
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
next-env.d.ts
|
||||||
36
website/README.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
First, run the development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
# or
|
||||||
|
yarn dev
|
||||||
|
# or
|
||||||
|
pnpm dev
|
||||||
|
# or
|
||||||
|
bun dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||||
|
|
||||||
|
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||||
|
|
||||||
|
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
To learn more about Next.js, take a look at the following resources:
|
||||||
|
|
||||||
|
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||||
|
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||||
|
|
||||||
|
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||||
|
|
||||||
|
## Deploy on Vercel
|
||||||
|
|
||||||
|
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||||
|
|
||||||
|
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||||
18
website/eslint.config.mjs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { defineConfig, globalIgnores } from "eslint/config";
|
||||||
|
import nextVitals from "eslint-config-next/core-web-vitals";
|
||||||
|
import nextTs from "eslint-config-next/typescript";
|
||||||
|
|
||||||
|
const eslintConfig = defineConfig([
|
||||||
|
...nextVitals,
|
||||||
|
...nextTs,
|
||||||
|
// Override default ignores of eslint-config-next.
|
||||||
|
globalIgnores([
|
||||||
|
// Default ignores of eslint-config-next:
|
||||||
|
".next/**",
|
||||||
|
"out/**",
|
||||||
|
"build/**",
|
||||||
|
"next-env.d.ts",
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
export default eslintConfig;
|
||||||
7
website/next.config.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
|
const nextConfig: NextConfig = {
|
||||||
|
/* config options here */
|
||||||
|
};
|
||||||
|
|
||||||
|
export default nextConfig;
|
||||||
6657
website/package-lock.json
generated
Normal file
28
website/package.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "website",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start",
|
||||||
|
"lint": "eslint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"framer-motion": "^12.34.3",
|
||||||
|
"lucide-react": "^0.575.0",
|
||||||
|
"next": "16.1.6",
|
||||||
|
"react": "19.2.3",
|
||||||
|
"react-dom": "19.2.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/postcss": "^4",
|
||||||
|
"@types/node": "^20",
|
||||||
|
"@types/react": "^19",
|
||||||
|
"@types/react-dom": "^19",
|
||||||
|
"eslint": "^9",
|
||||||
|
"eslint-config-next": "16.1.6",
|
||||||
|
"tailwindcss": "^4",
|
||||||
|
"typescript": "^5"
|
||||||
|
}
|
||||||
|
}
|
||||||
7
website/postcss.config.mjs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
const config = {
|
||||||
|
plugins: {
|
||||||
|
"@tailwindcss/postcss": {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
BIN
website/public/assets/logo.png
Normal file
|
After Width: | Height: | Size: 398 KiB |
1
website/public/file.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 391 B |
1
website/public/globe.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
1
website/public/next.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
1
website/public/vercel.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||||
|
After Width: | Height: | Size: 128 B |
1
website/public/window.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||||
|
After Width: | Height: | Size: 385 B |
210
website/src/app/catering/page.tsx
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import {
|
||||||
|
ArrowRight,
|
||||||
|
Users,
|
||||||
|
Heart,
|
||||||
|
Trophy,
|
||||||
|
PartyPopper,
|
||||||
|
CheckCircle2,
|
||||||
|
MessageSquareQuote,
|
||||||
|
} from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { AnimatedSection } from "@/components/AnimatedSection";
|
||||||
|
import { Section } from "@/components/Section";
|
||||||
|
import { ContactCTA } from "@/components/ContactCTA";
|
||||||
|
import { PlaceholderImage } from "@/components/PlaceholderImage";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Catering",
|
||||||
|
description:
|
||||||
|
"Catering in Reutte und Umgebung – für Firmenfeiern, Hochzeiten, Vereinsveranstaltungen und private Feste. Regionale Küche, verlässliche Organisation.",
|
||||||
|
};
|
||||||
|
|
||||||
|
const cateringTypes = [
|
||||||
|
{
|
||||||
|
icon: Trophy,
|
||||||
|
title: "Firmenfeiern & Seminare",
|
||||||
|
description:
|
||||||
|
"Vom Stehempfang beim Firmenjubiläum bis zum Mittagsbuffet bei der Klausurtagung. Wir kennen die Anforderungen und liefern zuverlässig.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Heart,
|
||||||
|
title: "Hochzeiten & Familienfeste",
|
||||||
|
description:
|
||||||
|
"Ihr Fest soll besonders sein – das Essen auch. Wir stellen gemeinsam ein Menü zusammen, das zu Ihnen passt.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Users,
|
||||||
|
title: "Vereinsveranstaltungen",
|
||||||
|
description:
|
||||||
|
"Ob Jahreshauptversammlung oder Vereinsfest: Wir liefern für jede Größe. Unkompliziert und zu fairen Konditionen.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: PartyPopper,
|
||||||
|
title: "Private Feiern",
|
||||||
|
description:
|
||||||
|
"Geburtstag, Taufe, Jubiläum – was auch immer der Anlass ist, wir sorgen für gutes Essen und einen reibungslosen Ablauf.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const steps = [
|
||||||
|
{
|
||||||
|
number: "01",
|
||||||
|
title: "Anfragen",
|
||||||
|
description:
|
||||||
|
"Sagen Sie uns, was Sie planen. Anlass, Datum, ungefähre Gästezahl – mehr brauchen wir zunächst nicht.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
number: "02",
|
||||||
|
title: "Planen",
|
||||||
|
description:
|
||||||
|
"Wir besprechen mit Ihnen Menü, Ablauf und Details. Sie bekommen ein Angebot, das passt.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
number: "03",
|
||||||
|
title: "Genießen",
|
||||||
|
description:
|
||||||
|
"Am Tag Ihres Events kümmern wir uns um alles. Sie können sich auf Ihre Gäste konzentrieren.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function CateringPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Hero */}
|
||||||
|
<section className="bg-gradient-to-br from-primary-dark to-primary pt-32 pb-20 sm:pt-40 sm:pb-28">
|
||||||
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||||
|
<AnimatedSection>
|
||||||
|
<p className="text-accent-light font-medium mb-3">
|
||||||
|
Catering im Außerfern
|
||||||
|
</p>
|
||||||
|
<h1 className="font-heading text-4xl sm:text-5xl lg:text-6xl font-bold text-white leading-tight tracking-tight max-w-3xl">
|
||||||
|
Catering für jeden Anlass
|
||||||
|
</h1>
|
||||||
|
<p className="mt-6 text-lg text-white/80 max-w-2xl leading-relaxed">
|
||||||
|
Sie planen ein Event? Wir bringen das Essen. Frisch gekocht,
|
||||||
|
regional beschafft, pünktlich geliefert – egal ob 20 oder 200
|
||||||
|
Gäste.
|
||||||
|
</p>
|
||||||
|
<Link
|
||||||
|
href="/kontakt"
|
||||||
|
className="inline-flex items-center gap-2 mt-8 rounded-lg bg-white px-6 py-3.5 text-base font-semibold text-primary hover:bg-sand transition-colors focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-dark"
|
||||||
|
>
|
||||||
|
Catering anfragen
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
</AnimatedSection>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Catering Types */}
|
||||||
|
<Section className="bg-cream">
|
||||||
|
<AnimatedSection>
|
||||||
|
<h2 className="font-heading text-3xl sm:text-4xl font-bold text-bark mb-4 text-center">
|
||||||
|
Für wen wir kochen
|
||||||
|
</h2>
|
||||||
|
<p className="text-bark-light text-lg max-w-2xl mx-auto text-center mb-12">
|
||||||
|
Jedes Event ist anders. Die Qualität bleibt gleich.
|
||||||
|
</p>
|
||||||
|
</AnimatedSection>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
||||||
|
{cateringTypes.map((type, index) => (
|
||||||
|
<AnimatedSection key={type.title} delay={index * 0.1}>
|
||||||
|
<div className="rounded-xl border border-driftwood bg-cream p-6 sm:p-8 h-full">
|
||||||
|
<type.icon className="h-8 w-8 text-primary mb-4" />
|
||||||
|
<h3 className="font-heading text-xl font-semibold text-bark mb-2">
|
||||||
|
{type.title}
|
||||||
|
</h3>
|
||||||
|
<p className="text-bark-light leading-relaxed">
|
||||||
|
{type.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* How it works */}
|
||||||
|
<Section className="bg-sand">
|
||||||
|
<AnimatedSection>
|
||||||
|
<h2 className="font-heading text-3xl sm:text-4xl font-bold text-bark mb-12 text-center">
|
||||||
|
So läuft's ab
|
||||||
|
</h2>
|
||||||
|
</AnimatedSection>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
|
{steps.map((step, index) => (
|
||||||
|
<AnimatedSection key={step.number} delay={index * 0.15}>
|
||||||
|
<div className="text-center">
|
||||||
|
<span className="inline-block font-heading text-5xl font-bold text-primary/20 mb-4">
|
||||||
|
{step.number}
|
||||||
|
</span>
|
||||||
|
<h3 className="font-heading text-xl font-semibold text-bark mb-2">
|
||||||
|
{step.title}
|
||||||
|
</h3>
|
||||||
|
<p className="text-bark-light leading-relaxed">
|
||||||
|
{step.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* What you get */}
|
||||||
|
<Section className="bg-cream">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||||
|
<AnimatedSection>
|
||||||
|
<PlaceholderImage
|
||||||
|
icon={Users}
|
||||||
|
label="Bild: Catering bei einer Veranstaltung"
|
||||||
|
/>
|
||||||
|
</AnimatedSection>
|
||||||
|
<AnimatedSection delay={0.1}>
|
||||||
|
<h2 className="font-heading text-3xl font-bold text-bark mb-6">
|
||||||
|
Was Sie von uns erwarten können
|
||||||
|
</h2>
|
||||||
|
<ul className="space-y-4">
|
||||||
|
{[
|
||||||
|
"Frische, regionale Zutaten aus dem Außerfern",
|
||||||
|
"Individuelle Menüplanung nach Ihren Wünschen",
|
||||||
|
"Pünktliche Lieferung und professioneller Auf-/Abbau",
|
||||||
|
"Erfahrenes Servicepersonal auf Wunsch",
|
||||||
|
"Flexible Lösungen für jede Gruppengröße",
|
||||||
|
"Transparente Preise ohne versteckte Kosten",
|
||||||
|
].map((item) => (
|
||||||
|
<li key={item} className="flex items-start gap-3">
|
||||||
|
<CheckCircle2 className="h-5 w-5 text-primary shrink-0 mt-0.5" />
|
||||||
|
<span className="text-bark-light">{item}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</AnimatedSection>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Testimonial */}
|
||||||
|
<Section className="bg-sand">
|
||||||
|
<AnimatedSection>
|
||||||
|
<div className="max-w-3xl mx-auto text-center">
|
||||||
|
<MessageSquareQuote className="h-10 w-10 text-primary/30 mx-auto mb-6" />
|
||||||
|
<blockquote className="font-heading text-2xl sm:text-3xl text-bark leading-snug mb-6">
|
||||||
|
“Wir lassen seit drei Jahren jede Firmenveranstaltung vom
|
||||||
|
Storfwirt betreuen. Das Essen ist immer herausragend, die
|
||||||
|
Organisation stimmt, und wir müssen uns um nichts kümmern.”
|
||||||
|
</blockquote>
|
||||||
|
<p className="text-bark-light">
|
||||||
|
<span className="font-medium text-bark">Christian M.</span>
|
||||||
|
{" "}– Geschäftsführer, Reutte
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* CTA */}
|
||||||
|
<ContactCTA
|
||||||
|
headline="Ihr Event verdient gutes Essen"
|
||||||
|
text="Schreiben Sie uns, was Sie planen. Wir melden uns mit einem Vorschlag."
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
173
website/src/app/datenschutz/page.tsx
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import { Section } from "@/components/Section";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Datenschutzerklärung",
|
||||||
|
description:
|
||||||
|
"Datenschutzerklärung des Storfwirt Reutte – Informationen zur Verarbeitung personenbezogener Daten.",
|
||||||
|
robots: { index: false, follow: false },
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function DatenschutzPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<section className="bg-primary-dark pt-32 pb-12 sm:pt-40 sm:pb-16">
|
||||||
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||||
|
<h1 className="font-heading text-3xl sm:text-4xl font-bold text-white">
|
||||||
|
Datenschutzerklärung
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<Section className="bg-cream">
|
||||||
|
<div className="max-w-3xl mx-auto">
|
||||||
|
<div className="space-y-8 text-bark-light leading-relaxed">
|
||||||
|
<div>
|
||||||
|
<h2 className="font-heading text-xl font-semibold text-bark mb-3">
|
||||||
|
1. Verantwortlicher
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
Storfwirt Reutte
|
||||||
|
<br />
|
||||||
|
Musterstraße 1
|
||||||
|
<br />
|
||||||
|
6600 Reutte, Österreich
|
||||||
|
<br />
|
||||||
|
E-Mail:{" "}
|
||||||
|
<a
|
||||||
|
href="mailto:info@storfwirt-reutte.at"
|
||||||
|
className="text-primary hover:underline"
|
||||||
|
>
|
||||||
|
info@storfwirt-reutte.at
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 className="font-heading text-xl font-semibold text-bark mb-3">
|
||||||
|
2. Erhebung und Verarbeitung personenbezogener Daten
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
Beim Besuch unserer Website werden keine personenbezogenen Daten
|
||||||
|
automatisch erfasst. Wir verwenden keine Cookies, Tracking-Tools
|
||||||
|
oder Analysedienste.
|
||||||
|
</p>
|
||||||
|
<p className="mt-3">
|
||||||
|
Personenbezogene Daten werden nur erhoben, wenn Sie uns diese im
|
||||||
|
Rahmen einer Kontaktanfrage freiwillig mitteilen (z.B. Name,
|
||||||
|
E-Mail-Adresse, Telefonnummer).
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 className="font-heading text-xl font-semibold text-bark mb-3">
|
||||||
|
3. Kontaktformular
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
Wenn Sie unser Kontaktformular nutzen, werden die von Ihnen
|
||||||
|
angegebenen Daten (Name, E-Mail-Adresse, Telefonnummer,
|
||||||
|
Nachricht) zum Zweck der Bearbeitung Ihrer Anfrage verarbeitet.
|
||||||
|
</p>
|
||||||
|
<p className="mt-3">
|
||||||
|
Rechtsgrundlage ist Art. 6 Abs. 1 lit. b DSGVO
|
||||||
|
(vorvertragliche Maßnahmen) bzw. Art. 6 Abs. 1 lit. a DSGVO
|
||||||
|
(Ihre Einwilligung). Die Daten werden nach Abschluss der Anfrage
|
||||||
|
und Ablauf der gesetzlichen Aufbewahrungsfristen gelöscht.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 className="font-heading text-xl font-semibold text-bark mb-3">
|
||||||
|
4. Keine Weitergabe an Dritte
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
Ihre personenbezogenen Daten werden nicht an Dritte
|
||||||
|
weitergegeben, es sei denn, dies ist zur Erfüllung Ihrer Anfrage
|
||||||
|
erforderlich oder gesetzlich vorgeschrieben.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 className="font-heading text-xl font-semibold text-bark mb-3">
|
||||||
|
5. Hosting
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
Unsere Website wird bei einem externen Dienstleister gehostet.
|
||||||
|
Der Hosting-Anbieter verarbeitet die technisch notwendigen Daten
|
||||||
|
(z.B. IP-Adresse, Browsertyp, Zeitpunkt des Zugriffs) im Rahmen
|
||||||
|
der Bereitstellung der Website. Rechtsgrundlage ist Art. 6
|
||||||
|
Abs. 1 lit. f DSGVO (berechtigtes Interesse an der
|
||||||
|
Bereitstellung der Website).
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 className="font-heading text-xl font-semibold text-bark mb-3">
|
||||||
|
6. Ihre Rechte
|
||||||
|
</h2>
|
||||||
|
<p>Sie haben das Recht auf:</p>
|
||||||
|
<ul className="list-disc list-inside mt-2 space-y-1">
|
||||||
|
<li>Auskunft über Ihre gespeicherten Daten</li>
|
||||||
|
<li>Berichtigung unrichtiger Daten</li>
|
||||||
|
<li>Löschung Ihrer Daten</li>
|
||||||
|
<li>Einschränkung der Verarbeitung</li>
|
||||||
|
<li>Datenübertragbarkeit</li>
|
||||||
|
<li>Widerruf einer erteilten Einwilligung</li>
|
||||||
|
</ul>
|
||||||
|
<p className="mt-3">
|
||||||
|
Zur Ausübung Ihrer Rechte wenden Sie sich bitte an die oben
|
||||||
|
genannte E-Mail-Adresse.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 className="font-heading text-xl font-semibold text-bark mb-3">
|
||||||
|
7. Beschwerderecht
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
Sie haben das Recht, sich bei der zuständigen Aufsichtsbehörde
|
||||||
|
zu beschweren:
|
||||||
|
</p>
|
||||||
|
<p className="mt-2">
|
||||||
|
Österreichische Datenschutzbehörde
|
||||||
|
<br />
|
||||||
|
Barichgasse 40-42
|
||||||
|
<br />
|
||||||
|
1030 Wien
|
||||||
|
<br />
|
||||||
|
<a
|
||||||
|
href="https://www.dsb.gv.at"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-primary hover:underline"
|
||||||
|
>
|
||||||
|
www.dsb.gv.at
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 className="font-heading text-xl font-semibold text-bark mb-3">
|
||||||
|
8. Änderungen
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
Wir behalten uns vor, diese Datenschutzerklärung bei Bedarf
|
||||||
|
anzupassen, um sie an geänderte Rechtslagen oder bei Änderungen
|
||||||
|
unserer Datenverarbeitungen anzupassen.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="border-t border-driftwood pt-6 mt-8">
|
||||||
|
<p className="text-sm text-bark-light/70">
|
||||||
|
<strong className="text-bark">Hinweis:</strong> Diese
|
||||||
|
Datenschutzerklärung ist ein Entwurf und muss vor der
|
||||||
|
Veröffentlichung von einem Rechtsanwalt oder Datenschutzexperten
|
||||||
|
geprüft und an die tatsächlichen Gegebenheiten angepasst werden.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
BIN
website/src/app/favicon.ico
Normal file
|
After Width: | Height: | Size: 25 KiB |
159
website/src/app/feinkost/page.tsx
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import {
|
||||||
|
ShoppingBag,
|
||||||
|
Gift,
|
||||||
|
ArrowRight,
|
||||||
|
Milk,
|
||||||
|
Beef,
|
||||||
|
CakeSlice,
|
||||||
|
Wine,
|
||||||
|
} from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { AnimatedSection } from "@/components/AnimatedSection";
|
||||||
|
import { Section } from "@/components/Section";
|
||||||
|
import { PlaceholderImage } from "@/components/PlaceholderImage";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Feinkost",
|
||||||
|
description:
|
||||||
|
"Regionale Feinkost und Spezialitäten aus dem Außerfern – Käse, Speck, Marmeladen, Geschenkkörbe und mehr. Direkt beim Storfwirt in Reutte.",
|
||||||
|
};
|
||||||
|
|
||||||
|
const categories = [
|
||||||
|
{
|
||||||
|
icon: Milk,
|
||||||
|
title: "Käse & Milchprodukte",
|
||||||
|
description:
|
||||||
|
"Bergkäse, Almkäse, Frischkäse – von Sennereien aus dem Außerfern und dem Allgäu.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Beef,
|
||||||
|
title: "Speck & Wurst",
|
||||||
|
description:
|
||||||
|
"Tiroler Speck, Kaminwurzen und Hauswürste. Geräuchert und gereift nach traditioneller Art.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: CakeSlice,
|
||||||
|
title: "Marmeladen & Aufstriche",
|
||||||
|
description:
|
||||||
|
"Selbstgemacht oder von kleinen Produzenten. Saisonale Sorten, je nachdem, was die Region gerade hergibt.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Wine,
|
||||||
|
title: "Getränke & Spirituosen",
|
||||||
|
description:
|
||||||
|
"Ausgewählte Weine, Edelbrände und Liköre. Viele davon aus Tirol und dem angrenzenden Allgäu.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function FeinkostPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Hero */}
|
||||||
|
<section className="bg-gradient-to-br from-primary-dark to-primary pt-32 pb-20 sm:pt-40 sm:pb-28">
|
||||||
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||||
|
<AnimatedSection>
|
||||||
|
<p className="text-accent-light font-medium mb-3">
|
||||||
|
Regionale Spezialitäten
|
||||||
|
</p>
|
||||||
|
<h1 className="font-heading text-4xl sm:text-5xl lg:text-6xl font-bold text-white leading-tight tracking-tight max-w-3xl">
|
||||||
|
Feinkost aus der Region
|
||||||
|
</h1>
|
||||||
|
<p className="mt-6 text-lg text-white/80 max-w-2xl leading-relaxed">
|
||||||
|
Gute Produkte von Menschen, die wir kennen. Käse, Speck,
|
||||||
|
Marmeladen und mehr – zum Mitnehmen oder als Geschenk.
|
||||||
|
</p>
|
||||||
|
</AnimatedSection>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Categories */}
|
||||||
|
<Section className="bg-cream">
|
||||||
|
<AnimatedSection>
|
||||||
|
<h2 className="font-heading text-3xl sm:text-4xl font-bold text-bark mb-12 text-center">
|
||||||
|
Unser Sortiment
|
||||||
|
</h2>
|
||||||
|
</AnimatedSection>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
||||||
|
{categories.map((category, index) => (
|
||||||
|
<AnimatedSection key={category.title} delay={index * 0.1}>
|
||||||
|
<div className="rounded-xl border border-driftwood bg-sand p-6 sm:p-8 h-full">
|
||||||
|
<category.icon className="h-8 w-8 text-accent mb-4" />
|
||||||
|
<h3 className="font-heading text-xl font-semibold text-bark mb-2">
|
||||||
|
{category.title}
|
||||||
|
</h3>
|
||||||
|
<p className="text-bark-light leading-relaxed">
|
||||||
|
{category.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Gift Baskets */}
|
||||||
|
<Section className="bg-sand">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||||
|
<AnimatedSection>
|
||||||
|
<PlaceholderImage
|
||||||
|
icon={Gift}
|
||||||
|
label="Bild: Geschenkkorb mit regionalen Produkten"
|
||||||
|
/>
|
||||||
|
</AnimatedSection>
|
||||||
|
<AnimatedSection delay={0.1}>
|
||||||
|
<Gift className="h-8 w-8 text-accent mb-4" />
|
||||||
|
<h2 className="font-heading text-3xl font-bold text-bark mb-6">
|
||||||
|
Geschenkkörbe nach Wunsch
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-4 text-bark-light leading-relaxed">
|
||||||
|
<p>
|
||||||
|
Ob für Geschäftspartner, Mitarbeiter oder privat –
|
||||||
|
unsere Geschenkkörbe stellen wir individuell zusammen.
|
||||||
|
Sagen Sie uns, was Ihnen vorschwebt, und wir kümmern
|
||||||
|
uns um den Rest.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Beliebt sind unsere Körbe besonders zu Weihnachten, als
|
||||||
|
Dankeschön an Kunden oder als Mitbringsel für Geburtstage.
|
||||||
|
Die Zusammenstellung variiert je nach Saison und Verfügbarkeit.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Link
|
||||||
|
href="/kontakt"
|
||||||
|
className="inline-flex items-center gap-2 mt-6 rounded-lg bg-primary px-5 py-2.5 text-sm font-medium text-white hover:bg-primary-dark transition-colors focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2"
|
||||||
|
>
|
||||||
|
Geschenkkorb anfragen
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
</AnimatedSection>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Visit us */}
|
||||||
|
<Section className="bg-cream">
|
||||||
|
<AnimatedSection>
|
||||||
|
<div className="max-w-2xl mx-auto text-center">
|
||||||
|
<ShoppingBag className="h-10 w-10 text-primary/30 mx-auto mb-4" />
|
||||||
|
<h2 className="font-heading text-3xl font-bold text-bark mb-4">
|
||||||
|
Am besten selbst vorbeikommen
|
||||||
|
</h2>
|
||||||
|
<p className="text-bark-light leading-relaxed mb-6">
|
||||||
|
Unsere Feinkost gibt es direkt bei uns im Haus. Schauen Sie vorbei,
|
||||||
|
probieren Sie – und nehmen Sie mit, was Ihnen schmeckt. Wir beraten
|
||||||
|
Sie gerne persönlich.
|
||||||
|
</p>
|
||||||
|
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
|
||||||
|
<Link
|
||||||
|
href="/kontakt"
|
||||||
|
className="inline-flex items-center gap-2 text-primary font-medium hover:gap-3 transition-all"
|
||||||
|
>
|
||||||
|
So finden Sie uns
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
</Section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
58
website/src/app/globals.css
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
@theme inline {
|
||||||
|
/* Brand Colors – Storfwirt Reutte */
|
||||||
|
--color-primary: #8F2E34;
|
||||||
|
--color-primary-dark: #6E1F24;
|
||||||
|
--color-primary-light: #B34D54;
|
||||||
|
--color-accent: #8F2E34;
|
||||||
|
--color-accent-dark: #6E1F24;
|
||||||
|
--color-accent-light: #F0D0D2;
|
||||||
|
|
||||||
|
/* Surfaces – clean white base */
|
||||||
|
--color-sand: #F5F5F5;
|
||||||
|
--color-sand-dark: #EBEBEB;
|
||||||
|
--color-cream: #FFFFFF;
|
||||||
|
|
||||||
|
/* Text – black base */
|
||||||
|
--color-bark: #000000;
|
||||||
|
--color-bark-light: #555555;
|
||||||
|
|
||||||
|
/* Borders */
|
||||||
|
--color-driftwood: #E0E0E0;
|
||||||
|
|
||||||
|
/* Fonts */
|
||||||
|
--font-heading: var(--font-lora);
|
||||||
|
--font-body: var(--font-inter);
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: var(--color-cream);
|
||||||
|
color: var(--color-bark);
|
||||||
|
font-family: var(--font-body), system-ui, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip-link {
|
||||||
|
position: absolute;
|
||||||
|
top: -100%;
|
||||||
|
left: 0;
|
||||||
|
z-index: 100;
|
||||||
|
padding: 1rem;
|
||||||
|
background: var(--color-primary);
|
||||||
|
color: white;
|
||||||
|
font-weight: 500;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip-link:focus {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
135
website/src/app/impressum/page.tsx
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import { Section } from "@/components/Section";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Impressum",
|
||||||
|
description: "Impressum und rechtliche Informationen des Storfwirt Reutte.",
|
||||||
|
robots: { index: false, follow: false },
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function ImpressumPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<section className="bg-primary-dark pt-32 pb-12 sm:pt-40 sm:pb-16">
|
||||||
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||||
|
<h1 className="font-heading text-3xl sm:text-4xl font-bold text-white">
|
||||||
|
Impressum
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<Section className="bg-cream">
|
||||||
|
<div className="max-w-3xl mx-auto prose prose-bark">
|
||||||
|
<h2 className="font-heading text-xl font-semibold text-bark mt-0">
|
||||||
|
Angaben gemäß § 5 ECG / § 25 MedienG
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div className="space-y-6 text-bark-light leading-relaxed">
|
||||||
|
<div>
|
||||||
|
<h3 className="font-heading text-lg font-semibold text-bark mb-2">
|
||||||
|
Unternehmen
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Storfwirt Reutte
|
||||||
|
<br />
|
||||||
|
Musterstraße 1
|
||||||
|
<br />
|
||||||
|
6600 Reutte
|
||||||
|
<br />
|
||||||
|
Österreich
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="font-heading text-lg font-semibold text-bark mb-2">
|
||||||
|
Kontakt
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Telefon:{" "}
|
||||||
|
<a
|
||||||
|
href="tel:+43567200000"
|
||||||
|
className="text-primary hover:underline"
|
||||||
|
>
|
||||||
|
+43 5672 00000
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
E-Mail:{" "}
|
||||||
|
<a
|
||||||
|
href="mailto:info@storfwirt-reutte.at"
|
||||||
|
className="text-primary hover:underline"
|
||||||
|
>
|
||||||
|
info@storfwirt-reutte.at
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="font-heading text-lg font-semibold text-bark mb-2">
|
||||||
|
Unternehmensgegenstand
|
||||||
|
</h3>
|
||||||
|
<p>Gastronomie, Catering, Eventlocation</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="font-heading text-lg font-semibold text-bark mb-2">
|
||||||
|
Aufsichtsbehörde
|
||||||
|
</h3>
|
||||||
|
<p>Bezirkshauptmannschaft Reutte</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="font-heading text-lg font-semibold text-bark mb-2">
|
||||||
|
Berufsrecht
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Gewerbeordnung:{" "}
|
||||||
|
<a
|
||||||
|
href="https://www.ris.bka.gv.at"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-primary hover:underline"
|
||||||
|
>
|
||||||
|
www.ris.bka.gv.at
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="font-heading text-lg font-semibold text-bark mb-2">
|
||||||
|
Haftungsausschluss
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Trotz sorgfältiger inhaltlicher Kontrolle übernehmen wir keine
|
||||||
|
Haftung für die Inhalte externer Links. Für den Inhalt der
|
||||||
|
verlinkten Seiten sind ausschließlich deren Betreiber
|
||||||
|
verantwortlich.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="font-heading text-lg font-semibold text-bark mb-2">
|
||||||
|
Urheberrecht
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Die durch den Seitenbetreiber erstellten Inhalte und Werke auf
|
||||||
|
diesen Seiten unterliegen dem österreichischen Urheberrecht.
|
||||||
|
Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der
|
||||||
|
Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der
|
||||||
|
schriftlichen Zustimmung des Erstellers.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="border-t border-driftwood pt-6 mt-8">
|
||||||
|
<p className="text-sm text-bark-light/70">
|
||||||
|
<strong className="text-bark">Hinweis:</strong> Die
|
||||||
|
Kontaktdaten und Angaben auf dieser Seite sind Platzhalter und
|
||||||
|
müssen vor der Veröffentlichung mit den tatsächlichen Daten des
|
||||||
|
Unternehmens ersetzt werden.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
139
website/src/app/kontakt/page.tsx
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import { Phone, Mail, MapPin, Clock } from "lucide-react";
|
||||||
|
import { AnimatedSection } from "@/components/AnimatedSection";
|
||||||
|
import { Section } from "@/components/Section";
|
||||||
|
import { ContactForm } from "@/components/ContactForm";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Kontakt",
|
||||||
|
description:
|
||||||
|
"Kontaktieren Sie den Storfwirt Reutte – für Catering-Anfragen, Eventplanung oder allgemeine Fragen. Per Formular, Telefon oder E-Mail.",
|
||||||
|
};
|
||||||
|
|
||||||
|
const contactInfo = [
|
||||||
|
{
|
||||||
|
icon: Phone,
|
||||||
|
label: "Telefon",
|
||||||
|
value: "+43 5672 00000",
|
||||||
|
href: "tel:+43567200000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Mail,
|
||||||
|
label: "E-Mail",
|
||||||
|
value: "info@storfwirt-reutte.at",
|
||||||
|
href: "mailto:info@storfwirt-reutte.at",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: MapPin,
|
||||||
|
label: "Adresse",
|
||||||
|
value: "Musterstraße 1, 6600 Reutte, Tirol",
|
||||||
|
href: null,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function KontaktPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Hero */}
|
||||||
|
<section className="bg-gradient-to-br from-primary-dark to-primary pt-32 pb-20 sm:pt-40 sm:pb-28">
|
||||||
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||||
|
<AnimatedSection>
|
||||||
|
<p className="text-accent-light font-medium mb-3">Kontakt</p>
|
||||||
|
<h1 className="font-heading text-4xl sm:text-5xl lg:text-6xl font-bold text-white leading-tight tracking-tight max-w-3xl">
|
||||||
|
Sprechen Sie mit uns
|
||||||
|
</h1>
|
||||||
|
<p className="mt-6 text-lg text-white/80 max-w-2xl leading-relaxed">
|
||||||
|
Egal ob Anfrage, Frage oder einfach nur ein Hallo – wir freuen uns
|
||||||
|
auf Ihre Nachricht.
|
||||||
|
</p>
|
||||||
|
</AnimatedSection>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Contact Section */}
|
||||||
|
<Section className="bg-cream">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-12">
|
||||||
|
{/* Form */}
|
||||||
|
<div className="lg:col-span-2">
|
||||||
|
<AnimatedSection>
|
||||||
|
<h2 className="font-heading text-2xl font-bold text-bark mb-6">
|
||||||
|
Anfrage senden
|
||||||
|
</h2>
|
||||||
|
<ContactForm />
|
||||||
|
</AnimatedSection>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Sidebar */}
|
||||||
|
<div>
|
||||||
|
<AnimatedSection delay={0.1}>
|
||||||
|
<div className="rounded-xl border border-driftwood bg-sand p-6 sm:p-8 space-y-6">
|
||||||
|
<h3 className="font-heading text-lg font-semibold text-bark">
|
||||||
|
Direkt erreichen
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
{contactInfo.map((info) => (
|
||||||
|
<div key={info.label} className="flex items-start gap-3">
|
||||||
|
<info.icon className="h-5 w-5 text-primary shrink-0 mt-0.5" />
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-medium text-bark">
|
||||||
|
{info.label}
|
||||||
|
</p>
|
||||||
|
{info.href ? (
|
||||||
|
<a
|
||||||
|
href={info.href}
|
||||||
|
className="text-sm text-bark-light hover:text-primary transition-colors"
|
||||||
|
>
|
||||||
|
{info.value}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<p className="text-sm text-bark-light">{info.value}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<div className="pt-4 border-t border-driftwood">
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<Clock className="h-5 w-5 text-primary shrink-0 mt-0.5" />
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-medium text-bark">
|
||||||
|
Öffnungszeiten
|
||||||
|
</p>
|
||||||
|
<div className="text-sm text-bark-light space-y-0.5 mt-1">
|
||||||
|
<p>Mo – Fr: 11:00 – 14:00</p>
|
||||||
|
<p>Sa: nach Vereinbarung</p>
|
||||||
|
<p>So: Ruhetag</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="pt-4 border-t border-driftwood">
|
||||||
|
<p className="text-sm text-bark-light leading-relaxed">
|
||||||
|
Antworten dauern in der Regel nicht länger als 24 Stunden.
|
||||||
|
Bei dringenden Anfragen rufen Sie uns einfach an.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Map Placeholder */}
|
||||||
|
<section className="bg-sand-dark">
|
||||||
|
<div className="aspect-[21/9] sm:aspect-[3/1] flex items-center justify-center">
|
||||||
|
<div className="text-center p-8">
|
||||||
|
<MapPin className="h-12 w-12 text-primary/25 mx-auto mb-3" />
|
||||||
|
<p className="text-bark-light text-sm">
|
||||||
|
Kartenansicht – Musterstraße 1, 6600 Reutte
|
||||||
|
</p>
|
||||||
|
<p className="text-bark-light/50 text-xs mt-1">
|
||||||
|
Hier kann eine interaktive Karte (z.B. OpenStreetMap) eingebunden werden
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
97
website/src/app/layout.tsx
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import { Lora, Inter } from "next/font/google";
|
||||||
|
import "./globals.css";
|
||||||
|
import { Header } from "@/components/Header";
|
||||||
|
import { Footer } from "@/components/Footer";
|
||||||
|
|
||||||
|
const lora = Lora({
|
||||||
|
variable: "--font-lora",
|
||||||
|
subsets: ["latin"],
|
||||||
|
display: "swap",
|
||||||
|
});
|
||||||
|
|
||||||
|
const inter = Inter({
|
||||||
|
variable: "--font-inter",
|
||||||
|
subsets: ["latin"],
|
||||||
|
display: "swap",
|
||||||
|
});
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: {
|
||||||
|
default: "Storfwirt Reutte – Catering & Eventlocation in Tirol",
|
||||||
|
template: "%s | Storfwirt Reutte",
|
||||||
|
},
|
||||||
|
description:
|
||||||
|
"Catering, Eventlocation, Mittagstisch und Feinkost in Reutte. Regionale Küche, professionelle Organisation – Ihr Partner für Events im Außerfern.",
|
||||||
|
keywords: [
|
||||||
|
"Catering Reutte",
|
||||||
|
"Eventlocation Tirol",
|
||||||
|
"Mittagstisch Reutte",
|
||||||
|
"Feinkost Außerfern",
|
||||||
|
"Restaurant Reutte",
|
||||||
|
"Firmenfeiern Tirol",
|
||||||
|
"Hochzeit Catering Tirol",
|
||||||
|
],
|
||||||
|
authors: [{ name: "Storfwirt Reutte" }],
|
||||||
|
openGraph: {
|
||||||
|
type: "website",
|
||||||
|
locale: "de_AT",
|
||||||
|
siteName: "Storfwirt Reutte",
|
||||||
|
title: "Storfwirt Reutte – Catering & Eventlocation",
|
||||||
|
description:
|
||||||
|
"Regionale Küche, professionelle Event-Organisation. Ihr Partner im Außerfern.",
|
||||||
|
},
|
||||||
|
robots: {
|
||||||
|
index: true,
|
||||||
|
follow: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const structuredData = {
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "Restaurant",
|
||||||
|
name: "Storfwirt Reutte",
|
||||||
|
description:
|
||||||
|
"Catering, Eventlocation und Restaurant in Reutte, Tirol. Regionale Küche für Events und den täglichen Genuss.",
|
||||||
|
address: {
|
||||||
|
"@type": "PostalAddress",
|
||||||
|
streetAddress: "Musterstraße 1",
|
||||||
|
addressLocality: "Reutte",
|
||||||
|
addressRegion: "Tirol",
|
||||||
|
postalCode: "6600",
|
||||||
|
addressCountry: "AT",
|
||||||
|
},
|
||||||
|
geo: {
|
||||||
|
"@type": "GeoCoordinates",
|
||||||
|
latitude: 47.4833,
|
||||||
|
longitude: 10.7167,
|
||||||
|
},
|
||||||
|
servesCuisine: "Regional, Österreichisch",
|
||||||
|
priceRange: "€€",
|
||||||
|
url: "https://www.storfwirt-reutte.at",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: Readonly<{
|
||||||
|
children: React.ReactNode;
|
||||||
|
}>) {
|
||||||
|
return (
|
||||||
|
<html lang="de">
|
||||||
|
<body
|
||||||
|
className={`${lora.variable} ${inter.variable} font-body antialiased`}
|
||||||
|
>
|
||||||
|
<script
|
||||||
|
type="application/ld+json"
|
||||||
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }}
|
||||||
|
/>
|
||||||
|
<a href="#main" className="skip-link">
|
||||||
|
Zum Inhalt springen
|
||||||
|
</a>
|
||||||
|
<Header />
|
||||||
|
<main id="main">{children}</main>
|
||||||
|
<Footer />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
194
website/src/app/leistungen/page.tsx
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import {
|
||||||
|
UtensilsCrossed,
|
||||||
|
Building2,
|
||||||
|
Clock,
|
||||||
|
ShoppingBag,
|
||||||
|
CheckCircle2,
|
||||||
|
ArrowRight,
|
||||||
|
Shield,
|
||||||
|
Leaf,
|
||||||
|
Handshake,
|
||||||
|
} from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { AnimatedSection } from "@/components/AnimatedSection";
|
||||||
|
import { Section } from "@/components/Section";
|
||||||
|
import { ContactCTA } from "@/components/ContactCTA";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Leistungen",
|
||||||
|
description:
|
||||||
|
"Alle Leistungen des Storfwirt Reutte im Überblick: Catering, Eventlocation, Mittagstisch und Feinkost. Regional, verlässlich, aus einer Hand.",
|
||||||
|
};
|
||||||
|
|
||||||
|
const services = [
|
||||||
|
{
|
||||||
|
icon: UtensilsCrossed,
|
||||||
|
title: "Catering für Events & Feiern",
|
||||||
|
description:
|
||||||
|
"Firmenfeiern, Hochzeiten, Vereinsveranstaltungen, private Feste. Wir liefern frisch gekochtes Essen – ob Buffet, Menü oder Fingerfood. Ab 20 bis über 200 Gäste.",
|
||||||
|
href: "/catering",
|
||||||
|
features: [
|
||||||
|
"Individuelle Menüplanung",
|
||||||
|
"Regionale Zutaten",
|
||||||
|
"Service-Personal auf Wunsch",
|
||||||
|
"Lieferung im gesamten Außerfern",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Building2,
|
||||||
|
title: "Eventlocation & Restaurant",
|
||||||
|
description:
|
||||||
|
"Unsere Räume in Reutte bieten Platz für bis zu 120 Gäste. Flexibel einrichtbar, modern ausgestattet, mit eigener Küche direkt im Haus.",
|
||||||
|
href: "/restaurant",
|
||||||
|
features: [
|
||||||
|
"Flexible Raumgestaltung",
|
||||||
|
"Eigene Küche im Haus",
|
||||||
|
"Parkplätze vorhanden",
|
||||||
|
"Zentrale Lage in Reutte",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Clock,
|
||||||
|
title: "Mittagstisch",
|
||||||
|
description:
|
||||||
|
"Jeden Werktag frisch gekocht. Wechselnde Menüs mit regionalen Zutaten, schnell serviert. Perfekt für die Mittagspause.",
|
||||||
|
href: "/mittagstisch",
|
||||||
|
features: [
|
||||||
|
"Mo – Fr, 11:00 – 14:00 Uhr",
|
||||||
|
"Wöchentlich wechselnde Karte",
|
||||||
|
"Frisch & regional",
|
||||||
|
"Faire Preise",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: ShoppingBag,
|
||||||
|
title: "Feinkost & regionale Spezialitäten",
|
||||||
|
description:
|
||||||
|
"Ausgewählte Produkte aus der Region – Käse, Speck, Marmeladen, Aufstriche und mehr. Auch als individuelle Geschenkkörbe.",
|
||||||
|
href: "/feinkost",
|
||||||
|
features: [
|
||||||
|
"Regionale Produzenten",
|
||||||
|
"Geschenkkörbe nach Wunsch",
|
||||||
|
"Saisonale Spezialitäten",
|
||||||
|
"Direktverkauf im Haus",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const advantages = [
|
||||||
|
{
|
||||||
|
icon: Shield,
|
||||||
|
title: "Verlässlichkeit",
|
||||||
|
description:
|
||||||
|
"Wenn wir sagen, dass es klappt, dann klappt es. Pünktlich, in der abgesprochenen Qualität, ohne Überraschungen.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Leaf,
|
||||||
|
title: "Regionale Qualität",
|
||||||
|
description:
|
||||||
|
"Unsere Zutaten kommen aus dem Außerfern und dem südlichen Allgäu. Kurze Wege, frische Produkte, ehrliche Küche.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Handshake,
|
||||||
|
title: "Persönliche Betreuung",
|
||||||
|
description:
|
||||||
|
"Bei uns haben Sie einen Ansprechpartner, der Ihr Event kennt. Keine Callcenter, keine Weiterleitungen.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function LeistungenPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Hero */}
|
||||||
|
<section className="bg-gradient-to-br from-primary-dark to-primary pt-32 pb-20 sm:pt-40 sm:pb-28">
|
||||||
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||||
|
<AnimatedSection>
|
||||||
|
<p className="text-accent-light font-medium mb-3">
|
||||||
|
Storfwirt Reutte
|
||||||
|
</p>
|
||||||
|
<h1 className="font-heading text-4xl sm:text-5xl lg:text-6xl font-bold text-white leading-tight tracking-tight max-w-3xl">
|
||||||
|
Unsere Leistungen
|
||||||
|
</h1>
|
||||||
|
<p className="mt-6 text-lg text-white/80 max-w-2xl leading-relaxed">
|
||||||
|
Vom Catering über die Eventlocation bis zum täglichen Mittagstisch.
|
||||||
|
Alles aus einer Küche, alles aus der Region.
|
||||||
|
</p>
|
||||||
|
</AnimatedSection>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Services Detail */}
|
||||||
|
<Section className="bg-cream">
|
||||||
|
<div className="space-y-16">
|
||||||
|
{services.map((service, index) => (
|
||||||
|
<AnimatedSection key={service.title}>
|
||||||
|
<div
|
||||||
|
className={`grid grid-cols-1 lg:grid-cols-2 gap-8 items-start ${
|
||||||
|
index % 2 === 1 ? "lg:direction-rtl" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="rounded-xl border border-driftwood bg-sand p-8 sm:p-10">
|
||||||
|
<service.icon className="h-10 w-10 text-primary mb-4" />
|
||||||
|
<h2 className="font-heading text-2xl sm:text-3xl font-bold text-bark mb-4">
|
||||||
|
{service.title}
|
||||||
|
</h2>
|
||||||
|
<p className="text-bark-light leading-relaxed mb-6">
|
||||||
|
{service.description}
|
||||||
|
</p>
|
||||||
|
<Link
|
||||||
|
href={service.href}
|
||||||
|
className="inline-flex items-center gap-2 text-primary font-medium hover:gap-3 transition-all"
|
||||||
|
>
|
||||||
|
Details ansehen
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3 lg:pt-4">
|
||||||
|
<h3 className="font-heading text-lg font-semibold text-bark mb-3">
|
||||||
|
Auf einen Blick
|
||||||
|
</h3>
|
||||||
|
{service.features.map((feature) => (
|
||||||
|
<div key={feature} className="flex items-center gap-3">
|
||||||
|
<CheckCircle2 className="h-5 w-5 text-primary shrink-0" />
|
||||||
|
<span className="text-bark-light">{feature}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Advantages */}
|
||||||
|
<Section className="bg-sand">
|
||||||
|
<AnimatedSection>
|
||||||
|
<h2 className="font-heading text-3xl sm:text-4xl font-bold text-bark mb-12 text-center">
|
||||||
|
Warum Storfwirt?
|
||||||
|
</h2>
|
||||||
|
</AnimatedSection>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
|
{advantages.map((advantage, index) => (
|
||||||
|
<AnimatedSection key={advantage.title} delay={index * 0.1}>
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="inline-flex items-center justify-center w-14 h-14 rounded-full bg-primary/10 mb-4">
|
||||||
|
<advantage.icon className="h-7 w-7 text-primary" />
|
||||||
|
</div>
|
||||||
|
<h3 className="font-heading text-xl font-semibold text-bark mb-2">
|
||||||
|
{advantage.title}
|
||||||
|
</h3>
|
||||||
|
<p className="text-bark-light leading-relaxed">
|
||||||
|
{advantage.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* CTA */}
|
||||||
|
<ContactCTA />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
239
website/src/app/mittagstisch/page.tsx
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import { Clock, MapPin, Phone, Leaf } from "lucide-react";
|
||||||
|
import { AnimatedSection } from "@/components/AnimatedSection";
|
||||||
|
import { Section } from "@/components/Section";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Mittagstisch",
|
||||||
|
description:
|
||||||
|
"Mittagstisch in Reutte – jeden Werktag frisch gekocht mit regionalen Zutaten. Wechselnde Menüs, faire Preise, schnell serviert.",
|
||||||
|
};
|
||||||
|
|
||||||
|
interface MenuItem {
|
||||||
|
label: string;
|
||||||
|
dish: string;
|
||||||
|
price: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DayMenu {
|
||||||
|
day: string;
|
||||||
|
menus: MenuItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const weeklyMenu: DayMenu[] = [
|
||||||
|
{
|
||||||
|
day: "Montag",
|
||||||
|
menus: [
|
||||||
|
{ label: "Menü 1", dish: "Tiroler Gröstl mit Spiegelei und Krautsalat", price: "€ 9,90" },
|
||||||
|
{ label: "Menü 2", dish: "Gemüsecremesuppe mit Brot", price: "€ 7,50" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day: "Dienstag",
|
||||||
|
menus: [
|
||||||
|
{ label: "Menü 1", dish: "Rindsgulasch mit Semmelknödel", price: "€ 10,50" },
|
||||||
|
{ label: "Menü 2", dish: "Spinatknödel mit Parmesan und Salat", price: "€ 9,50" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day: "Mittwoch",
|
||||||
|
menus: [
|
||||||
|
{ label: "Menü 1", dish: "Gebratene Forelle mit Petersilkartoffeln", price: "€ 11,90" },
|
||||||
|
{ label: "Menü 2", dish: "Kartoffelsuppe mit Einlage", price: "€ 7,90" },
|
||||||
|
{ label: "Menü 3", dish: "Salatteller mit gebratenen Pilzen", price: "€ 9,90" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day: "Donnerstag",
|
||||||
|
menus: [
|
||||||
|
{ label: "Menü 1", dish: "Kässpätzle mit Röstzwiebeln und Salat", price: "€ 9,50" },
|
||||||
|
{ label: "Menü 2", dish: "Wiener Schnitzel mit Erdäpfelsalat", price: "€ 12,90" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day: "Freitag",
|
||||||
|
menus: [
|
||||||
|
{ label: "Menü 1", dish: "Schweinsbraten mit Knödel und Blaukraut", price: "€ 10,90" },
|
||||||
|
{ label: "Menü 2", dish: "Fischstäbchen mit Reis und Tartarsauce", price: "€ 9,90" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function MittagstischPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Hero */}
|
||||||
|
<section className="bg-gradient-to-br from-primary-dark to-primary pt-32 pb-20 sm:pt-40 sm:pb-28">
|
||||||
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||||
|
<AnimatedSection>
|
||||||
|
<p className="text-accent-light font-medium mb-3">
|
||||||
|
Montag bis Freitag
|
||||||
|
</p>
|
||||||
|
<h1 className="font-heading text-4xl sm:text-5xl lg:text-6xl font-bold text-white leading-tight tracking-tight max-w-3xl">
|
||||||
|
Jeden Tag frisch auf dem Tisch
|
||||||
|
</h1>
|
||||||
|
<p className="mt-6 text-lg text-white/80 max-w-2xl leading-relaxed">
|
||||||
|
Unser Mittagstisch wechselt wöchentlich. Regionale Zutaten, ehrliche
|
||||||
|
Portionen, faire Preise. Ohne Reservierung, einfach vorbeikommen.
|
||||||
|
</p>
|
||||||
|
</AnimatedSection>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Info Bar */}
|
||||||
|
<section className="bg-sand-dark py-6">
|
||||||
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="flex flex-col sm:flex-row items-center justify-center gap-6 sm:gap-10 text-sm text-bark-light">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Clock className="h-4 w-4 text-primary" />
|
||||||
|
<span>Mo – Fr: 11:00 – 14:00 Uhr</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<MapPin className="h-4 w-4 text-primary" />
|
||||||
|
<span>Musterstraße 1, 6600 Reutte</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Phone className="h-4 w-4 text-primary" />
|
||||||
|
<a
|
||||||
|
href="tel:+43567200000"
|
||||||
|
className="hover:text-primary transition-colors"
|
||||||
|
>
|
||||||
|
+43 5672 00000
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Weekly Menu */}
|
||||||
|
<Section className="bg-white">
|
||||||
|
<AnimatedSection>
|
||||||
|
<div className="max-w-4xl mx-auto">
|
||||||
|
<div className="text-center mb-10">
|
||||||
|
<div className="inline-flex items-center gap-2 rounded-full bg-primary/10 px-4 py-1.5 text-sm font-medium text-primary mb-4">
|
||||||
|
<Leaf className="h-4 w-4" />
|
||||||
|
Beispiel-Wochenkarte
|
||||||
|
</div>
|
||||||
|
<h2 className="font-heading text-3xl sm:text-4xl font-bold text-black mb-3">
|
||||||
|
Diese Woche bei uns
|
||||||
|
</h2>
|
||||||
|
<p className="text-bark-light">
|
||||||
|
Die Karte wechselt wöchentlich. Am besten einfach vorbeikommen
|
||||||
|
oder kurz anrufen.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Desktop Table */}
|
||||||
|
<div className="hidden sm:block rounded-xl border border-driftwood overflow-hidden">
|
||||||
|
{weeklyMenu.map((dayEntry, dayIndex) => (
|
||||||
|
<div key={dayEntry.day}>
|
||||||
|
<table className="w-full">
|
||||||
|
<thead>
|
||||||
|
<tr className="bg-primary text-white">
|
||||||
|
<th
|
||||||
|
colSpan={3}
|
||||||
|
className="px-5 py-3 text-left text-sm font-semibold tracking-wide"
|
||||||
|
>
|
||||||
|
{dayEntry.day}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{dayEntry.menus.map((menu, menuIndex) => (
|
||||||
|
<tr
|
||||||
|
key={menu.label}
|
||||||
|
className={`${
|
||||||
|
menuIndex % 2 === 0 ? "bg-white" : "bg-sand"
|
||||||
|
} ${
|
||||||
|
dayIndex < weeklyMenu.length - 1 ||
|
||||||
|
menuIndex < dayEntry.menus.length - 1
|
||||||
|
? "border-b border-driftwood"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<td className="px-5 py-3 text-sm font-medium text-primary w-28">
|
||||||
|
{menu.label}
|
||||||
|
</td>
|
||||||
|
<td className="px-5 py-3 text-sm text-black">
|
||||||
|
{menu.dish}
|
||||||
|
</td>
|
||||||
|
<td className="px-5 py-3 text-sm font-semibold text-black text-right w-24 whitespace-nowrap">
|
||||||
|
{menu.price}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile Stacked Layout */}
|
||||||
|
<div className="sm:hidden space-y-4">
|
||||||
|
{weeklyMenu.map((dayEntry) => (
|
||||||
|
<div
|
||||||
|
key={dayEntry.day}
|
||||||
|
className="rounded-xl border border-driftwood overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="bg-primary px-4 py-2.5">
|
||||||
|
<h3 className="text-white font-semibold text-sm">
|
||||||
|
{dayEntry.day}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div className="divide-y divide-driftwood">
|
||||||
|
{dayEntry.menus.map((menu) => (
|
||||||
|
<div key={menu.label} className="px-4 py-3 bg-white">
|
||||||
|
<div className="flex items-center justify-between mb-1">
|
||||||
|
<span className="text-xs font-medium text-primary">
|
||||||
|
{menu.label}
|
||||||
|
</span>
|
||||||
|
<span className="text-sm font-semibold text-black">
|
||||||
|
{menu.price}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-black">{menu.dish}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-center text-bark-light text-sm mt-6">
|
||||||
|
Alle Gerichte inkl. Salat oder Suppe. Änderungen vorbehalten.
|
||||||
|
Allergene auf Anfrage.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Info Section */}
|
||||||
|
<Section className="bg-sand">
|
||||||
|
<AnimatedSection>
|
||||||
|
<div className="max-w-2xl mx-auto text-center">
|
||||||
|
<h2 className="font-heading text-3xl font-bold text-bark mb-6">
|
||||||
|
Gut zu wissen
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-4 text-bark-light leading-relaxed text-left">
|
||||||
|
<p>
|
||||||
|
Unseren Mittagstisch gibt es seit Jahren. Angefangen hat es mit
|
||||||
|
ein paar Stammgästen aus der Nachbarschaft – mittlerweile kommen
|
||||||
|
jeden Tag Berufstätige, Handwerker und Pensionisten gleichermaßen.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Reservieren müssen Sie nicht. Kommen Sie einfach vorbei.
|
||||||
|
Wenn Sie für eine größere Gruppe bestellen möchten, rufen Sie
|
||||||
|
kurz vorher an.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Übrigens: Unser Mittagstisch eignet sich auch als tägliches
|
||||||
|
Mitarbeiter-Essen für Firmen in der Umgebung. Sprechen Sie uns
|
||||||
|
an, wir finden eine Lösung.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
</Section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
238
website/src/app/page.tsx
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import {
|
||||||
|
ArrowRight,
|
||||||
|
UtensilsCrossed,
|
||||||
|
Building2,
|
||||||
|
Clock,
|
||||||
|
ShoppingBag,
|
||||||
|
Star,
|
||||||
|
} from "lucide-react";
|
||||||
|
import { AnimatedSection } from "@/components/AnimatedSection";
|
||||||
|
import { ContactCTA } from "@/components/ContactCTA";
|
||||||
|
import { Section } from "@/components/Section";
|
||||||
|
import { PlaceholderImage } from "@/components/PlaceholderImage";
|
||||||
|
|
||||||
|
const services = [
|
||||||
|
{
|
||||||
|
icon: UtensilsCrossed,
|
||||||
|
title: "Catering",
|
||||||
|
description:
|
||||||
|
"Von der Firmenfeier bis zur Hochzeit – wir bringen gutes Essen dahin, wo gefeiert wird.",
|
||||||
|
href: "/catering",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Building2,
|
||||||
|
title: "Eventlocation",
|
||||||
|
description:
|
||||||
|
"Unsere Räume bieten Platz für Ihre Veranstaltung. Flexibel einrichtbar, zentral in Reutte.",
|
||||||
|
href: "/restaurant",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Clock,
|
||||||
|
title: "Mittagstisch",
|
||||||
|
description:
|
||||||
|
"Jeden Tag frisch gekocht. Wechselnde Menüs aus regionalen Zutaten – schnell und gut.",
|
||||||
|
href: "/mittagstisch",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: ShoppingBag,
|
||||||
|
title: "Feinkost",
|
||||||
|
description:
|
||||||
|
"Regionale Spezialitäten, Geschenkkörbe und mehr – direkt bei uns im Haus.",
|
||||||
|
href: "/feinkost",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const testimonials = [
|
||||||
|
{
|
||||||
|
quote:
|
||||||
|
"Die haben unser Firmenjubiläum betreut – über 120 Gäste, und alles hat reibungslos geklappt. Von der Vorspeise bis zum Dessert war alles perfekt.",
|
||||||
|
author: "Markus H.",
|
||||||
|
role: "Unternehmer aus Reutte",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
quote:
|
||||||
|
"Wir bestellen regelmäßig den Mittagstisch. Schmeckt wie selbst gekocht, nur besser.",
|
||||||
|
author: "Sandra K.",
|
||||||
|
role: "Reutte",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
quote:
|
||||||
|
"Unsere Hochzeitsfeier im Storfwirt war genau so, wie wir sie uns vorgestellt haben. Unkompliziert und einfach gut.",
|
||||||
|
author: "Petra & Thomas W.",
|
||||||
|
role: "",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Hero Section */}
|
||||||
|
<section className="relative min-h-[90vh] flex items-center bg-gradient-to-br from-primary-dark via-primary to-primary-light overflow-hidden">
|
||||||
|
<div className="absolute inset-0 bg-[radial-gradient(circle_at_30%_40%,rgba(255,255,255,0.08)_0%,transparent_60%)]" />
|
||||||
|
<div className="absolute inset-0 bg-[radial-gradient(circle_at_80%_80%,rgba(143,46,52,0.15)_0%,transparent_50%)]" />
|
||||||
|
<div className="relative mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-32 sm:py-40">
|
||||||
|
<AnimatedSection>
|
||||||
|
<p className="text-accent-light font-medium text-base sm:text-lg mb-4 tracking-wide">
|
||||||
|
Catering & Eventlocation in Reutte
|
||||||
|
</p>
|
||||||
|
<h1 className="font-heading text-4xl sm:text-5xl lg:text-6xl xl:text-7xl font-bold text-white leading-tight tracking-tight max-w-4xl">
|
||||||
|
Gut essen.
|
||||||
|
<br />
|
||||||
|
Gut feiern.
|
||||||
|
</h1>
|
||||||
|
<p className="mt-6 text-lg sm:text-xl text-white/80 max-w-2xl leading-relaxed">
|
||||||
|
Wir kochen, organisieren und sorgen dafür, dass Ihr Event so wird,
|
||||||
|
wie Sie es sich vorstellen. In Reutte und der ganzen Region.
|
||||||
|
</p>
|
||||||
|
<div className="mt-10 flex flex-col sm:flex-row gap-4">
|
||||||
|
<Link
|
||||||
|
href="/kontakt"
|
||||||
|
className="inline-flex items-center justify-center gap-2 rounded-lg bg-white px-6 py-3.5 text-base font-semibold text-primary hover:bg-sand transition-colors focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-dark"
|
||||||
|
>
|
||||||
|
Event anfragen
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href="/leistungen"
|
||||||
|
className="inline-flex items-center justify-center gap-2 rounded-lg border border-white/30 px-6 py-3.5 text-base font-semibold text-white hover:bg-white/10 transition-colors focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-dark"
|
||||||
|
>
|
||||||
|
Unsere Leistungen
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
</div>
|
||||||
|
<div className="absolute bottom-0 left-0 right-0">
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 1440 60"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className="w-full h-auto block"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M0 60V30C240 0 480 0 720 30C960 60 1200 60 1440 30V60H0Z"
|
||||||
|
fill="var(--color-cream)"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Services Section */}
|
||||||
|
<Section className="bg-cream">
|
||||||
|
<AnimatedSection>
|
||||||
|
<div className="text-center mb-12 sm:mb-16">
|
||||||
|
<h2 className="font-heading text-3xl sm:text-4xl font-bold text-bark mb-4">
|
||||||
|
Was wir für Sie tun
|
||||||
|
</h2>
|
||||||
|
<p className="text-bark-light text-lg max-w-2xl mx-auto">
|
||||||
|
Ob großes Event oder schneller Mittagstisch – bei uns bekommen Sie
|
||||||
|
regionale Qualität aus einer Hand.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||||
|
{services.map((service, index) => (
|
||||||
|
<AnimatedSection key={service.title} delay={index * 0.1}>
|
||||||
|
<Link
|
||||||
|
href={service.href}
|
||||||
|
className="group block rounded-xl border border-driftwood bg-cream p-6 hover:bg-sand hover:border-primary/20 transition-all duration-300 h-full"
|
||||||
|
>
|
||||||
|
<service.icon className="h-8 w-8 text-primary mb-4 group-hover:text-primary-dark transition-colors" />
|
||||||
|
<h3 className="font-heading text-xl font-semibold text-bark mb-2">
|
||||||
|
{service.title}
|
||||||
|
</h3>
|
||||||
|
<p className="text-bark-light text-sm leading-relaxed">
|
||||||
|
{service.description}
|
||||||
|
</p>
|
||||||
|
<span className="inline-flex items-center gap-1 mt-4 text-sm font-medium text-primary group-hover:gap-2 transition-all">
|
||||||
|
Mehr erfahren
|
||||||
|
<ArrowRight className="h-3.5 w-3.5" />
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</AnimatedSection>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* About Teaser */}
|
||||||
|
<Section className="bg-sand">
|
||||||
|
<AnimatedSection>
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||||
|
<div>
|
||||||
|
<h2 className="font-heading text-3xl sm:text-4xl font-bold text-bark mb-6">
|
||||||
|
Verwurzelt in Reutte. Seit Jahren.
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-4 text-bark-light leading-relaxed">
|
||||||
|
<p>
|
||||||
|
Was als kleiner Gasthof angefangen hat, ist heute die erste
|
||||||
|
Adresse für Catering und Events im Außerfern. Aber eines ist
|
||||||
|
geblieben: Wir kochen noch selbst.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Regionale Zutaten, ehrliche Küche, persönliche Betreuung.
|
||||||
|
Kein Schnickschnack, dafür Verlässlichkeit. Das schätzen
|
||||||
|
unsere Gäste – und darauf sind wir stolz.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Link
|
||||||
|
href="/ueber-uns"
|
||||||
|
className="inline-flex items-center gap-2 mt-6 text-primary font-medium hover:gap-3 transition-all"
|
||||||
|
>
|
||||||
|
Mehr über uns
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<PlaceholderImage
|
||||||
|
icon={Building2}
|
||||||
|
label="Bild: Der Storfwirt in Reutte"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Testimonials */}
|
||||||
|
<Section className="bg-cream">
|
||||||
|
<AnimatedSection>
|
||||||
|
<div className="text-center mb-12">
|
||||||
|
<h2 className="font-heading text-3xl sm:text-4xl font-bold text-bark mb-4">
|
||||||
|
Das sagen unsere Gäste
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
|
{testimonials.map((testimonial, index) => (
|
||||||
|
<AnimatedSection key={testimonial.author} delay={index * 0.1}>
|
||||||
|
<div className="rounded-xl bg-sand p-6 sm:p-8 h-full flex flex-col">
|
||||||
|
<div className="flex gap-1 mb-4" aria-label="5 von 5 Sternen">
|
||||||
|
{Array.from({ length: 5 }).map((_, i) => (
|
||||||
|
<Star
|
||||||
|
key={i}
|
||||||
|
className="h-4 w-4 fill-accent text-accent"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<blockquote className="text-bark leading-relaxed flex-1">
|
||||||
|
“{testimonial.quote}”
|
||||||
|
</blockquote>
|
||||||
|
<div className="mt-4 pt-4 border-t border-driftwood">
|
||||||
|
<p className="font-medium text-bark text-sm">
|
||||||
|
{testimonial.author}
|
||||||
|
</p>
|
||||||
|
{testimonial.role && (
|
||||||
|
<p className="text-bark-light text-xs mt-0.5">
|
||||||
|
{testimonial.role}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Contact CTA */}
|
||||||
|
<ContactCTA />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
181
website/src/app/restaurant/page.tsx
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import {
|
||||||
|
ArrowRight,
|
||||||
|
Users,
|
||||||
|
Maximize2,
|
||||||
|
MapPin,
|
||||||
|
Wifi,
|
||||||
|
Car,
|
||||||
|
Music,
|
||||||
|
Building2,
|
||||||
|
} from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { AnimatedSection } from "@/components/AnimatedSection";
|
||||||
|
import { Section } from "@/components/Section";
|
||||||
|
import { ContactCTA } from "@/components/ContactCTA";
|
||||||
|
import { PlaceholderImage } from "@/components/PlaceholderImage";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Restaurant & Eventlocation",
|
||||||
|
description:
|
||||||
|
"Eventlocation in Reutte – flexibel einrichtbare Räume für Firmenfeiern, Hochzeiten und private Veranstaltungen. Zentral gelegen im Herzen von Reutte.",
|
||||||
|
};
|
||||||
|
|
||||||
|
const features = [
|
||||||
|
{
|
||||||
|
icon: Users,
|
||||||
|
title: "Bis zu 120 Gäste",
|
||||||
|
description: "Genug Platz für große Feiern, gemütlich genug für kleine Runden.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Maximize2,
|
||||||
|
title: "Flexible Raumgestaltung",
|
||||||
|
description: "Bestuhlung, Tischanordnung und Deko – wir richten den Raum nach Ihren Wünschen ein.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: MapPin,
|
||||||
|
title: "Zentrale Lage",
|
||||||
|
description: "Mitten in Reutte, gut erreichbar aus dem gesamten Außerfern und dem Allgäu.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Car,
|
||||||
|
title: "Parkplätze vorhanden",
|
||||||
|
description: "Ihre Gäste finden direkt vor dem Haus genügend Parkmöglichkeiten.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Wifi,
|
||||||
|
title: "Moderne Ausstattung",
|
||||||
|
description: "WLAN, Beamer und Tonanlage – für Präsentationen und Feiern gleichermaßen.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Music,
|
||||||
|
title: "Musik & Unterhaltung",
|
||||||
|
description: "Eigene Musikanlage vorhanden. Live-Musik oder DJ? Organisieren wir gerne.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function RestaurantPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Hero */}
|
||||||
|
<section className="bg-gradient-to-br from-primary-dark to-primary pt-32 pb-20 sm:pt-40 sm:pb-28">
|
||||||
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||||
|
<AnimatedSection>
|
||||||
|
<p className="text-accent-light font-medium mb-3">
|
||||||
|
Eventlocation in Reutte
|
||||||
|
</p>
|
||||||
|
<h1 className="font-heading text-4xl sm:text-5xl lg:text-6xl font-bold text-white leading-tight tracking-tight max-w-3xl">
|
||||||
|
Räume, die zu Ihrem Event passen
|
||||||
|
</h1>
|
||||||
|
<p className="mt-6 text-lg text-white/80 max-w-2xl leading-relaxed">
|
||||||
|
Nicht jeder Raum passt zu jedem Anlass. Unsere Location lässt sich
|
||||||
|
so einrichten, wie Sie es brauchen – ob Seminar, Hochzeit oder
|
||||||
|
Vereinsabend.
|
||||||
|
</p>
|
||||||
|
<Link
|
||||||
|
href="/kontakt"
|
||||||
|
className="inline-flex items-center gap-2 mt-8 rounded-lg bg-white px-6 py-3.5 text-base font-semibold text-primary hover:bg-sand transition-colors focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-dark"
|
||||||
|
>
|
||||||
|
Location anfragen
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
</AnimatedSection>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Features */}
|
||||||
|
<Section className="bg-cream">
|
||||||
|
<AnimatedSection>
|
||||||
|
<h2 className="font-heading text-3xl sm:text-4xl font-bold text-bark mb-4 text-center">
|
||||||
|
Was unsere Location bietet
|
||||||
|
</h2>
|
||||||
|
<p className="text-bark-light text-lg max-w-2xl mx-auto text-center mb-12">
|
||||||
|
Alles unter einem Dach: Raum, Küche, Service.
|
||||||
|
</p>
|
||||||
|
</AnimatedSection>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{features.map((feature, index) => (
|
||||||
|
<AnimatedSection key={feature.title} delay={index * 0.08}>
|
||||||
|
<div className="rounded-xl border border-driftwood bg-cream p-6 h-full">
|
||||||
|
<feature.icon className="h-7 w-7 text-primary mb-3" />
|
||||||
|
<h3 className="font-heading text-lg font-semibold text-bark mb-1.5">
|
||||||
|
{feature.title}
|
||||||
|
</h3>
|
||||||
|
<p className="text-bark-light text-sm leading-relaxed">
|
||||||
|
{feature.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Atmosphere */}
|
||||||
|
<Section className="bg-sand">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||||
|
<AnimatedSection>
|
||||||
|
<h2 className="font-heading text-3xl font-bold text-bark mb-6">
|
||||||
|
Einladend, nicht steif
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-4 text-bark-light leading-relaxed">
|
||||||
|
<p>
|
||||||
|
Unsere Räume sind warm und einladend eingerichtet. Hier fühlen
|
||||||
|
sich Ihre Gäste willkommen – ohne dass es nach Konferenzraum
|
||||||
|
aussieht.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Die Kombination aus gutem Essen direkt aus unserer Küche und einer
|
||||||
|
Location, die sich anpassen lässt, macht den Unterschied. Sie
|
||||||
|
müssen keinen externen Caterer organisieren – bei uns kommt alles
|
||||||
|
aus einer Hand.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Und wenn Sie nach dem Event noch zusammensitzen wollen? Der
|
||||||
|
Storfwirt schließt nicht, solange Sie feiern.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
<AnimatedSection delay={0.1}>
|
||||||
|
<PlaceholderImage
|
||||||
|
icon={Building2}
|
||||||
|
label="Bild: Innenansicht der Eventlocation"
|
||||||
|
/>
|
||||||
|
</AnimatedSection>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Gallery placeholder */}
|
||||||
|
<Section className="bg-cream">
|
||||||
|
<AnimatedSection>
|
||||||
|
<h2 className="font-heading text-3xl font-bold text-bark mb-8 text-center">
|
||||||
|
Eindrücke
|
||||||
|
</h2>
|
||||||
|
</AnimatedSection>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
|
{[
|
||||||
|
"Saal mit Tischgedeck",
|
||||||
|
"Stehempfang",
|
||||||
|
"Buffet-Aufbau",
|
||||||
|
"Festliche Dekoration",
|
||||||
|
"Außenbereich",
|
||||||
|
"Bar & Getränke",
|
||||||
|
].map((label, index) => (
|
||||||
|
<AnimatedSection key={label} delay={index * 0.08}>
|
||||||
|
<PlaceholderImage
|
||||||
|
icon={Building2}
|
||||||
|
label={`Bild: ${label}`}
|
||||||
|
aspectRatio="aspect-square"
|
||||||
|
/>
|
||||||
|
</AnimatedSection>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* CTA */}
|
||||||
|
<ContactCTA
|
||||||
|
headline="Ihre Feier, unsere Räume"
|
||||||
|
text="Beschreiben Sie uns Ihr Event – wir prüfen die Verfügbarkeit und melden uns."
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
193
website/src/app/ueber-uns/page.tsx
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import { Leaf, Heart, Users, ArrowRight } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { AnimatedSection } from "@/components/AnimatedSection";
|
||||||
|
import { Section } from "@/components/Section";
|
||||||
|
import { PlaceholderImage } from "@/components/PlaceholderImage";
|
||||||
|
import { ContactCTA } from "@/components/ContactCTA";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Über uns",
|
||||||
|
description:
|
||||||
|
"Lernen Sie den Storfwirt Reutte kennen – unsere Geschichte, unsere Werte und unser Team. Seit Jahren verwurzelt in Reutte und dem Außerfern.",
|
||||||
|
};
|
||||||
|
|
||||||
|
const values = [
|
||||||
|
{
|
||||||
|
icon: Leaf,
|
||||||
|
title: "Regional & frisch",
|
||||||
|
description:
|
||||||
|
"Unsere Zutaten kommen aus der Umgebung. Kurze Wege, frische Produkte, weniger Umweltbelastung. Nicht, weil es im Trend liegt – sondern weil wir das schon immer so gemacht haben.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Heart,
|
||||||
|
title: "Mit Herz & Handwerk",
|
||||||
|
description:
|
||||||
|
"Bei uns wird noch selbst gekocht. Keine Fertigprodukte, keine Abkürzungen. Das schmeckt man, und das soll auch so bleiben.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Users,
|
||||||
|
title: "Persönlich & direkt",
|
||||||
|
description:
|
||||||
|
"Wenn Sie bei uns anrufen, sprechen Sie mit jemandem, der Ihr Event auch betreut. Keine Weiterleitungen, kein Callcenter. So arbeiten wir.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const team = [
|
||||||
|
{
|
||||||
|
name: "Vorname Nachname",
|
||||||
|
role: "Geschäftsführung & Küche",
|
||||||
|
description: "Seit über 20 Jahren in der Gastronomie und der Kopf hinter dem Storfwirt.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Vorname Nachname",
|
||||||
|
role: "Eventorganisation",
|
||||||
|
description: "Zuständig für die Planung und Betreuung aller Veranstaltungen.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Vorname Nachname",
|
||||||
|
role: "Küche & Catering",
|
||||||
|
description: "Sorgt dafür, dass jeden Tag frisch und auf den Punkt gekocht wird.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function UeberUnsPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Hero */}
|
||||||
|
<section className="bg-gradient-to-br from-primary-dark to-primary pt-32 pb-20 sm:pt-40 sm:pb-28">
|
||||||
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||||
|
<AnimatedSection>
|
||||||
|
<p className="text-accent-light font-medium mb-3">
|
||||||
|
Über uns
|
||||||
|
</p>
|
||||||
|
<h1 className="font-heading text-4xl sm:text-5xl lg:text-6xl font-bold text-white leading-tight tracking-tight max-w-3xl">
|
||||||
|
Gastfreundschaft ist bei uns kein Slogan
|
||||||
|
</h1>
|
||||||
|
<p className="mt-6 text-lg text-white/80 max-w-2xl leading-relaxed">
|
||||||
|
Wir sind ein Familienbetrieb aus Reutte. Was wir machen, machen wir
|
||||||
|
seit Jahren – und wir machen es gerne.
|
||||||
|
</p>
|
||||||
|
</AnimatedSection>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Story */}
|
||||||
|
<Section className="bg-cream">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||||
|
<AnimatedSection>
|
||||||
|
<h2 className="font-heading text-3xl sm:text-4xl font-bold text-bark mb-6">
|
||||||
|
Unsere Geschichte
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-4 text-bark-light leading-relaxed">
|
||||||
|
<p>
|
||||||
|
Der Storfwirt hat als klassischer Gasthof in Reutte angefangen.
|
||||||
|
Gut bürgerliche Küche, Stammtisch, Sonntagsbraten. So wie man
|
||||||
|
sich das vorstellt.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Mit der Zeit kamen die Anfragen: Ob wir nicht auch für die
|
||||||
|
Firmenfeier kochen könnten. Ob die Räume für eine Hochzeit
|
||||||
|
gehen. Ob wir vielleicht auch Geschenkkörbe zusammenstellen.
|
||||||
|
Jede Anfrage haben wir als Einladung verstanden, besser zu
|
||||||
|
werden.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Heute sind wir die erste Adresse für Catering und Events
|
||||||
|
im Außerfern. Aber wir machen immer noch, was wir am Anfang
|
||||||
|
gemacht haben: kochen, was gut ist. Und uns um unsere Gäste
|
||||||
|
kümmern.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
<AnimatedSection delay={0.1}>
|
||||||
|
<PlaceholderImage
|
||||||
|
icon={Users}
|
||||||
|
label="Bild: Das Team vom Storfwirt"
|
||||||
|
/>
|
||||||
|
</AnimatedSection>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Values */}
|
||||||
|
<Section className="bg-sand">
|
||||||
|
<AnimatedSection>
|
||||||
|
<h2 className="font-heading text-3xl sm:text-4xl font-bold text-bark mb-12 text-center">
|
||||||
|
Wofür wir stehen
|
||||||
|
</h2>
|
||||||
|
</AnimatedSection>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
|
{values.map((value, index) => (
|
||||||
|
<AnimatedSection key={value.title} delay={index * 0.1}>
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="inline-flex items-center justify-center w-14 h-14 rounded-full bg-primary/10 mb-4">
|
||||||
|
<value.icon className="h-7 w-7 text-primary" />
|
||||||
|
</div>
|
||||||
|
<h3 className="font-heading text-xl font-semibold text-bark mb-3">
|
||||||
|
{value.title}
|
||||||
|
</h3>
|
||||||
|
<p className="text-bark-light leading-relaxed">
|
||||||
|
{value.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Team */}
|
||||||
|
<Section className="bg-cream">
|
||||||
|
<AnimatedSection>
|
||||||
|
<h2 className="font-heading text-3xl sm:text-4xl font-bold text-bark mb-4 text-center">
|
||||||
|
Unser Team
|
||||||
|
</h2>
|
||||||
|
<p className="text-bark-light text-center max-w-xl mx-auto mb-12">
|
||||||
|
Klein, eingespielt, verlässlich. Die Menschen hinter dem Storfwirt.
|
||||||
|
</p>
|
||||||
|
</AnimatedSection>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-6">
|
||||||
|
{team.map((member, index) => (
|
||||||
|
<AnimatedSection key={member.role} delay={index * 0.1}>
|
||||||
|
<div className="rounded-xl border border-driftwood bg-sand p-6 text-center h-full">
|
||||||
|
<div className="w-20 h-20 rounded-full bg-gradient-to-br from-primary/15 to-accent/15 mx-auto mb-4 flex items-center justify-center">
|
||||||
|
<Users className="h-8 w-8 text-primary/40" />
|
||||||
|
</div>
|
||||||
|
<h3 className="font-heading text-lg font-semibold text-bark">
|
||||||
|
{member.name}
|
||||||
|
</h3>
|
||||||
|
<p className="text-primary text-sm font-medium mt-1">
|
||||||
|
{member.role}
|
||||||
|
</p>
|
||||||
|
<p className="text-bark-light text-sm mt-3 leading-relaxed">
|
||||||
|
{member.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* CTA */}
|
||||||
|
<Section className="bg-sand">
|
||||||
|
<AnimatedSection>
|
||||||
|
<div className="max-w-2xl mx-auto text-center">
|
||||||
|
<h2 className="font-heading text-3xl font-bold text-bark mb-4">
|
||||||
|
Lernen Sie uns kennen
|
||||||
|
</h2>
|
||||||
|
<p className="text-bark-light leading-relaxed mb-6">
|
||||||
|
Am besten persönlich. Schauen Sie vorbei, rufen Sie an
|
||||||
|
oder schreiben Sie uns. Wir freuen uns auf Sie.
|
||||||
|
</p>
|
||||||
|
<Link
|
||||||
|
href="/kontakt"
|
||||||
|
className="inline-flex items-center gap-2 rounded-lg bg-primary px-6 py-3 text-base font-medium text-white hover:bg-primary-dark transition-colors focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2"
|
||||||
|
>
|
||||||
|
Kontakt aufnehmen
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</AnimatedSection>
|
||||||
|
</Section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
31
website/src/components/AnimatedSection.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useRef } from "react";
|
||||||
|
import { motion, useInView } from "framer-motion";
|
||||||
|
|
||||||
|
interface AnimatedSectionProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
|
delay?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AnimatedSection({
|
||||||
|
children,
|
||||||
|
className = "",
|
||||||
|
delay = 0,
|
||||||
|
}: AnimatedSectionProps) {
|
||||||
|
const ref = useRef(null);
|
||||||
|
const isInView = useInView(ref, { once: true, margin: "-80px" });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
ref={ref}
|
||||||
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 24 }}
|
||||||
|
transition={{ duration: 0.6, ease: "easeOut", delay }}
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
}
|
||||||
41
website/src/components/ContactCTA.tsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import { Phone, ArrowRight } from "lucide-react";
|
||||||
|
|
||||||
|
interface ContactCTAProps {
|
||||||
|
headline?: string;
|
||||||
|
text?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ContactCTA({
|
||||||
|
headline = "Wir freuen uns auf Ihre Anfrage",
|
||||||
|
text = "Erzählen Sie uns von Ihrem Event – wir melden uns zeitnah.",
|
||||||
|
}: ContactCTAProps) {
|
||||||
|
return (
|
||||||
|
<section className="bg-primary py-16 sm:py-20">
|
||||||
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 text-center">
|
||||||
|
<h2 className="font-heading text-3xl sm:text-4xl font-bold text-white mb-4">
|
||||||
|
{headline}
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg text-white/80 max-w-2xl mx-auto mb-8">
|
||||||
|
{text}
|
||||||
|
</p>
|
||||||
|
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
|
||||||
|
<Link
|
||||||
|
href="/kontakt"
|
||||||
|
className="inline-flex items-center gap-2 rounded-lg bg-white px-6 py-3 text-base font-medium text-primary hover:bg-sand transition-colors focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary"
|
||||||
|
>
|
||||||
|
Event anfragen
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
<a
|
||||||
|
href="tel:+43567200000"
|
||||||
|
className="inline-flex items-center gap-2 rounded-lg border border-white/30 px-6 py-3 text-base font-medium text-white hover:bg-white/10 transition-colors focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary"
|
||||||
|
>
|
||||||
|
<Phone className="h-4 w-4" />
|
||||||
|
+43 5672 00000
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
271
website/src/components/ContactForm.tsx
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState, type FormEvent } from "react";
|
||||||
|
import { Send, CheckCircle2 } from "lucide-react";
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
phone: string;
|
||||||
|
eventType: string;
|
||||||
|
date: string;
|
||||||
|
guests: string;
|
||||||
|
message: string;
|
||||||
|
privacy: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialFormData: FormData = {
|
||||||
|
name: "",
|
||||||
|
email: "",
|
||||||
|
phone: "",
|
||||||
|
eventType: "",
|
||||||
|
date: "",
|
||||||
|
guests: "",
|
||||||
|
message: "",
|
||||||
|
privacy: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const eventTypes = [
|
||||||
|
"Firmenfeier",
|
||||||
|
"Hochzeit",
|
||||||
|
"Vereinsveranstaltung",
|
||||||
|
"Private Feier",
|
||||||
|
"Catering-Anfrage",
|
||||||
|
"Geschenkkorb",
|
||||||
|
"Sonstiges",
|
||||||
|
];
|
||||||
|
|
||||||
|
export function ContactForm() {
|
||||||
|
const [formData, setFormData] = useState<FormData>(initialFormData);
|
||||||
|
const [isSubmitted, setIsSubmitted] = useState(false);
|
||||||
|
const [errors, setErrors] = useState<Partial<Record<keyof FormData, string>>>({});
|
||||||
|
|
||||||
|
function validate(): boolean {
|
||||||
|
const newErrors: Partial<Record<keyof FormData, string>> = {};
|
||||||
|
|
||||||
|
if (!formData.name.trim()) {
|
||||||
|
newErrors.name = "Bitte geben Sie Ihren Namen ein.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!formData.email.trim()) {
|
||||||
|
newErrors.email = "Bitte geben Sie Ihre E-Mail-Adresse ein.";
|
||||||
|
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
|
||||||
|
newErrors.email = "Bitte geben Sie eine gültige E-Mail-Adresse ein.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!formData.message.trim()) {
|
||||||
|
newErrors.message = "Bitte beschreiben Sie kurz Ihr Anliegen.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!formData.privacy) {
|
||||||
|
newErrors.privacy = "Bitte bestätigen Sie die Datenschutzerklärung.";
|
||||||
|
}
|
||||||
|
|
||||||
|
setErrors(newErrors);
|
||||||
|
return Object.keys(newErrors).length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSubmit(e: FormEvent) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!validate()) return;
|
||||||
|
|
||||||
|
// TODO: Connect to actual form submission endpoint
|
||||||
|
// Options: API route, FormSubmit.co, Netlify Forms, etc.
|
||||||
|
// For now, we simulate a successful submission.
|
||||||
|
setIsSubmitted(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleChange(
|
||||||
|
field: keyof FormData,
|
||||||
|
value: string | boolean
|
||||||
|
) {
|
||||||
|
setFormData((prev) => ({ ...prev, [field]: value }));
|
||||||
|
if (errors[field]) {
|
||||||
|
setErrors((prev) => ({ ...prev, [field]: undefined }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSubmitted) {
|
||||||
|
return (
|
||||||
|
<div className="rounded-xl border border-driftwood bg-sand p-8 sm:p-12 text-center">
|
||||||
|
<CheckCircle2 className="h-12 w-12 text-primary mx-auto mb-4" />
|
||||||
|
<h3 className="font-heading text-2xl font-bold text-bark mb-2">
|
||||||
|
Vielen Dank für Ihre Anfrage
|
||||||
|
</h3>
|
||||||
|
<p className="text-bark-light leading-relaxed max-w-md mx-auto">
|
||||||
|
Wir haben Ihre Nachricht erhalten und melden uns zeitnah bei Ihnen.
|
||||||
|
In der Regel innerhalb von 24 Stunden.
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
setIsSubmitted(false);
|
||||||
|
setFormData(initialFormData);
|
||||||
|
}}
|
||||||
|
className="mt-6 text-sm text-primary font-medium hover:underline"
|
||||||
|
>
|
||||||
|
Weitere Anfrage senden
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputClasses =
|
||||||
|
"w-full rounded-lg border border-driftwood bg-cream px-4 py-3 text-bark placeholder:text-bark-light/50 focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary transition-colors";
|
||||||
|
const labelClasses = "block text-sm font-medium text-bark mb-1.5";
|
||||||
|
const errorClasses = "text-red-600 text-xs mt-1";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit} noValidate className="space-y-5">
|
||||||
|
{/* Name */}
|
||||||
|
<div>
|
||||||
|
<label htmlFor="contact-name" className={labelClasses}>
|
||||||
|
Name <span className="text-red-500">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="contact-name"
|
||||||
|
type="text"
|
||||||
|
autoComplete="name"
|
||||||
|
value={formData.name}
|
||||||
|
onChange={(e) => handleChange("name", e.target.value)}
|
||||||
|
className={inputClasses}
|
||||||
|
placeholder="Ihr Name"
|
||||||
|
/>
|
||||||
|
{errors.name && <p className={errorClasses}>{errors.name}</p>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Email + Phone */}
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-5">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="contact-email" className={labelClasses}>
|
||||||
|
E-Mail <span className="text-red-500">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="contact-email"
|
||||||
|
type="email"
|
||||||
|
autoComplete="email"
|
||||||
|
value={formData.email}
|
||||||
|
onChange={(e) => handleChange("email", e.target.value)}
|
||||||
|
className={inputClasses}
|
||||||
|
placeholder="ihre@email.at"
|
||||||
|
/>
|
||||||
|
{errors.email && <p className={errorClasses}>{errors.email}</p>}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="contact-phone" className={labelClasses}>
|
||||||
|
Telefon
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="contact-phone"
|
||||||
|
type="tel"
|
||||||
|
autoComplete="tel"
|
||||||
|
value={formData.phone}
|
||||||
|
onChange={(e) => handleChange("phone", e.target.value)}
|
||||||
|
className={inputClasses}
|
||||||
|
placeholder="+43 ..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Event Type + Date */}
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-5">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="contact-event-type" className={labelClasses}>
|
||||||
|
Art der Veranstaltung
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="contact-event-type"
|
||||||
|
value={formData.eventType}
|
||||||
|
onChange={(e) => handleChange("eventType", e.target.value)}
|
||||||
|
className={inputClasses}
|
||||||
|
>
|
||||||
|
<option value="">Bitte wählen</option>
|
||||||
|
{eventTypes.map((type) => (
|
||||||
|
<option key={type} value={type}>
|
||||||
|
{type}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="contact-date" className={labelClasses}>
|
||||||
|
Gewünschtes Datum
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="contact-date"
|
||||||
|
type="date"
|
||||||
|
value={formData.date}
|
||||||
|
onChange={(e) => handleChange("date", e.target.value)}
|
||||||
|
className={inputClasses}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Guests */}
|
||||||
|
<div>
|
||||||
|
<label htmlFor="contact-guests" className={labelClasses}>
|
||||||
|
Ungefähre Gästeanzahl
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="contact-guests"
|
||||||
|
type="text"
|
||||||
|
value={formData.guests}
|
||||||
|
onChange={(e) => handleChange("guests", e.target.value)}
|
||||||
|
className={inputClasses}
|
||||||
|
placeholder="z.B. ca. 50 Personen"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Message */}
|
||||||
|
<div>
|
||||||
|
<label htmlFor="contact-message" className={labelClasses}>
|
||||||
|
Ihre Nachricht <span className="text-red-500">*</span>
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
id="contact-message"
|
||||||
|
rows={5}
|
||||||
|
value={formData.message}
|
||||||
|
onChange={(e) => handleChange("message", e.target.value)}
|
||||||
|
className={inputClasses}
|
||||||
|
placeholder="Beschreiben Sie kurz, was Sie planen..."
|
||||||
|
/>
|
||||||
|
{errors.message && <p className={errorClasses}>{errors.message}</p>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Privacy */}
|
||||||
|
<div>
|
||||||
|
<label className="flex items-start gap-3 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={formData.privacy}
|
||||||
|
onChange={(e) => handleChange("privacy", e.target.checked)}
|
||||||
|
className="mt-1 h-4 w-4 rounded border-driftwood text-primary focus:ring-primary"
|
||||||
|
/>
|
||||||
|
<span className="text-sm text-bark-light">
|
||||||
|
Ich habe die{" "}
|
||||||
|
<a
|
||||||
|
href="/datenschutz"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-primary underline hover:text-primary-dark"
|
||||||
|
>
|
||||||
|
Datenschutzerklärung
|
||||||
|
</a>{" "}
|
||||||
|
gelesen und stimme der Verarbeitung meiner Daten zu.{" "}
|
||||||
|
<span className="text-red-500">*</span>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
{errors.privacy && <p className={errorClasses}>{errors.privacy}</p>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Submit */}
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="inline-flex items-center gap-2 rounded-lg bg-primary px-6 py-3 text-base font-medium text-white hover:bg-primary-dark transition-colors focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 w-full sm:w-auto justify-center"
|
||||||
|
>
|
||||||
|
<Send className="h-4 w-4" />
|
||||||
|
Anfrage senden
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
134
website/src/components/Footer.tsx
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { Phone, Mail, MapPin, Clock } from "lucide-react";
|
||||||
|
|
||||||
|
const footerNavLinks = [
|
||||||
|
{ href: "/catering", label: "Catering" },
|
||||||
|
{ href: "/restaurant", label: "Restaurant" },
|
||||||
|
{ href: "/leistungen", label: "Leistungen" },
|
||||||
|
{ href: "/mittagstisch", label: "Mittagstisch" },
|
||||||
|
{ href: "/feinkost", label: "Feinkost" },
|
||||||
|
{ href: "/ueber-uns", label: "Über uns" },
|
||||||
|
{ href: "/kontakt", label: "Kontakt" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const legalLinks = [
|
||||||
|
{ href: "/impressum", label: "Impressum" },
|
||||||
|
{ href: "/datenschutz", label: "Datenschutz" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export function Footer() {
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<footer className="bg-primary-dark text-white" role="contentinfo">
|
||||||
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-16">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-12">
|
||||||
|
{/* Brand */}
|
||||||
|
<div>
|
||||||
|
<Link href="/" className="inline-block">
|
||||||
|
<Image
|
||||||
|
src="/assets/logo.png"
|
||||||
|
alt="Storfwirt Reutte Logo"
|
||||||
|
width={160}
|
||||||
|
height={50}
|
||||||
|
className="h-10 w-auto object-contain brightness-0 invert"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
<p className="mt-4 text-sm text-white/70 leading-relaxed">
|
||||||
|
Catering, Eventlocation und regionale Küche in Reutte.
|
||||||
|
Seit Jahren die erste Adresse im Außerfern.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Navigation */}
|
||||||
|
<div>
|
||||||
|
<h3 className="font-heading text-sm font-semibold uppercase tracking-wider mb-4">
|
||||||
|
Navigation
|
||||||
|
</h3>
|
||||||
|
<ul className="space-y-2">
|
||||||
|
{footerNavLinks.map((link) => (
|
||||||
|
<li key={link.href}>
|
||||||
|
<Link
|
||||||
|
href={link.href}
|
||||||
|
className="text-sm text-white/70 hover:text-white transition-colors"
|
||||||
|
>
|
||||||
|
{link.label}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Contact */}
|
||||||
|
<div>
|
||||||
|
<h3 className="font-heading text-sm font-semibold uppercase tracking-wider mb-4">
|
||||||
|
Kontakt
|
||||||
|
</h3>
|
||||||
|
<ul className="space-y-3">
|
||||||
|
<li className="flex items-start gap-3 text-sm text-white/70">
|
||||||
|
<MapPin className="h-4 w-4 mt-0.5 shrink-0" />
|
||||||
|
<span>
|
||||||
|
Musterstraße 1
|
||||||
|
<br />
|
||||||
|
6600 Reutte, Tirol
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="tel:+43567200000"
|
||||||
|
className="flex items-center gap-3 text-sm text-white/70 hover:text-white transition-colors"
|
||||||
|
>
|
||||||
|
<Phone className="h-4 w-4 shrink-0" />
|
||||||
|
+43 5672 00000
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="mailto:info@storfwirt-reutte.at"
|
||||||
|
className="flex items-center gap-3 text-sm text-white/70 hover:text-white transition-colors"
|
||||||
|
>
|
||||||
|
<Mail className="h-4 w-4 shrink-0" />
|
||||||
|
info@storfwirt-reutte.at
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Hours */}
|
||||||
|
<div>
|
||||||
|
<h3 className="font-heading text-sm font-semibold uppercase tracking-wider mb-4">
|
||||||
|
Öffnungszeiten
|
||||||
|
</h3>
|
||||||
|
<div className="flex items-start gap-3 text-sm text-white/70">
|
||||||
|
<Clock className="h-4 w-4 mt-0.5 shrink-0" />
|
||||||
|
<div className="space-y-1">
|
||||||
|
<p>Mo – Fr: 11:00 – 14:00</p>
|
||||||
|
<p>Sa: nach Vereinbarung</p>
|
||||||
|
<p>So: Ruhetag</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Bottom */}
|
||||||
|
<div className="mt-12 pt-8 border-t border-white/10 flex flex-col sm:flex-row items-center justify-between gap-4">
|
||||||
|
<p className="text-xs text-white/50">
|
||||||
|
© {currentYear} Storfwirt Reutte. Alle Rechte vorbehalten.
|
||||||
|
</p>
|
||||||
|
<div className="flex gap-6">
|
||||||
|
{legalLinks.map((link) => (
|
||||||
|
<Link
|
||||||
|
key={link.href}
|
||||||
|
href={link.href}
|
||||||
|
className="text-xs text-white/50 hover:text-white/70 transition-colors"
|
||||||
|
>
|
||||||
|
{link.label}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
150
website/src/components/Header.tsx
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { usePathname } from "next/navigation";
|
||||||
|
import { Menu, X, Phone } from "lucide-react";
|
||||||
|
import { AnimatePresence, motion } from "framer-motion";
|
||||||
|
|
||||||
|
const navLinks = [
|
||||||
|
{ href: "/catering", label: "Catering" },
|
||||||
|
{ href: "/restaurant", label: "Restaurant" },
|
||||||
|
{ href: "/leistungen", label: "Leistungen" },
|
||||||
|
{ href: "/mittagstisch", label: "Mittagstisch" },
|
||||||
|
{ href: "/feinkost", label: "Feinkost" },
|
||||||
|
{ href: "/ueber-uns", label: "Über uns" },
|
||||||
|
{ href: "/kontakt", label: "Kontakt" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export function Header() {
|
||||||
|
const [isScrolled, setIsScrolled] = useState(false);
|
||||||
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleScroll = () => {
|
||||||
|
setIsScrolled(window.scrollY > 20);
|
||||||
|
};
|
||||||
|
window.addEventListener("scroll", handleScroll, { passive: true });
|
||||||
|
return () => window.removeEventListener("scroll", handleScroll);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isMobileMenuOpen) {
|
||||||
|
document.body.style.overflow = "hidden";
|
||||||
|
} else {
|
||||||
|
document.body.style.overflow = "";
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
document.body.style.overflow = "";
|
||||||
|
};
|
||||||
|
}, [isMobileMenuOpen]);
|
||||||
|
|
||||||
|
// Close mobile menu on route change
|
||||||
|
useEffect(() => {
|
||||||
|
setIsMobileMenuOpen(false);
|
||||||
|
}, [pathname]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<header
|
||||||
|
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
|
||||||
|
isScrolled
|
||||||
|
? "bg-white/95 backdrop-blur-sm shadow-sm py-3"
|
||||||
|
: "bg-transparent py-5"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<nav
|
||||||
|
className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 flex items-center justify-between"
|
||||||
|
aria-label="Hauptnavigation"
|
||||||
|
>
|
||||||
|
<Link href="/" className="shrink-0">
|
||||||
|
<Image
|
||||||
|
src="/assets/logo.png"
|
||||||
|
alt="Storfwirt Reutte Logo"
|
||||||
|
width={180}
|
||||||
|
height={56}
|
||||||
|
className="h-10 w-auto sm:h-12 lg:h-14 object-contain"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Desktop Navigation */}
|
||||||
|
<div className="hidden lg:flex items-center gap-7">
|
||||||
|
{navLinks.map((link) => (
|
||||||
|
<Link
|
||||||
|
key={link.href}
|
||||||
|
href={link.href}
|
||||||
|
className={`text-sm font-medium transition-colors ${
|
||||||
|
pathname === link.href
|
||||||
|
? "text-primary"
|
||||||
|
: "text-bark-light hover:text-primary"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{link.label}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
<Link
|
||||||
|
href="/kontakt"
|
||||||
|
className="inline-flex items-center gap-2 rounded-lg bg-primary px-5 py-2.5 text-sm font-medium text-white hover:bg-primary-dark transition-colors focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2"
|
||||||
|
>
|
||||||
|
<Phone className="h-4 w-4" />
|
||||||
|
Event anfragen
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile Menu Button */}
|
||||||
|
<button
|
||||||
|
className="lg:hidden p-2 text-bark hover:text-primary transition-colors"
|
||||||
|
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
||||||
|
aria-label={isMobileMenuOpen ? "Menü schließen" : "Menü öffnen"}
|
||||||
|
aria-expanded={isMobileMenuOpen}
|
||||||
|
>
|
||||||
|
{isMobileMenuOpen ? (
|
||||||
|
<X className="h-6 w-6" />
|
||||||
|
) : (
|
||||||
|
<Menu className="h-6 w-6" />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{/* Mobile Menu */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{isMobileMenuOpen && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: -10 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, y: -10 }}
|
||||||
|
transition={{ duration: 0.2 }}
|
||||||
|
className="lg:hidden fixed inset-x-0 top-[60px] bottom-0 bg-white z-40 overflow-y-auto"
|
||||||
|
>
|
||||||
|
<div className="flex flex-col p-6 gap-1">
|
||||||
|
{navLinks.map((link) => (
|
||||||
|
<Link
|
||||||
|
key={link.href}
|
||||||
|
href={link.href}
|
||||||
|
className={`py-3 px-4 text-lg font-medium rounded-lg transition-colors ${
|
||||||
|
pathname === link.href
|
||||||
|
? "text-primary bg-sand"
|
||||||
|
: "text-bark hover:text-primary hover:bg-sand"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{link.label}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
<div className="mt-4 pt-4 border-t border-driftwood">
|
||||||
|
<Link
|
||||||
|
href="/kontakt"
|
||||||
|
className="inline-flex items-center justify-center gap-2 w-full rounded-lg bg-primary px-5 py-3 text-base font-medium text-white hover:bg-primary-dark transition-colors"
|
||||||
|
>
|
||||||
|
<Phone className="h-5 w-5" />
|
||||||
|
Event anfragen
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
}
|
||||||
26
website/src/components/PlaceholderImage.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import type { LucideIcon } from "lucide-react";
|
||||||
|
|
||||||
|
interface PlaceholderImageProps {
|
||||||
|
icon: LucideIcon;
|
||||||
|
label: string;
|
||||||
|
aspectRatio?: string;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PlaceholderImage({
|
||||||
|
icon: Icon,
|
||||||
|
label,
|
||||||
|
aspectRatio = "aspect-[4/3]",
|
||||||
|
className = "",
|
||||||
|
}: PlaceholderImageProps) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`relative ${aspectRatio} rounded-xl bg-gradient-to-br from-primary/8 via-sand-dark to-accent/8 flex items-center justify-center overflow-hidden ${className}`}
|
||||||
|
>
|
||||||
|
<div className="text-center p-8">
|
||||||
|
<Icon className="h-16 w-16 text-primary/25 mx-auto mb-3" />
|
||||||
|
<p className="text-bark-light/50 text-sm">{label}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
website/src/components/Section.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
interface SectionProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
|
id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Section({ children, className = "", id }: SectionProps) {
|
||||||
|
return (
|
||||||
|
<section id={id} className={`py-16 sm:py-20 lg:py-24 ${className}`}>
|
||||||
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">{children}</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
34
website/tsconfig.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2017",
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"incremental": true,
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"next-env.d.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".next/types/**/*.ts",
|
||||||
|
".next/dev/types/**/*.ts",
|
||||||
|
"**/*.mts"
|
||||||
|
],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||