Skip to content
53 changes: 53 additions & 0 deletions website/modules/asset/ui/src/clientSideFiltering.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Client-side filtering for case studies with page reload

const shouldInterceptClick = function (link) {
const href = link.getAttribute('href');
return (
href &&
(href.includes('#filter') ||
href.includes('?industry=') ||
href.includes('&industry=') ||
href.includes('?stack=') ||
href.includes('&stack=') ||
href.includes('?caseStudyType=') ||
href.includes('&caseStudyType='))
);
};

const handleFilterClick = function (event) {
const filterLink = event.target.closest(
'.tag-link, .remove-tag, .clear-all-link',
);
if (!filterLink || !shouldInterceptClick(filterLink)) {
return;
}

event.preventDefault();

const href = filterLink.getAttribute('href');
try {
const url = new URL(href, window.location.origin);
const newUrl = url.pathname + url.search + url.hash;

history.pushState({ clientSideFilter: true, url: newUrl }, '', newUrl);
window.location.reload();
} catch {
// Fallback to default navigation if URL construction fails
window.location.href = href;
}
};

const handlePopState = function (event) {
if (event.state?.clientSideFilter) {
window.location.reload();
}
};

export const initClientSideFiltering = function () {
if (!document.querySelector('.cs_list')) {
return;
}

window.addEventListener('popstate', handlePopState);
document.addEventListener('click', handleFilterClick);
};
38 changes: 20 additions & 18 deletions website/modules/asset/ui/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ import { initSmoothCounters } from './smoothCounters';
import lozad from 'lozad';
import { setupTagSearchForInput } from './searchInputHandler';
import { FilterModal } from './filterModal';
import { initClientSideFiltering } from './clientSideFiltering';

/* eslint-enable sort-imports */

// Initialize configuration from data attributes
function initConfiguration() {
// Set default fallback value first
window.DEFAULT_VISIBLE_TAGS_COUNT = 5;

const container = document.querySelector('.cs_container');
if (container) {
const defaultVisibleTags = container.getAttribute(
Expand All @@ -31,14 +30,11 @@ function initConfiguration() {
}
}

// Lazy loading
function initImageLozad() {
// Lazy loads elements with default selector as '.lozad'
const observer = lozad();
observer.observe();
}

// Change fonts for the hero FUTURE word
function initFontChanger() {
const heroContent = document.querySelector('.sf-hero-content strong');
if (!heroContent) return;
Expand Down Expand Up @@ -84,7 +80,6 @@ function initCaseStudiesTagFilter({
);
}

// Wrapper function
function initializeAllComponents() {
initImageLozad();
initAllSwipers();
Expand All @@ -94,6 +89,7 @@ function initializeAllComponents() {
initPhoneFormatting();
initCaseStudiesTagFilter();
initCaseStudiesFilterHandler();
initClientSideFiltering();
}

// Barba pages
Expand All @@ -114,7 +110,6 @@ function initBarbaPageTransitions() {
// Close menu if it's open
const menuButton = document.getElementById('nav-icon');
const menu = document.querySelector('[data-menu]');

if (menuButton && menu) {
menu.classList.remove('open');
menuButton.classList.remove('open');
Expand All @@ -126,7 +121,6 @@ function initBarbaPageTransitions() {
video.play();
}

// Call the wrapper function to initialize all components
initializeAllComponents();

// Initialize Apostrophe forms before removing old content
Expand Down Expand Up @@ -248,7 +242,6 @@ function initMenuToggle() {

// Filter Case Studies modal for Case Studies mobile page
function initFilterModal() {
// Only initialize if we're on the case studies page
if (!document.querySelector('.cs_list')) {
return;
}
Expand All @@ -266,21 +259,17 @@ function initFilterModal() {

document.addEventListener('DOMContentLoaded', initFilterModal);

// Initialize after Barba transitions
if (typeof barba !== 'undefined') {
barba.hooks.after(() => {
initFilterModal();
});
}

export default () => {
// Initialize configuration first
initConfiguration();

// Init all scripts after first visiting the page
initializeAllComponents();

// Initialize case studies filter handler when DOM is ready
apos.util.onReady(() => {
initCaseStudiesFilterHandler();
});
Expand All @@ -289,8 +278,21 @@ export default () => {
initAnchorNavigation();
initMenuToggle();

// Check if in edit mode
if (apos.adminBar) {
initSmoothCounters();
}
// Case studies anchor fix
setTimeout(() => {
const { pathname, search, hash } = window.location;
const isCasesPage = pathname.includes('/cases');
const hasFilterParams =
search.includes('industry') ||
search.includes('stack') ||
search.includes('caseStudyType') ||
hash.includes('filter');

if (isCasesPage && hasFilterParams) {
const filterAnchor = document.getElementById('filter');
if (filterAnchor) filterAnchor.scrollIntoView({ behavior: 'smooth' });
}
}, 300);

if (apos.adminBar) initSmoothCounters();
};
9 changes: 6 additions & 3 deletions website/modules/asset/ui/src/scss/_cases.scss
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
flex-direction: column;
gap: 32px;
align-items: center;
min-height: calc(100vh - 330px);

@include breakpoint-medium {
flex-direction: row;
Expand Down Expand Up @@ -616,14 +617,15 @@

.filter-anchor {
position: relative;
top: -64px;
top: -$mobile-header-height;
height: 0;
visibility: hidden;
@include breakpoint-medium {
top: -95px;
top: -$desktop-header-height;
}
}

// Case Study preview card
// Case Study preview card with loading state transition
.cs_grid {
display: grid;
grid-template-columns: 1fr;
Expand All @@ -632,6 +634,7 @@
opacity: 0;
transform: translateY(30px);
filter: blur(2px);
transition: opacity 0.3s ease;
animation: smoothFadeInUp 1.2s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.2s
forwards;

Expand Down
23 changes: 16 additions & 7 deletions website/modules/case-studies-page/views/index.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
{# modules/case-studies-page/views/index.new.html #} {% extends "layout.html" %}
{% import '@apostrophecms/pager:macros.html' as pager with context %} {% block
main %}
<div class="cs_container" data-default-visible-tags="{{ data.defaultVisibleTagsCount }}">
<div
class="cs_container"
data-default-visible-tags="{{ data.defaultVisibleTagsCount }}"
>
<div class="cs_content">
<div class="page-main_content">
{% area data.page, 'main' %}
<div id="filter" class="filter-anchor"></div>
</div>
<div class="page-main_content">{% area data.page, 'main' %}</div>

<div id="filter" class="filter-anchor"></div>

<div class="cs_filter-info">
<div class="filters-cta">Filter Case Studies</div>
Expand Down Expand Up @@ -165,7 +167,10 @@
{% endif %}
</li>
{% else %}
<li class="tag-item{% if loop.index > data.defaultVisibleTagsCount %} tag-item--hidden{% endif %}" data-label="{{ tag.label | lower }}">
<li
class="tag-item{% if loop.index > data.defaultVisibleTagsCount %} tag-item--hidden{% endif %}"
data-label="{{ tag.label | lower }}"
>
{% if filterType == 'industry' %}
<a
class="tag-link"
Expand Down Expand Up @@ -195,7 +200,11 @@
{% endif %} {% endfor %}
</ul>
{% if tags.length > data.defaultVisibleTagsCount %}
<button class="tags__show-more" data-filter-type="{{ filterType }}" type="button">
<button
class="tags__show-more"
data-filter-type="{{ filterType }}"
type="button"
>
<span class="tags__show-more--icon">
<img src="/images/plus.svg" alt="Plus icon" />
</span>
Expand Down
Loading