Skip to content

Commit 7a93d53

Browse files
committed
Editorial v3: kinetic monochrome redesign
Load intro sequence, blend-mode custom cursor, scroll-velocity marquee, word-by-word scroll-fill statement, horizontal-pinned work act, live clock, rotating role, clip-path section reveals. All reduced-motion gated.
1 parent 77633b4 commit 7a93d53

3 files changed

Lines changed: 426 additions & 79 deletions

File tree

‎src/pages/index.astro‎

Lines changed: 92 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const nav = [
1111
]
1212
1313
const stack = ['Java', 'C#', 'Python', 'Node.js', 'Flutter', 'Dart', 'Rust', 'SQL', 'Azure', 'Firebase', 'REST APIs', 'Git']
14+
const roles = ['web apps', 'REST APIs', 'mobile apps', 'developer tools']
1415
1516
const skills = [
1617
{ k: 'Languages', v: ['Java', 'C#', 'Python', 'JavaScript', 'SQL', 'Dart', 'Rust'] },
@@ -51,18 +52,29 @@ const certs = [
5152
<Base>
5253
<a id="top"></a>
5354

55+
<!-- Load intro -->
56+
<div id="ed-loader" aria-hidden="true">
57+
<span class="ed-loader__tag ed-mono">Ronan Roberts / Portfolio</span>
58+
<span class="ed-loader__count ed-mono" id="ed-count">000</span>
59+
<span class="ed-loader__bar"></span>
60+
</div>
61+
62+
<!-- Custom cursor -->
63+
<div id="ed-cursor" aria-hidden="true"></div>
64+
<div id="ed-cursor-ring" aria-hidden="true"><span id="ed-cursor-label"></span></div>
65+
5466
<header id="site-header" class="fixed top-0 inset-x-0 z-50">
5567
<div class="container-wide">
5668
<div id="nav-inner" class="flex items-center justify-between h-[72px] transition-all duration-300">
57-
<a href="#top" class="ed-mono font-bold tracking-tight text-sm">RR / ROBERTS</a>
69+
<a href="#top" class="ed-mono font-bold tracking-tight text-sm" data-cursor>RR / ROBERTS</a>
5870
<nav class="hidden md:flex items-center gap-7">
5971
{nav.map(item => (
60-
<a href={item.href} class="ed-mono text-xs uppercase tracking-widest nav-link">{item.label}</a>
72+
<a href={item.href} class="ed-mono text-xs uppercase tracking-widest nav-link" data-cursor>{item.label}</a>
6173
))}
6274
</nav>
6375
<div class="flex items-center gap-4">
6476
<span class="ed-avail hidden sm:inline-flex"><i></i>Available for work</span>
65-
<button class="ed-menu-btn ed-mono text-xs uppercase tracking-widest" id="ed-menu-open" aria-label="Open menu">Menu</button>
77+
<button class="ed-menu-btn ed-mono text-xs uppercase tracking-widest" id="ed-menu-open" aria-label="Open menu" data-cursor>Menu</button>
6678
</div>
6779
</div>
6880
</div>
@@ -76,32 +88,43 @@ const certs = [
7688
<main class="container-wide pt-[72px]">
7789

7890
<!-- Masthead -->
79-
<section class="min-h-[calc(100dvh-72px)] flex flex-col justify-center pt-10 pb-16">
80-
<div class="ed-kicker mb-6" data-reveal>Full-stack Developer, Germiston ZA</div>
81-
<hr class="ed-rule-accent mb-8" data-reveal />
91+
<section class="ed-hero min-h-[calc(100dvh-72px)] flex flex-col justify-center pt-10 pb-16">
92+
<div class="ed-hero-top" data-reveal>
93+
<span class="ed-kicker">Full-stack Developer</span>
94+
<span class="ed-kicker ed-clock" id="ed-clock">Germiston ZA</span>
95+
</div>
96+
<hr class="ed-rule-accent mb-8 mt-6" data-reveal />
8297

83-
<h1 class="ed-huge" style="font-size: clamp(3.4rem, 15vw, 13rem)" data-ed-title>
98+
<h1 class="ed-huge ed-name" data-ed-title>
8499
<span class="ed-line"><span>Ronan</span></span>
85100
<span class="ed-line"><span class="ed-outline">Roberts</span></span>
86101
</h1>
87102

88103
<hr class="ed-rule mt-10 mb-8" data-reveal />
89104
<div class="grid grid-cols-1 md:grid-cols-[1.7fr_1fr] gap-8 md:gap-16 items-end">
90-
<p class="text-lg md:text-xl leading-relaxed" style="max-width: 58ch" data-reveal>
91-
I build across the stack, web front-ends and back-ends in Java, C#,
92-
Python and Node.js, and cross-platform mobile apps in Flutter and Dart.
93-
Currently a Junior Software Engineer at Coast IT.
94-
</p>
105+
<div>
106+
<div class="ed-rotate ed-mono mb-5" aria-hidden="true">
107+
<span>I build</span>
108+
<span class="ed-rotate__mask"><span class="ed-rotate__list" data-rotate>
109+
{roles.map(r => <span>{r}</span>)}
110+
<span>{roles[0]}</span>
111+
</span></span>
112+
</div>
113+
<p class="text-lg md:text-xl leading-relaxed" style="max-width: 58ch" data-reveal>
114+
Web front-ends and back-ends in Java, C#, Python and Node.js, and cross-platform
115+
mobile apps in Flutter and Dart. Currently a Junior Software Engineer at Coast IT.
116+
</p>
117+
</div>
95118
<div class="flex flex-wrap gap-3 md:justify-end" data-reveal>
96-
<a href="#work" class="btn-primary magnetic" data-magnetic>View work</a>
97-
<a href="#contact" class="btn-ghost magnetic" data-magnetic>Get in touch</a>
119+
<a href="#work" class="btn-primary magnetic" data-magnetic data-cursor>View work</a>
120+
<a href="#contact" class="btn-ghost magnetic" data-magnetic data-cursor>Get in touch</a>
98121
</div>
99122
</div>
100123
</section>
101124
</main>
102125

103-
<!-- Tech marquee -->
104-
<section class="py-6 border-y" style="border-color: var(--border)" aria-hidden="true">
126+
<!-- Velocity marquee -->
127+
<section class="py-6 border-y ed-marquee-wrap" style="border-color: var(--border)" aria-hidden="true">
105128
<div class="marquee">
106129
<div class="marquee__track">
107130
{stack.map(s => <span class="marquee__item">{s}</span>)}
@@ -115,9 +138,15 @@ const certs = [
115138
<main class="container-wide">
116139

117140
<!-- Profile / skills -->
118-
<section id="profile" class="py-20 lg:py-28">
119-
<h2 class="ed-huge mb-12" style="font-size: clamp(2rem, 6vw, 4rem)" data-reveal>Profile</h2>
120-
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-10 gap-y-10">
141+
<section id="profile" class="py-24 lg:py-36">
142+
<h2 class="ed-huge ed-h2 mb-12" data-reveal>Profile</h2>
143+
144+
<p class="ed-fill" data-fill>
145+
I care about software that ships, holds up in production, and still reads clearly six
146+
months later. I work across the whole stack and own a feature from schema to screen.
147+
</p>
148+
149+
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-10 gap-y-10 mt-20">
121150
{skills.map(group => (
122151
<div data-reveal>
123152
<div class="ed-kicker mb-3 pb-2" style="border-bottom: 1px solid var(--border)">{group.k}</div>
@@ -128,38 +157,46 @@ const certs = [
128157
))}
129158
</div>
130159
</section>
160+
</main>
131161

132-
<!-- Work index -->
133-
<section id="work" class="py-20 lg:py-28">
134-
<div class="flex items-end justify-between mb-10 gap-4">
135-
<h2 class="ed-huge" style="font-size: clamp(2rem, 6vw, 4rem)" data-reveal>Selected Work</h2>
136-
<span class="ed-mono text-xs hidden sm:block" style="color: var(--muted)" data-reveal>2024 to 2026</span>
137-
</div>
138-
<div>
162+
<!-- Work: horizontal-pinned act (falls back to vertical stack) -->
163+
<section id="work" class="ed-work">
164+
<div class="container-wide ed-work-head">
165+
<h2 class="ed-huge ed-h2" data-reveal>Selected<br />Work</h2>
166+
<span class="ed-mono text-xs" style="color: var(--muted)" data-reveal>05 projects, 2024 to 2026</span>
167+
</div>
168+
<div class="ed-work-viewport">
169+
<div class="ed-work-track">
139170
{work.map(item => (
140-
<a href={item.href} target="_blank" rel="noopener noreferrer" class="work-row group" data-reveal>
141-
<span class="ed-num">{item.n}</span>
142-
<span>
143-
<span class="work-title block">{item.title}</span>
144-
<span class="ed-mono text-xs" style="color: var(--muted)">{item.meta}</span>
171+
<a href={item.href} target="_blank" rel="noopener noreferrer" class="ed-panel" data-hr data-cursor data-cursor-label="Open">
172+
<span class="ed-panel__num ed-outline">{item.n}</span>
173+
<span class="ed-panel__body">
174+
<span class="ed-panel__title">{item.title}</span>
175+
<span class="ed-mono text-sm" style="color: var(--muted)">{item.meta}</span>
145176
</span>
146-
<span class="flex items-center gap-4">
147-
<span class="hidden md:flex flex-wrap gap-1.5 justify-end" style="max-width: 220px">
177+
<span class="ed-panel__foot">
178+
<span class="flex flex-wrap gap-1.5">
148179
{item.tags.map(t => <span class="ed-tag">{t}</span>)}
149180
</span>
150-
<span class="ed-mono text-xs hidden sm:inline" style="color: var(--muted)">{item.year}</span>
151-
<span class="work-row__arrow" aria-hidden="true">
152-
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
181+
<span class="ed-panel__year ed-mono">{item.year}
182+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17L17 7M17 7H8M17 7V16"/></svg>
153183
</span>
154184
</span>
155185
</a>
156186
))}
187+
<a href="https://github.com/Ronan-R-R" target="_blank" rel="noopener noreferrer" class="ed-panel ed-panel--end" data-hr data-cursor data-cursor-label="GitHub">
188+
<span class="ed-panel__title">More<br />on GitHub</span>
189+
<span class="ed-mono text-sm" style="color: var(--muted)">github.com/Ronan-R-R</span>
190+
</a>
157191
</div>
158-
</section>
192+
</div>
193+
</section>
194+
195+
<main class="container-wide">
159196

160197
<!-- Record -->
161-
<section id="record" class="py-20 lg:py-28">
162-
<h2 class="ed-huge mb-12" style="font-size: clamp(2rem, 6vw, 4rem)" data-reveal>Record</h2>
198+
<section id="record" class="py-24 lg:py-36">
199+
<h2 class="ed-huge ed-h2 mb-12" data-reveal>Record</h2>
163200
<div class="grid grid-cols-1 lg:grid-cols-2 gap-x-16 gap-y-12">
164201
<div data-reveal>
165202
<div class="ed-kicker mb-4">Experience &amp; Education</div>
@@ -189,32 +226,37 @@ const certs = [
189226
</section>
190227

191228
<!-- Contact -->
192-
<section id="contact" class="py-20 lg:py-28">
193-
<h2 class="ed-huge mb-8" style="font-size: clamp(2rem, 6vw, 4rem)" data-reveal>Get in touch</h2>
194-
<hr class="ed-rule-accent mb-12" data-reveal />
229+
<section id="contact" class="py-24 lg:py-36">
230+
<h2 class="ed-huge ed-contact-title" data-ed-title>
231+
<span class="ed-line"><span>Let's</span></span>
232+
<span class="ed-line"><span class="ed-outline">Talk</span></span>
233+
</h2>
234+
<hr class="ed-rule-accent my-12" data-reveal />
195235
<div class="grid grid-cols-1 lg:grid-cols-[1fr_1fr] gap-12 lg:gap-20">
196236
<div data-reveal>
197237
<p class="text-2xl md:text-4xl font-display font-bold leading-tight mb-10" style="max-width: 16ch">
198238
Open to freelance projects and job opportunities.
199239
</p>
200240
<div class="ed-mono text-sm flex flex-col gap-3">
201-
<a href="mailto:ronanr2003@gmail.com" class="ed-link w-fit">ronanr2003@gmail.com</a>
202-
<a href="https://www.linkedin.com/in/rr-roberts/" target="_blank" rel="noopener noreferrer" class="ed-link w-fit">linkedin.com/in/rr-roberts</a>
203-
<a href="https://github.com/Ronan-R-R" target="_blank" rel="noopener noreferrer" class="ed-link w-fit">github.com/Ronan-R-R</a>
241+
<a href="mailto:ronanr2003@gmail.com" class="ed-link w-fit" data-cursor>ronanr2003@gmail.com</a>
242+
<a href="https://www.linkedin.com/in/rr-roberts/" target="_blank" rel="noopener noreferrer" class="ed-link w-fit" data-cursor>linkedin.com/in/rr-roberts</a>
243+
<a href="https://github.com/Ronan-R-R" target="_blank" rel="noopener noreferrer" class="ed-link w-fit" data-cursor>github.com/Ronan-R-R</a>
204244
</div>
205245
</div>
206246
<div data-reveal>
207247
<ContactForm client:visible />
208248
</div>
209249
</div>
210250
</section>
211-
212-
<footer class="py-10 ed-mono text-xs flex flex-col sm:flex-row justify-between gap-3" style="border-top: 1px solid var(--border); color: var(--muted)">
213-
<span>© <span id="footer-year"></span> Ronan Roberts</span>
214-
<span>Designed and built by Ronan Roberts</span>
215-
</footer>
216251
</main>
217252

253+
<div class="ed-footmark" aria-hidden="true"><span>ROBERTS</span></div>
254+
255+
<footer class="container-wide py-10 ed-mono text-xs flex flex-col sm:flex-row justify-between gap-3" style="border-top: 1px solid var(--border); color: var(--muted)">
256+
<span>© <span id="footer-year"></span> Ronan Roberts</span>
257+
<span>Designed and built by Ronan Roberts</span>
258+
</footer>
259+
218260
<script>
219261
const el = document.getElementById('footer-year')
220262
if (el) el.textContent = String(new Date().getFullYear())

0 commit comments

Comments
 (0)