/
romatur
/
rn-dev
Обзор
Документация
Войти
/
romatur
/
rn-dev
Код
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
index.html
1 009 строк
65 KB
Roman.Turusov
update resume site & project readme
24 май 2026, 17:50
24 май 2026, 17:50
eed4fed
Код
Авторство
О чём код?
<!doctype html> <html lang="ru"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Роман — Senior Mobile Engineer (React Native)</title> <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet" /> <style> :root { --bg: #0a0a0f; --surface: #12121a; --surface-2: #1a1a26; --border: #2a2a3a; --text: #e8e8f0; --text-dim: #8888a0; --accent: #ff478d; --accent-soft: rgba(255, 71, 141, 0.12); --accent-glow: rgba(255, 71, 141, 0.25); --green: #22c55e; --green-soft: rgba(34, 197, 94, 0.12); } * { margin: 0; padding: 0; box-sizing: border-box; } html { scroll-behavior: smooth; } body { font-family: "Outfit", sans-serif; background: var(--bg); color: var(--text); line-height: 1.6; -webkit-font-smoothing: antialiased; } body::before { content: ""; position: fixed; inset: 0; background: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.03'/%3E%3C/svg%3E"); pointer-events: none; z-index: 9999; } .container { max-width: 860px; margin: 0 auto; padding: 0 24px; } nav { position: fixed; top: 0; left: 0; right: 0; z-index: 100; backdrop-filter: blur(20px); background: rgba(10, 10, 15, 0.8); border-bottom: 1px solid var(--border); } nav .container { display: flex; justify-content: space-between; align-items: center; height: 56px; } nav .logo { font-weight: 600; font-size: 15px; letter-spacing: -0.02em; } nav .logo span { color: var(--accent); } nav .nav-links { display: flex; gap: 24px; } nav .nav-links a { color: var(--text-dim); text-decoration: none; font-size: 13px; font-weight: 500; transition: color 0.2s; } nav .nav-links a:hover { color: var(--text); } .hero { padding: 120px 0 80px; } .hero-grid { display: grid; grid-template-columns: 1fr auto; gap: 48px; align-items: center; } .hero-photo { width: 330px; height: 330px; border-radius: 32px; overflow: hidden; } .hero-photo img { width: 100%; height: 100%; object-fit: cover; object-position: center top; filter: grayscale(0.1) contrast(1.05); -webkit-mask-image: radial-gradient( ellipse 90% 85% at 50% 42%, black 55%, transparent 100% ); mask-image: radial-gradient( ellipse 90% 85% at 50% 42%, black 55%, transparent 100% ); } .status-badge { display: inline-flex; align-items: center; gap: 6px; padding: 6px 14px; border-radius: 100px; background: var(--green-soft); color: var(--green); font-size: 12px; font-weight: 500; margin-bottom: 16px; } .status-badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--green); animation: pulse 2s infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } .hero h1 { font-size: clamp(36px, 5vw, 52px); font-weight: 700; letter-spacing: -0.03em; line-height: 1.1; margin-bottom: 12px; } .hero h1 .accent { color: var(--accent); } .hero-subtitle { font-size: 18px; color: var(--text-dim); font-weight: 300; margin-bottom: 24px; max-width: 480px; } .hero-meta { display: flex; flex-wrap: wrap; gap: 16px; font-size: 13px; color: var(--text-dim); } .hero-meta span { display: flex; align-items: center; gap: 6px; } .hero-cta { display: inline-flex; align-items: center; gap: 6px; margin-top: 20px; padding: 12px 24px; border-radius: 10px; background: var(--accent); color: white; text-decoration: none; font-weight: 600; font-size: 14px; transition: transform 0.2s, box-shadow 0.2s; } .hero-cta:hover { transform: translateY(-2px); box-shadow: 0 8px 24px var(--accent-glow); } section { padding: 64px 0; border-top: 1px solid var(--border); } .section-label { font-family: "JetBrains Mono", monospace; font-size: 12px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 32px; } .about-text { font-size: 16px; color: var(--text-dim); font-weight: 300; line-height: 1.8; max-width: 640px; } .about-text strong { color: var(--text); font-weight: 500; } .stack-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; } .stack-card { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 14px 16px; transition: border-color 0.3s, transform 0.2s; } .stack-card:hover { border-color: var(--accent); transform: translateY(-2px); } .stack-card-label { font-size: 11px; color: var(--text-dim); font-family: "JetBrains Mono", monospace; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 8px; } .stack-card-items { display: flex; flex-wrap: wrap; gap: 4px; } .stack-tag { padding: 3px 8px; border-radius: 6px; background: var(--accent-soft); color: var(--accent); font-size: 12px; font-weight: 500; } .stack-card.is-wide { grid-column: 1 / -1; } .exp-block { position: relative; padding-left: 24px; border-left: 2px solid var(--border); padding-bottom: 40px; } .exp-block:last-child { padding-bottom: 0; } .exp-block::before { content: ""; position: absolute; left: -7px; top: 6px; width: 10px; height: 10px; border-radius: 50%; background: var(--accent); border: 1px solid var(--bg); } .exp-header { display: flex; justify-content: space-between; align-items: baseline; flex-wrap: wrap; gap: 8px; margin-bottom: 4px; } .exp-title { font-size: 17px; font-weight: 600; } .exp-period { font-size: 12px; color: var(--text-dim); font-family: "JetBrains Mono", monospace; } .exp-company { font-size: 14px; color: var(--accent); margin-bottom: 12px; } .exp-bullets { list-style: none; } .exp-bullets li { position: relative; padding-left: 16px; margin-bottom: 8px; font-size: 14px; color: var(--text-dim); line-height: 1.6; } .exp-bullets li::before { content: "›"; position: absolute; left: 0; color: var(--accent); font-weight: 700; } .exp-bullets li strong { color: var(--text); font-weight: 500; } .code-block { background: var(--surface); border: 1px solid var(--border); border-radius: 16px; overflow: hidden; } .code-block:hover { border-color: var(--accent); transform: translateY(-2px); } .code-header { display: flex; align-items: center; gap: 8px; padding: 12px 16px; border-bottom: 1px solid var(--border); font-family: "JetBrains Mono", monospace; font-size: 12px; color: var(--text-dim); } .code-dots { display: flex; gap: 5px; } .code-dots span { width: 10px; height: 10px; border-radius: 50%; background: var(--surface-2); border: 1px solid var(--border); } .contact-card { background: var(--surface); border: 1px solid var(--border); border-radius: 16px; padding: 32px; text-align: center; max-width: 480px; margin: 0 auto; } .contact-card h3 { font-size: 20px; font-weight: 600; margin-bottom: 8px; } .contact-card p { color: var(--text-dim); font-size: 14px; margin-bottom: 24px; } .contact-card p span { display: block; } .contact-actions { display: flex; justify-content: center; align-items: center; gap: 12px; } .contact-action { width: 56px; height: 56px; display: flex; align-items: center; justify-content: center; padding: 0; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border); color: var(--text); text-decoration: none; transition: transform 0.2s, border-color 0.2s, box-shadow 0.2s; } .contact-action:hover { transform: translateY(-2px); border-color: var(--accent); } .contact-action.primary { background: var(--accent); border-color: var(--accent); color: #fff; } .contact-action.primary:hover { box-shadow: 0 8px 24px var(--accent-glow); } .contact-action-main { display: flex; align-items: center; justify-content: center; } .contact-icon { width: 28px; height: 28px; flex: 0 0 28px; display: flex; align-items: center; justify-content: center; } .contact-action:not(.primary) .contact-icon { background: transparent; border: none; } .contact-icon svg { width: 26px; height: 26px; } .contact-telegram-mark { transform: translateX(-1.5px); } .contact-icon img { width: 28px; height: 28px; display: block; object-fit: contain; } .contact-hh-mark { transform: translateX(-1px); } .contact-dialog { width: fit-content; max-width: calc(100vw - 32px); max-height: calc(100vh - 32px); margin: auto; padding: 0; border: none; background: transparent; } .contact-dialog::backdrop { background: rgba(0, 0, 0, 0.34); backdrop-filter: blur(6px); } .contact-modal-link { display: block; position: relative; width: min(420px, calc(100vw - 32px)); aspect-ratio: 1206 / 1482; overflow: hidden; border-radius: 18px; background: var(--surface); box-shadow: 0 20px 60px rgba(0, 0, 0, 0.42); text-decoration: none; } .contact-modal-link::before { content: ""; position: absolute; inset: -16px; background-image: var(--contact-modal-bg); background-position: center; background-size: cover; filter: blur(18px); opacity: 0.62; transform: scale(1.04); } .contact-modal-image-wrap { position: relative; z-index: 1; display: block; width: 100%; height: 100%; overflow: hidden; } .contact-modal-link img { display: block; width: 100%; height: 100%; object-fit: contain; } .contact-modal-link.telegram-modal img { object-fit: cover; object-position: center 43%; } .contact-modal-go { position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; display: flex; align-items: center; justify-content: center; min-height: 46px; color: #fff; font-size: 14px; font-weight: 600; text-decoration: underline; text-underline-offset: 4px; } footer { padding: 32px 0; border-top: 1px solid var(--border); text-align: center; font-size: 12px; color: var(--text-dim); } @keyframes fadeUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } .animate { animation: fadeUp 0.6s ease-out both; } .delay-1 { animation-delay: 0.1s; } .delay-2 { animation-delay: 0.2s; } .delay-3 { animation-delay: 0.3s; } .delay-4 { animation-delay: 0.4s; } @media (max-width: 640px) { .hero-grid { grid-template-columns: 1fr; text-align: center; } .hero-photo { margin: 0 auto 24px; width: 270px; height: 270px; } .hero-meta { justify-content: center; } .hero-subtitle { margin: 0 auto 24px; } .stack-grid { grid-template-columns: 1fr; } .status-badge { margin: 0 auto 16px; } .hero-cta { margin: 20px auto 0; } .contact-card { padding: 24px; } .contact-action { width: 52px; height: 52px; } .contact-icon { width: 26px; height: 26px; flex-basis: 26px; } .exp-header { flex-direction: column; } nav .nav-links { gap: 14px; } nav .nav-links a { font-size: 12px; } } </style> </head> <body> <nav> <div class="container"> <div class="logo">roman<span>.dev</span></div> <div class="nav-links"> <a href="#about">Обо мне</a> <a href="#stack">Стек</a> <a href="#experience">Опыт</a> <a href="#code">Код</a> <a href="#contact">Контакт</a> </div> </div> </nav> <header class="hero"> <div class="container"> <div class="hero-grid animate"> <div> <div class="status-badge">Открыт к проектам</div> <h1>Роман<br /><span class="accent">React Native</span></h1> <p class="hero-subtitle"> Senior Mobile Engineer (React Native) с 8+ годами опыта. Специализация — offline-first, интеграции с бизнес-системами и AI-assisted development. </p> <div class="hero-meta"> <span>Удалённо · загрузка обсуждается</span> </div> <a href="#contact" class="hero-cta">Обсудить сотрудничество</a> </div> <div class="hero-photo"> <img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAQDAwMDAgQDAwMEBAQFBgoGBgUFBgwICQcKDgwPDg4MDQ0PERYTDxAVEQ0NExoTFRcYGRkZDxIbHRsYHRYYGRj/2wBDAQQEBAYFBgsGBgsYEA0QGBgYGBgYGBgYGB … [Строка слишком длинная. Вы можете скачать файл] alt="Роман" /> </div> </div> </div> </header> <section id="about"> <div class="container"> <div class="section-label animate">// обо мне</div> <p class="about-text animate delay-1"> <strong>Senior mobile engineer</strong> с 8+ годами опыта разработки mobile-приложений для retail и enterprise. Специализируюсь на <strong>React Native</strong>, offline-first архитектуре, интеграциях с бизнес-системами и полном цикле разработки: от анализа требований и проектирования до релизов, поддержки и развития production-приложений. Активно использую <strong>AI-инструменты</strong> для ускорения разработки, code review, рефакторинга и снижения рутины. </p> </div> </section> <section id="stack"> <div class="container"> <div class="section-label animate">// технический стек</div> <div class="stack-grid"> <div class="stack-card animate delay-1"> <div class="stack-card-label">Основной стек</div> <div class="stack-card-items"> <span class="stack-tag">React Native</span> <span class="stack-tag">TypeScript</span> </div> </div> <div class="stack-card animate delay-1"> <div class="stack-card-label">Архитектура</div> <div class="stack-card-items"> <span class="stack-tag">Redux</span> <span class="stack-tag">Realm</span> <span class="stack-tag">Offline-first sync</span> </div> </div> <div class="stack-card animate delay-2"> <div class="stack-card-label">UI</div> <div class="stack-card-items"> <span class="stack-tag">React Navigation</span> <span class="stack-tag">Reanimated</span> <span class="stack-tag">Figma</span> </div> </div> <div class="stack-card animate delay-2"> <div class="stack-card-label">Интеграции</div> <div class="stack-card-items"> <span class="stack-tag">REST API</span> <span class="stack-tag">WebSocket</span> <span class="stack-tag">Push Notifications</span> </div> </div> <div class="stack-card animate delay-3 is-wide"> <div class="stack-card-label">Delivery / AI</div> <div class="stack-card-items"> <span class="stack-tag">Git</span> <span class="stack-tag">CI/CD</span> <span class="stack-tag">Sentry</span> <span class="stack-tag">Claude</span> <span class="stack-tag">Codex</span> <span class="stack-tag">MCP</span> </div> </div> </div> </div> </section> <section id="experience"> <div class="container"> <div class="section-label animate">// опыт работы</div> <div class="exp-block animate delay-1"> <div class="exp-header"> <span class="exp-title">Senior React Native Developer</span> <span class="exp-period">2021 — настоящее время</span> </div> <div class="exp-company">Retail / NDA</div> <ul class="exp-bullets"> <li> Разработал <strong>offline-first приложение</strong> для контроля качества складских операций </li> <li> Реализовал фотофиксацию, осмотры, генерацию и печать отчётов, интеграцию со складской системой документооборота </li> <li> Спроектировал механизм офлайн-синхронизации с автоматической отправкой данных после восстановления сети </li> <li> Отвечал за mobile-направление проекта: архитектуру, разработку, релизы, поддержку и развитие приложения </li> </ul> </div> <div class="exp-block animate delay-2"> <div class="exp-header"> <span class="exp-title">Frontend-разработчик</span> <span class="exp-period">2018 — 2021</span> </div> <div class="exp-company">Enterprise / NDA</div> <ul class="exp-bullets"> <li> Разработал приложение для фиксации выполненных работ выездных бригад </li> <li> Участвовал в разработке мобильного приложения кассового аппарата: эквайринг, банковское API, фискальные операции, чековые принтеры </li> <li> Реализовывал интеграции с внешними сервисами и backend API </li> <li> Поддерживал стабильность приложения и улучшал UX в production-среде </li> </ul> </div> </div> </section> <section id="code"> <div class="container"> <div class="section-label animate">// код</div> <a href="https://gitverse.ru/romatur/rn-dev/content/master/rn-dev-project" target="_blank" class="code-block animate delay-1" style=" display: block; text-decoration: none; color: inherit; transition: border-color 0.3s, transform 0.2s; " > <div class="code-header"> <div class="code-dots"><span></span><span></span><span></span></div> gitverse.ru </div> <div style="padding: 24px; display: flex; align-items: center; gap: 16px" > <div style=" width: 48px; height: 48px; border-radius: 12px; background: var(--accent); display: flex; align-items: center; justify-content: center; box-shadow: 0 8px 24px var(--accent-glow); flex-shrink: 0; " > <svg xmlns="http://www.w3.org/2000/svg" fill="#fff" viewBox="0 0 32 32" aria-hidden="true" focusable="false" style=" width: 28px; height: 28px; display: block; " > <path d="M30.428 14.663l-13.095-13.094c-0.35-0.349-0.833-0.565-1.367-0.565s-1.017 0.216-1.367 0.565l0-0-2.713 2.718 3.449 3.449c0.22-0.077 0.473-0.121 0.737-0.121 1.269 0 2.297 1.028 2.297 2.297 0 0.269-0.046 0.526-0.131 0.766l0.005-0.016 3.322 3.324c0.222-0.079 0.479-0.125 0.746-0.125 1.268 0 2.296 1.028 2.296 2.296s-1.028 2.296-2.296 2.296c-1.268 0-2.296-1.028-2.296-2.296 0-0.313 0.063-0.611 0.176-0.883l-0.006 0.015-3.11-3.094v8.154c0.764 0.385 1.279 1.163 1.279 2.061 0 1.27-1.030 2.3-2.3 2.3s-2.3-1.030-2.3-2.3c0-0.634 0.256-1.207 0.671-1.623l-0 0c0.211-0.211 0.462-0.382 0.741-0.502l0.015-0.006v-8.234c-0.842-0.354-1.422-1.173-1.422-2.126 0-0.32 0.065-0.624 0.183-0.901l-0.006 0.015-3.389-3.405-8.98 8.974c-0.348 0.351-0.562 0.834-0.562 1.368s0.215 1.017 0.563 1.368l13.096 13.092c0.349 0.35 0.832 0.566 1.366 0.566s1.016-0.216 1.366-0.566l13.034-13.034c0.35-0.349 0.567-0.833 0.567-1.366s-0.217-1.017-0.567-1.366l-0-0z" /> </svg> </div> <div> <div style="font-size: 15px; font-weight: 600; margin-bottom: 4px" > Пример проекта на GitVerse </div> <div style=" font-size: 13px; color: var(--text-dim); line-height: 1.5; " > React Native · TypeScript · Архитектура, качество кода </div> <div style="font-size: 12px; color: var(--accent); margin-top: 8px" > Открыть репозиторий → </div> </div> </div> </a> </div> </section> <section id="contact"> <div class="container"> <div class="section-label animate">// связаться</div> <div class="contact-card animate delay-1"> <h3>Senior Mobile Engineer</h3> <p> <span>Проектная / постоянная работа, удалённо.</span> </p> <div class="contact-actions"> <a class="contact-action primary" href="https://t.me/romatur" target="_blank" rel="noopener" title="Telegram" aria-label="Открыть Telegram" data-contact-channel="Telegram" data-contact-image="assets/contact-telegram.jpg" > <span class="contact-action-main"> <span class="contact-icon" aria-hidden="true"> <svg class="contact-telegram-mark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" > <path fill="currentColor" d="M41.4193 7.30899C41.4193 7.30899 45.3046 5.79399 44.9808 9.47328C44.8729 10.9883 43.9016 16.2908 43.1461 22.0262L40.5559 39.0159C40.5559 39.0159 40.3401 41.5048 38.3974 41.9377C36.4547 42.3705 33.5408 40.4227 33.0011 39.9898C32.5694 39.6652 24.9068 34.7955 22.2086 32.4148C21.4531 31.7655 20.5897 30.4669 22.3165 28.9519L33.6487 18.1305C34.9438 16.8319 36.2389 13.8019 30.8426 17.4812L15.7331 27.7616C15.7331 27.7616 14.0063 28.8437 10.7686 27.8698L3.75342 25.7055C3.75342 25.7055 1.16321 24.0823 5.58815 22.459C16.3807 17.3729 29.6555 12.1786 41.4193 7.30899Z" /> </svg> </span> </span> </a> <a class="contact-action" href="https://max.ru/u/f9LHodD0cOLitu4m3M-n_h4znGNJloBQ25B3gZT0eYTKqGjiE3m0FxH3VsQ" target="_blank" rel="noopener" title="MAX" aria-label="Открыть MAX" data-contact-channel="MAX" data-contact-image="assets/contact-max.jpeg" > <span class="contact-action-main"> <span class="contact-icon" aria-hidden="true"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 720" > <path fill="currentColor" d="M350.4,9.6C141.8,20.5,4.1,184.1,12.8,390.4c3.8,90.3,40.1,168,48.7,253.7,2.2,22.2-4.2,49.6,21.4,59.3,31.5,11.9,79.8-8.1,106.2-26.4,9-6.1,17.6-13.2,24.2-22,27.3,18.1,53.2,35.6,85.7,43.4,143.1,34.3,299.9-44.2,369.6-170.3C799.6,291.2,622.5-4.6,350.4,9.6h0ZM269.4,504c-11.3,8.8-22.2,20.8-34.7,27.7-18.1,9.7-23.7-.4-30.5-16.4-21.4-50.9-24-137.6-11.5-190.9,16.8-72.5,72.9-136.3,150-143.1,78-6.9,150.4,32.7,183.1,104.2,72.4,159.1-112.9,316.2-256.4,218.6h0Z" /> </svg> </span> </span> </a> <a class="contact-action" href="https://hh.ru/resume/a4e5fbb3ff07ba218c0039ed1f374150315942" target="_blank" rel="noopener" title="HeadHunter" aria-label="Открыть резюме на HeadHunter" > <span class="contact-action-main"> <span class="contact-icon" aria-hidden="true"> <svg class="contact-hh-mark" viewBox="0 0 28 28" fill="currentColor" > <path d="M4.3 6.2h3.2v6.1c.7-.9 1.6-1.3 2.9-1.3 2.5 0 4 1.6 4 4.4v6.4h-3.2v-6c0-1.3-.6-2-1.7-2-1.2 0-2 .8-2 2.2v5.8H4.3V6.2Z" /> <path d="M15.1 6.2h3.2v6.1c.7-.9 1.6-1.3 2.9-1.3 2.5 0 4 1.6 4 4.4v6.4H22v-6c0-1.3-.6-2-1.7-2-1.2 0-2 .8-2 2.2v5.8h-3.2V6.2Z" /> </svg> </span> </span> </a> </div> </div> </div> </section> <footer> <div class="container"> <p>© 2026 Роман · Senior Mobile Engineer</p> </div> </footer> <dialog class="contact-dialog" id="contact-dialog"> <a class="contact-modal-link" id="contact-modal-link" href="#" target="_blank" rel="noopener" > <span class="contact-modal-image-wrap"> <img id="contact-modal-image" src="" alt="" /> </span> <span class="contact-modal-go">Перейти</span> </a> </dialog> <script> const contactDialog = document.getElementById("contact-dialog"); const contactDialogLink = document.getElementById("contact-modal-link"); const contactModalImage = document.getElementById("contact-modal-image"); const mobileContactQuery = window.matchMedia( "(max-width: 720px), (pointer: coarse)", ); document.querySelectorAll("[data-contact-channel]").forEach((link) => { link.addEventListener("click", (event) => { if (mobileContactQuery.matches) { return; } event.preventDefault(); const url = link.href; const channel = link.dataset.contactChannel; const image = link.dataset.contactImage; contactDialogLink.href = url; contactDialogLink.classList.toggle( "telegram-modal", channel === "Telegram", ); contactDialogLink.style.setProperty( "--contact-modal-bg", 'url("' + image + '")', ); contactModalImage.src = image; contactModalImage.alt = "QR-код для " + channel; if (typeof contactDialog.showModal === "function") { contactDialog.showModal(); } else { contactDialog.setAttribute("open", ""); } }); }); contactDialog.addEventListener("click", (event) => { if (event.target === contactDialog) { contactDialog.close(); } }); </script> </body> </html>