From cf8b81771f036374cb6034476a178c3332e2dea8 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Wed, 8 May 2024 09:08:42 +0200 Subject: [PATCH] DEV: implements (#26917) DropdownMenu component is meant as a way to describe the content of menus. Syntax: ``` First Second ``` --- .../app/components/admin-post-menu.gjs | 61 +-- .../app/components/bookmark-menu.gjs | 103 ++-- .../bulk-select-topics-dropdown.gjs} | 91 ++-- .../app/components/dropdown-menu.gjs | 17 + .../app/components/topic-admin-menu.gjs | 448 +++++++++--------- .../discourse/app/lib/plugin-api.gjs | 2 +- .../raw-views/topic-bulk-select-dropdown.gjs | 2 +- .../discourse/app/widgets/post-menu.js | 2 +- .../components/dropdown-menu-test.gjs | 37 ++ .../addon/components/d-inline-float.gjs | 6 + .../float-kit/addon/components/d-menu.gjs | 2 + .../stylesheets/common/components/_index.scss | 2 +- .../common/components/admin-post-menu.scss | 32 -- .../common/components/bookmark-menu.scss | 22 +- .../common/components/dropdown-menu.scss | 17 + .../stylesheets/mobile/components/_index.scss | 1 + .../mobile/components/bookmark-menu.scss | 11 - .../mobile/components/dropdown-menu.scss | 7 + .../page_objects/components/bookmark_menu.rb | 2 +- .../components/topic_list_header.rb | 8 +- spec/system/topic_page_spec.rb | 6 +- 21 files changed, 468 insertions(+), 411 deletions(-) rename app/assets/javascripts/{select-kit/addon/components/bulk-select-topics-dropdown.js => discourse/app/components/bulk-select-topics-dropdown.gjs} (77%) create mode 100644 app/assets/javascripts/discourse/app/components/dropdown-menu.gjs create mode 100644 app/assets/javascripts/discourse/tests/integration/components/dropdown-menu-test.gjs delete mode 100644 app/assets/stylesheets/common/components/admin-post-menu.scss create mode 100644 app/assets/stylesheets/common/components/dropdown-menu.scss create mode 100644 app/assets/stylesheets/mobile/components/dropdown-menu.scss diff --git a/app/assets/javascripts/discourse/app/components/admin-post-menu.gjs b/app/assets/javascripts/discourse/app/components/admin-post-menu.gjs index e5686a1f70e..34b51653dc9 100644 --- a/app/assets/javascripts/discourse/app/components/admin-post-menu.gjs +++ b/app/assets/javascripts/discourse/app/components/admin-post-menu.gjs @@ -4,6 +4,7 @@ import { action } from "@ember/object"; import { service } from "@ember/service"; import { and, not, or } from "truth-helpers"; import DButton from "discourse/components/d-button"; +import DropdownMenu from "discourse/components/dropdown-menu"; import concatClass from "discourse/helpers/concat-class"; export default class AdminPostMenu extends Component { @@ -46,20 +47,20 @@ export default class AdminPostMenu extends Component { } } diff --git a/app/assets/javascripts/discourse/app/components/bookmark-menu.gjs b/app/assets/javascripts/discourse/app/components/bookmark-menu.gjs index ed16c77d838..0d1233f6f01 100644 --- a/app/assets/javascripts/discourse/app/components/bookmark-menu.gjs +++ b/app/assets/javascripts/discourse/app/components/bookmark-menu.gjs @@ -5,6 +5,7 @@ import { action } from "@ember/object"; import didInsert from "@ember/render-modifiers/modifiers/did-insert"; import { inject as service } from "@ember/service"; import DButton from "discourse/components/d-button"; +import DropdownMenu from "discourse/components/dropdown-menu"; import BookmarkModal from "discourse/components/modal/bookmark"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { @@ -249,65 +250,69 @@ export default class BookmarkMenu extends Component { @arrow={{false}} > <:content> -
- + {{#unless this.showEditDeleteMenu}} -
{{icon "check-circle"}}{{i18n "bookmarks.bookmarked_success"}} -
+ + {{icon "check-circle"}} + {{i18n "bookmarks.bookmarked_success"}} + {{/unless}} {{#if this.showEditDeleteMenu}} {{#if this.site.mobileView}} -
{{icon "bookmark"}}{{i18n - "bookmarks.bookmark" - }} -
+ + {{icon "bookmark"}} + {{i18n "bookmarks.bookmark"}} + {{/if}} -
    -
  • - -
  • -
  • + + + + + + + {{else}} + + {{i18n "bookmarks.also_set_reminder"}} + + + + + {{#each this.reminderAtOptions as |option|}} + -
  • -
- {{else}} - {{i18n - "bookmarks.also_set_reminder" - }} -
    - {{#each this.reminderAtOptions as |option|}} -
  • - -
  • - {{/each}} -
+ + {{/each}} {{/if}} -
+
diff --git a/app/assets/javascripts/select-kit/addon/components/bulk-select-topics-dropdown.js b/app/assets/javascripts/discourse/app/components/bulk-select-topics-dropdown.gjs similarity index 77% rename from app/assets/javascripts/select-kit/addon/components/bulk-select-topics-dropdown.js rename to app/assets/javascripts/discourse/app/components/bulk-select-topics-dropdown.gjs index 75b224546a4..2572d04617f 100644 --- a/app/assets/javascripts/select-kit/addon/components/bulk-select-topics-dropdown.js +++ b/app/assets/javascripts/discourse/app/components/bulk-select-topics-dropdown.gjs @@ -1,22 +1,29 @@ +import Component from "@glimmer/component"; +import { fn } from "@ember/helper"; import { action } from "@ember/object"; import { service } from "@ember/service"; +import DButton from "discourse/components/d-button"; +import DropdownMenu from "discourse/components/dropdown-menu"; import BulkTopicActions, { addBulkDropdownAction, } from "discourse/components/modal/bulk-topic-actions"; +import concatClass from "discourse/helpers/concat-class"; +import icon from "discourse-common/helpers/d-icon"; import i18n from "discourse-common/helpers/i18n"; -import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box"; +import DMenu from "float-kit/components/d-menu"; const _customButtons = []; const _customOnSelection = {}; export function addBulkDropdownButton(opts) { _customButtons.push({ - id: opts.label, + id: opts.id, icon: opts.icon, name: i18n(opts.label), visible: opts.visible, + class: opts.class, }); - addBulkDropdownAction(opts.label, opts.action); + addBulkDropdownAction(opts.id, opts.action); const actionOpts = { label: opts.label, setComponent: true, @@ -24,27 +31,17 @@ export function addBulkDropdownButton(opts) { if (opts.actionType === "performAndRefresh") { actionOpts.setComponent = false; } - _customOnSelection[opts.label] = actionOpts; + _customOnSelection[opts.id] = actionOpts; } -export default DropdownSelectBoxComponent.extend({ - classNames: ["bulk-select-topics-dropdown"], - headerIcon: null, - showFullTitle: true, - selectKitOptions: { - showCaret: true, - showFullTitle: true, - none: "select_kit.components.bulk_select_topics_dropdown.title", - }, +export default class BulkSelectTopicsDropdown extends Component { + @service modal; + @service router; + @service currentUser; + @service siteSettings; - modal: service(), - router: service(), - currentUser: service(), - siteSettings: service(), - - computeContent() { - let options = []; - options = options.concat([ + get buttons() { + let options = [ { id: "update-category", icon: "pencil-alt", @@ -119,12 +116,12 @@ export default DropdownSelectBoxComponent.extend({ name: i18n("topic_bulk_actions.delete_topics.name"), visible: ({ currentUser }) => currentUser.staff, }, - ]); + ]; return [...options, ..._customButtons].filter(({ visible }) => { if (visible) { return visible({ - topics: this.bulkSelectHelper.selected, + topics: this.args.bulkSelectHelper.selected, currentUser: this.currentUser, siteSettings: this.siteSettings, }); @@ -132,7 +129,7 @@ export default DropdownSelectBoxComponent.extend({ return true; } }); - }, + } showBulkTopicActionsModal(actionName, title, opts = {}) { let allowSilent = false; @@ -160,14 +157,14 @@ export default DropdownSelectBoxComponent.extend({ action: actionName, title, description, - bulkSelectHelper: this.bulkSelectHelper, + bulkSelectHelper: this.args.bulkSelectHelper, refreshClosure: () => this.router.refresh(), allowSilent, initialAction, initialActionLabel, }, }); - }, + } @action onSelect(id) { @@ -228,5 +225,43 @@ export default DropdownSelectBoxComponent.extend({ }); } } - }, -}); + + this.dMenu.close(); + } + + @action + onRegisterApi(api) { + this.dMenu = api; + } + + +} diff --git a/app/assets/javascripts/discourse/app/components/dropdown-menu.gjs b/app/assets/javascripts/discourse/app/components/dropdown-menu.gjs new file mode 100644 index 00000000000..f96bbd20054 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/dropdown-menu.gjs @@ -0,0 +1,17 @@ +import { hash } from "@ember/helper"; + +const DropdownItem = ; + +const DropdownDivider = ; + +const DropdownMenu = ; + +export default DropdownMenu; diff --git a/app/assets/javascripts/discourse/app/components/topic-admin-menu.gjs b/app/assets/javascripts/discourse/app/components/topic-admin-menu.gjs index d6321738cde..511a57b4c2f 100644 --- a/app/assets/javascripts/discourse/app/components/topic-admin-menu.gjs +++ b/app/assets/javascripts/discourse/app/components/topic-admin-menu.gjs @@ -4,6 +4,7 @@ import { action } from "@ember/object"; import { inject as service } from "@ember/service"; import { and, not, or } from "truth-helpers"; import DButton from "discourse/components/d-button"; +import DropdownMenu from "discourse/components/dropdown-menu"; import concatClass from "discourse/helpers/concat-class"; import icon from "discourse-common/helpers/d-icon"; import getURL from "discourse-common/lib/get-url"; @@ -85,249 +86,230 @@ export default class TopicAdminMenu extends Component { <:trigger> {{icon "wrench"}} <:content> - + {{/if}} + + {{#if this.details.can_close_topic}} + + + + {{/if}} + + {{#if + (and + this.details.can_pin_unpin_topic + (not this.isPrivateMessage) + (or this.visible this.featured) + ) + }} + + + + {{/if}} + + {{#if + (and + this.details.can_archive_topic (not this.isPrivateMessage) + ) + }} + + + + {{/if}} + + {{#if this.details.can_toggle_topic_visibility}} + + + + {{/if}} + + {{#if (and this.details.can_convert_topic)}} + + + + {{/if}} + + + + {{#if this.currentUser.canManageTopic}} + + + + + {{#if this.currentUser.staff}} + + + + {{/if}} + + + + + + + + + + + {{/if}} + + {{#if (or this.currentUser.staff this.extraButtons.length)}} + {{#if this.currentUser.staff}} + + + + {{/if}} + + {{#each this.extraButtons as |button|}} + + + + {{/each}} + {{/if}} + diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.gjs b/app/assets/javascripts/discourse/app/lib/plugin-api.gjs index efee20a9dd9..9dbcff62e0b 100644 --- a/app/assets/javascripts/discourse/app/lib/plugin-api.gjs +++ b/app/assets/javascripts/discourse/app/lib/plugin-api.gjs @@ -1,5 +1,6 @@ import $ from "jquery"; import { h } from "virtual-dom"; +import { addBulkDropdownButton } from "discourse/components/bulk-select-topics-dropdown"; import { addApiImageWrapperButtonClickEvent, addComposerUploadHandler, @@ -141,7 +142,6 @@ import { replaceIcon, } from "discourse-common/lib/icon-library"; import { addImageWrapperButton } from "discourse-markdown-it/features/image-controls"; -import { addBulkDropdownButton } from "select-kit/components/bulk-select-topics-dropdown"; import { CUSTOM_USER_SEARCH_OPTIONS } from "select-kit/components/user-chooser"; import { modifySelectKit } from "select-kit/mixins/plugin-api"; diff --git a/app/assets/javascripts/discourse/app/raw-views/topic-bulk-select-dropdown.gjs b/app/assets/javascripts/discourse/app/raw-views/topic-bulk-select-dropdown.gjs index 8bdf82b6d0c..177224eaf73 100644 --- a/app/assets/javascripts/discourse/app/raw-views/topic-bulk-select-dropdown.gjs +++ b/app/assets/javascripts/discourse/app/raw-views/topic-bulk-select-dropdown.gjs @@ -1,7 +1,7 @@ import EmberObject from "@ember/object"; +import BulkSelectTopicsDropdown from "discourse/components/bulk-select-topics-dropdown"; import rawRenderGlimmer from "discourse/lib/raw-render-glimmer"; import i18n from "discourse-common/helpers/i18n"; -import BulkSelectTopicsDropdown from "select-kit/components/bulk-select-topics-dropdown"; export default class extends EmberObject { get selectedCount() { diff --git a/app/assets/javascripts/discourse/app/widgets/post-menu.js b/app/assets/javascripts/discourse/app/widgets/post-menu.js index 50c227304ed..5d09ed13db5 100644 --- a/app/assets/javascripts/discourse/app/widgets/post-menu.js +++ b/app/assets/javascripts/discourse/app/widgets/post-menu.js @@ -827,8 +827,8 @@ export default createWidget("post-menu", { this.menu.show(event.target, { identifier: "admin-post-menu", component: AdminPostMenu, - extraClassName: "popup-menu", modalForMobile: true, + autofocus: true, data: { scheduleRerender: this.scheduleRerender.bind(this), transformedPost: this.attrs, diff --git a/app/assets/javascripts/discourse/tests/integration/components/dropdown-menu-test.gjs b/app/assets/javascripts/discourse/tests/integration/components/dropdown-menu-test.gjs new file mode 100644 index 00000000000..e7524646d26 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/dropdown-menu-test.gjs @@ -0,0 +1,37 @@ +import { render } from "@ember/test-helpers"; +import { module, test } from "qunit"; +import DropdownMenu from "discourse/components/dropdown-menu"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; + +module("Integration | Component | ", function (hooks) { + setupRenderingTest(hooks); + + test("dropdown menu", async function (assert) { + await render(); + + assert + .dom("ul.dropdown-menu.test") + .exists("it renders the dropdown menu with custom class"); + }); + + test("dropdown menu item", async function (assert) { + await render(); + + assert + .dom("li.dropdown-menu__item.test") + .exists("it renders the item with custom class") + .hasText("test"); + }); + + test("dropdown menu divider", async function (assert) { + await render(); + + assert + .dom("li.test hr.dropdown-menu__divider") + .exists("it renders the divider with custom class"); + }); +}); diff --git a/app/assets/javascripts/float-kit/addon/components/d-inline-float.gjs b/app/assets/javascripts/float-kit/addon/components/d-inline-float.gjs index 032353a56bc..d56fbbf7287 100644 --- a/app/assets/javascripts/float-kit/addon/components/d-inline-float.gjs +++ b/app/assets/javascripts/float-kit/addon/components/d-inline-float.gjs @@ -1,7 +1,9 @@ import Component from "@glimmer/component"; +import { concat } from "@ember/helper"; import { inject as service } from "@ember/service"; import { and } from "truth-helpers"; import DModal from "discourse/components/d-modal"; +import concatClass from "discourse/helpers/concat-class"; import DFloatBody from "float-kit/components/d-float-body"; export default class DInlineFloat extends Component { @@ -15,6 +17,10 @@ export default class DInlineFloat extends Component { @hideHeader={{true}} data-identifier={{@instance.options.identifier}} data-content + class={{concatClass + "fk-d-menu-modal" + (concat @instance.options.identifier "-content") + }} > {{#if @instance.options.component}} <@instance.options.component diff --git a/app/assets/javascripts/float-kit/addon/components/d-menu.gjs b/app/assets/javascripts/float-kit/addon/components/d-menu.gjs index 81c86d82b28..689bf90728a 100644 --- a/app/assets/javascripts/float-kit/addon/components/d-menu.gjs +++ b/app/assets/javascripts/float-kit/addon/components/d-menu.gjs @@ -99,6 +99,8 @@ export default class DMenu extends Component { (concat this.options.identifier "-content") }} @inline={{(isTesting)}} + data-identifier={{@instance.options.identifier}} + data-content > {{#if (has-block)}} {{yield this.componentArgs}} diff --git a/app/assets/stylesheets/common/components/_index.scss b/app/assets/stylesheets/common/components/_index.scss index 0eb66bf6beb..d93c2f3c03c 100644 --- a/app/assets/stylesheets/common/components/_index.scss +++ b/app/assets/stylesheets/common/components/_index.scss @@ -48,4 +48,4 @@ @import "user-stream-item"; @import "user-stream"; @import "widget-dropdown"; -@import "admin-post-menu"; +@import "dropdown-menu"; diff --git a/app/assets/stylesheets/common/components/admin-post-menu.scss b/app/assets/stylesheets/common/components/admin-post-menu.scss deleted file mode 100644 index 3e1654ae0f9..00000000000 --- a/app/assets/stylesheets/common/components/admin-post-menu.scss +++ /dev/null @@ -1,32 +0,0 @@ -[data-content][data-identifier="admin-post-menu"] { - .d-modal__body { - padding: 0; - } - - ul { - padding: 0.5rem; - margin: 0; - list-style: none; - - li .btn { - width: 100%; - justify-content: flex-start; - } - - li { - margin-bottom: 2px; - border: none; - - &:last-child { - margin-bottom: 0; - } - } - - .btn { - justify-content: left; - text-align: left; - width: 100%; - padding: 0.5em; - } - } -} diff --git a/app/assets/stylesheets/common/components/bookmark-menu.scss b/app/assets/stylesheets/common/components/bookmark-menu.scss index 8359ca380da..8cbb1e6c947 100644 --- a/app/assets/stylesheets/common/components/bookmark-menu.scss +++ b/app/assets/stylesheets/common/components/bookmark-menu.scss @@ -1,22 +1,16 @@ .bookmark-menu-content { - .bookmark-menu__body { - background: var(--secondary); - display: flex; - flex-direction: column; + .dropdown-menu { + padding: 0; min-width: 200px; } - .bookmark-menu__actions { - margin: 0; - padding: 0; - list-style: none; - } + .bookmark-menu__title { display: flex; align-items: center; gap: 0.75em; background: var(--tertiary-low); color: var(--tertiary); - padding: 0.75rem; + padding: 0.75rem 1rem; font-weight: bold; .d-icon { @@ -25,7 +19,6 @@ } .bookmark-menu__row { - width: 100%; display: flex; &:hover, @@ -39,19 +32,18 @@ } .bookmark-menu__row-title { - padding: 0.75rem; - border-bottom: 1px solid var(--primary-low); + padding: 0.75rem 1rem; font-weight: bold; } .bookmark-menu__row-btn { margin: 0; - padding: 0.75rem !important; width: 100%; text-align: left; justify-content: left !important; - gap: 0.75em; + gap: 0.75rem; color: var(--primary); + &:hover, &:focus { color: var(--primary) !important; diff --git a/app/assets/stylesheets/common/components/dropdown-menu.scss b/app/assets/stylesheets/common/components/dropdown-menu.scss new file mode 100644 index 00000000000..a0d2d5c9706 --- /dev/null +++ b/app/assets/stylesheets/common/components/dropdown-menu.scss @@ -0,0 +1,17 @@ +.dropdown-menu { + padding: 0; + margin: 0; + list-style: none; + + &__item { + .btn { + padding: 0.65rem 1rem; + width: 100%; + justify-content: flex-start; + } + } + + &__divider { + margin: 0rem; + } +} diff --git a/app/assets/stylesheets/mobile/components/_index.scss b/app/assets/stylesheets/mobile/components/_index.scss index e0dad903fe9..4666a0f8798 100644 --- a/app/assets/stylesheets/mobile/components/_index.scss +++ b/app/assets/stylesheets/mobile/components/_index.scss @@ -3,3 +3,4 @@ @import "user-stream-item"; @import "more-topics"; @import "bookmark-menu"; +@import "dropdown-menu"; diff --git a/app/assets/stylesheets/mobile/components/bookmark-menu.scss b/app/assets/stylesheets/mobile/components/bookmark-menu.scss index 566163bb6f8..e69de29bb2d 100644 --- a/app/assets/stylesheets/mobile/components/bookmark-menu.scss +++ b/app/assets/stylesheets/mobile/components/bookmark-menu.scss @@ -1,11 +0,0 @@ -.bookmark-menu { - &__row { - border-bottom: 1px solid var(--primary-low); - &:last-child { - border-bottom: none; - } - } - &__row-title { - padding: 0.75rem; - } -} diff --git a/app/assets/stylesheets/mobile/components/dropdown-menu.scss b/app/assets/stylesheets/mobile/components/dropdown-menu.scss new file mode 100644 index 00000000000..53c5ece43df --- /dev/null +++ b/app/assets/stylesheets/mobile/components/dropdown-menu.scss @@ -0,0 +1,7 @@ +.dropdown-menu { + &__item { + .btn { + padding: 0.75rem 1rem; + } + } +} diff --git a/spec/system/page_objects/components/bookmark_menu.rb b/spec/system/page_objects/components/bookmark_menu.rb index c0114c86cd2..8343d4d57fa 100644 --- a/spec/system/page_objects/components/bookmark_menu.rb +++ b/spec/system/page_objects/components/bookmark_menu.rb @@ -8,7 +8,7 @@ module PageObjects end def open? - has_css?(".bookmark-menu__body") + has_css?(".bookmark-menu-content") end end end diff --git a/spec/system/page_objects/components/topic_list_header.rb b/spec/system/page_objects/components/topic_list_header.rb index 2d689a26a8b..6ec02a8061a 100644 --- a/spec/system/page_objects/components/topic_list_header.rb +++ b/spec/system/page_objects/components/topic_list_header.rb @@ -20,14 +20,12 @@ module PageObjects def has_bulk_select_topics_dropdown? page.has_css?( - "#{TOPIC_LIST_HEADER_SELECTOR} .bulk-select-topics div.bulk-select-topics-dropdown", + "#{TOPIC_LIST_HEADER_SELECTOR} .bulk-select-topics .bulk-select-topics-dropdown", ) end def click_bulk_select_topics_dropdown - find( - "#{TOPIC_LIST_HEADER_SELECTOR} .bulk-select-topics div.bulk-select-topics-dropdown", - ).click + find("#{TOPIC_LIST_HEADER_SELECTOR} .bulk-select-topics .bulk-select-topics-dropdown").click end def click_bulk_button(name) @@ -68,7 +66,7 @@ module PageObjects private def bulk_select_dropdown_item(name) - "#{TOPIC_LIST_HEADER_SELECTOR} .bulk-select-topics div.bulk-select-topics-dropdown li[data-value='#{name}']" + ".bulk-select-topics-dropdown-content li.dropdown-menu__item .btn.#{name}" end end end diff --git a/spec/system/topic_page_spec.rb b/spec/system/topic_page_spec.rb index 4a1efbc2ca9..aa65c048074 100644 --- a/spec/system/topic_page_spec.rb +++ b/spec/system/topic_page_spec.rb @@ -76,14 +76,14 @@ describe "Topic page", type: :system do visit("/t/#{topic.slug}/#{topic.id}") - expect(".topic-admin-menu-button-container").to be_present + expect(".toggle-admin-menu").to be_present send_keys([:shift, "a"]) - expect(page).to have_css(".topic-admin-popup-menu") + expect(page).to have_css(".topic-admin-menu-content") send_keys([:shift, "a"]) - expect(page).to have_no_css(".topic-admin-popup-menu") + expect(page).to have_no_css(".topic-admin-menu-content") end end