Compare commits
2
Commits
a9d2a6b15c
...
238d3d5d26
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
238d3d5d26 | ||
|
|
2036e909ea |
@@ -0,0 +1,8 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" shape-rendering="crispEdges">
|
||||
<rect x="7" y="2" width="2" height="13" fill="#00ff41"/>
|
||||
<rect x="3" y="4" width="2" height="5" fill="#00ff41"/>
|
||||
<rect x="3" y="7" width="4" height="2" fill="#00ff41"/>
|
||||
<rect x="11" y="5" width="2" height="6" fill="#00ff41"/>
|
||||
<rect x="9" y="9" width="4" height="2" fill="#00ff41"/>
|
||||
<rect x="1" y="15" width="14" height="1" fill="#9fa3a0"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 449 B |
@@ -1 +1,63 @@
|
||||
/* TODO: карточки проектов — этап 2 */
|
||||
.project-grid {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.project-card {
|
||||
border: var(--border);
|
||||
background: var(--color-bg-raised);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.project-card__bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-bottom: var(--border);
|
||||
color: var(--color-silver);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.project-card__bar span {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-accent-dim);
|
||||
opacity: 0.6;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.project-card__body {
|
||||
padding: 1.25rem 1.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.project-card__title {
|
||||
margin: 0;
|
||||
color: var(--color-accent);
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.project-card__desc {
|
||||
margin: 0;
|
||||
color: var(--color-fg);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.project-card__link {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.project-card__link::before {
|
||||
content: '$ ';
|
||||
color: var(--color-accent-dim);
|
||||
}
|
||||
|
||||
+101
-1
@@ -1 +1,101 @@
|
||||
/* TODO: вёрстка резюме — этап 2 */
|
||||
.hero {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2.5rem;
|
||||
padding: 2.5rem 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.hero-text h1 {
|
||||
margin: 0 0 0.4rem;
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.hero-text .role {
|
||||
margin: 0;
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.hero-text .tagline {
|
||||
margin: 0.75rem 0 0;
|
||||
color: var(--color-silver);
|
||||
max-width: 34ch;
|
||||
}
|
||||
|
||||
section {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
section > h2 {
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.about p {
|
||||
max-width: 68ch;
|
||||
}
|
||||
|
||||
.timeline {
|
||||
border-left: var(--border);
|
||||
margin: 0;
|
||||
padding: 0 0 0 1.5rem;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
position: relative;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.timeline-item::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -1.6rem;
|
||||
top: 0.4rem;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: var(--color-accent);
|
||||
box-shadow: 0 0 6px var(--color-accent-dim);
|
||||
}
|
||||
|
||||
.timeline-item__meta {
|
||||
color: var(--color-silver);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.timeline-item__role {
|
||||
color: var(--color-accent);
|
||||
margin: 0.15rem 0 0.5rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.timeline-item ul {
|
||||
margin: 0;
|
||||
padding-left: 1.2rem;
|
||||
}
|
||||
|
||||
.timeline-item li::marker {
|
||||
color: var(--color-accent-dim);
|
||||
}
|
||||
|
||||
.contact-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.contact-list a::before {
|
||||
content: '$ ';
|
||||
color: var(--color-accent-dim);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.hero {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
+176
-4
@@ -1,10 +1,12 @@
|
||||
:root {
|
||||
--color-bg: #0a0e0c;
|
||||
--color-bg-raised: #0f1512;
|
||||
--color-fg: #c7c7c7;
|
||||
--color-accent: #00ff41;
|
||||
--color-accent-dim: #0a8f2c;
|
||||
--color-silver: #9fa3a0;
|
||||
--font-mono: 'JetBrains Mono', 'Share Tech Mono', ui-monospace, monospace;
|
||||
--border: 1px solid #163020;
|
||||
}
|
||||
|
||||
* {
|
||||
@@ -13,26 +15,196 @@
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--color-bg);
|
||||
color: var(--color-fg);
|
||||
font-family: var(--font-mono);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--color-accent-dim);
|
||||
color: var(--color-bg);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:focus-visible,
|
||||
button:focus-visible {
|
||||
outline: 1px solid var(--color-accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 860px;
|
||||
margin: 0 auto;
|
||||
padding: 2.5rem 1.5rem 4rem;
|
||||
}
|
||||
|
||||
/* --- фон: canvas цифрового дождя --- */
|
||||
#matrix-rain {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: -2;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* лёгкие сканлайны поверх дождя, под контентом */
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
background: repeating-linear-gradient(
|
||||
to bottom,
|
||||
rgba(0, 0, 0, 0.15) 0px,
|
||||
rgba(0, 0, 0, 0.15) 1px,
|
||||
transparent 1px,
|
||||
transparent 3px
|
||||
);
|
||||
}
|
||||
|
||||
/* --- шапка --- */
|
||||
.site-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
padding-bottom: 1.5rem;
|
||||
border-bottom: var(--border);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
color: var(--color-accent);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.logo svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
filter: drop-shadow(0 0 4px var(--color-accent-dim));
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
color: var(--color-fg);
|
||||
}
|
||||
|
||||
.nav-links a:hover,
|
||||
.nav-links a[aria-current='page'] {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
/* --- терминальный префикс перед заголовками --- */
|
||||
.prompt::before {
|
||||
content: 'cacto@matrix:~$ ';
|
||||
color: var(--color-accent-dim);
|
||||
}
|
||||
|
||||
#matrix-rain {
|
||||
position: fixed;
|
||||
/* --- терминальное окно-обёртка для блоков контента --- */
|
||||
.term-window {
|
||||
border: var(--border);
|
||||
background: var(--color-bg-raised);
|
||||
margin: 1.75rem 0;
|
||||
}
|
||||
|
||||
.term-window__bar {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-bottom: var(--border);
|
||||
}
|
||||
|
||||
.term-window__bar span {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-accent-dim);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.term-window__body {
|
||||
padding: 1.25rem 1.5rem;
|
||||
}
|
||||
|
||||
/* --- ASCII-арт --- */
|
||||
.ascii-cactus {
|
||||
color: var(--color-accent);
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.15;
|
||||
margin: 0;
|
||||
text-shadow: 0 0 6px var(--color-accent-dim);
|
||||
}
|
||||
|
||||
/* --- glitch-эффект для акцентного текста --- */
|
||||
.glitch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.glitch::before,
|
||||
.glitch::after {
|
||||
content: attr(data-text);
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
overflow: hidden;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.glitch::before {
|
||||
color: var(--color-silver);
|
||||
clip-path: inset(0 0 55% 0);
|
||||
animation: glitch-shift 3.4s infinite steps(2);
|
||||
}
|
||||
|
||||
.glitch::after {
|
||||
color: var(--color-accent-dim);
|
||||
clip-path: inset(55% 0 0 0);
|
||||
animation: glitch-shift 2.6s infinite steps(2) reverse;
|
||||
}
|
||||
|
||||
@keyframes glitch-shift {
|
||||
0%, 92%, 100% { transform: translate(0, 0); }
|
||||
94% { transform: translate(-2px, 1px); }
|
||||
96% { transform: translate(2px, -1px); }
|
||||
}
|
||||
|
||||
/* --- теги (скиллы, стек проекта) --- */
|
||||
.tag-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.tag {
|
||||
border: 1px solid var(--color-accent-dim);
|
||||
color: var(--color-accent);
|
||||
padding: 0.15rem 0.6rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
+25
-6
@@ -4,16 +4,35 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>./battlecity — cacto</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/assets/cactus-logo.svg" />
|
||||
<link rel="stylesheet" href="/css/theme.css" />
|
||||
<link rel="stylesheet" href="/css/game.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main id="game-root">
|
||||
<!-- TODO: лобби (этап 3) и игровое поле на Quintus.js (этапы 4-5) -->
|
||||
<h1 class="prompt">./battlecity</h1>
|
||||
<div id="lobby"></div>
|
||||
<div id="battlecity-canvas-container"></div>
|
||||
</main>
|
||||
<canvas id="matrix-rain"></canvas>
|
||||
|
||||
<div class="container">
|
||||
<header class="site-header">
|
||||
<a href="/" class="logo" aria-label="cacto — на главную">
|
||||
<img src="/assets/cactus-logo.svg" width="20" height="20" alt="" />
|
||||
cacto
|
||||
</a>
|
||||
<ul class="nav-links">
|
||||
<li><a href="/">whoami</a></li>
|
||||
<li><a href="/projects.html">ls projects/</a></li>
|
||||
<li><a href="/game.html" aria-current="page">./battlecity</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<main id="game-root">
|
||||
<!-- TODO: лобби (этап 3) и игровое поле на Quintus.js (этапы 4-5) -->
|
||||
<h2 class="prompt">./battlecity</h2>
|
||||
<div id="lobby"></div>
|
||||
<div id="battlecity-canvas-container"></div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script type="module" src="/js/matrix-rain.js"></script>
|
||||
<script type="module" src="/js/game/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+125
-10
@@ -3,21 +3,136 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>cacto — Гаммель Дмитрий</title>
|
||||
<title>cacto — Гаммель Дмитрий, PHP/Go backend</title>
|
||||
<meta name="description" content="Гаммель Дмитрий — backend-разработчик PHP/Go. Резюме, проекты, эксперименты." />
|
||||
<link rel="icon" type="image/svg+xml" href="/assets/cactus-logo.svg" />
|
||||
<link rel="stylesheet" href="/css/theme.css" />
|
||||
<link rel="stylesheet" href="/css/resume.css" />
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="matrix-rain"></canvas>
|
||||
<main id="resume">
|
||||
<!-- TODO: вёрстка резюме, ASCII-арт кактуса — этап 2 -->
|
||||
<h1 class="prompt">whoami</h1>
|
||||
<p>Гаммель Дмитрий Викторович — PHP/Go backend, опыт КИПиА/АСУТП</p>
|
||||
<nav>
|
||||
<a href="/projects.html">ls projects/</a>
|
||||
<a href="/game.html">./battlecity</a>
|
||||
</nav>
|
||||
</main>
|
||||
|
||||
<div class="container">
|
||||
<header class="site-header">
|
||||
<a href="/" class="logo" aria-label="cacto — на главную">
|
||||
<img src="/assets/cactus-logo.svg" width="20" height="20" alt="" />
|
||||
cacto
|
||||
</a>
|
||||
<ul class="nav-links">
|
||||
<li><a href="/" aria-current="page">whoami</a></li>
|
||||
<li><a href="/projects.html">ls projects/</a></li>
|
||||
<li><a href="/game.html">./battlecity</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section class="hero">
|
||||
<pre class="ascii-cactus" aria-hidden="true">
|
||||
, ,
|
||||
|\_/|
|
||||
.--| |--.
|
||||
( | | )
|
||||
`--| |--'
|
||||
| |
|
||||
.--| |--.
|
||||
( | | )
|
||||
`--| |--'
|
||||
| |
|
||||
| |
|
||||
__| |__
|
||||
(_________)</pre>
|
||||
<div class="hero-text">
|
||||
<h1><span class="glitch" data-text="Гаммель Дмитрий">Гаммель Дмитрий</span></h1>
|
||||
<p class="role">PHP / Go backend-разработчик</p>
|
||||
<p class="tagline">Живучий, колючий, не требует много воды. Специализация — сложные запросы, legacy-код, архитектура.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="about">
|
||||
<h2 class="prompt">cat about.txt</h2>
|
||||
<div class="term-window">
|
||||
<div class="term-window__bar"><span></span><span></span><span></span></div>
|
||||
<div class="term-window__body">
|
||||
<p>
|
||||
Backend-разработчик с 6-летним коммерческим опытом на PHP: сложные запросы к базам данных,
|
||||
работа с legacy-кодом, архитектурные решения. Спроектировал аналитический контур на ClickHouse,
|
||||
ускоривший формирование отчётности в 15–20 раз; неофициально возглавлял разработку модуля
|
||||
документооборота в банковской IT-инфраструктуре.
|
||||
</p>
|
||||
<p>
|
||||
Начинал с электротехники и АСУТП — писал управляющий софт для автоматизированных систем.
|
||||
Путь «от электрического сигнала до строчки кода» помогает быстро разбираться в сложных
|
||||
legacy-системах и нестандартных задачах.
|
||||
</p>
|
||||
<p>
|
||||
Сейчас изучаю Go и продолжаю искать позицию Middle+/Senior backend-разработчика.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="experience">
|
||||
<h2 class="prompt">ls -la experience/</h2>
|
||||
<ol class="timeline">
|
||||
<li class="timeline-item">
|
||||
<div class="timeline-item__meta">июль 2022 — март 2026 · Екатеринбург</div>
|
||||
<h3 class="timeline-item__role">PHP-разработчик — ООО «ЭТП ГПБ» (дочернее АО «Газпромбанк»)</h3>
|
||||
<ul>
|
||||
<li>Поддерживал legacy на Zend Framework, участвовал в переходе на Symfony; PHP 7.4 → 8.0.</li>
|
||||
<li>Спроектировал аналитический контур отчётности на ClickHouse — сократил время формирования отчётов с 3–4 минут до 10–15 секунд.</li>
|
||||
<li>Интеграции с внутренними банковскими сервисами (проверка ЭП, машиночитаемые доверенности), очереди RabbitMQ.</li>
|
||||
<li>Неофициально возглавлял разработку нового модуля документооборота: архитектура, код-ревью, MVP.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="timeline-item">
|
||||
<div class="timeline-item__meta">март 2021 — июль 2022 · фриланс/субподряд</div>
|
||||
<h3 class="timeline-item__role">PHP-разработчик — kupisever.ru</h3>
|
||||
<ul>
|
||||
<li>Доработка бэкенда B2B-платформы (доска объявлений) на Yii2, стек PHP/PostgreSQL/RabbitMQ/Docker.</li>
|
||||
<li>Модуль email-рассылок с очередями сообщений и конструктором писем.</li>
|
||||
<li>Модуль категорий объявлений — админка и клиентское меню.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="timeline-item">
|
||||
<div class="timeline-item__meta">июль 2020 — март 2021 · Курган</div>
|
||||
<h3 class="timeline-item__role">PHP-разработчик (с обязанностями руководителя группы) — ИстВуд</h3>
|
||||
<ul>
|
||||
<li>Интернет-магазины на 1С-Битрикс, интеграции с 1С и платёжными системами.</li>
|
||||
<li>Фактически руководил командой из 3 разработчиков: задачи, код-ревью, технические собеседования.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section class="skills">
|
||||
<h2 class="prompt">skills --list</h2>
|
||||
<ul class="tag-list">
|
||||
<li class="tag">PHP8</li>
|
||||
<li class="tag">Symfony</li>
|
||||
<li class="tag">Zend Framework</li>
|
||||
<li class="tag">Yii2</li>
|
||||
<li class="tag">PostgreSQL</li>
|
||||
<li class="tag">MySQL</li>
|
||||
<li class="tag">ClickHouse</li>
|
||||
<li class="tag">RabbitMQ</li>
|
||||
<li class="tag">Docker</li>
|
||||
<li class="tag">REST API</li>
|
||||
<li class="tag">PHPUnit</li>
|
||||
<li class="tag">ООП</li>
|
||||
<li class="tag">Go (изучаю)</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="contact">
|
||||
<h2 class="prompt">cat contact.txt</h2>
|
||||
<ul class="contact-list">
|
||||
<li><a href="mailto:cactozzz93@gmail.com">cactozzz93@gmail.com</a></li>
|
||||
<li><a href="https://t.me/Cactozz">t.me/Cactozz</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script type="module" src="/js/matrix-rain.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,11 +1,45 @@
|
||||
// TODO: полноценный canvas-эффект цифрового дождя — этап 2
|
||||
const canvas = document.getElementById('matrix-rain');
|
||||
if (canvas) {
|
||||
|
||||
if (canvas && !window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
||||
const ctx = canvas.getContext('2d');
|
||||
const resize = () => {
|
||||
const chars = 'アカサタナハマヤラワ0123456789ABCDEFcacto$#@%&*'.split('');
|
||||
const fontSize = 15;
|
||||
const bg = getComputedStyle(document.documentElement).getPropertyValue('--color-bg').trim();
|
||||
const accent = getComputedStyle(document.documentElement).getPropertyValue('--color-accent').trim();
|
||||
const silver = getComputedStyle(document.documentElement).getPropertyValue('--color-silver').trim();
|
||||
|
||||
let columns = 0;
|
||||
let drops = [];
|
||||
|
||||
function setup() {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
};
|
||||
resize();
|
||||
window.addEventListener('resize', resize);
|
||||
columns = Math.floor(canvas.width / fontSize);
|
||||
drops = new Array(columns).fill(0).map(() => Math.floor((Math.random() * canvas.height) / fontSize));
|
||||
}
|
||||
|
||||
function draw() {
|
||||
ctx.fillStyle = `${bg}cc`;
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.font = `${fontSize}px monospace`;
|
||||
|
||||
for (let i = 0; i < columns; i++) {
|
||||
const char = chars[Math.floor(Math.random() * chars.length)];
|
||||
const x = i * fontSize;
|
||||
const y = drops[i] * fontSize;
|
||||
|
||||
ctx.fillStyle = Math.random() > 0.98 ? silver : accent;
|
||||
ctx.fillText(char, x, y);
|
||||
|
||||
if (y > canvas.height && Math.random() > 0.975) {
|
||||
drops[i] = 0;
|
||||
} else {
|
||||
drops[i]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setup();
|
||||
window.addEventListener('resize', setup);
|
||||
setInterval(draw, 50);
|
||||
}
|
||||
|
||||
+39
-1
@@ -1 +1,39 @@
|
||||
// TODO: рендер карточек проектов из данных — этап 2
|
||||
const projects = [
|
||||
{
|
||||
name: 'home_automatization',
|
||||
title: 'Home Automation Platform',
|
||||
description:
|
||||
'Микросервисная платформа умного дома на Go и Laravel. Первая зона — гроубокс (полив, свет, климат), дальше — весь дом.',
|
||||
tags: ['Go', 'Laravel', 'Docker', 'RabbitMQ', 'ClickHouse', 'gRPC', 'MQTT'],
|
||||
url: 'https://git.cactoz.su/cacto/home_automatization',
|
||||
},
|
||||
{
|
||||
name: 'cactoz.su',
|
||||
title: 'cactoz.su — этот сайт',
|
||||
description:
|
||||
'Личный сайт-визитка: резюме, проекты и мультиплеерный клон BattleCity. Тема — Матрица.',
|
||||
tags: ['HTML/CSS/JS', 'C++', 'uWebSockets', 'Quintus.js', 'nginx', 'Docker'],
|
||||
url: 'https://git.cactoz.su/cacto/cactoz.su',
|
||||
},
|
||||
];
|
||||
|
||||
const list = document.getElementById('project-list');
|
||||
|
||||
if (list) {
|
||||
list.innerHTML = projects
|
||||
.map(
|
||||
(p) => `
|
||||
<li class="project-card">
|
||||
<div class="project-card__bar"><span></span>${p.name}/README.md</div>
|
||||
<div class="project-card__body">
|
||||
<h3 class="project-card__title">${p.title}</h3>
|
||||
<p class="project-card__desc">${p.description}</p>
|
||||
<ul class="tag-list">
|
||||
${p.tags.map((t) => `<li class="tag">${t}</li>`).join('')}
|
||||
</ul>
|
||||
<a class="project-card__link" href="${p.url}" target="_blank" rel="noopener">${p.url.replace('https://', '')}</a>
|
||||
</div>
|
||||
</li>`
|
||||
)
|
||||
.join('');
|
||||
}
|
||||
|
||||
+26
-9
@@ -4,19 +4,36 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>ls projects/ — cacto</title>
|
||||
<meta name="description" content="Проекты Гаммеля Дмитрия: home automation platform и этот сайт." />
|
||||
<link rel="icon" type="image/svg+xml" href="/assets/cactus-logo.svg" />
|
||||
<link rel="stylesheet" href="/css/theme.css" />
|
||||
<link rel="stylesheet" href="/css/projects.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main id="projects">
|
||||
<!-- TODO: карточки проектов — этап 2 -->
|
||||
<h1 class="prompt">ls projects/</h1>
|
||||
<ul id="project-list"></ul>
|
||||
<nav>
|
||||
<a href="/">cd ~</a>
|
||||
<a href="/game.html">./battlecity</a>
|
||||
</nav>
|
||||
</main>
|
||||
<canvas id="matrix-rain"></canvas>
|
||||
|
||||
<div class="container">
|
||||
<header class="site-header">
|
||||
<a href="/" class="logo" aria-label="cacto — на главную">
|
||||
<img src="/assets/cactus-logo.svg" width="20" height="20" alt="" />
|
||||
cacto
|
||||
</a>
|
||||
<ul class="nav-links">
|
||||
<li><a href="/">whoami</a></li>
|
||||
<li><a href="/projects.html" aria-current="page">ls projects/</a></li>
|
||||
<li><a href="/game.html">./battlecity</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section>
|
||||
<h2 class="prompt">ls projects/</h2>
|
||||
<ul id="project-list" class="project-grid"></ul>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script type="module" src="/js/matrix-rain.js"></script>
|
||||
<script type="module" src="/js/projects.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user