mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-07 01:41:39 +00:00
[shared dir view] added support for mobile (#4425)
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { Button } from 'reactstrap';
|
import { Button, Dropdown, DropdownToggle, DropdownItem } from 'reactstrap';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import Account from './components/common/account';
|
import Account from './components/common/account';
|
||||||
import { gettext, siteRoot, mediaUrl, logoPath, logoWidth, logoHeight, siteTitle, thumbnailSizeForOriginal } from './utils/constants';
|
import { gettext, siteRoot, mediaUrl, logoPath, logoWidth, logoHeight, siteTitle, thumbnailSizeForOriginal } from './utils/constants';
|
||||||
@@ -193,6 +193,7 @@ class SharedDirView extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const isDesktop = Utils.isDesktop();
|
||||||
const modeBaseClass = 'btn btn-secondary btn-icon sf-view-mode-btn';
|
const modeBaseClass = 'btn btn-secondary btn-icon sf-view-mode-btn';
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
@@ -210,16 +211,19 @@ class SharedDirView extends React.Component {
|
|||||||
<div className="d-flex justify-content-between align-items-center op-bar">
|
<div className="d-flex justify-content-between align-items-center op-bar">
|
||||||
<p className="m-0">{gettext('Current path: ')}{this.renderPath()}</p>
|
<p className="m-0">{gettext('Current path: ')}{this.renderPath()}</p>
|
||||||
<div>
|
<div>
|
||||||
|
{isDesktop &&
|
||||||
<div className="view-mode btn-group">
|
<div className="view-mode btn-group">
|
||||||
<a href={`?p=${encodeURIComponent(path)}&mode=list`} className={`${modeBaseClass} sf2-icon-list-view ${mode == 'list' ? 'current-mode' : ''}`} title={gettext('List')}></a>
|
<a href={`?p=${encodeURIComponent(path)}&mode=list`} className={`${modeBaseClass} sf2-icon-list-view ${mode == 'list' ? 'current-mode' : ''}`} title={gettext('List')}></a>
|
||||||
<a href={`?p=${encodeURIComponent(path)}&mode=grid`} className={`${modeBaseClass} sf2-icon-grid-view ${mode == 'grid' ? 'current-mode' : ''}`} title={gettext('Grid')}></a>
|
<a href={`?p=${encodeURIComponent(path)}&mode=grid`} className={`${modeBaseClass} sf2-icon-grid-view ${mode == 'grid' ? 'current-mode' : ''}`} title={gettext('Grid')}></a>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
{showDownloadIcon &&
|
{showDownloadIcon &&
|
||||||
<Button color="success" onClick={this.zipDownloadFolder.bind(this, path)} className="ml-2 zip-btn">{gettext('ZIP')}</Button>
|
<Button color="success" onClick={this.zipDownloadFolder.bind(this, path)} className="ml-2 zip-btn">{gettext('ZIP')}</Button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Content
|
<Content
|
||||||
|
isDesktop={isDesktop}
|
||||||
isLoading={this.state.isLoading}
|
isLoading={this.state.isLoading}
|
||||||
errorMsg={this.state.errorMsg}
|
errorMsg={this.state.errorMsg}
|
||||||
items={this.state.items}
|
items={this.state.items}
|
||||||
@@ -281,7 +285,7 @@ class Content extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { isLoading, errorMsg, items, sortBy, sortOrder } = this.props;
|
const { isDesktop, isLoading, errorMsg, items, sortBy, sortOrder } = this.props;
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
@@ -291,6 +295,35 @@ class Content extends React.Component {
|
|||||||
return <p className="error mt-6 text-center">{errorMsg}</p>;
|
return <p className="error mt-6 text-center">{errorMsg}</p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tbody = (
|
||||||
|
<tbody>
|
||||||
|
{items.map((item, index) => {
|
||||||
|
return <Item
|
||||||
|
key={index}
|
||||||
|
isDesktop={isDesktop}
|
||||||
|
item={item}
|
||||||
|
zipDownloadFolder={this.props.zipDownloadFolder}
|
||||||
|
showImagePopup={this.props.showImagePopup}
|
||||||
|
/>;
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isDesktop) {
|
||||||
|
return (
|
||||||
|
<table className="table-hover table-thead-hidden">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="12%"></th>
|
||||||
|
<th width="80%"></th>
|
||||||
|
<th width="8%"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
{tbody}
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const sortIcon = <span className={`fas ${sortOrder == 'asc' ? 'fa-caret-up' : 'fa-caret-down'}`}></span>;
|
const sortIcon = <span className={`fas ${sortOrder == 'asc' ? 'fa-caret-up' : 'fa-caret-down'}`}></span>;
|
||||||
return mode == 'list' ? (
|
return mode == 'list' ? (
|
||||||
<table className="table-hover">
|
<table className="table-hover">
|
||||||
@@ -303,16 +336,7 @@ class Content extends React.Component {
|
|||||||
<th width="10%"></th>
|
<th width="10%"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
{tbody}
|
||||||
{items.map((item, index) => {
|
|
||||||
return <Item
|
|
||||||
key={index}
|
|
||||||
item={item}
|
|
||||||
zipDownloadFolder={this.props.zipDownloadFolder}
|
|
||||||
showImagePopup={this.props.showImagePopup}
|
|
||||||
/>;
|
|
||||||
})}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
) : (
|
) : (
|
||||||
<ul className="grid-view">
|
<ul className="grid-view">
|
||||||
@@ -334,10 +358,15 @@ class Item extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
isIconShown: false
|
isIconShown: false,
|
||||||
|
isOpMenuOpen: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleOpMenu = () => {
|
||||||
|
this.setState({isOpMenuOpen: !this.state.isOpMenuOpen});
|
||||||
|
}
|
||||||
|
|
||||||
handleMouseOver = () => {
|
handleMouseOver = () => {
|
||||||
this.setState({isIconShown: true});
|
this.setState({isIconShown: true});
|
||||||
}
|
}
|
||||||
@@ -362,11 +391,11 @@ class Item extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const item = this.props.item;
|
const { item, isDesktop } = this.props;
|
||||||
const { isIconShown } = this.state;
|
const { isIconShown } = this.state;
|
||||||
|
|
||||||
if (item.is_dir) {
|
if (item.is_dir) {
|
||||||
return (
|
return isDesktop ? (
|
||||||
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}>
|
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}>
|
||||||
<td className="text-center"><img src={Utils.getFolderIconUrl()} alt="" width="24" /></td>
|
<td className="text-center"><img src={Utils.getFolderIconUrl()} alt="" width="24" /></td>
|
||||||
<td>
|
<td>
|
||||||
@@ -381,11 +410,39 @@ class Item extends React.Component {
|
|||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
) : (
|
||||||
|
<tr>
|
||||||
|
<td className="text-center"><img src={Utils.getFolderIconUrl()} alt="" width="24" /></td>
|
||||||
|
<td>
|
||||||
|
<a href={`?p=${encodeURIComponent(item.folder_path.substr(0, item.folder_path.length - 1))}&mode=${mode}`}>{item.folder_name}</a>
|
||||||
|
<br />
|
||||||
|
<span className="item-meta-info">{moment(item.last_modified).fromNow()}</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{showDownloadIcon &&
|
||||||
|
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
|
||||||
|
<DropdownToggle
|
||||||
|
tag="i"
|
||||||
|
className="sf-dropdown-toggle fa fa-ellipsis-v ml-0"
|
||||||
|
title={gettext('More Operations')}
|
||||||
|
data-toggle="dropdown"
|
||||||
|
aria-expanded={this.state.isOpMenuOpen}
|
||||||
|
/>
|
||||||
|
<div className={this.state.isOpMenuOpen ? '' : 'd-none'} onClick={this.toggleOpMenu}>
|
||||||
|
<div className="mobile-operation-menu-bg-layer"></div>
|
||||||
|
<div className="mobile-operation-menu">
|
||||||
|
<DropdownItem className="mobile-menu-item" onClick={this.zipDownloadFolder}>{gettext('Download')}</DropdownItem>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const fileURL = `${siteRoot}d/${token}/files/?p=${encodeURIComponent(item.file_path)}`;
|
const fileURL = `${siteRoot}d/${token}/files/?p=${encodeURIComponent(item.file_path)}`;
|
||||||
const thumbnailURL = item.encoded_thumbnail_src ? `${siteRoot}${item.encoded_thumbnail_src}` : '';
|
const thumbnailURL = item.encoded_thumbnail_src ? `${siteRoot}${item.encoded_thumbnail_src}` : '';
|
||||||
return (
|
return isDesktop ? (
|
||||||
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}>
|
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}>
|
||||||
<td className="text-center">
|
<td className="text-center">
|
||||||
{thumbnailURL ?
|
{thumbnailURL ?
|
||||||
@@ -400,8 +457,41 @@ class Item extends React.Component {
|
|||||||
<td title={moment(item.last_modified).format('llll')}>{moment(item.last_modified).fromNow()}</td>
|
<td title={moment(item.last_modified).format('llll')}>{moment(item.last_modified).fromNow()}</td>
|
||||||
<td>
|
<td>
|
||||||
{showDownloadIcon &&
|
{showDownloadIcon &&
|
||||||
<a className={`action-icon sf2-icon-download${isIconShown ? '' : ' invisible'}`} href={`${fileURL}&dl=1`} title={gettext('Download')} aria-label={gettext('Download')}>
|
<a className={`action-icon sf2-icon-download${isIconShown ? '' : ' invisible'}`} href={`${fileURL}&dl=1`} title={gettext('Download')} aria-label={gettext('Download')}></a>
|
||||||
</a>
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
) : (
|
||||||
|
<tr>
|
||||||
|
<td className="text-center">
|
||||||
|
{thumbnailURL ?
|
||||||
|
<img className="thumbnail" src={thumbnailURL} alt="" /> :
|
||||||
|
<img src={Utils.getFileIconUrl(item.file_name)} alt="" width="24" />
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href={fileURL} onClick={this.handleFileClick}>{item.file_name}</a>
|
||||||
|
<br />
|
||||||
|
<span className="item-meta-info">{Utils.bytesToSize(item.size)}</span>
|
||||||
|
<span className="item-meta-info">{moment(item.last_modified).fromNow()}</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{showDownloadIcon &&
|
||||||
|
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
|
||||||
|
<DropdownToggle
|
||||||
|
tag="i"
|
||||||
|
className="sf-dropdown-toggle fa fa-ellipsis-v ml-0"
|
||||||
|
title={gettext('More Operations')}
|
||||||
|
data-toggle="dropdown"
|
||||||
|
aria-expanded={this.state.isOpMenuOpen}
|
||||||
|
/>
|
||||||
|
<div className={this.state.isOpMenuOpen ? '' : 'd-none'} onClick={this.toggleOpMenu}>
|
||||||
|
<div className="mobile-operation-menu-bg-layer"></div>
|
||||||
|
<div className="mobile-operation-menu">
|
||||||
|
<DropdownItem className="mobile-menu-item" tag="a" href={`${fileURL}&dl=1`}>{gettext('Download')}</DropdownItem>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
Reference in New Issue
Block a user