From 8b589470ac84025760828639a3b5b1c7f0d6b57a Mon Sep 17 00:00:00 2001 From: User Date: Mon, 6 Jan 2025 16:29:54 +0300 Subject: [PATCH] frontend (navbar+sidebar) --- frontend/NodeJS/index.html | 21 ++- frontend/NodeJS/package-lock.json | 116 +++++++++++++- frontend/NodeJS/package.json | 4 +- frontend/NodeJS/src/App.jsx | 31 ++-- frontend/NodeJS/src/Header.css | 9 +- frontend/NodeJS/src/Header.jsx | 9 +- frontend/NodeJS/src/Home.css | 16 ++ frontend/NodeJS/src/Home.jsx | 23 +++ frontend/NodeJS/src/ProductPage.css | 64 -------- frontend/NodeJS/src/ProductPage.jsx | 52 ------- frontend/NodeJS/src/components/Navbar.css | 141 ++++++++++++++++++ frontend/NodeJS/src/components/Navbar.jsx | 136 ++++++----------- .../NodeJS/src/components/ProductCard.css | 33 ++++ .../NodeJS/src/components/ProductCard.jsx | 15 ++ frontend/NodeJS/src/components/Sidebar.css | 82 ++++++++++ frontend/NodeJS/src/components/Sidebar.jsx | 130 +++++++++++----- frontend/NodeJS/src/context/index.jsx | 101 ------------- frontend/NodeJS/src/main.jsx | 23 +-- 18 files changed, 596 insertions(+), 410 deletions(-) create mode 100644 frontend/NodeJS/src/Home.css create mode 100644 frontend/NodeJS/src/Home.jsx delete mode 100644 frontend/NodeJS/src/ProductPage.css delete mode 100644 frontend/NodeJS/src/ProductPage.jsx create mode 100644 frontend/NodeJS/src/components/Navbar.css create mode 100644 frontend/NodeJS/src/components/ProductCard.css create mode 100644 frontend/NodeJS/src/components/ProductCard.jsx create mode 100644 frontend/NodeJS/src/components/Sidebar.css delete mode 100644 frontend/NodeJS/src/context/index.jsx diff --git a/frontend/NodeJS/index.html b/frontend/NodeJS/index.html index 0c589ecc..5b6ffce8 100644 --- a/frontend/NodeJS/index.html +++ b/frontend/NodeJS/index.html @@ -1,13 +1,12 @@ - + - - - - - Vite + React - - -
- - + + + + Marketplace + + +
+ + diff --git a/frontend/NodeJS/package-lock.json b/frontend/NodeJS/package-lock.json index 8567683d..ae2b2491 100644 --- a/frontend/NodeJS/package-lock.json +++ b/frontend/NodeJS/package-lock.json @@ -9,8 +9,10 @@ "version": "0.0.0", "dependencies": { "@clerk/clerk-react": "^5.21.0", + "@coreui/react": "^5.4.1", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-router-dom": "^7.1.1" }, "devDependencies": { "@eslint/js": "^9.17.0", @@ -396,6 +398,36 @@ "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", "license": "MIT" }, + "node_modules/@coreui/coreui": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@coreui/coreui/-/coreui-5.2.0.tgz", + "integrity": "sha512-DZLWzPIZP3KTNgcaRXny/7lcQm0rDMrheu3VsWpgbln5rUuJwxdopwhTSnOryVyCwjlDbs3Z8ZfIzOeBXNC4GA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/coreui" + } + ], + "license": "MIT", + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/@coreui/react": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@coreui/react/-/react-5.4.1.tgz", + "integrity": "sha512-ycO1XEGWqxa1Yx+1FK9wieEKVxSP8tS9QwgmtyEifZ6ArA6AvG8C1rPBuVb3FNE1SXwSEc50+zmy62QfRLtG0Q==", + "license": "MIT", + "dependencies": { + "@coreui/coreui": "^5.2.0", + "@popperjs/core": "^2.11.8", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.24.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", @@ -1062,6 +1094,16 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.29.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.1.tgz", @@ -1373,6 +1415,12 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -1824,6 +1872,15 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3484,7 +3541,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3747,7 +3803,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -3801,8 +3856,7 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-refresh": { "version": "0.14.2", @@ -3814,6 +3868,46 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.1.tgz", + "integrity": "sha512-39sXJkftkKWRZ2oJtHhCxmoCrBCULr/HAH4IT5DHlgu/Q0FCPV0S4Lx+abjDTx/74xoZzNYDYbOZWlJjruyuDQ==", + "license": "MIT", + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.1.1.tgz", + "integrity": "sha512-vSrQHWlJ5DCfyrhgo0k6zViOe9ToK8uT5XGSmnuC2R3/g261IdIMpZVqfjD6vWSXdnf5Czs4VA/V60oVR6/jnA==", + "license": "MIT", + "dependencies": { + "react-router": "7.1.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -3988,6 +4082,12 @@ "semver": "bin/semver.js" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -4315,6 +4415,12 @@ "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", "license": "0BSD" }, + "node_modules/turbo-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==", + "license": "ISC" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/frontend/NodeJS/package.json b/frontend/NodeJS/package.json index dc24f9fc..ef01d4c0 100644 --- a/frontend/NodeJS/package.json +++ b/frontend/NodeJS/package.json @@ -11,8 +11,10 @@ }, "dependencies": { "@clerk/clerk-react": "^5.21.0", + "@coreui/react": "^5.4.1", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-router-dom": "^7.1.1" }, "devDependencies": { "@eslint/js": "^9.17.0", diff --git a/frontend/NodeJS/src/App.jsx b/frontend/NodeJS/src/App.jsx index f71b68ed..b0bf80b1 100644 --- a/frontend/NodeJS/src/App.jsx +++ b/frontend/NodeJS/src/App.jsx @@ -1,28 +1,19 @@ import React from 'react'; -import { Route, Routes } from 'react-router-dom'; - -import { Sidebar, Navbar } from './components'; -import { CampaignDetails, CreateCampaign, Home, Profile } from './pages'; +import Navbar from './components/Navbar'; +import Sidebar from './components/Sidebar'; +import Home from './Home'; +import './App.css'; const App = () => { return ( -
-
+
+ +
-
- -
- - - - } /> - } /> - } /> - } /> - +
- ) -} + ); +}; -export default App \ No newline at end of file +export default App; diff --git a/frontend/NodeJS/src/Header.css b/frontend/NodeJS/src/Header.css index a24316ec..5d55dc5a 100644 --- a/frontend/NodeJS/src/Header.css +++ b/frontend/NodeJS/src/Header.css @@ -1,26 +1,27 @@ /* Стили для Header */ .header { - background-color: #1e90ff; /* Голубой цвет фона */ + background-color: #da1eff; /* Голубой цвет фона */ color: #ffffff; /* Белый цвет текста */ display: flex; justify-content: space-between; align-items: center; - padding: 20px 40px; + padding: 20px 100px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .logo { font-size: 36px; font-weight: bold; + } .project-name { margin: 0; - font-family: 'Arial', sans-serif; + font-family: 'Calibri', sans-serif; } .nav { - font-family: 'Arial', sans-serif; + font-family: 'Calibri', sans-serif; } .nav-links { diff --git a/frontend/NodeJS/src/Header.jsx b/frontend/NodeJS/src/Header.jsx index 5f86e255..66d6592c 100644 --- a/frontend/NodeJS/src/Header.jsx +++ b/frontend/NodeJS/src/Header.jsx @@ -7,14 +7,7 @@ const Header = () => {

Eternos

- + ); }; diff --git a/frontend/NodeJS/src/Home.css b/frontend/NodeJS/src/Home.css new file mode 100644 index 00000000..ec0d5e93 --- /dev/null +++ b/frontend/NodeJS/src/Home.css @@ -0,0 +1,16 @@ +.home { + padding: 2rem; + } + + .home-title { + font-size: 2rem; + margin-bottom: 2rem; + text-align: center; + } + + .product-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: 1rem; + } + \ No newline at end of file diff --git a/frontend/NodeJS/src/Home.jsx b/frontend/NodeJS/src/Home.jsx new file mode 100644 index 00000000..d3d3b011 --- /dev/null +++ b/frontend/NodeJS/src/Home.jsx @@ -0,0 +1,23 @@ +import React from "react"; +import ProductCard from "./components/ProductCard"; + +const Home = () => { + const products = [ + { id: 1, name: "Product 1", price: 50, image: "https://via.placeholder.com/150" }, + { id: 2, name: "Product 2", price: 75, image: "https://via.placeholder.com/150" }, + { id: 3, name: "Product 3", price: 100, image: "https://via.placeholder.com/150" }, + ]; + + return ( +
+

Welcome to Eternos

+
+ {products.map((product) => ( + + ))} +
+
+ ); +}; + +export default Home; diff --git a/frontend/NodeJS/src/ProductPage.css b/frontend/NodeJS/src/ProductPage.css deleted file mode 100644 index 47b399f5..00000000 --- a/frontend/NodeJS/src/ProductPage.css +++ /dev/null @@ -1,64 +0,0 @@ -/* Основные стили страницы */ -.product-page { - background-color: #f0f8ff; /* Светлый голубой фон */ - font-family: Arial, sans-serif; - padding: 20px; - text-align: center; - } - - .page-title { - color: #1e90ff; /* Синий цвет для заголовка */ - font-size: 36px; - margin-bottom: 40px; - } - - /* Контейнер для карточек товаров */ - .products { - display: flex; - justify-content: space-around; - flex-wrap: wrap; - gap: 20px; - margin-top: 20px; - } - - /* Стили для каждой карточки товара */ - .product-card { - background-color: #ffffff; /* Белый фон карточки */ - border-radius: 8px; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); - padding: 20px; - width: 250px; - transition: transform 0.3s ease-in-out; - } - - .product-card:hover { - transform: scale(1.05); /* Эффект увеличения при наведении */ - } - - /* Стили для изображения товара */ - .product-image { - width: 100%; - height: 200px; - object-fit: cover; - border-radius: 8px; - } - - /* Стили для текста */ - .product-name { - font-size: 24px; - color: #1e90ff; - margin-top: 15px; - } - - .product-description { - font-size: 14px; - color: #555555; - margin: 10px 0; - } - - .product-price { - font-size: 18px; - color: #1e90ff; - font-weight: bold; - } - \ No newline at end of file diff --git a/frontend/NodeJS/src/ProductPage.jsx b/frontend/NodeJS/src/ProductPage.jsx deleted file mode 100644 index f89f0245..00000000 --- a/frontend/NodeJS/src/ProductPage.jsx +++ /dev/null @@ -1,52 +0,0 @@ -import React from "react"; -import Header from "./Header"; // Подключаем Header -import "./ProductPage.css"; - -const ProductPage = () => { - const products = [ - { - id: 1, - name: "Товар 1", - description: "Описание товара 1", - price: "1000 ₽", - imageUrl: "https://via.placeholder.com/200", // Замените на реальный URL изображения - }, - { - id: 2, - name: "Товар 2", - description: "Описание товара 2", - price: "1500 ₽", - imageUrl: "https://via.placeholder.com/200", // Замените на реальный URL изображения - }, - { - id: 3, - name: "Товар 3", - description: "Описание товара 3", - price: "2000 ₽", - imageUrl: "https://via.placeholder.com/200", // Замените на реальный URL изображения - }, - ]; - - return ( -
-
{/* Используем Header */} -

Наши товары

-
- {products.map((product) => ( -
- {product.name} -

{product.name}

-

{product.description}

-

{product.price}

-
- ))} -
-
- ); -}; - -export default ProductPage; diff --git a/frontend/NodeJS/src/components/Navbar.css b/frontend/NodeJS/src/components/Navbar.css new file mode 100644 index 00000000..716d4779 --- /dev/null +++ b/frontend/NodeJS/src/components/Navbar.css @@ -0,0 +1,141 @@ +.navbar { + font-family: Arial, sans-serif; + background-color: #f8f8f8; + border-bottom: 1px solid #ddd; +} + +.navbar-main { + display: flex; + align-items: center; + padding: 10px 20px; +} + +.logo img { + height: 30px; +} + +.catalog-button { + background-color: #0073e6; + color: white; + border: none; + padding: 5px 10px; + margin-left: 20px; + cursor: pointer; + border-radius: 5px; +} + +.search-bar { + display: flex; + flex-grow: 1; + margin-left: 20px; +} + +.search-bar select, +.search-bar input { + border-radius: 5px; padding: 5px; + border: 1px solid #ddd; +} + +.search-bar input { + border-radius: 5px; + flex-grow: 1; + margin-left: 5px; +} + +.search-button { + border-radius: 5px; + background-color: #0073e6; + color: white; + border: none; + padding: 5px 10px; + cursor: pointer; +} + +.personal-doc-button { + background-color: #0073e6; + color: white; + border: none; + padding: 5px 15px; + margin-left: 20px; + border-radius: 5px; + cursor: pointer; +} + +.navbar-bottom { + display: flex; + justify-content: space-around; + padding: 10px; + font-size: 14px; + background-color: #fff; +} + +.navbar-bottom a { + text-decoration: none; + color: #0073e6; +} + + + +/* Адаптация для мобильных устройств */ +@media (max-width: 768px) { + .navbar-main { + flex-direction: column; + align-items: flex-start; + padding: 10px; + } + + .logo { + margin-bottom: 10px; + } + + .catalog-button { + width: 100%; + text-align: center; + margin: 0; + margin-bottom: 10px; + } + + .search-bar { + width: 100%; + flex-direction: column; + } + + .search-bar select, + .search-bar input, + .search-button { + width: 100%; + margin: 5px 0; + } + + .personal-doc-button { + width: 100%; + margin: 10px 0; + } + + .navbar-bottom { + flex-wrap: wrap; + justify-content: flex-start; + } + + .navbar-bottom a { + margin: 5px; + font-size: 12px; + } +} + +/* Адаптация для очень маленьких экранов (например, телефоны) */ +@media (max-width: 480px) { + .navbar-main { + align-items: center; + } + + .search-bar select { + display: none; /* Убираем селектор "Везде" для упрощения */ + } + + .navbar-bottom a { + flex: 1 1 100%; /* Каждая ссылка занимает всю ширину */ + text-align: center; + } +} + diff --git a/frontend/NodeJS/src/components/Navbar.jsx b/frontend/NodeJS/src/components/Navbar.jsx index 6ea8cd1b..ca5e3e27 100644 --- a/frontend/NodeJS/src/components/Navbar.jsx +++ b/frontend/NodeJS/src/components/Navbar.jsx @@ -1,97 +1,57 @@ -import React, { useState } from 'react' -import { Link, useNavigate } from 'react-router-dom'; - -import { useStateContext } from '../context'; -import { CustomButton } from './'; -import { logo, menu, search, thirdweb } from '../assets'; -import { navlinks } from '../constants'; +import React, { useState } from "react"; +import "./Navbar.css"; +import Sidebar from "./Sidebar"; const Navbar = () => { - const navigate = useNavigate(); - const [isActive, setIsActive] = useState('dashboard'); - const [toggleDrawer, setToggleDrawer] = useState(false); - const { connect, address } = useStateContext(); + const [isSidebarVisible, setIsSidebarVisible] = useState(false); + const [searchQuery, setSearchQuery] = useState(""); + + const toggleSidebar = () => { + // Открывать Sidebar только если пользователь ввел текст + if (searchQuery.trim() !== "") { + setIsSidebarVisible(!isSidebarVisible); + } else { + alert("Пожалуйста, введите текст для поиска."); + } + }; + + const handleSearchChange = (e) => { + setSearchQuery(e.target.value); + }; return ( -
-
- - -
- search -
-
- -
- { - if(address) navigate('create-campaign') - else connect() - }} - /> - - -
- user +
+ -export default Navbar \ No newline at end of file + {isSidebarVisible && ( +
+ +
+ )} +
+ ); +}; + +export default Navbar; diff --git a/frontend/NodeJS/src/components/ProductCard.css b/frontend/NodeJS/src/components/ProductCard.css new file mode 100644 index 00000000..c92db03f --- /dev/null +++ b/frontend/NodeJS/src/components/ProductCard.css @@ -0,0 +1,33 @@ +.product-card { + border: 1px solid #d1d5db; + border-radius: 10px; + padding: 1rem; + text-align: center; + background-color: #ffffff; +} + +.product-image { + width: 100%; + height: 200px; + object-fit: cover; + border-radius: 5px; +} + +.product-title { + font-size: 1.2rem; + margin: 1rem 0; +} + +.product-price { + font-size: 1rem; + color: #4ade80; +} + +.add-to-cart-btn { + background-color: #1e3a8a; + color: white; + border: none; + padding: 0.5rem 1rem; + border-radius: 5px; + cursor: pointer; +} diff --git a/frontend/NodeJS/src/components/ProductCard.jsx b/frontend/NodeJS/src/components/ProductCard.jsx new file mode 100644 index 00000000..2c745523 --- /dev/null +++ b/frontend/NodeJS/src/components/ProductCard.jsx @@ -0,0 +1,15 @@ +import React from "react"; +import "./ProductCard.css"; + +const ProductCard = ({ product }) => { + return ( +
+ {product.name} +

{product.name}

+

${product.price}

+ +
+ ); +}; + +export default ProductCard; diff --git a/frontend/NodeJS/src/components/Sidebar.css b/frontend/NodeJS/src/components/Sidebar.css new file mode 100644 index 00000000..41980835 --- /dev/null +++ b/frontend/NodeJS/src/components/Sidebar.css @@ -0,0 +1,82 @@ +.sidebar { + width: 300px; + background-color: #ffffff; + padding: 20px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + border-radius: 0; + font-family: Arial, sans-serif; +} + +.sidebar h2 { + font-size: 1.5rem; + margin-bottom: 20px; +} + +.filter-section { + margin-bottom: 20px; +} + +.filter-section h3 { + font-size: 1.2rem; + margin-bottom: 10px; +} + +.price-inputs input { + width: 45%; + padding: 5px; + margin-right: 10px; + border: 1px solid #ccc; + border-radius: 5px; +} + +.price-categories label, +.filter-section label { + display: block; + margin-bottom: 5px; + font-size: 1rem; +} + +label.switch { + position: relative; + display: inline-block; + width: 40px; + height: 20px; +} + +label.switch input { + opacity: 0; + width: 0; + height: 0; +} + +label.switch .slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + border-radius: 34px; + transition: 0.4s; +} + +label.switch .slider:before { + position: absolute; + content: ""; + height: 14px; + width: 14px; + left: 3px; + bottom: 3px; + background-color: white; + border-radius: 50%; + transition: 0.4s; +} + +label.switch input:checked + .slider { + background-color: #0073e6; +} + +label.switch input:checked + .slider:before { + transform: translateX(20px); +} diff --git a/frontend/NodeJS/src/components/Sidebar.jsx b/frontend/NodeJS/src/components/Sidebar.jsx index 40bb9d38..810ab3b0 100644 --- a/frontend/NodeJS/src/components/Sidebar.jsx +++ b/frontend/NodeJS/src/components/Sidebar.jsx @@ -1,50 +1,100 @@ -import React, { useState } from 'react'; -import { Link, useNavigate } from 'react-router-dom'; - -import { logo, sun } from '../assets'; -import { navlinks } from '../constants'; - -const Icon = ({ styles, name, imgUrl, isActive, disabled, handleClick }) => ( -
- {!isActive ? ( - fund_logo - ) : ( - fund_logo - )} -
-) +import React, { useState } from "react"; +import "./Sidebar.css"; const Sidebar = () => { - const navigate = useNavigate(); - const [isActive, setIsActive] = useState('dashboard'); + const [priceRange, setPriceRange] = useState({ min: 0, max: 25000 }); + const [selectedPriceCategory, setSelectedPriceCategory] = useState("any"); + const [isOriginal, setIsOriginal] = useState(false); + const [teaSort, setTeaSort] = useState(""); + + const handlePriceRangeChange = (e) => { + const { name, value } = e.target; + setPriceRange((prev) => ({ + ...prev, + [name]: value, + })); + }; return ( -
- - - +
+

Фильтры

-
-
- {navlinks.map((link) => ( - { - if(!link.disabled) { - setIsActive(link.name); - navigate(link.link); - } - }} - /> - ))} +
+

Рассрочка 0-0-6

+ +
+ +
+

Цена

+
+ +
+
+ {["до 500 ₽", "500–1 000 ₽", "1 000–2 000 ₽", "2 000 ₽ и дороже", "Неважно"].map( + (category, index) => ( + + ) + )} +
+
- +
+

Оригинальный товар

+ +
+ +
+

Сорт чая

+ {["Матча", "Сенча", "Улун", "Черный чай"].map((sort) => ( + + ))}
- ) -} + ); +}; -export default Sidebar \ No newline at end of file +export default Sidebar; diff --git a/frontend/NodeJS/src/context/index.jsx b/frontend/NodeJS/src/context/index.jsx deleted file mode 100644 index cbd5c0e0..00000000 --- a/frontend/NodeJS/src/context/index.jsx +++ /dev/null @@ -1,101 +0,0 @@ -import React, { useContext, createContext } from 'react'; - -import { useAddress, useContract, useMetamask, useContractWrite } from '@thirdweb-dev/react'; -import { ethers } from 'ethers'; -import { EditionMetadataWithOwnerOutputSchema } from '@thirdweb-dev/sdk'; - -const StateContext = createContext(); - -export const StateContextProvider = ({ children }) => { - const { contract } = useContract('0xf59A1f8251864e1c5a6bD64020e3569be27e6AA9'); - const { mutateAsync: createCampaign } = useContractWrite(contract, 'createCampaign'); - - const address = useAddress(); - const connect = useMetamask(); - - const publishCampaign = async (form) => { - try { - const data = await createCampaign({ - args: [ - address, // owner - form.title, // title - form.description, // description - form.target, - new Date(form.deadline).getTime(), // deadline, - form.image, - ], - }); - - console.log("contract call success", data) - } catch (error) { - console.log("contract call failure", error) - } - } - - const getCampaigns = async () => { - const campaigns = await contract.call('getCampaigns'); - - const parsedCampaings = campaigns.map((campaign, i) => ({ - owner: campaign.owner, - title: campaign.title, - description: campaign.description, - target: ethers.utils.formatEther(campaign.target.toString()), - deadline: campaign.deadline.toNumber(), - amountCollected: ethers.utils.formatEther(campaign.amountCollected.toString()), - image: campaign.image, - pId: i - })); - - return parsedCampaings; - } - - const getUserCampaigns = async () => { - const allCampaigns = await getCampaigns(); - - const filteredCampaigns = allCampaigns.filter((campaign) => campaign.owner === address); - - return filteredCampaigns; - } - - const donate = async (pId, amount) => { - const data = await contract.call('donateToCampaign', [pId], { value: ethers.utils.parseEther(amount)}); - - return data; - } - - const getDonations = async (pId) => { - const donations = await contract.call('getDonators', [pId]); - const numberOfDonations = donations[0].length; - - const parsedDonations = []; - - for(let i = 0; i < numberOfDonations; i++) { - parsedDonations.push({ - donator: donations[0][i], - donation: ethers.utils.formatEther(donations[1][i].toString()) - }) - } - - return parsedDonations; - } - - - return ( - - {children} - - ) -} - -export const useStateContext = () => useContext(StateContext); \ No newline at end of file diff --git a/frontend/NodeJS/src/main.jsx b/frontend/NodeJS/src/main.jsx index 2dffd2f5..d2cff4ac 100644 --- a/frontend/NodeJS/src/main.jsx +++ b/frontend/NodeJS/src/main.jsx @@ -1,20 +1,11 @@ import React from 'react'; -import ReactDOM from 'react-dom/client'; -import { BrowserRouter as Router } from 'react-router-dom'; -import { ChainId, ThirdwebProvider } from '@thirdweb-dev/react'; - -import { StateContextProvider } from './context'; +import ReactDOM from 'react-dom'; import App from './App'; import './index.css'; -const root = ReactDOM.createRoot(document.getElementById('root')); - -root.render( - - - - - - - -) \ No newline at end of file +ReactDOM.render( + + + , + document.getElementById('root') +);