This commit is contained in:
2026-03-13 17:14:38 +01:00
parent f7a7802daf
commit ca8e3a555c
3 changed files with 65 additions and 8 deletions

View File

@@ -54,7 +54,6 @@
<!-- HERO -->
<section id="home" class="hero">
<div class="hero-content">
<p class="hero-greeting">// Hello, world. I'm</p>
<h1 class="hero-name" >Nikolaj Gade</h1>
<p class="hero-role">Software Developer</p>
<p class="hero-pronouns">they/them · he/him</p>

View File

@@ -1,14 +1,55 @@
// ── Hero typewriter ────────────────────────────────────────────
function startHeroTypewriter(nameEl, fullName, restEls) {
const cursor = document.createElement('span');
cursor.className = 'hero-cursor';
nameEl.appendChild(cursor);
let i = 0;
function typeNext() {
if (i < fullName.length) {
nameEl.insertBefore(document.createTextNode(fullName[i]), cursor);
i++;
setTimeout(typeNext, 95);
} else {
// Cursor done — fade it out, then reveal the rest
cursor.style.transition = 'opacity 0.3s';
cursor.style.opacity = '0';
setTimeout(() => {
cursor.remove();
restEls.forEach((el, idx) => {
setTimeout(() => el.classList.add('visible'), idx * 110);
});
}, 0);
}
}
typeNext();
}
// ── Loader ────────────────────────────────────────────────────
(function () {
const loader = document.getElementById('loader');
const pctEl = document.getElementById('loaderPct');
const loader = document.getElementById('loader');
const pctEl = document.getElementById('loaderPct');
const nameEl = document.querySelector('.hero-name');
const restEls = [...document.querySelectorAll('.hero-role, .hero-pronouns, .hero-links, .hero-visual')];
// Store the name and clear it immediately (loader covers the page anyway)
const fullName = nameEl.textContent.trim();
nameEl.textContent = '';
// Hide hero elements that reveal after typing
restEls.forEach(el => el.classList.add('fade-up'));
let pct = 0;
const tick = setInterval(() => {
pct += Math.random() * 20;
pct += Math.random() * 15;
if (pct >= 100) {
pct = 100;
clearInterval(tick);
setTimeout(() => loader.classList.add('hide'), 300);
setTimeout(() => {
loader.classList.add('hide');
// Wait for the loader fade-out (0.6s), then start typing
setTimeout(() => startHeroTypewriter(nameEl, fullName, restEls), 600);
}, 300);
}
pctEl.textContent = Math.floor(pct) + '%';
}, 110);
@@ -166,7 +207,7 @@
(function () {
const targets = document.querySelectorAll(
'.section-header, .about-grid, .skill-card, .timeline-item, ' +
'.project-card, .edu-card, .hero-content, .hero-visual'
'.project-card, .edu-card'
);
targets.forEach(el => el.classList.add('fade-up'));

View File

@@ -71,7 +71,7 @@ button { font-family: var(--font); cursor: pointer; border: none; background: no
@keyframes lcFade { to { opacity: 1; transform: none; } }
.loader-bar-wrap { width: 200px; height: 3px; background: rgba(255,255,255,0.1); border-radius: 99px; margin: 0 auto 0.75rem; overflow: hidden; }
.loader-bar { height: 100%; background: var(--grad); width: 0%; animation: barFill 2.2s var(--ease) forwards; animation-delay: 0.5s; }
.loader-bar { height: 100%; background: var(--grad); width: 0%; animation: barFill 2.5s var(--ease) forwards; animation-delay: 0.5s; }
@keyframes barFill { to { width: 100%; } }
.loader-pct { font-family: var(--mono); font-size: 0.8rem; color: var(--orange); }
@@ -165,11 +165,27 @@ main { position: relative; z-index: 1; }
.fade-up { opacity: 0; transform: translateY(28px); transition: opacity 0.6s var(--ease), transform 0.6s var(--ease); }
.fade-up.visible { opacity: 1; transform: none; }
/* Hero typewriter cursor */
.hero-cursor {
display: inline-block;
width: 5px;
height: 0.8em;
background: var(--ink);
margin-left: 5px;
vertical-align: baseline;
border-radius: 1px;
animation: cursorBlink 0.7s step-end infinite;
}
@keyframes cursorBlink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
/* ── Hero ───────────────────────────────────────────────────── */
.hero {
min-height: 100vh;
display: flex; align-items: center;
padding: calc(var(--nav-h) + 1rem) 2rem 15rem;
padding: calc(var(--nav-h) + 1rem) 2rem 10rem;
max-width: var(--max-w);
margin: 0 auto 250px auto;
gap: 4rem;
@@ -184,6 +200,7 @@ main { position: relative; z-index: 1; }
font-weight: 900;
line-height: 1;
letter-spacing: -0.03em;
margin-top: 3rem;
margin-bottom: 0.75rem;
}
.hero-role {