mirror of
https://github.com/flarum/framework.git
synced 2025-05-23 23:29:57 +08:00
Make Dropdown and NotificationsDropdown components more extensible
This commit is contained in:
@ -1,8 +1,18 @@
|
|||||||
import Component from 'flarum/Component';
|
import Dropdown from 'flarum/components/Dropdown';
|
||||||
import icon from 'flarum/helpers/icon';
|
import icon from 'flarum/helpers/icon';
|
||||||
import NotificationList from 'flarum/components/NotificationList';
|
import NotificationList from 'flarum/components/NotificationList';
|
||||||
|
|
||||||
export default class NotificationsDropdown extends Component {
|
export default class NotificationsDropdown extends Dropdown {
|
||||||
|
static initProps(props) {
|
||||||
|
props.className = props.className || 'NotificationsDropdown';
|
||||||
|
props.buttonClassName = props.buttonClassName || 'Button Button--flat';
|
||||||
|
props.menuClassName = props.menuClassName || 'Dropdown-menu--right';
|
||||||
|
props.label = props.label || app.trans('core.notifications');
|
||||||
|
props.icon = props.icon || 'bell';
|
||||||
|
|
||||||
|
super.initProps(props);
|
||||||
|
}
|
||||||
|
|
||||||
constructor(...args) {
|
constructor(...args) {
|
||||||
super(...args);
|
super(...args);
|
||||||
|
|
||||||
@ -16,35 +26,51 @@ export default class NotificationsDropdown extends Component {
|
|||||||
this.list = new NotificationList();
|
this.list = new NotificationList();
|
||||||
}
|
}
|
||||||
|
|
||||||
view() {
|
getButton() {
|
||||||
const user = app.session.user;
|
const unread = this.getUnreadCount();
|
||||||
const unread = user.unreadNotificationsCount();
|
const vdom = super.getButton();
|
||||||
|
|
||||||
|
vdom.attrs.className += (unread ? ' unread' : '');
|
||||||
|
vdom.attrs.onclick = this.onclick.bind(this);
|
||||||
|
|
||||||
|
return vdom;
|
||||||
|
}
|
||||||
|
|
||||||
|
getButtonContent() {
|
||||||
|
const unread = this.getUnreadCount();
|
||||||
|
|
||||||
|
return [
|
||||||
|
icon(this.props.icon, {className: 'Button-icon'}),
|
||||||
|
unread ? <span className="NotificationsDropdown-unread">{unread}</span> : '',
|
||||||
|
<span className="Button-label">{this.props.label}</span>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
getMenu() {
|
||||||
return (
|
return (
|
||||||
<div className="Dropdown NotificationsDropdown">
|
<div className={'Dropdown-menu ' + this.props.menuClassName} onclick={this.menuClick.bind(this)}>
|
||||||
<a href="javascript:;"
|
|
||||||
className={'Dropdown-toggle Button Button--flat NotificationsDropdown-button' + (unread ? ' unread' : '')}
|
|
||||||
data-toggle="dropdown"
|
|
||||||
onclick={this.onclick.bind(this)}>
|
|
||||||
<span className="Button-icon">{unread || icon('bell')}</span>
|
|
||||||
<span className="Button-label">{app.trans('core.notifications')}</span>
|
|
||||||
</a>
|
|
||||||
<div className="Dropdown-menu Dropdown-menu--right" onclick={this.menuClick.bind(this)}>
|
|
||||||
{this.showing ? this.list.render() : ''}
|
{this.showing ? this.list.render() : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onclick() {
|
onclick() {
|
||||||
if (app.drawer.isOpen()) {
|
if (app.drawer.isOpen()) {
|
||||||
m.route(app.route('notifications'));
|
this.goToRoute();
|
||||||
} else {
|
} else {
|
||||||
this.showing = true;
|
this.showing = true;
|
||||||
this.list.load();
|
this.list.load();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goToRoute() {
|
||||||
|
m.route(app.route('notifications'));
|
||||||
|
}
|
||||||
|
|
||||||
|
getUnreadCount() {
|
||||||
|
return app.session.user.unreadNotificationsCount();
|
||||||
|
}
|
||||||
|
|
||||||
menuClick(e) {
|
menuClick(e) {
|
||||||
// Don't close the notifications dropdown if the user is opening a link in a
|
// Don't close the notifications dropdown if the user is opening a link in a
|
||||||
// new tab or window.
|
// new tab or window.
|
||||||
|
@ -23,20 +23,18 @@ export default class Dropdown extends Component {
|
|||||||
|
|
||||||
props.className = props.className || '';
|
props.className = props.className || '';
|
||||||
props.buttonClassName = props.buttonClassName || '';
|
props.buttonClassName = props.buttonClassName || '';
|
||||||
props.contentClassName = props.contentClassName || '';
|
props.menuClassName = props.menuClassName || '';
|
||||||
props.label = props.label || app.trans('core.controls');
|
props.label = props.label || app.trans('core.controls');
|
||||||
props.caretIcon = typeof props.caretIcon !== 'undefined' ? props.caretIcon : 'caret-down';
|
props.caretIcon = typeof props.caretIcon !== 'undefined' ? props.caretIcon : 'caret-down';
|
||||||
}
|
}
|
||||||
|
|
||||||
view() {
|
view() {
|
||||||
const items = listItems(this.props.children);
|
const items = this.props.children ? listItems(this.props.children) : [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'ButtonGroup Dropdown dropdown ' + this.props.className + ' itemCount' + items.length}>
|
<div className={'ButtonGroup Dropdown dropdown ' + this.props.className + ' itemCount' + items.length}>
|
||||||
{this.getButton()}
|
{this.getButton()}
|
||||||
<ul className={'Dropdown-menu dropdown-menu ' + this.props.menuClassName}>
|
{this.getMenu(items)}
|
||||||
{items}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -94,4 +92,12 @@ export default class Dropdown extends Component {
|
|||||||
this.props.caretIcon ? icon(this.props.caretIcon, {className: 'Button-caret'}) : ''
|
this.props.caretIcon ? icon(this.props.caretIcon, {className: 'Button-caret'}) : ''
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMenu(items) {
|
||||||
|
return (
|
||||||
|
<ul className={'Dropdown-menu dropdown-menu ' + this.props.menuClassName}>
|
||||||
|
{items}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,10 +76,9 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
.Notification {
|
.Notification {
|
||||||
> a {
|
|
||||||
display: block;
|
display: block;
|
||||||
padding: 8px 15px 8px 70px;
|
padding: 8px 15px 8px 70px;
|
||||||
color: @muted-color;
|
color: @muted-color !important; // required to override .light-contents applied to header
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.unread& {
|
.unread& {
|
||||||
@ -89,7 +88,6 @@
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
background: @control-bg;
|
background: @control-bg;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.Avatar {
|
.Avatar {
|
||||||
.Avatar--size(24px);
|
.Avatar--size(24px);
|
||||||
float: left;
|
float: left;
|
||||||
|
@ -24,21 +24,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.NotificationsDropdown-button.unread .Button-icon {
|
.NotificationsDropdown .Dropdown-toggle.unread .Button-icon {
|
||||||
display: inline-block;
|
color: @header-color;
|
||||||
border-radius: 12px;
|
}
|
||||||
height: 24px;
|
.NotificationsDropdown-unread {
|
||||||
width: 24px;
|
position: absolute;
|
||||||
text-align: center;
|
top: 1px;
|
||||||
padding: 2px 0;
|
right: 1px;
|
||||||
font-weight: bold;
|
background: @header-color;
|
||||||
margin: -2px 0;
|
color: @header-bg;
|
||||||
background: @primary-color;
|
font-size: 11px;
|
||||||
color: @body-bg;
|
font-weight: bold;
|
||||||
font-size: 13px;
|
padding: 2px 5px 3px;
|
||||||
vertical-align: 0;
|
line-height: 1em;
|
||||||
|
border-radius: 10px;
|
||||||
& when (@config-colored-header = true) {
|
border: 1px solid @header-bg;
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user