create-next-mdx-blog-app 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/Dockerfile +37 -0
  2. package/README.md +182 -0
  3. package/cli.js +52 -0
  4. package/components.json +21 -0
  5. package/eslint.config.mjs +16 -0
  6. package/mdx-components.tsx +208 -0
  7. package/next.config.ts +22 -0
  8. package/package.json +49 -0
  9. package/postcss.config.mjs +5 -0
  10. package/public/file.svg +1 -0
  11. package/public/globe.svg +1 -0
  12. package/public/next.svg +1 -0
  13. package/public/vercel.svg +1 -0
  14. package/public/window.svg +1 -0
  15. package/scripts/action-script/article-manager.ts +99 -0
  16. package/scripts/bash/project_setup.sh +19 -0
  17. package/scripts/powershell/project_setup.ps1 +18 -0
  18. package/scripts/sql/DDL/alterTable.sql +10 -0
  19. package/scripts/sql/DDL/createTable.sql +16 -0
  20. package/scripts/sql/DDL/dropTable.sql +3 -0
  21. package/scripts/sql/DDL/truncateTable.sql +2 -0
  22. package/scripts/sql/DML/deleteArticle.sql +6 -0
  23. package/scripts/sql/DML/fetchArticle.sql +15 -0
  24. package/scripts/sql/DML/insertArticle.sql +31 -0
  25. package/scripts/sql/DML/updateArticle.sql +12 -0
  26. package/src/app/dynamic/[dynamic_blog_post]/error.tsx +31 -0
  27. package/src/app/dynamic/[dynamic_blog_post]/page.tsx +18 -0
  28. package/src/app/favicon.ico +0 -0
  29. package/src/app/globals.css +159 -0
  30. package/src/app/layout.tsx +24 -0
  31. package/src/app/not-found.tsx +29 -0
  32. package/src/app/page.tsx +57 -0
  33. package/src/app/sample-blog-post-page/page.tsx +24 -0
  34. package/src/components/ArticleAuthorBio.tsx +27 -0
  35. package/src/components/ArticleCoverImage.tsx +17 -0
  36. package/src/components/ArticleHeader.tsx +40 -0
  37. package/src/components/DynamicArticle.tsx +32 -0
  38. package/src/components/MDXRemoteArticle.tsx +16 -0
  39. package/src/components/StaticArticle.tsx +14 -0
  40. package/src/components/customMDXComponents/CodeBlock.tsx +19 -0
  41. package/src/components/customMDXComponents/GitHubGist.tsx +48 -0
  42. package/src/components/customMDXComponents/MDXImage.tsx +21 -0
  43. package/src/components/ui/avatar.tsx +53 -0
  44. package/src/components/ui/badge.tsx +46 -0
  45. package/src/components/ui/button.tsx +59 -0
  46. package/src/lib/utils.ts +6 -0
  47. package/src/markdown/ArticleContent.mdx +108 -0
  48. package/src/markdown/DynamicArticleContent.mdx +58 -0
  49. package/src/utils/constants/ArticleAuthorInfoList.ts +10 -0
  50. package/src/utils/constants/ArticleHeaderInfoList.ts +18 -0
  51. package/src/utils/functions/crud/deleteArticle.ts +17 -0
  52. package/src/utils/functions/crud/fetchAllArticles.ts +16 -0
  53. package/src/utils/functions/crud/fetchArticle.ts +26 -0
  54. package/src/utils/functions/crud/insertArticle.ts +45 -0
  55. package/src/utils/functions/crud/updateArticle.ts +26 -0
  56. package/src/utils/functions/supabase_client/SupabaseClient.ts +13 -0
  57. package/src/utils/types/ArticleAuthorInfoType.ts +6 -0
  58. package/src/utils/types/ArticleCoverImageType.ts +4 -0
  59. package/src/utils/types/ArticleHeaderInfoType.ts +13 -0
  60. package/src/utils/types/GitHubGistType.ts +5 -0
  61. package/src/utils/types/MDXImageType.ts +8 -0
  62. package/tsconfig.json +39 -0
package/Dockerfile ADDED
@@ -0,0 +1,37 @@
1
+ # Dockerize the Next.js application and run a production version in a container using this Dockerfile
2
+ # Build stage
3
+ FROM node:20-alpine AS builder
4
+
5
+ WORKDIR /app
6
+
7
+ # Copy package files
8
+ COPY package*.json ./
9
+
10
+ # Install dependencies
11
+ RUN npm ci
12
+
13
+ # Copy the rest of the application
14
+ COPY . .
15
+
16
+ # Build the application
17
+ RUN npm run build
18
+
19
+ # Production stage
20
+ FROM node:20-alpine AS runner
21
+
22
+ WORKDIR /app
23
+
24
+ # Set environment variables
25
+ ENV NODE_ENV=production
26
+
27
+ # Copy necessary files from builder
28
+ COPY --from=builder /app/next.config.ts ./
29
+ COPY --from=builder /app/public ./public
30
+ COPY --from=builder /app/.next/standalone ./
31
+ COPY --from=builder /app/.next/static ./.next/static
32
+
33
+ # Expose the port the app runs on
34
+ EXPOSE 3000
35
+
36
+ # Command to run the application
37
+ CMD ["node", "server.js"]
package/README.md ADDED
@@ -0,0 +1,182 @@
1
+ # 🌟 Next-MDX-Blog-Starter
2
+ ## 📖 Introduction
3
+ This project is inspired by the elegant design and functionality of **Loveable**. It leverages the **Claude Sonnet 4** model for development, ensuring a robust and efficient coding experience.
4
+
5
+ The goal of this repository is to serve as a comprehensive starter kit for working with static and dynamic content using MDX, React, and Next.js (more specifically the App Router).
6
+
7
+ ## ⚙️ Project Setup
8
+
9
+ ### Prerequisites
10
+ - **Node.js**: Ensure you have Node.js installed (version 15.x or later).
11
+ - **NPM**: Node Package Manager comes with Node.js.
12
+
13
+ ### Installation
14
+ 1. Clone the repository:
15
+ ```bash
16
+ git clone https://github.com/CodingAbdullah/Next-MDX-Blog-Starter.git
17
+ cd mdx-medium-blog-post-provider
18
+ ```
19
+
20
+ 2. Install dependencies:
21
+ ```bash
22
+ npm install
23
+ ```
24
+
25
+ 3. Start the development server:
26
+ ```bash
27
+ npm run dev
28
+ ```
29
+
30
+ If you want, you can also run this project using the following command:
31
+ ```bash
32
+ npx create-next-blog-app .
33
+ ```
34
+ This will instantly create and setup the starter kit project for you to work on.
35
+
36
+ ## 🛠️ Tools
37
+ ### AI Tools
38
+ - **Cursor**: An AI-powered coding assistant that enhances productivity and code quality.
39
+ - **Loveable**: A design inspiration that emphasizes user-friendly interfaces and experiences.
40
+ - **Claude Sonnet 4**: A model that aids in development, providing intelligent suggestions and optimizations.
41
+
42
+ ### Common NPM Libraries
43
+ - **mdx**: A markdown format that allows you to write JSX in your markdown files, enabling rich content.
44
+ - **Supabase**: An open-source Firebase alternative that provides a backend as a service, including database and authentication.
45
+ - **shadcn/ui**: A collection of UI components designed for building modern web applications.
46
+ - **lucide-react**: A set of customizable icons for React applications, enhancing visual appeal.
47
+ - **gray-matter**: A library for parsing front matter from markdown files, useful for managing metadata.
48
+ - **react**: A JavaScript library for building user interfaces, allowing for the creation of reusable UI components.
49
+ - **react-syntax-highlighter**: A library for syntax highlighting in React applications, making code snippets more readable.
50
+ - **tsx**: Run TypeScript code without worrying about configuration! Run the `article-manager.ts` for manually working with published articles.
51
+
52
+ ## 🌐 Static/Dynamic Rendering with MDX
53
+ This project utilizes MDX for both static and dynamic rendering of blog posts. The two MDX files included in the project serve as examples of how to structure your content.
54
+
55
+ - **Static MDX**: Pre-rendered at build time (<b>route</b>: `/app/sample-blog-post-page`, <b>article content</b>: `/markdown/ArticleContent.mdx`).
56
+ - **Dynamic MDX**: Rendered on the server at request time (<b>route</b>: `/app/dynamic`, <b>article content</b>: `/markdown/DynamicArticleContent.mdx`).
57
+
58
+ ### Article Metadata
59
+ `.mdx` files can contain useful information that can be thought of as metadata for the file itself. This is called frontmatter and it is stored at the top of the file using this `---` opening and closing syntax.
60
+
61
+ A helpful package known as `gray-matter` is used to format and separate frontmatter from the article content which is useful when fetching and rendering dynamic MDX content.
62
+
63
+ Dynamic MDX content is rendered with the help of the `next-mdx-remote` package and utilizing the `MDXRemote` custom component.
64
+
65
+ ## 🖼️ MDX Components File
66
+ The `mdx-components.tsx` file located in the root, integrates styling for built-in HTML elements as well as optimizing built-in elements such as `<a>` and `<img>` using the built-in components provided by Next.js (`<Image>` and `<Link>`).
67
+
68
+ For more details on what this file is and how it is utilized in a Next.js application, you can refer to the official docs here.
69
+
70
+ ## 🧩 Custom React Components
71
+ Custom React components are created for enhanced functionality when working with MDX. The following are located in the `customMDXComponents` directory inside the `components` directory of the project.
72
+
73
+ ### Syntax Highlighting
74
+ The project includes a custom `CodeBlock` component for syntax highlighting code blocks using the `react-syntax-highlighter` package.
75
+
76
+ Default theme is set to the `vscDarkPlus` theme. Feel free to modify the theme and even add your own syntax highlighting library if you so choose.
77
+
78
+ You can read more about the library used in this project here.
79
+
80
+ ### GitHub Gists
81
+ For safety and ease of use, GitHub Gists can be integrated into MDX files to manage code snippets with its own custom component. Note that only GitHub Gists that are publicly available are supported. You can modify the component to integrate private Gists.
82
+
83
+ This custom component also utilizes the `react-syntax-highlighter` package for syntax highlighting the publicly accessible GitHub gists.
84
+
85
+ ### MDX Images
86
+ The project comes with its own `MDXImage` component that utilizes the Next.js built-in `Image` component as well as the built-in `figure` and `figcaption` elements to integrate imaging and captions seamlessly.
87
+
88
+ ## 🧩 Constants, Functions, & Types
89
+ In this project, you will find custom constants, functions, and types in the `/src/utils/` directory. Certain constants serve as placeholders in this demo application. While functions and data types are integral to the function of this web application, feel free to check them out.
90
+
91
+ ## 🗄️ Supabase Database Setup
92
+ The project uses Supabase for database management. The `SupabaseClient` module is configured to interact with your Supabase instance. The instance is located in `/src/utils/functions/supabase_client`.
93
+
94
+ **Ensure that the policies of the Supabase database enable you to perform the desired CRUD actions against your tables. You can modify these in the Supabase console.**
95
+
96
+ ### Environment Variables
97
+ Create a `.env` file in the root directory and add your Supabase secrets:
98
+
99
+ ``
100
+ SUPABASE_URL=your_supabase_url
101
+ ``
102
+
103
+ ``
104
+ SUPABASE_ANON_KEY=your_supabase_anon_key
105
+ ``
106
+
107
+ ## 🌩️ AWS
108
+ This application utilizes the AWS S3 service for the storage of images. You can find the external URL used to access these objects in the `next.config.ts` file. Feel free to use another service or modify the URL to point to a S3 bucket of your own.
109
+
110
+ Images are used in the `.mdx` files and utilized via the custom `MDXImage` component covered earlier.
111
+
112
+ ## 🐳 Docker
113
+ This application can be containerized using Docker.
114
+
115
+ To build an image, utilize the Dockerfile located in the root location of the repository and run the following commands to run this web application in a standalone container (passing in the Supabase credentials as well):
116
+
117
+ ``
118
+ docker build -t mdx-medium-blog .
119
+ ``
120
+
121
+ ``
122
+ docker run -e SUPABASE_URL=your_supabase_url \
123
+ -e SUPABASE_ANON_KEY=your_supabase_anon_key \
124
+ -p 3000:3000 mdx-medium-blog
125
+ ``
126
+
127
+ ## 🔄 CRUD Operations and Supabase Actions
128
+ Implementation of the CRUD operation functions is stored in the `/src/utils/functions/crud` directory. This includes functions for creating, reading, updating, and deleting articles in the Supabase database.
129
+
130
+ The `article-manager.ts` file utilizes these CRUD functions to successfully perform the desired actions.
131
+
132
+ ## 📜 Scripts for Setting Up Project
133
+ The `/scripts` folder contains various scripts to help set up the project and database.
134
+
135
+ ### Setup Scripts
136
+ - **SQL Scripts**: DDL and DML statements for initializing and populating the database.
137
+ - **Powershell Script**: Script for setting up project on Windows.
138
+ - **Bash Shell Script**: Script for setting up project on Linux, Mac, etc.
139
+
140
+ This project directly integrates Supabase in the front-end using React Server components which removes the need for custom back-end APIs.
141
+
142
+ ## 🛠️ Compiling TypeScript and Testing Locally
143
+ The `article-manager.ts` file (located in `/scripts/action-script`) utilizes the `tsx` package to perform the different actions (CRUD operations) on articles stored locally.
144
+
145
+ You can use this handy script for testing MDX and article functionality locally.
146
+
147
+ The following codeblock highlights the different command prompts that can be used with this file:
148
+
149
+ - Insert an Article into Supabase
150
+ npx tsx article-manager.ts insert article-slug
151
+
152
+ - Delete an Article from Supabase
153
+ npx tsx article-manager.ts delete article-slug
154
+
155
+ - Update an Article in Supabase
156
+ npx tsx article-manager.ts update article-slug new-article-file
157
+
158
+ - Fetch a Single Article from Supabase
159
+ npx tsx article-manager.ts fetch article-slug
160
+
161
+ - Fetch all Articles from Supabase
162
+ npx tsx article-manager.ts fetchAll
163
+
164
+ The article slug is the name of the markdown file located in the `/src/markdown` directory minus the extension, `.mdx`.
165
+
166
+ The update statement takes in an additional parameter which is also the same thing (file name minus the `.mdx` extension located in the `/src/markdown` directory).
167
+
168
+ ## 📊 Analytics
169
+ Integrated in this setup project is Vercel Analytics (`@vercel/analytics`) to track user interactions and performance metrics of the blog.
170
+
171
+ ## ⚙️ Next.js Configuration
172
+ The `next.config.ts` file is set up for working with AWS S3 and includes MDX extensions for enhanced functionality. Feel free to modify and add your own custom links to access storage and setting up other configurations.
173
+
174
+ ## 🔗 Useful Links
175
+ - [Next.js Documentation](https://nextjs.org/docs)
176
+ - [MDX Documentation](https://mdxjs.com/docs/)
177
+ - [Lee Robinson's Next.js + MDX Tutorial Video](https://www.youtube.com/watch?v=34bRv6cQezo&ab_channel=leerob)
178
+ - [MDX Playground](https://mdxjs.com/playground/)
179
+ - [React Documentation](https://reactjs.org/docs/getting-started.html)
180
+ - [Supabase Documentation](https://supabase.com/docs)
181
+ - [Docker Documentation](https://docs.docker.com/)
182
+ - [React Syntax Highlighter Package](https://github.com/react-syntax-highlighter/react-syntax-highlighter)
package/cli.js ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+
3
+ const execa = require('execa');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const inquirer = require('inquirer');
7
+
8
+ // Script for setting up CLI command for setting up project
9
+ async function setup() {
10
+ // Check if we are inside a project folder
11
+ const cwd = process.cwd();
12
+ const hasPackageJson = fs.existsSync(path.join(cwd, 'package.json'));
13
+
14
+ if (hasPackageJson) {
15
+ console.log('You already have a project setup here.');
16
+ return;
17
+ }
18
+
19
+ // Ask user for confirmation to set up
20
+ const answers = await inquirer.prompt([
21
+ {
22
+ type: 'confirm',
23
+ name: 'install',
24
+ message: 'Do you want to set up a Next.js blog app here?',
25
+ default: true,
26
+ },
27
+ ]);
28
+
29
+ if (!answers.install) {
30
+ console.log('Aborted the installation.');
31
+ return;
32
+ }
33
+
34
+ console.log('Setting up the project...');
35
+
36
+ // Initialize npm and install dependencies
37
+ try {
38
+ // Initialize package.json
39
+ await execa('npm', ['init', '-y']);
40
+
41
+ // Install dependencies
42
+ await execa('npm', ['install'], {
43
+ stdio: 'inherit',
44
+ });
45
+
46
+ console.log('Next.js Blog setup completed!');
47
+ } catch (error) {
48
+ console.error('Error during setup:', error);
49
+ }
50
+ }
51
+
52
+ setup();
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": true,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "src/app/globals.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "aliases": {
14
+ "components": "@/components",
15
+ "utils": "@/lib/utils",
16
+ "ui": "@/components/ui",
17
+ "lib": "@/lib",
18
+ "hooks": "@/hooks"
19
+ },
20
+ "iconLibrary": "lucide"
21
+ }
@@ -0,0 +1,16 @@
1
+ import { dirname } from "path";
2
+ import { fileURLToPath } from "url";
3
+ import { FlatCompat } from "@eslint/eslintrc";
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+
8
+ const compat = new FlatCompat({
9
+ baseDirectory: __dirname,
10
+ });
11
+
12
+ const eslintConfig = [
13
+ ...compat.extends("next/core-web-vitals", "next/typescript"),
14
+ ];
15
+
16
+ export default eslintConfig;
@@ -0,0 +1,208 @@
1
+ import type { MDXComponents } from 'mdx/types';
2
+ import Image, { ImageProps } from 'next/image';
3
+ import Link from 'next/link';
4
+ import { cn } from '@/lib/utils';
5
+ import CodeBlock from '@/components/customMDXComponents/CodeBlock';
6
+ import GitHubGist from '@/components/customMDXComponents/GitHubGist';
7
+ import MDXImage from '@/components/customMDXComponents/MDXImage';
8
+ // Custom MDX components for writing Medium article style blog posts
9
+ // Optimize Links and Images using Image and Link built-in components replacing img, a tags
10
+ // Code blocks, a, b, u, i, img, ul, ol, blockquote, h1, h2, h3, h4, h5, h6, custom component for handling GitHub Gists
11
+ // React-Syntax-Highlighting for Code Blocks (GitHub Gists) (integrate into MDX components file)
12
+ // Supabase containing Article Metadata (Name, Subtitle, Tags, Date, Slug, Description, etc.)
13
+ // *Check to see if Supabase can be used to store article content*
14
+ // Map markdown slugs to dynamic file path routing, loading static files
15
+ // Supabase for storing article metadata (article content?)
16
+ // AWS S3 for article images, thumbnails, etc.
17
+ // Gray Matter for MDX content metadata
18
+ // Dockerize the application
19
+ // Separate branch for SvelteKit version
20
+ // npx command script for downloading starting template
21
+ // Powershell/Shell script for creating the npx command script
22
+ // NPM package publishing as well
23
+ /*
24
+ // Example of Metadata for a MDX file
25
+ ---
26
+ title: "Understanding SEO in MDX"
27
+ description: "A guide on how to optimize MDX pages for search engines"
28
+ author: "John Doe"
29
+ date: "2025-05-28"
30
+ tags: ["SEO", "MDX", "React"]
31
+ slug: "/seo-in-mdx"
32
+ ---
33
+ */
34
+
35
+ // MDX Components mapper for both built-in and custom components
36
+ export function useMDXComponents(components: MDXComponents): MDXComponents {
37
+ return {
38
+ h1: ({ children, ...props }) => (
39
+ <h1 {...props} className={cn("text-3xl font-bold text-green-300 matrix-glow mt-8 mb-4", props.className)}>
40
+ {children}
41
+ </h1>
42
+ ),
43
+ h2: ({ children, ...props }) => (
44
+ <h2 {...props} className={cn("text-2xl font-bold text-green-300 matrix-glow mt-8 mb-4 border-b border-green-500/20 pb-2", props.className)}>
45
+ {children}
46
+ </h2>
47
+ ),
48
+ h3: ({ children, ...props }) => (
49
+ <h3 {...props} className={cn("text-xl font-bold text-green-300 matrix-glow mt-6 mb-3", props.className)}>
50
+ {children}
51
+ </h3>
52
+ ),
53
+ h4: ({ children, ...props }) => (
54
+ <h4 {...props} className={cn("text-lg font-bold text-green-300 matrix-glow mt-6 mb-2", props.className)}>
55
+ {children}
56
+ </h4>
57
+ ),
58
+ h5: ({ children, ...props }) => (
59
+ <h5 {...props} className={cn("text-base font-bold text-green-300 matrix-glow mt-4 mb-2", props.className)}>
60
+ {children}
61
+ </h5>
62
+ ),
63
+ h6: ({ children, ...props }) => (
64
+ <h6 {...props} className={cn("text-base font-bold text-green-300 mt-4 mb-2", props.className)}>
65
+ {children}
66
+ </h6>
67
+ ),
68
+ p: ({ children, ...props }) => {
69
+ // Check if the children is a code block
70
+ if (typeof children === 'string' && children.startsWith('```')) {
71
+ return <>{children}</>;
72
+ }
73
+ return (
74
+ <p {...props} className={cn("mb-4 leading-relaxed text-green-200/90", props.className)}>
75
+ {children}
76
+ </p>
77
+ );
78
+ },
79
+ a: ({ children, href, ...props }) => {
80
+ if (href?.startsWith('/')) {
81
+ return (
82
+ <Link href={href} className={cn("text-green-400 hover:text-green-300 underline", props.className)} {...props}>
83
+ {children}
84
+ </Link>
85
+ );
86
+ }
87
+ else if (href?.startsWith('https') || href?.startsWith('http')) {
88
+ return (
89
+ <a href={href} className={cn("text-green-400 hover:text-green-300 underline", props.className)} {...props}>
90
+ {children}
91
+ </a>
92
+ );
93
+ }
94
+ else {
95
+ return (
96
+ <Link
97
+ {...props}
98
+ href={href || ''}
99
+ className={cn("text-green-400 hover:text-green-300 underline", props.className)}>
100
+ {children}
101
+ </Link>
102
+ );
103
+ }
104
+ },
105
+ ul: ({ children, ...props }) => (
106
+ <ul {...props} className={cn("list-disc pl-6 mb-4 space-y-1", props.className)}>
107
+ {children}
108
+ </ul>
109
+ ),
110
+ ol: ({ children, ...props }) => (
111
+ <ol {...props} className={cn("list-decimal pl-6 mb-4 space-y-1", props.className)}>
112
+ {children}
113
+ </ol>
114
+ ),
115
+ li: ({ children, ...props }) => (
116
+ <li {...props} className={cn("mb-1 text-green-200/90", props.className)}>
117
+ {children}
118
+ </li>
119
+ ),
120
+ blockquote: ({ children, ...props }) => (
121
+ <blockquote
122
+ {...props}
123
+ className={cn("border-l-4 border-green-500/50 pl-4 py-1 mb-4 text-green-200/80 italic", props.className)}
124
+ >
125
+ {children}
126
+ </blockquote>
127
+ ),
128
+ img: (props) => (
129
+ <Image
130
+ width={50}
131
+ height={50}
132
+ sizes="100vw"
133
+ style={{ width: '50%', height: 'auto' }}
134
+ {...(props as ImageProps)}
135
+ />
136
+ ),
137
+ pre: ({ children, ...props }) => {
138
+ const codeChild =
139
+ typeof children === 'object' &&
140
+ children &&
141
+ 'props' in children &&
142
+ children.props;
143
+
144
+ if (codeChild) {
145
+ const { className, children: codeContent } = codeChild;
146
+
147
+ return (
148
+ <CodeBlock className={className}>
149
+ {codeContent}
150
+ </CodeBlock>
151
+ );
152
+ }
153
+
154
+ return (
155
+ <pre {...props} className={cn("not-prose my-6", props.className)}>
156
+ {children}
157
+ </pre>
158
+ );
159
+ },
160
+ strong: ({ children, ...props }) => (
161
+ <strong {...props} className="font-bold">
162
+ {children}
163
+ </strong>
164
+ ),
165
+ em: ({ children, ...props }) => (
166
+ <em {...props} className="italic">
167
+ {children}
168
+ </em>
169
+ ),
170
+ del: ({ children, ...props }) => (
171
+ <del {...props} className="line-through">
172
+ {children}
173
+ </del>
174
+ ),
175
+ table: ({ children, ...props }) => (
176
+ <div className="overflow-x-auto mb-6">
177
+ <table {...props} className="min-w-full border-collapse">
178
+ {children}
179
+ </table>
180
+ </div>
181
+ ),
182
+ thead: ({ children, ...props }) => (
183
+ <thead {...props} className="bg-green-900/30 border-b border-green-500/30">
184
+ {children}
185
+ </thead>
186
+ ),
187
+ th: ({ children, ...props }) => (
188
+ <th {...props} className="px-6 py-3 text-left text-sm font-semibold text-green-300">
189
+ {children}
190
+ </th>
191
+ ),
192
+ tr: ({ children, ...props }) => (
193
+ <tr {...props} className="border-b border-green-500/20">
194
+ {children}
195
+ </tr>
196
+ ),
197
+ td: ({ children, ...props }) => (
198
+ <td {...props} className="px-6 py-4 text-sm">
199
+ {children}
200
+ </td>
201
+ ),
202
+ hr: ({ ...props }) => (
203
+ <hr {...props} className="my-6 border-green-500/20" />
204
+ ),
205
+ GitHubGist,
206
+ MDXImage
207
+ }
208
+ };
package/next.config.ts ADDED
@@ -0,0 +1,22 @@
1
+ import createMDX from '@next/mdx';
2
+ import type { NextConfig } from 'next';
3
+
4
+ // Adding acceptable page extensions to be used in this application
5
+ // Adding external domains to be used in this application
6
+ const nextConfig: NextConfig = {
7
+ // Configure `pageExtensions` to include markdown and MDX files
8
+ pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'],
9
+ images: {
10
+ domains: ["mdx-blog-bucket.s3.us-east-2.amazonaws.com"]
11
+ },
12
+ experimental: {
13
+ mdxRs: true,
14
+ viewTransition: true
15
+ },
16
+ output: 'standalone' as const
17
+ }
18
+
19
+ const withMDX = createMDX({});
20
+
21
+ // Wrapping app configurations with the withMDX function
22
+ export default withMDX(nextConfig);
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "create-next-mdx-blog-app",
3
+ "version": "1.0.0",
4
+ "bin": {
5
+ "create-next-blog-app": "./cli.js"
6
+ },
7
+ "scripts": {
8
+ "dev": "next dev",
9
+ "build": "next build",
10
+ "start": "next start",
11
+ "lint": "next lint"
12
+ },
13
+ "dependencies": {
14
+ "@mdx-js/loader": "^3.1.0",
15
+ "@mdx-js/react": "^3.1.0",
16
+ "@next/mdx": "^15.3.2",
17
+ "@radix-ui/react-avatar": "^1.1.10",
18
+ "@radix-ui/react-slot": "^1.2.3",
19
+ "@supabase/supabase-js": "^2.49.8",
20
+ "@types/mdx": "^2.0.13",
21
+ "@types/react-syntax-highlighter": "^15.5.13",
22
+ "@vercel/analytics": "^1.5.0",
23
+ "class-variance-authority": "^0.7.1",
24
+ "clsx": "^2.1.1",
25
+ "execa": "^9.6.0",
26
+ "gray-matter": "^4.0.3",
27
+ "inquirer": "^12.6.3",
28
+ "lucide-react": "^0.511.0",
29
+ "next": "15.3.2",
30
+ "next-mdx-remote": "^5.0.0",
31
+ "react": "^19.0.0",
32
+ "react-dom": "^19.0.0",
33
+ "react-syntax-highlighter": "^15.6.1",
34
+ "tailwind-merge": "^3.3.0",
35
+ "tsx": "^4.19.4"
36
+ },
37
+ "devDependencies": {
38
+ "@eslint/eslintrc": "^3",
39
+ "@tailwindcss/postcss": "^4",
40
+ "@types/node": "^20.17.58",
41
+ "@types/react": "^19",
42
+ "@types/react-dom": "^19",
43
+ "eslint": "^9",
44
+ "eslint-config-next": "15.3.2",
45
+ "tailwindcss": "^4",
46
+ "tw-animate-css": "^1.3.2",
47
+ "typescript": "^5.8.3"
48
+ }
49
+ }
@@ -0,0 +1,5 @@
1
+ const config = {
2
+ plugins: ["@tailwindcss/postcss"],
3
+ };
4
+
5
+ export default config;
@@ -0,0 +1 @@
1
+ <svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>