feat: add sitemap.xml, robots.txt, full SEO metadata
This commit is contained in:
+40
-2
@@ -20,9 +20,47 @@ const jetbrainsMono = JetBrains_Mono({
|
||||
weight: ["400", "500", "600", "700"],
|
||||
});
|
||||
|
||||
const BASE_URL = 'https://ayrisai.xyz';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "DevHub YouTube | Educational Code & Resource Portal",
|
||||
description: "Official resource portal featuring tabbed code snippets, lesson notes, starter packs, and project downloads for my YouTube tutorials.",
|
||||
metadataBase: new URL(BASE_URL),
|
||||
title: {
|
||||
default: 'ayris.tech YouTube | Code & Resource Portal',
|
||||
template: '%s | ayris.tech YouTube',
|
||||
},
|
||||
description:
|
||||
'Official resource portal for the ayris.tech YouTube channel. Browse source code, lesson notes, cheatsheets, AI prompts, and project downloads for every tutorial.',
|
||||
keywords: [
|
||||
'Next.js', 'React', 'TypeScript', 'Tailwind CSS', 'Python',
|
||||
'YouTube tutorial', 'source code', 'ayris.tech', 'web development',
|
||||
'AI agents', 'Prisma', 'Docker', 'full-stack',
|
||||
],
|
||||
authors: [{ name: 'ayris.tech', url: BASE_URL }],
|
||||
creator: 'ayris.tech',
|
||||
openGraph: {
|
||||
type: 'website',
|
||||
locale: 'en_US',
|
||||
url: BASE_URL,
|
||||
siteName: 'ayris.tech YouTube Portal',
|
||||
title: 'ayris.tech YouTube | Code & Resource Portal',
|
||||
description:
|
||||
'Source code, lesson notes, cheatsheets, and project downloads for every ayris.tech YouTube tutorial.',
|
||||
images: [{ url: `${BASE_URL}/logo.jpeg`, width: 400, height: 400, alt: 'ayris.tech Logo' }],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
title: 'ayris.tech YouTube | Code & Resource Portal',
|
||||
description: 'Source code, cheatsheets, AI prompts and downloads for every ayris.tech tutorial.',
|
||||
images: [`${BASE_URL}/logo.jpeg`],
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true },
|
||||
},
|
||||
alternates: {
|
||||
canonical: BASE_URL,
|
||||
},
|
||||
};
|
||||
|
||||
export function generateStaticParams() {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { MetadataRoute } from 'next';
|
||||
|
||||
const BASE_URL = 'https://ayrisai.xyz';
|
||||
const PROTECTED = ['/admin/', '/api/'];
|
||||
|
||||
export default function robots(): MetadataRoute.Robots {
|
||||
return {
|
||||
rules: [
|
||||
// Genel arama botları — tüm public içerik açık
|
||||
{
|
||||
userAgent: '*',
|
||||
allow: '/',
|
||||
disallow: PROTECTED,
|
||||
},
|
||||
// AI arama / citation botları — izin ver
|
||||
{ userAgent: 'OAI-SearchBot', allow: '/', disallow: PROTECTED },
|
||||
{ userAgent: 'ChatGPT-User', allow: '/', disallow: PROTECTED },
|
||||
{ userAgent: 'PerplexityBot', allow: '/', disallow: PROTECTED },
|
||||
{ userAgent: 'Perplexity-User', allow: '/', disallow: PROTECTED },
|
||||
{ userAgent: 'Claude-SearchBot', allow: '/', disallow: PROTECTED },
|
||||
{ userAgent: 'Claude-User', allow: '/', disallow: PROTECTED },
|
||||
// Training crawler'ları engelle
|
||||
{ userAgent: 'GPTBot', disallow: '/' },
|
||||
{ userAgent: 'ClaudeBot', disallow: '/' },
|
||||
{ userAgent: 'Google-Extended', disallow: '/' },
|
||||
{ userAgent: 'CCBot', disallow: '/' },
|
||||
{ userAgent: 'Bytespider', disallow: '/' },
|
||||
{ userAgent: 'Meta-ExternalAgent', disallow: '/' },
|
||||
],
|
||||
sitemap: `${BASE_URL}/sitemap.xml`,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import type { MetadataRoute } from 'next';
|
||||
import { getLessons } from '@/lib/actions/lessonActions';
|
||||
import { getCheatsheets } from '@/lib/actions/cheatsheetActions';
|
||||
import { getPrompts } from '@/lib/actions/promptActions';
|
||||
|
||||
const BASE_URL = 'https://ayrisai.xyz';
|
||||
const LOCALES = ['en'];
|
||||
|
||||
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||
const now = new Date();
|
||||
|
||||
// Static pages
|
||||
const staticRoutes = [
|
||||
{ path: '', priority: 1.0, changeFrequency: 'daily' as const },
|
||||
{ path: '/lessons', priority: 0.9, changeFrequency: 'daily' as const },
|
||||
{ path: '/cheatsheets', priority: 0.8, changeFrequency: 'weekly' as const },
|
||||
{ path: '/prompts', priority: 0.8, changeFrequency: 'weekly' as const },
|
||||
{ path: '/contact', priority: 0.5, changeFrequency: 'monthly' as const },
|
||||
];
|
||||
|
||||
const staticEntries: MetadataRoute.Sitemap = LOCALES.flatMap((locale) =>
|
||||
staticRoutes.map(({ path, priority, changeFrequency }) => ({
|
||||
url: `${BASE_URL}/${locale}${path}`,
|
||||
lastModified: now,
|
||||
changeFrequency,
|
||||
priority,
|
||||
}))
|
||||
);
|
||||
|
||||
// Dynamic: Lessons
|
||||
let lessonEntries: MetadataRoute.Sitemap = [];
|
||||
try {
|
||||
const lessons = await getLessons();
|
||||
lessonEntries = LOCALES.flatMap((locale) =>
|
||||
lessons.map((lesson: any) => ({
|
||||
url: `${BASE_URL}/${locale}/lessons/${lesson.slug}`,
|
||||
lastModified: lesson.updatedAt || now,
|
||||
changeFrequency: 'weekly' as const,
|
||||
priority: 0.85,
|
||||
}))
|
||||
);
|
||||
} catch {}
|
||||
|
||||
// Dynamic: Cheatsheets
|
||||
let cheatEntries: MetadataRoute.Sitemap = [];
|
||||
try {
|
||||
const sheets = await getCheatsheets();
|
||||
cheatEntries = LOCALES.flatMap((locale) =>
|
||||
sheets.map((sheet: any) => ({
|
||||
url: `${BASE_URL}/${locale}/cheatsheets/${sheet.slug}`,
|
||||
lastModified: sheet.updatedAt || now,
|
||||
changeFrequency: 'monthly' as const,
|
||||
priority: 0.7,
|
||||
}))
|
||||
);
|
||||
} catch {}
|
||||
|
||||
// Dynamic: Prompts
|
||||
let promptEntries: MetadataRoute.Sitemap = [];
|
||||
try {
|
||||
const prompts = await getPrompts();
|
||||
promptEntries = LOCALES.flatMap((locale) =>
|
||||
prompts.map((prompt: any) => ({
|
||||
url: `${BASE_URL}/${locale}/prompts/${prompt.slug}`,
|
||||
lastModified: prompt.updatedAt || now,
|
||||
changeFrequency: 'monthly' as const,
|
||||
priority: 0.7,
|
||||
}))
|
||||
);
|
||||
} catch {}
|
||||
|
||||
return [...staticEntries, ...lessonEntries, ...cheatEntries, ...promptEntries];
|
||||
}
|
||||
Reference in New Issue
Block a user