1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-19 18:29:23 +00:00

12.0 change app structure (#6335)

* 01 change app structure

* 02 change setting page

* 03 optimize header style

* 04 change app mobile side panel logo
This commit is contained in:
Michael An
2024-07-11 17:45:30 +08:00
committed by GitHub
parent 4e16703d33
commit c41407f783
38 changed files with 238 additions and 408 deletions

View File

@@ -0,0 +1,41 @@
export const EVENT_BUS_TYPE = {
// metadata
QUERY_COLLABORATORS: 'query-collaborators',
QUERY_COLLABORATOR: 'query-collaborator',
UPDATE_TABLE_ROWS: 'update-table-rows',
// table
LOCAL_TABLE_CHANGED: 'local-table-changed',
SERVER_TABLE_CHANGED: 'server-table-changed',
TABLE_ERROR: 'table-error',
OPEN_EDITOR: 'open-editor',
CLOSE_EDITOR: 'close-editor',
SELECT_CELL: 'select_cell',
SELECT_START: 'select_start',
SELECT_UPDATE: 'select_update',
SELECT_END: 'select_end',
SELECT_END_WITH_SHIFT: 'select_end_with_shift',
SELECT_NONE: 'select_none',
COPY_CELLS: 'copy_cells',
PASTE_CELLS: 'paste_cells',
SEARCH_CELLS: 'search-cells',
CLOSE_SEARCH_CELLS: 'close-search-cells',
OPEN_SELECT: 'open-select',
UPDATE_LINKED_RECORDS: 'update_linked_records',
SELECT_COLUMN: 'select_column',
DRAG_ENTER: 'drag_enter',
COLLAPSE_ALL_GROUPS: 'collapse_all_groups',
EXPAND_ALL_GROUPS: 'expand_all_groups',
// modify view
MODIFY_FILTERS: 'modify_filters',
MODIFY_SORTS:'modify_sorts',
MODIFY_GROUPBYS:'modify_groupbys',
MODIFY_HIDDEN_COLUMNS:'modify_hidden_columns',
// change
VIEW_CHANGED: 'view_changed',
// library
CURRENT_LIBRARY_CHANGED: 'current_library_changed',
};

View File

@@ -0,0 +1,28 @@
class EventBus {
subscribers = {};
subscribe(type, handler) {
if (!this.subscribers[type]) {
this.subscribers[type] = [];
}
const handlers = this.subscribers[type];
handlers.push(handler);
return () => {
const index = handlers.indexOf(handler);
if (index > -1) {
handlers.splice(index, 1);
}
};
}
dispatch(type, ...data) {
const handlers = this.subscribers[type];
if (Array.isArray(handlers)) {
handlers.forEach(handler => handler(...data));
}
}
}
export default EventBus;

View File

@@ -0,0 +1,5 @@
.top-header {
background-color: #f8fafd;
border-bottom: 1px solid #eee;
padding: .5rem 1rem;
}

View File

@@ -3,7 +3,11 @@ import PropTypes from 'prop-types';
import Logo from './logo';
import CommonToolbar from './toolbar/common-toolbar';
import './header.css';
const propTypes = {
children: PropTypes.object,
eventBus: PropTypes.object.isRequired,
isSidePanelClosed: PropTypes.bool,
onCloseSidePanel: PropTypes.func,
onShowSidePanel: PropTypes.func,
@@ -15,21 +19,23 @@ const propTypes = {
class Header extends React.Component {
render() {
const { onShowSidePanel, onSearchedClick, showSearch } = this.props;
const { onShowSidePanel, onSearchedClick, showSearch, children } = this.props;
return (
<div id="header" className="d-flex justify-content-between py-2 px-4">
<div id="header" className="top-header d-flex justify-content-between flex-shrink-0">
<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={`flex-shrink-0 d-flex flex-fill ${children ? '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>
{children}
</div>
<CommonToolbar
showSearch={showSearch}
searchPlaceholder={this.props.searchPlaceholder}
onSearchedClick={onSearchedClick}
eventBus={this.props.eventBus}
/>
</div>
</div>

View File

@@ -1,13 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';
import { siteRoot, mediaUrl, logoPath, logoWidth, logoHeight, siteTitle } from '../utils/constants';
import { Utils } from '../utils/utils';
const propTypes = {
onCloseSidePanel: PropTypes.func,
showCloseSidePanelIcon: PropTypes.bool,
positioned: PropTypes.bool,
showLogoOnlyInMobile: PropTypes.bool
};
class Logo extends React.Component {
@@ -17,14 +14,8 @@ class Logo extends React.Component {
};
render() {
const { positioned, showLogoOnlyInMobile } = this.props;
if (showLogoOnlyInMobile && Utils.isDesktop()) {
return null;
}
return (
<div className={`top-logo ${positioned ? 'd-none d-md-block positioned-top-logo' : ''}`}>
<div className='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

@@ -1,22 +0,0 @@
import React, { Fragment } from 'react';
import GeneralToolBar from './toolbar/general-toolbar';
const MainContentWrapper = (WrapperedComponent) => {
return class Wrapper extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<Fragment>
<GeneralToolBar {...this.props} />
<WrapperedComponent {...this.props} />
</Fragment>
);
}
};
};
export default MainContentWrapper;

View File

@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import MediaQuery from 'react-responsive';
import Logo from './logo';
import MainSideNav from './main-side-nav';
import { SIDE_PANEL_FOLDED_WIDTH } from '../constants';
@@ -11,7 +12,6 @@ const propTypes = {
onCloseSidePanel: PropTypes.func,
tabItemClick: PropTypes.func,
children: PropTypes.object,
showLogoOnlyInMobile: PropTypes.bool,
isSidePanelFolded: PropTypes.bool,
toggleFoldSideNav: PropTypes.func
};
@@ -19,16 +19,15 @@ const propTypes = {
class SidePanel extends React.Component {
render() {
const { children, isSidePanelFolded, showLogoOnlyInMobile = false } = this.props;
const { children, isSidePanelFolded } = this.props;
const style = isSidePanelFolded ? { flexBasis: SIDE_PANEL_FOLDED_WIDTH } : {};
return (
<div className={classnames('side-panel', { 'side-panel-folded': isSidePanelFolded, 'left-zero': !this.props.isSidePanelClosed })} style={style}>
<div className={'side-panel-north'}>
<Logo
onCloseSidePanel={this.props.onCloseSidePanel}
showLogoOnlyInMobile={showLogoOnlyInMobile}
/>
</div>
<MediaQuery query="(max-width: 767.8px)">
<div className='side-panel-north'>
<Logo onCloseSidePanel={this.props.onCloseSidePanel} />
</div>
</MediaQuery>
<div className="side-panel-center">
{children ? children : (
<MainSideNav

View File

@@ -7,6 +7,7 @@ import SearchByName from '../search/search-by-name';
import Notification from '../common/notification';
import Account from '../common/account';
import Logout from '../common/logout';
import { EVENT_BUS_TYPE } from '../common/event-bus-type';
const propTypes = {
repoID: PropTypes.string,
@@ -16,14 +17,41 @@ const propTypes = {
onSearchedClick: PropTypes.func,
searchPlaceholder: PropTypes.string,
currentRepoInfo: PropTypes.object,
eventBus: PropTypes.object,
isViewFile: PropTypes.bool,
showSearch: PropTypes.bool
};
class CommonToolbar extends React.Component {
constructor(props) {
super(props);
this.state = {
repoID: props.repoID,
repoName: props.repoName,
isLibView: props.isLibView,
path: props.path,
isViewFile: props.isViewFile,
};
}
componentDidMount() {
if (this.props.eventBus) {
this.unsubscribeLibChange = this.props.eventBus.subscribe(EVENT_BUS_TYPE.CURRENT_LIBRARY_CHANGED, this.onRepoChange);
}
}
componentWillUnmount() {
this.unsubscribeLibChange && this.unsubscribeLibChange();
}
onRepoChange = ({ repoID, repoName, isLibView, path, isViewFile }) => {
this.setState({ repoID, repoName, isLibView, path, isViewFile });
};
renderSearch = () => {
const { repoID, repoName, isLibView, searchPlaceholder, path, isViewFile } = this.props;
const { repoID, repoName, isLibView, path, isViewFile } = this.state;
const { searchPlaceholder } = this.props;
const placeholder = searchPlaceholder || gettext('Search files');
if (isPro) {

View File

@@ -1,36 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import CommonToolbar from './common-toolbar';
const propTypes = {
searchPlaceholder: PropTypes.string,
onShowSidePanel: PropTypes.func.isRequired,
onSearchedClick: PropTypes.func.isRequired,
};
class GeneralToolbar extends React.Component {
render() {
// todo get repoID?
let { onShowSidePanel, onSearchedClick } = this.props;
return (
<div className="main-panel-north">
<div className="cur-view-toolbar">
<span
className="sf2-icon-menu side-nav-toggle hidden-md-up d-md-none"
title="Side Nav Menu"
onClick={onShowSidePanel}>
</span>
</div>
<CommonToolbar
searchPlaceholder={this.props.searchPlaceholder}
onSearchedClick={onSearchedClick}
/>
</div>
);
}
}
GeneralToolbar.propTypes = propTypes;
export default GeneralToolbar;

View File

@@ -0,0 +1,31 @@
import React from 'react';
import PropTypes from 'prop-types';
import Logo from '../logo';
import classnames from 'classnames';
import SideNav from './side-nav';
const propTypes = {
isSidePanelClosed: PropTypes.bool,
curItemID: PropTypes.string.isRequired,
data: PropTypes.array.isRequired,
onCloseSidePanel: PropTypes.func.isRequired,
};
class SettingSidePanel extends React.Component {
render() {
return (
<div className={classnames('side-panel', { 'left-zero': !this.props.isSidePanelClosed })}>
<div className="side-panel-north">
<Logo onCloseSidePanel={this.props.onCloseSidePanel}/>
</div>
<div className="side-panel-center">
<SideNav data={this.props.data} curItemID={this.props.curItemID} />
</div>
</div>
);
}
}
SettingSidePanel.propTypes = propTypes;
export default SettingSidePanel;

View File

@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import CommonToolbar from './common-toolbar';
import CommonToolbar from '../toolbar/common-toolbar';
const propTypes = {
onShowSidePanel: PropTypes.func,
@@ -10,7 +10,7 @@ const propTypes = {
showSearch: PropTypes.bool
};
class TopToolbar extends React.Component {
class SettingTopToolbar extends React.Component {
render() {
const { onShowSidePanel, onSearchedClick, children, showSearch } = this.props;
@@ -31,6 +31,6 @@ class TopToolbar extends React.Component {
}
}
TopToolbar.propTypes = propTypes;
SettingTopToolbar.propTypes = propTypes;
export default TopToolbar;
export default SettingTopToolbar;