π± Responsive Planto Ecommerce Website with React, Vite, TypeScript & Tailwind CSS π±
Welcome to an exciting journey in modern web development! π In this project, weβll create a fully responsive ecommerce website for selling herbs using cutting-edge technologies: React, Vite, TypeScript, and Tailwind CSS. This project is perfect for developers of all levels looking to sharpen their skills while building a practical application.
π» Features:
- Stunning Home Page: An eye-catching design to welcome your visitors.
- Smooth Checkout Process: Simplify purchasing with a user-friendly checkout page.
- Detailed Plant Product Pages: Highlight the unique benefits of each plant.
- Organized Plant Types Page: Help users browse by category.
- Functional Contact Page: Enable users to get in touch effortlessly.
π¦ What It contains:
- Responsive Design Best Practices: Ensure your website looks great on any device.
- Modern Component-Based Development: Build clean, reusable components.
- Tailwind CSS for Fast and Elegant Styling: Speed up styling with utility-first CSS.
β¨ Why Build This Project?
This ecommerce project is an excellent way to master:
- Developing responsive layouts.
- Using TypeScript for scalable and maintainable code.
- Implementing Tailwind CSS to craft modern, visually appealing UIs.
Whether youβre a beginner or an experienced developer, this project will help you gain valuable insights into crafting dynamic web applications.
π§ Tech Stack:
- React for UI Development
- Vite for Blazing-Fast Development
- TypeScript for Type Safety
- Tailwind CSS for Utility-First Styling
π¨ Code Overview:
Hereβs a glimpse of how the app is structured:
App.tsx
import { useState, useEffect } from 'react';
import { Routes, Route, useLocation } from 'react-router-dom';
import { Cart, Footer, Navbar } from './components';
import { Home, Checkout, PlantsType, Contact, PlantDetail } from './pages';
import { useCart } from './context/CartContext';
export default function App() {
const [isNavOpen, setIsNavOpen] = useState(false);
const [isCartOpen, setIsCartOpen] = useState(false);
const location = useLocation();
const { cart, updateQuantity, removeFromCart } = useCart();
const closeCart = () => setIsCartOpen(false);
useEffect(() => {
closeCart();
window.scrollTo(0, 0);
}, [location]);
return (
<div className="min-h-screen bg-sectionColor text-white font-sans relative">
<Navbar
isOpen={isNavOpen}
setIsOpen={setIsNavOpen}
cart={cart}
toggleCart={() => setIsCartOpen(prev => !prev)}
/>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/checkout" element={<Checkout />} />
<Route path="/plants-type" element={<PlantsType />} />
<Route path="/plant/:plantId" element={<PlantDetail />} />
<Route path="/contact" element={<Contact />} />
</Routes>
{isCartOpen && (
<Cart
cart={cart}
updateQuantity={updateQuantity}
removeFromCart={removeFromCart}
closeCart={closeCart}
/>
)}
<Footer />
</div>
);
}
Home.tsx
import React from 'react';
import { HeroSection, TopSelling, CustomerReview, BestO2 } from '../components';
import plantsData from '../data/plantsData';
const Home: React.FC = () => {
return (
<div>
<HeroSection />
<main className="container mx-auto px-4 py-8">
<TopSelling plants={plantsData} />
<CustomerReview />
<BestO2 plants={plantsData} />
</main>
</div>
);
};
export default Home;
Cart.tsx
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { Button }from './';
import { CartProps } from '../types/types';
import { PlusIcon, MinusIcon, TrashIcon, XMarkIcon } from "@heroicons/react/24/solid";
const Cart: React.FC<CartProps> = ({ cart, updateQuantity, removeFromCart, closeCart }) => {
const total = cart.reduce((sum, item) => sum + item.price * item.quantity, 0);
const navigate = useNavigate();
const handleCheckout = () => {
const checkoutData = cart.map(({ id, name, price, quantity }) => ({
id,
name,
price,
quantity,
}));
closeCart();
navigate('/checkout', { state: { cart: checkoutData } });
};
return (
<div className="fixed top-16 right-0 w-full max-w-md bg-[#11170f] rounded-3xl p-4 z-50 max-h-[80vh] overflow-y-auto">
<div className="container mx-auto px-4 py-8 relative">
<button
className="absolute top-4 right-4 text-gray-300 hover:text-white"
onClick={closeCart}
aria-label="Close cart"
>
<XMarkIcon className="h-6 w-6" />
</button>
<h1 className="text-3xl font-bold mb-8">Your Cart</h1>
{cart.length === 0 ? (
<p>Your cart is empty.</p>
) : (
<div className="grid md:grid-cols-1 gap-8">
<div className="md:col-span-1">
{/* Scrollable container for cart items */}
<div className="max-h-72 overflow-y-auto">
{cart.map((item) => (
<div key={item.id} className="flex items-center mb-4 bg-[#d8ebd1] bg-opacity-30 p-4 rounded-lg">
<img src={item.image} alt={item.name} className="w-20 h-20 object-cover rounded-md mr-4" />
<div className="flex-1">
<h3 className="text-lg font-semibold">{item.name}</h3>
<p className="text-gray-300">Rs. {item.price}</p>
<div className="flex items-center mt-2">
<button
className="text-gray-300 hover:text-white"
onClick={() => updateQuantity(item.id, Math.max(1, item.quantity - 1))}
aria-label="Decrease quantity"
>
<MinusIcon className="h-4 w-4" />
</button>
<span className="mx-2">{item.quantity}</span>
<button
className="text-gray-300 hover:text-white"
onClick={() => updateQuantity(item.id, item.quantity + 1)}
aria-label="Increase quantity"
>
<PlusIcon className="h-4 w-4" />
</button>
</div>
</div>
<button
className="text-gray-300 hover:text-white"
onClick={() => removeFromCart(item.id)}
aria-label={`Remove ${item.name} from cart`}
>
<TrashIcon className="h-6 w-6" />
</button>
</div>
))}
</div>
</div>
<div className="bg-[#d8ebd1] bg-opacity-30 p-4 rounded-lg h-fit">
<h3 className="text-xl font-semibold mb-4">Order Summary</h3>
<div className="space-y-2 mb-4">
<div className="flex justify-between">
<span>Subtotal</span>
<span>Rs. {total}</span>
</div>
<div className="flex justify-between">
<span>Shipping</span>
<span>Rs. 50</span>
</div>
<div className="flex justify-between font-semibold">
<span>Total</span>
<span>Rs. {total + 50}</span>
</div>
</div>
<div className="flex justify-end">
<Button text="Confirm Order" onClick={handleCheckout} />
</div>
</div>
</div>
)}
</div>
</div>
);
};
export default Cart;
π₯ Resources:
- Figma Design: Check out the inspiration
- Download the Code: Get the project here
π Connect & Share
If you find this project helpful, donβt forget to like, share, and subscribe! Letβs grow together. π
Feel free to leave your feedback in the comments below. Happy coding! π
Top comments (0)