diff --git a/assets/javascripts/discourse/controllers/docs-index.js.es6 b/assets/javascripts/discourse/controllers/docs-index.js.es6 index d1734f4..9cf09d1 100644 --- a/assets/javascripts/discourse/controllers/docs-index.js.es6 +++ b/assets/javascripts/discourse/controllers/docs-index.js.es6 @@ -1,10 +1,12 @@ import Controller, { inject as controller } from "@ember/controller"; import discourseComputed, { on } from "discourse-common/utils/decorators"; import { action } from "@ember/object"; -import { alias, equal, readOnly } from "@ember/object/computed"; +import { alias, equal, gt, readOnly } from "@ember/object/computed"; import Docs from "discourse/plugins/discourse-docs/discourse/models/docs"; import { getOwner } from "@ember/application"; +const SHOW_FILTER_AT = 10; + export default Controller.extend({ queryParams: { ascending: "ascending", @@ -31,6 +33,14 @@ export default Controller.extend({ ascending: null, orderColumn: null, + showCategoryFilter: gt("categories.length", SHOW_FILTER_AT), + categoryFilter: "", + categorySort: {}, + + showTagFilter: gt("tags.length", SHOW_FILTER_AT), + tagFilter: "", + tagSort: {}, + loadMoreUrl: alias("model.topics.load_more_url"), categories: readOnly("model.categories"), topics: alias("model.topics.topic_list.topics"), @@ -43,6 +53,106 @@ export default Controller.extend({ if (!this.site.mobileView) { this.set("expandedFilters", true); } + this.setProperties({ + categorySort: { + type: "numeric", // or alpha + direction: "desc", // or asc + }, + tagSort: { + type: "numeric", // or alpha + direction: "desc", // or asc + }, + }); + }, + @discourseComputed("categories", "categorySort", "categoryFilter") + sortedCategories(categories, categorySort, filter) { + let { type, direction } = categorySort; + if (type === "numeric") { + categories = categories.sort((a, b) => a.count - b.count); + } else { + categories = categories.sort((a, b) => { + const first = this.site.categories + .findBy("id", a.id) + .name.toLowerCase(), + second = this.site.categories.findBy("id", b.id).name.toLowerCase(); + return first.localeCompare(second); + }); + } + + if (direction === "desc") { + categories = categories.reverse(); + } + + if (this.showCategoryFilter) { + return categories.filter((category) => { + let categoryData = this.site.categories.findBy("id", category.id); + return ( + categoryData.name.toLowerCase().indexOf(filter.toLowerCase()) > -1 || + (categoryData.description_excerpt && + categoryData.description_excerpt + .toLowerCase() + .indexOf(filter.toLowerCase()) > -1) + ); + }); + } + + return categories; + }, + + @discourseComputed("categorySort") + categorySortNumericIcon(catSort) { + if (catSort.type === "numeric" && catSort.direction === "asc") { + return "sort-numeric-down"; + } + return "sort-numeric-up"; + }, + + @discourseComputed("categorySort") + categorySortAlphaIcon(catSort) { + if (catSort.type === "alpha" && catSort.direction === "asc") { + return "sort-alpha-down"; + } + return "sort-alpha-up"; + }, + + @discourseComputed("tags", "tagSort", "tagFilter") + sortedTags(tags, tagSort, filter) { + let { type, direction } = tagSort; + if (type === "numeric") { + tags = tags.sort((a, b) => a.count - b.count); + } else { + tags = tags.sort((a, b) => { + return a.id.toLowerCase().localeCompare(b.id.toLowerCase()); + }); + } + + if (direction === "desc") { + tags = tags.reverse(); + } + + if (this.showTagFilter) { + return tags.filter((tag) => { + return tag.id.toLowerCase().indexOf(filter.toLowerCase()) > -1; + }); + } + + return tags; + }, + + @discourseComputed("tagSort") + tagSortNumericIcon(tagSort) { + if (tagSort.type === "numeric" && tagSort.direction === "asc") { + return "sort-numeric-down"; + } + return "sort-numeric-up"; + }, + + @discourseComputed("tagSort") + tagSortAlphaIcon(tagSort) { + if (tagSort.type === "alpha" && tagSort.direction === "asc") { + return "sort-alpha-down"; + } + return "sort-alpha-up"; }, @discourseComputed("topics", "isSearching", "filterSolved") @@ -79,6 +189,31 @@ export default Controller.extend({ return !!filterTags; }, + @discourseComputed() + shouldShowTags() { + return this.siteSettings.tagging_enabled; + }, + + @action + toggleCategorySort(newType) { + let { type, direction } = this.categorySort; + this.set("categorySort", { + type: newType, + direction: + type === newType ? (direction === "asc" ? "desc" : "asc") : "asc", + }); + }, + + @action + toggleTagSort(newType) { + let { type, direction } = this.tagSort; + this.set("tagSort", { + type: newType, + direction: + type === newType ? (direction === "asc" ? "desc" : "asc") : "asc", + }); + }, + @action setSelectedTopic(topicId) { this.set("selectedTopic", topicId); diff --git a/assets/javascripts/discourse/templates/docs-index.hbs b/assets/javascripts/discourse/templates/docs-index.hbs index 3e67577..fce03c5 100644 --- a/assets/javascripts/discourse/templates/docs-index.hbs +++ b/assets/javascripts/discourse/templates/docs-index.hbs @@ -26,25 +26,59 @@ {{#if categories}}
-

{{i18n "docs.categories"}}

- {{#each categories as |category|}} - {{docs-category - category=category - selectCategory=(action "updateSelectedCategories" category) +
+

{{i18n "docs.categories"}}

+
+ {{d-button class=(if (eq categorySort.type "alpha") "categories-alphabet active" "categories-alphabet") icon=categorySortAlphaIcon action=toggleCategorySort actionParam="alpha"}} + {{d-button class=(if (eq categorySort.type "numeric") "categories-amount active" "categories-amount") icon=categorySortNumericIcon action=toggleCategorySort actionParam="numeric"}} +
+
+ {{#if showCategoryFilter}} + {{input + value=categoryFilter + class="filter" + placeholderKey="docs.categories_filter_placeholder" }} - {{/each}} + {{/if}} +
{{/if}} - {{#if tags}} + {{#if (and tags shouldShowTags)}}
-

{{i18n "docs.tags"}}

- {{#each tags as |tag|}} - {{docs-tag - tag=tag - selectTag=(action "updateSelectedTags" tag) +
+

{{i18n "docs.tags"}}

+
+ {{d-button class=(if (eq tagSort.type "alpha") "tags-alphabet active" "tags-alphabet") icon=tagSortAlphaIcon action=toggleTagSort actionParam="alpha"}} + {{d-button class=(if (eq tagSort.type "numeric") "tags-amount active" "tags-amount") icon=tagSortNumericIcon action=toggleTagSort actionParam="numeric"}} +
+
+ {{#if showTagFilter}} + {{input + value=tagFilter + class="filter" + placeholderKey="docs.tags_filter_placeholder" }} - {{/each}} + {{/if}} +
{{/if}} {{/if}} diff --git a/assets/stylesheets/common/docs.scss b/assets/stylesheets/common/docs.scss index 80b80bf..74d9b0e 100644 --- a/assets/stylesheets/common/docs.scss +++ b/assets/stylesheets/common/docs.scss @@ -75,7 +75,6 @@ } h3 { - padding-left: 0.35em; font-size: $font-up-1; } @@ -203,3 +202,35 @@ } } } + +.docs-items { + .item-controls { + display: flex; + justify-content: space-between; + .btn { + background-color: transparent; + padding: 0.25em; + svg { + color: var(--primary-high); + } + &:hover, + &.active { + background-color: var(--secondary-very-high); + svg { + color: var(--primary-high); + } + } + height: 28px; + } + } +} + +.docs-items { + input { + width: 100%; + } + ul { + margin: 0; + list-style: none; + } +} diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 192d5a3..a18470f 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -10,6 +10,8 @@ en: activity: "Activity" no_topics: "No topics in Docs." categories: "Categories" + categories_filter_placeholder: "Filter categories" + tags_filter_placeholder: "Filter tags" tags: "Tags" search: results: diff --git a/plugin.rb b/plugin.rb index 3ab8835..d282600 100644 --- a/plugin.rb +++ b/plugin.rb @@ -11,6 +11,11 @@ enabled_site_setting :docs_enabled register_asset 'stylesheets/common/docs.scss' register_asset 'stylesheets/mobile/docs.scss' +register_svg_icon 'sort-alpha-down' +register_svg_icon 'sort-alpha-up' +register_svg_icon 'sort-numeric-up' +register_svg_icon 'sort-numeric-down' + load File.expand_path('lib/docs/engine.rb', __dir__) load File.expand_path('lib/docs/query.rb', __dir__) diff --git a/test/javascripts/acceptance/docs-test.js.es6 b/test/javascripts/acceptance/docs-test.js.es6 index e310c80..8cef7e3 100644 --- a/test/javascripts/acceptance/docs-test.js.es6 +++ b/test/javascripts/acceptance/docs-test.js.es6 @@ -30,6 +30,8 @@ acceptance("Docs", function (needs) { }); test("index page", async function (assert) { + this.siteSettings.tagging_enabled = true; + await visit("/"); await click("#toggle-hamburger-menu"); await click(".docs-link");