1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-20 02:48:51 +00:00
* [user panel] combined 7 commits into 1:

[user side nav] added 'fold/unfold' for the sidebar

[redesign] redesigned toolbar for 'my libs' & 'shared with all'; redesigned 'top bar' for 'help', 'clients' and other pages

[Shared with all] 'share existing libraries' dialog: added the 'close' icon back, enabled clicking outside to close the dialog

['Invite Guest' page] redesigned the toolbar

['Share Admin' - 'Links'] 'Share Links' page: redesigned the toolbar

['Share Admin' - 'Links'] 'Upload Links' page: redesigned the toolbar

cleaned up code

* [user side panel] update

* [user panel] update

* [code style] update: remove an eslint warning
This commit is contained in:
llj
2024-07-09 15:08:47 +08:00
committed by GitHub
parent 0d5dd2a65a
commit ddbf0e7855
20 changed files with 378 additions and 337 deletions

View File

@@ -108,10 +108,10 @@ class ShareRepoDialog extends React.Component {
}
this.props.onRepoSelectedHandler(this.state.selectedRepoList);
this.onCloseDialog();
this.toggle();
};
onCloseDialog = () => {
toggle = () => {
this.props.onShareRepoDialogClose();
};
@@ -146,7 +146,7 @@ class ShareRepoDialog extends React.Component {
</ModalBody>
{this.state.errMessage && <Alert color="danger" className="mt-2">{this.state.errMessage}</Alert>}
<ModalFooter>
<Button color="secondary" onClick={this.onCloseDialog}>{gettext('Close')}</Button>
<Button color="secondary" onClick={this.toggle}>{gettext('Close')}</Button>
<Button color="primary" onClick={this.handleSubmit}>{gettext('Submit')}</Button>
</ModalFooter>
</Modal>

View File

@@ -0,0 +1,42 @@
import React from 'react';
import PropTypes from 'prop-types';
import Logo from './logo';
import CommonToolbar from './toolbar/common-toolbar';
const propTypes = {
isSidePanelClosed: PropTypes.bool,
onCloseSidePanel: PropTypes.func,
onShowSidePanel: PropTypes.func,
onSearchedClick: PropTypes.func,
searchPlaceholder: PropTypes.string,
showSearch: PropTypes.bool
};
class Header extends React.Component {
render() {
const { onShowSidePanel, onSearchedClick, showSearch } = this.props;
return (
<div id="header" className="d-flex justify-content-between py-2 px-4">
<div className={'flex-shrink-0 d-none d-md-flex'}>
<Logo onCloseSidePanel={this.props.onCloseSidePanel} />
</div>
<div className="flex-shrink-0 d-flex flex-fill">
<div className="cur-view-toolbar">
<span title="Side Nav Menu" onClick={onShowSidePanel} className="sf2-icon-menu side-nav-toggle hidden-md-up d-md-none">
</span>
</div>
<CommonToolbar
showSearch={showSearch}
searchPlaceholder={this.props.searchPlaceholder}
onSearchedClick={onSearchedClick}
/>
</div>
</div>
);
}
}
Header.propTypes = propTypes;
export default Header;

View File

@@ -5,6 +5,7 @@ import { siteRoot, mediaUrl, logoPath, logoWidth, logoHeight, siteTitle } from '
const propTypes = {
onCloseSidePanel: PropTypes.func,
showCloseSidePanelIcon: PropTypes.bool,
positioned: PropTypes.bool
};
class Logo extends React.Component {
@@ -14,8 +15,9 @@ class Logo extends React.Component {
};
render() {
const { positioned } = this.props;
return (
<div className="top-logo">
<div className={`top-logo ${positioned ? 'd-none d-md-block positioned-top-logo' : ''}`}>
<a href={siteRoot} id="logo">
<img src={logoPath.indexOf('image-view') != -1 ? logoPath : mediaUrl + logoPath} height={logoHeight} width={logoWidth} title={siteTitle} alt="logo" />
</a>

View File

@@ -5,7 +5,7 @@ import {
gettext, siteRoot, canAddGroup, canAddRepo, canShareRepo,
canGenerateShareLink, canGenerateUploadLink, canInvitePeople,
enableTC, sideNavFooterCustomHtml, additionalAppBottomLinks,
canViewOrg, isDocs, isPro, isDBSqlite3, customNavItems
canViewOrg, isDocs, isPro, isDBSqlite3, customNavItems, mediaUrl
} from '../utils/constants';
import { seafileAPI } from '../utils/seafile-api';
import { Utils } from '../utils/utils';
@@ -16,6 +16,8 @@ import CreateGroupDialog from '../components/dialog/create-group-dialog';
const propTypes = {
currentTab: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
tabItemClick: PropTypes.func.isRequired,
isSidePanelFolded: PropTypes.bool,
toggleFoldSideNav: PropTypes.func
};
const SUB_NAV_ITEM_HEIGHT = 28;
@@ -23,12 +25,13 @@ const SUB_NAV_ITEM_HEIGHT = 28;
class MainSideNav extends React.Component {
constructor(props) {
super(props);
this.state = {
filesNavUnfolded: false,
sharedExtended: false,
closeSideBar:false,
groupItems: [],
isCreateGroupDialogOpen: false
isCreateGroupDialogOpen: false,
};
this.adminHeight = 0;
this.filesNavHeight = 0;
@@ -214,12 +217,22 @@ class MainSideNav extends React.Component {
});
};
toggleMinimize = () => {
this.setState({
isMinimized: !this.state.isMinimized
}, () => {
localStorage.setItem('sf_user_side_nav_minimized', this.state.isMinimized);
});
};
render() {
let showActivity = isDocs || isPro || !isDBSqlite3;
const { filesNavUnfolded } = this.state;
const { isSidePanelFolded } = this.props;
return (
<div className="side-nav">
<div className="side-nav-con">
<div className={'side-nav-con d-flex flex-column'}>
<h2 className="mb-2 px-2 font-weight-normal heading">{gettext('Workspace')}</h2>
<ul className="nav nav-pills flex-column nav-container">
<li id="files" className={`nav-item flex-column ${this.getActiveClass('libraries')}`}>
@@ -334,6 +347,16 @@ class MainSideNav extends React.Component {
</ul>
)
}
<div className="side-nav-bottom-toolbar d-none d-md-flex mt-auto px-2 rounded flex-shrink-0 align-items-center" onClick={this.props.toggleFoldSideNav}>
{isSidePanelFolded ? <img src={`${mediaUrl}img/open-sidebar.svg`} width="20" alt="" title={gettext('Unfold the sidebar')} /> : (
<>
<img className="mr-2" src={`${mediaUrl}img/close-sidebar.svg`} width="20" alt="" />
<span>{gettext('Fold the sidebar')}</span>
</>
)}
</div>
</div>
</div>
);

View File

@@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Utils } from '../utils/utils';
import Logo from './logo';
import MainSideNav from './main-side-nav';
@@ -8,23 +9,30 @@ const propTypes = {
currentTab: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
onCloseSidePanel: PropTypes.func,
tabItemClick: PropTypes.func,
children: PropTypes.object
children: PropTypes.object,
showLogoOnlyInMobile: PropTypes.bool,
isSidePanelFolded: PropTypes.bool,
toggleFoldSideNav: PropTypes.func
};
class SidePanel extends React.Component {
render() {
const { children } = this.props;
const { children, isSidePanelFolded, showLogoOnlyInMobile = false } = this.props;
return (
<div className={`side-panel ${this.props.isSidePanelClosed ? '' : 'left-zero'}`}>
<div className="side-panel-north">
<Logo onCloseSidePanel={this.props.onCloseSidePanel}/>
<div className={`side-panel ${isSidePanelFolded ? 'side-panel-folded' : ''} ${this.props.isSidePanelClosed ? '' : 'left-zero'}`}>
<div className={'side-panel-north'}>
{showLogoOnlyInMobile && !Utils.isDesktop() && <Logo onCloseSidePanel={this.props.onCloseSidePanel} />}
</div>
<div className="side-panel-center">
{children ?
children :
<MainSideNav tabItemClick={this.props.tabItemClick} currentTab={this.props.currentTab} />
}
{children ? children : (
<MainSideNav
tabItemClick={this.props.tabItemClick}
currentTab={this.props.currentTab}
isSidePanelFolded={isSidePanelFolded}
toggleFoldSideNav={this.props.toggleFoldSideNav}
/>
)}
</div>
</div>
);

View File

@@ -1,46 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import CommonToolbar from './common-toolbar';
import { Button } from 'reactstrap';
import { gettext } from '../../utils/constants';
import { Utils } from '../../utils/utils';
const propTypes = {
onShowSidePanel: PropTypes.func.isRequired,
onSearchedClick: PropTypes.func.isRequired,
toggleInvitePeopleDialog: PropTypes.func.isRequired,
searchPlaceholder: PropTypes.string.isRequired,
};
class InvitationsToolbar extends React.Component {
constructor(props) {
super(props);
}
render() {
let { onShowSidePanel, onSearchedClick, toggleInvitePeopleDialog } = this.props;
return (
<div className="main-panel-north border-left-show">
<div className="cur-view-toolbar">
<span title="Side Nav Menu" onClick={onShowSidePanel} className="sf2-icon-menu side-nav-toggle hidden-md-up d-md-none">
</span>
{Utils.isDesktop() ? (
<div className="operation">
<Button color="btn btn-secondary operation-item" onClick={toggleInvitePeopleDialog}>
<i className="sf3-font sf3-font-enlarge text-secondary mr-1"></i>{gettext('Invite Guest')}
</Button>
</div>
) : (
<span className="sf2-icon-plus mobile-toolbar-icon" title={gettext('Invite Guest')} onClick={toggleInvitePeopleDialog}></span>
)}
</div>
<CommonToolbar searchPlaceholder={this.props.searchPlaceholder} onSearchedClick={onSearchedClick}/>
</div>
);
}
}
InvitationsToolbar.propTypes = propTypes;
export default InvitationsToolbar;

View File

@@ -1,91 +0,0 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { DropdownToggle, Dropdown, DropdownMenu, DropdownItem } from 'reactstrap';
import { Link, navigate } from '@gatsbyjs/reach-router';
import { Utils } from '../../utils/utils';
import { siteRoot, gettext } from '../../utils/constants';
import ModalPortal from '../modal-portal';
import CreateRepoDialog from '../dialog/create-repo-dialog';
const propTypes = {
onCreateRepo: PropTypes.func.isRequired,
moreShown: PropTypes.bool
};
class MyLibsToolbar extends React.Component {
constructor(props) {
super(props);
this.state = {
isCreateRepoDialogOpen: false,
isOpen: false,
};
}
onCreateRepo = (repo) => {
this.props.onCreateRepo(repo);
this.onCreateToggle();
};
onCreateToggle = () => {
this.setState({isCreateRepoDialogOpen: !this.state.isCreateRepoDialogOpen});
};
toggleMore = () => {
this.setState({ isOpen: !this.state.isOpen });
};
onDropdownToggleKeyDown = (e) => {
if (e.key == 'Enter' || e.key == 'Space') {
this.toggleMore();
}
};
visitDeletedviaKey = (e) => {
if (e.key == 'Enter' || e.key == 'Space') {
navigate(`${siteRoot}my-libs/deleted/`);
}
};
render() {
const { moreShown = false } = this.props;
return (
<Fragment>
{Utils.isDesktop() ? (
<div className="operation">
<button className="btn btn-secondary operation-item" title={gettext('New Library')} onClick={this.onCreateToggle}>
<i className="sf3-font sf3-font-enlarge text-secondary mr-1"></i>{gettext('New Library')}
</button>
{moreShown &&
<Dropdown isOpen={this.state.isOpen} toggle={this.toggleMore}>
<DropdownToggle className='btn btn-secondary operation-item' onKeyDown={this.onDropdownToggleKeyDown}>
{gettext('More')}
</DropdownToggle>
<DropdownMenu>
<DropdownItem className="link-dropdown-container" onKeyDown={this.visitDeletedviaKey}>
<Link className="link-dropdown-item" to={siteRoot + 'my-libs/deleted/'}>{gettext('Deleted Libraries')}</Link>
</DropdownItem>
</DropdownMenu>
</Dropdown>
}
</div>
) : (
<span className="sf2-icon-plus mobile-toolbar-icon" title={gettext('New Library')} onClick={this.onCreateToggle}></span>
)}
{this.state.isCreateRepoDialogOpen && (
<ModalPortal>
<CreateRepoDialog
libraryType='mine'
onCreateRepo={this.onCreateRepo}
onCreateToggle={this.onCreateToggle}
/>
</ModalPortal>
)}
</Fragment>
);
}
}
MyLibsToolbar.propTypes = propTypes;
export default MyLibsToolbar;