@xenterprises/nuxt-x-blog
v0.1.1
Published
Nuxt layer for building blog functionality with Nuxt Content v3 — provides pre-built components, composables, and pages for a complete blog experience.
Readme
@xenterprises/nuxt-x-blog
Nuxt layer for building blog functionality with Nuxt Content v3 — provides pre-built components, composables, and pages for a complete blog experience.
Installation
npm install @xenterprises/nuxt-x-blogAdd to your nuxt.config.ts:
export default defineNuxtConfig({
extends: ['@xenterprises/nuxt-x-blog'],
})Content Configuration
Create a content.config.ts in your project root:
import { defineContentConfig, defineCollection } from '@nuxt/content'
import { z } from 'zod'
export default defineContentConfig({
collections: {
blog: defineCollection({
type: 'page',
source: 'blog/*.md',
schema: z.object({
title: z.string(),
description: z.string().optional(),
date: z.date(),
author: z.string().optional(),
image: z.string().optional(),
tags: z.array(z.string()).optional(),
published: z.boolean().default(true),
readingTime: z.number().optional(),
}),
}),
},
})Minimal Usage
Create markdown files in content/blog/:
---
title: My First Post
description: A brief description
date: 2025-03-15
author: Jane Developer
tags:
- nuxt
- vue
published: true
---
Your markdown content here...The blog listing page is automatically available at /blog and individual posts at /blog/[slug].
Components
All components use the XBL prefix and are auto-imported.
| Component | Description | Key Props |
|-----------|-------------|-----------|
| XBLPostCard | Blog post card with image, tags, and metadata | post: BlogPost, showImage?, showTags?, showAuthor?, showReadingTime? |
| XBLPostList | Grid of post cards | posts: BlogPost[], columns?: 1 \| 2 \| 3, showImage? |
| XBLPostHeader | Full header for post detail page | post: BlogPost |
| XBLTagList | Tag filter buttons with counts | tags: {tag, count}[], showCount?, activeTag? |
| XBLPagination | Page navigation with ellipsis | page: number, totalPages: number |
| XBLSearchInput | Search input with icon | modelValue: string |
| XBLShareButtons | Social share buttons (Twitter, LinkedIn, Facebook, copy) | title: string, url? |
| XBLTableOfContents | Sidebar TOC with depth indentation | links: {id, text, depth}[] |
| XBLRecentPosts | Compact recent posts for sidebars | posts: BlogPost[], title? |
Component Events
| Component | Event | Payload |
|-----------|-------|---------|
| XBLTagList | select | tag: string |
| XBLPagination | update:page | page: number |
Composables
useBlog()
Auto-imported composable providing all blog data access and utility functions.
| Method | Returns | Description |
|--------|---------|-------------|
| config | BlogConfig | Current blog configuration from app.config.ts |
| getPosts(options?) | Promise<{posts, total, page, totalPages, hasMore}> | Paginated posts with optional tag filter |
| getPostByPath(path) | Promise<BlogPost \| null> | Single post by its content path |
| getAllTags() | Promise<{tag, count}[]> | All tags with post counts, sorted by frequency |
| getRecentPosts(limit?) | Promise<BlogPost[]> | Most recent published posts |
| getRelatedPosts(post, limit?) | Promise<BlogPost[]> | Posts sharing tags with the given post |
| formatDate(dateStr) | string | Format a date string to a readable format |
| estimateReadingTime(text) | number | Estimate reading time in minutes |
getPosts Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| page | number | 1 | Page number |
| tag | string | — | Filter by tag |
| limit | number | config.postsPerPage | Posts per page |
Pages
The layer provides two pages:
| Route | Description |
|-------|-------------|
| /blog | Blog listing with search, tag filtering, and pagination |
| /blog/[...slug] | Post detail with content rendering, TOC, share buttons, and related posts |
Configuration
Override defaults in your app.config.ts:
export default defineAppConfig({
xBlog: {
title: 'My Blog',
description: 'Articles about tech',
postsPerPage: 12,
showAuthor: true,
showReadingTime: true,
showTags: true,
showTableOfContents: true,
showShareButtons: true,
},
})| Option | Type | Default | Description |
|--------|------|---------|-------------|
| title | string | 'Blog' | Blog page title |
| description | string | 'Latest articles and updates' | Blog page description |
| postsPerPage | number | 9 | Posts per page on the listing |
| dateFormat | string | 'MMM d, yyyy' | Date display format |
| showAuthor | boolean | true | Show author name on cards and headers |
| showReadingTime | boolean | true | Show estimated reading time |
| showTags | boolean | true | Show tag badges |
| showTableOfContents | boolean | true | Show TOC sidebar on post detail |
| showShareButtons | boolean | true | Show social share buttons on post detail |
Environment Variables
No environment variables are required. The blog layer uses Nuxt Content v3 with local markdown files.
Frontmatter Schema
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| title | string | Yes | Post title |
| description | string | No | Post excerpt/summary |
| date | date | Yes | Publication date (YYYY-MM-DD) |
| author | string | No | Author name |
| image | string | No | Cover image URL |
| tags | string[] | No | Post tags for categorization |
| published | boolean | No | Whether the post is visible (default: true) |
| readingTime | number | No | Reading time in minutes (manual override) |
How It Works
The layer registers @nuxt/content and @nuxt/ui as Nuxt modules and provides:
- Content Collection: Blog posts are stored as markdown files in
content/blog/and managed via Nuxt Content v3's collection system with Zod schema validation. - Composable (
useBlog): WrapsqueryCollection('blog')calls with filtering, pagination, tag aggregation, and related post scoring. - Components: 9 XBL-prefixed components built on Nuxt UI v4 for cards, lists, navigation, and social sharing.
- Pages: Blog listing page with search/filter/pagination and a catch-all detail page with
ContentRendererfor markdown rendering. - App Config: All display options are configurable via
app.config.tsunder thexBlognamespace.
Layer Architecture
nuxt.config.ts— Registers@nuxt/ui,@nuxt/content, Tailwind CSS v4, and syntax highlighting themes.app/app.config.ts— Default blog configuration with TypeScript module augmentation.app/composables/useBlog.ts— All data access and utility logic.app/components/X/BL/— 9 auto-imported blog components.app/pages/blog/— Listing and detail pages.app/types/index.ts—BlogPost,BlogAuthor, andBlogConfiginterfaces.
Dependencies
@nuxt/contentv3+ (devDependency)@nuxt/uiv4+tailwindcssv4+better-sqlite3(required by Nuxt Content v3)
Development
npm install
npm run dev # Start playground dev server
npm run test # Run vitest tests
npm run build # Build playground for productionLicense
UNLICENSED
