feat: Add staggered entrance and icon pop-in animation for feature section cards
This commit is contained in:
@@ -112,8 +112,21 @@ a:hover { color: var(--color-primary); }
|
||||
transform: translateY(0);
|
||||
/* !important ensures this wins over transition: all on .oribi-card
|
||||
(same selector specificity, but .oribi-card appears later in the
|
||||
stylesheet and would otherwise override this). */
|
||||
transition: opacity .5s ease, transform .5s ease !important;
|
||||
stylesheet and would otherwise override this).
|
||||
var(--scroll-delay) is set per-card by demo-animator.js to produce
|
||||
a staggered entrance when multiple cards reveal at once. */
|
||||
transition: opacity .5s ease var(--scroll-delay, 0s), transform .5s ease var(--scroll-delay, 0s) !important;
|
||||
}
|
||||
|
||||
/* Icon pop-in animation — triggered by demo-animator.js when a
|
||||
feature-section card enters the viewport. */
|
||||
@keyframes icon-pop {
|
||||
0% { transform: scale(0.5); opacity: 0; }
|
||||
60% { transform: scale(1.2); opacity: 1; }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
.feature-icon.icon-pop {
|
||||
animation: icon-pop 0.4s ease-out backwards;
|
||||
}
|
||||
|
||||
/* Smooth theme transition */
|
||||
|
||||
63
theme/assets/js/demo-animator.js
Normal file
63
theme/assets/js/demo-animator.js
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Feature Section Card Animator
|
||||
* Staggered scroll-reveal entrance + icon pop-in for .feature-section cards.
|
||||
* Coordinates with the main.js scroll-hidden/visible system:
|
||||
* 1. Sets --scroll-delay CSS custom property on each card so main.js's
|
||||
* scroll-visible transition fires at staggered intervals.
|
||||
* 2. Uses MutationObserver to detect when scroll-visible is applied, then
|
||||
* triggers the icon-pop animation on the card's .feature-icon.
|
||||
* 3. Resets the delay to 0s after the entrance so hover interactions stay snappy.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var STAGGER = 0.08; // seconds between each card's entrance
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
|
||||
|
||||
// 1. Assign incrementing --scroll-delay to every card within a feature-section.
|
||||
// main.js's .scroll-visible rule reads this via var(--scroll-delay, 0s).
|
||||
document.querySelectorAll('.feature-section').forEach(function (section) {
|
||||
section.querySelectorAll('.oribi-card').forEach(function (card, i) {
|
||||
card.style.setProperty('--scroll-delay', (i * STAGGER).toFixed(2) + 's');
|
||||
});
|
||||
});
|
||||
|
||||
// 2. Watch for scroll-visible being added to each card.
|
||||
var cards = document.querySelectorAll('.feature-section .oribi-card');
|
||||
if (!cards.length) return;
|
||||
|
||||
var mo = new MutationObserver(function (mutations) {
|
||||
mutations.forEach(function (m) {
|
||||
var card = m.target;
|
||||
if (!card.classList.contains('scroll-visible')) return;
|
||||
|
||||
mo.unobserve(card);
|
||||
|
||||
// Trigger icon pop ~150ms after the card itself starts fading in.
|
||||
var icon = card.querySelector('.feature-icon');
|
||||
if (icon) {
|
||||
var cardDelay = parseFloat(card.style.getPropertyValue('--scroll-delay')) || 0;
|
||||
icon.style.animationDelay = (cardDelay + 0.15).toFixed(2) + 's';
|
||||
icon.classList.add('icon-pop');
|
||||
icon.addEventListener('animationend', function () {
|
||||
icon.classList.remove('icon-pop');
|
||||
icon.style.animationDelay = '';
|
||||
}, { once: true });
|
||||
}
|
||||
|
||||
// Reset stagger delay after entrance transition so hover isn't delayed.
|
||||
card.addEventListener('transitionend', function (e) {
|
||||
if (e.propertyName === 'opacity') {
|
||||
card.style.setProperty('--scroll-delay', '0s');
|
||||
}
|
||||
}, { once: true });
|
||||
});
|
||||
});
|
||||
|
||||
cards.forEach(function (card) {
|
||||
mo.observe(card, { attributes: true, attributeFilter: ['class'] });
|
||||
});
|
||||
});
|
||||
}());
|
||||
@@ -65,6 +65,15 @@ add_action( 'wp_enqueue_scripts', function () {
|
||||
true
|
||||
);
|
||||
|
||||
// Feature section card animator - staggered entrance and icon pop-in
|
||||
wp_enqueue_script(
|
||||
'oribi-demo-animator',
|
||||
ORIBI_URI . '/assets/js/demo-animator.js',
|
||||
[],
|
||||
ORIBI_VERSION . '.' . filemtime( ORIBI_DIR . '/assets/js/demo-animator.js' ),
|
||||
true
|
||||
);
|
||||
|
||||
// Localize AJAX endpoint for the contact form
|
||||
wp_localize_script( 'oribi-main', 'oribiAjax', [
|
||||
'url' => admin_url( 'admin-ajax.php' ),
|
||||
|
||||
Reference in New Issue
Block a user