roshan1997 commited on
Commit
6e6888e
Β·
verified Β·
1 Parent(s): cbd08da

PROMPT START

Browse files

Build a complete Online Shopping Website using Next.js (App Router), TypeScript, Tailwind CSS, and shadcn/ui.

πŸ“Œ Features I want
1. Authentication (Frontend Only)

Signup page

Login page

Logout button

Store logged-in user in localStorage

Protect cart page β†’ if user is not logged in, redirect to login

Authentication logic should be client-side only (I will add backend later)

2. Pages Needed

/ β†’ Home Page

/products β†’ Product listing

/products/[id] β†’ Product details page

/cart β†’ Cart page (PRIVATE)

/login β†’ Login

/signup β†’ Signup

3. Add to Cart System

Only logged-in users can add items to cart

Cart data stored in localStorage

Add, remove, increase, decrease quantity

Show cart count in navbar

Sync cart on page reload

4. Components Needed
Client Components

Navbar with login/signup/logout + cart count

ProductCard

AddToCartButton

LoginForm

SignupForm

CartItems

ProtectedRoute wrapper

Server Components

HomePage

ProductList (server-fetched dummy data)

ProductDetails (server component with client-side AddToCart button)

5. UI / Styling

Tailwind CSS

Use shadcn/ui for reusable UI components

Responsive + mobile-first

Beautiful minimal design

6. Dummy Product Data

Use products.json or a simple array inside server components

Structure: id, title, description, image, price, category

πŸ“ Folder Structure to Generate
app/
β”œβ”€ layout.tsx
β”œβ”€ page.tsx (Home)
β”œβ”€ login/page.tsx
β”œβ”€ signup/page.tsx
β”œβ”€ products/page.tsx
β”œβ”€ products/[id]/page.tsx
β”œβ”€ cart/page.tsx
components/
β”œβ”€ Navbar.tsx
β”œβ”€ ProductCard.tsx
β”œβ”€ AddToCartButton.tsx
β”œβ”€ LoginForm.tsx
β”œβ”€ SignupForm.tsx
β”œβ”€ CartItems.tsx
β”œβ”€ ProtectedRoute.tsx
lib/
β”œβ”€ cart.ts (cart utils localStorage)
β”œβ”€ auth.ts (login/signup localStorage)
data/
β”œβ”€ products.ts

7. Functionality Details
πŸ” Authentication

signup() saves user to localStorage

login() checks user

logout() clears currentUser

Save user as:

currentUser: { email: "", name: "" }

πŸ›’ Cart System Logic (localStorage)
cart = [
{ id, name, price, quantity, image }
]


Functions:

addToCart()
removeFromCart()
increaseQuantity()
decreaseQuantity()
getCart()
clearCart()

8. Add Realistic UI

Modern buttons

Product grid

Mobile drawer menu for navbar

Toast notifications for add to cart, login, signup

9. Code Requirements

βœ” Use client/server components correctly
βœ” Use "use client" only where needed
βœ” Full working components
βœ” Every page design clean
βœ” Functions well-commented
βœ” Redirect unauthenticated users
βœ” No backend β†’ everything on localStorage

PROMPT END

Files changed (6) hide show
  1. README.md +8 -5
  2. components/footer.js +64 -0
  3. components/navbar.js +125 -0
  4. index.html +50 -19
  5. script.js +170 -0
  6. style.css +29 -18
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Shopsphere E Commerce Delight
3
- emoji: πŸ‘€
4
- colorFrom: blue
5
- colorTo: purple
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: ShopSphere - E-Commerce Delight πŸ›οΈ
3
+ colorFrom: red
4
+ colorTo: red
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://huggingface.co/deepsite).
components/footer.js ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomFooter extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ .footer-link {
7
+ transition: color 0.2s ease;
8
+ }
9
+
10
+ .footer-link:hover {
11
+ color: #6366f1;
12
+ }
13
+ </style>
14
+ <footer class="bg-gray-800 text-white py-8">
15
+ <div class="container mx-auto px-4">
16
+ <div class="grid grid-cols-1 md:grid-cols-4 gap-8">
17
+ <div>
18
+ <h3 class="text-xl font-bold mb-4">ShopSphere</h3>
19
+ <p class="text-gray-400">Your one-stop shop for all your needs.</p>
20
+ </div>
21
+
22
+ <div>
23
+ <h4 class="font-semibold mb-4">Quick Links</h4>
24
+ <ul class="space-y-2">
25
+ <li><a href="/" class="footer-link text-gray-400">Home</a></li>
26
+ <li><a href="/products" class="footer-link text-gray-400">Products</a></li>
27
+ <li><a href="/cart" class="footer-link text-gray-400">Cart</a></li>
28
+ </ul>
29
+ </div>
30
+
31
+ <div>
32
+ <h4 class="font-semibold mb-4">Help</h4>
33
+ <ul class="space-y-2">
34
+ <li><a href="#" class="footer-link text-gray-400">FAQs</a></li>
35
+ <li><a href="#" class="footer-link text-gray-400">Shipping</a></li>
36
+ <li><a href="#" class="footer-link text-gray-400">Returns</a></li>
37
+ </ul>
38
+ </div>
39
+
40
+ <div>
41
+ <h4 class="font-semibold mb-4">Contact</h4>
42
+ <ul class="space-y-2">
43
+ <li class="flex items-center">
44
+ <i data-feather="mail" class="mr-2"></i>
45
+ <span class="text-gray-400">support@shopsphere.com</span>
46
+ </li>
47
+ <li class="flex items-center">
48
+ <i data-feather="phone" class="mr-2"></i>
49
+ <span class="text-gray-400">(123) 456-7890</span>
50
+ </li>
51
+ </ul>
52
+ </div>
53
+ </div>
54
+
55
+ <div class="border-t border-gray-700 mt-8 pt-8 text-center text-gray-400">
56
+ <p>&copy; ${new Date().getFullYear()} ShopSphere. All rights reserved.</p>
57
+ </div>
58
+ </div>
59
+ </footer>
60
+ `;
61
+ }
62
+ }
63
+
64
+ customElements.define('custom-footer', CustomFooter);
components/navbar.js ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomNavbar extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ .nav-link {
7
+ position: relative;
8
+ padding-bottom: 4px;
9
+ }
10
+
11
+ .nav-link::after {
12
+ content: '';
13
+ position: absolute;
14
+ bottom: 0;
15
+ left: 0;
16
+ width: 0;
17
+ height: 2px;
18
+ background-color: #6366f1;
19
+ transition: width 0.3s ease;
20
+ }
21
+
22
+ .nav-link:hover::after {
23
+ width: 100%;
24
+ }
25
+
26
+ .mobile-menu {
27
+ transition: all 0.3s ease;
28
+ }
29
+
30
+ .cart-count {
31
+ display: none;
32
+ position: absolute;
33
+ top: -8px;
34
+ right: -8px;
35
+ background-color: #f43f5e;
36
+ color: white;
37
+ border-radius: 50%;
38
+ width: 20px;
39
+ height: 20px;
40
+ font-size: 12px;
41
+ align-items: center;
42
+ justify-content: center;
43
+ }
44
+ </style>
45
+ <nav class="bg-white shadow-sm">
46
+ <div class="container mx-auto px-4 py-4">
47
+ <div class="flex justify-between items-center">
48
+ <a href="/" class="text-2xl font-bold text-primary">ShopSphere</a>
49
+
50
+ <div class="hidden md:flex items-center space-x-8">
51
+ <a href="/" class="nav-link text-gray-700 hover:text-primary">Home</a>
52
+ <a href="/products" class="nav-link text-gray-700 hover:text-primary">Products</a>
53
+ <a href="/cart" class="nav-link text-gray-700 hover:text-primary relative">
54
+ <i data-feather="shopping-cart"></i>
55
+ <span id="cart-count" class="cart-count">0</span>
56
+ </a>
57
+
58
+ ${auth.isAuthenticated() ? `
59
+ <div class="flex items-center space-x-4">
60
+ <span class="text-gray-700">Hi, ${auth.currentUser.name}</span>
61
+ <button onclick="auth.logout()" class="bg-secondary text-white px-4 py-2 rounded hover:bg-secondary-600 transition">
62
+ Logout
63
+ </button>
64
+ </div>
65
+ ` : `
66
+ <div class="flex items-center space-x-4">
67
+ <a href="/login" class="text-gray-700 hover:text-primary">Login</a>
68
+ <a href="/signup" class="bg-primary text-white px-4 py-2 rounded hover:bg-primary-600 transition">
69
+ Sign Up
70
+ </a>
71
+ </div>
72
+ `}
73
+ </div>
74
+
75
+ <button id="mobile-menu-button" class="md:hidden text-gray-700">
76
+ <i data-feather="menu"></i>
77
+ </button>
78
+ </div>
79
+
80
+ <div id="mobile-menu" class="mobile-menu hidden md:hidden mt-4 pb-4">
81
+ <a href="/" class="block py-2 text-gray-700 hover:text-primary">Home</a>
82
+ <a href="/products" class="block py-2 text-gray-700 hover:text-primary">Products</a>
83
+ <a href="/cart" class="block py-2 text-gray-700 hover:text-primary relative">
84
+ <span class="flex items-center">
85
+ <i data-feather="shopping-cart" class="mr-2"></i> Cart
86
+ <span id="mobile-cart-count" class="cart-count ml-2">0</span>
87
+ </span>
88
+ </a>
89
+
90
+ ${auth.isAuthenticated() ? `
91
+ <div class="mt-4 pt-4 border-t border-gray-200">
92
+ <p class="text-gray-700 mb-2">Hi, ${auth.currentUser.name}</p>
93
+ <button onclick="auth.logout()" class="w-full bg-secondary text-white px-4 py-2 rounded hover:bg-secondary-600 transition">
94
+ Logout
95
+ </button>
96
+ </div>
97
+ ` : `
98
+ <div class="mt-4 pt-4 border-t border-gray-200 space-y-2">
99
+ <a href="/login" class="block py-2 text-gray-700 hover:text-primary">Login</a>
100
+ <a href="/signup" class="block bg-primary text-white px-4 py-2 rounded text-center hover:bg-primary-600 transition">
101
+ Sign Up
102
+ </a>
103
+ </div>
104
+ `}
105
+ </div>
106
+ </div>
107
+ </nav>
108
+
109
+ <script>
110
+ document.addEventListener('DOMContentLoaded', () => {
111
+ const menuButton = this.shadowRoot.getElementById('mobile-menu-button');
112
+ const mobileMenu = this.shadowRoot.getElementById('mobile-menu');
113
+
114
+ menuButton.addEventListener('click', () => {
115
+ mobileMenu.classList.toggle('hidden');
116
+ });
117
+
118
+ feather.replace();
119
+ });
120
+ </script>
121
+ `;
122
+ }
123
+ }
124
+
125
+ customElements.define('custom-navbar', CustomNavbar);
index.html CHANGED
@@ -1,19 +1,50 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>ShopSphere - E-Commerce Delight</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
10
+ <script src="https://unpkg.com/feather-icons"></script>
11
+ <script>
12
+ tailwind.config = {
13
+ theme: {
14
+ extend: {
15
+ colors: {
16
+ primary: '#6366f1',
17
+ secondary: '#f43f5e',
18
+ }
19
+ }
20
+ }
21
+ }
22
+ </script>
23
+ </head>
24
+ <body class="bg-gray-50">
25
+ <custom-navbar></custom-navbar>
26
+ <main class="container mx-auto px-4 py-8">
27
+ <section class="hero-section mb-12">
28
+ <div class="bg-gradient-to-r from-primary to-secondary rounded-2xl p-8 text-white">
29
+ <h1 class="text-4xl md:text-5xl font-bold mb-4">Welcome to ShopSphere</h1>
30
+ <p class="text-xl mb-6">Discover amazing products at unbeatable prices</p>
31
+ <a href="/products" class="bg-white text-primary px-6 py-3 rounded-lg font-medium hover:bg-opacity-90 transition">Shop Now</a>
32
+ </div>
33
+ </section>
34
+
35
+ <section class="featured-products mb-12">
36
+ <h2 class="text-2xl font-bold mb-6">Featured Products</h2>
37
+ <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6" id="featured-products">
38
+ <!-- Products will be loaded via JavaScript -->
39
+ </div>
40
+ </section>
41
+ </main>
42
+ <custom-footer></custom-footer>
43
+
44
+ <script src="components/navbar.js"></script>
45
+ <script src="components/footer.js"></script>
46
+ <script src="script.js"></script>
47
+ <script>feather.replace();</script>
48
+ <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
49
+ </body>
50
+ </html>
script.js ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Auth functions
2
+ const auth = {
3
+ currentUser: JSON.parse(localStorage.getItem('currentUser')) || null,
4
+
5
+ signup: (name, email, password) => {
6
+ const user = { name, email };
7
+ localStorage.setItem('currentUser', JSON.stringify(user));
8
+ auth.currentUser = user;
9
+ showToast('Account created successfully!');
10
+ window.location.href = '/';
11
+ },
12
+
13
+ login: (email, password) => {
14
+ // In a real app, this would verify against a backend
15
+ const user = { name: 'Demo User', email };
16
+ localStorage.setItem('currentUser', JSON.stringify(user));
17
+ auth.currentUser = user;
18
+ showToast('Logged in successfully!');
19
+ window.location.href = '/';
20
+ },
21
+
22
+ logout: () => {
23
+ localStorage.removeItem('currentUser');
24
+ auth.currentUser = null;
25
+ showToast('Logged out successfully!');
26
+ window.location.href = '/';
27
+ },
28
+
29
+ isAuthenticated: () => {
30
+ return auth.currentUser !== null;
31
+ }
32
+ };
33
+
34
+ // Cart functions
35
+ const cart = {
36
+ getCart: () => {
37
+ return JSON.parse(localStorage.getItem('cart')) || [];
38
+ },
39
+
40
+ addToCart: (product) => {
41
+ if (!auth.isAuthenticated()) {
42
+ window.location.href = '/login';
43
+ return;
44
+ }
45
+
46
+ const cartItems = cart.getCart();
47
+ const existingItem = cartItems.find(item => item.id === product.id);
48
+
49
+ if (existingItem) {
50
+ existingItem.quantity += 1;
51
+ } else {
52
+ cartItems.push({
53
+ ...product,
54
+ quantity: 1
55
+ });
56
+ }
57
+
58
+ localStorage.setItem('cart', JSON.stringify(cartItems));
59
+ updateCartCount();
60
+ showToast(`${product.name} added to cart!`);
61
+ },
62
+
63
+ removeFromCart: (productId) => {
64
+ const cartItems = cart.getCart().filter(item => item.id !== productId);
65
+ localStorage.setItem('cart', JSON.stringify(cartItems));
66
+ updateCartCount();
67
+ },
68
+
69
+ updateQuantity: (productId, newQuantity) => {
70
+ const cartItems = cart.getCart();
71
+ const item = cartItems.find(item => item.id === productId);
72
+
73
+ if (item) {
74
+ if (newQuantity <= 0) {
75
+ cart.removeFromCart(productId);
76
+ } else {
77
+ item.quantity = newQuantity;
78
+ localStorage.setItem('cart', JSON.stringify(cartItems));
79
+ }
80
+ }
81
+
82
+ updateCartCount();
83
+ },
84
+
85
+ clearCart: () => {
86
+ localStorage.removeItem('cart');
87
+ updateCartCount();
88
+ }
89
+ };
90
+
91
+ // Helper functions
92
+ function updateCartCount() {
93
+ const cartCount = document.getElementById('cart-count');
94
+ if (cartCount) {
95
+ const count = cart.getCart().reduce((sum, item) => sum + item.quantity, 0);
96
+ cartCount.textContent = count;
97
+ cartCount.style.display = count > 0 ? 'flex' : 'none';
98
+ }
99
+ }
100
+
101
+ function showToast(message) {
102
+ const toast = document.createElement('div');
103
+ toast.className = 'toast';
104
+ toast.textContent = message;
105
+ document.body.appendChild(toast);
106
+
107
+ setTimeout(() => {
108
+ toast.remove();
109
+ }, 3000);
110
+ }
111
+
112
+ // Load featured products
113
+ document.addEventListener('DOMContentLoaded', () => {
114
+ const featuredContainer = document.getElementById('featured-products');
115
+
116
+ if (featuredContainer) {
117
+ const products = [
118
+ {
119
+ id: 1,
120
+ name: 'Wireless Headphones',
121
+ price: 99.99,
122
+ image: 'http://static.photos/technology/320x240/1',
123
+ description: 'Premium wireless headphones with noise cancellation'
124
+ },
125
+ {
126
+ id: 2,
127
+ name: 'Smart Watch',
128
+ price: 199.99,
129
+ image: 'http://static.photos/technology/320x240/2',
130
+ description: 'Track your fitness and stay connected'
131
+ },
132
+ {
133
+ id: 3,
134
+ name: 'Bluetooth Speaker',
135
+ price: 79.99,
136
+ image: 'http://static.photos/technology/320x240/3',
137
+ description: 'Portable speaker with crystal clear sound'
138
+ },
139
+ {
140
+ id: 4,
141
+ name: 'Wireless Charger',
142
+ price: 29.99,
143
+ image: 'http://static.photos/technology/320x240/4',
144
+ description: 'Fast charging for all Qi-enabled devices'
145
+ }
146
+ ];
147
+
148
+ products.forEach(product => {
149
+ const productCard = document.createElement('div');
150
+ productCard.className = 'product-card bg-white rounded-lg overflow-hidden shadow-md';
151
+ productCard.innerHTML = `
152
+ <img src="${product.image}" alt="${product.name}" class="w-full h-48 object-cover">
153
+ <div class="p-4">
154
+ <h3 class="font-semibold text-lg mb-1">${product.name}</h3>
155
+ <p class="text-gray-600 text-sm mb-2">${product.description}</p>
156
+ <div class="flex justify-between items-center mt-4">
157
+ <span class="font-bold text-primary">$${product.price.toFixed(2)}</span>
158
+ <button onclick="cart.addToCart(${JSON.stringify(product).replace(/"/g, '&quot;')})"
159
+ class="bg-primary text-white px-4 py-2 rounded hover:bg-primary-600 transition">
160
+ Add to Cart
161
+ </button>
162
+ </div>
163
+ </div>
164
+ `;
165
+ featuredContainer.appendChild(productCard);
166
+ });
167
+ }
168
+
169
+ updateCartCount();
170
+ });
style.css CHANGED
@@ -1,28 +1,39 @@
 
 
1
  body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
 
 
 
 
 
 
 
 
 
28
  }
 
 
 
 
 
 
1
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
2
+
3
  body {
4
+ font-family: 'Inter', sans-serif;
5
+ min-height: 100vh;
6
+ display: flex;
7
+ flex-direction: column;
8
  }
9
 
10
+ main {
11
+ flex: 1;
 
12
  }
13
 
14
+ .product-card {
15
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
 
 
 
16
  }
17
 
18
+ .product-card:hover {
19
+ transform: translateY(-5px);
20
+ box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
 
 
 
21
  }
22
 
23
+ /* Toast notification styles */
24
+ .toast {
25
+ position: fixed;
26
+ bottom: 20px;
27
+ right: 20px;
28
+ background: #4CAF50;
29
+ color: white;
30
+ padding: 16px;
31
+ border-radius: 8px;
32
+ z-index: 1000;
33
+ animation: slideIn 0.5s forwards;
34
  }
35
+
36
+ @keyframes slideIn {
37
+ from { transform: translateX(100%); }
38
+ to { transform: translateX(0); }
39
+ }