Add Saleh Kargar factory website with FA/AR i18n.
Clone of salehkargar.ir as a Next.js site with localized pages, SEO, and product gallery. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
ab5425663f
commit
eccbb5d79d
@@ -0,0 +1,72 @@
|
||||
import type { Metadata } from "next";
|
||||
import Image from "next/image";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
import PageShell from "@/components/PageShell";
|
||||
import { buildMetadata } from "@/lib/seo";
|
||||
|
||||
const sectionMeta = [
|
||||
{ key: "history", image: "/images/about-lime/1.jpg" },
|
||||
{ key: "traditional", image: "/images/about-lime/2.jpg" },
|
||||
{ key: "difference", image: "/images/about-lime/3.jpg" },
|
||||
{ key: "uses", image: "/images/products/building-lime.jpg" },
|
||||
] as const;
|
||||
|
||||
type Props = {
|
||||
params: Promise<{ locale: string }>;
|
||||
};
|
||||
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { locale } = await params;
|
||||
const t = await getTranslations({ locale, namespace: "Meta" });
|
||||
return buildMetadata({
|
||||
title: t("aboutLimeTitle"),
|
||||
description: t("aboutLimeDescription"),
|
||||
path: `/${locale}/aboutlime`,
|
||||
locale,
|
||||
});
|
||||
}
|
||||
|
||||
export default async function AboutLimePage({ params }: Props) {
|
||||
const { locale } = await params;
|
||||
setRequestLocale(locale);
|
||||
const t = await getTranslations("AboutLimePage");
|
||||
|
||||
return (
|
||||
<PageShell title={t("title")}>
|
||||
<section className="section content-page">
|
||||
<div className="container">
|
||||
{sectionMeta.map((section, index) => (
|
||||
<article
|
||||
key={section.key}
|
||||
className={`content-block${index % 2 === 1 ? " is-reverse" : ""}`}
|
||||
>
|
||||
<div className="content-block-media shadow-box">
|
||||
<Image
|
||||
src={section.image}
|
||||
alt={t(`sections.${section.key}.title`)}
|
||||
width={700}
|
||||
height={520}
|
||||
/>
|
||||
</div>
|
||||
<div className="content-block-text">
|
||||
<h2>{t(`sections.${section.key}.title`)}</h2>
|
||||
<Image
|
||||
src="/images/infoitems/line.png"
|
||||
alt=""
|
||||
width={151}
|
||||
height={5}
|
||||
className="section-line"
|
||||
/>
|
||||
{t(`sections.${section.key}.body`)
|
||||
.split("\n")
|
||||
.map((para) =>
|
||||
para.trim() ? <p key={para.slice(0, 24)}>{para}</p> : null,
|
||||
)}
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import type { Metadata } from "next";
|
||||
import Image from "next/image";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
import PageShell from "@/components/PageShell";
|
||||
import { buildMetadata } from "@/lib/seo";
|
||||
|
||||
const sectionMeta = [
|
||||
{ key: "history", image: "/images/about-chalk/1.jpg" },
|
||||
{ key: "method", image: "/images/about-chalk/2.jpg" },
|
||||
{ key: "strength", image: "/images/about-chalk/3.jpg" },
|
||||
{ key: "pros", image: "/images/about-chalk/4.jpg" },
|
||||
{ key: "cons", image: "/images/about-chalk/1.jpg" },
|
||||
{ key: "super", image: "/images/products/super-chalk.jpg" },
|
||||
] as const;
|
||||
|
||||
type Props = {
|
||||
params: Promise<{ locale: string }>;
|
||||
};
|
||||
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { locale } = await params;
|
||||
const t = await getTranslations({ locale, namespace: "Meta" });
|
||||
return buildMetadata({
|
||||
title: t("aboutChalkTitle"),
|
||||
description: t("aboutChalkDescription"),
|
||||
path: `/${locale}/aboutsuperchalk`,
|
||||
locale,
|
||||
});
|
||||
}
|
||||
|
||||
export default async function AboutChalkPage({ params }: Props) {
|
||||
const { locale } = await params;
|
||||
setRequestLocale(locale);
|
||||
const t = await getTranslations("AboutChalkPage");
|
||||
|
||||
return (
|
||||
<PageShell title={t("title")}>
|
||||
<section className="section content-page">
|
||||
<div className="container">
|
||||
{sectionMeta.map((section, index) => (
|
||||
<article
|
||||
key={section.key}
|
||||
className={`content-block${index % 2 === 1 ? " is-reverse" : ""}`}
|
||||
>
|
||||
<div className="content-block-media shadow-box">
|
||||
<Image
|
||||
src={section.image}
|
||||
alt={t(`sections.${section.key}.title`)}
|
||||
width={700}
|
||||
height={520}
|
||||
/>
|
||||
</div>
|
||||
<div className="content-block-text">
|
||||
<h2>{t(`sections.${section.key}.title`)}</h2>
|
||||
<Image
|
||||
src="/images/infoitems/line.png"
|
||||
alt=""
|
||||
width={151}
|
||||
height={5}
|
||||
className="section-line"
|
||||
/>
|
||||
{t(`sections.${section.key}.body`)
|
||||
.split("\n")
|
||||
.map((para) =>
|
||||
para.trim() ? <p key={para.slice(0, 24)}>{para}</p> : null,
|
||||
)}
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import type { Metadata } from "next";
|
||||
import Image from "next/image";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
import PageShell from "@/components/PageShell";
|
||||
import { buildMetadata } from "@/lib/seo";
|
||||
|
||||
type Props = {
|
||||
params: Promise<{ locale: string }>;
|
||||
};
|
||||
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { locale } = await params;
|
||||
const t = await getTranslations({ locale, namespace: "Meta" });
|
||||
return buildMetadata({
|
||||
title: t("aboutUsTitle"),
|
||||
description: t("aboutUsDescription"),
|
||||
path: `/${locale}/aboutus`,
|
||||
locale,
|
||||
});
|
||||
}
|
||||
|
||||
export default async function AboutUsPage({ params }: Props) {
|
||||
const { locale } = await params;
|
||||
setRequestLocale(locale);
|
||||
const t = await getTranslations("AboutUsPage");
|
||||
|
||||
return (
|
||||
<PageShell title={t("title")}>
|
||||
<section className="section about-us-page">
|
||||
<div className="container about-us-grid">
|
||||
<div className="about-us-media shadow-box">
|
||||
<Image
|
||||
src="/images/about-us/1.jpg"
|
||||
alt={t("imageAlt")}
|
||||
width={900}
|
||||
height={600}
|
||||
priority
|
||||
sizes="(max-width: 1024px) 100vw, 55vw"
|
||||
/>
|
||||
</div>
|
||||
<div className="about-us-copy">
|
||||
<Image
|
||||
src="/images/about-us/2.png"
|
||||
alt=""
|
||||
width={90}
|
||||
height={90}
|
||||
className="about-us-icon"
|
||||
/>
|
||||
<h2>{t("title")}</h2>
|
||||
<Image
|
||||
src="/images/infoitems/line.png"
|
||||
alt=""
|
||||
width={151}
|
||||
height={5}
|
||||
className="section-line"
|
||||
/>
|
||||
<p>{t("p1")}</p>
|
||||
<p>{t("p2")}</p>
|
||||
<p>{t("p3")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import type { Metadata } from "next";
|
||||
import Image from "next/image";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
import PageShell from "@/components/PageShell";
|
||||
import { galleryImages } from "@/data/pages";
|
||||
import { buildMetadata } from "@/lib/seo";
|
||||
|
||||
type Props = {
|
||||
params: Promise<{ locale: string }>;
|
||||
};
|
||||
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { locale } = await params;
|
||||
const t = await getTranslations({ locale, namespace: "Meta" });
|
||||
return buildMetadata({
|
||||
title: t("galleryTitle"),
|
||||
description: t("galleryDescription"),
|
||||
path: `/${locale}/gallery`,
|
||||
locale,
|
||||
});
|
||||
}
|
||||
|
||||
export default async function GalleryPage({ params }: Props) {
|
||||
const { locale } = await params;
|
||||
setRequestLocale(locale);
|
||||
const t = await getTranslations("GalleryPage");
|
||||
|
||||
return (
|
||||
<PageShell title={t("title")}>
|
||||
<section className="section">
|
||||
<div className="container">
|
||||
<div className="gallery-grid">
|
||||
{galleryImages.map((item) => (
|
||||
<figure key={item.id} className="gallery-item">
|
||||
<Image
|
||||
src={item.src}
|
||||
alt={t("itemAlt", { n: item.id })}
|
||||
width={700}
|
||||
height={500}
|
||||
sizes="(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw"
|
||||
/>
|
||||
</figure>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import type { Metadata, Viewport } from "next";
|
||||
import { hasLocale, NextIntlClientProvider } from "next-intl";
|
||||
import { getMessages, getTranslations, setRequestLocale } from "next-intl/server";
|
||||
import { Vazirmatn } from "next/font/google";
|
||||
import { notFound } from "next/navigation";
|
||||
import JsonLd, {
|
||||
localBusinessJsonLd,
|
||||
organizationJsonLd,
|
||||
} from "@/components/JsonLd";
|
||||
import { routing } from "@/i18n/routing";
|
||||
import { siteConfig } from "@/data/seo";
|
||||
import "../globals.css";
|
||||
|
||||
const vazirmatn = Vazirmatn({
|
||||
subsets: ["arabic"],
|
||||
weight: ["300", "400", "500", "700", "800"],
|
||||
variable: "--font-vazirmatn",
|
||||
display: "swap",
|
||||
});
|
||||
|
||||
export const viewport: Viewport = {
|
||||
width: "device-width",
|
||||
initialScale: 1,
|
||||
themeColor: "#000000",
|
||||
};
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
params: Promise<{ locale: string }>;
|
||||
};
|
||||
|
||||
export function generateStaticParams() {
|
||||
return routing.locales.map((locale) => ({ locale }));
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}): Promise<Metadata> {
|
||||
const { locale } = await params;
|
||||
const t = await getTranslations({ locale, namespace: "Meta" });
|
||||
|
||||
return {
|
||||
metadataBase: new URL(siteConfig.url),
|
||||
title: {
|
||||
default: t("siteName"),
|
||||
template: `%s | ${t("siteName")}`,
|
||||
},
|
||||
description: t("homeDescription"),
|
||||
applicationName: siteConfig.shortName,
|
||||
icons: {
|
||||
icon: "/favicon.png",
|
||||
apple: "/favicon.png",
|
||||
},
|
||||
openGraph: {
|
||||
type: "website",
|
||||
locale: locale === "ar" ? "ar_SA" : "fa_IR",
|
||||
url: `${siteConfig.url}/${locale}`,
|
||||
siteName: t("siteName"),
|
||||
title: t("siteName"),
|
||||
description: t("homeDescription"),
|
||||
images: [
|
||||
{
|
||||
url: siteConfig.ogImage,
|
||||
width: 1920,
|
||||
height: 680,
|
||||
alt: t("siteName"),
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: t("siteName"),
|
||||
description: t("homeDescription"),
|
||||
images: [siteConfig.ogImage],
|
||||
},
|
||||
alternates: {
|
||||
canonical: `/${locale}`,
|
||||
languages: {
|
||||
"fa-IR": "/fa",
|
||||
"ar": "/ar",
|
||||
"x-default": "/fa",
|
||||
},
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default async function LocaleLayout({ children, params }: Props) {
|
||||
const { locale } = await params;
|
||||
if (!hasLocale(routing.locales, locale)) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
setRequestLocale(locale);
|
||||
const messages = await getMessages();
|
||||
|
||||
return (
|
||||
<html lang={locale} dir="rtl" className={`${vazirmatn.variable} h-full`}>
|
||||
<body className={`${vazirmatn.className} min-h-full antialiased`}>
|
||||
<NextIntlClientProvider messages={messages}>
|
||||
<JsonLd data={[organizationJsonLd(), localBusinessJsonLd()]} />
|
||||
{children}
|
||||
</NextIntlClientProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import type { Metadata } from "next";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
import AboutTabs from "@/components/AboutTabs";
|
||||
import Footer from "@/components/Footer";
|
||||
import Header from "@/components/Header";
|
||||
import Hero from "@/components/Hero";
|
||||
import Location from "@/components/Location";
|
||||
import PowderFeatures from "@/components/PowderFeatures";
|
||||
import Productions from "@/components/Productions";
|
||||
import ProductsCarousel from "@/components/ProductsCarousel";
|
||||
import { buildMetadata } from "@/lib/seo";
|
||||
|
||||
type Props = {
|
||||
params: Promise<{ locale: string }>;
|
||||
};
|
||||
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { locale } = await params;
|
||||
const t = await getTranslations({ locale, namespace: "Meta" });
|
||||
|
||||
return buildMetadata({
|
||||
title: t("homeTitle"),
|
||||
description: t("homeDescription"),
|
||||
path: `/${locale}`,
|
||||
locale,
|
||||
});
|
||||
}
|
||||
|
||||
export default async function HomePage({ params }: Props) {
|
||||
const { locale } = await params;
|
||||
setRequestLocale(locale);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main>
|
||||
<Hero />
|
||||
<Productions />
|
||||
<PowderFeatures />
|
||||
<AboutTabs />
|
||||
<ProductsCarousel />
|
||||
<Location />
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import type { Metadata } from "next";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
import { notFound } from "next/navigation";
|
||||
import JsonLd, { breadcrumbJsonLd, productJsonLd } from "@/components/JsonLd";
|
||||
import PageShell from "@/components/PageShell";
|
||||
import ProductDetail from "@/components/ProductDetail";
|
||||
import { getProductBySlug, getProducts } from "@/data/products";
|
||||
import { buildMetadata } from "@/lib/seo";
|
||||
|
||||
type Props = {
|
||||
params: Promise<{ locale: string; slug: string }>;
|
||||
};
|
||||
|
||||
export async function generateStaticParams() {
|
||||
return getProducts().map((product) => ({ slug: product.slug }));
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { locale, slug } = await params;
|
||||
const product = getProductBySlug(slug);
|
||||
const t = await getTranslations({ locale, namespace: "Products" });
|
||||
if (!product) return { title: t("notFound") };
|
||||
|
||||
return buildMetadata({
|
||||
title: t(`items.${product.slug}.title`),
|
||||
description: t(`items.${product.slug}.description`),
|
||||
path: `/${locale}/products/${product.slug}`,
|
||||
image: product.image,
|
||||
locale,
|
||||
});
|
||||
}
|
||||
|
||||
export default async function ProductDetailPage({ params }: Props) {
|
||||
const { locale, slug } = await params;
|
||||
setRequestLocale(locale);
|
||||
const product = getProductBySlug(slug);
|
||||
const t = await getTranslations("Products");
|
||||
const tCommon = await getTranslations("Common");
|
||||
if (!product) notFound();
|
||||
|
||||
const title = t(`items.${product.slug}.title`);
|
||||
|
||||
return (
|
||||
<PageShell title={t("detailsTitle")}>
|
||||
<JsonLd
|
||||
data={[
|
||||
productJsonLd({
|
||||
...product,
|
||||
title,
|
||||
description: t(`items.${product.slug}.description`),
|
||||
}),
|
||||
breadcrumbJsonLd([
|
||||
{ name: tCommon("home"), path: `/${locale}` },
|
||||
{ name: tCommon("products"), path: `/${locale}/products` },
|
||||
{
|
||||
name: title,
|
||||
path: `/${locale}/products/${product.slug}`,
|
||||
},
|
||||
]),
|
||||
]}
|
||||
/>
|
||||
<ProductDetail product={product} />
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import type { Metadata } from "next";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
import PageShell from "@/components/PageShell";
|
||||
import ProductGrid from "@/components/ProductGrid";
|
||||
import { getProducts } from "@/data/products";
|
||||
import { buildMetadata } from "@/lib/seo";
|
||||
|
||||
type Props = {
|
||||
params: Promise<{ locale: string }>;
|
||||
};
|
||||
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { locale } = await params;
|
||||
const t = await getTranslations({ locale, namespace: "Meta" });
|
||||
return buildMetadata({
|
||||
title: t("productsTitle"),
|
||||
description: t("productsDescription"),
|
||||
path: `/${locale}/products`,
|
||||
locale,
|
||||
});
|
||||
}
|
||||
|
||||
export default async function ProductsPage({ params }: Props) {
|
||||
const { locale } = await params;
|
||||
setRequestLocale(locale);
|
||||
const t = await getTranslations("Products");
|
||||
const products = getProducts();
|
||||
|
||||
return (
|
||||
<PageShell title={t("pageTitle")}>
|
||||
<section className="section">
|
||||
<div className="container">
|
||||
<ProductGrid products={products} />
|
||||
</div>
|
||||
</section>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
+1348
-15
File diff suppressed because it is too large
Load Diff
+5
-25
@@ -1,29 +1,9 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: LayoutProps<"/">) {
|
||||
return (
|
||||
<html
|
||||
lang="en"
|
||||
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
|
||||
>
|
||||
<body className="min-h-full flex flex-col">{children}</body>
|
||||
</html>
|
||||
);
|
||||
export default function RootLayout({ children }: Props) {
|
||||
return children;
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
import Image from "next/image";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="flex flex-col flex-1 items-center justify-center bg-zinc-50 font-sans dark:bg-black">
|
||||
<main className="flex flex-1 w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
|
||||
<Image
|
||||
className="dark:invert h-5 w-[100px]"
|
||||
src="/next.svg"
|
||||
alt="Next.js logo"
|
||||
width={100}
|
||||
height={20}
|
||||
priority
|
||||
/>
|
||||
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
|
||||
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
|
||||
To get started, edit the{" "}
|
||||
<code className="rounded bg-black/[.06] px-1.5 py-0.5 font-mono text-[0.9em] dark:bg-white/[.08]">
|
||||
page.tsx
|
||||
</code>{" "}
|
||||
file.
|
||||
</h1>
|
||||
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
|
||||
Looking for a starting point or more instructions? Head over to{" "}
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
||||
>
|
||||
Templates
|
||||
</a>{" "}
|
||||
or the{" "}
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
||||
>
|
||||
Learning
|
||||
</a>{" "}
|
||||
center.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
|
||||
<a
|
||||
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
className="dark:invert h-[14px] w-4"
|
||||
src="/vercel.svg"
|
||||
alt="Vercel logomark"
|
||||
width={16}
|
||||
height={14}
|
||||
/>
|
||||
Deploy Now
|
||||
</a>
|
||||
<a
|
||||
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { MetadataRoute } from "next";
|
||||
import { siteConfig } from "@/data/seo";
|
||||
|
||||
export default function robots(): MetadataRoute.Robots {
|
||||
return {
|
||||
rules: {
|
||||
userAgent: "*",
|
||||
allow: "/",
|
||||
},
|
||||
sitemap: `${siteConfig.url}/sitemap.xml`,
|
||||
host: siteConfig.url,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import type { MetadataRoute } from "next";
|
||||
import { siteConfig } from "@/data/seo";
|
||||
import { getProducts } from "@/data/products";
|
||||
import { routing } from "@/i18n/routing";
|
||||
|
||||
export default function sitemap(): MetadataRoute.Sitemap {
|
||||
const now = new Date();
|
||||
const staticPaths = [
|
||||
"",
|
||||
"/products",
|
||||
"/aboutsuperchalk",
|
||||
"/aboutlime",
|
||||
"/gallery",
|
||||
"/aboutus",
|
||||
];
|
||||
|
||||
const productPaths = getProducts().map(
|
||||
(product) => `/products/${product.slug}`,
|
||||
);
|
||||
|
||||
const entries: MetadataRoute.Sitemap = [];
|
||||
|
||||
for (const locale of routing.locales) {
|
||||
for (const path of [...staticPaths, ...productPaths]) {
|
||||
entries.push({
|
||||
url: `${siteConfig.url}/${locale}${path}`,
|
||||
lastModified: now,
|
||||
changeFrequency: path.startsWith("/products") ? "weekly" : "monthly",
|
||||
priority: path === "" ? 1 : path === "/products" ? 0.9 : 0.8,
|
||||
alternates: {
|
||||
languages: Object.fromEntries(
|
||||
routing.locales.map((item) => [
|
||||
item,
|
||||
`${siteConfig.url}/${item}${path}`,
|
||||
]),
|
||||
),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
Reference in New Issue
Block a user