Build main layout
Summary: This diff introduces the. main sections and restyled resizable panes according to the Figma design Reviewed By: cekkaewnumchai Differential Revision: D23758349 fbshipit-source-id: 7f09574f6b5fb54551141c13667c664e1769f09a
This commit is contained in:
committed by
Facebook GitHub Bot
parent
0100224833
commit
95638af321
@@ -36,12 +36,13 @@ const LeftRailSection = styled(FlexColumn)({
|
|||||||
});
|
});
|
||||||
LeftRailSection.displayName = 'LeftRailSection';
|
LeftRailSection.displayName = 'LeftRailSection';
|
||||||
|
|
||||||
const LeftRailButtonElem = styled(Button)<{small?: boolean}>(({small}) => ({
|
const LeftRailButtonElem = styled(Button)<{margin: number}>(({margin}) => ({
|
||||||
width: 36,
|
width: 36,
|
||||||
height: 36,
|
height: 36,
|
||||||
margin: small ? 2 : 6,
|
margin,
|
||||||
padding: '5px 0',
|
padding: '5px 0',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
|
boxShadow: 'none',
|
||||||
}));
|
}));
|
||||||
LeftRailButtonElem.displayName = 'LeftRailButtonElem';
|
LeftRailButtonElem.displayName = 'LeftRailButtonElem';
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ function LeftRailButton({
|
|||||||
return (
|
return (
|
||||||
<Tooltip title={title} placement="right">
|
<Tooltip title={title} placement="right">
|
||||||
<LeftRailButtonElem
|
<LeftRailButtonElem
|
||||||
small={small}
|
margin={small ? 2 : 6}
|
||||||
type={active ? 'primary' : 'ghost'}
|
type={active ? 'primary' : 'ghost'}
|
||||||
icon={iconElement}
|
icon={iconElement}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -8,135 +8,84 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {connect} from 'react-redux';
|
import {styled} from 'flipper';
|
||||||
import {State as Store} from '../reducers';
|
import {DatePicker} from 'antd';
|
||||||
import {Settings, updateSettings} from '../reducers/settings';
|
import {Layout, FlexRow} from '../ui';
|
||||||
import {styled, FlexColumn, colors, Text} from 'flipper';
|
|
||||||
import {DatePicker, Button} from 'antd';
|
|
||||||
import {Layout, FlexBox} from '../ui';
|
|
||||||
import {theme} from './theme';
|
import {theme} from './theme';
|
||||||
|
|
||||||
import {LeftRail} from './LeftRail';
|
import {LeftRail} from './LeftRail';
|
||||||
import {CloseCircleOutlined} from '@ant-design/icons';
|
import {TemporarilyTitlebar} from './TemporarilyTitlebar';
|
||||||
|
|
||||||
type StateFromProps = {settings: Settings};
|
export function SandyApp() {
|
||||||
type DispatchFromProps = {disableSandy: (settings: Settings) => void};
|
|
||||||
type OwnProps = {};
|
|
||||||
|
|
||||||
type Props = StateFromProps & DispatchFromProps & OwnProps;
|
|
||||||
|
|
||||||
const Container = styled(FlexColumn)({
|
|
||||||
height: '100%',
|
|
||||||
width: '100%',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
backgroundColor: colors.light02,
|
|
||||||
});
|
|
||||||
|
|
||||||
const Box = styled(FlexColumn)({
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
background: colors.white,
|
|
||||||
borderRadius: 10,
|
|
||||||
boxShadow: '0 1px 3px rgba(0,0,0,0.25)',
|
|
||||||
paddingBottom: 16,
|
|
||||||
});
|
|
||||||
|
|
||||||
const AnnoucementText = styled(Text)({
|
|
||||||
fontSize: 24,
|
|
||||||
fontWeight: 300,
|
|
||||||
textAlign: 'center',
|
|
||||||
margin: 16,
|
|
||||||
color: theme.primaryColor,
|
|
||||||
background: theme.backgroundWash,
|
|
||||||
});
|
|
||||||
|
|
||||||
const LeftContainer = styled(FlexBox)({
|
|
||||||
height: '100% ',
|
|
||||||
});
|
|
||||||
|
|
||||||
// This component should be dropped, and insetTitlebar should be removed from Electron startup once Sandy is the default
|
|
||||||
const TemporarilyTitlebar = styled('div')<{focused?: boolean}>(({focused}) => ({
|
|
||||||
textAlign: 'center',
|
|
||||||
userSelect: 'none',
|
|
||||||
height: '38px',
|
|
||||||
lineHeight: '38px',
|
|
||||||
fontSize: '10pt',
|
|
||||||
color: colors.macOSTitleBarIcon,
|
|
||||||
background: true
|
|
||||||
? `linear-gradient(to bottom, ${colors.macOSTitleBarBackgroundTop} 0%, ${colors.macOSTitleBarBackgroundBottom} 100%)`
|
|
||||||
: colors.macOSTitleBarBackgroundBlur,
|
|
||||||
borderBottom: `1px solid ${
|
|
||||||
focused ? colors.macOSTitleBarBorder : colors.macOSTitleBarBorderBlur
|
|
||||||
}`,
|
|
||||||
WebkitAppRegion: 'drag',
|
|
||||||
}));
|
|
||||||
|
|
||||||
function SandyApp(props: Props) {
|
|
||||||
return (
|
return (
|
||||||
<Layout.Top>
|
<Layout.Top>
|
||||||
<TemporarilyTitlebar focused /*TODO: make dynamic */>
|
<TemporarilyTitlebar />
|
||||||
[Sandy] Flipper{' '}
|
<Layout.Left initialSize={348} minSize={200}>
|
||||||
<Button
|
<LeftMenu>
|
||||||
size="small"
|
|
||||||
type="link"
|
|
||||||
icon={<CloseCircleOutlined />}
|
|
||||||
onClick={() => props.disableSandy(props.settings)}></Button>
|
|
||||||
</TemporarilyTitlebar>
|
|
||||||
<Layout.Left>
|
|
||||||
<LeftContainer>
|
|
||||||
<LeftRail />
|
<LeftRail />
|
||||||
<LeftMenu />
|
<div>LeftMenu</div>
|
||||||
</LeftContainer>
|
</LeftMenu>
|
||||||
<Layout.Right>
|
<MainContainer>
|
||||||
<MainContainer>
|
<Layout.Right initialSize={300} minSize={200}>
|
||||||
<TemporarilyContent />
|
<MainContentWrapper>
|
||||||
</MainContainer>
|
<ContentContainer>
|
||||||
<RightMenu />
|
<TemporarilyContent />
|
||||||
</Layout.Right>
|
</ContentContainer>
|
||||||
|
</MainContentWrapper>
|
||||||
|
<MainContentWrapper>
|
||||||
|
<ContentContainer>
|
||||||
|
<RightMenu />
|
||||||
|
</ContentContainer>
|
||||||
|
</MainContentWrapper>
|
||||||
|
</Layout.Right>
|
||||||
|
</MainContainer>
|
||||||
</Layout.Left>
|
</Layout.Left>
|
||||||
</Layout.Top>
|
</Layout.Top>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function LeftMenu() {
|
const LeftMenu = styled(FlexRow)({
|
||||||
return <div>LeftMenu</div>;
|
boxShadow: `inset -1px 0px 0px ${theme.dividerColor}`,
|
||||||
}
|
height: '100%',
|
||||||
|
width: '100%',
|
||||||
|
});
|
||||||
|
|
||||||
|
const MainContainer = styled('div')({
|
||||||
|
display: 'flex',
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
background: theme.backgroundWash,
|
||||||
|
paddingRight: theme.space.middle,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ContentContainer = styled('div')({
|
||||||
|
width: '100%',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
background: theme.backgroundDefault,
|
||||||
|
border: `1px solid ${theme.dividerColor}`,
|
||||||
|
borderRadius: theme.space.small,
|
||||||
|
boxShadow: `0px 0px 5px rgba(0, 0, 0, 0.05), 0px 0px 1px rgba(0, 0, 0, 0.05)`,
|
||||||
|
});
|
||||||
|
|
||||||
|
const MainContentWrapper = styled('div')({
|
||||||
|
height: '100%',
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'stretch',
|
||||||
|
padding: `${theme.space.middle}px 0`,
|
||||||
|
});
|
||||||
|
|
||||||
function RightMenu() {
|
function RightMenu() {
|
||||||
return <div>RightMenu</div>;
|
return <div>RightMenu</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function MainContainer({children}: any) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
MainContainer
|
|
||||||
<br />
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function TemporarilyContent() {
|
function TemporarilyContent() {
|
||||||
return (
|
return (
|
||||||
<Container>
|
<>
|
||||||
<Box>
|
New UI for Flipper, Sandy Project! Nothing to see now. Go back to current
|
||||||
<AnnoucementText>
|
Flipper
|
||||||
New UI for Flipper, Sandy Project! Nothing to see now. Go back to
|
<DatePicker />
|
||||||
current Flipper
|
</>
|
||||||
</AnnoucementText>
|
|
||||||
<DatePicker />
|
|
||||||
</Box>
|
|
||||||
</Container>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
|
||||||
({settingsState}) => ({settings: settingsState}),
|
|
||||||
(dispatch) => ({
|
|
||||||
disableSandy: (settings: Settings) => {
|
|
||||||
console.log(settings);
|
|
||||||
dispatch(updateSettings({...settings, enableSandy: false}));
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)(SandyApp);
|
|
||||||
|
|||||||
65
desktop/app/src/sandy-chrome/TemporarilyTitlebar.tsx
Normal file
65
desktop/app/src/sandy-chrome/TemporarilyTitlebar.tsx
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* 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 React from 'react';
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import {State as Store} from '../reducers';
|
||||||
|
import {Settings, updateSettings} from '../reducers/settings';
|
||||||
|
import {styled, colors} from 'flipper';
|
||||||
|
import {Button} from 'antd';
|
||||||
|
import {CloseCircleOutlined} from '@ant-design/icons';
|
||||||
|
|
||||||
|
type StateFromProps = {settings: Settings};
|
||||||
|
type DispatchFromProps = {disableSandy: (settings: Settings) => void};
|
||||||
|
type OwnProps = {};
|
||||||
|
|
||||||
|
type Props = StateFromProps & DispatchFromProps & OwnProps;
|
||||||
|
|
||||||
|
// This component should be dropped, and insetTitlebar should be removed from Electron startup once Sandy is the default
|
||||||
|
const TemporarilyTitlebarContainer = styled('div')<{focused?: boolean}>(
|
||||||
|
({focused}) => ({
|
||||||
|
textAlign: 'center',
|
||||||
|
userSelect: 'none',
|
||||||
|
height: '38px',
|
||||||
|
lineHeight: '38px',
|
||||||
|
fontSize: '10pt',
|
||||||
|
color: colors.macOSTitleBarIcon,
|
||||||
|
background: true
|
||||||
|
? `linear-gradient(to bottom, ${colors.macOSTitleBarBackgroundTop} 0%, ${colors.macOSTitleBarBackgroundBottom} 100%)`
|
||||||
|
: colors.macOSTitleBarBackgroundBlur,
|
||||||
|
borderBottom: `1px solid ${
|
||||||
|
focused ? colors.macOSTitleBarBorder : colors.macOSTitleBarBorderBlur
|
||||||
|
}`,
|
||||||
|
WebkitAppRegion: 'drag',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const TemporarilyTitlebar = connect<
|
||||||
|
StateFromProps,
|
||||||
|
DispatchFromProps,
|
||||||
|
OwnProps,
|
||||||
|
Store
|
||||||
|
>(
|
||||||
|
({settingsState}) => ({settings: settingsState}),
|
||||||
|
(dispatch) => ({
|
||||||
|
disableSandy: (settings: Settings) => {
|
||||||
|
console.log(settings);
|
||||||
|
dispatch(updateSettings({...settings, enableSandy: false}));
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)((props: Props) => (
|
||||||
|
<TemporarilyTitlebarContainer focused /*TODO: make dynamic */>
|
||||||
|
[Sandy] Flipper{' '}
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
type="link"
|
||||||
|
icon={<CloseCircleOutlined />}
|
||||||
|
onClick={() => props.disableSandy(props.settings)}></Button>
|
||||||
|
</TemporarilyTitlebarContainer>
|
||||||
|
));
|
||||||
@@ -22,4 +22,10 @@ export const theme = {
|
|||||||
backgroundWash: 'var(--flipper-background-wash)',
|
backgroundWash: 'var(--flipper-background-wash)',
|
||||||
dividerColor: 'var(--flipper-divider-color)',
|
dividerColor: 'var(--flipper-divider-color)',
|
||||||
borderRadius: 'var(--flipper-border-radius)',
|
borderRadius: 'var(--flipper-border-radius)',
|
||||||
|
space: {
|
||||||
|
// from Space component in Ant
|
||||||
|
small: 8,
|
||||||
|
middle: 16,
|
||||||
|
large: 24,
|
||||||
|
} as const,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ type InteractiveProps = {
|
|||||||
style?: Object;
|
style?: Object;
|
||||||
className?: string;
|
className?: string;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
gutterWidth?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type InteractiveState = {
|
type InteractiveState = {
|
||||||
@@ -549,11 +550,12 @@ export default class Interactive extends React.Component<
|
|||||||
const x = event.clientX - offsetLeft;
|
const x = event.clientX - offsetLeft;
|
||||||
const y = event.clientY - offsetTop;
|
const y = event.clientY - offsetTop;
|
||||||
|
|
||||||
const atTop: boolean = y <= WINDOW_CURSOR_BOUNDARY;
|
const gutterWidth = this.props.gutterWidth || WINDOW_CURSOR_BOUNDARY;
|
||||||
const atBottom: boolean = y >= height - WINDOW_CURSOR_BOUNDARY;
|
const atTop: boolean = y <= gutterWidth;
|
||||||
|
const atBottom: boolean = y >= height - gutterWidth;
|
||||||
|
|
||||||
const atLeft: boolean = x <= WINDOW_CURSOR_BOUNDARY;
|
const atLeft: boolean = x <= gutterWidth;
|
||||||
const atRight: boolean = x >= width - WINDOW_CURSOR_BOUNDARY;
|
const atRight: boolean = x >= width - gutterWidth;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bottom: canResize.bottom === true && atBottom,
|
bottom: canResize.bottom === true && atBottom,
|
||||||
|
|||||||
@@ -9,9 +9,20 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import {Sidebar} from '..';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
/**
|
||||||
|
* If set, the dynamically sized pane will get scrollbars when needed
|
||||||
|
*/
|
||||||
scrollable?: boolean;
|
scrollable?: boolean;
|
||||||
|
/**
|
||||||
|
* If set, the 'fixed' child will no longer be sized based on it's own dimensions,
|
||||||
|
* but rather it will be possible to resize it
|
||||||
|
*/
|
||||||
|
initialSize?: number;
|
||||||
|
minSize?: number;
|
||||||
|
|
||||||
children: [React.ReactNode, React.ReactNode];
|
children: [React.ReactNode, React.ReactNode];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,16 +53,35 @@ const Container = styled('div')<{horizontal: boolean}>(({horizontal}) => ({
|
|||||||
Container.displayName = 'Layout:Container';
|
Container.displayName = 'Layout:Container';
|
||||||
|
|
||||||
function renderLayout(
|
function renderLayout(
|
||||||
{children, scrollable}: Props,
|
{children, scrollable, initialSize, minSize}: Props,
|
||||||
horizontal: boolean,
|
horizontal: boolean,
|
||||||
reverse: boolean,
|
reverse: boolean,
|
||||||
) {
|
) {
|
||||||
if (children.length !== 2) {
|
if (children.length !== 2) {
|
||||||
throw new Error('Layout expects exactly 2 children');
|
throw new Error('Layout expects exactly 2 children');
|
||||||
}
|
}
|
||||||
const fixedElement = (
|
const fixedChild = reverse ? children[1] : children[0];
|
||||||
<FixedContainer>{reverse ? children[1] : children[0]}</FixedContainer>
|
|
||||||
);
|
const fixedElement =
|
||||||
|
initialSize === undefined ? (
|
||||||
|
<FixedContainer>{fixedChild}</FixedContainer>
|
||||||
|
) : horizontal ? (
|
||||||
|
<Sidebar
|
||||||
|
position={reverse ? 'right' : 'left'}
|
||||||
|
width={initialSize}
|
||||||
|
minWidth={minSize}
|
||||||
|
gutter>
|
||||||
|
{fixedChild}
|
||||||
|
</Sidebar>
|
||||||
|
) : (
|
||||||
|
<Sidebar
|
||||||
|
position={reverse ? 'bottom' : 'top'}
|
||||||
|
height={initialSize}
|
||||||
|
minHeight={minSize}
|
||||||
|
gutter>
|
||||||
|
{fixedChild}
|
||||||
|
</Sidebar>
|
||||||
|
);
|
||||||
const dynamicElement = (
|
const dynamicElement = (
|
||||||
<ScrollContainer scrollable={!!scrollable}>
|
<ScrollContainer scrollable={!!scrollable}>
|
||||||
{reverse ? children[0] : children[1]}
|
{reverse ? children[0] : children[1]}
|
||||||
@@ -77,6 +107,8 @@ function renderLayout(
|
|||||||
* The main area will be scrollable by default, but if multiple containers are nested,
|
* The main area will be scrollable by default, but if multiple containers are nested,
|
||||||
* scrolling can be disabled by using `scrollable={false}`
|
* scrolling can be disabled by using `scrollable={false}`
|
||||||
*
|
*
|
||||||
|
* If initialSize is set, the fixed container will be made resizable
|
||||||
|
*
|
||||||
* Use Layout.Top / Right / Bottom / Left to indicate where the fixed element should live.
|
* Use Layout.Top / Right / Bottom / Left to indicate where the fixed element should live.
|
||||||
*/
|
*/
|
||||||
const Layout: Record<'Left' | 'Right' | 'Top' | 'Bottom', React.FC<Props>> = {
|
const Layout: Record<'Left' | 'Right' | 'Top' | 'Bottom', React.FC<Props>> = {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
import Interactive from './Interactive';
|
import Interactive from './Interactive';
|
||||||
import FlexColumn from './FlexColumn';
|
import FlexColumn from './FlexColumn';
|
||||||
import {colors} from './colors';
|
import {colors} from './colors';
|
||||||
import {Component} from 'react';
|
import {Component, ReactNode} from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import {
|
import {
|
||||||
BackgroundClipProperty,
|
BackgroundClipProperty,
|
||||||
@@ -19,6 +19,9 @@ import {
|
|||||||
BackgroundColorProperty,
|
BackgroundColorProperty,
|
||||||
} from 'csstype';
|
} from 'csstype';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import FlexRow from './FlexRow';
|
||||||
|
import {MoreOutlined} from '@ant-design/icons';
|
||||||
|
import {theme} from '../../sandy-chrome/theme';
|
||||||
|
|
||||||
const SidebarInteractiveContainer = styled(Interactive)({
|
const SidebarInteractiveContainer = styled(Interactive)({
|
||||||
flex: 'none',
|
flex: 'none',
|
||||||
@@ -31,12 +34,18 @@ const SidebarContainer = styled(FlexColumn)<{
|
|||||||
position: 'right' | 'top' | 'left' | 'bottom';
|
position: 'right' | 'top' | 'left' | 'bottom';
|
||||||
backgroundColor?: BackgroundClipProperty;
|
backgroundColor?: BackgroundClipProperty;
|
||||||
overflow?: boolean;
|
overflow?: boolean;
|
||||||
|
unstyled?: boolean;
|
||||||
}>((props) => ({
|
}>((props) => ({
|
||||||
backgroundColor: props.backgroundColor || colors.macOSTitleBarBackgroundBlur,
|
...(props.unstyled
|
||||||
borderLeft: props.position === 'right' ? '1px solid #b3b3b3' : 'none',
|
? undefined
|
||||||
borderTop: props.position === 'bottom' ? '1px solid #b3b3b3' : 'none',
|
: {
|
||||||
borderRight: props.position === 'left' ? '1px solid #b3b3b3' : 'none',
|
backgroundColor:
|
||||||
borderBottom: props.position === 'top' ? '1px solid #b3b3b3' : 'none',
|
props.backgroundColor || colors.macOSTitleBarBackgroundBlur,
|
||||||
|
borderLeft: props.position === 'right' ? '1px solid #b3b3b3' : 'none',
|
||||||
|
borderTop: props.position === 'bottom' ? '1px solid #b3b3b3' : 'none',
|
||||||
|
borderRight: props.position === 'left' ? '1px solid #b3b3b3' : 'none',
|
||||||
|
borderBottom: props.position === 'top' ? '1px solid #b3b3b3' : 'none',
|
||||||
|
}),
|
||||||
height: '100%',
|
height: '100%',
|
||||||
overflowX: 'hidden',
|
overflowX: 'hidden',
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
@@ -93,6 +102,10 @@ type SidebarProps = {
|
|||||||
* Class name to customise styling.
|
* Class name to customise styling.
|
||||||
*/
|
*/
|
||||||
className?: string;
|
className?: string;
|
||||||
|
/**
|
||||||
|
* use a Sandy themed large gutter
|
||||||
|
*/
|
||||||
|
gutter?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SidebarState = {
|
type SidebarState = {
|
||||||
@@ -138,7 +151,7 @@ export default class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {backgroundColor, onResize, position, children} = this.props;
|
const {backgroundColor, onResize, position, children, gutter} = this.props;
|
||||||
let height: number | undefined;
|
let height: number | undefined;
|
||||||
let minHeight: number | undefined;
|
let minHeight: number | undefined;
|
||||||
let maxHeight: number | undefined;
|
let maxHeight: number | undefined;
|
||||||
@@ -183,11 +196,58 @@ export default class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||||||
maxHeight={maxHeight}
|
maxHeight={maxHeight}
|
||||||
height={!horizontal ? (onResize ? height : this.state.height) : '100%'}
|
height={!horizontal ? (onResize ? height : this.state.height) : '100%'}
|
||||||
resizable={resizable}
|
resizable={resizable}
|
||||||
onResize={this.onResize}>
|
onResize={this.onResize}
|
||||||
<SidebarContainer position={position} backgroundColor={backgroundColor}>
|
gutterWidth={gutter ? theme.space.middle : undefined}>
|
||||||
{children}
|
<SidebarContainer
|
||||||
|
position={position}
|
||||||
|
backgroundColor={backgroundColor}
|
||||||
|
unstyled={gutter}>
|
||||||
|
{gutter ? (
|
||||||
|
<GutterWrapper position={position}>{children}</GutterWrapper>
|
||||||
|
) : (
|
||||||
|
children
|
||||||
|
)}
|
||||||
</SidebarContainer>
|
</SidebarContainer>
|
||||||
</SidebarInteractiveContainer>
|
</SidebarInteractiveContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GutterWrapper = ({
|
||||||
|
position,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
position: SidebarPosition;
|
||||||
|
children: ReactNode;
|
||||||
|
}) => {
|
||||||
|
return position === 'right' ? (
|
||||||
|
<FlexRow grow>
|
||||||
|
<VerticalGutter />
|
||||||
|
{children}
|
||||||
|
</FlexRow>
|
||||||
|
) : (
|
||||||
|
<FlexRow grow>
|
||||||
|
{children}
|
||||||
|
<VerticalGutter />
|
||||||
|
</FlexRow>
|
||||||
|
); // TODO: support top / bottom
|
||||||
|
};
|
||||||
|
|
||||||
|
const VerticalGutterContainer = styled('div')({
|
||||||
|
width: theme.space.middle,
|
||||||
|
height: '100%',
|
||||||
|
color: theme.textColorPlaceholder,
|
||||||
|
fontSize: '16px',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
background: theme.backgroundWash,
|
||||||
|
':hover': {
|
||||||
|
background: theme.dividerColor,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const VerticalGutter = () => (
|
||||||
|
<VerticalGutterContainer>
|
||||||
|
<MoreOutlined />
|
||||||
|
</VerticalGutterContainer>
|
||||||
|
);
|
||||||
|
|||||||
@@ -144,10 +144,14 @@ function compileRegex(s: string): RegExp | null {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Searchable = (
|
/**
|
||||||
|
* Higher-order-component that allows adding a searchbar on top of the wrapped
|
||||||
|
* component. See SearchableManagedTable for usage with a table.
|
||||||
|
*/
|
||||||
|
export default function Searchable(
|
||||||
Component: React.ComponentType<any>,
|
Component: React.ComponentType<any>,
|
||||||
): React.ComponentType<any> =>
|
): React.ComponentType<any> {
|
||||||
class extends PureComponent<Props, State> {
|
return class extends PureComponent<Props, State> {
|
||||||
static displayName = `Searchable(${Component.displayName})`;
|
static displayName = `Searchable(${Component.displayName})`;
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
@@ -544,9 +548,4 @@ const Searchable = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Higher-order-component that allows adding a searchbar on top of the wrapped
|
|
||||||
* component. See SearchableManagedTable for usage with a table.
|
|
||||||
*/
|
|
||||||
export default Searchable;
|
|
||||||
|
|||||||
@@ -176,5 +176,6 @@ export {default as Info} from './components/Info';
|
|||||||
export {default as Bordered} from './components/Bordered';
|
export {default as Bordered} from './components/Bordered';
|
||||||
export {default as AlternatingRows} from './components/AlternatingRows';
|
export {default as AlternatingRows} from './components/AlternatingRows';
|
||||||
export {default as Layout} from './components/Layout';
|
export {default as Layout} from './components/Layout';
|
||||||
|
|
||||||
export {default as Scrollable} from './components/Scrollable';
|
export {default as Scrollable} from './components/Scrollable';
|
||||||
export * from './components/Highlight';
|
export * from './components/Highlight';
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
This section maps theme colors to CSS variables so that thye can be
|
This section maps theme colors to CSS variables so that thye can be
|
||||||
used in styled components, see sandyColors.tsx
|
used in styled components, see theme.tsx
|
||||||
*/
|
*/
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
|||||||
Reference in New Issue
Block a user