fix(seo): configure canonical links dynamically per page
This commit is contained in:
@@ -65,6 +65,9 @@ export async function generateMetadata({
|
||||
return {
|
||||
title: `${content.title} | Ayris Tech`,
|
||||
description: content.excerpt,
|
||||
alternates: {
|
||||
canonical: `/${lang}/blog/${slug}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@ export async function generateMetadata({ params }: { params: Promise<{ lang: Loc
|
||||
return {
|
||||
title: dict.meta.blog.title,
|
||||
description: dict.meta.blog.desc,
|
||||
alternates: {
|
||||
canonical: `/${lang}/blog`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ export async function generateMetadata({ params }: { params: Promise<{ lang: Loc
|
||||
return {
|
||||
title: dict.meta.contact.title,
|
||||
description: dict.meta.contact.desc,
|
||||
alternates: {
|
||||
canonical: `/${lang}/contact`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ export async function generateMetadata({ params }: { params: Promise<{ lang: Loc
|
||||
return {
|
||||
title: `${titleStr} | ${dict.nav.brandName}`,
|
||||
description: `${titleStr} - ${dict.work.desc}`,
|
||||
alternates: {
|
||||
canonical: `/${lang}/expertise/${slug}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ export async function generateMetadata({ params }: { params: Promise<{ lang: Loc
|
||||
return {
|
||||
title: dict.meta.faq.title,
|
||||
description: dict.meta.faq.desc,
|
||||
alternates: {
|
||||
canonical: `/${lang}/faq`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ export async function generateMetadata({ params }: { params: Promise<{ lang: Loc
|
||||
images: ['/og-image.jpg'],
|
||||
},
|
||||
alternates: {
|
||||
canonical: '/',
|
||||
languages: {
|
||||
'en': '/en',
|
||||
'tr': '/tr',
|
||||
|
||||
@@ -8,6 +8,9 @@ export async function generateMetadata({ params }: { params: Promise<{ lang: Loc
|
||||
return {
|
||||
title: dict.meta.home.title,
|
||||
description: dict.meta.home.desc,
|
||||
alternates: {
|
||||
canonical: `/${lang}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ export async function generateMetadata({ params }: { params: Promise<{ lang: Loc
|
||||
return {
|
||||
title: dict.meta.process.title,
|
||||
description: dict.meta.process.desc,
|
||||
alternates: {
|
||||
canonical: `/${lang}/process`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ export async function generateMetadata({ params }: { params: Promise<{ lang: Loc
|
||||
return {
|
||||
title: dict.meta.services.title,
|
||||
description: dict.meta.services.desc,
|
||||
alternates: {
|
||||
canonical: `/${lang}/services`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@ export async function generateMetadata({
|
||||
return {
|
||||
title: `${project.title} — ${dict.nav.brandName}${dict.nav.brandSub}`,
|
||||
description: project.desc,
|
||||
alternates: {
|
||||
canonical: `/${lang}/work/${slug}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@ export async function generateMetadata({ params }: { params: Promise<{ lang: Loc
|
||||
return {
|
||||
title: dict.meta.work.title,
|
||||
description: dict.meta.work.desc,
|
||||
alternates: {
|
||||
canonical: `/${lang}/work`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -164,6 +164,7 @@ export default function BlogClient({
|
||||
</div>
|
||||
<Link
|
||||
href={`/${lang}/blog/${post.slug}`}
|
||||
aria-label={content.title as string}
|
||||
className="w-10 h-10 border border-[#C8C2B8] group-hover:border-[#0A0A0A] group-hover:bg-[#0A0A0A] group-hover:text-[#FFE600] text-[#0A0A0A] flex items-center justify-center transition-all"
|
||||
>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
||||
|
||||
@@ -109,8 +109,8 @@ export default function ContactClient({ lang, dict }: { lang: Locale; dict: any
|
||||
className="w-full bg-transparent border-b border-[#C8C2B8] focus:border-[#0A0A0A] outline-none py-3 text-sm text-[#0A0A0A] placeholder-[#C8C2B8] transition-colors" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block font-mono text-[9px] font-bold uppercase tracking-[0.3em] text-[#A0998E] mb-2">{dict.contact.formTrack}</label>
|
||||
<select value={formState.service} onChange={e => setFormState({ ...formState, service: e.target.value })}
|
||||
<label htmlFor="form-service" className="block font-mono text-[9px] font-bold uppercase tracking-[0.3em] text-[#A0998E] mb-2">{dict.contact.formTrack}</label>
|
||||
<select id="form-service" value={formState.service} onChange={e => setFormState({ ...formState, service: e.target.value })}
|
||||
className="w-full bg-transparent border-b border-[#C8C2B8] focus:border-[#0A0A0A] outline-none py-3 text-sm text-[#0A0A0A] transition-colors cursor-pointer">
|
||||
<option value="AI Solutions" className="bg-[#F4F0E8]">{dict.services.items.ai.title}</option>
|
||||
<option value="Blockchain Dev" className="bg-[#F4F0E8]">{dict.services.items.blockchain.title}</option>
|
||||
|
||||
@@ -510,6 +510,7 @@ export default function HomeClientBelowFold({ lang, dict }: { lang: Locale; dict
|
||||
</div>
|
||||
<Link
|
||||
href={`/${lang}/blog/${post.slug}`}
|
||||
aria-label={content.title as string}
|
||||
className="w-10 h-10 border border-[#C8C2B8] group-hover:border-[#0A0A0A] group-hover:bg-[#0A0A0A] group-hover:text-[#FFE600] text-[#0A0A0A] flex items-center justify-center transition-all"
|
||||
>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
||||
@@ -622,13 +623,14 @@ export default function HomeClientBelowFold({ lang, dict }: { lang: Locale; dict
|
||||
{ label: dict.contact.formTrack, type: "select", options: ["$5k – $20k", "$20k – $50k", "$50k – $100k", "$100k+"] },
|
||||
].map((field, fi) => (
|
||||
<div key={fi} className="flex flex-col">
|
||||
<label className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-3">{field.label}</label>
|
||||
<label htmlFor={`field-${fi}`} className="font-mono text-[9px] tracking-[0.3em] uppercase text-[#A0998E] mb-3">{field.label}</label>
|
||||
{field.type === "select" ? (
|
||||
<select className="bg-transparent border-b border-[#C8C2B8] focus:border-[#0A0A0A] text-[#0A0A0A] text-sm py-3 focus:outline-none transition-colors cursor-pointer appearance-none">
|
||||
<select id={`field-${fi}`} className="bg-transparent border-b border-[#C8C2B8] focus:border-[#0A0A0A] text-[#0A0A0A] text-sm py-3 focus:outline-none transition-colors cursor-pointer appearance-none">
|
||||
{field.options?.map(opt => <option key={opt} value={opt} className="bg-[#F4F0E8]">{opt}</option>)}
|
||||
</select>
|
||||
) : (
|
||||
<input
|
||||
id={`field-${fi}`}
|
||||
required
|
||||
type={field.type}
|
||||
placeholder={field.placeholder}
|
||||
|
||||
Reference in New Issue
Block a user