feat: improve blog
This commit is contained in:
parent
fd89bc424e
commit
8b1487e743
|
|
@ -12,6 +12,33 @@ import {
|
|||
BlogSidebar,
|
||||
BlogShareButtons,
|
||||
} 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 {
|
||||
params: Promise<{ slug: string }>;
|
||||
|
|
@ -41,7 +68,12 @@ export default async function BlogPostPage({ params }: PageProps) {
|
|||
const relatedArticles = getPostsBySlugs(post.relatedArticles);
|
||||
|
||||
return (
|
||||
<main>
|
||||
<>
|
||||
<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">
|
||||
|
|
@ -73,5 +105,6 @@ export default async function BlogPostPage({ params }: PageProps) {
|
|||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export const BlogImage = ({
|
|||
alt={alt}
|
||||
placeholder="blur"
|
||||
className="w-full h-auto"
|
||||
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 66vw, 800px"
|
||||
/>
|
||||
) : (
|
||||
<div className="relative aspect-video bg-gray-100">
|
||||
|
|
@ -33,6 +34,7 @@ export const BlogImage = ({
|
|||
alt={alt}
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 66vw, 800px"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -23,13 +23,13 @@ export const BlogShareButtons = ({ url, title }: BlogShareButtonsProps) => {
|
|||
const linkedinUrl = `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(shareUrl)}`;
|
||||
|
||||
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
|
||||
href={twitterUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
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">
|
||||
<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"
|
||||
rel="noopener noreferrer"
|
||||
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">
|
||||
<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
|
||||
onClick={handleCopyLink}
|
||||
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" />
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ export const metadata: Metadata = {
|
|||
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@BanatieApp',
|
||||
creator: '@BanatieApp',
|
||||
title: 'Blog | Banatie',
|
||||
description:
|
||||
'Articles, guides, and updates about AI-powered image generation.',
|
||||
|
|
@ -60,7 +62,7 @@ export default function BlogPage() {
|
|||
return (
|
||||
<>
|
||||
<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="grid grid-cols-1 lg:grid-cols-12 gap-8 lg:gap-12">
|
||||
<div className="lg:col-span-8 xl:col-span-9">
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ export const generatePostMetadata = (post: BlogPost): Metadata => ({
|
|||
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@BanatieApp',
|
||||
creator: '@BanatieApp',
|
||||
title: post.title,
|
||||
description: post.description,
|
||||
images: [post.heroImage],
|
||||
|
|
|
|||
|
|
@ -8,6 +8,14 @@ export default function LandingsLayout({
|
|||
}) {
|
||||
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 */}
|
||||
<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">
|
||||
|
|
|
|||
Loading…
Reference in New Issue