feat: SEO altyapısı + admin editör/favicon/menü düzeltmeleri

Admin & site:
- @tailwindcss/typography ekle → editör ve yayın içeriği prose stilleriyle düzgün render
- Favicon: logo.png'den kare app/icon.png + apple-icon.png, varsayılan favicon.ico kaldırıldı
- SEO keyword: seo_settings.default_keywords + seo_pages.keywords + buildMetadata birleştirme
- Menü düzeni admin'den yönetilebilir (site_settings.nav_items, /admin/menu, header & mobile-menu refactor)

SEO:
- app/sitemap.ts (statik + blog/hizmet/çözüm/proje/sektör dinamik)
- app/robots.ts (sitemap ref + /admin,/api disallow)
- app/llms.txt/route.ts (AI/LLM rehberi)
- BlogPosting/Service/FAQ/Article JSON-LD wire (json-ld bileşenleri bağlandı)
- buildMetadata: blog/proje OG görseli + type article + keywords birleştirme düzeltmesi
- blog tags → keyword
This commit is contained in:
egecankomur
2026-06-04 07:15:18 +03:00
parent a321ac5c9b
commit d49c9aa225
26 changed files with 780 additions and 151 deletions
+45
View File
@@ -1,4 +1,5 @@
import type {
BlogPostRow,
ProjectRow,
ServiceRow,
SiteSettingsRow,
@@ -6,6 +7,12 @@ import type {
} from "@/lib/types";
import { siteConfig } from "@/lib/site-config";
function absUrl(url?: string | null): string | undefined {
if (!url) return undefined;
if (url.startsWith("http")) return url;
return `${siteConfig.url}${url.startsWith("/") ? "" : "/"}${url}`;
}
export function JsonLd({ data }: { data: object }) {
return (
<script
@@ -137,6 +144,44 @@ export function BreadcrumbLd({
);
}
export function BlogPostingLd({
post,
settings,
}: {
post: BlogPostRow;
settings?: SiteSettingsRow | null;
}) {
const image = absUrl(post.seo_image || post.cover_image) ?? `${siteConfig.url}/logo.png`;
const url = `${siteConfig.url}/blog/${post.slug}`;
const data: Record<string, unknown> = {
"@context": "https://schema.org",
"@type": "BlogPosting",
headline: post.title,
description: post.seo_description || post.excerpt || undefined,
image,
datePublished: post.published_at ?? post.$createdAt,
dateModified: post.$updatedAt,
author: {
"@type": post.author ? "Person" : "Organization",
name: post.author || settings?.site_name || siteConfig.name,
},
publisher: {
"@type": "Organization",
name: settings?.site_name ?? siteConfig.name,
logo: {
"@type": "ImageObject",
url: `${siteConfig.url}/logo.png`,
},
},
mainEntityOfPage: { "@type": "WebPage", "@id": url },
url,
};
if (post.tags && post.tags.length > 0) {
data.keywords = post.tags.join(", ");
}
return <JsonLd data={data} />;
}
export function ArticleLd({ post }: { post: ProjectRow }) {
return (
<JsonLd