{"_id":"@danielsanjp/next-mdx-blog","_rev":"5-1543c95288478ed6874ac18c4b31ba0b","name":"@danielsanjp/next-mdx-blog","dist-tags":{"latest":"1.0.4"},"versions":{"1.0.0":{"name":"@danielsanjp/next-mdx-blog","version":"1.0.0","keywords":["nextjs","next","mdx","blog","typescript","react","markdown","static-site","ssg","cms","blogging","content","nextjs-blog","blog-system"],"author":{"name":"Daniel"},"license":"MIT","_id":"@danielsanjp/next-mdx-blog@1.0.0","maintainers":[{"name":"danielsanjp","email":"daniel.m514@outlook.com"}],"homepage":"https://github.com/DanielSanJP/next-mdx-blog#readme","bugs":{"url":"https://github.com/DanielSanJP/next-mdx-blog/issues"},"bin":{"next-mdx-blog":"bin/setup.js"},"dist":{"shasum":"c2532d26a1ff1c473aba9d81831d3e0d9d04fe88","tarball":"https://registry.npmjs.org/@danielsanjp/next-mdx-blog/-/next-mdx-blog-1.0.0.tgz","fileCount":15,"integrity":"sha512-m0VzQ5Tj0jsvqJxXRLWbSvJf0cFfIPgi3c4iy9FvhEDgCLjK0P1HZpl4CCYw/3tZNbxb8NqVOY2ZVRJHjrfWPg==","signatures":[{"sig":"MEUCIQDZwUS6ZYeDW8rfKkYzIL5ddmmYuslrI9fNdubqyB7HVgIgDhLsdJjh4dqQRaG+OdIgYPTBoy5uA6Y/D2rjEMQpRXU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":39458},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"92107b971c745a3904f4c5d2461abbfa83e566e3","scripts":{"build":"tsc","setup":"node bin/setup.js","prepublishOnly":"npm run build"},"_npmUser":{"name":"danielsanjp","email":"daniel.m514@outlook.com"},"repository":{"url":"git+https://github.com/DanielSanJP/next-mdx-blog.git","type":"git"},"_npmVersion":"10.9.0","description":"A simple, beautiful MDX-based blog system for Next.js with TypeScript support. Zero config, SEO optimized, and highly customizable.","directories":{},"_nodeVersion":"20.11.1","dependencies":{"chalk":"^4.1.2","fs-extra":"^11.2.0","inquirer":"^8.2.5","commander":"^11.1.0"},"_hasShrinkwrap":false,"devDependencies":{"next":"^15.0.0","react":"^18.2.0","typescript":"^5.3.3","@types/node":"^20.10.0","gray-matter":"^4.0.3","@types/react":"^18.2.42","reading-time":"^1.5.0","@types/fs-extra":"^11.0.4","next-mdx-remote":"^4.4.1"},"peerDependencies":{"next":">=14.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"optionalDependencies":{"gray-matter":"^4.0.3","reading-time":"^1.5.0","next-mdx-remote":"^4.4.1"},"_npmOperationalInternal":{"tmp":"tmp/next-mdx-blog_1.0.0_1760443032997_0.40552593936138503","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@danielsanjp/next-mdx-blog","version":"1.0.1","keywords":["nextjs","next","mdx","blog","typescript","react","markdown","static-site","ssg","cms","blogging","content","nextjs-blog","blog-system"],"author":{"name":"Daniel"},"license":"MIT","_id":"@danielsanjp/next-mdx-blog@1.0.1","maintainers":[{"name":"danielsanjp","email":"daniel.m514@outlook.com"}],"homepage":"https://github.com/DanielSanJP/next-mdx-blog#readme","bugs":{"url":"https://github.com/DanielSanJP/next-mdx-blog/issues"},"bin":{"next-mdx-blog":"bin/setup.js"},"dist":{"shasum":"a850988143a3077e30ab12f7be295762527a5907","tarball":"https://registry.npmjs.org/@danielsanjp/next-mdx-blog/-/next-mdx-blog-1.0.1.tgz","fileCount":15,"integrity":"sha512-xvfBYwCwI/1s5ki6mhXWahv4JWtEdFZjypDRHe49O2OxCSSp2ClP6SiNaSDGJ0Yxj0oTWAJ0lvaQ+m/8jT4uZA==","signatures":[{"sig":"MEQCIGHctup6z5tWlWaDfLIeRfV4/PLlr76hdU1PJxzhKmRrAiAXwGcL24PdgzcCheo6/4KqpvwXDRAOCE75o+YL4d8Eow==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37142},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./dist/*":"./dist/*"},"gitHead":"92107b971c745a3904f4c5d2461abbfa83e566e3","scripts":{"build":"tsc","setup":"node bin/setup.js","prepublishOnly":"npm run build"},"_npmUser":{"name":"danielsanjp","email":"daniel.m514@outlook.com"},"repository":{"url":"git+https://github.com/DanielSanJP/next-mdx-blog.git","type":"git"},"_npmVersion":"10.9.0","description":"A simple, beautiful MDX-based blog system for Next.js with TypeScript support. Zero config, SEO optimized, and highly customizable.","directories":{},"_nodeVersion":"20.11.1","dependencies":{"chalk":"^5.3.0","fs-extra":"^11.2.0","inquirer":"^10.2.2","commander":"^12.1.0"},"_hasShrinkwrap":false,"devDependencies":{"next":"^15.0.0","react":"^18.2.0","typescript":"^5.3.3","@types/node":"^20.10.0","gray-matter":"^4.0.3","@types/react":"^18.2.42","reading-time":"^1.5.0","@types/fs-extra":"^11.0.4","next-mdx-remote":"^4.4.1"},"peerDependencies":{"next":">=14.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"optionalDependencies":{"gray-matter":"^4.0.3","reading-time":"^1.5.0","next-mdx-remote":"^4.4.1"},"_npmOperationalInternal":{"tmp":"tmp/next-mdx-blog_1.0.1_1760443764277_0.40002560774500795","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@danielsanjp/next-mdx-blog","version":"1.0.2","keywords":["nextjs","next","mdx","blog","typescript","react","markdown","static-site","ssg","cms","blogging","content","nextjs-blog","blog-system"],"author":{"name":"Daniel"},"license":"MIT","_id":"@danielsanjp/next-mdx-blog@1.0.2","maintainers":[{"name":"danielsanjp","email":"daniel.m514@outlook.com"}],"homepage":"https://github.com/DanielSanJP/next-mdx-blog#readme","bugs":{"url":"https://github.com/DanielSanJP/next-mdx-blog/issues"},"bin":{"next-mdx-blog":"bin/setup.js"},"dist":{"shasum":"03604225f074799fd500e8e0f7415f1b8c05d1f8","tarball":"https://registry.npmjs.org/@danielsanjp/next-mdx-blog/-/next-mdx-blog-1.0.2.tgz","fileCount":15,"integrity":"sha512-USU5v3eHI5G9ebmV55F+lpbouUtNh09KPWoJLqOmpwBNP8C3P8sNb9zNjRymKD3tdxIgSzz4c7WOXCWdydPUVw==","signatures":[{"sig":"MEUCICDORqMaskk6dPY0g4zYLyTICdWEwD/KKuAxrNML0JFtAiEA9kD0/r4K34/TzBsnFWX8Q9tuTMIdM/F4ZOqoB1MKQsk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37317},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./dist/*":"./dist/*"},"gitHead":"92107b971c745a3904f4c5d2461abbfa83e566e3","scripts":{"build":"tsc","setup":"node bin/setup.js","prepublishOnly":"npm run build"},"_npmUser":{"name":"danielsanjp","email":"daniel.m514@outlook.com"},"repository":{"url":"git+https://github.com/DanielSanJP/next-mdx-blog.git","type":"git"},"_npmVersion":"10.9.0","description":"A simple, beautiful MDX-based blog system for Next.js with TypeScript support. Zero config, SEO optimized, and highly customizable.","directories":{},"_nodeVersion":"20.11.1","dependencies":{"chalk":"^5.3.0","fs-extra":"^11.2.0","inquirer":"^10.2.2","commander":"^12.1.0"},"_hasShrinkwrap":false,"devDependencies":{"next":"^15.0.0","react":"^18.2.0","typescript":"^5.3.3","@types/node":"^20.10.0","gray-matter":"^4.0.3","@types/react":"^18.2.42","reading-time":"^1.5.0","@types/fs-extra":"^11.0.4","next-mdx-remote":"^4.4.1"},"peerDependencies":{"next":">=14.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"optionalDependencies":{"gray-matter":"^4.0.3","reading-time":"^1.5.0","next-mdx-remote":"^4.4.1"},"_npmOperationalInternal":{"tmp":"tmp/next-mdx-blog_1.0.2_1760444649272_0.8546737722634237","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@danielsanjp/next-mdx-blog","version":"1.0.3","keywords":["nextjs","next","mdx","blog","typescript","react","markdown","static-site","ssg","cms","blogging","content","nextjs-blog","blog-system"],"author":{"name":"Daniel"},"license":"MIT","_id":"@danielsanjp/next-mdx-blog@1.0.3","maintainers":[{"name":"danielsanjp","email":"daniel.m514@outlook.com"}],"homepage":"https://github.com/DanielSanJP/next-mdx-blog#readme","bugs":{"url":"https://github.com/DanielSanJP/next-mdx-blog/issues"},"bin":{"next-mdx-blog":"bin/setup.js"},"dist":{"shasum":"489c90a63845c745cbae6b36a40776c098384b47","tarball":"https://registry.npmjs.org/@danielsanjp/next-mdx-blog/-/next-mdx-blog-1.0.3.tgz","fileCount":11,"integrity":"sha512-/M8DcmH0UHc/o8prV82zjYeFJ2+YZz+css5FzKGjNgSAeDvovXRbH/iVCK/4srA3YV8Y7fdnMzT8OE9OuN/xNg==","signatures":[{"sig":"MEUCIQC6kxITune8zH6U1xIZoNB78LN1OK2SS9J9OgW4mfWX/QIgGG6l2UpW2sFk4ILwyXVfQcVr/NqcPJ7CESlW0k0OOHs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51927},"type":"module","gitHead":"d9680670cba0f06e29d021056de6b39ff7ec2aff","scripts":{"setup":"node bin/setup.js"},"_npmUser":{"name":"danielsanjp","email":"daniel.m514@outlook.com"},"repository":{"url":"git+https://github.com/DanielSanJP/next-mdx-blog.git","type":"git"},"_npmVersion":"10.9.0","description":"A simple, beautiful MDX-based blog system for Next.js with TypeScript support. Zero config, SEO optimized, Table of Contents, and highly customizable.","directories":{},"_nodeVersion":"20.11.1","dependencies":{"chalk":"^5.3.0","fs-extra":"^11.2.0","inquirer":"^12.10.0","commander":"^14.0.1","rehype-slug":"^6.0.0"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^22.10.5","@types/fs-extra":"^11.0.4"},"peerDependencies":{"next":">=14.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/next-mdx-blog_1.0.3_1760459569704_0.5992240878800881","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@danielsanjp/next-mdx-blog","version":"1.0.4","description":"A simple, beautiful MDX-based blog system for Next.js with TypeScript support. Zero config, SEO optimized, Table of Contents, and highly customizable.","type":"module","bin":{"next-mdx-blog":"bin/setup.js"},"scripts":{"setup":"node bin/setup.js"},"keywords":["nextjs","next","mdx","blog","typescript","react","markdown","static-site","ssg","cms","blogging","content","nextjs-blog","blog-system"],"author":{"name":"Daniel"},"license":"MIT","homepage":"https://github.com/DanielSanJP/next-mdx-blog#readme","repository":{"type":"git","url":"git+https://github.com/DanielSanJP/next-mdx-blog.git"},"bugs":{"url":"https://github.com/DanielSanJP/next-mdx-blog/issues"},"peerDependencies":{"next":">=14.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"dependencies":{"chalk":"^5.3.0","commander":"^14.0.1","fs-extra":"^11.2.0","inquirer":"^12.10.0","rehype-slug":"^6.0.0"},"devDependencies":{"@types/fs-extra":"^11.0.4","@types/node":"^22.10.5"},"_id":"@danielsanjp/next-mdx-blog@1.0.4","gitHead":"d9680670cba0f06e29d021056de6b39ff7ec2aff","_nodeVersion":"20.11.1","_npmVersion":"10.9.0","dist":{"integrity":"sha512-l4PFBo+CzsSPxT0RskjwxVmWp5fCZtn17/o9WqL/DJ0Yr949/9vM1Vppi0XXa/SDLU3jusl8g7SbXzT5I1+kFA==","shasum":"eb7445b5e5817f5e6a53d23a3d531574232753c0","tarball":"https://registry.npmjs.org/@danielsanjp/next-mdx-blog/-/next-mdx-blog-1.0.4.tgz","fileCount":11,"unpackedSize":51665,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDn4ao11jTER/d140b4pfTuixlsyu4i0OIzo6ARwq/K/AiBNx3Dua2Nf6UTWT05V769PVfLQg7Nv4YQBS7/su3b5uQ=="}]},"_npmUser":{"name":"danielsanjp","email":"daniel.m514@outlook.com"},"directories":{},"maintainers":[{"name":"danielsanjp","email":"daniel.m514@outlook.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/next-mdx-blog_1.0.4_1760459952079_0.2121865378235197"},"_hasShrinkwrap":false}},"time":{"created":"2025-10-14T11:57:12.775Z","modified":"2025-10-14T16:39:12.461Z","1.0.0":"2025-10-14T11:57:13.176Z","1.0.1":"2025-10-14T12:09:24.521Z","1.0.2":"2025-10-14T12:24:09.463Z","1.0.3":"2025-10-14T16:32:49.882Z","1.0.4":"2025-10-14T16:39:12.268Z"},"bugs":{"url":"https://github.com/DanielSanJP/next-mdx-blog/issues"},"author":{"name":"Daniel"},"license":"MIT","homepage":"https://github.com/DanielSanJP/next-mdx-blog#readme","keywords":["nextjs","next","mdx","blog","typescript","react","markdown","static-site","ssg","cms","blogging","content","nextjs-blog","blog-system"],"repository":{"type":"git","url":"git+https://github.com/DanielSanJP/next-mdx-blog.git"},"description":"A simple, beautiful MDX-based blog system for Next.js with TypeScript support. Zero config, SEO optimized, Table of Contents, and highly customizable.","maintainers":[{"name":"danielsanjp","email":"daniel.m514@outlook.com"}],"readme":"# Next MDX Blog\r\n\r\nA simple, beautiful blog system for Next.js 15+ with MDX support. Write your blog posts in MDX and get a professional blog with zero configuration.\r\n\r\n## Features\r\n\r\n- **MDX Support** - Write blog posts in MDX with full JSX support\r\n- **TypeScript** - Fully typed for better development experience\r\n- **Zero Config** - Works out of the box\r\n- **SEO Optimized** - Automatic metadata and Open Graph tags\r\n- **Table of Contents** - Auto-generated sticky sidebar with active section highlighting\r\n- **Reading Time** - Automatic reading time calculation\r\n- **Tags & Categories** - Organize posts with tags\r\n- **Beautiful Styling** - Professional, responsive design\r\n- **Static Generation** - All pages statically generated for best performance\r\n- **Easy Setup** - CLI tool to scaffold everything in seconds\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install @danielsanjp/next-mdx-blog\r\n```\r\n\r\n### Dependencies\r\n\r\nThis package requires a Next.js 15+ project with Tailwind CSS configured. Additional dependencies will be installed automatically:\r\n\r\n```bash\r\nnpm install gray-matter reading-time next-mdx-remote remark-gfm rehype-slug\r\n```\r\n\r\n## Quick Start\r\n\r\n### 1. Run Setup\r\n\r\n```bash\r\nnpx @danielsanjp/next-mdx-blog\r\n```\r\n\r\nThis will:\r\n\r\n- Create blog pages in `src/app/blog/` (or `app/blog/` if no src directory)\r\n- Create a `content/blog/` directory with an example post\r\n- Create/update `mdx-components.tsx` for MDX rendering\r\n\r\n### 2. Write Your First Post\r\n\r\nCreate a file in `content/blog/my-first-post.mdx`:\r\n\r\n```mdx\r\n---\r\ntitle: \"My First Blog Post\"\r\ndescription: \"This is my first blog post using Next MDX Blog\"\r\ndate: \"2025-10-15\"\r\nauthor: \"Your Name\"\r\ntags: [\"Getting-started\", \"Tutorial\"]\r\n# Optional: Add a cover image\r\n# image: \"/blog/my-first-post.jpg\"\r\n# imageAlt: \"Blog post cover image\"\r\n---\r\n\r\n# Hello World!\r\n\r\nThis is my first blog post. I can use **markdown** and even _JSX components_!\r\n\r\n## Features I Love\r\n\r\n- Easy to write\r\n- Fast performance\r\n- Great SEO\r\n\r\nCheck out more at [my website](https://example.com).\r\n```\r\n\r\n### 3. Visit Your Blog\r\n\r\nStart your Next.js dev server and visit:\r\n\r\n- `/blog` - See all your posts\r\n- `/blog/my-first-post` - View individual post\r\n\r\n## What Gets Created\r\n\r\nThe setup command creates these files in your project:\r\n\r\n### Blog Pages\r\n\r\n- `app/blog/page.tsx` - Blog index with all posts\r\n- `app/blog/[slug]/page.tsx` - Individual blog post pages\r\n\r\n### Content & Utilities\r\n\r\n- `content/blog/example-post.mdx` - Example blog post\r\n- `lib/blog.tsx` - Blog data fetching functions (fully customizable)\r\n- `lib/mdx-components.tsx` - MDX styling components (shadcn/ui standards)\r\n- `mdx-components.tsx` - Root MDX config (required by Next.js)\r\n\r\n### Functions Available\r\n\r\nAfter setup, you can use these functions from `@/lib/blog`:\r\n\r\n```typescript\r\n// Get all blog posts (sorted by date)\r\nconst posts = await getAllPosts();\r\n\r\n// Get a specific post\r\nconst post = await getPostBySlug(\"my-first-post\");\r\n\r\n// Get posts by tag\r\nconst taggedPosts = await getPostsByTag(\"Tutorial\");\r\n\r\n// Get all unique tags\r\nconst tags = await getAllTags();\r\n```\r\n\r\n### Blog Post Interface\r\n\r\n```typescript\r\ninterface BlogPost {\r\n  slug: string;\r\n  title: string;\r\n  date: string;\r\n  excerpt: string;\r\n  author?: string;\r\n  tags?: string[];\r\n  readingTime?: number;\r\n  content?: React.ReactElement;\r\n  image?: string;\r\n  imageAlt?: string;\r\n}\r\n```\r\n\r\n### Frontmatter Fields\r\n\r\n| Field         | Type     | Required | Description                   |\r\n| ------------- | -------- | -------- | ----------------------------- |\r\n| `title`       | string   | Yes      | Post title                    |\r\n| `description` | string   | Yes      | Post excerpt/description      |\r\n| `date`        | string   | Yes      | Publication date (ISO format) |\r\n| `author`      | string   | No       | Author name                   |\r\n| `tags`        | string[] | No       | Array of tags                 |\r\n| `image`       | string   | No       | Cover image URL               |\r\n| `imageAlt`    | string   | No       | Image alt text                |\r\n\r\n## Customization\r\n\r\nAll files are copied to your project, giving you **full control** to customize everything:\r\n\r\n### Custom MDX Components\r\n\r\nEdit `lib/mdx-components.tsx` to style your blog posts:\r\n\r\n```typescript\r\n// lib/mdx-components.tsx\r\nconst mdxComponents: MDXComponents = {\r\n  h1: ({ children }) => (\r\n    <h1 className=\"text-4xl font-bold text-primary\">{children}</h1>\r\n  ),\r\n  // ... customize all elements\r\n};\r\n```\r\n\r\nThe default styling follows [shadcn/ui typography standards](https://ui.shadcn.com/docs/components/typography) for a clean, professional look.\r\n\r\n### Blog Functions\r\n\r\nEdit `lib/blog.tsx` to customize data fetching:\r\n\r\n```typescript\r\n// Change content directory\r\nconst contentDirectory = path.join(process.cwd(), \"posts\"); // instead of \"content/blog\"\r\n\r\n// Add custom post processing\r\n// Modify sorting, filtering, etc.\r\n```\r\n\r\n### Styling\r\n\r\nThe generated pages use Tailwind CSS. Customize these classes in the template files:\r\n\r\n- `container` - Main container\r\n- `bg-background`, `text-foreground` - Theme colors\r\n- `bg-muted`, `text-muted-foreground` - Muted colors\r\n- `text-primary`, `bg-primary` - Primary colors\r\n- `border` - Border colors\r\n\r\nYou can customize these in your `tailwind.config.js`.\r\n\r\n### Page Templates\r\n\r\nAfter running setup, you can freely edit the generated pages:\r\n\r\n- `app/blog/page.tsx` - Blog index page\r\n- `app/blog/[slug]/page.tsx` - Individual post page\r\n\r\n## File Structure\r\n\r\n```\r\nyour-nextjs-project/\r\n├── content/\r\n│   └── blog/\r\n│       ├── my-first-post.mdx\r\n│       └── another-post.mdx\r\n├── src/\r\n│   └── app/\r\n│       └── blog/\r\n│           ├── page.tsx           # Blog index\r\n│           └── [slug]/\r\n│               └── page.tsx       # Individual post\r\n├── mdx-components.tsx\r\n└── package.json\r\n```\r\n\r\n## API Reference\r\n\r\nAfter setup, you'll have these functions in `lib/blog.tsx`:\r\n\r\n### `getAllPosts(): Promise<BlogPost[]>`\r\n\r\nReturns all blog posts sorted by date (newest first).\r\n\r\n```typescript\r\nimport { getAllPosts } from \"@/lib/blog\";\r\nconst posts = await getAllPosts();\r\n```\r\n\r\n### `getPostBySlug(slug: string): Promise<BlogPost | null>`\r\n\r\nGet a single post by its slug (filename without extension).\r\n\r\n```typescript\r\nimport { getPostBySlug } from \"@/lib/blog\";\r\nconst post = await getPostBySlug(\"my-post\");\r\n```\r\n\r\n### `getPostsByTag(tag: string): Promise<BlogPost[]>`\r\n\r\nGet all posts with a specific tag.\r\n\r\n```typescript\r\nimport { getPostsByTag } from \"@/lib/blog\";\r\nconst posts = await getPostsByTag(\"Tutorial\");\r\n```\r\n\r\n### `getAllTags(): Promise<string[]>`\r\n\r\nGet all unique tags used across all posts.\r\n\r\n```typescript\r\nimport { getAllTags } from \"@/lib/blog\";\r\nconst tags = await getAllTags();\r\n```\r\n\r\n## Requirements\r\n\r\n- Next.js 15.0.0 or higher\r\n- React 18.0.0 or higher\r\n- Tailwind CSS\r\n- TypeScript (recommended)\r\n\r\n## Tips\r\n\r\n### Table of Contents\r\n\r\nThe blog automatically generates a **sticky sidebar Table of Contents** for each post:\r\n\r\n- Auto-extracts all `h2` and `h3` headings\r\n- Smooth scroll to sections\r\n- Active section highlighting as you scroll\r\n- Hidden on mobile, visible on large screens (xl breakpoint)\r\n- Styled with shadcn/ui design standards\r\n\r\n**How it works:**\r\n\r\n1. `rehype-slug` automatically adds IDs to all headings\r\n2. The `TableOfContents` component extracts headings from the DOM\r\n3. Uses Intersection Observer to track which section is visible\r\n4. Smooth scrolls when clicking TOC links\r\n\r\n**Customize the TOC:**\r\n\r\nEdit `components/TableOfContents.tsx` to:\r\n\r\n- Change which heading levels are included (currently h2 and h3)\r\n- Modify the styling and colors\r\n- Adjust the scroll offset\r\n- Change the Intersection Observer thresholds\r\n\r\n### Images in Blog Posts\r\n\r\n**Adding cover images:**\r\n\r\n1. Place images in `public/blog/` directory\r\n2. Reference them in frontmatter:\r\n\r\n```yaml\r\n---\r\nimage: \"/blog/my-image.jpg\"\r\nimageAlt: \"Description for accessibility\"\r\n---\r\n```\r\n\r\n**No image?** No problem! A beautiful placeholder will be shown automatically with a hint to add an image.\r\n\r\n### Syntax Highlighting\r\n\r\nInstall a code highlighting library like `rehype-highlight` or `rehype-prism-plus` and configure in your MDX compilation.\r\n\r\n### Draft Posts\r\n\r\nAdd a `draft: true` field to frontmatter and filter them out:\r\n\r\n```typescript\r\nconst posts = await getAllPosts();\r\nconst published = posts.filter((p) => !p.draft);\r\n```\r\n\r\n## Examples\r\n\r\n### Custom Blog Index\r\n\r\n```typescript\r\nimport { getAllPosts, getAllTags } from \"@/lib/blog\";\r\n\r\nexport default async function BlogPage() {\r\n  const posts = await getAllPosts();\r\n  const tags = await getAllTags();\r\n\r\n  return (\r\n    <div>\r\n      <h1>Blog</h1>\r\n      <div className=\"tags\">\r\n        {tags.map((tag) => (\r\n          <span key={tag}>{tag}</span>\r\n        ))}\r\n      </div>\r\n      <div className=\"posts\">\r\n        {posts.map((post) => (\r\n          <article key={post.slug}>\r\n            <h2>{post.title}</h2>\r\n            <p>{post.excerpt}</p>\r\n          </article>\r\n        ))}\r\n      </div>\r\n    </div>\r\n  );\r\n}\r\n```\r\n\r\n### RSS Feed\r\n\r\nCreate `app/blog/rss.xml/route.ts`:\r\n\r\n```typescript\r\nimport { getAllPosts } from \"@/lib/blog\";\r\n\r\nexport async function GET() {\r\n  const posts = await getAllPosts();\r\n\r\n  const rss = `<?xml version=\"1.0\"?>\r\n    <rss version=\"2.0\">\r\n      <channel>\r\n        <title>My Blog</title>\r\n        ${posts\r\n          .map(\r\n            (post) => `\r\n          <item>\r\n            <title>${post.title}</title>\r\n            <link>https://example.com/blog/${post.slug}</link>\r\n            <description>${post.excerpt}</description>\r\n            <pubDate>${new Date(post.date).toUTCString()}</pubDate>\r\n          </item>\r\n        `\r\n          )\r\n          .join(\"\")}\r\n      </channel>\r\n    </rss>`;\r\n\r\n  return new Response(rss, {\r\n    headers: { \"Content-Type\": \"application/xml\" },\r\n  });\r\n}\r\n```\r\n\r\n## Troubleshooting\r\n\r\n### MDX not rendering\r\n\r\nRun the setup command: `npx @danielsanjp/next-mdx-blog` to ensure all required files are created.\r\n\r\n### Styles not working\r\n\r\nMake sure Tailwind CSS is properly configured in your Next.js project.\r\n\r\n## License\r\n\r\nMIT\r\n\r\n## Contributing\r\n\r\nContributions are welcome! Please feel free to submit a Pull Request.\r\n\r\n## Support\r\n\r\nIf you have questions or need help, please open an issue on GitHub.\r\n\r\n---\r\n\r\nMade with ❤️ for the Next.js community\r\n","readmeFilename":"README.md"}