feat(all): 1-st site version
No files matched your search
@@ -0,0 +1,7 @@
|
||||
.git/
|
||||
.github/
|
||||
.forgejo/
|
||||
.idea/
|
||||
.venv/
|
||||
shell.nix
|
||||
README.md
|
||||
@@ -0,0 +1,95 @@
|
||||
name: Build, Test and Push Flask App
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
|
||||
jobs:
|
||||
docker-build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Docker CLI
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y docker.io
|
||||
docker --version
|
||||
|
||||
- name: Configure Docker CLI for insecure registry
|
||||
run: |
|
||||
mkdir -p ~/.docker
|
||||
echo '{"insecure-registries" : ["git.rustprogersteam.ru"]}' > ~/.docker/config.json
|
||||
cat ~/.docker/config.json
|
||||
|
||||
- name: 'Docker Tags'
|
||||
id: tags
|
||||
uses: https://github.com/cssnr/docker-tags-action@v2
|
||||
with:
|
||||
images: 'git.rustprogersteam.ru/${{ vars.DOCKER_USERNAME }}/myresume'
|
||||
|
||||
- name: Login to Docker Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: git.rustprogersteam.ru
|
||||
username: ${{ vars.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: |
|
||||
git.rustprogersteam.ru/${{ vars.DOCKER_USERNAME }}/myresume/resume:latest
|
||||
git.rustprogersteam.ru/${{ vars.DOCKER_USERNAME }}/myresume/resume:${{ github.sha }}
|
||||
labels: ${{ steps.tags.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
deploy:
|
||||
needs: docker-build-and-push
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Ansible
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y ansible openssh-client
|
||||
|
||||
- name: Set up SSH key
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
printf '%s\n' "$SSH_PRIVATE_KEY" > ~/.ssh/deploy_key
|
||||
chmod 600 ~/.ssh/deploy_key
|
||||
ssh-keygen -y -f ~/.ssh/deploy_key >/dev/null
|
||||
|
||||
- name: Trust server host key
|
||||
run: |
|
||||
ssh-keyscan -H "${{ secrets.SERVER_IP }}" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Test SSH
|
||||
run: |
|
||||
ssh \
|
||||
-i ~/.ssh/deploy_key \
|
||||
-o StrictHostKeyChecking=yes \
|
||||
"${{ secrets.SERVER_USER }}@${{ secrets.SERVER_IP }}" \
|
||||
'echo SSH works'
|
||||
|
||||
- name: Run Ansible playbook
|
||||
run: |
|
||||
ansible-playbook \
|
||||
-i "${{ secrets.SERVER_IP }}," \
|
||||
ansible/restart_compose.yml \
|
||||
--user "${{ secrets.SERVER_USER }}" \
|
||||
--private-key ~/.ssh/deploy_key
|
||||
@@ -0,0 +1,12 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN pip install --no-cache-dir -r dependencies.txt
|
||||
|
||||
ENV FLASK_ENV=production
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
CMD ["gunicorn", "app:app", "-b", "0.0.0.0:80", "--workers", "1"]
|
||||
@@ -0,0 +1,15 @@
|
||||
- name: Restart Docker Compose services
|
||||
hosts: all
|
||||
# become: yes # <-- больше не нужно, т.к. пользователь уже имеет права Docker
|
||||
tasks:
|
||||
- name: docker compose down
|
||||
ansible.builtin.shell:
|
||||
cmd: docker compose down
|
||||
chdir: /etc/compose/resume
|
||||
- name: prune system
|
||||
ansible.builtin.shell:
|
||||
cmd: docker system prune -a -f
|
||||
- name: docker compose up -d
|
||||
ansible.builtin.shell:
|
||||
cmd: docker compose up -d
|
||||
chdir: /etc/compose/resume
|
||||
@@ -0,0 +1,12 @@
|
||||
from flask import Flask, render_template
|
||||
import os
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
return render_template('main.html')
|
||||
|
||||
@app.route("/author")
|
||||
def author():
|
||||
return render_template('author.html')
|
||||
@@ -0,0 +1,2 @@
|
||||
flask==3.1.2
|
||||
gunicorn
|
||||
@@ -0,0 +1,21 @@
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
|
||||
pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
python3
|
||||
ruff
|
||||
pyright
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
if [ ! -d ".venv" ]; then
|
||||
python -m venv .venv
|
||||
fi
|
||||
|
||||
source .venv/bin/activate
|
||||
|
||||
if [ -f "dependencies.txt" ]; then
|
||||
pip install -r dependencies.txt
|
||||
fi
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,809 @@
|
||||
:root {
|
||||
--bg: #07080d;
|
||||
--bg-soft: #0c0e16;
|
||||
--card: rgba(255, 255, 255, 0.035);
|
||||
--card-border: rgba(255, 255, 255, 0.08);
|
||||
--text: #e8ecf5;
|
||||
--muted: #97a0b5;
|
||||
--accent: #5eead4;
|
||||
--accent-2: #7c8cff;
|
||||
--accent-3: #f472b6;
|
||||
--radius: 18px;
|
||||
--max: 1140px;
|
||||
--font: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
|
||||
--mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", monospace;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
html { scroll-behavior: smooth; }
|
||||
|
||||
body {
|
||||
font-family: var(--font);
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
line-height: 1.65;
|
||||
overflow-x: hidden;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
a { color: inherit; text-decoration: none; }
|
||||
|
||||
::selection { background: rgba(94, 234, 212, 0.25); }
|
||||
|
||||
/* ---------- фон ---------- */
|
||||
.bg-glow {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: -2;
|
||||
background:
|
||||
radial-gradient(600px 400px at 15% 0%, rgba(124, 140, 255, 0.18), transparent 65%),
|
||||
radial-gradient(700px 500px at 85% 10%, rgba(94, 234, 212, 0.14), transparent 65%),
|
||||
radial-gradient(800px 600px at 50% 110%, rgba(244, 114, 182, 0.10), transparent 70%);
|
||||
animation: drift 24s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes drift {
|
||||
from { transform: translate3d(-2%, -1%, 0) scale(1); }
|
||||
to { transform: translate3d(2%, 2%, 0) scale(1.06); }
|
||||
}
|
||||
|
||||
.grid-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
background-image:
|
||||
linear-gradient(rgba(255,255,255,0.035) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(255,255,255,0.035) 1px, transparent 1px);
|
||||
background-size: 64px 64px;
|
||||
mask-image: radial-gradient(ellipse at 50% 30%, #000 30%, transparent 85%);
|
||||
-webkit-mask-image: radial-gradient(ellipse at 50% 30%, #000 30%, transparent 85%);
|
||||
}
|
||||
|
||||
/* ---------- хедер ---------- */
|
||||
.site-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 50;
|
||||
backdrop-filter: blur(14px);
|
||||
-webkit-backdrop-filter: blur(14px);
|
||||
background: rgba(7, 8, 13, 0.72);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
||||
transition: box-shadow .3s ease;
|
||||
}
|
||||
|
||||
.site-header.scrolled { box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45); }
|
||||
|
||||
.nav {
|
||||
max-width: var(--max);
|
||||
margin: 0 auto;
|
||||
padding: 16px 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-weight: 700;
|
||||
font-size: 1.05rem;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.logo-mark {
|
||||
font-family: var(--mono);
|
||||
font-size: .8rem;
|
||||
padding: 5px 9px;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(135deg, rgba(94, 234, 212, .2), rgba(124, 140, 255, .2));
|
||||
border: 1px solid rgba(94, 234, 212, .35);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.accent { color: var(--accent); }
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
display: block;
|
||||
padding: 8px 14px;
|
||||
border-radius: 10px;
|
||||
font-size: .92rem;
|
||||
color: var(--muted);
|
||||
transition: color .2s, background .2s;
|
||||
}
|
||||
|
||||
.nav-links a:hover { color: var(--text); background: rgba(255, 255, 255, 0.06); }
|
||||
|
||||
.nav-cta {
|
||||
color: var(--accent) !important;
|
||||
border: 1px solid rgba(94, 234, 212, .35);
|
||||
background: rgba(94, 234, 212, .07);
|
||||
}
|
||||
|
||||
.nav-cta:hover { background: rgba(94, 234, 212, .14) !important; }
|
||||
|
||||
.nav-toggle {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
background: none;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.nav-toggle span {
|
||||
width: 22px;
|
||||
height: 2px;
|
||||
background: var(--text);
|
||||
border-radius: 2px;
|
||||
transition: transform .25s, opacity .25s;
|
||||
}
|
||||
|
||||
.nav-toggle.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
|
||||
.nav-toggle.open span:nth-child(2) { opacity: 0; }
|
||||
.nav-toggle.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
|
||||
|
||||
/* ---------- hero ---------- */
|
||||
.hero {
|
||||
max-width: var(--max);
|
||||
margin: 0 auto;
|
||||
padding: clamp(70px, 12vw, 130px) 24px clamp(50px, 8vw, 90px);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 9px;
|
||||
font-family: var(--mono);
|
||||
font-size: .78rem;
|
||||
letter-spacing: .04em;
|
||||
padding: 7px 15px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, .04);
|
||||
border: 1px solid rgba(255, 255, 255, .1);
|
||||
color: var(--muted);
|
||||
margin-bottom: 26px;
|
||||
}
|
||||
|
||||
.pulse {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #34d399;
|
||||
box-shadow: 0 0 0 0 rgba(52, 211, 153, .7);
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
70% { box-shadow: 0 0 0 9px rgba(52, 211, 153, 0); }
|
||||
100% { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0); }
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-size: clamp(2.3rem, 6.5vw, 4.3rem);
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.035em;
|
||||
font-weight: 700;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.gradient-text {
|
||||
background: linear-gradient(100deg, var(--accent) 0%, var(--accent-2) 45%, var(--accent-3) 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
max-width: 660px;
|
||||
margin: 0 auto 34px;
|
||||
color: var(--muted);
|
||||
font-size: clamp(1rem, 2vw, 1.12rem);
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 14px;
|
||||
justify-content: center;
|
||||
margin-bottom: 56px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 13px 26px;
|
||||
border-radius: 12px;
|
||||
font-size: .95rem;
|
||||
font-weight: 600;
|
||||
transition: transform .2s, box-shadow .2s, background .2s, border-color .2s;
|
||||
}
|
||||
|
||||
.btn:active { transform: translateY(1px); }
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, var(--accent), #2dd4bf);
|
||||
color: #04120f;
|
||||
box-shadow: 0 8px 26px rgba(94, 234, 212, .22);
|
||||
}
|
||||
|
||||
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 14px 34px rgba(94, 234, 212, .32); }
|
||||
|
||||
.btn-ghost {
|
||||
border: 1px solid rgba(255, 255, 255, .14);
|
||||
color: var(--text);
|
||||
background: rgba(255, 255, 255, .03);
|
||||
}
|
||||
|
||||
.btn-ghost:hover { background: rgba(255, 255, 255, .08); border-color: rgba(255, 255, 255, .25); }
|
||||
|
||||
.hero-stats {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: clamp(26px, 6vw, 70px);
|
||||
}
|
||||
|
||||
.stat { display: flex; flex-direction: column; gap: 2px; }
|
||||
|
||||
.stat-num {
|
||||
font-family: var(--mono);
|
||||
font-size: clamp(1.7rem, 4vw, 2.4rem);
|
||||
font-weight: 600;
|
||||
background: linear-gradient(180deg, #fff, var(--accent));
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.stat-label { font-size: .8rem; color: var(--muted); letter-spacing: .03em; }
|
||||
|
||||
/* ---------- секции ---------- */
|
||||
.section {
|
||||
max-width: var(--max);
|
||||
margin: 0 auto;
|
||||
padding: clamp(50px, 8vw, 90px) 24px;
|
||||
}
|
||||
|
||||
.section-head { max-width: 700px; margin-bottom: 46px; }
|
||||
|
||||
.section-tag {
|
||||
display: inline-block;
|
||||
font-family: var(--mono);
|
||||
font-size: .78rem;
|
||||
color: var(--accent);
|
||||
letter-spacing: .08em;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: clamp(1.7rem, 4vw, 2.5rem);
|
||||
letter-spacing: -0.03em;
|
||||
line-height: 1.2;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.section-desc { color: var(--muted); }
|
||||
|
||||
/* ---------- карточки ---------- */
|
||||
.cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.card {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
padding: 26px;
|
||||
border-radius: var(--radius);
|
||||
background: var(--card);
|
||||
border: 1px solid var(--card-border);
|
||||
overflow: hidden;
|
||||
transition: transform .3s ease, border-color .3s ease, background .3s ease;
|
||||
}
|
||||
|
||||
.card::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(140deg, rgba(94, 234, 212, .10), transparent 45%);
|
||||
opacity: 0;
|
||||
transition: opacity .35s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-6px);
|
||||
border-color: rgba(94, 234, 212, .35);
|
||||
background: rgba(255, 255, 255, .055);
|
||||
}
|
||||
|
||||
.card:hover::before { opacity: 1; }
|
||||
|
||||
.card-icon {
|
||||
font-size: 1.9rem;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 14px;
|
||||
background: rgba(255, 255, 255, .05);
|
||||
border: 1px solid rgba(255, 255, 255, .08);
|
||||
padding: 10px;
|
||||
object-fit: contain;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.card-body h3 {
|
||||
font-size: 1.22rem;
|
||||
letter-spacing: -0.02em;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card-body p { font-size: .93rem; color: var(--muted); }
|
||||
|
||||
.card-badge {
|
||||
align-self: flex-start;
|
||||
margin-top: auto;
|
||||
font-family: var(--mono);
|
||||
font-size: .72rem;
|
||||
letter-spacing: .05em;
|
||||
text-transform: uppercase;
|
||||
padding: 5px 11px;
|
||||
border-radius: 999px;
|
||||
background: rgba(124, 140, 255, .1);
|
||||
border: 1px solid rgba(124, 140, 255, .25);
|
||||
color: #a9b3ff;
|
||||
}
|
||||
|
||||
.card-featured {
|
||||
background: linear-gradient(160deg, rgba(94, 234, 212, .08), rgba(255, 255, 255, .03));
|
||||
border-color: rgba(94, 234, 212, .25);
|
||||
}
|
||||
|
||||
.inline-link {
|
||||
color: var(--accent);
|
||||
border-bottom: 1px dashed rgba(94, 234, 212, .5);
|
||||
font-weight: 600;
|
||||
transition: border-color .2s, color .2s;
|
||||
}
|
||||
|
||||
.inline-link:hover { color: #fff; border-bottom-color: #fff; }
|
||||
|
||||
/* ---------- о сервере ---------- */
|
||||
.about {
|
||||
display: grid;
|
||||
grid-template-columns: 1.1fr 1fr;
|
||||
gap: 40px;
|
||||
align-items: center;
|
||||
padding: clamp(28px, 5vw, 48px);
|
||||
border-radius: 24px;
|
||||
background: rgba(255, 255, 255, .03);
|
||||
border: 1px solid var(--card-border);
|
||||
}
|
||||
|
||||
.about-text p { color: var(--muted); margin-bottom: 16px; font-size: .97rem; }
|
||||
.about-btn { margin-top: 8px; }
|
||||
|
||||
img.card-icon { border-radius: 12px; }
|
||||
|
||||
/* ---------- характеристики сервера ---------- */
|
||||
.about-sub {
|
||||
font-size: 1.02rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.01em;
|
||||
margin: 24px 0 6px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.spec-list { margin: 0; }
|
||||
|
||||
.spec-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 6px 16px;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px dashed rgba(255, 255, 255, .08);
|
||||
}
|
||||
|
||||
.spec-row:last-child { border-bottom: 0; }
|
||||
|
||||
.spec-row dt {
|
||||
font-family: var(--mono);
|
||||
font-size: .74rem;
|
||||
letter-spacing: .08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.spec-row dd {
|
||||
margin: 0;
|
||||
text-align: right;
|
||||
font-size: .96rem;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.about-terminal {
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
background: #0a0d14;
|
||||
border: 1px solid rgba(255, 255, 255, .1);
|
||||
box-shadow: 0 24px 60px rgba(0, 0, 0, .55);
|
||||
}
|
||||
|
||||
.terminal-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 11px 14px;
|
||||
background: rgba(255, 255, 255, .04);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, .07);
|
||||
}
|
||||
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; }
|
||||
.dot.red { background: #ff5f57; }
|
||||
.dot.yellow { background: #febc2e; }
|
||||
.dot.green { background: #28c840; }
|
||||
|
||||
.terminal-title {
|
||||
margin-left: 8px;
|
||||
font-family: var(--mono);
|
||||
font-size: .76rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.terminal-body {
|
||||
padding: 20px;
|
||||
font-family: var(--mono);
|
||||
font-size: .85rem;
|
||||
line-height: 1.85;
|
||||
min-height: 260px;
|
||||
color: #c9d4e8;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.terminal-body .prompt { color: var(--accent); }
|
||||
.terminal-body .dim { color: #6b7691; }
|
||||
.terminal-body .ok { color: #4ade80; }
|
||||
.terminal-body .cursor {
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 1.05em;
|
||||
background: var(--accent);
|
||||
vertical-align: text-bottom;
|
||||
animation: blink 1s steps(1) infinite;
|
||||
}
|
||||
|
||||
@keyframes blink { 50% { opacity: 0; } }
|
||||
|
||||
/* ---------- футер ---------- */
|
||||
.site-footer {
|
||||
margin-top: clamp(40px, 7vw, 80px);
|
||||
border-top: 1px solid rgba(255, 255, 255, .07);
|
||||
background: rgba(255, 255, 255, .02);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.footer-inner {
|
||||
max-width: var(--max);
|
||||
margin: 0 auto;
|
||||
padding: 26px 24px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
align-items: center;
|
||||
gap: 18px;
|
||||
font-size: .87rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.footer-left { justify-self: start; }
|
||||
.footer-center { justify-self: center; text-align: center; }
|
||||
.footer-right { justify-self: end; text-align: right; }
|
||||
|
||||
.footer-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 9px;
|
||||
padding: 7px 14px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, .04);
|
||||
border: 1px solid rgba(255, 255, 255, .09);
|
||||
}
|
||||
|
||||
.footer-center a,
|
||||
.footer-right a {
|
||||
color: var(--muted);
|
||||
transition: color .2s;
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
.footer-center a:hover,
|
||||
.footer-right a:hover {
|
||||
color: var(--accent);
|
||||
border-bottom-color: rgba(94, 234, 212, .5);
|
||||
}
|
||||
|
||||
/* ---------- страница об авторе ---------- */
|
||||
.card-icon svg { width: 24px; height: 24px; color: var(--accent); }
|
||||
|
||||
.author-hero {
|
||||
max-width: 880px;
|
||||
margin: 0 auto;
|
||||
padding: clamp(56px, 10vw, 110px) 24px clamp(24px, 4vw, 44px);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.author-avatar {
|
||||
display: block;
|
||||
width: clamp(140px, 24vw, 190px);
|
||||
height: auto;
|
||||
aspect-ratio: 1;
|
||||
margin: 0 auto 26px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 3px solid rgba(94, 234, 212, .45);
|
||||
box-shadow: 0 0 0 10px rgba(94, 234, 212, .07), 0 26px 60px rgba(0, 0, 0, .55);
|
||||
}
|
||||
|
||||
.author-name {
|
||||
font-size: clamp(1.9rem, 5vw, 3rem);
|
||||
letter-spacing: -0.03em;
|
||||
line-height: 1.15;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.author-role {
|
||||
font-family: var(--mono);
|
||||
font-size: .82rem;
|
||||
letter-spacing: .16em;
|
||||
text-transform: uppercase;
|
||||
color: var(--accent);
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.author-bio {
|
||||
max-width: 640px;
|
||||
margin: 0 auto;
|
||||
color: var(--muted);
|
||||
font-size: 1.02rem;
|
||||
}
|
||||
|
||||
.contact-groups {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 26px;
|
||||
margin-top: 34px;
|
||||
}
|
||||
|
||||
.contact-group h3 {
|
||||
font-family: var(--mono);
|
||||
font-size: .74rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: .16em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
text-align: center;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.contact-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.contact-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 11px 18px;
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, .04);
|
||||
border: 1px solid rgba(255, 255, 255, .1);
|
||||
font-size: .92rem;
|
||||
font-weight: 600;
|
||||
transition: transform .2s ease, border-color .2s ease, background .2s ease;
|
||||
}
|
||||
|
||||
.contact-btn img { width: 18px; height: 18px; opacity: .9; }
|
||||
|
||||
.contact-btn .handle {
|
||||
font-family: var(--mono);
|
||||
font-size: .8rem;
|
||||
font-weight: 400;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.contact-btn:hover {
|
||||
transform: translateY(-3px);
|
||||
border-color: rgba(94, 234, 212, .4);
|
||||
background: rgba(94, 234, 212, .08);
|
||||
}
|
||||
|
||||
.author-cards .card-wide { grid-column: span 2; }
|
||||
|
||||
.card-body .list {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 9px;
|
||||
font-size: .93rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.card-body .list li::before {
|
||||
content: "\203A";
|
||||
color: var(--accent);
|
||||
margin-right: 9px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.card-body strong { color: var(--text); }
|
||||
|
||||
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
|
||||
|
||||
.chip {
|
||||
font-family: var(--mono);
|
||||
font-size: .76rem;
|
||||
padding: 6px 12px;
|
||||
border-radius: 999px;
|
||||
background: rgba(124, 140, 255, .1);
|
||||
border: 1px solid rgba(124, 140, 255, .25);
|
||||
color: #b6beff;
|
||||
}
|
||||
|
||||
/* ---------- кнопка друга ---------- */
|
||||
.friend-cta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
padding: 6px 24px clamp(40px, 7vw, 72px);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.friend-note {
|
||||
font-family: var(--mono);
|
||||
font-size: .78rem;
|
||||
letter-spacing: .1em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.friend-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
padding: 16px 28px;
|
||||
border-radius: 16px;
|
||||
font-weight: 700;
|
||||
font-size: 1.02rem;
|
||||
background: linear-gradient(135deg, rgba(244, 114, 182, .14), rgba(124, 140, 255, .14));
|
||||
border: 1px solid rgba(244, 114, 182, .35);
|
||||
transition: transform .2s ease, box-shadow .2s ease;
|
||||
}
|
||||
|
||||
.friend-btn:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 16px 40px rgba(244, 114, 182, .22);
|
||||
}
|
||||
|
||||
/* ---------- нижняя строка футера / nix webring ---------- */
|
||||
.footer-bottom {
|
||||
max-width: var(--max);
|
||||
margin: 0 auto;
|
||||
padding: 0 24px 26px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.webring {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.webring a {
|
||||
display: inline-block;
|
||||
min-width: 42px;
|
||||
font-family: var(--mono);
|
||||
font-size: .82rem;
|
||||
letter-spacing: .06em;
|
||||
color: var(--muted);
|
||||
padding: 8px 16px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(255, 255, 255, .1);
|
||||
background: rgba(255, 255, 255, .03);
|
||||
transition: color .2s ease, border-color .2s ease, background .2s ease;
|
||||
}
|
||||
|
||||
.webring a:hover {
|
||||
color: var(--accent);
|
||||
border-color: rgba(94, 234, 212, .4);
|
||||
background: rgba(94, 234, 212, .08);
|
||||
}
|
||||
|
||||
.webring .webring-main { font-weight: 600; letter-spacing: .1em; }
|
||||
|
||||
/* ---------- появление ---------- */
|
||||
[data-reveal] {
|
||||
opacity: 0;
|
||||
transform: translateY(26px);
|
||||
transition: opacity .7s cubic-bezier(.22, 1, .36, 1), transform .7s cubic-bezier(.22, 1, .36, 1);
|
||||
}
|
||||
|
||||
[data-reveal].visible { opacity: 1; transform: none; }
|
||||
|
||||
/* ---------- адаптив ---------- */
|
||||
@media (max-width: 900px) {
|
||||
.about { grid-template-columns: 1fr; }
|
||||
.author-cards .card-wide { grid-column: auto; }
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.nav-toggle { display: flex; }
|
||||
|
||||
.nav-links {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 4px;
|
||||
padding: 14px 20px 22px;
|
||||
background: rgba(9, 10, 16, .97);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, .08);
|
||||
transform: translateY(-14px);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity .25s, transform .25s;
|
||||
}
|
||||
|
||||
.nav-links.open {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.nav-links a { padding: 12px 14px; text-align: center; }
|
||||
|
||||
.footer-inner {
|
||||
grid-template-columns: 1fr;
|
||||
text-align: center;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.footer-left, .footer-center, .footer-right {
|
||||
justify-self: center;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after {
|
||||
animation-duration: .01ms !important;
|
||||
transition-duration: .01ms !important;
|
||||
}
|
||||
html { scroll-behavior: auto; }
|
||||
}
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,210 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="300mm"
|
||||
height="207mm"
|
||||
viewBox="0 0 300 207"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<title
|
||||
id="title1">copyparty_logo</title>
|
||||
<defs
|
||||
id="defs1">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient1">
|
||||
<stop
|
||||
style="stop-color:#ffcc55;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop1" />
|
||||
<stop
|
||||
style="stop-color:#ffcc00;stop-opacity:1"
|
||||
offset="0.2"
|
||||
id="stop2" />
|
||||
<stop
|
||||
style="stop-color:#ff8800;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient1"
|
||||
id="linearGradient2"
|
||||
x1="15"
|
||||
y1="15"
|
||||
x2="15"
|
||||
y2="143"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>copyparty_logo</dc:title>
|
||||
<dc:source>github.com/9001/copyparty</dc:source>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
inkscape:label="kassett">
|
||||
<rect
|
||||
style="fill:#333333"
|
||||
id="rect1"
|
||||
width="300"
|
||||
height="205"
|
||||
x="0"
|
||||
y="0"
|
||||
rx="12"
|
||||
ry="12" />
|
||||
<rect
|
||||
style="fill:url(#linearGradient2)"
|
||||
id="rect2"
|
||||
width="270"
|
||||
height="128"
|
||||
x="15"
|
||||
y="15"
|
||||
rx="8"
|
||||
ry="8" />
|
||||
<rect
|
||||
style="fill:#333333"
|
||||
id="rect3"
|
||||
width="172"
|
||||
height="52"
|
||||
x="64"
|
||||
y="72"
|
||||
rx="26"
|
||||
ry="26" />
|
||||
<circle
|
||||
style="fill:#cccccc"
|
||||
id="circle1"
|
||||
cx="91"
|
||||
cy="98"
|
||||
r="18" />
|
||||
<circle
|
||||
style="fill:#cccccc"
|
||||
id="circle2"
|
||||
cx="209"
|
||||
cy="98"
|
||||
r="18" />
|
||||
<path
|
||||
style="fill:#737373;stroke-width:1px"
|
||||
d="m 48,207 10,-39 c 1.79,-6.2 5.6,-7.8 12,-8 60,-1 100,-1 160,0 6.4,0.2 10,1.8 12,8 l 10,39 z"
|
||||
id="path1"
|
||||
sodipodi:nodetypes="ccccccc" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer3"
|
||||
inkscape:label="tekst"
|
||||
style="display:none">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:38.8056px;line-height:1.25;font-family:Akbar;-inkscape-font-specification:Akbar;letter-spacing:3.70417px;word-spacing:0px;fill:#333333"
|
||||
x="47.153069"
|
||||
y="55.548954"
|
||||
id="text1"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1"
|
||||
x="47.153069"
|
||||
y="55.548954"
|
||||
style="-inkscape-font-specification:Akbar"
|
||||
rotate="0 0">copyparty</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer4"
|
||||
inkscape:label="stensatt">
|
||||
<path
|
||||
d="m 63.5,50.9 q -0.85,0.93 -4.73,2.3 -3.6,1.3 -4.4,1.3 -3.3,0 -5.1,-2.1 -1.75,-2 -1.75,-5.36 0,-4.6 3.76,-7.64 3.3,-2.7 7.3,-2.7 0.4,0 0.93,0.74 0.54,0.7 0.54,1.16 0,2.06 -2.2,2.7 -1.36,0.4 -4.04,1.16 -2.2,1.16 -2.2,4.4 0,3.2 2.9,3.2 0.85,0 0.85,0 0.54,0 1.44,-0.16 1.1,-0.23 2.9,-0.74 1.8,-0.54 2.13,-0.54 0.4,0 1.75,0.6 z"
|
||||
style="fill:#333333"
|
||||
id="path11" />
|
||||
<path
|
||||
d="m 87.6,45 q 0,4.2 -3.7,6.95 -3.2,2.3 -6.87,2.3 -3.4,0 -6,-2.6 -2.5,-2.6 -2.5,-6 0,-3.6 3.14,-6.64 3.2,-3 6.8,-3 3.5,0 6.3,2.76 2.83,2.76 2.83,6.25 z m -3.4,0.16 q 0,-2.25 -1.75,-3.7 -1.7,-1.5 -4,-1.5 -0.1,0 -1.6,1.6 -1.44,1.55 -2.44,1.55 -0.6,0 -0.8,-0.3 -1.16,2.3 -1.16,3 0,2.25 2.13,3.4 1.6,0.9 3.6,0.9 2,0 3.76,-1.1 2.25,-1.4 2.25,-3.84 z"
|
||||
style="fill:#333333"
|
||||
id="path12" />
|
||||
<path
|
||||
d="m 112.8,46.8 q 0,2.8 -1.9,4.4 -1.8,1.5 -4.7,1.5 -0.7,0 -2.7,-0.4 -1.9,-0.4 -2.6,-0.4 -2.1,0 -2.1,2.64 0,0.85 0.23,2.6 0.2,1.75 0.2,2.6 0,1.9 -0.77,2.83 -1.44,0 -3,-0.85 -1.46,-9.5 -1.46,-12 0,-3.65 1.75,-8.1 2.37,-6.05 6.45,-6.05 3.7,0 7.3,4.1 3.3,3.84 3.3,7.14 z m -3.8,0.2 q -0.6,-2.2 -2.6,-4.4 -2.3,-2.5 -4.3,-2.5 -1.3,0 -2.33,2.2 -0.9,1.8 -0.9,3.26 0,0.47 0.38,1.24 0.43,0.8 0.85,0.8 1.1,0 3.2,0.3 2.1,0.3 3.2,0.3 0.3,0 1.3,-0.4 1,-0.47 1.3,-0.74 z"
|
||||
style="fill:#333333"
|
||||
id="path13" />
|
||||
<path
|
||||
d="m 133,40 q -2.1,4.1 -3.2,7 -0.1,0.3 -1.6,4.5 -0.4,1.36 -1,4.2 -0.5,2.83 -1,4.2 -1,2.83 -2.3,2.64 -1.4,-0.2 -1.6,-1.6 0,-0.2 0,-0.5 0,-0.16 0.3,-1.5 1,-5.04 1,-6.44 0,-0.54 -0.1,-0.74 -1.4,-2.44 -4.1,-7.4 -2.7,-4.97 -2.4,-7.7 1.5,-1.36 2.1,-1.36 0.4,0 1.1,0.6 0.6,0.6 0.7,1.1 0.8,6.2 4.9,11.1 1,-1.8 1.8,-4.04 0.5,-1.4 1.6,-4.15 1.9,-4.46 3.4,-4.46 0.2,0 0.4,0.1 0.9,0.3 1.3,2.8 z"
|
||||
style="fill:#333333"
|
||||
id="path14" />
|
||||
<path
|
||||
d="m 157.5,48 q 0,2.8 -1.9,4.4 -1.8,1.5 -4.7,1.5 -0.7,0 -2.7,-0.4 -1.9,-0.4 -2.6,-0.4 -2,0 -2,2.64 0,0.85 0.2,2.6 0.2,1.75 0.2,2.6 0,1.9 -0.7,2.83 -1.5,0 -3,-0.85 -1.5,-9.5 -1.5,-11.95 0,-3.65 1.8,-8.1 2.3,-6.05 6.4,-6.05 3.7,0 7.2,4.1 3.3,3.84 3.3,7.14 z m -3.8,0.2 q -0.6,-2.2 -2.6,-4.4 -2.3,-2.5 -4.3,-2.5 -1.3,0 -2.3,2.2 -0.9,1.8 -0.9,3.26 0,0.47 0.4,1.24 0.4,0.8 0.8,0.8 1.1,0 3.2,0.3 2.1,0.3 3.2,0.3 0.3,0 1.3,-0.4 1,-0.47 1.3,-0.74 z"
|
||||
style="fill:#333333"
|
||||
id="path15" />
|
||||
<path
|
||||
d="m 182,53.3 q 0,0.9 -0.6,1.5 -0.6,0.6 -1.4,0.6 -1.6,0 -3,-0.9 -1.4,-0.93 -2.1,-2.3 -0.7,-0.1 -1.5,0.85 -0.9,1.16 -1.1,1.24 -1.2,0.54 -3.9,0.54 -2.2,0 -3.9,-2.44 -1.5,-2.13 -1.5,-4 0,-3.4 3.4,-6.4 3.2,-2.9 6.7,-2.9 0.9,0 1.7,0.6 0.8,0.6 0.8,1.44 0,0.54 -0.4,1.1 2.4,0.9 2.4,2.83 0,0.35 -0.1,1.05 -0.1,0.7 -0.1,1.05 0,0.4 0.1,0.6 0.5,1.3 2.5,3.4 1.9,1.9 1.9,2.2 z m -8.1,-10.1 q -0.4,0 -1.1,-0.1 -0.8,-0.16 -1.1,-0.16 -1.3,0 -3.2,1.94 -1.9,1.94 -1.9,3.3 0,0.8 0.7,1.8 0.9,1.3 2.2,1.3 2.6,0 3.5,-2.9 0.5,-2.6 1,-5.16 z"
|
||||
style="fill:#333333"
|
||||
id="path16" />
|
||||
<path
|
||||
d="m 203.8,42.4 q -0.4,0.4 -1.5,0.4 -0.9,0 -2.5,-0.3 -1.7,-0.3 -2.5,-0.3 -4.7,0 -5.5,6.9 -0.3,3.1 -0.4,3.3 -0.4,1 -1.7,2.3 h -1.1 q -0.7,-1.2 -1.3,-4.1 -0.6,-2.76 -0.6,-4.27 0,-1.16 0.1,-1.5 0.2,-0.54 1,-0.54 0.3,0 0.6,0.3 0.4,0.3 0.4,0.3 1.9,-3.53 3.1,-4.6 1.8,-1.7 5.1,-1.7 1.4,0 3.6,0.9 2.8,1.16 3.3,2.8 z"
|
||||
style="fill:#333333"
|
||||
id="path17" />
|
||||
<path
|
||||
d="m 229.5,37.16 q 0.3,0.8 0.3,1.44 0,1.86 -2.4,1.86 -1,0 -3.5,-0.5 -2.5,-0.54 -3.4,-0.54 -1.3,0 -1.5,0.1 -0.4,0.2 -0.4,1.2 0,2.2 0.6,6.9 0.7,5.86 1.6,6.13 -0.4,0.35 -0.4,1.1 -1.2,0.7 -2.6,0.7 -1.4,0 -2,-3.9 -0.2,-1.36 -0.5,-7.76 -0.2,-4.6 -0.8,-5.5 -0.3,-0.47 -4.3,-0.35 -1,0 -1.6,0.1 -0.5,0 -0.3,0 -0.8,0 -1.2,-0.7 -0.5,-1.3 -0.5,-1.4 0,-1.44 4.1,-2 1.6,-0.16 4.7,-0.5 0,-0.85 -0.1,-2.56 0,-1.75 0,-2.6 0,-4.35 2.1,-4.35 0.5,0 1.1,0.6 0.6,0.6 0.6,1.1 v 7.9 q 1.1,1.2 5,1.7 3.9,0.5 5.3,1.86 z"
|
||||
style="fill:#333333"
|
||||
id="path18" />
|
||||
<path
|
||||
d="m 251.2,40.2 q -2,4.1 -3.2,7 -0.1,0.3 -1.5,4.5 -0.5,1.36 -1,4.2 -0.5,2.83 -1,4.2 -1,2.83 -2.4,2.64 -1.4,-0.2 -1.5,-1.6 -0.1,-0.2 -0.1,-0.5 0,-0.16 0.3,-1.5 1.1,-5.04 1.1,-6.44 0,-0.54 -0.1,-0.74 -1.4,-2.44 -4.1,-7.4 -2.7,-4.97 -2.4,-7.7 1.4,-1.36 2.1,-1.36 0.4,0 1,0.6 0.6,0.6 0.7,1.1 0.9,6.2 4.9,11.1 1,-1.8 1.9,-4.04 0.5,-1.4 1.6,-4.15 1.8,-4.46 3.4,-4.46 0.2,0 0.4,0.1 0.8,0.3 1.2,2.8 z"
|
||||
style="fill:#333333"
|
||||
id="path19" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer5"
|
||||
inkscape:label="tagger">
|
||||
<g
|
||||
id="g1">
|
||||
<path
|
||||
id="path4"
|
||||
style="fill:#333333"
|
||||
d="m 111.4,83.335 -9.526,5.5 2.5,4.33 9.526,-5.5 z m -33.775,19.5 -9.526,5.5 2.5,4.33 9.526,-5.5 z"
|
||||
sodipodi:nodetypes="cccccccccc" />
|
||||
<path
|
||||
id="path5"
|
||||
style="fill:#333333"
|
||||
d="M 88.5,73 V 84 h 5 V 73 Z m 0,39 v 11 h 5 V 112 Z"
|
||||
sodipodi:nodetypes="cccccccccc" />
|
||||
<path
|
||||
id="path6"
|
||||
style="fill:#333333"
|
||||
d="m 68.1,87.665 9.526,5.5 2.5,-4.33 -9.526,-5.5 z m 33.775,19.5 9.527,5.5 2.5,-4.33 -9.527,-5.5 z"
|
||||
sodipodi:nodetypes="cccccccccc" />
|
||||
</g>
|
||||
<g
|
||||
id="g2"
|
||||
transform="rotate(30,150,318.19)">
|
||||
<path
|
||||
id="path7"
|
||||
style="fill:#333333"
|
||||
d="m 111.4,83.335 -9.526,5.5 2.5,4.33 9.526,-5.5 z m -33.775,19.5 -9.526,5.5 2.5,4.33 9.526,-5.5 z"
|
||||
sodipodi:nodetypes="cccccccccc" />
|
||||
<path
|
||||
id="path8"
|
||||
style="fill:#333333"
|
||||
d="M 88.5,73 V 84 h 5 V 73 Z m 0,39 v 11 h 5 V 112 Z"
|
||||
sodipodi:nodetypes="cccccccccc" />
|
||||
<path
|
||||
id="path9"
|
||||
style="fill:#333333"
|
||||
d="m 68.1,87.665 9.526,5.5 2.5,-4.33 -9.526,-5.5 z m 33.775,19.5 9.527,5.5 2.5,-4.33 -9.527,-5.5 z"
|
||||
sodipodi:nodetypes="cccccccccc" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.3 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="#ffffff" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Discord</title><path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="#ffffff" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Forgejo</title><path d="M16.7773 0c1.6018 0 2.9004 1.2986 2.9004 2.9005s-1.2986 2.9004-2.9004 2.9004c-1.0854 0-2.0315-.596-2.5288-1.4787H12.91c-2.3322 0-4.2272 1.8718-4.2649 4.195l-.0007 2.1175a7.0759 7.0759 0 0 1 4.148-1.4205l.1176-.001 1.3385.0002c.4973-.8827 1.4434-1.4788 2.5288-1.4788 1.6018 0 2.9004 1.2986 2.9004 2.9005s-1.2986 2.9004-2.9004 2.9004c-1.0854 0-2.0315-.596-2.5288-1.4787H12.91c-2.3322 0-4.2272 1.8718-4.2649 4.195l-.0007 2.319c.8827.4973 1.4788 1.4434 1.4788 2.5287 0 1.602-1.2986 2.9005-2.9005 2.9005-1.6018 0-2.9004-1.2986-2.9004-2.9005 0-1.0853.596-2.0314 1.4788-2.5287l-.0002-9.9831c0-3.887 3.1195-7.0453 6.9915-7.108l.1176-.001h1.3385C14.7458.5962 15.692 0 16.7773 0ZM7.2227 19.9052c-.6596 0-1.1943.5347-1.1943 1.1943s.5347 1.1943 1.1943 1.1943 1.1944-.5347 1.1944-1.1943-.5348-1.1943-1.1944-1.1943Zm9.5546-10.4644c-.6596 0-1.1944.5347-1.1944 1.1943s.5348 1.1943 1.1944 1.1943c.6596 0 1.1943-.5347 1.1943-1.1943s-.5347-1.1943-1.1943-1.1943Zm0-7.7346c-.6596 0-1.1944.5347-1.1944 1.1943s.5348 1.1943 1.1944 1.1943c.6596 0 1.1943-.5347 1.1943-1.1943s-.5347-1.1943-1.1943-1.1943Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 71 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="#609926" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Gitea</title><path d="M4.209 4.603c-.247 0-.525.02-.84.088-.333.07-1.28.283-2.054 1.027C-.403 7.25.035 9.685.089 10.052c.065.446.263 1.687 1.21 2.768 1.749 2.141 5.513 2.092 5.513 2.092s.462 1.103 1.168 2.119c.955 1.263 1.936 2.248 2.89 2.367 2.406 0 7.212-.004 7.212-.004s.458.004 1.08-.394c.535-.324 1.013-.893 1.013-.893s.492-.527 1.18-1.73c.21-.37.385-.729.538-1.068 0 0 2.107-4.471 2.107-8.823-.042-1.318-.367-1.55-.443-1.627-.156-.156-.366-.153-.366-.153s-4.475.252-6.792.306c-.508.011-1.012.023-1.512.027v4.474l-.634-.301c0-1.39-.004-4.17-.004-4.17-1.107.016-3.405-.084-3.405-.084s-5.399-.27-5.987-.324c-.187-.011-.401-.032-.648-.032zm.354 1.832h.111s.271 2.269.6 3.597C5.549 11.147 6.22 13 6.22 13s-.996-.119-1.641-.348c-.99-.324-1.409-.714-1.409-.714s-.73-.511-1.096-1.52C1.444 8.73 2.021 7.7 2.021 7.7s.32-.859 1.47-1.145c.395-.106.863-.12 1.072-.12zm8.33 2.554c.26.003.509.127.509.127l.868.422-.529 1.075a.686.686 0 0 0-.614.359.685.685 0 0 0 .072.756l-.939 1.924a.69.69 0 0 0-.66.527.687.687 0 0 0 .347.763.686.686 0 0 0 .867-.206.688.688 0 0 0-.069-.882l.916-1.874a.667.667 0 0 0 .237-.02.657.657 0 0 0 .271-.137 8.826 8.826 0 0 1 1.016.512.761.761 0 0 1 .286.282c.073.21-.073.569-.073.569-.087.29-.702 1.55-.702 1.55a.692.692 0 0 0-.676.477.681.681 0 1 0 1.157-.252c.073-.141.141-.282.214-.431.19-.397.515-1.16.515-1.16.035-.066.218-.394.103-.814-.095-.435-.48-.638-.48-.638-.467-.301-1.116-.58-1.116-.58s0-.156-.042-.27a.688.688 0 0 0-.148-.241l.516-1.062 2.89 1.401s.48.218.583.619c.073.282-.019.534-.069.657-.24.587-2.1 4.317-2.1 4.317s-.232.554-.748.588a1.065 1.065 0 0 1-.393-.045l-.202-.08-4.31-2.1s-.417-.218-.49-.596c-.083-.31.104-.691.104-.691l2.073-4.272s.183-.37.466-.497a.855.855 0 0 1 .35-.077z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="#ffffff" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
|
||||
|
After Width: | Height: | Size: 837 B |
@@ -0,0 +1 @@
|
||||
<svg fill="#F46800" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Grafana</title><path d="M23.02 10.59a8.578 8.578 0 0 0-.862-3.034 8.911 8.911 0 0 0-1.789-2.445c.337-1.342-.413-2.505-.413-2.505-1.292-.08-2.113.4-2.416.62-.052-.02-.102-.044-.154-.064-.22-.089-.446-.172-.677-.247-.231-.073-.47-.14-.711-.197a9.867 9.867 0 0 0-.875-.161C14.557.753 12.94 0 12.94 0c-1.804 1.145-2.147 2.744-2.147 2.744l-.018.093c-.098.029-.2.057-.298.088-.138.042-.275.094-.413.143-.138.055-.275.107-.41.166a8.869 8.869 0 0 0-1.557.87l-.063-.029c-2.497-.955-4.716.195-4.716.195-.203 2.658.996 4.33 1.235 4.636a11.608 11.608 0 0 0-.607 2.635C1.636 12.677.953 15.014.953 15.014c1.926 2.214 4.171 2.351 4.171 2.351.003-.002.006-.002.006-.005.285.509.615.994.986 1.446.156.19.32.371.488.548-.704 2.009.099 3.68.099 3.68 2.144.08 3.553-.937 3.849-1.173a9.784 9.784 0 0 0 3.164.501h.08l.055-.003.107-.002.103-.005.003.002c1.01 1.44 2.788 1.646 2.788 1.646 1.264-1.332 1.337-2.653 1.337-2.94v-.058c0-.02-.003-.039-.003-.06.265-.187.52-.387.758-.6a7.875 7.875 0 0 0 1.415-1.7c1.43.083 2.437-.885 2.437-.885-.236-1.49-1.085-2.216-1.264-2.354l-.018-.013-.016-.013a.217.217 0 0 1-.031-.02c.008-.092.016-.18.02-.27.011-.162.016-.323.016-.48v-.253l-.005-.098-.008-.135a1.891 1.891 0 0 0-.01-.13c-.003-.042-.008-.083-.013-.125l-.016-.124-.018-.122a6.215 6.215 0 0 0-2.032-3.73 6.015 6.015 0 0 0-3.222-1.46 6.292 6.292 0 0 0-.85-.048l-.107.002h-.063l-.044.003-.104.008a4.777 4.777 0 0 0-3.335 1.695c-.332.4-.592.84-.768 1.297a4.594 4.594 0 0 0-.312 1.817l.003.091c.005.055.007.11.013.164a3.615 3.615 0 0 0 .698 1.82 3.53 3.53 0 0 0 1.827 1.282c.33.098.66.14.971.137.039 0 .078 0 .114-.002l.063-.003c.02 0 .041-.003.062-.003.034-.002.065-.007.099-.01.007 0 .018-.003.028-.003l.031-.005.06-.008a1.18 1.18 0 0 0 .112-.02c.036-.008.072-.013.109-.024a2.634 2.634 0 0 0 .914-.415c.028-.02.056-.041.085-.065a.248.248 0 0 0 .039-.35.244.244 0 0 0-.309-.06l-.078.042c-.09.044-.184.083-.283.116a2.476 2.476 0 0 1-.475.096c-.028.003-.054.006-.083.006l-.083.002c-.026 0-.054 0-.08-.002l-.102-.006h-.012l-.024.006c-.016-.003-.031-.003-.044-.006-.031-.002-.06-.007-.091-.01a2.59 2.59 0 0 1-.724-.213 2.557 2.557 0 0 1-.667-.438 2.52 2.52 0 0 1-.805-1.475 2.306 2.306 0 0 1-.029-.444l.006-.122v-.023l.002-.031c.003-.021.003-.04.005-.06a3.163 3.163 0 0 1 1.352-2.29 3.12 3.12 0 0 1 .937-.43 2.946 2.946 0 0 1 .776-.101h.06l.07.002.045.003h.026l.07.005a4.041 4.041 0 0 1 1.635.49 3.94 3.94 0 0 1 1.602 1.662 3.77 3.77 0 0 1 .397 1.414l.005.076.003.075c.002.026.002.05.002.075 0 .024.003.052 0 .07v.065l-.002.073-.008.174a6.195 6.195 0 0 1-.08.639 5.1 5.1 0 0 1-.267.927 5.31 5.31 0 0 1-.624 1.13 5.052 5.052 0 0 1-3.237 2.014 4.82 4.82 0 0 1-.649.066l-.039.003h-.287a6.607 6.607 0 0 1-1.716-.265 6.776 6.776 0 0 1-3.4-2.274 6.75 6.75 0 0 1-.746-1.15 6.616 6.616 0 0 1-.714-2.596l-.005-.083-.002-.02v-.056l-.003-.073v-.096l-.003-.104v-.07l.003-.163c.008-.22.026-.45.054-.678a8.707 8.707 0 0 1 .28-1.355c.128-.444.286-.872.473-1.277a7.04 7.04 0 0 1 1.456-2.1 5.925 5.925 0 0 1 .953-.763c.169-.111.343-.213.524-.306.089-.05.182-.091.273-.135.047-.02.093-.042.138-.062a7.177 7.177 0 0 1 .714-.267l.145-.045c.049-.015.098-.026.148-.041.098-.029.197-.052.296-.076.049-.013.1-.02.15-.033l.15-.032.151-.028.076-.013.075-.01.153-.024c.057-.01.114-.013.171-.023l.169-.021c.036-.003.073-.008.106-.01l.073-.008.036-.003.042-.002c.057-.003.114-.008.171-.01l.086-.006h.023l.037-.003.145-.007a7.999 7.999 0 0 1 1.708.125 7.917 7.917 0 0 1 2.048.68 8.253 8.253 0 0 1 1.672 1.09l.09.077.089.078c.06.052.114.107.171.159.057.052.112.106.166.16.052.055.107.107.159.164a8.671 8.671 0 0 1 1.41 1.978c.012.026.028.052.04.078l.04.078.075.156c.023.051.05.1.07.153l.065.15a8.848 8.848 0 0 1 .45 1.34.19.19 0 0 0 .201.142.186.186 0 0 0 .172-.184c.01-.246.002-.532-.024-.856z"/></svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="#ffffff" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Matrix</title><path d="M.632.55v22.9H2.28V24H0V0h2.28v.55zm7.043 7.26v1.157h.033c.309-.443.683-.784 1.117-1.024.433-.245.936-.365 1.5-.365.54 0 1.033.107 1.481.314.448.208.785.582 1.02 1.108.254-.374.6-.706 1.034-.992.434-.287.95-.43 1.546-.43.453 0 .872.056 1.26.167.388.11.716.286.993.53.276.245.489.559.646.951.152.392.23.863.23 1.417v5.728h-2.349V11.52c0-.286-.01-.559-.032-.812a1.755 1.755 0 0 0-.18-.66 1.106 1.106 0 0 0-.438-.448c-.194-.11-.457-.166-.785-.166-.332 0-.6.064-.803.189a1.38 1.38 0 0 0-.48.499 1.946 1.946 0 0 0-.231.696 5.56 5.56 0 0 0-.06.785v4.768h-2.35v-4.8c0-.254-.004-.503-.018-.752a2.074 2.074 0 0 0-.143-.688 1.052 1.052 0 0 0-.415-.503c-.194-.125-.476-.19-.854-.19-.111 0-.259.024-.439.074-.18.051-.36.143-.53.282-.171.138-.319.337-.439.595-.12.259-.18.6-.18 1.02v4.966H5.46V7.81zm15.693 15.64V.55H21.72V0H24v24h-2.28v-.55z"/></svg>
|
||||
|
After Width: | Height: | Size: 954 B |
|
After Width: | Height: | Size: 59 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="#ffffff" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Steam</title><path d="M11.979 0C5.678 0 .511 4.86.022 11.037l6.432 2.658c.545-.371 1.203-.59 1.912-.59.063 0 .125.004.188.006l2.861-4.142V8.91c0-2.495 2.028-4.524 4.524-4.524 2.494 0 4.524 2.031 4.524 4.527s-2.03 4.525-4.524 4.525h-.105l-4.076 2.911c0 .052.004.105.004.159 0 1.875-1.515 3.396-3.39 3.396-1.635 0-3.016-1.173-3.331-2.727L.436 15.27C1.862 20.307 6.486 24 11.979 24c6.627 0 11.999-5.373 11.999-12S18.605 0 11.979 0zM7.54 18.21l-1.473-.61c.262.543.714.999 1.314 1.25 1.297.539 2.793-.076 3.332-1.375.263-.63.264-1.319.005-1.949s-.75-1.121-1.377-1.383c-.624-.26-1.29-.249-1.878-.03l1.523.63c.956.4 1.409 1.5 1.009 2.455-.397.957-1.497 1.41-2.454 1.012H7.54zm11.415-9.303c0-1.662-1.353-3.015-3.015-3.015-1.665 0-3.015 1.353-3.015 3.015 0 1.665 1.35 3.015 3.015 3.015 1.663 0 3.015-1.35 3.015-3.015zm-5.273-.005c0-1.252 1.013-2.266 2.265-2.266 1.249 0 2.266 1.014 2.266 2.266 0 1.251-1.017 2.265-2.266 2.265-1.253 0-2.265-1.014-2.265-2.265z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="#ffffff" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Telegram</title><path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/></svg>
|
||||
|
After Width: | Height: | Size: 757 B |
@@ -0,0 +1,153 @@
|
||||
(() => {
|
||||
"use strict";
|
||||
|
||||
/* ---------- мобильное меню ---------- */
|
||||
const toggle = document.getElementById("navToggle");
|
||||
const links = document.getElementById("navLinks");
|
||||
|
||||
if (toggle && links) {
|
||||
toggle.addEventListener("click", () => {
|
||||
const open = links.classList.toggle("open");
|
||||
toggle.classList.toggle("open", open);
|
||||
toggle.setAttribute("aria-expanded", String(open));
|
||||
});
|
||||
|
||||
links.querySelectorAll("a").forEach((a) =>
|
||||
a.addEventListener("click", () => {
|
||||
links.classList.remove("open");
|
||||
toggle.classList.remove("open");
|
||||
toggle.setAttribute("aria-expanded", "false");
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/* ---------- тень хедера при скролле ---------- */
|
||||
const header = document.querySelector(".site-header");
|
||||
const onScroll = () => header && header.classList.toggle("scrolled", window.scrollY > 8);
|
||||
onScroll();
|
||||
window.addEventListener("scroll", onScroll, { passive: true });
|
||||
|
||||
/* ---------- появление блоков ---------- */
|
||||
const reveal = document.querySelectorAll("[data-reveal]");
|
||||
if ("IntersectionObserver" in window) {
|
||||
const io = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry, i) => {
|
||||
if (entry.isIntersecting) {
|
||||
const el = entry.target;
|
||||
setTimeout(() => el.classList.add("visible"), i * 70);
|
||||
io.unobserve(el);
|
||||
}
|
||||
});
|
||||
},
|
||||
{ threshold: 0.12, rootMargin: "0px 0px -40px 0px" }
|
||||
);
|
||||
reveal.forEach((el) => io.observe(el));
|
||||
} else {
|
||||
reveal.forEach((el) => el.classList.add("visible"));
|
||||
}
|
||||
|
||||
/* ---------- счётчики ---------- */
|
||||
const counters = document.querySelectorAll("[data-count]");
|
||||
const animateCount = (el) => {
|
||||
const target = parseInt(el.dataset.count, 10);
|
||||
const duration = 1400;
|
||||
const start = performance.now();
|
||||
const step = (now) => {
|
||||
const p = Math.min((now - start) / duration, 1);
|
||||
const eased = 1 - Math.pow(1 - p, 3);
|
||||
el.textContent = Math.round(target * eased).toString();
|
||||
if (p < 1) requestAnimationFrame(step);
|
||||
};
|
||||
requestAnimationFrame(step);
|
||||
};
|
||||
|
||||
if ("IntersectionObserver" in window) {
|
||||
const co = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
animateCount(entry.target);
|
||||
co.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
},
|
||||
{ threshold: 0.5 }
|
||||
);
|
||||
counters.forEach((el) => co.observe(el));
|
||||
} else {
|
||||
counters.forEach((el) => (el.textContent = el.dataset.count));
|
||||
}
|
||||
|
||||
/* ---------- печатающийся терминал ---------- */
|
||||
const typed = document.getElementById("typed");
|
||||
if (typed) {
|
||||
const lines = [
|
||||
{ t: '<span class="prompt">$</span> docker ps --format "table {{.Names}}\\t{{.Status}}"', d: 22 },
|
||||
{ t: "\n", d: 0 },
|
||||
{ t: '<span class="dim">NAMES STATUS</span>\n', d: 14 },
|
||||
{ t: "gitea <span class=\"ok\">Up 14 months</span>\n", d: 14 },
|
||||
{ t: "matrix <span class=\"ok\">Up 14 months</span>\n", d: 14 },
|
||||
{ t: "sharkey <span class=\"ok\">Up 14 months</span>\n", d: 14 },
|
||||
{ t: "copyparty <span class=\"ok\">Up 14 months</span>\n", d: 14 },
|
||||
{ t: "grafana <span class=\"ok\">Up 14 months</span>\n", d: 14 },
|
||||
{ t: "4get <span class=\"ok\">Up 14 months</span>\n", d: 14 },
|
||||
{ t: '<span class="prompt">$</span> uptime', d: 22 },
|
||||
{ t: '\n <span class="ok">all systems nominal</span>', d: 14 },
|
||||
{ t: '<span class="prompt">$</span> ', d: 22 },
|
||||
];
|
||||
|
||||
// токенизируем: HTML-теги — атомарные, текст — посимвольно
|
||||
const tokenize = (str) => str.match(/<[^>]+>|./gs) || [];
|
||||
|
||||
let lineIndex = 0;
|
||||
let tokens = [];
|
||||
let pos = 0;
|
||||
let html = "";
|
||||
|
||||
const render = () => {
|
||||
typed.innerHTML = html + '<span class="cursor"></span>';
|
||||
};
|
||||
|
||||
const typeNext = () => {
|
||||
if (lineIndex >= lines.length) {
|
||||
render();
|
||||
return;
|
||||
}
|
||||
|
||||
if (pos === 0) tokens = tokenize(lines[lineIndex].t);
|
||||
|
||||
if (pos < tokens.length) {
|
||||
html += tokens[pos++];
|
||||
render();
|
||||
const step = tokens[pos - 1].startsWith("<")
|
||||
? 0
|
||||
: lines[lineIndex].d + Math.random() * 35;
|
||||
setTimeout(typeNext, step);
|
||||
} else {
|
||||
lineIndex++;
|
||||
pos = 0;
|
||||
setTimeout(typeNext, 190);
|
||||
}
|
||||
};
|
||||
|
||||
const startTyping = () => setTimeout(typeNext, 500);
|
||||
|
||||
if ("IntersectionObserver" in window) {
|
||||
const to = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
startTyping();
|
||||
to.disconnect();
|
||||
}
|
||||
});
|
||||
},
|
||||
{ threshold: 0.3 }
|
||||
);
|
||||
to.observe(typed);
|
||||
} else {
|
||||
startTyping();
|
||||
}
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,233 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Black Raven — SRE/DevOps инженер. Контакты, аккаунты и немного о себе.">
|
||||
<title>Black Raven</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
<link rel="icon" href="{{ url_for('static', filename='images/gitAva.jpeg') }}" type="image/jpeg">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="bg-glow" aria-hidden="true"></div>
|
||||
<div class="grid-overlay" aria-hidden="true"></div>
|
||||
|
||||
<header class="site-header" id="top">
|
||||
<nav class="nav">
|
||||
<a class="logo" href="{{ url_for('index') }}">
|
||||
<span class="logo-mark"></></span>
|
||||
<span class="logo-text">srcoder<span class="accent">.moe</span></span>
|
||||
</a>
|
||||
|
||||
<button class="nav-toggle" id="navToggle" aria-label="Меню" aria-expanded="false">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
|
||||
<ul class="nav-links" id="navLinks">
|
||||
<li><a href="{{ url_for('index') }}">Главная</a></li>
|
||||
<li><a href="{{ url_for('index') }}#services">Сервисы</a></li>
|
||||
<li><a href="{{ url_for('author') }}" class="nav-cta" aria-current="page">Об авторе</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section class="author-hero">
|
||||
<img class="author-avatar"
|
||||
src="{{ url_for('static', filename='images/gitAva.jpeg') }}"
|
||||
alt="Аватар Black Raven" width="190" height="190" data-reveal>
|
||||
|
||||
<h1 class="author-name" data-reveal>Black Raven</h1>
|
||||
<p class="author-role" data-reveal>SRE / DevOps инженер</p>
|
||||
|
||||
<p class="author-bio" data-reveal>
|
||||
Привет! Собираю инфраструктуру как код, автоматизирую рутину
|
||||
и держу собственный сервер — именно на нём живёт всё,
|
||||
что вы видите на главной странице. Здесь коротко о том,
|
||||
кто я и где меня можно найти.
|
||||
</p>
|
||||
|
||||
<div class="contact-groups" data-reveal>
|
||||
<div class="contact-group">
|
||||
<h3>Контактная информация</h3>
|
||||
<div class="contact-buttons">
|
||||
<a class="contact-btn" href="https://t.me/simpleRussianProger" target="_blank" rel="noopener">
|
||||
<img src="{{ url_for('static', filename='images/telegram.svg') }}" alt="" width="18" height="18">
|
||||
Telegram <span class="handle">@simpleRussianProger</span>
|
||||
</a>
|
||||
|
||||
<a class="contact-btn" href="https://matrix.to/#/@raven:srcoder.moe" target="_blank" rel="noopener">
|
||||
<img src="{{ url_for('static', filename='images/matrix.svg') }}" alt="" width="18" height="18">
|
||||
Matrix <span class="handle">@raven:srcoder.moe</span>
|
||||
</a>
|
||||
|
||||
<a class="contact-btn" href="https://discord.com/users/767707485255106590" target="_blank" rel="noopener">
|
||||
<img src="{{ url_for('static', filename='images/discord.svg') }}" alt="" width="18" height="18">
|
||||
Discord <span class="handle">профиль</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="contact-group">
|
||||
<h3>Development</h3>
|
||||
<div class="contact-buttons">
|
||||
<a class="contact-btn" href="https://github.com/BlackCorbeau" target="_blank" rel="noopener">
|
||||
<img src="{{ url_for('static', filename='images/github.svg') }}" alt="" width="18" height="18">
|
||||
GitHub <span class="handle">BlackCorbeau</span>
|
||||
</a>
|
||||
|
||||
<a class="contact-btn" href="https://git.srcoder.moe/Black_Raven" target="_blank" rel="noopener">
|
||||
<img src="{{ url_for('static', filename='images/gitea.svg') }}" alt="" width="18" height="18">
|
||||
Gitea <span class="handle">Black_Raven</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="contact-group">
|
||||
<h3>Games</h3>
|
||||
<div class="contact-buttons">
|
||||
<a class="contact-btn" href="https://steamcommunity.com/profiles/76561199137306791" target="_blank" rel="noopener">
|
||||
<img src="{{ url_for('static', filename='images/steam.svg') }}" alt="" width="18" height="18">
|
||||
Steam <span class="handle">профиль</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="details">
|
||||
<div class="cards author-cards">
|
||||
<article class="card" data-reveal>
|
||||
<div class="card-icon">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path></svg>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3>Образование</h3>
|
||||
<p><strong>2023–2027, ННГУ им. Лобачевского</strong>, Нижний Новгород —
|
||||
программная инженерия.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card" data-reveal>
|
||||
<div class="card-icon">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="7"></circle><polyline points="8.21 13.89 7 23 12 20 17 23 15.79 13.88"></polyline></svg>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3>Достижения</h3>
|
||||
<ul class="list">
|
||||
<li><strong>2025</strong> — хакатон от ИТ-холдинга Т1, 3-е место
|
||||
<a class="inline-link" href="https://disk.rustprogersteam.ru/shr/kvpwutpbt7tt/%D0%A21_%D0%9A%D0%BE%D0%B4_%D0%9C%D0%B0%D1%80%D1%82_Certificate_2025_04_13_17_33_29_145Z_1_compressed.pdf" target="_blank" rel="noopener">сертификат</a></li>
|
||||
<li><strong>2026</strong> — ИТ-марафон «Кейс Лаб», направление
|
||||
«Облачные сервисы»
|
||||
<a class="inline-link" href="https://disk.rustprogersteam.ru/shr/890gdowwch0y/%D0%A0%D0%B5%D0%BC%D0%B8%D0%B7%D0%BE%D0%B2%20%D0%9A%D0%B8%D1%80%D0%B8%D0%BB%D0%BB%20%D0%9B%D1%8C%D0%B2%D0%BE%D0%B2%D0%B8%D1%87.pdf" target="_blank" rel="noopener">сертификат</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card" data-reveal>
|
||||
<div class="card-icon">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="2" y1="12" x2="22" y2="12"></line><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></svg>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3>Языки</h3>
|
||||
<ul class="list">
|
||||
<li>Английский — B2</li>
|
||||
<li>Французский — A1?</li>
|
||||
</ul>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card" data-reveal>
|
||||
<div class="card-icon">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3>Обо мне</h3>
|
||||
<p>Ответственный и пунктуальный, люблю своё дело,
|
||||
умею работать в команде и открыт к обмену опытом.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card card-wide" data-reveal>
|
||||
<div class="card-icon">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="4" width="16" height="16" rx="2" ry="2"></rect><rect x="9" y="9" width="6" height="6"></rect><line x1="9" y1="1" x2="9" y2="4"></line><line x1="15" y1="1" x2="15" y2="4"></line><line x1="9" y1="20" x2="9" y2="23"></line><line x1="15" y1="20" x2="15" y2="23"></line><line x1="20" y1="9" x2="23" y2="9"></line><line x1="20" y1="14" x2="23" y2="14"></line><line x1="1" y1="9" x2="4" y2="9"></line><line x1="1" y1="14" x2="4" y2="14"></line></svg>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3>Навыки</h3>
|
||||
<div class="chips">
|
||||
<span class="chip">Linux</span>
|
||||
<span class="chip">Docker / Compose</span>
|
||||
<span class="chip">Ansible</span>
|
||||
<span class="chip">Terraform</span>
|
||||
<span class="chip">Git</span>
|
||||
<span class="chip">GitHub Actions</span>
|
||||
<span class="chip">Bash</span>
|
||||
<span class="chip">Python</span>
|
||||
<span class="chip">Kubernetes</span>
|
||||
<span class="chip">Argo CD</span>
|
||||
<span class="chip">Vim</span>
|
||||
<span class="chip">сеть и безопасность</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card card-wide" data-reveal>
|
||||
<div class="card-icon">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3>Проекты</h3>
|
||||
<ul class="list">
|
||||
<li><strong>Terraform</strong> — инфраструктура как код:
|
||||
<a class="inline-link" href="https://github.com/BlackCorbeau/final_assessment" target="_blank" rel="noopener">final_assessment</a></li>
|
||||
<li><strong>Argo CD</strong> — GitOps-доставка в Kubernetes:
|
||||
<a class="inline-link" href="https://github.com/BlackCorbeau/lab4" target="_blank" rel="noopener">lab4</a></li>
|
||||
<li><strong>Ansible + Docker</strong> — конфигурация серверов и контейнеризация:
|
||||
<a class="inline-link" href="https://git.rustprogersteam.ru/Black_Raven/MyResume" target="_blank" rel="noopener">MyResume</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="friend-cta" data-reveal>
|
||||
<p class="friend-note">Также рекомендую ознакомиться</p>
|
||||
<a class="friend-btn" href="https://risdeveau.lair.moe" target="_blank" rel="noopener">
|
||||
risdeveau.lair.moe
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="site-footer">
|
||||
<div class="footer-inner">
|
||||
<div class="footer-col footer-left">
|
||||
<span class="footer-badge"><span class="pulse"></span>Сервер существует с 2025 года</span>
|
||||
</div>
|
||||
|
||||
<div class="footer-col footer-center">
|
||||
<a href="https://git.srcoder.moe/Black_Raven/srcoder.moe" rel="noopener">
|
||||
Исходный код сайта
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="footer-col footer-right">
|
||||
<a href="mailto:w0ron.black@yandex.ru">w0ron.black@yandex.ru</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-bottom">
|
||||
<div class="webring">
|
||||
<a href="https://nixwebr.ing/prev/srcoder" rel="external prev" title="Предыдущий сайт">←</a>
|
||||
<a href="https://nixwebr.ing/" rel="external" class="webring-main">Nix webring</a>
|
||||
<a href="https://nixwebr.ing/next/srcoder" rel="external next" title="Следующий сайт">→</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,220 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="srcoder.moe — личный сервер: Gitea, Matrix, Sharkey, Copyparty, Grafana и поиск 4get.">
|
||||
<title>srcoder.moe — мой сервер</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🛰️</text></svg>">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="bg-glow" aria-hidden="true"></div>
|
||||
<div class="grid-overlay" aria-hidden="true"></div>
|
||||
|
||||
<header class="site-header" id="top">
|
||||
<nav class="nav">
|
||||
<a class="logo" href="#top">
|
||||
<span class="logo-mark"></></span>
|
||||
<span class="logo-text">srcoder<span class="accent">.moe</span></span>
|
||||
</a>
|
||||
|
||||
<button class="nav-toggle" id="navToggle" aria-label="Меню" aria-expanded="false">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
|
||||
<ul class="nav-links" id="navLinks">
|
||||
<li><a href="#services">Сервисы</a></li>
|
||||
<li><a href="#about">О сервере</a></li>
|
||||
<li><a href="{{ url_for('author') }}" class="nav-cta">Об авторе</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section class="hero">
|
||||
<h1 class="hero-title" data-reveal>
|
||||
Привет, это <span class="gradient-text">srcoder.moe</span>
|
||||
</h1>
|
||||
|
||||
<p class="hero-subtitle" data-reveal>
|
||||
Самостоятельно развернутый и поддерживаемый мной домашний сервер.
|
||||
Хостинг сервисов для разработки, общения, хранения файлов и мониторинга —
|
||||
всё крутится у меня, а не у чужого провайдера.
|
||||
</p>
|
||||
|
||||
<div class="hero-actions" data-reveal>
|
||||
<a href="#services" class="btn btn-primary">Что тут развёрнуто</a>
|
||||
<a href="#about" class="btn btn-ghost">Подробнее о сервере</a>
|
||||
</div>
|
||||
|
||||
<div class="hero-stats" data-reveal>
|
||||
<div class="stat"><span class="stat-num" data-count="6">0</span><span class="stat-label">сервисов</span></div>
|
||||
<div class="stat"><span class="stat-num" data-count="24">0</span><span class="stat-label">часа аптайма / 7 дней</span></div>
|
||||
<div class="stat"><span class="stat-num" data-count="2025">0</span><span class="stat-label">год запуска</span></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="services">
|
||||
<div class="section-head" data-reveal>
|
||||
<span class="section-tag">// сервисы</span>
|
||||
<h2 class="section-title">Что развёрнуто на сервере</h2>
|
||||
<p class="section-desc">Шесть сервисов, закрывающих все базовые потребности — от кода до поиска.</p>
|
||||
</div>
|
||||
|
||||
<div class="cards">
|
||||
<article class="card" data-reveal>
|
||||
<img class="card-icon" src="{{ url_for('static', filename='images/gitea.svg')}}" alt="" loading="lazy">
|
||||
<div class="card-body">
|
||||
<h3>Gitea</h3>
|
||||
<p>Лёгкая самохостируемая платформа для хранения git-репозиториев:
|
||||
Issues, Pull Requests, вики, CI и права доступа — весь процесс
|
||||
разработки живёт на моём домене, без зависимости от внешних хостингов.</p>
|
||||
</div>
|
||||
<span class="card-badge">git / разработка</span>
|
||||
</article>
|
||||
|
||||
<article class="card" data-reveal>
|
||||
<img class="card-icon" src="{{ url_for('static', filename='images/matrix.svg')}}" alt="" loading="lazy">
|
||||
<div class="card-body">
|
||||
<h3>Matrix</h3>
|
||||
<p>Открытый децентрализованный протокол обмена сообщениями в реальном времени —
|
||||
по сути независимый мессенджер с сквозным шифрованием, комнатами и звонками.
|
||||
Свои данные сервер хранит сам, а общение идёт напрямую между участниками.</p>
|
||||
</div>
|
||||
<span class="card-badge">мессенджер</span>
|
||||
</article>
|
||||
|
||||
<article class="card" data-reveal>
|
||||
<img class="card-icon" src="{{ url_for('static', filename='images/sharkey.png')}}" alt="" loading="lazy">
|
||||
<div class="card-body">
|
||||
<h3>Sharkey</h3>
|
||||
<p>Современный форк федерированной соцсети Misskey: микроблоги, реакции,
|
||||
сторис и ленты. Через протокол ActivityPub аккаунты общаются с другими
|
||||
инстансами Fediverse — то есть это моя собственная соцсеть с мостом
|
||||
в Mastodon и соседние сервера.</p>
|
||||
</div>
|
||||
<span class="card-badge">соцсеть</span>
|
||||
</article>
|
||||
|
||||
<article class="card" data-reveal>
|
||||
<img class="card-icon" src="{{ url_for('static', filename='images/copyparty.svg')}}" alt="" loading="lazy">
|
||||
<div class="card-body">
|
||||
<h3>Copyparty</h3>
|
||||
<p>Самописный файловый сервер с веб-интерфейсом: загрузка, шаринг,
|
||||
инстант-загрузчики, интегрированный файловый браузер и даже
|
||||
возможность стримить звук. Простое и быстрое хранилище
|
||||
для любых файлов — от бэкапов до публичных дистрибутивов.</p>
|
||||
</div>
|
||||
<span class="card-badge">файлы</span>
|
||||
</article>
|
||||
|
||||
<article class="card" data-reveal>
|
||||
<img class="card-icon" src="{{ url_for('static', filename='images/grafana.svg')}}" alt="" loading="lazy">
|
||||
<div class="card-body">
|
||||
<h3>Grafana</h3>
|
||||
<p>Система мониторинга и визуализации: собирает метрики сервера —
|
||||
нагрузку CPU, память, диск, трафик и здоровье сервисов —
|
||||
и рисует их живыми дашбордами. Благодаря ей я вижу, что происходит
|
||||
с машиной, ещё до того, как что-то сломается.</p>
|
||||
</div>
|
||||
<span class="card-badge">мониторинг</span>
|
||||
</article>
|
||||
|
||||
<article class="card card-featured" data-reveal>
|
||||
<img class="card-icon" src="{{ url_for('static', filename='images/4get.png')}}" alt="" loading="lazy">
|
||||
<div class="card-body">
|
||||
<h3>4get</h3>
|
||||
<p>Самописная мета-поисковая система: параллельно опрашивает несколько
|
||||
поисковиков и выдаёт объединённую выдачу без рекламы и слежки.
|
||||
Расположена по адресу <a class="inline-link" href="https://search.srcoder.moe" rel="noopener">search.srcoder.moe</a>.</p>
|
||||
</div>
|
||||
<span class="card-badge">поиск</span>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="about">
|
||||
<div class="about" data-reveal>
|
||||
<div class="about-text">
|
||||
<span class="section-tag">// о сервере</span>
|
||||
|
||||
<p>
|
||||
Хостер моего сервера — <a class="inline-link" href="https://play2go.cloud" rel="noopener">Play2Go</a>:
|
||||
он предоставляет хорошие тарифы на виртуальные серверы по доступной цене
|
||||
и современное оборудование. Из минусов — иногда случаются проблемы с сетью,
|
||||
но в целом для моих задач подходит хорошо.
|
||||
</p>
|
||||
|
||||
<h3 class="about-sub">Характеристики сервера</h3>
|
||||
<dl class="spec-list">
|
||||
<div class="spec-row">
|
||||
<dt>Процессор</dt>
|
||||
<dd>2 vCPU AMD Ryzen 9 5950X</dd>
|
||||
</div>
|
||||
<div class="spec-row">
|
||||
<dt>Оперативная память</dt>
|
||||
<dd>4 GB DDR4</dd>
|
||||
</div>
|
||||
<div class="spec-row">
|
||||
<dt>Хранилище</dt>
|
||||
<dd>120 GB NVMe SSD</dd>
|
||||
</div>
|
||||
<div class="spec-row">
|
||||
<dt>Скорость сети</dt>
|
||||
<dd>До 1 Gbit/s</dd>
|
||||
</div>
|
||||
<div class="spec-row">
|
||||
<dt>Защита от DDoS</dt>
|
||||
<dd>Мощная защита от атак L3–L4</dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
<a href="{{ url_for('author') }}" class="btn btn-primary about-btn">Страница об авторе →</a>
|
||||
</div>
|
||||
<div class="about-terminal" aria-hidden="true">
|
||||
<div class="terminal-bar">
|
||||
<span class="dot red"></span><span class="dot yellow"></span><span class="dot green"></span>
|
||||
<span class="terminal-title">srcoder@srv</span>
|
||||
</div>
|
||||
<pre class="terminal-body"><code id="typed"></code></pre>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="site-footer">
|
||||
<div class="footer-inner">
|
||||
<div class="footer-col footer-left">
|
||||
<span class="footer-badge"><span class="pulse"></span>Сервер существует с 2025 года</span>
|
||||
</div>
|
||||
|
||||
<div class="footer-col footer-center">
|
||||
<a href="https://git.srcoder.moe/Black_Raven/srcoder.moe" rel="noopener">
|
||||
Исходный код сайта
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="footer-col footer-right">
|
||||
<a href="mailto:w0ron.black@yandex.ru">w0ron.black@yandex.ru</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-bottom">
|
||||
<div class="webring">
|
||||
<a href="https://nixwebr.ing/prev/srcoder" rel="external prev" title="Предыдущий сайт">←</a>
|
||||
<a href="https://nixwebr.ing/" rel="external" class="webring-main">Nix webring</a>
|
||||
<a href="https://nixwebr.ing/next/srcoder" rel="external next" title="Следующий сайт">→</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||