diff --git a/frontend/src/components/wiki-card-view/wiki-card-group.js b/frontend/src/components/wiki-card-view/wiki-card-group.js new file mode 100644 index 00000000000..1466f3c8131 --- /dev/null +++ b/frontend/src/components/wiki-card-view/wiki-card-group.js @@ -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 ( +
+

+ + {username === owner ? gettext('My Wikis') : wikis[0].owner_nickname} +

+
+ {wikis.map((wiki, index) => { + return ( + + ); + })} +
+
+ ); + } +} + +WikiCardGroup.propTypes = propTypes; + +export default WikiCardGroup; diff --git a/frontend/src/components/wiki-card-view/wiki-card-item.js b/frontend/src/components/wiki-card-view/wiki-card-item.js new file mode 100644 index 00000000000..c19c84b4ccc --- /dev/null +++ b/frontend/src/components/wiki-card-view/wiki-card-item.js @@ -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 ( +
+ {gettext('Avatar')} + {wiki.owner_nickname} +
+ ); + }; + + renderDept = () => { + const { wiki } = this.props; + return ( +
+ + {wiki.owner_nickname} +
+ ); + }; + + 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 ( + <> +
+
+
+ + {wikiName} +
+ + + + {/* {gettext('Rename')} */} + {gettext('Unpublish')} + + +
+
+ {owner === username ? this.renderAvatar() : this.renderDept()} + {moment(wiki.updated_at).fromNow()} +
+
+ {this.state.isShowDeleteDialog && + + + + } + + ); + } +} + +WikiCardItem.propTypes = propTypes; + +export default WikiCardItem; diff --git a/frontend/src/components/wiki-card-view/wiki-card-view.css b/frontend/src/components/wiki-card-view/wiki-card-view.css new file mode 100644 index 00000000000..a074ae77c08 --- /dev/null +++ b/frontend/src/components/wiki-card-view/wiki-card-view.css @@ -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; + } +} diff --git a/frontend/src/components/wiki-card-view/wiki-card-view.js b/frontend/src/components/wiki-card-view/wiki-card-view.js new file mode 100644 index 00000000000..771cdd8752e --- /dev/null +++ b/frontend/src/components/wiki-card-view/wiki-card-view.js @@ -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 ; + } + if (errorMsg) { + return

{errorMsg}

; + } + const { myWikis, department2WikisMap } = this.classifyWikis(wikis); + let wikiCardGroups = []; + wikiCardGroups.push( + + ); + for (let key in department2WikisMap) { + wikiCardGroups.push( + + ); + } + return wikiCardGroups; + } +} + +WikiCardView.propTypes = propTypes; + +export default WikiCardView; diff --git a/frontend/src/pages/wikis/wikis.js b/frontend/src/pages/wikis/wikis.js index c774a35fde0..1546dd8a192 100644 --- a/frontend/src/pages/wikis/wikis.js +++ b/frontend/src/pages/wikis/wikis.js @@ -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 {

{gettext('Wikis')}

-
- {(this.state.loading || this.state.wikis.length !== 0) && - + - } - {(!this.state.loading && this.state.wikis.length === 0) && +
+ } + {(!this.state.loading && this.state.wikis.length === 0) && +

{gettext('No Wikis')}

{gettext('You have not any wikis yet.')}

{gettext('A wiki can be accessed by anyone, not only users, via its URL.')}

{gettext('You can add a wiki by clicking the "Add Wiki" button in the menu bar.')}

- } -
+ + }