Unify scroll reveals, hero entrance, nav active-underline, button springs, the scroll-progress bar and backdrop parallax under one Motion system (src/scripts/anim.ts), bundled into a self-hosted /_astro module so CSP script-src 'self' holds. Progress bar + parallax now scroll()-driven and cross-browser (was Chromium-only animation-timeline). Fail-open, reduced-motion aware, content fully visible with JS off.
This commit is contained in:
@@ -114,39 +114,13 @@ import { cvAvailable } from "../lib/assets";
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
/* Staggered entrance — CSS-only (runs with JS off), motion-aware. */
|
||||
/* The staggered fade-up entrance is driven by the Motion layer
|
||||
(src/scripts/anim.ts). What stays here is the one-shot electric sheen that
|
||||
sweeps across the nameplate once on load — a pure background-position paint
|
||||
effect (no transform/opacity), motion-aware. */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.hero__eyebrow,
|
||||
.hero__title,
|
||||
.hero__positioning,
|
||||
.hero__tags,
|
||||
.hero__cta {
|
||||
animation: heroIn 0.7s var(--ease) both;
|
||||
}
|
||||
/* Entrance + a one-shot electric sheen sweeping across the name. */
|
||||
.hero__title {
|
||||
animation:
|
||||
heroIn 0.7s var(--ease) 0.06s both,
|
||||
heroSheen 1.6s var(--ease) 0.7s both;
|
||||
}
|
||||
.hero__positioning {
|
||||
animation-delay: 0.14s;
|
||||
}
|
||||
.hero__tags {
|
||||
animation-delay: 0.22s;
|
||||
}
|
||||
.hero__cta {
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
}
|
||||
@keyframes heroIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(12px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
animation: heroSheen 1.6s var(--ease) 0.7s both;
|
||||
}
|
||||
}
|
||||
/* The light sheen band (1st layer) sweeps left across the glyphs once, then
|
||||
|
||||
@@ -3,11 +3,11 @@ import ThemeToggle from "./ThemeToggle.astro";
|
||||
import { site } from "../data/site";
|
||||
|
||||
const links = [
|
||||
{ label: "About", href: "/#about" },
|
||||
{ label: "Skills", href: "/#skills" },
|
||||
{ label: "Projects", href: "/projects/" },
|
||||
{ label: "Blog", href: "/blog/" },
|
||||
{ label: "Contact", href: "/#contact" },
|
||||
{ label: "About", href: "/#about", id: "about" },
|
||||
{ label: "Skills", href: "/#skills", id: "skills" },
|
||||
{ label: "Projects", href: "/projects/", id: null },
|
||||
{ label: "Blog", href: "/blog/", id: null },
|
||||
{ label: "Contact", href: "/#contact", id: "contact" },
|
||||
];
|
||||
---
|
||||
|
||||
@@ -18,7 +18,11 @@ const links = [
|
||||
</a>
|
||||
|
||||
<nav class="nav__links" aria-label="Primary">
|
||||
{links.map((l) => <a href={l.href}>{l.label}</a>)}
|
||||
{links.map((l) => (
|
||||
<a href={l.href} data-nav-id={l.id}>
|
||||
{l.label}<span class="nav__ul" aria-hidden="true"></span>
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
<div class="nav__actions">
|
||||
@@ -80,12 +84,28 @@ const links = [
|
||||
font-size: var(--step--1);
|
||||
}
|
||||
.nav__links a {
|
||||
position: relative;
|
||||
color: var(--text-dim);
|
||||
}
|
||||
.nav__links a:hover {
|
||||
color: var(--text);
|
||||
text-decoration: none;
|
||||
}
|
||||
/* Active-section / hover underline — scaleX scrubbed by the Motion layer
|
||||
(spring). transform-origin left so it grows from the start of the label. */
|
||||
.nav__ul {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: -0.45rem;
|
||||
height: 2px;
|
||||
border-radius: 2px;
|
||||
background: linear-gradient(90deg, var(--accent), var(--accent-2));
|
||||
box-shadow: 0 0 8px var(--accent-glow);
|
||||
transform: scaleX(0);
|
||||
transform-origin: 0 50%;
|
||||
pointer-events: none;
|
||||
}
|
||||
.nav__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user