Files
Gainsight/Custom_Templates/customer_templates/ACPA Sandbox v1/catalog.html.liquid
Norm Rasmussen 2de37ce3bc Tasks.
2025-04-15 14:10:04 -04:00

467 lines
17 KiB
Plaintext

{% include "header" %}
{% include "course_version_outdated_alert", courses: courses.in_catalog %}
{% include "sub_navigation" %}
<main class="np-main np-catalog np-subpage-container np-max-width">
<div class="np-catalog-header-wrapper">
<div class="np-catalog-header">
<div class="np-resource-title">{{ catalog.headline }}</div>
<div class="np-resource-subtitle">{{ catalog.subheadline }}</div>
</div>
</div>
<div class="catalog-wrapper row">
<!-- Filter Sidebar -->
<div class="catalog-filter-wrapper col-md-3 col-12 np-hidden-mobile">
<div class="catalog-filter-header">Categories</div>
<div class="catalog-filter">
{% assign sorted_categories = current_school.filterable_categories | sort: "name" %}
{% for category in sorted_categories %}
{% unless category.name contains '[Role]' %}
<div class="filter-entry">
<input type="checkbox" class="filter-checkbox category-checkbox"
data-filter-type="category" value="{{ category.id }}" id="cat-{{ category.id }}">
<label for="cat-{{ category.id }}">{{ category.name }}</label>
</div>
{% endunless %}
{% endfor %}
</div>
<div id="duration-filter-block">
<div class="catalog-filter-header">Duration</div>
{% assign allDurations = "10 Minutes or less, 10 - 30 Minutes, 30 - 60 Minutes, 1 - 2 Hours, 2 Hours or more" | split: ', ' %}
{% for duration in allDurations %}
{% assign duration_id = duration | replace: ' ', '-' | replace: ',', '' | downcase %}
<div class="filter-entry">
<input type="checkbox" class="filter-checkbox duration-checkbox"
data-filter-type="duration" value="{{ duration }}" id="dur-{{ duration_id }}">
<label for="dur-{{ duration_id }}">{{ duration }}</label>
</div>
{% endfor %}
</div>
{% assign render_roles = false %}
{% for category in current_school.filterable_categories %}
{% if category.name contains '[Role]' %}
{% assign render_roles = true %}
{% endif %}
{% endfor %}
{% if render_roles %}
<div id="role-filter-block">
<div class="catalog-filter-header">Role</div>
{% assign sorted_cats = current_school.filterable_categories | sort: "name" %}
{% for category in sorted_cats %}
{% if category.name contains '[Role]' %}
{% assign roleSplit = category.name | split: '-' %}
{% assign roleName = roleSplit[1] | strip %}
{% assign role_id = roleName | replace: ' ', '-' | downcase %}
<div class="filter-entry">
<input type="checkbox" class="filter-checkbox role-checkbox"
data-filter-type="rolecategory" value="{{ category.id }}" id="role-{{ role_id }}">
<label for="role-{{ role_id }}">{{ roleName }}</label>
</div>
{% endif %}
{% endfor %}
</div>
{% endif %}
</div>
<!-- Courses Grid -->
<div class="np-catalog-courses row row-with-thumbnails col-md-9 col-12">
{% if courses.in_catalog and courses.in_catalog.size > 0 %}
{% for course in courses.in_catalog %}
<div class="col-xs-12 col-md-6 col-lg-4 np-stretch-content catalog-content"
data-categories="{% for category in course.categories %}{{ category.id }}{% unless forloop.last %},{% endunless %}{% endfor %}"
data-duration="{{ course.properties['course_time'] | default: 0 }}"
data-roles="{% for category in course.categories %}{% if category.name contains '[Role]' %}{{ category.id }}{% unless forloop.last %},{% endunless %}{% endif %}{% endfor %}">
<div class="np-card">
<div class="np-card-container">
<div class="np-card-image-content-top" style="top: 0.75rem; left: 0.75rem">
<div class="np-card-content-progress np-button-color" style="color: white; font-size: 14px; font-weight: 600;">
Not started
</div>
</div>
{% if course.image_url %}
<img class="np-card-image" alt="{{ course.name }}" src="{{ course.image_url }}">
{% endif %}
</div>
<div class="np-card-content np-card-content-vertical np-card-padding course-card-content" style="padding: 1.5rem; min-height: 255px;">
<div class="np-course-details">
<div class="np-course-detail">
<strong>{{ course.name }}</strong>
</div>
</div>
<div class="np-course-details">
<div class="np-course-detail" style="display:flex; align-items:center;">
<strong class="np-detail-text" style="margin-right:0.5rem;">{{ course.activities_count }}</strong>
<span class="np-details-label">
Activities
</span>
</div>
<div class="np-course-detail" style="display:flex; align-items:center;">
<strong class="np-detail-text" style="margin-right:0.5rem;">
{{ course.properties['course_time'] | default: 0 }}
</strong>
<span class="np-details-label">
Mins
</span>
</div>
</div>
<div class="np-card-content-footer">
{% capture course_path %}{% route course, id: course.id %}{% endcapture %}
<a class="np-top-button np-button-font-color np-button np-button-big" href="{{ course_path }}">
Start
</a>
</div>
</div>
</div>
</div>
{% endfor %}
{% else %}
<p class="np-text-muted">No courses found matching your filters.</p>
{% endif %}
</div>
</div>
</main>
{% include "footer" %}
<style>
.catalog-filter-wrapper {
padding: 25px;
background: #f8fafc;
border-radius: 8px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.catalog-filter-header {
color: #0254a1;
font-size: 1.1rem;
font-weight: 600;
margin: 20px 0 15px;
padding-bottom: 8px;
border-bottom: 2px solid #e2e8f0;
}
.filter-entry {
margin: 12px 0;
padding: 8px 12px;
border-radius: 4px;
transition: background-color 0.2s;
}
.filter-entry:hover {
background-color: rgba(2, 84, 161, 0.05);
}
.filter-entry label {
color: #1e293b;
font-size: 0.95rem;
cursor: pointer;
margin-left: 8px;
}
.filter-entry input[type="checkbox"] {
transform: scale(1.1);
margin-right: 8px;
}
.course-card-content {
background: #192B4C;
border-radius: 0 0 8px 8px;
}
.np-card {
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
border-radius: 8px;
overflow: hidden;
margin-bottom: 20px;
}
.np-card-image {
height: 200px;
object-fit: cover;
width: 100%;
}
.np-button-color {
background: #0254a1;
padding: 4px 12px;
border-radius: 4px;
display: inline-block;
}
.np-details-label {
color: #8c9db5;
font-size: 0.9rem;
}
.np-course-detail strong {
color: white;
font-size: 16px;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
const checkboxes = document.querySelectorAll('.filter-checkbox');
const courseCards = document.querySelectorAll('.catalog-content');
function applyFilters() {
const activeFilters = {
categories: new Set(),
durations: new Set(),
roles: new Set()
};
checkboxes.forEach(checkbox => {
if (checkbox.checked) {
const filterType = checkbox.dataset.filterType;
const value = checkbox.value;
if (filterType === 'category') activeFilters.categories.add(value);
if (filterType === 'duration') activeFilters.durations.add(value);
if (filterType === 'rolecategory') activeFilters.roles.add(value);
}
});
courseCards.forEach(card => {
const cardCategories = card.dataset.categories?.split(',') || [];
const cardDuration = parseInt(card.dataset.duration) || 0;
const cardRoles = card.dataset.roles?.split(',') || [];
const categoryMatch = activeFilters.categories.size === 0 ||
[...activeFilters.categories].some(cat => cardCategories.includes(cat));
const durationMatch = activeFilters.durations.size === 0 ||
[...activeFilters.durations].some(d => checkDuration(d, cardDuration));
const roleMatch = activeFilters.roles.size === 0 ||
[...activeFilters.roles].some(role => cardRoles.includes(role));
card.style.display = (categoryMatch && durationMatch && roleMatch) ? 'block' : 'none';
});
}
function checkDuration(durationRange, minutes) {
const ranges = {
'10 Minutes or less': m => m <= 10,
'10 - 30 Minutes': m => m > 10 && m <= 30,
'30 - 60 Minutes': m => m > 30 && m <= 60,
'1 - 2 Hours': m => m > 60 && m <= 120,
'2 Hours or more': m => m > 120
};
return ranges[durationRange]?.(minutes) || false;
}
checkboxes.forEach(checkbox => checkbox.addEventListener('change', applyFilters));
});
</script>
{% include "header" %}
{% include "course_version_outdated_alert", courses: courses.in_catalog %}
{% include "sub_navigation" %}
<main class="np-main np-catalog np-subpage-container np-max-width">
<div class="np-catalog-header-wrapper">
<div class="np-catalog-header">
<div class="np-resource-title">{{ catalog.headline }}</div>
<div class="np-resource-subtitle">{{ catalog.subheadline }}</div>
</div>
</div>
<div class="catalog-wrapper row">
<!-- Filter Sidebar -->
<div class="catalog-filter-wrapper col-md-3 col-12 np-hidden-mobile">
<div class="catalog-filter-header">Categories</div>
<div class="catalog-filter">
{% assign sorted_categories = current_school.filterable_categories | sort: "name" %}
{% for category in sorted_categories %}
{% unless category.name contains '[Role]' %}
<div class="filter-entry">
<input type="checkbox" class="filter-checkbox category-checkbox"
data-filter-type="category" value="{{ category.id }}" id="cat-{{ category.id }}">
<label for="cat-{{ category.id }}">{{ category.name }}</label>
</div>
{% endunless %}
{% endfor %}
</div>
<div id="duration-filter-block">
<div class="catalog-filter-header">Duration</div>
{% assign allDurations = "10 Minutes or less, 10 - 30 Minutes, 30 - 60 Minutes, 1 - 2 Hours, 2 Hours or more" | split: ', ' %}
{% for duration in allDurations %}
{% assign duration_id = duration | replace: ' ', '-' | replace: ',', '' | downcase %}
<div class="filter-entry">
<input type="checkbox" class="filter-checkbox duration-checkbox"
data-filter-type="duration" value="{{ duration }}" id="dur-{{ duration_id }}">
<label for="dur-{{ duration_id }}">{{ duration }}</label>
</div>
{% endfor %}
</div>
{% assign render_roles = false %}
{% for category in current_school.filterable_categories %}
{% if category.name contains '[Role]' %}
{% assign render_roles = true %}
{% endif %}
{% endfor %}
{% if render_roles %}
<div id="role-filter-block">
<div class="catalog-filter-header">Role</div>
{% assign sorted_cats = current_school.filterable_categories | sort: "name" %}
{% for category in sorted_cats %}
{% if category.name contains '[Role]' %}
{% assign roleSplit = category.name | split: '-' %}
{% assign roleName = roleSplit[1] | strip %}
{% assign role_id = roleName | replace: ' ', '-' | downcase %}
<div class="filter-entry">
<input type="checkbox" class="filter-checkbox role-checkbox"
data-filter-type="rolecategory" value="{{ category.id }}" id="role-{{ role_id }}">
<label for="role-{{ role_id }}">{{ roleName }}</label>
</div>
{% endif %}
{% endfor %}
</div>
{% endif %}
</div>
<!-- Courses Grid -->
<div class="np-catalog-courses col-md-9 col-12">
{% if courses.in_catalog and courses.in_catalog.size > 0 %}
<div class="row">
{% for course in courses.in_catalog %}
<div class="catalog-content col-md-4"
data-categories="{% for category in course.categories %}{{ category.id }}{% unless forloop.last %},{% endunless %}{% endfor %}"
data-duration="{{ course.properties['course_time'] | default: 0 }}"
data-roles="{% for category in course.categories %}{% if category.name contains '[Role]' %}{{ category.id }}{% unless forloop.last %},{% endunless %}{% endif %}{% endfor %}">
<!-- Maintain original course card structure -->
<div class="np-card">
{% if course.image_url %}
<img class="np-card-image" src="{{ course.image_url }}" alt="{{ course.name }}">
{% endif %}
<div class="np-card-content">
<h3 class="np-card-title">{{ course.name }}</h3>
<div class="np-card-description">{{ course.full_description | truncate: 120 }}</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<p class="np-text-muted">No courses found matching your filters.</p>
{% endif %}
</div>
</div>
</main>
{% include "footer" %}
<script>
document.addEventListener('DOMContentLoaded', function() {
const checkboxes = document.querySelectorAll('.filter-checkbox');
const courseCards = document.querySelectorAll('.catalog-content');
function applyFilters() {
const activeFilters = {
categories: new Set(),
durations: new Set(),
roles: new Set()
};
// Collect active filters
checkboxes.forEach(checkbox => {
if (checkbox.checked) {
const filterType = checkbox.dataset.filterType;
const value = checkbox.value;
if (filterType === 'category') activeFilters.categories.add(value);
if (filterType === 'duration') activeFilters.durations.add(value);
if (filterType === 'rolecategory') activeFilters.roles.add(value);
}
});
// Filter courses
courseCards.forEach(card => {
const cardCategories = card.dataset.categories?.split(',') || [];
const cardDuration = parseInt(card.dataset.duration) || 0;
const cardRoles = card.dataset.roles?.split(',') || [];
const categoryMatch = activeFilters.categories.size === 0 ||
[...activeFilters.categories].some(cat => cardCategories.includes(cat));
const durationMatch = activeFilters.durations.size === 0 ||
[...activeFilters.durations].some(d => checkDuration(d, cardDuration));
const roleMatch = activeFilters.roles.size === 0 ||
[...activeFilters.roles].some(role => cardRoles.includes(role));
card.style.display = (categoryMatch && durationMatch && roleMatch) ? 'block' : 'none';
});
}
function checkDuration(durationRange, minutes) {
const ranges = {
'10 Minutes or less': m => m <= 10,
'10 - 30 Minutes': m => m > 10 && m <= 30,
'30 - 60 Minutes': m => m > 30 && m <= 60,
'1 - 2 Hours': m => m > 60 && m <= 120,
'2 Hours or more': m => m > 120
};
return ranges[durationRange]?.(minutes) || false;
}
checkboxes.forEach(checkbox => checkbox.addEventListener('change', applyFilters));
});
</script>
<style>
.catalog-filter-wrapper {
padding: 25px;
background: #f8fafc; /* Light blue-gray background matching catalog text */
border-radius: 8px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.catalog-filter-header {
color: #0254a1; /* Matching catalog link color */
font-size: 1.1rem;
font-weight: 600;
margin: 20px 0 15px;
padding-bottom: 8px;
border-bottom: 2px solid #e2e8f0;
}
.filter-entry {
margin: 12px 0;
padding: 8px 12px;
border-radius: 4px;
transition: background-color 0.2s;
}
.filter-entry:hover {
background-color: rgba(2, 84, 161, 0.05);
}
.filter-entry label {
color: #1e293b; /* Dark text color matching catalog */
font-size: 0.95rem;
cursor: pointer;
margin-left: 8px;
}
.filter-entry input[type="checkbox"] {
transform: scale(1.1);
margin-right: 8px;
}
</style>