feat: improve blog
This commit is contained in:
parent
fd89bc424e
commit
8b1487e743
|
|
@ -12,6 +12,33 @@ import {
|
||||||
BlogSidebar,
|
BlogSidebar,
|
||||||
BlogShareButtons,
|
BlogShareButtons,
|
||||||
} from '../_components';
|
} from '../_components';
|
||||||
|
import type { BlogPost } from '../types';
|
||||||
|
|
||||||
|
const generateJsonLd = (post: BlogPost) => ({
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'Article',
|
||||||
|
headline: post.title,
|
||||||
|
description: post.description,
|
||||||
|
image: `https://banatie.app${post.heroImage}`,
|
||||||
|
datePublished: post.date,
|
||||||
|
dateModified: post.date,
|
||||||
|
author: {
|
||||||
|
'@type': 'Person',
|
||||||
|
name: post.author.name,
|
||||||
|
},
|
||||||
|
publisher: {
|
||||||
|
'@type': 'Organization',
|
||||||
|
name: 'Banatie',
|
||||||
|
logo: {
|
||||||
|
'@type': 'ImageObject',
|
||||||
|
url: 'https://banatie.app/banatie-logo.png',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mainEntityOfPage: {
|
||||||
|
'@type': 'WebPage',
|
||||||
|
'@id': `https://banatie.app/blog/${post.slug}/`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
params: Promise<{ slug: string }>;
|
params: Promise<{ slug: string }>;
|
||||||
|
|
@ -41,8 +68,13 @@ export default async function BlogPostPage({ params }: PageProps) {
|
||||||
const relatedArticles = getPostsBySlugs(post.relatedArticles);
|
const relatedArticles = getPostsBySlugs(post.relatedArticles);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<>
|
||||||
<BlogPostHeader post={post} />
|
<script
|
||||||
|
type="application/ld+json"
|
||||||
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(generateJsonLd(post)) }}
|
||||||
|
/>
|
||||||
|
<main id="main-content">
|
||||||
|
<BlogPostHeader post={post} />
|
||||||
|
|
||||||
<div className="bg-white border-t-0 -mt-1 pt-12 lg:pt-16 pb-12">
|
<div className="bg-white border-t-0 -mt-1 pt-12 lg:pt-16 pb-12">
|
||||||
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
|
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
|
@ -72,6 +104,7 @@ export default async function BlogPostPage({ params }: PageProps) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ export const BlogImage = ({
|
||||||
alt={alt}
|
alt={alt}
|
||||||
placeholder="blur"
|
placeholder="blur"
|
||||||
className="w-full h-auto"
|
className="w-full h-auto"
|
||||||
|
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 66vw, 800px"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="relative aspect-video bg-gray-100">
|
<div className="relative aspect-video bg-gray-100">
|
||||||
|
|
@ -33,6 +34,7 @@ export const BlogImage = ({
|
||||||
alt={alt}
|
alt={alt}
|
||||||
fill
|
fill
|
||||||
className="object-cover"
|
className="object-cover"
|
||||||
|
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 66vw, 800px"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,13 @@ export const BlogShareButtons = ({ url, title }: BlogShareButtonsProps) => {
|
||||||
const linkedinUrl = `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(shareUrl)}`;
|
const linkedinUrl = `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(shareUrl)}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="sticky top-28 flex flex-col gap-4 items-center">
|
<div className="sticky top-38 flex flex-col gap-4 items-center">
|
||||||
<a
|
<a
|
||||||
href={twitterUrl}
|
href={twitterUrl}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
aria-label="Share on Twitter"
|
aria-label="Share on Twitter"
|
||||||
className="p-2 rounded-full bg-white text-gray-500 hover:text-violet-500 transition-colors border border-gray-200 shadow-sm"
|
className="p-3 rounded-full bg-white text-gray-500 hover:text-violet-500 transition-colors border border-gray-200 shadow-sm"
|
||||||
>
|
>
|
||||||
<svg className="w-5 h-5 fill-current" viewBox="0 0 24 24">
|
<svg className="w-5 h-5 fill-current" viewBox="0 0 24 24">
|
||||||
<path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z" />
|
<path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z" />
|
||||||
|
|
@ -41,7 +41,7 @@ export const BlogShareButtons = ({ url, title }: BlogShareButtonsProps) => {
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
aria-label="Share on LinkedIn"
|
aria-label="Share on LinkedIn"
|
||||||
className="p-2 rounded-full bg-white text-gray-500 hover:text-blue-600 transition-colors border border-gray-200 shadow-sm"
|
className="p-3 rounded-full bg-white text-gray-500 hover:text-blue-600 transition-colors border border-gray-200 shadow-sm"
|
||||||
>
|
>
|
||||||
<svg className="w-5 h-5 fill-current" viewBox="0 0 24 24">
|
<svg className="w-5 h-5 fill-current" viewBox="0 0 24 24">
|
||||||
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" />
|
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" />
|
||||||
|
|
@ -51,7 +51,7 @@ export const BlogShareButtons = ({ url, title }: BlogShareButtonsProps) => {
|
||||||
<button
|
<button
|
||||||
onClick={handleCopyLink}
|
onClick={handleCopyLink}
|
||||||
aria-label="Copy Link"
|
aria-label="Copy Link"
|
||||||
className="p-2 rounded-full bg-white text-gray-500 hover:text-gray-900 transition-colors border border-gray-200 shadow-sm"
|
className="p-3 rounded-full bg-white text-gray-500 hover:text-gray-900 transition-colors border border-gray-200 shadow-sm"
|
||||||
>
|
>
|
||||||
<LinkIcon className="w-5 h-5" />
|
<LinkIcon className="w-5 h-5" />
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,8 @@ export const metadata: Metadata = {
|
||||||
|
|
||||||
twitter: {
|
twitter: {
|
||||||
card: 'summary_large_image',
|
card: 'summary_large_image',
|
||||||
|
site: '@BanatieApp',
|
||||||
|
creator: '@BanatieApp',
|
||||||
title: 'Blog | Banatie',
|
title: 'Blog | Banatie',
|
||||||
description:
|
description:
|
||||||
'Articles, guides, and updates about AI-powered image generation.',
|
'Articles, guides, and updates about AI-powered image generation.',
|
||||||
|
|
@ -60,7 +62,7 @@ export default function BlogPage() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<BlogBackground />
|
<BlogBackground />
|
||||||
<main className="flex-grow bg-transparent relative z-10 pt-10 pb-12 lg:pt-16 lg:pb-20">
|
<main id="main-content" className="flex-grow bg-transparent relative z-10 pt-10 pb-12 lg:pt-16 lg:pb-20">
|
||||||
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
|
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 lg:gap-12">
|
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 lg:gap-12">
|
||||||
<div className="lg:col-span-8 xl:col-span-9">
|
<div className="lg:col-span-8 xl:col-span-9">
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ export const generatePostMetadata = (post: BlogPost): Metadata => ({
|
||||||
|
|
||||||
twitter: {
|
twitter: {
|
||||||
card: 'summary_large_image',
|
card: 'summary_large_image',
|
||||||
|
site: '@BanatieApp',
|
||||||
|
creator: '@BanatieApp',
|
||||||
title: post.title,
|
title: post.title,
|
||||||
description: post.description,
|
description: post.description,
|
||||||
images: [post.heroImage],
|
images: [post.heroImage],
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,14 @@ export default function LandingsLayout({
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{/* Skip to content link for accessibility */}
|
||||||
|
<a
|
||||||
|
href="#main-content"
|
||||||
|
className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-[100] focus:px-4 focus:py-2 focus:bg-violet-600 focus:text-white focus:rounded-lg focus:outline-none focus:ring-2 focus:ring-violet-400"
|
||||||
|
>
|
||||||
|
Skip to content
|
||||||
|
</a>
|
||||||
|
|
||||||
{/* Sticky Header */}
|
{/* Sticky Header */}
|
||||||
<header className="sticky top-0 z-50 bg-slate-900/80 backdrop-blur-md border-b border-white/5">
|
<header className="sticky top-0 z-50 bg-slate-900/80 backdrop-blur-md border-b border-white/5">
|
||||||
<nav className="max-w-7xl mx-auto px-4 sm:px-6 py-2 sm:py-3 flex justify-between items-center h-12 sm:h-14 md:h-16">
|
<nav className="max-w-7xl mx-auto px-4 sm:px-6 py-2 sm:py-3 flex justify-between items-center h-12 sm:h-14 md:h-16">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue