mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-15 23:00:57 +00:00
change wikis list style (#6125)
This commit is contained in:
40
frontend/src/components/wiki-card-view/wiki-card-group.js
Normal file
40
frontend/src/components/wiki-card-view/wiki-card-group.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { gettext, username } from '../../utils/constants';
|
||||
import WikiCardItem from './wiki-card-item';
|
||||
|
||||
const propTypes = {
|
||||
wikis: PropTypes.array.isRequired,
|
||||
deleteWiki: PropTypes.func.isRequired,
|
||||
owner: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
class WikiCardGroup extends Component {
|
||||
render() {
|
||||
let { wikis, owner } = this.props;
|
||||
return (
|
||||
<div className='wiki-card-group'>
|
||||
<h4 className="sf-heading my-4">
|
||||
<span className={`sf3-font nav-icon sf3-font-${username === owner ? 'mine' : 'department'}`} aria-hidden="true"></span>
|
||||
{username === owner ? gettext('My Wikis') : wikis[0].owner_nickname}
|
||||
</h4>
|
||||
<div className='wiki-card-group-items'>
|
||||
{wikis.map((wiki, index) => {
|
||||
return (
|
||||
<WikiCardItem
|
||||
key={index}
|
||||
wiki={wiki}
|
||||
deleteWiki={this.props.deleteWiki}
|
||||
owner={owner}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
WikiCardGroup.propTypes = propTypes;
|
||||
|
||||
export default WikiCardGroup;
|
132
frontend/src/components/wiki-card-view/wiki-card-item.js
Normal file
132
frontend/src/components/wiki-card-view/wiki-card-item.js
Normal file
@@ -0,0 +1,132 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
|
||||
import PropTypes from 'prop-types';
|
||||
import moment from 'moment';
|
||||
import { siteRoot, gettext, appAvatarURL, username } from '../../utils/constants';
|
||||
import ModalPortal from '../modal-portal';
|
||||
import WikiDeleteDialog from '../dialog/wiki-delete-dialog';
|
||||
|
||||
const propTypes = {
|
||||
owner: PropTypes.string.isRequired,
|
||||
wiki: PropTypes.object.isRequired,
|
||||
deleteWiki: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
class WikiCardItem extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isShowDeleteDialog: false,
|
||||
isItemMenuShow: false,
|
||||
};
|
||||
}
|
||||
|
||||
onDeleteToggle = (e) => {
|
||||
e.preventDefault();
|
||||
this.setState({
|
||||
isShowDeleteDialog: !this.state.isShowDeleteDialog,
|
||||
});
|
||||
};
|
||||
|
||||
onDeleteCancel = () => {
|
||||
this.setState({
|
||||
isShowDeleteDialog: !this.state.isShowDeleteDialog,
|
||||
});
|
||||
};
|
||||
|
||||
deleteWiki = () => {
|
||||
let wiki = this.props.wiki;
|
||||
this.props.deleteWiki(wiki);
|
||||
this.setState({
|
||||
isShowDeleteDialog: !this.state.isShowDeleteDialog,
|
||||
});
|
||||
};
|
||||
|
||||
clickWikiCard = (link) => {
|
||||
window.open(link);
|
||||
};
|
||||
|
||||
toggleDropDownMenu = () => {
|
||||
this.setState({isItemMenuShow: !this.state.isItemMenuShow});
|
||||
};
|
||||
|
||||
onClickDropdown = (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
renderAvatar = () => {
|
||||
const { wiki } = this.props;
|
||||
// const userProfileURL = `${siteRoot}profile/${encodeURIComponent(wiki.owner)}/`;
|
||||
return (
|
||||
<div className="wiki-card-item-avatar-container">
|
||||
<img src={appAvatarURL} className="avatar mr-1" alt={gettext('Avatar')} />
|
||||
<span title={wiki.owner_nickname}>{wiki.owner_nickname}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
renderDept = () => {
|
||||
const { wiki } = this.props;
|
||||
return (
|
||||
<div className="wiki-card-item-avatar-container">
|
||||
<span className='sf3-font-department sf3-font nav-icon mr-1'></span>
|
||||
<span title={wiki.owner_nickname}>{wiki.owner_nickname}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { owner, wiki } = this.props;
|
||||
let isOldVersion = wiki.version !== 'v2';
|
||||
let publishedUrl = `${siteRoot}published/${encodeURIComponent(wiki.slug)}/`;
|
||||
let editUrl = `${siteRoot}wikis/${wiki.id}/`;
|
||||
let wikiName = isOldVersion ? <>{wiki.name} (old version)</> : <>{wiki.name}</>;
|
||||
return (
|
||||
<>
|
||||
<div className="wiki-card-item" onClick={this.clickWikiCard.bind(this, isOldVersion ? publishedUrl : editUrl )}>
|
||||
<div className="wiki-card-item-top">
|
||||
<div className="d-flex align-items-center">
|
||||
<span className="sf3-font-wiki sf3-font" aria-hidden="true"></span>
|
||||
<span className="wiki-card-item-name ml-2 text-truncate">{wikiName}</span>
|
||||
</div>
|
||||
<Dropdown isOpen={this.state.isItemMenuShow} toggle={this.toggleDropDownMenu} onClick={this.onClickDropdown}>
|
||||
<DropdownToggle
|
||||
tag="i"
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
className="sf-dropdown-toggle sf3-font-more sf3-font"
|
||||
title={gettext('More operations')}
|
||||
aria-label={gettext('More operations')}
|
||||
data-toggle="dropdown"
|
||||
aria-expanded={this.state.isItemMenuShow}
|
||||
aria-haspopup={true}
|
||||
style={{'minWidth': '0'}}
|
||||
/>
|
||||
<DropdownMenu right={true} className="dtable-dropdown-menu">
|
||||
{/* <DropdownItem onClick={}>{gettext('Rename')}</DropdownItem> */}
|
||||
<DropdownItem onClick={this.onDeleteToggle}>{gettext('Unpublish')}</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</div>
|
||||
<div className="wiki-card-item-bottom">
|
||||
{owner === username ? this.renderAvatar() : this.renderDept()}
|
||||
<span className="wiki-item-updated-time">{moment(wiki.updated_at).fromNow()}</span>
|
||||
</div>
|
||||
</div>
|
||||
{this.state.isShowDeleteDialog &&
|
||||
<ModalPortal>
|
||||
<WikiDeleteDialog
|
||||
toggleCancel={this.onDeleteCancel}
|
||||
handleSubmit={this.deleteWiki}
|
||||
/>
|
||||
</ModalPortal>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
WikiCardItem.propTypes = propTypes;
|
||||
|
||||
export default WikiCardItem;
|
93
frontend/src/components/wiki-card-view/wiki-card-view.css
Normal file
93
frontend/src/components/wiki-card-view/wiki-card-view.css
Normal file
@@ -0,0 +1,93 @@
|
||||
.wiki-card-group-items {
|
||||
display: grid;
|
||||
grid-template-columns: 32.5% 32.5% 32.5%;
|
||||
gap: 16px 16px;
|
||||
}
|
||||
|
||||
.wiki-card-item {
|
||||
height: 120px;
|
||||
width: 100%;
|
||||
border: 1px solid #EEEEEE;
|
||||
padding: 20px;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wiki-card-item:hover {
|
||||
border: 1px solid #DBDBDB;
|
||||
}
|
||||
|
||||
.wiki-card-item .wiki-card-item-top,
|
||||
.wiki-card-item .wiki-card-item-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.wiki-card-item .wiki-item-updated-time {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.wiki-card-item .wiki-card-item-top .sf3-font-wiki.sf3-font {
|
||||
color: #FF8900;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.wiki-card-item .wiki-card-item-top .wiki-card-item-name {
|
||||
max-width: 250px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.wiki-card-item .wiki-card-item-top .dropdown .sf-dropdown-toggle {
|
||||
border: 1px solid #dbdbdb;
|
||||
padding: 2px 4px;
|
||||
border-radius: 3px;
|
||||
opacity: 0;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.wiki-card-item:hover .wiki-card-item-top .dropdown .sf-dropdown-toggle {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.wiki-card-item:hover .wiki-card-item-top .dropdown .sf-dropdown-toggle:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.wiki-card-item .wiki-card-item-avatar-container {
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1px solid #EEEEEE;
|
||||
border-radius: 10px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.wiki-card-item .wiki-card-item-avatar-container .avatar {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.wiki-card-item .wiki-card-item-avatar-container span {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.wiki-card-item .wiki-card-item-avatar-container .sf3-font-department {
|
||||
font-size: 1rem;
|
||||
line-height: 1;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.wiki-card-group-items {
|
||||
display: grid;
|
||||
grid-template-columns: 100%;
|
||||
}
|
||||
.wiki-card-item .wiki-card-item-top .dropdown .sf-dropdown-toggle {
|
||||
border: none;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
63
frontend/src/components/wiki-card-view/wiki-card-view.js
Normal file
63
frontend/src/components/wiki-card-view/wiki-card-view.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { username } from '../../utils/constants';
|
||||
import WikiCardGroup from './wiki-card-group';
|
||||
import './wiki-card-view.css';
|
||||
|
||||
const propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
deleteWiki: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
class WikiCardView extends Component {
|
||||
|
||||
classifyWikis = (wikis) => {
|
||||
let myWikis = [];
|
||||
let department2WikisMap = {};
|
||||
for (let i = 0; i < wikis.length; i++) {
|
||||
if (wikis[i].owner === username) {
|
||||
myWikis.push(wikis[i]);
|
||||
continue;
|
||||
}
|
||||
if (!department2WikisMap[wikis[i].owner]) {
|
||||
department2WikisMap[wikis[i].owner] = [];
|
||||
}
|
||||
department2WikisMap[wikis[i].owner].push(wikis[i]);
|
||||
}
|
||||
return { department2WikisMap, myWikis };
|
||||
};
|
||||
|
||||
render() {
|
||||
let { loading, errorMsg, wikis } = this.props.data;
|
||||
|
||||
if (loading) {
|
||||
return <span className="loading-icon loading-tip"></span>;
|
||||
}
|
||||
if (errorMsg) {
|
||||
return <p className="error text-center">{errorMsg}</p>;
|
||||
}
|
||||
const { myWikis, department2WikisMap } = this.classifyWikis(wikis);
|
||||
let wikiCardGroups = [];
|
||||
wikiCardGroups.push(
|
||||
<WikiCardGroup
|
||||
deleteWiki={this.props.deleteWiki}
|
||||
wikis={myWikis}
|
||||
owner={username}
|
||||
/>
|
||||
);
|
||||
for (let key in department2WikisMap) {
|
||||
wikiCardGroups.push(
|
||||
<WikiCardGroup
|
||||
deleteWiki={this.props.deleteWiki}
|
||||
wikis={department2WikisMap[key]}
|
||||
owner={key}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return wikiCardGroups;
|
||||
}
|
||||
}
|
||||
|
||||
WikiCardView.propTypes = propTypes;
|
||||
|
||||
export default WikiCardView;
|
@@ -9,8 +9,8 @@ import ModalPortal from '../../components/modal-portal';
|
||||
import EmptyTip from '../../components/empty-tip';
|
||||
import CommonToolbar from '../../components/toolbar/common-toolbar';
|
||||
import AddWikiDialog from '../../components/dialog/add-wiki-dialog';
|
||||
import WikiListView from '../../components/wiki-list-view/wiki-list-view';
|
||||
import wikiAPI from '../../utils/wiki-api';
|
||||
import WikiCardView from '../../components/wiki-card-view/wiki-card-view';
|
||||
|
||||
const propTypes = {
|
||||
onShowSidePanel: PropTypes.func.isRequired,
|
||||
@@ -156,22 +156,24 @@ class Wikis extends Component {
|
||||
<h3 className="sf-heading m-0">{gettext('Wikis')}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div className="cur-view-content">
|
||||
{(this.state.loading || this.state.wikis.length !== 0) &&
|
||||
<WikiListView
|
||||
<div className="cur-view-content pb-4">
|
||||
<WikiCardView
|
||||
data={this.state}
|
||||
deleteWiki={this.deleteWiki}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
{(!this.state.loading && this.state.wikis.length === 0) &&
|
||||
<div className="cur-view-content">
|
||||
<EmptyTip>
|
||||
<h2>{gettext('No Wikis')}</h2>
|
||||
<p>{gettext('You have not any wikis yet.')}</p>
|
||||
<p>{gettext('A wiki can be accessed by anyone, not only users, via its URL.')}</p>
|
||||
<p>{gettext('You can add a wiki by clicking the "Add Wiki" button in the menu bar.')}</p>
|
||||
</EmptyTip>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
|
Reference in New Issue
Block a user