mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-05 17:02:47 +00:00
change UI 1
This commit is contained in:
@@ -5,6 +5,7 @@ import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import { gettext, siteRoot } from '../../utils/constants';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import { processor } from '@seafile/seafile-editor';
|
||||
import '../../css/notice-item.css';
|
||||
|
||||
const propTypes = {
|
||||
noticeItem: PropTypes.object.isRequired,
|
||||
@@ -38,35 +39,26 @@ class NoticeItem extends React.Component {
|
||||
let detail = noticeItem.detail;
|
||||
|
||||
if (noticeType === MSG_TYPE_ADD_USER_TO_GROUP) {
|
||||
|
||||
let avatar_url = detail.group_staff_avatar_url;
|
||||
|
||||
let groupStaff = detail.group_staff_name;
|
||||
|
||||
// group name does not support special characters
|
||||
let userHref = siteRoot + 'profile/' + detail.group_staff_email + '/';
|
||||
let groupHref = siteRoot + 'group/' + detail.group_id + '/';
|
||||
let groupName = detail.group_name;
|
||||
|
||||
let username = detail.group_staff_name;
|
||||
let notice = gettext('User {user_link} has added you to {group_link}');
|
||||
let userLink = '<a href=' + userHref + '>' + groupStaff + '</a>';
|
||||
let groupLink = '<a href=' + groupHref + '>' + groupName + '</a>';
|
||||
|
||||
notice = notice.replace('{user_link}', userLink);
|
||||
notice = notice.replace('{group_link}', groupLink);
|
||||
|
||||
return { avatar_url, notice };
|
||||
return { avatar_url, notice, username };
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_REPO_SHARE) {
|
||||
|
||||
let avatar_url = detail.share_from_user_avatar_url;
|
||||
|
||||
let shareFrom = detail.share_from_user_name;
|
||||
|
||||
let repoName = detail.repo_name;
|
||||
let repoUrl = siteRoot + 'library/' + detail.repo_id + '/' + repoName + '/';
|
||||
|
||||
let path = detail.path;
|
||||
let notice = '';
|
||||
// 1. handle translate
|
||||
@@ -75,21 +67,17 @@ class NoticeItem extends React.Component {
|
||||
} else { // share folder
|
||||
notice = gettext('{share_from} has shared a folder named {repo_link} to you.');
|
||||
}
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{share_from}', shareFrom);
|
||||
notice = notice.replace('{repo_link}', `{tagA}${repoName}{/tagA}`);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
|
||||
// 3. add jump link
|
||||
notice = notice.replace('{tagA}', `<a href='${Utils.encodePath(repoUrl)}'>`);
|
||||
notice = notice.replace('{/tagA}', '</a>');
|
||||
|
||||
return { avatar_url, notice };
|
||||
return { avatar_url, notice, username: shareFrom };
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_REPO_SHARE_PERM_CHANGE) {
|
||||
|
||||
let avatar_url = detail.share_from_user_avatar_url;
|
||||
let shareFrom = detail.share_from_user_name;
|
||||
let permission = detail.permission;
|
||||
@@ -103,22 +91,18 @@ class NoticeItem extends React.Component {
|
||||
} else { // share folder
|
||||
notice = gettext('{share_from} has changed the permission of folder {repo_link} to {permission}.');
|
||||
}
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{share_from}', shareFrom);
|
||||
notice = notice.replace('{repo_link}', `{tagA}${repoName}{/tagA}`);
|
||||
notice = notice.replace('{permission}', permission);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
|
||||
// 3. add jump link
|
||||
notice = notice.replace('{tagA}', `<a href='${Utils.encodePath(repoUrl)}'>`);
|
||||
notice = notice.replace('{/tagA}', '</a>');
|
||||
|
||||
return { avatar_url, notice };
|
||||
return { avatar_url, notice, username: shareFrom };
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_REPO_SHARE_PERM_DELETE) {
|
||||
|
||||
let avatar_url = detail.share_from_user_avatar_url;
|
||||
let shareFrom = detail.share_from_user_name;
|
||||
let repoName = detail.repo_name;
|
||||
@@ -130,26 +114,20 @@ class NoticeItem extends React.Component {
|
||||
} else { // share folder
|
||||
notice = gettext('{share_from} has cancelled the sharing of folder {repo_name}.');
|
||||
}
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{share_from}', shareFrom);
|
||||
notice = notice.replace('{repo_name}', repoName);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
return { avatar_url, notice };
|
||||
return { avatar_url, notice, username: shareFrom };
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_REPO_SHARE_TO_GROUP) {
|
||||
|
||||
let avatar_url = detail.share_from_user_avatar_url;
|
||||
|
||||
let shareFrom = detail.share_from_user_name;
|
||||
|
||||
let repoName = detail.repo_name;
|
||||
let repoUrl = siteRoot + 'library/' + detail.repo_id + '/' + repoName + '/';
|
||||
|
||||
let groupUrl = siteRoot + 'group/' + detail.group_id + '/';
|
||||
let groupName = detail.group_name;
|
||||
|
||||
let path = detail.path;
|
||||
let notice = '';
|
||||
// 1. handle translate
|
||||
@@ -158,60 +136,50 @@ class NoticeItem extends React.Component {
|
||||
} else {
|
||||
notice = gettext('{share_from} has shared a folder named {repo_link} to group {group_link}.');
|
||||
}
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{share_from}', shareFrom);
|
||||
notice = notice.replace('{repo_link}', `{tagA}${repoName}{/tagA}`);
|
||||
notice = notice.replace('{group_link}', `{tagB}${groupName}{/tagB}`);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
|
||||
// 3. add jump link
|
||||
notice = notice.replace('{tagA}', `<a href='${Utils.encodePath(repoUrl)}'>`);
|
||||
notice = notice.replace('{/tagA}', '</a>');
|
||||
notice = notice.replace('{tagB}', `<a href='${Utils.encodePath(groupUrl)}'>`);
|
||||
notice = notice.replace('{/tagB}', '</a>');
|
||||
return { avatar_url, notice };
|
||||
return { avatar_url, notice, username: shareFrom };
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_REPO_TRANSFER) {
|
||||
|
||||
let avatar_url = detail.transfer_from_user_avatar_url;
|
||||
|
||||
let repoOwner = detail.transfer_from_user_name;
|
||||
|
||||
let repoName = detail.repo_name;
|
||||
let repoUrl = siteRoot + 'library/' + detail.repo_id + '/' + repoName + '/';
|
||||
// 1. handle translate
|
||||
let notice = gettext('{user} has transfered a library named {repo_link} to you.');
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{user}', repoOwner);
|
||||
notice = notice.replace('{repo_link}', `{tagA}${repoName}{/tagA}`);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
|
||||
// 3. add jump link
|
||||
notice = notice.replace('{tagA}', `<a href=${Utils.encodePath(repoUrl)}>`);
|
||||
notice = notice.replace('{/tagA}', '</a>');
|
||||
return { avatar_url, notice };
|
||||
return { avatar_url, notice, username: repoOwner };
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_FILE_UPLOADED) {
|
||||
let avatar_url = detail.uploaded_user_avatar_url;
|
||||
let fileName = detail.file_name;
|
||||
let fileLink = siteRoot + 'lib/' + detail.repo_id + '/' + 'file' + detail.file_path;
|
||||
|
||||
let folderName = detail.folder_name;
|
||||
let folderLink = siteRoot + 'library/' + detail.repo_id + '/' + detail.repo_name + detail.folder_path;
|
||||
let notice = '';
|
||||
if (detail.repo_id) { // todo is repo exist ?
|
||||
// 1. handle translate
|
||||
notice = gettext('A file named {upload_file_link} is uploaded to {uploaded_link}.');
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{upload_file_link}', `{tagA}${fileName}{/tagA}`);
|
||||
notice = notice.replace('{uploaded_link}', `{tagB}${folderName}{/tagB}`);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
|
||||
// 3. add jump link
|
||||
notice = notice.replace('{tagA}', `<a href=${Utils.encodePath(fileLink)}>`);
|
||||
notice = notice.replace('{/tagA}', '</a>');
|
||||
@@ -220,7 +188,6 @@ class NoticeItem extends React.Component {
|
||||
} else {
|
||||
// 1. handle translate
|
||||
notice = gettext('A file named {upload_file_link} is uploaded.');
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{upload_file_link}', `${fileName}`);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
@@ -344,17 +311,11 @@ class NoticeItem extends React.Component {
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_DELETED_FILES) {
|
||||
const {
|
||||
repo_id,
|
||||
repo_name,
|
||||
} = detail;
|
||||
|
||||
const { repo_id, repo_name } = detail;
|
||||
const repoURL = `${siteRoot}library/${repo_id}/${encodeURIComponent(repo_name)}/`;
|
||||
const repoLink = `<a href=${repoURL} target="_blank">${Utils.HTMLescape(repo_name)}</a>`;
|
||||
|
||||
let notice = gettext('Your library {libraryName} has recently deleted a large number of files.');
|
||||
notice = notice.replace('{libraryName}', repoLink);
|
||||
|
||||
return { avatar_url: null, notice };
|
||||
}
|
||||
|
||||
@@ -374,7 +335,6 @@ class NoticeItem extends React.Component {
|
||||
if (noticeType === MSG_TYPE_SAML_SSO_FAILED) {
|
||||
const { error_msg } = detail;
|
||||
let notice = gettext(error_msg);
|
||||
|
||||
return { avatar_url: null, notice };
|
||||
}
|
||||
|
||||
@@ -424,7 +384,7 @@ class NoticeItem extends React.Component {
|
||||
|
||||
// }
|
||||
|
||||
return { avatar_url: null, notice: null };
|
||||
return { avatar_url: null, notice: null, username: null };
|
||||
}
|
||||
|
||||
onNoticeItemClick = () => {
|
||||
@@ -455,18 +415,21 @@ class NoticeItem extends React.Component {
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
<li onClick={this.onNoticeItemClick} className={noticeItem.seen ? 'read' : 'unread'}>
|
||||
<div className="notice-item">
|
||||
<div className="main-info">
|
||||
<div className="auther-info">
|
||||
<img src={avatar_url} width="32" height="32" className="avatar" alt=""/>
|
||||
<p>{username}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="brief" dangerouslySetInnerHTML={{ __html: notice }}></p>
|
||||
<li className='notification-item' onClick={this.onNoticeItemClick}>
|
||||
<div className="notification-item-header">
|
||||
{!noticeItem.seen &&
|
||||
<span className="notification-point" onClick={this.onMarkNotificationRead}></span>
|
||||
}
|
||||
<div className="notification-header-info">
|
||||
<div className="notification-user-detail">
|
||||
<img className="notification-user-avatar" src={avatar_url} alt="" />
|
||||
<span className="ml-2 notification-user-name">{username || gettext('System')}</span>
|
||||
</div>
|
||||
<span className="notification-time">{dayjs(noticeItem.time).fromNow()}</span>
|
||||
</div>
|
||||
<p className="time">{dayjs(noticeItem.time).fromNow()}</p>
|
||||
</div>
|
||||
<div className="notification-content-wrapper">
|
||||
<div dangerouslySetInnerHTML={{ __html: notice }}></div>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
|
@@ -66,7 +66,7 @@
|
||||
}
|
||||
|
||||
.notification-container .mark-all-read {
|
||||
color: #b4b4b4;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -187,6 +187,9 @@
|
||||
|
||||
.notification-container .notification-body .mark-notifications {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #ededed;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.notification-container .notification-body .mark-notifications .mark-all-read:hover {
|
||||
@@ -198,8 +201,9 @@
|
||||
margin-right: 15px;
|
||||
margin-left: 15px;
|
||||
font-size: 14px;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.notification-container .notification-body .nav .nav-item .nav-link.active {
|
||||
color: #ED7109 !important;
|
||||
}
|
||||
color: #ED7109;
|
||||
}
|
||||
|
@@ -18,6 +18,8 @@ export default class NotificationPopover extends React.Component {
|
||||
tabItemClick: PropTypes.func,
|
||||
children: PropTypes.any,
|
||||
currentTab: PropTypes.string,
|
||||
generalNoticeListUnseen: PropTypes.number,
|
||||
discussionNoticeListUnseen: PropTypes.number,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
@@ -56,7 +58,7 @@ export default class NotificationPopover extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { headerText, bodyText, footerText, currentTab } = this.props;
|
||||
const { headerText, bodyText, footerText, currentTab, generalNoticeListUnseen, discussionNoticeListUnseen } = this.props;
|
||||
return (
|
||||
<Popover
|
||||
className="notification-wrapper"
|
||||
@@ -77,11 +79,13 @@ export default class NotificationPopover extends React.Component {
|
||||
<li className="nav-item" onClick={() => this.tabItemClick('general')}>
|
||||
<span className={`nav-link ${currentTab === 'general' ? 'active' : ''}`}>
|
||||
{gettext('General')}
|
||||
{generalNoticeListUnseen > 0 && <span>({generalNoticeListUnseen})</span>}
|
||||
</span>
|
||||
</li>
|
||||
<li className="nav-item" onClick={() => this.tabItemClick('discussion')}>
|
||||
<span className={`nav-link ${currentTab === 'discussion' ? 'active' : ''}`}>
|
||||
{gettext('Discussion')}
|
||||
{discussionNoticeListUnseen > 0 && <span>({discussionNoticeListUnseen})</span>}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -103,23 +107,6 @@ export default class NotificationPopover extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
{/* <div className="mark-notifications" onClick={this.props.onMarkAllNotifications}>
|
||||
<ul className="nav dtable-external-links-tab">
|
||||
<li className="nav-item">
|
||||
<span className="nav-link">General</span>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<span className="nav-link">Discussion</span>
|
||||
</li>
|
||||
</ul>
|
||||
<span className="mark-all-read">{bodyText}</span>
|
||||
</div>
|
||||
<div className="notification-list-container" onScroll={this.onHandleScroll} ref={ref => this.notificationListRef = ref}>
|
||||
<div ref={ref => this.notificationsWrapperRef = ref}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="notification-footer" onClick={this.onNotificationDialogToggle}>{footerText}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -123,7 +123,9 @@ class Notification extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { unseenCount, currentTab } = this.state;
|
||||
const { unseenCount, currentTab, generalNoticeList, discussionNoticeList } = this.state;
|
||||
const generalNoticeListUnseen = generalNoticeList.filter(item => !item.seen).length;
|
||||
const discussionNoticeListUnseen = discussionNoticeList.filter(item => !item.seen).length;
|
||||
return (
|
||||
<div id="notifications">
|
||||
<a href="#" onClick={this.onClick} className="no-deco" id="notice-icon" title={gettext('Notifications')} aria-label={gettext('Notifications')}>
|
||||
@@ -140,25 +142,35 @@ class Notification extends React.Component {
|
||||
onNotificationDialogToggle={this.onNotificationDialogToggle}
|
||||
onMarkAllNotifications={this.onMarkAllNotifications}
|
||||
tabItemClick={this.tabItemClick}
|
||||
generalNoticeListUnseen={generalNoticeListUnseen}
|
||||
discussionNoticeListUnseen={discussionNoticeListUnseen}
|
||||
>
|
||||
{this.state.currentTab === 'general' &&
|
||||
{currentTab === 'general' &&
|
||||
<ul className="notice-list list-unstyled" id="notice-popover">
|
||||
{this.state.generalNoticeList.map(item => {
|
||||
return (<NoticeItem key={item.id} noticeItem={item} onNoticeItemClick={this.onNoticeItemClick}/>);
|
||||
{generalNoticeList.map(item => {
|
||||
return (
|
||||
<NoticeItem key={item.id} noticeItem={item} onNoticeItemClick={this.onNoticeItemClick}/>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
}
|
||||
{this.state.currentTab === 'discussion' &&
|
||||
{currentTab === 'discussion' &&
|
||||
<ul className="notice-list list-unstyled" id="notice-popover">
|
||||
{this.state.discussionNoticeList.map(item => {
|
||||
return (<NoticeItem key={item.id} noticeItem={item} onNoticeItemClick={this.onNoticeItemClick}/>);
|
||||
{discussionNoticeList.map(item => {
|
||||
return (
|
||||
<NoticeItem key={item.id} noticeItem={item} onNoticeItemClick={this.onNoticeItemClick}/>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
}
|
||||
</NotificationPopover>
|
||||
}
|
||||
{this.state.isShowNotificationDialog &&
|
||||
<UserNotificationsDialog onNotificationDialogToggle={this.onNotificationDialogToggle} />
|
||||
<UserNotificationsDialog
|
||||
onNotificationDialogToggle={this.onNotificationDialogToggle}
|
||||
generalNoticeListUnseen={generalNoticeListUnseen}
|
||||
discussionNoticeListUnseen={discussionNoticeListUnseen}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
94
frontend/src/css/notice-item.css
Normal file
94
frontend/src/css/notice-item.css
Normal file
@@ -0,0 +1,94 @@
|
||||
.notification-item {
|
||||
padding: 14px 16px 14px 10px;
|
||||
border-bottom: 1px solid #ededed;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.notification-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.notification-item:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.notification-item .notification-item-header {
|
||||
display: flex;
|
||||
align-items: center
|
||||
}
|
||||
|
||||
.notification-item .notification-point {
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: red;
|
||||
margin-right: 12px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.notification-item .notification-header-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
margin-left: 20px;
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
|
||||
.notification-item .notification-user-detail {
|
||||
display: flex;
|
||||
width: 65%;
|
||||
}
|
||||
|
||||
.notification-item .notification-user-detail .notification-user-avatar {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-top: 3px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.notification-item .notification-user-detail .notification-user-name {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
font-weight: 500;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.notification-item .notification-header-info .notification-time {
|
||||
color: #666;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.notification-item .notification-content-wrapper {
|
||||
font-size: 13px;
|
||||
margin-left: 52px;
|
||||
}
|
||||
|
||||
.notification-item .notification-content-quotes {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.notification-item .notification-comment-content {
|
||||
max-width: calc(100% - 16px);
|
||||
}
|
||||
|
||||
.notification-item .notification-comment-content p {
|
||||
display: inline-block;
|
||||
letter-spacing: 1px;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.notification-item .notification-comment-content p img {
|
||||
max-width: 70%;
|
||||
height: auto;
|
||||
max-height: 60px;
|
||||
}
|
@@ -56,44 +56,11 @@
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
#notice-popover li {
|
||||
padding: 9px 0 3px;
|
||||
border-bottom: 1px solid #dfdfe1;
|
||||
}
|
||||
|
||||
#notice-popover li.unread {
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
border-left: 2px solid #feac74;
|
||||
}
|
||||
|
||||
#notice-popover li.read {
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
border-left: 2px solid transparent;
|
||||
}
|
||||
|
||||
#notice-popover li:hover {
|
||||
background: #f5f5f7;
|
||||
}
|
||||
|
||||
#notice-popover li.read:hover {
|
||||
background: #f5f5f7;
|
||||
border-left: 2px solid #dfdfe1;
|
||||
}
|
||||
|
||||
#notice-popover .avatar {
|
||||
border-radius: 1000px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#notice-popover .brief {
|
||||
margin-left: 40px;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
#notice-popover .time {
|
||||
margin: 0;
|
||||
color: #999;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
.notification-list-dialog {
|
||||
width: 720px;
|
||||
width: calc(100% - 20rem);
|
||||
max-width: calc(100% - 1rem);
|
||||
height: calc(100% - 56px);
|
||||
}
|
||||
@@ -35,10 +35,26 @@
|
||||
|
||||
.notification-list-content .notification-modal-body {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
min-height: 27rem;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.notification-list-content .notification-modal-body .notice-dialog-side {
|
||||
border-right: 1px solid #eee;
|
||||
display: flex;
|
||||
flex: 0 0 20%;
|
||||
padding: 12px 8px;
|
||||
}
|
||||
|
||||
.notification-list-content .notification-modal-body .notice-dialog-main {
|
||||
display: flex;
|
||||
flex: 0 0 80%;
|
||||
overflow: inherit;
|
||||
}
|
||||
|
||||
.notification-modal-body .notification-dialog-body {
|
||||
overflow: auto;
|
||||
padding: 2rem 1rem;
|
||||
@@ -80,22 +96,3 @@
|
||||
font-size: 14px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.wechat-dialog-body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 3rem;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.wechat-dialog-message {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 1rem;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Modal, ModalHeader, ModalBody, Dropdown, DropdownToggle, DropdownMenu, DropdownItem, TabPane, Nav, NavItem, NavLink, TabContent } from 'reactstrap';
|
||||
import { Utils } from './utils/utils';
|
||||
@@ -209,19 +209,22 @@ class UserNotificationsDialog extends React.Component {
|
||||
|
||||
|
||||
renderNoticeContent = (content) => {
|
||||
const { generalNoticeListUnseen, discussionNoticeListUnseen } = this.props;
|
||||
let activeTab = this.state.activeTab;
|
||||
return (
|
||||
<Fragment>
|
||||
<>
|
||||
<div className="notice-dialog-side">
|
||||
<Nav pills>
|
||||
<Nav pills className="flex-column">
|
||||
<NavItem role="tab" aria-selected={activeTab === 'general'} aria-controls="general-notice-panel">
|
||||
<NavLink className={activeTab === 'general' ? 'active' : ''} onClick={this.tabItemClick} tabIndex="0" value="general">
|
||||
{gettext('General')}
|
||||
{generalNoticeListUnseen > 0 && <span>({generalNoticeListUnseen})</span>}
|
||||
</NavLink>
|
||||
</NavItem>
|
||||
<NavItem role="tab" aria-selected={activeTab === 'discussion'} aria-controls="discussion-notice-panel">
|
||||
<NavLink className={activeTab === 'discussion' ? 'active' : ''} onClick={this.tabItemClick} tabIndex="1" value="discussion">
|
||||
{gettext('Discussion')}
|
||||
{discussionNoticeListUnseen > 0 && <span>({discussionNoticeListUnseen})</span>}
|
||||
</NavLink>
|
||||
</NavItem>
|
||||
</Nav>
|
||||
@@ -229,24 +232,22 @@ class UserNotificationsDialog extends React.Component {
|
||||
<div className="notice-dialog-main">
|
||||
<TabContent activeTab={this.state.activeTab}>
|
||||
{activeTab === 'general' &&
|
||||
<TabPane tabId="general" role="tabpanel" id="general-notice-panel">
|
||||
<div className="notification-dialog-body" ref={ref => this.notificationTableRef = ref}
|
||||
onScroll={this.onHandleScroll}>
|
||||
<TabPane tabId="general" role="tabpanel" id="general-notice-panel" className="h-100">
|
||||
<div className="notification-dialog-body" ref={ref => this.notificationTableRef = ref} onScroll={this.onHandleScroll}>
|
||||
{content}
|
||||
</div>
|
||||
</TabPane>
|
||||
}
|
||||
{activeTab === 'discussion' &&
|
||||
<TabPane tabId="discussion" role="tabpanel" id="discussion-notice-panel">
|
||||
<div className="notification-dialog-body" ref={ref => this.notificationTableRef = ref}
|
||||
onScroll={this.onHandleScroll}>
|
||||
<TabPane tabId="discussion" role="tabpanel" id="discussion-notice-panel" className="h-100">
|
||||
<div className="notification-dialog-body" ref={ref => this.notificationTableRef = ref} onScroll={this.onHandleScroll}>
|
||||
{content}
|
||||
</div>
|
||||
</TabPane>
|
||||
}
|
||||
</TabContent>
|
||||
</div>
|
||||
</Fragment>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -278,7 +279,9 @@ class UserNotificationsDialog extends React.Component {
|
||||
</thead>
|
||||
<tbody>
|
||||
{items.map((item, index) => {
|
||||
return (<NoticeItem key={index} noticeItem={item} tr={true} />);
|
||||
return (
|
||||
<NoticeItem key={index} noticeItem={item} tr={true} />
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -289,8 +292,14 @@ class UserNotificationsDialog extends React.Component {
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal isOpen={true} toggle={this.toggle} className="notification-list-dialog" contentClassName="notification-list-content"
|
||||
zIndex={1046}>
|
||||
<Modal
|
||||
isOpen={true}
|
||||
size={'lg'}
|
||||
toggle={this.toggle}
|
||||
className="notification-list-dialog"
|
||||
contentClassName="notification-list-content"
|
||||
zIndex={1046}
|
||||
>
|
||||
<ModalHeader close={this.renderHeaderRowBtn()} toggle={this.toggle}>{gettext('Notifications')}</ModalHeader>
|
||||
<ModalBody className="notification-modal-body">
|
||||
{this.renderNoticeContent(content)}
|
||||
|
Reference in New Issue
Block a user