Вёрстка резюме и карточек проектов в теме Matrix/cacto

Резюме: ASCII-кактус, glitch-заголовок, таймлайн опыта, скилл-теги, контакты.
Проекты: карточки-терминалы (home_automatization, cactoz.su) со ссылками на git.cactoz.su.
Canvas-дождь на цифровых/катакана символах, пиксельный SVG-кактус как лого/favicon.
This commit is contained in:
2026-07-26 20:47:21 +05:00
parent a9d2a6b15c
commit 2036e909ea
9 changed files with 603 additions and 38 deletions
+40 -6
View File
@@ -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
View File
@@ -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('');
}