refactor(shell): strip global chrome and retire /posts routes

This commit is contained in:
kbot
2026-07-06 20:28:01 -05:00
parent 3e2a5a391c
commit 7199eb458a
6 changed files with 15 additions and 229 deletions

View File

@@ -3,9 +3,6 @@ import { Fraunces, IBM_Plex_Mono, JetBrains_Mono, Space_Grotesk } from 'next/fon
import { ThemeProvider } from '@wrksz/themes/next' import { ThemeProvider } from '@wrksz/themes/next'
import './globals.css' import './globals.css'
import 'katex/dist/katex.min.css' import 'katex/dist/katex.min.css'
import { Header } from '@/components/layout/Header'
import { Footer } from '@/components/layout/Footer'
import { ScrollProgress } from '@/components/ui/ScrollProgress'
import { Providers } from './providers' import { Providers } from './providers'
const fraunces = Fraunces({ const fraunces = Fraunces({
@@ -63,12 +60,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
forcedTheme="dark" forcedTheme="dark"
disableTransitionOnChange disableTransitionOnChange
> >
<Providers> <Providers>{children}</Providers>
<ScrollProgress />
<Header />
{children}
<Footer />
</Providers>
</ThemeProvider> </ThemeProvider>
</body> </body>
</html> </html>

View File

@@ -1,30 +1,18 @@
import { getPosts } from '@/lib/posts' import Link from 'next/link'
import { PostList } from '@/components/posts/PostList'
export default async function HomePage() {
const posts = await getPosts()
export default function HomePage() {
return ( return (
<main className="mx-auto max-w-5xl px-6 py-10 sm:py-14"> <div className="flex min-h-screen flex-col items-center justify-center gap-6 bg-blacksite-bg px-6 text-center text-blacksite-text">
<section aria-labelledby="recent-heading" className="space-y-7"> {/* Temporary placeholder until the portfolio landing is implemented in P5. */}
<div className="border-b border-border pb-5"> <h1 className="font-display text-4xl font-semibold tracking-tight sm:text-6xl">
<h1 id="recent-heading" className="heading-xl m-0 text-ink"> Krishna Ayyalasomayajula
Recent
</h1> </h1>
<Link
href="/blog/"
className="font-mono text-xs uppercase tracking-[0.22em] text-signal-cyan underline-offset-4 transition hover:text-signal-orange hover:underline"
>
Field Notes
</Link>
</div> </div>
{posts.length > 0 ? (
<PostList posts={posts} />
) : (
<div className="empty-state">
<p className="font-mono text-xs uppercase tracking-[0.22em] text-ink-soft">No posts yet</p>
<h3 className="heading-sm m-0 text-ink">The notebook is ready.</h3>
<p className="m-0 max-w-xl text-sm leading-6 text-ink-soft">
Add your first MDX post and it will show up here with the same polished card treatment.
</p>
</div>
)}
</section>
</main>
) )
} }

View File

@@ -1,88 +0,0 @@
import { notFound } from 'next/navigation'
import Link from 'next/link'
import { getPosts, getPost } from '@/lib/posts'
import { tagToSlug } from '@/lib/tags'
import { TableOfContents } from '@/components/posts/TableOfContents'
import { ScrollToTop } from '@/components/ui/ScrollToTop'
import { ReadingProgress } from '@/components/ui/ReadingProgress'
export const dynamicParams = false
export const dynamic = 'force-static'
export async function generateStaticParams() {
const posts = await getPosts()
if (posts.length === 0) {
return [{ slug: '__no-posts__' }]
}
return posts.map((post) => ({ slug: post.slug }))
}
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
const slug = (await params).slug
const post = await getPost(slug)
if (!post) return { title: 'Not Found' }
return { title: post.title }
}
export default async function PostPage({ params }: { params: Promise<{ slug: string }> }) {
const slug = (await params).slug
if (slug === '__no-posts__') notFound()
const post = await getPost(slug)
if (!post) notFound()
const { default: PostContent } = await import(
/* turbopackOptional: true */
`@/content/posts/${slug}.mdx`
)
return (
<>
<ScrollToTop />
<ReadingProgress />
<div className="mx-auto max-w-6xl px-6 py-16">
<div className="grid grid-cols-1 gap-8 lg:grid-cols-[minmax(0,1fr)_14rem] lg:gap-12">
<article className="min-w-0">
<header className="mb-12">
<time className="font-mono text-sm text-ink-soft" dateTime={post.date}>{new Date(post.date).toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' })}</time>
<h1 className="heading-xl text-ink mt-3 mb-2">
{post.title}
</h1>
<div className="flex items-center gap-4 font-mono text-xs text-ink-soft">
{post.author && <span>by {post.author}</span>}
<span>{post.readingTime} min read</span>
</div>
{post.coverImage && (
<img
src={post.coverImage}
alt={`Featured image for article: ${post.title}`}
className="my-8 aspect-[16/9] w-full rounded-2xl border border-border bg-surface object-cover shadow-card"
loading="eager"
decoding="async"
fetchPriority="high"
/>
)}
{post.tags.length > 0 && (
<div className="flex flex-wrap gap-2 mt-4">
{post.tags.map((tag) => (
<Link key={tag} href={`/tags/${tagToSlug(tag)}/`} className="rounded-full bg-surface px-3 py-1 text-xs font-medium text-ink-soft border border-border transition-colors hover:border-accent/50 hover:text-accent focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent">
{tag}
</Link>
))}
</div>
)}
</header>
<div className="prose prose-lg article-prose max-w-none min-w-0">
<PostContent />
</div>
</article>
<aside className="hidden lg:block">
<TableOfContents />
</aside>
</div>
</div>
</>
)
}

View File

@@ -1,30 +0,0 @@
import { getPosts } from '@/lib/posts'
import { PostSearch } from '@/components/posts/PostSearch'
export const metadata = { title: 'Posts' }
export default async function PostsPage() {
const posts = await getPosts()
return (
<main className="mx-auto max-w-5xl px-6 py-12 sm:py-16">
<header className="mb-10 border-b border-border pb-8">
<h1 className="heading-xl m-0 text-ink">
Posts
</h1>
</header>
{posts.length > 0 ? (
<PostSearch posts={posts} />
) : (
<section className="empty-state" aria-label="No posts published">
<p className="font-mono text-xs uppercase tracking-[0.22em] text-ink-soft">No posts yet</p>
<h2 className="heading-sm m-0 text-ink">The archive is empty.</h2>
<p className="m-0 max-w-xl text-sm leading-6 text-ink-soft">
Publish an MDX post to populate this list and enable archive search.
</p>
</section>
)}
</main>
)
}

View File

@@ -1,61 +0,0 @@
import type { Metadata } from 'next'
import { notFound } from 'next/navigation'
import { PostCard } from '@/components/posts/PostCard'
import { getAllTags, getPostsByTag } from '@/lib/posts'
type TagPageProps = {
params: Promise<{ tag: string }>
}
export const dynamicParams = false
export const dynamic = 'force-static'
export async function generateStaticParams() {
const tags = await getAllTags()
if (tags.length === 0) {
return [{ tag: '__no-tags__' }]
}
return tags.map((tag) => ({ tag: tag.slug }))
}
export async function generateMetadata({ params }: TagPageProps): Promise<Metadata> {
const slug = (await params).tag
const tags = await getAllTags()
const tag = tags.find((item) => item.slug === slug)
if (!tag) return { title: 'Not Found' }
return { title: `${tag.label} posts` }
}
export default async function TagPage({ params }: TagPageProps) {
const slug = (await params).tag
if (slug === '__no-tags__') notFound()
const tags = await getAllTags()
const tag = tags.find((item) => item.slug === slug)
if (!tag) notFound()
const posts = await getPostsByTag(slug)
return (
<main className="max-w-4xl mx-auto px-6 py-12">
<header className="mb-12">
<p className="font-mono text-sm text-ink-soft mb-3">Tag</p>
<h1 className="heading-xl text-ink mb-3">{tag.label}</h1>
<p className="text-ink-soft">
{tag.count} {tag.count === 1 ? 'post' : 'posts'}
</p>
</header>
<ul className="space-y-8">
{posts.map((post, index) => (
<li key={post.slug}>
<PostCard {...post} index={index} />
</li>
))}
</ul>
</main>
)
}

View File

@@ -1,15 +0,0 @@
"use client";
import { m } from "motion/react";
export default function Template({ children }: { children: React.ReactNode }) {
return (
<m.div
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, ease: "easeOut" }}
>
{children}
</m.div>
);
}