Made sidebars toggleable
Summary: Implemented a first button: make main menu collapsible. Also introduced some additional utilities and hooked up startup performance logging Reviewed By: cekkaewnumchai Differential Revision: D23783500 fbshipit-source-id: 2456fd781a52d497facbaccfabe885e4f8c408c5
This commit is contained in:
committed by
Facebook GitHub Bot
parent
95638af321
commit
e7fdd8332d
@@ -79,17 +79,12 @@ const PluginContent = styled(FlexRow)({
|
|||||||
PluginContent.displayName = 'App:PluginContent';
|
PluginContent.displayName = 'App:PluginContent';
|
||||||
type Props = StateFromProps & OwnProps & DispatchProps;
|
type Props = StateFromProps & OwnProps & DispatchProps;
|
||||||
|
|
||||||
export class App extends React.Component<Props> {
|
export function registerStartupTime(logger: Logger) {
|
||||||
componentDidMount() {
|
|
||||||
// track time since launch
|
// track time since launch
|
||||||
const [s, ns] = process.hrtime();
|
const [s, ns] = process.hrtime();
|
||||||
const launchEndTime = s * 1e3 + ns / 1e6;
|
const launchEndTime = s * 1e3 + ns / 1e6;
|
||||||
ipcRenderer.on('getLaunchTime', (_: any, launchStartTime: number) => {
|
ipcRenderer.on('getLaunchTime', (_: any, launchStartTime: number) => {
|
||||||
this.props.logger.track(
|
logger.track('performance', 'launchTime', launchEndTime - launchStartTime);
|
||||||
'performance',
|
|
||||||
'launchTime',
|
|
||||||
launchEndTime - launchStartTime,
|
|
||||||
);
|
|
||||||
|
|
||||||
QuickPerformanceLogger.markerPoint(
|
QuickPerformanceLogger.markerPoint(
|
||||||
FLIPPER_QPL_EVENTS.STARTUP,
|
FLIPPER_QPL_EVENTS.STARTUP,
|
||||||
@@ -109,7 +104,11 @@ export class App extends React.Component<Props> {
|
|||||||
|
|
||||||
ipcRenderer.send('getLaunchTime');
|
ipcRenderer.send('getLaunchTime');
|
||||||
ipcRenderer.send('componentDidMount');
|
ipcRenderer.send('componentDidMount');
|
||||||
|
}
|
||||||
|
|
||||||
|
export class App extends React.Component<Props> {
|
||||||
|
componentDidMount() {
|
||||||
|
registerStartupTime(this.props.logger);
|
||||||
if (hasNewChangesToShow(window.localStorage)) {
|
if (hasNewChangesToShow(window.localStorage)) {
|
||||||
this.props.setActiveSheet(ACTIVE_SHEET_CHANGELOG_RECENT_ONLY);
|
this.props.setActiveSheet(ACTIVE_SHEET_CHANGELOG_RECENT_ONLY);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,12 @@ import {
|
|||||||
MedicineBoxOutlined,
|
MedicineBoxOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import {SidebarLeft, SidebarRight} from './SandyIcons';
|
import {SidebarLeft, SidebarRight} from './SandyIcons';
|
||||||
|
import {useDispatch, useStore} from '../utils/useStore';
|
||||||
|
import {toggleLeftSidebarVisible} from '../reducers/application';
|
||||||
|
import {theme} from './theme';
|
||||||
|
|
||||||
const LeftRailContainer = styled(FlexColumn)({
|
const LeftRailContainer = styled(FlexColumn)({
|
||||||
|
background: theme.backgroundDefault,
|
||||||
width: 48,
|
width: 48,
|
||||||
boxShadow: 'inset -1px 0px 0px rgba(0, 0, 0, 0.1)',
|
boxShadow: 'inset -1px 0px 0px rgba(0, 0, 0, 0.1)',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
@@ -36,10 +40,10 @@ const LeftRailSection = styled(FlexColumn)({
|
|||||||
});
|
});
|
||||||
LeftRailSection.displayName = 'LeftRailSection';
|
LeftRailSection.displayName = 'LeftRailSection';
|
||||||
|
|
||||||
const LeftRailButtonElem = styled(Button)<{margin: number}>(({margin}) => ({
|
const LeftRailButtonElem = styled(Button)<{kind?: 'small'}>(({kind}) => ({
|
||||||
width: 36,
|
width: kind === 'small' ? 32 : 36,
|
||||||
height: 36,
|
height: kind === 'small' ? 32 : 36,
|
||||||
margin,
|
margin: 6,
|
||||||
padding: '5px 0',
|
padding: '5px 0',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
boxShadow: 'none',
|
boxShadow: 'none',
|
||||||
@@ -49,15 +53,19 @@ LeftRailButtonElem.displayName = 'LeftRailButtonElem';
|
|||||||
function LeftRailButton({
|
function LeftRailButton({
|
||||||
icon,
|
icon,
|
||||||
small,
|
small,
|
||||||
active,
|
selected,
|
||||||
|
toggled,
|
||||||
count,
|
count,
|
||||||
title,
|
title,
|
||||||
|
onClick,
|
||||||
}: {
|
}: {
|
||||||
icon?: React.ReactElement;
|
icon?: React.ReactElement;
|
||||||
small?: boolean;
|
small?: boolean;
|
||||||
active?: boolean;
|
toggled?: boolean;
|
||||||
|
selected?: boolean;
|
||||||
count?: number;
|
count?: number;
|
||||||
title: string;
|
title: string;
|
||||||
|
onClick?: React.MouseEventHandler<HTMLElement>;
|
||||||
}) {
|
}) {
|
||||||
let iconElement =
|
let iconElement =
|
||||||
icon && cloneElement(icon, {style: {fontSize: small ? 16 : 24}});
|
icon && cloneElement(icon, {style: {fontSize: small ? 16 : 24}});
|
||||||
@@ -67,9 +75,14 @@ function LeftRailButton({
|
|||||||
return (
|
return (
|
||||||
<Tooltip title={title} placement="right">
|
<Tooltip title={title} placement="right">
|
||||||
<LeftRailButtonElem
|
<LeftRailButtonElem
|
||||||
margin={small ? 2 : 6}
|
kind={small ? 'small' : undefined}
|
||||||
type={active ? 'primary' : 'ghost'}
|
type={selected ? 'primary' : 'ghost'}
|
||||||
icon={iconElement}
|
icon={iconElement}
|
||||||
|
onClick={onClick}
|
||||||
|
style={{
|
||||||
|
color: toggled ? theme.primaryColor : undefined,
|
||||||
|
background: toggled ? theme.backgroundWash : undefined,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
@@ -86,7 +99,7 @@ export function LeftRail() {
|
|||||||
return (
|
return (
|
||||||
<LeftRailContainer>
|
<LeftRailContainer>
|
||||||
<LeftRailSection>
|
<LeftRailSection>
|
||||||
<LeftRailButton icon={<MobileFilled />} active title="App Inspect" />
|
<LeftRailButton icon={<MobileFilled />} title="App Inspect" />
|
||||||
<LeftRailButton icon={<AppstoreOutlined />} title="Plugin Manager" />
|
<LeftRailButton icon={<AppstoreOutlined />} title="Plugin Manager" />
|
||||||
<LeftRailButton
|
<LeftRailButton
|
||||||
count={8}
|
count={8}
|
||||||
@@ -117,17 +130,33 @@ export function LeftRail() {
|
|||||||
title="Feedback / Bug Reporter"
|
title="Feedback / Bug Reporter"
|
||||||
/>
|
/>
|
||||||
<LeftRailButton
|
<LeftRailButton
|
||||||
icon={<SidebarLeft />}
|
icon={<SidebarRight />}
|
||||||
small
|
small
|
||||||
title="Right Sidebar Toggle"
|
title="Right Sidebar Toggle"
|
||||||
/>
|
/>
|
||||||
<LeftRailButton
|
<LeftSidebarToggleButton />
|
||||||
icon={<SidebarRight />}
|
|
||||||
small
|
|
||||||
title="Left Sidebar Toggle"
|
|
||||||
/>
|
|
||||||
<LeftRailButton icon={<LoginOutlined />} title="Log In" />
|
<LeftRailButton icon={<LoginOutlined />} title="Log In" />
|
||||||
</LeftRailSection>
|
</LeftRailSection>
|
||||||
</LeftRailContainer>
|
</LeftRailContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function LeftSidebarToggleButton() {
|
||||||
|
const mainMenuVisible = useStore(
|
||||||
|
(state) => state.application.leftSidebarVisible,
|
||||||
|
);
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LeftRailButton
|
||||||
|
icon={<SidebarLeft />}
|
||||||
|
small
|
||||||
|
title="Left Sidebar Toggle"
|
||||||
|
toggled={mainMenuVisible}
|
||||||
|
onClick={() => {
|
||||||
|
dispatch(toggleLeftSidebarVisible());
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,23 +7,40 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React, {useEffect} from 'react';
|
||||||
import {styled} from 'flipper';
|
import {styled} from 'flipper';
|
||||||
import {DatePicker} from 'antd';
|
import {DatePicker} from 'antd';
|
||||||
import {Layout, FlexRow} from '../ui';
|
import {Layout, FlexRow} from '../ui';
|
||||||
import {theme} from './theme';
|
import {theme} from './theme';
|
||||||
|
import {Logger} from '../fb-interfaces/Logger';
|
||||||
|
|
||||||
import {LeftRail} from './LeftRail';
|
import {LeftRail} from './LeftRail';
|
||||||
import {TemporarilyTitlebar} from './TemporarilyTitlebar';
|
import {TemporarilyTitlebar} from './TemporarilyTitlebar';
|
||||||
|
import {registerStartupTime} from '../App';
|
||||||
|
import {useStore} from '../utils/useStore';
|
||||||
|
|
||||||
|
export function SandyApp({logger}: {logger: Logger}) {
|
||||||
|
useEffect(() => {
|
||||||
|
registerStartupTime(logger);
|
||||||
|
// don't warn about logger, even with a new logger we don't want to re-register
|
||||||
|
// eslint-disable-next-line
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const mainMenuVisible = useStore(
|
||||||
|
(state) => state.application.leftSidebarVisible,
|
||||||
|
);
|
||||||
|
|
||||||
export function SandyApp() {
|
|
||||||
return (
|
return (
|
||||||
<Layout.Top>
|
<Layout.Top>
|
||||||
<TemporarilyTitlebar />
|
<TemporarilyTitlebar />
|
||||||
<Layout.Left initialSize={348} minSize={200}>
|
<Layout.Left
|
||||||
<LeftMenu>
|
initialSize={mainMenuVisible ? 348 : undefined}
|
||||||
|
minSize={200}>
|
||||||
|
<LeftMenu collapsed={!mainMenuVisible}>
|
||||||
<LeftRail />
|
<LeftRail />
|
||||||
<div>LeftMenu</div>
|
{mainMenuVisible && (
|
||||||
|
<div style={{background: 'white', width: '100%'}}>LeftMenu</div>
|
||||||
|
)}
|
||||||
</LeftMenu>
|
</LeftMenu>
|
||||||
<MainContainer>
|
<MainContainer>
|
||||||
<Layout.Right initialSize={300} minSize={200}>
|
<Layout.Right initialSize={300} minSize={200}>
|
||||||
@@ -44,11 +61,13 @@ export function SandyApp() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const LeftMenu = styled(FlexRow)({
|
const LeftMenu = styled(FlexRow)<{collapsed: boolean}>(({collapsed}) => ({
|
||||||
boxShadow: `inset -1px 0px 0px ${theme.dividerColor}`,
|
background: theme.backgroundWash,
|
||||||
|
boxShadow: collapsed ? undefined : `1px 0px 0px ${theme.dividerColor}`,
|
||||||
|
paddingRight: collapsed ? theme.space.middle : 0,
|
||||||
height: '100%',
|
height: '100%',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
});
|
}));
|
||||||
|
|
||||||
const MainContainer = styled('div')({
|
const MainContainer = styled('div')({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export const SidebarLeft = (props: React.SVGProps<SVGSVGElement>) => (
|
export const SidebarRight = (props: React.SVGProps<SVGSVGElement>) => (
|
||||||
<svg width={16} height={16} viewBox="0 0 16 16" fill="none" {...props}>
|
<svg width={16} height={16} viewBox="0 0 16 16" fill="none" {...props}>
|
||||||
<path
|
<path
|
||||||
fillRule="evenodd"
|
fillRule="evenodd"
|
||||||
@@ -24,7 +24,7 @@ export const SidebarLeft = (props: React.SVGProps<SVGSVGElement>) => (
|
|||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const SidebarRight = (props: React.SVGProps<SVGSVGElement>) => (
|
export const SidebarLeft = (props: React.SVGProps<SVGSVGElement>) => (
|
||||||
<svg width={16} height={16} viewBox="0 0 16 16" fill="none" {...props}>
|
<svg width={16} height={16} viewBox="0 0 16 16" fill="none" {...props}>
|
||||||
<path
|
<path
|
||||||
fillRule="evenodd"
|
fillRule="evenodd"
|
||||||
|
|||||||
35
desktop/app/src/utils/useStore.tsx
Normal file
35
desktop/app/src/utils/useStore.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
useSelector,
|
||||||
|
shallowEqual,
|
||||||
|
useDispatch as useDispatchBase,
|
||||||
|
} from 'react-redux';
|
||||||
|
import {Dispatch} from 'redux';
|
||||||
|
import {State, Actions} from '../reducers/index';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strongly typed wrapper or Redux's useSelector.
|
||||||
|
*
|
||||||
|
* Equality defaults to shallowEquality
|
||||||
|
*/
|
||||||
|
export function useStore<Selected>(
|
||||||
|
selector: (state: State) => Selected,
|
||||||
|
equalityFn: (left: Selected, right: Selected) => boolean = shallowEqual,
|
||||||
|
): Selected {
|
||||||
|
return useSelector(selector, equalityFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strongly typed useDispatch wrapper for the Flipper redux store.
|
||||||
|
*/
|
||||||
|
export function useDispatch(): Dispatch<Actions> {
|
||||||
|
return useDispatchBase();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user