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.