+
+
+
-
-
-
-
-
-
- } />
- } />
- } />
- } />
-
+
- )
-}
+ );
+};
-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.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 (
-
-
-
-
-
-

-
-
-
-
-
{
- if(address) navigate('create-campaign')
- else connect()
- }}
- />
-
-
-
-

+
+
-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.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 ? (
-

- ) : (
-

- )}
-
-)
+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 (
-
-
-
-
+
+
Фильтры
-
-
- )
-}
+ );
+};
-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')
+);