create-next-mdx-blog-app 2.2.1 β†’ 2.2.3

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 (2) hide show
  1. package/README.md +427 -416
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,416 +1,427 @@
1
- # 🌟 Next-MDX-Blog-Starter
2
- ## πŸ“– Introduction
3
- This project is inspired by the elegant design and functionality of **Lovable**. It leverages the **Claude Sonnet 4.6** 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
- ### πŸš€ SSG-Compliant Architecture
8
- This starter kit is built with **Static Site Generation (SSG)** compliance at its core, ensuring optimal performance and SEO benefits:
9
-
10
- - **Pre-rendered Pages**: All blog posts and content pages are statically generated at build time for lightning-fast loading
11
- - **Optimized Assets**: Images, fonts, and other assets are optimized for static delivery
12
- - **SEO-Ready**: Meta tags, structured data, and semantic HTML are generated statically for better search engine visibility
13
- - **CDN-Friendly**: Static output can be easily deployed to any CDN or static hosting provider
14
- - **Zero Runtime Dependencies**: Core content rendering requires no client-side JavaScript, ensuring accessibility and performance
15
-
16
- ## βš™οΈ Project Setup
17
-
18
- ### Prerequisites
19
- - **Node.js**: Ensure you have Node.js installed (version 18.17.0 or later).
20
- - **NPM**: Node Package Manager comes with Node.js.
21
-
22
- ### Installation
23
- 1. Clone the repository:
24
- ```bash
25
- git clone https://github.com/CodingAbdullah/Next-MDX-Blog-Starter.git
26
- cd mdx-medium-blog-post-provider
27
- ```
28
-
29
- 2. Install dependencies:
30
- ```bash
31
- npm install
32
- ```
33
-
34
- 3. Configure environment variables:
35
- ```bash
36
- cp .env.example .env.local
37
- # Fill in SUPABASE_URL, SUPABASE_ANON_KEY, ANTHROPIC_API_KEY, and others in .env.local
38
- ```
39
-
40
- 4. Start the development server:
41
- ```bash
42
- npm run dev
43
- ```
44
-
45
- If you want, you can also run this project using the following command:
46
- ```bash
47
- npx create-next-mdx-blog-app .
48
- ```
49
- This will clone the repository, install dependencies, and guide you through environment setup automatically.
50
-
51
- ## ![NPM](https://img.shields.io/badge/NPM-CB3837?style=for-the-badge&logo=npm&logoColor=white) Package
52
-
53
- ### Quick Start
54
-
55
- **`npx create-next-mdx-blog-app .`**
56
-
57
- ```bash
58
- npx create-next-mdx-blog-app .
59
- ```
60
-
61
- ### Package Information
62
-
63
- - **Package Name**: `create-next-mdx-blog-app`
64
- - **Version**: `2.2.1`
65
- - **License**: MIT
66
- - **Homepage**: [https://www.npmjs.com/package/create-next-mdx-blog-app](https://www.npmjs.com/package/create-next-mdx-blog-app/)
67
-
68
- ## πŸ› οΈ Tools
69
- ### AI Tools
70
- - **Cursor**: An AI-powered coding assistant that enhances productivity and code quality.
71
- - **Lovable**: A design inspiration that emphasizes user-friendly interfaces and experiences.
72
- - **Claude Sonnet 4.6**: A model that aids in development, providing intelligent suggestions and optimizations.
73
-
74
- ### Common NPM Libraries
75
- - **mdx**: A markdown format that allows you to write JSX in your markdown files, enabling rich content.
76
- - **Supabase**: An open-source Firebase alternative that provides a backend as a service, including database and authentication.
77
- - **shadcn/ui**: A collection of UI components designed for building modern web applications.
78
- - **lucide-react**: A set of customizable icons for React applications, enhancing visual appeal.
79
- - **gray-matter**: A library for parsing front matter from markdown files, useful for managing metadata.
80
- - **react**: A JavaScript library for building user interfaces, allowing for the creation of reusable UI components.
81
- - **react-syntax-highlighter**: A library for syntax highlighting in React applications, making code snippets more readable.
82
- - **tsx**: Run TypeScript code without worrying about configuration! Run the `article-manager.ts` for manually working with published articles.
83
- - **@codesandbox/sandpack-react**: Powers the in-browser JavaScript/TypeScript code execution environment, running code entirely client-side with no server required.
84
- - **ai** (Vercel AI SDK): Provides streaming AI response primitives and transport utilities (`TextStreamChatTransport`, `streamText`, tool support) used by both the interactive chatbot and the AI article summarizer.
85
- - **@ai-sdk/anthropic**: Anthropic provider for the Vercel AI SDK, used to connect to Claude models.
86
- - **@ai-sdk/react**: React hooks (`useChat`) for building streaming AI chat interfaces.
87
- - **zod**: TypeScript-first schema validation library used to define and validate AI tool parameters.
88
- - **sonner**: Lightweight toast notification library used for user feedback across the Code Sandbox, the `CodeBlock` copy button, and the GitHub Gist copy button.
89
-
90
- ## 🌐 Static/Dynamic Rendering with MDX
91
- 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.
92
-
93
- - **Static MDX**: Pre-rendered at build time (<b>route</b>: `/app/sample-blog-post-page`, <b>article content</b>: `/markdown/ArticleContent.mdx`).
94
- - **Dynamic MDX**: Rendered on the server at request time (<b>route</b>: `/app/dynamic`, <b>article content</b>: `/markdown/DynamicArticleContent.mdx`).
95
-
96
- ### Article Metadata
97
- `.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.
98
-
99
- 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.
100
-
101
- Dynamic MDX content is rendered with the help of the `next-mdx-remote` package and utilizing the `MDXRemote` custom component.
102
-
103
- ## πŸ–ΌοΈ MDX Components File
104
- 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>`).
105
-
106
- 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 <a href="https://nextjs.org/docs/app/api-reference/file-conventions/mdx-components">here</a>.
107
-
108
- ## 🧩 Custom React Components
109
- 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.
110
-
111
- ### Syntax Highlighting
112
- The project includes a custom `CodeBlock` component for syntax highlighting code blocks using the `react-syntax-highlighter` package.
113
-
114
- 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.
115
-
116
- A **copy button** is rendered in the top-right corner of every code block. Clicking it writes the code to the clipboard and triggers a sonner toast notification confirming success or failure.
117
-
118
- You can read more about the library used in this project <a href="https://react-syntax-highlighter.github.io/react-syntax-highlighter/demo/">here.</a>
119
-
120
- ### GitHub Gists
121
- GitHub Gists can be embedded directly in MDX files using the `<GitHubGist>` custom component. The component fetches gist content live from the **GitHub REST API** at render time and caches the result for one hour via Next.js ISR (`next: { revalidate: 3600 }`).
122
-
123
- ```mdx
124
- <GitHubGist id="your-gist-id" figCaptionText="Caption shown below the gist" />
125
- ```
126
-
127
- #### How it works
128
- 1. `GitHubGist` calls `https://api.github.com/gists/<id>` to retrieve metadata (file name, detected language).
129
- 2. It then fetches the raw file content from the `raw_url` returned by the API.
130
- 3. The language is mapped to a Prism-compatible token using the built-in `GITHUB_GIST_LANGUAGE_MAP` constant (70+ languages supported β€” see `src/utils/constants/GitHubGistConstants.ts`).
131
- 4. The code is rendered via `GistCodeBlock` (syntax-highlighted with `react-syntax-highlighter`) inside a scrollable container with a custom green scrollbar (`scrollbar-gist`).
132
-
133
- #### mdxgists.net
134
- Each rendered gist includes a header bar with:
135
- - The detected **language badge**
136
- - A **Copy** button that writes the raw content to clipboard with a sonner toast confirmation
137
- - A **mdxgists.net** link that opens the gist on [mdxgists.net](https://mdxgists.net) β€” a companion site for browsing and sharing MDX-ready gists
138
-
139
- The mdxgists.net URL is constructed as `<GIST_BASE_URL>/<GITHUB_USERNAME>/<gist-id>` using values from `GitHubGistConstants.ts`. Both values can be overridden via environment variables (see below).
140
-
141
- #### Components
142
- - `src/components/customMDXComponents/GitHubGist.tsx` β€” async Server Component; fetches from GitHub API, resolves language, builds the mdxgists.net URL, renders the full gist UI
143
- - `src/components/customMDXComponents/GistCodeBlock.tsx` β€” syntax-highlighted code display using `react-syntax-highlighter`
144
- - `src/components/customMDXComponents/GistCopyButton.tsx` β€” `"use client"` component; copy-to-clipboard with sonner toast + mdxgists.net external link
145
-
146
- #### Language Detection
147
- The `GITHUB_GIST_LANGUAGE_MAP` in `src/utils/constants/GitHubGistConstants.ts` maps GitHub's reported language names to Prism-compatible identifiers. Over 70 languages are supported out of the box including TypeScript, Python, Rust, Go, Solidity, YAML, SQL, and more. If a language is not in the map, the component falls back to `language.toLowerCase()`. If no language is detected, it falls back to `text`.
148
-
149
- #### GitHub OAuth Token (optional but recommended)
150
- Unauthenticated requests to the GitHub API are rate-limited to **60 requests per hour** per IP. For production use, set a `GITHUB_TOKEN` environment variable to increase this to **5,000 requests per hour**:
151
-
152
- ```bash
153
- # .env.local
154
- GITHUB_TOKEN=ghp_your_personal_access_token
155
- ```
156
-
157
- To generate a token: GitHub β†’ Settings β†’ Developer settings β†’ Personal access tokens β†’ Generate new token. The token only needs the **read-only** `gist` scope (or no scopes at all for public gists).
158
-
159
- > Only **public** gists are supported by default. The component can be modified to support private gists by adding the appropriate scopes to the token.
160
-
161
- ### MDX Images
162
- 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.
163
-
164
- Images are displayed inside a styled container with a **green glow border** and a **hover scale effect** consistent with the rest of the matrix-green design system.
165
-
166
- ### Article Header Actions
167
- A **Copy Link** button (`src/components/CopyLinkButton.tsx`) is rendered in the article header, writing the current page URL to the clipboard on click and displaying a brief "Copied!" confirmation via icon swap. **Social Share** buttons (`src/components/SocialShareButtons.tsx`) sit alongside it, opening pre-filled share dialogs for X (Twitter), LinkedIn, and Reddit in a new tab using the article title and URL.
168
-
169
- ### Reading Progress Bar
170
- A thin green bar (`src/components/ReadingProgressBar.tsx`) is fixed to the top of the viewport on all article pages, growing from left to right as the reader scrolls through the article. It uses a passive scroll listener for zero performance impact and includes `role="progressbar"` ARIA attributes for accessibility.
171
-
172
- ### Back to Top Button
173
- A floating circular button (`src/components/BackToTopButton.tsx`) appears in the bottom-right corner of the screen once the reader has scrolled more than 400px down the page. Clicking it smoothly scrolls back to the top. The button is hidden when not needed and matches the green colour scheme of the rest of the UI.
174
-
175
- ### Light / Dark Mode Toggle
176
- A theme toggle button (`src/components/ThemeToggle.tsx`) is rendered in the site header, allowing readers to switch between **dark** (default) and **light** modes. Theme state is managed by `next-themes` via the `ThemeProvider` wrapper (`src/components/ThemeProvider.tsx`) mounted in the root layout. The active theme is persisted to `localStorage` automatically. Toast notifications use `ThemedToaster` (`src/components/ThemedToaster.tsx`), a thin wrapper around `sonner` that picks the correct Sonner theme to match the active colour scheme.
177
-
178
- ### View Counter
179
- Each article page displays a live view count stored in a dedicated `view_counts` Supabase table, incremented atomically via the `increment_view_count` RPC function. Dynamic pages increment server-side at render time; static pages use a `ViewCounter` client component that calls the `/api/views/[slug]` Route Handler after hydration.
180
-
181
- ## πŸ–₯️ Code Sandbox
182
- The project includes an interactive in-browser code execution environment powered by **Sandpack** (<b>route</b>: `/code-sandbox`).
183
-
184
- ### Features
185
- - **JavaScript & TypeScript runtimes**: Switch between JS and TS with a single click. The editor reloads with a language-appropriate default snippet.
186
- - **Quick Examples**: Pre-loaded snippets covering Fibonacci, Async/Await, Data Structures (JS) and Types & Interfaces, Generics, Classes & OOP (TS) β€” load any with one click.
187
- - **Sandpack Editor**: Full code editor with line numbers, inline TypeScript errors, and a matrix-green custom theme (`JetBrains Mono`).
188
- - **Toolbar**: Run, Copy to clipboard, Download file, and Reset to default β€” all accessible from above the editor.
189
- - **Console Panel**: Live console output displayed side-by-side with the editor. Execution is entirely in-browser β€” no code reaches the server.
190
- - **Features Section**: Highlights Secure Sandbox, Instant Execution, Easy Copy, and JS & TypeScript support.
191
-
192
- ### Components
193
- - `src/components/SandpackEditor.tsx` β€” Sandpack provider, matrix-themed editor, toolbar, and console panel.
194
- - `src/components/CodeSandboxFeaturesSection.tsx` β€” Feature highlights grid displayed below the editor.
195
-
196
- ## πŸ€– Blog Assistant Chatbot
197
- The project includes an interactive AI-powered chatbot optimised for readers of this technical blog (<b>route</b>: `/chat`).
198
-
199
- ### Features
200
- - **Streaming responses**: Powered by the Vercel AI SDK (`TextStreamChatTransport`) and Anthropic's Claude Haiku model via an edge API route (`/api/chat`).
201
- - **Blog-focused tools**: Three tools are available to the model during a conversation:
202
- - `searchBlogTopics` β€” searches a curated list of topics covered by this blog (JS, TS, React, Next.js, MDX, Docker, AWS, etc.)
203
- - `getCodeExample` β€” signals the model to generate a runnable code example for a given concept and language.
204
- - `explainConcept` β€” signals the model to produce a brief or detailed technical explanation.
205
- - **No persistence**: Conversations are ephemeral β€” nothing is stored on a server or in a database. A "New Chat" button clears the session.
206
- - **Matrix-green styling**: Consistent with the Code Sandbox, the chat UI uses the same dark/neon-green palette and `JetBrains Mono` font.
207
- - **Tool result display**: Each tool call and its result is rendered inline in the message thread via the `ChatToolResult` component.
208
-
209
- ### Configuration
210
- - `src/utils/constants/AiChatConfig.ts` β€” Model name (`claude-haiku-4-5-20251001`), temperature, max tokens, and the blog-focused system prompt.
211
- - `src/utils/constants/ToolConfig.ts` β€” Icon, label, and colour mappings for each tool displayed in the UI.
212
-
213
- ### Components
214
- - `src/components/chat/chat-interface.tsx` β€” Top-level client component; owns `useChat` state, "New Chat" handler, and layout.
215
- - `src/components/chat/chat-messages.tsx` β€” Message thread with auto-scroll, empty state, loading indicator, and error display.
216
- - `src/components/chat/chat-input.tsx` β€” Textarea + send button; supports `Enter` to send and `Shift+Enter` for newlines.
217
- - `src/components/chat/chat-tool-result.tsx` β€” Renders tool call and tool result states inline in the message thread.
218
-
219
- ### API Route
220
- `src/app/api/chat/route.ts` β€” Next.js edge route. Accepts the `UIMessages` array, converts it to `CoreMessages` via `convertToModelMessages`, streams a response using `streamText` with the three blog tools, and returns `result.toTextStreamResponse()`.
221
-
222
- ## ✨ AI Article Summarizer
223
- A **Generate TL;DR** button above every dynamic article streams a short Claude Haiku summary into a collapsible green panel. The slug is the only thing sent over the wire β€” `src/app/api/summarize/[slug]/route.ts` (edge) fetches the article server-side, applies an origin allow-list (`NEXT_PUBLIC_SITE_URL`) + per-IP rate limit (10/min) + 1-hour in-memory cache, then calls `streamText` and writes the final text to cache via `after()`. The client (`src/components/ArticleSummarizer.tsx`) uses `AbortController` to cancel in-flight requests on close/unmount. Model and prompt live in `src/utils/constants/AiSummaryConfig.ts`.
224
-
225
- ## πŸ‘₯ Author Profile Pages
226
- A `/authors` index lists every distinct contributor pulled from the Supabase `Article` table, with per-author profile routes at `/authors/[slug]` showing their bio, avatar, and every article they've published.
227
-
228
- ## πŸ“¬ Newsletter Subscription
229
- The project ships with an integrated **newsletter signup form** powered by [Resend](https://resend.com). Visitors can subscribe from the home page or from the bottom of any article; new subscribers are added to a Resend **Audience** and immediately receive a welcome email.
230
-
231
- ### Components & Routes
232
- - `src/components/NewsletterSignup.tsx` β€” reusable client component with `matrix` (article pages, glass-card + green) and `neutral` (home page, white/black/silver shadcn) visual variants.
233
- - `src/app/api/newsletter/subscribe/route.ts` β€” Node-runtime POST handler; validates the email with Zod and forwards it to the Resend SDK.
234
- - `src/utils/functions/newsletter/subscribeToNewsletter.ts` β€” server-side helper that adds the contact to your Resend Audience and triggers the welcome email.
235
- - `src/utils/functions/newsletter/welcomeEmailTemplate.ts` β€” builds the subject + HTML/text bodies for the confirmation email.
236
- - `src/utils/functions/resend_client/ResendClient.ts` β€” server-only Resend client factory.
237
-
238
- ### Setup Steps
239
- 1. Create a Resend account at [resend.com](https://resend.com).
240
- 2. **API Key** β€” go to **API Keys β†’ Create API Key** and grant it access to **Sending** and **Audiences**. Copy the key into `RESEND_API_KEY` in `.env.local`.
241
- 3. **Audience** β€” go to **Audiences β†’ Create Audience**, give it a name, and copy the generated UUID into `RESEND_AUDIENCE_ID` in `.env.local`.
242
- 4. Restart `npm run dev` after editing `.env.local` so Next.js picks up the new variables.
243
-
244
- ### Environment Variables
245
- | Variable | Required for |
246
- |---|---|
247
- | `RESEND_API_KEY` | Authenticating with the Resend API |
248
- | `RESEND_AUDIENCE_ID` | The Resend Audience that new subscribers are added to |
249
-
250
- ### ⚠️ ***Important: A verified sending domain on Resend is required for the email-sending feature to fully work.***
251
- Out of the box the welcome email is sent from **`onboarding@resend.dev`**, which is Resend's sandbox sender. **`onboarding@resend.dev` is only allowed to deliver to the email address that owns your Resend account** β€” sending to any other recipient will be rejected by Resend.
252
-
253
- > 🚨 ***You MUST set up and verify your own sending domain on Resend (Resend dashboard β†’ Domains β†’ Add Domain, then complete the SPF / DKIM DNS records) before the newsletter can deliver welcome emails to real subscribers.*** Once your domain is verified, update the `WELCOME_EMAIL_FROM` constant in `src/utils/functions/newsletter/subscribeToNewsletter.ts` to an address on that domain (for example `newsletter@yourdomain.com`).
254
-
255
- If the domain step is skipped, the contact will still be added to your Resend Audience, but the welcome email will silently fail (the failure is logged to the server console as `[newsletter] Resend emails.send returned an error: ...`).
256
-
257
- ## 🧩 Constants, Functions, & Types
258
- 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.
259
-
260
- While functions and data types are integral to the function of this web application, feel free to check them out.
261
-
262
- ## πŸ—„οΈ Supabase Database Setup
263
- 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`.
264
-
265
- **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.**
266
-
267
- ### Environment Variables & Credentials
268
- A `.env.example` file is provided at the root of the project listing all required environment variable keys with empty placeholders. Copy it to `.env.local` and fill in your values:
269
-
270
- ```bash
271
- cp .env.example .env.local
272
- ```
273
-
274
- | Variable | Required for |
275
- |---|---|
276
- | `SUPABASE_URL` | Dynamic blog post fetching (Supabase client) |
277
- | `SUPABASE_ANON_KEY` | Dynamic blog post fetching (Supabase client) |
278
- | `ANTHROPIC_API_KEY` | Blog Assistant chatbot (`/api/chat` edge route) |
279
- | `GITHUB_TOKEN` | GitHub API authentication for `<GitHubGist>` β€” optional but raises rate limit from 60 to 5,000 req/hr |
280
- | `GITHUB_USERNAME` | Your GitHub username, used to construct the mdxgists.net URL (defaults to `CodingAbdullah`) |
281
- | `GIST_BASE_URL` | Base URL for mdxgists.net links (defaults to `https://mdxgists.net`) |
282
- | `RESEND_API_KEY` | Newsletter signup β€” authenticates with the Resend API (see the **Newsletter Subscription** section below) |
283
- | `RESEND_AUDIENCE_ID` | Newsletter signup β€” the Resend Audience that new subscribers are added to |
284
-
285
- ```
286
- # .env.local
287
- SUPABASE_URL=
288
- SUPABASE_ANON_KEY=
289
- ANTHROPIC_API_KEY=
290
- GITHUB_TOKEN=
291
- GITHUB_USERNAME=
292
- GIST_BASE_URL=
293
- RESEND_API_KEY=
294
- RESEND_AUDIENCE_ID=
295
- ```
296
-
297
- ## 🌩️ AWS
298
- 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.
299
-
300
- Images are used in the `.mdx` files and utilized via the custom `MDXImage` component covered earlier.
301
-
302
- ## 🐳 Docker
303
- This application can be containerized using Docker.
304
-
305
- 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 credentials as well):
306
-
307
- ``
308
- docker build -t mdx-medium-blog .
309
- ``
310
-
311
- ``
312
- docker run -e SUPABASE_URL=your_supabase_url \ -e SUPABASE_ANON_KEY=your_supabase_anon_key \ -e ANTHROPIC_API_KEY=your_anthropic_api_key \ -e GITHUB_TOKEN=your_github_token \ -e GITHUB_USERNAME=your_github_username \ -e GIST_BASE_URL=https://mdxgists.net \ -e RESEND_API_KEY=your_resend_api_key \ -e RESEND_AUDIENCE_ID=your_resend_audience_id \ -p 3000:3000 mdx-medium-blog
313
- ``
314
-
315
- ## πŸ”„ CRUD Operations and Supabase Actions
316
- 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. Supabase RPC functions (such as `incrementViewCount`) are kept separately in `/src/utils/functions/rpc`.
317
-
318
- The `article-manager.ts` file utilizes these CRUD functions to successfully perform the desired actions.
319
-
320
- ## πŸ“œ Scripts for Setting Up Project
321
- The `/scripts` folder contains various scripts to help set up the project and database.
322
-
323
- ### Setup Scripts
324
- - **SQL Scripts**: DDL and DML statements for initializing and populating the database.
325
- - **Powershell Script**: Script for setting up project on Windows.
326
- - **Bash Shell Script**: Script for setting up project on Linux, Mac, etc.
327
-
328
- ### GitHub Gist Fetcher
329
- > **Note:** This script is no longer required for rendering gists in MDX. The `<GitHubGist>` component now fetches content live from the GitHub API at render time. This script is retained for offline inspection or local caching workflows.
330
-
331
- **Location**: `/scripts/github-gist-fetcher/fetch-github-gist.ts`
332
-
333
- **Usage**:
334
- ```bash
335
- npx tsx scripts/github-gist-fetcher/fetch-github-gist.ts <gist-id>
336
- ```
337
-
338
- **Features**:
339
- - Fetches public GitHub Gist content using the GitHub API
340
- - Exports the raw content from the fetch call to `/src/github_gists/<gist-id>.txt`
341
- - Automatically creates the output directory if it does not exist
342
- - Provides clear error handling and status messages
343
-
344
- This project directly integrates Supabase in the front-end using React Server components which removes the need for custom back-end APIs.
345
-
346
- ## πŸ› οΈ Compiling TypeScript and Testing Locally
347
- 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.
348
-
349
- You can use this handy script for testing MDX and article functionality locally.
350
-
351
- The following codeblock highlights the different command prompts that can be used with this file:
352
-
353
- - Insert an Article into Supabase
354
- npx tsx article-manager.ts insert article-slug
355
-
356
- - Delete an Article from Supabase
357
- npx tsx article-manager.ts delete article-slug
358
-
359
- - Update an Article in Supabase
360
- npx tsx article-manager.ts update article-slug new-article-file
361
-
362
- - Fetch a Single Article from Supabase
363
- npx tsx article-manager.ts fetch article-slug
364
-
365
- - Fetch all Articles from Supabase
366
- npx tsx article-manager.ts fetchAll
367
-
368
- The article slug is the name of the markdown file located in the `/src/markdown` directory minus the extension, `.mdx`.
369
-
370
- 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).
371
-
372
- ## πŸ“± Mobile Responsiveness
373
- All components in the starter kit are built mobile-first using Tailwind CSS responsive prefixes (`sm:`, `md:`, `lg:`).
374
-
375
- Key responsive behaviours:
376
-
377
- | Component | Mobile behaviour |
378
- |---|---|
379
- | `ArticleHeader` | Title scales from `text-2xl` β†’ `text-4xl`; author row stacks vertically on small screens |
380
- | `ArticleAuthorBio` | Avatar and text stack vertically; button goes full-width; text is center-aligned on mobile |
381
- | `GitHubGist` | Header wraps via `flex-wrap`; code area scrolls horizontally with a styled green scrollbar |
382
- | `CodeBlock` | Copy button is absolutely positioned and does not interfere with code flow |
383
- | `MDXImage` | Image container scales inline; hover effect applies on capable devices |
384
- | Chat & Code Sandbox | Responsive padding and height calculations across all breakpoints |
385
-
386
- The root layout exports a `viewport` configuration (via Next.js `Viewport` type) ensuring correct scaling on all mobile browsers:
387
-
388
- ```ts
389
- export const viewport: Viewport = {
390
- width: 'device-width',
391
- initialScale: 1,
392
- };
393
- ```
394
-
395
- ## πŸ“Š Analytics
396
- Integrated in this setup project is Vercel Analytics (`@vercel/analytics`) to track user interactions and performance metrics of the blog.
397
-
398
- ## πŸ—ΊοΈ Sitemap & Robots
399
- A `sitemap.xml` is auto-generated at build time via `src/app/sitemap.ts`, covering all static routes and every dynamic article slug fetched from Supabase. A companion `robots.txt` is served from `src/app/robots.ts`, permitting all crawlers and pointing them to the generated sitemap for full search engine discoverability.
400
-
401
- ## βš™οΈ Next.js Configuration
402
- 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.
403
-
404
- ## πŸ”— Useful Links
405
- - [Next.js Documentation](https://nextjs.org/docs)
406
- - [MDX Documentation](https://mdxjs.com/docs/)
407
- - [Lee Robinson's Next.js + MDX Tutorial Video](https://www.youtube.com/watch?v=34bRv6cQezo&ab_channel=leerob)
408
- - [MDX Playground](https://mdxjs.com/playground/)
409
- - [React Documentation](https://reactjs.org/docs/getting-started.html)
410
- - [Supabase Documentation](https://supabase.com/docs)
411
- - [Docker Documentation](https://docs.docker.com/)
412
- - [React Syntax Highlighter Package](https://github.com/react-syntax-highlighter/react-syntax-highlighter)
413
- - [Sandpack Documentation](https://sandpack.codesandbox.io/docs)
414
- - [Vercel AI SDK Documentation](https://sdk.vercel.ai/docs)
415
- - [Anthropic AI SDK Provider](https://sdk.vercel.ai/providers/ai-sdk-providers/anthropic)
416
- - [Zod Documentation](https://zod.dev)
1
+ # 🌟 Next-MDX-Blog-Starter
2
+
3
+ A production-ready technical blog starter kit built with **Next.js (App Router)**, **MDX**, **Supabase**, and **TypeScript strict mode**. SSG-first for performance and SEO, with AI-powered reader features, an in-browser code sandbox, and a full content-management toolchain.
4
+
5
+ **Live demo**: [next-mdx-blog-starter-sigma.vercel.app](https://next-mdx-blog-starter-sigma.vercel.app/)
6
+
7
+ This project was developed with the help of **Claude** (Anthropic) and **Cursor**, with design inspiration from **Lovable**.
8
+
9
+ ## πŸ“‘ Table of Contents
10
+
11
+ - [Quick Start](#%EF%B8%8F-quick-start)
12
+ - [Environment Variables](#-environment-variables)
13
+ - [Architecture & Core Stack](#%EF%B8%8F-architecture--core-stack)
14
+ - [MDX Content System](#-mdx-content-system)
15
+ - [Custom MDX Components](#-custom-mdx-components)
16
+ - [Reader Experience Features](#-reader-experience-features)
17
+ - [AI Features](#-ai-features)
18
+ - [Code Sandbox](#%EF%B8%8F-code-sandbox)
19
+ - [Author Profile Pages](#-author-profile-pages)
20
+ - [Search](#-search)
21
+ - [Newsletter Subscription](#-newsletter-subscription)
22
+ - [Supabase Database](#%EF%B8%8F-supabase-database)
23
+ - [Article Manager CLI](#%EF%B8%8F-article-manager-cli)
24
+ - [Project Scripts](#-project-scripts)
25
+ - [AWS S3 Image Storage](#%EF%B8%8F-aws-s3-image-storage)
26
+ - [SEO: Sitemap & Robots](#%EF%B8%8F-seo-sitemap--robots)
27
+ - [Mobile Responsiveness](#-mobile-responsiveness)
28
+ - [Analytics](#-analytics)
29
+ - [Docker](#-docker)
30
+ - [Useful Links](#-useful-links)
31
+
32
+ ## βš™οΈ Quick Start
33
+
34
+ ### Prerequisites
35
+ - **Node.js** 18.17.0 or later (NPM included)
36
+
37
+ ### Option 1 β€” NPM installer (recommended)
38
+
39
+ Scaffold the blog into an empty directory:
40
+
41
+ ```bash
42
+ npx create-next-mdx-blog-app .
43
+ ```
44
+
45
+ The installer ([`create-next-mdx-blog-app`](https://www.npmjs.com/package/create-next-mdx-blog-app/), v2.2.3, MIT) clones the app, installs dependencies, and prints the environment setup steps.
46
+
47
+ ### Option 2 β€” Manual clone
48
+
49
+ ```bash
50
+ git clone https://github.com/CodingAbdullah/Next-MDX-Blog-Starter.git
51
+ cd Next-MDX-Blog-Starter/mdx-medium-blog-post-provider
52
+ npm install
53
+ ```
54
+
55
+ ### Configure and run
56
+
57
+ ```bash
58
+ cp .env.example .env.local # fill in your credentials (see table below)
59
+ npm run dev
60
+ ```
61
+
62
+ ## πŸ” Environment Variables
63
+
64
+ A `.env.example` file at the project root lists every key. Copy it to `.env.local` and fill in your values:
65
+
66
+ ```bash
67
+ cp .env.example .env.local
68
+ ```
69
+
70
+ ```bash
71
+ # .env.local
72
+
73
+ # Supabase β€” dynamic blog post fetching
74
+ SUPABASE_URL=
75
+ SUPABASE_ANON_KEY=
76
+
77
+ # Anthropic β€” Blog Assistant chatbot + AI Article Summarizer
78
+ ANTHROPIC_API_KEY=
79
+
80
+ # Site β€” public base URL (sitemap, robots.txt, summarizer origin allow-list)
81
+ NEXT_PUBLIC_SITE_URL=
82
+
83
+ # GitHub β€” optional, for the <GitHubGist> component
84
+ GITHUB_TOKEN=
85
+ GITHUB_USERNAME=
86
+ GIST_BASE_URL=
87
+
88
+ # Resend β€” newsletter signup
89
+ RESEND_API_KEY=
90
+ RESEND_AUDIENCE_ID=
91
+ ```
92
+
93
+ ### Required
94
+
95
+ | Variable | Used by |
96
+ |---|---|
97
+ | `SUPABASE_URL` | Dynamic blog post fetching (Supabase client) |
98
+ | `SUPABASE_ANON_KEY` | Dynamic blog post fetching (Supabase client) |
99
+ | `ANTHROPIC_API_KEY` | Blog Assistant chatbot (`/api/chat`) and AI Article Summarizer (`/api/summarize/[slug]`) |
100
+ | `RESEND_API_KEY` | Newsletter signup β€” authenticates with the Resend API |
101
+ | `RESEND_AUDIENCE_ID` | Newsletter signup β€” the Resend Audience new subscribers are added to |
102
+
103
+ ### Optional (sensible defaults)
104
+
105
+ | Variable | Used by | Default |
106
+ |---|---|---|
107
+ | `NEXT_PUBLIC_SITE_URL` | Sitemap, robots.txt, summarizer origin allow-list | `http://localhost:3000` |
108
+ | `GITHUB_TOKEN` | `<GitHubGist>` GitHub API auth β€” raises rate limit from 60 to 5,000 req/hr | unauthenticated |
109
+ | `GITHUB_USERNAME` | mdxgists.net URL construction | `CodingAbdullah` |
110
+ | `GIST_BASE_URL` | mdxgists.net link base URL | `https://mdxgists.net` |
111
+
112
+ > πŸ”’ **Never commit `.env` files.** They are git-ignored and excluded from Docker images via `.dockerignore`. Server-only secrets (Supabase keys, Anthropic and Resend API keys, GitHub token) are read exclusively in Server Components and Route Handlers β€” only `NEXT_PUBLIC_SITE_URL` is exposed to the browser.
113
+
114
+ ## πŸ—οΈ Architecture & Core Stack
115
+
116
+ This starter kit is **SSG-first**: Static Site Generation is preferred everywhere, with dynamic rendering used only where required.
117
+
118
+ - **Pre-rendered pages**: Blog posts and content pages are statically generated at build time
119
+ - **Server Components first**: Supabase is queried directly from React Server Components β€” no custom backend APIs
120
+ - **SEO-ready**: Meta tags, structured data, and semantic HTML generated statically
121
+ - **CDN-friendly**: Static output deploys to any CDN or static host
122
+ - **Minimal client JS**: Core content rendering requires no client-side JavaScript
123
+
124
+ | Layer | Technology |
125
+ |---|---|
126
+ | Framework | Next.js (App Router), React, TypeScript (strict mode) |
127
+ | Content | MDX, `gray-matter`, `next-mdx-remote` |
128
+ | Database | Supabase (`@supabase/supabase-js`) |
129
+ | Image storage | AWS S3 (via Next `<Image>`) |
130
+ | Styling / UI | Tailwind CSS, shadcn/ui, `lucide-react`, `class-variance-authority` |
131
+ | AI | Vercel AI SDK (`ai`, `@ai-sdk/anthropic`, `@ai-sdk/react`), `zod` |
132
+ | Code sandbox | `@codesandbox/sandpack-react` |
133
+ | Syntax highlighting | `react-syntax-highlighter` |
134
+ | Email | Resend (`resend`) |
135
+ | Notifications | `sonner` toasts |
136
+ | Theming | `next-themes` |
137
+ | Tooling | Docker, Vercel Analytics, `tsx`, `react-doctor` (`npm run doctor`) |
138
+
139
+ ## 🌐 MDX Content System
140
+
141
+ This project renders blog posts from `.mdx` files in two modes, each with an included example:
142
+
143
+ - **Static MDX** β€” pre-rendered at build time. Route: `/sample-blog-post-page`, content: `src/markdown/ArticleContent.mdx`
144
+ - **Dynamic MDX** β€” rendered on the server at request time via `next-mdx-remote`'s `MDXRemote` component. Route: `/dynamic/[dynamic_blog_post]`, content: `src/markdown/DynamicArticleContent.mdx`
145
+
146
+ ### Frontmatter (article metadata)
147
+
148
+ Each `.mdx` file carries metadata at the top of the file between `---` delimiters, parsed with `gray-matter`:
149
+
150
+ ```yaml
151
+ ---
152
+ title: string
153
+ description: string
154
+ publishedAt: string
155
+ author: string
156
+ tags: string[]
157
+ image: string
158
+ ---
159
+ ```
160
+
161
+ ### The `mdx-components.tsx` file
162
+
163
+ `mdx-components.tsx` at the project root styles built-in HTML elements and swaps `<img>` and `<a>` for the optimized Next.js `<Image>` and `<Link>` components. See the [Next.js docs](https://nextjs.org/docs/app/api-reference/file-conventions/mdx-components) for how this file convention works.
164
+
165
+ ## 🧩 Custom MDX Components
166
+
167
+ Custom components for MDX content live in `src/components/customMDXComponents/`.
168
+
169
+ ### CodeBlock β€” syntax highlighting
170
+
171
+ Highlights code blocks with `react-syntax-highlighter` (default theme: `vscDarkPlus` β€” [demo of available themes](https://react-syntax-highlighter.github.io/react-syntax-highlighter/demo/)). A **copy button** in the top-right corner writes the code to the clipboard and confirms via a sonner toast.
172
+
173
+ ### GitHubGist β€” live gist embeds
174
+
175
+ Embed public GitHub Gists directly in MDX:
176
+
177
+ ```mdx
178
+ <GitHubGist id="your-gist-id" figCaptionText="Caption shown below the gist" />
179
+ ```
180
+
181
+ **How it works:**
182
+ 1. `GitHubGist` (an async Server Component) calls `https://api.github.com/gists/<id>` for metadata (file name, detected language), then fetches the raw content from the returned `raw_url`. Results are cached for one hour via Next.js ISR (`next: { revalidate: 3600 }`).
183
+ 2. The language is mapped to a Prism-compatible token via `GITHUB_GIST_LANGUAGE_MAP` (`src/utils/constants/GitHubGistConstants.ts`) β€” 70+ languages supported, with sensible fallbacks (`language.toLowerCase()`, then `text`).
184
+ 3. The code renders through `GistCodeBlock` inside a scrollable container with a custom green scrollbar.
185
+
186
+ **Each gist header includes:** a language badge, a **Copy** button (with toast confirmation), and a link to the gist on [mdxgists.net](https://mdxgists.net) β€” a companion site for browsing and sharing MDX-ready gists. The URL is built as `<GIST_BASE_URL>/<GITHUB_USERNAME>/<gist-id>`; both values are overridable via environment variables.
187
+
188
+ **Components:**
189
+ - `GitHubGist.tsx` β€” async Server Component; fetching, language resolution, gist UI
190
+ - `GistCodeBlock.tsx` β€” syntax-highlighted code display
191
+ - `GistCopyButton.tsx` β€” client component; copy-to-clipboard + external link
192
+
193
+ **GitHub token (optional but recommended):** unauthenticated GitHub API requests are limited to **60/hr per IP**. Set `GITHUB_TOKEN` in `.env.local` to raise this to **5,000/hr**. Generate one at GitHub β†’ Settings β†’ Developer settings β†’ Personal access tokens β€” the read-only `gist` scope (or no scopes for public gists) is sufficient.
194
+
195
+ > Only **public** gists are supported by default; the component can be extended for private gists with appropriate token scopes.
196
+
197
+ ### MDXImage β€” optimized images with captions
198
+
199
+ Wraps the Next.js `<Image>` component with `<figure>`/`<figcaption>` for seamless captions, displayed in a styled container with a green glow border and hover scale effect consistent with the matrix-green design system.
200
+
201
+ ## 🎨 Reader Experience Features
202
+
203
+ | Feature | Component | Behaviour |
204
+ |---|---|---|
205
+ | **Light/dark mode** | `src/components/ThemeToggle.tsx` | Header toggle between dark (default) and light themes via `next-themes` (`ThemeProvider.tsx`); persisted to `localStorage`. `ThemedToaster.tsx` keeps sonner toasts theme-matched |
206
+ | **Reading progress bar** | `src/components/ReadingProgressBar.tsx` | Thin green bar fixed to the top of article pages; passive scroll listener, `role="progressbar"` ARIA attributes |
207
+ | **Back to top** | `src/components/BackToTopButton.tsx` | Floating button appears after 400px of scroll; smooth-scrolls to top |
208
+ | **Copy link** | `src/components/CopyLinkButton.tsx` | Article-header button; copies the page URL with a brief icon-swap confirmation |
209
+ | **Social share** | `src/components/SocialShareButtons.tsx` | Pre-filled share dialogs for X (Twitter), LinkedIn, and Reddit using the article title and URL |
210
+ | **View counter** | `src/components/ViewCounter.tsx` | Live per-article view count in a Supabase `view_counts` table, incremented atomically via the `increment_view_count` RPC. Dynamic pages increment server-side; static pages call the `/api/views/[slug]` route after hydration |
211
+
212
+ ## πŸ€– AI Features
213
+
214
+ Both AI features use **Claude Haiku** through the Vercel AI SDK and require `ANTHROPIC_API_KEY`.
215
+
216
+ ### Blog Assistant Chatbot (`/chat`)
217
+
218
+ An interactive AI chatbot optimised for readers of this technical blog.
219
+
220
+ - **Streaming responses** via `TextStreamChatTransport` and an edge API route (`src/app/api/chat/route.ts`), which converts `UIMessages` with `convertToModelMessages` and streams via `streamText`
221
+ - **Three blog-focused tools** available to the model:
222
+ - `searchBlogTopics` β€” searches a curated list of topics covered by this blog (JS, TS, React, Next.js, MDX, Docker, AWS, etc.)
223
+ - `getCodeExample` β€” generates a runnable code example for a concept and language
224
+ - `explainConcept` β€” produces a brief or detailed technical explanation
225
+ - **Ephemeral conversations** β€” nothing is persisted server-side; a "New Chat" button clears the session
226
+ - **Tool calls rendered inline** in the message thread via `chat-tool-result.tsx`
227
+
228
+ Configuration lives in `src/utils/constants/AiChatConfig.ts` (model, temperature, max tokens, system prompt) and `ToolConfig.ts` (tool icons/labels/colours). UI components are under `src/components/chat/` (`chat-interface.tsx`, `chat-messages.tsx`, `chat-input.tsx`, `chat-tool-result.tsx`).
229
+
230
+ ### AI Article Summarizer
231
+
232
+ A **Generate TL;DR** button above every dynamic article streams a short summary into a collapsible green panel.
233
+
234
+ - Only the article **slug** is sent over the wire β€” `src/app/api/summarize/[slug]/route.ts` (edge) fetches the article server-side
235
+ - Protected by an **origin allow-list** (`NEXT_PUBLIC_SITE_URL`), a **per-IP rate limit** (10/min), and a **1-hour in-memory cache** (written via `after()`)
236
+ - The client (`src/components/ArticleSummarizer.tsx`) cancels in-flight requests with `AbortController` on close/unmount
237
+ - Model and prompt configured in `src/utils/constants/AiSummaryConfig.ts`
238
+
239
+ ## πŸ–₯️ Code Sandbox
240
+
241
+ An interactive in-browser code execution environment powered by **Sandpack** at `/code-sandbox`.
242
+
243
+ - **JavaScript & TypeScript runtimes** β€” switch with one click; the editor reloads with a language-appropriate default snippet
244
+ - **Quick Examples** β€” pre-loaded snippets (Fibonacci, Async/Await, Data Structures for JS; Types & Interfaces, Generics, Classes & OOP for TS) defined in `src/utils/constants/SandboxExamples.ts`
245
+ - **Full editor** β€” line numbers, inline TypeScript errors, matrix-green custom theme with `JetBrains Mono`
246
+ - **Toolbar** β€” Run, Copy, Download, and Reset
247
+ - **Live console panel** side-by-side with the editor β€” execution is **entirely in-browser**; no code reaches the server
248
+
249
+ Components: `src/components/SandpackEditor.tsx` (provider, editor, toolbar, console) and `CodeSandboxFeaturesSection.tsx` (feature highlights grid).
250
+
251
+ ## πŸ‘₯ Author Profile Pages
252
+
253
+ A `/authors` index lists every distinct contributor pulled from the Supabase `Article` table, with per-author profile routes at `/authors/[slug]` showing their bio, avatar, and every article they've published.
254
+
255
+ ## πŸ” Search
256
+
257
+ Full-text search across published articles at `/search`, powered by native Postgres `tsvector` β€” no external search service required.
258
+
259
+ - **Search-as-you-type** β€” `src/components/ArticleSearch.tsx` debounces input (300 ms), cancels stale requests with `AbortController`, caches repeated queries, and waits for at least 2 characters before querying
260
+ - **Prefix matching** β€” partial words match while you type (`reac` β†’ `react`)
261
+ - **Ranked, weighted results** β€” scored by `ts_rank` with column weights (title > tags > description > content) and returned as lightweight summaries (the heavy `content` column is excluded)
262
+ - **Request flow** β€” `GET /api/search?q=…` (`src/app/api/search/route.ts`) β†’ `searchArticles()` (`src/utils/functions/rpc/searchArticles.ts`) β†’ the `search_articles` Postgres RPC
263
+
264
+ ### One-time setup
265
+
266
+ Run **`scripts/sql/DDL/createSearchArticlesFunction.sql`** once in the Supabase SQL editor. It creates the weighted GIN index and the `search_articles` function. Search returns an error until this script is deployed.
267
+
268
+ ### ⚠️ Change the hardcoded author filter
269
+
270
+ The shipped function locks results to a single author:
271
+
272
+ ```sql
273
+ AND a."articleAuthorName" = 'Abdullah Muhammad.'
274
+ ```
275
+
276
+ Before deploying, replace `'Abdullah Muhammad.'` with **your own author name** β€” it must match the `articleAuthorName` values in your `Article` table **exactly**, including any trailing punctuation. Alternatively, **delete that line entirely** to search across all authors. Re-run the script after editing.
277
+
278
+ ## πŸ“¬ Newsletter Subscription
279
+
280
+ An integrated newsletter signup form powered by [Resend](https://resend.com). Visitors can subscribe from the home page or the bottom of any article; new subscribers are added to a Resend **Audience** and receive a welcome email.
281
+
282
+ ### Components & routes
283
+ - `src/components/NewsletterSignup.tsx` β€” reusable client component with `matrix` (article pages) and `neutral` (home page) visual variants
284
+ - `src/app/api/newsletter/subscribe/route.ts` β€” Node-runtime POST handler; validates the email with Zod
285
+ - `src/utils/functions/newsletter/subscribeToNewsletter.ts` β€” adds the contact to your Audience and triggers the welcome email
286
+ - `src/utils/functions/newsletter/welcomeEmailTemplate.ts` β€” subject + HTML/text bodies
287
+ - `src/utils/functions/resend_client/ResendClient.ts` β€” server-only Resend client factory
288
+
289
+ ### Setup
290
+ 1. Create a Resend account at [resend.com](https://resend.com)
291
+ 2. **API key** β€” API Keys β†’ Create API Key with **Sending** and **Audiences** access β†’ set `RESEND_API_KEY`
292
+ 3. **Audience** β€” Audiences β†’ Create Audience β†’ copy the UUID into `RESEND_AUDIENCE_ID`
293
+ 4. Restart `npm run dev` so Next.js picks up the new variables
294
+
295
+ ### ⚠️ ***Important: a verified sending domain on Resend is required for email delivery to real subscribers.***
296
+
297
+ Out of the box the welcome email is sent from **`onboarding@resend.dev`**, Resend's sandbox sender, which **only delivers to the email address that owns your Resend account**.
298
+
299
+ > 🚨 ***You MUST verify your own sending domain (Resend dashboard β†’ Domains β†’ Add Domain, then complete the SPF/DKIM DNS records) before the newsletter can deliver welcome emails to real subscribers.*** Once verified, update the `WELCOME_EMAIL_FROM` constant in `src/utils/functions/newsletter/subscribeToNewsletter.ts` to an address on that domain (e.g. `newsletter@yourdomain.com`).
300
+
301
+ If the domain step is skipped, the contact is still added to your Audience, but the welcome email silently fails (logged server-side as `[newsletter] Resend emails.send returned an error: ...`).
302
+
303
+ ## πŸ—„οΈ Supabase Database
304
+
305
+ Supabase is integrated **directly in Server Components** β€” no custom backend API layer. The client factory lives in `src/utils/functions/supabase_client/`.
306
+
307
+ - **CRUD functions** β€” `src/utils/functions/crud/` (create, read, update, delete articles)
308
+ - **RPC functions** β€” `src/utils/functions/rpc/` (e.g. `incrementViewCount`)
309
+ - **SQL scripts** β€” `scripts/sql/DDL/` (create/alter/drop tables, view-counts table, RPC function) and `scripts/sql/DML/` (insert/fetch/update/delete article statements)
310
+
311
+ **Ensure your Supabase Row Level Security policies allow the CRUD actions you need** β€” these are configured in the Supabase console.
312
+
313
+ Shared constants, helper functions, and TypeScript types live under `src/utils/` (`constants/`, `functions/`, `types/`). Some constants serve as placeholders for this demo application.
314
+
315
+ ## ⌨️ Article Manager CLI
316
+
317
+ `scripts/action-script/article-manager.ts` manages articles in Supabase from the command line using the CRUD functions above, run via `tsx` (no TypeScript build config needed):
318
+
319
+ ```bash
320
+ # Insert an article into Supabase
321
+ npx tsx article-manager.ts insert article-slug
322
+
323
+ # Delete an article
324
+ npx tsx article-manager.ts delete article-slug
325
+
326
+ # Update an article
327
+ npx tsx article-manager.ts update article-slug new-article-file
328
+
329
+ # Fetch a single article
330
+ npx tsx article-manager.ts fetch article-slug
331
+
332
+ # Fetch all articles
333
+ npx tsx article-manager.ts fetchAll
334
+ ```
335
+
336
+ The **article slug** is the name of the markdown file in `src/markdown/` minus the `.mdx` extension. The `update` command's second argument follows the same convention.
337
+
338
+ ## πŸ“œ Project Scripts
339
+
340
+ The `/scripts` folder contains tooling for project and database setup:
341
+
342
+ - **`scripts/sql/`** β€” DDL and DML statements for initializing and populating the database
343
+ - **`scripts/powershell/`** β€” Windows setup plus bulk article/S3 helpers (`project_setup.ps1`, `bulk-create-articles.ps1`, `bulk-update-articles.ps1`, `bulk-s3-folder-creation.ps1`, `create-missing-mdx-files.ps1`)
344
+ - **`scripts/bash/`** β€” the same toolkit for Linux/macOS
345
+ - **`scripts/action-script/`** β€” the Article Manager CLI (above)
346
+ - **`scripts/github-gist-fetcher/`** β€” fetches a public gist's raw content to `src/github_gists/<gist-id>.txt`:
347
+ ```bash
348
+ npx tsx scripts/github-gist-fetcher/fetch-github-gist.ts <gist-id>
349
+ ```
350
+ > **Note:** no longer required for rendering β€” `<GitHubGist>` fetches live from the GitHub API. Retained for offline inspection or local caching workflows.
351
+
352
+ ## 🌩️ AWS S3 Image Storage
353
+
354
+ Images referenced in `.mdx` files (via the `MDXImage` component) are served from AWS S3. The allowed external image domain is configured in `next.config.ts` β€” point it at your own bucket, or swap in another storage service entirely.
355
+
356
+ ## πŸ—ΊοΈ SEO: Sitemap & Robots
357
+
358
+ - **`sitemap.xml`** β€” auto-generated at build time by `src/app/sitemap.ts`, covering all static routes and every dynamic article slug fetched from Supabase
359
+ - **`robots.txt`** β€” served from `src/app/robots.ts`, permitting all crawlers and pointing them at the sitemap
360
+
361
+ Both use `NEXT_PUBLIC_SITE_URL` as the base URL.
362
+
363
+ ## πŸ“± Mobile Responsiveness
364
+
365
+ All components are built mobile-first with Tailwind responsive prefixes (`sm:`, `md:`, `lg:`). Key behaviours:
366
+
367
+ | Component | Mobile behaviour |
368
+ |---|---|
369
+ | `ArticleHeader` | Title scales `text-2xl` β†’ `text-4xl`; author row stacks vertically |
370
+ | `ArticleAuthorBio` | Avatar and text stack vertically; full-width button; center-aligned text |
371
+ | `GitHubGist` | Header wraps via `flex-wrap`; code scrolls horizontally with a styled green scrollbar |
372
+ | `CodeBlock` | Copy button absolutely positioned, never interferes with code flow |
373
+ | `MDXImage` | Container scales inline; hover effect on capable devices |
374
+ | Chat & Code Sandbox | Responsive padding and height calculations across breakpoints |
375
+
376
+ The root layout exports a `viewport` configuration (Next.js `Viewport` type) for correct scaling on all mobile browsers:
377
+
378
+ ```ts
379
+ export const viewport: Viewport = {
380
+ width: 'device-width',
381
+ initialScale: 1,
382
+ };
383
+ ```
384
+
385
+ ## πŸ“Š Analytics
386
+
387
+ Vercel Analytics (`@vercel/analytics`) is integrated to track user interactions and performance metrics β€” kept lightweight and non-blocking.
388
+
389
+ ## 🐳 Docker
390
+
391
+ A multi-stage `Dockerfile` at the project root produces a production image with environment variables injected at runtime:
392
+
393
+ ```bash
394
+ docker build -t mdx-medium-blog .
395
+ ```
396
+
397
+ ```bash
398
+ docker run \
399
+ -e SUPABASE_URL=your_supabase_url \
400
+ -e SUPABASE_ANON_KEY=your_supabase_anon_key \
401
+ -e ANTHROPIC_API_KEY=your_anthropic_api_key \
402
+ -e NEXT_PUBLIC_SITE_URL=https://yourdomain.com \
403
+ -e GITHUB_TOKEN=your_github_token \
404
+ -e GITHUB_USERNAME=your_github_username \
405
+ -e GIST_BASE_URL=https://mdxgists.net \
406
+ -e RESEND_API_KEY=your_resend_api_key \
407
+ -e RESEND_AUDIENCE_ID=your_resend_audience_id \
408
+ -p 3000:3000 mdx-medium-blog
409
+ ```
410
+
411
+ The project also remains compatible with **Vercel** and pure **static hosting** (SSG mode).
412
+
413
+ ## πŸ”— Useful Links
414
+
415
+ - [Next.js Documentation](https://nextjs.org/docs)
416
+ - [MDX Documentation](https://mdxjs.com/docs/)
417
+ - [Lee Robinson's Next.js + MDX Tutorial Video](https://www.youtube.com/watch?v=34bRv6cQezo&ab_channel=leerob)
418
+ - [MDX Playground](https://mdxjs.com/playground/)
419
+ - [React Documentation](https://react.dev/)
420
+ - [Supabase Documentation](https://supabase.com/docs)
421
+ - [Docker Documentation](https://docs.docker.com/)
422
+ - [React Syntax Highlighter](https://github.com/react-syntax-highlighter/react-syntax-highlighter)
423
+ - [Sandpack Documentation](https://sandpack.codesandbox.io/docs)
424
+ - [Vercel AI SDK Documentation](https://sdk.vercel.ai/docs)
425
+ - [Anthropic AI SDK Provider](https://sdk.vercel.ai/providers/ai-sdk-providers/anthropic)
426
+ - [Resend Documentation](https://resend.com/docs)
427
+ - [Zod Documentation](https://zod.dev)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-next-mdx-blog-app",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "description": "A production-ready technical blog starter kit built with Next.js, MDX, Supabase, and TypeScript.",
5
5
  "author": {
6
6
  "name": "Abdullah Muhammad",