mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
feat: implement sidebar collapsing
This commit is contained in:
parent
1e6ac168ba
commit
abeb399688
6 changed files with 101 additions and 35 deletions
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 = () => <Layout />;
|
||||
|
||||
export const WithContent = () => (
|
||||
<Layout>
|
||||
<h1>Lorem ipsum dolor sit amet</h1>
|
||||
const SampleContent = () => (
|
||||
<>
|
||||
<h1 style={{ textAlign: 'center' }}>Lorem ipsum dolor sit amet</h1>
|
||||
{[...Array(10)].map((_, i) => (
|
||||
<p key={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.
|
||||
</p>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
||||
export const Default = () => <Layout />;
|
||||
|
||||
export const WithContent = () => (
|
||||
<Layout>
|
||||
<SampleContent />
|
||||
</Layout>
|
||||
);
|
||||
|
||||
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 (
|
||||
<Layout>
|
||||
<SampleContent />
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
25
app/src/action/app.ts
Normal file
25
app/src/action/app.ts
Normal file
|
|
@ -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;
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<CollapsedProps>`
|
||||
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<CollapsedProps>`
|
||||
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 (
|
||||
<Background>
|
||||
<Container>
|
||||
<MenuIcon />
|
||||
<Aside>
|
||||
<MenuIcon onClick={app.toggleSidebar} />
|
||||
<Aside collapsed={sidebarCollapsed}>
|
||||
<Sidebar />
|
||||
</Aside>
|
||||
<Content>
|
||||
<Content collapsed={sidebarCollapsed}>
|
||||
<div className="container">{children}</div>
|
||||
</Content>
|
||||
</Container>
|
||||
|
|
@ -49,4 +68,4 @@ const Layout: React.FC = ({ children }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
export default observer(Layout);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import { Channel, NodeBalances, NodeInfo, Swap } from 'types/state';
|
|||
* The store used to manage global app state
|
||||
*/
|
||||
export class Store {
|
||||
// App state
|
||||
@observable sidebarCollapsed = false;
|
||||
// API data
|
||||
@observable info?: NodeInfo = undefined;
|
||||
@observable balances?: NodeBalances = undefined;
|
||||
@observable channels: Channel[] = [];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue