A modern blog platform built with Next.js and Tina CMS, featuring a beautiful UI powered by Tailwind CSS.
This blog platform combines the power of Next.js for frontend rendering, Tina CMS for content management, and Tailwind CSS for styling. It allows you to write, manage, and publish blog posts with a beautiful and responsive interface.
- Next.js 14: React framework for production
- Tina CMS: Headless CMS for content management
- Tailwind CSS: Utility-first CSS framework
- MDX: For enhanced markdown content
tina/
├── content/ # Content managed by Tina CMS
│ ├── posts/ # Blog posts
│ └── pages/ # Static pages (About, etc.)
├── public/ # Static assets
│ └── uploads/ # Media uploads
├── src/
│ └── app/ # Next.js app directory
│ ├── posts/ # Blog post pages
│ ├── about/ # About page
│ └── page.js # Homepage
├── tina/
│ ├── config.js # Tina CMS configuration
│ └── __generated__/ # Generated Tina types
└── package.json # Project dependencies
Tina CMS manages content through a Git-based workflow:
- Content is stored as Markdown/MDX files in the
content/
directory - Media files are stored in
public/uploads/
- Changes are committed directly to your Git repository
The tina/config.js
file defines how content is structured:
// Blog Post Schema
{
name: "post",
label: "Blog Posts",
path: "content/posts",
fields: [
{
type: "string",
name: "title",
label: "Title",
isTitle: true,
required: true,
},
{
type: "string",
name: "description",
label: "Description",
required: true,
},
{
type: "datetime",
name: "date",
label: "Date",
required: true,
},
// ... other fields
]
}
Blog posts are integrated into Next.js pages through Tina's client:
// src/app/posts/page.js
import { client } from '../../../tina/__generated__/client';
async function getBlogPosts() {
const postsResponse = await client.queries.postConnection();
return postsResponse.data.postConnection.edges;
}
export default async function BlogPage() {
const posts = await getBlogPosts();
// Render posts...
}
Individual blog posts use dynamic routing:
// src/app/posts/[slug]/page.js
async function getPost(slug) {
const postResponse = await client.queries.post({
relativePath: `${slug}.md`,
});
return postResponse.data.post;
}
-
Install Dependencies:
npm install
-
Environment Variables: Create a
.env
file:NEXT_PUBLIC_TINA_CLIENT_ID=<your-client-id> TINA_TOKEN=<your-token>
-
Start Development Server:
npm run dev
- Next.js runs on: http://localhost:3000
- Tina CMS admin: http://localhost:3000/admin
-
Write a Blog Post:
- Navigate to http://localhost:3000/admin
- Click "New Post"
- Fill in the required fields:
- Title
- Description
- Date
- Content (supports Markdown)
- Save and publish
-
Add Media:
- Use the media picker in the admin interface
- Images are automatically optimized and stored in
public/uploads/
The project uses Tailwind CSS for styling:
- Global styles:
src/app/globals.css
- Tailwind config:
tailwind.config.js
- Typography plugin for blog content
- Responsive design for all screen sizes
Tina CMS provides authentication through:
- Local development: No authentication required
- Production: GitHub-based authentication
- Custom auth providers can be configured
-
Blog Features:
- Responsive layout
- SEO optimization
- Social sharing
- Categories and tags
- Author information
-
CMS Features:
- Visual editing
- Media management
- Content validation
- Git-based storage
- Real-time preview
-
Developer Features:
- Hot reloading
- TypeScript support
- API routes
- Static generation
- Dynamic imports
-
Build the Project:
npm run build
-
Deploy to Hosting:
- Supports Vercel, Netlify, etc.
- Configure environment variables
- Set up Git integration
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
This project is MIT licensed.