Release v1.2.0: Newspaper-style layout with major UI refinements
This release transforms PING into a sophisticated newspaper-style digital publication with enhanced readability and professional presentation. Major Features: - New FeaturedPostHero component with full-width newspaper design - Completely redesigned homepage with responsive newspaper grid layout - Enhanced PostCard component with refined typography and spacing - Improved mobile-first responsive design (mobile → tablet → desktop → 2XL) - Archive section with multi-column layout for deeper content discovery Technical Improvements: - Enhanced blog post validation and error handling in lib/blog.ts - Better date handling and normalization for scheduled posts - Improved Dockerfile with correct content volume mount paths - Fixed port configuration (3025 throughout stack) - Updated Tailwind config with refined typography and newspaper aesthetics - Added getFeaturedPost() function for hero selection UI/UX Enhancements: - Professional newspaper-style borders and dividers - Improved dark mode styling throughout - Better content hierarchy and visual flow - Enhanced author bylines and metadata presentation - Refined color palette with newspaper sophistication Documentation: - Added DESIGN_BRIEF_NEWSPAPER_LAYOUT.md detailing design principles - Added TESTING_RESULTS_25_POSTS.md with test scenarios This release establishes PING as a premium publication platform for AI orchestration and contextual intelligence thought leadership. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { notFound } from 'next/navigation'
|
||||
import { MDXRemote } from 'next-mdx-remote/rsc'
|
||||
import { getPostData, getAllPostSlugs } from '@/lib/blog'
|
||||
import { getPostData } from '@/lib/blog'
|
||||
import BlogHeader from '@/components/BlogHeader'
|
||||
import BlogFooter from '@/components/BlogFooter'
|
||||
import Link from 'next/link'
|
||||
@@ -15,10 +15,8 @@ interface PostPageProps {
|
||||
}>
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const slugs = getAllPostSlugs()
|
||||
return slugs.map(({ params }) => ({ slug: params.slug }))
|
||||
}
|
||||
// Force dynamic rendering - no static generation
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
export async function generateMetadata({ params }: PostPageProps) {
|
||||
const { slug } = await params
|
||||
@@ -102,38 +100,38 @@ export default async function PostPage({ params }: PostPageProps) {
|
||||
))}
|
||||
</div>
|
||||
|
||||
<h1 className="text-h1 font-logo text-carbon-950 dark:text-mulberry-100 mb-6">
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-h1 font-bold text-carbon-950 dark:text-mulberry-100 mb-6 leading-tight">
|
||||
{post.title}
|
||||
</h1>
|
||||
|
||||
<p className="text-xl text-carbon-700 dark:text-carbon-300 leading-relaxed mb-8">
|
||||
<p className="text-base sm:text-lg md:text-xl text-carbon-700 dark:text-carbon-300 leading-relaxed mb-8">
|
||||
{post.description}
|
||||
</p>
|
||||
|
||||
<div className="flex items-center justify-between border-b border-carbon-300 dark:border-carbon-800 pb-8">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between border-b border-carbon-300 dark:border-carbon-800 pb-8 gap-4">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="w-12 h-12 bg-gradient-to-br from-mulberry-400 to-ocean-500 rounded-full flex items-center justify-center">
|
||||
<span className="text-carbon-950 font-semibold">
|
||||
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-gradient-to-br from-mulberry-400 to-ocean-500 rounded-full flex items-center justify-center">
|
||||
<span className="text-carbon-950 font-semibold text-sm sm:text-base">
|
||||
{post.author.name.charAt(0)}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-carbon-950 dark:text-carbon-200 font-medium">
|
||||
<p className="text-carbon-950 dark:text-carbon-200 font-medium text-sm sm:text-base">
|
||||
{post.author.name}
|
||||
</p>
|
||||
{post.author.role && (
|
||||
<p className="text-carbon-600 dark:text-carbon-500 text-sm">
|
||||
<p className="text-carbon-600 dark:text-carbon-500 text-xs sm:text-sm">
|
||||
{post.author.role}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="blog-meta text-right">
|
||||
<time dateTime={post.date} className="block">
|
||||
<div className="blog-meta sm:text-right">
|
||||
<time dateTime={post.date} className="block text-sm sm:text-base">
|
||||
{formattedDate}
|
||||
</time>
|
||||
<span className="text-carbon-600 dark:text-carbon-600">
|
||||
<span className="text-carbon-600 dark:text-carbon-600 text-xs sm:text-sm">
|
||||
{post.readingTime} min read
|
||||
</span>
|
||||
</div>
|
||||
@@ -141,7 +139,7 @@ export default async function PostPage({ params }: PostPageProps) {
|
||||
</header>
|
||||
|
||||
{/* Article content */}
|
||||
<div className="prose prose-lg max-w-none">
|
||||
<div className="prose prose-lg max-w-none dark:prose-invert">
|
||||
<MDXRemote source={post.content} options={mdxOptions} />
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user