DEV: Refactor topic admin menu to use `<DMenu>` (#26678)
* DEV: Refactor topic admin menu to use `<DMenu>` This PR also introduces a new plugin API to add buttons to the topic admin menu ```javascript api.addTopicAdminMenuButton((topic) => { return { action: () => { alert('Sunrise!'); }, icon: 'sun', className: 'sunrise-button', label: 'actions.rise', }; }); ``` The plugins that needed to be updated are: - [discourse-zoom](https://github.com/discourse/discourse-zoom/pull/73) - [discourse-salesforce](https://github.com/discourse/discourse-salesforce/pull/74) - [discourse-topic-noindex](https://github.com/discourse/discourse-topic-noindex/pull/11)
This commit is contained in:
parent
9fb888923d
commit
8dd883d4e5
|
@ -52,7 +52,7 @@ export default class AdminPostMenu extends Component {
|
|||
<DButton
|
||||
@label="review.moderation_history"
|
||||
@icon="list"
|
||||
class="btn popup-menu-btn moderation-history"
|
||||
class="btn btn-transparent moderation-history"
|
||||
@href={{this.reviewUrl}}
|
||||
/>
|
||||
</li>
|
||||
|
@ -68,7 +68,7 @@ export default class AdminPostMenu extends Component {
|
|||
}}
|
||||
@icon="shield-alt"
|
||||
class={{concatClass
|
||||
"btn popup-menu-btn toggle-post-type"
|
||||
"btn btn-transparent toggle-post-type"
|
||||
(if @data.transformedPost.isModeratorAction "btn-success")
|
||||
}}
|
||||
@action={{fn this.topicAction "togglePostType"}}
|
||||
|
@ -87,7 +87,7 @@ export default class AdminPostMenu extends Component {
|
|||
}}
|
||||
title="post.controls.unhide"
|
||||
class={{concatClass
|
||||
"btn popup-menu-btn"
|
||||
"btn btn-transparent"
|
||||
(if @data.transformedPost.notice "change-notice" "add-notice")
|
||||
(if @data.transformedPost.notice "btn-success")
|
||||
}}
|
||||
|
@ -101,7 +101,7 @@ export default class AdminPostMenu extends Component {
|
|||
<DButton
|
||||
@label="post.controls.unhide"
|
||||
@icon="far-eye"
|
||||
class="btn popup-menu-btn unhide-post"
|
||||
class="btn btn-transparent unhide-post"
|
||||
@action={{fn this.topicAction "unhidePost"}}
|
||||
/>
|
||||
</li>
|
||||
|
@ -121,7 +121,7 @@ export default class AdminPostMenu extends Component {
|
|||
@label="post.controls.change_owner"
|
||||
@icon="user"
|
||||
title="post.controls.lock_post_description"
|
||||
class="btn popup-menu-btn change-owner"
|
||||
class="btn btn-transparent change-owner"
|
||||
@action={{fn this.topicAction "changePostOwner"}}
|
||||
/>
|
||||
</li>
|
||||
|
@ -133,7 +133,7 @@ export default class AdminPostMenu extends Component {
|
|||
<DButton
|
||||
@label="post.controls.grant_badge"
|
||||
@icon="certificate"
|
||||
class="btn popup-menu-btn grant-badge"
|
||||
class="btn btn-transparent grant-badge"
|
||||
@action={{fn this.topicAction "grantBadge"}}
|
||||
/>
|
||||
</li>
|
||||
|
@ -146,7 +146,7 @@ export default class AdminPostMenu extends Component {
|
|||
@icon="unlock"
|
||||
title="post.controls.unlock_post_description"
|
||||
class={{concatClass
|
||||
"btn popup-menu-btn unlock-post"
|
||||
"btn btn-transparent unlock-post"
|
||||
(if @data.post.locked "btn-success")
|
||||
}}
|
||||
@action={{fn this.topicAction "unlockPost"}}
|
||||
|
@ -158,7 +158,7 @@ export default class AdminPostMenu extends Component {
|
|||
@label="post.controls.lock_post"
|
||||
@icon="lock"
|
||||
title="post.controls.lock_post_description"
|
||||
class="btn popup-menu-btn lock-post"
|
||||
class="btn btn-transparent lock-post"
|
||||
@action={{fn this.topicAction "lockPost"}}
|
||||
/>
|
||||
</li>
|
||||
|
@ -170,7 +170,7 @@ export default class AdminPostMenu extends Component {
|
|||
<DButton
|
||||
@label="post.controls.permanently_delete"
|
||||
@icon="trash-alt"
|
||||
class="btn popup-menu-btn permanently-delete"
|
||||
class="btn btn-transparent permanently-delete"
|
||||
@action={{fn this.topicAction "permanentlyDeletePost"}}
|
||||
/>
|
||||
</li>
|
||||
|
@ -183,7 +183,7 @@ export default class AdminPostMenu extends Component {
|
|||
@label="post.controls.unwiki"
|
||||
@icon="far-edit"
|
||||
class={{concatClass
|
||||
"btn popup-menu-btn wiki wikied"
|
||||
"btn btn-transparent wiki wikied"
|
||||
(if @data.transformedPost.wiki "btn-success")
|
||||
}}
|
||||
@action={{fn this.topicAction "toggleWiki"}}
|
||||
|
@ -194,7 +194,7 @@ export default class AdminPostMenu extends Component {
|
|||
<DButton
|
||||
@label="post.controls.wiki"
|
||||
@icon="far-edit"
|
||||
class="btn popup-menu-btn wiki"
|
||||
class="btn btn-transparent wiki"
|
||||
@action={{fn this.topicAction "toggleWiki"}}
|
||||
/>
|
||||
</li>
|
||||
|
@ -206,7 +206,7 @@ export default class AdminPostMenu extends Component {
|
|||
<DButton
|
||||
@label="post.controls.publish_page"
|
||||
@icon="file"
|
||||
class="btn popup-menu-btn publish-page"
|
||||
class="btn btn-transparent publish-page"
|
||||
@action={{fn this.topicAction "showPagePublish"}}
|
||||
/>
|
||||
</li>
|
||||
|
@ -217,7 +217,7 @@ export default class AdminPostMenu extends Component {
|
|||
<DButton
|
||||
@label="post.controls.rebake"
|
||||
@icon="sync-alt"
|
||||
class="btn popup-menu-btn rebuild-html"
|
||||
class="btn btn-transparent rebuild-html"
|
||||
@action={{fn this.topicAction "rebakePost"}}
|
||||
/>
|
||||
</li>
|
||||
|
@ -229,7 +229,7 @@ export default class AdminPostMenu extends Component {
|
|||
@label={{button.label}}
|
||||
@translatedLabel={{button.translatedLabel}}
|
||||
@icon={{button.icon}}
|
||||
class={{concatClass "btn popup-menu-btn" button.className}}
|
||||
class={{concatClass "btn btn-transparent" button.className}}
|
||||
@action={{fn this.extraAction button}}
|
||||
/>
|
||||
</li>
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
import MountWidget from "discourse/components/mount-widget";
|
||||
|
||||
export default MountWidget.extend({
|
||||
classNames: "topic-admin-menu-button-container",
|
||||
tagName: "span",
|
||||
widget: "topic-admin-menu-button",
|
||||
|
||||
buildArgs() {
|
||||
return this.getProperties("topic", "openUpwards", "rightSide");
|
||||
},
|
||||
});
|
|
@ -0,0 +1,311 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { fn } from "@ember/helper";
|
||||
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 concatClass from "discourse/helpers/concat-class";
|
||||
import icon from "discourse-common/helpers/d-icon";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import DMenu from "float-kit/components/d-menu";
|
||||
|
||||
export default class TopicAdminMenu extends Component {
|
||||
@service adminTopicMenuButtons;
|
||||
@service currentUser;
|
||||
|
||||
@action
|
||||
onRegisterApi(api) {
|
||||
this.dMenu = api;
|
||||
}
|
||||
|
||||
@action
|
||||
onButtonAction(buttonAction) {
|
||||
this.args[buttonAction]?.();
|
||||
this.dMenu.close();
|
||||
}
|
||||
|
||||
@action
|
||||
onExtraButtonAction(buttonAction) {
|
||||
buttonAction?.();
|
||||
this.dMenu.close();
|
||||
}
|
||||
|
||||
get extraButtons() {
|
||||
return this.adminTopicMenuButtons.callbacks
|
||||
.map((callback) => {
|
||||
return callback(this.args.topic);
|
||||
})
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
get details() {
|
||||
return this.args.topic.get("details");
|
||||
}
|
||||
|
||||
get isPrivateMessage() {
|
||||
return this.args.topic.get("isPrivateMessage");
|
||||
}
|
||||
|
||||
get featured() {
|
||||
return (
|
||||
!!this.args.topic.get("pinned_at") || this.args.topic.get("isBanner")
|
||||
);
|
||||
}
|
||||
|
||||
get visible() {
|
||||
return this.args.topic.get("visible");
|
||||
}
|
||||
|
||||
get canDelete() {
|
||||
return this.details.get("can_delete");
|
||||
}
|
||||
|
||||
get canRecover() {
|
||||
return this.details.get("can_recover");
|
||||
}
|
||||
|
||||
get archived() {
|
||||
return this.args.topic.get("archived");
|
||||
}
|
||||
|
||||
get topicModerationHistoryUrl() {
|
||||
return getURL(`/review?topic_id=${this.args.topic.id}&status=all`);
|
||||
}
|
||||
|
||||
<template>
|
||||
<span class="topic-admin-menu-button-container">
|
||||
<span class="topic-admin-menu-button">
|
||||
<DMenu
|
||||
@onRegisterApi={{this.onRegisterApi}}
|
||||
@triggerClass="toggle-admin-menu"
|
||||
@modalForMobile={{true}}
|
||||
>
|
||||
<:trigger>
|
||||
{{icon "wrench"}}
|
||||
</:trigger>
|
||||
<:content>
|
||||
<div class="popup-menu topic-admin-popup-menu">
|
||||
<ul>
|
||||
<ul class="topic-admin-menu-topic">
|
||||
{{#if
|
||||
(or
|
||||
this.currentUser.canManageTopic
|
||||
this.details.can_split_merge_topic
|
||||
)
|
||||
}}
|
||||
<li class="topic-admin-multi-select">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.multi_select"
|
||||
@action={{fn this.onButtonAction "toggleMultiSelect"}}
|
||||
@icon="tasks"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if
|
||||
(or
|
||||
this.currentUser.canManageTopic
|
||||
this.details.can_moderate_category
|
||||
)
|
||||
}}
|
||||
{{#if this.canDelete}}
|
||||
<li class="topic-admin-delete">
|
||||
<DButton
|
||||
@label="topic.actions.delete"
|
||||
@action={{fn this.onButtonAction "deleteTopic"}}
|
||||
@icon="far-trash-alt"
|
||||
class="popup-menu-btn-danger btn-danger btn-transparent"
|
||||
/>
|
||||
</li>
|
||||
{{else if this.canRecover}}
|
||||
<li class="topic-admin-recover">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.recover"
|
||||
@action={{fn this.onButtonAction "recoverTopic"}}
|
||||
@icon="undo"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if this.details.can_close_topic}}
|
||||
<li
|
||||
class={{if
|
||||
@topic.closed
|
||||
"topic-admin-open"
|
||||
"topic-admin-close"
|
||||
}}
|
||||
>
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
@topic.closed
|
||||
"topic.actions.open"
|
||||
"topic.actions.close"
|
||||
}}
|
||||
@action={{fn this.onButtonAction "toggleClosed"}}
|
||||
@icon={{if @topic.closed "unlock" "lock"}}
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if
|
||||
(and
|
||||
this.details.can_pin_unpin_topic
|
||||
(not this.isPrivateMessage)
|
||||
(or this.visible this.featured)
|
||||
)
|
||||
}}
|
||||
<li class="topic-admin-pin">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
this.featured
|
||||
"topic.actions.unpin"
|
||||
"topic.actions.pin"
|
||||
}}
|
||||
@action={{fn this.onButtonAction "showFeatureTopic"}}
|
||||
@icon="thumbtack"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if
|
||||
(and
|
||||
this.details.can_archive_topic (not this.isPrivateMessage)
|
||||
)
|
||||
}}
|
||||
<li class="topic-admin-archive">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
this.archived
|
||||
"topic.actions.unarchive"
|
||||
"topic.actions.archive"
|
||||
}}
|
||||
@action={{fn this.onButtonAction "toggleArchived"}}
|
||||
@icon="folder"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.details.can_toggle_topic_visibility}}
|
||||
<li class="topic-admin-visible">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
this.visible
|
||||
"topic.actions.invisible"
|
||||
"topic.actions.visible"
|
||||
}}
|
||||
@action={{fn this.onButtonAction "toggleVisibility"}}
|
||||
@icon={{if this.visible "far-eye-slash" "far-eye"}}
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if (and this.details.can_convert_topic)}}
|
||||
<li class="topic-admin-convert">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
this.isPrivateMessage
|
||||
"topic.actions.make_public"
|
||||
"topic.actions.make_private"
|
||||
}}
|
||||
@action={{fn
|
||||
this.onButtonAction
|
||||
(if
|
||||
this.isPrivateMessage
|
||||
"convertToPublicTopic"
|
||||
"convertToPrivateMessage"
|
||||
)
|
||||
}}
|
||||
@icon={{if this.isPrivateMessage "comment" "envelope"}}
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
|
||||
<ul class="topic-admin-menu-time">
|
||||
{{#if this.currentUser.canManageTopic}}
|
||||
<li class="admin-topic-timer-update">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.timed_update"
|
||||
@action={{fn this.onButtonAction "showTopicTimerModal"}}
|
||||
@icon="far-clock"
|
||||
/>
|
||||
</li>
|
||||
|
||||
{{#if this.currentUser.staff}}
|
||||
<li class="topic-admin-change-timestamp">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.change_timestamp.title"
|
||||
@action={{fn
|
||||
this.onButtonAction
|
||||
"showChangeTimestamp"
|
||||
}}
|
||||
@icon="calendar-alt"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
<li class="topic-admin-reset-bump-date">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.reset_bump_date"
|
||||
@action={{fn this.onButtonAction "resetBumpDate"}}
|
||||
@icon="anchor"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<li class="topic-admin-slow-mode">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.slow_mode"
|
||||
@action={{fn
|
||||
this.onButtonAction
|
||||
"showTopicSlowModeUpdate"
|
||||
}}
|
||||
@icon="hourglass-start"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
|
||||
<ul class="topic-admin-menu-undefined">
|
||||
{{#if this.currentUser.staff}}
|
||||
<li class="topic-admin-moderation-history">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="review.moderation_history"
|
||||
@href={{this.topicModerationHistoryUrl}}
|
||||
@icon="list"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#each this.extraButtons as |button|}}
|
||||
<li>
|
||||
<DButton
|
||||
@label={{button.label}}
|
||||
@translatedLabel={{button.translatedLabel}}
|
||||
@icon={{button.icon}}
|
||||
class={{concatClass "btn-transparent" button.className}}
|
||||
@action={{fn this.onExtraButtonAction button.action}}
|
||||
/>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
</:content>
|
||||
</DMenu>
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
<div class="topic-footer-main-buttons">
|
||||
<TopicAdminMenuButton
|
||||
<TopicAdminMenu
|
||||
@topic={{this.topic}}
|
||||
@openUpwards="true"
|
||||
@toggleMultiSelect={{this.toggleMultiSelect}}
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
@name="timeline-controls-before"
|
||||
@outletArgs={{hash model=@model}}
|
||||
/>
|
||||
<TopicAdminMenuButton
|
||||
<TopicAdminMenu
|
||||
@topic={{@model}}
|
||||
@addKeyboardTargetClass={{true}}
|
||||
@toggleMultiSelect={{@toggleMultiSelect}}
|
||||
|
@ -175,7 +175,7 @@
|
|||
@showCaret={{false}}
|
||||
/>
|
||||
{{#if @mobileView}}
|
||||
<TopicAdminMenuButton
|
||||
<TopicAdminMenu
|
||||
@topic={{@model}}
|
||||
@addKeyboardTargetClass={{true}}
|
||||
@openUpwards={{true}}
|
||||
|
|
|
@ -150,7 +150,7 @@ import { modifySelectKit } from "select-kit/mixins/plugin-api";
|
|||
// docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md whenever you change the version
|
||||
// using the format described at https://keepachangelog.com/en/1.0.0/.
|
||||
|
||||
export const PLUGIN_API_VERSION = "1.29.0";
|
||||
export const PLUGIN_API_VERSION = "1.31.0";
|
||||
|
||||
const DEPRECATED_HEADER_WIDGETS = [
|
||||
"header",
|
||||
|
@ -675,6 +675,30 @@ class PluginApi {
|
|||
.addButton(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new button in the topic admin menu.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* api.addTopicAdminMenuButton((topic) => {
|
||||
* return {
|
||||
* action: () => {
|
||||
* alert('You clicked on the coffee button!');
|
||||
* },
|
||||
* icon: 'coffee',
|
||||
* className: 'hot-coffee',
|
||||
* label: 'coffee.title',
|
||||
* };
|
||||
* });
|
||||
* ```
|
||||
**/
|
||||
addTopicAdminMenuButton(callback) {
|
||||
this.container
|
||||
.lookup("service:admin-topic-menu-buttons")
|
||||
.addButton(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove existing button below a post with your plugin.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import Service from "@ember/service";
|
||||
|
||||
export default class AdminTopicMenuButtons extends Service {
|
||||
callbacks = [];
|
||||
|
||||
addButton(callback) {
|
||||
this.callbacks.push(callback);
|
||||
}
|
||||
}
|
|
@ -280,7 +280,7 @@
|
|||
}}
|
||||
/>
|
||||
</span>
|
||||
<TopicAdminMenuButton
|
||||
<TopicAdminMenu
|
||||
@topic={{this.model}}
|
||||
@openUpwards="true"
|
||||
@rightSide="true"
|
||||
|
|
|
@ -828,6 +828,7 @@ export default createWidget("post-menu", {
|
|||
identifier: "admin-post-menu",
|
||||
component: AdminPostMenu,
|
||||
extraClassName: "popup-menu",
|
||||
modalForMobile: true,
|
||||
data: {
|
||||
scheduleRerender: this.scheduleRerender.bind(this),
|
||||
transformedPost: this.attrs,
|
||||
|
|
|
@ -1,409 +0,0 @@
|
|||
import $ from "jquery";
|
||||
import { h } from "virtual-dom";
|
||||
import { headerOffset } from "discourse/lib/offset-calculator";
|
||||
import { applyDecorators, createWidget } from "discourse/widgets/widget";
|
||||
|
||||
createWidget("admin-menu-button", {
|
||||
tagName: "li",
|
||||
|
||||
buildClasses(attrs) {
|
||||
return attrs.className;
|
||||
},
|
||||
|
||||
html(attrs) {
|
||||
let className;
|
||||
if (attrs.buttonClass) {
|
||||
className = attrs.buttonClass;
|
||||
}
|
||||
|
||||
return this.attach("button", {
|
||||
className,
|
||||
action: attrs.action,
|
||||
url: attrs.url,
|
||||
icon: attrs.icon,
|
||||
label: attrs.fullLabel || `topic.${attrs.label}`,
|
||||
secondaryAction: "hideAdminMenu",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
createWidget("topic-admin-menu-button", {
|
||||
tagName: "span.topic-admin-menu-button",
|
||||
buildKey: () => "topic-admin-menu-button",
|
||||
|
||||
defaultState() {
|
||||
return { expanded: false, position: null };
|
||||
},
|
||||
|
||||
html(attrs, state) {
|
||||
const result = [];
|
||||
|
||||
const menu = this.attach("topic-admin-menu", {
|
||||
position: state.position,
|
||||
topic: attrs.topic,
|
||||
openUpwards: attrs.openUpwards,
|
||||
rightSide: this.site.desktopView && attrs.rightSide,
|
||||
actionButtons: [],
|
||||
});
|
||||
|
||||
// We don't show the button when expanded on the right side on desktop
|
||||
if (
|
||||
menu.attrs.actionButtons.length &&
|
||||
(!(attrs.rightSide && state.expanded) || this.site.mobileView)
|
||||
) {
|
||||
result.push(
|
||||
this.attach("button", {
|
||||
className:
|
||||
"btn-default popup-menu-button toggle-admin-menu" +
|
||||
(attrs.addKeyboardTargetClass ? " keyboard-target-admin-menu" : ""),
|
||||
title: "topic_admin_menu",
|
||||
icon: "wrench",
|
||||
action: "showAdminMenu",
|
||||
sendActionEvent: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (state.expanded) {
|
||||
result.push(menu);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
hideAdminMenu() {
|
||||
this.state.expanded = false;
|
||||
this.state.position = null;
|
||||
},
|
||||
|
||||
showAdminMenu(e) {
|
||||
this.state.expanded = true;
|
||||
let button;
|
||||
|
||||
if (e === undefined) {
|
||||
button = document.querySelector(".keyboard-target-admin-menu");
|
||||
} else {
|
||||
button = e.target.closest("button");
|
||||
}
|
||||
|
||||
const position = { top: button.offsetTop, left: button.offsetLeft };
|
||||
const spacing = 3;
|
||||
const menuWidth = 212;
|
||||
|
||||
const rtl = document.documentElement.classList.contains("html.rtl");
|
||||
const buttonDOMRect = button.getBoundingClientRect();
|
||||
position.outerHeight = buttonDOMRect.height;
|
||||
|
||||
if (this.attrs.openUpwards) {
|
||||
if (rtl) {
|
||||
position.left -= buttonDOMRect.width + spacing;
|
||||
} else {
|
||||
position.left += buttonDOMRect.width + spacing;
|
||||
}
|
||||
} else {
|
||||
if (rtl) {
|
||||
if (buttonDOMRect.left < menuWidth) {
|
||||
position.left += 0;
|
||||
} else {
|
||||
position.left -= menuWidth - buttonDOMRect.width;
|
||||
}
|
||||
} else {
|
||||
const offsetRight = window.innerWidth - buttonDOMRect.right;
|
||||
|
||||
if (offsetRight < menuWidth) {
|
||||
position.left -= menuWidth - buttonDOMRect.width;
|
||||
}
|
||||
}
|
||||
|
||||
position.top += buttonDOMRect.height + spacing;
|
||||
}
|
||||
|
||||
this.state.position = position;
|
||||
},
|
||||
|
||||
didRenderWidget() {
|
||||
let menuButtons = document.querySelectorAll(
|
||||
".topic-admin-popup-menu button"
|
||||
);
|
||||
|
||||
if (menuButtons && menuButtons[0]) {
|
||||
menuButtons[0].focus();
|
||||
}
|
||||
},
|
||||
|
||||
topicToggleActions() {
|
||||
this.state.expanded ? this.hideAdminMenu() : this.showAdminMenu();
|
||||
},
|
||||
});
|
||||
|
||||
export default createWidget("topic-admin-menu", {
|
||||
tagName: "div.popup-menu.topic-admin-popup-menu",
|
||||
|
||||
buildClasses(attrs) {
|
||||
if (attrs.rightSide) {
|
||||
return "right-side";
|
||||
}
|
||||
},
|
||||
|
||||
init(attrs) {
|
||||
const topic = attrs.topic;
|
||||
const details = topic.get("details");
|
||||
const isPrivateMessage = topic.get("isPrivateMessage");
|
||||
const featured = topic.get("pinned_at") || topic.get("isBanner");
|
||||
const visible = topic.get("visible");
|
||||
|
||||
// Admin actions
|
||||
if (
|
||||
this.get("currentUser.canManageTopic") ||
|
||||
details.can_split_merge_topic
|
||||
) {
|
||||
this.addActionButton({
|
||||
className: "topic-admin-multi-select",
|
||||
buttonClass: "popup-menu-btn",
|
||||
action: "toggleMultiSelect",
|
||||
icon: "tasks",
|
||||
label: "actions.multi_select",
|
||||
button_group: "topic",
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
this.get("currentUser.canManageTopic") ||
|
||||
details.get("can_moderate_category")
|
||||
) {
|
||||
if (details.get("can_delete")) {
|
||||
this.addActionButton({
|
||||
className: "topic-admin-delete",
|
||||
buttonClass: "popup-menu-btn-danger",
|
||||
action: "deleteTopic",
|
||||
icon: "far-trash-alt",
|
||||
label: "actions.delete",
|
||||
button_group: "topic",
|
||||
});
|
||||
}
|
||||
|
||||
if (topic.get("deleted") && details.get("can_recover")) {
|
||||
this.addActionButton({
|
||||
className: "topic-admin-recover",
|
||||
buttonClass: "popup-menu-btn",
|
||||
action: "recoverTopic",
|
||||
icon: "undo",
|
||||
label: "actions.recover",
|
||||
button_group: "topic",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (this.currentUser && details.get("can_close_topic")) {
|
||||
if (topic.get("closed")) {
|
||||
this.addActionButton({
|
||||
className: "topic-admin-open",
|
||||
buttonClass: "popup-menu-btn",
|
||||
action: "toggleClosed",
|
||||
icon: "unlock",
|
||||
label: "actions.open",
|
||||
button_group: "topic",
|
||||
});
|
||||
} else {
|
||||
this.addActionButton({
|
||||
className: "topic-admin-close",
|
||||
buttonClass: "popup-menu-btn",
|
||||
action: "toggleClosed",
|
||||
icon: "lock",
|
||||
label: "actions.close",
|
||||
button_group: "topic",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (this.get("currentUser.canManageTopic")) {
|
||||
this.addActionButton({
|
||||
className: "admin-topic-timer-update",
|
||||
buttonClass: "popup-menu-btn",
|
||||
action: "showTopicTimerModal",
|
||||
icon: "far-clock",
|
||||
label: "actions.timed_update",
|
||||
button_group: "time",
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
details.get("can_pin_unpin_topic") &&
|
||||
!isPrivateMessage &&
|
||||
(topic.get("visible") || featured)
|
||||
) {
|
||||
this.addActionButton({
|
||||
className: "topic-admin-pin",
|
||||
buttonClass: "popup-menu-btn",
|
||||
action: "showFeatureTopic",
|
||||
icon: "thumbtack",
|
||||
label: featured ? "actions.unpin" : "actions.pin",
|
||||
button_group: "topic",
|
||||
});
|
||||
}
|
||||
|
||||
if (this.get("currentUser.canManageTopic")) {
|
||||
if (this.currentUser.get("staff")) {
|
||||
this.addActionButton({
|
||||
className: "topic-admin-change-timestamp",
|
||||
buttonClass: "popup-menu-btn",
|
||||
action: "showChangeTimestamp",
|
||||
icon: "calendar-alt",
|
||||
label: "change_timestamp.title",
|
||||
button_group: "time",
|
||||
});
|
||||
}
|
||||
|
||||
this.addActionButton({
|
||||
className: "topic-admin-reset-bump-date",
|
||||
buttonClass: "popup-menu-btn",
|
||||
action: "resetBumpDate",
|
||||
icon: "anchor",
|
||||
label: "actions.reset_bump_date",
|
||||
button_group: "time",
|
||||
});
|
||||
}
|
||||
|
||||
if (this.currentUser && details.get("can_archive_topic")) {
|
||||
if (!isPrivateMessage) {
|
||||
this.addActionButton({
|
||||
className: "topic-admin-archive",
|
||||
buttonClass: "popup-menu-btn",
|
||||
action: "toggleArchived",
|
||||
icon: "folder",
|
||||
label: topic.get("archived")
|
||||
? "actions.unarchive"
|
||||
: "actions.archive",
|
||||
button_group: "topic",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (details.get("can_toggle_topic_visibility")) {
|
||||
this.addActionButton({
|
||||
className: "topic-admin-visible",
|
||||
buttonClass: "popup-menu-btn",
|
||||
action: "toggleVisibility",
|
||||
icon: visible ? "far-eye-slash" : "far-eye",
|
||||
label: visible ? "actions.invisible" : "actions.visible",
|
||||
button_group: "topic",
|
||||
});
|
||||
}
|
||||
|
||||
if (this.get("currentUser.canManageTopic")) {
|
||||
if (details.get("can_convert_topic")) {
|
||||
this.addActionButton({
|
||||
className: "topic-admin-convert",
|
||||
buttonClass: "popup-menu-btn",
|
||||
action: isPrivateMessage
|
||||
? "convertToPublicTopic"
|
||||
: "convertToPrivateMessage",
|
||||
icon: isPrivateMessage ? "comment" : "envelope",
|
||||
label: isPrivateMessage
|
||||
? "actions.make_public"
|
||||
: "actions.make_private",
|
||||
button_group: "topic",
|
||||
});
|
||||
}
|
||||
|
||||
this.addActionButton({
|
||||
className: "topic-admin-slow-mode",
|
||||
buttonClass: "popup-menu-btn",
|
||||
action: "showTopicSlowModeUpdate",
|
||||
icon: "hourglass-start",
|
||||
label: "actions.slow_mode",
|
||||
button_group: "time",
|
||||
});
|
||||
|
||||
if (this.currentUser.get("staff")) {
|
||||
this.addActionButton({
|
||||
icon: "list",
|
||||
buttonClass: "popup-menu-btn",
|
||||
fullLabel: "review.moderation_history",
|
||||
url: `/review?topic_id=${topic.id}&status=all`,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
buildAttributes(attrs) {
|
||||
let { top, left, outerHeight } = attrs.position;
|
||||
const position = this.site.mobileView ? "fixed" : "absolute";
|
||||
const approxMenuHeight = attrs.actionButtons.length * 42;
|
||||
|
||||
if (attrs.rightSide) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (attrs.openUpwards) {
|
||||
const documentHeight = $(document).height();
|
||||
const mainHeight = $(".ember-application").height();
|
||||
let bottom =
|
||||
documentHeight - top - 70 - $(".ember-application").offset().top;
|
||||
|
||||
if (documentHeight > mainHeight) {
|
||||
bottom = bottom - (documentHeight - mainHeight) - outerHeight;
|
||||
}
|
||||
|
||||
if (top < approxMenuHeight) {
|
||||
bottom =
|
||||
bottom - (approxMenuHeight - outerHeight - top) - headerOffset();
|
||||
}
|
||||
|
||||
if (this.site.mobileView) {
|
||||
bottom = 50;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
return {
|
||||
style: `position: ${position}; bottom: ${bottom}px; left: ${left}px;`,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
style: `position: ${position}; top: ${top}px; left: ${left}px;`,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
addActionButton(button) {
|
||||
this.attrs.actionButtons.push(button);
|
||||
},
|
||||
|
||||
html(attrs) {
|
||||
const extraButtons = applyDecorators(
|
||||
this,
|
||||
"adminMenuButtons",
|
||||
this.attrs,
|
||||
this.state
|
||||
);
|
||||
|
||||
const actionButtons = attrs.actionButtons
|
||||
.concat(extraButtons)
|
||||
.filter(Boolean);
|
||||
|
||||
const buttonMap = actionButtons.reduce(
|
||||
(prev, current) =>
|
||||
prev.set(current.button_group, [
|
||||
...(prev.get(current.button_group) || []),
|
||||
current,
|
||||
]),
|
||||
new Map()
|
||||
);
|
||||
|
||||
let combinedButtonLists = [];
|
||||
|
||||
for (const [group, buttons] of buttonMap.entries()) {
|
||||
let buttonList = [];
|
||||
buttons.forEach((button) => {
|
||||
buttonList.push(this.attach("admin-menu-button", button));
|
||||
});
|
||||
combinedButtonLists.push(h(`ul.topic-admin-menu-${group}`, buttonList));
|
||||
}
|
||||
|
||||
return h("ul", combinedButtonLists);
|
||||
},
|
||||
|
||||
clickOutside() {
|
||||
this.sendWidgetAction("hideAdminMenu");
|
||||
},
|
||||
});
|
|
@ -1,10 +1,12 @@
|
|||
import { click, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
updateCurrentUser,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
acceptance("Topic - Admin Menu Anonymous Users", function () {
|
||||
test("Enter as a regular user", async function (assert) {
|
||||
|
@ -44,16 +46,34 @@ acceptance("Topic - Admin Menu", function (needs) {
|
|||
);
|
||||
});
|
||||
|
||||
test("Toggle the menu as admin focuses the first item", async function (assert) {
|
||||
test("Button added using addTopicAdminMenuButton", async function (assert) {
|
||||
updateCurrentUser({ admin: true });
|
||||
this.set("actionCalled", false);
|
||||
|
||||
withPluginApi("1.31.0", (api) => {
|
||||
api.addTopicAdminMenuButton(() => {
|
||||
return {
|
||||
className: "extra-button",
|
||||
icon: "heart",
|
||||
label: "yes_value",
|
||||
action: () => {
|
||||
this.set("actionCalled", true);
|
||||
},
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
await visit("/t/internationalization-localization/280");
|
||||
assert.ok(exists("#topic"), "The topic was rendered");
|
||||
await click(".toggle-admin-menu");
|
||||
|
||||
assert.strictEqual(
|
||||
document.activeElement,
|
||||
document.querySelector(".topic-admin-multi-select > button")
|
||||
assert.ok(
|
||||
exists(".extra-button svg.d-icon-heart"),
|
||||
"The icon was rendered"
|
||||
);
|
||||
assert
|
||||
.dom(".extra-button .d-button-label")
|
||||
.hasText(I18n.t("yes_value"), "The label was rendered");
|
||||
await click(".extra-button");
|
||||
assert.ok(this.actionCalled, "The action was called");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
import { getOwner } from "@ember/application";
|
||||
import { render } from "@ember/test-helpers";
|
||||
import { hbs } from "ember-cli-htmlbars";
|
||||
import { module, test } from "qunit";
|
||||
import Category from "discourse/models/category";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { exists } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
const createArgs = (topic) => {
|
||||
return {
|
||||
topic,
|
||||
openUpwards: "true",
|
||||
toggleMultiSelect: () => {},
|
||||
deleteTopic: () => {},
|
||||
recoverTopic: () => {},
|
||||
toggleClosed: () => {},
|
||||
toggleArchived: () => {},
|
||||
toggleVisibility: () => {},
|
||||
showTopicTimerModal: () => {},
|
||||
showFeatureTopic: () => {},
|
||||
showChangeTimestamp: () => {},
|
||||
resetBumpDate: () => {},
|
||||
convertToPublicTopic: () => {},
|
||||
convertToPrivateMessage: () => {},
|
||||
};
|
||||
};
|
||||
|
||||
module(
|
||||
"Integration | Component | Widget | topic-admin-menu-button",
|
||||
function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test("topic-admin-menu-button is present for admin/moderators", async function (assert) {
|
||||
this.currentUser.setProperties({
|
||||
admin: true,
|
||||
moderator: true,
|
||||
id: 123,
|
||||
});
|
||||
|
||||
const store = getOwner(this).lookup("service:store");
|
||||
const topic = store.createRecord("topic", {
|
||||
user_id: this.currentUser.id,
|
||||
});
|
||||
topic.set("category_id", Category.create({ read_restricted: true }).id);
|
||||
|
||||
this.siteSettings.allow_featured_topic_on_user_profiles = true;
|
||||
this.set("args", createArgs(topic));
|
||||
|
||||
await render(
|
||||
hbs`<MountWidget @widget="topic-admin-menu-button" @args={{this.args}} />`
|
||||
);
|
||||
|
||||
assert.ok(exists(".toggle-admin-menu"), "admin wrench is present");
|
||||
});
|
||||
|
||||
test("topic-admin-menu-button hides for non-admin when there is no action", async function (assert) {
|
||||
this.currentUser.setProperties({
|
||||
admin: false,
|
||||
moderator: false,
|
||||
id: 123,
|
||||
});
|
||||
|
||||
const store = getOwner(this).lookup("service:store");
|
||||
const topic = store.createRecord("topic", {
|
||||
user_id: this.currentUser.id,
|
||||
});
|
||||
topic.set("category_id", Category.create({ read_restricted: true }).id);
|
||||
|
||||
this.siteSettings.allow_featured_topic_on_user_profiles = true;
|
||||
this.set("args", createArgs(topic));
|
||||
|
||||
await render(
|
||||
hbs`<MountWidget @widget="topic-admin-menu-button" @args={{this.args}} />`
|
||||
);
|
||||
|
||||
assert.ok(!exists(".toggle-admin-menu"), "admin wrench is not present");
|
||||
});
|
||||
}
|
||||
);
|
|
@ -1,26 +1,50 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { and } from "truth-helpers";
|
||||
import DModal from "discourse/components/d-modal";
|
||||
import DFloatBody from "float-kit/components/d-float-body";
|
||||
|
||||
const DInlineFloat = <template>
|
||||
{{#if @instance.expanded}}
|
||||
<DFloatBody
|
||||
@instance={{@instance}}
|
||||
@trapTab={{@trapTab}}
|
||||
@mainClass={{@mainClass}}
|
||||
@innerClass={{@innerClass}}
|
||||
@role={{@role}}
|
||||
@portalOutletElement={{@portalOutletElement}}
|
||||
@inline={{@inline}}
|
||||
>
|
||||
{{#if @instance.options.component}}
|
||||
<@instance.options.component
|
||||
@data={{@instance.options.data}}
|
||||
@close={{@instance.close}}
|
||||
/>
|
||||
{{else}}
|
||||
{{@instance.options.content}}
|
||||
{{/if}}
|
||||
</DFloatBody>
|
||||
{{/if}}
|
||||
</template>;
|
||||
export default class DInlineFloat extends Component {
|
||||
@service site;
|
||||
|
||||
export default DInlineFloat;
|
||||
<template>
|
||||
{{#if @instance.expanded}}
|
||||
{{#if (and this.site.mobileView @instance.options.modalForMobile)}}
|
||||
<DModal
|
||||
@closeModal={{@instance.close}}
|
||||
@hideHeader={{true}}
|
||||
data-identifier={{@instance.options.identifier}}
|
||||
data-content
|
||||
>
|
||||
{{#if @instance.options.component}}
|
||||
<@instance.options.component
|
||||
@data={{@instance.options.data}}
|
||||
@close={{@instance.close}}
|
||||
/>
|
||||
{{else}}
|
||||
{{@instance.options.content}}
|
||||
{{/if}}
|
||||
</DModal>
|
||||
{{else}}
|
||||
<DFloatBody
|
||||
@instance={{@instance}}
|
||||
@trapTab={{@trapTab}}
|
||||
@mainClass={{@mainClass}}
|
||||
@innerClass={{@innerClass}}
|
||||
@role={{@role}}
|
||||
@portalOutletElement={{@portalOutletElement}}
|
||||
@inline={{@inline}}
|
||||
>
|
||||
{{#if @instance.options.component}}
|
||||
<@instance.options.component
|
||||
@data={{@instance.options.data}}
|
||||
@close={{@instance.close}}
|
||||
/>
|
||||
{{else}}
|
||||
{{@instance.options.content}}
|
||||
{{/if}}
|
||||
</DFloatBody>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ export default class DMenu extends Component {
|
|||
"fk-d-menu__trigger"
|
||||
(if this.menuInstance.expanded "-expanded")
|
||||
(concat this.options.identifier "-trigger")
|
||||
@triggerClass
|
||||
}}
|
||||
id={{this.menuInstance.id}}
|
||||
data-identifier={{this.options.identifier}}
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
@import "not-found";
|
||||
@import "onebox";
|
||||
@import "personal-message";
|
||||
@import "popup-menu";
|
||||
@import "redirection";
|
||||
@import "reviewables";
|
||||
@import "revise-and-reject-post-reviewable";
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
.popup-menu {
|
||||
background-color: var(--secondary);
|
||||
width: 14em;
|
||||
border: 1px solid var(--primary-low);
|
||||
z-index: z("dropdown");
|
||||
box-shadow: var(--shadow-card);
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
|
||||
li {
|
||||
border-bottom: 1px solid rgba(var(--primary-low-rgb), 0.5);
|
||||
|
||||
&:last-child {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
justify-content: left;
|
||||
text-align: left;
|
||||
background: none;
|
||||
width: 100%;
|
||||
padding: 0.5em;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
|
||||
.d-icon {
|
||||
color: var(--primary-medium);
|
||||
align-self: flex-start;
|
||||
margin-right: 0.75em;
|
||||
margin-top: 0.1em; // vertical alignment
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
color: var(--primary);
|
||||
background: var(--d-hover);
|
||||
|
||||
.d-icon {
|
||||
color: var(--primary-medium);
|
||||
}
|
||||
}
|
||||
|
||||
&.popup-menu-btn-danger {
|
||||
.d-icon {
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.d-button-label {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
.d-icon,
|
||||
.d-button-label {
|
||||
color: var(--danger);
|
||||
}
|
||||
background: var(--danger-low);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +1,10 @@
|
|||
// Styles for the topic admin menu
|
||||
|
||||
.topic-admin-popup-menu {
|
||||
@include breakpoint(mobile-extra-large) {
|
||||
width: calc(100% - 20px);
|
||||
margin: 0 10px;
|
||||
padding: 0;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
z-index: z("modal", "popover");
|
||||
|
||||
@keyframes slideUp {
|
||||
0% {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
animation: slideUp 0.3s;
|
||||
@media (prefers-reduced-motion) {
|
||||
animation-duration: 0s;
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-view & {
|
||||
z-index: z("modal", "popover");
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 0.5rem;
|
||||
|
||||
.d-icon {
|
||||
font-size: var(--font-down-1);
|
||||
margin-top: 2px; // vertical alignment
|
||||
margin-right: 0.75em;
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
|
||||
li {
|
||||
border: none;
|
||||
&:not(:last-of-type) {
|
||||
|
@ -45,81 +13,22 @@
|
|||
}
|
||||
}
|
||||
ul {
|
||||
padding: 0.5rem;
|
||||
padding: 0.5em;
|
||||
&:not(:last-of-type) {
|
||||
border-bottom: 1px solid var(--primary-low);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body.feature-topic {
|
||||
max-height: 70vh !important;
|
||||
padding: 0 1em;
|
||||
input.date-picker {
|
||||
margin: 0;
|
||||
}
|
||||
.feature-section {
|
||||
display: block;
|
||||
padding: 1.25em 0;
|
||||
&:not(:last-of-type) {
|
||||
border-bottom: 1px solid var(--primary-low);
|
||||
}
|
||||
.desc {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
p:first-of-type {
|
||||
margin: 0;
|
||||
}
|
||||
p {
|
||||
margin: 10px 0 0;
|
||||
max-width: 31em;
|
||||
}
|
||||
}
|
||||
.with-validation {
|
||||
position: relative;
|
||||
|
||||
> span {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
> .d-icon {
|
||||
padding-top: 0.75em;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
justify-content: left;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
padding: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Select posts
|
||||
|
||||
.selected-posts {
|
||||
border: 1px solid var(--tertiary-medium);
|
||||
background-color: var(--tertiary-low);
|
||||
.btn {
|
||||
border: none;
|
||||
color: var(--secondary);
|
||||
font-weight: normal;
|
||||
margin-bottom: 10px;
|
||||
&:not(.btn-danger) {
|
||||
background: var(--tertiary);
|
||||
border-color: var(--tertiary);
|
||||
&[href] {
|
||||
color: var(--secondary);
|
||||
}
|
||||
&:hover {
|
||||
color: var(--secondary);
|
||||
background: var(--tertiary-high);
|
||||
}
|
||||
&:active {
|
||||
@include linear-gradient(var(--tertiary-hover), var(--tertiary));
|
||||
color: var(--secondary);
|
||||
}
|
||||
}
|
||||
&[disabled] {
|
||||
text-shadow: 0 1px 0 rgba(var(--primary-rgb), 0.2);
|
||||
@include linear-gradient(var(--tertiary), var(--tertiary-hover));
|
||||
box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.33);
|
||||
}
|
||||
.fk-d-menu {
|
||||
.topic-admin-popup-menu {
|
||||
width: 14em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,23 +148,9 @@
|
|||
display: flex;
|
||||
}
|
||||
}
|
||||
.topic-admin-popup-menu.right-side {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: auto;
|
||||
transition: bottom 0.5s;
|
||||
transform: translateZ(
|
||||
0
|
||||
); // iOS11 Rendering bug https://meta.discourse.org/t/wrench-menu-not-disappearing-on-ios/94297
|
||||
}
|
||||
|
||||
&.docked {
|
||||
position: initial;
|
||||
.topic-admin-popup-menu.right-side {
|
||||
bottom: unset;
|
||||
right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
html:not(.footer-nav-visible) & {
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
[data-content][data-identifier="admin-post-menu"] {
|
||||
.d-modal__body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding: 0.5rem;
|
||||
margin: 0;
|
||||
|
@ -17,5 +21,12 @@
|
|||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
justify-content: left;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
padding: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,39 +135,6 @@ sub sub {
|
|||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
@media screen and (max-height: 600px) {
|
||||
.topic-admin-popup-menu {
|
||||
box-sizing: border-box;
|
||||
padding: 0.25em;
|
||||
width: unset;
|
||||
ul {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
|
||||
@media screen and (max-width: 550px) {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
ul {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.d-button-label {
|
||||
@include ellipsis;
|
||||
}
|
||||
|
||||
.popup-menu-btn {
|
||||
@include ellipsis;
|
||||
}
|
||||
|
||||
li {
|
||||
border: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container.posts .topic-navigation {
|
||||
// better positioning for the docked progress bar on large screens using mobile view
|
||||
grid-area: posts;
|
||||
|
|
|
@ -7,6 +7,10 @@ in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.31.0] - 2024-04-22
|
||||
|
||||
- Adds `addTopicAdminMenuButton` which allows to register a new button in the topic admin menu.
|
||||
|
||||
## [1.30.0] - 2024-03-20
|
||||
|
||||
- Added `addAdminPluginConfigurationNav`, which defines a list of links used in the adminPlugins.show page for a specific plugin, and displays them either in an inner sidebar or in a top horizontal nav.
|
||||
|
|
Loading…
Reference in New Issue