From abeb39968809df44bd36b1570df6fcb8b07d1966 Mon Sep 17 00:00:00 2001 From: jamaljsr Date: Tue, 21 Apr 2020 00:50:20 -0400 Subject: [PATCH] feat: implement sidebar collapsing --- app/.storybook/preview.tsx | 23 ++++----------- app/src/__stories__/Layout.stories.tsx | 39 ++++++++++++++++++++++---- app/src/action/app.ts | 25 +++++++++++++++++ app/src/action/index.ts | 9 ++++-- app/src/components/layout/Layout.tsx | 37 ++++++++++++++++++------ app/src/store/index.ts | 3 ++ 6 files changed, 101 insertions(+), 35 deletions(-) create mode 100644 app/src/action/app.ts diff --git a/app/.storybook/preview.tsx b/app/.storybook/preview.tsx index c2227030..0c53a205 100644 --- a/app/.storybook/preview.tsx +++ b/app/.storybook/preview.tsx @@ -1,11 +1,8 @@ import React from 'react'; import 'mobx-react-lite/batchingForReactDom'; -import { addDecorator } from '@storybook/react'; +import { addDecorator, addParameters } from '@storybook/react'; import '../src/App.scss'; -import ChannelAction from '../src/action/channel'; -import NodeAction from '../src/action/node'; -import SwapAction from '../src/action/swap'; -import { LndApi, LoopApi } from '../src/api'; +import { createActions } from '../src/action'; import { Background } from '../src/components/common/base'; import { ThemeProvider } from '../src/components/theme'; import { Store, StoreProvider } from '../src/store'; @@ -31,23 +28,13 @@ const grpc = { return Promise.resolve(response); }, }; -const lndApi = new LndApi(grpc); -const loopApi = new LoopApi(grpc); - -// actions exposed to UI components -const node = new NodeAction(store, lndApi); -const channel = new ChannelAction(store, lndApi); -const swap = new SwapAction(store, loopApi); - -const actions = { - node, - channel, - swap, -}; +const actions = createActions(store, grpc); // execute actions to populate the store data with the sample API responses actions.node.getBalances(); +addParameters({ store }); + /** * decorator function to wrap all stories with the necessary providers */ diff --git a/app/src/__stories__/Layout.stories.tsx b/app/src/__stories__/Layout.stories.tsx index 50442115..5ba7ee87 100644 --- a/app/src/__stories__/Layout.stories.tsx +++ b/app/src/__stories__/Layout.stories.tsx @@ -1,4 +1,6 @@ -import React from 'react'; +import React, { useEffect } from 'react'; +import { StoryContext } from '@storybook/addons'; +import { Store } from 'store'; import { Layout } from '../components/layout'; export default { @@ -6,11 +8,9 @@ export default { component: Layout, }; -export const Empty = () => ; - -export const WithContent = () => ( - -

Lorem ipsum dolor sit amet

+const SampleContent = () => ( + <> +

Lorem ipsum dolor sit amet

{[...Array(10)].map((_, i) => (

At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis @@ -26,5 +26,32 @@ export const WithContent = () => ( consequatur aut perferendis doloribus asperiores repellat.

))} + +); + +export const Default = () => ; + +export const WithContent = () => ( + + ); + +export const Collapsed = (ctx: StoryContext) => { + useEffect(() => { + // grab the store from the Storybook parameter defined in preview.tsx + const store = ctx.parameters.store as Store; + store.sidebarCollapsed = true; + + // change back to expanded when the component is unmounted + return () => { + store.sidebarCollapsed = false; + }; + }, []); + + return ( + + + + ); +}; diff --git a/app/src/action/app.ts b/app/src/action/app.ts new file mode 100644 index 00000000..28026b96 --- /dev/null +++ b/app/src/action/app.ts @@ -0,0 +1,25 @@ +import { action, toJS } from 'mobx'; +import { log } from 'util/log'; +import { Store } from 'store'; + +/** + * Action used to update app level state + */ +class AppAction { + private _store: Store; + + constructor(store: Store) { + this._store = store; + } + + /** + * toggle the sidebar to be collapsed or expanded + */ + @action.bound toggleSidebar() { + log.info('toggling sidebar'); + this._store.sidebarCollapsed = !this._store.sidebarCollapsed; + log.info('updated store.sidebarCollapsed', toJS(this._store.sidebarCollapsed)); + } +} + +export default AppAction; diff --git a/app/src/action/index.ts b/app/src/action/index.ts index c09abe66..eb0b930d 100644 --- a/app/src/action/index.ts +++ b/app/src/action/index.ts @@ -2,11 +2,13 @@ import GrpcClient from 'api/grpc'; import LndApi from 'api/lnd'; import LoopApi from 'api/loop'; import { Store } from 'store'; +import AppAction from './app'; import ChannelAction from './channel'; import NodeAction from './node'; import SwapAction from './swap'; export interface StoreActions { + app: AppAction; node: NodeAction; channel: ChannelAction; swap: SwapAction; @@ -15,19 +17,22 @@ export interface StoreActions { /** * Creates actions that modify the state of the given mobx store * @param store the Store instance that the actions will modify + * @param grpcClient optionally provide an alternate grpc client if necessary */ -export const createActions = (store: Store): StoreActions => { +export const createActions = (store: Store, grpcClient?: GrpcClient): StoreActions => { // low level dependencies - const grpc = new GrpcClient(); + const grpc = grpcClient || new GrpcClient(); const lndApi = new LndApi(grpc); const loopApi = new LoopApi(grpc); // actions exposed to UI components + const app = new AppAction(store); const node = new NodeAction(store, lndApi); const channel = new ChannelAction(store, lndApi); const swap = new SwapAction(store, loopApi); return { + app, node, channel, swap, diff --git a/app/src/components/layout/Layout.tsx b/app/src/components/layout/Layout.tsx index 75db0454..8e166b64 100644 --- a/app/src/components/layout/Layout.tsx +++ b/app/src/components/layout/Layout.tsx @@ -1,9 +1,15 @@ import React from 'react'; +import { observer } from 'mobx-react-lite'; +import { useActions, useStore } from 'store'; import { Background } from 'components/common/base'; import { Menu } from 'components/common/icons'; import { styled } from 'components/theme'; import Sidebar from './Sidebar'; +interface CollapsedProps { + collapsed: boolean; +} + const Styled = { Container: styled.div` position: relative; @@ -18,30 +24,43 @@ const Styled = { z-index: 1; cursor: pointer; `, - Aside: styled.aside` + Aside: styled.aside` position: fixed; top: 0; height: 100vh; background-color: ${props => props.theme.colors.darkBlue}; - width: 285px; - padding: 15px; + overflow: hidden; + + /* change sidebar dimensions based on collapsed toggle */ + width: ${props => (props.collapsed ? '0' : '285px')}; + padding: ${props => (props.collapsed ? '0' : '15px')}; + transition: all 0.2s; + + /* set a width on the child to improve the collapse animation */ + & > div { + width: 285px; + } `, - Content: styled.div` - margin-left: 285px; + Content: styled.div` + margin-left: ${props => (props.collapsed ? '0' : '285px')}; padding: 15px; + transition: all 0.2s; `, }; const Layout: React.FC = ({ children }) => { + const { sidebarCollapsed } = useStore(); + const { app } = useActions(); + const { Container, MenuIcon, Aside, Content } = Styled; return ( - -