diff --git a/static/css/author.css b/static/css/author.css new file mode 100644 index 0000000..0674134 --- /dev/null +++ b/static/css/author.css @@ -0,0 +1,109 @@ +:root { + --bg: #0e1116; + --card: #161b22; + --line: #262d36; + --line-strong: #3a4553; + --ink: #e6edf3; + --muted: #8b98a5; + --accent: #3fb950; + --mono: 'JetBrains Mono', monospace; +} +* { margin: 0; padding: 0; box-sizing: border-box; } +html { scroll-behavior: smooth; } +body { font-family: 'Inter', system-ui, sans-serif; background: var(--bg); color: var(--ink); line-height: 1.6; font-size: 16px; } +.container { max-width: 1080px; margin: 0 auto; padding: 0 24px; } +code { font-family: var(--mono); font-size: .9em; background: var(--card); padding: 1px 5px; } + +header { border-bottom: 1px solid var(--line-strong); position: sticky; top: 0; background: var(--bg); z-index: 10; } +.nav { display: flex; align-items: center; justify-content: space-between; height: 58px; } +.logo { font-family: var(--mono); font-weight: 500; font-size: 15px; color: var(--ink); text-decoration: none; } +.logo b { color: var(--accent); } +.nav-links { display: flex; gap: 4px; list-style: none; } +.nav-links a { color: var(--muted); text-decoration: none; font-size: 13.5px; font-family: var(--mono); padding: 6px 12px; border: 1px solid transparent; } +.nav-links a:hover { color: var(--ink); border-color: var(--line); } +.nav-links a.nav-cta { background: var(--accent); color: #000; border-color: var(--accent); font-weight: 500; } +.nav-links a.nav-cta:hover { color: #000; border-color: var(--accent); opacity: .9; } + +.hero { padding: 48px 0 36px; display: flex; justify-content: space-between; align-items: flex-start; gap: 40px; flex-wrap: wrap; border-bottom: 1px solid var(--line); } +.hero-id { display: flex; align-items: center; gap: 28px; } +.avatar { width: 108px; height: 108px; object-fit: cover; flex: none; border: 1px solid var(--line-strong); } +.hero h1 { font-size: 36px; font-weight: 600; letter-spacing: -0.02em; } +.hero .role { font-family: var(--mono); font-size: 13px; color: var(--accent); margin-top: 4px; } +.hero-contacts { display: flex; flex-direction: column; gap: 14px; min-width: 280px; } + +section { padding: 44px 0; border-bottom: 1px solid var(--line); } +.sec-head { display: flex; align-items: baseline; gap: 14px; margin-bottom: 24px; } +.sec-head .num { font-family: var(--mono); font-size: 13px; color: var(--accent); } +h2 { font-size: 22px; font-weight: 600; letter-spacing: -0.02em; } +.sec-head .rule { flex: 1; height: 1px; background: var(--line); } + +.buttons { display: flex; flex-wrap: wrap; gap: 8px; } +.contact-btn { display: inline-flex; align-items: center; gap: 8px; background: var(--card); border: 1px solid var(--line); padding: 9px 15px; color: var(--ink); text-decoration: none; font-size: 14px; transition: border-color .15s; } +.contact-btn:hover { border-color: var(--accent); } +.contact-btn img { width: 16px; height: 16px; } +.group-label { font-family: var(--mono); font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; } +.hero-contacts .group-label { margin-bottom: 8px; } + +.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); } +.cell { background: var(--card); padding: 24px; } +.cell h3 { font-family: var(--mono); text-transform: uppercase; letter-spacing: .04em; font-size: 12.5px; font-weight: 500; color: var(--accent); margin-bottom: 10px; } +.cell p, .cell li { font-size: 15px; color: var(--muted); } +.cell ul { padding-left: 18px; } +.cell a { color: var(--accent); } +.wide { grid-column: 1 / -1; } + +.chips { display: flex; flex-wrap: wrap; gap: 8px; } +.chip { display: inline-flex; align-items: center; gap: 6px; background: var(--bg); border: 1px solid var(--line); padding: 5px 12px; font-size: 13.5px; } +.chip img { width: 14px; height: 14px; } + +details { border-top: 1px solid var(--line); padding: 14px 0; } +details:first-of-type { border-top: none; } +summary { cursor: pointer; font-size: 15px; font-weight: 600; list-style: none; display: flex; justify-content: space-between; gap: 12px; } +summary::-webkit-details-marker { display: none; } +summary .year { color: var(--accent); font-family: var(--mono); font-size: 12.5px; font-weight: 400; } +details .body { padding-top: 10px; color: var(--muted); font-size: 14.5px; } +.stack { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; } +.stack-tag { font-family: var(--mono); background: var(--bg); border: 1px solid var(--line); padding: 2px 8px; font-size: 12px; } + +.activity-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--line); border: 1px solid var(--line); } +.panel { background: var(--card); padding: 24px; } +.panel-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin-bottom: 14px; } +.panel-head h2 { margin: 0; font-size: 18px; } +.panel-head .meta { display: flex; align-items: center; gap: 10px; } +.meta { font-size: 12px; color: var(--muted); font-family: var(--mono); } +.refresh { background: none; border: 1px solid var(--line); color: var(--muted); font-family: var(--mono); font-size: 13px; line-height: 1; padding: 4px 7px; cursor: pointer; transition: color .15s, border-color .15s; } +.refresh:hover { color: var(--accent); border-color: var(--accent); } +.sub { font-family: var(--mono); font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--accent); margin: 16px 0 8px; } +.sub:first-of-type { margin-top: 0; } +.list { list-style: none; } +.list li { padding: 9px 0; border-bottom: 1px solid var(--line); font-size: 14.5px; color: var(--muted); } +.list li:last-child { border-bottom: none; } +.ym-track { display: flex; } +.ym-link { display: flex; align-items: center; gap: 12px; width: 100%; color: inherit; text-decoration: none; } +.ym-cover { width: 42px; height: 42px; object-fit: cover; flex: none; background: var(--bg); } +.ym-cover-empty { display: flex; align-items: center; justify-content: center; font-size: 20px; } +.ym-info { display: flex; flex-direction: column; min-width: 0; flex: 1; } +.ym-track-title { color: var(--ink); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.ym-artists, .ym-context { font-size: 13px; } +.ym-day { font-size: 13px; flex: none; } +.ym-track.ym-playing .ym-track-title, +.ym-track.ym-playing .ym-artists, +.ym-day.ym-now { color: var(--accent); } +.ym-now-link { display: flex; align-items: center; gap: 14px; text-decoration: none; color: inherit; margin-bottom: 14px; } +.ym-now-cover { width: 60px; height: 60px; object-fit: cover; background: var(--bg); } +.ym-now-info { display: flex; flex-direction: column; } +.ym-error { color: #f85149; } + +.friend-cta { text-align: center; padding: 30px 0 10px; color: var(--muted); font-size: 14px; font-family: var(--mono); } +.friend-cta a { color: var(--accent); font-size: 16px; font-weight: 500; text-decoration: none; } + +footer { border-top: 1px solid var(--line-strong); } +.footer-inner { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; padding: 22px 0; font-size: 14px; color: var(--muted); font-family: var(--mono); } +.footer-inner a { color: var(--muted); text-decoration: none; } +.footer-inner a:hover { color: var(--accent); } + +@media (max-width: 720px) { + .hero { flex-direction: column; align-items: flex-start; } + .hero-id { flex-direction: column; align-items: flex-start; gap: 16px; } + .activity-grid { grid-template-columns: 1fr; } +} diff --git a/static/css/main.css b/static/css/main.css new file mode 100644 index 0000000..d4a62d9 --- /dev/null +++ b/static/css/main.css @@ -0,0 +1,69 @@ +:root { + --bg: #0e1116; + --card: #161b22; + --line: #262d36; + --line-strong: #3a4553; + --ink: #e6edf3; + --muted: #8b98a5; + --accent: #3fb950; + --mono: 'JetBrains Mono', monospace; +} +* { margin: 0; padding: 0; box-sizing: border-box; } +html { scroll-behavior: smooth; } +body { font-family: 'Inter', system-ui, sans-serif; background: var(--bg); color: var(--ink); line-height: 1.6; font-size: 16px; } +.container { max-width: 1080px; margin: 0 auto; padding: 0 24px; } + +header { border-bottom: 1px solid var(--line-strong); background: var(--bg); position: sticky; top: 0; z-index: 10; } +.nav { display: flex; align-items: center; justify-content: space-between; height: 58px; } +.logo { font-family: var(--mono); font-weight: 500; font-size: 15px; color: var(--ink); text-decoration: none; } +.logo b { color: var(--accent); } +.nav-links { display: flex; gap: 4px; list-style: none; } +.nav-links a { + color: var(--muted); text-decoration: none; font-size: 13.5px; + font-family: var(--mono); padding: 6px 12px; border: 1px solid transparent; +} +.nav-links a:hover { color: var(--ink); border-color: var(--line); } +.nav-links a.nav-cta { background: var(--accent); color: #000; border-color: var(--accent); font-weight: 500; } +.nav-links a.nav-cta:hover { color: #000; border-color: var(--accent); opacity: .9; } + +.hero { padding: 80px 0 56px; border-bottom: 1px solid var(--line); } +.hero .idx { font-family: var(--mono); font-size: 13px; color: var(--accent); margin-bottom: 20px; } +.hero h1 { font-size: 46px; font-weight: 600; letter-spacing: -0.03em; line-height: 1.1; max-width: 760px; } +.hero p { margin-top: 20px; font-size: 18px; color: var(--muted); max-width: 620px; } + +section { padding: 56px 0; } +.sec-head { display: flex; align-items: baseline; gap: 14px; margin-bottom: 28px; } +.sec-head .num { font-family: var(--mono); font-size: 13px; color: var(--accent); } +h2 { font-size: 24px; font-weight: 600; letter-spacing: -0.02em; } +.sec-head .rule { flex: 1; height: 1px; background: var(--line); } + +.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); } +.card { background: var(--card); padding: 26px; display: flex; flex-direction: column; } +.card-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; } +.card-top img { width: 26px; height: 26px; object-fit: contain; } +.card-top .num { font-family: var(--mono); font-size: 12px; color: var(--muted); } +.card h3 { font-size: 17px; font-weight: 600; margin-bottom: 8px; } +.card p { font-size: 14.5px; color: var(--muted); flex: 1; } +.card a { color: var(--accent); } +.cat { margin-top: 16px; font-family: var(--mono); font-size: 11.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; } + +.about-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--line); border: 1px solid var(--line); } +.about-grid > div { background: var(--card); padding: 32px; } +.about-grid p { color: var(--muted); margin-bottom: 16px; } +.about-grid a { color: var(--accent); } +.specs { list-style: none; } +.specs li { display: flex; justify-content: space-between; gap: 14px; padding: 11px 0; border-bottom: 1px solid var(--line); font-size: 15px; } +.specs li:first-child { padding-top: 0; } +.specs li:last-child { border-bottom: none; } +.specs li span:first-child { color: var(--muted); font-family: var(--mono); font-size: 13.5px; } +.specs li span:last-child { font-weight: 500; text-align: right; } + +footer { border-top: 1px solid var(--line-strong); } +.footer-inner { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; padding: 24px 0; font-size: 14px; color: var(--muted); font-family: var(--mono); } +.footer-inner a { color: var(--muted); text-decoration: none; } +.footer-inner a:hover { color: var(--accent); } + +@media (max-width: 720px) { + .hero h1 { font-size: 32px; } + .about-grid { grid-template-columns: 1fr; } +} diff --git a/static/css/style.css b/static/css/style.css deleted file mode 100644 index ddc0fbc..0000000 --- a/static/css/style.css +++ /dev/null @@ -1,1209 +0,0 @@ -: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 { - display: inline-flex; - align-items: center; - gap: 7px; - 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; -} - -.chip-icon { width: 14px; height: 14px; flex: none; object-fit: contain; } -.chip-icon-svg { color: #b6beff; } - -/* ---------- карточка проектов с выдвижным списком ---------- */ -.card-flyout { overflow: visible; } - -.card-flyout:hover, -.card-flyout:focus-within, -.card-flyout.flyout-open { z-index: 30; } - -.flyout-hint { - margin-top: auto; - display: inline-flex; - align-items: center; - gap: 7px; - font-family: var(--mono); - font-size: .72rem; - letter-spacing: .05em; - color: var(--muted); -} - -.flyout-hint::before { - content: "▸"; - color: var(--accent); - transition: transform .25s ease; -} - -.card-flyout:hover .flyout-hint::before, -.card-flyout:focus-within .flyout-hint::before, -.card-flyout.flyout-open .flyout-hint::before { transform: rotate(90deg); } - -.flyout { - position: absolute; - top: calc(100% + 12px); - left: 0; - right: 0; - z-index: 30; - opacity: 0; - visibility: hidden; - transform: translateY(-10px); - transition: opacity .25s ease, transform .25s ease, visibility .25s; - pointer-events: none; -} - -.card-flyout:hover .flyout, -.card-flyout:focus-within .flyout, -.card-flyout.flyout-open .flyout { - opacity: 1; - visibility: visible; - transform: none; - pointer-events: auto; -} - -.flyout-inner { - display: flex; - flex-direction: column; - gap: 18px; - padding: 22px; - border-radius: var(--radius); - background: rgba(10, 12, 20, .97); - border: 1px solid rgba(94, 234, 212, .3); - box-shadow: 0 24px 60px rgba(0, 0, 0, .6); - backdrop-filter: blur(14px); - -webkit-backdrop-filter: blur(14px); -} - -.project + .project { - border-top: 1px dashed rgba(255, 255, 255, .1); - padding-top: 18px; -} - -.project-title { - display: flex; - flex-wrap: wrap; - align-items: baseline; - gap: 10px; - font-size: 1rem; - letter-spacing: -0.01em; - margin-bottom: 10px; -} - -.project-year { - font-family: var(--mono); - font-size: .7rem; - color: var(--accent); - border: 1px solid rgba(94, 234, 212, .3); - border-radius: 999px; - padding: 2px 9px; -} - -.project-stack { - display: flex; - flex-wrap: wrap; - gap: 6px; - margin-bottom: 12px; -} - -.stack-tag { - font-family: var(--mono); - font-size: .68rem; - padding: 3px 9px; - border-radius: 999px; - background: rgba(124, 140, 255, .1); - border: 1px solid rgba(124, 140, 255, .25); - color: #b6beff; -} - -.stack-tag.stack-role { - background: rgba(94, 234, 212, .08); - border-color: rgba(94, 234, 212, .3); - color: var(--accent); -} - -.project-points { gap: 7px; font-size: .88rem; } - -.project-points code { - font-family: var(--mono); - font-size: .8rem; - padding: 2px 6px; - border-radius: 6px; - background: rgba(255, 255, 255, .06); - border: 1px solid rgba(255, 255, 255, .08); -} - -/* ---------- трекер Яндекс Музыки ---------- */ -.ym-tracker { - max-width: 880px; - margin: 0 auto; - padding: 0 24px; -} - -.ym-head { - display: flex; - align-items: center; - justify-content: space-between; - gap: 14px; - flex-wrap: wrap; - margin-bottom: 18px; -} - -.ym-title { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; } - -.ym-title h2 { - font-size: clamp(1.1rem, 3vw, 1.4rem); - letter-spacing: -0.02em; -} - -.ym-live { - display: inline-flex; - align-items: center; - gap: 7px; - font-family: var(--mono); - font-size: .68rem; - letter-spacing: .14em; - text-transform: uppercase; - color: var(--accent); - padding: 4px 10px; - border-radius: 999px; - background: rgba(94, 234, 212, .08); - border: 1px solid rgba(94, 234, 212, .3); -} - -.ym-now { - display: flex; - align-items: center; - gap: 16px; - padding: 14px 16px; - margin-bottom: 16px; - border: 1px solid rgba(94, 234, 212, .25); - border-radius: 12px; - background: linear-gradient(120deg, rgba(94, 234, 212, .07), rgba(255, 255, 255, .02)); - flex-wrap: wrap; -} - -.ym-now-label { - display: inline-flex; - align-items: center; - gap: 7px; - font-family: var(--mono); - font-size: .68rem; - letter-spacing: .14em; - text-transform: uppercase; - color: var(--accent); - flex-shrink: 0; -} - -.ym-now-body { min-width: 0; } - -.ym-now-link { - display: flex; - align-items: center; - gap: 12px; - min-width: 0; - color: inherit; - text-decoration: none; -} - -a.ym-now-link:hover .ym-track-title { color: var(--accent); } - -.ym-now-cover { - width: 72px; - height: 72px; - border-radius: 8px; - object-fit: cover; - flex-shrink: 0; - background: rgba(255, 255, 255, .06); -} - -.ym-now-cover.ym-cover-empty { font-size: 1.5rem; } - -.ym-now-info { display: flex; flex-direction: column; gap: 3px; min-width: 0; } - -.ym-now-idle { - font-family: var(--mono); - font-size: .8rem; - color: var(--muted); -} - -.ym-meta { - display: flex; - align-items: center; - gap: 10px; - font-family: var(--mono); - font-size: .74rem; - color: var(--muted); -} - -.ym-refresh { - font: inherit; - color: var(--muted); - background: rgba(255, 255, 255, .04); - border: 1px solid rgba(255, 255, 255, .1); - border-radius: 8px; - padding: 3px 9px; - cursor: pointer; - transition: color .2s, border-color .2s; -} - -.ym-refresh:hover { color: var(--accent); border-color: rgba(94, 234, 212, .4); } - -.ym-list { - list-style: none; - display: flex; - flex-direction: column; - gap: 8px; - counter-reset: ym; -} - -.ym-status { - font-family: var(--mono); - font-size: .84rem; - color: var(--muted); - padding: 18px; - text-align: center; - background: var(--card); - border: 1px dashed var(--card-border); - border-radius: var(--radius); -} - -.ym-status.ym-error { color: #fca5a5; border-color: rgba(248, 113, 113, .35); } - -.ym-track { counter-increment: ym; } - -.ym-link { - display: flex; - align-items: center; - gap: 14px; - padding: 10px 14px; - background: var(--card); - border: 1px solid var(--card-border); - border-radius: 14px; - transition: transform .2s ease, border-color .2s ease, background .2s ease; -} - -.ym-link::before { - content: counter(ym, decimal-leading-zero); - font-family: var(--mono); - font-size: .74rem; - color: var(--muted); - min-width: 22px; -} - -.ym-link:hover { - transform: translateX(4px); - border-color: rgba(94, 234, 212, .4); - background: rgba(94, 234, 212, .06); -} - -.ym-cover { - width: 48px; - height: 48px; - border-radius: 8px; - object-fit: cover; - flex-shrink: 0; - background: rgba(255, 255, 255, .06); -} - -.ym-cover-empty { - display: inline-flex; - align-items: center; - justify-content: center; - color: var(--accent); - font-size: 1.1rem; -} - -.ym-info { display: flex; flex-direction: column; min-width: 0; flex: 1; } - -.ym-track-title { - font-weight: 600; - font-size: .95rem; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.ym-artists { - font-size: .82rem; - color: var(--muted); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.ym-context { font-family: var(--mono); font-size: .74rem; } - -.ym-day { - font-family: var(--mono); - font-size: .72rem; - letter-spacing: .06em; - text-transform: uppercase; - color: var(--muted); - flex-shrink: 0; -} - -.ym-day.ym-now { - color: var(--accent); - animation: ym-blink 1.6s ease-in-out infinite; -} - -.ym-track.ym-playing .ym-link { - border-color: rgba(94, 234, 212, .45); - background: rgba(94, 234, 212, .06); -} - -@keyframes ym-blink { - 0%, 100% { opacity: 1; } - 50% { opacity: .45; } -} - -.ym-track.ym-new .ym-link { - animation: ym-pop .6s cubic-bezier(.22, 1, .36, 1); - border-color: rgba(94, 234, 212, .55); - box-shadow: 0 0 0 3px rgba(94, 234, 212, .12); -} - -@keyframes ym-pop { - from { opacity: 0; transform: translateY(-8px) scale(.98); } - to { opacity: 1; transform: none; } -} - -@media (max-width: 760px) { - .ym-day { display: none; } - .ym-link { padding: 9px 11px; gap: 10px; } -} - -/* ---------- активность: музыка слева, Steam справа ---------- */ -.activity-grid { - display: grid; - grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); - gap: 26px; - align-items: start; -} - -.activity-grid .ym-tracker { - max-width: none; - margin: 0; - padding: 0; -} - -.steam-panel { min-width: 0; } - -.st-sub { - display: flex; - align-items: center; - gap: 12px; - margin: 18px 0 10px; -} - -.st-sub h3 { - font-family: var(--mono); - font-size: .74rem; - font-weight: 600; - letter-spacing: .12em; - text-transform: uppercase; - color: var(--muted); - white-space: nowrap; -} - -.st-sub::after { - content: ""; - flex: 1; - height: 1px; - background: rgba(255, 255, 255, .07); -} - -.st-foot { - display: flex; - align-items: center; - justify-content: space-between; - flex-wrap: wrap; - gap: 8px 14px; - margin-top: 16px; - font-family: var(--mono); - font-size: .76rem; - color: var(--muted); -} - -@media (max-width: 900px) { - .activity-grid { grid-template-columns: 1fr; } -} - -/* ---------- кнопка друга ---------- */ -.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); -} - -/* ---------- появление ---------- */ -[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; } - - .flyout { - position: static; - display: none; - opacity: 1; - visibility: visible; - transform: none; - pointer-events: auto; - margin-top: 16px; - } - - .card-flyout.flyout-open .flyout { display: block; } -} - -@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; } -} diff --git a/static/js/main.js b/static/js/main.js deleted file mode 100644 index eaeac91..0000000 --- a/static/js/main.js +++ /dev/null @@ -1,176 +0,0 @@ -(() => { - "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 flyoutCards = document.querySelectorAll(".card-flyout"); - - flyoutCards.forEach((card) => { - card.addEventListener("click", (e) => { - if (e.target.closest("a")) return; - card.classList.toggle("flyout-open"); - }); - }); - - document.addEventListener("click", (e) => { - flyoutCards.forEach((card) => { - if (!card.contains(e.target)) card.classList.remove("flyout-open"); - }); - }); - - document.addEventListener("keydown", (e) => { - if (e.key === "Escape") { - flyoutCards.forEach((card) => card.classList.remove("flyout-open")); - } - }); - - /* ---------- печатающийся терминал ---------- */ - const typed = document.getElementById("typed"); - if (typed) { - const lines = [ - { t: '$ docker ps --format "table {{.Names}}\\t{{.Status}}"', d: 22 }, - { t: "\n", d: 0 }, - { t: 'NAMES STATUS\n', d: 14 }, - { t: "gitea Up 14 months\n", d: 14 }, - { t: "matrix Up 14 months\n", d: 14 }, - { t: "sharkey Up 14 months\n", d: 14 }, - { t: "copyparty Up 14 months\n", d: 14 }, - { t: "grafana Up 14 months\n", d: 14 }, - { t: "freshrss Up 14 months\n", d: 14 }, - { t: "4get Up 14 months\n", d: 14 }, - { t: '$ uptime', d: 22 }, - { t: '\n all systems nominal', d: 14 }, - { t: '$ ', d: 22 }, - ]; - - // токенизируем: HTML-теги — атомарные, текст — посимвольно - const tokenize = (str) => str.match(/<[^>]+>|./gs) || []; - - let lineIndex = 0; - let tokens = []; - let pos = 0; - let html = ""; - - const render = () => { - typed.innerHTML = html + ''; - }; - - 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(); - } - } -})(); diff --git a/templates/author.html b/templates/author.html index 29c47de..dc125c6 100644 --- a/templates/author.html +++ b/templates/author.html @@ -4,335 +4,168 @@ - Black Raven + Black Raven — srcoder.moe - - + + - - - - -
-
- Аватар Black Raven +
+
+
+ Аватар Black Raven +
+

Black Raven

+
SRE / DevOps инженер
+
+
-

Black Raven

-

SRE / DevOps инженер

- -

- Привет! Собираю инфраструктуру как код, автоматизирую рутину - и держу собственный сервер — именно на нём живёт всё, - что вы видите на главной странице. Здесь коротко о том, - кто я и где меня можно найти. -

- -
-
-

Контактная информация

-
- - - Telegram - - - - - Matrix - - - - - Discord - +
+
+
Связь
+
- -
-

Development

-
- - - GitHub - - - - - Gitea - +
+
Разработка
+
- -
-

Games

-
- - - Steam - +
+
Игры
+
+ steam
-
-
-
-
- +
+
01

Немного фактов

+
+
+

Образование

+

2023–2027, ННГУ им. Лобачевского, Нижний Новгород — программная инженерия.

+
+
+

Достижения

+
    +
  • 2025 — хакатон от ИТ-холдинга Т1, 3-е место (сертификат)
  • +
  • 2026 — ИТ-марафон «Кейс Лаб», «Облачные сервисы» (сертификат)
  • +
+
+
+

Языки

+
    +
  • Английский — B2
  • +
  • Французский — A1?
  • +
+
+
+

Навыки

+
+ Linux + Docker / Compose + Ansible + Terraform + Git + GitHub Actions + Bash + Python + Kubernetes + Argo CD + Vim + сеть и безопасность
-
-

Образование

-

2023–2027, ННГУ им. Лобачевского, Нижний Новгород — - программная инженерия.

-
-
- -
-
- -
-
-

Достижения

-
    -
  • 2025 — хакатон от ИТ-холдинга Т1, 3-е место - сертификат
  • -
  • 2026 — ИТ-марафон «Кейс Лаб», направление - «Облачные сервисы» - сертификат
  • -
-
-
- -
-
- -
-
-

Языки

-
    -
  • Английский — B2
  • -
  • Французский — A1?
  • -
-
-
- -
-
- -
-
-

Обо мне

-

Ответственный и пунктуальный, люблю своё дело, - умею работать в команде и открыт к обмену опытом.

-
-
- -
-
- -
-
-

Навыки

-
- Linux - Docker / Compose - Ansible - Terraform - Git - GitHub Actions - Bash - Python - Kubernetes - Argo CD - Vim - сеть и безопасность +
+
+

Проекты

+
+ Отказоустойчивый веб-хостинг в VK Cloud 2026 +
+
+ TerraformDockerGitHub ActionsPostgreSQLL7 LB +
+ Спроектировал облачную инфраструктуру: VPC с public/private-подсетями, 2 web-VM в приватном контуре, bastion и управляемую PostgreSQL; доступ через L7 Load Balancer. Terraform со S3 backend, CI/CD в GitHub Actions, проверка отказоустойчивости тестом ab -n 1000 -c 10.
-
-
- -
-
- -
-
-

Проекты

-
    -
  • Отказоустойчивый веб-хостинг в VK Cloud
  • -
  • Мониторинг веб-инфраструктуры в VK Cloud
  • -
  • CI/CD и GitOps для Kubernetes
  • -
-
- наведите курсор — расскажу подробнее - -
-
-
-

Отказоустойчивый веб-хостинг в VK Cloud 2026

-
- Terraform - Docker - GitHub Actions - PostgreSQL - L7 Load Balancer - личный проект - GitHub -
-
    -
  • Спроектировал облачную инфраструктуру: VPC с public/private-подсетями, 2 web-VM в приватном контуре, bastion и управляемую PostgreSQL; веб-доступ организовал через L7 Load Balancer.
  • -
  • Описал инфраструктуру в Terraform, настроил S3 backend для state и security groups: SSH ограничен моим IP, PostgreSQL доступна только из приватной подсети.
  • -
  • Настроил запуск Flask/Gunicorn в Docker и CI/CD в GitHub Actions с этапами plan → apply → destroy; параметры облака передаются через GitHub Secrets.
  • -
  • Проверил отказоустойчивость остановкой контейнера на одном web-сервере и нагрузочным тестом ab -n 1000 -c 10: 999 успешных запросов из 1000, 76.54 req/s.
  • -
-
- -
-

Мониторинг веб-инфраструктуры в VK Cloud 2026

-
- Terraform - Prometheus - Grafana - Alertmanager - Node Exporter - L7 Load Balancer - личный проект -
-
    -
  • Развернул через Terraform 2 web-VM в приватной подсети, bastion/monitoring-VM и L7 Load Balancer с HTTP health-check для контроля доступности сервисов.
  • -
  • Автоматизировал установку и запуск Prometheus, Grafana, Alertmanager и Node Exporter через user_data и systemd; Prometheus собирает метрики с monitoring- и web-узлов каждые 15 секунд.
  • -
  • Добавил правило алерта InstanceDown с условием недоступности узла более 5 минут и настроил сетевые правила для мониторинговых endpoints.
  • -
-
- -
-

CI/CD и GitOps для Kubernetes 2026

-
- Terraform - GitHub Actions - Kubernetes - Argo CD - Kustomize - GitHub -
-
    -
  • Описал инфраструктуру VK Cloud и Kubernetes-ресурсы в Git: Deployment, Service, ConfigMap и Kustomize; приложение разворачивается в двух репликах.
  • -
  • Настроил GitHub Actions: validate и plan запускаются для изменений, артефакт tfplan передаётся в этап apply после успешного плана.
  • -
  • Интегрировал pipeline с GitOps-подходом: после Terraform Apply workflow получает IP балансировщика, обновляет ConfigMap и коммитит изменение обратно в Git для дальнейшей синхронизации в Kubernetes.
  • -
+ +
+ Мониторинг веб-инфраструктуры в VK Cloud 2026 +
+
+ TerraformPrometheusGrafanaAlertmanagerNode Exporter
+ Развернул 2 web-VM в приватной подсети, bastion/monitoring-VM и L7 Load Balancer с HTTP health-check. Установку сервисов автоматизировал через user_data и systemd; добавил алерт InstanceDown на недоступность узла более 5 минут.
-
-
+ +
+ CI/CD и GitOps для Kubernetes 2026 +
+
+ TerraformGitHub ActionsKubernetesArgo CDKustomize +
+ Описал инфраструктуру и Kubernetes-ресурсы в Git (Deployment, Service, ConfigMap, Kustomize). Настроил validate/plan/apply в GitHub Actions и GitOps-синхронизацию через Argo CD. +
+
+
-
+
+
02

Чем я занят

-
-
-
-
-

Что я слушаю

-
-
- подключение… - -
-
- -
- играет сейчас -
проверяю…
-
- -
    -
  1. Загрузка истории…
  2. -
+
+
+

Что я слушаю

+ подключение…
+
+
  1. Загрузка истории…
- -
-
-
-
-

Во что я играю

-
-
- подключение… - -
-
- -

Недавно Играл

-
    -
  1. Загрузка…
  2. -
- -

Больше всего времени

-
    -
  1. Загрузка…
  2. -
- -

- профиль Steam - -

+
+
+

Во что я играю

+ подключение…
+
Недавно играл
+
  1. Загрузка…
+
Больше всего времени
+
  1. Загрузка…
-
-

Также рекомендую ознакомиться

- - risdeveau.lair.moe - +
+

# также рекомендую ознакомиться

+ risdeveau.lair.moe
-