Add infinite scrolling cause zeppo is silly
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 1m57s
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 1m57s
This commit is contained in:
@@ -62,6 +62,8 @@
|
|||||||
|
|
||||||
<section class="testimonials">
|
<section class="testimonials">
|
||||||
<h2>What Others Are Saying</h2>
|
<h2>What Others Are Saying</h2>
|
||||||
|
<div class="testimonial-viewport">
|
||||||
|
<div id="testimonial-track">
|
||||||
<div class="testimonial">
|
<div class="testimonial">
|
||||||
<p>"I have never met a yinglet with such presence. Zeppo is a force of nature wrapped in fur."</p>
|
<p>"I have never met a yinglet with such presence. Zeppo is a force of nature wrapped in fur."</p>
|
||||||
<cite>— A Very Reliable Source</cite>
|
<cite>— A Very Reliable Source</cite>
|
||||||
@@ -74,6 +76,8 @@
|
|||||||
<p>"I asked him to tone it down and he toned it UP. Respect."</p>
|
<p>"I asked him to tone it down and he toned it UP. Respect."</p>
|
||||||
<cite>— Anonymous</cite>
|
<cite>— Anonymous</cite>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="stats">
|
<section class="stats">
|
||||||
@@ -108,5 +112,6 @@
|
|||||||
<footer>
|
<footer>
|
||||||
<p>Built with love and a healthy fear of Zeppo's judgment.</p>
|
<p>Built with love and a healthy fear of Zeppo's judgment.</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
<script src="script.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
121
script.js
Normal file
121
script.js
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var fragments = [
|
||||||
|
'I have never met a yinglet with such presence.',
|
||||||
|
'Zeppo is a force of nature wrapped in fur.',
|
||||||
|
'He once stared down a baxxid and the baxxid blinked first (even though it doesn\'t have eyelids).',
|
||||||
|
'Legend.',
|
||||||
|
'I asked him to tone it down and he toned it UP.',
|
||||||
|
'Respect.',
|
||||||
|
'Zeppo doesn\'t walk into a room \u2014 he arrives.',
|
||||||
|
'Whiskers perfectly groomed, tail held high and shelltooth sharp.',
|
||||||
|
'He knows he\'s him.',
|
||||||
|
'Wits sharper than a creystone blade.',
|
||||||
|
'Zeppo could scheme his way out of any jam and still have time to steal your lunch.',
|
||||||
|
'Despite being a tiny rodent-person, his heart is the size of a melon.',
|
||||||
|
'Loyal, fierce, and ride-or-die for his crew.',
|
||||||
|
'Name a better dental situation. You can\'t.',
|
||||||
|
'That shelltooth has 10,000 PSI of pure charisma.',
|
||||||
|
'Where Zeppo goes, adventure follows.',
|
||||||
|
'Not always good adventure, but never boring.',
|
||||||
|
'The universe literally cannot ignore him.',
|
||||||
|
'No throne needed. Zeppo rules through sheer force of personality.',
|
||||||
|
'Say his name three times and he appears to judge you.',
|
||||||
|
];
|
||||||
|
|
||||||
|
var sources = [
|
||||||
|
'A Very Reliable Source',
|
||||||
|
'Witness',
|
||||||
|
'Anonymous',
|
||||||
|
'Local Prophet',
|
||||||
|
'The Council of Elders',
|
||||||
|
'A Slightly Biased Fan',
|
||||||
|
'His Mother',
|
||||||
|
'A Former Rival',
|
||||||
|
'The Oracle of Weh',
|
||||||
|
'Some Guy',
|
||||||
|
'An Expert',
|
||||||
|
'History',
|
||||||
|
'A Completely Unbiased Observer',
|
||||||
|
'The Voices',
|
||||||
|
'A Very Smart Person',
|
||||||
|
'The Echo',
|
||||||
|
'A Distant Admiral',
|
||||||
|
'A Humble Historian',
|
||||||
|
'A Random Vagrant',
|
||||||
|
'The Governor',
|
||||||
|
'A Self-Proclaimed Expert',
|
||||||
|
'The Town Crier',
|
||||||
|
'A Very Loud Individual',
|
||||||
|
];
|
||||||
|
|
||||||
|
function randomItem(arr) {
|
||||||
|
return arr[Math.floor(Math.random() * arr.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateQuote() {
|
||||||
|
var count = Math.random() > 0.5 ? 2 : 1;
|
||||||
|
var selected = [];
|
||||||
|
var available = fragments.slice();
|
||||||
|
for (var i = 0; i < count && available.length > 0; i++) {
|
||||||
|
var idx = Math.floor(Math.random() * available.length);
|
||||||
|
selected.push(available.splice(idx, 1)[0]);
|
||||||
|
}
|
||||||
|
var text = selected.join(' ');
|
||||||
|
if (Math.random() > 0.3) {
|
||||||
|
var extra = randomItem(fragments);
|
||||||
|
if (selected.indexOf(extra) === -1) {
|
||||||
|
text += ' ' + extra;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var source = randomItem(sources);
|
||||||
|
return { text: text, source: source };
|
||||||
|
}
|
||||||
|
|
||||||
|
function createElement(data) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.className = 'testimonial';
|
||||||
|
var p = document.createElement('p');
|
||||||
|
p.textContent = '\u201C' + data.text + '\u201D';
|
||||||
|
div.appendChild(p);
|
||||||
|
var cite = document.createElement('cite');
|
||||||
|
cite.textContent = '\u2014 ' + data.source;
|
||||||
|
div.appendChild(cite);
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
|
||||||
|
var track = document.getElementById('testimonial-track');
|
||||||
|
if (!track) return;
|
||||||
|
|
||||||
|
var viewport = track.parentElement;
|
||||||
|
var paused = false;
|
||||||
|
var scrollPos = 0;
|
||||||
|
var speed = 0.35;
|
||||||
|
|
||||||
|
function step() {
|
||||||
|
try {
|
||||||
|
if (!paused) {
|
||||||
|
scrollPos += speed;
|
||||||
|
track.style.transform = 'translateY(' + (-scrollPos) + 'px)';
|
||||||
|
|
||||||
|
var first = track.firstElementChild;
|
||||||
|
var second = first && first.nextElementSibling;
|
||||||
|
if (first && second) {
|
||||||
|
var distance = second.offsetTop - first.offsetTop;
|
||||||
|
if (distance > 0 && scrollPos >= distance) {
|
||||||
|
scrollPos -= distance;
|
||||||
|
track.removeChild(first);
|
||||||
|
track.appendChild(createElement(generateQuote()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
requestAnimationFrame(step);
|
||||||
|
}
|
||||||
|
|
||||||
|
viewport.addEventListener('mouseenter', function () { paused = true; });
|
||||||
|
viewport.addEventListener('mouseleave', function () { paused = false; });
|
||||||
|
|
||||||
|
step();
|
||||||
|
})();
|
||||||
24
style.css
24
style.css
@@ -218,6 +218,30 @@ footer {
|
|||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.testimonial-viewport {
|
||||||
|
overflow: hidden;
|
||||||
|
max-height: 320px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.testimonial-viewport::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 48px;
|
||||||
|
background: linear-gradient(transparent, #151520);
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#testimonial-track {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
h1 { font-size: 3rem; }
|
h1 { font-size: 3rem; }
|
||||||
.hero h2 { font-size: 2rem; }
|
.hero h2 { font-size: 2rem; }
|
||||||
|
|||||||
Reference in New Issue
Block a user