├── src ├── App.css ├── index.css ├── main.jsx ├── components │ ├── Footer.jsx │ ├── NotFound.jsx │ ├── ProductGrid.jsx │ ├── Banner.jsx │ ├── Header.jsx │ ├── ProductCard.jsx │ ├── AboutUs.jsx │ └── ProductDetails.jsx ├── pages │ ├── Products.jsx │ ├── About.tsx │ └── Home.jsx ├── App.jsx └── data.js ├── postcss.config.js ├── vite.config.js ├── .hintrc ├── tailwind.config.js ├── .gitignore ├── index.html ├── README.md ├── package.json ├── eslint.config.js └── public └── vite.svg /src/App.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /.hintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "development" 4 | ], 5 | "hints": { 6 | "axe/language": [ 7 | "default", 8 | { 9 | "html-has-lang": "off" 10 | } 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from "react"; 2 | import { createRoot } from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | import "./index.css"; 5 | 6 | createRoot(document.getElementById("root")).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /src/components/Footer.jsx: -------------------------------------------------------------------------------- 1 | const Footer = () => { 2 | return ( 3 |
4 |

Copyright © 2024 Xbeauty Store

5 |

Powered by Xbeauty Store

6 |
7 | ); 8 | }; 9 | 10 | export default Footer; 11 | -------------------------------------------------------------------------------- /src/pages/Products.jsx: -------------------------------------------------------------------------------- 1 | import Footer from "../components/Footer"; 2 | import Header from "../components/Header"; 3 | import ProductListing from "../components/ProductGrid"; 4 | 5 | const Products = () => { 6 | return ( 7 |
8 |
9 | 10 |
12 | ); 13 | }; 14 | 15 | export default Products; 16 | -------------------------------------------------------------------------------- /src/pages/About.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Header from "../components/Header"; 3 | import Footer from "../components/Footer"; 4 | import AboutUs from "../components/AboutUs"; 5 | 6 | const About = () => { 7 | return ( 8 |
9 |
10 | 11 |
13 | ); 14 | }; 15 | 16 | export default About; 17 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Xbeauty Store 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/pages/Home.jsx: -------------------------------------------------------------------------------- 1 | import Banner from "../components/Banner"; 2 | import Footer from "../components/Footer"; 3 | import Header from "../components/Header"; 4 | import ProductListing from "../components/ProductGrid"; 5 | 6 | const Home = () => { 7 | return ( 8 |
9 |
10 | 11 | 12 | 13 |
15 | ); 16 | }; 17 | 18 | export default Home; 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | -------------------------------------------------------------------------------- /src/components/NotFound.jsx: -------------------------------------------------------------------------------- 1 | const NotFound = () => { 2 | return ( 3 |
4 |
5 |

404

6 |

Page Not Found

7 |

8 | Sorry, the page you are looking for does not exist. 9 |

10 | 14 | Go to Home 15 | 16 |
17 |
18 | ); 19 | }; 20 | 21 | export default NotFound; 22 | -------------------------------------------------------------------------------- /src/components/ProductGrid.jsx: -------------------------------------------------------------------------------- 1 | import products from "../data"; // Assuming product data is stored separately. 2 | import ProductCard from "./ProductCard"; 3 | 4 | const ProductListing = () => { 5 | return ( 6 |
7 |

8 | Our Products 9 |

10 |
11 |
12 | {products.map((product) => ( 13 | 14 | ))} 15 |
16 |
17 |
18 | ); 19 | }; 20 | 21 | export default ProductListing; 22 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import { BrowserRouter as Router, Route, Routes } from "react-router-dom"; 2 | 3 | import ProductDetails from "./components/ProductDetails"; 4 | import Home from "./pages/Home"; 5 | import NotFound from "./components/NotFound"; 6 | import About from "./pages/About"; 7 | import Products from "./pages/Products"; 8 | 9 | function App() { 10 | return ( 11 | 12 | 13 | } /> 14 | } /> 15 | } /> 16 | } /> 17 | } /> 18 | 19 | 20 | ); 21 | } 22 | 23 | export default App; 24 | -------------------------------------------------------------------------------- /src/components/Banner.jsx: -------------------------------------------------------------------------------- 1 | const Banner = () => { 2 | return ( 3 |
4 |
5 |
6 |

7 | Welcome to Our Store! 8 | 9 | {" "} 10 | Find the best products here 11 | 12 |

13 | 14 |

15 | We have a wide range of Heater products for you to choose from. 16 |

17 |
18 |
19 |
20 | ); 21 | }; 22 | 23 | export default Banner; 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "amazon", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.3.1", 14 | "react-dom": "^18.3.1", 15 | "react-router-dom": "^6.27.0" 16 | }, 17 | "devDependencies": { 18 | "@eslint/js": "^9.11.1", 19 | "@types/react": "^18.3.10", 20 | "@types/react-dom": "^18.3.0", 21 | "@vitejs/plugin-react": "^4.3.2", 22 | "autoprefixer": "^10.4.20", 23 | "eslint": "^9.11.1", 24 | "eslint-plugin-react": "^7.37.0", 25 | "eslint-plugin-react-hooks": "^5.1.0-rc.0", 26 | "eslint-plugin-react-refresh": "^0.4.12", 27 | "globals": "^15.9.0", 28 | "postcss": "^8.4.47", 29 | "tailwindcss": "^3.4.14", 30 | "vite": "^5.4.8" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/components/Header.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | const Header = () => { 4 | return ( 5 |
6 |
7 |

8 | Xbeauty 9 |

10 |
11 | 25 |
26 |
27 |
28 | ); 29 | }; 30 | 31 | export default Header; 32 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js' 2 | import globals from 'globals' 3 | import react from 'eslint-plugin-react' 4 | import reactHooks from 'eslint-plugin-react-hooks' 5 | import reactRefresh from 'eslint-plugin-react-refresh' 6 | 7 | export default [ 8 | { ignores: ['dist'] }, 9 | { 10 | files: ['**/*.{js,jsx}'], 11 | languageOptions: { 12 | ecmaVersion: 2020, 13 | globals: globals.browser, 14 | parserOptions: { 15 | ecmaVersion: 'latest', 16 | ecmaFeatures: { jsx: true }, 17 | sourceType: 'module', 18 | }, 19 | }, 20 | settings: { react: { version: '18.3' } }, 21 | plugins: { 22 | react, 23 | 'react-hooks': reactHooks, 24 | 'react-refresh': reactRefresh, 25 | }, 26 | rules: { 27 | ...js.configs.recommended.rules, 28 | ...react.configs.recommended.rules, 29 | ...react.configs['jsx-runtime'].rules, 30 | ...reactHooks.configs.recommended.rules, 31 | 'react/jsx-no-target-blank': 'off', 32 | 'react-refresh/only-export-components': [ 33 | 'warn', 34 | { allowConstantExport: true }, 35 | ], 36 | }, 37 | }, 38 | ] 39 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ProductCard.jsx: -------------------------------------------------------------------------------- 1 | import { useNavigate } from "react-router-dom"; 2 | 3 | /* eslint-disable react/prop-types */ 4 | const ProductCard = ({ product }) => { 5 | const navigate = useNavigate(); 6 | const imageSrc = product.Images?.[0]; 7 | 8 | const title = product.Title.slice(0, 48) + "..."; 9 | const handleClick = () => { 10 | navigate(`/product/${product.id}`); // Navigate to product details page 11 | }; 12 | 13 | return ( 14 |
18 |
19 | {product.Title} 24 |
25 |
26 |

{title}

27 |
28 |
29 |

Color :

30 |

{product.Color}

31 |
32 |
33 |

Price:

34 |

{product.Price}

35 |
36 |
37 |
38 |
39 | ); 40 | }; 41 | 42 | export default ProductCard; 43 | -------------------------------------------------------------------------------- /src/components/AboutUs.jsx: -------------------------------------------------------------------------------- 1 | // src/components/AboutUs.js 2 | import React from "react"; 3 | 4 | const AboutUs = () => { 5 | return ( 6 |
7 |
8 |

9 | About Us 10 |

11 |
12 |
13 |

14 | Flame Speed & Brightness Adjustments 15 |

16 |

17 | Our electric fireplace allows you to adjust the flame's speed and 18 | brightness to match your mood. The flame effects can function 19 | independently of the heater, giving you the perfect ambiance 20 | without additional heat. Choose from four vibrant flame colors and 21 | use the dimmer to set the ideal brightness. 22 |

23 |
24 | 25 |
26 |

27 | Safe & Overheat Protection 28 |

29 |

30 | Safety is our top priority. The built-in overheat protection 31 | system ensures the heater automatically shuts off when critical 32 | temperatures are reached. Designed with a bottom air outlet, it 33 | effectively prevents overheating and potential harm. 34 |

35 |
36 | 37 |
38 |

39 | Two-Stage Temperature Control 40 |

41 |

42 | Our heater features two temperature settings: 500W and 1500W. 43 | Additionally, the built-in timer lets you control when the heater 44 | operates, helping you save energy and enjoy a warm room upon 45 | arrival. 46 |

47 |
48 | 49 |
50 |

51 | Graceful Infrared Heating Design 52 |

53 |

54 | Designed with elegance and portability in mind, this fireplace 55 | features a classic retro style with a sturdy build. Special 56 | lightweight materials ensure easy mobility, making it suitable for 57 | various settings such as offices, restaurants, or homes. 58 |

59 |
60 | 61 |
62 |

63 | Realistic & Bright Flame Effect 64 |

65 |

66 | Our advanced technology creates a flame effect that surpasses the 67 | aesthetics of real fire. Enjoy the ambiance of dancing flames and 68 | glowing logs without the risks associated with an open flame. The 69 | transparent glass design provides a stunning view from all angles. 70 |

71 |
72 | 73 |
74 |

75 | Warm & Comfortable Experience 76 |

77 |

78 | Using the latest infrared heating technology, our heater offers 79 | fast and efficient warmth. It covers areas between 400 to 500 80 | square feet, with a heating time of just 5 to 7 minutes. The 81 | bottom vents reduce operational noise, ensuring a peaceful 82 | environment with noise levels under 40dB. 83 |

84 |
85 |
86 |
87 |
88 | ); 89 | }; 90 | 91 | export default AboutUs; 92 | -------------------------------------------------------------------------------- /src/components/ProductDetails.jsx: -------------------------------------------------------------------------------- 1 | import { useParams } from "react-router-dom"; 2 | import products from "../data"; // Make sure this points to your products data file 3 | import { useEffect, useState, useRef } from "react"; 4 | import Header from "./Header"; 5 | import Footer from "./Footer"; 6 | import NotFound from "./NotFound"; 7 | 8 | const ProductDetails = () => { 9 | const { id } = useParams(); 10 | const [product, setProduct] = useState(null); 11 | const [mainImage, setMainImage] = useState(""); 12 | const [isZoomed, setIsZoomed] = useState(false); // Start with no zoom 13 | const [zoomPosition, setZoomPosition] = useState({ x: 0, y: 0 }); // Mouse position tracking 14 | const [productNotFound, setProductNotFound] = useState(false); 15 | 16 | const zoomRef = useRef(null); // Ref for the zoom container 17 | 18 | useEffect(() => { 19 | const foundProduct = products.find((p) => p.id === id); 20 | if (foundProduct) setMainImage(foundProduct.Images[0]); // Set initial main image 21 | if (foundProduct) { 22 | setProduct(foundProduct); 23 | setProductNotFound(false); // Reset the not found state if product is found 24 | } else { 25 | setProductNotFound(true); // Set not found state to true if product is not found 26 | } 27 | }, [id]); 28 | 29 | if (productNotFound) return ; 30 | if (!product) 31 | return ( 32 |

Loading ...

33 | ); 34 | 35 | const toggleZoom = () => { 36 | setIsZoomed((prev) => !prev); // Toggle zoom state 37 | }; 38 | 39 | const handleMouseMove = (e) => { 40 | if (!isZoomed) return; // Only track when zoom is active 41 | 42 | const { left, top, width, height } = 43 | zoomRef.current.getBoundingClientRect(); 44 | const x = ((e.clientX - left) / width) * 100; // Get mouse position as a percentage 45 | const y = ((e.clientY - top) / height) * 100; 46 | 47 | setZoomPosition({ x, y }); // Store the position as percentages 48 | }; 49 | 50 | const handleImageClick = (img) => setMainImage(img); // Update main image 51 | 52 | return ( 53 | <> 54 |
55 | 56 |
57 | {/* Left Side: Image Gallery */} 58 |
59 |
67 | {/* Main Image with Zoom Functionality */} 68 | {product.Title} 80 | 81 | {/* Zoom Icon (Only shown when not zoomed) */} 82 | {!isZoomed && ( 83 |
84 | 85 | 🔍 86 | 87 |
88 | )} 89 |
90 | 91 | {/* Thumbnails */} 92 |
93 | {product.Images.map((img, index) => ( 94 | {`${product.Title} handleImageClick(img)} 102 | /> 103 | ))} 104 |
105 |
106 | 107 | {/* Right Side: Product Details */} 108 |
109 |

{product.Title}

110 | {/* 1 */} 111 |
112 | Color: 113 | {product.Color} 114 |
115 | 116 | {/* 2 */} 117 |
118 | Brand: 119 | {product.Brand} 120 |
121 | {/* 3 */} 122 |
123 | PowerSource: 124 | 125 | {product.PowerSource} 126 | 127 |
128 | {/* 4*/} 129 |
130 | 131 | {" "} 132 | ProductDimensions: 133 | 134 | 135 | {product.ProductDimensions} 136 | 137 |
138 | {/* 5*/} 139 |
140 | Material: 141 | 142 | {product.Material} 143 | 144 |
145 | {/* 6*/} 146 |
147 | FinishType: 148 | 149 | {product.FinishType} 150 | 151 |
152 | {/* 7*/} 153 |
154 | InstallationType: 155 | 156 | {product.InstallationType} 157 | 158 |
159 | {/* 8*/} 160 |
161 | Heat_Output: 162 | 163 | {product.Heat_Output} 164 | 165 |
166 | {/* 9*/} 167 |
168 | Special_Feature: 169 | 170 | {product.Special_Feature} 171 | 172 |
173 | {/* 10*/} 174 |
175 | Style: 176 | {product.Style} 177 |
178 | {/* 11*/} 179 |
180 | Room_Type: 181 | 182 | {product.Room_Type} 183 | 184 |
185 | {/* 9*/} 186 |
187 | Ventilation_Type: 188 | 189 | {product.Ventilation_Type} 190 | 191 |
192 |
193 |
194 | 195 | {/* Additional Details Section */} 196 |
197 |

Product Details

198 | {product.detail.map((paragraph, index) => ( 199 |

200 | .{paragraph} 201 |

202 | ))} 203 |
204 | 205 |