feat(seo): robots.txt, richer sitemap, llms.txt, manifest, OG image, JSON-LD
CI/CD / test-and-build (push) Waiting to run
CI/CD / deploy (push) Blocked by required conditions

- Add app/robots.ts (allow crawl, disallow admin/api, sitemap URL)
- Expand sitemap to industries/[slug], accessories/[slug] and more static routes
- Add public/llms.txt (AI summary), site.webmanifest, 1200x630 og.jpg
- Layout: default OG/Twitter image, manifest, robots meta, Organization + WebSite JSON-LD
- Robot pages: canonical, OG image, Product + BreadcrumbList JSON-LD; home canonical

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Najjar
2026-07-06 13:45:38 +04:00
co-authored by Claude Opus 4.8
parent 873026a4a9
commit 60d50e15e4
10 changed files with 263 additions and 16 deletions
+18
View File
@@ -1,6 +1,8 @@
import type { Metadata, Viewport } from "next";
import { ErrorBoundary } from "@/components/ErrorBoundary";
import { I18nProvider } from "@/components/I18nProvider";
import JsonLd from "@/components/JsonLd";
import { OG_IMAGE, siteName, organizationJsonLd, websiteJsonLd } from "@/lib/seo";
import "./globals.css";
export const metadata: Metadata = {
@@ -28,17 +30,32 @@ export const metadata: Metadata = {
],
openGraph: {
type: 'website',
url: '/',
title: 'YS Lootah Robotics UAE Destination for Unitree & Pudu Robotics',
description:
'Advanced robotics. UAE access. Selected Unitree and Pudu solutions available through YS Lootah Robotics in Dubai.',
locale: 'en_AE',
siteName: 'YS Lootah Robotics',
images: [{ url: OG_IMAGE, width: 1200, height: 630, alt: siteName }],
},
twitter: {
card: 'summary_large_image',
title: 'YS Lootah Robotics UAE Destination for Unitree & Pudu Robotics',
description:
'The UAE’s dedicated destination for Unitree and Pudu Robotics sales, demo inquiries, and business deployment.',
images: [OG_IMAGE],
},
manifest: '/site.webmanifest',
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
'max-image-preview': 'large',
'max-snippet': -1,
'max-video-preview': -1,
},
},
};
@@ -63,6 +80,7 @@ export default function RootLayout({
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@200;300;400;500;600;700&display=swap" rel="stylesheet" />
</head>
<body suppressHydrationWarning>
<JsonLd data={[organizationJsonLd, websiteJsonLd]} />
<ErrorBoundary>
<I18nProvider>
{children}
+1
View File
@@ -35,6 +35,7 @@ export const metadata: Metadata = {
'robotics configuration UAE',
'robot sales and demo UAE',
],
alternates: { canonical: '/' },
};
export default function HomePage() {
+16
View File
@@ -0,0 +1,16 @@
import type { MetadataRoute } from 'next';
import { SITE_URL } from '@/lib/seo';
export default function robots(): MetadataRoute.Robots {
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: ['/admin', '/admin/', '/api/'],
},
],
sitemap: `${SITE_URL}/sitemap.xml`,
host: SITE_URL,
};
}
+26 -2
View File
@@ -11,6 +11,8 @@ import { ProductSpecTable } from '@/components/robotics/ProductSpecTable';
import { ProductGallery } from '@/components/robotics/ProductGallery';
import { MotionSection } from '@/components/ui/MotionSection';
import { ROBOTS, getRobotBySlug, BRANDS, CATEGORY_LABELS } from '@/data/robots';
import JsonLd from '@/components/JsonLd';
import { canonical, abs, productJsonLd, breadcrumbJsonLd } from '@/lib/seo';
type Params = { slug: string };
@@ -22,10 +24,17 @@ export async function generateMetadata({ params }: { params: Promise<Params> }):
const { slug } = await params;
const robot = getRobotBySlug(slug);
if (!robot) return { title: 'Robot not found YS Lootah Robotics' };
const url = canonical(`/robots/${robot.slug}`);
const img = abs(robot.image);
const title = `${robot.brandLabel} ${robot.name} Available in Dubai | YS Lootah Robotics`;
const description = `${robot.shortDescription} Available through YS Lootah Robotics in Dubai request a price or book a live demo.`;
return {
title: `${robot.brandLabel} ${robot.name} Available in Dubai | YS Lootah Robotics`,
description: `${robot.shortDescription} Available through YS Lootah Robotics in Dubai request a price or book a live demo.`,
title,
description,
keywords: [robot.brandLabel, robot.name, 'Dubai', 'UAE', CATEGORY_LABELS[robot.category], 'robotics'],
alternates: { canonical: url },
openGraph: { type: 'website', url, title, description, images: [{ url: img, alt: `${robot.brandLabel} ${robot.name}` }] },
twitter: { card: 'summary_large_image', title, description, images: [img] },
};
}
@@ -37,8 +46,23 @@ export default async function RobotDetailPage({ params }: { params: Promise<Para
const brand = BRANDS[robot.brand];
const related = ROBOTS.filter((r) => r.id !== robot.id && (r.brand === robot.brand || r.category === robot.category)).slice(0, 3);
const productLd = productJsonLd({
name: `${robot.brandLabel} ${robot.name}`,
description: robot.shortDescription,
image: robot.image,
brandName: brand.name,
path: `/robots/${robot.slug}`,
category: CATEGORY_LABELS[robot.category],
});
const crumbLd = breadcrumbJsonLd([
{ name: 'Home', path: '/' },
{ name: 'Robots', path: '/robots' },
{ name: robot.name, path: `/robots/${robot.slug}` },
]);
return (
<>
<JsonLd data={[productLd, crumbLd]} />
<Navbar />
<main style={{ paddingTop: 'clamp(6rem, 10vw, 8rem)', paddingBottom: 'clamp(4rem, 8vw, 6rem)' }}>
+33 -14
View File
@@ -1,29 +1,48 @@
import { MetadataRoute } from 'next';
import { ROBOTS } from '@/data/robots';
const baseUrl = 'https://yslootahrobotics.com';
import { INDUSTRIES } from '@/data/industries';
import { ACCESSORIES } from '@/data/accessories';
import { SITE_URL } from '@/lib/seo';
export default function sitemap(): MetadataRoute.Sitemap {
const now = new Date();
const u = (path: string) => `${SITE_URL}${path}`;
const staticRoutes: MetadataRoute.Sitemap = [
{ url: `${baseUrl}/`, lastModified: now, changeFrequency: 'weekly', priority: 1 },
{ url: `${baseUrl}/robots/`, lastModified: now, changeFrequency: 'weekly', priority: 0.9 },
{ url: `${baseUrl}/brands/`, lastModified: now, changeFrequency: 'weekly', priority: 0.8 },
{ url: `${baseUrl}/industries/`, lastModified: now, changeFrequency: 'weekly', priority: 0.8 },
{ url: `${baseUrl}/about/`, lastModified: now, changeFrequency: 'monthly', priority: 0.6 },
{ url: `${baseUrl}/contact/`, lastModified: now, changeFrequency: 'monthly', priority: 0.7 },
{ url: `${baseUrl}/book-demo/`, lastModified: now, changeFrequency: 'monthly', priority: 0.8 },
{ url: `${baseUrl}/configure/`, lastModified: now, changeFrequency: 'monthly', priority: 0.8 },
{ url: `${baseUrl}/privacy-policy/`, lastModified: now, changeFrequency: 'yearly', priority: 0.3 },
{ url: `${baseUrl}/terms-of-service/`, lastModified: now, changeFrequency: 'yearly', priority: 0.3 },
{ url: u('/'), lastModified: now, changeFrequency: 'weekly', priority: 1 },
{ url: u('/robots/'), lastModified: now, changeFrequency: 'weekly', priority: 0.9 },
{ url: u('/configure/'), lastModified: now, changeFrequency: 'weekly', priority: 0.9 },
{ url: u('/brands/'), lastModified: now, changeFrequency: 'weekly', priority: 0.8 },
{ url: u('/industries/'), lastModified: now, changeFrequency: 'weekly', priority: 0.8 },
{ url: u('/accessories/'), lastModified: now, changeFrequency: 'weekly', priority: 0.7 },
{ url: u('/book-demo/'), lastModified: now, changeFrequency: 'monthly', priority: 0.8 },
{ url: u('/contact/'), lastModified: now, changeFrequency: 'monthly', priority: 0.7 },
{ url: u('/about/'), lastModified: now, changeFrequency: 'monthly', priority: 0.6 },
{ url: u('/bu-sunaidah/'), lastModified: now, changeFrequency: 'monthly', priority: 0.5 },
{ url: u('/privacy-policy/'), lastModified: now, changeFrequency: 'yearly', priority: 0.3 },
{ url: u('/terms-of-service/'), lastModified: now, changeFrequency: 'yearly', priority: 0.3 },
];
const robotRoutes: MetadataRoute.Sitemap = ROBOTS.map((r) => ({
url: `${baseUrl}/robots/${r.slug}/`,
url: u(`/robots/${r.slug}/`),
lastModified: now,
changeFrequency: 'monthly',
priority: 0.7,
}));
return [...staticRoutes, ...robotRoutes];
const industryRoutes: MetadataRoute.Sitemap = INDUSTRIES.map((i) => ({
url: u(`/industries/${i.slug}/`),
lastModified: now,
changeFrequency: 'monthly',
priority: 0.6,
}));
const accessoryRoutes: MetadataRoute.Sitemap = ACCESSORIES.map((a) => ({
url: u(`/accessories/${a.slug}/`),
lastModified: now,
changeFrequency: 'monthly',
priority: 0.5,
}));
return [...staticRoutes, ...robotRoutes, ...industryRoutes, ...accessoryRoutes];
}