A production-ready, full-stack blogging platform built with React + Appwrite.
Write beautifully. Publish instantly. Read with intention.
Click the screenshot to open the live app ↑
Blogify is a single-page application that handles the complete lifecycle of a blog post — from account creation and rich-text authoring, through image upload and storage, to public reading — with zero custom backend code. Appwrite Cloud handles all server-side concerns: authentication, database, and file storage.
The front end is built around a handcrafted editorial design system — Fraunces variable serif for display text, Inter for UI chrome, and a warm paper palette that makes long-form content genuinely pleasant to read.
| Layer | Technology | Why |
|---|---|---|
| UI | React 18 + Vite | Component model + instant HMR in dev, optimised bundles in prod |
| Styling | Tailwind CSS | Custom design tokens (paper, ink, terracotta) wired directly into utilities |
| BaaS | Appwrite Cloud | Auth + Database + Storage — no Express, no Prisma, no deployment config |
| State | Redux Toolkit | Predictable global auth state with zero boilerplate |
| Forms | React Hook Form | Uncontrolled inputs, schema validation, isSubmitting guard out of the box |
| Editor | TinyMCE | Battle-tested WYSIWYG; content_style mirrors the reading-page prose styles |
| Routing | React Router v6 | Nested layouts, protected route guards, v7 future flags enabled |
Core
- Full post CRUD — create, edit, publish (
active), draft (inactive), delete - Author-only edit and delete controls rendered inline on the reading page
- Auto-generated URL slug from title with manual override
- Featured image upload, stored in Appwrite Storage, served via
getFileView()
Auth
- Email + password signup and login
- Session persistence — Redux state rehydrated from Appwrite on every mount
- Protected routes redirect unauthenticated users; auth pages redirect logged-in users
UX Details
- Shimmer skeleton loaders on every async page — no blank flash, no layout shift
- Live word count and estimated read time, calculated in the editor and shown on the post page
- One-click copy-link-to-clipboard on every post
isSubmittingdisabled state on all form buttons — no double-submits- Keyboard focus rings on every interactive element (WCAG AA)
prefers-reduced-motionrespected via a global CSS override
Blogify/
├── src/
│ ├── appwrite/ # AuthService (auth) + Service (database, storage)
│ ├── components/ # All UI components + AuthLayout route guard
│ ├── conf/ # conf.js — wraps import.meta.env for type safety
│ ├── pages/ # One component per route
│ ├── store/ # Redux store + authSlice
│ ├── App.jsx # Root layout — Appwrite session check on mount
│ ├── main.jsx # Entry point — createBrowserRouter + Provider
│ └── index.css # Tailwind directives + editorial base + .browser-css prose
│
├── index.html # HTML shell — Google Fonts (Fraunces + Inter) preloaded
├── .env # Local environment secrets — never committed
├── .env.example # Safe template committed for collaborators
├── tailwind.config.js # Extended: editorial color palette + font families
└── README.md
Prerequisites: Node.js ≥ 18 · Appwrite Cloud account · TinyMCE API key (free)
# Clone and install
git clone https://github.com/yasirrajput4/Blogify.git
cd Blogify
npm install
# Configure secrets
cp .env.example .env
# → fill in your Appwrite + TinyMCE values
# Run
npm run dev
# → http://localhost:5173VITE_APPWRITE_URL="https://cloud.appwrite.io/v1"
VITE_APPWRITE_PROJECT_ID="your_project_id"
VITE_APPWRITE_DATABASE_ID="your_database_id"
VITE_APPWRITE_COLLECTION_ID="your_collection_id"
VITE_APPWRITE_BUCKET_ID="your_bucket_id"
VITE_TINYMCE_API_KEY="your_tinymce_api_key"Variables are consumed in
src/conf/conf.jsand injected at build time viaimport.meta.env..envis already in.gitignore.
Database collection attributes
| Attribute | Type | Required |
|---|---|---|
title |
String (255) | ✅ |
content |
String (unlimited) | ✅ |
featuredImage |
String (255) | ✅ |
status |
String (20) | ✅ |
userId |
String (255) | ✅ |
Collection permissions — Any → Read · Users → Create, Read, Update, Delete
Bucket permissions — Users → Create, Read, Update, Delete
getFileView()is used instead ofgetFilePreview()— public bucket read is not required.
Web platforms — register http://localhost:5173 and your production domain under Project → Platforms → Web to prevent CORS errors.
| Path | Page | Auth |
|---|---|---|
/ |
Home — latest published posts | Public |
/login |
Login | Redirects home if authenticated |
/signup |
Signup | Redirects home if authenticated |
/all-posts |
All posts grid | Protected |
/add-post |
Post editor — create | Protected |
/edit-post/:slug |
Post editor — edit | Protected |
/post/:slug |
Post reading page | Public |
npm run dev # Dev server → http://localhost:5173
npm run build # Production build → dist/
npm run preview # Serve production build locally
npm run lint # ESLintIssues and pull requests are welcome.
git checkout -b feat/your-feature
git commit -m "feat: describe your change"
git push origin feat/your-feature
# open a Pull RequestFollow Conventional Commits.
MIT — see LICENSE.