467 lines
17 KiB
Plaintext
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>
|
|
|