From d5d9b90b8df929745d339d3d38226a16cc6fac13 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sun, 23 May 2021 10:39:29 +0200 Subject: Add GoodReads CSS. --- pydis_site/static/css/resources/resources_list.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources_list.css b/pydis_site/static/css/resources/resources_list.css index 33129c87..e6808a99 100644 --- a/pydis_site/static/css/resources/resources_list.css +++ b/pydis_site/static/css/resources/resources_list.css @@ -34,12 +34,12 @@ i.resource-icon.is-youtube-red:hover { color: #f80000; } -i.resource-icon.is-amazon-orange { - color: #FF9900; +i.resource-icon.is-goodreads-cream { + color: #f3f2e9; } -i.resource-icon.is-amazon-orange:hover { - color: #ffb71a; +i.resource-icon.is-goodreads-cream:hover { + color: #ffffff; } i.resource-icon.is-black { -- cgit v1.2.3 From c781ed1f80188ffb274eeada974172f4aa07c0b5 Mon Sep 17 00:00:00 2001 From: fisher60 Date: Fri, 23 Jul 2021 20:20:10 -0500 Subject: change resources to prepare for smart resource search --- pydis_site/apps/resources/urls.py | 2 +- pydis_site/apps/resources/views/__init__.py | 4 +- pydis_site/apps/resources/views/resources.py | 10 +- pydis_site/static/css/resources/resources.css | 51 +++++----- pydis_site/templates/resources/resources.html | 131 ++++++++++++++------------ 5 files changed, 105 insertions(+), 93 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/apps/resources/urls.py b/pydis_site/apps/resources/urls.py index cd4f53e7..c8d441df 100644 --- a/pydis_site/apps/resources/urls.py +++ b/pydis_site/apps/resources/urls.py @@ -4,6 +4,6 @@ from pydis_site.apps.resources import views app_name = "resources" urlpatterns = [ - path("", views.ResourcesView.as_view(), name="index"), + path("", views.resources.resource_view, name="index"), path("list/", views.ResourcesListView.as_view(), name="resources") ] diff --git a/pydis_site/apps/resources/views/__init__.py b/pydis_site/apps/resources/views/__init__.py index 8eb383b5..c89071c5 100644 --- a/pydis_site/apps/resources/views/__init__.py +++ b/pydis_site/apps/resources/views/__init__.py @@ -1,4 +1,4 @@ -from .resources import ResourcesView +from .resources import resource_view from .resources_list import ResourcesListView -__all__ = ["ResourcesView", "ResourcesListView"] +__all__ = ["resource_view", "ResourcesListView"] diff --git a/pydis_site/apps/resources/views/resources.py b/pydis_site/apps/resources/views/resources.py index 25ce3e50..dfd21682 100644 --- a/pydis_site/apps/resources/views/resources.py +++ b/pydis_site/apps/resources/views/resources.py @@ -1,7 +1,11 @@ from django.views.generic import TemplateView +from django.shortcuts import render +# class ResourcesView(TemplateView): +# """View for resources index page.""" +# +# template_name = "resources/resources.html" -class ResourcesView(TemplateView): - """View for resources index page.""" - template_name = "resources/resources.html" +def resource_view(request): + return render(request, template_name="resources/resources.html") diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index cf4cb472..a9226647 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -1,29 +1,30 @@ -.box, .tile.is-parent { - transition: 0.1s ease-out; -} -.box { - min-height: 15vh; -} -.tile.is-parent:hover .box { - box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); -} -.tile.is-parent:hover { - padding: 0.65rem 0.85rem 0.85rem 0.65rem; - filter: saturate(1.1) brightness(1.1); -} +/*.box, .tile.is-parent {*/ +/* transition: 0.1s ease-out;*/ +/*}*/ +/*.box {*/ +/* min-height: 15vh;*/ +/*}*/ +/*.tile.is-parent:hover .box {*/ +/* box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);*/ +/*}*/ +/*.tile.is-parent:hover {*/ +/* padding: 0.65rem 0.85rem 0.85rem 0.65rem;*/ +/* filter: saturate(1.1) brightness(1.1);*/ +/*}*/ -#readingBlock { - background-image: linear-gradient(141deg, #911eb4 0%, #b631de 71%, #cf4bf7 100%); -} +/*#readingBlock {*/ +/* background-image: linear-gradient(141deg, #911eb4 0%, #b631de 71%, #cf4bf7 100%);*/ +/*}*/ -#interactiveBlock { - background-image: linear-gradient(141deg, #d05600 0%, #da722a 71%, #e68846 100%); -} +/*#interactiveBlock {*/ +/* background-image: linear-gradient(141deg, #d05600 0%, #da722a 71%, #e68846 100%);*/ +/*}*/ -#communitiesBlock { - background-image: linear-gradient(141deg, #3b756f 0%, #3a847c 71%, #41948b 100%); -} +/*#communitiesBlock {*/ +/* background-image: linear-gradient(141deg, #3b756f 0%, #3a847c 71%, #41948b 100%);*/ +/*}*/ + +/*#podcastsBlock {*/ +/* background-image: linear-gradient(141deg, #232382 0%, #30309c 71%, #4343ad 100%);*/ +/*}*/ -#podcastsBlock { - background-image: linear-gradient(141deg, #232382 0%, #30309c 71%, #4343ad 100%); -} diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index 04744f90..7eb21432 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -12,79 +12,86 @@
-

Resources

+

Resources

+
+
+
+ {% endblock %} -- cgit v1.2.3 From a4d0139215b29058d0f8de17f389d589dafed34c Mon Sep 17 00:00:00 2001 From: swfarnsworth Date: Sat, 24 Jul 2021 20:32:34 -0400 Subject: Remove extra newline from end of file (there is now one newline). --- pydis_site/static/css/resources/resources.css | 1 - 1 file changed, 1 deletion(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index a9226647..488effc3 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -27,4 +27,3 @@ /*#podcastsBlock {*/ /* background-image: linear-gradient(141deg, #232382 0%, #30309c 71%, #4343ad 100%);*/ /*}*/ - -- cgit v1.2.3 From 1dbe8046c38d43bc87fe6a78b1bfc61a3599de01 Mon Sep 17 00:00:00 2001 From: dawnofmidnight Date: Tue, 3 Aug 2021 14:53:17 -0400 Subject: styles: filtering resources page --- pydis_site/apps/resources/utils.py | 2 +- pydis_site/static/css/resources/resources_list.css | 9 ++++++ pydis_site/templates/resources/resources.html | 34 ++++++++++------------ 3 files changed, 25 insertions(+), 20 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/apps/resources/utils.py b/pydis_site/apps/resources/utils.py index 623dd7b6..bc444df4 100644 --- a/pydis_site/apps/resources/utils.py +++ b/pydis_site/apps/resources/utils.py @@ -21,7 +21,7 @@ RESOURCES: dict[str, Resource] = {path.stem: yaml.safe_load(path.read_text()) fo RESOURCE_TABLE = {category: defaultdict(set) for category in ( "topics", - "payment_tiers", + "payment_tiers", "complexity", "type" )} diff --git a/pydis_site/static/css/resources/resources_list.css b/pydis_site/static/css/resources/resources_list.css index e6808a99..283a506b 100644 --- a/pydis_site/static/css/resources/resources_list.css +++ b/pydis_site/static/css/resources/resources_list.css @@ -53,3 +53,12 @@ i.resource-icon.is-black { i.has-icon-padding { padding: 0 10px 25px 0; } + +#tab-content p { + display: none; +} + +#tab-content p.is-active { +display: block; +} + \ No newline at end of file diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index f2d5a976..8105a557 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -17,58 +17,58 @@

Resources


-
+

Search Options

-
- Topic +
+
Topic
{% for topic in topics %}
-
{% endfor %}
-
- Type +
+
Type
{% for tag_type in tag_types %}
{% endfor %}
-
- Payment +
+
Payment
{% for payment_tier in payment_tiers %}
{% endfor %}
-
- Level +
+
Level
{% for complexity in complexities %}
{% endfor %} @@ -76,7 +76,6 @@
- @@ -84,12 +83,9 @@ -
-
-
{% if resources|length > 0 %} @@ -120,7 +116,7 @@
{% else %} -

No resources matching search.

+

No resources matching search.

{% endif %} {% endblock %} -- cgit v1.2.3 From e759cffd78591919a70b727c41d787f753431f7c Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sun, 23 Jan 2022 13:34:15 +0100 Subject: Make GoodReads icons readable. --- pydis_site/static/css/resources/resources_list.css | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources_list.css b/pydis_site/static/css/resources/resources_list.css index 351030f8..c2151bee 100644 --- a/pydis_site/static/css/resources/resources_list.css +++ b/pydis_site/static/css/resources/resources_list.css @@ -34,20 +34,14 @@ i.resource-icon.is-youtube-red:hover { color: #f80000; } -i.resource-icon.is-goodreads-cream { - color: #f3f2e9; -} - -i.resource-icon.is-goodreads-cream:hover { - color: #ffffff; -} - +i.resource-icon.is-goodreads-cream, i.resource-icon.is-black { - color: #000000; + color: #2c3334; } -i.resource-icon.is-black { - color: #191919; +i.resource-icon.is-goodreads-cream:hover, +i.resource-icon.is-black:hover { + color: #475d6d; } i.has-icon-padding { -- cgit v1.2.3 From 5f214647521a93fa6cb54fcac7d4e1ae66fb7cec Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Thu, 27 Jan 2022 10:23:11 +0100 Subject: Resource filtering on the client, pt 1. Here's the initial version of this system. We've got filtering, but only by clicking checkboxes. The overall look and style are pretty close to where we want them, but it's missing tons of polish to be complete. The following commits will contain that polish. --- pydis_site/apps/resources/views/resources.py | 125 ++++++++++++----- pydis_site/static/css/resources/resources.css | 48 +++---- pydis_site/static/js/resources.js | 178 +++++++++++++++++++----- pydis_site/templates/resources/resources.html | 192 ++++++++++---------------- 4 files changed, 336 insertions(+), 207 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/apps/resources/views/resources.py b/pydis_site/apps/resources/views/resources.py index de6b2dac..57cb4f71 100644 --- a/pydis_site/apps/resources/views/resources.py +++ b/pydis_site/apps/resources/views/resources.py @@ -1,40 +1,103 @@ +from pathlib import Path + +import yaml +from django.core.handlers.wsgi import WSGIRequest from django.http import HttpRequest, HttpResponse from django.shortcuts import render +from django.views import View -from pydis_site.apps.resources.resource_search import RESOURCE_TABLE, get_resources_from_search +from pydis_site import settings -RESOURCE_META_TAGS = {k: set(v) for k, v in RESOURCE_TABLE.items()} +RESOURCES_PATH = Path(settings.BASE_DIR, "pydis_site", "apps", "resources", "resources") -def _parse_checkbox_options(options: str) -> set[str]: - """Split up the comma separated query parameters for checkbox options into a list.""" - return set(options.split(",")[:-1]) +class ResourceView(View): + """Our curated list of good learning resources.""" + def __init__(self, *args, **kwargs): + """Set up all the resources.""" + super().__init__(*args, **kwargs) -def resource_view(request: HttpRequest) -> HttpResponse: - """View for resources index page.""" - checkbox_options = { - option: _parse_checkbox_options(request.GET.get(url_param, "")) - for option, url_param in ( - ('topics', 'topic'), - ('type', 'type'), - ('payment_tiers', 'payment'), - ('complexity', 'complexity'), - ) - } - - topics = sorted(RESOURCE_META_TAGS.get("topics")) - - return render( - request, - template_name="resources/resources.html", - context={ - "checkboxOptions": checkbox_options, - "topics_1": topics[:len(topics) // 2], - "topics_2": topics[len(topics) // 2:], - "tag_types": sorted(RESOURCE_META_TAGS.get("type")), - "payment_tiers": sorted(RESOURCE_META_TAGS.get("payment_tiers")), - "complexities": sorted(RESOURCE_META_TAGS.get("complexity")), - "resources": get_resources_from_search(checkbox_options) + # Load the resources from the yaml files in /resources/ + self.resources = { + path.stem: yaml.safe_load(path.read_text()) + for path in RESOURCES_PATH.rglob("*.yaml") + } + + # Parse out all current tags + resource_tags = { + "topics": set(), + "payment_tiers": set(), + "complexity": set(), + "type": set(), } - ) + for resource_name, resource in self.resources.items(): + css_classes = [] + for tag_type in resource_tags.keys(): + # Store the tags into `resource_tags` + tags = resource.get("tags", {}).get(tag_type, []) + for tag in tags: + tag = tag.title() + tag = tag.replace("And", "and") + resource_tags[tag_type].add(tag) + + # Make a CSS class friendly representation too, while we're already iterating. + for tag in tags: + css_tag = f"{tag_type}-{tag}" + css_tag = css_tag.replace("_", "-") + css_tag = css_tag.replace(" ", "-") + css_classes.append(css_tag) + + # Now add the css classes back to the resource, so we can use them in the template. + self.resources[resource_name]["css_classes"] = " ".join(css_classes) + + # Set up all the filter checkbox metadata + self.filters = { + "Complexity": { + "filters": sorted(resource_tags.get("complexity")), + "icon": "fas fa-brain", + "hidden": False, + }, + "Type": { + "filters": sorted(resource_tags.get("type")), + "icon": "fas fa-photo-video", + "hidden": False, + }, + "Payment tiers": { + "filters": sorted(resource_tags.get("payment_tiers")), + "icon": "fas fa-dollar-sign", + "hidden": True, + }, + "Topics": { + "filters": sorted(resource_tags.get("topics")), + "icon": "fas fa-lightbulb", + "hidden": True, + } + } + + @staticmethod + def _get_filter_options(request: WSGIRequest) -> dict[str, set]: + """Get the requested filter options out of the request object.""" + return { + option: set(request.GET.get(url_param, "").split(",")[:-1]) + for option, url_param in ( + ('topics', 'topics'), + ('type', 'type'), + ('payment_tiers', 'payment'), + ('complexity', 'complexity'), + ) + } + + def get(self, request: WSGIRequest) -> HttpResponse: + """List out all the resources, and any filtering options from the URL.""" + filter_options = self._get_filter_options(request) + + return render( + request, + template_name="resources/resources.html", + context={ + "resources": self.resources, + "filters": self.filters, + "filter_options": filter_options, + } + ) diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index 488effc3..f70cbd64 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -1,29 +1,27 @@ -/*.box, .tile.is-parent {*/ -/* transition: 0.1s ease-out;*/ -/*}*/ -/*.box {*/ -/* min-height: 15vh;*/ -/*}*/ -/*.tile.is-parent:hover .box {*/ -/* box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);*/ -/*}*/ -/*.tile.is-parent:hover {*/ -/* padding: 0.65rem 0.85rem 0.85rem 0.65rem;*/ -/* filter: saturate(1.1) brightness(1.1);*/ -/*}*/ +/* Disable highlighting for all text in the filters. */ +.filter-checkbox, +.filter-panel label, +.card-header span { + user-select: none +} -/*#readingBlock {*/ -/* background-image: linear-gradient(141deg, #911eb4 0%, #b631de 71%, #cf4bf7 100%);*/ -/*}*/ +/* Remove pointless margin in panel header */ +#filter-panel-header { + margin-bottom: 0; +} -/*#interactiveBlock {*/ -/* background-image: linear-gradient(141deg, #d05600 0%, #da722a 71%, #e68846 100%);*/ -/*}*/ +/* Full width filter cards */ +#resource-filtering-panel .card .collapsible-content .card-content { + padding:0 +} -/*#communitiesBlock {*/ -/* background-image: linear-gradient(141deg, #3b756f 0%, #3a847c 71%, #41948b 100%);*/ -/*}*/ +/* Disable clicking on the checkbox itself. */ +/* Instead, we want to let the anchor tag handle clicks. */ +.filter-checkbox { + pointer-events: none; +} -/*#podcastsBlock {*/ -/* background-image: linear-gradient(141deg, #232382 0%, #30309c 71%, #4343ad 100%);*/ -/*}*/ +/* Blurple category icons */ +i.is-primary { + color: #7289da; +} diff --git a/pydis_site/static/js/resources.js b/pydis_site/static/js/resources.js index 5c353f97..dee59e52 100644 --- a/pydis_site/static/js/resources.js +++ b/pydis_site/static/js/resources.js @@ -1,48 +1,156 @@ "use strict"; -const initialParams = new URLSearchParams(window.location.search); -const checkboxOptions = ['topic', 'type', 'payment', 'complexity']; -const createQuerySelect = (opt) => { - return "input[name=" + opt + "]" -} +// Filters that are currently selected +var activeFilters = { + topics: [], + type: [], + "payment-tiers": [], + complexity: [] +}; -checkboxOptions.forEach((option) => { - document.querySelectorAll(createQuerySelect(option)).forEach((checkbox) => { - if (initialParams.get(option).includes(checkbox.value)) { - checkbox.checked = true - } - }); -}); +/* Update the resources to match 'active_filters' */ +function update() { + let resources = $('.resource-box'); -function buildQueryParams() { - let params = new URLSearchParams(window.location.search); - checkboxOptions.forEach((option) => { - let tempOut = "" - document.querySelectorAll(createQuerySelect(option)).forEach((checkbox) => { - if (checkbox.checked) { - tempOut += checkbox.value + ","; + // If there's nothing in the filters, show everything and return. + if ( + activeFilters.topics.length === 0 && + activeFilters.type.length === 0 && + activeFilters["payment-tiers"].length === 0 && + activeFilters.complexity.length === 0 + ) { + resources.show(); + return; + } + + // Otherwise, hide everything and then filter the resources to decide what to show. + resources.hide(); + resources.filter(function() { + let validation = { + topics: false, + type: false, + 'payment-tiers': false, + complexity: false + }; + let resourceBox = $(this); + + // Validate the filters + $.each(activeFilters, function(filterType, activeFilters) { + // If the filter list is empty, this passes validation. + if (activeFilters.length === 0) { + validation[filterType] = true; + return; } + + // Otherwise, we need to check if one of the classes exist. + $.each(activeFilters, function(index, filter) { + if (resourceBox.hasClass(filter)) { + validation[filterType] = true; + } + }); }); - params.set(option, tempOut); - }); - window.location.search = params; + // If validation passes, show the resource. + if (Object.values(validation).every(Boolean)) { + return true; + } else { + return false; + } + }).show(); } -function clearQueryParams() { - checkboxOptions.forEach((option) => { - document.querySelectorAll(createQuerySelect(option)).forEach((checkbox) => { - checkbox.checked = false; - }); +// Executed when the page has finished loading. +document.addEventListener("DOMContentLoaded", function () { + + // If you collapse or uncollapse a filter group, swap the icon. + $('button.collapsible').click(function() { + let icon = $(this).find(".card-header-icon i"); + + if ($(icon).hasClass("fa-window-minimize")) { + $(icon).removeClass(["far", "fa-window-minimize"]); + $(icon).addClass(["fas", "fa-angle-down"]); + } else { + $(icon).removeClass(["fas", "fa-angle-down"]); + $(icon).addClass(["far", "fa-window-minimize"]); + } + }); + + // Update the filters on page load to reflect URL parameters. + + // If you click on the div surrounding the filter checkbox, it clicks the checkbox. + $('.filter-panel').click(function() { + let checkbox = $(this).find(".filter-checkbox"); + checkbox.prop("checked", !checkbox.prop("checked")); + checkbox.change(); }); -} -function selectAllQueryParams(column) { - checkboxOptions.forEach((option) => { - document.querySelectorAll(createQuerySelect(option)).forEach((checkbox) => { - if (checkbox.className == column) { - checkbox.checked = true; + // When checkboxes are toggled, trigger a filter update. + $('.filter-checkbox').change(function () { + let filterItem = this.dataset.filterItem; + let filterName = this.dataset.filterName; + let cssClass = filterName + "-" + filterItem; + var filterIndex = activeFilters[filterName].indexOf(cssClass); + + if (this.checked) { + if (filterIndex === -1) { + activeFilters[filterName].push(cssClass); } - }); + update(); + } else { + if (filterIndex !== -1) { + activeFilters[filterName].splice(filterIndex, 1); + } + update(); + } }); -} +}); + + + +// const initialParams = new URLSearchParams(window.location.search); +// const checkboxOptions = ['topic', 'type', 'payment', 'complexity']; +// +// const createQuerySelect = (opt) => { +// return "input[name=" + opt + "]" +// } +// +// checkboxOptions.forEach((option) => { +// document.querySelectorAll(createQuerySelect(option)).forEach((checkbox) => { +// if (initialParams.get(option).includes(checkbox.value)) { +// checkbox.checked = true +// } +// }); +// }); +// +// function buildQueryParams() { +// let params = new URLSearchParams(window.location.search); +// checkboxOptions.forEach((option) => { +// let tempOut = "" +// document.querySelectorAll(createQuerySelect(option)).forEach((checkbox) => { +// if (checkbox.checked) { +// tempOut += checkbox.value + ","; +// } +// }); +// params.set(option, tempOut); +// }); +// +// window.location.search = params; +// } +// +// function clearQueryParams() { +// checkboxOptions.forEach((option) => { +// document.querySelectorAll(createQuerySelect(option)).forEach((checkbox) => { +// checkbox.checked = false; +// }); +// }); +// } +// +// function selectAllQueryParams(column) { +// checkboxOptions.forEach((option) => { +// document.querySelectorAll(createQuerySelect(option)).forEach((checkbox) => { +// if (checkbox.className == column) { +// checkbox.checked = true; +// } +// }); +// }); +// } diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index 427f417e..77723a8f 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -1,146 +1,106 @@ {% extends 'base/base.html' %} {% load as_icon %} +{% load as_css_class %} {% load static %} {% block title %}Resources{% endblock %} {% block head %} + + + + {% endblock %} {% block content %} {% include "base/navbar.html" %} - -
-
+ {% if resources|length > 0 %} +
+ {# Headline #}

Resources


-
-

Search Options

- -
-
-
-
Topic
-
-
- {% for topic in topics_1 %} -
- -
- {% endfor %} -
-
- {% for topic in topics_2 %} -
- -
- {% endfor %} -
-
- - - -
-
-
Type
+
+ {# Filtering toolbox #} +
+
+ +
+
- {% for payment_tier in payment_tiers %} -
- -
+ {# Actual resources #} +
+
+
+ {% for resource in resources.values %} + {% include "resources/resource_box.html" %} {% endfor %} - - - -
-
-
Level
+ {% for subcategory in subcategories %} +

+ + {{ subcategory.category_info.name }} + +

+

{{ subcategory.category_info.description|safe }}

- {% for complexity in complexities %} -
- -
- {% endfor %} - - - + {% for resource in subcategory.resources %} + {% with category_info=subcategory.category_info %} + {% include "resources/resource_box.html" %} + {% endwith %} + {% endfor %} + {% endfor %}
- -
- - - - - - - -
-
-
-
- - {% if resources|length > 0 %} -
-
-
-
- {% for resource in resources %} - {% include "resources/resource_box.html" %} - {% endfor %} - - {% for subcategory in subcategories %} -

- - {{ subcategory.category_info.name }} - -

-

{{ subcategory.category_info.description|safe }}

- - {% for resource in subcategory.resources %} - {% with category_info=subcategory.category_info %} - {% include "resources/resource_box.html" %} - {% endwith %} - {% endfor %} - {% endfor %}
-
-
+
{% else %} -

No resources matching search.

+

No resources matching search.

{% endif %} {% endblock %} -- cgit v1.2.3 From 4bd629b3d8b0fb5a1edd1c3aa30772094dc9deec Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Thu, 27 Jan 2022 12:39:19 +0100 Subject: Reflect and retain filter state in URL params. This commits makes two important changes: - Whenever we click on filter checkboxes, the URL is immediately updated to include parameters that represent the chosen options. For example, if you select Beginner complexity, the url is updated with ?complexity=beginner. - Whenever the page is loaded, we deserialize any parameters that exist in the URL and change the filter state to match it. In other words, refreshing the page at any time retains the current state, and you can now link people to exactly the filter results that you want to share. --- pydis_site/static/js/resources.js | 130 +++++++++++++------------- pydis_site/templates/resources/resources.html | 1 + 2 files changed, 66 insertions(+), 65 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/js/resources.js b/pydis_site/static/js/resources.js index dee59e52..836ef4ec 100644 --- a/pydis_site/static/js/resources.js +++ b/pydis_site/static/js/resources.js @@ -8,17 +8,67 @@ var activeFilters = { complexity: [] }; +/* Check if there are no filters */ +function noFilters() { + return ( + activeFilters.topics.length === 0 && + activeFilters.type.length === 0 && + activeFilters["payment-tiers"].length === 0 && + activeFilters.complexity.length === 0 + ); +} + +/* Update the URL with new parameters */ +function updateURL() { + // If there's nothing in the filters, we don't want anything in the URL. + if (noFilters()) { + window.history.replaceState(null, document.title, './'); + return; + } + + // Iterate through and get rid of empty ones + let searchParams = new URLSearchParams(activeFilters); + $.each(activeFilters, function(filterType, filters) { + if (filters.length === 0) { + searchParams.delete(filterType); + } + }); + + // Now update the URL + window.history.replaceState(null, document.title, `?${searchParams.toString()}`); +} + +/* Get the params out of the URL and use them. This is run when the page loads. */ +function deserializeURLParams() { + let searchParams = new window.URLSearchParams(window.location.search); + + // Work through the parameters and add them to the filter object + $.each(Object.keys(activeFilters), function(_, filterType) { + let paramFilterContent = searchParams.get(filterType); + + if (paramFilterContent !== null) { + // We use split here because we always want an array, not a string. + let paramFilterArray = paramFilterContent.split(","); + activeFilters[filterType] = paramFilterArray; + + // Check corresponding checkboxes, so the UI reflects the internal state. + $(paramFilterArray).each(function(_, filter) { + let checkbox = $(`.filter-checkbox[data-filter-name=${filterType}][data-filter-item=${filter}]`); + checkbox.prop("checked", true); + }); + } + }); +} + /* Update the resources to match 'active_filters' */ function update() { let resources = $('.resource-box'); + // Update the URL to match the new filters. + updateURL(); + // If there's nothing in the filters, show everything and return. - if ( - activeFilters.topics.length === 0 && - activeFilters.type.length === 0 && - activeFilters["payment-tiers"].length === 0 && - activeFilters.complexity.length === 0 - ) { + if (noFilters()) { resources.show(); return; } @@ -35,16 +85,16 @@ function update() { let resourceBox = $(this); // Validate the filters - $.each(activeFilters, function(filterType, activeFilters) { + $.each(activeFilters, function(filterType, filters) { // If the filter list is empty, this passes validation. - if (activeFilters.length === 0) { + if (filters.length === 0) { validation[filterType] = true; return; } // Otherwise, we need to check if one of the classes exist. - $.each(activeFilters, function(index, filter) { - if (resourceBox.hasClass(filter)) { + $.each(filters, function(index, filter) { + if (resourceBox.hasClass(`${filterType}-${filter}`)) { validation[filterType] = true; } }); @@ -61,6 +111,9 @@ function update() { // Executed when the page has finished loading. document.addEventListener("DOMContentLoaded", function () { + // Update the filters on page load to reflect URL parameters. + deserializeURLParams(); + update(); // If you collapse or uncollapse a filter group, swap the icon. $('button.collapsible').click(function() { @@ -75,8 +128,6 @@ document.addEventListener("DOMContentLoaded", function () { } }); - // Update the filters on page load to reflect URL parameters. - // If you click on the div surrounding the filter checkbox, it clicks the checkbox. $('.filter-panel').click(function() { let checkbox = $(this).find(".filter-checkbox"); @@ -88,12 +139,11 @@ document.addEventListener("DOMContentLoaded", function () { $('.filter-checkbox').change(function () { let filterItem = this.dataset.filterItem; let filterName = this.dataset.filterName; - let cssClass = filterName + "-" + filterItem; - var filterIndex = activeFilters[filterName].indexOf(cssClass); + var filterIndex = activeFilters[filterName].indexOf(filterItem); if (this.checked) { if (filterIndex === -1) { - activeFilters[filterName].push(cssClass); + activeFilters[filterName].push(filterItem); } update(); } else { @@ -104,53 +154,3 @@ document.addEventListener("DOMContentLoaded", function () { } }); }); - - - -// const initialParams = new URLSearchParams(window.location.search); -// const checkboxOptions = ['topic', 'type', 'payment', 'complexity']; -// -// const createQuerySelect = (opt) => { -// return "input[name=" + opt + "]" -// } -// -// checkboxOptions.forEach((option) => { -// document.querySelectorAll(createQuerySelect(option)).forEach((checkbox) => { -// if (initialParams.get(option).includes(checkbox.value)) { -// checkbox.checked = true -// } -// }); -// }); -// -// function buildQueryParams() { -// let params = new URLSearchParams(window.location.search); -// checkboxOptions.forEach((option) => { -// let tempOut = "" -// document.querySelectorAll(createQuerySelect(option)).forEach((checkbox) => { -// if (checkbox.checked) { -// tempOut += checkbox.value + ","; -// } -// }); -// params.set(option, tempOut); -// }); -// -// window.location.search = params; -// } -// -// function clearQueryParams() { -// checkboxOptions.forEach((option) => { -// document.querySelectorAll(createQuerySelect(option)).forEach((checkbox) => { -// checkbox.checked = false; -// }); -// }); -// } -// -// function selectAllQueryParams(column) { -// checkboxOptions.forEach((option) => { -// document.querySelectorAll(createQuerySelect(option)).forEach((checkbox) => { -// if (checkbox.className == column) { -// checkbox.checked = true; -// } -// }); -// }); -// } diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index 77723a8f..134c826b 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -45,6 +45,7 @@ {% endif %} + {# Checkboxes #} {% if filter_data.hidden %}
-- cgit v1.2.3 From da706784eef24e5b7bb45b50e2ebc1d8dd163a6c Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Fri, 28 Jan 2022 00:53:24 +0100 Subject: Make all tags interactive. Adds a bunch of tag-related quality of life improvements: - You can now see which filters you've added at the top left. - You can click on tags to start filtering to that tag. - You can click on tags in the filter box to remove the filter. - Tags will now show an outline when they are active. --- pydis_site/static/css/resources/resources.css | 91 +++++++++++++++++ pydis_site/static/js/resources.js | 123 +++++++++++++++++------ pydis_site/templates/resources/resource_box.html | 37 ++++++- pydis_site/templates/resources/resources.html | 123 ++++++++++++++++------- 4 files changed, 300 insertions(+), 74 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index f70cbd64..c6347eab 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -25,3 +25,94 @@ i.is-primary { color: #7289da; } + +/* A little space around the filter card, please! */ +.filter-tags { + padding-bottom: .5em; + padding-right: .5em; +} + +/* Set default display to inline-flex, for centering. */ +span.filter-box-tag { + display: inline-flex; + align-items: center; + cursor: pointer; + user-select: none; +} + +/* Make resource tags clickable */ +.resource-tag { + cursor: pointer; + user-select: none; +} + +/* Move the x down 1 pixel to align center */ +button.delete { + margin-top: 1px; +} + +/* Colors for delete button x's */ +button.delete.is-primary::before, +button.delete.is-primary::after { + background-color: #2a45a2; +} +button.delete.is-success::before, +button.delete.is-success::after { + background-color: #2c9659; +} +button.delete.is-danger::before, +button.delete.is-danger::after { + background-color: #c32841; +} +button.delete.is-info::before, +button.delete.is-info::after { + background-color: #237fbd; +} + +/* Give outlines to active tags */ +span.filter-box-tag, +span.resource-tag.active { + outline-width: 1px; + outline-style: solid; +} + +/* Make filter tags sparkle when selected! */ +@keyframes glow_success { + from { box-shadow: 0 0 2px 2px #aef4af; } + 33% { box-shadow: 0 0 2px 2px #87af7a; } + 66% { box-shadow: 0 0 2px 2px #9ceaac; } + to { box-shadow: 0 0 2px 2px #7cbf64; } +} + +@keyframes glow_primary { + from { box-shadow: 0 0 2px 2px #aeb8f3; } + 33% { box-shadow: 0 0 2px 2px #909ed9; } + 66% { box-shadow: 0 0 2px 2px #6d7ed4; } + to { box-shadow: 0 0 2px 2px #6383b3; } +} + +@keyframes glow_danger { + from { box-shadow: 0 0 2px 2px #c9495f; } + 33% { box-shadow: 0 0 2px 2px #92486f; } + 66% { box-shadow: 0 0 2px 2px #d455ba; } + to { box-shadow: 0 0 2px 2px #ff8192; } +} +@keyframes glow_info { + from { box-shadow: 0 0 2px 2px #4592c9; } + 33% { box-shadow: 0 0 2px 2px #6196bb; } + 66% { box-shadow: 0 0 2px 2px #5adade; } + to { box-shadow: 0 0 2px 2px #6bcfdc; } +} + +span.resource-tag.active.is-primary { + animation: glow_primary 4s infinite alternate; +} +span.resource-tag.active.has-background-danger-light { + animation: glow_danger 4s infinite alternate; +} +span.resource-tag.active.has-background-success-light { + animation: glow_success 4s infinite alternate; +} +span.resource-tag.active.has-background-info-light { + animation: glow_info 4s infinite alternate; +} diff --git a/pydis_site/static/js/resources.js b/pydis_site/static/js/resources.js index 836ef4ec..c9ce408b 100644 --- a/pydis_site/static/js/resources.js +++ b/pydis_site/static/js/resources.js @@ -8,6 +8,37 @@ var activeFilters = { complexity: [] }; +function addFilter(filterName, filterItem) { + // Push the filter into the stack + var filterIndex = activeFilters[filterName].indexOf(filterItem); + if (filterIndex === -1) { + activeFilters[filterName].push(filterItem); + } + updateUI(); + + // Show a corresponding filter box tag + $(`.filter-box-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).show(); + $(".filter-tags").css("padding-bottom", "0.5em"); + + // Make corresponding resource tags active + $(`.resource-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).addClass("active"); +} + +function removeFilter(filterName, filterItem) { + // Remove the filter from the stack + var filterIndex = activeFilters[filterName].indexOf(filterItem); + if (filterIndex !== -1) { + activeFilters[filterName].splice(filterIndex, 1); + } + updateUI(); + + // Hide the corresponding filter box tag + $(`.filter-box-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).hide(); + + // Make corresponding resource tags inactive + $(`.resource-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).removeClass("active"); +} + /* Check if there are no filters */ function noFilters() { return ( @@ -18,26 +49,6 @@ function noFilters() { ); } -/* Update the URL with new parameters */ -function updateURL() { - // If there's nothing in the filters, we don't want anything in the URL. - if (noFilters()) { - window.history.replaceState(null, document.title, './'); - return; - } - - // Iterate through and get rid of empty ones - let searchParams = new URLSearchParams(activeFilters); - $.each(activeFilters, function(filterType, filters) { - if (filters.length === 0) { - searchParams.delete(filterType); - } - }); - - // Now update the URL - window.history.replaceState(null, document.title, `?${searchParams.toString()}`); -} - /* Get the params out of the URL and use them. This is run when the page loads. */ function deserializeURLParams() { let searchParams = new window.URLSearchParams(window.location.search); @@ -51,18 +62,43 @@ function deserializeURLParams() { let paramFilterArray = paramFilterContent.split(","); activeFilters[filterType] = paramFilterArray; - // Check corresponding checkboxes, so the UI reflects the internal state. + // Update the corresponding filter UI, so it reflects the internal state. $(paramFilterArray).each(function(_, filter) { let checkbox = $(`.filter-checkbox[data-filter-name=${filterType}][data-filter-item=${filter}]`); + let filterTag = $(`.filter-box-tag[data-filter-name=${filterType}][data-filter-item=${filter}]`); + let resourceTags = $(`.resource-tag[data-filter-name=${filterType}][data-filter-item=${filter}]`); checkbox.prop("checked", true); + filterTag.show(); + resourceTags.addClass("active"); }); } }); } +/* Update the URL with new parameters */ +function updateURL() { + // If there's nothing in the filters, we don't want anything in the URL. + if (noFilters()) { + window.history.replaceState(null, document.title, './'); + return; + } + + // Iterate through and get rid of empty ones + let searchParams = new URLSearchParams(activeFilters); + $.each(activeFilters, function(filterType, filters) { + if (filters.length === 0) { + searchParams.delete(filterType); + } + }); + + // Now update the URL + window.history.replaceState(null, document.title, `?${searchParams.toString()}`); +} + /* Update the resources to match 'active_filters' */ -function update() { +function updateUI() { let resources = $('.resource-box'); + let filterTags = $('.filter-box-tag'); // Update the URL to match the new filters. updateURL(); @@ -70,6 +106,8 @@ function update() { // If there's nothing in the filters, show everything and return. if (noFilters()) { resources.show(); + filterTags.hide(); + $(".filter-tags").css("padding-bottom", "0"); return; } @@ -112,8 +150,9 @@ function update() { // Executed when the page has finished loading. document.addEventListener("DOMContentLoaded", function () { // Update the filters on page load to reflect URL parameters. + $('.filter-box-tag').hide(); deserializeURLParams(); - update(); + updateUI(); // If you collapse or uncollapse a filter group, swap the icon. $('button.collapsible').click(function() { @@ -128,29 +167,47 @@ document.addEventListener("DOMContentLoaded", function () { } }); - // If you click on the div surrounding the filter checkbox, it clicks the checkbox. + // If you click on the div surrounding the filter checkbox, it clicks the corresponding checkbox. $('.filter-panel').click(function() { let checkbox = $(this).find(".filter-checkbox"); checkbox.prop("checked", !checkbox.prop("checked")); checkbox.change(); }); + // If you click on one of the tags in the filter box, it unchecks the corresponding checkbox. + $('.filter-box-tag').click(function() { + let filterItem = this.dataset.filterItem; + let filterName = this.dataset.filterName; + let checkbox = $(`.filter-checkbox[data-filter-name=${filterName}][data-filter-item=${filterItem}]`); + + removeFilter(filterName, filterItem); + checkbox.prop("checked", false); + }); + + // If you click on one of the tags in the resource cards, it clicks the corresponding checkbox. + $('.resource-tag').click(function() { + let filterItem = this.dataset.filterItem; + let filterName = this.dataset.filterName; + let checkbox = $(`.filter-checkbox[data-filter-name=${filterName}][data-filter-item=${filterItem}]`) + + if (!$(this).hasClass("active")) { + addFilter(filterName, filterItem); + checkbox.prop("checked", true); + } else { + removeFilter(filterName, filterItem); + checkbox.prop("checked", false); + } + }); + // When checkboxes are toggled, trigger a filter update. $('.filter-checkbox').change(function () { let filterItem = this.dataset.filterItem; let filterName = this.dataset.filterName; - var filterIndex = activeFilters[filterName].indexOf(filterItem); if (this.checked) { - if (filterIndex === -1) { - activeFilters[filterName].push(filterItem); - } - update(); + addFilter(filterName, filterItem); } else { - if (filterIndex !== -1) { - activeFilters[filterName].splice(filterIndex, 1); - } - update(); + removeFilter(filterName, filterItem); } }); }); diff --git a/pydis_site/templates/resources/resource_box.html b/pydis_site/templates/resources/resource_box.html index 09256751..476a4841 100644 --- a/pydis_site/templates/resources/resource_box.html +++ b/pydis_site/templates/resources/resource_box.html @@ -1,4 +1,5 @@ {% load as_icon %} +{% load as_css_class %} {% load get_category_icon %}
@@ -34,16 +35,44 @@ {# Tags #}
{% for tag in resource.tags.topics %} - {{ tag|title }} + + + {{ tag|title }} + {% endfor %} {% for tag in resource.tags.type %} - {{ tag|title }} + + + {{ tag|title }} + {% endfor %} {% for tag in resource.tags.payment_tiers %} - {{ tag|title }} + + + {{ tag|title }} + {% endfor %} {% for tag in resource.tags.complexity %} - {{ tag|title }} + + + {{ tag|title }} + {% endfor %}
diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index 134c826b..87c28153 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -1,74 +1,123 @@ {% extends 'base/base.html' %} {% load as_icon %} {% load as_css_class %} +{% load get_category_icon %} {% load static %} {% block title %}Resources{% endblock %} {% block head %} - - - + + + {% endblock %} {% block content %} {% include "base/navbar.html" %} {% if resources|length > 0 %}
- {# Headline #} -
-

Resources

-
-
-
{# Filtering toolbox #}
-- cgit v1.2.3 From 72ca8758da4b80b638a83093a35a031210a8d9f2 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sat, 29 Jan 2022 12:39:21 +0100 Subject: Let the user know when there are no matches. --- pydis_site/static/css/resources/resources.css | 6 + pydis_site/static/js/resources.js | 11 ++ pydis_site/templates/resources/resources.html | 162 ++++++++++++-------------- 3 files changed, 91 insertions(+), 88 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index c6347eab..218d9a59 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -15,6 +15,12 @@ padding:0 } +/* Hide the no resources h2 by default */ +h2.no-resources-found { + display: none; + margin-top: 1em; +} + /* Disable clicking on the checkbox itself. */ /* Instead, we want to let the anchor tag handle clicks. */ .filter-checkbox { diff --git a/pydis_site/static/js/resources.js b/pydis_site/static/js/resources.js index c9ce408b..89b8ae06 100644 --- a/pydis_site/static/js/resources.js +++ b/pydis_site/static/js/resources.js @@ -112,6 +112,8 @@ function updateUI() { } // Otherwise, hide everything and then filter the resources to decide what to show. + let hasMatches = false; + console.log(hasMatches); resources.hide(); resources.filter(function() { let validation = { @@ -140,11 +142,20 @@ function updateUI() { // If validation passes, show the resource. if (Object.values(validation).every(Boolean)) { + hasMatches = true; return true; } else { return false; } }).show(); + + // If there are no matches, show the no matches message + console.log(hasMatches); + if (!hasMatches) { + $(".no-resources-found").show(); + } else { + $(".no-resources-found").hide(); + } } // Executed when the page has finished loading. diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index 87c28153..b82f16e1 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -16,141 +16,127 @@ {% block content %} {% include "base/navbar.html" %} - {% if resources|length > 0 %} -
-
- {# Filtering toolbox #} -
-
-
+ {% endfor %} +
+
- {# Actual resources #} -
-
-
- {% for resource in resources.values %} - {% include "resources/resource_box.html" %} - {% endfor %} - - {% for subcategory in subcategories %} -

- - {{ subcategory.category_info.name }} - -

-

{{ subcategory.category_info.description|safe }}

+
+ {# Message to display when there are no hits #} +

No matching resources found!

- {% for resource in subcategory.resources %} - {% with category_info=subcategory.category_info %} - {% include "resources/resource_box.html" %} - {% endwith %} - {% endfor %} - {% endfor %} -
+ {# Resource cards #} +
+
+ {% for resource in resources.values %} + {% include "resources/resource_box.html" %} + {% endfor %}
-
- {% else %} -

No resources matching search.

- {% endif %} +

+
{% endblock %} + + -- cgit v1.2.3 From 783bb2af9c5b5940f0fa2d3a0d0cbd34ec7e1316 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sat, 29 Jan 2022 12:58:10 +0100 Subject: Don't round edges of the filter category headers. --- pydis_site/static/css/resources/resources.css | 5 +++++ pydis_site/templates/resources/resources.html | 26 +++++++++++++------------- 2 files changed, 18 insertions(+), 13 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index 218d9a59..db083a41 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -15,6 +15,11 @@ padding:0 } +/* Don't round the corners of the collapsibles */ +.filter-category-header { + border-radius: 0; +} + /* Hide the no resources h2 by default */ h2.no-resources-found { display: none; diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index b82f16e1..411ae056 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -80,19 +80,19 @@ {# Filter checkboxes #} {% for filter_name, filter_data in filters.items %} -
- +
+ {# Checkboxes #} {% if filter_data.hidden %} -- cgit v1.2.3 From e54a3d18e208dd532533b5bbe146b1bff9875ba4 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sat, 29 Jan 2022 13:42:38 +0100 Subject: Complexity -> Difficulty. --- pydis_site/apps/resources/resources/adafruit.yaml | 2 +- pydis_site/apps/resources/resources/atom.yaml | 2 +- .../apps/resources/resources/automate_the_boring_stuff_book.yaml | 2 +- .../resources/resources/automate_the_boring_stuff_course.yaml | 2 +- .../apps/resources/resources/awesome_programming_discord.yaml | 2 +- pydis_site/apps/resources/resources/byte_of_python.yaml | 2 +- pydis_site/apps/resources/resources/code_combat.yaml | 2 +- pydis_site/apps/resources/resources/corey_schafer.yaml | 2 +- .../apps/resources/resources/data_science_from_scratch.yaml | 2 +- pydis_site/apps/resources/resources/edublocks.yaml | 2 +- pydis_site/apps/resources/resources/effective_python.yaml | 2 +- pydis_site/apps/resources/resources/exercism.yaml | 2 +- pydis_site/apps/resources/resources/flask_web_development.yaml | 2 +- pydis_site/apps/resources/resources/fluent_python.yaml | 2 +- .../apps/resources/resources/getting_started_with_kivy.yaml | 2 +- .../getting_started_with_python_for_non_programmers.yaml | 2 +- .../resources/getting_started_with_python_for_programmers.yaml | 2 +- pydis_site/apps/resources/resources/google_collab.yaml | 2 +- .../apps/resources/resources/hitchhikers_guide_to_python.yaml | 2 +- pydis_site/apps/resources/resources/inferential_thinking.yaml | 2 +- pydis_site/apps/resources/resources/jetbrains_academy.yaml | 2 +- pydis_site/apps/resources/resources/jetbrains_videos.yaml | 2 +- pydis_site/apps/resources/resources/jim_shaped_coding.yaml | 2 +- pydis_site/apps/resources/resources/kaggle_pandas_tutorial.yaml | 2 +- pydis_site/apps/resources/resources/kivy.yaml | 2 +- pydis_site/apps/resources/resources/microsoft.yaml | 2 +- pydis_site/apps/resources/resources/microsoft_videos.yaml | 2 +- pydis_site/apps/resources/resources/mission_python.yaml | 2 +- .../mit_introduction_to_computer_science_and_programming.yaml | 2 +- pydis_site/apps/resources/resources/mu_editor.yaml | 2 +- pydis_site/apps/resources/resources/netbats_project_ideas.yaml | 2 +- .../resources/neural_networks_from_scratch_in_python.yaml | 2 +- pydis_site/apps/resources/resources/pallets.yaml | 2 +- pydis_site/apps/resources/resources/panda3d.yaml | 2 +- pydis_site/apps/resources/resources/people_postgres_data.yaml | 2 +- pydis_site/apps/resources/resources/podcast_dunder_init.yaml | 2 +- .../apps/resources/resources/practical_python_programming.yaml | 2 +- pydis_site/apps/resources/resources/pycharm.yaml | 2 +- pydis_site/apps/resources/resources/pyglet.yaml | 2 +- pydis_site/apps/resources/resources/python_bytes.yaml | 2 +- pydis_site/apps/resources/resources/python_cheat_sheet.yaml | 2 +- pydis_site/apps/resources/resources/python_cookbook.yaml | 2 +- pydis_site/apps/resources/resources/python_crash_course.yaml | 2 +- pydis_site/apps/resources/resources/python_developer_guide.yaml | 2 +- pydis_site/apps/resources/resources/python_discord_videos.yaml | 2 +- pydis_site/apps/resources/resources/python_morsels.yaml | 2 +- pydis_site/apps/resources/resources/python_subreddit.yaml | 2 +- pydis_site/apps/resources/resources/python_tricks.yaml | 2 +- pydis_site/apps/resources/resources/python_tutor.yaml | 2 +- pydis_site/apps/resources/resources/real_python.yaml | 2 +- pydis_site/apps/resources/resources/regex101.yaml | 2 +- pydis_site/apps/resources/resources/repl_it.yaml | 2 +- pydis_site/apps/resources/resources/screen_readers.yaml | 2 +- pydis_site/apps/resources/resources/sentdex.yaml | 2 +- pydis_site/apps/resources/resources/simple_guide_to_git.yaml | 2 +- pydis_site/apps/resources/resources/sololearn.yaml | 2 +- pydis_site/apps/resources/resources/spyder.yaml | 2 +- pydis_site/apps/resources/resources/sublime_text.yaml | 2 +- pydis_site/apps/resources/resources/talk_python_to_me.yaml | 2 +- pydis_site/apps/resources/resources/talon_voice.yaml | 2 +- pydis_site/apps/resources/resources/test_and_code.yaml | 2 +- pydis_site/apps/resources/resources/the_flask_mega_tutorial.yaml | 2 +- pydis_site/apps/resources/resources/the_real_python_podcast.yaml | 2 +- pydis_site/apps/resources/resources/think_python.yaml | 2 +- pydis_site/apps/resources/resources/thonny.yaml | 2 +- pydis_site/apps/resources/resources/two_scoops_of_django.yaml | 2 +- pydis_site/apps/resources/resources/university_of_michigan.yaml | 2 +- pydis_site/apps/resources/resources/university_of_toronto.yaml | 2 +- .../apps/resources/resources/vcokltfre_discord_bot_tutorial.yaml | 2 +- pydis_site/apps/resources/resources/visual_studio_code.yaml | 2 +- pydis_site/apps/resources/resources/wtf_python.yaml | 2 +- pydis_site/apps/resources/views/resources.py | 8 ++++---- pydis_site/static/js/resources.js | 6 +++--- pydis_site/templates/resources/resource_box.html | 4 ++-- pydis_site/templates/resources/resources.html | 2 +- 75 files changed, 81 insertions(+), 81 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/apps/resources/resources/adafruit.yaml b/pydis_site/apps/resources/resources/adafruit.yaml index e8eeee37..f9466bd8 100644 --- a/pydis_site/apps/resources/resources/adafruit.yaml +++ b/pydis_site/apps/resources/resources/adafruit.yaml @@ -14,7 +14,7 @@ tags: - microcontrollers payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/atom.yaml b/pydis_site/apps/resources/resources/atom.yaml index 3a46a45f..26e125b1 100644 --- a/pydis_site/apps/resources/resources/atom.yaml +++ b/pydis_site/apps/resources/resources/atom.yaml @@ -7,7 +7,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/automate_the_boring_stuff_book.yaml b/pydis_site/apps/resources/resources/automate_the_boring_stuff_book.yaml index bc0e19ec..9bf9aba8 100644 --- a/pydis_site/apps/resources/resources/automate_the_boring_stuff_book.yaml +++ b/pydis_site/apps/resources/resources/automate_the_boring_stuff_book.yaml @@ -15,7 +15,7 @@ tags: payment_tiers: - free - paid - complexity: + difficulty: - beginner type: - book diff --git a/pydis_site/apps/resources/resources/automate_the_boring_stuff_course.yaml b/pydis_site/apps/resources/resources/automate_the_boring_stuff_course.yaml index b93ef868..133033f7 100644 --- a/pydis_site/apps/resources/resources/automate_the_boring_stuff_course.yaml +++ b/pydis_site/apps/resources/resources/automate_the_boring_stuff_course.yaml @@ -7,7 +7,7 @@ tags: - general payment_tiers: - paid - complexity: + difficulty: - beginner type: - course diff --git a/pydis_site/apps/resources/resources/awesome_programming_discord.yaml b/pydis_site/apps/resources/resources/awesome_programming_discord.yaml index 4233f26e..0ef7aefc 100644 --- a/pydis_site/apps/resources/resources/awesome_programming_discord.yaml +++ b/pydis_site/apps/resources/resources/awesome_programming_discord.yaml @@ -11,7 +11,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/byte_of_python.yaml b/pydis_site/apps/resources/resources/byte_of_python.yaml index d2b8fa35..c4b671c2 100644 --- a/pydis_site/apps/resources/resources/byte_of_python.yaml +++ b/pydis_site/apps/resources/resources/byte_of_python.yaml @@ -16,7 +16,7 @@ tags: payment_tiers: - free - paid - complexity: + difficulty: - beginner type: - book diff --git a/pydis_site/apps/resources/resources/code_combat.yaml b/pydis_site/apps/resources/resources/code_combat.yaml index ab4a4aed..84597c4d 100644 --- a/pydis_site/apps/resources/resources/code_combat.yaml +++ b/pydis_site/apps/resources/resources/code_combat.yaml @@ -13,7 +13,7 @@ tags: payment_tiers: - free - subscription - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/corey_schafer.yaml b/pydis_site/apps/resources/resources/corey_schafer.yaml index cb20bc24..b73f4b5d 100644 --- a/pydis_site/apps/resources/resources/corey_schafer.yaml +++ b/pydis_site/apps/resources/resources/corey_schafer.yaml @@ -22,7 +22,7 @@ tags: - tooling payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/data_science_from_scratch.yaml b/pydis_site/apps/resources/resources/data_science_from_scratch.yaml index 8ba95e9b..57e73a28 100644 --- a/pydis_site/apps/resources/resources/data_science_from_scratch.yaml +++ b/pydis_site/apps/resources/resources/data_science_from_scratch.yaml @@ -16,7 +16,7 @@ tags: - data science payment_tiers: - paid - complexity: + difficulty: - beginner type: - book diff --git a/pydis_site/apps/resources/resources/edublocks.yaml b/pydis_site/apps/resources/resources/edublocks.yaml index 9fd87945..3eaefc35 100644 --- a/pydis_site/apps/resources/resources/edublocks.yaml +++ b/pydis_site/apps/resources/resources/edublocks.yaml @@ -12,7 +12,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner type: - interactive diff --git a/pydis_site/apps/resources/resources/effective_python.yaml b/pydis_site/apps/resources/resources/effective_python.yaml index 4e361bcb..96a3b21a 100644 --- a/pydis_site/apps/resources/resources/effective_python.yaml +++ b/pydis_site/apps/resources/resources/effective_python.yaml @@ -15,7 +15,7 @@ tags: - software design payment_tiers: - paid - complexity: + difficulty: - intermediate type: - book diff --git a/pydis_site/apps/resources/resources/exercism.yaml b/pydis_site/apps/resources/resources/exercism.yaml index ba8cd2df..b8f53d72 100644 --- a/pydis_site/apps/resources/resources/exercism.yaml +++ b/pydis_site/apps/resources/resources/exercism.yaml @@ -13,7 +13,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/flask_web_development.yaml b/pydis_site/apps/resources/resources/flask_web_development.yaml index 95b75a5b..0bd418e5 100644 --- a/pydis_site/apps/resources/resources/flask_web_development.yaml +++ b/pydis_site/apps/resources/resources/flask_web_development.yaml @@ -14,7 +14,7 @@ tags: - web development payment_tiers: - paid - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/fluent_python.yaml b/pydis_site/apps/resources/resources/fluent_python.yaml index e35c0134..1d525baa 100644 --- a/pydis_site/apps/resources/resources/fluent_python.yaml +++ b/pydis_site/apps/resources/resources/fluent_python.yaml @@ -15,7 +15,7 @@ tags: - software design payment_tiers: - paid - complexity: + difficulty: - intermediate type: - book diff --git a/pydis_site/apps/resources/resources/getting_started_with_kivy.yaml b/pydis_site/apps/resources/resources/getting_started_with_kivy.yaml index 5dbcd387..06eb2c14 100644 --- a/pydis_site/apps/resources/resources/getting_started_with_kivy.yaml +++ b/pydis_site/apps/resources/resources/getting_started_with_kivy.yaml @@ -8,7 +8,7 @@ tags: - game development payment_tiers: - free - complexity: + difficulty: - beginner type: - tutorial diff --git a/pydis_site/apps/resources/resources/getting_started_with_python_for_non_programmers.yaml b/pydis_site/apps/resources/resources/getting_started_with_python_for_non_programmers.yaml index 85c061bd..6fab0114 100644 --- a/pydis_site/apps/resources/resources/getting_started_with_python_for_non_programmers.yaml +++ b/pydis_site/apps/resources/resources/getting_started_with_python_for_non_programmers.yaml @@ -7,7 +7,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner type: - tutorial diff --git a/pydis_site/apps/resources/resources/getting_started_with_python_for_programmers.yaml b/pydis_site/apps/resources/resources/getting_started_with_python_for_programmers.yaml index 2565eedd..74b6efb9 100644 --- a/pydis_site/apps/resources/resources/getting_started_with_python_for_programmers.yaml +++ b/pydis_site/apps/resources/resources/getting_started_with_python_for_programmers.yaml @@ -8,7 +8,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - intermediate type: - tutorial diff --git a/pydis_site/apps/resources/resources/google_collab.yaml b/pydis_site/apps/resources/resources/google_collab.yaml index 65876c0e..067a79c9 100644 --- a/pydis_site/apps/resources/resources/google_collab.yaml +++ b/pydis_site/apps/resources/resources/google_collab.yaml @@ -10,7 +10,7 @@ tags: - data science payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/hitchhikers_guide_to_python.yaml b/pydis_site/apps/resources/resources/hitchhikers_guide_to_python.yaml index bfac404a..c4b78af6 100644 --- a/pydis_site/apps/resources/resources/hitchhikers_guide_to_python.yaml +++ b/pydis_site/apps/resources/resources/hitchhikers_guide_to_python.yaml @@ -11,7 +11,7 @@ tags: - general payment_tiers: - paid - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/inferential_thinking.yaml b/pydis_site/apps/resources/resources/inferential_thinking.yaml index 20409f3a..a8cf2bc8 100644 --- a/pydis_site/apps/resources/resources/inferential_thinking.yaml +++ b/pydis_site/apps/resources/resources/inferential_thinking.yaml @@ -8,7 +8,7 @@ tags: - data science payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/jetbrains_academy.yaml b/pydis_site/apps/resources/resources/jetbrains_academy.yaml index 63c061ce..c3cb7657 100644 --- a/pydis_site/apps/resources/resources/jetbrains_academy.yaml +++ b/pydis_site/apps/resources/resources/jetbrains_academy.yaml @@ -12,7 +12,7 @@ tags: - data science payment_tiers: - subscription - complexity: + difficulty: - beginner type: - interactive diff --git a/pydis_site/apps/resources/resources/jetbrains_videos.yaml b/pydis_site/apps/resources/resources/jetbrains_videos.yaml index aba7c687..00d34e69 100644 --- a/pydis_site/apps/resources/resources/jetbrains_videos.yaml +++ b/pydis_site/apps/resources/resources/jetbrains_videos.yaml @@ -14,7 +14,7 @@ tags: - web development payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/jim_shaped_coding.yaml b/pydis_site/apps/resources/resources/jim_shaped_coding.yaml index 30992ef2..c9727888 100644 --- a/pydis_site/apps/resources/resources/jim_shaped_coding.yaml +++ b/pydis_site/apps/resources/resources/jim_shaped_coding.yaml @@ -15,7 +15,7 @@ tags: - web development payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/kaggle_pandas_tutorial.yaml b/pydis_site/apps/resources/resources/kaggle_pandas_tutorial.yaml index a1907e0f..c8e72c6e 100644 --- a/pydis_site/apps/resources/resources/kaggle_pandas_tutorial.yaml +++ b/pydis_site/apps/resources/resources/kaggle_pandas_tutorial.yaml @@ -7,7 +7,7 @@ tags: - data science payment_tiers: - free - complexity: + difficulty: - intermediate type: - tutorial diff --git a/pydis_site/apps/resources/resources/kivy.yaml b/pydis_site/apps/resources/resources/kivy.yaml index 5d7d3844..dad29e9a 100644 --- a/pydis_site/apps/resources/resources/kivy.yaml +++ b/pydis_site/apps/resources/resources/kivy.yaml @@ -21,7 +21,7 @@ tags: - game development payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/microsoft.yaml b/pydis_site/apps/resources/resources/microsoft.yaml index cc5ca93f..e1d62955 100644 --- a/pydis_site/apps/resources/resources/microsoft.yaml +++ b/pydis_site/apps/resources/resources/microsoft.yaml @@ -12,7 +12,7 @@ tags: - tooling payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/microsoft_videos.yaml b/pydis_site/apps/resources/resources/microsoft_videos.yaml index 39187650..f45aef63 100644 --- a/pydis_site/apps/resources/resources/microsoft_videos.yaml +++ b/pydis_site/apps/resources/resources/microsoft_videos.yaml @@ -19,7 +19,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner type: - video diff --git a/pydis_site/apps/resources/resources/mission_python.yaml b/pydis_site/apps/resources/resources/mission_python.yaml index 4e7b30b0..e8e0a6b8 100644 --- a/pydis_site/apps/resources/resources/mission_python.yaml +++ b/pydis_site/apps/resources/resources/mission_python.yaml @@ -14,7 +14,7 @@ tags: - game development payment_tiers: - paid - complexity: + difficulty: - beginner type: - book diff --git a/pydis_site/apps/resources/resources/mit_introduction_to_computer_science_and_programming.yaml b/pydis_site/apps/resources/resources/mit_introduction_to_computer_science_and_programming.yaml index 4aa028ea..4e74936d 100644 --- a/pydis_site/apps/resources/resources/mit_introduction_to_computer_science_and_programming.yaml +++ b/pydis_site/apps/resources/resources/mit_introduction_to_computer_science_and_programming.yaml @@ -10,7 +10,7 @@ tags: payment_tiers: - free - paid - complexity: + difficulty: - beginner type: - course diff --git a/pydis_site/apps/resources/resources/mu_editor.yaml b/pydis_site/apps/resources/resources/mu_editor.yaml index 68c9b7db..b6318d0e 100644 --- a/pydis_site/apps/resources/resources/mu_editor.yaml +++ b/pydis_site/apps/resources/resources/mu_editor.yaml @@ -9,7 +9,7 @@ tags: - microcontrollers payment_tiers: - free - complexity: + difficulty: - beginner type: - tool diff --git a/pydis_site/apps/resources/resources/netbats_project_ideas.yaml b/pydis_site/apps/resources/resources/netbats_project_ideas.yaml index faa029f9..80ba771c 100644 --- a/pydis_site/apps/resources/resources/netbats_project_ideas.yaml +++ b/pydis_site/apps/resources/resources/netbats_project_ideas.yaml @@ -7,7 +7,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/neural_networks_from_scratch_in_python.yaml b/pydis_site/apps/resources/resources/neural_networks_from_scratch_in_python.yaml index 5d3060a4..6313cabe 100644 --- a/pydis_site/apps/resources/resources/neural_networks_from_scratch_in_python.yaml +++ b/pydis_site/apps/resources/resources/neural_networks_from_scratch_in_python.yaml @@ -13,7 +13,7 @@ tags: - data science payment_tiers: - paid - complexity: + difficulty: - intermediate type: - book diff --git a/pydis_site/apps/resources/resources/pallets.yaml b/pydis_site/apps/resources/resources/pallets.yaml index de3f7fad..0da2a625 100644 --- a/pydis_site/apps/resources/resources/pallets.yaml +++ b/pydis_site/apps/resources/resources/pallets.yaml @@ -12,7 +12,7 @@ tags: - web development payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/panda3d.yaml b/pydis_site/apps/resources/resources/panda3d.yaml index 0d488565..61ecba4b 100644 --- a/pydis_site/apps/resources/resources/panda3d.yaml +++ b/pydis_site/apps/resources/resources/panda3d.yaml @@ -16,7 +16,7 @@ tags: - game development payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/people_postgres_data.yaml b/pydis_site/apps/resources/resources/people_postgres_data.yaml index 70088af2..c2d63252 100644 --- a/pydis_site/apps/resources/resources/people_postgres_data.yaml +++ b/pydis_site/apps/resources/resources/people_postgres_data.yaml @@ -20,7 +20,7 @@ tags: - databases payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/podcast_dunder_init.yaml b/pydis_site/apps/resources/resources/podcast_dunder_init.yaml index ee3028a3..2751481a 100644 --- a/pydis_site/apps/resources/resources/podcast_dunder_init.yaml +++ b/pydis_site/apps/resources/resources/podcast_dunder_init.yaml @@ -7,7 +7,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/practical_python_programming.yaml b/pydis_site/apps/resources/resources/practical_python_programming.yaml index 85b3967a..12873b7c 100644 --- a/pydis_site/apps/resources/resources/practical_python_programming.yaml +++ b/pydis_site/apps/resources/resources/practical_python_programming.yaml @@ -12,7 +12,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner type: - course diff --git a/pydis_site/apps/resources/resources/pycharm.yaml b/pydis_site/apps/resources/resources/pycharm.yaml index 1fda3bff..574158bc 100644 --- a/pydis_site/apps/resources/resources/pycharm.yaml +++ b/pydis_site/apps/resources/resources/pycharm.yaml @@ -8,7 +8,7 @@ tags: payment_tiers: - free - paid - complexity: + difficulty: - intermediate type: - tool diff --git a/pydis_site/apps/resources/resources/pyglet.yaml b/pydis_site/apps/resources/resources/pyglet.yaml index d4a37fa8..a47c7e62 100644 --- a/pydis_site/apps/resources/resources/pyglet.yaml +++ b/pydis_site/apps/resources/resources/pyglet.yaml @@ -15,7 +15,7 @@ tags: - game development payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/python_bytes.yaml b/pydis_site/apps/resources/resources/python_bytes.yaml index 578fff2e..9beba4f4 100644 --- a/pydis_site/apps/resources/resources/python_bytes.yaml +++ b/pydis_site/apps/resources/resources/python_bytes.yaml @@ -8,7 +8,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/python_cheat_sheet.yaml b/pydis_site/apps/resources/resources/python_cheat_sheet.yaml index da9b980f..56f61165 100644 --- a/pydis_site/apps/resources/resources/python_cheat_sheet.yaml +++ b/pydis_site/apps/resources/resources/python_cheat_sheet.yaml @@ -7,7 +7,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner type: - tutorial diff --git a/pydis_site/apps/resources/resources/python_cookbook.yaml b/pydis_site/apps/resources/resources/python_cookbook.yaml index 855adb2f..fbb1bdc8 100644 --- a/pydis_site/apps/resources/resources/python_cookbook.yaml +++ b/pydis_site/apps/resources/resources/python_cookbook.yaml @@ -15,7 +15,7 @@ tags: - software design payment_tiers: - paid - complexity: + difficulty: - intermediate type: - book diff --git a/pydis_site/apps/resources/resources/python_crash_course.yaml b/pydis_site/apps/resources/resources/python_crash_course.yaml index 379cf954..9de1a53c 100644 --- a/pydis_site/apps/resources/resources/python_crash_course.yaml +++ b/pydis_site/apps/resources/resources/python_crash_course.yaml @@ -21,7 +21,7 @@ tags: - game development payment_tiers: - paid - complexity: + difficulty: - beginner type: - book diff --git a/pydis_site/apps/resources/resources/python_developer_guide.yaml b/pydis_site/apps/resources/resources/python_developer_guide.yaml index f17c88ce..2806d75d 100644 --- a/pydis_site/apps/resources/resources/python_developer_guide.yaml +++ b/pydis_site/apps/resources/resources/python_developer_guide.yaml @@ -7,7 +7,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - intermediate type: - tutorial diff --git a/pydis_site/apps/resources/resources/python_discord_videos.yaml b/pydis_site/apps/resources/resources/python_discord_videos.yaml index bf44083f..15a04097 100644 --- a/pydis_site/apps/resources/resources/python_discord_videos.yaml +++ b/pydis_site/apps/resources/resources/python_discord_videos.yaml @@ -8,7 +8,7 @@ tags: - software design payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/python_morsels.yaml b/pydis_site/apps/resources/resources/python_morsels.yaml index de02be7f..bbc8133b 100644 --- a/pydis_site/apps/resources/resources/python_morsels.yaml +++ b/pydis_site/apps/resources/resources/python_morsels.yaml @@ -13,7 +13,7 @@ tags: - software design payment_tiers: - subscription - complexity: + difficulty: - intermediate type: - interactive diff --git a/pydis_site/apps/resources/resources/python_subreddit.yaml b/pydis_site/apps/resources/resources/python_subreddit.yaml index ef9f23d9..e94f84fc 100644 --- a/pydis_site/apps/resources/resources/python_subreddit.yaml +++ b/pydis_site/apps/resources/resources/python_subreddit.yaml @@ -9,7 +9,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/python_tricks.yaml b/pydis_site/apps/resources/resources/python_tricks.yaml index 17f40732..a38fa74b 100644 --- a/pydis_site/apps/resources/resources/python_tricks.yaml +++ b/pydis_site/apps/resources/resources/python_tricks.yaml @@ -13,7 +13,7 @@ tags: - software design payment_tiers: - paid - complexity: + difficulty: - intermediate type: - book diff --git a/pydis_site/apps/resources/resources/python_tutor.yaml b/pydis_site/apps/resources/resources/python_tutor.yaml index 4f6d5130..6bee0d69 100644 --- a/pydis_site/apps/resources/resources/python_tutor.yaml +++ b/pydis_site/apps/resources/resources/python_tutor.yaml @@ -6,7 +6,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/real_python.yaml b/pydis_site/apps/resources/resources/real_python.yaml index 1669638e..0d0b2ad3 100644 --- a/pydis_site/apps/resources/resources/real_python.yaml +++ b/pydis_site/apps/resources/resources/real_python.yaml @@ -15,7 +15,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/regex101.yaml b/pydis_site/apps/resources/resources/regex101.yaml index db3df957..45d00f1b 100644 --- a/pydis_site/apps/resources/resources/regex101.yaml +++ b/pydis_site/apps/resources/resources/regex101.yaml @@ -8,7 +8,7 @@ tags: - other payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/repl_it.yaml b/pydis_site/apps/resources/resources/repl_it.yaml index e1ba1d19..e0f6cbb3 100644 --- a/pydis_site/apps/resources/resources/repl_it.yaml +++ b/pydis_site/apps/resources/resources/repl_it.yaml @@ -7,7 +7,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/screen_readers.yaml b/pydis_site/apps/resources/resources/screen_readers.yaml index 9673a132..b086b301 100644 --- a/pydis_site/apps/resources/resources/screen_readers.yaml +++ b/pydis_site/apps/resources/resources/screen_readers.yaml @@ -10,7 +10,7 @@ tags: payment_tiers: - free - paid - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/sentdex.yaml b/pydis_site/apps/resources/resources/sentdex.yaml index 47a8852d..d9131039 100644 --- a/pydis_site/apps/resources/resources/sentdex.yaml +++ b/pydis_site/apps/resources/resources/sentdex.yaml @@ -24,7 +24,7 @@ tags: - data science payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/simple_guide_to_git.yaml b/pydis_site/apps/resources/resources/simple_guide_to_git.yaml index 6dacdf5c..3bb46e6d 100644 --- a/pydis_site/apps/resources/resources/simple_guide_to_git.yaml +++ b/pydis_site/apps/resources/resources/simple_guide_to_git.yaml @@ -8,7 +8,7 @@ tags: - tooling payment_tiers: - free - complexity: + difficulty: - beginner type: - tutorial diff --git a/pydis_site/apps/resources/resources/sololearn.yaml b/pydis_site/apps/resources/resources/sololearn.yaml index b9b59bca..998f5368 100644 --- a/pydis_site/apps/resources/resources/sololearn.yaml +++ b/pydis_site/apps/resources/resources/sololearn.yaml @@ -10,7 +10,7 @@ tags: payment_tiers: - free - subscription - complexity: + difficulty: - beginner type: - interactive diff --git a/pydis_site/apps/resources/resources/spyder.yaml b/pydis_site/apps/resources/resources/spyder.yaml index 8dc05542..668e9306 100644 --- a/pydis_site/apps/resources/resources/spyder.yaml +++ b/pydis_site/apps/resources/resources/spyder.yaml @@ -7,7 +7,7 @@ tags: - data science payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/sublime_text.yaml b/pydis_site/apps/resources/resources/sublime_text.yaml index 76aeac45..05596477 100644 --- a/pydis_site/apps/resources/resources/sublime_text.yaml +++ b/pydis_site/apps/resources/resources/sublime_text.yaml @@ -7,7 +7,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/talk_python_to_me.yaml b/pydis_site/apps/resources/resources/talk_python_to_me.yaml index 00726203..509922c3 100644 --- a/pydis_site/apps/resources/resources/talk_python_to_me.yaml +++ b/pydis_site/apps/resources/resources/talk_python_to_me.yaml @@ -7,7 +7,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/talon_voice.yaml b/pydis_site/apps/resources/resources/talon_voice.yaml index 0f28a328..3be5fe20 100644 --- a/pydis_site/apps/resources/resources/talon_voice.yaml +++ b/pydis_site/apps/resources/resources/talon_voice.yaml @@ -8,7 +8,7 @@ tags: - other payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/test_and_code.yaml b/pydis_site/apps/resources/resources/test_and_code.yaml index efe0c218..f0d1c3b3 100644 --- a/pydis_site/apps/resources/resources/test_and_code.yaml +++ b/pydis_site/apps/resources/resources/test_and_code.yaml @@ -8,7 +8,7 @@ tags: - tooling payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/the_flask_mega_tutorial.yaml b/pydis_site/apps/resources/resources/the_flask_mega_tutorial.yaml index 514da947..151768a5 100644 --- a/pydis_site/apps/resources/resources/the_flask_mega_tutorial.yaml +++ b/pydis_site/apps/resources/resources/the_flask_mega_tutorial.yaml @@ -6,7 +6,7 @@ tags: - web development payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/the_real_python_podcast.yaml b/pydis_site/apps/resources/resources/the_real_python_podcast.yaml index 62ba32ce..647779d5 100644 --- a/pydis_site/apps/resources/resources/the_real_python_podcast.yaml +++ b/pydis_site/apps/resources/resources/the_real_python_podcast.yaml @@ -9,7 +9,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/think_python.yaml b/pydis_site/apps/resources/resources/think_python.yaml index aceaf951..f9211308 100644 --- a/pydis_site/apps/resources/resources/think_python.yaml +++ b/pydis_site/apps/resources/resources/think_python.yaml @@ -18,7 +18,7 @@ tags: - software design payment_tiers: - paid - complexity: + difficulty: - beginner type: - book diff --git a/pydis_site/apps/resources/resources/thonny.yaml b/pydis_site/apps/resources/resources/thonny.yaml index a60e4d1b..29ba9e07 100644 --- a/pydis_site/apps/resources/resources/thonny.yaml +++ b/pydis_site/apps/resources/resources/thonny.yaml @@ -8,7 +8,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner type: - tool diff --git a/pydis_site/apps/resources/resources/two_scoops_of_django.yaml b/pydis_site/apps/resources/resources/two_scoops_of_django.yaml index 4eadc28d..63730ac9 100644 --- a/pydis_site/apps/resources/resources/two_scoops_of_django.yaml +++ b/pydis_site/apps/resources/resources/two_scoops_of_django.yaml @@ -14,7 +14,7 @@ tags: - web development payment_tiers: - paid - complexity: + difficulty: - intermediate type: - book diff --git a/pydis_site/apps/resources/resources/university_of_michigan.yaml b/pydis_site/apps/resources/resources/university_of_michigan.yaml index 843b64ed..7aaaf2ae 100644 --- a/pydis_site/apps/resources/resources/university_of_michigan.yaml +++ b/pydis_site/apps/resources/resources/university_of_michigan.yaml @@ -7,7 +7,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner type: - course diff --git a/pydis_site/apps/resources/resources/university_of_toronto.yaml b/pydis_site/apps/resources/resources/university_of_toronto.yaml index d057eb39..94df96f2 100644 --- a/pydis_site/apps/resources/resources/university_of_toronto.yaml +++ b/pydis_site/apps/resources/resources/university_of_toronto.yaml @@ -13,7 +13,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/vcokltfre_discord_bot_tutorial.yaml b/pydis_site/apps/resources/resources/vcokltfre_discord_bot_tutorial.yaml index 02f9fe5a..1a3dd457 100644 --- a/pydis_site/apps/resources/resources/vcokltfre_discord_bot_tutorial.yaml +++ b/pydis_site/apps/resources/resources/vcokltfre_discord_bot_tutorial.yaml @@ -8,7 +8,7 @@ tags: - discord bots payment_tiers: - free - complexity: + difficulty: - intermediate type: - tutorial diff --git a/pydis_site/apps/resources/resources/visual_studio_code.yaml b/pydis_site/apps/resources/resources/visual_studio_code.yaml index f09efcf8..3cf858f8 100644 --- a/pydis_site/apps/resources/resources/visual_studio_code.yaml +++ b/pydis_site/apps/resources/resources/visual_studio_code.yaml @@ -6,7 +6,7 @@ tags: - general payment_tiers: - free - complexity: + difficulty: - beginner - intermediate type: diff --git a/pydis_site/apps/resources/resources/wtf_python.yaml b/pydis_site/apps/resources/resources/wtf_python.yaml index 7f67ccf9..6d90ba39 100644 --- a/pydis_site/apps/resources/resources/wtf_python.yaml +++ b/pydis_site/apps/resources/resources/wtf_python.yaml @@ -12,7 +12,7 @@ tags: - other payment_tiers: - free - complexity: + difficulty: - intermediate type: - tutorial diff --git a/pydis_site/apps/resources/views/resources.py b/pydis_site/apps/resources/views/resources.py index 57cb4f71..14b3d0bf 100644 --- a/pydis_site/apps/resources/views/resources.py +++ b/pydis_site/apps/resources/views/resources.py @@ -28,7 +28,7 @@ class ResourceView(View): resource_tags = { "topics": set(), "payment_tiers": set(), - "complexity": set(), + "difficulty": set(), "type": set(), } for resource_name, resource in self.resources.items(): @@ -53,8 +53,8 @@ class ResourceView(View): # Set up all the filter checkbox metadata self.filters = { - "Complexity": { - "filters": sorted(resource_tags.get("complexity")), + "Difficulty": { + "filters": sorted(resource_tags.get("difficulty")), "icon": "fas fa-brain", "hidden": False, }, @@ -84,7 +84,7 @@ class ResourceView(View): ('topics', 'topics'), ('type', 'type'), ('payment_tiers', 'payment'), - ('complexity', 'complexity'), + ('difficulty', 'difficulty'), ) } diff --git a/pydis_site/static/js/resources.js b/pydis_site/static/js/resources.js index 89b8ae06..eaca3978 100644 --- a/pydis_site/static/js/resources.js +++ b/pydis_site/static/js/resources.js @@ -5,7 +5,7 @@ var activeFilters = { topics: [], type: [], "payment-tiers": [], - complexity: [] + difficulty: [] }; function addFilter(filterName, filterItem) { @@ -45,7 +45,7 @@ function noFilters() { activeFilters.topics.length === 0 && activeFilters.type.length === 0 && activeFilters["payment-tiers"].length === 0 && - activeFilters.complexity.length === 0 + activeFilters.difficulty.length === 0 ); } @@ -120,7 +120,7 @@ function updateUI() { topics: false, type: false, 'payment-tiers': false, - complexity: false + difficulty: false }; let resourceBox = $(this); diff --git a/pydis_site/templates/resources/resource_box.html b/pydis_site/templates/resources/resource_box.html index 476a4841..8a1017b5 100644 --- a/pydis_site/templates/resources/resource_box.html +++ b/pydis_site/templates/resources/resource_box.html @@ -64,10 +64,10 @@ {{ tag|title }} {% endfor %} - {% for tag in resource.tags.complexity %} + {% for tag in resource.tags.difficulty %} diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index 166863c3..9ebebe1f 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -29,7 +29,7 @@
{% for filter_name, filter_data in filters.items %} {% for filter_item in filter_data.filters %} - {% if filter_name == "Complexity" %} + {% if filter_name == "Difficulty" %} Date: Sun, 30 Jan 2022 11:41:44 +0100 Subject: Redirects from old endpoints now filter correctly. For example, navigating to pydis.com/resources/communities will now correctly redirect to pydis.com/resources/?type=community. --- pydis_site/apps/redirect/redirects.yaml | 10 ++++++---- pydis_site/apps/resources/urls.py | 1 + pydis_site/apps/resources/views/resources.py | 25 ++++++++----------------- pydis_site/static/js/resources.js | 8 ++++++++ pydis_site/templates/resources/resources.html | 1 + 5 files changed, 24 insertions(+), 21 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/apps/redirect/redirects.yaml b/pydis_site/apps/redirect/redirects.yaml index bee65103..533b9e25 100644 --- a/pydis_site/apps/redirect/redirects.yaml +++ b/pydis_site/apps/redirect/redirects.yaml @@ -90,30 +90,32 @@ resources_index_redirect: resources_reading_redirect: original_path: resources/reading/ redirect_route: "resources:index" + redirect_arguments: ["book"] resources_videos_redirect: original_path: resources/videos/ redirect_route: "resources:index" - -resources_interactive_redirect: - original_path: resources/interactive/ - redirect_route: "resources:index" + redirect_arguments: ["video"] resources_courses_redirect: original_path: resources/courses/ redirect_route: "resources:index" + redirect_arguments: ["course"] resources_communities_redirect: original_path: resources/communities/ redirect_route: "resources:index" + redirect_arguments: ["community"] resources_podcasts_redirect: original_path: resources/podcasts/ redirect_route: "resources:index" + redirect_arguments: ["podcast"] resources_tools_redirect: original_path: resources/tools/ redirect_route: "resources:index" + redirect_arguments: ["tool"] # Events events_index_redirect: diff --git a/pydis_site/apps/resources/urls.py b/pydis_site/apps/resources/urls.py index 5d5ae7fb..ed24dc99 100644 --- a/pydis_site/apps/resources/urls.py +++ b/pydis_site/apps/resources/urls.py @@ -5,4 +5,5 @@ from pydis_site.apps.resources import views app_name = "resources" urlpatterns = [ distill_path("", views.resources.ResourceView.as_view(), name="index"), + distill_path("/", views.resources.ResourceView.as_view(), name="index"), ] diff --git a/pydis_site/apps/resources/views/resources.py b/pydis_site/apps/resources/views/resources.py index d0b8bae7..b828d89a 100644 --- a/pydis_site/apps/resources/views/resources.py +++ b/pydis_site/apps/resources/views/resources.py @@ -1,8 +1,9 @@ from pathlib import Path +import typing as t import yaml from django.core.handlers.wsgi import WSGIRequest -from django.http import HttpResponse +from django.http import HttpResponse, HttpResponseNotFound from django.shortcuts import render from django.views import View @@ -78,22 +79,12 @@ class ResourceView(View): } } - @staticmethod - def _get_filter_options(request: WSGIRequest) -> dict[str, set]: - """Get the requested filter options out of the request object.""" - return { - option: set(request.GET.get(url_param, "").split(",")[:-1]) - for option, url_param in ( - ('topics', 'topics'), - ('type', 'type'), - ('payment_tiers', 'payment'), - ('difficulty', 'difficulty'), - ) - } - - def get(self, request: WSGIRequest) -> HttpResponse: + def get(self, request: WSGIRequest, resource_type: t.Optional[str] = None) -> HttpResponse: """List out all the resources, and any filtering options from the URL.""" - filter_options = self._get_filter_options(request) + + # Add type filtering if the request is made to somewhere like /resources/video + if resource_type and resource_type.title() not in self.filters['Type']['filters']: + return HttpResponseNotFound() return render( request, @@ -101,6 +92,6 @@ class ResourceView(View): context={ "resources": self.resources, "filters": self.filters, - "filter_options": filter_options, + "resource_type": resource_type, } ) diff --git a/pydis_site/static/js/resources.js b/pydis_site/static/js/resources.js index eaca3978..bf570097 100644 --- a/pydis_site/static/js/resources.js +++ b/pydis_site/static/js/resources.js @@ -160,6 +160,14 @@ function updateUI() { // Executed when the page has finished loading. document.addEventListener("DOMContentLoaded", function () { + /* Check if the user has navigated to one of the old resource pages, + like pydis.com/resources/communities. In this case, we'll rewrite + the URL before we do anything else. */ + let resourceTypeInput = $("#resource-type-input").val(); + if (resourceTypeInput.length !== 0) { + window.history.replaceState(null, document.title, `../?type=${resourceTypeInput}`); + } + // Update the filters on page load to reflect URL parameters. $('.filter-box-tag').hide(); deserializeURLParams(); diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index 9ebebe1f..7a284fd6 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -16,6 +16,7 @@ {% block content %} {% include "base/navbar.html" %} +
{# Filtering toolbox #} -- cgit v1.2.3 From 05a8f9a193b451cdf0333b16cf2d525e9d6eb8f4 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sun, 30 Jan 2022 12:01:58 +0100 Subject: Don't redirect if the resource_type is None! --- pydis_site/static/js/resources.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/js/resources.js b/pydis_site/static/js/resources.js index bf570097..bfcd569d 100644 --- a/pydis_site/static/js/resources.js +++ b/pydis_site/static/js/resources.js @@ -113,7 +113,6 @@ function updateUI() { // Otherwise, hide everything and then filter the resources to decide what to show. let hasMatches = false; - console.log(hasMatches); resources.hide(); resources.filter(function() { let validation = { @@ -164,7 +163,7 @@ document.addEventListener("DOMContentLoaded", function () { like pydis.com/resources/communities. In this case, we'll rewrite the URL before we do anything else. */ let resourceTypeInput = $("#resource-type-input").val(); - if (resourceTypeInput.length !== 0) { + if (resourceTypeInput !== "None") { window.history.replaceState(null, document.title, `../?type=${resourceTypeInput}`); } -- cgit v1.2.3 From aa1420aeb91a9663a714cdceb0f957d9837740e7 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sun, 30 Jan 2022 12:33:20 +0100 Subject: Clean up hover effects. - We now have a hover effect for all icons. - We also now support hover effects for all tags. - However, we don't have any hover effect for icons in titles. That just looks weird. Additionally, we're getting rid of some bloat and consolidating the CSS into one place. --- pydis_site/static/css/resources/resources.css | 48 ++++++++++++++++++ pydis_site/static/css/resources/resources_list.css | 57 ---------------------- pydis_site/templates/resources/resource_box.html | 4 +- 3 files changed, 50 insertions(+), 59 deletions(-) delete mode 100644 pydis_site/static/css/resources/resources_list.css (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index db083a41..7038d0d7 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -1,3 +1,45 @@ +/* Colors for icons */ +i.resource-icon.is-orangered { + color: #FE640A; +} +i.resource-icon.is-blurple { + color: #7289DA; +} +i.resource-icon.is-teal { + color: #95DBE5; +} +i.resource-icon.is-youtube-red { + color: #BB0000; +} +i.resource-icon.is-black { + color: #2c3334; +} + +/* Colors when icons are hovered */ +i.resource-icon.is-hoverable:hover { + filter: brightness(125%); +} +i.resource-icon.is-hoverable.is-black:hover { + filter: brightness(170%); +} +i.resource-icon.is-hoverable.is-teal:hover { + filter: brightness(80%); +} + +/* Icon padding */ +.breadcrumb-section { + padding: 1rem; +} +i.has-icon-padding { + padding: 0 10px 25px 0; +} +#tab-content p { + display: none; +} +#tab-content p.is-active { +display: block; +} + /* Disable highlighting for all text in the filters. */ .filter-checkbox, .filter-panel label, @@ -57,6 +99,12 @@ span.filter-box-tag { user-select: none; } +/* When hovering tags, brighten them a bit. */ +.resource-tag:hover, +.filter-box-tag:hover { + filter: brightness(95%); +} + /* Move the x down 1 pixel to align center */ button.delete { margin-top: 1px; diff --git a/pydis_site/static/css/resources/resources_list.css b/pydis_site/static/css/resources/resources_list.css deleted file mode 100644 index c2151bee..00000000 --- a/pydis_site/static/css/resources/resources_list.css +++ /dev/null @@ -1,57 +0,0 @@ -.breadcrumb-section { - padding: 1rem; -} - -i.resource-icon.is-orangered { - color: #FE640A; -} - -i.resource-icon.is-orangered:hover { - color: #fe9840; -} - -i.resource-icon.is-blurple { - color: #7289DA; -} - -i.resource-icon.is-blurple:hover { - color: #93a8da; -} - -i.resource-icon.is-teal { - color: #95DBE5; -} - -i.resource-icon.is-teal:hover { - color: #a9f5ff; -} - -i.resource-icon.is-youtube-red { - color: #BB0000; -} - -i.resource-icon.is-youtube-red:hover { - color: #f80000; -} - -i.resource-icon.is-goodreads-cream, -i.resource-icon.is-black { - color: #2c3334; -} - -i.resource-icon.is-goodreads-cream:hover, -i.resource-icon.is-black:hover { - color: #475d6d; -} - -i.has-icon-padding { - padding: 0 10px 25px 0; -} - -#tab-content p { - display: none; -} - -#tab-content p.is-active { -display: block; -} diff --git a/pydis_site/templates/resources/resource_box.html b/pydis_site/templates/resources/resource_box.html index 8a1017b5..b06ffd31 100644 --- a/pydis_site/templates/resources/resource_box.html +++ b/pydis_site/templates/resources/resource_box.html @@ -18,7 +18,7 @@ {% if 'title_url' in resource %} - + {% endif %} @@ -27,7 +27,7 @@ {% for icon in resource.urls %} - + {% endfor %} -- cgit v1.2.3 From d8c5571a266438d5e2e0c9fd4a35adf469688730 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sun, 30 Jan 2022 12:34:29 +0100 Subject: Support dashful redirects. Previously, trying to go to `resources/project%20ideas` would crash the filtering JS. This has now been sorted out, so that these types of redirects have their spaces replaced by dashes, which makes them valid again. --- pydis_site/apps/resources/views/resources.py | 7 +++++-- pydis_site/static/js/resources.js | 11 +++++------ pydis_site/templates/resources/resources.html | 1 - 3 files changed, 10 insertions(+), 9 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/apps/resources/views/resources.py b/pydis_site/apps/resources/views/resources.py index b828d89a..709fad6c 100644 --- a/pydis_site/apps/resources/views/resources.py +++ b/pydis_site/apps/resources/views/resources.py @@ -82,9 +82,12 @@ class ResourceView(View): def get(self, request: WSGIRequest, resource_type: t.Optional[str] = None) -> HttpResponse: """List out all the resources, and any filtering options from the URL.""" - # Add type filtering if the request is made to somewhere like /resources/video - if resource_type and resource_type.title() not in self.filters['Type']['filters']: + # Add type filtering if the request is made to somewhere like /resources/video. + # We also convert all spaces to dashes, so they'll correspond with the filters. + dashless_resource_type = resource_type.replace("-", " ") + if resource_type and dashless_resource_type.title() not in self.filters['Type']['filters']: return HttpResponseNotFound() + resource_type = resource_type.replace(" ", "-") return render( request, diff --git a/pydis_site/static/js/resources.js b/pydis_site/static/js/resources.js index bfcd569d..34587c81 100644 --- a/pydis_site/static/js/resources.js +++ b/pydis_site/static/js/resources.js @@ -64,9 +64,9 @@ function deserializeURLParams() { // Update the corresponding filter UI, so it reflects the internal state. $(paramFilterArray).each(function(_, filter) { - let checkbox = $(`.filter-checkbox[data-filter-name=${filterType}][data-filter-item=${filter}]`); - let filterTag = $(`.filter-box-tag[data-filter-name=${filterType}][data-filter-item=${filter}]`); - let resourceTags = $(`.resource-tag[data-filter-name=${filterType}][data-filter-item=${filter}]`); + let checkbox = $(`.filter-checkbox[data-filter-name='${filterType}'][data-filter-item='${filter}']`); + let filterTag = $(`.filter-box-tag[data-filter-name='${filterType}'][data-filter-item='${filter}']`); + let resourceTags = $(`.resource-tag[data-filter-name='${filterType}'][data-filter-item='${filter}']`); checkbox.prop("checked", true); filterTag.show(); resourceTags.addClass("active"); @@ -149,7 +149,6 @@ function updateUI() { }).show(); // If there are no matches, show the no matches message - console.log(hasMatches); if (!hasMatches) { $(".no-resources-found").show(); } else { @@ -196,7 +195,7 @@ document.addEventListener("DOMContentLoaded", function () { $('.filter-box-tag').click(function() { let filterItem = this.dataset.filterItem; let filterName = this.dataset.filterName; - let checkbox = $(`.filter-checkbox[data-filter-name=${filterName}][data-filter-item=${filterItem}]`); + let checkbox = $(`.filter-checkbox[data-filter-name='${filterName}'][data-filter-item='${filterItem}']`); removeFilter(filterName, filterItem); checkbox.prop("checked", false); @@ -206,7 +205,7 @@ document.addEventListener("DOMContentLoaded", function () { $('.resource-tag').click(function() { let filterItem = this.dataset.filterItem; let filterName = this.dataset.filterName; - let checkbox = $(`.filter-checkbox[data-filter-name=${filterName}][data-filter-item=${filterItem}]`) + let checkbox = $(`.filter-checkbox[data-filter-name='${filterName}'][data-filter-item='${filterItem}']`); if (!$(this).hasClass("active")) { addFilter(filterName, filterItem); diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index 7a284fd6..4dd07270 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -7,7 +7,6 @@ {% block title %}Resources{% endblock %} {% block head %} - -- cgit v1.2.3 From 2cbaeb129b793fa3dc162258dd4e60781e35d5f1 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sun, 30 Jan 2022 13:04:58 +0100 Subject: Show a duck pond when no filters match. --- pydis_site/static/css/resources/resources.css | 7 +++++++ pydis_site/static/images/resources/duck_pond_404.png | Bin 0 -> 2371374 bytes pydis_site/templates/resources/resources.html | 6 +++++- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 pydis_site/static/images/resources/duck_pond_404.png (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index 7038d0d7..b48beca6 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -93,6 +93,13 @@ span.filter-box-tag { user-select: none; } +/* Center the 404 div */ +.no-resources-found { + display: flex; + flex-direction: column; + align-items: center; +} + /* Make resource tags clickable */ .resource-tag { cursor: pointer; diff --git a/pydis_site/static/images/resources/duck_pond_404.png b/pydis_site/static/images/resources/duck_pond_404.png new file mode 100644 index 00000000..3aed4d62 Binary files /dev/null and b/pydis_site/static/images/resources/duck_pond_404.png differ diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index 4dd07270..53feb255 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -124,7 +124,11 @@
{# Message to display when there are no hits #} -

No matching resources found!

+
+

No matching resources found!

+ +
+ {# Resource cards #}
-- cgit v1.2.3 From 295cd818e3d679083b962ee90e334ad4cbc9adba Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sun, 30 Jan 2022 14:03:10 +0100 Subject: Fix broken css for no-resource duck pond. --- pydis_site/static/css/resources/resources.css | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index b48beca6..aa47be8f 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -62,8 +62,15 @@ display: block; border-radius: 0; } +/* Center the 404 div */ +.no-resources-found { + display: flex; + flex-direction: column; + align-items: center; +} + /* Hide the no resources h2 by default */ -h2.no-resources-found { +.no-resources-found { display: none; margin-top: 1em; } @@ -93,13 +100,6 @@ span.filter-box-tag { user-select: none; } -/* Center the 404 div */ -.no-resources-found { - display: flex; - flex-direction: column; - align-items: center; -} - /* Make resource tags clickable */ .resource-tag { cursor: pointer; -- cgit v1.2.3 From df51385ab8adf715d61841eceebeb7cb2f220e77 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sun, 30 Jan 2022 14:14:51 +0100 Subject: Show a "No filters selected" indicator. --- pydis_site/static/js/resources.js | 10 ++++++++-- pydis_site/templates/resources/resource_box.html | 6 +++--- pydis_site/templates/resources/resources.html | 8 +++++++- 3 files changed, 18 insertions(+), 6 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/js/resources.js b/pydis_site/static/js/resources.js index 34587c81..718e1e88 100644 --- a/pydis_site/static/js/resources.js +++ b/pydis_site/static/js/resources.js @@ -18,10 +18,12 @@ function addFilter(filterName, filterItem) { // Show a corresponding filter box tag $(`.filter-box-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).show(); - $(".filter-tags").css("padding-bottom", "0.5em"); // Make corresponding resource tags active $(`.resource-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).addClass("active"); + + // Hide the "No filters selected" tag. + $(".no-tags-selected.tag").hide(); } function removeFilter(filterName, filterItem) { @@ -37,6 +39,11 @@ function removeFilter(filterName, filterItem) { // Make corresponding resource tags inactive $(`.resource-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).removeClass("active"); + + // Show "No filters selected" tag, if there are no filters active + if (noFilters()) { + $(".no-tags-selected.tag").show(); + } } /* Check if there are no filters */ @@ -107,7 +114,6 @@ function updateUI() { if (noFilters()) { resources.show(); filterTags.hide(); - $(".filter-tags").css("padding-bottom", "0"); return; } diff --git a/pydis_site/templates/resources/resource_box.html b/pydis_site/templates/resources/resource_box.html index b06ffd31..88ddee80 100644 --- a/pydis_site/templates/resources/resource_box.html +++ b/pydis_site/templates/resources/resource_box.html @@ -18,16 +18,16 @@ {% if 'title_url' in resource %} - + {% endif %} - {#Add all additional icon #} + {# Add all additional icon #} {% for icon in resource.urls %} - + {% endfor %} diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index 53feb255..c3881092 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -27,6 +27,12 @@ {# Filter box tags #}
+ {# A filter tag for when there are no filters active #} + + + No filters selected + + {% for filter_name, filter_data in filters.items %} {% for filter_item in filter_data.filters %} {% if filter_name == "Difficulty" %} @@ -125,7 +131,7 @@
{# Message to display when there are no hits #}
-

No matching resources found!

+

No matching resources found!

-- cgit v1.2.3 From dda3e355ac31dc4b9629f2e9e63474bbba69d740 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sun, 30 Jan 2022 14:29:48 +0100 Subject: Refactor: collapsibles as a stand-alone component --- pydis_site/apps/resources/urls.py | 1 + pydis_site/static/css/collapsibles.css | 12 ++ pydis_site/static/css/content/page.css | 13 -- pydis_site/static/js/collapsibles.js | 13 ++ pydis_site/static/js/content/page.js | 13 -- pydis_site/static/js/resources.js | 236 -------------------------- pydis_site/static/js/resources/resources.js | 236 ++++++++++++++++++++++++++ pydis_site/templates/content/base.html | 3 +- pydis_site/templates/resources/resources.html | 6 +- 9 files changed, 267 insertions(+), 266 deletions(-) create mode 100644 pydis_site/static/css/collapsibles.css create mode 100644 pydis_site/static/js/collapsibles.js delete mode 100644 pydis_site/static/js/content/page.js delete mode 100644 pydis_site/static/js/resources.js create mode 100644 pydis_site/static/js/resources/resources.js (limited to 'pydis_site/static') diff --git a/pydis_site/apps/resources/urls.py b/pydis_site/apps/resources/urls.py index aa3892b6..044f7072 100644 --- a/pydis_site/apps/resources/urls.py +++ b/pydis_site/apps/resources/urls.py @@ -31,6 +31,7 @@ VALID_RESOURCE_TYPES = [ def get_all_pages() -> typing.Iterator[dict[str, str]]: + """Get all the valid options for the resource_type path selector.""" for resource_type in VALID_RESOURCE_TYPES: yield {"resource_type": resource_type} diff --git a/pydis_site/static/css/collapsibles.css b/pydis_site/static/css/collapsibles.css new file mode 100644 index 00000000..7b76d8d5 --- /dev/null +++ b/pydis_site/static/css/collapsibles.css @@ -0,0 +1,12 @@ +.collapsible { + cursor: pointer; + width: 100%; + border: none; + outline: none; +} + +.collapsible-content { + overflow: hidden; + max-height: 0; + transition: max-height 0.2s ease-out; +} \ No newline at end of file diff --git a/pydis_site/static/css/content/page.css b/pydis_site/static/css/content/page.css index 2d4bd325..d831f86d 100644 --- a/pydis_site/static/css/content/page.css +++ b/pydis_site/static/css/content/page.css @@ -77,16 +77,3 @@ ul.menu-list.toc { li img { margin-top: 0.5em; } - -.collapsible { - cursor: pointer; - width: 100%; - border: none; - outline: none; -} - -.collapsible-content { - overflow: hidden; - max-height: 0; - transition: max-height 0.2s ease-out; -} diff --git a/pydis_site/static/js/collapsibles.js b/pydis_site/static/js/collapsibles.js new file mode 100644 index 00000000..366a033c --- /dev/null +++ b/pydis_site/static/js/collapsibles.js @@ -0,0 +1,13 @@ +document.addEventListener("DOMContentLoaded", () => { + const headers = document.getElementsByClassName("collapsible"); + for (const header of headers) { + header.addEventListener("click", () => { + var content = header.nextElementSibling; + if (content.style.maxHeight){ + content.style.maxHeight = null; + } else { + content.style.maxHeight = content.scrollHeight + "px"; + } + }); + } +}); diff --git a/pydis_site/static/js/content/page.js b/pydis_site/static/js/content/page.js deleted file mode 100644 index 366a033c..00000000 --- a/pydis_site/static/js/content/page.js +++ /dev/null @@ -1,13 +0,0 @@ -document.addEventListener("DOMContentLoaded", () => { - const headers = document.getElementsByClassName("collapsible"); - for (const header of headers) { - header.addEventListener("click", () => { - var content = header.nextElementSibling; - if (content.style.maxHeight){ - content.style.maxHeight = null; - } else { - content.style.maxHeight = content.scrollHeight + "px"; - } - }); - } -}); diff --git a/pydis_site/static/js/resources.js b/pydis_site/static/js/resources.js deleted file mode 100644 index 718e1e88..00000000 --- a/pydis_site/static/js/resources.js +++ /dev/null @@ -1,236 +0,0 @@ -"use strict"; - -// Filters that are currently selected -var activeFilters = { - topics: [], - type: [], - "payment-tiers": [], - difficulty: [] -}; - -function addFilter(filterName, filterItem) { - // Push the filter into the stack - var filterIndex = activeFilters[filterName].indexOf(filterItem); - if (filterIndex === -1) { - activeFilters[filterName].push(filterItem); - } - updateUI(); - - // Show a corresponding filter box tag - $(`.filter-box-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).show(); - - // Make corresponding resource tags active - $(`.resource-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).addClass("active"); - - // Hide the "No filters selected" tag. - $(".no-tags-selected.tag").hide(); -} - -function removeFilter(filterName, filterItem) { - // Remove the filter from the stack - var filterIndex = activeFilters[filterName].indexOf(filterItem); - if (filterIndex !== -1) { - activeFilters[filterName].splice(filterIndex, 1); - } - updateUI(); - - // Hide the corresponding filter box tag - $(`.filter-box-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).hide(); - - // Make corresponding resource tags inactive - $(`.resource-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).removeClass("active"); - - // Show "No filters selected" tag, if there are no filters active - if (noFilters()) { - $(".no-tags-selected.tag").show(); - } -} - -/* Check if there are no filters */ -function noFilters() { - return ( - activeFilters.topics.length === 0 && - activeFilters.type.length === 0 && - activeFilters["payment-tiers"].length === 0 && - activeFilters.difficulty.length === 0 - ); -} - -/* Get the params out of the URL and use them. This is run when the page loads. */ -function deserializeURLParams() { - let searchParams = new window.URLSearchParams(window.location.search); - - // Work through the parameters and add them to the filter object - $.each(Object.keys(activeFilters), function(_, filterType) { - let paramFilterContent = searchParams.get(filterType); - - if (paramFilterContent !== null) { - // We use split here because we always want an array, not a string. - let paramFilterArray = paramFilterContent.split(","); - activeFilters[filterType] = paramFilterArray; - - // Update the corresponding filter UI, so it reflects the internal state. - $(paramFilterArray).each(function(_, filter) { - let checkbox = $(`.filter-checkbox[data-filter-name='${filterType}'][data-filter-item='${filter}']`); - let filterTag = $(`.filter-box-tag[data-filter-name='${filterType}'][data-filter-item='${filter}']`); - let resourceTags = $(`.resource-tag[data-filter-name='${filterType}'][data-filter-item='${filter}']`); - checkbox.prop("checked", true); - filterTag.show(); - resourceTags.addClass("active"); - }); - } - }); -} - -/* Update the URL with new parameters */ -function updateURL() { - // If there's nothing in the filters, we don't want anything in the URL. - if (noFilters()) { - window.history.replaceState(null, document.title, './'); - return; - } - - // Iterate through and get rid of empty ones - let searchParams = new URLSearchParams(activeFilters); - $.each(activeFilters, function(filterType, filters) { - if (filters.length === 0) { - searchParams.delete(filterType); - } - }); - - // Now update the URL - window.history.replaceState(null, document.title, `?${searchParams.toString()}`); -} - -/* Update the resources to match 'active_filters' */ -function updateUI() { - let resources = $('.resource-box'); - let filterTags = $('.filter-box-tag'); - - // Update the URL to match the new filters. - updateURL(); - - // If there's nothing in the filters, show everything and return. - if (noFilters()) { - resources.show(); - filterTags.hide(); - return; - } - - // Otherwise, hide everything and then filter the resources to decide what to show. - let hasMatches = false; - resources.hide(); - resources.filter(function() { - let validation = { - topics: false, - type: false, - 'payment-tiers': false, - difficulty: false - }; - let resourceBox = $(this); - - // Validate the filters - $.each(activeFilters, function(filterType, filters) { - // If the filter list is empty, this passes validation. - if (filters.length === 0) { - validation[filterType] = true; - return; - } - - // Otherwise, we need to check if one of the classes exist. - $.each(filters, function(index, filter) { - if (resourceBox.hasClass(`${filterType}-${filter}`)) { - validation[filterType] = true; - } - }); - }); - - // If validation passes, show the resource. - if (Object.values(validation).every(Boolean)) { - hasMatches = true; - return true; - } else { - return false; - } - }).show(); - - // If there are no matches, show the no matches message - if (!hasMatches) { - $(".no-resources-found").show(); - } else { - $(".no-resources-found").hide(); - } -} - -// Executed when the page has finished loading. -document.addEventListener("DOMContentLoaded", function () { - /* Check if the user has navigated to one of the old resource pages, - like pydis.com/resources/communities. In this case, we'll rewrite - the URL before we do anything else. */ - let resourceTypeInput = $("#resource-type-input").val(); - if (resourceTypeInput !== "None") { - window.history.replaceState(null, document.title, `../?type=${resourceTypeInput}`); - } - - // Update the filters on page load to reflect URL parameters. - $('.filter-box-tag').hide(); - deserializeURLParams(); - updateUI(); - - // If you collapse or uncollapse a filter group, swap the icon. - $('button.collapsible').click(function() { - let icon = $(this).find(".card-header-icon i"); - - if ($(icon).hasClass("fa-window-minimize")) { - $(icon).removeClass(["far", "fa-window-minimize"]); - $(icon).addClass(["fas", "fa-angle-down"]); - } else { - $(icon).removeClass(["fas", "fa-angle-down"]); - $(icon).addClass(["far", "fa-window-minimize"]); - } - }); - - // If you click on the div surrounding the filter checkbox, it clicks the corresponding checkbox. - $('.filter-panel').click(function() { - let checkbox = $(this).find(".filter-checkbox"); - checkbox.prop("checked", !checkbox.prop("checked")); - checkbox.change(); - }); - - // If you click on one of the tags in the filter box, it unchecks the corresponding checkbox. - $('.filter-box-tag').click(function() { - let filterItem = this.dataset.filterItem; - let filterName = this.dataset.filterName; - let checkbox = $(`.filter-checkbox[data-filter-name='${filterName}'][data-filter-item='${filterItem}']`); - - removeFilter(filterName, filterItem); - checkbox.prop("checked", false); - }); - - // If you click on one of the tags in the resource cards, it clicks the corresponding checkbox. - $('.resource-tag').click(function() { - let filterItem = this.dataset.filterItem; - let filterName = this.dataset.filterName; - let checkbox = $(`.filter-checkbox[data-filter-name='${filterName}'][data-filter-item='${filterItem}']`); - - if (!$(this).hasClass("active")) { - addFilter(filterName, filterItem); - checkbox.prop("checked", true); - } else { - removeFilter(filterName, filterItem); - checkbox.prop("checked", false); - } - }); - - // When checkboxes are toggled, trigger a filter update. - $('.filter-checkbox').change(function () { - let filterItem = this.dataset.filterItem; - let filterName = this.dataset.filterName; - - if (this.checked) { - addFilter(filterName, filterItem); - } else { - removeFilter(filterName, filterItem); - } - }); -}); diff --git a/pydis_site/static/js/resources/resources.js b/pydis_site/static/js/resources/resources.js new file mode 100644 index 00000000..718e1e88 --- /dev/null +++ b/pydis_site/static/js/resources/resources.js @@ -0,0 +1,236 @@ +"use strict"; + +// Filters that are currently selected +var activeFilters = { + topics: [], + type: [], + "payment-tiers": [], + difficulty: [] +}; + +function addFilter(filterName, filterItem) { + // Push the filter into the stack + var filterIndex = activeFilters[filterName].indexOf(filterItem); + if (filterIndex === -1) { + activeFilters[filterName].push(filterItem); + } + updateUI(); + + // Show a corresponding filter box tag + $(`.filter-box-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).show(); + + // Make corresponding resource tags active + $(`.resource-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).addClass("active"); + + // Hide the "No filters selected" tag. + $(".no-tags-selected.tag").hide(); +} + +function removeFilter(filterName, filterItem) { + // Remove the filter from the stack + var filterIndex = activeFilters[filterName].indexOf(filterItem); + if (filterIndex !== -1) { + activeFilters[filterName].splice(filterIndex, 1); + } + updateUI(); + + // Hide the corresponding filter box tag + $(`.filter-box-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).hide(); + + // Make corresponding resource tags inactive + $(`.resource-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).removeClass("active"); + + // Show "No filters selected" tag, if there are no filters active + if (noFilters()) { + $(".no-tags-selected.tag").show(); + } +} + +/* Check if there are no filters */ +function noFilters() { + return ( + activeFilters.topics.length === 0 && + activeFilters.type.length === 0 && + activeFilters["payment-tiers"].length === 0 && + activeFilters.difficulty.length === 0 + ); +} + +/* Get the params out of the URL and use them. This is run when the page loads. */ +function deserializeURLParams() { + let searchParams = new window.URLSearchParams(window.location.search); + + // Work through the parameters and add them to the filter object + $.each(Object.keys(activeFilters), function(_, filterType) { + let paramFilterContent = searchParams.get(filterType); + + if (paramFilterContent !== null) { + // We use split here because we always want an array, not a string. + let paramFilterArray = paramFilterContent.split(","); + activeFilters[filterType] = paramFilterArray; + + // Update the corresponding filter UI, so it reflects the internal state. + $(paramFilterArray).each(function(_, filter) { + let checkbox = $(`.filter-checkbox[data-filter-name='${filterType}'][data-filter-item='${filter}']`); + let filterTag = $(`.filter-box-tag[data-filter-name='${filterType}'][data-filter-item='${filter}']`); + let resourceTags = $(`.resource-tag[data-filter-name='${filterType}'][data-filter-item='${filter}']`); + checkbox.prop("checked", true); + filterTag.show(); + resourceTags.addClass("active"); + }); + } + }); +} + +/* Update the URL with new parameters */ +function updateURL() { + // If there's nothing in the filters, we don't want anything in the URL. + if (noFilters()) { + window.history.replaceState(null, document.title, './'); + return; + } + + // Iterate through and get rid of empty ones + let searchParams = new URLSearchParams(activeFilters); + $.each(activeFilters, function(filterType, filters) { + if (filters.length === 0) { + searchParams.delete(filterType); + } + }); + + // Now update the URL + window.history.replaceState(null, document.title, `?${searchParams.toString()}`); +} + +/* Update the resources to match 'active_filters' */ +function updateUI() { + let resources = $('.resource-box'); + let filterTags = $('.filter-box-tag'); + + // Update the URL to match the new filters. + updateURL(); + + // If there's nothing in the filters, show everything and return. + if (noFilters()) { + resources.show(); + filterTags.hide(); + return; + } + + // Otherwise, hide everything and then filter the resources to decide what to show. + let hasMatches = false; + resources.hide(); + resources.filter(function() { + let validation = { + topics: false, + type: false, + 'payment-tiers': false, + difficulty: false + }; + let resourceBox = $(this); + + // Validate the filters + $.each(activeFilters, function(filterType, filters) { + // If the filter list is empty, this passes validation. + if (filters.length === 0) { + validation[filterType] = true; + return; + } + + // Otherwise, we need to check if one of the classes exist. + $.each(filters, function(index, filter) { + if (resourceBox.hasClass(`${filterType}-${filter}`)) { + validation[filterType] = true; + } + }); + }); + + // If validation passes, show the resource. + if (Object.values(validation).every(Boolean)) { + hasMatches = true; + return true; + } else { + return false; + } + }).show(); + + // If there are no matches, show the no matches message + if (!hasMatches) { + $(".no-resources-found").show(); + } else { + $(".no-resources-found").hide(); + } +} + +// Executed when the page has finished loading. +document.addEventListener("DOMContentLoaded", function () { + /* Check if the user has navigated to one of the old resource pages, + like pydis.com/resources/communities. In this case, we'll rewrite + the URL before we do anything else. */ + let resourceTypeInput = $("#resource-type-input").val(); + if (resourceTypeInput !== "None") { + window.history.replaceState(null, document.title, `../?type=${resourceTypeInput}`); + } + + // Update the filters on page load to reflect URL parameters. + $('.filter-box-tag').hide(); + deserializeURLParams(); + updateUI(); + + // If you collapse or uncollapse a filter group, swap the icon. + $('button.collapsible').click(function() { + let icon = $(this).find(".card-header-icon i"); + + if ($(icon).hasClass("fa-window-minimize")) { + $(icon).removeClass(["far", "fa-window-minimize"]); + $(icon).addClass(["fas", "fa-angle-down"]); + } else { + $(icon).removeClass(["fas", "fa-angle-down"]); + $(icon).addClass(["far", "fa-window-minimize"]); + } + }); + + // If you click on the div surrounding the filter checkbox, it clicks the corresponding checkbox. + $('.filter-panel').click(function() { + let checkbox = $(this).find(".filter-checkbox"); + checkbox.prop("checked", !checkbox.prop("checked")); + checkbox.change(); + }); + + // If you click on one of the tags in the filter box, it unchecks the corresponding checkbox. + $('.filter-box-tag').click(function() { + let filterItem = this.dataset.filterItem; + let filterName = this.dataset.filterName; + let checkbox = $(`.filter-checkbox[data-filter-name='${filterName}'][data-filter-item='${filterItem}']`); + + removeFilter(filterName, filterItem); + checkbox.prop("checked", false); + }); + + // If you click on one of the tags in the resource cards, it clicks the corresponding checkbox. + $('.resource-tag').click(function() { + let filterItem = this.dataset.filterItem; + let filterName = this.dataset.filterName; + let checkbox = $(`.filter-checkbox[data-filter-name='${filterName}'][data-filter-item='${filterItem}']`); + + if (!$(this).hasClass("active")) { + addFilter(filterName, filterItem); + checkbox.prop("checked", true); + } else { + removeFilter(filterName, filterItem); + checkbox.prop("checked", false); + } + }); + + // When checkboxes are toggled, trigger a filter update. + $('.filter-checkbox').change(function () { + let filterItem = this.dataset.filterItem; + let filterName = this.dataset.filterName; + + if (this.checked) { + addFilter(filterName, filterItem); + } else { + removeFilter(filterName, filterItem); + } + }); +}); diff --git a/pydis_site/templates/content/base.html b/pydis_site/templates/content/base.html index 00f4fce4..4a19a275 100644 --- a/pydis_site/templates/content/base.html +++ b/pydis_site/templates/content/base.html @@ -7,7 +7,8 @@ - + + {% endblock %} {% block content %} diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index c3881092..80577c2b 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -7,10 +7,10 @@ {% block title %}Resources{% endblock %} {% block head %} - + - - + + {% endblock %} {% block content %} -- cgit v1.2.3 From efc24acb63e4faf10644fb22b3c72aa13d792b79 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sun, 30 Jan 2022 20:01:27 +0100 Subject: Hide the filter tags initially. Helps prevent a flash of tags. --- pydis_site/static/css/resources/resources.css | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index aa47be8f..ebd946d9 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -94,12 +94,17 @@ i.is-primary { /* Set default display to inline-flex, for centering. */ span.filter-box-tag { - display: inline-flex; + display: none; align-items: center; cursor: pointer; user-select: none; } +/* Make sure jQuery will use inline-flex when setting `show()` again. */ +span.filter-box-tag[style*='display: block'] { + display: inline-flex !important; +} + /* Make resource tags clickable */ .resource-tag { cursor: pointer; -- cgit v1.2.3 From bc6829b93246e2f8833b5b418d3d7bd8eadc99cf Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sun, 30 Jan 2022 20:02:06 +0100 Subject: Make the category headers smaller on mobile. --- pydis_site/static/css/resources/resources.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index ebd946d9..59f8b78e 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -187,3 +187,15 @@ span.resource-tag.active.has-background-success-light { span.resource-tag.active.has-background-info-light { animation: glow_info 4s infinite alternate; } + +/* Smaller filter category headers when on mobile */ +@media screen and (max-width: 480px) { + .filter-category-header .card-header .card-header-title { + font-size: 14px; + padding: 0; + } + .filter-panel { + padding-top: 4px; + padding-bottom: 4px; + } +} \ No newline at end of file -- cgit v1.2.3 From ca45357255f5957cf779c109fc24e83de904a195 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sun, 30 Jan 2022 20:25:34 +0100 Subject: Collapse category headers on load for mobile only. --- pydis_site/static/css/resources/resources.css | 8 ++++++++ pydis_site/static/js/resources/resources.js | 13 ++++++++++++- pydis_site/templates/resources/resources.html | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index 59f8b78e..b24fcb5b 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -198,4 +198,12 @@ span.resource-tag.active.has-background-info-light { padding-top: 4px; padding-bottom: 4px; } +} + +/* Disable transitions */ +.no-transition { + -webkit-transition: none !important; + -moz-transition: none !important; + -o-transition: none !important; + transition: none !important; } \ No newline at end of file diff --git a/pydis_site/static/js/resources/resources.js b/pydis_site/static/js/resources/resources.js index 718e1e88..44d4db5c 100644 --- a/pydis_site/static/js/resources/resources.js +++ b/pydis_site/static/js/resources/resources.js @@ -178,7 +178,7 @@ document.addEventListener("DOMContentLoaded", function () { updateUI(); // If you collapse or uncollapse a filter group, swap the icon. - $('button.collapsible').click(function() { + $('button.collapsible').on("click", function() { let icon = $(this).find(".card-header-icon i"); if ($(icon).hasClass("fa-window-minimize")) { @@ -190,6 +190,17 @@ document.addEventListener("DOMContentLoaded", function () { } }); + // If this is a mobile device, collapse the categories to win back some screen real estate. + if (screen.width < 480) { + let categoryHeaders = $(".filter-category-header .collapsible-content"); + let icons = $('.filter-category-header button .card-header-icon i'); + categoryHeaders.addClass("no-transition"); + categoryHeaders.css("max-height", 0); + icons.removeClass(["far", "fa-window-minimize"]); + icons.addClass(["fas", "fa-angle-down"]); + categoryHeaders.removeClass("no-transition"); + } + // If you click on the div surrounding the filter checkbox, it clicks the corresponding checkbox. $('.filter-panel').click(function() { let checkbox = $(this).find(".filter-checkbox"); diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index 80577c2b..a7b25f5c 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -104,7 +104,7 @@ {% if filter_data.hidden %}
{% else %} -
+
{% endif %}
{% for filter_item in filter_data.filters %} -- cgit v1.2.3 From 8726a61b965988b30a7f28416a22d8c807177436 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Mon, 31 Jan 2022 11:51:55 +0100 Subject: Shrink and center the duck pond 404. --- pydis_site/static/css/resources/resources.css | 10 +++++----- pydis_site/static/images/resources/duck_pond_404.jpg | Bin 0 -> 123824 bytes pydis_site/static/images/resources/duck_pond_404.png | Bin 2371374 -> 0 bytes pydis_site/templates/resources/resources.html | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 pydis_site/static/images/resources/duck_pond_404.jpg delete mode 100644 pydis_site/static/images/resources/duck_pond_404.png (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index b24fcb5b..55284605 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -64,15 +64,15 @@ display: block; /* Center the 404 div */ .no-resources-found { - display: flex; + display: none; flex-direction: column; align-items: center; + margin-top: 1em; } -/* Hide the no resources h2 by default */ -.no-resources-found { - display: none; - margin-top: 1em; +/* Make sure jQuery will use flex when setting `show()` again. */ +.no-resources-found[style*='display: block'] { + display: flex !important; } /* Disable clicking on the checkbox itself. */ diff --git a/pydis_site/static/images/resources/duck_pond_404.jpg b/pydis_site/static/images/resources/duck_pond_404.jpg new file mode 100644 index 00000000..29bcf1d6 Binary files /dev/null and b/pydis_site/static/images/resources/duck_pond_404.jpg differ diff --git a/pydis_site/static/images/resources/duck_pond_404.png b/pydis_site/static/images/resources/duck_pond_404.png deleted file mode 100644 index 3aed4d62..00000000 Binary files a/pydis_site/static/images/resources/duck_pond_404.png and /dev/null differ diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index dcf520f6..2fb0f543 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -132,7 +132,7 @@ {# Message to display when there are no hits #}

No matching resources found!

- +
-- cgit v1.2.3 From 46702b73cc8a54409da633e4492846f72bb5a338 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Mon, 31 Jan 2022 12:07:04 +0100 Subject: Make the resource link icons a size smaller. We also add a little breathing room to the tag container, so that it doesn't encroach on the personal space of the icons. --- pydis_site/static/css/resources/resources.css | 5 +++++ pydis_site/templates/resources/resource_box.html | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index 55284605..3b235a05 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -111,6 +111,11 @@ span.filter-box-tag[style*='display: block'] { user-select: none; } +/* Give the resource tags a bit of breathing room */ +.resource-tag-container { + padding-left: 1.5rem; +} + /* When hovering tags, brighten them a bit. */ .resource-tag:hover, .filter-box-tag:hover { diff --git a/pydis_site/templates/resources/resource_box.html b/pydis_site/templates/resources/resource_box.html index 8f634333..0ba8b0ec 100644 --- a/pydis_site/templates/resources/resource_box.html +++ b/pydis_site/templates/resources/resource_box.html @@ -16,24 +16,24 @@
{# Add primary link #} {% if 'title_url' in resource %} - + - + {% endif %} {# Add all additional icon #} {% for icon in resource.urls %} - + - + {% endfor %} {# Tags #} -
+
{% for tag in resource.tags.topics %} Date: Mon, 31 Jan 2022 12:20:40 +0100 Subject: Indent checkboxes under the headers. --- pydis_site/static/css/resources/resources.css | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index 3b235a05..2465e9dc 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -62,6 +62,17 @@ display: block; border-radius: 0; } +/* Make the checkboxes indent under the filter headers */ +.filter-category-header .card-header .card-header-title { + padding-left: 0; +} +.filter-panel { + padding-left: 1.5rem; +} +.filter-checkbox { + margin-right: 0.25em !important; +} + /* Center the 404 div */ .no-resources-found { display: none; -- cgit v1.2.3 From 98ac8a963bc196e49b60899080b94bacc29f04e1 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Mon, 31 Jan 2022 16:05:13 +0100 Subject: Added margins and max-width to filtering column. --- pydis_site/static/css/resources/resources.css | 20 ++++++++++++++------ pydis_site/templates/resources/resources.html | 4 ++-- 2 files changed, 16 insertions(+), 8 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index 2465e9dc..26ddc14e 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -163,6 +163,14 @@ span.resource-tag.active { outline-style: solid; } +/* Disable transitions */ +.no-transition { + -webkit-transition: none !important; + -moz-transition: none !important; + -o-transition: none !important; + transition: none !important; +} + /* Make filter tags sparkle when selected! */ @keyframes glow_success { from { box-shadow: 0 0 2px 2px #aef4af; } @@ -216,10 +224,10 @@ span.resource-tag.active.has-background-info-light { } } -/* Disable transitions */ -.no-transition { - -webkit-transition: none !important; - -moz-transition: none !important; - -o-transition: none !important; - transition: none !important; +/* Constrain the width of the filterbox */ +@media screen and (min-width: 769px) { + .filtering-column { + max-width: 25rem; + min-width: 18rem; + } } \ No newline at end of file diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index 2fb0f543..13bba1f2 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -17,9 +17,9 @@ {% include "base/navbar.html" %}
-
+
{# Filtering toolbox #} -
+
{% endblock %} - - -- cgit v1.2.3 From 24edd0ada26af34e946965d5692b6a35b7622ef9 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Mon, 31 Jan 2022 22:16:20 +0100 Subject: Add a button for removing all active filters. --- pydis_site/static/css/resources/resources.css | 21 ++++- pydis_site/static/js/resources/resources.js | 67 +++++++++------ pydis_site/templates/resources/resources.html | 118 ++++++++++++++------------ 3 files changed, 123 insertions(+), 83 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index 16226936..2fb3a9b5 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -97,12 +97,29 @@ i.is-primary { color: #7289da; } -/* A little space around the filter card, please! */ +/* A little space above the filter card, please! */ .filter-tags { padding-bottom: .5em; - padding-right: .5em; } +/* Style the close all filters button */ +.close-filters-button { + margin-left: auto; + display:none; +} +.close-filters-button a { + height: fit-content; + width: fit-content; + margin-right: 6px; +} +.close-filters-button a i { + color: #939bb3; +} +.close-filters-button a i:hover { + filter: brightness(115%); +} + + /* Set default display to inline-flex, for centering. */ span.filter-box-tag { display: none; diff --git a/pydis_site/static/js/resources/resources.js b/pydis_site/static/js/resources/resources.js index 0e951c38..8627a359 100644 --- a/pydis_site/static/js/resources/resources.js +++ b/pydis_site/static/js/resources/resources.js @@ -8,42 +8,33 @@ var activeFilters = { difficulty: [] }; +/* Add a filter, and update the UI */ function addFilter(filterName, filterItem) { - // Push the filter into the stack var filterIndex = activeFilters[filterName].indexOf(filterItem); if (filterIndex === -1) { activeFilters[filterName].push(filterItem); } updateUI(); +} - // Show a corresponding filter box tag - $(`.filter-box-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).show(); - - // Make corresponding resource tags active - $(`.resource-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).addClass("active"); - - // Hide the "No filters selected" tag. - $(".no-tags-selected.tag").hide(); +/* Remove all filters, and update the UI */ +function removeAllFilters() { + activeFilters = { + topics: [], + type: [], + "payment-tiers": [], + difficulty: [] + }; + updateUI(); } +/* Remove a filter, and update the UI */ function removeFilter(filterName, filterItem) { - // Remove the filter from the stack var filterIndex = activeFilters[filterName].indexOf(filterItem); if (filterIndex !== -1) { activeFilters[filterName].splice(filterIndex, 1); } updateUI(); - - // Hide the corresponding filter box tag - $(`.filter-box-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).hide(); - - // Make corresponding resource tags inactive - $(`.resource-tag[data-filter-name=${filterName}][data-filter-item=${filterItem}]`).removeClass("active"); - - // Show "No filters selected" tag, if there are no filters active - if (noFilters()) { - $(".no-tags-selected.tag").show(); - } } /* Check if there are no filters */ @@ -76,7 +67,7 @@ function deserializeURLParams() { window.location.href = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"; } else if (String(filter) === "sneakers" && filterType === "topics") { window.location.href = "https://www.youtube.com/watch?v=NNZscmNE9QI"; - } else if (validFilters[filterType].includes(String(filter))) { + } else if (validFilters.hasOwnProperty(filterType) && validFilters[filterType].includes(String(filter))) { let checkbox = $(`.filter-checkbox[data-filter-name='${filterType}'][data-filter-item='${filter}']`); let filterTag = $(`.filter-box-tag[data-filter-name='${filterType}'][data-filter-item='${filter}']`); let resourceTags = $(`.resource-tag[data-filter-name='${filterType}'][data-filter-item='${filter}']`); @@ -91,9 +82,10 @@ function deserializeURLParams() { // Ditch all the params from the URL, and recalculate the URL params updateURL(); - // If we've added a filter, hide the no filters tag. + // If we've added a filter, hide stuff if (filterAdded) { $(".no-tags-selected.tag").hide(); + $(".close-filters-button").show(); } } }); @@ -123,15 +115,36 @@ function updateURL() { function updateUI() { let resources = $('.resource-box'); let filterTags = $('.filter-box-tag'); + let noTagsSelected = $(".no-tags-selected.tag"); + let closeFiltersButton = $(".close-filters-button"); // Update the URL to match the new filters. updateURL(); - // If there's nothing in the filters, show everything and return. + // If there's nothing in the filters, we can return early. if (noFilters()) { resources.show(); filterTags.hide(); + noTagsSelected.show(); + closeFiltersButton.hide(); + $(`.filter-checkbox:checked`).prop("checked", false) return; + } else { + $.each(activeFilters, function(filterType, filters) { + $.each(filters, function(index, filter) { + // Show a corresponding filter box tag + $(`.filter-box-tag[data-filter-name=${filterType}][data-filter-item=${filter}]`).show(); + + // Make corresponding resource tags active + $(`.resource-tag[data-filter-name=${filterType}][data-filter-item=${filter}]`).addClass("active"); + + // Hide the "No filters selected" tag. + noTagsSelected.hide(); + + // Show the close filters button + closeFiltersButton.show(); + }); + }); } // Otherwise, hide everything and then filter the resources to decide what to show. @@ -147,7 +160,6 @@ function updateUI() { let resourceBox = $(this); // Validate the filters - $.each(activeFilters, function(filterType, filters) { // If the filter list is empty, this passes validation. if (filters.length === 0) { @@ -256,6 +268,11 @@ document.addEventListener("DOMContentLoaded", function () { } }); + // When you click the little gray x, remove all filters. + $(".close-filters-button").on("click", function() { + removeAllFilters(); + }); + // When checkboxes are toggled, trigger a filter update. $('.filter-checkbox').on("change", function (event) { let filterItem = this.dataset.filterItem; diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index 4b7e9040..cebaace2 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -31,64 +31,70 @@ {# Filter box tags #}
-
- {# A little x in the top right, visible only when filters are active, which removes all filters. #} - - - {# A filter tag for when there are no filters active #} - - - No filters selected - +
+
+ {# A filter tag for when there are no filters active #} + + + No filters selected + - {% for filter_name, filter_data in filters.items %} - {% for filter_item in filter_data.filters %} - {% if filter_name == "Difficulty" %} - - - {{ filter_item|title }} - - - {% endif %} - {% if filter_name == "Type" %} - - - {{ filter_item|title }} - - - {% endif %} - {% if filter_name == "Payment tiers" %} - - - {{ filter_item|title }} - - - {% endif %} - {% if filter_name == "Topics" %} - - - {{ filter_item|title }} - - - {% endif %} + {% for filter_name, filter_data in filters.items %} + {% for filter_item in filter_data.filters %} + {% if filter_name == "Difficulty" %} + + + {{ filter_item|title }} + + + {% endif %} + {% if filter_name == "Type" %} + + + {{ filter_item|title }} + + + {% endif %} + {% if filter_name == "Payment tiers" %} + + + {{ filter_item|title }} + + + {% endif %} + {% if filter_name == "Topics" %} + + + {{ filter_item|title }} + + + {% endif %} + {% endfor %} {% endfor %} - {% endfor %} +
+
+ {# A little x in the top right, visible only when filters are active, which removes all filters. #} + + + + +
-- cgit v1.2.3 From 4dfde7fbf09a38134e997abe5b2b7ebe08fc0538 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Tue, 1 Feb 2022 01:18:57 +0100 Subject: Make resource tags correctly deactivate. --- pydis_site/static/js/resources/resources.js | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'pydis_site/static') diff --git a/pydis_site/static/js/resources/resources.js b/pydis_site/static/js/resources/resources.js index 8627a359..bffb5e91 100644 --- a/pydis_site/static/js/resources/resources.js +++ b/pydis_site/static/js/resources/resources.js @@ -115,6 +115,7 @@ function updateURL() { function updateUI() { let resources = $('.resource-box'); let filterTags = $('.filter-box-tag'); + let resourceTags = $('.resource-tag'); let noTagsSelected = $(".no-tags-selected.tag"); let closeFiltersButton = $(".close-filters-button"); @@ -127,9 +128,17 @@ function updateUI() { filterTags.hide(); noTagsSelected.show(); closeFiltersButton.hide(); + resourceTags.removeClass("active"); $(`.filter-checkbox:checked`).prop("checked", false) return; } else { + // Hide everything + $('.filter-box-tag').hide(); + $('.resource-tag').removeClass("active"); + noTagsSelected.show(); + closeFiltersButton.hide(); + + // Now conditionally show the stuff we want $.each(activeFilters, function(filterType, filters) { $.each(filters, function(index, filter) { // Show a corresponding filter box tag -- cgit v1.2.3 From 3c92f66890a67a19ba082acd50ebcd2df311f305 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Tue, 1 Feb 2022 01:21:21 +0100 Subject: When hovering titles, make them light, not black. --- pydis_site/static/css/resources/resources.css | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/resources/resources.css b/pydis_site/static/css/resources/resources.css index 2fb3a9b5..b8456e38 100644 --- a/pydis_site/static/css/resources/resources.css +++ b/pydis_site/static/css/resources/resources.css @@ -119,6 +119,12 @@ i.is-primary { filter: brightness(115%); } +/* When hovering title anchors, just make the color a lighter primary, not black. */ +.resource-box a:hover { + filter: brightness(120%); + color: #7289DA; +} + /* Set default display to inline-flex, for centering. */ span.filter-box-tag { -- cgit v1.2.3 From d31340f8abeabc5df1c778d7d8eae4d0806fad0e Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Tue, 1 Feb 2022 02:13:34 +0100 Subject: Fix bug where transition wouldn't work on first collapse. --- pydis_site/static/css/collapsibles.css | 6 +++++- pydis_site/static/js/collapsibles.js | 6 +----- pydis_site/static/js/resources/resources.js | 7 ++++--- pydis_site/templates/resources/resources.html | 4 ++-- 4 files changed, 12 insertions(+), 11 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/collapsibles.css b/pydis_site/static/css/collapsibles.css index 8fdd1f12..d35e77ea 100644 --- a/pydis_site/static/css/collapsibles.css +++ b/pydis_site/static/css/collapsibles.css @@ -6,7 +6,11 @@ } .collapsible-content { + max-height: 40em; + transition: max-height 0.3s ease-out; +} + +.collapsible-content.collapsed { overflow: hidden; max-height: 0; - transition: max-height 0.2s ease-out; } diff --git a/pydis_site/static/js/collapsibles.js b/pydis_site/static/js/collapsibles.js index 366a033c..d12d9f86 100644 --- a/pydis_site/static/js/collapsibles.js +++ b/pydis_site/static/js/collapsibles.js @@ -3,11 +3,7 @@ document.addEventListener("DOMContentLoaded", () => { for (const header of headers) { header.addEventListener("click", () => { var content = header.nextElementSibling; - if (content.style.maxHeight){ - content.style.maxHeight = null; - } else { - content.style.maxHeight = content.scrollHeight + "px"; - } + content.classList.toggle('collapsed'); }); } }); diff --git a/pydis_site/static/js/resources/resources.js b/pydis_site/static/js/resources/resources.js index bffb5e91..00bc6ad8 100644 --- a/pydis_site/static/js/resources/resources.js +++ b/pydis_site/static/js/resources/resources.js @@ -234,11 +234,12 @@ document.addEventListener("DOMContentLoaded", function () { if (screen.width < 480) { let categoryHeaders = $(".filter-category-header .collapsible-content"); let icons = $('.filter-category-header button .card-header-icon i'); - categoryHeaders.addClass("no-transition"); - categoryHeaders.css("max-height", ""); + categoryHeaders.addClass("no-transition collapsed"); icons.removeClass(["far", "fa-window-minimize"]); icons.addClass(["fas", "fa-angle-down"]); - categoryHeaders.removeClass("no-transition"); + + // Wait 10ms before removing this class, or else the transition will animate due to a race condition. + setTimeout(() => { categoryHeaders.removeClass("no-transition"); }, 10); } // If you click on the div surrounding the filter checkbox, it clicks the corresponding checkbox. diff --git a/pydis_site/templates/resources/resources.html b/pydis_site/templates/resources/resources.html index cebaace2..c221c8a3 100644 --- a/pydis_site/templates/resources/resources.html +++ b/pydis_site/templates/resources/resources.html @@ -116,9 +116,9 @@ {# Checkboxes #} {% if filter_data.hidden %} -
+