Add responsive menu (#257)

This commit is contained in:
WithoutPants
2019-12-13 05:57:13 +11:00
committed by Leopere
parent bb164f1895
commit 50930f6ca7
4 changed files with 185 additions and 86 deletions

View File

@@ -1,4 +1,4 @@
import React, { FunctionComponent, useEffect } from "react"; import React, { FunctionComponent, useState } from "react";
import { Route, Switch } from "react-router-dom"; import { Route, Switch } from "react-router-dom";
import { ErrorBoundary } from "./components/ErrorBoundary"; import { ErrorBoundary } from "./components/ErrorBoundary";
import Galleries from "./components/Galleries/Galleries"; import Galleries from "./components/Galleries/Galleries";
@@ -11,26 +11,80 @@ import { Stats } from "./components/Stats";
import Studios from "./components/Studios/Studios"; import Studios from "./components/Studios/Studios";
import Tags from "./components/Tags/Tags"; import Tags from "./components/Tags/Tags";
import { SceneFilenameParser } from "./components/scenes/SceneFilenameParser"; import { SceneFilenameParser } from "./components/scenes/SceneFilenameParser";
import { Sidebar } from "./components/Sidebar";
import { IconName } from "@blueprintjs/core";
export interface IMenuItem {
icon: IconName
text: string
href: string
}
interface IProps {} interface IProps {}
export const App: FunctionComponent<IProps> = (props: IProps) => { export const App: FunctionComponent<IProps> = (props: IProps) => {
const [menuOpen, setMenuOpen] = useState<boolean>(false);
function getSidebarClosedClass() {
if (!menuOpen) {
return " sidebar-closed";
}
return "";
}
const menuItems: IMenuItem[] = [
{
icon: "video",
text: "Scenes",
href: "/scenes"
},
{
href: "/scenes/markers",
icon: "map-marker",
text: "Markers"
},
{
href: "/galleries",
icon: "media",
text: "Galleries"
},
{
href: "/performers",
icon: "person",
text: "Performers"
},
{
href: "/studios",
icon: "mobile-video",
text: "Studios"
},
{
href: "/tags",
icon: "tag",
text: "Tags"
}
];
return ( return (
<div className="bp3-dark"> <div className="bp3-dark">
<ErrorBoundary> <ErrorBoundary>
<MainNavbar /> <MainNavbar onMenuToggle={() => setMenuOpen(!menuOpen)} menuItems={menuItems}/>
<Switch> <Sidebar className={getSidebarClosedClass()} menuItems={menuItems}/>
<Route exact={true} path="/" component={Stats} /> <div className={"main" + getSidebarClosedClass()}>
<Route path="/scenes" component={Scenes} /> <Switch>
{/* <Route path="/scenes/:id" component={Scene} /> */} <Route exact={true} path="/" component={Stats} />
<Route path="/galleries" component={Galleries} /> <Route path="/scenes" component={Scenes} />
<Route path="/performers" component={Performers} /> {/* <Route path="/scenes/:id" component={Scene} /> */}
<Route path="/tags" component={Tags} /> <Route path="/galleries" component={Galleries} />
<Route path="/studios" component={Studios} /> <Route path="/performers" component={Performers} />
<Route path="/settings" component={Settings} /> <Route path="/tags" component={Tags} />
<Route path="/sceneFilenameParser" component={SceneFilenameParser} /> <Route path="/studios" component={Studios} />
<Route component={PageNotFound} /> <Route path="/settings" component={Settings} />
</Switch> <Route path="/sceneFilenameParser" component={SceneFilenameParser} />
<Route component={PageNotFound} />
</Switch>
</div>
</ErrorBoundary> </ErrorBoundary>
</div> </div>
); );

View File

@@ -3,12 +3,17 @@ import {
NavbarDivider, NavbarDivider,
NavbarGroup, NavbarGroup,
NavbarHeading, NavbarHeading,
Button,
} from "@blueprintjs/core"; } from "@blueprintjs/core";
import React, { FunctionComponent, useEffect, useState } from "react"; import React, { FunctionComponent, useEffect, useState } from "react";
import { Link, NavLink } from "react-router-dom"; import { Link, NavLink } from "react-router-dom";
import useLocation from "react-use/lib/useLocation"; import useLocation from "react-use/lib/useLocation";
import { IMenuItem } from "../App";
interface IProps {} interface IProps {
onMenuToggle() : void
menuItems: IMenuItem[]
}
export const MainNavbar: FunctionComponent<IProps> = (props) => { export const MainNavbar: FunctionComponent<IProps> = (props) => {
const [newButtonPath, setNewButtonPath] = useState<string | undefined>(undefined); const [newButtonPath, setNewButtonPath] = useState<string | undefined>(undefined);
@@ -46,76 +51,38 @@ export const MainNavbar: FunctionComponent<IProps> = (props) => {
} }
return ( return (
<Navbar fixedToTop={true}> <>
<div> <Navbar fixedToTop={true}>
<NavbarGroup align="left"> <div>
<NavbarHeading><Link to="/" className="bp3-button bp3-minimal">Stash</Link></NavbarHeading> <NavbarGroup align="left">
<NavbarDivider /> <Button className="menu-button" icon="menu" onClick={() => props.onMenuToggle()}/>
<NavbarHeading><Link to="/" className="bp3-button bp3-minimal">Stash</Link></NavbarHeading>
<NavbarDivider />
<NavLink {props.menuItems.map((i) => {
exact={true} return (
to="/scenes" <NavLink
className="bp3-button bp3-minimal bp3-icon-video" exact={true}
activeClassName="bp3-active" to={i.href}
> className={"bp3-button bp3-minimal collapsible-navlink bp3-icon-" + i.icon}
Scenes activeClassName="bp3-active"
</NavLink> >
{i.text}
<NavLink </NavLink>
exact={true} );
to="/scenes/markers" })}
className="bp3-button bp3-minimal bp3-icon-map-marker" </NavbarGroup>
activeClassName="bp3-active" <NavbarGroup align="right">
> {renderNewButton()}
Markers <NavLink
</NavLink> exact={true}
to="/settings"
<NavLink className="bp3-button bp3-minimal bp3-icon-cog"
exact={true} activeClassName="bp3-active"
to="/galleries" />
className="bp3-button bp3-minimal bp3-icon-media" </NavbarGroup>
activeClassName="bp3-active" </div>
> </Navbar>
Galleries </>
</NavLink>
<NavLink
exact={true}
to="/performers"
className="bp3-button bp3-minimal bp3-icon-person"
activeClassName="bp3-active"
>
Performers
</NavLink>
<NavLink
exact={true}
to="/studios"
className="bp3-button bp3-minimal bp3-icon-mobile-video"
activeClassName="bp3-active"
>
Studios
</NavLink>
<NavLink
exact={true}
to="/tags"
className="bp3-button bp3-minimal bp3-icon-tag"
activeClassName="bp3-active"
>
Tags
</NavLink>
</NavbarGroup>
<NavbarGroup align="right">
{renderNewButton()}
<NavLink
exact={true}
to="/settings"
className="bp3-button bp3-minimal bp3-icon-cog"
activeClassName="bp3-active"
/>
</NavbarGroup>
</div>
</Navbar>
); );
}; };

View File

@@ -0,0 +1,32 @@
import {
MenuItem,
Menu,
IconName,
} from "@blueprintjs/core";
import React, { FunctionComponent } from "react";
import { IMenuItem } from "../App";
interface IProps {
className: string
menuItems: IMenuItem[]
}
export const Sidebar: FunctionComponent<IProps> = (props) => {
return (
<>
<div className={"sidebar" + props.className}>
<Menu large={true}>
{props.menuItems.map((i) => {
return (
<MenuItem
icon={i.icon}
text={i.text}
href={i.href}
/>
)
})}
</Menu>
</div>
</>
);
};

View File

@@ -477,3 +477,49 @@ span.block {
.aliases-field > label{ .aliases-field > label{
font-weight: 300; font-weight: 300;
} }
@media only screen and (max-width: 768px) {
// collapse menu items into sidemenu
.collapsible-navlink {
display: none;
}
}
.sidebar {
position: fixed;
top: 50px;
bottom: 0;
left: 0;
width: 200px;
background-color: #394b59;
transition: left 0.5s;
z-index: 11;
}
.sidebar.sidebar-closed {
left: -200px;
transition: left 0.5s;
}
// overlay menu on smaller devices
@media only screen and (min-width: 768px) {
// hide menu button on larger devices
.menu-button {
display: none;
}
.main {
margin-left: 200px;
transition: margin-left 0.5s;
}
.sidebar {
left: -200px;
}
.main.sidebar-closed {
margin-left: 0px;
transition: margin-left 0.5s;
}
}