A modern, responsive social network for sharing posts.
Built with Next.js 16, React 19, Tailwind CSS v4, Firebase Auth, and Cloud Firestore,
focused on performance, real-time social interactions, fluid typography, accessibility, and clean code.
CodeLeap Network is a Twitter/Instagram-style social feed where users can create, edit, and delete posts, like, repost, comment with @mentions, attach images, and filter/sort the feed — all with infinite scroll, Firebase authentication, and real-time social interactions powered by Cloud Firestore .
✅ Fully Responsive with fluid typography (font-size: clamp())
✅ Firebase Authentication (Google + Email/Password + Anonymous fallback)
✅ Cloud Firestore for real-time social data shared across all users
✅ Full CRUD for posts via REST API
✅ Infinite Scroll with IntersectionObserver + TanStack Query
✅ Permanent Likes (no unlike, Instagram-style) — synced via Firestore
✅ Reposts with toggle on/off and counter — synced via Firestore
✅ Automatic Views via IntersectionObserver (once per session) — synced via Firestore
✅ Comments with @mention autocomplete dropdown
✅ Real-time Notifications 🔔 (comments, likes, reposts, @mentions)
✅ Smooth Animations with Framer Motion
✅ Clean Code with ESLint, Prettier, and strict TypeScript
Coming soon: production deployment link
Technology
Version
Description
Next.js
16.1.6
React framework with App Router
React
19.2.3
UI library with hooks
TypeScript
5
Static typing
Tailwind CSS
v4
Utility-first styling with @theme
Technology
Version
Description
TanStack React Query
5.90+
Cache, mutations, and infinite scroll
Firebase
12.10+
Auth (Google + Email + Anonymous) + Cloud Firestore
react-hook-form
7.71+
Form management
zod
4.3+
Schema validation
Technology
Version
Description
Framer Motion
12.35+
Enter/exit animations
lucide-react
0.577+
SVG icons
sonner
2.0+
Toast notifications
date-fns
4.1+
Relative date formatting
Tool
Description
ESLint
TypeScript/JSX linter
Prettier
Automatic code formatter
TypeScript strict
Strict type checking
Login/Register with Firebase Auth (Email + Google)
Anonymous Authentication for simple login users (provides stable Firebase UID)
Password strength indicators on registration
Automatic user registration in Firestore users collection on login
Session persistence via localStorage
Create with title, content, and optional image ([img:URL])
Inline editing via modal
Deletion with confirmation modal
Validation with react-hook-form + zod
3. ❤️ Social Interactions (Cloud Firestore — Real-time)
All social data is stored in Cloud Firestore and synced in real-time across all users via onSnapshot listeners.
Permanent Like — no unlike option (Instagram-style), shared across all users
Repost — toggle on/off with counter, shared across all users
Views — automatic counting via IntersectionObserver (deduplicated per user)
Comments — with @mention autocomplete dropdown (MentionInput component)
@Mentions highlighted in blue with clickable autocomplete
Previously stored in localStorage (per-browser only). Migrated to Firestore so all interactions are visible to every user.
4. 🔔 Real-time Notifications
Bell icon 🔔 in the header with unread count badge
Notification types : like, comment, repost, @mention
Post author receives notifications when someone likes, comments, or reposts
Mentioned users receive notifications when tagged with @username in comments
Mark individual or all notifications as read
Real-time updates via Firestore onSnapshot
Fluid typography with clamp() (320px → 1200px)
Adaptive layout across all screen sizes
Responsive cards, modals, and forms
Pagination via useInfiniteQuery (TanStack Query)
Sentinel element with IntersectionObserver
Filter by username and sort order (newest/oldest)
Card entrance with fade + slide (Framer Motion)
Heart pulse on like
Smooth modal transitions (scale + opacity)
AnimatePresence for animated exit
The project follows the Next.js App Router architecture with client-side components and clear separation of concerns.
┌─────────────────────────────────────────────────────────────────┐
│ NEXT.JS APP ROUTER ARCHITECTURE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ │
│ │ layout.tsx │ ◀── Root layout (Providers, fonts, metadata) │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Providers │ │
│ │ ┌─────────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ QueryClient │ │ AuthProv │ │ Toaster │ │ │
│ │ └─────────────┘ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ page.tsx │ │
│ │ ┌──────────┐ ┌────────────┐ ┌────────────┐ │ │
│ │ │AppHeader │ │CreatePost │ │ PostList │ │ │
│ │ └──────────┘ │ Form │ │ (∞ scroll) │ │ │
│ │ └────────────┘ └─────┬──────┘ │ │
│ └────────────────────────────────────┼─────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ PostCard │ │
│ │ ┌─────────────┐│ │
│ │ │Like│Repost ││ │
│ │ │Comment│View ││ │
│ │ └─────────────┘│ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────┐ ┌─────────────┐ ┌──────────────────────┐
│ User Action │─────▶│ React Hook │─────▶│ TanStack Query │
│ (click/type)│ │ (custom) │ │ (cache + mutations) │
└─────────────┘ └─────────────┘ └──────────┬───────────┘
│
┌───────────┴───────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────────┐
│ REST API │ │ Cloud Firestore │
│ (CodeLeap) │ │ (likes/reposts/ │
│ posts CRUD │ │ views/comments/ │
└──────────────┘ │ notifications) │
└──────────────────┘
┌──────────────────────────────────────────────────────────────────────────┐
│ COMPLETE USER FLOW │
└──────────────────────────────────────────────────────────────────────────┘
┌─────────┐ NO ┌──────────────┐ Firebase? ┌──────────┐
│ Access │──────────────▶│ LoginModal │───── YES ──────▶│ Firebase │
│ / │ authenticated?│ │ │ Auth │
└─────────┘ │ ┌─────────┐│ NO │ Google + │
│ │ │ Simple ││◀────────────────│ Email │
│ YES │ │username ││ └──────────┘
│ │ └─────────┘│
▼ └──────┬───────┘
┌─────────────────┐ │
│ AppHeader │◀─────────────┘ login OK
│ "CodeLeap Net" │
│ [Logout] │
└────────┬────────┘
│
▼
┌─────────────────┐ submit ┌──────────────────────┐
│ CreatePostForm │──────────────▶│ POST /careers/ │
│ Title │ │ (REST API) │
│ Content │ └──────────┬───────────┘
│ [Image] │ │ invalidate cache
└────────┬────────┘ │
│ ▼
▼ ┌──────────────────┐
┌─────────────────┐ │ TanStack Query │
│ FilterBar │ │ refetch posts │
│ Sort ↕ Search │ └──────────────────┘
└────────┬────────┘ │
│ │
▼ ▼
┌──────────────────────────────────────────────────────┐
│ PostList │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ PostCard │ │
│ │ ┌────────────────────────────────────────────┐ │ │
│ │ │ Header: Title [🗑️ Delete] [✏️ Edit] │ │ │
│ │ ├────────────────────────────────────────────┤ │ │
│ │ │ @username 25 minutes ago │ │ │
│ │ │ │ │ │
│ │ │ Post content with @mentions │ │ │
│ │ │ [attached image] │ │ │
│ │ │ │ │ │
│ │ │ ❤️ Like 💬 Comment 🔁 Repost 👁️ Views │ │ │
│ │ │ │ │ │
│ │ │ ┌─ Comments ─────────────────────────────┐ │ │ │
│ │ │ │ @user1: comment with @mention │ │ │ │
│ │ │ │ @user2: another comment │ │ │ │
│ │ │ │ [write a comment... ] [▶️] │ │ │ │
│ │ │ └────────────────────────────────────────┘ │ │ │
│ │ └────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┐ │
│ PostCard ... PostCard ... (infinite scroll) │ │
│ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┘ │
│ │
│ ┌──────────────────┐ │
│ │ 🔽 Sentinel │ ◀── IntersectionObserver │
│ │ (load more) │ triggers fetchNextPage() │
│ └──────────────────┘ │
└──────────────────────────────────────────────────────┘
┌──────────────── Modals ─────────────────┐
│ │
│ ┌─────────────┐ ┌─────────────────┐ │
│ │ DeleteModal │ │ EditModal │ │
│ │ "Are you │ │ Title: [____] │ │
│ │ sure?" │ │ Content:[____] │ │
│ │ [Cancel] │ │ [Cancel] [Save] │ │
│ │ [Delete] │ │ │ │
│ └─────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────────────────────────┐ │
│ │ LogoutModal │ │
│ │ "Leaving so soon?" │ │
│ │ [Stay] [Yes, log out] │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
❤️ LIKE 🔁 REPOST 👁️ VIEW 🔔 NOTIFY
───────── ────────── ────────── ──────────
Click Click Viewport On action
│ │ intersection │
▼ ▼ │ ▼
already ──YES──▶ nothing reposted? ──YES──▶ remove already seen createNotification()
liked? │ this session? │
│ NO │ ┌────┴────┐
NO │ NO │ │
│ ▼ │ post owner @mentioned
▼ toggleRepost() ▼ user users
addLike() │ recordView() │ │
│ ▼ │ ▼ ▼
▼ Firestore ▼ Firestore Firestore
Firestore reposts + count Firestore notifications/
likes + count (real-time) view counts {userId}/items/
(real-time) (real-time)
codeleap/
├── 📄 package.json # Dependencies and scripts
├── 📄 next.config.ts # Next.js configuration
├── 📄 tsconfig.json # TypeScript configuration
├── 📄 eslint.config.mjs # ESLint configuration
├── 📄 postcss.config.mjs # PostCSS configuration
├── 📄 README.md # This documentation
│
├── 📁 public/ # Static assets
│ └── 📁 icon/
│ ├── 🖼️ ic_baseline-delete-forever.svg # Delete icon
│ └── 🖼️ bx_bx-edit.svg # Edit icon
│
└── 📁 src/ # Source code
│
├── 📁 app/ # App Router (Next.js)
│ ├── 📄 layout.tsx # Root layout (providers, fonts)
│ ├── 📄 page.tsx # Main page (feed)
│ ├── 📄 error.tsx # Error boundary
│ ├── 📄 not-found.tsx # 404 page
│ └── 📄 globals.css # Global styles + design tokens
│
├── 📁 components/ # React components
│ ├── 📁 auth/
│ │ └── 📄 LoginModal.tsx # Login/Register (Firebase + simple)
│ ├── 📁 feed/
│ │ ├── 📄 AppHeader.tsx # Sticky header + logout modal
│ │ ├── 📄 CreatePostForm.tsx # Post creation form
│ │ ├── 📄 PostCard.tsx # Full card with interactions
│ │ └── 📄 PostList.tsx # Feed with filter + infinite scroll
│ ├── 📁 modals/
│ │ ├── 📄 DeletePostModal.tsx # Deletion confirmation
│ │ └── 📄 EditPostModal.tsx # Post editing
│ ├── 📁 states/
│ │ ├── 📄 EmptyState.tsx # Empty feed
│ │ ├── 📄 ErrorState.tsx # Loading error
│ │ └── 📄 LoadingSkeleton.tsx # Skeleton loading
│ └── 📁 ui/
│ ├── 📄 Button.tsx # 5 variants, 3 sizes, loading
│ ├── 📄 Input.tsx # Input with label + error
│ ├── 📄 Textarea.tsx # Textarea with label + error
│ ├── 📄 Modal.tsx # Animated modal (ESC, overlay)
│ ├── 📄 Skeleton.tsx # Loading placeholder
│ └── 📄 index.ts # Barrel exports
│
├── 📁 contexts/
│ └── 📄 AuthContext.tsx # Authentication provider
│
├── 📁 hooks/ # Custom hooks
│ ├── 📄 useCreatePost.ts # Create mutation
│ ├── 📄 useDeletePost.ts # Delete mutation
│ ├── 📄 useUpdatePost.ts # Update mutation
│ ├── 📄 usePosts.ts # Infinite post query
│ ├── 📄 usePostInteractions.ts # Consolidated: likes, reposts, views, comments + notifications
│ ├── 📄 useNotifications.ts # Real-time notification subscription
│ └── 📄 useIntersectionObserver.ts # Generic observer
│
├── 📁 lib/ # Utilities
│ ├── 📄 api.ts # HTTP client (REST API)
│ ├── 📄 firebase.ts # Firebase init (Auth + Firestore)
│ ├── 📄 firestore.ts # Firestore service layer (all read/write ops)
│ ├── 📄 providers.tsx # Providers wrapper
│ └── 📄 utils.ts # cn() + formatTimeAgo()
│
└── 📁 types/
└── 📄 api.ts # TypeScript interfaces
Token
Value
Usage
--color-primary
#7695ec
Buttons, links, header, focus
--color-primary-dark
#5a7be8
Primary hover
--color-primary-light
#eef2fd
Highlight background
--color-danger
#ef4444
Delete button, errors
--color-danger-dark
#dc2626
Danger hover
--color-success
#47b960
Active repost, success
--color-page-bg
#dddddd
Page background
Token
Value (clamp())
Range
--font-size-heading
clamp(1.125rem, 1rem + 0.5vw, 1.375rem)
18px → 22px
--font-size-heading-xl
clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem)
20px → 24px
--font-size-subheading
clamp(0.938rem, 0.85rem + 0.4vw, 1.125rem)
15px → 18px
--font-size-label
clamp(0.875rem, 0.82rem + 0.25vw, 1rem)
14px → 16px
--font-size-body
clamp(0.8rem, 0.76rem + 0.2vw, 0.875rem)
12.8px → 14px
--font-size-caption
clamp(0.688rem, 0.66rem + 0.15vw, 0.75rem)
11px → 12px
Token
Value
Usage
--shadow-sm
0 1px 4px rgba(0,0,0,0.08)
Subtle hover
--shadow-md
0 4px 20px rgba(0,0,0,0.1)
Elevated cards
--shadow-lg
0 16px 48px rgba(0,0,0,0.16)
Modals
Component
Props
Description
Button
variant, size, isLoading
5 variants × 3 sizes + spinner
Input
label, error
Input with forwardRef for forms
Textarea
label, error
Fixed textarea, 3 rows, no resize
Modal
isOpen, onClose, closeOnOverlayClick
Overlay + ESC + focus trap
Skeleton
className
Animated pulsing placeholder
Component
Description
AppHeader
Sticky header + notification bell 🔔 + logout modal
CreatePostForm
Validated form with image attachment
PostList
Feed with sort, filter, and infinite scroll
PostCard
Full card: like, repost, view, comment, @mention
MentionInput
Text input with @username autocomplete dropdown
Component
When Displayed
LoadingSkeleton
While posts are loading
EmptyState
Feed has no posts
ErrorState
Failed to load posts
Hook
Responsibility
usePosts()
useInfiniteQuery — feed pagination (PAGE_SIZE = 10)
useCreatePost()
POST mutation + cache invalidation
useUpdatePost()
PATCH mutation + invalidation
useDeletePost()
DELETE mutation + invalidation
usePostInteractions()
Consolidated: likes, reposts, views, comments + notification dispatch
useNotifications()
Real-time notification subscription via Firestore onSnapshot
useIntersectionObserver()
Generic observer for scroll sentinel
Note: The previous useLikes, useReposts, useViews, and useComments hooks (localStorage-based) were consolidated into a single usePostInteractions hook backed by Cloud Firestore.
Feature
Implementation
ARIA Labels
All buttons and interactive elements
ARIA Pressed
Like and repost state
ARIA Modal
role="dialog" + aria-modal="true"
Focus Trap
Auto-focus on modal panel
Keyboard Navigation
Escape closes modals
Focus Visible
Blue ring with animated outline-offset
Semantic HTML
<header>, <main>, <article>, <time>, <form>
Scroll Lock
body overflow: hidden when modal is open
Alt Texts
Images with descriptive alt or aria-hidden
Node.js v18 or higher
pnpm v9 or higher
# 1. Clone the repository
git clone https://github.com/glauccoeng-prog/CodeLeap.git
cd CodeLeap/codeleap
# 2. Install dependencies
pnpm install
# 3. Configure Firebase (create .env.local)
cp .env.example .env.local
# Fill in your Firebase project credentials
# 4. Start the development server
pnpm dev
# 5. Open in your browser
# http://localhost:3000
# Generate optimized build
pnpm build
# Serve the build locally
pnpm start
Command
Runs
Description
pnpm dev
next dev
Development server
pnpm build
next build
Optimized production build
pnpm start
next start
Serves the generated build
pnpm lint
eslint
Checks for lint errors
pnpm type-check
tsc --noEmit
Checks TypeScript types
pnpm format
prettier --write .
Formats all code
This project was built based on the Figma designs for CodeLeap Network:
Login/Signup — Authentication modal (Firebase + simple)
Main Screen — Post feed with header, creation, and listing
Delete Modal — Post deletion confirmation
Edit Modal — Title and content editing
posts_meta/{postId} → { likeCount, commentCount, repostCount, viewCount }
└── likes/{userId} → { likedAt }
└── reposts/{userId} → { repostedAt }
└── views/{userId} → { viewedAt }
└── comments/{commentId} → { userId, username, text, createdAt }
notifications/{userId}/items/{notifId} → { type, fromUsername, fromUserId, postId, postTitle, read, createdAt }
users/{uid} → { username, updatedAt }
Type
Trigger
Recipient
like
User likes a post
Post author
comment
User comments on a post
Post author
repost
User reposts a post
Post author
mention
User mentions @username in comment
Mentioned user
Glaucco Siqueira