Skip to content

Commit c7c38e2

Browse files
committed
feat: add animated intro, scroll controls, and UI polish for hero + socials
- Added topbar slide-in animation on page load - Introduced hero text (h1 + tagline) scroll-up reveal with delay - Updated social icons to slide up together under tagline - Styled scroll-down and back-to-top arrows with circular borders - Synced back-to-top arrow with same animation as scroll-down - Fixed greeting close button styling + behavior - Adjusted scroll-down arrow to align with About section (topbar offset) - Improved nav link behavior on mobile (prevent sticky focus highlight)
1 parent 0af808f commit c7c38e2

6 files changed

Lines changed: 385 additions & 49 deletions

File tree

assets/projects/HVAC-Thumb.jpg

427 KB
Loading
-305 KB
Loading
99.9 KB
Loading

index.html

Lines changed: 59 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -29,43 +29,53 @@
2929
</div>
3030
</nav>
3131

32-
<div class="greeting">
32+
<div class="greeting" id="greeting">
3333
Hello, thank you for visiting my Website! I am currently seeking internship opportunities in software development.
3434
If you think I'm a good fit, please send me an
3535
<a class="email-link" href="mailto:tyndall5818@gmail.com">email</a>.
36+
</span>
37+
<button class="greeting__close" id="greetingClose" aria-label="Close greeting" title="Close greeting">x</button>
3638
</div>
3739
</div>
3840

3941
<!-- HERO -->
4042
<header id="home" class="header hero">
4143
<div class="header__overlay"></div>
4244
<div class="container hero__content">
43-
<h1>Mark Tyndall</h1>
44-
<p class="tagline">
45+
<h1 class="reveal-up">Mark Tyndall</h1>
46+
<p class="tagline reveal-up">
4547
U.S. Marine Corps Veteran | DoD TS/SCI Security Clearance | CS Student<br>
4648
Background Image: Glacier Point, Yosemite National Park by Mark Tyndall
4749
</p>
4850

4951
<!-- Social icons -->
5052
<nav class="social">
51-
<a class="social__link" href="https://github.com/mtyndall88" target="_blank" aria-label="GitHub" rel="noopener">
53+
<a class="social__link reveal-up" href="https://github.com/mtyndall88" target="_blank" aria-label="GitHub" rel="noopener">
5254
<!-- GitHub SVG -->
5355
<svg viewBox="0 0 24 24" class="icon"><path d="M12 .5a11.5 11.5 0 0 0-3.64 22.41c.58.11.79-.25.79-.55v-2.1c-3.2.7-3.88-1.37-3.88-1.37-.53-1.36-1.3-1.72-1.3-1.72-1.06-.73.08-.72.08-.72 1.17.08 1.79 1.22 1.79 1.22 1.04 1.78 2.73 1.27 3.4.97.11-.75.41-1.27.75-1.56-2.55-.29-5.23-1.28-5.23-5.68 0-1.25.45-2.27 1.2-3.07-.12-.29-.52-1.45.12-3.03 0 0 .98-.31 3.2 1.17a11.04 11.04 0 0 1 5.82 0c2.22-1.48 3.2-1.17 3.2-1.17.64 1.58.24 2.74.12 3.03.75.8 1.2 1.82 1.2 3.07 0 4.41-2.69 5.38-5.25 5.67.42.36.8 1.07.8 2.16v3.2c0 .31.2.67.8.55A11.5 11.5 0 0 0 12 .5z"/></svg>
5456
</a>
55-
<a class="social__link" href="https://www.linkedin.com/in/mark-tyndall/" target="_blank" aria-label="LinkedIn" rel="noopener">
57+
<a class="social__link reveal-up" href="https://www.linkedin.com/in/mark-tyndall/" target="_blank" aria-label="LinkedIn" rel="noopener">
5658
<!-- LinkedIn SVG -->
5759
<svg viewBox="0 0 24 24" class="icon"><path d="M20.45 20.45h-3.55v-5.57c0-1.33-.02-3.03-1.85-3.03-1.85 0-2.13 1.44-2.13 2.93v5.67H9.37V9h3.4v1.56h.05c.47-.88 1.62-1.8 3.33-1.8 3.56 0 4.22 2.34 4.22 5.38v6.31zM5.34 7.43a2.06 2.06 0 1 1 0-4.12 2.06 2.06 0 0 1 0 4.12zM7.11 20.45H3.57V9h3.54v11.45z"/></svg>
5860
</a>
59-
<a class="social__link" href="assets/Mark Tyndall_Resume_09232025.pdf" target="_blank" aria-label="Resume" rel="noopener">
61+
<a class="social__link reveal-up" href="assets/Mark Tyndall_Resume_09232025.pdf" target="_blank" aria-label="Resume" rel="noopener">
6062
<!-- File/Resume SVG -->
6163
<svg viewBox="0 0 24 24" class="icon"><path d="M14 2H6a2 2 0 0 0-2 2v16c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>
6264
</a>
63-
<a class="social__link" href="mailto:tyndall5818@gmail.com" aria-label="Email">
65+
<a class="social__link reveal-up" href="mailto:tyndall5818@gmail.com" aria-label="Email">
6466
<!-- E-Mail SVG -->
6567
<svg viewBox="0 0 24 24" class="icon"><path d="M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2zm0 2l8 5 8-5"/></svg>
6668
</a>
6769
</nav>
6870
</div>
71+
<!-- Scroll down button -->
72+
<a href="#about" class="scroll-down" aria-label="Scroll to About">
73+
<span class="scroll-down__circle">
74+
<span class="scroll-down__arrow" aria-hidden="true"></span>
75+
</span>
76+
<span class="scroll-down__text">Scroll down</span>
77+
</a>
78+
6979
</header>
7080

7181
<!-- About Section -->
@@ -129,8 +139,10 @@ <h2 class="section-title">Work Experience</h2>
129139
<div class="experience-title">Sales Associate</div>
130140
<div class="experience-company">Rossman Realty</div>
131141
<div class="experience-description">
132-
Prepared sales contracts and delivered final offers, closing statements, and deeds. Developed and
133-
maintained relationships with clients throughout the entire sales process.
142+
Prepared and executed purchase/sale contracts; delivered offers, counteroffers, closing statements, and
143+
deeds in compliance with state and brokerage standards. Built and sustained client relationships
144+
end-to-end—from discovery through post-close—coordinating with lenders, title, and attorneys to ensure
145+
accurate, on-time closings.
134146
</div>
135147
</div>
136148

@@ -139,48 +151,55 @@ <h2 class="section-title">Work Experience</h2>
139151
<div class="experience-title">Field Service Representative</div>
140152
<div class="experience-company">ECS Federal LLC.</div>
141153
<div class="experience-description">
142-
Provided technical client support, management, testing, and strategic assessments of artificial
143-
intelligence and machine learning technologies to support Air Force full motion video operations
144-
and senior decision makers. This includes conducting background research in evaluating the feasibility
145-
of and potential applications for new technological concepts, producing and presenting findings and
146-
recommendations to a team of colleagues and clients at the Under Secretary of Defense for Intelligence
147-
Algorithmic Warfare Cross-Functional Team. Assisted with technical program management and program
148-
development, and drafted briefing materials overviewing government research and development efforts
149-
for both technical and public audiences.
154+
Provided client-facing technical leadership on AI/ML solutions supporting Air Force full-motion-video
155+
(FMV) workflows and senior decision-makers. Led feasibility research, requirements discovery, testing,
156+
and strategic assessments to translate mission needs into practical applications. Produced and presented
157+
findings and recommendations to colleagues and clients within the DoD Algorithmic Warfare Cross-Functional
158+
Team (Office of the Under Secretary of Defense for Intelligence & Security). Supported technical program
159+
management and program development—roadmaps, risks/issues, test plans, and vendor coordination—and authored
160+
executive briefings and technical summaries for both technical and public audiences. Recognized for
161+
mission-focused leadership, stakeholder alignment, clear communication, analytical rigor, and disciplined
162+
execution under tight timelines.
150163
</div>
151164
</div>
152165
<div class="experience-item fade-in">
153166
<div class="experience-date">June, 2017 - December, 2018</div>
154167
<div class="experience-title">Senior Consultant</div>
155168
<div class="experience-company">Booz Allen Hamilton</div>
156169
<div class="experience-description">
157-
Conducted exploitation & analysis of Unmanned Aircraft System (UAS) full motion video (FMV) for
158-
dissemination in support of CENTCOM operations for dissemination to higher echelons and supporting
159-
units. Collaborated with the customer and aircrew on threat analysis and identification.
170+
Led analysis of unmanned aircraft (UAS) full-motion video in support of U.S. combatant command
171+
operations, producing real-time and post-mission intelligence for decision-makers. Coordinated with
172+
mission customers and aircrews on threat detection and identification, set priorities under tight
173+
timelines, and enforced quality standards for all products. Mentored junior analysts and streamlined
174+
workflows to improve accuracy and speed. Known for calm, mission-focused leadership, clear communication,
175+
analytical rigor, and sound judgment under pressure.
160176
</div>
161177
</div>
162178
<div class="experience-item fade-in">
163179
<div class="experience-date">March, 2013 - June, 2017</div>
164-
<div class="experience-title">Sergeant</div>
180+
<div class="experience-title">Imagery Analysis Specialist</div>
165181
<div class="experience-company">United States Marine Corps</div>
166182
<div class="experience-description">
167-
Served as the FMV Intelligence Lead during multiple live fire exercises to prepare infantry units for
168-
combat deployments. Performed multi-sensor imagery exploitation to produce tailored IMINT products.
169-
Quality-checked imagery products before distribution and oversaw the professional development of imagery
170-
intelligence Marines, ensuring that they were proficient in the required imagery interpretation and
171-
analysis skills.
183+
Led full-motion video (FMV) analysis during live-fire training events, supervising a team of imagery
184+
analysts and coordinating with training and safety staff to deliver real-time, decision-ready visuals.
185+
Managed multi-sensor imagery exploitation, set priorities under pressure, and enforced rigorous quality
186+
standards. Trained and mentored junior analysts, improving accuracy, speed, and reporting discipline.
187+
Recognized for mission-focused leadership, clear communication, sound risk judgment, adaptability, and
188+
a strong work ethic.
172189
</div>
173190
</div>
174191

175192
<div class="experience-item fade-in">
176193
<div class="experience-date">March, 2008 - March, 2013</div>
177-
<div class="experience-title">Private - Corporal</div>
194+
<div class="experience-title">Force Protection Specialist</div>
178195
<div class="experience-company">United States Marine Corps</div>
179196
<div class="experience-description">
180-
Served as the Senior watch chief and Senior Watch NCO in RCT-8 Combat Operations Center. Supervised a
181-
crew of 10 in daily high-stress military war zone operations, including the evaluation, discipline, and
182-
cleanliness of our work environment. Assisted in security operations of nuclear weapons, submarines,
183-
and facilities.
197+
Senior operations lead for a 24/7 command center, supervising a 10-person team in high-pressure,
198+
time-sensitive environments. Set priorities, coached and evaluated staff, managed schedules and
199+
standards, and kept the workspace safe, clean, and mission-ready. Supported security operations for
200+
critical national assets—including nuclear programs, submarines, and restricted facilities—while
201+
adhering to strict compliance and confidentiality. Known for steady leadership, adaptability under
202+
pressure, clear communication, strong work ethic, and a focus on safety, accountability, and results.
184203
</div>
185204
</div>
186205
</div>
@@ -192,21 +211,21 @@ <h2 class="section-title">Work Experience</h2>
192211
<h2 class="section-title">Education</h2>
193212

194213
<div class="experience-item fade-in">
195-
<div class="experience-date">March, 2025 - Expected Graduation September, 2026</div>
214+
<div class="experience-date">March 2025 - Expected Graduation September 2026</div>
196215
<div class="experience-title">Bachelor of Science, Computer Science</div>
197216
<div class="experience-company">Rasmussen University</div>
198217
<div class="experience-description">GPA: 4.0.</div>
199218
</div>
200219

201220
<div class="experience-item fade-in">
202-
<div class="experience-date">January, 2019 - April, 2020</div>
203-
<div class="experience-title">Bachelor of Art, Business Management</div>
221+
<div class="experience-date">January 2019 - April 2020</div>
222+
<div class="experience-title">Bachelor of Arts, Business Management</div>
204223
<div class="experience-company">Golden Gate University</div>
205224
<div class="experience-description">GPA: 3.2</div>
206225
</div>
207226

208227
<div class="experience-item fade-in">
209-
<div class="experience-date">March, 2012 - November, 2018</div>
228+
<div class="experience-date">March 2012 - November 2018</div>
210229
<div class="experience-title">Associate of Arts, General Studies</div>
211230
<div class="experience-company">American Military University</div>
212231
<div class="experience-description">GPA: 3.6</div>
@@ -346,6 +365,11 @@ <h2 class="section-title">Contact</h2>
346365
</div>
347366
</section>
348367

368+
<!-- Back to top button -->
369+
<button id="backToTop" class="back-to-top" aria-label="Back to top" title="Back to top">
370+
<span class="back-to-top__arrow"></span>
371+
</button>
372+
349373
<!-- Footer -->
350374
<footer class="footer">
351375
<div class="container">

index.js

Lines changed: 122 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,61 @@
11
/* ===================================================================
2-
* Custom merged JS from Ceevee Template for My Portfolio
3-
* ------------------------------------------------------------------- */
2+
* Custom Site JS - Mark Tyndall ideas from Ceevee Template
3+
* I kept things minimal but reliable.
4+
* FEATURES:
5+
* - Topbar show/hide + "after hero" styling.
6+
* - Scroll spy with smooth anchor scrolling
7+
* - Fade-in on scroll
8+
* - About carousel
9+
* - Project modal
10+
* - Contact form submit (Formspree)
11+
* - Mobile fixes (no sticky hover, stable nav)
12+
* - Greeting dismiss, Scroll-down & Back-to-top
13+
* =================================================================== */
14+
15+
/* ===== First-load intro: mount topbar, then reveal hero text & socials ===== */
16+
(function initIntroMount(){
17+
const topbar = document.getElementById('topbar');
18+
const h1 = document.querySelector('.hero__content h1.reveal-up');
19+
const tagline = document.querySelector('.hero__content .tagline.reveal-up');
20+
const socials = document.querySelectorAll('.social .reveal-up');
21+
22+
// Timings
23+
const TOPBAR_DELAY = 120; // slide topbar
24+
const HERO_DELAY = 900; // reveal hero text
25+
const SOCIAL_DELAY = 1400; // socials start (same time)
26+
27+
const onLoad = () => {
28+
if (topbar) {
29+
setTimeout(() => {
30+
topbar.classList.add('is-mounted');
31+
topbar.classList.remove('is-hidden');
32+
}, TOPBAR_DELAY);
33+
}
34+
35+
setTimeout(() => {
36+
h1?.classList.add('is-in');
37+
tagline?.classList.add('is-in');
38+
}, HERO_DELAY);
39+
40+
// Reveal ALL social icons at once
41+
setTimeout(() => {
42+
socials.forEach(icon => icon.classList.add('is-in'));
43+
}, SOCIAL_DELAY);
44+
};
45+
46+
if (document.readyState === 'complete') onLoad();
47+
else window.addEventListener('load', onLoad);
48+
})();
449

550
/* ===== Topbar controller: hide over hero text, show after; dark after hero ===== */
651
(function initTopbarController(){
752
const topbar = document.getElementById('topbar');
8-
const hero = document.getElementById('home'); // full hero section
9-
const heroContent = document.querySelector('.hero__content'); // name/tagline/icons wrapper
53+
const hero = document.getElementById('home'); // full hero section
54+
const heroContent = document.querySelector('.hero__content'); // name/tagline/icons wrapper
1055
if (!topbar || !hero || !heroContent) return;
1156

12-
let heroBottom = 0; // absolute Y where hero ends
13-
let contentBottomAbs = 0; // absolute Y where hero text ends
57+
let heroBottom = 0; // absolute Y where hero ends
58+
let contentBottomAbs = 0; // absolute Y where hero text ends
1459
let ticking = false;
1560

1661
const measure = () => {
@@ -32,8 +77,11 @@
3277
if (scrollY <= 2) {
3378
topbar.classList.remove('is-hidden');
3479
} else {
80+
// delay auto-hide right after a nav click
81+
const ts = Number(document.documentElement.dataset.navClickTs || 0);
82+
const suppressHide = ts && (Date.now() - ts < 700); // ~0.7s window
3583
const overlappingHeroText = (scrollY + topbarH) < (contentBottomAbs + 50);
36-
topbar.classList.toggle('is-hidden', overlappingHeroText);
84+
topbar.classList.toggle('is-hidden', !suppressHide && overlappingHeroText);
3785
}
3886

3987
// 2) Transparent while within hero, dark after hero
@@ -62,6 +110,51 @@
62110
window.addEventListener('load', onResize);
63111
})();
64112

113+
/* ===== Greeting close ===== */
114+
(function initGreetingClose(){
115+
const bar = document.getElementById('greeting');
116+
const btn = document.getElementById('greetingClose');
117+
if (!bar || !btn) return;
118+
119+
const KEY = 'mt_greeting_dismissed';
120+
121+
// If this page load is a *reload*, clear the flag so the banner returns
122+
try {
123+
const nav = performance.getEntriesByType && performance.getEntriesByType('navigation')[0];
124+
const isReload = nav ? nav.type === 'reload'
125+
: (performance.navigation && performance.navigation.type === 1); // Safari fallback
126+
if (isReload) sessionStorage.removeItem(KEY);
127+
} catch(_) {}
128+
129+
if (sessionStorage.getItem(KEY) === '1') {
130+
bar.style.display = 'none';
131+
return;
132+
}
133+
134+
btn.addEventListener('click', () => {
135+
bar.style.display = 'none';
136+
sessionStorage.setItem(KEY, '1');
137+
});
138+
})();
139+
140+
/* ===== Back to top ===== */
141+
(function initBackToTop(){
142+
const btn = document.getElementById('backToTop');
143+
if (!btn) return;
144+
145+
const toggle = () => {
146+
const show = window.scrollY > (window.innerHeight * 0.6);
147+
btn.classList.toggle('is-visible', show);
148+
};
149+
window.addEventListener('scroll', toggle, { passive: true });
150+
window.addEventListener('resize', toggle);
151+
toggle();
152+
153+
btn.addEventListener('click', () => {
154+
window.scrollTo({ top: 0, behavior: 'smooth' });
155+
});
156+
})();
157+
65158
/* ===== Scroll-spy (active nav link) ===== */
66159
(function initScrollSpy() {
67160
const links = Array.from(document.querySelectorAll('.nav-links a[href^="#"]'));
@@ -111,14 +204,36 @@
111204
setActive(id);
112205

113206
const top = target.offsetTop - getOffset();
207+
// keep topbar stable during user navigation
208+
document.documentElement.dataset.navClickTs = Date.now().toString();
114209
window.scrollTo({ top, behavior: 'smooth' });
210+
// drop focus to avoid sticky :focus highlight on mobile
211+
a.blur();
115212
history.pushState(null, '', `#${id}`);
116213
});
117214
});
118215

119216
updateByScroll();
120217
})();
121218

219+
/* ===== Scroll-down button click ===== */
220+
(function initScrollDown(){
221+
const btn = document.querySelector('.scroll-down');
222+
const target = document.getElementById('about'); // the section you want to hit
223+
const topbar = document.getElementById('topbar');
224+
225+
if (!btn || !target) return;
226+
227+
const getOffset = () => (topbar ? topbar.getBoundingClientRect().height : 0);
228+
229+
btn.addEventListener('click', (e) => {
230+
e.preventDefault();
231+
const top = target.offsetTop - getOffset();
232+
window.scrollTo({ top, behavior: 'smooth' });
233+
history.pushState(null, '', '#about'); // optional: update URL like nav click
234+
});
235+
})();
236+
122237
/* ===== Reveal on scroll (fade-in) ===== */
123238
const observer = new IntersectionObserver((entries) => {
124239
entries.forEach((entry) => {

0 commit comments

Comments
 (0)