This commit is contained in:
2025-08-20 14:10:34 +03:00
commit 34b9672a36
23 changed files with 2633 additions and 0 deletions

24
.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

12
Dockerfile Normal file
View File

@@ -0,0 +1,12 @@
FROM node:22.18.0-alpine as build
WORKDIR /usr/app
COPY . /usr/app
RUN npm i
RUN npm run build
FROM nginx:1.23.1-alpine
RUN rm -rf /usr/share/nginx/html/*
COPY --from=build /usr/app/dist /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]

29
eslint.config.js Normal file
View File

@@ -0,0 +1,29 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import { defineConfig, globalIgnores } from 'eslint/config'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{js,jsx}'],
extends: [
js.configs.recommended,
reactHooks.configs['recommended-latest'],
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
rules: {
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
},
},
])

13
index.html Normal file
View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

2038
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

29
package.json Normal file
View File

@@ -0,0 +1,29 @@
{
"name": "portfolio",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-router-dom": "^7.8.1"
},
"devDependencies": {
"@eslint/js": "^9.33.0",
"@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7",
"@vitejs/plugin-react": "^5.0.1",
"eslint": "^9.33.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.3.0",
"sass": "^1.90.0",
"vite": "^7.1.3"
}
}

BIN
public/bsuir.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
public/server.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 KiB

78
src/About.jsx Normal file
View File

@@ -0,0 +1,78 @@
import "./About.scss";
export default function About() {
return (
<div class="about-main">
<article class="section">
<h3 class="section__title">Experiences</h3>
<br />
<h4>Finmarket Soft (2021 - Present)</h4>
<p>
Product company. Forex broker user cabinet development.
Payment system integrations,
maintenance of finance operations processing flow.
API development.
Trading platform implementations (MT4, MT5, TT),
API and database optimization and etc
</p>
<br />
<h4>Skills</h4>
<ul class="section__list">
<li class="section__list-item">.NET Core</li>
<li class="section__list-item">Entity Framework</li>
<li class="section__list-item">Docker</li>
<li class="section__list-item">Kubernets</li>
<li class="section__list-item">Ceph</li>
<li class="section__list-item">Gitlab CI/CD</li>
<li class="section__list-item">Networking</li>
</ul>
</article>
<br />
<article class="section">
<h3 class="section__title">Education</h3>
<div class="image-with-text">
<img class="section__img" src="/bsuir.png" width="100"/>
<div>
<p>
<strong>Belarusian State University of Informatics and Radioelectronics (2021 - 2025)</strong>
</p>
<p>
Computing systems and networks.
</p>
</div>
</div>
</article>
<br />
<article class="section">
<h3 class="section__title">Hobbies</h3>
<div class="image-with-text">
<img class="main-img" src="/server.jpg" height="100" width="140"/>
<div>
<p>
<strong>HomeLab</strong>
</p>
<ul class="section__list">
<li class="section__list-item">Bare metal server (HP Proliant DL380 Gen9) administrator</li>
<li class="section__list-item">40 TB Torrent seed</li>
<li class="section__list-item">Domain owner</li>
</ul>
</div>
</div>
<p>
<strong>Other</strong>
</p>
<ul class="section__list">
<li class="section__list-item">Drums</li>
<li class="section__list-item">Drawing</li>
</ul>
</article>
</div>
);
}

36
src/About.scss Normal file
View File

@@ -0,0 +1,36 @@
@use '_colors';
.main {
flex: 1;
padding: 10px;
}
.section {
margin-bottom: 20px;
.image-with-text {
margin-top: 10px;
display: flex;
align-items: center;
gap: 10px;
p {
margin: 0;
}
}
&__list {
padding-left: 17px;
margin: 0;
list-style: "- ";
}
&__title {
color: colors.$color-heading;
margin: 0 0 5px 0;
}
strong {
margin-bottom: 10px;
}
}

29
src/App.jsx Normal file
View File

@@ -0,0 +1,29 @@
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Navbar from './Navbar';
import Homelab from './Homelab';
import About from './About';
import Sidebar from "./Sidebar";
import Footer from './Footer';
import "./App.scss";
export default function App() {
return (
<Router>
<div className="app-container">
<Navbar />
<div className="wrapper">
<div className='content'>
<Routes>
<Route path="/" element={<About />} />
<Route path="/homelab" element={<Homelab />} />
</Routes>
</div>
<div className="sidebar">
<Sidebar />
</div>
</div>
<Footer />
</div>
</Router>
);
}

42
src/App.scss Normal file
View File

@@ -0,0 +1,42 @@
@use '_colors';
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body, #root {
height: 100%;
}
/* Центральный «островок» */
.app-container {
width: 1024px;
min-height: 100vh; /* на всю высоту окна */
margin: 0 auto; /* центрирование по горизонтали */
display: flex;
flex-direction: column;
background-color: colors.$color-white; /* цвет островка, можно поменять */
box-shadow: 0 0 10px rgba(0,0,0,0.1); /* легкая тень для отделения от белого фона */
}
body {
font-family: Consolas, sans-serif;
}
.wrapper {
display: flex;
min-height: 87vh;
}
.content {
flex: 1;
padding: 20px;
background-color: colors.$color-white;
}
.sidebar {
width: 250px;
padding: 20px;
}

9
src/Footer.jsx Normal file
View File

@@ -0,0 +1,9 @@
import "./Footer.scss";
export default function Footer() {
return (
<footer className="footer">
© {new Date().getFullYear()} Peabody28 Network
</footer>
);
}

13
src/Footer.scss Normal file
View File

@@ -0,0 +1,13 @@
@use '_colors';
.footer {
font-size: 10px;
margin-top: 20px;
padding: 10px;
border-top: 1px solid colors.$color-border;
display: flex;
flex-direction: column;
gap: 5px;
align-items: center;
height: 3vh;
}

48
src/Homelab.jsx Normal file
View File

@@ -0,0 +1,48 @@
import "./Homelab.scss";
export default function Home() {
return (
<article className="section">
<h4>Begin</h4>
<p>
When I moved from the dorm to my first rented apartment,
there was a static IP address. I decided that it could be used,
and sometimes I started leaving my home computer turned on to take files from it.
</p>
<br />
<h4>First server</h4>
<p>
Later, I built a separate tower server for this, with Ubuntu
running on it and my pet projects, file server, and Torrent running.
Later, I installed a hypervisor (Proxmox) and delegated some services to separate machines.
</p>
<br />
<h4>Networks and Security</h4>
<p>
Almost at the same time, I started dealing with networks and decided that my virtual machines and home network
It needs to be secured. I have configured OpenVPN to access my home network. When I got Mikrotik, life
became much more fun, I switched to the simplicity of WireGuard, set up a firewall and created separate networks for different purposes.
</p>
<br />
<h4>Enterprise Quality</h4>
<p>
When I started to run into disk storage, I decided to take a serious server to meet my
upgrade requirements, disk storage and memory. I currently have one HP Proliant DL380 Gen9 machine.
with 96 GB of RAM and 10TB of disk storage.
</p>
<br />
<h4>Storage and Services</h4>
<p>
My storage is organized with Ceph,
this allows me to easily change the disk configuration without RAID.
All my applications are deployed in Kubernetes
</p>
</article>
);
}

0
src/Homelab.scss Normal file
View File

19
src/Navbar.jsx Normal file
View File

@@ -0,0 +1,19 @@
import { Link } from 'react-router-dom';
import "./Navbar.scss";
export default function Navbar() {
return (
<header className="header">
<div className="header__top">
<p>Backend Developer</p>
<p>Maksim Harbacheuski</p>
</div>
<nav className="header__nav">
<ul className="header__nav-list">
<li className="header__nav-list-item"><Link to="/" className="text-blue-600 hover:underline">About</Link></li>
<li className="header__nav-list-item active"><Link to="/homelab" className="text-blue-600 hover:underline">Homelab</Link></li>
</ul>
</nav>
</header>
);
}

44
src/Navbar.scss Normal file
View File

@@ -0,0 +1,44 @@
@use '_colors';
.header {
height: 7vh;
&__top {
padding: 5px;
display: flex;
justify-content: space-between;
background-color: colors.$color-primary;
p {
font-size: 12px;
margin: 0;
color: colors.$color-white;
}
}
&__nav {
background-color: colors.$color-secondary;
padding: 10px;
&-list {
width: 100%;
padding: 0;
margin: 0;
list-style: none;
display: flex;
justify-content: space-around;
&-item {
font-weight: bold;
a {
color: colors.$color-white;
text-decoration: none;
}
&.active a {
color: #2c2c2c;
}
}
}
}
}

52
src/Sidebar.jsx Normal file
View File

@@ -0,0 +1,52 @@
import "./Sidebar.scss";
export default function Sidebar() {
return (
<div>
<div class="sidebar-item">
<div class="sidebar-item-top island-top">
<strong class="island-top-text">Facts</strong>
</div>
<div class="sidebar-item-content">
<div class="sidebar-item-content__block">
<ul>
<li>21 years old</li>
<li>Higher education (systems engineer)</li>
<li>In programming since 12 years old</li>
<li>40 TB torrent seed</li>
</ul>
</div>
</div>
</div>
<div class="sidebar-item">
<div class="sidebar-item-top island-top">
<strong class="island-top-text">Links</strong>
</div>
<div class="sidebar-item-content">
<div class="sidebar-item-content__block">
<strong>Contact</strong>
<ul>
<li><a href="www.linkedin.com/in/peabody28">LinkedIn</a></li>
<li><a href="mailto:gorbachewski.m@gmail.com">E-mail</a></li>
</ul>
</div>
<div class="sidebar-item-content__block">
<strong>Publications</strong>
<ul>
<li><a href="https://habr.com/ru/users/peabody28/">Habr</a></li>
</ul>
</div>
<div class="sidebar-item-content__block">
<strong>Git Repos</strong>
<ul>
<li><a href="https://github.com/peabody28">GitHub</a></li>
<li><a href="https://gitlab.com/peabody28">GitLab</a></li>
</ul>
</div>
</div>
</div>
</div>
);
}

93
src/Sidebar.scss Normal file
View File

@@ -0,0 +1,93 @@
@use '_colors';
.sidebar {
width: 200px;
font-size: 14px;
&-item {
background-color: colors.$color-right-sidebar;
border-radius: 5px 5px 0 0;
padding-bottom: 3px;
margin-bottom: 25px;
&-top {
padding-top: 5px;
}
&-content {
padding: 3px;
background-color: colors.$color-white;
margin: 3px 3px 0 3px;
&__block {
margin-bottom: 10px;
ul {
margin-top: 10px;
padding-left: 17px;
list-style: "- ";
}
}
}
}
.links {
margin-bottom: 0 !important;
}
a {
color: colors.$color-link;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
.section {
margin-bottom: 20px;
.image-with-text {
margin-top: 10px;
display: flex;
align-items: center;
gap: 10px;
p {
margin: 0;
}
}
&__list {
padding-left: 17px;
margin: 0;
list-style: "- ";
}
&__title {
color: colors.$color-heading;
margin: 0 0 5px 0;
}
strong {
margin-bottom: 10px;
}
}
.island-top {
height: 20px;
border-radius: 5px 5px 0 0;
background-color: colors.$color-primary;
&-text {
display: flex;
align-items: center;
height: 100%;
color: colors.$color-white;
padding-left: 5px;
padding-bottom: 5px;
}
}

9
src/_colors.scss Normal file
View File

@@ -0,0 +1,9 @@
$color-primary: #01649C;
$color-secondary: #FFCC66;
$color-heading: #cc6600;
$color-highlight: #ffffcc;
$color-right-sidebar: #EEEECC;
$color-link: #003399;
$color-border: #ccc;
$color-white: #ffffff;
$color-grey: grey;

9
src/main.jsx Normal file
View File

@@ -0,0 +1,9 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.jsx'
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
)

7
vite.config.js Normal file
View File

@@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
})