ultimate-jekyll-manager 0.0.138 → 0.0.141
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/assets/themes/classy/_config.scss +4 -1
- package/dist/assets/themes/classy/_theme.js +3 -3
- package/dist/assets/themes/classy/_theme.scss +1 -1
- package/dist/assets/themes/classy/css/components/_infinite-scroll.scss +140 -0
- package/dist/assets/themes/classy/js/infinite-scroll.js +139 -0
- package/dist/defaults/dist/_includes/themes/classy/frontend/components/testimonial-scroll.html +84 -0
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/index.html +5 -71
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +1 -67
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/team/index.html +11 -5
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/team/member.html +1 -1
- package/dist/defaults/src/_includes/frontend/sections/nav.json +11 -7
- package/dist/gulp/tasks/defaults.js +8 -1
- package/dist/gulp/tasks/distribute.js +6 -1
- package/dist/gulp/tasks/jekyll.js +3 -1
- package/package.json +2 -2
- package/dist/assets/themes/classy/css/components/_logo-scroll.scss +0 -57
- package/dist/assets/themes/classy/js/logo-scroll.js +0 -83
package/README.md
CHANGED
|
@@ -59,6 +59,14 @@ npm start -- --debug=true
|
|
|
59
59
|
```bash
|
|
60
60
|
npm start -- --ujPluginDevMode=true
|
|
61
61
|
```
|
|
62
|
+
* `--profile` - Enables Jekyll build profiling to see how long each phase takes.
|
|
63
|
+
```bash
|
|
64
|
+
npm start -- --profile
|
|
65
|
+
```
|
|
66
|
+
* `--all-posts` - Disables the development post limit (15 posts) and builds with all posts. Useful when you need to test with full blog content.
|
|
67
|
+
```bash
|
|
68
|
+
npm start -- --all-posts
|
|
69
|
+
```
|
|
62
70
|
|
|
63
71
|
### Other ENV variables
|
|
64
72
|
```bash
|
|
@@ -14,8 +14,8 @@ window.bootstrap = bootstrap;
|
|
|
14
14
|
|
|
15
15
|
// Import navbar scroll functionality
|
|
16
16
|
import setupNavbarScroll from './js/navbar-scroll.js';
|
|
17
|
-
// Import logo scroll
|
|
18
|
-
import
|
|
17
|
+
// Import infinite scroll functionality (used by logo scroll, testimonials, etc.)
|
|
18
|
+
import { setupInfiniteScroll } from './js/infinite-scroll.js';
|
|
19
19
|
// Import tooltip initialization
|
|
20
20
|
import initializeTooltips from './js/initialize-tooltips.js';
|
|
21
21
|
|
|
@@ -23,7 +23,7 @@ import initializeTooltips from './js/initialize-tooltips.js';
|
|
|
23
23
|
domReady().then(() => {
|
|
24
24
|
// Classy Theme Initializations
|
|
25
25
|
setupNavbarScroll();
|
|
26
|
-
|
|
26
|
+
setupInfiniteScroll();
|
|
27
27
|
|
|
28
28
|
// Generic Bootstrap initializations
|
|
29
29
|
initializeTooltips();
|
|
@@ -29,6 +29,6 @@
|
|
|
29
29
|
@import 'css/components/carousel';
|
|
30
30
|
@import 'css/components/forms';
|
|
31
31
|
@import 'css/components/links';
|
|
32
|
-
@import 'css/components/
|
|
32
|
+
@import 'css/components/infinite-scroll';
|
|
33
33
|
@import 'css/components/spinners';
|
|
34
34
|
@import 'css/components/text';
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// Infinite Scroll Animation Component
|
|
2
|
+
// A reusable horizontal infinite scrolling container
|
|
3
|
+
// Used by: logo scroll, testimonial scroll, etc.
|
|
4
|
+
|
|
5
|
+
// ============================================
|
|
6
|
+
// Container & Track
|
|
7
|
+
// ============================================
|
|
8
|
+
|
|
9
|
+
.infinite-scroll-wrapper {
|
|
10
|
+
position: relative;
|
|
11
|
+
width: 100vw;
|
|
12
|
+
margin-left: calc(-50vw + 50%);
|
|
13
|
+
overflow: hidden;
|
|
14
|
+
|
|
15
|
+
// Fade edges modifier
|
|
16
|
+
&.infinite-scroll-fade-edges {
|
|
17
|
+
&::before,
|
|
18
|
+
&::after {
|
|
19
|
+
content: '';
|
|
20
|
+
position: absolute;
|
|
21
|
+
top: 0;
|
|
22
|
+
bottom: 0;
|
|
23
|
+
width: 100px;
|
|
24
|
+
z-index: 10;
|
|
25
|
+
pointer-events: none;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&::before {
|
|
29
|
+
left: 0;
|
|
30
|
+
background: linear-gradient(to right, var(--bs-body-bg), transparent);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&::after {
|
|
34
|
+
right: 0;
|
|
35
|
+
background: linear-gradient(to left, var(--bs-body-bg), transparent);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.infinite-scroll-track {
|
|
41
|
+
display: flex;
|
|
42
|
+
width: fit-content;
|
|
43
|
+
animation: infinite-scroll var(--infinite-scroll-duration, 30s) linear infinite;
|
|
44
|
+
|
|
45
|
+
&:hover {
|
|
46
|
+
animation-play-state: paused;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Gap modifiers
|
|
50
|
+
&.gap-sm {
|
|
51
|
+
gap: 1rem;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&.gap-md {
|
|
55
|
+
gap: 1.5rem;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
&.gap-lg {
|
|
59
|
+
gap: 2rem;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.infinite-scroll-item {
|
|
64
|
+
flex-shrink: 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ============================================
|
|
68
|
+
// Animation
|
|
69
|
+
// ============================================
|
|
70
|
+
|
|
71
|
+
@keyframes infinite-scroll {
|
|
72
|
+
0% {
|
|
73
|
+
transform: translateX(0);
|
|
74
|
+
}
|
|
75
|
+
100% {
|
|
76
|
+
transform: translateX(var(--infinite-scroll-distance, -50%));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ============================================
|
|
81
|
+
// Specific Item Types
|
|
82
|
+
// ============================================
|
|
83
|
+
|
|
84
|
+
// Logo items (used by trusted-by/partner sections)
|
|
85
|
+
.infinite-scroll-item--logo {
|
|
86
|
+
padding: 0 3rem;
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
height: 60px;
|
|
90
|
+
|
|
91
|
+
img, svg {
|
|
92
|
+
height: 40px;
|
|
93
|
+
width: auto;
|
|
94
|
+
max-width: 150px;
|
|
95
|
+
transition: all 0.3s ease;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Card items (used by testimonials, etc.)
|
|
100
|
+
.infinite-scroll-item--card {
|
|
101
|
+
width: 320px;
|
|
102
|
+
padding: 0.5rem 0;
|
|
103
|
+
|
|
104
|
+
.card {
|
|
105
|
+
height: 100%;
|
|
106
|
+
border-radius: 0.75rem;
|
|
107
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
108
|
+
|
|
109
|
+
&:hover {
|
|
110
|
+
transform: translateY(-2px);
|
|
111
|
+
box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.1) !important;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ============================================
|
|
117
|
+
// Responsive Design
|
|
118
|
+
// ============================================
|
|
119
|
+
|
|
120
|
+
@media (max-width: 768px) {
|
|
121
|
+
.infinite-scroll-wrapper.infinite-scroll-fade-edges {
|
|
122
|
+
&::before,
|
|
123
|
+
&::after {
|
|
124
|
+
width: 50px;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.infinite-scroll-item--logo {
|
|
129
|
+
padding: 0 2rem;
|
|
130
|
+
height: 50px;
|
|
131
|
+
|
|
132
|
+
img, svg {
|
|
133
|
+
height: 30px;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.infinite-scroll-item--card {
|
|
138
|
+
width: 280px;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// Infinite Scroll Animation Component
|
|
2
|
+
// A reusable horizontal infinite scrolling animation
|
|
3
|
+
// Used by: logo scroll, testimonial scroll, etc.
|
|
4
|
+
|
|
5
|
+
// Default scroll speed (pixels per second)
|
|
6
|
+
const DEFAULT_SCROLL_SPEED = 40;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Initialize infinite scroll for all matching elements
|
|
10
|
+
* @param {Object} options - Configuration options
|
|
11
|
+
* @param {string} options.selector - CSS selector for scroll tracks (default: '.infinite-scroll-track')
|
|
12
|
+
* @param {number} options.speed - Scroll speed in pixels per second (default: 40)
|
|
13
|
+
*/
|
|
14
|
+
export function setupInfiniteScroll(options = {}) {
|
|
15
|
+
const {
|
|
16
|
+
selector = '.infinite-scroll-track',
|
|
17
|
+
speed = DEFAULT_SCROLL_SPEED,
|
|
18
|
+
} = options;
|
|
19
|
+
|
|
20
|
+
const scrollTracks = document.querySelectorAll(selector);
|
|
21
|
+
|
|
22
|
+
scrollTracks.forEach(track => {
|
|
23
|
+
initializeTrack(track, speed);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Recalculate on window resize
|
|
27
|
+
setupResizeHandler(scrollTracks, speed);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Initialize a single scroll track
|
|
32
|
+
* @param {HTMLElement} track - The scroll track element
|
|
33
|
+
* @param {number} speed - Scroll speed in pixels per second
|
|
34
|
+
*/
|
|
35
|
+
function initializeTrack(track, speed) {
|
|
36
|
+
if (!track) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Check if already initialized
|
|
41
|
+
if (track.dataset.infiniteScrollInitialized === 'true') {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Get original items
|
|
46
|
+
const originalItems = Array.from(track.children);
|
|
47
|
+
if (originalItems.length === 0) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Store original count for resize handling
|
|
52
|
+
track.dataset.originalItemCount = originalItems.length;
|
|
53
|
+
track.dataset.infiniteScrollInitialized = 'true';
|
|
54
|
+
|
|
55
|
+
// Calculate total width of original items
|
|
56
|
+
let totalWidth = 0;
|
|
57
|
+
const computedStyle = getComputedStyle(track);
|
|
58
|
+
const gap = parseFloat(computedStyle.gap) || 0;
|
|
59
|
+
|
|
60
|
+
originalItems.forEach((item, index) => {
|
|
61
|
+
totalWidth += item.getBoundingClientRect().width;
|
|
62
|
+
if (index < originalItems.length - 1) {
|
|
63
|
+
totalWidth += gap;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Calculate how many sets we need to fill the screen plus extra for smooth scrolling
|
|
68
|
+
const viewportWidth = window.innerWidth;
|
|
69
|
+
const setsNeeded = Math.ceil((viewportWidth * 2.5) / totalWidth);
|
|
70
|
+
|
|
71
|
+
// Clone item sets
|
|
72
|
+
for (let i = 0; i < setsNeeded; i++) {
|
|
73
|
+
originalItems.forEach(item => {
|
|
74
|
+
const clone = item.cloneNode(true);
|
|
75
|
+
track.appendChild(clone);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Calculate animation duration based on total width
|
|
80
|
+
const allItems = track.children;
|
|
81
|
+
let animationWidth = 0;
|
|
82
|
+
|
|
83
|
+
// Calculate width of half the items (for the seamless loop)
|
|
84
|
+
const halfCount = Math.floor(allItems.length / 2);
|
|
85
|
+
for (let i = 0; i < halfCount; i++) {
|
|
86
|
+
animationWidth += allItems[i].getBoundingClientRect().width + gap;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Set CSS variables for animation
|
|
90
|
+
const duration = animationWidth / speed;
|
|
91
|
+
track.style.setProperty('--infinite-scroll-duration', `${duration}s`);
|
|
92
|
+
track.style.setProperty('--infinite-scroll-distance', `-${animationWidth}px`);
|
|
93
|
+
|
|
94
|
+
// Restart animation when it completes to ensure seamless loop
|
|
95
|
+
track.addEventListener('animationiteration', () => {
|
|
96
|
+
// Reset the animation to prevent accumulation of drift
|
|
97
|
+
track.style.animation = 'none';
|
|
98
|
+
track.offsetHeight; // Trigger reflow
|
|
99
|
+
track.style.animation = `infinite-scroll var(--infinite-scroll-duration, ${duration}s) linear infinite`;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Setup resize handler for recalculating scroll animations
|
|
105
|
+
* @param {NodeList} scrollTracks - All scroll track elements
|
|
106
|
+
* @param {number} speed - Scroll speed in pixels per second
|
|
107
|
+
*/
|
|
108
|
+
function setupResizeHandler(scrollTracks, speed) {
|
|
109
|
+
let resizeTimeout;
|
|
110
|
+
|
|
111
|
+
window.addEventListener('resize', () => {
|
|
112
|
+
clearTimeout(resizeTimeout);
|
|
113
|
+
resizeTimeout = setTimeout(() => {
|
|
114
|
+
scrollTracks.forEach(track => {
|
|
115
|
+
// Get original item count
|
|
116
|
+
const originalCount = parseInt(track.dataset.originalItemCount, 10) || 0;
|
|
117
|
+
if (originalCount === 0) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Remove cloned items
|
|
122
|
+
while (track.children.length > originalCount) {
|
|
123
|
+
track.removeChild(track.lastChild);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Reset initialization flag
|
|
127
|
+
track.dataset.infiniteScrollInitialized = 'false';
|
|
128
|
+
|
|
129
|
+
// Re-initialize
|
|
130
|
+
initializeTrack(track, speed);
|
|
131
|
+
});
|
|
132
|
+
}, 250);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Default export for backward compatibility
|
|
137
|
+
export default function() {
|
|
138
|
+
setupInfiniteScroll();
|
|
139
|
+
}
|
package/dist/defaults/dist/_includes/themes/classy/frontend/components/testimonial-scroll.html
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{% comment %}
|
|
2
|
+
Testimonial Scroll Component
|
|
3
|
+
A scrolling masonry-style testimonial display inspired by modern SaaS landing pages.
|
|
4
|
+
Uses the generic infinite-scroll component for animation.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
{% include themes/classy/frontend/components/testimonial-scroll.html
|
|
8
|
+
testimonials=page.resolved.testimonials %}
|
|
9
|
+
|
|
10
|
+
Required data structure:
|
|
11
|
+
testimonials:
|
|
12
|
+
superheadline:
|
|
13
|
+
icon: "megaphone"
|
|
14
|
+
text: "Testimonials"
|
|
15
|
+
headline: "What people are saying"
|
|
16
|
+
headline_accent: "about us"
|
|
17
|
+
subheadline: "Hear from real customers"
|
|
18
|
+
items:
|
|
19
|
+
- quote: "..."
|
|
20
|
+
author: "Name"
|
|
21
|
+
role: "Title"
|
|
22
|
+
company: "Company"
|
|
23
|
+
initial: "N"
|
|
24
|
+
handle: "@username" (optional)
|
|
25
|
+
{% endcomment %}
|
|
26
|
+
|
|
27
|
+
<!-- Testimonials Section -->
|
|
28
|
+
<section class="testimonial-scroll-section overflow-hidden">
|
|
29
|
+
<div class="container">
|
|
30
|
+
<div class="text-center mb-5" data-lazy="@class animation-slide-up">
|
|
31
|
+
{% iftruthy include.testimonials.superheadline.text %}
|
|
32
|
+
<span class="badge bg-body-tertiary border-gradient-rainbow border-1 text-body p-2 mb-1 fw-semibold small">
|
|
33
|
+
{% iftruthy include.testimonials.superheadline.icon %}
|
|
34
|
+
{% uj_icon include.testimonials.superheadline.icon, "me-1" %}
|
|
35
|
+
{% endiftruthy %}
|
|
36
|
+
{{ include.testimonials.superheadline.text }}
|
|
37
|
+
</span>
|
|
38
|
+
{% endiftruthy %}
|
|
39
|
+
<h2 class="h2 mb-2">
|
|
40
|
+
{{ include.testimonials.headline }}
|
|
41
|
+
{% iftruthy include.testimonials.headline_accent %}
|
|
42
|
+
<span class="text-accent">{{ include.testimonials.headline_accent }}</span>
|
|
43
|
+
{% endiftruthy %}
|
|
44
|
+
</h2>
|
|
45
|
+
{% iftruthy include.testimonials.subheadline %}
|
|
46
|
+
<p class="fs-5 text-muted">{{ include.testimonials.subheadline }}</p>
|
|
47
|
+
{% endiftruthy %}
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
{% if include.testimonials.items %}
|
|
52
|
+
<div class="infinite-scroll-wrapper infinite-scroll-fade-edges" data-lazy="@class animation-fade-in">
|
|
53
|
+
<div class="infinite-scroll-track gap-md" data-scroll-speed="30">
|
|
54
|
+
{% for testimonial in include.testimonials.items %}
|
|
55
|
+
<div class="infinite-scroll-item infinite-scroll-item--card">
|
|
56
|
+
<div class="card border-0 shadow-sm">
|
|
57
|
+
<div class="card-body p-4">
|
|
58
|
+
<!-- Header with avatar and info -->
|
|
59
|
+
<div class="d-flex align-items-center mb-3">
|
|
60
|
+
<div class="avatar avatar-md rounded-circle bg-primary text-light d-flex align-items-center justify-content-center flex-shrink-0">
|
|
61
|
+
<span class="fw-bold">{{ testimonial.initial }}</span>
|
|
62
|
+
</div>
|
|
63
|
+
<div class="ms-3">
|
|
64
|
+
<div class="fw-semibold text-body">{{ testimonial.author }}</div>
|
|
65
|
+
<div class="small text-muted">
|
|
66
|
+
{% iftruthy testimonial.handle %}
|
|
67
|
+
{{ testimonial.handle }}
|
|
68
|
+
{% endiftruthy %}
|
|
69
|
+
{% iffalsy testimonial.handle %}
|
|
70
|
+
{{ testimonial.role }}{% iftruthy testimonial.company %} at {{ testimonial.company }}{% endiftruthy %}
|
|
71
|
+
{% endiffalsy %}
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
<!-- Quote -->
|
|
76
|
+
<p class="mb-0 text-body">{{ testimonial.quote }}</p>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
{% endfor %}
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
{% endif %}
|
|
84
|
+
</section>
|
|
@@ -50,7 +50,7 @@ hero:
|
|
|
50
50
|
|
|
51
51
|
# Trusted By Section
|
|
52
52
|
trusted_by:
|
|
53
|
-
headline: "Trusted by the
|
|
53
|
+
headline: "Trusted by the best"
|
|
54
54
|
logos:
|
|
55
55
|
# - name: "airbnb"
|
|
56
56
|
- name: "amazon"
|
|
@@ -348,10 +348,10 @@ cta:
|
|
|
348
348
|
<h3 class="fs-4">{{ page.resolved.trusted_by.headline }}</h3>
|
|
349
349
|
</div>
|
|
350
350
|
|
|
351
|
-
<div class="
|
|
352
|
-
<div class="
|
|
351
|
+
<div class="infinite-scroll-wrapper" data-lazy="@class animation-slide-up">
|
|
352
|
+
<div class="infinite-scroll-track">
|
|
353
353
|
{% for logo in page.resolved.trusted_by.logos %}
|
|
354
|
-
<div class="
|
|
354
|
+
<div class="infinite-scroll-item infinite-scroll-item--logo filter-adaptive hover-opacity">
|
|
355
355
|
{% uj_logo logo.name, "combomarks", "original" %}
|
|
356
356
|
</div>
|
|
357
357
|
{% endfor %}
|
|
@@ -544,73 +544,7 @@ cta:
|
|
|
544
544
|
</div>
|
|
545
545
|
</section>
|
|
546
546
|
|
|
547
|
-
|
|
548
|
-
<section>
|
|
549
|
-
<div class="container">
|
|
550
|
-
<div class="text-center mb-5" data-lazy="@class animation-slide-up">
|
|
551
|
-
{% iftruthy page.resolved.testimonials.superheadline.text %}
|
|
552
|
-
<span class="badge bg-body-tertiary border-gradient-rainbow border-1 text-body p-2 mb-1 fw-semibold small">
|
|
553
|
-
{% iftruthy page.resolved.testimonials.superheadline.icon %}
|
|
554
|
-
{% uj_icon page.resolved.testimonials.superheadline.icon, "me-1" %}
|
|
555
|
-
{% endiftruthy %}
|
|
556
|
-
{{ page.resolved.testimonials.superheadline.text }}
|
|
557
|
-
</span>
|
|
558
|
-
{% endiftruthy %}
|
|
559
|
-
<h2 class="h2 mb-2">
|
|
560
|
-
{{ page.resolved.testimonials.headline }}
|
|
561
|
-
{% iftruthy page.resolved.testimonials.headline_accent %}
|
|
562
|
-
<span class="text-accent">{{ page.resolved.testimonials.headline_accent }}</span>
|
|
563
|
-
{% endiftruthy %}
|
|
564
|
-
</h2>
|
|
565
|
-
{% iftruthy page.resolved.testimonials.subheadline %}
|
|
566
|
-
<p class="fs-5 text-muted">{{ page.resolved.testimonials.subheadline }}</p>
|
|
567
|
-
{% endiftruthy %}
|
|
568
|
-
</div>
|
|
569
|
-
|
|
570
|
-
{% if page.resolved.testimonials.items %}
|
|
571
|
-
<div id="homeTestimonialCarousel" class="carousel slide" data-bs-ride="carousel" data-lazy="@class animation-slide-up">
|
|
572
|
-
<div class="carousel-indicators">
|
|
573
|
-
{% for testimonial in page.resolved.testimonials.items %}
|
|
574
|
-
<button type="button" data-bs-target="#homeTestimonialCarousel" data-bs-slide-to="{{ forloop.index0 }}" {% if forloop.first %}class="active" aria-current="true"{% endif %} aria-label="Slide {{ forloop.index }}"></button>
|
|
575
|
-
{% endfor %}
|
|
576
|
-
</div>
|
|
577
|
-
|
|
578
|
-
<div class="carousel-inner">
|
|
579
|
-
{% for testimonial in page.resolved.testimonials.items %}
|
|
580
|
-
<div class="carousel-item {% if forloop.first %}active{% endif %}">
|
|
581
|
-
<div class="row justify-content-center">
|
|
582
|
-
<div class="col-md-8">
|
|
583
|
-
<div class="card border-0 shadow-sm my-1 rounded-3">
|
|
584
|
-
<div class="card-body p-5 text-center">
|
|
585
|
-
<div class="d-flex justify-content-center mb-4">
|
|
586
|
-
<div class="avatar avatar-xl rounded-circle bg-primary text-light d-flex align-items-center justify-content-center">
|
|
587
|
-
<span class="fs-2 fw-bold">{{ testimonial.initial }}</span>
|
|
588
|
-
</div>
|
|
589
|
-
</div>
|
|
590
|
-
<blockquote class="mb-4">
|
|
591
|
-
<p class="fs-4 fw-bold">"{{ testimonial.quote }}"</p>
|
|
592
|
-
</blockquote>
|
|
593
|
-
<p class="text-muted fs-5 mb-0">{{ testimonial.author }}, {{ testimonial.role }} at {{ testimonial.company }}</p>
|
|
594
|
-
</div>
|
|
595
|
-
</div>
|
|
596
|
-
</div>
|
|
597
|
-
</div>
|
|
598
|
-
</div>
|
|
599
|
-
{% endfor %}
|
|
600
|
-
</div>
|
|
601
|
-
|
|
602
|
-
<button class="carousel-control-prev" type="button" data-bs-target="#homeTestimonialCarousel" data-bs-slide="prev">
|
|
603
|
-
<span class="carousel-control-prev-icon rounded-circle p-3" aria-hidden="true"></span>
|
|
604
|
-
<span class="visually-hidden">Previous</span>
|
|
605
|
-
</button>
|
|
606
|
-
<button class="carousel-control-next" type="button" data-bs-target="#homeTestimonialCarousel" data-bs-slide="next">
|
|
607
|
-
<span class="carousel-control-next-icon rounded-circle p-3" aria-hidden="true"></span>
|
|
608
|
-
<span class="visually-hidden">Next</span>
|
|
609
|
-
</button>
|
|
610
|
-
</div>
|
|
611
|
-
{% endif %}
|
|
612
|
-
</div>
|
|
613
|
-
</section>
|
|
547
|
+
{% include themes/classy/frontend/components/testimonial-scroll.html testimonials=page.resolved.testimonials %}
|
|
614
548
|
|
|
615
549
|
<!-- Stats Section -->
|
|
616
550
|
<section>
|
|
@@ -739,73 +739,7 @@ faqs:
|
|
|
739
739
|
</div>
|
|
740
740
|
</section>
|
|
741
741
|
|
|
742
|
-
|
|
743
|
-
<section>
|
|
744
|
-
<div class="container">
|
|
745
|
-
<div class="text-center mb-5" data-lazy="@class animation-slide-up">
|
|
746
|
-
{% iftruthy page.resolved.testimonials.superheadline.text %}
|
|
747
|
-
<span class="badge bg-body-tertiary border-gradient-rainbow border-1 text-body p-2 mb-1 fw-semibold small">
|
|
748
|
-
{% iftruthy page.resolved.testimonials.superheadline.icon %}
|
|
749
|
-
{% uj_icon page.resolved.testimonials.superheadline.icon, "me-1" %}
|
|
750
|
-
{% endiftruthy %}
|
|
751
|
-
{{ page.resolved.testimonials.superheadline.text }}
|
|
752
|
-
</span>
|
|
753
|
-
{% endiftruthy %}
|
|
754
|
-
<h2 class="h2 mb-2">
|
|
755
|
-
{{ page.resolved.testimonials.headline }}
|
|
756
|
-
{% iftruthy page.resolved.testimonials.headline_accent %}
|
|
757
|
-
<span class="text-accent">{{ page.resolved.testimonials.headline_accent }}</span>
|
|
758
|
-
{% endiftruthy %}
|
|
759
|
-
</h2>
|
|
760
|
-
{% iftruthy page.resolved.testimonials.subheadline %}
|
|
761
|
-
<p class="fs-5 text-muted">{{ page.resolved.testimonials.subheadline }}</p>
|
|
762
|
-
{% endiftruthy %}
|
|
763
|
-
</div>
|
|
764
|
-
|
|
765
|
-
{% if page.resolved.testimonials.items %}
|
|
766
|
-
<div id="testimonialCarousel" class="carousel slide" data-bs-ride="carousel" data-lazy="@class animation-slide-up">
|
|
767
|
-
<div class="carousel-indicators">
|
|
768
|
-
{% for testimonial in page.resolved.testimonials.items %}
|
|
769
|
-
<button type="button" data-bs-target="#testimonialCarousel" data-bs-slide-to="{{ forloop.index0 }}" {% if forloop.first %}class="active" aria-current="true"{% endif %} aria-label="Slide {{ forloop.index }}"></button>
|
|
770
|
-
{% endfor %}
|
|
771
|
-
</div>
|
|
772
|
-
|
|
773
|
-
<div class="carousel-inner">
|
|
774
|
-
{% for testimonial in page.resolved.testimonials.items %}
|
|
775
|
-
<div class="carousel-item {% if forloop.first %}active{% endif %}">
|
|
776
|
-
<div class="row justify-content-center">
|
|
777
|
-
<div class="col-md-8">
|
|
778
|
-
<div class="card border-0 shadow-sm my-1">
|
|
779
|
-
<div class="card-body p-5 text-center">
|
|
780
|
-
<div class="d-flex justify-content-center mb-4">
|
|
781
|
-
<div class="avatar avatar-xl rounded-circle bg-primary text-light d-flex align-items-center justify-content-center">
|
|
782
|
-
<span class="fs-2 fw-bold">{{ testimonial.initial }}</span>
|
|
783
|
-
</div>
|
|
784
|
-
</div>
|
|
785
|
-
<blockquote class="mb-4">
|
|
786
|
-
<p class="fs-4 fw-bold">"{{ testimonial.quote }}"</p>
|
|
787
|
-
</blockquote>
|
|
788
|
-
<p class="text-muted fs-5 mb-0">{{ testimonial.author }}, {{ testimonial.role }} at {{ testimonial.company }}</p>
|
|
789
|
-
</div>
|
|
790
|
-
</div>
|
|
791
|
-
</div>
|
|
792
|
-
</div>
|
|
793
|
-
</div>
|
|
794
|
-
{% endfor %}
|
|
795
|
-
</div>
|
|
796
|
-
|
|
797
|
-
<button class="carousel-control-prev" type="button" data-bs-target="#testimonialCarousel" data-bs-slide="prev">
|
|
798
|
-
<span class="carousel-control-prev-icon rounded-circle p-3" aria-hidden="true"></span>
|
|
799
|
-
<span class="visually-hidden">Previous</span>
|
|
800
|
-
</button>
|
|
801
|
-
<button class="carousel-control-next" type="button" data-bs-target="#testimonialCarousel" data-bs-slide="next">
|
|
802
|
-
<span class="carousel-control-next-icon rounded-circle p-3" aria-hidden="true"></span>
|
|
803
|
-
<span class="visually-hidden">Next</span>
|
|
804
|
-
</button>
|
|
805
|
-
</div>
|
|
806
|
-
{% endif %}
|
|
807
|
-
</div>
|
|
808
|
-
</section>
|
|
742
|
+
{% include themes/classy/frontend/components/testimonial-scroll.html testimonials=page.resolved.testimonials %}
|
|
809
743
|
|
|
810
744
|
<!-- FAQ Section -->
|
|
811
745
|
<section>
|
|
@@ -24,7 +24,7 @@ company_values:
|
|
|
24
24
|
<div class="row justify-content-center text-center">
|
|
25
25
|
<div class="col-lg-10">
|
|
26
26
|
<h1 class="h1 mb-3">
|
|
27
|
-
Meet
|
|
27
|
+
Meet our <span class="text-gradient-rainbow">amazing team</span>
|
|
28
28
|
</h1>
|
|
29
29
|
<p class="fs-5 text-muted mb-0">
|
|
30
30
|
We're a diverse group of passionate individuals working together to build the future of {{ site.brand.name }}. Get to know the people behind the magic.
|
|
@@ -46,7 +46,7 @@ company_values:
|
|
|
46
46
|
{% for member in site.team %}
|
|
47
47
|
<div class="col-lg-4 col-md-6">
|
|
48
48
|
<div class="card h-100 border-0 shadow-sm team-member-card">
|
|
49
|
-
<div class="card-body p-4 text-center">
|
|
49
|
+
<div class="card-body p-4 text-center d-flex flex-column">
|
|
50
50
|
<div class="position-relative mb-3 d-inline-block">
|
|
51
51
|
<a href="{{ site.url }}{{ member.url }}" class="text-decoration-none d-block">
|
|
52
52
|
<div class="avatar avatar-2xl">
|
|
@@ -61,19 +61,25 @@ company_values:
|
|
|
61
61
|
</a>
|
|
62
62
|
</h4>
|
|
63
63
|
<p class="text-primary fw-semibold mb-3">{{ member.member.position }}</p>
|
|
64
|
-
<p class="text-muted small mb-
|
|
64
|
+
<p class="text-muted small mb-0 flex-grow-1">{{ member.member.description }}</p>
|
|
65
65
|
|
|
66
66
|
{% iftruthy member.member.links %}
|
|
67
|
-
<div class="d-flex justify-content-center gap-2">
|
|
67
|
+
<div class="d-flex justify-content-center gap-2 mt-3">
|
|
68
68
|
{% for link in member.member.links %}
|
|
69
69
|
{% assign link_icon = link.id %}
|
|
70
70
|
{% if link.id == "website" %}{% assign link_icon = "globe" %}{% endif %}
|
|
71
|
-
<a href="{{ link.url }}" class="btn btn-outline-
|
|
71
|
+
<a href="{{ link.url }}" class="btn btn-outline-adaptive btn-sm avatar avatar-md rounded-circle d-flex align-items-center justify-content-center" target="_blank" rel="nofollow noopener" title="{{ link.title }}">
|
|
72
72
|
{% uj_icon link_icon, "" %}
|
|
73
73
|
</a>
|
|
74
74
|
{% endfor %}
|
|
75
75
|
</div>
|
|
76
76
|
{% endiftruthy %}
|
|
77
|
+
|
|
78
|
+
<div class="mt-3">
|
|
79
|
+
<a href="{{ site.url }}{{ member.url }}" class="btn btn-outline-primary btn-sm">
|
|
80
|
+
View Profile
|
|
81
|
+
</a>
|
|
82
|
+
</div>
|
|
77
83
|
</div>
|
|
78
84
|
</div>
|
|
79
85
|
</div>
|
|
@@ -12,7 +12,7 @@ layout: themes/[ site.theme.id ]/frontend/core/base
|
|
|
12
12
|
<div class="col-lg-10">
|
|
13
13
|
<div class="text-center">
|
|
14
14
|
<!-- Member Image -->
|
|
15
|
-
<div class="mb-4 avatar avatar-
|
|
15
|
+
<div class="mb-4 avatar avatar-5xl">
|
|
16
16
|
{%- uj_member page.member.id, "image-tag", class="rounded-circle object-fit-cover shadow-lg team-member-image" -%}
|
|
17
17
|
</div>
|
|
18
18
|
|
|
@@ -5,13 +5,17 @@
|
|
|
5
5
|
text: '{{ site.brand.name }}',
|
|
6
6
|
},
|
|
7
7
|
links: [
|
|
8
|
+
{
|
|
9
|
+
label: 'Pricing',
|
|
10
|
+
href: '/pricing'
|
|
11
|
+
},
|
|
8
12
|
{
|
|
9
13
|
label: 'About',
|
|
10
14
|
href: '/about'
|
|
11
15
|
},
|
|
12
16
|
{
|
|
13
|
-
label: '
|
|
14
|
-
href: '/
|
|
17
|
+
label: 'Contact',
|
|
18
|
+
href: '/contact'
|
|
15
19
|
},
|
|
16
20
|
{
|
|
17
21
|
label: 'Explore',
|
|
@@ -24,13 +28,13 @@
|
|
|
24
28
|
{
|
|
25
29
|
label: 'Team',
|
|
26
30
|
href: '/team'
|
|
27
|
-
}
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
label: 'Careers',
|
|
34
|
+
href: '/careers'
|
|
35
|
+
},
|
|
28
36
|
]
|
|
29
37
|
},
|
|
30
|
-
{
|
|
31
|
-
label: 'Contact',
|
|
32
|
-
href: '/contact'
|
|
33
|
-
}
|
|
34
38
|
],
|
|
35
39
|
actions: [
|
|
36
40
|
{
|
|
@@ -18,6 +18,9 @@ const config = Manager.getConfig('project');
|
|
|
18
18
|
const rootPathPackage = Manager.getRootPath('main');
|
|
19
19
|
const rootPathProject = Manager.getRootPath('project');
|
|
20
20
|
|
|
21
|
+
// Constants
|
|
22
|
+
const LOUD = process.env.UJ_LOUD_LOGS === 'true';
|
|
23
|
+
|
|
21
24
|
// Load ultimate-jekyll-manager.json config
|
|
22
25
|
const ujConfigPath = path.join(rootPathPackage, 'dist/defaults/config/ultimate-jekyll-manager.json');
|
|
23
26
|
const ujConfig = jetpack.exists(ujConfigPath) ? JSON5.parse(jetpack.read(ujConfigPath)) : {};
|
|
@@ -465,7 +468,11 @@ function customTransform() {
|
|
|
465
468
|
|
|
466
469
|
// Skip if instructed
|
|
467
470
|
if (options.skip || (!options.overwrite && exists && !options.merge && !options.mergeLines)) {
|
|
468
|
-
|
|
471
|
+
// Log if loud is enabled
|
|
472
|
+
if (LOUD) {
|
|
473
|
+
logger.log(`Skipping file: ${relativePath}`);
|
|
474
|
+
}
|
|
475
|
+
|
|
469
476
|
return callback();
|
|
470
477
|
}
|
|
471
478
|
|
|
@@ -13,6 +13,9 @@ const config = Manager.getConfig('project');
|
|
|
13
13
|
const rootPathPackage = Manager.getRootPath('main');
|
|
14
14
|
const rootPathProject = Manager.getRootPath('project');
|
|
15
15
|
|
|
16
|
+
// Constants
|
|
17
|
+
const LOUD = process.env.UJ_LOUD_LOGS === 'true';
|
|
18
|
+
|
|
16
19
|
// Glob
|
|
17
20
|
const input = [
|
|
18
21
|
// Files to include
|
|
@@ -75,7 +78,9 @@ function customTransform() {
|
|
|
75
78
|
const relativePath = path.relative(file.base, file.path).replace(/\\/g, '/');
|
|
76
79
|
|
|
77
80
|
// Log
|
|
78
|
-
|
|
81
|
+
if (LOUD) {
|
|
82
|
+
logger.log(`Processing file: ${relativePath}`);
|
|
83
|
+
}
|
|
79
84
|
|
|
80
85
|
// Change path if it starts with 'pages/'
|
|
81
86
|
// if (relativePath.startsWith('pages/')) {
|
|
@@ -99,7 +99,9 @@ async function jekyll(complete) {
|
|
|
99
99
|
Manager.isBuildMode() ? '' : `./node_modules/${package.name}/dist/config/_config_development.yml`,
|
|
100
100
|
].join(','),
|
|
101
101
|
'--incremental',
|
|
102
|
-
Manager.isBuildMode() ? ' --profile' : '',
|
|
102
|
+
(Manager.isBuildMode() || argv.profile) ? ' --profile' : '',
|
|
103
|
+
// Limit posts in development for faster builds (use --all-posts to disable)
|
|
104
|
+
(!Manager.isBuildMode() && !argv['all-posts']) ? '--limit_posts 15' : '',
|
|
103
105
|
// '--disable-disk-cache',
|
|
104
106
|
]
|
|
105
107
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultimate-jekyll-manager",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.141",
|
|
4
4
|
"description": "Ultimate Jekyll dependency manager",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"sass": "^1.94.2",
|
|
98
98
|
"spellchecker": "^3.7.1",
|
|
99
99
|
"through2": "^4.0.2",
|
|
100
|
-
"web-manager": "^4.0.
|
|
100
|
+
"web-manager": "^4.0.32",
|
|
101
101
|
"webpack": "^5.103.0",
|
|
102
102
|
"wonderful-fetch": "^1.3.4",
|
|
103
103
|
"wonderful-version": "^1.3.2",
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
// Logo Scroll Animation Component
|
|
2
|
-
// Infinite scrolling logo carousel for partner/client sections
|
|
3
|
-
|
|
4
|
-
// ============================================
|
|
5
|
-
// Container & Track
|
|
6
|
-
// ============================================
|
|
7
|
-
|
|
8
|
-
.logo-scroll-wrapper {
|
|
9
|
-
position: relative;
|
|
10
|
-
width: 100vw;
|
|
11
|
-
margin-left: calc(-50vw + 50%);
|
|
12
|
-
overflow: hidden;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.logo-scroll-track {
|
|
16
|
-
display: flex;
|
|
17
|
-
width: fit-content;
|
|
18
|
-
animation: scroll-logos var(--logo-scroll-duration, 30s) linear infinite;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.logo-item {
|
|
22
|
-
padding: 0 3rem;
|
|
23
|
-
display: flex;
|
|
24
|
-
align-items: center;
|
|
25
|
-
height: 60px;
|
|
26
|
-
flex-shrink: 0;
|
|
27
|
-
|
|
28
|
-
img, svg {
|
|
29
|
-
height: 40px;
|
|
30
|
-
width: auto;
|
|
31
|
-
max-width: 150px;
|
|
32
|
-
transition: all 0.3s ease;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
@keyframes scroll-logos {
|
|
37
|
-
0% {
|
|
38
|
-
transform: translateX(0);
|
|
39
|
-
}
|
|
40
|
-
100% {
|
|
41
|
-
transform: translateX(var(--logo-scroll-distance, -50%));
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ============================================
|
|
46
|
-
// Responsive Design
|
|
47
|
-
// ============================================
|
|
48
|
-
@media (max-width: 768px) {
|
|
49
|
-
.logo-item {
|
|
50
|
-
padding: 0 2rem;
|
|
51
|
-
height: 50px;
|
|
52
|
-
|
|
53
|
-
img, svg {
|
|
54
|
-
height: 30px;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
// Setup speed
|
|
2
|
-
const SCROLL_SPEED_PX_PER_SECOND = 40; // Pixels per second
|
|
3
|
-
|
|
4
|
-
// Logo scroll animation setup
|
|
5
|
-
export default function setupLogoScroll() {
|
|
6
|
-
const scrollTracks = document.querySelectorAll('.logo-scroll-track');
|
|
7
|
-
|
|
8
|
-
scrollTracks.forEach(track => {
|
|
9
|
-
if (!track) {
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// Get original logos
|
|
14
|
-
const originalLogos = Array.from(track.children);
|
|
15
|
-
if (originalLogos.length === 0) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Calculate total width of original logos
|
|
20
|
-
let totalWidth = 0;
|
|
21
|
-
originalLogos.forEach(logo => {
|
|
22
|
-
totalWidth += logo.getBoundingClientRect().width;
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// Calculate how many sets we need to fill the screen plus extra for smooth scrolling
|
|
26
|
-
const viewportWidth = window.innerWidth;
|
|
27
|
-
const setsNeeded = Math.ceil((viewportWidth * 2.5) / totalWidth);
|
|
28
|
-
|
|
29
|
-
// Clone logo sets
|
|
30
|
-
for (let i = 0; i < setsNeeded; i++) {
|
|
31
|
-
originalLogos.forEach(logo => {
|
|
32
|
-
const clone = logo.cloneNode(true);
|
|
33
|
-
track.appendChild(clone);
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Calculate animation duration based on total width
|
|
38
|
-
// Slower speed for better visibility
|
|
39
|
-
const allLogos = track.children;
|
|
40
|
-
let animationWidth = 0;
|
|
41
|
-
|
|
42
|
-
// Calculate width of half the logos (for the 50% translation)
|
|
43
|
-
const halfCount = Math.floor(allLogos.length / 2);
|
|
44
|
-
for (let i = 0; i < halfCount; i++) {
|
|
45
|
-
animationWidth += allLogos[i].getBoundingClientRect().width;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Set CSS variables for animation
|
|
49
|
-
const duration = animationWidth / SCROLL_SPEED_PX_PER_SECOND;
|
|
50
|
-
track.style.setProperty('--logo-scroll-duration', `${duration}s`);
|
|
51
|
-
track.style.setProperty('--logo-scroll-distance', `-${animationWidth}px`);
|
|
52
|
-
|
|
53
|
-
// Restart animation when it completes to ensure seamless loop
|
|
54
|
-
track.addEventListener('animationiteration', () => {
|
|
55
|
-
// Reset the animation to prevent accumulation of drift
|
|
56
|
-
track.style.animation = 'none';
|
|
57
|
-
track.offsetHeight; // Trigger reflow
|
|
58
|
-
track.style.animation = `scroll-logos var(--logo-scroll-duration, ${duration}s) linear infinite`;
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// Recalculate on window resize
|
|
63
|
-
let resizeTimeout;
|
|
64
|
-
window.addEventListener('resize', () => {
|
|
65
|
-
clearTimeout(resizeTimeout);
|
|
66
|
-
resizeTimeout = setTimeout(() => {
|
|
67
|
-
// Reset and recalculate
|
|
68
|
-
scrollTracks.forEach(track => {
|
|
69
|
-
// Remove cloned logos
|
|
70
|
-
const logos = Array.from(track.children);
|
|
71
|
-
const originalCount = logos.length / (Math.ceil(logos.length / 8)); // Estimate original count
|
|
72
|
-
|
|
73
|
-
// Keep only estimated original logos
|
|
74
|
-
while (track.children.length > 8) { // Assuming max 8 original logos
|
|
75
|
-
track.removeChild(track.lastChild);
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// Re-run setup
|
|
80
|
-
setupLogoScroll();
|
|
81
|
-
}, 250);
|
|
82
|
-
});
|
|
83
|
-
}
|