@terminal-bird/theme
v0.1.18
Published
A terminal-aesthetic Next.js theme for developers. Drop it into a Next.js project and get a fully-featured personal site — with articles, projects, testimonials, contact, and about pages — driven entirely by Markdown files and a single config object.
Readme
@terminal-bird/theme
A terminal-aesthetic Next.js theme for developers. Drop it into a Next.js project and get a fully-featured personal site — with articles, projects, testimonials, contact, and about pages — driven entirely by Markdown files and a single config object.
Requirements
- Node.js 18+
- Next.js 14+
- React 18+
Installation
npm install @terminal-bird/themeThe package runs a postinstall script that scaffolds all required files into your project automatically. If you're installing into an existing Next.js project, it will only add files that don't already exist and will merge missing keys into your package.json without overwriting anything.
After install, run:
npm install # pick up any newly added dependencies
npm run devProject Structure
After install, your project will contain:
app/
layout.tsx ← root layout (wraps TerminalBirdLayout)
page.tsx ← home page
about/page.tsx
articles/ ← list, detail, pagination, category, tag pages
projects/ ← list, detail, pagination, category, tag pages
contact/page.tsx
testimonials/ ← list + pagination pages
not-found.tsx
sitemap.ts
robots.ts
manifest.ts
rss.xml/route.ts
opengraph-image.tsx
icon.tsx
config/
site.ts ← identity, SEO, social links, navigation
home.ts
about.ts
articles.ts
projects.ts
contact.ts
testimonials.ts
layout.ts
theme.ts
notfound.ts
content/
articles/ ← Markdown files for articles
projects/ ← Markdown files for projects
testimonials/ ← Markdown files for testimonials
theme.config.ts ← assembles all config into one object
next.config.js
tsconfig.jsonSetup
1. Configure your site identity
Edit config/site.ts:
export const siteConfig = {
logo: 'YN', // short prompt label, e.g. "$ YN"
name: 'Your Name',
url: 'https://yoursite.com',
description: 'One-sentence description for SEO.',
author: {
name: 'Your Name',
email: '[email protected]',
},
keywords: ['developer', 'typescript'],
social: {
github: 'https://github.com/yourusername',
linkedin: 'https://linkedin.com/in/yourusername',
twitter: '@yourusername',
},
navigation: [
{ label: 'Home', href: '/', showInHeader: true, showInFooter: false },
{ label: 'About', href: '/about', showInHeader: true, showInFooter: true },
{ label: 'Articles', href: '/articles', showInHeader: true, showInFooter: true },
{ label: 'Projects', href: '/projects', showInHeader: true, showInFooter: true },
{ label: 'Testimonials', href: '/testimonials', showInHeader: false, showInFooter: true },
{ label: 'Contact', href: '/contact', showInHeader: true, showInFooter: true },
],
}2. Wire up the root layout
Your app/layout.tsx should pass the config to TerminalBirdLayout:
import { TerminalBirdLayout } from '@terminal-bird/theme'
import '@terminal-bird/theme/styles'
import themeConfig from '../theme.config'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return <TerminalBirdLayout config={themeConfig}>{children}</TerminalBirdLayout>
}3. Wire up pages
Each page is a thin re-export. Example app/page.tsx:
import { HomePage } from '@terminal-bird/theme'
export default HomePageAll other pages follow the same pattern — the scaffolded files already do this for you.
Content
Content lives in Markdown files under content/. Each file requires a frontmatter block.
Articles — content/articles/*.md
---
title: 'My Article'
slug: 'my-article'
description: 'Short description.'
excerpt: 'One-sentence teaser shown in listings.'
publishedAt: '2024-06-01'
updatedAt: '2024-06-01'
category: 'engineering'
subcategory: 'typescript' # optional
tags: ['typescript', 'dx']
author: 'Your Name'
readingTime: 5 # minutes, integer
published: true # set false to draft
seo:
metaTitle: 'My Article — Your Name'
metaDescription: 'Short description for search engines.'
keywords: ['typescript', 'dx']
canonicalUrl: '/articles/my-article'
ogImage: '/opengraph-image.png'
---
Article body in Markdown. Supports Mermaid diagrams and syntax-highlighted code blocks.Projects — content/projects/*.md
---
title: 'My Project'
slug: 'my-project'
description: 'What it does.'
excerpt: 'One-sentence teaser.'
category: 'open-source'
status: 'active' # active | beta | stable | archived
license: 'MIT'
lastCommit: '2024-06-01'
tags: ['rust', 'cli']
featured: true # floats to top of list
published: true
stats:
stars: 120
forks: 14
contributors: 3
version: '1.2.0'
buildStatus: 'passing' # passing | failing | unknown
coverage: 87
links:
github: 'https://github.com/you/project'
demo: 'https://demo.example.com'
docs: 'https://docs.example.com'
npm: 'https://npmjs.com/package/your-package'
seo:
metaTitle: 'My Project — Your Name'
metaDescription: 'What it does.'
keywords: ['rust', 'cli']
canonicalUrl: '/projects/my-project'
ogImage: '/opengraph-image.png'
---
Project body in Markdown.Testimonials — content/testimonials/*.md
---
title: 'Great to work with'
slug: 'jane-doe-testimonial'
excerpt: 'One-sentence pull quote.'
author: 'Jane Doe'
role: 'Engineering Manager'
company: 'Acme Corp'
publishedAt: '2024-03-15'
published: true
---
Full testimonial text in Markdown.Configuration Reference
All config is assembled in theme.config.ts and typed as TerminalBirdConfig.
layout
// config/layout.ts
export const layoutConfig = {
mainWidth: '90vw', // CSS value for <main> width on desktop; mobile is always 100vw
}theme
// config/theme.ts
export const themeConfig = {
activeLight: 'light', // 'light' | 'light_lux'
activeDark: 'dark', // 'dark' | 'dark_lux'
}Four built-in palettes:
| Name | Style |
|-------------|------------------------------|
| dark | Deep green terminal |
| light | Soft green terminal |
| dark_lux | Neutral dark, minimal colour |
| light_lux | Neutral light, minimal colour|
home
export const homeConfig = {
sections: { hero: '80vw' },
hero: {
title: 'Hello, World.',
taglines: ['I build things.', 'I write about code.'],
description: 'Paragraph shown below the typewriter.',
cta: {
primary: { label: 'View Projects', href: '/projects' },
secondary: { label: 'Read Articles', href: '/articles' },
},
},
}about
Controls the /about page sections: hero, coreServices, expertise, principles, certifications, cta. Each section accepts a title, description, and an array of items with { title, value, description, href }.
articles / projects / testimonials
export const articlesConfig = {
sections: { list: '90vw', detail: '70vw' },
hero: { title: 'Articles', description: 'Writing on engineering and craft.' },
metadata: { title: 'Articles', description: 'All articles.' },
backLink: { text: '← Back to articles' },
itemsPerPage: 10,
}contact
export const contactConfig = {
sections: { contact: '80vw' },
metadata: { description: 'Get in touch.' },
title: 'Contact',
subtitle: 'Ways to reach me.',
methods: [
{ title: 'Email', value: '[email protected]', description: 'Best for async.', href: 'mailto:[email protected]' },
],
}notFound
export const notFoundConfig = {
title: '404',
tagline: 'Page not found.',
description: 'The page you were looking for does not exist.',
buttons: [
{ label: 'Go Home', href: '/', variant: 'primary' },
],
}Updating
npm install @terminal-bird/theme@latestThe postinstall script only adds new files — it never overwrites existing ones. Your content and config are always safe.
To see what version you're on:
npm list @terminal-bird/themeUtilities
The package exports server-side helpers for sitemap, robots, manifest, and RSS:
import { generateSitemap, generateRobots, generateManifest, generateRssFeed } from '@terminal-bird/theme'And content loaders:
import { getAllArticles, getArticleBySlug } from '@terminal-bird/theme'
import { getAllProjects, getProjectBySlug } from '@terminal-bird/theme'
import { getAllTestimonials } from '@terminal-bird/theme'License
MIT
