diff --git a/.gitignore b/.gitignore
index 4d29575..e9f1cd7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,22 +2,22 @@
# dependencies
/node_modules
-/.pnp
-.pnp.js
+# /.pnp
+# .pnp.js
# testing
-/coverage
+# /coverage
# production
-/build
+# /build
# misc
-.DS_Store
-.env.local
-.env.development.local
-.env.test.local
-.env.production.local
+# .DS_Store
+# .env.local
+# .env.development.local
+# .env.test.local
+# .env.production.local
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
+# npm-debug.log*
+# yarn-debug.log*
+# yarn-error.log*
diff --git a/src/App.css b/src/App.css
index 74b5e05..b036241 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,38 +1,11 @@
-.App {
- text-align: center;
+body {
+ width: 100%;
+ height: 100%;
+ background-color: rgb(44, 44, 44);
}
-.App-logo {
- height: 40vmin;
- pointer-events: none;
-}
-
-@media (prefers-reduced-motion: no-preference) {
- .App-logo {
- animation: App-logo-spin infinite 20s linear;
- }
-}
-
-.App-header {
- background-color: #282c34;
- min-height: 100vh;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- font-size: calc(10px + 2vmin);
- color: white;
-}
-
-.App-link {
- color: #61dafb;
-}
-
-@keyframes App-logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
+#root {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+}
\ No newline at end of file
diff --git a/src/App.js b/src/App.js
deleted file mode 100644
index 3784575..0000000
--- a/src/App.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import logo from './logo.svg';
-import './App.css';
-
-function App() {
- return (
-
- );
-}
-
-export default App;
diff --git a/src/App.jsx b/src/App.jsx
new file mode 100644
index 0000000..4522f66
--- /dev/null
+++ b/src/App.jsx
@@ -0,0 +1,8 @@
+import './App.css';
+import { MainPage } from './pages/Home.jsx';
+
+export default function App() {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/src/App.test.js b/src/App.test.js
deleted file mode 100644
index 1f03afe..0000000
--- a/src/App.test.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { render, screen } from '@testing-library/react';
-import App from './App';
-
-test('renders learn react link', () => {
- render();
- const linkElement = screen.getByText(/learn react/i);
- expect(linkElement).toBeInTheDocument();
-});
diff --git a/src/components/Client/Client.css b/src/components/Client/Client.css
new file mode 100644
index 0000000..88ef6e3
--- /dev/null
+++ b/src/components/Client/Client.css
@@ -0,0 +1,104 @@
+.acc-icon {
+ border-radius: 30px;
+ background-image: 'client_icon.svg';
+}
+
+.circle {
+ width: 40px;
+ height: 40px;
+ border: 2px solid none;
+ border-radius: 50%;
+ background: #e1e1e1;
+ display: flex;
+}
+
+.circle svg {
+ margin: auto;
+}
+
+.device {
+ height: 90px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ background-color: #333;
+ color: white;
+ padding: 10px;
+ border-top: rgb(94, 93, 93) 1px solid;
+ flex-wrap: wrap;
+}
+
+.device .info {
+ width: 270px;
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+}
+
+.device .avatar {
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ margin-right: 10px;
+}
+
+.device .ip {
+ color: #959393;
+ font-size: 0.9rem;
+}
+
+.device .details .name {
+ font-weight: bold;
+}
+
+.info .lst-time {
+ font-size: 0.8rem;
+ color: #959393;
+ align-self: self-end;
+}
+
+.device .data {
+ display: flex;
+ align-items: center;
+}
+
+.device .data div {
+ display: flex;
+ flex-direction: column;
+ margin: 0 10px;
+}
+
+.data .total {
+ color: #959393;
+ font-size: 0.8rem;
+}
+
+.device .controls {
+ display: flex;
+ align-items: center;
+}
+
+.device .controls button {
+ background: none;
+ border: none;
+ width: 45px;
+ height: 45px;
+ cursor: pointer;
+ padding: 5px 10px;
+ margin: 0 10px;
+ background-color: rgb(94, 93, 93);
+ border-radius: 30%;
+}
+
+.device .controls button:hover {
+ background-color: #830202;
+}
+
+.device .toggle.red {
+ background-color: red;
+ border-radius: 50%;
+}
+
+.controls button svg {
+ margin: auto;
+}
\ No newline at end of file
diff --git a/src/components/Client/Client.jsx b/src/components/Client/Client.jsx
new file mode 100644
index 0000000..d7d0aba
--- /dev/null
+++ b/src/components/Client/Client.jsx
@@ -0,0 +1,88 @@
+import React from "react"
+import './Client.css'
+import './checkbox.css'
+import TrafficFormatter from "../DataFormatter/TrafficFormatter"
+import TimeFormatter from "../DataFormatter/TimeFormatter"
+
+export default function Client({deviceName, ip, lastConnect, uploadSpeed, downloadSpeed, downloadTraffic, uploadTraffic}) {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ {/* */}
+ {/*
*/}
+ >
+ )
+}
\ No newline at end of file
diff --git a/src/components/Client/checkbox.css b/src/components/Client/checkbox.css
new file mode 100644
index 0000000..5bd679c
--- /dev/null
+++ b/src/components/Client/checkbox.css
@@ -0,0 +1,61 @@
+.switch {
+ position: relative;
+ display: inline-block;
+ width: 60px;
+ height: 34px;
+}
+
+.switch input {
+ display: none;
+}
+
+.slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #ccc;
+ -webkit-transition: .4s;
+ transition: .4s;
+ border-radius: 34px;
+}
+
+.slider:before {
+ position: absolute;
+ content: "";
+ height: 26px;
+ width: 26px;
+ left: 4px;
+ bottom: 4px;
+ background-color: white;
+ -webkit-transition: .4s;
+ transition: .4s;
+ border-radius: 50%;
+}
+
+input:checked+.slider {
+ background-color: #830202;
+}
+
+input:focus+.slider {
+ box-shadow: 0 0 1px #830202;
+}
+
+input:checked+.slider:before {
+ -webkit-transform: translateX(26px);
+ -ms-transform: translateX(26px);
+ transform: translateX(26px);
+}
+
+
+/* Rounded sliders */
+
+.slider.round {
+ border-radius: 34px;
+}
+
+.slider.round:before {
+ border-radius: 50%;
+}
\ No newline at end of file
diff --git a/src/components/ClientList/ClientList.css b/src/components/ClientList/ClientList.css
new file mode 100644
index 0000000..292b6a9
--- /dev/null
+++ b/src/components/ClientList/ClientList.css
@@ -0,0 +1,28 @@
+#clients {
+ border-radius: 5px;
+ background-color: #333;
+ color: white;
+}
+
+#clients-header {
+ padding: 10px 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+#new-device {
+ color: white;
+ background: none;
+ border: 1px solid rgb(94, 93, 93);
+ cursor: pointer;
+ padding: 10px 15px;
+ margin: 0 10px;
+ background-color: #333;
+ border-radius: 5px;
+}
+
+#new-device:hover {
+ background-color: #830202;
+ border: #830202;
+}
\ No newline at end of file
diff --git a/src/components/ClientList/ClientList.jsx b/src/components/ClientList/ClientList.jsx
new file mode 100644
index 0000000..a597d06
--- /dev/null
+++ b/src/components/ClientList/ClientList.jsx
@@ -0,0 +1,17 @@
+import React from "react";
+import Client from "../Client/Client";
+import clientsData from '../../data/clients.json'
+import './ClientList.css'
+
+export default function ClientsList() {
+ return
+
+ {clientsData.map(client => (
+
+ ))}
+
+}
\ No newline at end of file
diff --git a/src/components/DataFormatter/TimeFormatter.jsx b/src/components/DataFormatter/TimeFormatter.jsx
new file mode 100644
index 0000000..4c72e28
--- /dev/null
+++ b/src/components/DataFormatter/TimeFormatter.jsx
@@ -0,0 +1,43 @@
+import React from "react";
+
+// отвечает за преобразование поступающего в секундах значения в минуты, часы, дни
+export default function TimeFormatter ( {seconds, withAgo = true }) {
+ if (seconds === undefined || seconds === null) return null;
+
+ const formatTime = (sec) => {
+ const timeUnits = [
+ { limit: 60, unit: 'сек' },
+ { limit: 3600, unit: 'мин' }, // 60*60
+ { limit: 86400, unit: 'ч' }, // 60*60*24
+ { limit: Infinity, unit: 'д' }
+ ];
+
+ for (const { limit, unit } of timeUnits) {
+ if (sec < limit) {
+ const value = unit == 'д'
+ ? Math.floor(sec / 86400)
+ : unit === 'ч'
+ ? Math.floor(sec / 3600)
+ : unit === 'мин'
+ ? Math.floor(sec / 60)
+ : sec;
+
+ return {value, unit};
+ }
+ }
+
+ return {value: sec, unit: 'сек'};
+ };
+
+ const {value, unit} = formatTime(seconds)
+
+ if (value === 0 && unit === 'сек') {
+ return только что
+ }
+
+ return (
+
+ {value} {unit}{withAgo && ' назад'}
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/DataFormatter/TrafficFormatter.jsx b/src/components/DataFormatter/TrafficFormatter.jsx
new file mode 100644
index 0000000..abc33c7
--- /dev/null
+++ b/src/components/DataFormatter/TrafficFormatter.jsx
@@ -0,0 +1,22 @@
+import React from "react";
+
+// отвечает за преобразование поступающего в байтах значения в КБ, МБ, ГБ
+export default function TrafficFormatter ({ bytes, precision = 2}) {
+ if (bytes === undefined || bytes === null) return null;
+
+ const units = ['Б', 'КБ', 'МБ', 'ГБ'];
+
+ let value = bytes;
+ let unitIndex = 0;
+
+ while (value >= 1024 && unitIndex < units.length - 1) {
+ value /= 1024;
+ unitIndex += 1;
+ }
+
+ return (
+
+ {value.toFixed(precision)} {units[unitIndex]}
+
+ )
+}
\ No newline at end of file
diff --git a/src/data/clients.json b/src/data/clients.json
new file mode 100644
index 0000000..a7d8e18
--- /dev/null
+++ b/src/data/clients.json
@@ -0,0 +1,9 @@
+[{
+ "deviceName": "homePC",
+ "ip": "10.8.0.3",
+ "lastConnect": 23260,
+ "uploadSpeed": 500,
+ "downloadSpeed": 12300,
+ "uploadTraffic": 120838,
+ "downloadTraffic": 3423534
+}]
\ No newline at end of file
diff --git a/src/logo.svg b/src/logo.svg
deleted file mode 100644
index 9dfc1c0..0000000
--- a/src/logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/pages/Home.css b/src/pages/Home.css
new file mode 100644
index 0000000..d8b9523
--- /dev/null
+++ b/src/pages/Home.css
@@ -0,0 +1,10 @@
+#main-container {
+ width: 60%;
+}
+
+#main-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ color: white;
+}
\ No newline at end of file
diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx
new file mode 100644
index 0000000..7145755
--- /dev/null
+++ b/src/pages/Home.jsx
@@ -0,0 +1,18 @@
+import React from "react";
+import Client from "../components/Client/Client";
+import ClientsList from "../components/ClientList/ClientList";
+import './Home.css'
+
+export function MainPage() {
+ return (
+ <>
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx
new file mode 100644
index 0000000..e69de29