arnobt78/Quotes-Generator--NextJS-Fundamental-Project-8
A modern, interactive quotes application built with Next.js, React, TypeScript,Tailwind CSS. The app fetches random quotes from the TheQuote API, displays them with author details, lets you save favorites. Designed for learning React fundamentals, API integration, Context API, custom hooks—including floating balloon animation, ripple buttons & more
Quotes Generator – Next.js, React, TypeScript, TheQuote API, TailwindCSS, Framer Motion Fundamental Project 8
A modern, interactive quotes application built with Next.js, React, TypeScript, and Tailwind CSS. The app fetches random quotes from the TheQuote API, displays them with author details, and lets you save favorites. Designed as a learning project for React fundamentals, API integration, Context API, custom hooks, and modern UI patterns—including floating balloon animations, ripple buttons, and toast notifications.
- Live Demo: https://quotes-builder.vercel.app/
Table of Contents
- Project Summary
- Features
- Technology Stack
- Project Structure
- Setup & Installation
- Environment Variables
- API & Backend
- Routes & Pages
- Components & Functionality
- Reusing Components
- Libraries & Dependencies
- Keywords
- Learning & Teaching
- Conclusion
- License
Project Summary
This Quotes Generator is a full-stack learning project that demonstrates:
- SSR/CSR separation: Next.js App Router pages handle server-side rendering; client-side logic lives in components.
- API integration: Fetches random quotes from TheQuote API with proper error handling.
- State management: React Context API for favorites; custom hooks for quote fetching.
- Modern UI: Tailwind CSS, Framer Motion animations, GSAP floating balloons, ripple buttons, Sonner toasts.
- TypeScript: Strict typing across the codebase with no
any.
Features
- Random Quote Fetching: Click "New Quote" to load a new quote from TheQuote API.
- Favorites: Add quotes to a favorites list; view and remove them via the heart icon.
- Floating Balloons: Decorative circles that wander across the card, react to mouse (repel + wind), and avoid overlapping.
- Ripple Buttons: All buttons use a ripple effect for clear click feedback.
- Loading States: Skeleton loading for quotes; spinner and "Generating…" on the New Quote button.
- Toast Notifications: Sonner toasts for "New quote loaded", "Added to favorites", and "Already in favorites".
- Educational Section: "How this app works" explains State, Hooks, API, and Context.
- Responsive Design: Mobile-first layout with
max-w-9xland responsive breakpoints. - SEO: Metadata, OpenGraph, Twitter cards, and favicon configured.
Technology Stack
| Technology | Purpose |
|---|---|
| Next.js 16 | React framework with App Router, SSR, and file-based routing |
| React 19 | UI library with hooks and Context API |
| TypeScript 5.6 | Type safety and better DX |
| Tailwind CSS 3.4 | Utility-first styling |
| Framer Motion 11 | Animations and transitions |
| GSAP 3.14 | Floating balloon animations |
| Lucide React | Icon library |
| Sonner | Toast notifications |
| TheQuote API | External API for random quotes |
Project Structure
quotes-generator/
├── .env.example # Example env vars (copy to .env)
├── .gitignore
├── eslint.config.mjs # ESLint flat config
├── next.config.ts # Next.js config
├── package.json
├── postcss.config.mjs # PostCSS for Tailwind
├── tailwind.config.ts # Tailwind theme, fonts, keyframes
├── tsconfig.json
├── vercel.json # Vercel deployment (framework: nextjs)
├── public/
│ ├── favicon.ico
│ └── hero2.avif # Background image
└── src/
├── app/
│ ├── globals.css # Tailwind + custom scrollbar
│ ├── layout.tsx # Root layout, fonts, metadata, providers
│ └── page.tsx # SSR page (renders HomePage)
├── Components/
│ ├── pages/
│ │ └── HomePage.tsx # Main client page
│ ├── QuoteCard.tsx # Quote display + skeleton
│ ├── FavoritesList.tsx # Favorites panel
│ ├── FloatingBalloons.tsx # GSAP balloons
│ ├── EducationalSection.tsx
│ ├── Footer.tsx
│ └── ui/
│ ├── Button.tsx # Primary/secondary + loading
│ ├── RippleButton.tsx
│ └── SonnerToaster.tsx
├── context/
│ └── FavoritesContext.tsx # Favorites state + actions
├── hooks/
│ └── useQuote.ts # Quote fetch hook
├── lib/
│ └── api/
│ └── quote.ts # TheQuote API client
└── types/
└── quote.ts # Quote, QuoteApiResponseSetup & Installation
Prerequisites
- Node.js 18+ (nodejs.org)
- npm (included with Node.js)
Steps
# 1. Clone the repository
git clone https://github.com/arnobt78/Quotes-Generator--React.git
cd Quotes-Generator--React
# 2. Install dependencies
npm install
# 3. (Optional) Set up environment variables (see Environment Variables)
cp .env.example .env
# Edit .env and add your API key
# 4. Start development server
npm run devVisit http://localhost:3000 in your browser.
Scripts
| Command | Description |
|---|---|
npm run dev |
Start dev server (Turbopack) |
npm run build |
Production build |
npm run start |
Start production server |
npm run lint |
Run ESLint (0 warnings) |
Environment Variables
You can run this project without any environment variables. The app will load, but quote fetching will fail until you add an API key.
Optional: TheQuote API Key
To fetch random quotes, create a .env file in the project root:
# .env
NEXT_PUBLIC_QUOTE_API_KEY=your-api-key-here- Get your key: TheQuote API – sign up with your email.
- Why
NEXT_PUBLIC_? Next.js only exposes env vars with this prefix to the browser. The quote API is called client-side. - Copy from example:
cp .env.example .envand replaceyour-api-key-here.
If Migrating from Vite
The old variable was VITE_QUOTE_API_KEY. In Next.js, use NEXT_PUBLIC_QUOTE_API_KEY.
API & Backend
TheQuote API
- Endpoint:
GET https://thequoteapi.com/api/quotes/random/ - Auth: Header
api_key: <your-key> - Response:
{ text: string, author: string }
Implementation
The API is called from src/lib/api/quote.ts:
export async function fetchRandomQuote(apiKey: string): Promise<Quote> {
const response = await fetch(QUOTE_API_URL, {
headers: { api_key: apiKey },
});
if (!response.ok) throw new Error(`Quote API error: ${response.status}`);
const data = await response.json();
return { text: data.text, author: data.author };
}There is no custom backend. All logic runs in the browser; the only external service is TheQuote API.
Routes & Pages
| Route | File | Description |
|---|---|---|
/ |
src/app/page.tsx |
Home – renders HomePage |
/_not-found |
Next.js default | 404 page |
The app uses Next.js App Router. page.tsx is a server component that renders the client HomePage component. All interactive state (quotes, favorites, UI) lives in HomePage.
Components & Functionality
HomePage (src/Components/pages/HomePage.tsx)
- Role: Main client page; holds quote state, favorites toggle, and card layout.
- Uses:
useQuote,useFavorites,QuoteCard,FavoritesList,FloatingBalloons,Button,EducationalSection. - Flow: Click "New Quote" →
fetchNewQuote()→ toast; click heart → toggle favorites panel; click "Add to Favorites" →addFavorite()→ toast.
QuoteCard (src/Components/QuoteCard.tsx)
- Role: Displays quote text and author; shows skeleton when loading.
- Props:
quote,loading. - Features: Framer Motion entrance; decorative
"marks; centered text, right-aligned author.
FavoritesList (src/Components/FavoritesList.tsx)
- Role: Slide-over panel listing saved quotes; each has a remove button.
- Props:
favorites,onClose,onRemove. - Features: AnimatePresence for add/remove; custom scrollbar; teal gradient background.
FloatingBalloons (src/Components/FloatingBalloons.tsx)
- Role: Decorative circles that wander across the card and react to mouse.
- Props:
cardRef(for mouse events). - Features: GSAP random wander; mouse repel; wind gust on fast movement; collision avoidance.
Button (src/Components/ui/Button.tsx)
- Role: Reusable button with ripple, loading state, and variants.
- Props:
variant("primary" | "secondary"),loading,disabled,children. - Features: Ripple on click; spinner + "Generating…" when loading.
RippleButton (src/Components/ui/RippleButton.tsx)
- Role: Base button with ripple effect; used by
Buttonand heart/close/trash icons. - How it works: On click, creates a span at click position, animates with
animate-ripple, removes after 600ms.
EducationalSection (src/Components/EducationalSection.tsx)
- Role: Explains State, Hooks, API, Context, and quick tips for learners.
Footer (src/Components/Footer.tsx)
- Role: Copyright notice with current year and Lucide icon.
Reusing Components
Button
import { Button } from "@/Components/ui/Button";
<Button variant="primary" onClick={handleClick} loading={isLoading}>
Submit
</Button>;RippleButton (for icons or custom styles)
import { RippleButton } from "@/Components/ui/RippleButton";
<RippleButton onClick={onClose} className="p-2 rounded-full hover:bg-white/10">
<X className="w-6 h-6" />
</RippleButton>;useQuote Hook
import { useQuote } from "@/hooks/useQuote";
const { quote, loading, error, fetchNewQuote } = useQuote(apiKey, {
onSuccess: (q) => console.log("Loaded:", q),
});useFavorites (requires FavoritesProvider)
import { useFavorites } from "@/context/FavoritesContext";
const { favorites, addFavorite, removeFavorite, isInFavorites } =
useFavorites();FloatingBalloons
const cardRef = useRef<HTMLDivElement>(null);
<div ref={cardRef}>
<FloatingBalloons cardRef={cardRef} />
</div>;Libraries & Dependencies
| Package | Version | Purpose |
|---|---|---|
| next | ^16.1.7 | React framework, App Router, SSR |
| react / react-dom | ^19.2.4 | UI library |
| framer-motion | ^11.11.17 | Animations (AnimatePresence, motion.div) |
| gsap | ^3.14.2 | Floating balloon animations |
| lucide-react | ^0.460.0 | Icons (Heart, RefreshCw, BookMarked, etc.) |
| sonner | ^1.7.0 | Toast notifications |
| tailwindcss | ^3.4.14 | Utility CSS |
| typescript | ^5.6.3 | Type checking |
| eslint / eslint-config-next | ^9 / ^16 | Linting |
Example: Framer Motion
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.4, ease: "easeOut" }}
>
{content}
</motion.div>Example: Sonner Toast
import { toast } from "sonner";
toast.success("Added to favorites", {
description: `"${quote.text}" — ${quote.author}`,
});Keywords
- React, Next.js, TypeScript, Tailwind CSS
- TheQuote API, API integration
- Quotes Generator, Favorite quotes
- Context API, Custom hooks, useState
- Framer Motion, GSAP, Animations
- Ripple button, Toast notifications
- .env, NEXTPUBLIC
- Learning project, Beginner tutorial
Learning & Teaching
For Beginners
- State:
useStatefor quote, loading, error, favorites,showFavorites. - Hooks:
useQuote(custom) anduseFavorites(Context). - API:
fetch()with headers; error handling with try/catch. - Components: Props, children, conditional rendering.
For Intermediate
- SSR vs CSR:
page.tsx(SSR) vsHomePage.tsx(CSR). - Context:
FavoritesProviderwraps the app;useFavoritesconsumes it. - TypeScript: Interfaces for
Quote,QuoteApiResponse, component props. - Tailwind: Custom theme (
max-w-9xl, fonts,animate-ripple).
Extension Ideas
- Add search or filter for quotes.
- Persist favorites to
localStorage. - Add theme toggle (light/dark).
- Add share-to-Twitter or copy-to-clipboard.
Conclusion
The Quotes Generator is a practical Next.js + React project that covers API integration, state management, animations, and modern UI patterns. Use it to learn, teach, or extend with new features.
License
This project is licensed under the MIT License. Feel free to use, modify, and distribute the code as per the terms of the license.
Happy Coding! 🎉
This is an open-source project - feel free to use, enhance, and extend this project further!
If you have any questions or want to share your work, reach out via GitHub or my portfolio at https://www.arnobmahmud.com.
Enjoy building and learning! 🚀
Thank you! 😊

