mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2026-03-02 05:36:38 +00:00
Added swipable menu
This commit is contained in:
@@ -9,7 +9,7 @@ import CreateServer from './servers/CreateServer';
|
||||
export default class App extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="container-fluid">
|
||||
<div className="container-fluid app-container">
|
||||
<MainHeader/>
|
||||
|
||||
<div className="app">
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
@import './utils/base';
|
||||
|
||||
.app-container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.app {
|
||||
padding-top: $headerHeight;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@@ -6,12 +6,23 @@ import { NavLink } from 'react-router-dom';
|
||||
import DeleteServerButton from '../servers/DeleteServerButton';
|
||||
import './AsideMenu.scss';
|
||||
import PropTypes from 'prop-types';
|
||||
import { serverType } from '../servers/prop-types';
|
||||
|
||||
export default function AsideMenu({ selectedServer }) {
|
||||
const defaultProps = {
|
||||
className: '',
|
||||
showOnMobile: false,
|
||||
};
|
||||
const propTypes = {
|
||||
selectedServer: serverType,
|
||||
className: PropTypes.string,
|
||||
showOnMobile: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default function AsideMenu({ selectedServer, className, showOnMobile }) {
|
||||
const serverId = selectedServer ? selectedServer.id : '';
|
||||
|
||||
return (
|
||||
<aside className="aside-menu col-lg-2 col-md-3">
|
||||
<aside className={`aside-menu ${!showOnMobile ? 'aside-menu--hidden' : ''} ${className}`}>
|
||||
<nav className="nav flex-column aside-menu__nav">
|
||||
<NavLink
|
||||
className="aside-menu__item"
|
||||
@@ -39,11 +50,5 @@ export default function AsideMenu({ selectedServer }) {
|
||||
);
|
||||
}
|
||||
|
||||
AsideMenu.propTypes = {
|
||||
selectedServer: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
url: PropTypes.string,
|
||||
apiKey: PropTypes.string,
|
||||
}),
|
||||
};
|
||||
AsideMenu.defaultProps = defaultProps;
|
||||
AsideMenu.propTypes = propTypes;
|
||||
|
||||
@@ -1,22 +1,38 @@
|
||||
@import '../utils/base';
|
||||
@import '../utils/mixins/box-shadow';
|
||||
|
||||
$asideMenuMobileWidth: 280px;
|
||||
|
||||
.aside-menu {
|
||||
background-color: #f7f7f7;
|
||||
padding-top: 10px;
|
||||
position: fixed !important;
|
||||
padding-top: 13px;
|
||||
padding-bottom: 10px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: block;
|
||||
z-index: 1050;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
|
||||
@media (min-width: $mdMin) {
|
||||
position: fixed !important;
|
||||
top: $headerHeight;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
display: block;
|
||||
padding: 30px 15px 15px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
|
||||
@media (max-width: $smMax) {
|
||||
width: $asideMenuMobileWidth !important;
|
||||
@include box-shadow(-10px 0px 50px 11px rgba(0, 0, 0, 0.55));
|
||||
transition: left 300ms;
|
||||
}
|
||||
}
|
||||
|
||||
.aside-menu--hidden {
|
||||
@media (max-width: $smMax) {
|
||||
left: -($asideMenuMobileWidth + 35px);
|
||||
}
|
||||
}
|
||||
|
||||
.aside-menu__nav {
|
||||
|
||||
@@ -1,48 +1,79 @@
|
||||
import React from 'react';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
import { Route, Switch, withRouter } from 'react-router-dom';
|
||||
import { connect } from 'react-redux';
|
||||
import { compose } from 'redux';
|
||||
import { selectServer } from '../servers/reducers/selectedServer';
|
||||
import CreateShortUrl from '../short-urls/CreateShortUrl';
|
||||
import ShortUrls from '../short-urls/ShortUrls';
|
||||
import ShortUrlsVisits from '../short-urls/ShortUrlVisits';
|
||||
import AsideMenu from './AsideMenu';
|
||||
import { pick } from 'ramda';
|
||||
import Swipeable from 'react-swipeable';
|
||||
import './MenuLayout.scss';
|
||||
|
||||
export class MenuLayout extends React.Component {
|
||||
state = { showSideBar: false };
|
||||
|
||||
// FIXME Shouldn't use componentWillMount, but this code has to be run before children components are rendered
|
||||
componentWillMount() {
|
||||
const { serverId } = this.props.match.params;
|
||||
this.props.selectServer(serverId);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { location } = this.props;
|
||||
|
||||
// Hide sidebar when location changes
|
||||
if (location !== prevProps.location) {
|
||||
this.setState({ showSideBar: false });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { selectedServer } = this.props;
|
||||
|
||||
return (
|
||||
<div className="row">
|
||||
<AsideMenu selectedServer={selectedServer} />
|
||||
<div className="col-lg-10 offset-lg-2 col-md-9 offset-md-3">
|
||||
<Switch>
|
||||
<Route
|
||||
exact
|
||||
path="/server/:serverId/list-short-urls/:page"
|
||||
component={ShortUrls}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/server/:serverId/create-short-url"
|
||||
component={CreateShortUrl}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/server/:serverId/short-code/:shortCode/visits"
|
||||
component={ShortUrlsVisits}
|
||||
/>
|
||||
</Switch>
|
||||
<Swipeable
|
||||
delta={40}
|
||||
onSwipedLeft={() => this.setState({ showSideBar: false })}
|
||||
onSwipedRight={() => this.setState({ showSideBar: true })}
|
||||
className="menu-layout__swipeable"
|
||||
>
|
||||
<div className="row menu-layout__swipeable-inner">
|
||||
<AsideMenu
|
||||
className="col-lg-2 col-md-3"
|
||||
selectedServer={selectedServer}
|
||||
showOnMobile={this.state.showSideBar}
|
||||
/>
|
||||
<div
|
||||
className="col-lg-10 offset-lg-2 col-md-9 offset-md-3"
|
||||
onClick={() => this.setState({ showSideBar: false })}
|
||||
>
|
||||
<Switch>
|
||||
<Route
|
||||
exact
|
||||
path="/server/:serverId/list-short-urls/:page"
|
||||
component={ShortUrls}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/server/:serverId/create-short-url"
|
||||
component={CreateShortUrl}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/server/:serverId/short-code/:shortCode/visits"
|
||||
component={ShortUrlsVisits}
|
||||
/>
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Swipeable>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(pick(['selectedServer', 'shortUrlsListParams']), { selectServer })(MenuLayout);
|
||||
export default compose(
|
||||
connect(pick(['selectedServer', 'shortUrlsListParams']), { selectServer }),
|
||||
withRouter
|
||||
)(MenuLayout);
|
||||
|
||||
12
src/common/MenuLayout.scss
Normal file
12
src/common/MenuLayout.scss
Normal file
@@ -0,0 +1,12 @@
|
||||
.menu-layout__swipeable {
|
||||
$offset: 15px;
|
||||
height: 100%;
|
||||
margin-right: -$offset;
|
||||
margin-left: -$offset;
|
||||
padding-left: $offset;
|
||||
padding-right: $offset;
|
||||
}
|
||||
|
||||
.menu-layout__swipeable-inner {
|
||||
height: 100%;
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
@import './utils/base';
|
||||
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
height: 100%
|
||||
}
|
||||
|
||||
* {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { withRouter } from 'react-router-dom';
|
||||
import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
|
||||
import { compose } from 'redux';
|
||||
import { deleteServer } from './reducers/server';
|
||||
import { serverType } from './prop-types';
|
||||
|
||||
export const DeleteServerModal = ({ server, toggle, isOpen, deleteServer, history }) => {
|
||||
const closeModal = () => {
|
||||
@@ -34,12 +35,7 @@ export const DeleteServerModal = ({ server, toggle, isOpen, deleteServer, histor
|
||||
DeleteServerModal.propTypes = {
|
||||
toggle: PropTypes.func.isRequired,
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
server: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
url: PropTypes.string,
|
||||
apiKey: PropTypes.string,
|
||||
}),
|
||||
server: serverType,
|
||||
};
|
||||
|
||||
export default compose(
|
||||
|
||||
8
src/servers/prop-types/index.js
Normal file
8
src/servers/prop-types/index.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export const serverType = PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
url: PropTypes.string,
|
||||
apiKey: PropTypes.string,
|
||||
});
|
||||
Reference in New Issue
Block a user