diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 3e212e1..d5a5d48 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -2,20 +2,21 @@ module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
- 'eslint:recommended',
- 'plugin:react/recommended',
- 'plugin:react/jsx-runtime',
- 'plugin:react-hooks/recommended',
+ "eslint:recommended",
+ "plugin:react/recommended",
+ "plugin:react/jsx-runtime",
+ "plugin:react-hooks/recommended",
],
- ignorePatterns: ['dist', '.eslintrc.cjs'],
- parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
- settings: { react: { version: '18.2' } },
- plugins: ['react-refresh'],
+ ignorePatterns: ["dist", ".eslintrc.cjs"],
+ parserOptions: { ecmaVersion: "latest", sourceType: "module" },
+ settings: { react: { version: "18.2" } },
+ plugins: ["react-refresh"],
rules: {
- 'react/jsx-no-target-blank': 'off',
- 'react-refresh/only-export-components': [
- 'warn',
+ "react/prop-types": "off",
+ "react/jsx-no-target-blank": "off",
+ "react-refresh/only-export-components": [
+ "warn",
{ allowConstantExport: true },
],
},
-}
+};
diff --git a/package-lock.json b/package-lock.json
index b8b9273..54432a1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,7 +14,9 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^9.1.0",
- "styled-components": "^6.1.8"
+ "react-router-dom": "^6.22.3",
+ "styled-components": "^6.1.8",
+ "uid": "^2.0.2"
},
"devDependencies": {
"@types/react": "^18.2.66",
@@ -915,6 +917,14 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@lukeed/csprng": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz",
+ "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -973,6 +983,14 @@
}
}
},
+ "node_modules/@remix-run/router": {
+ "version": "1.15.3",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz",
+ "integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz",
@@ -3729,6 +3747,36 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "6.22.3",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz",
+ "integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==",
+ "dependencies": {
+ "@remix-run/router": "1.15.3"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "6.22.3",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz",
+ "integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==",
+ "dependencies": {
+ "@remix-run/router": "1.15.3",
+ "react-router": "6.22.3"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
"node_modules/redux": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
@@ -4329,6 +4377,17 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/uid": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz",
+ "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==",
+ "dependencies": {
+ "@lukeed/csprng": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/unbox-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
diff --git a/package.json b/package.json
index 640cb18..fca9547 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,9 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^9.1.0",
- "styled-components": "^6.1.8"
+ "react-router-dom": "^6.22.3",
+ "styled-components": "^6.1.8",
+ "uid": "^2.0.2"
},
"devDependencies": {
"@types/react": "^18.2.66",
diff --git a/src/App.css b/src/App.css
index b9d355d..e69de29 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,42 +0,0 @@
-#root {
- max-width: 1280px;
- margin: 0 auto;
- padding: 2rem;
- text-align: center;
-}
-
-.logo {
- height: 6em;
- padding: 1.5em;
- will-change: filter;
- transition: filter 300ms;
-}
-.logo:hover {
- filter: drop-shadow(0 0 2em #646cffaa);
-}
-.logo.react:hover {
- filter: drop-shadow(0 0 2em #61dafbaa);
-}
-
-@keyframes logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
-
-@media (prefers-reduced-motion: no-preference) {
- a:nth-of-type(2) .logo {
- animation: logo-spin infinite 20s linear;
- }
-}
-
-.card {
- padding: 2em;
-}
-
-.read-the-docs {
- color: #888;
-}
diff --git a/src/App.jsx b/src/App.jsx
index 6a9eeb6..2d32a20 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,42 +1,18 @@
-import { useEffect, useState } from "react";
-import reactLogo from "./assets/react.svg";
-import viteLogo from "/vite.svg";
-import "./App.css";
-import { useDispatch } from "react-redux";
-import { fetchCars } from "./redux/cars/operations";
-// import { selectCars } from "./redux/cars/carsSelectors";
+import { lazy } from "react";
+import { Route, Routes } from "react-router-dom";
+import { AppLayout } from "./components/AppLayout/AppLayout";
-function App() {
- const [count, setCount] = useState(0);
- const dispatch = useDispatch();
- // const cars = useSelector(selectCars);
- useEffect(() => {
- dispatch(fetchCars());
- }, [dispatch]);
+const HomePage = lazy(() => import("./pages/HomePage"));
+const NotFoundPage = lazy(() => import("./pages/NotFoundPage"));
+function App() {
return (
- <>
-
- Vite + React
-
-
-
- Edit src/App.jsx
and save to test HMR
-
-
-
- Click on the Vite and React logos to learn more
-
- >
+
+ }>
+ } />
+
+ } />
+
);
}
diff --git a/src/assets/sprite.svg b/src/assets/sprite.svg
new file mode 100644
index 0000000..cbbf64e
--- /dev/null
+++ b/src/assets/sprite.svg
@@ -0,0 +1,98 @@
+
diff --git a/src/components/AppLayout/AppLayout.jsx b/src/components/AppLayout/AppLayout.jsx
new file mode 100644
index 0000000..22b015a
--- /dev/null
+++ b/src/components/AppLayout/AppLayout.jsx
@@ -0,0 +1,23 @@
+import { Outlet } from "react-router-dom";
+import { Suspense, useEffect } from "react";
+import { GlobalStyle } from "../GlobalStyle";
+import { useDispatch } from "react-redux";
+import { fetchCars } from "../../redux/cars/operations";
+
+export const AppLayout = () => {
+ const dispatch = useDispatch();
+ useEffect(() => {
+ dispatch(fetchCars());
+ }, [dispatch]);
+
+ return (
+ <>
+
+ Loader}>
+
+
+
+
+ >
+ );
+};
diff --git a/src/components/AppLayout/AppLayout.styled.js b/src/components/AppLayout/AppLayout.styled.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/Car/Car.jsx b/src/components/Car/Car.jsx
new file mode 100644
index 0000000..05f9d61
--- /dev/null
+++ b/src/components/Car/Car.jsx
@@ -0,0 +1,30 @@
+import { uid } from "uid";
+import { Icon } from "../Icon/Icon";
+
+export const Car = ({ car }) => {
+ return (
+
+
+
+
+
{car.name}
+
€{car.price}.00
+
+
+
+
+ {car.rating} {car.reviews.length || 0} Reviews
+
+
{car.location}
+
+
{car.description}
+
+ {/* {Object.entries(car.details).map(([key, value]) => {
+
+ })} */}
+
+
+
+
+ );
+};
diff --git a/src/components/Car/Car.styled.js b/src/components/Car/Car.styled.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/CarModal/CarModal.jsx b/src/components/CarModal/CarModal.jsx
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/CarModal/CarModal.styled.js b/src/components/CarModal/CarModal.styled.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/CarsList/CarsList.jsx b/src/components/CarsList/CarsList.jsx
new file mode 100644
index 0000000..889f869
--- /dev/null
+++ b/src/components/CarsList/CarsList.jsx
@@ -0,0 +1,17 @@
+import { useSelector } from "react-redux";
+import { selectCars } from "../../redux/cars/carsSelectors";
+import { Car } from "../Car/Car";
+
+export const CarsList = () => {
+ const cars = useSelector(selectCars);
+ // console.log(cars);
+ return (
+
+
+ {cars.map((car) => {
+ return ;
+ })}
+
+
+ );
+};
diff --git a/src/components/CarsList/CarsList.styled.js b/src/components/CarsList/CarsList.styled.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/FilterButton/FilterButton.jsx b/src/components/FilterButton/FilterButton.jsx
new file mode 100644
index 0000000..cd9e851
--- /dev/null
+++ b/src/components/FilterButton/FilterButton.jsx
@@ -0,0 +1,14 @@
+import { Icon } from "../Icon/Icon";
+
+export const FilterButton = ({ id, iconType, text }) => {
+ return (
+
+ );
+};
diff --git a/src/components/FilterButton/FilterButton.styled.js b/src/components/FilterButton/FilterButton.styled.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/Filters/Filters.jsx b/src/components/Filters/Filters.jsx
new file mode 100644
index 0000000..6f8b099
--- /dev/null
+++ b/src/components/Filters/Filters.jsx
@@ -0,0 +1,48 @@
+import { FilterButton } from "../FilterButton/FilterButton";
+
+export const Filters = () => {
+ return (
+
+
+
Filters
+
+
Vehicle equipment
+
+
+
+
+
+
+
+
+
Vehicle type
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/components/Filters/Filters.styled.js b/src/components/Filters/Filters.styled.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/GlobalStyle.jsx b/src/components/GlobalStyle.jsx
new file mode 100644
index 0000000..0b03fab
--- /dev/null
+++ b/src/components/GlobalStyle.jsx
@@ -0,0 +1,88 @@
+import "modern-normalize";
+import { createGlobalStyle } from "styled-components";
+
+export const GlobalStyle = createGlobalStyle`
+ body {
+ margin: 0;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ font-family: "Inter", sans-serif;
+ }
+
+
+main {
+ min-height: calc(100vh - 688px - 54px);
+}
+
+h1,
+h2,
+h3,
+h4,
+p,
+ul,
+ol,
+li {
+ list-style: none;
+ margin-top: 0;
+ margin-bottom: 0;
+ padding: 0;
+}
+
+button {
+ margin: 0;
+ padding: 0;
+}
+
+p {
+ font-size: 14px;
+ line-height: 21px;
+ font-weight: 400;
+}
+
+img {
+ display: block;
+}
+
+.list {
+ list-style-type: none;
+}
+
+.link {
+ text-decoration: none;
+}
+
+a {
+ text-decoration: none;
+}
+
+img {
+ display: block;
+ max-width: 100%;
+}
+
+button {
+ cursor: pointer;
+ font-family: "Roboto", sans-serif;
+ font-size: 14px;
+ line-height: 21px;
+ font-weight: 400;
+}
+
+.is-hidden {
+ display: none;
+}
+
+.visually-hidden {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ margin: -1px;
+ border: 0;
+ padding: 0;
+
+ white-space: nowrap;
+ clip-path: inset(100%);
+ clip: rect(0 0 0 0);
+}
+
+`;
diff --git a/src/components/Icon/Icon.jsx b/src/components/Icon/Icon.jsx
new file mode 100644
index 0000000..b9a07ae
--- /dev/null
+++ b/src/components/Icon/Icon.jsx
@@ -0,0 +1,11 @@
+import sprite from "../../assets/sprite.svg";
+
+export const Icon = ({ styles, width, height, iconId }) => {
+ return (
+ <>
+
+ >
+ );
+};
diff --git a/src/components/Icon/Icon.styled.js b/src/components/Icon/Icon.styled.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/index.css b/src/index.css
index 6119ad9..c798e28 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,4 +1,4 @@
-:root {
+/* :root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
@@ -65,4 +65,4 @@ button:focus-visible {
button {
background-color: #f9f9f9;
}
-}
+} */
diff --git a/src/main.jsx b/src/main.jsx
index 5e9bd71..7c00c99 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -4,11 +4,18 @@ import App from "./App.jsx";
import "./index.css";
import { store } from "./redux/store.js";
import { Provider } from "react-redux";
+import { BrowserRouter } from "react-router-dom";
+import { ThemeProvider } from "styled-components";
+import { theme } from "./theme.js";
ReactDOM.createRoot(document.getElementById("root")).render(
-
-
-
+
+
+
+
+
+
+
);
diff --git a/src/pages/HomePage.jsx b/src/pages/HomePage.jsx
new file mode 100644
index 0000000..078f5be
--- /dev/null
+++ b/src/pages/HomePage.jsx
@@ -0,0 +1,11 @@
+import { CarsList } from "../components/CarsList/CarsList";
+import { Filters } from "../components/Filters/Filters";
+
+export default function HomePage() {
+ return (
+
+ );
+}
diff --git a/src/pages/NotFoundPage.jsx b/src/pages/NotFoundPage.jsx
new file mode 100644
index 0000000..e7fc050
--- /dev/null
+++ b/src/pages/NotFoundPage.jsx
@@ -0,0 +1,9 @@
+export default function NotFoundPage() {
+ return (
+
+ );
+}
diff --git a/src/theme.js b/src/theme.js
new file mode 100644
index 0000000..95cdb39
--- /dev/null
+++ b/src/theme.js
@@ -0,0 +1,17 @@
+export const theme = {
+ colors: {
+ dark: "#101828",
+ grey: "#475467",
+ red: "#E44848",
+ yellow: "#FFC531",
+ mainWhite: "#F2F4F7",
+ white: "#F7F7F7",
+ },
+ radius: {
+ sm: "4px",
+ md: "8px",
+ lg: "16px",
+ },
+};
+
+// ${p => p.theme.colors.white}