diff --git a/src/app/(marketing)/contact/page.tsx b/src/app/(marketing)/contact/page.tsx index 0161544..ee26513 100644 --- a/src/app/(marketing)/contact/page.tsx +++ b/src/app/(marketing)/contact/page.tsx @@ -1,7 +1,7 @@ import type { Metadata } from "next"; -import Link from "next/link"; import { getTranslations } from "next-intl/server"; -import { LanguageSwitcher } from "@/components/LanguageSwitcher"; +import { SiteHeader } from "@/components/SiteHeader"; +import { SiteFooter } from "@/components/SiteFooter"; import { ContactForm } from "@/components/contact/ContactForm"; export const metadata: Metadata = { @@ -12,27 +12,11 @@ export const metadata: Metadata = { }; export default async function ContactPage() { - const t = await getTranslations(); const c = await getTranslations("contact"); return ( <> - +
@@ -47,27 +31,7 @@ export default async function ContactPage() {
- + ); } diff --git a/src/app/(marketing)/destination/[slug]/page.tsx b/src/app/(marketing)/destination/[slug]/page.tsx index 245317e..400c51a 100644 --- a/src/app/(marketing)/destination/[slug]/page.tsx +++ b/src/app/(marketing)/destination/[slug]/page.tsx @@ -2,8 +2,9 @@ import type { Metadata } from "next"; import Link from "next/link"; import { notFound } from "next/navigation"; import { getLocale, getTranslations } from "next-intl/server"; -import { LanguageSwitcher } from "@/components/LanguageSwitcher"; import { JsonLd } from "@/components/seo/JsonLd"; +import { SiteHeader } from "@/components/SiteHeader"; +import { SiteFooter } from "@/components/SiteFooter"; import { getCountryName } from "@/lib/data"; import { allDestinationSlugs, @@ -118,7 +119,6 @@ export default async function DestinationPage({ // German slugs force German rendering (see generateMetadata). const locale = entry.locale === "de" ? "de" : await getLocale(); const t = await getTranslations({ locale, namespace: "destination" }); - const nav = await getTranslations({ locale, namespace: "nav" }); const tip = await getTranslations({ locale, namespace: "tooltip" }); const alts = localizedSlugsForSlug(slug); const hrefByLocale = alts ? switcherHrefs(alts) : undefined; @@ -147,26 +147,12 @@ export default async function DestinationPage({ return ( <> - +
@@ -251,6 +237,8 @@ export default async function DestinationPage({
+ + ); } diff --git a/src/app/(marketing)/page.tsx b/src/app/(marketing)/page.tsx index 8def4f1..7839865 100644 --- a/src/app/(marketing)/page.tsx +++ b/src/app/(marketing)/page.tsx @@ -1,9 +1,10 @@ import type { Metadata } from "next"; import Link from "next/link"; import { getTranslations } from "next-intl/server"; -import { LanguageSwitcher } from "@/components/LanguageSwitcher"; import { JsonLd } from "@/components/seo/JsonLd"; import { HeroDestinationSearch } from "@/components/HeroDestinationSearch"; +import { SiteHeader } from "@/components/SiteHeader"; +import { SiteFooter } from "@/components/SiteFooter"; const webAppJsonLd = { "@context": "https://schema.org", @@ -115,41 +116,7 @@ export default async function MarketingPage() { return ( <> - {/* Navigation */} - + {/* Hero */}
@@ -368,36 +335,7 @@ export default async function MarketingPage() {
- {/* Footer */} - + ); } diff --git a/src/app/(marketing)/privacy/page.tsx b/src/app/(marketing)/privacy/page.tsx index 4d4b6a5..c6e7b78 100644 --- a/src/app/(marketing)/privacy/page.tsx +++ b/src/app/(marketing)/privacy/page.tsx @@ -1,7 +1,7 @@ import type { Metadata } from "next"; -import Link from "next/link"; import { getTranslations } from "next-intl/server"; -import { LanguageSwitcher } from "@/components/LanguageSwitcher"; +import { SiteHeader } from "@/components/SiteHeader"; +import { SiteFooter } from "@/components/SiteFooter"; export const metadata: Metadata = { title: "Privacy Policy — PackedPlaces.com", @@ -11,27 +11,11 @@ export const metadata: Metadata = { }; export default async function PrivacyPage() { - const t = await getTranslations(); const p = await getTranslations("privacy"); return ( <> - +
@@ -129,27 +113,7 @@ export default async function PrivacyPage() {
-
-
-

{t("footer.copyright", { year: new Date().getFullYear() })}

-
- - {t("footer.privacy")} - - - {t("footer.contact")} - - - {t("footer.github")} - -
-
-
+ ); } diff --git a/src/components/SiteFooter.tsx b/src/components/SiteFooter.tsx new file mode 100644 index 0000000..d590ceb --- /dev/null +++ b/src/components/SiteFooter.tsx @@ -0,0 +1,46 @@ +import Link from "next/link"; +import { getTranslations } from "next-intl/server"; + +interface Props { + /** Render the footer in a specific locale (e.g. a forced-German destination slug). */ + locale?: string; +} + +/** Shared site footer used across the landing page and content pages. */ +export async function SiteFooter({ locale }: Props) { + const t = locale + ? await getTranslations({ locale, namespace: "footer" }) + : await getTranslations("footer"); + + return ( + + ); +} diff --git a/src/components/SiteHeader.tsx b/src/components/SiteHeader.tsx new file mode 100644 index 0000000..0c787e5 --- /dev/null +++ b/src/components/SiteHeader.tsx @@ -0,0 +1,67 @@ +import Link from "next/link"; +import { getTranslations } from "next-intl/server"; +import { LanguageSwitcher } from "@/components/LanguageSwitcher"; + +interface Props { + /** Render the header in a specific locale (e.g. a forced-German destination slug). */ + locale?: string; + /** Selected locale for the switcher, when it differs from the request locale. */ + currentLocale?: string; + /** Per-locale hrefs so the switcher can jump to a localized URL. */ + hrefByLocale?: Record; + /** Target for the "open map" button; defaults to the generic map. */ + mapHref?: string; +} + +/** Shared site header used across the landing page and content pages. */ +export async function SiteHeader({ + locale, + currentLocale, + hrefByLocale, + mapHref = "/map", +}: Props) { + const t = locale + ? await getTranslations({ locale, namespace: "nav" }) + : await getTranslations("nav"); + + return ( + + ); +} diff --git a/src/components/features/FeaturePageShell.tsx b/src/components/features/FeaturePageShell.tsx index 765a8e6..427d9c7 100644 --- a/src/components/features/FeaturePageShell.tsx +++ b/src/components/features/FeaturePageShell.tsx @@ -1,6 +1,7 @@ import Link from "next/link"; import { getTranslations } from "next-intl/server"; -import { LanguageSwitcher } from "@/components/LanguageSwitcher"; +import { SiteHeader } from "@/components/SiteHeader"; +import { SiteFooter } from "@/components/SiteFooter"; const FEATURE_SLUGS = [ { slug: "crowdedness", key: "crowdedness" }, @@ -18,7 +19,6 @@ interface Props { } export async function FeaturePageShell({ slug, children }: Props) { - const t = await getTranslations(); const nav = await getTranslations("featurePages.nav"); const shell = await getTranslations("featurePages.shell"); const feature = await getTranslations(`featurePages.${FEATURE_SLUGS.find((f) => f.slug === slug)?.key ?? slug}`); @@ -27,22 +27,7 @@ export async function FeaturePageShell({ slug, children }: Props) { return ( <> - +
@@ -102,27 +87,7 @@ export async function FeaturePageShell({ slug, children }: Props) {
-
-
-

{t("footer.copyright", { year: new Date().getFullYear() })}

-
- - {t("footer.privacy")} - - - {t("footer.contact")} - - - {t("footer.github")} - -
-
-
+ ); }