From ca117bd2f0e9cd59a3dd1cfc3a99759e0fd04154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=81=A5=E8=BE=89?= <40563566+WangJianhui666@users.noreply.github.com> Date: Wed, 9 Jan 2019 12:10:33 +0800 Subject: [PATCH] display readme.md (#2772) --- frontend/src/components/dir-view/dir-panel.js | 18 ++-- frontend/src/components/dir-view/dir-view.js | 24 +++++ frontend/src/components/filetags-viewer.js | 74 ---------------- frontend/src/components/main-side-nav.js | 2 +- frontend/src/components/repo-info-bar.js | 87 +++++++++++++++++++ frontend/src/css/repo-info-bar.css | 56 ++++++++++++ frontend/src/css/repo-tag.css | 32 ------- .../src/pages/repo-wiki-mode/main-panel.js | 18 ++-- frontend/src/repo-wiki-mode.js | 24 ++++- 9 files changed, 209 insertions(+), 126 deletions(-) delete mode 100644 frontend/src/components/filetags-viewer.js create mode 100644 frontend/src/components/repo-info-bar.js create mode 100644 frontend/src/css/repo-info-bar.css diff --git a/frontend/src/components/dir-view/dir-panel.js b/frontend/src/components/dir-view/dir-panel.js index 13d46be508..ca58bfb42e 100644 --- a/frontend/src/components/dir-view/dir-panel.js +++ b/frontend/src/components/dir-view/dir-panel.js @@ -12,7 +12,7 @@ import DirentDetail from '../dirent-detail/dirent-details'; import FileUploader from '../file-uploader/file-uploader'; import ModalPortal from '../modal-portal'; import LibDecryptDialog from '../dialog/lib-decrypt-dialog'; -import FileTagsViewer from '../../components/filetags-viewer'; +import RepoInfoBar from '../repo-info-bar'; const propTypes = { currentRepoInfo: PropTypes.object, @@ -51,6 +51,7 @@ const propTypes = { onSearchedClick: PropTypes.func.isRequired, onFileUploadSuccess: PropTypes.func.isRequired, usedRepoTags: PropTypes.array.isRequired, + readmeMarkdown: PropTypes.object, }; class DirPanel extends React.Component { @@ -183,14 +184,13 @@ class DirPanel extends React.Component { {!this.props.pathExist ? errMessage : - {(this.props.usedRepoTags.length > 0 && this.props.path === '/') && ( -
- -
+ {this.props.path === '/' && !(this.props.usedRepoTags.length === 0 && this.props.readmeMarkdown === null) && ( + )} { + this.setState({readmeMarkdown: null}); + direntList.some(item => { + let fileName = item.name.toLowerCase(); + if (fileName === 'readme.md' || fileName === 'readme.markdown') { + this.setState({readmeMarkdown: item}); + return true; + } + }); + } + updateDirentList = (filePath) => { let repoID = this.state.repoID; this.setState({isDirentListLoading: true}); seafileAPI.listDir(repoID, filePath).then(res => { let direntList = res.data.map(item => { + let fileName = item.name.toLowerCase(); + if (fileName === 'readme.md' || fileName === 'readme.markdown') { + this.setState({readmeMarkdown: item}); + } return new Dirent(item); }); this.setState({ @@ -198,6 +214,7 @@ class DirView extends React.Component { let dirent = this.createDirent(name, 'file', res.data); let direntList = this.addItem(dirent, 'file'); this.setState({direntList: direntList}); + this.updateReadmeMarkdown(direntList); }); } @@ -215,6 +232,7 @@ class DirView extends React.Component { seafileAPI.deleteFile(repoID, direntPath).then(() => { let direntList = this.deleteItem(dirent); this.setState({direntList: direntList}); + this.updateReadmeMarkdown(direntList); }).catch(() => { // todo }) @@ -235,6 +253,7 @@ class DirView extends React.Component { seafileAPI.renameFile(repoID, direntPath, newName).then(() => { let direntList = this.renameItem(dirent, newName); this.setState({direntList: direntList}); + this.updateReadmeMarkdown(direntList); }).catch(() => { //todo }); @@ -248,6 +267,7 @@ class DirView extends React.Component { let direntList = this.deleteItem(dirent); this.setState({direntList: direntList}); + this.updateReadmeMarkdown(direntList); let message = gettext('Successfully moved %(name)s.'); message = message.replace('%(name)s', dirName); @@ -319,6 +339,7 @@ class DirView extends React.Component { isDirentSelected: false, selectedDirentList: [], }); + this.updateReadmeMarkdown(direntList); let message = gettext('Successfully moved %(name)s.'); message = message.replace('%(name)s', dirNames); toaster.success(message); @@ -348,6 +369,7 @@ class DirView extends React.Component { let repoID = this.state.repoID; seafileAPI.deleteMutipleDirents(repoID, this.state.path, dirNames).then(res => { let direntList = this.deleteItems(dirNames); + this.updateReadmeMarkdown(direntList); this.setState({ direntList: direntList, isDirentSelected: false, @@ -446,6 +468,7 @@ class DirView extends React.Component { this.setState({direntList: [dirent, ...this.state.direntList]}); } else { this.setState({direntList: [...this.state.direntList, dirent]}); + this.updateReadmeMarkdown(this.state.direntList); } } } @@ -632,6 +655,7 @@ class DirView extends React.Component { libNeedDecrypt={this.state.libNeedDecrypt} onLibDecryptDialog={this.onLibDecryptDialog} usedRepoTags={this.state.usedRepoTags} + readmeMarkdown={this.state.readmeMarkdown} /> ); } diff --git a/frontend/src/components/filetags-viewer.js b/frontend/src/components/filetags-viewer.js deleted file mode 100644 index 4a5bb0c2c7..0000000000 --- a/frontend/src/components/filetags-viewer.js +++ /dev/null @@ -1,74 +0,0 @@ -import React, { Fragment } from 'react'; -import PropTypes from 'prop-types'; -import ModalPortal from './modal-portal'; -import { Modal } from 'reactstrap'; -import ListTaggedFilesDialog from './dialog/list-taggedfiles-dialog'; - -const propTypes = { - repoID: PropTypes.string.isRequired, - currentPath: PropTypes.string.isRequired, - usedRepoTags: PropTypes.array.isRequired, -}; - -class FileTagsViewer extends React.Component { - - constructor(props) { - super(props); - this.state = { - usedRepoTags: [], - currentTag: null, - isListTaggedFileShow: false, - }; - } - - onListTaggedFiles = (currentTag) => { - this.setState({ - currentTag: currentTag, - isListTaggedFileShow: !this.state.isListTaggedFileShow, - }); - } - - onCloseDialog = () => { - this.setState({ - isListTaggedFileShow: false - }); - } - - render() { - let {usedRepoTags, repoID} = this.props; - - return ( - -
    - {usedRepoTags.map((usedRepoTag) => { - return ( -
  • - - {usedRepoTag.name} - - {usedRepoTag.fileCount > 1 ? usedRepoTag.fileCount + ' files' : usedRepoTag.fileCount + ' file'} - -
  • - ); - })} -
- {this.state.isListTaggedFileShow && ( - - - - - - )} -
- ); - } -} - -FileTagsViewer.propTypes = propTypes; - -export default FileTagsViewer; diff --git a/frontend/src/components/main-side-nav.js b/frontend/src/components/main-side-nav.js index 9b7ae2b6b6..b197264635 100644 --- a/frontend/src/components/main-side-nav.js +++ b/frontend/src/components/main-side-nav.js @@ -179,7 +179,7 @@ class MainSideNav extends React.Component {
  • this.tabItemClick('wikis')}> - {gettext('Wikis')} + {gettext('Wikis')}
  • } diff --git a/frontend/src/components/repo-info-bar.js b/frontend/src/components/repo-info-bar.js new file mode 100644 index 0000000000..9838a5ab3e --- /dev/null +++ b/frontend/src/components/repo-info-bar.js @@ -0,0 +1,87 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import ModalPortal from './modal-portal'; +import { Modal } from 'reactstrap'; +import ListTaggedFilesDialog from './dialog/list-taggedfiles-dialog'; +import { siteRoot } from '../utils/constants'; +import { Utils } from '../utils/utils'; + +import '../css/repo-info-bar.css'; + +const propTypes = { + repoID: PropTypes.string.isRequired, + currentPath: PropTypes.string.isRequired, + usedRepoTags: PropTypes.array.isRequired, + readmeMarkdown: PropTypes.object, +}; + +class RepoInfoBar extends React.Component { + + constructor(props) { + super(props); + this.state = { + currentTag: null, + isListTaggedFileShow: false, + }; + } + + onListTaggedFiles = (currentTag) => { + this.setState({ + currentTag: currentTag, + isListTaggedFileShow: !this.state.isListTaggedFileShow, + }); + } + + onCloseDialog = () => { + this.setState({ + isListTaggedFileShow: false + }); + } + + render() { + let {repoID, currentPath, usedRepoTags, readmeMarkdown} = this.props; + let href = readmeMarkdown !== null ? siteRoot + 'lib/' + repoID + '/file' + Utils.joinPath(currentPath, readmeMarkdown.name) : ''; + + return ( +
    + {usedRepoTags.length > 0 && ( +
      + {usedRepoTags.map((usedRepoTag) => { + return ( +
    • + + {usedRepoTag.name} + + {usedRepoTag.fileCount > 1 ? usedRepoTag.fileCount + ' files' : usedRepoTag.fileCount + ' file'} + +
    • + ); + })} +
    + )} + {readmeMarkdown !== null && ( +
    + + {readmeMarkdown.name} +
    + )} + {this.state.isListTaggedFileShow && ( + + + + + + )} +
    + ); + } +} + +RepoInfoBar.propTypes = propTypes; + +export default RepoInfoBar; diff --git a/frontend/src/css/repo-info-bar.css b/frontend/src/css/repo-info-bar.css new file mode 100644 index 0000000000..1d29acb9c8 --- /dev/null +++ b/frontend/src/css/repo-info-bar.css @@ -0,0 +1,56 @@ +.repo-info-bar { + margin-bottom: 5px; + padding: 0 10px; + border: 1px solid #e6e6dd; + border-radius: 5px; + background: #f8f8f8; +} + +.used-tag-list { + list-style: none; + margin: 8px 0; +} + +.used-tag-item { + display: inline-block; + margin: auto 15px; +} + +.used-tag { + display: inline-block; + width: 12px; + height: 12px; + border-radius: 50%; +} + +.used-tag-name { + margin: 0 0.25rem; +} + +.used-tag-files { + color: #666; + font-size: 14px; +} + +.used-tag-files:hover { + cursor: pointer; + text-decoration: underline; +} + +.readme-file { + margin: 8px 15px; +} + +.readme-file a { + color: #333; +} + +.readme-flag { + font-size: 12px; + color: #f19645; +} + +.readme-name { + margin: 0 0.25rem; + font-size: 14px; +} diff --git a/frontend/src/css/repo-tag.css b/frontend/src/css/repo-tag.css index 5dcf7c7d25..23d0181740 100644 --- a/frontend/src/css/repo-tag.css +++ b/frontend/src/css/repo-tag.css @@ -93,35 +93,3 @@ .tag-dialog-back:focus { color: #444; } - -.tags-summary-bar { - margin-bottom: 5px; - padding: 0 10px; - border: 1px solid #e6e6dd; - border-radius: 5px; -} -.used-tag-list { - list-style: none; - line-height: 40px; -} -.used-tag-item { - display: inline-block; - margin: auto 15px; -} -.used-tag { - display: inline-block; - width: 0.8rem; - height: 0.8rem; - border-radius: 50%; -} -.used-tag-name { - margin: 0 0.25rem; -} -.used-tag-files { - color: #666; - font-size: 14px; -} -.used-tag-files:hover { - cursor: pointer; - text-decoration: underline; -} diff --git a/frontend/src/pages/repo-wiki-mode/main-panel.js b/frontend/src/pages/repo-wiki-mode/main-panel.js index b290178932..30af465137 100644 --- a/frontend/src/pages/repo-wiki-mode/main-panel.js +++ b/frontend/src/pages/repo-wiki-mode/main-panel.js @@ -14,7 +14,7 @@ import MarkdownContentViewer from '../../components/markdown-viewer'; import DirentListView from '../../components/dirent-list-view/dirent-list-view'; import DirentDetail from '../../components/dirent-detail/dirent-details'; import FileUploader from '../../components/file-uploader/file-uploader'; -import FileTagsViewer from '../../components/filetags-viewer'; +import RepoInfoBar from '../../components/repo-info-bar'; const propTypes = { content: PropTypes.string, @@ -61,6 +61,7 @@ const propTypes = { goDraftPage: PropTypes.func, reviewID: PropTypes.any, usedRepoTags: PropTypes.array.isRequired, + readmeMarkdown: PropTypes.object, }; class MainPanel extends Component { @@ -256,14 +257,13 @@ class MainPanel extends Component { goReviewPage={this.props.goReviewPage} /> : - {(this.props.usedRepoTags.length > 0 && this.props.path === '/') && ( -
    - -
    + {this.props.path === '/' && !(this.props.usedRepoTags.length === 0 && this.props.readmeMarkdown === null) && ( + )} { + this.setState({readmeMarkdown: null}); + direntList.some(item => { + let fileName = item.name.toLowerCase(); + if (fileName === 'readme.md' || fileName === 'readme.markdown') { + this.setState({readmeMarkdown: item}); + return true; + } + }); + } + loadDirentList = (filePath) => { this.setState({isDirentListLoading: true}); seafileAPI.listDir(repoID, filePath).then(res => { let direntList = []; res.data.forEach(item => { + let fileName = item.name.toLowerCase(); + if (fileName === 'readme.md' || fileName === 'readme.markdown') { + this.setState({readmeMarkdown: item}); + } let dirent = new Dirent(item); direntList.push(dirent); }); @@ -513,6 +529,7 @@ class Wiki extends Component { return item; }); this.setState({ direntList: direntList }); + this.updateReadmeMarkdown(direntList); } else if (Utils.isAncestorPath(direntPath, this.state.path)) { // example: direntPath = /A/B, state.path = /A/B/C let newPath = Utils.renameAncestorPath(this.state.path, direntPath, newDirentPath); @@ -532,6 +549,7 @@ class Wiki extends Component { return item.name !== name; }); this.setState({ direntList: direntList }); + this.updateReadmeMarkdown(direntList); } else if (Utils.isAncestorPath(direntPath, this.state.path)) { // the deleted item is ancester of the current item let parentPath = Utils.getDirName(direntPath); @@ -565,6 +583,7 @@ class Wiki extends Component { } } this.setState({direntList: direntList}); + this.updateReadmeMarkdown(direntList); } moveDirent = (filePath) => { @@ -573,6 +592,7 @@ class Wiki extends Component { return item.name !== name; }); this.setState({direntList: direntList}); + this.updateReadmeMarkdown(direntList); } onFileUploadSuccess = (direntObject) => { @@ -597,6 +617,7 @@ class Wiki extends Component { this.setState({direntList: [dirent, ...this.state.direntList]}); } else { this.setState({direntList: [...this.state.direntList, dirent]}); + this.updateReadmeMarkdown(this.state.direntList); } } } @@ -991,6 +1012,7 @@ class Wiki extends Component { goDraftPage={this.goDraftPage} goReviewPage={this.goReviewPage} usedRepoTags={this.state.usedRepoTags} + readmeMarkdown={this.state.readmeMarkdown} /> );