Dmytro Chernyshov
Was ich mache
Meine Projekte
AI-Skills & Tools
Über mich
Kontakt
DE
EN
Product Owner · Data & Prototyping
Kontakt
E-Mail
chernyshovdmytro1@gmail.com
LinkedIn
Profil ansehen
'+esc(T(c.note))+'' : ''; var verify = c.url ? '
'+esc(tr('about.certs_verify'))+' \u2197
' : ''; var pdfBtn = c.pdf ? '
'+esc(tr('about.certs_pdf_view'))+'
' : ''; return '
'+esc(T(c.title))+'
' + '
'+esc(T(c.issuer))+'
'+note+'
' + '
'+esc(c.date)+'
'+verify+pdfBtn+'
' + (c.pdf ? '
' : '') + '
'; }).join(''); } function aboutPageHTML(){ var d = I18N[LANG]||I18N.de; var a = d.about; var li = '
' + '
' + '
' + '
'+esc(a.linkedin_cta)+'
' + (CV_DATA ? '
' + '
' + '
'+esc(a.cv_cta||'CV (PDF)')+'
' : '') + '
'; return '
' + '
← '+esc(tr('ui.back_home'))+'
' + '
' + '
'+(ABOUT_PHOTO ? '
' : '
'+esc(a.photo_hint)+'
')+'
' + '
'+esc(a.heading)+'
' + '
'+esc(a.p1)+'
'+esc(a.p2)+'
'+(a.p3?'
'+esc(a.p3)+'
':'')+(a.p4?'
'+esc(a.p4)+'
':'')+li+'
' + '
' + '
'+esc(a.certs_heading)+'
'+certListHTML()+'
' + '
'; } function isNarrow(){ return window.matchMedia && window.matchMedia('(max-width:640px)').matches; } function _fit(h1){ var avail=h1.parentNode.clientWidth; if(!avail) return; var min=18,max=72,best=min; for(var i=0;i<14;i++){ var mid=(min+max)/2; h1.style.fontSize=mid+'px'; if(h1.scrollWidth<=avail){best=mid;min=mid;}else{max=mid;} } h1.style.fontSize=best+'px'; } function fitTitle(){ /* uniform CSS font-size; no per-title scaling */ } function initDocToc(){ var items = Array.prototype.slice.call(document.querySelectorAll('.doc-toc .toc-item')); if(!items.length) return; var sections = items.map(function(it){ return document.getElementById(it.getAttribute('data-toc')); }); function show(idx){ items.forEach(function(it,i){ it.classList.toggle('is-active', i===idx); }); sections.forEach(function(sec,i){ if(sec) sec.classList.toggle('is-shown', i===idx); }); } show(0); window._docShow = show; // used by the click handler } function renderPage(){ var page = document.getElementById('page'); if(!current){ page.innerHTML=''; document.documentElement.classList.remove('page-mode'); document.title = tr('meta.title'); return; } if(current.kind==='project'){ var p = bySlug(current.slug); if(!p){ current=null; renderPage(); return; } page.innerHTML = projectPageHTML(p); document.title = (p[LANG]||p.de).title + ' — Dmytro Chernyshov'; initDocToc(); fitTitle(); loadApp(p.slug); } else if(current.kind==='skill'){ var sk = skillBySlug(current.slug); if(!sk){ current=null; renderPage(); return; } page.innerHTML = skillPageHTML(sk); document.title = (sk[LANG]||sk.de).title + ' — Dmytro Chernyshov'; fitTitle(); } else if(current.kind==='skills'){ page.innerHTML = allSkillsHTML(); document.title = tr('models.heading') + ' — Dmytro Chernyshov'; } else if(current.kind==='about'){ page.innerHTML = aboutPageHTML(); document.title = tr('nav.about') + ' — Dmytro Chernyshov'; } else { page.innerHTML = allProjectsHTML(); document.title = tr('projects.heading') + ' — Dmytro Chernyshov'; } document.documentElement.classList.add('page-mode'); } function openProject(slug){ current={kind:'project', slug:slug}; renderPage(); window.scrollTo(0,0); }function openAll(){ current={kind:'all'}; renderPage(); window.scrollTo(0,0); } function openSkill(slug){ current={kind:'skill', slug:slug}; renderPage(); window.scrollTo(0,0); } function openAllSkills(){ current={kind:'skills'}; renderPage(); window.scrollTo(0,0); } function openAbout(){ current={kind:'about'}; renderPage(); window.scrollTo(0,0); } function goHome(anchor){ current=null; renderPage(); closeMenus(); if(anchor){ var el=document.getElementById(anchor); if(el){ el.scrollIntoView({behavior:'smooth', block:'start'}); return; } } window.scrollTo(0,0); } function applyLang(lang){ if(LANGS.indexOf(lang)<0) lang='de'; LANG=lang; store('dc-lang', lang); var y = window.scrollY; renderHome(); renderPage(); window.scrollTo(0, y); } /* ---------- chrome ---------- */ function openContact(){ var m=document.getElementById('contact-modal'); if(m){ m.hidden=false; document.body.style.overflow='hidden'; } } function closeContact(){ var m=document.getElementById('contact-modal'); if(m){ m.hidden=true; document.body.style.overflow=''; } } function closeMenus(){ document.querySelectorAll('.navdrop').forEach(function(d){ d.classList.remove('open'); var t=d.querySelector('.navdrop-t'); if(t) t.setAttribute('aria-expanded','false'); }); var header=document.querySelector('.site-header'), nav=header.querySelector('nav'), mb=document.getElementById('menu-toggle'); nav.classList.remove('is-open'); header.classList.remove('is-open'); mb.setAttribute('aria-expanded','false'); } document.addEventListener('click', function(e){ var t = e.target.closest ? e.target : null; if(!t) return; var el; if((el=t.closest('[data-project]'))){ e.preventDefault(); openProject(el.getAttribute('data-project')); closeMenus(); return; } if((el=t.closest('[data-cv]'))){ e.preventDefault(); if(!CV_DATA) return; try{ var bin=atob(CV_DATA), bytes=new Uint8Array(bin.length); for(var i=0;i
=0 && window._docShow){ window._docShow(idx); } return; } if((el=t.closest('[data-projects-all]'))){ e.preventDefault(); openAll(); closeMenus(); return; } if((el=t.closest('[data-skill]'))){ e.preventDefault(); openSkill(el.getAttribute('data-skill')); closeMenus(); return; } if((el=t.closest('[data-skills-all]'))){ e.preventDefault(); openAllSkills(); closeMenus(); return; } if((el=t.closest('[data-about]'))){ e.preventDefault(); openAbout(); closeMenus(); return; } if((el=t.closest('[data-pdf]'))){ e.preventDefault(); var id = el.getAttribute('data-pdf'); var holder = document.getElementById('certpdf-'+id); if(!holder) return; if(holder.getAttribute('data-open')==='1'){ var oldUrl = holder.getAttribute('data-url'); if(oldUrl) URL.revokeObjectURL(oldUrl); holder.innerHTML=''; holder.removeAttribute('data-open'); holder.removeAttribute('data-url'); return; } var src = document.getElementById(id); if(!src) return; try{ var bin = atob(src.textContent.trim()); var bytes = new Uint8Array(bin.length); for(var i=0;i
'; holder.setAttribute('data-open','1'); holder.setAttribute('data-url', url); holder.scrollIntoView({behavior:'smooth', block:'nearest'}); }catch(err){} return; } if((el=t.closest('[data-download-skill]'))){ e.preventDefault(); downloadSkill(el.getAttribute('data-download-skill')); return; } if((el=t.closest('[data-home]'))){ e.preventDefault(); goHome(); return; } if((el=t.closest('[data-anchor]'))){ e.preventDefault(); goHome(el.getAttribute('data-anchor')); return; } if((el=t.closest('[data-lang]'))){ applyLang(el.getAttribute('data-lang')); return; } if((el=t.closest('.navdrop-t'))){ e.stopPropagation(); var d=el.parentNode; var willOpen = !d.classList.contains('open'); document.querySelectorAll('.navdrop.open').forEach(function(o){ if(o!==d){ o.classList.remove('open'); var ot=o.querySelector('.navdrop-t'); if(ot) ot.setAttribute('aria-expanded','false'); } }); d.classList.toggle('open', willOpen); el.setAttribute('aria-expanded', willOpen?'true':'false'); return; } if((el=t.closest('#theme-toggle'))){ var html=document.documentElement; var next=html.getAttribute('data-theme')==='light'?'dark':'light'; html.setAttribute('data-theme',next); store('dc-theme',next); return; } if((el=t.closest('#menu-toggle'))){ var header=document.querySelector('.site-header'), nav=header.querySelector('nav'); var open=nav.classList.toggle('is-open'); header.classList.toggle('is-open',open); el.setAttribute('aria-expanded',open?'true':'false'); return; } if(!t.closest('.navdrop')){ document.querySelectorAll('.navdrop.open').forEach(function(d){ d.classList.remove('open'); d.querySelector('.navdrop-t').setAttribute('aria-expanded','false'); }); } }); document.addEventListener('keydown', function(e){ if(e.key==='Escape'){ closeContact(); closeMenus(); return; } if((e.key==='Enter'||e.key===' ') && e.target && e.target.matches && e.target.matches('a[role="link"],a[role="button"]')){ e.preventDefault(); e.target.click(); } }); /* ---------- boot ---------- */ (function(){ var th = load('dc-theme'); if(th==='light'||th==='dark') document.documentElement.setAttribute('data-theme', th); var lg = load('dc-lang'); if(!lg){ var nl=(navigator.languages||[navigator.language||'de']); for(var i=0;i
=0){ lg=c; break; } } } LANG = LANGS.indexOf(lg)>=0 ? lg : 'de'; renderHome(); var _rt; window.addEventListener('resize', function(){ clearTimeout(_rt); _rt=setTimeout(fitTitle, 120); }); })();